Skip to content
Snippets Groups Projects
component.py 12.9 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

class ComponentTest(unittest.TestCase):
    def test_component_noargs(self):
        template = Template("""
        
        ${mycomp()}
        
        <%component name="mycomp">
            hello mycomp ${variable}
        </%component>
        
        """)
        print template.code
        assert template.render(variable='hi').strip() == """hello mycomp hi"""

    def test_component_blankargs(self):
        template = Template("""
        <%component name="mycomp()">
            hello mycomp ${variable}
        </%component>

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

    def test_component_args(self):
        template = Template("""
        <%component name="mycomp(a, b)">
            hello mycomp ${variable}, ${a}, ${b}
        </%component>

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

    def test_inter_component(self):
        """test components calling each other"""
        template = Template("""
Mike Bayer's avatar
Mike Bayer committed
        ${b()}
Mike Bayer's avatar
Mike Bayer committed
        <%component name="a">\
        im a
        </%component>
Mike Bayer's avatar
Mike Bayer committed
        <%component name="b">
        im b
        and heres a:  ${a()}
        </%component>
Mike Bayer's avatar
Mike Bayer committed
        <%component name="c">
        im c
        </%component>
""")
        # 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("""
        <%component name="a">
            this is a, and y is ${y}
        </%component>

        ${a()}

        <%
            y = 7
        %>

        ${a()}

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
""")
        assert flatten_result(t.render(y=None)) == "y is None y is 7"
    def test_scope_three(self):
        """test in place assignment/undeclared variable combinations
        
        i.e. things like 'x=x+1', x is declared and undeclared at the same time"""
        template = Template("""
        hi
    	<%component name="a">
    	    y is ${y}

            <%
                x = x + y
                a = 3
            %>
            
            x is ${x}
    	</%component>

    	${a()}
    """)
Mike Bayer's avatar
Mike Bayer committed
        assert flatten_result(template.render(x=5, y=10)) == "hi y is 10 x is 15"
    def test_scope_four(self):
        """test that variables are pulled from 'enclosing' scope before context."""
        t = Template("""
            <%
                x = 5
            %>
            <%component name="a">
                this is a. x is ${x}.
            </%component>
            
            <%component name="b">
                <%
                    x = 9
                %>
                this is b. x is ${x}.
                calling a. ${a()}
            </%component>
        
            ${b()}
""")
        print t.code
        print t.render()
        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("""
            <%component name="enclosing">
            <%
                x = 5
            %>
            <%component name="a">
                this is a. x is ${x}.
            </%component>

            <%component name="b">
                <%
                    x = 9
                %>
                this is b. x is ${x}.
                calling a. ${a()}
            </%component>

            ${b()}
            </%component>
            ${enclosing()}
""")
        print t.code
        print t.render()
        assert flatten_result(t.render()) == "this is b. x is 9. calling a. this is a. x is 5."

    def test_scope_six(self):
        """test that the initial context counts as 'enclosing' scope, for plain components"""
        t = Template("""

        <%component name="a">
            a: x is ${x}
        </%component>

        <%component name="b">
            <%
                x = 10
            %>
            b. x is ${x}.  ${a()}
        </%component>

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

    def test_scope_seven(self):
        """test that the initial context counts as 'enclosing' scope, for nested components"""
        t = Template("""
        <%component name="enclosing">
            <%component name="a">
                a: x is ${x}
            </%component>

            <%component name="b">
                <%
                    x = 10
                %>
                b. x is ${x}.  ${a()}
            </%component>

            ${b()}
        </%component>
        ${enclosing()}
    """)
        assert flatten_result(t.render(x=5)) == "b. x is 10. a: x is 5"

    def test_scope_eight(self):
        """test that the initial context counts as 'enclosing' scope, for nested components"""
        t = Template("""
        <%component name="enclosing">
            <%component name="a">
                a: x is ${x}
            </%component>

            <%component name="b">
                <%
                    x = 10
                    context['x'] = x
                %>
                
                b. x is ${x}.  ${a()}
            </%component>

            ${b()}
        </%component>
        ${enclosing()}
    """)
        assert flatten_result(t.render(x=5)) == "b. x is 10. a: x is 10"

    def test_scope_nine(self):
        """test that 'enclosing scope' doesnt get exported to other templates"""
        tmpl = {}
        class LocalTmplCollection(lookup.TemplateCollection):
            def get_template(self, uri):
                return tmpl[uri]
        collection = LocalTmplCollection()
        
        tmpl['main'] = Template("""
        <%
            x = 5
        %>
        this is main.  <%include file="secondary"/>
""", lookup=collection)

        tmpl['secondary'] = Template("""
        this is secondary.  x is ${x}
""", lookup=collection)

        assert flatten_result(tmpl['main'].render(x=2)) == "this is main. this is secondary. x is 2"
        
        
class NestedComponentTest(unittest.TestCase):
    def test_nested_component(self):
Mike Bayer's avatar
Mike Bayer committed
        t = Template("""

        ${hi()}
        
        <%component name="hi">
            hey, im hi.
            and heres ${foo()}, ${bar()}
            
            <%component name="foo">
                this is foo
            </%component>
            
            <%component name="bar">
                this is bar
            </%component>
        </%component>
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()}
        <%component name="a">
            <%component name="b(x, y=2)">
                b x is ${x} y is ${y}
            </%component>
            a ${b(5)}
        </%component>
""")
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
        
    def test_nested_component_2(self):
        template = Template("""
        ${a()}
        <%component name="a">
            <%component name="b">
                <%component name="c">
                    comp c
                </%component>
                ${c()}
            </%component>
            ${b()}
        </%component>
""")
Mike Bayer's avatar
Mike Bayer committed
        assert flatten_result(template.render()) == "comp c"

    def test_nested_nested_component(self):
Mike Bayer's avatar
Mike Bayer committed
        t = Template("""
        
        ${a()}
        <%component name="a">
            <%component name="b1">
            </%component>
            <%component name="b2">
                a_b2 ${c1()}
                <%component name="c1">
                    a_b2_c1
                </%component>
            </%component>
            <%component name="b3">
                a_b3 ${c1()}
                <%component name="c1">
                    a_b3_c1 heres x: ${x}
                    <%
                        y = 7
                    %>
                    y is ${y}
                </%component>
                <%component name="c2">
                    a_b3_c2
                    y is ${y}
                    c1 is ${c1()}
                </%component>
                ${c2()}
            </%component>
            
            ${b1()} ${b2()}  ${b3()}
        </%component>
Mike Bayer's avatar
Mike Bayer committed
""")
Mike Bayer's avatar
Mike Bayer committed
        assert flatten_result(t.render(x=5)) == "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"
    
    def test_nested_nested_component_2(self):
Mike Bayer's avatar
Mike Bayer committed
        t = Template("""
        <%component name="a">
            this is a ${b()}
            <%component name="b">
                this is b
                ${c()}
            </%component>
            
            <%component name="c">
                this is c
            </%component>
        </%component>
        ${a()}
Mike Bayer's avatar
Mike Bayer committed
""" )
        assert flatten_result(t.render()) == "this is a this is b this is c"

    def test_scope_ten(self):
        t = Template("""
            main/y: ${y}
            
            <%component name="a">
                <%component name="b">
                    b/y: ${y}
                    <%
                        y = 19
                    %>
                    b/c: ${c()}
                    b/y: ${y}
                </%component>
                
                a/y: ${y}
                <%
                    y = 10
                    x  = 12
                %>
                a/y: ${y}
                a/b: ${b()}
                <%component name="c">
                    c/y: ${y}
                </%component>
            </%component>

            <%
                y = 7
            %>
            main/y: ${y}
            main/a: ${a}
            main/y: ${y}
""")
    def test_local_local_names(self):
        """test assignment of variables inside nested components, which requires extra scoping logic"""
Mike Bayer's avatar
Mike Bayer committed
        t = Template("""
            heres y: ${y}
            
            <%component name="a">
                <%component name="b">
                    b, heres y: ${y}
                    
                    <%
                        y = 19
                    %>
                    
                    b, heres c: ${c()}
                    
                    b, heres y again: ${y}
                </%component>
                
                a, heres y: ${y}
                <% 
                    y = 10
                    x = 12
                %>
                
                a, now heres y: ${y}
                a, heres b: ${b()}
                
                <%component name="c">
                    this is c
                </%component>
            </%component>
            
        <%
            y = 7
        %>
Mike Bayer's avatar
Mike Bayer committed
""")
        print t.code
        print flatten_result(t.render(y=5))
Mike Bayer's avatar
Mike Bayer committed
        assert flatten_result(t.render(y=5)) == "heres y: 5 now heres y 7 a, heres y: 7 a, now heres y: 10 a, heres b: b, heres y: 10 b, heres c: this is c b, heres y again: 19 heres y again: 7"

    def test_outer_scope(self):
        t = Template("""
        <%component name="a">
            a: x is ${x}
        </%component>

        <%component name="b">
            <%component name="c">
            <%
                x = 10
            %>
            c. x is ${x}.  ${a()}
            
            b. ${c()}
        </%component>

        ${b()}
Mike Bayer's avatar
Mike Bayer committed
        
        x is ${x}
Mike Bayer's avatar
Mike Bayer committed
        assert flatten_result(t.render(x=5)) == "b. c. x is 10. a: x is 10 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()