comparison tests/conftest.py @ 1:74b83e3d921e

Add more states, add more tests.
author Ludovic Chabant <ludovic@chabant.com>
date Mon, 02 Jan 2017 21:54:59 -0800
parents 243401c49520
children 59fe8cb6190d
comparison
equal deleted inserted replaced
0:243401c49520 1:74b83e3d921e
2 import logging 2 import logging
3 import yaml 3 import yaml
4 import pytest 4 import pytest
5 from fontaine.document import ( 5 from fontaine.document import (
6 FontaineSceneElement, 6 FontaineSceneElement,
7 TYPE_ACTION, TYPE_CHARACTER, TYPE_DIALOG, TYPE_PARENTHETICAL) 7 TYPE_ACTION, TYPE_CENTEREDACTION, TYPE_CHARACTER, TYPE_DIALOG,
8 TYPE_PARENTHETICAL, TYPE_TRANSITION, TYPE_LYRICS, TYPE_PAGEBREAK,
9 _scene_element_type_str)
8 from fontaine.parser import FontaineParser, FontaineParserError 10 from fontaine.parser import FontaineParser, FontaineParserError
11 from fontaine.renderer import BaseRenderer
9 12
10 13
11 def pytest_addoption(parser): 14 def pytest_addoption(parser):
12 parser.addoption( 15 parser.addoption(
13 '--log-debug', 16 '--log-debug',
65 68
66 def _d(text): 69 def _d(text):
67 return FontaineSceneElement(TYPE_DIALOG, text) 70 return FontaineSceneElement(TYPE_DIALOG, text)
68 71
69 72
73 def _t(text):
74 return FontaineSceneElement(TYPE_TRANSITION, text)
75
76
77 def _l(text):
78 return FontaineSceneElement(TYPE_LYRICS, text)
79
80
81 class UnexpectedScriptOutput(Exception):
82 def __init__(self, actual, expected):
83 self.actual = actual
84 self.expected = expected
85
86
70 class FontaineScriptTestFile(pytest.File): 87 class FontaineScriptTestFile(pytest.File):
71 def collect(self): 88 def collect(self):
72 spec = yaml.load_all(self.fspath.open(encoding='utf8')) 89 spec = yaml.load_all(self.fspath.open(encoding='utf8'))
73 for i, item in enumerate(spec): 90 for i, item in enumerate(spec):
74 name = '%s_%d' % (self.fspath.basename, i) 91 name = '%s_%d' % (self.fspath.basename, i)
94 111
95 parser = FontaineParser() 112 parser = FontaineParser()
96 doc = parser.parseString(intext) 113 doc = parser.parseString(intext)
97 if title is not None: 114 if title is not None:
98 assert title == doc.title_values 115 assert title == doc.title_values
99 assert_scenes(doc.scenes, make_scenes(expected)) 116
117 exp_scenes = make_scenes(expected)
118 try:
119 assert_scenes(doc.scenes, exp_scenes)
120 except AssertionError:
121 raise UnexpectedScriptOutput(doc.scenes, exp_scenes)
100 122
101 def repr_failure(self, excinfo): 123 def repr_failure(self, excinfo):
102 if isinstance(excinfo.value, FontaineParserError): 124 if isinstance(excinfo.value, FontaineParserError):
103 return ('\n'.join( 125 return ('\n'.join(
104 ['Parser error:', str(excinfo.value)])) 126 ['Parser error:', str(excinfo.value)]))
127 if isinstance(excinfo.value, UnexpectedScriptOutput):
128 return ('\n'.join(
129 ['Unexpected output:'] +
130 ['', 'Actual:'] +
131 list(_repr_doc_scenes(excinfo.value.actual)) +
132 ['', 'Expected:'] +
133 list(_repr_expected_scenes(excinfo.value.expected))))
105 return super().repr_failure(excinfo) 134 return super().repr_failure(excinfo)
135
136
137 def _repr_doc_scenes(scenes):
138 for s in scenes:
139 yield 'Scene: "%s"' % s.header
140 for p in s.paragraphs:
141 yield ' %s: "%s"' % (_scene_element_type_str(p.type),
142 p.text)
143
144
145 def _repr_expected_scenes(scenes):
146 for s in scenes:
147 yield 'Scene: "%s"' % s[0]
148 for p in s[1:]:
149 if isinstance(p, str):
150 yield ' ACTION: "%s"' % p
151 else:
152 yield ' %s: "%s"' % (_scene_element_type_str(p.type),
153 p.text)
106 154
107 155
108 def make_scenes(spec): 156 def make_scenes(spec):
109 if not isinstance(spec, list): 157 if not isinstance(spec, list):
110 raise Exception("Script specs must be lists.") 158 raise Exception("Script specs must be lists.")
112 out = [] 160 out = []
113 cur_header = None 161 cur_header = None
114 cur_paras = [] 162 cur_paras = []
115 163
116 for item in spec: 164 for item in spec:
165 if item == '<pagebreak>':
166 cur_paras.append(FontaineSceneElement(TYPE_PAGEBREAK, None))
167 continue
168
117 token = item[:1] 169 token = item[:1]
118 if token == '.': 170 if token == '.':
119 if cur_header or cur_paras: 171 if cur_header or cur_paras:
120 out.append([cur_header] + cur_paras) 172 out.append([cur_header] + cur_paras)
121 cur_header = item[1:] 173 cur_header = item[1:]
174 cur_paras = []
122 elif token == '!': 175 elif token == '!':
123 cur_paras.append(item[1:]) 176 if item[1:3] == '><':
177 cur_paras.append(
178 FontaineSceneElement(TYPE_CENTEREDACTION, item[3:]))
179 else:
180 cur_paras.append(item[1:])
124 elif token == '@': 181 elif token == '@':
125 cur_paras.append(_c(item[1:])) 182 cur_paras.append(_c(item[1:]))
126 elif token == '=': 183 elif token == '=':
127 cur_paras.append(_d(item[1:])) 184 cur_paras.append(_d(item[1:]))
128 elif token == '_': 185 elif token == '_':
129 cur_paras.append(_p(item[1:])) 186 cur_paras.append(_p(item[1:]))
187 elif token == '>':
188 cur_paras.append(_t(item[1:]))
189 elif token == '~':
190 cur_paras.append(_l(item[1:]))
130 else: 191 else:
131 raise Exception("Unknown token: %s" % token) 192 raise Exception("Unknown token: %s" % token)
132 if cur_header or cur_paras: 193 if cur_header or cur_paras:
133 out.append([cur_header] + cur_paras) 194 out.append([cur_header] + cur_paras)
134 return out 195 return out
196
197
198 class TestRenderer(BaseRenderer):
199 def write_bold(self, text):
200 pass
201
202 def write_italics(self, text):
203 pass
204
205 def write_underline(self, text):
206 pass