Coverage for tests / test_templite.py: 100.000%

143 statements  

« prev     ^ index     » next       coverage.py v7.12.1a0.dev1, created at 2025-11-30 17:57 +0000

1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 

2# For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt 

3 

4"""Tests for coverage.templite.""" 

5 

6from __future__ import annotations 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

7 

8import re 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

9 

10from types import SimpleNamespace 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

11from typing import Any, ContextManager 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

12 

13import pytest 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

14 

15from coverage.templite import Templite, TempliteSyntaxError, TempliteValueError 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

16 

17from tests.coveragetest import CoverageTest 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

18 

19# pylint: disable=possibly-unused-variable 

20 

21 

22class TempliteTest(CoverageTest): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

23 """Tests for Templite.""" 

24 

25 run_in_temp_dir = False 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

26 

27 def try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%

28 self, 

29 text: str, 

30 ctx: dict[str, Any] | None = None, 

31 result: str | None = None, 

32 ) -> None: 

33 """Render `text` through `ctx`, and it had better be `result`. 

34 

35 Result defaults to None so we can shorten the calls where we expect 

36 an exception and never get to the result comparison. 

37 

38 """ 

39 actual = Templite(text).render(ctx or {}) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

40 # If result is None, then an exception should have prevented us getting 

41 # to here. 

42 assert result is not None 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

43 assert actual == result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

44 

45 def assertSynErr(self, msg: str) -> ContextManager[None]: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

46 """Assert that a `TempliteSyntaxError` will happen. 

47 

48 A context manager, and the message should be `msg`. 

49 

50 """ 

51 pat = "^" + re.escape(msg) + "$" 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

52 return pytest.raises(TempliteSyntaxError, match=pat) # type: ignore 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

53 

