diff options
Diffstat (limited to 'pystache/tests/test_renderengine.py')
-rw-r--r-- | pystache/tests/test_renderengine.py | 165 |
1 files changed, 131 insertions, 34 deletions
diff --git a/pystache/tests/test_renderengine.py b/pystache/tests/test_renderengine.py index b13e246..db916f7 100644 --- a/pystache/tests/test_renderengine.py +++ b/pystache/tests/test_renderengine.py @@ -5,13 +5,23 @@ Unit tests of renderengine.py. """ +import sys import unittest -from pystache.context import ContextStack +from pystache.context import ContextStack, KeyNotFoundError from pystache import defaults from pystache.parser import ParsingError -from pystache.renderengine import RenderEngine -from pystache.tests.common import AssertStringMixin, Attachable +from pystache.renderer import Renderer +from pystache.renderengine import context_get, RenderEngine +from pystache.tests.common import AssertStringMixin, AssertExceptionMixin, Attachable + + +def _get_unicode_char(): + if sys.version_info < (3, ): + return 'u' + return '' + +_UNICODE_CHAR = _get_unicode_char() def mock_literal(s): @@ -45,14 +55,16 @@ class RenderEngineTestCase(unittest.TestCase): """ # In real-life, these arguments would be functions - engine = RenderEngine(load_partial="foo", literal="literal", escape="escape") + engine = RenderEngine(resolve_partial="foo", literal="literal", + escape="escape", to_str="str") self.assertEqual(engine.escape, "escape") self.assertEqual(engine.literal, "literal") - self.assertEqual(engine.load_partial, "foo") + self.assertEqual(engine.resolve_partial, "foo") + self.assertEqual(engine.to_str, "str") -class RenderTests(unittest.TestCase, AssertStringMixin): +class RenderTests(unittest.TestCase, AssertStringMixin, AssertExceptionMixin): """ Tests RenderEngine.render(). @@ -68,8 +80,9 @@ class RenderTests(unittest.TestCase, AssertStringMixin): Create and return a default RenderEngine for testing. """ - escape = defaults.TAG_ESCAPE - engine = RenderEngine(literal=unicode, escape=escape, load_partial=None) + renderer = Renderer(string_encoding='utf-8', missing_tags='strict') + engine = renderer._make_render_engine() + return engine def _assert_render(self, expected, template, *context, **kwargs): @@ -81,25 +94,26 @@ class RenderTests(unittest.TestCase, AssertStringMixin): engine = kwargs.get('engine', self._engine()) if partials is not None: - engine.load_partial = lambda key: unicode(partials[key]) + engine.resolve_partial = lambda key: unicode(partials[key]) context = ContextStack(*context) - actual = engine.render(template, context) + # RenderEngine.render() only accepts unicode template strings. + actual = engine.render(unicode(template), context) self.assertString(actual=actual, expected=expected) def test_render(self): self._assert_render(u'Hi Mom', 'Hi {{person}}', {'person': 'Mom'}) - def test__load_partial(self): + def test__resolve_partial(self): """ Test that render() uses the load_template attribute. """ engine = self._engine() partials = {'partial': u"{{person}}"} - engine.load_partial = lambda key: partials[key] + engine.resolve_partial = lambda key: partials[key] self._assert_render(u'Hi Mom', 'Hi {{>partial}}', {'person': 'Mom'}, engine=engine) @@ -170,6 +184,47 @@ class RenderTests(unittest.TestCase, AssertStringMixin): self._assert_render(u'**bar bar**', template, context, engine=engine) + # Custom to_str for testing purposes. + def _to_str(self, val): + if not val: + return '' + else: + return str(val) + + def test_to_str(self): + """Test the to_str attribute.""" + engine = self._engine() + template = '{{value}}' + context = {'value': None} + + self._assert_render(u'None', template, context, engine=engine) + engine.to_str = self._to_str + self._assert_render(u'', template, context, engine=engine) + + def test_to_str__lambda(self): + """Test the to_str attribute for a lambda.""" + engine = self._engine() + template = '{{value}}' + context = {'value': lambda: None} + + self._assert_render(u'None', template, context, engine=engine) + engine.to_str = self._to_str + self._assert_render(u'', template, context, engine=engine) + + def test_to_str__section_list(self): + """Test the to_str attribute for a section list.""" + engine = self._engine() + template = '{{#list}}{{.}}{{/list}}' + context = {'list': [None, None]} + + self._assert_render(u'NoneNone', template, context, engine=engine) + engine.to_str = self._to_str + self._assert_render(u'', template, context, engine=engine) + + def test_to_str__section_lambda(self): + # TODO: add a test for a "method with an arity of 1". + pass + def test__non_basestring__literal_and_escaped(self): """ Test a context value that is not a basestring instance. @@ -285,6 +340,16 @@ class RenderTests(unittest.TestCase, AssertStringMixin): context = {'section': item, attr_name: 7} self._assert_render(u'7', template, context) + # This test is also important for testing 2to3. + def test_interpolation__nonascii_nonunicode(self): + """ + Test a tag whose value is a non-ascii, non-unicode string. + + """ + template = '{{nonascii}}' + context = {'nonascii': u'abcdé'.encode('utf-8')} + self._assert_render(u'abcdé', template, context) + def test_implicit_iterator__literal(self): """ Test an implicit iterator in a literal tag. @@ -343,6 +408,28 @@ class RenderTests(unittest.TestCase, AssertStringMixin): self._assert_render(u'unescaped: < escaped: <', template, context, engine=engine, partials=partials) + ## Test cases related specifically to lambdas. + + # This test is also important for testing 2to3. + def test_section__nonascii_nonunicode(self): + """ + Test a section whose value is a non-ascii, non-unicode string. + + """ + template = '{{#nonascii}}{{.}}{{/nonascii}}' + context = {'nonascii': u'abcdé'.encode('utf-8')} + self._assert_render(u'abcdé', template, context) + + # This test is also important for testing 2to3. + def test_lambda__returning_nonascii_nonunicode(self): + """ + Test a lambda tag value returning a non-ascii, non-unicode string. + + """ + template = '{{lambda}}' + context = {'lambda': lambda: u'abcdé'.encode('utf-8')} + self._assert_render(u'abcdé', template, context) + ## Test cases related specifically to sections. def test_section__end_tag_with_no_start_tag(self): @@ -461,6 +548,25 @@ class RenderTests(unittest.TestCase, AssertStringMixin): context = {'test': (lambda text: 'Hi %s' % text)} self._assert_render(u'Hi Mom', template, context) + # This test is also important for testing 2to3. + def test_section__lambda__returning_nonascii_nonunicode(self): + """ + Test a lambda section value returning a non-ascii, non-unicode string. + + """ + template = '{{#lambda}}{{/lambda}}' + context = {'lambda': lambda text: u'abcdé'.encode('utf-8')} + self._assert_render(u'abcdé', template, context) + + def test_section__lambda__returning_nonstring(self): + """ + Test a lambda section value returning a non-string. + + """ + template = '{{#lambda}}foo{{/lambda}}' + context = {'lambda': lambda text: len(text)} + self._assert_render(u'3', template, context) + def test_section__iterable(self): """ Check that objects supporting iteration (aside from dicts) behave like lists. @@ -609,33 +715,15 @@ class RenderTests(unittest.TestCase, AssertStringMixin): context = {'person': person} self._assert_render(u'Hello, Biggles. I see you are 42.', template, context) - def test_dot_notation__missing_attributes_or_keys(self): - """ - Test dot notation with missing keys or attributes. - - Check that if a key or attribute in a dotted name does not exist, then - the tag renders as the empty string. - - """ - template = """I cannot see {{person.name}}'s age: {{person.age}}. - Nor {{other_person.name}}'s: .""" - expected = u"""I cannot see Biggles's age: . - Nor Mr. Bradshaw's: .""" - context = {'person': {'name': 'Biggles'}, - 'other_person': Attachable(name='Mr. Bradshaw')} - self._assert_render(expected, template, context) - def test_dot_notation__multiple_levels(self): """ Test dot notation with multiple levels. """ template = """Hello, Mr. {{person.name.lastname}}. - I see you're back from {{person.travels.last.country.city}}. - I'm missing some of your details: {{person.details.private.editor}}.""" + I see you're back from {{person.travels.last.country.city}}.""" expected = u"""Hello, Mr. Pither. - I see you're back from Cornwall. - I'm missing some of your details: .""" + I see you're back from Cornwall.""" context = {'person': {'name': {'firstname': 'unknown', 'lastname': 'Pither'}, 'travels': {'last': {'country': {'city': 'Cornwall'}}}, 'details': {'public': 'likes cycling'}}} @@ -667,6 +755,15 @@ class RenderTests(unittest.TestCase, AssertStringMixin): https://github.com/mustache/spec/pull/48 """ - template = '{{a.b}} :: ({{#c}}{{a}} :: {{a.b}}{{/c}})' context = {'a': {'b': 'A.B'}, 'c': {'a': 'A'} } - self._assert_render(u'A.B :: (A :: )', template, context) + + template = '{{a.b}}' + self._assert_render(u'A.B', template, context) + + template = '{{#c}}{{a}}{{/c}}' + self._assert_render(u'A', template, context) + + template = '{{#c}}{{a.b}}{{/c}}' + self.assertException(KeyNotFoundError, "Key %(unicode)s'a.b' not found: missing %(unicode)s'b'" % + {'unicode': _UNICODE_CHAR}, + self._assert_render, 'A.B :: (A :: )', template, context) |