Skip to content
Snippets Groups Projects
def.py 11.2 KiB
Newer Older
from mako.template import Template
from mako import lookup
import unittest
Mike Bayer's avatar
Mike Bayer committed
from util import flatten_result
Mike Bayer's avatar
Mike Bayer committed
class DefTest(unittest.TestCase):
    def test_def_noargs(self):
        template = Template("""
        
        ${mycomp()}
        
Mike Bayer's avatar
Mike Bayer committed
        <%def name="mycomp">
            hello mycomp ${variable}
Mike Bayer's avatar
Mike Bayer committed
        </%def>
        
        """)
        assert template.render(variable='hi').strip() == """hello mycomp hi"""

Mike Bayer's avatar
Mike Bayer committed
    def test_def_blankargs(self):
        template = Template("""
Mike Bayer's avatar
Mike Bayer committed
        <%def name="mycomp()">
            hello mycomp ${variable}
Mike Bayer's avatar
Mike Bayer committed
        </%def>

        ${mycomp()}""")
        assert template.render(variable='hi').strip() == """hello mycomp hi"""

Mike Bayer's avatar
Mike Bayer committed
    def test_def_args(self):
        template = Template("""
Mike Bayer's avatar
Mike Bayer committed
        <%def name="mycomp(a, b)">
            hello mycomp ${variable}, ${a}, ${b}
Mike Bayer's avatar
Mike Bayer committed
        </%def>

        ${mycomp(5, 6)}""")
        assert template.render(variable='hi', a=5, b=6).strip() == """hello mycomp hi, 5, 6"""

Mike Bayer's avatar
Mike Bayer committed
    def test_inter_def(self):
        """test defs calling each other"""
        template = Template("""
Mike Bayer's avatar
Mike Bayer committed
        ${b()}
Mike Bayer's avatar
Mike Bayer committed
        <%def name="a">\
Mike Bayer's avatar
Mike Bayer committed
        im a
Mike Bayer's avatar
Mike Bayer committed
        </%def>
Mike Bayer's avatar
Mike Bayer committed
        <%def name="b">
Mike Bayer's avatar
Mike Bayer committed
        im b
        and heres a:  ${a()}
Mike Bayer's avatar
Mike Bayer committed
        </%def>
Mike Bayer's avatar
Mike Bayer committed
        <%def name="c">
Mike Bayer's avatar
Mike Bayer committed
        im c
Mike Bayer's avatar
Mike Bayer committed
        </%def>
Mike Bayer's avatar
Mike Bayer committed
""")
        # check that "a" is declared in "b", but not in "c"
        assert "a" not in template.module.render_c.func_code.co_varnames
        assert "a" in template.module.render_b.func_code.co_varnames
        
        # then test output
Mike Bayer's avatar
Mike Bayer committed
        assert flatten_result(template.render()) == "im b and heres a: im a"
class ScopeTest(unittest.TestCase):
    """test scoping rules.  The key is, enclosing scope always takes precedence over contextual scope."""
    def test_scope_one(self):
Mike Bayer's avatar
Mike Bayer committed
        t = Template("""
Mike Bayer's avatar
Mike Bayer committed
        <%def name="a">
            this is a, and y is ${y}
Mike Bayer's avatar
Mike Bayer committed
        </%def>
Mike Bayer's avatar
Mike Bayer committed
""")
        assert flatten_result(t.render(y=None)) == "this is a, and y is None this is a, and y is 7"
    def test_scope_two(self):
Mike Bayer's avatar
Mike Bayer committed
        t = Template("""
        y is ${y}

        <%
            y = 7
        %>

        y is ${y}
Mike Bayer's avatar
Mike Bayer committed
""")
        try:
            t.render(y=None)
            assert False
        except UnboundLocalError:
            assert True
    def test_scope_four(self):
        """test that variables are pulled from 'enclosing' scope before context."""
        t = Template("""
            <%
                x = 5
            %>
Mike Bayer's avatar
Mike Bayer committed
            <%def name="a">
                this is a. x is ${x}.
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
            <%def name="b">
                <%
                    x = 9
                %>
                this is b. x is ${x}.
                calling a. ${a()}
Mike Bayer's avatar
Mike Bayer committed
            </%def>
        
            ${b()}
""")
        assert flatten_result(t.render()) == "this is b. x is 9. calling a. this is a. x is 5."
    
    def test_scope_five(self):
        """test that variables are pulled from 'enclosing' scope before context."""
        # same as test four, but adds a scope around it.
        t = Template("""
Mike Bayer's avatar
Mike Bayer committed
            <%def name="enclosing">
Mike Bayer's avatar
Mike Bayer committed
            <%def name="a">
                this is a. x is ${x}.
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
            <%def name="b">
                <%
                    x = 9
                %>
                this is b. x is ${x}.
                calling a. ${a()}
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
            </%def>
            ${enclosing()}
""")
        assert flatten_result(t.render()) == "this is b. x is 9. calling a. this is a. x is 5."

    def test_scope_six(self):
