From: Kartheek Lenkala Date: Sun, 22 Mar 2015 09:58:54 +0000 (+0530) Subject: Pytest migration initial commit X-Git-Tag: 2.8~27^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d4afa1160af46f5b464d544ae71e37a85c6140b;p=thirdparty%2Fjinja.git Pytest migration initial commit --- diff --git a/jinja2/testsuite/__init__.py b/jinja2/testsuite/__init__.py deleted file mode 100644 index 635c83e5..00000000 --- a/jinja2/testsuite/__init__.py +++ /dev/null @@ -1,156 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite - ~~~~~~~~~~~~~~~~ - - All the unittests of Jinja2. These tests can be executed by - either running run-tests.py using multiple Python versions at - the same time. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import os -import re -import sys -import unittest -from traceback import format_exception -from jinja2 import loaders -from jinja2._compat import PY2 - - -here = os.path.dirname(os.path.abspath(__file__)) - -dict_loader = loaders.DictLoader({ - 'justdict.html': 'FOO' -}) -package_loader = loaders.PackageLoader('jinja2.testsuite.res', 'templates') -filesystem_loader = loaders.FileSystemLoader(here + '/res/templates') -function_loader = loaders.FunctionLoader({'justfunction.html': 'FOO'}.get) -choice_loader = loaders.ChoiceLoader([dict_loader, package_loader]) -prefix_loader = loaders.PrefixLoader({ - 'a': filesystem_loader, - 'b': dict_loader -}) - - -class JinjaTestCase(unittest.TestCase): - - ### use only these methods for testing. If you need standard - ### unittest method, wrap them! - - def setup(self): - pass - - def teardown(self): - pass - - def setUp(self): - self.setup() - - def tearDown(self): - self.teardown() - - def assert_equal(self, a, b): - return self.assertEqual(a, b) - - def assert_raises(self, *args, **kwargs): - return self.assertRaises(*args, **kwargs) - - def assert_traceback_matches(self, callback, expected_tb): - try: - callback() - except Exception as e: - tb = format_exception(*sys.exc_info()) - if re.search(expected_tb.strip(), ''.join(tb)) is None: - raise self.fail('Traceback did not match:\n\n%s\nexpected:\n%s' - % (''.join(tb), expected_tb)) - else: - self.fail('Expected exception') - - -def find_all_tests(suite): - """Yields all the tests and their names from a given suite.""" - suites = [suite] - while suites: - s = suites.pop() - try: - suites.extend(s) - except TypeError: - yield s, '%s.%s.%s' % ( - s.__class__.__module__, - s.__class__.__name__, - s._testMethodName - ) - - -class BetterLoader(unittest.TestLoader): - """A nicer loader that solves two problems. First of all we are setting - up tests from different sources and we're doing this programmatically - which breaks the default loading logic so this is required anyways. - Secondly this loader has a nicer interpolation for test names than the - default one so you can just do ``run-tests.py ViewTestCase`` and it - will work. - """ - - def getRootSuite(self): - return suite() - - def loadTestsFromName(self, name, module=None): - root = self.getRootSuite() - if name == 'suite': - return root - - all_tests = [] - for testcase, testname in find_all_tests(root): - if testname == name or \ - testname.endswith('.' + name) or \ - ('.' + name + '.') in testname or \ - testname.startswith(name + '.'): - all_tests.append(testcase) - - if not all_tests: - raise LookupError('could not find test case for "%s"' % name) - - if len(all_tests) == 1: - return all_tests[0] - rv = unittest.TestSuite() - for test in all_tests: - rv.addTest(test) - return rv - - -def suite(): - from jinja2.testsuite import ext, filters, tests, core_tags, \ - loader, inheritance, imports, lexnparse, security, api, \ - regression, debug, utils, bytecode_cache, doctests - suite = unittest.TestSuite() - suite.addTest(ext.suite()) - suite.addTest(filters.suite()) - suite.addTest(tests.suite()) - suite.addTest(core_tags.suite()) - suite.addTest(loader.suite()) - suite.addTest(inheritance.suite()) - suite.addTest(imports.suite()) - suite.addTest(lexnparse.suite()) - suite.addTest(security.suite()) - suite.addTest(api.suite()) - suite.addTest(regression.suite()) - suite.addTest(debug.suite()) - suite.addTest(utils.suite()) - suite.addTest(bytecode_cache.suite()) - - # doctests will not run on python 3 currently. Too many issues - # with that, do not test that on that platform. - if PY2: - suite.addTest(doctests.suite()) - - return suite - - -def main(): - """Runs the testsuite as command line application.""" - try: - unittest.main(testLoader=BetterLoader(), defaultTest='suite') - except Exception as e: - print('Error: %s' % e) diff --git a/jinja2/testsuite/bytecode_cache.py b/jinja2/testsuite/bytecode_cache.py deleted file mode 100644 index 9f5c635b..00000000 --- a/jinja2/testsuite/bytecode_cache.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.bytecode_cache - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Test bytecode caching - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest - -from jinja2.testsuite import JinjaTestCase, package_loader - -from jinja2 import Environment -from jinja2.bccache import FileSystemBytecodeCache -from jinja2.exceptions import TemplateNotFound - -bytecode_cache = FileSystemBytecodeCache() -env = Environment( - loader=package_loader, - bytecode_cache=bytecode_cache, -) - - -class ByteCodeCacheTestCase(JinjaTestCase): - - def test_simple(self): - tmpl = env.get_template('test.html') - assert tmpl.render().strip() == 'BAR' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ByteCodeCacheTestCase)) - return suite diff --git a/jinja2/testsuite/conftest.py b/jinja2/testsuite/conftest.py new file mode 100644 index 00000000..f8154eab --- /dev/null +++ b/jinja2/testsuite/conftest.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +""" + jinja2.testsuite.conftest + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + Configuration for the tests + + :copyright: (c) 2010 by the Jinja Team. + :license: BSD, see LICENSE for more details. +""" +from fixtures import * diff --git a/jinja2/testsuite/doctests.py b/jinja2/testsuite/doctests.py deleted file mode 100644 index 616d3b6e..00000000 --- a/jinja2/testsuite/doctests.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jinja2.testsuite.doctests - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - The doctests. Collects all tests we want to test from - the Jinja modules. - - :copyright: (c) 2010 by the Jinja Team. - :license: BSD, see LICENSE for more details. -""" -import unittest -import doctest - - -def suite(): - from jinja2 import utils, sandbox, runtime, meta, loaders, \ - ext, environment, bccache, nodes - suite = unittest.TestSuite() - suite.addTest(doctest.DocTestSuite(utils)) - suite.addTest(doctest.DocTestSuite(sandbox)) - suite.addTest(doctest.DocTestSuite(runtime)) - suite.addTest(doctest.DocTestSuite(meta)) - suite.addTest(doctest.DocTestSuite(loaders)) - suite.addTest(doctest.DocTestSuite(ext)) - suite.addTest(doctest.DocTestSuite(environment)) - suite.addTest(doctest.DocTestSuite(bccache)) - suite.addTest(doctest.DocTestSuite(nodes)) - return suite diff --git a/jinja2/testsuite/fixtures.py b/jinja2/testsuite/fixtures.py new file mode 100644 index 00000000..4b7473d2 --- /dev/null +++ b/jinja2/testsuite/fixtures.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +""" + jinja2.testsuite.fixtures + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + Contains fixtures used by tests. + + :copyright: (c) 2010 by the Jinja Team. + :license: BSD, see LICENSE for more details. +""" +import pytest +import os +import re +import sys + +from traceback import format_exception +from jinja2 import loaders +from jinja2._compat import PY2 +from jinja2 import Environment + + +@pytest.fixture +def env(): + '''returns a new environment. + ''' + return Environment() + + +@pytest.fixture +def dict_loader(): + '''returns DictLoader + ''' + return loaders.DictLoader({ + 'justdict.html': 'FOO' + }) + + +@pytest.fixture +def package_loader(): + '''returns PackageLoader initialized from templates + ''' + return loaders.PackageLoader('jinja2.testsuite.res', 'templates') + + +@pytest.fixture +def filesystem_loader(): + '''returns FileSystemLoader initialized to res/templates directory + ''' + here = os.path.dirname(os.path.abspath(__file__)) + return loaders.FileSystemLoader(here + '/res/templates') + + +@pytest.fixture +def function_loader(): + '''returns a FunctionLoader + ''' + return loaders.FunctionLoader({'justfunction.html': 'FOO'}.get) + + +@pytest.fixture +def choice_loader(dict_loader, package_loader): + '''returns a ChoiceLoader + ''' + return loaders.ChoiceLoader([dict_loader, package_loader]) + + +@pytest.fixture +def prefix_loader(filesystem_loader, dict_loader): + '''returns a PrefixLoader + ''' + return loaders.PrefixLoader({ + 'a': filesystem_loader, + 'b': dict_loader + }) diff --git a/jinja2/testsuite/api.py b/jinja2/testsuite/test_api.py similarity index 61% rename from jinja2/testsuite/api.py rename to jinja2/testsuite/test_api.py index ea3739bf..37617f2a 100644 --- a/jinja2/testsuite/api.py +++ b/jinja2/testsuite/test_api.py @@ -8,24 +8,22 @@ :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 - +import pytest from jinja2 import Environment, Undefined, DebugUndefined, \ StrictUndefined, UndefinedError, meta, \ is_undefined, Template, DictLoader, make_logging_undefined from jinja2.utils import Cycler -env = Environment() - -class ExtendedAPITestCase(JinjaTestCase): +@pytest.mark.api +@pytest.mark.extended +class TestExtendedAPI(): - def test_item_and_attribute(self): + def test_item_and_attribute(self, env): from jinja2.sandbox import SandboxedEnvironment for env in Environment(), SandboxedEnvironment(): @@ -37,7 +35,7 @@ class ExtendedAPITestCase(JinjaTestCase): tmpl = env.from_string('{{ foo["items"] }}') assert tmpl.render(foo={'items': 42}) == '42' - def test_finalizer(self): + def test_finalizer(self, env): def finalize_none_empty(value): if value is None: value = u'' @@ -48,7 +46,7 @@ class ExtendedAPITestCase(JinjaTestCase): tmpl = env.from_string('<{{ none }}>') assert tmpl.render() == '<>' - def test_cycler(self): + def test_cycler(self, env): items = 1, 2, 3 c = Cycler(*items) for item in items + items: @@ -59,7 +57,7 @@ class ExtendedAPITestCase(JinjaTestCase): c.reset() assert c.current == 1 - def test_expressions(self): + def test_expressions(self, env): expr = env.compile_expression("foo") assert expr() is None assert expr(foo=42) == 42 @@ -69,23 +67,23 @@ class ExtendedAPITestCase(JinjaTestCase): expr = env.compile_expression("42 + foo") assert expr(foo=42) == 84 - def test_template_passthrough(self): + def test_template_passthrough(self, env): 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 test_autoescape_autoselect(self, env): 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 }}' - })) + 'test.txt': '{{ foo }}', + 'test.html': '{{ foo }}' + })) t = env.get_template('test.txt') assert t.render(foo='') == '' t = env.get_template('test.html') @@ -94,20 +92,23 @@ class ExtendedAPITestCase(JinjaTestCase): assert t.render(foo='') == '' -class MetaTestCase(JinjaTestCase): +@pytest.mark.api +@pytest.mark.meta +class TestMeta(): - def test_find_undeclared_variables(self): + def test_find_undeclared_variables(self, env): 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 %}') + '{% 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): + def test_find_refererenced_templates(self, env): ast = env.parse('{% extends "layout.html" %}{% include helper %}') i = meta.find_referenced_templates(ast) assert next(i) == 'layout.html' @@ -121,7 +122,7 @@ class MetaTestCase(JinjaTestCase): i = meta.find_referenced_templates(ast) assert list(i) == ['layout.html', 'test.html', 'meh.html', 'muh.html'] - def test_find_included_templates(self): + def test_find_included_templates(self, env): ast = env.parse('{% include ["foo.html", "bar.html"] %}') i = meta.find_referenced_templates(ast) assert list(i) == ['foo.html', 'bar.html'] @@ -139,28 +140,30 @@ class MetaTestCase(JinjaTestCase): assert list(i) == ['foo.html', 'bar.html', None] -class StreamingTestCase(JinjaTestCase): +@pytest.mark.api +@pytest.mark.streaming +class TestStreaming(): - def test_basic_streaming(self): + def test_basic_streaming(self, env): tmpl = env.from_string("
    {% for item in seq %}
  • {{ loop.index " "}} - {{ item }}
  • {%- endfor %}
") stream = tmpl.stream(seq=list(range(4))) - self.assert_equal(next(stream), '
    ') - self.assert_equal(next(stream), '
  • 1 - 0
  • ') - self.assert_equal(next(stream), '
  • 2 - 1
  • ') - self.assert_equal(next(stream), '
  • 3 - 2
  • ') - self.assert_equal(next(stream), '
  • 4 - 3
  • ') - self.assert_equal(next(stream), '
') - - def test_buffered_streaming(self): + assert next(stream) == '
    ' + assert next(stream) == '
  • 1 - 0
  • ' + assert next(stream) == '
  • 2 - 1
  • ' + assert next(stream) == '
  • 3 - 2
  • ' + assert next(stream) == '
  • 4 - 3
  • ' + assert next(stream) == '
' + + def test_buffered_streaming(self, env): tmpl = env.from_string("
    {% for item in seq %}
  • {{ loop.index " "}} - {{ item }}
  • {%- endfor %}
") stream = tmpl.stream(seq=list(range(4))) stream.enable_buffering(size=3) - self.assert_equal(next(stream), u'
  • 1 - 0
  • 2 - 1
  • ') - self.assert_equal(next(stream), u'
  • 3 - 2
  • 4 - 3
') + assert next(stream) == u'
  • 1 - 0
  • 2 - 1
  • ' + assert next(stream) == u'
  • 3 - 2
  • 4 - 3
