Commit | Line | Data |
---|---|---|
0235b0db MJ |
1 | # SPDX-License-Identifier: BSD-2-Clause |
2 | # | |
b85894a3 MJ |
3 | # Copyright (c) 2016, Matt Layman |
4 | ||
5 | from tap.adapter import Adapter | |
6 | from tap.directive import Directive | |
7 | from tap.i18n import _ | |
8 | from tap.line import Result | |
9 | ||
10 | ||
11 | class Rules(object): | |
12 | ||
13 | def __init__(self, filename, suite): | |
14 | self._filename = filename | |
15 | self._suite = suite | |
16 | self._lines_seen = {'plan': [], 'test': 0, 'version': []} | |
17 | ||
18 | def check(self, final_line_count): | |
19 | """Check the status of all provided data and update the suite.""" | |
20 | if self._lines_seen['version']: | |
21 | self._process_version_lines() | |
22 | self._process_plan_lines(final_line_count) | |
23 | ||
24 | def _process_version_lines(self): | |
25 | """Process version line rules.""" | |
26 | if len(self._lines_seen['version']) > 1: | |
27 | self._add_error(_('Multiple version lines appeared.')) | |
28 | elif self._lines_seen['version'][0] != 1: | |
29 | self._add_error(_('The version must be on the first line.')) | |
30 | ||
31 | def _process_plan_lines(self, final_line_count): | |
32 | """Process plan line rules.""" | |
33 | if not self._lines_seen['plan']: | |
34 | self._add_error(_('Missing a plan.')) | |
35 | return | |
36 | ||
37 | if len(self._lines_seen['plan']) > 1: | |
38 | self._add_error(_('Only one plan line is permitted per file.')) | |
39 | return | |
40 | ||
41 | plan, at_line = self._lines_seen['plan'][0] | |
42 | if not self._plan_on_valid_line(at_line, final_line_count): | |
43 | self._add_error( | |
44 | _('A plan must appear at the beginning or end of the file.')) | |
45 | return | |
46 | ||
47 | if plan.expected_tests != self._lines_seen['test']: | |
48 | self._add_error(_( | |
49 | 'Expected {expected_count} tests ' | |
50 | 'but only {seen_count} ran.').format( | |
51 | expected_count=plan.expected_tests, | |
52 | seen_count=self._lines_seen['test'])) | |
53 | ||
54 | def _plan_on_valid_line(self, at_line, final_line_count): | |
55 | """Check if a plan is on a valid line.""" | |
56 | # Put the common cases first. | |
57 | if at_line == 1 or at_line == final_line_count: | |
58 | return True | |
59 | ||
60 | # The plan may only appear on line 2 if the version is at line 1. | |
61 | after_version = ( | |
62 | self._lines_seen['version'] and | |
63 | self._lines_seen['version'][0] == 1 and | |
64 | at_line == 2) | |
65 | if after_version: | |
66 | return True | |
67 | ||
68 | return False | |
69 | ||
70 | def handle_bail(self, bail): | |
71 | """Handle a bail line.""" | |
72 | self._add_error(_('Bailed: {reason}').format(reason=bail.reason)) | |
73 | ||
74 | def handle_file_does_not_exist(self): | |
75 | """Handle a test file that does not exist.""" | |
76 | self._add_error(_('{filename} does not exist.').format( | |
77 | filename=self._filename)) | |
78 | ||
79 | def handle_skipping_plan(self, skip_plan): | |
80 | """Handle a plan that contains a SKIP directive.""" | |
81 | skip_line = Result( | |
82 | True, None, skip_plan.directive.text, Directive('SKIP')) | |
83 | self._suite.addTest(Adapter(self._filename, skip_line)) | |
84 | ||
85 | def saw_plan(self, plan, at_line): | |
86 | """Record when a plan line was seen.""" | |
87 | self._lines_seen['plan'].append((plan, at_line)) | |
88 | ||
89 | def saw_test(self): | |
90 | """Record when a test line was seen.""" | |
91 | self._lines_seen['test'] += 1 | |
92 | ||
93 | def saw_version_at(self, line_counter): | |
94 | """Record when a version line was seen.""" | |
95 | self._lines_seen['version'].append(line_counter) | |
96 | ||
97 | def _add_error(self, message): | |
98 | """Add an error test to the suite.""" | |
99 | error_line = Result(False, None, message, Directive('')) | |
100 | self._suite.addTest(Adapter(self._filename, error_line)) |