Mike Bayer's avatar
Mike Bayer committed
        """test that the initial context counts as 'enclosing' scope, for plain defs"""
Mike Bayer's avatar
Mike Bayer committed
        <%def name="a">
Mike Bayer's avatar
Mike Bayer committed
        </%def>
Mike Bayer's avatar
Mike Bayer committed
        <%def name="b">
            <%
                x = 10
            %>
            b. x is ${x}.  ${a()}
Mike Bayer's avatar
Mike Bayer committed
        </%def>

        ${b()}
    """)
        assert flatten_result(t.render(x=5)) == "b. x is 10. a: x is 5"

    def test_scope_seven(self):
Mike Bayer's avatar
Mike Bayer committed
        """test that the initial context counts as 'enclosing' scope, for nested defs"""
        t = Template("""
Mike Bayer's avatar
Mike Bayer committed
        <%def name="enclosing">
            <%def name="a">
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
            <%def name="b">
                <%
                    x = 10
                %>
                b. x is ${x}.  ${a()}
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
        </%def>
        ${enclosing()}
    """)
        assert flatten_result(t.render(x=5)) == "b. x is 10. a: x is 5"

    def test_scope_eight(self):
Mike Bayer's avatar
Mike Bayer committed
        """test that the initial context counts as 'enclosing' scope, for nested defs"""
        t = Template("""
Mike Bayer's avatar
Mike Bayer committed
        <%def name="enclosing">
            <%def name="a">
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
            <%def name="b">
                <%
                    x = 10
                %>
                
                b. x is ${x}.  ${a()}
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
        </%def>
        ${enclosing()}
    """)
        assert flatten_result(t.render(x=5)) == "b. x is 10. a: x is 5"

    def test_scope_nine(self):
        """test that 'enclosing scope' doesnt get exported to other templates"""
        
        l = lookup.TemplateLookup()
        l.put_string('main', """
        <%
            x = 5
        %>
        this is main.  <%include file="secondary"/>
        this is secondary.  x is ${x}
        assert flatten_result(l.get_template('main').render(x=2)) == "this is main. this is secondary. x is 2"
    def test_scope_ten(self):
        t = Template("""
Mike Bayer's avatar
Mike Bayer committed
            <%def name="a">
                <%def name="b">
Mike Bayer's avatar
Mike Bayer committed
                </%def>
                <%def name="c">
Mike Bayer's avatar
Mike Bayer committed
                </%def>

                <%
                    # we assign to "y".  but the 'enclosing scope' of "b" and "c" is from the "y" on the outside
                    y = 10
                %>
                a/y: ${y}
                a/b: ${b()}
Mike Bayer's avatar
Mike Bayer committed
            </%def>

            <%
                y = 7
            %>
            main/a: ${a()}
            main/y: ${y}
    """)
        assert flatten_result(t.render()) == "main/a: a/y: 10 a/b: b/c: c/y: 10 b/y: 19 main/y: 7"

    def test_unbound_scope(self):
        t = Template("""
            <%
                y = 10
            %>
Mike Bayer's avatar
Mike Bayer committed
            <%def name="a">
                y is: ${y}
                <%
                    # should raise error ?
                    y = 15
                %>
                y is ${y}
Mike Bayer's avatar
Mike Bayer committed
            </%def>
            ${a()}
""")
        try:
            print t.render()
            assert False
        except UnboundLocalError:
            assert True

    def test_unbound_scope_two(self):
        t = Template("""
Mike Bayer's avatar
Mike Bayer committed
            <%def name="enclosing">
Mike Bayer's avatar
Mike Bayer committed
            <%def name="a">
                y is: ${y}
                <%
                    # should raise error ?
                    y = 15
                %>
                y is ${y}
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
            </%def>
            ${enclosing()}
""")
        try:
            print t.render()
            assert False
        except UnboundLocalError:
            assert True
Mike Bayer's avatar
Mike Bayer committed
class NestedDefTest(unittest.TestCase):
    def test_nested_def(self):
Mike Bayer's avatar
Mike Bayer committed
        t = Template("""
Mike Bayer's avatar
Mike Bayer committed
        <%def name="hi">
            hey, im hi.
            and heres ${foo()}, ${bar()}
            
Mike Bayer's avatar
Mike Bayer committed
            <%def name="foo">
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
            <%def name="bar">
Mike Bayer's avatar
Mike Bayer committed
            </%def>
        </%def>
Mike Bayer's avatar
Mike Bayer committed
""")
        assert flatten_result(t.render()) == "hey, im hi. and heres this is foo , this is bar"
