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