1from mako import exceptions
2from mako.lookup import TemplateLookup
3from mako.template import Template
4from mako.testing.assertions import assert_raises_message
5from mako.testing.fixtures import TemplateTest
6from mako.testing.helpers import result_lines
7
8
9class BlockTest(TemplateTest):
10    def test_anonymous_block_namespace_raises(self):
11        assert_raises_message(
12            exceptions.CompileException,
13            "Can't put anonymous blocks inside <%namespace>",
14            Template,
15            """
16                <%namespace name="foo">
17                    <%block>
18                        block
19                    </%block>
20                </%namespace>
21            """,
22        )
23
24    def test_anonymous_block_in_call(self):
25        template = Template(
26            """
27
28            <%self:foo x="5">
29                <%block>
30                    this is the block x
31                </%block>
32            </%self:foo>
33
34            <%def name="foo(x)">
35                foo:
36                ${caller.body()}
37            </%def>
38        """
39        )
40        self._do_test(
41            template, ["foo:", "this is the block x"], filters=result_lines
42        )
43
44    def test_named_block_in_call(self):
45        assert_raises_message(
46            exceptions.CompileException,
47            "Named block 'y' not allowed inside of <%call> tag",
48            Template,
49            """
50
51            <%self:foo x="5">
52                <%block name="y">
53                    this is the block
54                </%block>
55            </%self:foo>
56
57            <%def name="foo(x)">
58                foo:
59                ${caller.body()}
60                ${caller.y()}
61            </%def>
62        """,
63        )
64
65    def test_name_collision_blocks_toplevel(self):
66        assert_raises_message(
67            exceptions.CompileException,
68            "%def or %block named 'x' already exists in this template",
69            Template,
70            """
71                <%block name="x">
72                    block
73                </%block>
74
75                foob
76
77                <%block name="x">
78                    block
79                </%block>
80            """,
81        )
82
83    def test_name_collision_blocks_nested_block(self):
84        assert_raises_message(
85            exceptions.CompileException,
86            "%def or %block named 'x' already exists in this template",
87            Template,
88            """
89                <%block>
90                <%block name="x">
91                    block
92                </%block>
93
94                foob
95
96                <%block name="x">
97                    block
98                </%block>
99                </%block>
100            """,
101        )
102
103    def test_name_collision_blocks_nested_def(self):
104        assert_raises_message(
105            exceptions.CompileException,
106            "Named block 'x' not allowed inside of def 'foo'",
107            Template,
108            """
109                <%def name="foo()">
110                <%block name="x">
111                    block
112                </%block>
113
114                foob
115
116                <%block name="x">
117                    block
118                </%block>
119                </%def>
120            """,
121        )
122
123    def test_name_collision_block_def_toplevel(self):
124        assert_raises_message(
125            exceptions.CompileException,
126            "%def or %block named 'x' already exists in this template",
127            Template,
128            """
129                <%block name="x">
130                    block
131                </%block>
132
133                foob
134
135                <%def name="x()">
136                    block
137                </%def>
138            """,
139        )
140
141    def test_name_collision_def_block_toplevel(self):
142        assert_raises_message(
143            exceptions.CompileException,
144            "%def or %block named 'x' already exists in this template",
145            Template,
146            """
147                <%def name="x()">
148                    block
149                </%def>
150
151                foob
152
153                <%block name="x">
154                    block
155                </%block>
156
157            """,
158        )
159
160    def test_named_block_renders(self):
161        template = Template(
162            """
163            above
164            <%block name="header">
165                the header
166            </%block>
167            below
168        """
169        )
170        self._do_test(
171            template, ["above", "the header", "below"], filters=result_lines
172        )
173
174    def test_inherited_block_no_render(self):
175        l = TemplateLookup()
176        l.put_string(
177            "index",
178            """
179                <%inherit file="base"/>
180                <%block name="header">
181                    index header
182                </%block>
183            """,
184        )
185        l.put_string(
186            "base",
187            """
188            above
189            <%block name="header">
190                the header
191            </%block>
192
193            ${next.body()}
194            below
195        """,
196        )
197        self._do_test(
198            l.get_template("index"),
199            ["above", "index header", "below"],
200            filters=result_lines,
201        )
202
203    def test_no_named_in_def(self):
204        assert_raises_message(
205            exceptions.CompileException,
206            "Named block 'y' not allowed inside of def 'q'",
207            Template,
208            """
209            <%def name="q()">
210                <%block name="y">
211                </%block>
212            </%def>
213        """,
214        )
215
216    def test_inherited_block_nested_both(self):
217        l = TemplateLookup()
218        l.put_string(
219            "index",
220            """
221                <%inherit file="base"/>
222                <%block name="title">
223                    index title
224                </%block>
225
226                <%block name="header">
227                    index header
228                    ${parent.header()}
229                </%block>
230            """,
231        )
232        l.put_string(
233            "base",
234            """
235            above
236            <%block name="header">
237                base header
238                <%block name="title">
239                    the title
240                </%block>
241            </%block>
242
243            ${next.body()}
244            below
245        """,
246        )
247        self._do_test(
248            l.get_template("index"),
249            ["above", "index header", "base header", "index title", "below"],
250            filters=result_lines,
251        )
252
253    def test_inherited_block_nested_inner_only(self):
254        l = TemplateLookup()
255        l.put_string(
256            "index",
257            """
258                <%inherit file="base"/>
259                <%block name="title">
260                    index title
261                </%block>
262
263            """,
264        )
265        l.put_string(
266            "base",
267            """
268            above
269            <%block name="header">
270                base header
271                <%block name="title">
272                    the title
273                </%block>
274            </%block>
275
276            ${next.body()}
277            below
278        """,
279        )
280        self._do_test(
281            l.get_template("index"),
282            ["above", "base header", "index title", "below"],
283            filters=result_lines,
284        )
285
286    def test_noninherited_block_no_render(self):
287        l = TemplateLookup()
288        l.put_string(
289            "index",
290            """
291                <%inherit file="base"/>
292                <%block name="some_thing">
293                    some thing
294                </%block>
295            """,
296        )
297        l.put_string(
298            "base",
299            """
300            above
301            <%block name="header">
302                the header
303            </%block>
304
305            ${next.body()}
306            below
307        """,
308        )
309        self._do_test(
310            l.get_template("index"),
311            ["above", "the header", "some thing", "below"],
312            filters=result_lines,
313        )
314
315    def test_no_conflict_nested_one(self):
316        l = TemplateLookup()
317        l.put_string(
318            "index",
319            """
320                <%inherit file="base"/>
321                <%block>
322                    <%block name="header">
323                        inner header
324                    </%block>
325                </%block>
326            """,
327        )
328        l.put_string(
329            "base",
330            """
331            above
332            <%block name="header">
333                the header
334            </%block>
335
336            ${next.body()}
337            below
338        """,
339        )
340        self._do_test(
341            l.get_template("index"),
342            ["above", "inner header", "below"],
343            filters=result_lines,
344        )
345
346    def test_nested_dupe_names_raise(self):
347        assert_raises_message(
348            exceptions.CompileException,
349            "%def or %block named 'header' already exists in this template.",
350            Template,
351            """
352                <%inherit file="base"/>
353                <%block name="header">
354                    <%block name="header">
355                        inner header
356                    </%block>
357                </%block>
358            """,
359        )
360
361    def test_two_levels_one(self):
362        l = TemplateLookup()
363        l.put_string(
364            "index",
365            """
366                <%inherit file="middle"/>
367                <%block name="header">
368                    index header
369                </%block>
370                <%block>
371                    index anon
372                </%block>
373            """,
374        )
375        l.put_string(
376            "middle",
377            """
378            <%inherit file="base"/>
379            <%block>
380                middle anon
381            </%block>
382            ${next.body()}
383        """,
384        )
385        l.put_string(
386            "base",
387            """
388            above
389            <%block name="header">
390                the header
391            </%block>
392
393            ${next.body()}
394            below
395        """,
396        )
397        self._do_test(
398            l.get_template("index"),
399            ["above", "index header", "middle anon", "index anon", "below"],
400            filters=result_lines,
401        )
402
403    def test_filter(self):
404        template = Template(
405            """
406            <%block filter="h">
407                <html>
408            </%block>
409        """
410        )
411        self._do_test(template, ["&lt;html&gt;"], filters=result_lines)
412
413    def test_anon_in_named(self):
414        template = Template(
415            """
416            <%block name="x">
417                outer above
418                <%block>
419                    inner
420                </%block>
421                outer below
422            </%block>
423        """
424        )
425        self._test_block_in_block(template)
426
427    def test_named_in_anon(self):
428        template = Template(
429            """
430            <%block>
431                outer above
432                <%block name="x">
433                    inner
434                </%block>
435                outer below
436            </%block>
437        """
438        )
439        self._test_block_in_block(template)
440
441    def test_anon_in_anon(self):
442        template = Template(
443            """
444            <%block>
445                outer above
446                <%block>
447                    inner
448                </%block>
449                outer below
450            </%block>
451        """
452        )
453        self._test_block_in_block(template)
454
455    def test_named_in_named(self):
456        template = Template(
457            """
458            <%block name="x">
459                outer above
460                <%block name="y">
461                    inner
462                </%block>
463                outer below
464            </%block>
465        """
466        )
467        self._test_block_in_block(template)
468
469    def _test_block_in_block(self, template):
470        self._do_test(
471            template,
472            ["outer above", "inner", "outer below"],
473            filters=result_lines,
474        )
475
476    def test_iteration(self):
477        t = Template(
478            """
479            % for i in (1, 2, 3):
480                <%block>${i}</%block>
481            % endfor
482        """
483        )
484        self._do_test(t, ["1", "2", "3"], filters=result_lines)
485
486    def test_conditional(self):
487        t = Template(
488            """
489            % if True:
490                <%block>true</%block>
491            % endif
492
493            % if False:
494                <%block>false</%block>
495            % endif
496        """
497        )
498        self._do_test(t, ["true"], filters=result_lines)
499
500    def test_block_overridden_by_def(self):
501        l = TemplateLookup()
502        l.put_string(
503            "index",
504            """
505                <%inherit file="base"/>
506                <%def name="header()">
507                    inner header
508                </%def>
509            """,
510        )
511        l.put_string(
512            "base",
513            """
514            above
515            <%block name="header">
516                the header
517            </%block>
518
519            ${next.body()}
520            below
521        """,
522        )
523        self._do_test(
524            l.get_template("index"),
525            ["above", "inner header", "below"],
526            filters=result_lines,
527        )
528
529    def test_def_overridden_by_block(self):
530        l = TemplateLookup()
531        l.put_string(
532            "index",
533            """
534                <%inherit file="base"/>
535                <%block name="header">
536                    inner header
537                </%block>
538            """,
539        )
540        l.put_string(
541            "base",
542            """
543            above
544            ${self.header()}
545            <%def name="header()">
546                the header
547            </%def>
548
549            ${next.body()}
550            below
551        """,
552        )
553        self._do_test(
554            l.get_template("index"),
555            ["above", "inner header", "below"],
556            filters=result_lines,
557        )
558
559    def test_block_args(self):
560        l = TemplateLookup()
561        l.put_string(
562            "caller",
563            """
564
565            <%include file="callee" args="val1='3', val2='4'"/>
566
567        """,
568        )
569        l.put_string(
570            "callee",
571            """
572            <%page args="val1, val2"/>
573            <%block name="foob" args="val1, val2">
574                foob, ${val1}, ${val2}
575            </%block>
576        """,
577        )
578        self._do_test(
579            l.get_template("caller"), ["foob, 3, 4"], filters=result_lines
580        )
581
582    def test_block_variables_contextual(self):
583        t = Template(
584            """
585            <%block name="foob" >
586                foob, ${val1}, ${val2}
587            </%block>
588        """
589        )
590        self._do_test(
591            t,
592            ["foob, 3, 4"],
593            template_args={"val1": 3, "val2": 4},
594            filters=result_lines,
595        )
596
597    def test_block_args_contextual(self):
598        t = Template(
599            """
600            <%page args="val1"/>
601            <%block name="foob" args="val1">
602                foob, ${val1}, ${val2}
603            </%block>
604        """
605        )
606        self._do_test(
607            t,
608            ["foob, 3, 4"],
609            template_args={"val1": 3, "val2": 4},
610            filters=result_lines,
611        )
612
613    def test_block_pageargs_contextual(self):
614        t = Template(
615            """
616            <%block name="foob">
617                foob, ${pageargs['val1']}, ${pageargs['val2']}
618            </%block>
619        """
620        )
621        self._do_test(
622            t,
623            ["foob, 3, 4"],
624            template_args={"val1": 3, "val2": 4},
625            filters=result_lines,
626        )
627
628    def test_block_pageargs(self):
629        l = TemplateLookup()
630        l.put_string(
631            "caller",
632            """
633
634            <%include file="callee" args="val1='3', val2='4'"/>
635
636        """,
637        )
638        l.put_string(
639            "callee",
640            """
641            <%block name="foob">
642                foob, ${pageargs['val1']}, ${pageargs['val2']}
643            </%block>
644        """,
645        )
646        self._do_test(
647            l.get_template("caller"), ["foob, 3, 4"], filters=result_lines
648        )
649