Commit | Line | Data |
---|---|---|
d2d06893 MJ |
1 | # SPDX-FileCopyrightText: 2023 Philippe Proulx <eeppeliteloop@gmail.com> |
2 | # SPDX-License-Identifier: MIT | |
bf8f3b38 PP |
3 | |
4 | import re | |
5 | ||
6 | import pytest | |
7 | ||
8 | import normand | |
9 | ||
10 | ||
11 | def pytest_collect_file(parent, file_path): | |
12 | ext = ".nt" | |
13 | ||
14 | if file_path.suffix != ext: | |
15 | # Not a Normand test file: cancel | |
16 | return | |
17 | ||
18 | test_name = "test-{}".format(file_path.name.replace(ext, "")) | |
19 | ||
20 | # Create the file node | |
21 | if file_path.name.startswith("fail-"): | |
22 | return _NormandTestFileFail.from_parent(parent, path=file_path, name=test_name) | |
23 | elif file_path.name.startswith("pass-"): | |
24 | return _NormandTestFilePass.from_parent(parent, path=file_path, name=test_name) | |
25 | else: | |
26 | # `.nt` file isn't a test case | |
27 | return | |
28 | ||
29 | ||
30 | def _split_nt_file(path): | |
31 | normand_lines = [] | |
32 | output_lines = [] | |
33 | cur_lines = normand_lines | |
34 | ||
35 | with open(path) as f: | |
36 | for line in f: | |
37 | if line.rstrip() == "---" and len(output_lines) == 0: | |
38 | cur_lines = output_lines | |
39 | continue | |
40 | ||
41 | cur_lines.append(line) | |
42 | ||
43 | return "".join(normand_lines), "".join(output_lines).strip() | |
44 | ||
45 | ||
46 | class _NormandTestItem(pytest.Item): | |
47 | def runtest(self): | |
48 | self._runtest(*_split_nt_file(self.path)) | |
49 | ||
50 | def reportinfo(self): | |
51 | return self.path, None, self.name | |
52 | ||
53 | ||
54 | class _NormandTestItemFail(_NormandTestItem): | |
55 | def _runtest(self, normand_text, output): | |
56 | with pytest.raises(normand.ParseError) as exc_info: | |
57 | normand.parse(normand_text) | |
58 | ||
59 | exc = exc_info.value | |
ee724c95 | 60 | expected_msg = "" |
f5dcb24c PP |
61 | |
62 | for msg in reversed(exc.messages): | |
63 | expected_msg += "{}:{} - {}\n".format( | |
64 | msg.text_location.line_no, msg.text_location.col_no, msg.text | |
65 | ) | |
66 | ||
67 | assert output.strip() == expected_msg.strip() | |
bf8f3b38 PP |
68 | |
69 | ||
70 | class _NormandTestItemPass(_NormandTestItem): | |
71 | @staticmethod | |
72 | def _data_from_output(output): | |
73 | hex_bytes = re.split(r"\s+", output.strip()) | |
74 | return bytearray([int(b, 16) for b in hex_bytes]) | |
75 | ||
76 | def _runtest(self, normand_text, output): | |
77 | assert normand.parse(normand_text).data == self._data_from_output(output) | |
78 | ||
79 | ||
80 | class _NormandTestFile(pytest.File): | |
81 | def __init__(self, name, **kwargs): | |
82 | super().__init__(**kwargs) | |
83 | self._name = name | |
84 | ||
85 | def collect(self): | |
86 | # Yield a single item | |
87 | yield self._item_cls.from_parent(self, name=self._name) | |
88 | ||
89 | ||
90 | class _NormandTestFileFail(_NormandTestFile): | |
91 | _item_cls = _NormandTestItemFail | |
92 | ||
93 | ||
94 | class _NormandTestFilePass(_NormandTestFile): | |
95 | _item_cls = _NormandTestItemPass |