54 def test_passthrough(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

55 # Strings without variables are passed through unchanged. 

56 assert Templite("Hello").render() == "Hello" 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

57 assert Templite("Hello, 20% fun time!").render() == "Hello, 20% fun time!" 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

58 

59 def test_variables(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

60 # Variables use {{var}} syntax. 

61 self.try_render("Hello, {{name}}!", {"name": "Ned"}, "Hello, Ned!") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

62 

63 def test_undefined_variables(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

64 # Using undefined names is an error. 

65 with pytest.raises(Exception, match="'name'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

66 self.try_render("Hi, {{name}}!") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

67 

68 def test_pipes(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

69 # Variables can be filtered with pipes. 

70 data = { 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

71 "name": "Ned", 

72 "upper": lambda x: x.upper(), 

73 "second": lambda x: x[1], 

74 } 

75 self.try_render("Hello, {{name|upper}}!", data, "Hello, NED!") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

76 

77 # Pipes can be concatenated. 

78 self.try_render("Hello, {{name|upper|second}}!", data, "Hello, E!") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

79 

80 def test_reusability(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

81 # A single Templite can be used more than once with different data. 

82 globs = { 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

83 "upper": lambda x: x.upper(), 

84 "punct": "!", 

85 } 

86 

87 template = Templite("This is {{name|upper}}{{punct}}", globs) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

88 assert template.render({"name": "Ned"}) == "This is NED!" 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

89 assert template.render({"name": "Ben"}) == "This is BEN!" 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

90 

91 def test_attribute(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

92 # Variables' attributes can be accessed with dots. 

93 obj = SimpleNamespace(a="Ay") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

94 self.try_render("{{obj.a}}", locals(), "Ay") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

95 

96 obj2 = SimpleNamespace(obj=obj, b="Bee") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

97 self.try_render("{{obj2.obj.a}} {{obj2.b}}", locals(), "Ay Bee") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

98 

99 def test_member_function(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

100 # Variables' member functions can be used, as long as they are nullary. 

101 class WithMemberFns(SimpleNamespace): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

102 """A class to try out member function access.""" 

103 

104 def ditto(self) -> str: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

105 """Return twice the .txt attribute.""" 

106 return self.txt + self.txt # type: ignore 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

107 

108 obj = WithMemberFns(txt="Once") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

109 self.try_render("{{obj.ditto}}", locals(), "OnceOnce") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

110 

111 def test_item_access(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

112 # Variables' items can be used. 

113 d = {"a": 17, "b": 23} 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

114 self.try_render("{{d.a}} < {{d.b}}", locals(), "17 < 23") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

115 

116 def test_loops(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

117 # Loops work like in Django. 

118 nums = [1, 2, 3, 4] 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

119 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

120 "Look: {% for n in nums %}{{n}}, {% endfor %}done.", 

121 locals(), 

122 "Look: 1, 2, 3, 4, done.", 

123 ) 

124 

125 # Loop iterables can be filtered. 

126 def rev(l: list[int]) -> list[int]: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

127 """Return the reverse of `l`.""" 

128 l = l[:] 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

129 l.reverse() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

130 return l 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

131 

132 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

133 "Look: {% for n in nums|rev %}{{n}}, {% endfor %}done.", 

134 locals(), 

135 "Look: 4, 3, 2, 1, done.", 

136 ) 

137 

138 def test_empty_loops(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

139 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

140 "Empty: {% for n in nums %}{{n}}, {% endfor %}done.", 

141 {"nums": []}, 

142 "Empty: done.", 

143 ) 

144 

145 def test_multiline_loops(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

146 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

147 "Look: \n{% for n in nums %}\n{{n}}, \n{% endfor %}done.", 

148 {"nums": [1, 2, 3]}, 

149 "Look: \n\n1, \n\n2, \n\n3, \ndone.", 

150 ) 

151 

152 def test_multiple_loops(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

153 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

154 "{% for n in nums %}{{n}}{% endfor %} and " + "{% for n in nums %}{{n}}{% endfor %}", 

155 {"nums": [1, 2, 3]}, 

156 "123 and 123", 

157 ) 

158 

159 def test_comments(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

160 # Single-line comments work: 

161 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

162 "Hello, {# Name goes here: #}{{name}}!", 

163 {"name": "Ned"}, 

164 "Hello, Ned!", 

165 ) 

166 # and so do multi-line comments: 

167 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

168 "Hello, {# Name\ngoes\nhere: #}{{name}}!", 

169 {"name": "Ned"}, 

170 "Hello, Ned!", 

171 ) 

172 

173 def test_if(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

174 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

175 "Hi, {% if ned %}NED{% endif %}{% if ben %}BEN{% endif %}!", 

176 {"ned": 1, "ben": 0}, 

177 "Hi, NED!", 

178 ) 

179 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

180 "Hi, {% if ned %}NED{% endif %}{% if ben %}BEN{% endif %}!", 

181 {"ned": 0, "ben": 1}, 

182 "Hi, BEN!", 

183 ) 

184 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

185 "Hi, {% if ned %}NED{% if ben %}BEN{% endif %}{% endif %}!", 

186 {"ned": 0, "ben": 0}, 

187 "Hi, !", 

188 ) 

189 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

190 "Hi, {% if ned %}NED{% if ben %}BEN{% endif %}{% endif %}!", 

191 {"ned": 1, "ben": 0}, 

192 "Hi, NED!", 

193 ) 

194 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

195 "Hi, {% if ned %}NED{% if ben %}BEN{% endif %}{% endif %}!", 

196 {"ned": 1, "ben": 1}, 

197 "Hi, NEDBEN!", 

198 ) 

199 

200 def test_if_else(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

201 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

202 "Hi, {% if ned %}NED{% else %}NO NED{% endif %}!", 

203 {"ned": 1}, 

204 "Hi, NED!", 

205 ) 

206 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

207 "Hi, {% if ned %}NED{% else %}NO NED{% endif %}!", 

208 {"ned": 0}, 

209 "Hi, NO NED!", 

210 ) 

211 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

212 "Hi, {% if n %}NED{% if b %}BEN{% else %}NO BEN{% endif %}{% else %}NO NED{% endif %}!", 

213 {"n": 1, "b": 1}, 

214 "Hi, NEDBEN!", 

215 ) 

216 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

217 "Hi, {% if n %}NED{% if b %}BEN{% else %}NO BEN{% endif %}{% else %}NO NED{% endif %}!", 

218 {"n": 1, "b": 0}, 

219 "Hi, NEDNO BEN!", 

220 ) 