' - def test_streaming_behavior(self): + def test_streaming_behavior(self, env): tmpl = env.from_string("") stream = tmpl.stream() assert not stream.buffered @@ -169,29 +172,31 @@ class StreamingTestCase(JinjaTestCase): stream.disable_buffering() assert not stream.buffered - def test_dump_stream(self): + def test_dump_stream(self, env): 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') + assert f.read() == b'\xe2\x9c\x93' finally: shutil.rmtree(tmp) -class UndefinedTestCase(JinjaTestCase): +@pytest.mark.api +@pytest.mark.undefined +class TestUndefined(): - def test_stopiteration_is_undefined(self): + def test_stopiteration_is_undefined(self, env): 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) + pytest.raises(UndefinedError, t.render, test=test) - def test_undefined_and_special_attributes(self): + def test_undefined_and_special_attributes(self, env): try: Undefined('Foo').__dict__ except AttributeError: @@ -199,67 +204,78 @@ class UndefinedTestCase(JinjaTestCase): else: assert False, "Expected actual attribute error" - def test_logging_undefined(self): + def test_logging_undefined(self, env): _messages = [] + class DebugLogger(object): def warning(self, msg, *args): _messages.append('W:' + msg % args) + def error(self, msg, *args): _messages.append('E:' + msg % args) logging_undefined = make_logging_undefined(DebugLogger()) env = Environment(undefined=logging_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') - self.assert_equal(_messages, [ + assert env.from_string('{{ missing }}').render() == u'' + pytest.raises(UndefinedError, + env.from_string('{{ missing.attribute }}').render) + assert env.from_string('{{ missing|list }}').render() == '[]' + assert env.from_string('{{ missing is not defined }}').render() \ + == 'True' + assert env.from_string('{{ foo.missing }}').render(foo=42) == '' + assert env.from_string('{{ not missing }}').render() == 'True' + assert _messages == [ 'W:Template variable warning: missing is undefined', "E:Template variable error: 'missing' is undefined", 'W:Template variable warning: missing is undefined', 'W:Template variable warning: int object has no attribute missing', 'W:Template variable warning: missing is undefined', - ]) + ] - def test_default_undefined(self): + def test_default_undefined(self, env): 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): + assert env.from_string('{{ missing }}').render() == u'' + pytest.raises(UndefinedError, + env.from_string('{{ missing.attribute }}').render) + assert env.from_string('{{ missing|list }}').render() == '[]' + assert env.from_string('{{ missing is not defined }}').render() \ + == 'True' + assert env.from_string('{{ foo.missing }}').render(foo=42) == '' + assert env.from_string('{{ not missing }}').render() == 'True' + + def test_debug_undefined(self, env): 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): + assert env.from_string('{{ missing }}').render() == '{{ missing }}' + pytest.raises(UndefinedError, + env.from_string('{{ missing.attribute }}').render) + assert env.from_string('{{ missing|list }}').render() == '[]' + assert env.from_string('{{ missing is not defined }}').render() \ + == 'True' + assert env.from_string('{{ foo.missing }}').render(foo=42) \ + == u"{{ no such element: int object['missing'] }}" + assert env.from_string('{{ not missing }}').render() == 'True' + + def test_strict_undefined(self, env): 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): + pytest.raises(UndefinedError, env.from_string('{{ missing }}').render) + pytest.raises(UndefinedError, + env.from_string('{{ missing.attribute }}').render) + pytest.raises(UndefinedError, + env.from_string('{{ missing|list }}').render) + assert env.from_string('{{ missing is not defined }}').render() \ + == 'True' + pytest.raises(UndefinedError, + env.from_string('{{ foo.missing }}').render, foo=42) + pytest.raises(UndefinedError, + env.from_string('{{ not missing }}').render) + assert env.from_string('{{ missing|default("default", true) }}')\ + .render() == 'default' + + def test_indexing_gives_undefined(self, env): t = Template("{{ var[42].foo }}") - self.assert_raises(UndefinedError, t.render, var=0) + pytest.raises(UndefinedError, t.render, var=0) - def test_none_gives_proper_error(self): + def test_none_gives_proper_error(self, env): try: Environment().getattr(None, 'split')() except UndefinedError as e: @@ -267,19 +283,10 @@ class UndefinedTestCase(JinjaTestCase): else: assert False, 'expected exception' - def test_object_repr(self): + def test_object_repr(self, env): 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 diff --git a/jinja2/testsuite/test_bytecode_cache.py b/jinja2/testsuite/test_bytecode_cache.py new file mode 100644 index 00000000..2ffe4c60 --- /dev/null +++ b/jinja2/testsuite/test_bytecode_cache.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +""" + jinja2.testsuite.bytecode_cache + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Test bytecode caching + + :copyright: (c) 2010 by the Jinja Team. + :license: BSD, see LICENSE for more details. +""" +import pytest +from jinja2 import Environment +from jinja2.bccache import FileSystemBytecodeCache +from jinja2.exceptions import TemplateNotFound + + +@pytest.fixture +def env(package_loader): + bytecode_cache = FileSystemBytecodeCache() + return Environment( + loader=package_loader, + bytecode_cache=bytecode_cache, + ) + + +@pytest.mark.byte_code_cache +class TestByteCodeCache(): + + def test_simple(self, env): + tmpl = env.get_template('test.html') + assert tmpl.render().strip() == 'BAR' + pytest.raises(TemplateNotFound, env.get_template, 'missing.html') diff --git a/jinja2/testsuite/core_tags.py b/jinja2/testsuite/test_core_tags.py similarity index 68% rename from jinja2/testsuite/core_tags.py rename to jinja2/testsuite/test_core_tags.py index e1cff3bf..2ea7757e 100644 --- a/jinja2/testsuite/core_tags.py +++ b/jinja2/testsuite/test_core_tags.py @@ -8,31 +8,34 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD, see LICENSE for more details. """ -import unittest - -from jinja2.testsuite import JinjaTestCase - +import pytest from jinja2 import Environment, TemplateSyntaxError, UndefinedError, \ DictLoader -env = Environment() +@pytest.fixture +def env_trim(): + return Environment(trim_blocks=True) -class ForLoopTestCase(JinjaTestCase): - def test_simple(self): +@pytest.mark.core_tags +@pytest.mark.for_loop +class TestForLoop(): + + def test_simple(self, env): tmpl = env.from_string('{% for item in seq %}{{ item }}{% endfor %}') assert tmpl.render(seq=list(range(10))) == '0123456789' - def test_else(self): - tmpl = env.from_string('{% for item in seq %}XXX{% else %}...{% endfor %}') + def test_else(self, env): + tmpl = env.from_string( + '{% for item in seq %}XXX{% else %}...{% endfor %}') assert tmpl.render() == '...' - def test_empty_blocks(self): + def test_empty_blocks(self, env): tmpl = env.from_string('<{% for item in seq %}{% else %}{% endfor %}>') assert tmpl.render() == '<>' - def test_context_vars(self): + def test_context_vars(self, env): slist = [42, 24] for seq in [slist, iter(slist), reversed(slist), (_ for _ in slist)]: tmpl = env.from_string('''{% for item in seq -%} @@ -53,19 +56,19 @@ class ForLoopTestCase(JinjaTestCase): assert one_last == 'False' and two_last == 'True' assert one_length == two_length == '2' - def test_cycling(self): + def test_cycling(self, env): tmpl = env.from_string('''{% for item in seq %}{{ loop.cycle('<1>', '<2>') }}{% endfor %}{% for item in seq %}{{ loop.cycle(*through) }}{% endfor %}''') output = tmpl.render(seq=list(range(4)), through=('<1>', '<2>')) assert output == '<1><2>' * 4 - def test_scope(self): + def test_scope(self, env): tmpl = env.from_string('{% for item in seq %}{% endfor %}{{ item }}') output = tmpl.render(seq=list(range(10))) assert not output - def test_varlen(self): + def test_varlen(self, env): def inner(): for item in range(5): yield item @@ -73,11 +76,11 @@ class ForLoopTestCase(JinjaTestCase): output = tmpl.render(iter=inner()) assert output == '01234' - def test_noniter(self): + def test_noniter(self, env): tmpl = env.from_string('{% for item in none %}...{% endfor %}') - self.assert_raises(TypeError, tmpl.render) + pytest.raises(TypeError, tmpl.render) - def test_recursive(self): + def test_recursive(self, env): tmpl = env.from_string('''{% for item in seq recursive -%} [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] {%- endfor %}''') @@ -87,27 +90,27 @@ class ForLoopTestCase(JinjaTestCase): dict(a=3, b=[dict(a='a')]) ]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]' - def test_recursive_depth0(self): + def test_recursive_depth0(self, env): tmpl = env.from_string('''{% for item in seq recursive -%} [{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] {%- endfor %}''') - self.assertEqual(tmpl.render(seq=[ + assert tmpl.render(seq=[ dict(a=1, b=[dict(a=1), dict(a=2)]), dict(a=2, b=[dict(a=1), dict(a=2)]), dict(a=3, b=[dict(a='a')]) - ]), '[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]') + ]) == '[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]' - def test_recursive_depth(self): + def test_recursive_depth(self, env): tmpl = env.from_string('''{% for item in seq recursive -%} [{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] {%- endfor %}''') - self.assertEqual(tmpl.render(seq=[ + assert tmpl.render(seq=[ dict(a=1, b=[dict(a=1), dict(a=2)]), dict(a=2, b=[dict(a=1), dict(a=2)]), dict(a=3, b=[dict(a='a')]) - ]), '[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]') + ]) == '[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]' - def test_looploop(self): + def test_looploop(self, env): tmpl = env.from_string('''{% for row in table %} {%- set rowloop = loop -%} {% for cell in row -%} @@ -116,21 +119,21 @@ class ForLoopTestCase(JinjaTestCase): {%- endfor %}''') assert tmpl.render(table=['ab', 'cd']) == '[1|1][1|2][2|1][2|2]' - def test_reversed_bug(self): + def test_reversed_bug(self, env): tmpl = env.from_string('{% for i in items %}{{ i }}' '{% if not loop.last %}' ',{% endif %}{% endfor %}') assert tmpl.render(items=reversed([3, 2, 1])) == '1,2,3' - def test_loop_errors(self): + def test_loop_errors(self, env): tmpl = env.from_string('''{% for item in [1] if loop.index == 0 %}...{% endfor %}''') - self.assert_raises(UndefinedError, tmpl.render) + pytest.raises(UndefinedError, tmpl.render) tmpl = env.from_string('''{% for item in [] %}...{% else %}{{ loop }}{% endfor %}''') assert tmpl.render() == '' - def test_loop_filter(self): + def test_loop_filter(self, env): tmpl = env.from_string('{% for item in range(10) if item ' 'is even %}[{{ item }}]{% endfor %}') assert tmpl.render() == '[0][2][4][6][8]' @@ -139,16 +142,18 @@ class ForLoopTestCase(JinjaTestCase): loop.index }}:{{ item }}]{% endfor %}''') assert tmpl.render() == '[1:0][2:2][3:4][4:6][5:8]' - def test_loop_unassignable(self): - self.assert_raises(TemplateSyntaxError, env.from_string, - '{% for loop in seq %}...{% endfor %}') + def test_loop_unassignable(self, env): + pytest.raises(TemplateSyntaxError, env.from_string, + '{% for loop in seq %}...{% endfor %}') - def test_scoped_special_var(self): - t = env.from_string('{% for s in seq %}[{{ loop.first }}{% for c in s %}' - '|{{ loop.first }}{% endfor %}]{% endfor %}') - assert t.render(seq=('ab', 'cd')) == '[True|True|False][False|True|False]' + def test_scoped_special_var(self, env): + t = env.from_string( + '{% for s in seq %}[{{ loop.first }}{% for c in s %}' + '|{{ loop.first }}{% endfor %}]{% endfor %}') + assert t.render(seq=('ab', 'cd')) \ + == '[True|True|False][False|True|False]' - def test_scoped_loop_var(self): + def test_scoped_loop_var(self, env): t = env.from_string('{% for x in seq %}{{ loop.first }}' '{% for y in seq %}{% endfor %}{% endfor %}') assert t.render(seq='ab') == 'TrueFalse' @@ -156,13 +161,13 @@ class ForLoopTestCase(JinjaTestCase): '{{ loop.first }}{% endfor %}{% endfor %}') assert t.render(seq='ab') == 'TrueFalseTrueFalse' - def test_recursive_empty_loop_iter(self): + def test_recursive_empty_loop_iter(self, env): t = env.from_string(''' {%- for item in foo recursive -%}{%- endfor -%} ''') assert t.render(dict(foo=[])) == '' - def test_call_in_loop(self): + def test_call_in_loop(self, env): t = env.from_string(''' {%- macro do_something() -%} [{{ caller() }}] @@ -176,7 +181,7 @@ class ForLoopTestCase(JinjaTestCase): ''') assert t.render() == '[1][2][3]' - def test_scoping_bug(self): + def test_scoping_bug(self, env): t = env.from_string(''' {%- for item in foo %}...{{ item }}...{% endfor %} {%- macro item(a) %}...{{ a }}...{% endmacro %} @@ -184,110 +189,119 @@ class ForLoopTestCase(JinjaTestCase): ''') assert t.render(foo=(1,)) == '...1......2...' - def test_unpacking(self): + def test_unpacking(self, env): tmpl = env.from_string('{% for a, b, c in [[1, 2, 3]] %}' - '{{ a }}|{{ b }}|{{ c }}{% endfor %}') + '{{ a }}|{{ b }}|{{ c }}{% endfor %}') assert tmpl.render() == '1|2|3' -class IfConditionTestCase(JinjaTestCase): +@pytest.mark.core_tags +@pytest.mark.if_condition +class TestIfCondition(): - def test_simple(self): + def test_simple(self, env): tmpl = env.from_string('''{% if true %}...{% endif %}''') assert tmpl.render() == '...' - def test_elif(self): + def test_elif(self, env): tmpl = env.from_string('''{% if false %}XXX{% elif true %}...{% else %}XXX{% endif %}''') assert tmpl.render() == '...' - def test_else(self): + def test_else(self, env): tmpl = env.from_string('{% if false %}XXX{% else %}...{% endif %}') assert tmpl.render() == '...' - def test_empty(self): + def test_empty(self, env): tmpl = env.from_string('[{% if true %}{% else %}{% endif %}]') assert tmpl.render() == '[]' - def test_complete(self): + def test_complete(self, env): tmpl = env.from_string('{% if a %}A{% elif b %}B{% elif c == d %}' 'C{% else %}D{% endif %}') assert tmpl.render(a=0, b=False, c=42, d=42.0) == 'C' - def test_no_scope(self): - tmpl = env.from_string('{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}') + def test_no_scope(self, env): + tmpl = env.from_string( + '{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}') assert tmpl.render(a=True) == '1' - tmpl = env.from_string('{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}') + tmpl = env.from_string( + '{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}') assert tmpl.render() == '1' -class MacrosTestCase(JinjaTestCase): - env = Environment(trim_blocks=True) - - def test_simple(self): - tmpl = self.env.from_string('''\ +@pytest.mark.core_tags +@pytest.mark.macros +class TestMacros(): + def test_simple(self, env_trim): + tmpl = env_trim.from_string('''\ {% macro say_hello(name) %}Hello {{ name }}!{% endmacro %} {{ say_hello('Peter') }}''') assert tmpl.render() == 'Hello Peter!' - def test_scoping(self): - tmpl = self.env.from_string('''\ + def test_scoping(self, env_trim): + tmpl = env_trim.from_string('''\ {% macro level1(data1) %} {% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %} {{ level2('bar') }}{% endmacro %} {{ level1('foo') }}''') assert tmpl.render() == 'foo|bar' - def test_arguments(self): - tmpl = self.env.from_string('''\ + def test_arguments(self, env_trim): + tmpl = env_trim.from_string('''\ {% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %} {{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}''') assert tmpl.render() == '||c|d|a||c|d|a|b|c|d|1|2|3|d' - def test_arguments_defaults_nonsense(self): - self.assert_raises(TemplateSyntaxError, self.env.from_string, '''\ + def test_arguments_defaults_nonsense(self, env_trim): + pytest.raises(TemplateSyntaxError, env_trim.from_string, '''\ {% macro m(a, b=1, c) %}a={{ a }}, b={{ b }}, c={{ c }}{% endmacro %}''') - def test_caller_defaults_nonsense(self): - self.assert_raises(TemplateSyntaxError, self.env.from_string, '''\ + def test_caller_defaults_nonsense(self, env_trim): + pytest.raises(TemplateSyntaxError, env_trim.from_string, '''\ {% macro a() %}{{ caller() }}{% endmacro %} {% call(x, y=1, z) a() %}{% endcall %}''') - def test_varargs(self): - tmpl = self.env.from_string('''\ + def test_varargs(self, env_trim): + tmpl = env_trim.from_string('''\ {% macro test() %}{{ varargs|join('|') }}{% endmacro %}\ {{ test(1, 2, 3) }}''') assert tmpl.render() == '1|2|3' - def test_simple_call(self): - tmpl = self.env.from_string('''\ + def test_simple_call(self, env_trim): + tmpl = env_trim.from_string('''\ {% macro test() %}[[{{ caller() }}]]{% endmacro %}\ {% call test() %}data{% endcall %}''') assert tmpl.render() == '[[data]]' - def test_complex_call(self): - tmpl = self.env.from_string('''\ + def test_complex_call(self, env_trim): + tmpl = env_trim.from_string('''\ {% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\ {% call(data) test() %}{{ data }}{% endcall %}''') assert tmpl.render() == '[[data]]' - def test_caller_undefined(self): - tmpl = self.env.from_string('''\ + def test_caller_undefined(self, env_trim): + tmpl = env_trim.from_string('''\ {% set caller = 42 %}\ {% macro test() %}{{ caller is not defined }}{% endmacro %}\ {{ test() }}''') assert tmpl.render() == 'True' - def test_include(self): - self.env = Environment(loader=DictLoader({'include': - '{% macro test(foo) %}[{{ foo }}]{% endmacro %}'})) - tmpl = self.env.from_string('{% from "include" import test %}{{ test("foo") }}') + def test_include(self, env_trim): + env_trim = Environment( + loader=DictLoader({ + 'include': '{% macro test(foo) %}[{{ foo }}]{% endmacro %}' + }) + ) + tmpl = env_trim.from_string( + '{% from "include" import test %}{{ test("foo") }}') assert tmpl.render() == '[foo]' - def test_macro_api(self): - tmpl = self.env.from_string('{% macro foo(a, b) %}{% endmacro %}' - '{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}' - '{% macro baz() %}{{ caller() }}{% endmacro %}') + def test_macro_api(self, env_trim): + tmpl = env_trim.from_string( + '{% macro foo(a, b) %}{% endmacro %}' + '{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}' + '{% macro baz() %}{{ caller() }}{% endmacro %}') assert tmpl.module.foo.arguments == ('a', 'b') assert tmpl.module.foo.defaults == () assert tmpl.module.foo.name == 'foo' @@ -301,31 +315,23 @@ class MacrosTestCase(JinjaTestCase): assert tmpl.module.bar.catch_varargs assert tmpl.module.baz.caller - def test_callself(self): - tmpl = self.env.from_string('{% macro foo(x) %}{{ x }}{% if x > 1 %}|' + def test_callself(self, env_trim): + tmpl = env_trim.from_string('{% macro foo(x) %}{{ x }}{% if x > 1 %}|' '{{ foo(x - 1) }}{% endif %}{% endmacro %}' '{{ foo(5) }}') assert tmpl.render() == '5|4|3|2|1' -class SetTestCase(JinjaTestCase): - env = Environment(trim_blocks=True) +@pytest.mark.core_tags +@pytest.mark.set +class TestSet(): - def test_normal(self): - tmpl = self.env.from_string('{% set foo = 1 %}{{ foo }}') + def test_normal(self, env_trim): + tmpl = env_trim.from_string('{% set foo = 1 %}{{ foo }}') assert tmpl.render() == '1' assert tmpl.module.foo == 1 - def test_block(self): - tmpl = self.env.from_string('{% set foo %}42{% endset %}{{ foo }}') + def test_block(self, env_trim): + tmpl = env_trim.from_string('{% set foo %}42{% endset %}{{ foo }}') assert tmpl.render() == '42' assert tmpl.module.foo == u'42' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ForLoopTestCase)) - suite.addTest(unittest.makeSuite(IfConditionTestCase)) - suite.addTest(unittest.makeSuite(MacrosTestCase)) - suite.addTest(unittest.makeSuite(SetTestCase)) - return suite diff --git a/jinja2/testsuite/debug.py b/jinja2/testsuite/test_debug.py similarity index 56% rename from jinja2/testsuite/debug.py rename to jinja2/testsuite/test_debug.py index 2588a83e..d8617ae0 100644 --- a/jinja2/testsuite/debug.py +++ b/jinja2/testsuite/test_debug.py @@ -8,41 +8,62 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD, see LICENSE for more details. """ -import unittest +import pytest -from jinja2.testsuite import JinjaTestCase, filesystem_loader +import re + +import sys +from traceback import format_exception from jinja2 import Environment, TemplateSyntaxError +from traceback import format_exception + + +@pytest.fixture +def fs_env(filesystem_loader): + '''returns a new environment. + ''' + return Environment(loader=filesystem_loader) -env = Environment(loader=filesystem_loader) +@pytest.mark.debug +class TestDebug(): -class DebugTestCase(JinjaTestCase): + def assert_traceback_matches(self, callback, expected_tb): + try: + callback() + except Exception as e: + tb = format_exception(*sys.exc_info()) + if re.search(expected_tb.strip(), ''.join(tb)) is None: + assert False, ('Traceback did not match:\n\n%s\nexpected:\n%s' % + (''.join(tb), expected_tb)) + else: + assert False, 'Expected exception' - def test_runtime_error(self): + def test_runtime_error(self, fs_env): def test(): tmpl.render(fail=lambda: 1 / 0) - tmpl = env.get_template('broken.html') + tmpl = fs_env.get_template('broken.html') self.assert_traceback_matches(test, r''' File ".*?broken.html", line 2, in (top-level template code|) \{\{ fail\(\) \}\} - File ".*?debug.pyc?", line \d+, in + File ".*debug?.pyc?", line \d+, in tmpl\.render\(fail=lambda: 1 / 0\) ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero ''') - def test_syntax_error(self): + def test_syntax_error(self, fs_env): # XXX: the .*? is necessary for python3 which does not hide # some of the stack frames we don't want to show. Not sure # what's up with that, but that is not that critical. Should # be fixed though. - self.assert_traceback_matches(lambda: env.get_template('syntaxerror.html'), r'''(?sm) + self.assert_traceback_matches(lambda: fs_env.get_template('syntaxerror.html'), r'''(?sm) File ".*?syntaxerror.html", line 4, in (template|) \{% endif %\}.*? (jinja2\.exceptions\.)?TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja was looking for the following tags: 'endfor' or 'else'. The innermost block that needs to be closed is 'for'. ''') - def test_regular_syntax_error(self): + def test_regular_syntax_error(self, fs_env): def test(): raise TemplateSyntaxError('wtf', 42) self.assert_traceback_matches(test, r''' @@ -50,9 +71,3 @@ ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero raise TemplateSyntaxError\('wtf', 42\) (jinja2\.exceptions\.)?TemplateSyntaxError: wtf line 42''') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(DebugTestCase)) - return suite diff --git a/jinja2/testsuite/ext.py b/jinja2/testsuite/test_ext.py similarity index 88% rename from jinja2/testsuite/ext.py rename to jinja2/testsuite/test_ext.py index 4f0b2231..8985416c 100644 --- a/jinja2/testsuite/ext.py +++ b/jinja2/testsuite/test_ext.py @@ -9,9 +9,7 @@ :license: BSD, see LICENSE for more details. """ import re -import unittest - -from jinja2.testsuite import JinjaTestCase +import pytest from jinja2 import Environment, DictLoader, contextfunction, nodes from jinja2.exceptions import TemplateAssertionError @@ -100,6 +98,7 @@ newstyle_i18n_env = Environment( ) newstyle_i18n_env.install_gettext_callables(gettext, ngettext, newstyle=True) + class TestExtension(Extension): tags = set(['test']) ext_attr = 42 @@ -160,12 +159,14 @@ class StreamFilterExtension(Extension): yield Token(lineno, 'data', token.value[pos:]) -class ExtensionsTestCase(JinjaTestCase): +@pytest.mark.ext +class TestExtensions(): def test_extend_late(self): env = Environment() env.add_extension('jinja2.ext.autoescape') - t = env.from_string('{% autoescape true %}{{ "" }}{% endautoescape %}') + t = env.from_string( + '{% autoescape true %}{{ "" }}{% endautoescape %}') assert t.render() == '<test>' def test_loop_controls(self): @@ -235,6 +236,7 @@ class ExtensionsTestCase(JinjaTestCase): def test_extension_ordering(self): class T1(Extension): priority = 1 + class T2(Extension): priority = 2 env = Environment(extensions=[T1, T2]) @@ -243,7 +245,8 @@ class ExtensionsTestCase(JinjaTestCase): assert ext[1].__class__ is T2 -class InternationalizationTestCase(JinjaTestCase): +@pytest.mark.ext +class TestInternationalization(): def test_trans(self): tmpl = i18n_env.get_template('child.html') @@ -251,24 +254,28 @@ class InternationalizationTestCase(JinjaTestCase): def test_trans_plural(self): tmpl = i18n_env.get_template('plural.html') - assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online' + assert tmpl.render(LANGUAGE='de', user_count=1) \ + == 'Ein Benutzer online' assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online' def test_trans_plural_with_functions(self): tmpl = i18n_env.get_template('plural2.html') + def get_user_count(): get_user_count.called += 1 return 1 get_user_count.called = 0 - assert tmpl.render(LANGUAGE='de', get_user_count=get_user_count) == '1s' + assert tmpl.render(LANGUAGE='de', get_user_count=get_user_count) \ + == '1s' assert get_user_count.called == 1 def test_complex_plural(self): - tmpl = i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% ' - 'pluralize count %}{{ count }} items{% endtrans %}') + tmpl = i18n_env.from_string( + '{% trans foo=42, count=2 %}{{ count }} item{% ' + 'pluralize count %}{{ count }} items{% endtrans %}') assert tmpl.render() == '2 items' - self.assert_raises(TemplateAssertionError, i18n_env.from_string, - '{% trans foo %}...{% pluralize bar %}...{% endtrans %}') + pytest.raises(TemplateAssertionError, i18n_env.from_string, + '{% trans foo %}...{% pluralize bar %}...{% endtrans %}') def test_trans_stringformatting(self): tmpl = i18n_env.get_template('stringformat.html') @@ -280,8 +287,9 @@ class InternationalizationTestCase(JinjaTestCase): {{ gettext('Hello World') }} {% trans %}Hello World{% endtrans %} {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %} - '''.encode('ascii')) # make python 3 happy - assert list(babel_extract(source, ('gettext', 'ngettext', '_'), [], {})) == [ + '''.encode('ascii')) # make python 3 happy + assert list(babel_extract(source, + ('gettext', 'ngettext', '_'), [], {})) == [ (2, 'gettext', u'Hello World', []), (3, 'gettext', u'Hello World', []), (4, 'ngettext', (u'%(users)s user', u'%(users)s users', None), []) @@ -295,15 +303,19 @@ class InternationalizationTestCase(JinjaTestCase): {% trans %}Hello World{% endtrans %}{# trans second #} {#: third #} {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %} - '''.encode('utf-8')) # make python 3 happy - assert list(babel_extract(source, ('gettext', 'ngettext', '_'), ['trans', ':'], {})) == [ + '''.encode('utf-8')) # make python 3 happy + assert list(babel_extract(source, + ('gettext', 'ngettext', '_'), + ['trans', ':'], {})) == [ (3, 'gettext', u'Hello World', ['first']), (4, 'gettext', u'Hello World', ['second']), - (6, 'ngettext', (u'%(users)s user', u'%(users)s users', None), ['third']) + (6, 'ngettext', (u'%(users)s user', u'%(users)s users', None), + ['third']) ] -class NewstyleInternationalizationTestCase(JinjaTestCase): +@pytest.mark.ext +class TestNewstyleInternationalization(): def test_trans(self): tmpl = newstyle_i18n_env.get_template('child.html') @@ -311,15 +323,17 @@ class NewstyleInternationalizationTestCase(JinjaTestCase): def test_trans_plural(self): tmpl = newstyle_i18n_env.get_template('plural.html') - assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online' + assert tmpl.render(LANGUAGE='de', user_count=1) \ + == 'Ein Benutzer online' assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online' def test_complex_plural(self): - tmpl = newstyle_i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% ' - 'pluralize count %}{{ count }} items{% endtrans %}') + tmpl = newstyle_i18n_env.from_string( + '{% trans foo=42, count=2 %}{{ count }} item{% ' + 'pluralize count %}{{ count }} items{% endtrans %}') assert tmpl.render() == '2 items' - self.assert_raises(TemplateAssertionError, i18n_env.from_string, - '{% trans foo %}...{% pluralize bar %}...{% endtrans %}') + pytest.raises(TemplateAssertionError, i18n_env.from_string, + '{% trans foo %}...{% pluralize bar %}...{% endtrans %}') def test_trans_stringformatting(self): tmpl = newstyle_i18n_env.get_template('stringformat.html') @@ -333,8 +347,9 @@ class NewstyleInternationalizationTestCase(JinjaTestCase): def test_autoescape_support(self): env = Environment(extensions=['jinja2.ext.autoescape', 'jinja2.ext.i18n']) - env.install_gettext_callables(lambda x: u'Wert: %(name)s', - lambda s, p, n: s, newstyle=True) + env.install_gettext_callables( + lambda x: u'Wert: %(name)s', + lambda s, p, n: s, newstyle=True) t = env.from_string('{% autoescape ae %}{{ gettext("foo", name=' '"") }}{% endautoescape %}') assert t.render(ae=True) == 'Wert: <test>' @@ -373,7 +388,8 @@ class NewstyleInternationalizationTestCase(JinjaTestCase): assert t.render() == '%(foo)s' -class AutoEscapeTestCase(JinjaTestCase): +@pytest.mark.ext +class TestAutoEscape(): def test_scoped_setting(self): env = Environment(extensions=['jinja2.ext.autoescape'], @@ -419,8 +435,9 @@ class AutoEscapeTestCase(JinjaTestCase): def test_scoping(self): env = Environment(extensions=['jinja2.ext.autoescape']) - tmpl = env.from_string('{% autoescape true %}{% set x = "" %}{{ x }}' - '{% endautoescape %}{{ x }}{{ "" }}') + tmpl = env.from_string( + '{% autoescape true %}{% set x = "" %}{{ x }}' + '{% endautoescape %}{{ x }}{{ "" }}') assert tmpl.render(x=1) == '<x>1' def test_volatile_scoping(self): @@ -448,12 +465,3 @@ class AutoEscapeTestCase(JinjaTestCase): autoescape=True) pysource = env.compile(tmplsource, raw=True) assert '<testing>\\n' in pysource - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ExtensionsTestCase)) - suite.addTest(unittest.makeSuite(InternationalizationTestCase)) - suite.addTest(unittest.makeSuite(NewstyleInternationalizationTestCase)) - suite.addTest(unittest.makeSuite(AutoEscapeTestCase)) - return suite diff --git a/jinja2/testsuite/filters.py b/jinja2/testsuite/test_filters.py similarity index 76% rename from jinja2/testsuite/filters.py rename to jinja2/testsuite/test_filters.py index a32db374..42c55583 100644 --- a/jinja2/testsuite/filters.py +++ b/jinja2/testsuite/test_filters.py @@ -8,37 +8,34 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD, see LICENSE for more details. """ -import unittest -from jinja2.testsuite import JinjaTestCase - +import pytest from jinja2 import Markup, Environment from jinja2._compat import text_type, implements_to_string -env = Environment() - -class FilterTestCase(JinjaTestCase): +@pytest.mark.filter +class TestFilter(): - def test_filter_calling(self): + def test_filter_calling(self, env): rv = env.call_filter('sum', [1, 2, 3]) - self.assert_equal(rv, 6) + assert rv == 6 - def test_capitalize(self): + def test_capitalize(self, env): tmpl = env.from_string('{{ "foo bar"|capitalize }}') assert tmpl.render() == 'Foo bar' - def test_center(self): + def test_center(self, env): tmpl = env.from_string('{{ "foo"|center(9) }}') assert tmpl.render() == ' foo ' - def test_default(self): + def test_default(self, env): tmpl = env.from_string( "{{ missing|default('no') }}|{{ false|default('no') }}|" "{{ false|default('no', true) }}|{{ given|default('no') }}" ) assert tmpl.render(given='yes') == 'no|False|no|yes' - def test_dictsort(self): + def test_dictsort(self, env): tmpl = env.from_string( '{{ foo|dictsort }}|' '{{ foo|dictsort(true) }}|' @@ -49,33 +46,33 @@ class FilterTestCase(JinjaTestCase): "[('AB', 3), ('aa', 0), ('b', 1), ('c', 2)]|" "[('aa', 0), ('b', 1), ('c', 2), ('AB', 3)]") - def test_batch(self): + def test_batch(self, env): tmpl = env.from_string("{{ foo|batch(3)|list }}|" "{{ foo|batch(3, 'X')|list }}") out = tmpl.render(foo=list(range(10))) assert out == ("[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]|" "[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 'X', 'X']]") - def test_slice(self): + def test_slice(self, env): tmpl = env.from_string('{{ foo|slice(3)|list }}|' '{{ foo|slice(3, "X")|list }}') out = tmpl.render(foo=list(range(10))) assert out == ("[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|" "[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]") - def test_escape(self): + def test_escape(self, env): tmpl = env.from_string('''{{ '<">&'|escape }}''') out = tmpl.render() assert out == '<">&' - def test_striptags(self): + def test_striptags(self, env): tmpl = env.from_string('''{{ foo|striptags }}''') out = tmpl.render(foo='

just a small \n ' 'example link

\n

to a webpage

' '') assert out == 'just a small example link to a webpage' - def test_filesizeformat(self): + def test_filesizeformat(self, env): tmpl = env.from_string( '{{ 100|filesizeformat }}|' '{{ 1000|filesizeformat }}|' @@ -89,12 +86,12 @@ class FilterTestCase(JinjaTestCase): '{{ 1000000000000|filesizeformat(true) }}' ) out = tmpl.render() - self.assert_equal(out, ( + assert out == ( '100 Bytes|1.0 kB|1.0 MB|1.0 GB|1.0 TB|100 Bytes|' '1000 Bytes|976.6 KiB|953.7 MiB|931.3 GiB' - )) + ) - def test_filesizeformat_issue59(self): + def test_filesizeformat_issue59(self, env): tmpl = env.from_string( '{{ 300|filesizeformat }}|' '{{ 3000|filesizeformat }}|' @@ -106,96 +103,96 @@ class FilterTestCase(JinjaTestCase): '{{ 3000000|filesizeformat(true) }}' ) out = tmpl.render() - self.assert_equal(out, ( + assert out == ( '300 Bytes|3.0 kB|3.0 MB|3.0 GB|3.0 TB|300 Bytes|' '2.9 KiB|2.9 MiB' - )) - + ) - def test_first(self): + def test_first(self, env): tmpl = env.from_string('{{ foo|first }}') out = tmpl.render(foo=list(range(10))) assert out == '0' - def test_float(self): + def test_float(self, env): tmpl = env.from_string('{{ "42"|float }}|' '{{ "ajsghasjgd"|float }}|' '{{ "32.32"|float }}') out = tmpl.render() assert out == '42.0|0.0|32.32' - def test_format(self): + def test_format(self, env): tmpl = env.from_string('''{{ "%s|%s"|format("a", "b") }}''') out = tmpl.render() assert out == 'a|b' - def test_indent(self): + def test_indent(self, env): tmpl = env.from_string('{{ foo|indent(2) }}|{{ foo|indent(2, true) }}') text = '\n'.join([' '.join(['foo', 'bar'] * 2)] * 2) out = tmpl.render(foo=text) assert out == ('foo bar foo bar\n foo bar foo bar| ' 'foo bar foo bar\n foo bar foo bar') - def test_int(self): + def test_int(self, env): tmpl = env.from_string('{{ "42"|int }}|{{ "ajsghasjgd"|int }}|' '{{ "32.32"|int }}') out = tmpl.render() assert out == '42|0|32' - def test_join(self): + def test_join(self, env): tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}') out = tmpl.render() assert out == '1|2|3' env2 = Environment(autoescape=True) - tmpl = env2.from_string('{{ ["", "foo"|safe]|join }}') + tmpl = env2.from_string( + '{{ ["", "foo"|safe]|join }}') assert tmpl.render() == '<foo>foo' - def test_join_attribute(self): + def test_join_attribute(self, env): class User(object): def __init__(self, username): self.username = username tmpl = env.from_string('''{{ users|join(', ', 'username') }}''') assert tmpl.render(users=map(User, ['foo', 'bar'])) == 'foo, bar' - def test_last(self): + def test_last(self, env): tmpl = env.from_string('''{{ foo|last }}''') out = tmpl.render(foo=list(range(10))) assert out == '9' - def test_length(self): + def test_length(self, env): tmpl = env.from_string('''{{ "hello world"|length }}''') out = tmpl.render() assert out == '11' - def test_lower(self): + def test_lower(self, env): tmpl = env.from_string('''{{ "FOO"|lower }}''') out = tmpl.render() assert out == 'foo' - def test_pprint(self): + def test_pprint(self, env): from pprint import pformat tmpl = env.from_string('''{{ data|pprint }}''') data = list(range(1000)) assert tmpl.render(data=data) == pformat(data) - def test_random(self): + def test_random(self, env): tmpl = env.from_string('''{{ seq|random }}''') seq = list(range(100)) for _ in range(10): assert int(tmpl.render(seq=seq)) in seq - def test_reverse(self): + def test_reverse(self, env): tmpl = env.from_string('{{ "foobar"|reverse|join }}|' '{{ [1, 2, 3]|reverse|list }}') assert tmpl.render() == 'raboof|[3, 2, 1]' - def test_string(self): + def test_string(self, env): x = [1, 2, 3, 4, 5] tmpl = env.from_string('''{{ obj|string }}''') assert tmpl.render(obj=x) == text_type(x) - def test_title(self): + def test_title(self, env): tmpl = env.from_string('''{{ "foo bar"|title }}''') assert tmpl.render() == "Foo Bar" tmpl = env.from_string('''{{ "foo's bar"|title }}''') @@ -219,7 +216,7 @@ class FilterTestCase(JinjaTestCase): out = tmpl.render(data=Foo()) assert out == 'Foo-Bar' - def test_truncate(self): + def test_truncate(self, env): tmpl = env.from_string( '{{ data|truncate(15, true, ">>>") }}|' '{{ data|truncate(15, false, ">>>") }}|' @@ -230,7 +227,7 @@ class FilterTestCase(JinjaTestCase): msg = 'Current output: %s' % out assert out == 'foobar baz b>>>|foobar baz >>>|foobar baz bar', msg - def test_truncate_very_short(self): + def test_truncate_very_short(self, env): tmpl = env.from_string( '{{ "foo bar baz"|truncate(9) }}|' '{{ "foo bar baz"|truncate(9, true) }}' @@ -238,45 +235,55 @@ class FilterTestCase(JinjaTestCase): out = tmpl.render() assert out == 'foo ...|foo ba...', out - def test_truncate_end_length(self): + def test_truncate_end_length(self, env): tmpl = env.from_string('{{ "Joel is a slug"|truncate(9, true) }}') out = tmpl.render() assert out == 'Joel i...', 'Current output: %s' % out - def test_upper(self): + def test_upper(self, env): tmpl = env.from_string('{{ "foo"|upper }}') assert tmpl.render() == 'FOO' - def test_urlize(self): - tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}') + def test_urlize(self, env): + tmpl = env.from_string( + '{{ "foo http://www.example.com/ bar"|urlize }}') assert tmpl.render() == 'foo '\ 'http://www.example.com/ bar' - def test_urlize_target_parameter(self): - tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize(target="_blank") }}') - assert tmpl.render() == 'foo '\ - 'http://www.example.com/ bar' - tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize(target=42) }}') + def test_urlize_target_parameter(self, env): + tmpl = env.from_string( + '{{ "foo http://www.example.com/ bar"|urlize(target="_blank") }}' + ) + assert tmpl.render() \ + == 'foo '\ + 'http://www.example.com/ bar' + tmpl = env.from_string( + '{{ "foo http://www.example.com/ bar"|urlize(target=42) }}' + ) assert tmpl.render() == 'foo '\ 'http://www.example.com/ bar' - def test_wordcount(self): + def test_wordcount(self, env): tmpl = env.from_string('{{ "foo bar baz"|wordcount }}') assert tmpl.render() == '3' - def test_block(self): - tmpl = env.from_string('{% filter lower|escape %}{% endfilter %}') + def test_block(self, env): + tmpl = env.from_string( + '{% filter lower|escape %}{% endfilter %}' + ) assert tmpl.render() == '<hehe>' - def test_chaining(self): - tmpl = env.from_string('''{{ ['', '']|first|upper|escape }}''') + def test_chaining(self, env): + tmpl = env.from_string( + '''{{ ['', '']|first|upper|escape }}''' + ) assert tmpl.render() == '<FOO>' - def test_sum(self): + def test_sum(self, env): tmpl = env.from_string('''{{ [1, 2, 3, 4, 5, 6]|sum }}''') assert tmpl.render() == '21' - def test_sum_attributes(self): + def test_sum_attributes(self, env): tmpl = env.from_string('''{{ values|sum('value') }}''') assert tmpl.render(values=[ {'value': 23}, @@ -284,7 +291,7 @@ class FilterTestCase(JinjaTestCase): {'value': 18}, ]) == '42' - def test_sum_attributes_nested(self): + def test_sum_attributes_nested(self, env): tmpl = env.from_string('''{{ values|sum('real.value') }}''') assert tmpl.render(values=[ {'real': {'value': 23}}, @@ -292,7 +299,7 @@ class FilterTestCase(JinjaTestCase): {'real': {'value': 18}}, ]) == '42' - def test_sum_attributes_tuple(self): + def test_sum_attributes_tuple(self, env): tmpl = env.from_string('''{{ values.items()|sum('1') }}''') assert tmpl.render(values={ 'foo': 23, @@ -300,54 +307,57 @@ class FilterTestCase(JinjaTestCase): 'baz': 18, }) == '42' - def test_abs(self): + def test_abs(self, env): tmpl = env.from_string('''{{ -1|abs }}|{{ 1|abs }}''') assert tmpl.render() == '1|1', tmpl.render() - def test_round_positive(self): + def test_round_positive(self, env): tmpl = env.from_string('{{ 2.7|round }}|{{ 2.1|round }}|' "{{ 2.1234|round(3, 'floor') }}|" "{{ 2.1|round(0, 'ceil') }}") assert tmpl.render() == '3.0|2.0|2.123|3.0', tmpl.render() - def test_round_negative(self): + def test_round_negative(self, env): tmpl = env.from_string('{{ 21.3|round(-1)}}|' "{{ 21.3|round(-1, 'ceil')}}|" "{{ 21.3|round(-1, 'floor')}}") - assert tmpl.render() == '20.0|30.0|20.0',tmpl.render() + assert tmpl.render() == '20.0|30.0|20.0', tmpl.render() - def test_xmlattr(self): - tmpl = env.from_string("{{ {'foo': 42, 'bar': 23, 'fish': none, " - "'spam': missing, 'blub:blub': ''}|xmlattr }}") + def test_xmlattr(self, env): + tmpl = env.from_string( + "{{ {'foo': 42, 'bar': 23, 'fish': none, " + "'spam': missing, 'blub:blub': ''}|xmlattr }}") out = tmpl.render().split() assert len(out) == 3 assert 'foo="42"' in out assert 'bar="23"' in out assert 'blub:blub="<?>"' in out - def test_sort1(self): - tmpl = env.from_string('{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}') + def test_sort1(self, env): + tmpl = env.from_string( + '{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}') assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]' - def test_sort2(self): + def test_sort2(self, env): tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort) }}') assert tmpl.render() == 'AbcD' - def test_sort3(self): + def test_sort3(self, env): tmpl = env.from_string('''{{ ['foo', 'Bar', 'blah']|sort }}''') assert tmpl.render() == "['Bar', 'blah', 'foo']" - def test_sort4(self): + def test_sort4(self, env): @implements_to_string class Magic(object): def __init__(self, value): self.value = value + def __str__(self): return text_type(self.value) tmpl = env.from_string('''{{ items|sort(attribute='value')|join }}''') assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == '1234' - def test_groupby(self): + def test_groupby(self, env): tmpl = env.from_string(''' {%- for grouper, list in [{'foo': 1, 'bar': 2}, {'foo': 2, 'bar': 3}, @@ -362,19 +372,20 @@ class FilterTestCase(JinjaTestCase): "" ] - def test_groupby_tuple_index(self): + def test_groupby_tuple_index(self, env): tmpl = env.from_string(''' {%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%} {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}| {%- endfor %}''') assert tmpl.render() == 'a:1:2|b:1|' - def test_groupby_multidot(self): + def test_groupby_multidot(self, env): class Date(object): def __init__(self, day, month, year): self.day = day self.month = month self.year = year + class Article(object): def __init__(self, title, *date): self.date = Date(*date) @@ -395,12 +406,12 @@ class FilterTestCase(JinjaTestCase): '' ] - def test_filtertag(self): + def test_filtertag(self, env): tmpl = env.from_string("{% filter upper|replace('FOO', 'foo') %}" "foobar{% endfilter %}") assert tmpl.render() == 'fooBAR' - def test_replace(self): + def test_replace(self, env): env = Environment() tmpl = env.from_string('{{ string|replace("o", 42) }}') assert tmpl.render(string='') == '' @@ -412,35 +423,36 @@ class FilterTestCase(JinjaTestCase): tmpl = env.from_string('{{ string|replace("o", ">x<") }}') assert tmpl.render(string=Markup('foo')) == 'f>x<>x<' - def test_forceescape(self): + def test_forceescape(self, env): tmpl = env.from_string('{{ x|forceescape }}') assert tmpl.render(x=Markup('
')) == u'<div />' - def test_safe(self): + def test_safe(self, env): env = Environment(autoescape=True) tmpl = env.from_string('{{ "
foo
"|safe }}') assert tmpl.render() == '
foo
' tmpl = env.from_string('{{ "
foo
" }}') assert tmpl.render() == '<div>foo</div>' - def test_urlencode(self): + def test_urlencode(self, env): env = Environment(autoescape=True) tmpl = env.from_string('{{ "Hello, world!"|urlencode }}') assert tmpl.render() == 'Hello%2C%20world%21' tmpl = env.from_string('{{ o|urlencode }}') - assert tmpl.render(o=u"Hello, world\u203d") == "Hello%2C%20world%E2%80%BD" + assert tmpl.render(o=u"Hello, world\u203d") \ + == "Hello%2C%20world%E2%80%BD" assert tmpl.render(o=(("f", 1),)) == "f=1" assert tmpl.render(o=(('f', 1), ("z", 2))) == "f=1&z=2" assert tmpl.render(o=((u"\u203d", 1),)) == "%E2%80%BD=1" assert tmpl.render(o={u"\u203d": 1}) == "%E2%80%BD=1" assert tmpl.render(o={0: 1}) == "0=1" - def test_simple_map(self): + def test_simple_map(self, env): env = Environment() tmpl = env.from_string('{{ ["1", "2", "3"]|map("int")|sum }}') - self.assertEqual(tmpl.render(), '6') + assert tmpl.render() == '6' - def test_attribute_map(self): + def test_attribute_map(self, env): class User(object): def __init__(self, name): self.name = name @@ -451,34 +463,38 @@ class FilterTestCase(JinjaTestCase): User('mike'), ] tmpl = env.from_string('{{ users|map(attribute="name")|join("|") }}') - self.assertEqual(tmpl.render(users=users), 'john|jane|mike') + assert tmpl.render(users=users) == 'john|jane|mike' - def test_empty_map(self): + def test_empty_map(self, env): env = Environment() tmpl = env.from_string('{{ none|map("upper")|list }}') - self.assertEqual(tmpl.render(), '[]') + assert tmpl.render() == '[]' - def test_simple_select(self): + def test_simple_select(self, env): env = Environment() tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|select("odd")|join("|") }}') - self.assertEqual(tmpl.render(), '1|3|5') + assert tmpl.render() == '1|3|5' - def test_bool_select(self): + def test_bool_select(self, env): env = Environment() - tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|select|join("|") }}') - self.assertEqual(tmpl.render(), '1|2|3|4|5') + tmpl = env.from_string( + '{{ [none, false, 0, 1, 2, 3, 4, 5]|select|join("|") }}' + ) + assert tmpl.render() == '1|2|3|4|5' - def test_simple_reject(self): + def test_simple_reject(self, env): env = Environment() tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|reject("odd")|join("|") }}') - self.assertEqual(tmpl.render(), '2|4') + assert tmpl.render() == '2|4' - def test_bool_reject(self): + def test_bool_reject(self, env): env = Environment() - tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|reject|join("|") }}') - self.assertEqual(tmpl.render(), 'None|False|0') + tmpl = env.from_string( + '{{ [none, false, 0, 1, 2, 3, 4, 5]|reject|join("|") }}' + ) + assert tmpl.render() == 'None|False|0' - def test_simple_select_attr(self): + def test_simple_select_attr(self, env): class User(object): def __init__(self, name, is_active): self.name = name @@ -489,11 +505,13 @@ class FilterTestCase(JinjaTestCase): User('jane', True), User('mike', False), ] - tmpl = env.from_string('{{ users|selectattr("is_active")|' - 'map(attribute="name")|join("|") }}') - self.assertEqual(tmpl.render(users=users), 'john|jane') + tmpl = env.from_string( + '{{ users|selectattr("is_active")|' + 'map(attribute="name")|join("|") }}' + ) + assert tmpl.render(users=users) == 'john|jane' - def test_simple_reject_attr(self): + def test_simple_reject_attr(self, env): class User(object): def __init__(self, name, is_active): self.name = name @@ -505,10 +523,10 @@ class FilterTestCase(JinjaTestCase): User('mike', False), ] tmpl = env.from_string('{{ users|rejectattr("is_active")|' - 'map(attribute="name")|join("|") }}') - self.assertEqual(tmpl.render(users=users), 'mike') + 'map(attribute="name")|join("|") }}') + assert tmpl.render(users=users) == 'mike' - def test_func_select_attr(self): + def test_func_select_attr(self, env): class User(object): def __init__(self, id, name): self.id = id @@ -520,10 +538,10 @@ class FilterTestCase(JinjaTestCase): User(3, 'mike'), ] tmpl = env.from_string('{{ users|selectattr("id", "odd")|' - 'map(attribute="name")|join("|") }}') - self.assertEqual(tmpl.render(users=users), 'john|mike') + 'map(attribute="name")|join("|") }}') + assert tmpl.render(users=users) == 'john|mike' - def test_func_reject_attr(self): + def test_func_reject_attr(self, env): class User(object): def __init__(self, id, name): self.id = id @@ -535,11 +553,5 @@ class FilterTestCase(JinjaTestCase): User(3, 'mike'), ] tmpl = env.from_string('{{ users|rejectattr("id", "odd")|' - 'map(attribute="name")|join("|") }}') - self.assertEqual(tmpl.render(users=users), 'jane') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(FilterTestCase)) - return suite + 'map(attribute="name")|join("|") }}') + assert tmpl.render(users=users) == 'jane' diff --git a/jinja2/testsuite/imports.py b/jinja2/testsuite/test_imports.py similarity index 73% rename from jinja2/testsuite/imports.py rename to jinja2/testsuite/test_imports.py index 3db9008d..643c995c 100644 --- a/jinja2/testsuite/imports.py +++ b/jinja2/testsuite/test_imports.py @@ -8,46 +8,56 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD, see LICENSE for more details. """ -import unittest - -from jinja2.testsuite import JinjaTestCase +import pytest from jinja2 import Environment, DictLoader from jinja2.exceptions import TemplateNotFound, TemplatesNotFound -test_env = Environment(loader=DictLoader(dict( - module='{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}', - header='[{{ foo }}|{{ 23 }}]', - o_printer='({{ o }})' -))) -test_env.globals['bar'] = 23 +@pytest.fixture +def test_env(): + env = Environment(loader=DictLoader(dict( + module='{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}', + header='[{{ foo }}|{{ 23 }}]', + o_printer='({{ o }})' + ))) + env.globals['bar'] = 23 + return env -class ImportsTestCase(JinjaTestCase): +@pytest.mark.imports +class TestImports(): - def test_context_imports(self): + def test_context_imports(self, test_env): t = test_env.from_string('{% import "module" as m %}{{ m.test() }}') assert t.render(foo=42) == '[|23]' - t = test_env.from_string('{% import "module" as m without context %}{{ m.test() }}') + t = test_env.from_string( + '{% import "module" as m without context %}{{ m.test() }}' + ) assert t.render(foo=42) == '[|23]' - t = test_env.from_string('{% import "module" as m with context %}{{ m.test() }}') + t = test_env.from_string( + '{% import "module" as m with context %}{{ m.test() }}' + ) assert t.render(foo=42) == '[42|23]' t = test_env.from_string('{% from "module" import test %}{{ test() }}') assert t.render(foo=42) == '[|23]' - t = test_env.from_string('{% from "module" import test without context %}{{ test() }}') + t = test_env.from_string( + '{% from "module" import test without context %}{{ test() }}' + ) assert t.render(foo=42) == '[|23]' - t = test_env.from_string('{% from "module" import test with context %}{{ test() }}') + t = test_env.from_string( + '{% from "module" import test with context %}{{ test() }}' + ) assert t.render(foo=42) == '[42|23]' - def test_trailing_comma(self): + def test_trailing_comma(self, test_env): test_env.from_string('{% from "foo" import bar, baz with context %}') test_env.from_string('{% from "foo" import bar, baz, with context %}') test_env.from_string('{% from "foo" import bar, with context %}') test_env.from_string('{% from "foo" import bar, with, context %}') test_env.from_string('{% from "foo" import bar, with with context %}') - def test_exports(self): + def test_exports(self, test_env): m = test_env.from_string(''' {% macro toplevel() %}...{% endmacro %} {% macro __private() %}...{% endmacro %} @@ -62,9 +72,11 @@ class ImportsTestCase(JinjaTestCase): assert not hasattr(m, 'notthere') -class IncludesTestCase(JinjaTestCase): +@pytest.mark.imports +@pytest.mark.includes +class TestIncludes(): - def test_context_include(self): + def test_context_include(self, test_env): t = test_env.from_string('{% include "header" %}') assert t.render(foo=42) == '[42|23]' t = test_env.from_string('{% include "header" with context %}') @@ -72,15 +84,17 @@ class IncludesTestCase(JinjaTestCase): t = test_env.from_string('{% include "header" without context %}') assert t.render(foo=42) == '[|23]' - def test_choice_includes(self): + def test_choice_includes(self, test_env): t = test_env.from_string('{% include ["missing", "header"] %}') assert t.render(foo=42) == '[42|23]' - t = test_env.from_string('{% include ["missing", "missing2"] ignore missing %}') + t = test_env.from_string( + '{% include ["missing", "missing2"] ignore missing %}' + ) assert t.render(foo=42) == '' t = test_env.from_string('{% include ["missing", "missing2"] %}') - self.assert_raises(TemplateNotFound, t.render) + pytest.raises(TemplateNotFound, t.render) try: t.render() except TemplatesNotFound as e: @@ -106,22 +120,22 @@ class IncludesTestCase(JinjaTestCase): t = test_env.from_string('{% include [x] %}') test_includes(t, x='header') - def test_include_ignoring_missing(self): + def test_include_ignoring_missing(self, test_env): t = test_env.from_string('{% include "missing" %}') - self.assert_raises(TemplateNotFound, t.render) + pytest.raises(TemplateNotFound, t.render) for extra in '', 'with context', 'without context': t = test_env.from_string('{% include "missing" ignore missing ' + extra + ' %}') assert t.render() == '' - def test_context_include_with_overrides(self): + def test_context_include_with_overrides(self, test_env): env = Environment(loader=DictLoader(dict( main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}", item="{{ item }}" ))) assert env.get_template("main").render() == "123" - def test_unoptimized_scopes(self): + def test_unoptimized_scopes(self, test_env): t = test_env.from_string(""" {% macro outer(o) %} {% macro inner() %} @@ -132,10 +146,3 @@ class IncludesTestCase(JinjaTestCase): {{ outer("FOO") }} """) assert t.render().strip() == '(FOO)' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ImportsTestCase)) - suite.addTest(unittest.makeSuite(IncludesTestCase)) - return suite diff --git a/jinja2/testsuite/inheritance.py b/jinja2/testsuite/test_inheritance.py similarity index 81% rename from jinja2/testsuite/inheritance.py rename to jinja2/testsuite/test_inheritance.py index e0f51cda..1cb73904 100644 --- a/jinja2/testsuite/inheritance.py +++ b/jinja2/testsuite/test_inheritance.py @@ -8,9 +8,7 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD, see LICENSE for more details. """ -import unittest - -from jinja2.testsuite import JinjaTestCase +import pytest from jinja2 import Environment, DictLoader, TemplateError @@ -66,45 +64,48 @@ DOUBLEEXTENDS = '''\ ''' -env = Environment(loader=DictLoader({ - 'layout': LAYOUTTEMPLATE, - 'level1': LEVEL1TEMPLATE, - 'level2': LEVEL2TEMPLATE, - 'level3': LEVEL3TEMPLATE, - 'level4': LEVEL4TEMPLATE, - 'working': WORKINGTEMPLATE, - 'doublee': DOUBLEEXTENDS, -}), trim_blocks=True) +@pytest.fixture +def env(): + return Environment(loader=DictLoader({ + 'layout': LAYOUTTEMPLATE, + 'level1': LEVEL1TEMPLATE, + 'level2': LEVEL2TEMPLATE, + 'level3': LEVEL3TEMPLATE, + 'level4': LEVEL4TEMPLATE, + 'working': WORKINGTEMPLATE, + 'doublee': DOUBLEEXTENDS, + }), trim_blocks=True) -class InheritanceTestCase(JinjaTestCase): +@pytest.mark.inheritance +class TestInheritance(): - def test_layout(self): + def test_layout(self, env): tmpl = env.get_template('layout') assert tmpl.render() == ('|block 1 from layout|block 2 from ' 'layout|nested block 4 from layout|') - def test_level1(self): + def test_level1(self, env): tmpl = env.get_template('level1') assert tmpl.render() == ('|block 1 from level1|block 2 from ' 'layout|nested block 4 from layout|') - def test_level2(self): + def test_level2(self, env): tmpl = env.get_template('level2') assert tmpl.render() == ('|block 1 from level1|nested block 5 from ' 'level2|nested block 4 from layout|') - def test_level3(self): + def test_level3(self, env): tmpl = env.get_template('level3') assert tmpl.render() == ('|block 1 from level1|block 5 from level3|' 'block 4 from level3|') - def test_level4(sel): + def test_level4(self, env): tmpl = env.get_template('level4') assert tmpl.render() == ('|block 1 from level1|block 5 from ' 'level3|block 3 from level4|') - def test_super(self): + def test_super(self, env): env = Environment(loader=DictLoader({ 'a': '{% block intro %}INTRO{% endblock %}|' 'BEFORE|{% block data %}INNER{% endblock %}|AFTER', @@ -117,23 +118,24 @@ class InheritanceTestCase(JinjaTestCase): tmpl = env.get_template('c') assert tmpl.render() == '--INTRO--|BEFORE|[(INNER)]|AFTER' - def test_working(self): + def test_working(self, env): tmpl = env.get_template('working') - def test_reuse_blocks(self): + def test_reuse_blocks(self, env): tmpl = env.from_string('{{ self.foo() }}|{% block foo %}42' '{% endblock %}|{{ self.foo() }}') assert tmpl.render() == '42|42|42' - def test_preserve_blocks(self): + def test_preserve_blocks(self, env): env = Environment(loader=DictLoader({ - 'a': '{% if false %}{% block x %}A{% endblock %}{% endif %}{{ self.x() }}', + 'a': '{% if false %}{% block x %}A{% endblock %}' + '{% endif %}{{ self.x() }}', 'b': '{% extends "a" %}{% block x %}B{{ super() }}{% endblock %}' })) tmpl = env.get_template('b') assert tmpl.render() == 'BA' - def test_dynamic_inheritance(self): + def test_dynamic_inheritance(self, env): env = Environment(loader=DictLoader({ 'master1': 'MASTER1{% block x %}{% endblock %}', 'master2': 'MASTER2{% block x %}{% endblock %}', @@ -143,19 +145,20 @@ class InheritanceTestCase(JinjaTestCase): for m in range(1, 3): assert tmpl.render(master='master%d' % m) == 'MASTER%dCHILD' % m - def test_multi_inheritance(self): + def test_multi_inheritance(self, env): env = Environment(loader=DictLoader({ 'master1': 'MASTER1{% block x %}{% endblock %}', 'master2': 'MASTER2{% block x %}{% endblock %}', - 'child': '''{% if master %}{% extends master %}{% else %}{% extends - 'master1' %}{% endif %}{% block x %}CHILD{% endblock %}''' + 'child': + '''{% if master %}{% extends master %}{% else %}{% extends + 'master1' %}{% endif %}{% block x %}CHILD{% endblock %}''' })) tmpl = env.get_template('child') assert tmpl.render(master='master2') == 'MASTER2CHILD' assert tmpl.render(master='master1') == 'MASTER1CHILD' assert tmpl.render() == 'MASTER1CHILD' - def test_scoped_block(self): + def test_scoped_block(self, env): env = Environment(loader=DictLoader({ 'master.html': '{% for item in seq %}[{% block item scoped %}' '{% endblock %}]{% endfor %}' @@ -164,7 +167,7 @@ class InheritanceTestCase(JinjaTestCase): '{{ item }}{% endblock %}') assert t.render(seq=list(range(5))) == '[0][1][2][3][4]' - def test_super_in_scoped_block(self): + def test_super_in_scoped_block(self, env): env = Environment(loader=DictLoader({ 'master.html': '{% for item in seq %}[{% block item scoped %}' '{{ item }}{% endblock %}]{% endfor %}' @@ -173,7 +176,7 @@ class InheritanceTestCase(JinjaTestCase): '{{ super() }}|{{ item * 2 }}{% endblock %}') assert t.render(seq=list(range(5))) == '[0|0][1|2][2|4][3|6][4|8]' - def test_scoped_block_after_inheritance(self): + def test_scoped_block_after_inheritance(self, env): env = Environment(loader=DictLoader({ 'layout.html': ''' {% block useless %}{% endblock %} @@ -197,9 +200,10 @@ class InheritanceTestCase(JinjaTestCase): assert rv == ['43', '44', '45'] -class BugFixTestCase(JinjaTestCase): +@pytest.mark.inheritance +class TestBugFix(): - def test_fixed_macro_scoping_bug(self): + def test_fixed_macro_scoping_bug(self, env): assert Environment(loader=DictLoader({ 'test.html': '''\ {% extends 'details.html' %} @@ -231,9 +235,10 @@ class BugFixTestCase(JinjaTestCase): 'standard.html': ''' {% block content %} {% endblock %} ''' - })).get_template("test.html").render().split() == [u'outer_box', u'my_macro'] + })).get_template("test.html").render().split() \ + == [u'outer_box', u'my_macro'] - def test_double_extends(self): + def test_double_extends(self, env): """Ensures that a template with more than 1 {% extends ... %} usage raises a ``TemplateError``. """ @@ -241,10 +246,3 @@ class BugFixTestCase(JinjaTestCase): tmpl = env.get_template('doublee') except Exception as e: assert isinstance(e, TemplateError) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(InheritanceTestCase)) - suite.addTest(unittest.makeSuite(BugFixTestCase)) - return suite diff --git a/jinja2/testsuite/lexnparse.py b/jinja2/testsuite/test_lexnparse.py similarity index 69% rename from jinja2/testsuite/lexnparse.py rename to jinja2/testsuite/test_lexnparse.py index 8ca0b7c8..ff334bf0 100644 --- a/jinja2/testsuite/lexnparse.py +++ b/jinja2/testsuite/test_lexnparse.py @@ -8,9 +8,7 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD, see LICENSE for more details. """ -import unittest - -from jinja2.testsuite import JinjaTestCase +import pytest from jinja2 import Environment, Template, TemplateSyntaxError, \ UndefinedError, nodes @@ -18,8 +16,6 @@ from jinja2._compat import iteritems, text_type, PY2 from jinja2.lexer import Token, TokenStream, TOKEN_EOF, \ TOKEN_BLOCK_BEGIN, TOKEN_BLOCK_END -env = Environment() - # how does a string look like in jinja syntax? if PY2: @@ -29,12 +25,14 @@ else: jinja_string_repr = repr -class TokenStreamTestCase(JinjaTestCase): +@pytest.mark.lexnparse +@pytest.mark.tokenstream +class TestTokenStream(): test_tokens = [Token(1, TOKEN_BLOCK_BEGIN, ''), Token(2, TOKEN_BLOCK_END, ''), - ] + ] - def test_simple(self): + def test_simple(self, env): ts = TokenStream(self.test_tokens, "foo", "bar") assert ts.current.type is TOKEN_BLOCK_BEGIN assert bool(ts) @@ -48,29 +46,35 @@ class TokenStreamTestCase(JinjaTestCase): assert not bool(ts) assert bool(ts.eos) - def test_iter(self): - token_types = [t.type for t in TokenStream(self.test_tokens, "foo", "bar")] + def test_iter(self, env): + token_types = [ + t.type for t in TokenStream(self.test_tokens, "foo", "bar") + ] assert token_types == ['block_begin', 'block_end', ] -class LexerTestCase(JinjaTestCase): +@pytest.mark.lexnparse +@pytest.mark.lexer +class TestLexer(): - def test_raw1(self): - tmpl = env.from_string('{% raw %}foo{% endraw %}|' - '{%raw%}{{ bar }}|{% baz %}{% endraw %}') + def test_raw1(self, env): + tmpl = env.from_string( + '{% raw %}foo{% endraw %}|' + '{%raw%}{{ bar }}|{% baz %}{% endraw %}') assert tmpl.render() == 'foo|{{ bar }}|{% baz %}' - def test_raw2(self): + def test_raw2(self, env): tmpl = env.from_string('1 {%- raw -%} 2 {%- endraw -%} 3') assert tmpl.render() == '123' - def test_balancing(self): + def test_balancing(self, env): env = Environment('{%', '%}', '${', '}') tmpl = env.from_string('''{% for item in seq %}${{'foo': item}|upper}{% endfor %}''') - assert tmpl.render(seq=list(range(3))) == "{'FOO': 0}{'FOO': 1}{'FOO': 2}" + assert tmpl.render(seq=list(range(3))) \ + == "{'FOO': 0}{'FOO': 1}{'FOO': 2}" - def test_comments(self): + def test_comments(self, env): env = Environment('', '{', '}') tmpl = env.from_string('''\
    @@ -78,21 +82,21 @@ class LexerTestCase(JinjaTestCase):
  • {item}
''') - assert tmpl.render(seq=list(range(3))) == ("
    \n
  • 0
  • \n " - "
  • 1
  • \n
  • 2
  • \n
") + assert tmpl.render(seq=list(range(3))) \ + == ("
    \n
  • 0
  • \n ""
  • 1
  • \n
  • 2
  • \n
") - def test_string_escapes(self): + def test_string_escapes(self, env): for char in u'\0', u'\u2668', u'\xe4', u'\t', u'\r', u'\n': tmpl = env.from_string('{{ %s }}' % jinja_string_repr(char)) assert tmpl.render() == char assert env.from_string('{{ "\N{HOT SPRINGS}" }}').render() == u'\u2668' - def test_bytefallback(self): + def test_bytefallback(self, env): from pprint import pformat tmpl = env.from_string(u'''{{ 'foo'|pprint }}|{{ 'bär'|pprint }}''') assert tmpl.render() == pformat('foo') + '|' + pformat(u'bär') - def test_operators(self): + def test_operators(self, env): from jinja2.lexer import operators for test, expect in iteritems(operators): if test in '([{}])': @@ -101,17 +105,17 @@ class LexerTestCase(JinjaTestCase): next(stream) assert stream.current.type == expect - def test_normalizing(self): + def test_normalizing(self, env): for seq in '\r', '\r\n', '\n': env = Environment(newline_sequence=seq) tmpl = env.from_string('1\n2\r\n3\n4\n') result = tmpl.render() assert result.replace(seq, 'X') == '1X2X3X4' - def test_trailing_newline(self): + def test_trailing_newline(self, env): for keep in [True, False]: env = Environment(keep_trailing_newline=keep) - for template,expected in [ + for template, expected in [ ('', {}), ('no\nnewline', {}), ('with\nnewline\n', {False: 'with\nnewline'}), @@ -122,9 +126,12 @@ class LexerTestCase(JinjaTestCase): result = tmpl.render() assert result == expect, (keep, template, result, expect) -class ParserTestCase(JinjaTestCase): - def test_php_syntax(self): +@pytest.mark.lexnparse +@pytest.mark.parser +class TestParser(): + + def test_php_syntax(self, env): env = Environment('', '', '') tmpl = env.from_string('''\ \ @@ -133,7 +140,7 @@ class ParserTestCase(JinjaTestCase): ''') assert tmpl.render(seq=list(range(5))) == '01234' - def test_erb_syntax(self): + def test_erb_syntax(self, env): env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>') tmpl = env.from_string('''\ <%# I'm a comment, I'm not interesting %>\ @@ -142,7 +149,7 @@ class ParserTestCase(JinjaTestCase): <%- endfor %>''') assert tmpl.render(seq=list(range(5))) == '01234' - def test_comment_syntax(self): + def test_comment_syntax(self, env): env = Environment('', '${', '}', '') tmpl = env.from_string('''\ \ @@ -151,26 +158,27 @@ class ParserTestCase(JinjaTestCase): ''') assert tmpl.render(seq=list(range(5))) == '01234' - def test_balancing(self): + def test_balancing(self, env): tmpl = env.from_string('''{{{'foo':'bar'}.foo}}''') assert tmpl.render() == 'bar' - def test_start_comment(self): + def test_start_comment(self, env): tmpl = env.from_string('''{# foo comment and bar comment #} {% macro blub() %}foo{% endmacro %} {{ blub() }}''') assert tmpl.render().strip() == 'foo' - def test_line_syntax(self): + def test_line_syntax(self, env): env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%') tmpl = env.from_string('''\ <%# regular comment %> % for item in seq: ${item} % endfor''') - assert [int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()] == \ - list(range(5)) + assert [ + int(x.strip()) for x in tmpl.render(seq=list(range(5))).split() + ] == list(range(5)) env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##') tmpl = env.from_string('''\ @@ -178,10 +186,11 @@ and bar comment #} % for item in seq: ${item} ## the rest of the stuff % endfor''') - assert [int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()] == \ - list(range(5)) + assert [ + int(x.strip()) for x in tmpl.render(seq=list(range(5))).split() + ] == list(range(5)) - def test_line_syntax_priority(self): + def test_line_syntax_priority(self, env): # XXX: why is the whitespace there in front of the newline? env = Environment('{%', '%}', '${', '}', '/*', '*/', '##', '#') tmpl = env.from_string('''\ @@ -201,7 +210,7 @@ and bar comment #} # endfor''') assert tmpl.render(seq=[1, 2]).strip() == '* 1\n\n* 2' - def test_error_messages(self): + def test_error_messages(self, env): def assert_error(code, expected): try: Template(code) @@ -214,10 +223,11 @@ and bar comment #} "Encountered unknown tag 'endif'. Jinja was looking " "for the following tags: 'endfor' or 'else'. The " "innermost block that needs to be closed is 'for'.") - assert_error('{% if foo %}{% for item in seq %}...{% endfor %}{% endfor %}', - "Encountered unknown tag 'endfor'. Jinja was looking for " - "the following tags: 'elif' or 'else' or 'endif'. The " - "innermost block that needs to be closed is 'if'.") + assert_error( + '{% if foo %}{% for item in seq %}...{% endfor %}{% endfor %}', + "Encountered unknown tag 'endfor'. Jinja was looking for " + "the following tags: 'elif' or 'else' or 'endif'. The " + "innermost block that needs to be closed is 'if'.") assert_error('{% if foo %}', "Unexpected end of template. Jinja was looking for the " "following tags: 'elif' or 'else' or 'endif'. The " @@ -226,95 +236,101 @@ and bar comment #} "Unexpected end of template. Jinja was looking for the " "following tags: 'endfor' or 'else'. The innermost block " "that needs to be closed is 'for'.") - assert_error('{% block foo-bar-baz %}', - "Block names in Jinja have to be valid Python identifiers " - "and may not contain hyphens, use an underscore instead.") + assert_error( + '{% block foo-bar-baz %}', + "Block names in Jinja have to be valid Python identifiers " + "and may not contain hyphens, use an underscore instead.") assert_error('{% unknown_tag %}', "Encountered unknown tag 'unknown_tag'.") -class SyntaxTestCase(JinjaTestCase): +@pytest.mark.lexnparse +@pytest.mark.syntax +class TestSyntax(): - def test_call(self): + def test_call(self, env): env = Environment() env.globals['foo'] = lambda a, b, c, e, g: a + b + c + e + g - tmpl = env.from_string("{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}") + tmpl = env.from_string( + "{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}" + ) assert tmpl.render() == 'abdfh' - def test_slicing(self): + def test_slicing(self, env): tmpl = env.from_string('{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}') assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]' - def test_attr(self): + def test_attr(self, env): tmpl = env.from_string("{{ foo.bar }}|{{ foo['bar'] }}") assert tmpl.render(foo={'bar': 42}) == '42|42' - def test_subscript(self): + def test_subscript(self, env): tmpl = env.from_string("{{ foo[0] }}|{{ foo[-1] }}") assert tmpl.render(foo=[0, 1, 2]) == '0|2' - def test_tuple(self): + def test_tuple(self, env): tmpl = env.from_string('{{ () }}|{{ (1,) }}|{{ (1, 2) }}') assert tmpl.render() == '()|(1,)|(1, 2)' - def test_math(self): + def test_math(self, env): tmpl = env.from_string('{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}') assert tmpl.render() == '1.5|8' - def test_div(self): + def test_div(self, env): tmpl = env.from_string('{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}') assert tmpl.render() == '1|1.5|1' - def test_unary(self): + def test_unary(self, env): tmpl = env.from_string('{{ +3 }}|{{ -3 }}') assert tmpl.render() == '3|-3' - def test_concat(self): + def test_concat(self, env): tmpl = env.from_string("{{ [1, 2] ~ 'foo' }}") assert tmpl.render() == '[1, 2]foo' - def test_compare(self): + def test_compare(self, env): tmpl = env.from_string('{{ 1 > 0 }}|{{ 1 >= 1 }}|{{ 2 < 3 }}|' '{{ 2 == 2 }}|{{ 1 <= 1 }}') assert tmpl.render() == 'True|True|True|True|True' - def test_inop(self): + def test_inop(self, env): tmpl = env.from_string('{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}') assert tmpl.render() == 'True|False' - def test_literals(self): + def test_literals(self, env): tmpl = env.from_string('{{ [] }}|{{ {} }}|{{ () }}') assert tmpl.render().lower() == '[]|{}|()' - def test_bool(self): + def test_bool(self, env): tmpl = env.from_string('{{ true and false }}|{{ false ' 'or true }}|{{ not false }}') assert tmpl.render() == 'False|True|True' - def test_grouping(self): - tmpl = env.from_string('{{ (true and false) or (false and true) and not false }}') + def test_grouping(self, env): + tmpl = env.from_string( + '{{ (true and false) or (false and true) and not false }}') assert tmpl.render() == 'False' - def test_django_attr(self): + def test_django_attr(self, env): tmpl = env.from_string('{{ [1, 2, 3].0 }}|{{ [[1]].0.0 }}') assert tmpl.render() == '1|1' - def test_conditional_expression(self): + def test_conditional_expression(self, env): tmpl = env.from_string('''{{ 0 if true else 1 }}''') assert tmpl.render() == '0' - def test_short_conditional_expression(self): + def test_short_conditional_expression(self, env): tmpl = env.from_string('<{{ 1 if false }}>') assert tmpl.render() == '<>' tmpl = env.from_string('<{{ (1 if false).bar }}>') - self.assert_raises(UndefinedError, tmpl.render) + pytest.raises(UndefinedError, tmpl.render) - def test_filter_priority(self): + def test_filter_priority(self, env): tmpl = env.from_string('{{ "foo"|upper + "bar"|upper }}') assert tmpl.render() == 'FOOBAR' - def test_function_calls(self): + def test_function_calls(self, env): tests = [ (True, '*foo, bar'), (True, '*foo, *bar'), @@ -329,12 +345,12 @@ class SyntaxTestCase(JinjaTestCase): ] for should_fail, sig in tests: if should_fail: - self.assert_raises(TemplateSyntaxError, - env.from_string, '{{ foo(%s) }}' % sig) + pytest.raises(TemplateSyntaxError, + env.from_string, '{{ foo(%s) }}' % sig) else: env.from_string('foo(%s)' % sig) - def test_tuple_expr(self): + def test_tuple_expr(self, env): for tmpl in [ '{{ () }}', '{{ (1, 2) }}', @@ -347,169 +363,175 @@ class SyntaxTestCase(JinjaTestCase): ]: assert env.from_string(tmpl) - def test_trailing_comma(self): + def test_trailing_comma(self, env): tmpl = env.from_string('{{ (1, 2,) }}|{{ [1, 2,] }}|{{ {1: 2,} }}') assert tmpl.render().lower() == '(1, 2)|[1, 2]|{1: 2}' - def test_block_end_name(self): + def test_block_end_name(self, env): env.from_string('{% block foo %}...{% endblock foo %}') - self.assert_raises(TemplateSyntaxError, env.from_string, - '{% block x %}{% endblock y %}') + pytest.raises(TemplateSyntaxError, env.from_string, + '{% block x %}{% endblock y %}') - def test_constant_casing(self): + def test_constant_casing(self, env): for const in True, False, None: tmpl = env.from_string('{{ %s }}|{{ %s }}|{{ %s }}' % ( str(const), str(const).lower(), str(const).upper() )) assert tmpl.render() == '%s|%s|' % (const, const) - def test_test_chaining(self): - self.assert_raises(TemplateSyntaxError, env.from_string, - '{{ foo is string is sequence }}') - assert env.from_string('{{ 42 is string or 42 is number }}' - ).render() == 'True' + def test_test_chaining(self, env): + pytest.raises(TemplateSyntaxError, env.from_string, + '{{ foo is string is sequence }}') + assert env.from_string( + '{{ 42 is string or 42 is number }}' + ).render() == 'True' - def test_string_concatenation(self): + def test_string_concatenation(self, env): tmpl = env.from_string('{{ "foo" "bar" "baz" }}') assert tmpl.render() == 'foobarbaz' - def test_notin(self): + def test_notin(self, env): bar = range(100) tmpl = env.from_string('''{{ not 42 in bar }}''') assert tmpl.render(bar=bar) == text_type(not 42 in bar) - def test_implicit_subscribed_tuple(self): + def test_implicit_subscribed_tuple(self, env): class Foo(object): def __getitem__(self, x): return x t = env.from_string('{{ foo[1, 2] }}') assert t.render(foo=Foo()) == u'(1, 2)' - def test_raw2(self): + def test_raw2(self, env): tmpl = env.from_string('{% raw %}{{ FOO }} and {% BAR %}{% endraw %}') assert tmpl.render() == '{{ FOO }} and {% BAR %}' - def test_const(self): - tmpl = env.from_string('{{ true }}|{{ false }}|{{ none }}|' - '{{ none is defined }}|{{ missing is defined }}') + def test_const(self, env): + tmpl = env.from_string( + '{{ true }}|{{ false }}|{{ none }}|' + '{{ none is defined }}|{{ missing is defined }}') assert tmpl.render() == 'True|False|None|True|False' - def test_neg_filter_priority(self): + def test_neg_filter_priority(self, env): node = env.parse('{{ -1|foo }}') assert isinstance(node.body[0].nodes[0], nodes.Filter) assert isinstance(node.body[0].nodes[0].node, nodes.Neg) - def test_const_assign(self): + def test_const_assign(self, env): constass1 = '''{% set true = 42 %}''' constass2 = '''{% for none in seq %}{% endfor %}''' for tmpl in constass1, constass2: - self.assert_raises(TemplateSyntaxError, env.from_string, tmpl) + pytest.raises(TemplateSyntaxError, env.from_string, tmpl) - def test_localset(self): + def test_localset(self, env): tmpl = env.from_string('''{% set foo = 0 %}\ {% for item in [1, 2] %}{% set foo = 1 %}{% endfor %}\ {{ foo }}''') assert tmpl.render() == '0' - def test_parse_unary(self): + def test_parse_unary(self, env): tmpl = env.from_string('{{ -foo["bar"] }}') assert tmpl.render(foo={'bar': 42}) == '-42' tmpl = env.from_string('{{ -foo["bar"]|abs }}') assert tmpl.render(foo={'bar': 42}) == '42' -class LstripBlocksTestCase(JinjaTestCase): +@pytest.mark.lexnparse +@pytest.mark.lstripblocks +class TestLstripBlocks(): - def test_lstrip(self): + def test_lstrip(self, env): env = Environment(lstrip_blocks=True, trim_blocks=False) tmpl = env.from_string(''' {% if True %}\n {% endif %}''') assert tmpl.render() == "\n" - def test_lstrip_trim(self): + def test_lstrip_trim(self, env): env = Environment(lstrip_blocks=True, trim_blocks=True) tmpl = env.from_string(''' {% if True %}\n {% endif %}''') assert tmpl.render() == "" - def test_no_lstrip(self): + def test_no_lstrip(self, env): env = Environment(lstrip_blocks=True, trim_blocks=False) tmpl = env.from_string(''' {%+ if True %}\n {%+ endif %}''') assert tmpl.render() == " \n " - def test_lstrip_endline(self): + def test_lstrip_endline(self, env): env = Environment(lstrip_blocks=True, trim_blocks=False) - tmpl = env.from_string(''' hello{% if True %}\n goodbye{% endif %}''') + tmpl = env.from_string( + ''' hello{% if True %}\n goodbye{% endif %}''') assert tmpl.render() == " hello\n goodbye" - def test_lstrip_inline(self): + def test_lstrip_inline(self, env): env = Environment(lstrip_blocks=True, trim_blocks=False) tmpl = env.from_string(''' {% if True %}hello {% endif %}''') assert tmpl.render() == 'hello ' - def test_lstrip_nested(self): + def test_lstrip_nested(self, env): env = Environment(lstrip_blocks=True, trim_blocks=False) - tmpl = env.from_string(''' {% if True %}a {% if True %}b {% endif %}c {% endif %}''') + tmpl = env.from_string( + ''' {% if True %}a {% if True %}b {% endif %}c {% endif %}''') assert tmpl.render() == 'a b c ' - def test_lstrip_left_chars(self): + def test_lstrip_left_chars(self, env): env = Environment(lstrip_blocks=True, trim_blocks=False) tmpl = env.from_string(''' abc {% if True %} hello{% endif %}''') assert tmpl.render() == ' abc \n hello' - def test_lstrip_embeded_strings(self): + def test_lstrip_embeded_strings(self, env): env = Environment(lstrip_blocks=True, trim_blocks=False) tmpl = env.from_string(''' {% set x = " {% str %} " %}{{ x }}''') assert tmpl.render() == ' {% str %} ' - def test_lstrip_preserve_leading_newlines(self): + def test_lstrip_preserve_leading_newlines(self, env): env = Environment(lstrip_blocks=True, trim_blocks=False) tmpl = env.from_string('''\n\n\n{% set hello = 1 %}''') assert tmpl.render() == '\n\n\n' - - def test_lstrip_comment(self): + + def test_lstrip_comment(self, env): env = Environment(lstrip_blocks=True, trim_blocks=False) tmpl = env.from_string(''' {# if True #} hello {#endif#}''') assert tmpl.render() == '\nhello\n' - def test_lstrip_angle_bracket_simple(self): + def test_lstrip_angle_bracket_simple(self, env): env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##', - lstrip_blocks=True, trim_blocks=True) + lstrip_blocks=True, trim_blocks=True) tmpl = env.from_string(''' <% if True %>hello <% endif %>''') assert tmpl.render() == 'hello ' - def test_lstrip_angle_bracket_comment(self): + def test_lstrip_angle_bracket_comment(self, env): env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##', - lstrip_blocks=True, trim_blocks=True) + lstrip_blocks=True, trim_blocks=True) tmpl = env.from_string(''' <%# if True %>hello <%# endif %>''') assert tmpl.render() == 'hello ' - def test_lstrip_angle_bracket(self): + def test_lstrip_angle_bracket(self, env): env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##', - lstrip_blocks=True, trim_blocks=True) + lstrip_blocks=True, trim_blocks=True) tmpl = env.from_string('''\ <%# regular comment %> <% for item in seq %> ${item} ## the rest of the stuff <% endfor %>''') assert tmpl.render(seq=range(5)) == \ - ''.join('%s\n' % x for x in range(5)) - - def test_lstrip_angle_bracket_compact(self): + ''.join('%s\n' % x for x in range(5)) + + def test_lstrip_angle_bracket_compact(self, env): env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##', - lstrip_blocks=True, trim_blocks=True) + lstrip_blocks=True, trim_blocks=True) tmpl = env.from_string('''\ <%#regular comment%> <%for item in seq%> ${item} ## the rest of the stuff <%endfor%>''') assert tmpl.render(seq=range(5)) == \ - ''.join('%s\n' % x for x in range(5)) - - def test_php_syntax_with_manual(self): + ''.join('%s\n' % x for x in range(5)) + + def test_php_syntax_with_manual(self, env): env = Environment('', '', '', - lstrip_blocks=True, trim_blocks=True) + lstrip_blocks=True, trim_blocks=True) tmpl = env.from_string('''\ @@ -517,45 +539,48 @@ ${item} ## the rest of the stuff ''') assert tmpl.render(seq=range(5)) == '01234' - def test_php_syntax(self): + def test_php_syntax(self, env): env = Environment('', '', '', - lstrip_blocks=True, trim_blocks=True) + lstrip_blocks=True, trim_blocks=True) tmpl = env.from_string('''\ ''') - assert tmpl.render(seq=range(5)) == ''.join(' %s\n' % x for x in range(5)) + assert tmpl.render(seq=range(5)) \ + == ''.join(' %s\n' % x for x in range(5)) - def test_php_syntax_compact(self): + def test_php_syntax_compact(self, env): env = Environment('', '', '', - lstrip_blocks=True, trim_blocks=True) + lstrip_blocks=True, trim_blocks=True) tmpl = env.from_string('''\ ''') - assert tmpl.render(seq=range(5)) == ''.join(' %s\n' % x for x in range(5)) + assert tmpl.render(seq=range(5)) \ + == ''.join(' %s\n' % x for x in range(5)) - def test_erb_syntax(self): + def test_erb_syntax(self, env): env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>', - lstrip_blocks=True, trim_blocks=True) - #env.from_string('') - #for n,r in env.lexer.rules.iteritems(): + lstrip_blocks=True, trim_blocks=True) + # env.from_string('') + # for n,r in env.lexer.rules.iteritems(): # print n - #print env.lexer.rules['root'][0][0].pattern - #print "'%s'" % tmpl.render(seq=range(5)) + # print env.lexer.rules['root'][0][0].pattern + # print "'%s'" % tmpl.render(seq=range(5)) tmpl = env.from_string('''\ <%# I'm a comment, I'm not interesting %> <% for item in seq %> <%= item %> <% endfor %> ''') - assert tmpl.render(seq=range(5)) == ''.join(' %s\n' % x for x in range(5)) + assert tmpl.render(seq=range(5)) \ + == ''.join(' %s\n' % x for x in range(5)) - def test_erb_syntax_with_manual(self): + def test_erb_syntax_with_manual(self, env): env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>', - lstrip_blocks=True, trim_blocks=True) + lstrip_blocks=True, trim_blocks=True) tmpl = env.from_string('''\ <%# I'm a comment, I'm not interesting %> <% for item in seq -%> @@ -563,9 +588,9 @@ ${item} ## the rest of the stuff <%- endfor %>''') assert tmpl.render(seq=range(5)) == '01234' - def test_erb_syntax_no_lstrip(self): + def test_erb_syntax_no_lstrip(self, env): env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>', - lstrip_blocks=True, trim_blocks=True) + lstrip_blocks=True, trim_blocks=True) tmpl = env.from_string('''\ <%# I'm a comment, I'm not interesting %> <%+ for item in seq -%> @@ -573,21 +598,12 @@ ${item} ## the rest of the stuff <%- endfor %>''') assert tmpl.render(seq=range(5)) == ' 01234' - def test_comment_syntax(self): + def test_comment_syntax(self, env): env = Environment('', '${', '}', '', - lstrip_blocks=True, trim_blocks=True) + lstrip_blocks=True, trim_blocks=True) tmpl = env.from_string('''\ \ ${item} ''') assert tmpl.render(seq=range(5)) == '01234' - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TokenStreamTestCase)) - suite.addTest(unittest.makeSuite(LexerTestCase)) - suite.addTest(unittest.makeSuite(ParserTestCase)) - suite.addTest(unittest.makeSuite(SyntaxTestCase)) - suite.addTest(unittest.makeSuite(LstripBlocksTestCase)) - return suite diff --git a/jinja2/testsuite/loader.py b/jinja2/testsuite/test_loader.py similarity index 69% rename from jinja2/testsuite/loader.py rename to jinja2/testsuite/test_loader.py index 73a7f300..7a8bba5b 100644 --- a/jinja2/testsuite/loader.py +++ b/jinja2/testsuite/test_loader.py @@ -12,64 +12,63 @@ import os import sys import tempfile import shutil +import pytest import unittest -from jinja2.testsuite import JinjaTestCase, dict_loader, \ - package_loader, filesystem_loader, function_loader, \ - choice_loader, prefix_loader - from jinja2 import Environment, loaders from jinja2._compat import PYPY, PY2 from jinja2.loaders import split_template_path from jinja2.exceptions import TemplateNotFound -class LoaderTestCase(JinjaTestCase): +@pytest.mark.loaders +class TestLoaders(): - def test_dict_loader(self): + def test_dict_loader(self, dict_loader): env = Environment(loader=dict_loader) tmpl = env.get_template('justdict.html') assert tmpl.render().strip() == 'FOO' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') + pytest.raises(TemplateNotFound, env.get_template, 'missing.html') - def test_package_loader(self): + def test_package_loader(self, package_loader): env = Environment(loader=package_loader) tmpl = env.get_template('test.html') assert tmpl.render().strip() == 'BAR' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') + pytest.raises(TemplateNotFound, env.get_template, 'missing.html') - def test_filesystem_loader(self): + def test_filesystem_loader(self, filesystem_loader): env = Environment(loader=filesystem_loader) tmpl = env.get_template('test.html') assert tmpl.render().strip() == 'BAR' tmpl = env.get_template('foo/test.html') assert tmpl.render().strip() == 'FOO' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') + pytest.raises(TemplateNotFound, env.get_template, 'missing.html') - def test_choice_loader(self): + def test_choice_loader(self, choice_loader): env = Environment(loader=choice_loader) tmpl = env.get_template('justdict.html') assert tmpl.render().strip() == 'FOO' tmpl = env.get_template('test.html') assert tmpl.render().strip() == 'BAR' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') + pytest.raises(TemplateNotFound, env.get_template, 'missing.html') - def test_function_loader(self): + def test_function_loader(self, function_loader): env = Environment(loader=function_loader) tmpl = env.get_template('justfunction.html') assert tmpl.render().strip() == 'FOO' - self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') + pytest.raises(TemplateNotFound, env.get_template, 'missing.html') - def test_prefix_loader(self): + def test_prefix_loader(self, prefix_loader): env = Environment(loader=prefix_loader) tmpl = env.get_template('a/test.html') assert tmpl.render().strip() == 'BAR' tmpl = env.get_template('b/justdict.html') assert tmpl.render().strip() == 'FOO' - self.assert_raises(TemplateNotFound, env.get_template, 'missing') + pytest.raises(TemplateNotFound, env.get_template, 'missing') def test_caching(self): changed = False + class TestLoader(loaders.BaseLoader): def get_source(self, environment, template): return u'foo', None, lambda: not changed @@ -82,7 +81,7 @@ class LoaderTestCase(JinjaTestCase): env = Environment(loader=TestLoader(), cache_size=0) assert env.get_template('template') \ - is not env.get_template('template') + is not env.get_template('template') env = Environment(loader=TestLoader(), cache_size=2) t1 = env.get_template('one') @@ -104,14 +103,15 @@ class LoaderTestCase(JinjaTestCase): def test_split_template_path(self): assert split_template_path('foo/bar') == ['foo', 'bar'] assert split_template_path('./foo/bar') == ['foo', 'bar'] - self.assert_raises(TemplateNotFound, split_template_path, '../foo') + pytest.raises(TemplateNotFound, split_template_path, '../foo') -class ModuleLoaderTestCase(JinjaTestCase): +@pytest.mark.loaders +@pytest.mark.moduleloader +class TestModuleLoader(): archive = None - def compile_down(self, zip='deflated', py_compile=False): - super(ModuleLoaderTestCase, self).setup() + def compile_down(self, prefix_loader, zip='deflated', py_compile=False): log = [] self.reg_env = Environment(loader=prefix_loader) if zip is not None: @@ -126,7 +126,6 @@ class ModuleLoaderTestCase(JinjaTestCase): return ''.join(log) def teardown(self): - super(ModuleLoaderTestCase, self).teardown() if hasattr(self, 'mod_env'): if os.path.isfile(self.archive): os.remove(self.archive) @@ -134,8 +133,8 @@ class ModuleLoaderTestCase(JinjaTestCase): shutil.rmtree(self.archive) self.archive = None - def test_log(self): - log = self.compile_down() + def test_log(self, prefix_loader): + log = self.compile_down(prefix_loader) assert 'Compiled "a/foo/test.html" as ' \ 'tmpl_a790caf9d669e39ea4d280d597ec891c4ef0404a' in log assert 'Finished compiling templates' in log @@ -151,20 +150,20 @@ class ModuleLoaderTestCase(JinjaTestCase): tmpl2 = self.mod_env.get_template('b/justdict.html') assert tmpl1.render() == tmpl2.render() - def test_deflated_zip_compile(self): - self.compile_down(zip='deflated') + def test_deflated_zip_compile(self, prefix_loader): + self.compile_down(prefix_loader, zip='deflated') self._test_common() - def test_stored_zip_compile(self): - self.compile_down(zip='stored') + def test_stored_zip_compile(self, prefix_loader): + self.compile_down(prefix_loader, zip='stored') self._test_common() - def test_filesystem_compile(self): - self.compile_down(zip=None) + def test_filesystem_compile(self, prefix_loader): + self.compile_down(prefix_loader, zip=None) self._test_common() - def test_weak_references(self): - self.compile_down() + def test_weak_references(self, prefix_loader): + self.compile_down(prefix_loader) tmpl = self.mod_env.get_template('a/test.html') key = loaders.ModuleLoader.get_template_key('a/test.html') name = self.mod_env.loader.module.__name__ @@ -184,17 +183,19 @@ class ModuleLoaderTestCase(JinjaTestCase): assert name not in sys.modules # This test only makes sense on non-pypy python 2 - if PY2 and not PYPY: - def test_byte_compilation(self): - log = self.compile_down(py_compile=True) - assert 'Byte-compiled "a/test.html"' in log - tmpl1 = self.mod_env.get_template('a/test.html') - mod = self.mod_env.loader.module. \ - tmpl_3c4ddf650c1a73df961a6d3d2ce2752f1b8fd490 - assert mod.__file__.endswith('.pyc') - - def test_choice_loader(self): - log = self.compile_down() + @pytest.mark.skipif( + not (PY2 and not PYPY), + reason='This test only makes sense on non-pypy python 2') + def test_byte_compilation(self, prefix_loader): + log = self.compile_down(prefix_loader, py_compile=True) + assert 'Byte-compiled "a/test.html"' in log + tmpl1 = self.mod_env.get_template('a/test.html') + mod = self.mod_env.loader.module. \ + tmpl_3c4ddf650c1a73df961a6d3d2ce2752f1b8fd490 + assert mod.__file__.endswith('.pyc') + + def test_choice_loader(self, prefix_loader): + log = self.compile_down(prefix_loader) self.mod_env.loader = loaders.ChoiceLoader([ self.mod_env.loader, @@ -202,12 +203,12 @@ class ModuleLoaderTestCase(JinjaTestCase): ]) tmpl1 = self.mod_env.get_template('a/test.html') - self.assert_equal(tmpl1.render(), 'BAR') + assert tmpl1.render() == 'BAR' tmpl2 = self.mod_env.get_template('DICT_SOURCE') - self.assert_equal(tmpl2.render(), 'DICT_TEMPLATE') + assert tmpl2.render() == 'DICT_TEMPLATE' - def test_prefix_loader(self): - log = self.compile_down() + def test_prefix_loader(self, prefix_loader): + log = self.compile_down(prefix_loader) self.mod_env.loader = loaders.PrefixLoader({ 'MOD': self.mod_env.loader, @@ -215,13 +216,6 @@ class ModuleLoaderTestCase(JinjaTestCase): }) tmpl1 = self.mod_env.get_template('MOD/a/test.html') - self.assert_equal(tmpl1.render(), 'BAR') + assert tmpl1.render() == 'BAR' tmpl2 = self.mod_env.get_template('DICT/test.html') - self.assert_equal(tmpl2.render(), 'DICT_TEMPLATE') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(LoaderTestCase)) - suite.addTest(unittest.makeSuite(ModuleLoaderTestCase)) - return suite + assert tmpl2.render() == 'DICT_TEMPLATE' diff --git a/jinja2/testsuite/regression.py b/jinja2/testsuite/test_regression.py similarity index 74% rename from jinja2/testsuite/regression.py rename to jinja2/testsuite/test_regression.py index c5f7d5c6..a4aa1571 100644 --- a/jinja2/testsuite/regression.py +++ b/jinja2/testsuite/test_regression.py @@ -8,20 +8,17 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD, see LICENSE for more details. """ -import unittest - -from jinja2.testsuite import JinjaTestCase +import pytest from jinja2 import Template, Environment, DictLoader, TemplateSyntaxError, \ TemplateNotFound, PrefixLoader from jinja2._compat import text_type -env = Environment() - -class CornerTestCase(JinjaTestCase): +@pytest.mark.regression +class TestCorner(): - def test_assigned_scoping(self): + def test_assigned_scoping(self, env): t = env.from_string(''' {%- for item in (1, 2, 3, 4) -%} [{{ item }}] @@ -48,7 +45,7 @@ class CornerTestCase(JinjaTestCase): ''') assert t.render() == '[1][2][3][4]42' - def test_closure_scoping(self): + def test_closure_scoping(self, env): t = env.from_string(''' {%- set wrapper = "" %} {%- for item in (1, 2, 3, 4) %} @@ -79,30 +76,34 @@ class CornerTestCase(JinjaTestCase): assert t.render(wrapper=23) == '[1][2][3][4]23' -class BugTestCase(JinjaTestCase): +@pytest.mark.regression +class TestBug(): - def test_keyword_folding(self): + def test_keyword_folding(self, env): env = Environment() env.filters['testing'] = lambda value, some: value + some assert env.from_string("{{ 'test'|testing(some='stuff') }}") \ - .render() == 'teststuff' + .render() == 'teststuff' - def test_extends_output_bugs(self): + def test_extends_output_bugs(self, env): env = Environment(loader=DictLoader({ 'parent.html': '(({% block title %}{% endblock %}))' })) - t = env.from_string('{% if expr %}{% extends "parent.html" %}{% endif %}' - '[[{% block title %}title{% endblock %}]]' - '{% for item in [1, 2, 3] %}({{ item }}){% endfor %}') + t = env.from_string( + '{% if expr %}{% extends "parent.html" %}{% endif %}' + '[[{% block title %}title{% endblock %}]]' + '{% for item in [1, 2, 3] %}({{ item }}){% endfor %}' + ) assert t.render(expr=False) == '[[title]](1)(2)(3)' assert t.render(expr=True) == '((title))' - def test_urlize_filter_escaping(self): + def test_urlize_filter_escaping(self, env): tmpl = env.from_string('{{ "http://www.example.org/http://www.example.org/<foo' + assert tmpl.render() == ''\ + 'http://www.example.org/<foo' - def test_loop_call_loop(self): + def test_loop_call_loop(self, env): tmpl = env.from_string(''' {% macro test() %} @@ -119,24 +120,25 @@ class BugTestCase(JinjaTestCase): ''') - assert tmpl.render().split() == [text_type(x) for x in range(1, 11)] * 5 + assert tmpl.render().split() \ + == [text_type(x) for x in range(1, 11)] * 5 - def test_weird_inline_comment(self): + def test_weird_inline_comment(self, env): env = Environment(line_statement_prefix='%') - self.assert_raises(TemplateSyntaxError, env.from_string, - '% for item in seq {# missing #}\n...% endfor') + pytest.raises(TemplateSyntaxError, env.from_string, + '% for item in seq {# missing #}\n...% endfor') - def test_old_macro_loop_scoping_bug(self): + def test_old_macro_loop_scoping_bug(self, env): tmpl = env.from_string('{% for i in (1, 2) %}{{ i }}{% endfor %}' '{% macro i() %}3{% endmacro %}{{ i() }}') assert tmpl.render() == '123' - def test_partial_conditional_assignments(self): + def test_partial_conditional_assignments(self, env): tmpl = env.from_string('{% if b %}{% set a = 42 %}{% endif %}{{ a }}') assert tmpl.render(a=23) == '23' assert tmpl.render(b=True) == '42' - def test_stacked_locals_scoping_bug(self): + def test_stacked_locals_scoping_bug(self, env): env = Environment(line_statement_prefix='#') t = env.from_string('''\ # for j in [1, 2]: @@ -160,7 +162,7 @@ class BugTestCase(JinjaTestCase): ''') assert t.render(a=0, b=False, c=42, d=42.0) == '1111C' - def test_stacked_locals_scoping_bug_twoframe(self): + def test_stacked_locals_scoping_bug_twoframe(self, env): t = Template(''' {% set x = 1 %} {% for item in foo %} @@ -173,7 +175,7 @@ class BugTestCase(JinjaTestCase): rv = t.render(foo=[1]).strip() assert rv == u'1' - def test_call_with_args(self): + def test_call_with_args(self, env): t = Template("""{% macro dump_users(users) -%}
    {%- for user in users -%} @@ -192,9 +194,9 @@ class BugTestCase(JinjaTestCase): {% endcall %}""") assert [x.strip() for x in t.render(list_of_user=[{ - 'username':'apo', - 'realname':'something else', - 'description':'test' + 'username': 'apo', + 'realname': 'something else', + 'description': 'test' }]).splitlines()] == [ u'
    • apo

      ', u'
      Realname
      ', @@ -205,12 +207,15 @@ class BugTestCase(JinjaTestCase): u'
    ' ] - def test_empty_if_condition_fails(self): - self.assert_raises(TemplateSyntaxError, Template, '{% if %}....{% endif %}') - self.assert_raises(TemplateSyntaxError, Template, '{% if foo %}...{% elif %}...{% endif %}') - self.assert_raises(TemplateSyntaxError, Template, '{% for x in %}..{% endfor %}') + def test_empty_if_condition_fails(self, env): + pytest.raises(TemplateSyntaxError, + Template, '{% if %}....{% endif %}') + pytest.raises(TemplateSyntaxError, + Template, '{% if foo %}...{% elif %}...{% endif %}') + pytest.raises(TemplateSyntaxError, + Template, '{% for x in %}..{% endfor %}') - def test_recursive_loop_bug(self): + def test_recursive_loop_bug(self, env): tpl1 = Template(""" {% for p in foo recursive%} {{p.bar}} @@ -237,7 +242,7 @@ class BugTestCase(JinjaTestCase): {% endfor %} """) - def test_else_loop_bug(self): + def test_else_loop_bug(self, env): t = Template(''' {% for x in y %} {{ loop.index0 }} @@ -245,9 +250,9 @@ class BugTestCase(JinjaTestCase): {% for i in range(3) %}{{ i }}{% endfor %} {% endfor %} ''') - self.assertEqual(t.render(y=[]).strip(), '012') + assert t.render(y=[]).strip() == '012' - def test_correct_prefix_loader_name(self): + def test_correct_prefix_loader_name(self, env): env = Environment(loader=PrefixLoader({ 'foo': DictLoader({}) })) @@ -258,22 +263,16 @@ class BugTestCase(JinjaTestCase): else: assert False, 'expected error here' - def test_contextfunction_callable_classes(self): + def test_contextfunction_callable_classes(self, env): from jinja2.utils import contextfunction + class CallableClass(object): @contextfunction def __call__(self, ctx): return ctx.resolve('hello') tpl = Template("""{{ callableclass() }}""") - output = tpl.render(callableclass = CallableClass(), hello = 'TEST') + output = tpl.render(callableclass=CallableClass(), hello='TEST') expected = 'TEST' - self.assert_equal(output, expected) - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(CornerTestCase)) - suite.addTest(unittest.makeSuite(BugTestCase)) - return suite + assert output == expected diff --git a/jinja2/testsuite/security.py b/jinja2/testsuite/test_security.py similarity index 72% rename from jinja2/testsuite/security.py rename to jinja2/testsuite/test_security.py index 246d0f07..e5b463fc 100644 --- a/jinja2/testsuite/security.py +++ b/jinja2/testsuite/test_security.py @@ -8,9 +8,7 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD, see LICENSE for more details. """ -import unittest - -from jinja2.testsuite import JinjaTestCase +import pytest from jinja2 import Environment from jinja2.sandbox import SandboxedEnvironment, \ @@ -42,38 +40,40 @@ class PublicStuff(object): return 'PublicStuff' -class SandboxTestCase(JinjaTestCase): +@pytest.mark.sandbox +class TestSandbox(): - def test_unsafe(self): + def test_unsafe(self, env): env = SandboxedEnvironment() - self.assert_raises(SecurityError, env.from_string("{{ foo.foo() }}").render, - foo=PrivateStuff()) - self.assert_equal(env.from_string("{{ foo.bar() }}").render(foo=PrivateStuff()), '23') - - self.assert_raises(SecurityError, env.from_string("{{ foo._foo() }}").render, - foo=PublicStuff()) - self.assert_equal(env.from_string("{{ foo.bar() }}").render(foo=PublicStuff()), '23') - self.assert_equal(env.from_string("{{ foo.__class__ }}").render(foo=42), '') - self.assert_equal(env.from_string("{{ foo.func_code }}").render(foo=lambda:None), '') + pytest.raises(SecurityError, env.from_string("{{ foo.foo() }}").render, + foo=PrivateStuff()) + assert env.from_string("{{ foo.bar() }}").render(foo=PrivateStuff()) == '23' + + pytest.raises(SecurityError, + env.from_string("{{ foo._foo() }}").render, + foo=PublicStuff()) + assert env.from_string("{{ foo.bar() }}").render(foo=PublicStuff()) == '23' + assert env.from_string("{{ foo.__class__ }}").render(foo=42) == '' + assert env.from_string("{{ foo.func_code }}").render(foo=lambda:None) == '' # security error comes from __class__ already. - self.assert_raises(SecurityError, env.from_string( + pytest.raises(SecurityError, env.from_string( "{{ foo.__class__.__subclasses__() }}").render, foo=42) - def test_immutable_environment(self): + def test_immutable_environment(self, env): env = ImmutableSandboxedEnvironment() - self.assert_raises(SecurityError, env.from_string( + pytest.raises(SecurityError, env.from_string( '{{ [].append(23) }}').render) - self.assert_raises(SecurityError, env.from_string( + pytest.raises(SecurityError, env.from_string( '{{ {1:2}.clear() }}').render) - def test_restricted(self): + def test_restricted(self, env): env = SandboxedEnvironment() - self.assert_raises(TemplateSyntaxError, env.from_string, + pytest.raises(TemplateSyntaxError, env.from_string, "{% for item.attribute in seq %}...{% endfor %}") - self.assert_raises(TemplateSyntaxError, env.from_string, + pytest.raises(TemplateSyntaxError, env.from_string, "{% for foo, bar.baz in seq %}...{% endfor %}") - def test_markup_operations(self): + def test_markup_operations(self, env): # adding two strings should escape the unsafe one unsafe = '' safe = Markup('username') @@ -81,7 +81,7 @@ class SandboxTestCase(JinjaTestCase): # string interpolations are safe to use too assert Markup('%s') % '' == \ - '<bad user>' + '<bad user>' assert Markup('%(username)s') % { 'username': '' } == '<bad user>' @@ -97,18 +97,19 @@ class SandboxTestCase(JinjaTestCase): class Foo(object): def __html__(self): return 'awesome' + def __unicode__(self): return 'awesome' assert Markup(Foo()) == 'awesome' assert Markup('%s') % Foo() == \ - 'awesome' + 'awesome' # escaping and unescaping assert escape('"<>&\'') == '"<>&'' assert Markup("Foo & Bar").striptags() == "Foo & Bar" assert Markup("<test>").unescape() == "" - def test_template_data(self): + def test_template_data(self, env): env = Environment(autoescape=True) t = env.from_string('{% macro say_hello(name) %}' '

    Hello {{ name }}!

    {% endmacro %}' @@ -120,12 +121,12 @@ class SandboxTestCase(JinjaTestCase): assert t.module.say_hello('foo') == escaped_out assert escape(t.module.say_hello('foo')) == escaped_out - def test_attr_filter(self): + def test_attr_filter(self, env): env = SandboxedEnvironment() tmpl = env.from_string('{{ cls|attr("__subclasses__")() }}') - self.assert_raises(SecurityError, tmpl.render, cls=int) + pytest.raises(SecurityError, tmpl.render, cls=int) - def test_binary_operator_intercepting(self): + def test_binary_operator_intercepting(self, env): def disable_op(left, right): raise TemplateRuntimeError('that operator so does not work') for expr, ctx, rv in ('1 + 2', {}, '3'), ('a + 2', {'a': 2}, '4'): @@ -140,9 +141,9 @@ class SandboxTestCase(JinjaTestCase): except TemplateRuntimeError as e: pass else: - self.fail('expected runtime error') + assert False, 'expected runtime error' - def test_unary_operator_intercepting(self): + def test_unary_operator_intercepting(self, env): def disable_op(arg): raise TemplateRuntimeError('that operator so does not work') for expr, ctx, rv in ('-1', {}, '-1'), ('-a', {'a': 2}, '-2'): @@ -157,10 +158,4 @@ class SandboxTestCase(JinjaTestCase): except TemplateRuntimeError as e: pass else: - self.fail('expected runtime error') - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(SandboxTestCase)) - return suite + assert False, 'expected runtime error' diff --git a/jinja2/testsuite/tests.py b/jinja2/testsuite/test_tests.py similarity index 80% rename from jinja2/testsuite/tests.py rename to jinja2/testsuite/test_tests.py index 704f0687..9e54038c 100644 --- a/jinja2/testsuite/tests.py +++ b/jinja2/testsuite/test_tests.py @@ -8,33 +8,32 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD, see LICENSE for more details. """ -import unittest -from jinja2.testsuite import JinjaTestCase +import pytest from jinja2 import Markup, Environment -env = Environment() +@pytest.mark.test_tests +class TestTestsCase(): -class TestsTestCase(JinjaTestCase): - - def test_defined(self): - tmpl = env.from_string('{{ missing is defined }}|{{ true is defined }}') + def test_defined(self, env): + tmpl = env.from_string('{{ missing is defined }}|' + '{{ true is defined }}') assert tmpl.render() == 'False|True' - def test_even(self): + def test_even(self, env): tmpl = env.from_string('''{{ 1 is even }}|{{ 2 is even }}''') assert tmpl.render() == 'False|True' - def test_odd(self): + def test_odd(self, env): tmpl = env.from_string('''{{ 1 is odd }}|{{ 2 is odd }}''') assert tmpl.render() == 'True|False' - def test_lower(self): + def test_lower(self, env): tmpl = env.from_string('''{{ "foo" is lower }}|{{ "FOO" is lower }}''') assert tmpl.render() == 'True|False' - def test_typechecks(self): + def test_typechecks(self, env): tmpl = env.from_string(''' {{ 42 is undefined }} {{ 42 is defined }} @@ -56,15 +55,17 @@ class TestsTestCase(JinjaTestCase): {{ 3.14159 is number }} {{ complex is number }} ''') + class MyDict(dict): pass + assert tmpl.render(mydict=MyDict(), complex=complex(1, 2)).split() == [ 'False', 'True', 'False', 'True', 'True', 'False', 'True', 'True', 'True', 'True', 'False', 'True', 'True', 'True', 'False', 'True', 'True', 'True', 'True' ] - def test_sequence(self): + def test_sequence(self, env): tmpl = env.from_string( '{{ [1, 2, 3] is sequence }}|' '{{ "foo" is sequence }}|' @@ -72,11 +73,11 @@ class TestsTestCase(JinjaTestCase): ) assert tmpl.render() == 'True|True|False' - def test_upper(self): + def test_upper(self, env): tmpl = env.from_string('{{ "FOO" is upper }}|{{ "foo" is upper }}') assert tmpl.render() == 'True|False' - def test_equalto(self): + def test_equalto(self, env): tmpl = env.from_string('{{ foo is equalto 12 }}|' '{{ foo is equalto 0 }}|' '{{ foo is equalto (3 * 4) }}|' @@ -85,24 +86,19 @@ class TestsTestCase(JinjaTestCase): '{{ bar is equalto ("ba" + "z") }}|' '{{ bar is equalto bar }}|' '{{ bar is equalto foo }}') - assert tmpl.render(foo=12, bar="baz") == 'True|False|True|True|False|True|True|False' + assert tmpl.render(foo=12, bar="baz") \ + == 'True|False|True|True|False|True|True|False' - def test_sameas(self): + def test_sameas(self, env): tmpl = env.from_string('{{ foo is sameas false }}|' '{{ 0 is sameas false }}') assert tmpl.render(foo=False) == 'True|False' - def test_no_paren_for_arg1(self): + def test_no_paren_for_arg1(self, env): tmpl = env.from_string('{{ foo is sameas none }}') assert tmpl.render(foo=None) == 'True' - def test_escaped(self): + def test_escaped(self, env): env = Environment(autoescape=True) tmpl = env.from_string('{{ x is escaped }}|{{ y is escaped }}') assert tmpl.render(x='foo', y=Markup('foo')) == 'False|True' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestsTestCase)) - return suite diff --git a/jinja2/testsuite/utils.py b/jinja2/testsuite/test_utils.py similarity index 61% rename from jinja2/testsuite/utils.py rename to jinja2/testsuite/test_utils.py index cab9b09a..37310361 100644 --- a/jinja2/testsuite/utils.py +++ b/jinja2/testsuite/test_utils.py @@ -9,16 +9,17 @@ :license: BSD, see LICENSE for more details. """ import gc -import unittest -import pickle +import pytest -from jinja2.testsuite import JinjaTestCase +import pickle from jinja2.utils import LRUCache, escape, object_type_repr -class LRUCacheTestCase(JinjaTestCase): +@pytest.mark.utils +@pytest.mark.lrucache +class TestLRUCache(): def test_simple(self): d = LRUCache(3) @@ -43,20 +44,25 @@ class LRUCacheTestCase(JinjaTestCase): assert copy._queue == cache._queue -class HelpersTestCase(JinjaTestCase): +@pytest.mark.utils +@pytest.mark.helpers +class TestHelpers(): def test_object_type_repr(self): class X(object): pass - self.assert_equal(object_type_repr(42), 'int object') - self.assert_equal(object_type_repr([]), 'list object') - self.assert_equal(object_type_repr(X()), - 'jinja2.testsuite.utils.X object') - self.assert_equal(object_type_repr(None), 'None') - self.assert_equal(object_type_repr(Ellipsis), 'Ellipsis') + assert object_type_repr(42) == 'int object' + assert object_type_repr([]) == 'list object' + assert object_type_repr(X()) == 'test_utils.X object' + assert object_type_repr(None) == 'None' + assert object_type_repr(Ellipsis) == 'Ellipsis' -class MarkupLeakTestCase(JinjaTestCase): +@pytest.mark.utils +@pytest.mark.markupleak +@pytest.mark.skipif(hasattr(escape, 'func_code'), + reason='this test only tests the c extension') +class TestMarkupLeak(): def test_markup_leaks(self): counts = set() @@ -68,15 +74,3 @@ class MarkupLeakTestCase(JinjaTestCase): escape(u"") counts.add(len(gc.get_objects())) assert len(counts) == 1, 'ouch, c extension seems to leak objects' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(LRUCacheTestCase)) - suite.addTest(unittest.makeSuite(HelpersTestCase)) - - # this test only tests the c extension - if not hasattr(escape, 'func_code'): - suite.addTest(unittest.makeSuite(MarkupLeakTestCase)) - - return suite diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..df3eb518 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts = --doctest-modules diff --git a/setup.py b/setup.py index 3f080b96..2cf3106f 100644 --- a/setup.py +++ b/setup.py @@ -71,10 +71,9 @@ setup( 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Text Processing :: Markup :: HTML' ], - packages=['jinja2', 'jinja2.testsuite', 'jinja2.testsuite.res'], + packages=['jinja2'], install_requires=['MarkupSafe'], extras_require={'i18n': ['Babel>=0.8']}, - test_suite='jinja2.testsuite.suite', include_package_data=True, entry_points=""" [babel.extractors] diff --git a/tox.ini b/tox.ini index 8dc90020..e02581d1 100644 --- a/tox.ini +++ b/tox.ini @@ -2,4 +2,4 @@ envlist = py26, py27, pypy, py33, py34 [testenv] -commands = python run-tests.py {posargs} +commands = py.test jinja2