summaryrefslogtreecommitdiff
path: root/pystache/tests/test_renderengine.py
diff options
context:
space:
mode:
Diffstat (limited to 'pystache/tests/test_renderengine.py')
-rw-r--r--pystache/tests/test_renderengine.py165
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: &lt;', 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)