1import contextlib
2import os
3import re
4import unittest
5
6from mako import compat
7from mako.cache import CacheImpl
8from mako.cache import register_plugin
9from mako.compat import py33
10from mako.compat import py3k
11from mako.template import Template
12from mako.util import update_wrapper
13
14try:
15    # unitttest has a SkipTest also but pytest doesn't
16    # honor it unless nose is imported too...
17    from nose import SkipTest
18except ImportError:
19    from _pytest.runner import Skipped as SkipTest
20
21template_base = os.path.join(os.path.dirname(__file__), "templates")
22module_base = os.path.join(template_base, "modules")
23
24
25class TemplateTest(unittest.TestCase):
26    def _file_template(self, filename, **kw):
27        filepath = self._file_path(filename)
28        return Template(
29            uri=filename, filename=filepath, module_directory=module_base, **kw
30        )
31
32    def _file_path(self, filename):
33        name, ext = os.path.splitext(filename)
34
35        if py3k:
36            py3k_path = os.path.join(template_base, name + "_py3k" + ext)
37            if os.path.exists(py3k_path):
38                return py3k_path
39
40        return os.path.join(template_base, filename)
41
42    def _do_file_test(
43        self,
44        filename,
45        expected,
46        filters=None,
47        unicode_=True,
48        template_args=None,
49        **kw
50    ):
51        t1 = self._file_template(filename, **kw)
52        self._do_test(
53            t1,
54            expected,
55            filters=filters,
56            unicode_=unicode_,
57            template_args=template_args,
58        )
59
60    def _do_memory_test(
61        self,
62        source,
63        expected,
64        filters=None,
65        unicode_=True,
66        template_args=None,
67        **kw
68    ):
69        t1 = Template(text=source, **kw)
70        self._do_test(
71            t1,
72            expected,
73            filters=filters,
74            unicode_=unicode_,
75            template_args=template_args,
76        )
77
78    def _do_test(
79        self,
80        template,
81        expected,
82        filters=None,
83        template_args=None,
84        unicode_=True,
85    ):
86        if template_args is None:
87            template_args = {}
88        if unicode_:
89            output = template.render_unicode(**template_args)
90        else:
91            output = template.render(**template_args)
92
93        if filters:
94            output = filters(output)
95        eq_(output, expected)
96
97
98def eq_(a, b, msg=None):
99    """Assert a == b, with repr messaging on failure."""
100    assert a == b, msg or "%r != %r" % (a, b)
101
102
103def teardown():
104    import shutil
105
106    shutil.rmtree(module_base, True)
107
108
109if py33:
110    from unittest import mock  # noqa
111else:
112    import mock  # noqa
113
114
115@contextlib.contextmanager
116def raises(except_cls, message=None):
117    try:
118        yield
119        success = False
120    except except_cls as e:
121        if message:
122            assert re.search(
123                message, compat.text_type(e), re.UNICODE
124            ), "%r !~ %s" % (message, e)
125            print(compat.text_type(e).encode("utf-8"))
126        success = True
127
128    # assert outside the block so it works for AssertionError too !
129    assert success, "Callable did not raise an exception"
130
131
132def assert_raises(except_cls, callable_, *args, **kw):
133    with raises(except_cls):
134        return callable_(*args, **kw)
135
136
137def assert_raises_message(except_cls, msg, callable_, *args, **kwargs):
138    with raises(except_cls, msg):
139        return callable_(*args, **kwargs)
140
141
142def skip_if(predicate, reason=None):
143    """Skip a test if predicate is true."""
144    reason = reason or predicate.__name__
145
146    def decorate(fn):
147        fn_name = fn.__name__
148
149        def maybe(*args, **kw):
150            if predicate():
151                msg = "'%s' skipped: %s" % (fn_name, reason)
152                raise SkipTest(msg)
153            else:
154                return fn(*args, **kw)
155
156        return update_wrapper(maybe, fn)
157
158    return decorate
159
160
161def requires_python_3(fn):
162    return skip_if(lambda: not py3k, "Requires Python 3.xx")(fn)
163
164
165def requires_python_2(fn):
166    return skip_if(lambda: py3k, "Requires Python 2.xx")(fn)
167
168
169def requires_pygments_14(fn):
170    try:
171        import pygments
172
173        version = pygments.__version__
174    except:
175        version = "0"
176    return skip_if(
177        lambda: version < "1.4", "Requires pygments 1.4 or greater"
178    )(fn)
179
180
181def requires_no_pygments_exceptions(fn):
182    def go(*arg, **kw):
183        from mako import exceptions
184
185        exceptions._install_fallback()
186        try:
187            return fn(*arg, **kw)
188        finally:
189            exceptions._install_highlighting()
190
191    return update_wrapper(go, fn)
192
193
194class PlainCacheImpl(CacheImpl):
195    """Simple memory cache impl so that tests which
196    use caching can run without beaker.  """
197
198    def __init__(self, cache):
199        self.cache = cache
200        self.data = {}
201
202    def get_or_create(self, key, creation_function, **kw):
203        if key in self.data:
204            return self.data[key]
205        else:
206            self.data[key] = data = creation_function(**kw)
207            return data
208
209    def put(self, key, value, **kw):
210        self.data[key] = value
211
212    def get(self, key, **kw):
213        return self.data[key]
214
215    def invalidate(self, key, **kw):
216        del self.data[key]
217
218
219register_plugin("plain", __name__, "PlainCacheImpl")
220