Mercurial > jouvence
comparison tests/conftest.py @ 0:243401c49520
Initial commit.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Mon, 02 Jan 2017 12:30:49 -0800 |
parents | |
children | 74b83e3d921e |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:243401c49520 |
---|---|
1 import sys | |
2 import logging | |
3 import yaml | |
4 import pytest | |
5 from fontaine.document import ( | |
6 FontaineSceneElement, | |
7 TYPE_ACTION, TYPE_CHARACTER, TYPE_DIALOG, TYPE_PARENTHETICAL) | |
8 from fontaine.parser import FontaineParser, FontaineParserError | |
9 | |
10 | |
11 def pytest_addoption(parser): | |
12 parser.addoption( | |
13 '--log-debug', | |
14 action='store_true', | |
15 help="Sets the Fontaine logger to output debug info to stdout.") | |
16 | |
17 | |
18 def pytest_configure(config): | |
19 if config.getoption('--log-debug'): | |
20 hdl = logging.StreamHandler(stream=sys.stdout) | |
21 logging.getLogger('fontaine').addHandler(hdl) | |
22 logging.getLogger('fontaine').setLevel(logging.DEBUG) | |
23 | |
24 | |
25 def pytest_collect_file(parent, path): | |
26 if path.ext == '.yaml' and path.basename.startswith("test"): | |
27 return FontaineScriptTestFile(path, parent) | |
28 return None | |
29 | |
30 | |
31 def assert_scenes(actual, scenes): | |
32 assert len(actual) == len(scenes) | |
33 for a, e in zip(actual, scenes): | |
34 assert_scene(a, e[0], e[1:]) | |
35 | |
36 | |
37 def assert_scene(actual, header, paragraphs): | |
38 if header is not None: | |
39 assert actual.header == header | |
40 assert len(actual.paragraphs) == len(paragraphs) | |
41 for a, e in zip(actual.paragraphs, paragraphs): | |
42 assert_paragraph(a, e) | |
43 | |
44 | |
45 def assert_paragraph(actual, expected): | |
46 if isinstance(expected, str): | |
47 assert isinstance(actual, FontaineSceneElement) | |
48 assert actual.type == TYPE_ACTION | |
49 assert actual.text == expected | |
50 elif isinstance(expected, FontaineSceneElement): | |
51 assert isinstance(actual, FontaineSceneElement) | |
52 assert actual.type == expected.type | |
53 assert actual.text == expected.text | |
54 else: | |
55 raise NotImplementedError("Don't know what this is: %s" % expected) | |
56 | |
57 | |
58 def _c(name): | |
59 return FontaineSceneElement(TYPE_CHARACTER, name) | |
60 | |
61 | |
62 def _p(text): | |
63 return FontaineSceneElement(TYPE_PARENTHETICAL, text) | |
64 | |
65 | |
66 def _d(text): | |
67 return FontaineSceneElement(TYPE_DIALOG, text) | |
68 | |
69 | |
70 class FontaineScriptTestFile(pytest.File): | |
71 def collect(self): | |
72 spec = yaml.load_all(self.fspath.open(encoding='utf8')) | |
73 for i, item in enumerate(spec): | |
74 name = '%s_%d' % (self.fspath.basename, i) | |
75 if 'test_name' in item: | |
76 name += '_%s' % item['test_name'] | |
77 yield FontaineScriptTestItem(name, self, item) | |
78 | |
79 | |
80 class FontaineScriptTestItem(pytest.Item): | |
81 def __init__(self, name, parent, spec): | |
82 super().__init__(name, parent) | |
83 self.spec = spec | |
84 | |
85 def reportinfo(self): | |
86 return self.fspath, 0, "fontaine script test: %s" % self.name | |
87 | |
88 def runtest(self): | |
89 intext = self.spec.get('in') | |
90 expected = self.spec.get('out') | |
91 title = self.spec.get('title') | |
92 if intext is None or expected is None: | |
93 raise Exception("No 'in' or 'out' specified.") | |
94 | |
95 parser = FontaineParser() | |
96 doc = parser.parseString(intext) | |
97 if title is not None: | |
98 assert title == doc.title_values | |
99 assert_scenes(doc.scenes, make_scenes(expected)) | |
100 | |
101 def repr_failure(self, excinfo): | |
102 if isinstance(excinfo.value, FontaineParserError): | |
103 return ('\n'.join( | |
104 ['Parser error:', str(excinfo.value)])) | |
105 return super().repr_failure(excinfo) | |
106 | |
107 | |
108 def make_scenes(spec): | |
109 if not isinstance(spec, list): | |
110 raise Exception("Script specs must be lists.") | |
111 | |
112 out = [] | |
113 cur_header = None | |
114 cur_paras = [] | |
115 | |
116 for item in spec: | |
117 token = item[:1] | |
118 if token == '.': | |
119 if cur_header or cur_paras: | |
120 out.append([cur_header] + cur_paras) | |
121 cur_header = item[1:] | |
122 elif token == '!': | |
123 cur_paras.append(item[1:]) | |
124 elif token == '@': | |
125 cur_paras.append(_c(item[1:])) | |
126 elif token == '=': | |
127 cur_paras.append(_d(item[1:])) | |
128 elif token == '_': | |
129 cur_paras.append(_p(item[1:])) | |
130 else: | |
131 raise Exception("Unknown token: %s" % token) | |
132 if cur_header or cur_paras: | |
133 out.append([cur_header] + cur_paras) | |
134 return out |