221 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

222 "Hi, {% if n %}NED{% if b %}BEN{% else %}NO BEN{% endif %}{% else %}NO NED{% endif %}!", 

223 {"n": 0, "b": 1}, 

224 "Hi, NO NED!", 

225 ) 

226 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

227 "Hi, {% if n %}NED{% if b %}BEN{% else %}NO BEN{% endif %}{% else %}NO NED{% endif %}!", 

228 {"n": 0, "b": 0}, 

229 "Hi, NO NED!", 

230 ) 

231 

232 def test_complex_if(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

233 class Complex(SimpleNamespace): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

234 """A class to try out complex data access.""" 

235 

236 def getit(self): # type: ignore 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

237 """Return it.""" 

238 return self.it 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

239 

240 obj = Complex(it={"x": "Hello", "y": 0}) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

241 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

242 "@" 

243 + "{% if obj.getit.x %}X{% endif %}" 

244 + "{% if obj.getit.y %}Y{% endif %}" 

245 + "{% if obj.getit.y|str %}S{% endif %}" 

246 + "!", 

247 {"obj": obj, "str": str}, 

248 "@XS!", 

249 ) 

250 

251 def test_loop_if(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

252 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

253 "@{% for n in nums %}{% if n %}Z{% endif %}{{n}}{% endfor %}!", 

254 {"nums": [0, 1, 2]}, 

255 "@0Z1Z2!", 

256 ) 

257 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

258 "X{%if nums%}@{% for n in nums %}{{n}}{% endfor %}{%endif%}!", 

259 {"nums": [0, 1, 2]}, 

260 "X@012!", 

261 ) 

262 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

263 "X{%if nums%}@{% for n in nums %}{{n}}{% endfor %}{%endif%}!", 

264 {"nums": []}, 

265 "X!", 

266 ) 

267 

268 def test_nested_loops(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

269 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

270 "@" 

271 + "{% for n in nums %}" 

272 + "{% for a in abc %}{{a}}{{n}}{% endfor %}" 

273 + "{% endfor %}" 

274 + "!", 

275 {"nums": [0, 1, 2], "abc": ["a", "b", "c"]}, 

276 "@a0b0c0a1b1c1a2b2c2!", 

277 ) 

278 

279 def test_whitespace_handling(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

280 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

281 "@{% for n in nums %}\n" 

282 + " {% for a in abc %}{{a}}{{n}}{% endfor %}\n" 

283 + "{% endfor %}!\n", 

284 {"nums": [0, 1, 2], "abc": ["a", "b", "c"]}, 

285 "@\n a0b0c0\n\n a1b1c1\n\n a2b2c2\n!\n", 

286 ) 

287 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

288 "@{% for n in nums -%}\n" 

289 + " {% for a in abc -%}\n" 

290 + " {# this disappears completely -#}\n" 

291 + " {{a-}}\n" 

292 + " {{n -}}\n" 

293 + " {{n -}}\n" 

294 + " {% endfor %}\n" 

295 + "{% endfor %}!\n", 

296 {"nums": [0, 1, 2], "abc": ["a", "b", "c"]}, 

297 "@a00b00c00\na11b11c11\na22b22c22\n!\n", 

298 ) 

299 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

300 "@{% for n in nums -%}\n" + " {{n -}}\n" + " x\n" + "{% endfor %}!\n", 

301 {"nums": [0, 1, 2]}, 

302 "@0x\n1x\n2x\n!\n", 

303 ) 

304 self.try_render(" hello ", {}, " hello ") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

305 

