summaryrefslogtreecommitdiff
path: root/tests/test_renderer.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_renderer.py')
-rw-r--r--tests/test_renderer.py556
1 files changed, 556 insertions, 0 deletions
diff --git a/tests/test_renderer.py b/tests/test_renderer.py
new file mode 100644
index 0000000..a69d11a
--- /dev/null
+++ b/tests/test_renderer.py
@@ -0,0 +1,556 @@
+# coding: utf-8
+
+"""
+Unit tests of template.py.
+
+"""
+
+import codecs
+import os
+import sys
+import unittest
+
+from examples.simple import Simple
+from pystache import Renderer
+from pystache import TemplateSpec
+from pystache.loader import Loader
+
+from tests.common import get_data_path
+from tests.common import AssertStringMixin
+from tests.data.views import SayHello
+
+
+class RendererInitTestCase(unittest.TestCase):
+
+ """
+ Tests the Renderer.__init__() method.
+
+ """
+
+ def test_partials__default(self):
+ """
+ Test the default value.
+
+ """
+ renderer = Renderer()
+ self.assertTrue(renderer.partials is None)
+
+ def test_partials(self):
+ """
+ Test that the attribute is set correctly.
+
+ """
+ renderer = Renderer(partials={'foo': 'bar'})
+ self.assertEquals(renderer.partials, {'foo': 'bar'})
+
+ def test_escape__default(self):
+ escape = Renderer().escape
+
+ self.assertEquals(escape(">"), ">")
+ self.assertEquals(escape('"'), """)
+ # Single quotes are not escaped.
+ self.assertEquals(escape("'"), "'")
+
+ def test_escape(self):
+ escape = lambda s: "**" + s
+ renderer = Renderer(escape=escape)
+ self.assertEquals(renderer.escape("bar"), "**bar")
+
+ def test_decode_errors__default(self):
+ """
+ Check the default value.
+
+ """
+ renderer = Renderer()
+ self.assertEquals(renderer.decode_errors, 'strict')
+
+ def test_decode_errors(self):
+ """
+ Check that the constructor sets the attribute correctly.
+
+ """
+ renderer = Renderer(decode_errors="foo")
+ self.assertEquals(renderer.decode_errors, "foo")
+
+ def test_file_encoding__default(self):
+ """
+ Check the file_encoding default.
+
+ """
+ renderer = Renderer()
+ self.assertEquals(renderer.file_encoding, renderer.string_encoding)
+
+ def test_file_encoding(self):
+ """
+ Check that the file_encoding attribute is set correctly.
+
+ """
+ renderer = Renderer(file_encoding='foo')
+ self.assertEquals(renderer.file_encoding, 'foo')
+
+ def test_file_extension__default(self):
+ """
+ Check the file_extension default.
+
+ """
+ renderer = Renderer()
+ self.assertEquals(renderer.file_extension, 'mustache')
+
+ def test_file_extension(self):
+ """
+ Check that the file_encoding attribute is set correctly.
+
+ """
+ renderer = Renderer(file_extension='foo')
+ self.assertEquals(renderer.file_extension, 'foo')
+
+ def test_search_dirs__default(self):
+ """
+ Check the search_dirs default.
+
+ """
+ renderer = Renderer()
+ self.assertEquals(renderer.search_dirs, [os.curdir])
+
+ def test_search_dirs__string(self):
+ """
+ Check that the search_dirs attribute is set correctly when a string.
+
+ """
+ renderer = Renderer(search_dirs='foo')
+ self.assertEquals(renderer.search_dirs, ['foo'])
+
+ def test_search_dirs__list(self):
+ """
+ Check that the search_dirs attribute is set correctly when a list.
+
+ """
+ renderer = Renderer(search_dirs=['foo'])
+ self.assertEquals(renderer.search_dirs, ['foo'])
+
+ def test_string_encoding__default(self):
+ """
+ Check the default value.
+
+ """
+ renderer = Renderer()
+ self.assertEquals(renderer.string_encoding, sys.getdefaultencoding())
+
+ def test_string_encoding(self):
+ """
+ Check that the constructor sets the attribute correctly.
+
+ """
+ renderer = Renderer(string_encoding="foo")
+ self.assertEquals(renderer.string_encoding, "foo")
+
+
+class RendererTests(unittest.TestCase, AssertStringMixin):
+
+ """Test the Renderer class."""
+
+ def _renderer(self):
+ return Renderer()
+
+ ## Test Renderer.unicode().
+
+ def test_unicode__string_encoding(self):
+ """
+ Test that the string_encoding attribute is respected.
+
+ """
+ renderer = Renderer()
+ s = "é"
+
+ renderer.string_encoding = "ascii"
+ self.assertRaises(UnicodeDecodeError, renderer.unicode, s)
+
+ renderer.string_encoding = "utf-8"
+ self.assertEquals(renderer.unicode(s), u"é")
+
+ def test_unicode__decode_errors(self):
+ """
+ Test that the decode_errors attribute is respected.
+
+ """
+ renderer = Renderer()
+ renderer.string_encoding = "ascii"
+ s = "déf"
+
+ renderer.decode_errors = "ignore"
+ self.assertEquals(renderer.unicode(s), "df")
+
+ renderer.decode_errors = "replace"
+ # U+FFFD is the official Unicode replacement character.
+ self.assertEquals(renderer.unicode(s), u'd\ufffd\ufffdf')
+
+ ## Test the _make_loader() method.
+
+ def test__make_loader__return_type(self):
+ """
+ Test that _make_loader() returns a Loader.
+
+ """
+ renderer = Renderer()
+ loader = renderer._make_loader()
+
+ self.assertEquals(type(loader), Loader)
+
+ def test__make_loader__attributes(self):
+ """
+ Test that _make_loader() sets all attributes correctly..
+
+ """
+ unicode_ = lambda x: x
+
+ renderer = Renderer()
+ renderer.file_encoding = 'enc'
+ renderer.file_extension = 'ext'
+ renderer.unicode = unicode_
+
+ loader = renderer._make_loader()
+
+ self.assertEquals(loader.extension, 'ext')
+ self.assertEquals(loader.file_encoding, 'enc')
+ self.assertEquals(loader.to_unicode, unicode_)
+
+ ## Test the render() method.
+
+ def test_render__return_type(self):
+ """
+ Check that render() returns a string of type unicode.
+
+ """
+ renderer = Renderer()
+ rendered = renderer.render('foo')
+ self.assertEquals(type(rendered), unicode)
+
+ def test_render__unicode(self):
+ renderer = Renderer()
+ actual = renderer.render(u'foo')
+ self.assertEquals(actual, u'foo')
+
+ def test_render__str(self):
+ renderer = Renderer()
+ actual = renderer.render('foo')
+ self.assertEquals(actual, 'foo')
+
+ def test_render__non_ascii_character(self):
+ renderer = Renderer()
+ actual = renderer.render(u'Poincaré')
+ self.assertEquals(actual, u'Poincaré')
+
+ def test_render__context(self):
+ """
+ Test render(): passing a context.
+
+ """
+ renderer = Renderer()
+ self.assertEquals(renderer.render('Hi {{person}}', {'person': 'Mom'}), 'Hi Mom')
+
+ def test_render__context_and_kwargs(self):
+ """
+ Test render(): passing a context and **kwargs.
+
+ """
+ renderer = Renderer()
+ template = 'Hi {{person1}} and {{person2}}'
+ self.assertEquals(renderer.render(template, {'person1': 'Mom'}, person2='Dad'), 'Hi Mom and Dad')
+
+ def test_render__kwargs_and_no_context(self):
+ """
+ Test render(): passing **kwargs and no context.
+
+ """
+ renderer = Renderer()
+ self.assertEquals(renderer.render('Hi {{person}}', person='Mom'), 'Hi Mom')
+
+ def test_render__context_and_kwargs__precedence(self):
+ """
+ Test render(): **kwargs takes precedence over context.
+
+ """
+ renderer = Renderer()
+ self.assertEquals(renderer.render('Hi {{person}}', {'person': 'Mom'}, person='Dad'), 'Hi Dad')
+
+ def test_render__kwargs_does_not_modify_context(self):
+ """
+ Test render(): passing **kwargs does not modify the passed context.
+
+ """
+ context = {}
+ renderer = Renderer()
+ renderer.render('Hi {{person}}', context=context, foo="bar")
+ self.assertEquals(context, {})
+
+ def test_render__nonascii_template(self):
+ """
+ Test passing a non-unicode template with non-ascii characters.
+
+ """
+ renderer = Renderer()
+ template = "déf"
+
+ # Check that decode_errors and string_encoding are both respected.
+ renderer.decode_errors = 'ignore'
+ renderer.string_encoding = 'ascii'
+ self.assertEquals(renderer.render(template), "df")
+
+ renderer.string_encoding = 'utf_8'
+ self.assertEquals(renderer.render(template), u"déf")
+
+ def test_make_load_partial(self):
+ """
+ Test the _make_load_partial() method.
+
+ """
+ renderer = Renderer()
+ renderer.partials = {'foo': 'bar'}
+ load_partial = renderer._make_load_partial()
+
+ actual = load_partial('foo')
+ self.assertEquals(actual, 'bar')
+ self.assertEquals(type(actual), unicode, "RenderEngine requires that "
+ "load_partial return unicode strings.")
+
+ def test_make_load_partial__unicode(self):
+ """
+ Test _make_load_partial(): that load_partial doesn't "double-decode" Unicode.
+
+ """
+ renderer = Renderer()
+
+ renderer.partials = {'partial': 'foo'}
+ load_partial = renderer._make_load_partial()
+ self.assertEquals(load_partial("partial"), "foo")
+
+ # Now with a value that is already unicode.
+ renderer.partials = {'partial': u'foo'}
+ load_partial = renderer._make_load_partial()
+ # If the next line failed, we would get the following error:
+ # TypeError: decoding Unicode is not supported
+ self.assertEquals(load_partial("partial"), "foo")
+
+ def test_render_path(self):
+ """
+ Test the render_path() method.
+
+ """
+ renderer = Renderer()
+ path = get_data_path('say_hello.mustache')
+ actual = renderer.render_path(path, to='foo')
+ self.assertEquals(actual, "Hello, foo")
+
+ def test_render__object(self):
+ """
+ Test rendering an object instance.
+
+ """
+ renderer = Renderer()
+
+ say_hello = SayHello()
+ actual = renderer.render(say_hello)
+ self.assertEquals('Hello, World', actual)
+
+ actual = renderer.render(say_hello, to='Mars')
+ self.assertEquals('Hello, Mars', actual)
+
+ def test_render__template_spec(self):
+ """
+ Test rendering a TemplateSpec instance.
+
+ """
+ renderer = Renderer()
+
+ class Spec(TemplateSpec):
+ template = "hello, {{to}}"
+ to = 'world'
+
+ spec = Spec()
+ actual = renderer.render(spec)
+ self.assertString(actual, u'hello, world')
+
+ def test_render__view(self):
+ """
+ Test rendering a View instance.
+
+ """
+ renderer = Renderer()
+
+ view = Simple()
+ actual = renderer.render(view)
+ self.assertEquals('Hi pizza!', actual)
+
+
+# By testing that Renderer.render() constructs the right RenderEngine,
+# we no longer need to exercise all rendering code paths through
+# the Renderer. It suffices to test rendering paths through the
+# RenderEngine for the same amount of code coverage.
+class Renderer_MakeRenderEngineTests(unittest.TestCase):
+
+ """
+ Check the RenderEngine returned by Renderer._make_render_engine().
+
+ """
+
+ ## Test the engine's load_partial attribute.
+
+ def test__load_partial__returns_unicode(self):
+ """
+ Check that load_partial returns unicode (and not a subclass).
+
+ """
+ class MyUnicode(unicode):
+ pass
+
+ renderer = Renderer()
+ renderer.string_encoding = 'ascii'
+ renderer.partials = {'str': 'foo', 'subclass': MyUnicode('abc')}
+
+ engine = renderer._make_render_engine()
+
+ actual = engine.load_partial('str')
+ self.assertEquals(actual, "foo")
+ self.assertEquals(type(actual), unicode)
+
+ # Check that unicode subclasses are not preserved.
+ actual = engine.load_partial('subclass')
+ self.assertEquals(actual, "abc")
+ self.assertEquals(type(actual), unicode)
+
+ def test__load_partial__not_found(self):
+ """
+ Check that load_partial provides a nice message when a template is not found.
+
+ """
+ renderer = Renderer()
+ renderer.partials = {}
+
+ engine = renderer._make_render_engine()
+ load_partial = engine.load_partial
+
+ try:
+ load_partial("foo")
+ raise Exception("Shouldn't get here")
+ except Exception, err:
+ self.assertEquals(str(err), "Partial not found with name: 'foo'")
+
+ ## Test the engine's literal attribute.
+
+ def test__literal__uses_renderer_unicode(self):
+ """
+ Test that literal uses the renderer's unicode function.
+
+ """
+ renderer = Renderer()
+ renderer.unicode = lambda s: s.upper()
+
+ engine = renderer._make_render_engine()
+ literal = engine.literal
+
+ self.assertEquals(literal("foo"), "FOO")
+
+ def test__literal__handles_unicode(self):
+ """
+ Test that literal doesn't try to "double decode" unicode.
+
+ """
+ renderer = Renderer()
+ renderer.string_encoding = 'ascii'
+
+ engine = renderer._make_render_engine()
+ literal = engine.literal
+
+ self.assertEquals(literal(u"foo"), "foo")
+
+ def test__literal__returns_unicode(self):
+ """
+ Test that literal returns unicode (and not a subclass).
+
+ """
+ renderer = Renderer()
+ renderer.string_encoding = 'ascii'
+
+ engine = renderer._make_render_engine()
+ literal = engine.literal
+
+ self.assertEquals(type(literal("foo")), unicode)
+
+ class MyUnicode(unicode):
+ pass
+
+ s = MyUnicode("abc")
+
+ self.assertEquals(type(s), MyUnicode)
+ self.assertTrue(isinstance(s, unicode))
+ self.assertEquals(type(literal(s)), unicode)
+
+ ## Test the engine's escape attribute.
+
+ def test__escape__uses_renderer_escape(self):
+ """
+ Test that escape uses the renderer's escape function.
+
+ """
+ renderer = Renderer()
+ renderer.escape = lambda s: "**" + s
+
+ engine = renderer._make_render_engine()
+ escape = engine.escape
+
+ self.assertEquals(escape("foo"), "**foo")
+
+ def test__escape__uses_renderer_unicode(self):
+ """
+ Test that escape uses the renderer's unicode function.
+
+ """
+ renderer = Renderer()
+ renderer.unicode = lambda s: s.upper()
+
+ engine = renderer._make_render_engine()
+ escape = engine.escape
+
+ self.assertEquals(escape("foo"), "FOO")
+
+ def test__escape__has_access_to_original_unicode_subclass(self):
+ """
+ Test that escape receives strings with the unicode subclass intact.
+
+ """
+ renderer = Renderer()
+ renderer.escape = lambda s: type(s).__name__
+
+ engine = renderer._make_render_engine()
+ escape = engine.escape
+
+ class MyUnicode(unicode):
+ pass
+
+ self.assertEquals(escape("foo"), "unicode")
+ self.assertEquals(escape(u"foo"), "unicode")
+ self.assertEquals(escape(MyUnicode("foo")), "MyUnicode")
+
+ def test__escape__returns_unicode(self):
+ """
+ Test that literal returns unicode (and not a subclass).
+
+ """
+ renderer = Renderer()
+ renderer.string_encoding = 'ascii'
+
+ engine = renderer._make_render_engine()
+ escape = engine.escape
+
+ self.assertEquals(type(escape("foo")), unicode)
+
+ # Check that literal doesn't preserve unicode subclasses.
+ class MyUnicode(unicode):
+ pass
+
+ s = MyUnicode("abc")
+
+ self.assertEquals(type(s), MyUnicode)
+ self.assertTrue(isinstance(s, unicode))
+ self.assertEquals(type(escape(s)), unicode)
+