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