1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
"""Test the various features of our custom library object.
"""
from nose.tools import assert_raises
from jinja2 import TemplateAssertionError as Jinja2TemplateAssertionError
from django.template import Template, Context, \
TemplateSyntaxError as DjangoTemplateSyntaxError
# TODO: It would be preferrable to split these tests into those checks
# which actually test the Library object, and those which test the assembly
# of the Environment instance. Testcode for the former could be written more
# cleanly by creating the library instances within the test code and
# registering them manually with the environment, rather than having to
# place them in fake Django apps in completely different files to have
# them loaded.
# The tests for the compatibility layer could also be factored out.
def test_nodes_and_extensions():
"""Test availability of registered nodes/extensions.
"""
from coffin.common import env
# Jinja2 extensions, loaded from a Coffin library
assert env.from_string('a{% foo %}b').render() == 'a{foo}b'
assert env.from_string('a{% foo_ex %}b').render() == 'a{my_foo}b'
# Django tags, loaded from a Coffin library
assert Template('{% load django_tags %}a{% foo_coffin %}b').render(Context()) == 'a{foo}b'
def test_objects():
"""For coffin, global objects can be registered.
"""
from coffin.common import env
# Jinja2 global objects, loaded from a Coffin library
assert env.from_string('{{ hello("John") }}').render() == 'Hello John'
def test_filters():
"""Test availability of registered filters.
"""
from coffin.common import env
# Filter registered with a Coffin library is available in Django and Jinja2
assert env.from_string('a{{ "b"|foo }}c').render() == 'a{foo}c'
assert Template('{% load portable_filters %}a{{ "b"|foo }}c').render(Context()) == 'a{foo}c'
# Filter registered with a Django library is also available in Jinja2
Template('{% load django_library %}{{ "b"|foo_django }}').render(Context())
assert env.from_string('a{{ "b"|foo }}c').render() == 'a{foo}c'
# Some filters, while registered with a Coffin library, are only
# available in Jinja2:
# - when using @environmentfilter
env.from_string('{{ "b"|environment }}')
assert_raises(Exception, Template, '{% load jinja2_filters %}{{ "b"|environment }}')
# - when using @contextfilter
env.from_string('{{ "b"|context }}')
assert_raises(Exception, Template, '{% load jinja2_filters %}{{ "b"|context }}')
# - when requiring more than one argument
env.from_string('{{ "b"|multiarg(1,2) }}')
assert_raises(Exception, Template, '{% load jinja2_filters %}{{ "b"|multiarg }}')
# - when Jinja2-exclusivity is explicitly requested
env.from_string('{{ "b"|jinja_forced }}')
assert_raises(Exception, Template, '{% load jinja2_filters %}{{ "b"|jinja_forced }}')
# [bug] Jinja2-exclusivity caused the compatibility layer to be not
# applied, causing for example safe strings to be escaped.
assert env.from_string('{{ "><"|django_jinja_forced }}').render() == '><'
def test_env_builtins_django():
"""Test that when the environment is assembled, Django libraries which
are included in the list of builtins are properly supported.
"""
from coffin.common import get_env
from coffin.template import add_to_builtins
add_to_builtins('apps.django_lib')
assert get_env().from_string('a{{ "b"|foo_django_builtin }}c').render() == 'a{foo}c'
def test_filter_compat_safestrings():
"""Test filter compatibility layer with respect to safe strings.
"""
from coffin.common import env
env.autoescape = True
# Jinja-style safe output strings are considered "safe" by both engines
assert env.from_string('{{ "<b>"|jinja_safe_output }}').render() == '<b>'
# TODO: The below actually works regardless of our converting between
# the same string types: Jinja's Markup() strings are actually immune
# to Django's escape() attempt, since they have a custom version of
# replace() that operates on an already escaped version.
assert Template('{% load compat_filters %}{{ "<b>"|jinja_safe_output }}').render(Context()) == '<b>'
# Unsafe, unmarked output strings are considered "unsafe" by both engines
assert env.from_string('{{ "<b>"|unsafe_output }}').render() == '<b>'
assert Template('{% load compat_filters %}{{ "<b>"|unsafe_output }}').render(Context()) == '<b>'
# Django-style safe output strings are considered "safe" by both engines
assert env.from_string('{{ "<b>"|django_safe_output }}').render() == '<b>'
assert Template('{% load compat_filters %}{{ "<b>"|django_safe_output }}').render(Context()) == '<b>'
def test_filter_compat_escapetrings():
"""Test filter compatibility layer with respect to strings flagged as
"wanted for escaping".
"""
from coffin.common import env
env.autoescape = False
# Django-style "force escaping" works in both engines
assert env.from_string('{{ "<b>"|django_escape_output }}').render() == '<b>'
assert Template('{% load compat_filters %}{{ "<b>"|django_escape_output }}').render(Context()) == '<b>'
def test_filter_compat_other():
"""Test other features of the filter compatibility layer.
"""
# A Django filter with @needs_autoescape works in Jinja2
from coffin.common import env
env.autoescape = True
assert env.from_string('{{ "b"|needing_autoescape }}').render() == 'True'
env.autoescape = False
assert env.from_string('{{ "b"|needing_autoescape }}').render() == 'False'
# [bug] @needs_autoescape also (still) works correctly in Django
assert Template('{% load compat_filters %}{{ "b"|needing_autoescape }}').render(Context()) == 'True'
# The Django filters can handle "Undefined" values
assert env.from_string('{{ doesnotexist|django_raw_output }}').render() == ''
# TODO: test @stringfilter
|