Skip to content

Commit 631ee41

Browse files
author
Abhilash Joseph C
committed
Updated the folder name
1 parent e848ab7 commit 631ee41

File tree

2 files changed

+352
-2
lines changed

2 files changed

+352
-2
lines changed

resttest3/reports/templite.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,8 @@ def __process(self, buffered, code, flush_output, in_joined, ops_stack, squash,
190190
words = token[start:end].strip().split()
191191
if words[0] == 'if':
192192
# An if statement: evaluate the expression to determine if.
193-
# if len(words) != 2:
194-
# self._syntax_error("Don't understand if", token)
193+
if len(words) != 2:
194+
self._syntax_error("Don't understand if", token)
195195
ops_stack.append('if')
196196
code.add_line("if %s:" % self._expr_code(words[1]))
197197
code.indent()

tests/test_templite.py

+350
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
# coding: utf-8
2+
# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
3+
# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
4+
5+
"""Tests for coverage.templite."""
6+
7+
import re
8+
import unittest
9+
10+
from resttest3.reports.templite import Templite, TempliteSyntaxError, TempliteValueError
11+
12+
13+
# pylint: disable=possibly-unused-variable
14+
15+
class AnyOldObject(object):
16+
"""Simple testing object.
17+
18+
Use keyword arguments in the constructor to set attributes on the object.
19+
20+
"""
21+
22+
def __init__(self, **attrs):
23+
for n, v in attrs.items():
24+
setattr(self, n, v)
25+
26+
27+
class TempliteTest(unittest.TestCase):
28+
"""Tests for Templite."""
29+
30+
run_in_temp_dir = False
31+
32+
def try_render(self, text, ctx=None, result=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 {})
40+
# If result is None, then an exception should have prevented us getting
41+
# to here.
42+
assert result is not None
43+
self.assertEqual(actual, result)
44+
45+
def assertSynErr(self, msg):
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) + "$"
52+
return self.assertRaisesRegex(TempliteSyntaxError, pat)
53+
54+
def test_passthrough(self):
55+
# Strings without variables are passed through unchanged.
56+
self.assertEqual(Templite("Hello").render(), "Hello")
57+
self.assertEqual(
58+
Templite("Hello, 20% fun time!").render(),
59+
"Hello, 20% fun time!"
60+
)
61+
62+
def test_variables(self):
63+
# Variables use {{var}} syntax.
64+
self.try_render("Hello, {{name}}!", {'name': 'Ned'}, "Hello, Ned!")
65+
66+
def test_undefined_variables(self):
67+
# Using undefined names is an error.
68+
with self.assertRaisesRegex(Exception, "'name'"):
69+
self.try_render("Hi, {{name}}!")
70+
71+
def test_pipes(self):
72+
# Variables can be filtered with pipes.
73+
data = {
74+
'name': 'Ned',
75+
'upper': lambda x: x.upper(),
76+
'second': lambda x: x[1],
77+
}
78+
self.try_render("Hello, {{name|upper}}!", data, "Hello, NED!")
79+
80+
# Pipes can be concatenated.
81+
self.try_render("Hello, {{name|upper|second}}!", data, "Hello, E!")
82+
83+
def test_reusability(self):
84+
# A single Templite can be used more than once with different data.
85+
globs = {
86+
'upper': lambda x: x.upper(),
87+
'punct': '!',
88+
}
89+
90+
template = Templite("This is {{name|upper}}{{punct}}", globs)
91+
self.assertEqual(template.render({'name': 'Ned'}), "This is NED!")
92+
self.assertEqual(template.render({'name': 'Ben'}), "This is BEN!")
93+
94+
def test_attribute(self):
95+
# Variables' attributes can be accessed with dots.
96+
obj = AnyOldObject(a="Ay")
97+
self.try_render("{{obj.a}}", locals(), "Ay")
98+
99+
obj2 = AnyOldObject(obj=obj, b="Bee")
100+
self.try_render("{{obj2.obj.a}} {{obj2.b}}", locals(), "Ay Bee")
101+
102+
def test_member_function(self):
103+
# Variables' member functions can be used, as long as they are nullary.
104+
class WithMemberFns(AnyOldObject):
105+
"""A class to try out member function access."""
106+
107+
def ditto(self):
108+
"""Return twice the .txt attribute."""
109+
return self.txt + self.txt
110+
111+
obj = WithMemberFns(txt="Once")
112+
self.try_render("{{obj.ditto}}", locals(), "OnceOnce")
113+
114+
def test_item_access(self):
115+
# Variables' items can be used.
116+
d = {'a': 17, 'b': 23}
117+
self.try_render("{{d.a}} < {{d.b}}", locals(), "17 < 23")
118+
119+
def test_loops(self):
120+
# Loops work like in Django.
121+
nums = [1, 2, 3, 4]
122+
self.try_render(
123+
"Look: {% for n in nums %}{{n}}, {% endfor %}done.",
124+
locals(),
125+
"Look: 1, 2, 3, 4, done."
126+
)
127+
128+
# Loop iterables can be filtered.
129+
def rev(l):
130+
"""Return the reverse of `l`."""
131+
l = l[:]
132+
l.reverse()
133+
return l
134+
135+
self.try_render(
136+
"Look: {% for n in nums|rev %}{{n}}, {% endfor %}done.",
137+
locals(),
138+
"Look: 4, 3, 2, 1, done."
139+
)
140+
141+
def test_empty_loops(self):
142+
self.try_render(
143+
"Empty: {% for n in nums %}{{n}}, {% endfor %}done.",
144+
{'nums': []},
145+
"Empty: done."
146+
)
147+
148+
def test_multiline_loops(self):
149+
self.try_render(
150+
"Look: \n{% for n in nums %}\n{{n}}, \n{% endfor %}done.",
151+
{'nums': [1, 2, 3]},
152+
"Look: \n\n1, \n\n2, \n\n3, \ndone."
153+
)
154+
155+
def test_multiple_loops(self):
156+
self.try_render(
157+
"{% for n in nums %}{{n}}{% endfor %} and "
158+
"{% for n in nums %}{{n}}{% endfor %}",
159+
{'nums': [1, 2, 3]},
160+
"123 and 123"
161+
)
162+
163+
def test_comments(self):
164+
# Single-line comments work:
165+
self.try_render(
166+
"Hello, {# Name goes here: #}{{name}}!",
167+
{'name': 'Ned'}, "Hello, Ned!"
168+
)
169+
# and so do multi-line comments:
170+
self.try_render(
171+
"Hello, {# Name\ngoes\nhere: #}{{name}}!",
172+
{'name': 'Ned'}, "Hello, Ned!"
173+
)
174+
175+
def test_if(self):
176+
self.try_render(
177+
"Hi, {% if ned %}NED{% endif %}{% if ben %}BEN{% endif %}!",
178+
{'ned': 1, 'ben': 0},
179+
"Hi, NED!"
180+
)
181+
self.try_render(
182+
"Hi, {% if ned %}NED{% endif %}{% if ben %}BEN{% endif %}!",
183+
{'ned': 0, 'ben': 1},
184+
"Hi, BEN!"
185+
)
186+
self.try_render(
187+
"Hi, {% if ned %}NED{% if ben %}BEN{% endif %}{% endif %}!",
188+
{'ned': 0, 'ben': 0},
189+
"Hi, !"
190+
)
191+
self.try_render(
192+
"Hi, {% if ned %}NED{% if ben %}BEN{% endif %}{% endif %}!",
193+
{'ned': 1, 'ben': 0},
194+
"Hi, NED!"
195+
)
196+
self.try_render(
197+
"Hi, {% if ned %}NED{% if ben %}BEN{% endif %}{% endif %}!",
198+
{'ned': 1, 'ben': 1},
199+
"Hi, NEDBEN!"
200+
)
201+
202+
def test_complex_if(self):
203+
class Complex(AnyOldObject):
204+
"""A class to try out complex data access."""
205+
206+
def getit(self):
207+
"""Return it."""
208+
return self.it
209+
210+
obj = Complex(it={'x': "Hello", 'y': 0})
211+
self.try_render(
212+
"@"
213+
"{% if obj.getit.x %}X{% endif %}"
214+
"{% if obj.getit.y %}Y{% endif %}"
215+
"{% if obj.getit.y|str %}S{% endif %}"
216+
"!",
217+
{'obj': obj, 'str': str},
218+
"@XS!"
219+
)
220+
221+
def test_loop_if(self):
222+
self.try_render(
223+
"@{% for n in nums %}{% if n %}Z{% endif %}{{n}}{% endfor %}!",
224+
{'nums': [0, 1, 2]},
225+
"@0Z1Z2!"
226+
)
227+
self.try_render(
228+
"X{%if nums%}@{% for n in nums %}{{n}}{% endfor %}{%endif%}!",
229+
{'nums': [0, 1, 2]},
230+
"X@012!"
231+
)
232+
self.try_render(
233+
"X{%if nums%}@{% for n in nums %}{{n}}{% endfor %}{%endif%}!",
234+
{'nums': []},
235+
"X!"
236+
)
237+
238+
def test_nested_loops(self):
239+
self.try_render(
240+
"@"
241+
"{% for n in nums %}"
242+
"{% for a in abc %}{{a}}{{n}}{% endfor %}"
243+
"{% endfor %}"
244+
"!",
245+
{'nums': [0, 1, 2], 'abc': ['a', 'b', 'c']},
246+
"@a0b0c0a1b1c1a2b2c2!"
247+
)
248+
249+
def test_whitespace_handling(self):
250+
self.try_render(
251+
"@{% for n in nums %}\n"
252+
" {% for a in abc %}{{a}}{{n}}{% endfor %}\n"
253+
"{% endfor %}!\n",
254+
{'nums': [0, 1, 2], 'abc': ['a', 'b', 'c']},
255+
"@\n a0b0c0\n\n a1b1c1\n\n a2b2c2\n!\n"
256+
)
257+
self.try_render(
258+
"@{% for n in nums -%}\n"
259+
" {% for a in abc -%}\n"
260+
" {# this disappears completely -#}\n"
261+
" {{a-}}\n"
262+
" {{n -}}\n"
263+
" {{n -}}\n"
264+
" {% endfor %}\n"
265+
"{% endfor %}!\n",
266+
{'nums': [0, 1, 2], 'abc': ['a', 'b', 'c']},
267+
"@a00b00c00\na11b11c11\na22b22c22\n!\n"
268+
)
269+
self.try_render(
270+
"@{% for n in nums -%}\n"
271+
" {{n -}}\n"
272+
" x\n"
273+
"{% endfor %}!\n",
274+
{'nums': [0, 1, 2]},
275+
"@0x\n1x\n2x\n!\n"
276+
)
277+
self.try_render(" hello ", {}, " hello ")
278+
279+
def test_eat_whitespace(self):
280+
self.try_render(
281+
"Hey!\n"
282+
"{% joined %}\n"
283+
"@{% for n in nums %}\n"
284+
" {% for a in abc %}\n"
285+
" {# this disappears completely #}\n"
286+
" X\n"
287+
" Y\n"
288+
" {{a}}\n"
289+
" {{n }}\n"
290+
" {% endfor %}\n"
291+
"{% endfor %}!\n"
292+
"{% endjoined %}\n",
293+
{'nums': [0, 1, 2], 'abc': ['a', 'b', 'c']},
294+
"Hey!\n@XYa0XYb0XYc0XYa1XYb1XYc1XYa2XYb2XYc2!\n"
295+
)
296+
297+
def test_non_ascii(self):
298+
self.try_render(
299+
u"{{where}} ollǝɥ",
300+
{'where': u'ǝɹǝɥʇ'},
301+
u"ǝɹǝɥʇ ollǝɥ"
302+
)
303+
304+
def test_exception_during_evaluation(self):
305+
# TypeError: Couldn't evaluate {{ foo.bar.baz }}:
306+
regex = "^Couldn't evaluate None.bar$"
307+
with self.assertRaisesRegex(TempliteValueError, regex):
308+
self.try_render(
309+
"Hey {{foo.bar.baz}} there", {'foo': None}, "Hey ??? there"
310+
)
311+
312+
def test_bad_names(self):
313+
with self.assertSynErr("Not a valid name: 'var%&!@'"):
314+
self.try_render("Wat: {{ var%&!@ }}")
315+
with self.assertSynErr("Not a valid name: 'filter%&!@'"):
316+
self.try_render("Wat: {{ foo|filter%&!@ }}")
317+
with self.assertSynErr("Not a valid name: '@'"):
318+
self.try_render("Wat: {% for @ in x %}{% endfor %}")
319+
320+
def test_bogus_tag_syntax(self):
321+
with self.assertSynErr("Don't understand tag: 'bogus'"):
322+
self.try_render("Huh: {% bogus %}!!{% endbogus %}??")
323+
324+
def test_malformed_if(self):
325+
with self.assertSynErr("Don't understand if: '{% if %}'"):
326+
self.try_render("Buh? {% if %}hi!{% endif %}")
327+
with self.assertSynErr("Don't understand if: '{% if this or that %}'"):
328+
self.try_render("Buh? {% if this or that %}hi!{% endif %}")
329+
330+
def test_malformed_for(self):
331+
with self.assertSynErr("Don't understand for: '{% for %}'"):
332+
self.try_render("Weird: {% for %}loop{% endfor %}")
333+
with self.assertSynErr("Don't understand for: '{% for x from y %}'"):
334+
self.try_render("Weird: {% for x from y %}loop{% endfor %}")
335+
with self.assertSynErr("Don't understand for: '{% for x, y in z %}'"):
336+
self.try_render("Weird: {% for x, y in z %}loop{% endfor %}")
337+
338+
def test_bad_nesting(self):
339+
with self.assertSynErr("Unmatched action tag: 'if'"):
340+
self.try_render("{% if x %}X")
341+
with self.assertSynErr("Mismatched end tag: 'for'"):
342+
self.try_render("{% if x %}X{% endfor %}")
343+
with self.assertSynErr("Too many ends: '{% endif %}'"):
344+
self.try_render("{% if x %}{% endif %}{% endif %}")
345+
346+
def test_malformed_end(self):
347+
with self.assertSynErr("Don't understand end: '{% end if %}'"):
348+
self.try_render("{% if x %}X{% end if %}")
349+
with self.assertSynErr("Don't understand end: '{% endif now %}'"):
350+
self.try_render("{% if x %}X{% endif now %}")

0 commit comments

Comments
 (0)