Skip to content
Snippets Groups Projects
def.py 12.1 KiB
Newer Older
from mako.template import Template
from mako import lookup
import unittest
from util import flatten_result, result_lines
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_scope_eleven(self):
        t = Template("""
            x is ${x}
            <%def name="a(x)">
                this is a, ${b()}
                <%def name="b">
                    this is b, x is ${x}
                </%def>
            </%def>
            
            ${a(x=5)}
""")
        assert result_lines(t.render(x=10)) == [
            "x is 10",
            "this is a,", 
            "this is b, x is 5"
        ]

    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"
    def test_nested_2(self):
        t = Template("""
            x is ${x}
            <%def name="a">
                this is a, x is ${x}
                ${b()}
                <%def name="b">
                    this is b: ${x}
                </%def>
            </%def>
            ${a()}
""")
        
        assert flatten_result(t.render(x=10)) == "x is 10 this is a, x is 10 this is b: 10"
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()