306 def test_eat_whitespace(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

307 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

308 "Hey!\n" 

309 + "{% joined %}\n" 

310 + "@{% for n in nums %}\n" 

311 + " {% for a in abc %}\n" 

312 + " {# this disappears completely #}\n" 

313 + " X\n" 

314 + " Y\n" 

315 + " {{a}}\n" 

316 + " {{n }}\n" 

317 + " {% endfor %}\n" 

318 + "{% endfor %}!\n" 

319 + "{% endjoined %}\n", 

320 {"nums": [0, 1, 2], "abc": ["a", "b", "c"]}, 

321 "Hey!\n@XYa0XYb0XYc0XYa1XYb1XYc1XYa2XYb2XYc2!\n", 

322 ) 

323 

324 def test_non_ascii(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

325 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

326 "{{where}} ollǝɥ", 

327 {"where": "ǝɹǝɥʇ"}, 

328 "ǝɹǝɥʇ ollǝɥ", 

329 ) 

330 

331 def test_exception_during_evaluation(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

332 # TypeError: Couldn't evaluate {{ foo.bar.baz }}: 

333 regex = "^Couldn't evaluate None.bar$" 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

334 with pytest.raises(TempliteValueError, match=regex): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

335 self.try_render( 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

336 "Hey {{foo.bar.baz}} there", 

337 {"foo": None}, 

338 "Hey ??? there", 

339 ) 

340 

341 def test_bad_names(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

342 with self.assertSynErr("Not a valid name: 'var%&!@'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

343 self.try_render("Wat: {{ var%&!@ }}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

344 with self.assertSynErr("Not a valid name: 'filter%&!@'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

345 self.try_render("Wat: {{ foo|filter%&!@ }}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

346 with self.assertSynErr("Not a valid name: '@'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

347 self.try_render("Wat: {% for @ in x %}{% endfor %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

348 

349 def test_bogus_tag_syntax(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

350 with self.assertSynErr("Don't understand tag: 'bogus'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

351 self.try_render("Huh: {% bogus %}!!{% endbogus %}??") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

352 

353 def test_malformed_if(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

354 with self.assertSynErr("Don't understand if: '{% if %}'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

355 self.try_render("Buh? {% if %}hi!{% endif %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

356 with self.assertSynErr("Don't understand if: '{% if this or that %}'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

357 self.try_render("Buh? {% if this or that %}hi!{% endif %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

358 

359 def test_malformed_else(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

360 with self.assertSynErr("Don't understand else: '{% else now %}'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

361 self.try_render("Buh? {% if x %}hi!{% else now %}{% endif %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

362 with self.assertSynErr("Mismatched else: '{% else %}'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

363 self.try_render("Buh? {% else %}hi!{% endif %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

364 with self.assertSynErr("Mismatched else: '{% else %}'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

365 self.try_render("Buh? {% for x in xs %}{% else %}hi!{% endfor %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

366 

367 def test_malformed_for(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

368 with self.assertSynErr("Don't understand for: '{% for %}'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

369 self.try_render("Weird: {% for %}loop{% endfor %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

370 with self.assertSynErr("Don't understand for: '{% for x from y %}'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

371 self.try_render("Weird: {% for x from y %}loop{% endfor %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

372 with self.assertSynErr("Don't understand for: '{% for x, y in z %}'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

373 self.try_render("Weird: {% for x, y in z %}loop{% endfor %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

374 

375 def test_bad_nesting(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

376 with self.assertSynErr("Unmatched action tag: 'if'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

377 self.try_render("{% if x %}X") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

378 with self.assertSynErr("Mismatched end tag: 'for'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

379 self.try_render("{% if x %}X{% endfor %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

380 with self.assertSynErr("Too many ends: '{% endif %}'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

381 self.try_render("{% if x %}{% endif %}{% endif %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

382 

383 def test_malformed_end(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

384 with self.assertSynErr("Don't understand end: '{% end if %}'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

385 self.try_render("{% if x %}X{% end if %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

386 with self.assertSynErr("Don't understand end: '{% endif now %}'"): 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()

387 self.try_render("{% if x %}X{% endif now %}") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'()