| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- # -*- coding: utf-8 -*-
- """
- jinja2.testsuite.api
- ~~~~~~~~~~~~~~~~~~~~
- Tests the public API and related stuff.
- :copyright: (c) 2010 by the Jinja Team.
- :license: BSD, see LICENSE for more details.
- """
- import unittest
- import os
- import tempfile
- import shutil
- from jinja2.testsuite import JinjaTestCase
- from jinja2._compat import next
- from jinja2 import Environment, Undefined, DebugUndefined, \
- StrictUndefined, UndefinedError, meta, \
- is_undefined, Template, DictLoader
- from jinja2.utils import Cycler
- env = Environment()
- class ExtendedAPITestCase(JinjaTestCase):
- def test_item_and_attribute(self):
- from jinja2.sandbox import SandboxedEnvironment
- for env in Environment(), SandboxedEnvironment():
- # the |list is necessary for python3
- tmpl = env.from_string('{{ foo.items()|list }}')
- assert tmpl.render(foo={'items': 42}) == "[('items', 42)]"
- tmpl = env.from_string('{{ foo|attr("items")()|list }}')
- assert tmpl.render(foo={'items': 42}) == "[('items', 42)]"
- tmpl = env.from_string('{{ foo["items"] }}')
- assert tmpl.render(foo={'items': 42}) == '42'
- def test_finalizer(self):
- def finalize_none_empty(value):
- if value is None:
- value = u''
- return value
- env = Environment(finalize=finalize_none_empty)
- tmpl = env.from_string('{% for item in seq %}|{{ item }}{% endfor %}')
- assert tmpl.render(seq=(None, 1, "foo")) == '||1|foo'
- tmpl = env.from_string('<{{ none }}>')
- assert tmpl.render() == '<>'
- def test_cycler(self):
- items = 1, 2, 3
- c = Cycler(*items)
- for item in items + items:
- assert c.current == item
- assert next(c) == item
- next(c)
- assert c.current == 2
- c.reset()
- assert c.current == 1
- def test_expressions(self):
- expr = env.compile_expression("foo")
- assert expr() is None
- assert expr(foo=42) == 42
- expr2 = env.compile_expression("foo", undefined_to_none=False)
- assert is_undefined(expr2())
- expr = env.compile_expression("42 + foo")
- assert expr(foo=42) == 84
- def test_template_passthrough(self):
- t = Template('Content')
- assert env.get_template(t) is t
- assert env.select_template([t]) is t
- assert env.get_or_select_template([t]) is t
- assert env.get_or_select_template(t) is t
- def test_autoescape_autoselect(self):
- def select_autoescape(name):
- if name is None or '.' not in name:
- return False
- return name.endswith('.html')
- env = Environment(autoescape=select_autoescape,
- loader=DictLoader({
- 'test.txt': '{{ foo }}',
- 'test.html': '{{ foo }}'
- }))
- t = env.get_template('test.txt')
- assert t.render(foo='<foo>') == '<foo>'
- t = env.get_template('test.html')
- assert t.render(foo='<foo>') == '<foo>'
- t = env.from_string('{{ foo }}')
- assert t.render(foo='<foo>') == '<foo>'
- class MetaTestCase(JinjaTestCase):
- def test_find_undeclared_variables(self):
- ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')
- x = meta.find_undeclared_variables(ast)
- assert x == set(['bar'])
- ast = env.parse('{% set foo = 42 %}{{ bar + foo }}'
- '{% macro meh(x) %}{{ x }}{% endmacro %}'
- '{% for item in seq %}{{ muh(item) + meh(seq) }}{% endfor %}')
- x = meta.find_undeclared_variables(ast)
- assert x == set(['bar', 'seq', 'muh'])
- def test_find_refererenced_templates(self):
- ast = env.parse('{% extends "layout.html" %}{% include helper %}')
- i = meta.find_referenced_templates(ast)
- assert next(i) == 'layout.html'
- assert next(i) is None
- assert list(i) == []
- ast = env.parse('{% extends "layout.html" %}'
- '{% from "test.html" import a, b as c %}'
- '{% import "meh.html" as meh %}'
- '{% include "muh.html" %}')
- i = meta.find_referenced_templates(ast)
- assert list(i) == ['layout.html', 'test.html', 'meh.html', 'muh.html']
- def test_find_included_templates(self):
- ast = env.parse('{% include ["foo.html", "bar.html"] %}')
- i = meta.find_referenced_templates(ast)
- assert list(i) == ['foo.html', 'bar.html']
- ast = env.parse('{% include ("foo.html", "bar.html") %}')
- i = meta.find_referenced_templates(ast)
- assert list(i) == ['foo.html', 'bar.html']
- ast = env.parse('{% include ["foo.html", "bar.html", foo] %}')
- i = meta.find_referenced_templates(ast)
- assert list(i) == ['foo.html', 'bar.html', None]
- ast = env.parse('{% include ("foo.html", "bar.html", foo) %}')
- i = meta.find_referenced_templates(ast)
- assert list(i) == ['foo.html', 'bar.html', None]
- class StreamingTestCase(JinjaTestCase):
- def test_basic_streaming(self):
- tmpl = env.from_string("<ul>{% for item in seq %}<li>{{ loop.index "
- "}} - {{ item }}</li>{%- endfor %}</ul>")
- stream = tmpl.stream(seq=list(range(4)))
- self.assert_equal(next(stream), '<ul>')
- self.assert_equal(next(stream), '<li>1 - 0</li>')
- self.assert_equal(next(stream), '<li>2 - 1</li>')
- self.assert_equal(next(stream), '<li>3 - 2</li>')
- self.assert_equal(next(stream), '<li>4 - 3</li>')
- self.assert_equal(next(stream), '</ul>')
- def test_buffered_streaming(self):
- tmpl = env.from_string("<ul>{% for item in seq %}<li>{{ loop.index "
- "}} - {{ item }}</li>{%- endfor %}</ul>")
- stream = tmpl.stream(seq=list(range(4)))
- stream.enable_buffering(size=3)
- self.assert_equal(next(stream), u'<ul><li>1 - 0</li><li>2 - 1</li>')
- self.assert_equal(next(stream), u'<li>3 - 2</li><li>4 - 3</li></ul>')
- def test_streaming_behavior(self):
- tmpl = env.from_string("")
- stream = tmpl.stream()
- assert not stream.buffered
- stream.enable_buffering(20)
- assert stream.buffered
- stream.disable_buffering()
- assert not stream.buffered
- def test_dump_stream(self):
- tmp = tempfile.mkdtemp()
- try:
- tmpl = env.from_string(u"\u2713")
- stream = tmpl.stream()
- stream.dump(os.path.join(tmp, 'dump.txt'), 'utf-8')
- with open(os.path.join(tmp, 'dump.txt'), 'rb') as f:
- self.assertEqual(f.read(), b'\xe2\x9c\x93')
- finally:
- shutil.rmtree(tmp)
- class UndefinedTestCase(JinjaTestCase):
- def test_stopiteration_is_undefined(self):
- def test():
- raise StopIteration()
- t = Template('A{{ test() }}B')
- assert t.render(test=test) == 'AB'
- t = Template('A{{ test().missingattribute }}B')
- self.assert_raises(UndefinedError, t.render, test=test)
- def test_undefined_and_special_attributes(self):
- try:
- Undefined('Foo').__dict__
- except AttributeError:
- pass
- else:
- assert False, "Expected actual attribute error"
- def test_default_undefined(self):
- env = Environment(undefined=Undefined)
- self.assert_equal(env.from_string('{{ missing }}').render(), u'')
- self.assert_raises(UndefinedError,
- env.from_string('{{ missing.attribute }}').render)
- self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]')
- self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
- self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42), '')
- self.assert_equal(env.from_string('{{ not missing }}').render(), 'True')
- def test_debug_undefined(self):
- env = Environment(undefined=DebugUndefined)
- self.assert_equal(env.from_string('{{ missing }}').render(), '{{ missing }}')
- self.assert_raises(UndefinedError,
- env.from_string('{{ missing.attribute }}').render)
- self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]')
- self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
- self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42),
- u"{{ no such element: int object['missing'] }}")
- self.assert_equal(env.from_string('{{ not missing }}').render(), 'True')
- def test_strict_undefined(self):
- env = Environment(undefined=StrictUndefined)
- self.assert_raises(UndefinedError, env.from_string('{{ missing }}').render)
- self.assert_raises(UndefinedError, env.from_string('{{ missing.attribute }}').render)
- self.assert_raises(UndefinedError, env.from_string('{{ missing|list }}').render)
- self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
- self.assert_raises(UndefinedError, env.from_string('{{ foo.missing }}').render, foo=42)
- self.assert_raises(UndefinedError, env.from_string('{{ not missing }}').render)
- self.assert_equal(env.from_string('{{ missing|default("default", true) }}').render(), 'default')
- def test_indexing_gives_undefined(self):
- t = Template("{{ var[42].foo }}")
- self.assert_raises(UndefinedError, t.render, var=0)
- def test_none_gives_proper_error(self):
- try:
- Environment().getattr(None, 'split')()
- except UndefinedError as e:
- assert e.message == "'None' has no attribute 'split'"
- else:
- assert False, 'expected exception'
- def test_object_repr(self):
- try:
- Undefined(obj=42, name='upper')()
- except UndefinedError as e:
- assert e.message == "'int object' has no attribute 'upper'"
- else:
- assert False, 'expected exception'
- def suite():
- suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(ExtendedAPITestCase))
- suite.addTest(unittest.makeSuite(MetaTestCase))
- suite.addTest(unittest.makeSuite(StreamingTestCase))
- suite.addTest(unittest.makeSuite(UndefinedTestCase))
- return suite
|