1#============================================================= -*-perl-*-
2#
3# t/view.t
4#
5# Tests the 'View' plugin.
6#
7# Written by Andy Wardley <abw@kfs.org>
8#
9# Copyright (C) 2000 Andy Wardley. All Rights Reserved.
10#
11# This is free software; you can redistribute it and/or modify it
12# under the same terms as Perl itself.
13#
14# $Id$
15#
16#========================================================================
17
18use strict;
19use lib qw( ./lib ../lib );
20use Template::Test;
21$^W = 1;
22
23use Template::View;
24
25#$Template::View::DEBUG = 1;
26#$Template::Test::DEBUG = 0;
27#$Template::Parser::DEBUG = 1;
28#$Template::Directive::PRETTY = 1;
29$Template::Test::PRESERVE = 1;
30
31#------------------------------------------------------------------------
32package Foo;
33
34sub new {
35    my $class = shift;
36    bless { @_ }, $class;
37}
38
39sub present {
40    my $self = shift;
41    return '{ ' . join(', ', map { "$_ => $self->{ $_ }" } 
42		       sort keys %$self) . ' }';
43}
44
45sub reverse {
46    my $self = shift;
47    return '{ ' . join(', ', map { "$_ => $self->{ $_ }" } 
48		       reverse sort keys %$self) . ' }';
49}
50
51#------------------------------------------------------------------------
52package Blessed::List;
53
54sub as_list {
55    my $self = shift;
56    return @$self;
57}
58
59#------------------------------------------------------------------------
60package main;
61
62my $vars = {
63    foo => Foo->new( pi => 3.14, e => 2.718 ),
64    blessed_list => bless([ "Hello", "World" ], 'Blessed::List'),
65};
66
67my $template = Template->new() || die Template->error;
68my $context  = $template->context();
69my $view     = $context->view( );
70ok( $view );
71
72$view = $context->view( prefix => 'my' );
73ok( $view );
74match( $view->prefix(), 'my' );
75
76my $config = {
77    VIEWS => [
78        bottom => { prefix => 'bottom/' },
79        middle => { prefix => 'middle/', base => 'bottom' },
80    ],
81};
82        
83test_expect(\*DATA, $config, $vars);
84
85__DATA__
86-- test --
87-- name pre-defined bottom view --
88[% BLOCK bottom/list; "BOTTOM LIST: "; item.join(', '); END;
89   list = [10, 20 30];
90   bottom.print(list)
91%]
92-- expect --
93BOTTOM LIST: 10, 20, 30
94
95-- test --
96-- name pre-defined middle view --
97[% BLOCK bottom/list; "BOTTOM LIST: "; item.join(', '); END;
98   BLOCK middle/hash; "MIDDLE HASH: "; item.values.nsort.join(', '); END;
99   list = [10, 20 30];
100   hash = { pi => 3.142, e => 2.718 };
101   middle.print(list); "\n";
102   middle.print(hash); "\n";
103%]
104-- expect --
105BOTTOM LIST: 10, 20, 30
106MIDDLE HASH: 2.718, 3.142
107
108-- test --
109[% USE v = View -%]
110[[% v.prefix %]]
111-- expect --
112[]
113
114-- test --
115[% USE v = View( map => { default="any" } ) -%]
116[[% v.map.default %]]
117-- expect --
118[any]
119
120-- test --
121[% USE view( prefix=> 'foo/', suffix => '.tt2') -%]
122[[% view.prefix %]bar[% view.suffix %]]
123[[% view.template_name('baz') %]]
124-- expect --
125[foo/bar.tt2]
126[foo/baz.tt2]
127
128-- test --
129[% USE view( prefix=> 'foo/', suffix => '.tt2') -%]
130[[% view.prefix %]bar[% view.suffix %]]
131[[% view.template_name('baz') %]]
132-- expect --
133[foo/bar.tt2]
134[foo/baz.tt2]
135
136-- test --
137[% USE view -%]
138[% view.print('Hello World') %]
139[% BLOCK text %]TEXT: [% item %][% END -%]
140-- expect --
141TEXT: Hello World
142
143-- test --
144[% USE view -%]
145[% view.print( { foo => 'bar' } ) %]
146[% BLOCK hash %]HASH: {
147[% FOREACH key = item.keys.sort -%]
148   [% key %] => [% item.$key %]
149[%- END %]
150}
151[% END -%]
152-- expect --
153HASH: {
154   foo => bar
155}
156
157-- test --
158[% USE view -%]
159[% view = view.clone( prefix => 'my_' ) -%]
160[% view.view('hash', { bar => 'baz' }) %]
161[% BLOCK my_hash %]HASH: {
162[% FOREACH key = item.keys.sort -%]
163   [% key %] => [% item.$key %]
164[%- END %]
165}
166[% END -%]
167-- expect --
168HASH: {
169   bar => baz
170}
171
172
173-- test --
174[% USE view(prefix='my_') -%]
175[% view.print( foo => 'wiz', bar => 'waz' ) %]
176[% BLOCK my_hash %]KEYS: [% item.keys.sort.join(', ') %][% END %]
177
178-- expect --
179KEYS: bar, foo
180
181-- test --
182[% USE view -%]
183[% view.print( view ) %]
184[% BLOCK Template_View %]Printing a Template::View object[% END -%]
185-- expect --
186Printing a Template::View object
187
188-- test --
189[% USE view(prefix='my_') -%]
190[% view.print( view ) %]
191[% view.print( view, prefix='your_' ) %]
192[% BLOCK my_Template_View %]Printing my Template::View object[% END -%]
193[% BLOCK your_Template_View %]Printing your Template::View object[% END -%]
194-- expect --
195Printing my Template::View object
196Printing your Template::View object
197
198-- test --
199[% USE view(prefix='my_', notfound='any' ) -%]
200[% view.print( view ) %]
201[% view.print( view, prefix='your_' ) %]
202[% BLOCK my_any %]Printing any of my objects[% END -%]
203[% BLOCK your_any %]Printing any of your objects[% END -%]
204-- expect --
205Printing any of my objects
206Printing any of your objects
207
208-- test --
209[% USE view(prefix => 'my_', map => { default => 'catchall' } ) -%]
210[% view.print( view ) %]
211[% view.print( view, default="catchsome" ) %]
212[% BLOCK my_catchall %]Catching all defaults[% END -%]
213[% BLOCK my_catchsome %]Catching some defaults[% END -%]
214-- expect --
215Catching all defaults
216Catching some defaults
217
218-- test --
219[% USE view(prefix => 'my_', map => { default => 'catchnone' } ) -%]
220[% view.default %]
221[% view.default = 'catchall' -%]
222[% view.default %]
223[% view.print( view ) %]
224[% view.print( view, default="catchsome" ) %]
225[% BLOCK my_catchall %]Catching all defaults[% END -%]
226[% BLOCK my_catchsome %]Catching some defaults[% END -%]
227-- expect --
228catchnone
229catchall
230Catching all defaults
231Catching some defaults
232
233-- test --
234[% USE view(prefix='my_', default='catchall' notfound='lost') -%]
235[% view.print( view ) %]
236[% BLOCK my_lost %]Something has been found[% END -%]
237-- expect --
238Something has been found
239
240-- test --
241[% USE view -%]
242[% TRY ;
243     view.print( view ) ;
244   CATCH view ;
245     "[$error.type] $error.info" ;
246   END
247%]
248-- expect --
249[view] file error - Template_View: not found
250
251
252-- test --
253[% USE view -%]
254[% view.print( foo ) %]
255-- expect --
256{ e => 2.718, pi => 3.14 }
257
258-- test --
259[% USE view -%]
260[% view.print( foo, method => 'reverse' ) %]
261-- expect --
262{ pi => 3.14, e => 2.718 }
263
264-- test --
265[% USE view(prefix='my_', include_naked=0, view_naked=1) -%]
266[% BLOCK my_foo; "Foo: $item"; END -%]
267[[% view.view_foo(20) %]]
268[[% view.foo(30) %]]
269-- expect --
270[Foo: 20]
271[Foo: 30]
272
273-- test --
274[% USE view(prefix='my_', include_naked=0, view_naked=0) -%]
275[% BLOCK my_foo; "Foo: $item"; END -%]
276[[% view.view_foo(20) %]]
277[% TRY ;
278     view.foo(30) ;
279   CATCH ;
280     error.info ;
281   END
282%]
283-- expect --
284[Foo: 20]
285no such view member: foo
286
287-- test --
288[% USE view(map => { HASH => 'my_hash', ARRAY => 'your_list' }) -%]
289[% BLOCK text %]TEXT: [% item %][% END -%]
290[% BLOCK my_hash %]HASH: [% item.keys.sort.join(', ') %][% END -%]
291[% BLOCK your_list %]LIST: [% item.join(', ') %][% END -%]
292[% view.print("some text") %]
293[% view.print({ alpha => 'a', bravo => 'b' }) %]
294[% view.print([ 'charlie', 'delta' ]) %]
295-- expect --
296TEXT: some text
297HASH: alpha, bravo
298LIST: charlie, delta
299
300-- test --
301[% USE view(item => 'thing',
302	    map => { HASH => 'my_hash', ARRAY => 'your_list' }) -%]
303[% BLOCK text %]TEXT: [% thing %][% END -%]
304[% BLOCK my_hash %]HASH: [% thing.keys.sort.join(', ') %][% END -%]
305[% BLOCK your_list %]LIST: [% thing.join(', ') %][% END -%]
306[% view.print("some text") %]
307[% view.print({ alpha => 'a', bravo => 'b' }) %]
308[% view.print([ 'charlie', 'delta' ]) %]
309-- expect --
310TEXT: some text
311HASH: alpha, bravo
312LIST: charlie, delta
313
314-- test --
315[% USE view -%]
316[% view.print('Hello World') %]
317[% view1 = view.clone( prefix='my_') -%]
318[% view1.print('Hello World') %]
319[% view2 = view1.clone( prefix='dud_', notfound='no_text' ) -%]
320[% view2.print('Hello World') %]
321[% BLOCK text %]TEXT: [% item %][% END -%]
322[% BLOCK my_text %]MY TEXT: [% item %][% END -%]
323[% BLOCK dud_no_text %]NO TEXT: [% item %][% END -%]
324-- expect --
325TEXT: Hello World
326MY TEXT: Hello World
327NO TEXT: Hello World
328
329-- test --
330[% USE view( prefix = 'base_', default => 'any' ) -%]
331[% view1 = view.clone( prefix => 'one_') -%]
332[% view2 = view.clone( prefix => 'two_') -%]
333[% view.default %] / [% view.map.default %]
334[% view1.default = 'anyone' -%]
335[% view1.default %] / [% view1.map.default %]
336[% view2.map.default = 'anytwo' -%]
337[% view2.default %] / [% view2.map.default %]
338[% view.print("Hello World") %] / [% view.print(blessed_list) %]
339[% view1.print("Hello World") %] / [% view1.print(blessed_list) %]
340[% view2.print("Hello World") %] / [% view2.print(blessed_list) %]
341[% BLOCK base_text %]ANY TEXT: [% item %][% END -%]
342[% BLOCK one_text %]ONE TEXT: [% item %][% END -%]
343[% BLOCK two_text %]TWO TEXT: [% item %][% END -%]
344[% BLOCK base_any %]BASE ANY: [% item.as_list.join(', ') %][% END -%]
345[% BLOCK one_anyone %]ONE ANY: [% item.as_list.join(', ') %][% END -%]
346[% BLOCK two_anytwo %]TWO ANY: [% item.as_list.join(', ') %][% END -%]
347-- expect --
348any / any
349anyone / anyone
350anytwo / anytwo
351ANY TEXT: Hello World / BASE ANY: Hello, World
352ONE TEXT: Hello World / ONE ANY: Hello, World
353TWO TEXT: Hello World / TWO ANY: Hello, World
354
355-- test --
356[% USE view( prefix => 'my_', item => 'thing' ) -%]
357[% view.view('thingy', [ 'foo', 'bar'] ) %]
358[% BLOCK my_thingy %]thingy: [ [% thing.join(', ') %] ][%END %]
359-- expect --
360thingy: [ foo, bar ]
361
362-- test --
363[% USE view -%]
364[% view.map.${'Template::View'} = 'myview' -%]
365[% view.print(view) %]
366[% BLOCK myview %]MYVIEW[% END%]
367-- expect --
368MYVIEW
369
370-- test --
371[% USE view -%]
372[% view.include('greeting', msg => 'Hello World!') %]
373[% BLOCK greeting %]msg: [% msg %][% END -%]
374-- expect --
375msg: Hello World!
376
377-- test --
378[% USE view( prefix="my_" )-%]
379[% view.include('greeting', msg => 'Hello World!') %]
380[% BLOCK my_greeting %]msg: [% msg %][% END -%]
381-- expect --
382msg: Hello World!
383
384-- test --
385[% USE view( prefix="my_" )-%]
386[% view.include_greeting( msg => 'Hello World!') %]
387[% BLOCK my_greeting %]msg: [% msg %][% END -%]
388-- expect --
389msg: Hello World!
390
391-- test --
392[% USE view( prefix="my_" )-%]
393[% INCLUDE $view.template('greeting')
394   msg = 'Hello World!' %]
395[% BLOCK my_greeting %]msg: [% msg %][% END -%]
396-- expect --
397msg: Hello World!
398
399-- test --
400[% USE view( title="My View" )-%]
401[% view.title %]
402-- expect --
403My View
404
405-- test --
406[% USE view( title="My View" )-%]
407[% newview = view.clone( col = 'Chartreuse') -%]
408[% newerview = newview.clone( title => 'New Title' ) -%]
409[% view.title %]
410[% newview.title %]
411[% newview.col %]
412[% newerview.title %]
413[% newerview.col %]
414-- expect --
415My View
416My View
417Chartreuse
418New Title
419Chartreuse
420
421
422#------------------------------------------------------------------------
423
424-- test --
425[% VIEW fred prefix='blat_' %]
426This is the view
427[% END -%]
428[% BLOCK blat_foo; 'This is blat_foo'; END -%]
429[% fred.view_foo %]
430-- expect --
431This is blat_foo
432
433-- test --
434[% VIEW fred %]
435This is the view
436[% view.prefix = 'blat_' %]
437[% END -%]
438[% BLOCK blat_foo; 'This is blat_foo'; END -%]
439[% fred.view_foo %]
440-- expect --
441This is blat_foo
442
443-- test --
444[% VIEW fred %]
445This is the view
446[% view.prefix = 'blat_' %]
447[% view.thingy = 'bloop' %]
448[% fred.name = 'Freddy' %]
449[% END -%]
450[% fred.prefix %]
451[% fred.thingy %]
452[% fred.name %]
453-- expect --
454blat_
455bloop
456Freddy
457
458
459-- test --
460[% VIEW fred prefix='blat_'; view.name='Fred'; END -%]
461[% fred.prefix %]
462[% fred.name %]
463[% TRY;
464     fred.prefix = 'nonblat_';
465   CATCH;
466     error;
467   END
468%]
469[% TRY;
470     fred.name = 'Derek';
471   CATCH;
472     error;
473   END
474%]
475-- expect --
476blat_
477Fred
478view error - cannot update config item in sealed view: prefix
479view error - cannot update item in sealed view: name
480
481-- test --
482[% VIEW foo prefix='blat_' default="default" notfound="notfound"
483     title="fred" age=23 height=1.82 %]
484[% view.other = 'another' %]
485[% END -%]
486[% BLOCK blat_hash -%]
487[% FOREACH key = item.keys.sort -%]
488   [% key %] => [% item.$key %]
489[% END -%]
490[% END -%]
491[% foo.print(foo.data) %]
492-- expect --
493   age => 23
494   height => 1.82
495   other => another
496   title => fred
497
498-- test --
499[% VIEW foo %]
500[% BLOCK hello -%]
501Hello World!
502[% END %]
503[% BLOCK goodbye -%]
504Goodbye World!
505[% END %]
506[% END -%]
507[% TRY; INCLUDE foo; CATCH; error; END %]
508[% foo.include_hello %]
509-- expect --
510file error - foo: not found
511Hello World!
512
513-- test --
514[% title = "Previous Title" -%]
515[% VIEW foo 
516     include_naked = 1
517     title = title or 'Default Title'
518     copy  = 'me, now'
519-%]
520
521[% view.bgcol = '#ffffff' -%]
522
523[% BLOCK header -%]
524Header:  bgcol: [% view.bgcol %]
525         title: [% title %]
526    view.title: [% view.title %]
527[%- END %]
528
529[% BLOCK footer -%]
530&copy; Copyright [% view.copy %]
531[%- END %]
532
533[% END -%]
534[% title = 'New Title' -%]
535[% foo.header %]
536[% foo.header(bgcol='#dead' title="Title Parameter") %]
537[% foo.footer %]
538[% foo.footer(copy="you, then") %]
539
540-- expect --
541Header:  bgcol: #ffffff
542         title: New Title
543    view.title: Previous Title
544Header:  bgcol: #ffffff
545         title: Title Parameter
546    view.title: Previous Title
547&copy; Copyright me, now
548&copy; Copyright me, now
549
550-- test --
551[% VIEW foo 
552    title  = 'My View' 
553    author = 'Andy Wardley'
554    bgcol  = bgcol or '#ffffff'
555-%]
556[% view.arg1 = 'argument #1' -%]
557[% view.data.arg2 = 'argument #2' -%]
558[% END -%]
559 [% foo.title %]
560 [% foo.author %]
561 [% foo.bgcol %]
562 [% foo.arg1 %]
563 [% foo.arg2 %]
564[% bar = foo.clone( title='New View', arg1='New Arg1' ) %]cloned!
565 [% bar.title %]
566 [% bar.author %]
567 [% bar.bgcol %]
568 [% bar.arg1 %]
569 [% bar.arg2 %]
570originals:
571 [% foo.title %]
572 [% foo.arg1 %]
573
574
575-- expect --
576 My View
577 Andy Wardley
578 #ffffff
579 argument #1
580 argument #2
581cloned!
582 New View
583 Andy Wardley
584 #ffffff
585 New Arg1
586 argument #2
587originals:
588 My View
589 argument #1
590
591
592-- test --
593[% VIEW basic title = "My Web Site" %]
594  [% BLOCK header -%]
595  This is the basic header: [% title or view.title %]
596  [%- END -%]
597[% END -%]
598
599[%- VIEW fancy 
600      title = "<fancy>$basic.title</fancy>"
601      basic = basic 
602%]
603  [% BLOCK header ; view.basic.header(title = title or view.title) %]
604  Fancy new part of header
605  [%- END %]
606[% END -%]
607===
608[% basic.header %]
609[% basic.header( title = "New Title" ) %]
610===
611[% fancy.header %]
612[% fancy.header( title = "Fancy Title" ) %]
613-- expect --
614===
615  This is the basic header: My Web Site
616  This is the basic header: New Title
617===
618  This is the basic header: <fancy>My Web Site</fancy>
619  Fancy new part of header
620  This is the basic header: Fancy Title
621  Fancy new part of header
622
623-- test --
624[% VIEW baz  notfound='lost' %]
625[% BLOCK lost; 'lost, not found'; END %]
626[% END -%]
627[% baz.any %]
628-- expect --
629lost, not found
630
631-- test --
632[% VIEW woz  prefix='outer_' %]
633[% BLOCK wiz; 'The inner wiz'; END %]
634[% END -%]
635[% BLOCK outer_waz; 'The outer waz'; END -%]
636[% woz.wiz %]
637[% woz.waz %]
638-- expect --
639The inner wiz
640The outer waz
641
642-- test --
643[% VIEW foo %]
644
645   [% BLOCK file -%]
646      File: [% item.name %]
647   [%- END -%]
648
649   [% BLOCK directory -%]
650      Dir: [% item.name %]
651   [%- END %]
652
653[% END -%]
654[% foo.view_file({ name => 'some_file' }) %]
655[% foo.include_file(item => { name => 'some_file' }) %]
656[% foo.view('directory', { name => 'some_dir' }) %]
657-- expect --
658      File: some_file
659      File: some_file
660      Dir: some_dir
661
662-- test --
663[% BLOCK parent -%]
664This is the base block
665[%- END -%]
666[% VIEW super %]
667   [%- BLOCK parent -%]
668   [%- INCLUDE parent | replace('base', 'super') -%]
669   [%- END -%]
670[% END -%]
671base: [% INCLUDE parent %]
672super: [% super.parent %]
673-- expect --
674base: This is the base block
675super: This is the super block
676
677-- test --
678[% BLOCK foo -%]
679public foo block
680[%- END -%]
681[% VIEW plain %]
682   [% BLOCK foo -%]
683<plain>[% PROCESS foo %]</plain>
684   [%- END %]
685[% END -%]
686[% VIEW fancy %]
687   [% BLOCK foo -%]
688   [%- plain.foo | replace('plain', 'fancy') -%]
689   [%- END %]
690[% END -%]
691[% plain.foo %]
692[% fancy.foo %]
693-- expect --
694<plain>public foo block</plain>
695<fancy>public foo block</fancy>
696
697-- test --
698[% VIEW foo %]
699[% BLOCK Blessed_List -%]
700This is a list: [% item.as_list.join(', ') %]
701[% END -%]
702[% END -%]
703[% foo.print(blessed_list) %]
704-- expect --
705This is a list: Hello, World
706
707-- test --
708[% VIEW my.foo value=33; END -%]
709n: [% my.foo.value %]
710-- expect --
711n: 33
712
713-- test --
714[% VIEW parent -%]
715[% BLOCK one %]This is base one[% END %]
716[% BLOCK two %]This is base two[% END %]
717[% END -%]
718
719[%- VIEW child1 base=parent %]
720[% BLOCK one %]This is child1 one[% END %]
721[% END -%]
722
723[%- VIEW child2 base=parent %]
724[% BLOCK two %]This is child2 two[% END %]
725[% END -%]
726
727[%- VIEW child3 base=child2 %]
728[% BLOCK two %]This is child3 two[% END %]
729[% END -%]
730
731[%- FOREACH child = [ child1, child2, child3 ] -%]
732one: [% child.one %]
733[% END -%]
734[% FOREACH child = [ child1, child2, child3 ] -%]
735two: [% child.two %]
736[% END %]
737
738-- expect --
739one: This is child1 one
740one: This is base one
741one: This is base one
742two: This is base two
743two: This is child2 two
744two: This is child3 two
745
746-- test --
747[% VIEW my.view.default
748        prefix = 'view/default/'
749        value  = 3.14;
750   END
751-%]
752value: [% my.view.default.value %]
753-- expect --
754value: 3.14
755
756-- test --
757[% VIEW my.view.default
758        prefix = 'view/default/'
759        value  = 3.14;
760   END;
761   VIEW my.view.one
762        base   = my.view.default
763        prefix = 'view/one/';
764   END;
765   VIEW my.view.two
766	base  = my.view.default
767        value = 2.718;
768   END;
769-%]
770[% BLOCK view/default/foo %]Default foo[% END -%]
771[% BLOCK view/one/foo %]One foo[% END -%]
7720: [% my.view.default.foo %]
7731: [% my.view.one.foo %]
7742: [% my.view.two.foo %]
7750: [% my.view.default.value %]
7761: [% my.view.one.value %]
7772: [% my.view.two.value %]
778-- expect --
7790: Default foo
7801: One foo
7812: Default foo
7820: 3.14
7831: 3.14
7842: 2.718
785
786-- test --
787[% VIEW foo number = 10 sealed = 0; END -%]
788a: [% foo.number %]
789b: [% foo.number = 20 %]
790c: [% foo.number %]
791d: [% foo.number(30) %]
792e: [% foo.number %]
793-- expect --
794a: 10
795b: 
796c: 20
797d: 30
798e: 30
799
800-- test --
801[% VIEW foo number = 10 silent = 1; END -%]
802a: [% foo.number %]
803b: [% foo.number = 20 %]
804c: [% foo.number %]
805d: [% foo.number(30) %]
806e: [% foo.number %]
807-- expect --
808a: 10
809b: 
810c: 10
811d: 10
812e: 10
813
814-- test --
815-- name bad base --
816[%  TRY; 
817        VIEW wiz base=no_such_base_at_all; 
818        END;
819    CATCH;
820        error;
821    END
822-%]
823-- expect --
824view error - Invalid base specified for view
825