Mike Bayer's avatar
Mike Bayer committed
    def test_nested_with_args(self):
Mike Bayer's avatar
Mike Bayer committed
        t = Template("""
Mike Bayer's avatar
Mike Bayer committed
        ${a()}
Mike Bayer's avatar
Mike Bayer committed
        <%def name="a">
            <%def name="b(x, y=2)">
Mike Bayer's avatar
Mike Bayer committed
                b x is ${x} y is ${y}
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
            a ${b(5)}
Mike Bayer's avatar
Mike Bayer committed
        </%def>
Mike Bayer's avatar
Mike Bayer committed
""")
Mike Bayer's avatar
Mike Bayer committed
        assert flatten_result(t.render()) == "a b x is 5 y is 2"
Mike Bayer's avatar
Mike Bayer committed
        
Mike Bayer's avatar
Mike Bayer committed
    def test_nested_def_2(self):
Mike Bayer's avatar
Mike Bayer committed
        <%def name="a">
            <%def name="b">
                <%def name="c">
Mike Bayer's avatar
Mike Bayer committed
                </%def>
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
        </%def>
Mike Bayer's avatar
Mike Bayer committed
        assert flatten_result(template.render()) == "comp c"

Mike Bayer's avatar
Mike Bayer committed
    def test_nested_nested_def(self):
Mike Bayer's avatar
Mike Bayer committed
        t = Template("""
Mike Bayer's avatar
Mike Bayer committed
        <%def name="a">
Mike Bayer's avatar
Mike Bayer committed
            <%def name="b1">
Mike Bayer's avatar
Mike Bayer committed
            </%def>
            <%def name="b2">
Mike Bayer's avatar
Mike Bayer committed
                <%def name="c1">
Mike Bayer's avatar
Mike Bayer committed
                </%def>
            </%def>
            <%def name="b3">
Mike Bayer's avatar
Mike Bayer committed
                <%def name="c1">
                    a_b3_c1 heres x: ${x}
                    <%
                        y = 7
                    %>
                    y is ${y}
Mike Bayer's avatar
Mike Bayer committed
                </%def>
                <%def name="c2">
                    a_b3_c2
                    y is ${y}
                    c1 is ${c1()}
Mike Bayer's avatar
Mike Bayer committed
                </%def>
Mike Bayer's avatar
Mike Bayer committed
            </%def>
            
            ${b1()} ${b2()}  ${b3()}
Mike Bayer's avatar
Mike Bayer committed
        </%def>
Mike Bayer's avatar
Mike Bayer committed
""")
        assert flatten_result(t.render(x=5, y=None)) == "a a_b1 a_b2 a_b2_c1 a_b3 a_b3_c1 heres x: 5 y is 7 a_b3_c2 y is None c1 is a_b3_c1 heres x: 5 y is 7"
Mike Bayer's avatar
Mike Bayer committed
    def test_nested_nested_def_2(self):
Mike Bayer's avatar
Mike Bayer committed
        t = Template("""
Mike Bayer's avatar
Mike Bayer committed
        <%def name="a">
Mike Bayer's avatar
Mike Bayer committed
            <%def name="b">
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
            <%def name="c">
Mike Bayer's avatar
Mike Bayer committed
            </%def>
        </%def>
Mike Bayer's avatar
Mike Bayer committed
""" )
        assert flatten_result(t.render()) == "this is a this is b this is c"
    def test_outer_scope(self):
        t = Template("""
Mike Bayer's avatar
Mike Bayer committed
        <%def name="a">
            a: x is ${x}
Mike Bayer's avatar
Mike Bayer committed
        </%def>
Mike Bayer's avatar
Mike Bayer committed
        <%def name="b">
            <%def name="c">
            <%
                x = 10
            %>
            c. x is ${x}.  ${a()}
Mike Bayer's avatar
Mike Bayer committed
            </%def>
Mike Bayer's avatar
Mike Bayer committed
        </%def>
Mike Bayer's avatar
Mike Bayer committed
        
        x is ${x}
        assert flatten_result(t.render(x=5)) == "b. c. x is 10. a: x is 5 x is 5"
class ExceptionTest(unittest.TestCase):
    def test_raise(self):
        template = Template("""
            <%
                raise Exception("this is a test")
            %>
    """, format_exceptions=False)
        try:
            template.render()
            assert False
        except Exception, e:
            assert str(e) == "this is a test"
    def test_handler(self):
        def handle(context, error):
            context.write("error message is " + str(error))
            return True
            
        template = Template("""
            <%
                raise Exception("this is a test")
            %>
    """, error_handler=handle)
        assert template.render().strip() == """error message is this is a test"""
        

if __name__ == '__main__':
    unittest.main()