add maphash to the array wrapper
[bse.git] / t / 020-templater / 040-original.t
CommitLineData
d09682dd
TC
1#!perl -w
2# Basic tests for Squirrel::Template
3use strict;
64881d03 4use Test::More;
1c78dcb4 5use HTML::Entities;
d09682dd 6
ac507437 7sub template_test($$$$;$$);
d09682dd
TC
8
9my $gotmodule = require_ok('Squirrel::Template');
10
6c4b07aa
TC
11my %extra_opts;
12
d09682dd 13SKIP: {
d64413ee 14 skip "couldn't load module", 15 unless $gotmodule;
d09682dd
TC
15
16 my $flag = 0;
17 my $str = "ABC";
58f0ca94 18 my $str2 = "DEF";
d09682dd
TC
19 my ($repeat_limit, $repeat_value);
20
21 my %acts =
22 (
23 ifEq => \&tag_ifeq,
24 iterate_repeat_reset =>
25 [ \&iter_repeat_reset, \$repeat_limit, \$repeat_value ],
26 iterate_repeat =>
27 [ \&iter_repeat, \$repeat_limit, \$repeat_value ],
28 repeat => \$repeat_value,
29 strref => \$str,
30 str => $str,
58f0ca94 31 str2 => $str2,
81f3292d 32 with_upper => \&tag_with_upper,
3994cfb9 33 cat => \&tag_cat,
aef10b58 34 ifFalse => 0,
58f0ca94
TC
35 dead => sub { die "foo\n" },
36 noimpl => sub { die "ENOIMPL\n" },
d09682dd 37 );
ac507437
TC
38 my %vars =
39 (
40 a =>
41 {
42 b =>
43 {
44 c => "CEE"
45 }
46 },
47 str => $str,
48 somelist => [ 'a' .. 'f' ],
49 somehash => { qw(a 11 b 12 c 14 e 8) },
50 num1 => 101,
51 num2 => 202,
7238940a 52 testclass => Squirrel::Template::Expr::WrapClass->new("TestClass"),
7c11c195
TC
53 error =>
54 {
55 noimpl => sub { die "ENOIMPL\n" },
56 },
5dde4b09
TC
57 callback1 => sub {
58 my ($cb, $templater, @args) = @_;
59
60 for my $foo ("a" .. "e") {
61 $templater->set_var(foo => $foo);
62 $cb->();
63 }
64 },
dd94dd8e
TC
65 somecode1 => sub { return "FOO" },
66 somecode2 => sub { return [ @_ ] },
105ac913
TC
67 dumper => sub {
68 use Data::Dumper;
69 Dumper($_[0]);
70 },
64881d03
TC
71 objs =>
72 [
73 { id => 1, val1 => "abc", val2 => "def" },
74 { id => 2, val1 => "ghi", val2 => "jkl" }
75 ],
ac507437 76 );
d09682dd
TC
77 template_test("<:str:>", "ABC", "simple", \%acts);
78 template_test("<:strref:>", "ABC", "scalar ref", \%acts);
79 $str = "DEF";
80 template_test("<:strref:>", "DEF", "scalar ref2", \%acts);
81 template_test(<<TEMPLATE, "12345", "iterate", \%acts, "in");
82<:iterator begin repeat 1 5:><:repeat:><:iterator end repeat:>
83TEMPLATE
84 template_test(<<TEMPLATE, "1|2|3|4|5", "iterate sep", \%acts, "in");
85<:iterator begin repeat 1 5:><:repeat:><:
86iterator separator repeat:>|<:iterator end repeat:>
87TEMPLATE
88 template_test('<:ifEq [str] "ABC":>YES<:or:>NO<:eif:>', "YES",
89 "cond1", \%acts);
90 template_test('<:if Eq [str] "ABC":>YES<:or Eq:>NO<:eif Eq:>', "YES",
91 "cond2", \%acts);
58f0ca94
TC
92 template_test("<:dead:>", "* foo\n *", "dead", \%acts);
93 template_test("<:noimpl:>", "<:noimpl:>", "noimpl", \%acts);
94 template_test("<:unknown:>", "<:unknown:>", "unknown tag", \%acts);
95 template_test("<:ifDead:><:str:><:or:><:str2:><:eif:>",
96 "* foo\n *<:ifDead:>ABC<:or:>DEF<:eif:>", "ifDead", \%acts);
97 template_test("<:ifNoimpl:><:str:><:or:><:str2:><:eif:>",
98 "<:ifNoimpl:>ABC<:or:>DEF<:eif:>", "ifNoimpl", \%acts);
33e0317f
TC
99
100 template_test("<:if!False:>FOO<:eif:>", "FOO", "if!False", \%acts);
40d9d2f7 101 template_test("<:if !False:>FOO<:eif:>", "FOO", "if !False", \%acts);
33e0317f
TC
102 template_test("<:if!Str:>FOO<:eif:>", "", "if!Str", \%acts);
103 template_test("<:if!Dead:><:str:><:eif:>",
104 "* foo\n *<:if!Dead:>ABC<:eif:>", "if!Dead", \%acts);
105 template_test("<:if!Noimpl:><:str:><:eif:>",
106 "<:if!Noimpl:>ABC<:eif:>", "if!Noimpl", \%acts);
107
a6208af0
TC
108 template_test(<<TEMPLATE, <<OUTPUT, "wrap", \%acts, "in");
109<:wrap wraptest.tmpl title=>[cat "foo " [str]], menu => 1, showtitle => "abc" :>Alpha
110<:param menu:>
111<:param showtitle:>
ac5f7d51 112<:= params.showtitle :>
a6208af0 113TEMPLATE
d09682dd
TC
114<title>foo ABC</title>
115Alpha
a6208af0
TC
1161
117abc
ac5f7d51 118abc
58f0ca94
TC
119OUTPUT
120
8ca0c874 121 template_test(<<TEMPLATE, <<OUTPUT, "wrap more", \%acts, "both");
58f0ca94
TC
122Before
123<:wrap wraptest.tmpl title=>[cat "foo " [str]], menu => 1, showtitle => "abc" -:>
124Alpha
125<:param menu:>
126<:param showtitle:>
127<:-endwrap-:>
128After
129TEMPLATE
130Before
131<title>foo ABC</title>
132Alpha
1331
134abc
135After
136OUTPUT
137
138 template_test(<<TEMPLATE, <<OUTPUT, "wrap with too much parameter text", \%acts, "in");
139<:wrap wraptest.tmpl title=>[cat "foo " [str]], menu => 1, showtitle => "abc" junk :>Alpha
140<:param menu:>
141<:param showtitle:>
142TEMPLATE
143* WARNING: Extra data after parameters ' junk' *<title>foo ABC</title>
144Alpha
1451
146abc
147OUTPUT
148
149 template_test(<<TEMPLATE, <<OUTPUT, "wrap recursive", \%acts, "both");
150<:wrap wrapself.tmpl title=>[cat "foo " [str]], menu => 1, showtitle => "abc" :>Alpha
151<:param menu:>
152<:param showtitle:>
153TEMPLATE
154* Error starting wrap: Too many levels of wrap for 'wrapself.tmpl' *<title>foo ABC</title>
155<title>foo ABC</title>
156<title>foo ABC</title>
157<title>foo ABC</title>
158<title>foo ABC</title>
159<title>foo ABC</title>
160<title>foo ABC</title>
161<title>foo ABC</title>
162<title>foo ABC</title>
163<title>foo ABC</title>
164Alpha
1651
166abc
167OUTPUT
168
169 template_test(<<TEMPLATE, <<OUTPUT, "wrap unknown", \%acts, "both");
170<:wrap unknown.tmpl:>
171Body
172TEMPLATE
173* Loading wrap: File unknown.tmpl not found *
174OUTPUT
175
176 template_test(<<TEMPLATE, <<OUTPUT, "unwrapped wrap here", \%acts, "both");
177before
178<:wrap here:>
179after
180TEMPLATE
181before
182* wrap here without being wrapped *
183after
8ca0c874
TC
184OUTPUT
185
186 template_test(<<TEMPLATE, <<OUTPUT, ".wrap simple", \%acts, "in", \%vars);
187<:.wrap "wraptest.tmpl", "title": "foo " _ str, "menu": 1, "showtitle":"abc" :>Alpha
188<:param menu:>
189<:param showtitle:>
190<:= params.showtitle :>
191TEMPLATE
192<title>foo ABC</title>
193Alpha
1941
195abc
196abc
197OUTPUT
198
199 template_test(<<TEMPLATE, <<OUTPUT, ".wrap unknown", \%acts, "both");
200<:.wrap "unknown.tmpl":>
201Body
202TEMPLATE
203* Loading wrap: File unknown.tmpl not found *
204OUTPUT
205
206 template_test(<<TEMPLATE, <<OUTPUT, ".wrap recursive", \%acts, "both", \%vars);
207<:.wrap "wrapself.tmpl", "title":"foo " _ str, "menu":1, "showtitle":"abc" :>Alpha
208<:= params.menu :>
209<:= params.showtitle :>
210TEMPLATE
211* Error starting wrap: Too many levels of wrap for 'wrapself.tmpl' *<title>foo ABC</title>
212<title>foo ABC</title>
213<title>foo ABC</title>
214<title>foo ABC</title>
215<title>foo ABC</title>
216<title>foo ABC</title>
217<title>foo ABC</title>
218<title>foo ABC</title>
219<title>foo ABC</title>
220<title>foo ABC</title>
221Alpha
2221
223abc
224OUTPUT
225
226 template_test(<<TEMPLATE, <<OUTPUT, ".wrap more", \%acts, "both", \%vars);
227Before
228<:.wrap "wraptest.tmpl", "title":"foo " _ str, "menu":1, "showtitle":"abc" -:>
229Alpha
230<:= params.menu:>
231<:= params.showtitle:>
232<:-.end wrap-:>
233After
234TEMPLATE
235Before
236<title>foo ABC</title>
237Alpha
2381
239abc
240After
58f0ca94
TC
241OUTPUT
242
243 # undefined iterator - replacement should happen on the inside
244 template_test(<<TEMPLATE, <<OUTPUT, "undefined iterator", \%acts);
245<:iterator begin unknown:>
246<:if Eq "1" "1":>TRUE<:or:>FALSE<:eif:>
247<:iterator separator unknown:>
248<:if Eq "1" "0":>TRUE<:or:>FALSE<:eif:>
249<:iterator end unknown:>
250TEMPLATE
251<:iterator begin unknown:>
252TRUE
253<:iterator separator unknown:>
254FALSE
255<:iterator end unknown:>
256OUTPUT
257
258 template_test(<<TEMPLATE, <<OUTPUT, "multi wrap", \%acts, "in");
259<:wrap wrapinner.tmpl title => "ABC":>
260Test
261TEMPLATE
262<title>ABC</title>
263
264<head1>ABC</head1>
265
266Test
d09682dd 267OUTPUT
a6208af0 268
de30d08a
TC
269 my $switch = <<IN;
270<:switch:>ignored<:case Eq [strref] "ABC":>ONE<:case Eq [strref] "XYZ":>TWO<:
271case default:>DEF<:endswitch:>
272IN
273 $str = "ABC";
274 template_test($switch, "ONE", "switch1", \%acts, "both");
275 $str = "XYZ";
276 template_test($switch, "TWO", "switch2", \%acts, "both");
277 $str = "DEF";
278 template_test($switch, "DEF", "switch def", \%acts, "both");
81f3292d 279
d1657849
TC
280 my $switch2 = <<IN;
281<:switch:><:case Eq [strref] "ABC":>ONE<:case Eq [strref] "XYZ":>TWO<:
282case default:>DEF<:endswitch:>
283IN
284 $str = "ABC";
285 template_test($switch2, "ONE", "switch without ignored", \%acts, "both");
286
58f0ca94 287 template_test(<<IN, <<OUT, "unimplemented switch (by die)", \%acts, "both");
67eb1563 288<foo><:strref bar |h:></foo><:switch:><:case Eq [strref] "XYZ":>FAIL<:case Eq [unknown] "ABC":><:endswitch:>
52a9c798 289IN
67eb1563 290<foo>ABC</foo><:switch:><:case Eq [unknown] "ABC":><:endswitch:>
52a9c798
TC
291OUT
292
58f0ca94
TC
293 template_test(<<IN, <<OUT, "unimplemented switch (by missing)", \%acts, "both");
294<foo><:strref bar |h:></foo><:switch:><:case Eq [strref] "XYZ":>FAIL<:case Unknown:><:str:><:case Eq [unknown] "ABC":><:str2:><:endswitch:>
295IN
296<foo>ABC</foo><:switch:><:case Unknown:>ABC<:case Eq [unknown] "ABC":>DEF<:endswitch:>
297OUT
298
299 template_test(<<IN, <<OUT, "switch with die in case and unknown", \%acts, "both");
300<:switch:><:case Eq [strref] "XYZ":>FAIL<:case Dead:><:str:><:case Eq [unknown] "ABC":><:str2:><:endswitch:>
301IN
302* foo
303 *<:switch:><:case Eq [unknown] "ABC":>DEF<:endswitch:>
304OUT
305
306 template_test(<<IN, <<OUT, "switch with die no matches", \%acts, "both");
307<:switch:><:case Eq [strref] "XYZ":>FAIL<:case Dead:><:str:><:case False:><:str2:><:endswitch:>
308IN
309* foo
310 *
311OUT
312
c11c1f71
TC
313 template_test(<<IN, <<OUT, "switch with case !", \%acts, "both");
314<:switch:><:case !Str:>NOT STR<:case !False:>FALSE<:endswitch:>
315IN
316FALSE
317OUT
318
81f3292d 319 template_test("<:with begin upper:>Alpha<:with end upper:>", "ALPHA", "with", \%acts);
58f0ca94
TC
320
321 template_test("<:with begin unknown:>Alpha<:str:><:with end unknown:>", <<EOS, "with", \%acts, "out");
322<:with begin unknown:>AlphaABC<:with end unknown:>
323EOS
324
d64413ee 325 template_test("<:include doesnt/exist optional:>", "", "optional include", \%acts);
58f0ca94 326 template_test("<:include doesnt/exist:>", "* cannot find include doesnt/exist in path *", "failed include", \%acts);
d64413ee 327 template_test("x<:include included.include:>z", "xyz", "include", \%acts);
b873a8fa
TC
328
329 template_test <<IN, <<OUT, "nested in undefined if", \%acts;
330<:if Unknown:><:if Eq "1" "1":>Equal<:or Eq:>Not Equal<:eif Eq:><:or Unknown:>false unknown<:eif Unknown:>
331IN
332<:if Unknown:>Equal<:or Unknown:>false unknown<:eif Unknown:>
333OUT
334 template_test <<IN, <<OUT, "nested in undefined switch case", \%acts;
335<:switch:>
336<:case ifUnknown:><:if Eq 1 1:>Equal<:or Eq:>Unequal<:eif Eq:>
337<:endswitch:>
338IN
339<:switch:><:case ifUnknown:>Equal
340<:endswitch:>
341OUT
aef10b58
TC
342
343 { # using - for removing whitespace
344 template_test(<<IN, <<OUT, "space value", \%acts, "both");
345<foo>
346<:-str-:>
347</foo>
348<foo>
349<:str-:>
350</foo>
351<foo>
352<:str:>
353</foo>
354IN
355<foo>ABC</foo>
356<foo>
357ABC</foo>
358<foo>
359ABC
360</foo>
361OUT
362
363 template_test(<<IN, <<OUT, "space simple cond", \%acts, "both");
364<foo>
365<:-ifStr:>TRUE<:or-:><:eif-:>
366</foo>
367<foo2>
368<:-ifStr-:>
369TRUE
370<:-or:><:eif-:>
371</foo2>
372<foo3>
373<:-ifStr-:>
374TRUE
375<:-or-:>
376<:-eif-:>
377</foo3>
378<foo4>
379<:-ifFalse-:>TRUE<:-or-:>FALSE<:-eif-:>
380</foo4>
381<foo5>
382<:-ifFalse-:>
383TRUE
384<:-or-:>
385FALSE
386<:-eif-:>
387</foo5>
388<foo6>
389<:ifFalse:>
390TRUE
391<:or:>
392FALSE
393<:eif:>
394</foo6>
395IN
396<foo>TRUE</foo>
397<foo2>TRUE</foo2>
398<foo3>TRUE</foo3>
399<foo4>FALSE</foo4>
400<foo5>FALSE</foo5>
401<foo6>
402
403FALSE
404
405</foo6>
406OUT
407
408 template_test(<<IN, <<OUT, "space iterator", \%acts, "both");
409<foo>
410<:-iterator begin repeat 1 5 -:>
411<:-repeat-:>
412<:-iterator end repeat -:>
413</foo>
414<foo2>
415<:-iterator begin repeat 1 5 -:>
416<:-repeat-:>
417<:-iterator separator repeat -:>
418,
419<:-iterator end repeat -:>
420</foo2>
421IN
422<foo>12345</foo>
423<foo2>1,2,3,4,5</foo2>
f93b320c
TC
424OUT
425
426 template_test(<<IN, <<OUT, "space switch", \%acts, "both");
427<foo>
428<:- switch:>
429
430 <:- case default:>FOO
431<:- endswitch:>
432</foo>
433IN
434<foo>FOO
435</foo>
394018ef
TC
436OUT
437
438 template_test(<<IN, <<OUT, "while", \%acts);
439<:.set work = [ "a" .. "z" ] -:>
440<:.while work.size and work[0] ne "d" -:>
441<:= work.shift :>
442<:.end while -:>
443IN
444a
445b
446c
aef10b58
TC
447OUT
448
7d6dab3c
TC
449 template_test(<<IN, <<OUT, "space complex", \%acts, "both");
450<div class="window">
451 <h1><:str:></h1>
452 <ul class="children list">
c007732a 453 <:iterator begin repeat 1 2:>
7d6dab3c
TC
454 <:- switch:>
455 <:- case False:>
456 <li class="error message"><:repeat:></li>
457 <:case str:>
458 </ul>
459 <h2><:repeat:></h2>
460 <ul class="children list">
461 <:- case default:>
462 <li><:repeat:></li>
463 <:- endswitch:>
464 <:iterator end repeat:>
465 </ul>
466</div>
467IN
c007732a
TC
468<div class="window">
469 <h1>ABC</h1>
470 <ul class="children list">
471
472 </ul>
473 <h2>1</h2>
474 <ul class="children list">
475
476 </ul>
477 <h2>2</h2>
478 <ul class="children list">
479
480 </ul>
481</div>
7d6dab3c 482OUT
aef10b58 483 }
ac507437 484
7238940a
TC
485 template_test("<:= unknown :>", "<:= unknown :>", "unknown", \%acts, "", \%vars);
486 template_test(<<TEMPLATE, "2", "multi-statement", \%acts, "", \%vars);
487<:.set foo = [] :><:% foo.push(1); foo.push(2) :><:= foo.size() -:>
7aa487e3
TC
488TEMPLATE
489
490 template_test(<<TEMPLATE, "2", "multi-statement no ws", \%acts, "", \%vars);
491<:.set foo=[]:><:%foo.push(1);foo.push(2):><:= foo.size() -:>
7238940a
TC
492TEMPLATE
493
ac507437 494 template_test("<:= str :>", "ABC", "simple exp", \%acts, "", \%vars);
7aa487e3 495 template_test("<:=str:>", "ABC", "simple exp no ws", \%acts, "", \%vars);
ac507437
TC
496 template_test("<:= a.b.c :>", "CEE", "hash methods", \%acts, "", \%vars);
497 template_test(<<IN, <<OUT, "simple set", \%acts, "both", \%vars);
498<:.set d = "test" -:><:= d :>
499IN
500test
501OUT
502 my @expr_tests =
503 (
504 [ 'num1 + num2', 303 ],
505 [ 'num1 - num2', -101 ],
506 [ 'num1 + num2 * 2', 505 ],
507 [ 'num2 mod 5', '2' ],
508 [ 'num1 / 5', '20.2' ],
509 [ 'num1 div 5', 20 ],
510 [ '+num1', 101 ],
511 [ '-(num1 + num2)', -303 ],
512 [ '"hello " _ str', 'hello ABC' ],
513 [ 'num1 < num2', 1 ],
514 [ 'num1 < 101', '' ],
515 [ 'num1 < 100', '' ],
516 [ 'num1 > num2', '' ],
517 [ 'num2 > num1', 1 ],
518 [ 'num1 > 101', '' ],
519 [ 'num1 == 101.0', '1' ],
520 [ 'num1 == 101', '1' ],
521 [ 'num1 == 100', '' ],
522 [ 'num1 != 101', '' ],
523 [ 'num1 != "101.0"', '' ],
524 [ 'num1 != 100', 1 ],
525 [ 'num1 >= 101', 1 ],
526 [ 'num1 >= 100', 1 ],
527 [ 'num1 >= 102', '' ],
528 [ 'num1 <= 101', 1 ],
529 [ 'num1 <= 100', '' ],
530 [ 'num1 <= 102', '1' ],
b83d0c53
TC
531 [ 'num1 <=> 102', '-1' ],
532 [ 'num1 <=> 101', '0' ],
ac507437
TC
533 [ 'str eq "ABC"', '1' ],
534 [ 'str eq "AB"', '' ],
535 [ 'str ne "AB"', '1' ],
536 [ 'str ne "ABC"', '' ],
b83d0c53
TC
537 [ 'str cmp "ABC"', 0 ],
538 [ 'str cmp "AB"', 1 ],
ac507437
TC
539 [ 'str.lower', 'abc' ],
540 [ 'somelist.size', 6 ],
541 [ '[ 4, 2, 3 ].first', 4 ],
542 [ '[ 1, 4, 9 ].join(",")', "1,4,9" ],
543 [ '[ "xx", "aa" .. "ad", "zz" ].join(" ")', "xx aa ab ac ad zz" ],
544 [ '1 ? "TRUE" : "FALSE"', 'TRUE' ],
545 [ '0 ? "TRUE" : "FALSE"', 'FALSE' ],
546 [ '[ 1 .. 4 ][2]', 3 ],
547 [ 'somelist[2]', "c" ],
548 [ 'somehash["b"]', "12" ],
549 [ 'not 1', '' ],
550 [ 'not 1 or 1', 1 ],
551 [ 'not 1 and 1', "" ],
552 [ '"xabcy" =~ /abc/', 1 ],
66a07e7c 553 [ '"xabcy" !~ /abc/', "" ],
ac507437 554 [ '[ "abc" =~ /(.)(.)/ ][1]', "b" ],
66a07e7c 555 [ '"xabcy" !~ /abg/', 1 ],
f17f9f79 556 [ '{ "a": 11, "b": 12, "c": 20 }["b"]', 12 ],
7b7d3881 557 [ '[ 1, 2, 3 ][1]', 2 ],
7238940a 558 [ 'testclass.foo', "[TestClass.foo]" ],
e1e37937 559 [ '@undef.defined', "" ],
b83d0c53
TC
560 [ '(@{: "abc" })()', "abc" ],
561 [ '(@{a,b: a+b})(12, 13)', '25' ],
562 [ '(@{a,b: a; b; a-b })(10, 5)', '5' ],
7b4c11f9
TC
563
564 # WrapScalar
565 [ '"foo".length', 3 ],
566 [ '"foo".length(1)', "* scalar.length takes no parameters *" ],
567 [ '"foo".upper', "FOO" ],
568 [ '"foo".upper(1)', "* scalar.upper takes no parameters *" ],
569 [ '"Foo".lower', "foo" ],
570 [ '"Foo".lower(1)', "* scalar.lower takes no parameters *" ],
571 [ '"foo".defined', '1' ],
572 [ '"foo".defined(1)', '* scalar.defined takes no parameters *' ],
573 [ '"foo".trim', "foo" ],
574 [ '" a b ".trim', "a b" ],
575 [ '" a b ".trim(1)', "* scalar.trim takes no parameters *" ],
576 [ '"a b".split.join("|")', "a|b" ],
577 [ '"a,b,c".split(",").join("|")', 'a|b|c' ],
578 [ '"a,b,c".split(",",2).join("|")', 'a|b,c' ],
579 [ '(10.1).format("%.2f")', "10.10" ],
580 [ '(10.1).format("%.2f", 1)', "* scalar.format takes one parameter *" ],
581 [ '"str".evaltag', 'ABC' ],
582 [ '"cat [str] [str2]".evaltag', 'ABCDEF' ],
583 [ '"abc*".quotemeta', "abc\\*" ],
584 [ '"abc".quotemeta(1)', "* scalar.quotemeta takes no parameters *" ],
585 [ '"abcdef".contains("cde")', 1 ],
586 [ '"abcdef".contains("cdf")', "" ],
587 [ '"abcdef".contains("cdf",1)', "* scalar.contains requires one parameter *" ],
588 [ '"abcdefabcdef".index("cde")', 2 ],
589 [ '"abcdefabcdef".index("cdf")', -1 ],
590 [ '"abcdefabcdef".index("cde", 5)', 8 ],
591 [ '"abc".index("ab",1,2)', '* scalar.index requires one or two parameters *' ],
592 [ '"abcdefabcdef".rindex("cde")', 8 ],
593 [ '"abcdefabcdef".rindex("cde", 7)', 2 ],
594 [ '"abcdefabcdef".rindex("cde", 7, 3)', '* scalar.rindex requires one or two parameters *' ],
595 [ "(65).chr", "A" ],
596 [ "(10.1).int", 10 ],
597 [ "(10).int", 10 ],
598 [ "(10).rand < 10 and (10).rand >= 0", 1 ],
599 [ "(-10).abs", "10" ],
600 [ '(10).floor', 10 ],
601 [ '(10.1).floor', 10 ],
602 [ '(-10.1).floor', -11 ],
603 [ '(10).ceil', 10 ],
604 [ '(10.1).ceil', 11 ],
605 [ '(-10.1).ceil', -10 ],
2d96abcc
TC
606 [ '"test".is_list', 0 ],
607 [ '"test".is_hash', 0 ],
d64aa8a6 608 [ '"abc".replace(/(.)(.)(.)/, "$3$2$1")', "cba" ],
105ac913
TC
609 [ '"abc def ghi".replace(/(?:^|\b)([a-z])/, @{m: m.text.upper }, 1)',
610 'Abc Def Ghi' ],
1c78dcb4 611 [ '"a&b".escape("html")', 'a&amp;b' ],
394018ef
TC
612 [ '"abc".match(/b/).start', "1" ],
613 [ '"abc".match(/b/).end', "2" ],
614 [ '"abc".match(/b/).length', "1" ],
105ac913 615 [ '"abc".match(/b/).text', "b" ],
394018ef
TC
616 [ '"abc".match(/(b)/).subexpr[0].start', "1" ],
617 [ '"abc".match(/(b)/).subexpr[0].end', "2" ],
618 [ '"abc".match(/(b)/).subexpr[0].length', "1" ],
105ac913
TC
619 [ '"abc".match(/(b)/).subexpr[0].text', "b" ],
620 [ '"abc".match(/(?<foo>b)/).named["foo"].text', "b" ],
621 [ '"abc".match(/(?<foo>b)/).named["bar"]', "" ],
394018ef
TC
622 [ '"abcd".substring(1)', "bcd" ],
623 [ '"abcd".substring(1,2)', "bc" ],
624 [ '"abcd".substring(1,-2)', "b" ],
7d807a0e
TC
625
626 # WrapArray
627 [ '[ [ 1, 2 ], 3 ].expand.join(",")', "1,2,3" ],
2d96abcc
TC
628 [ '[ 1, 2 ].is_list', 1 ],
629 [ '[ 1, 2 ].is_hash', 0 ],
32c735ef 630 [ '[ 1 .. 5 ].shuffle.size', 5 ],
e368e65e 631 [ '([ "a", 1, "b", "2" ].as_hash)["a"]', 1 ],
b83d0c53
TC
632 [ '[ 1 .. 5].grep(@{a: a mod 2 == 0 }).join(",")', '2,4' ],
633 [ '[ { a: 3 }, { a: 1 }, { a: 2 } ].sort(@{a,b: b.a <=> a.a }).map(@{a: a.a}).join("")', '321' ],
040f9364
TC
634 [ '[ "A" .. "Z" ].slice([ 0 .. 5 ]).join("")', 'ABCDEF' ],
635 [ '[ "A" .. "Z" ].slice(0, 1, -2, -1).join("")', 'ABYZ' ],
636 [ '[ "A" .. "Z" ].splice(0, 5).join("")', 'ABCDE' ],
64881d03
TC
637 [ 'objs.maphash("id")[2].val2', 'jkl' ],
638 [ 'objs.maphash("id", "val1")[1]', 'abc' ],
639 [ 'objs.maphash("val1", "val2")["abc"]', 'def' ],
640 [ 'objs.maphash("val1", @{i: i.id _ i.val2 })["abc"]', '1def' ],
641 [ 'objs.maphash(@{i: i.val1 _ i.val2 }, @{i: i.id _ i.val2 })["abcdef"]', '1def' ],
642 [ 'somelist.maphash().exists("a")', '1' ],
643 [ 'somelist.maphash().exists("k")', '' ],
2d96abcc
TC
644
645 # WrapHash
646 [ '{ "foo": 1 }.is_list', 0 ],
647 [ '{ "foo": 1 }.is_hash', 1 ],
3b9279e2 648 [ '{ foo: 1, bar: 1 }.extend({ bar:2 })["bar"]', 2 ],
ac507437
TC
649 );
650 for my $test (@expr_tests) {
651 my ($expr, $result) = @$test;
652
653 template_test("<:= $expr :>", $result, "expr: $expr", \%acts, "", \%vars);
654 }
c507244d
TC
655
656 template_test(<<IN, "", "define no use", \%acts, "both", \%vars);
657<:-.define foo:>
658<:.end-:>
659<:-.define bar:>
660<:.end define-:>
661IN
ac4e30d2 662 template_test(<<IN, "avaluebvalue", "define with call", \%acts, "both", \%vars);
c507244d
TC
663<:-.define foo:>
664<:-= avar -:>
665<:.end-:>
53c28223 666<:.call "foo", avar:"avalue"-:>
ac4e30d2 667<:.call "foo",
53c28223
TC
668 avar:"bvalue"-:>
669IN
670 template_test(<<IN, "2716", "define defaults with call", \%acts, "both", \%vars);
671<:-.define foo; abc:1, def:abc+5 :>
672<:-= abc -:><:= def -:>
673<:.end-:>
674<:.call "foo", "abc":"2"-:>
675<:.call "foo" -:>
c507244d
TC
676IN
677 template_test(<<IN, "other value", "external call", \%acts, "", \%vars);
678<:.call "called.tmpl", "avar":"other value"-:>
755fd5f3
TC
679IN
680 template_test(<<IN, "This was preloaded", "call preloaded", \%acts, "both", \%vars);
681<:.call "preloaded"-:>
c507244d 682IN
f75af510
TC
683 template_test(<<IN, <<OUT, "simple .for", \%acts, "", \%vars);
684<:.for x in [ "a" .. "d" ] -:>
76a42014 685Value: <:= x :> Index: <:= loop.index :> Count: <:= loop.count:> Prev: <:= loop.prev :> Next: <:= loop.next :> Even: <:= loop.even :> Odd: <:= loop.odd :> Parity: <:= loop.parity :> is_first: <:= loop.is_first :> is_last: <:= loop.is_last :> Current by index: <:= loop.current :>-
f75af510
TC
686<:.end-:>
687IN
76a42014
TC
688Value: a Index: 0 Count: 1 Prev: Next: b Even: Odd: 1 Parity: odd is_first: 1 is_last: Current by index: a-
689Value: b Index: 1 Count: 2 Prev: a Next: c Even: 1 Odd: Parity: even is_first: is_last: Current by index: b-
690Value: c Index: 2 Count: 3 Prev: b Next: d Even: Odd: 1 Parity: odd is_first: is_last: Current by index: c-
691Value: d Index: 3 Count: 4 Prev: c Next: Even: 1 Odd: Parity: even is_first: is_last: 1 Current by index: d-
2421be86
TC
692OUT
693 template_test(<<IN, <<OUT, "simple .if", \%acts, "", \%vars);
694<:.if "a" eq "b" :>FAIL<:.else:>SUCCESS<:.end:>
695<:.if "a" eq "a" :>SUCCESS<:.else:>FAIL<:.end:>
696<:.if "a" eq "c" :>FAIL1<:.elsif "a" eq "a":>SUCCESS<:.else:>FAIL2<:.end:>
697IN
698SUCCESS
699SUCCESS
700SUCCESS
701OUT
702 template_test(<<IN, <<OUT, "unknown .if", \%acts, "", \%vars);
703<:.if unknown:>TRUE<:.end:>
704<:.if "a" eq "a":>TRUE<:.elsif unknown:>TRUE<:.end:>
705<:.if "a" eq "b" :>TRUE<:.elsif unknown:>TRUE<:.end:>
706<:.if "a" ne "a" :>TRUE<:.elsif 0:>ELIF<:.elsif unknown:>TRUE<:.end:>
707IN
708<:.if unknown:>TRUE<:.end:>
709TRUE
710<:.if 0 :><:.elsif unknown:>TRUE<:.end:>
711<:.if 0 :><:.elsif unknown:>TRUE<:.end:>
f75af510 712OUT
d09682dd 713
c81138c9
TC
714 template_test(<<IN, <<OUT, "stack overflow on .call", \%acts, "", \%vars);
715<:.define foo:>
716<:-.call "foo"-:>
717<:.end:>
718<:-.call "foo"-:>
719IN
720Error opening scope for call: Too many scope levels
721Backtrace:
722 .call 'foo' from test:1
723 .call 'foo' from test:1
724 .call 'foo' from test:1
725 .call 'foo' from test:1
726 .call 'foo' from test:1
727 .call 'foo' from test:1
728 .call 'foo' from test:1
729 .call 'foo' from test:1
730 .call 'foo' from test:1
731 .call 'foo' from test:1
732 .call 'foo' from test:1
733 .call 'foo' from test:1
734 .call 'foo' from test:1
735 .call 'foo' from test:1
736 .call 'foo' from test:1
737 .call 'foo' from test:1
738 .call 'foo' from test:1
739 .call 'foo' from test:1
740 .call 'foo' from test:1
741 .call 'foo' from test:1
742 .call 'foo' from test:1
743 .call 'foo' from test:1
744 .call 'foo' from test:1
745 .call 'foo' from test:1
746 .call 'foo' from test:1
747 .call 'foo' from test:1
748 .call 'foo' from test:1
749 .call 'foo' from test:1
750 .call 'foo' from test:1
751 .call 'foo' from test:1
752 .call 'foo' from test:1
753 .call 'foo' from test:1
754 .call 'foo' from test:1
755 .call 'foo' from test:1
756 .call 'foo' from test:1
757 .call 'foo' from test:1
758 .call 'foo' from test:1
759 .call 'foo' from test:1
760 .call 'foo' from test:1
761 .call 'foo' from test:1
762 .call 'foo' from test:1
763 .call 'foo' from test:1
764 .call 'foo' from test:1
765 .call 'foo' from test:1
766 .call 'foo' from test:1
767 .call 'foo' from test:1
768 .call 'foo' from test:1
769 .call 'foo' from test:3
a96f9b25
TC
770OUT
771
772 template_test(<<IN, <<OUT, "evaltags", \%acts, "", \%vars);
773<:= "str".evaltag :>
774<:= "cat [str] [str2]".evaltag :>
775IN
776ABC
777ABCDEF
947ae73b
TC
778OUT
779
780template_test(<<IN, <<OUT, "hash methods", \%acts, "", \%vars);
781<:.set foo = { "abc": 1, "def":2 } -:>
782<:% foo.set("ghi", 3) -:>
783ghi: <:= foo.ghi :>
784keys: <:= foo.keys.sort.join(",") :>
785size: <:= foo.size :>
786values: <:= foo.values.sort.join(",") :>
787<:.for i in foo.list -:>
788<:= i.key _ "=" _ i.value :>
789<:.end for-:>
790IN
791ghi: 3
792keys: abc,def,ghi
793size: 3
794values: 1,2,3
795abc=1
796def=2
797ghi=3
06b4938a
TC
798OUT
799
800template_test(<<IN, <<OUT, "array methods", \%acts, "", \%vars);
801<:.set foo = [ 1, 2, 4 ] -:>
802<:% foo.set(2, 3) -:>
8032: <:= foo[2] :>
040f9364
TC
804<:.set foo = [ "A" .. "J" ] -:>
805<:= foo.splice(8, 2, [ "Y", "Z" ]).join("") :>
806<:= foo.join("") :>
807<:.set foo = [ "A" .. "J" ] -:>
808<:= foo.splice(5).join("") :>
809<:= foo.join("") :>
06b4938a
TC
810IN
8112: 3
040f9364
TC
812IJ
813ABCDEFGHYZ
814FGHIJ
815ABCDE
7c11c195
TC
816OUT
817
818 template_test(<<IN, <<OUT, "set undef", \%acts, "", \%vars);
819<:.set foo = unknown :>
820<:.set bar = error.noimpl :>
821IN
822<:.set foo = unknown :>
823<:.set bar = error.noimpl :>
5dde4b09
TC
824OUT
825
826 template_test(<<IN, <<OUT, "iterateover", \%acts, "", \%vars);
827<:.iterateover callback1-:>
828<:= foo -:>
829<:.end:>
830IN
831abcde
7b7d3881
TC
832OUT
833
dd94dd8e 834 template_test(<<'IN', <<OUT, "globals default variable", \%acts, "", \%vars);
7b7d3881
TC
835<:.set globals.foo = "test" -:>
836<:= globals.foo :>
dd94dd8e
TC
837<:.set name="foo" -:>
838<:= testclass.$name :>
839<:= testclass.$name() :>
840<:= testclass.$name(1) :>
7b7d3881
TC
841IN
842test
dd94dd8e
TC
843[TestClass.foo]
844[TestClass.foo]
845[TestClass.foo]
846OUT
847
848 template_test(<<'IN', <<OUT, "function calls", \%acts, "", \%vars);
849<:= somecode1() :>
850<:= somecode2().join(",") :>
851<:= somecode2("a", "b").join(",") :>
852IN
853FOO
854
855a,b
c81138c9 856OUT
6c4b07aa
TC
857
858 {
859 local $extra_opts{error_not_defined} = 1;
860 template_test(<<'IN', <<'OUT', "error !defined: expr", \%acts, "", \%vars);
861<:= unknown_var :>
862IN
863* Variable 'unknown_var' not set
864 *
865OUT
866 template_test(<<'IN', <<'OUT', "error !defined: .if", \%acts, "", \%vars);
867<:.if unknown_var -:>
868a
869<:-.else -:>
870b
871<:-.end if:>
872IN
873* Variable 'unknown_var' not set
874 *
875OUT
876 template_test(<<'IN', <<'OUT', "error !defined: .set", \%acts, "", \%vars);
877<:.set foo = unknown_var :>
878IN
879* Variable 'unknown_var' not set
880 *
881OUT
882 }
c81138c9 883}
c507244d 884
64881d03
TC
885done_testing();
886
ac507437
TC
887sub template_test ($$$$;$$) {
888 my ($in, $out, $desc, $acts, $stripnl, $vars) = @_;
d09682dd
TC
889
890 $stripnl ||= 'none';
891 $in =~ s/\n$// if $stripnl eq 'in' || $stripnl eq 'both';
892 $out =~ s/\n$// if $stripnl eq 'out' || $stripnl eq 'both';
893
755fd5f3
TC
894 my $templater = Squirrel::Template->new
895 (
896 template_dir=>'t/templates',
1c78dcb4
TC
897 preload => "preload.tmpl",
898 formats =>
899 {
900 html => sub {
901 encode_entities($_[0], '&<>');
902 }
6c4b07aa
TC
903 },
904 %extra_opts,
755fd5f3 905 );
d09682dd 906
ac507437 907 my $result = $templater->replace_template($in, $acts, undef, "test", $vars);
d09682dd
TC
908
909 is($result, $out, $desc);
910}
911
912sub iter_repeat_reset {
913 my ($rlimit, $rvalue, $args) = @_;
914
915 ($$rvalue, $$rlimit) = split ' ', $args;
916 --$$rvalue;
917}
918
919sub iter_repeat {
920 my ($rlimit, $rvalue) = @_;
921
922 ++$$rvalue <= $$rlimit;
923}
924
925sub tag_ifeq {
926 my ($args, $acts, $func, $templater) = @_;
927
928 my @args = get_expr($args, $acts, $templater);
929
930 @args >= 2
931 or die "ifEq takes 2 arguments";
932
933 $args[0] eq $args[1];
934}
935
936sub get_expr {
937 my ($origargs, $acts, $templater) = @_;
938
939 my @values;
940 my $args = $origargs;
941 while ($args) {
942 if ($args =~ s/\s*\[([^\[\]]+)\]\s*//) {
943 my $expr = $1;
944 my ($func, $funcargs) = split ' ', $expr, 2;
52a9c798 945 exists $acts->{$func} or die "ENOIMPL\n";
d09682dd
TC
946 push @values, scalar $templater->perform($acts, $func, $funcargs, $expr);
947 }
948 elsif ($args =~ s/\s*\"((?:[^\"\\]|\\[\"\\]|\"\")*)\"\s*//) {
949 my $str = $1;
950 $str =~ s/(?:\\([\"\\])|\"(\"))/$1 || $2/eg;
951 push @values, $str;
952 }
953 elsif ($args =~ s/\s*(\S+)\s*//) {
954 push @values, $1;
955 }
956 else {
957 print "Arg parse failure with '$origargs' at '$args'\n";
958 exit;
959 }
960 }
961
962 @values;
963}
81f3292d
TC
964
965sub tag_with_upper {
966 my ($args, $text) = @_;
967
968 return uc($text);
969}
3994cfb9
TC
970
971sub tag_cat {
972 my ($args, $acts, $func, $templater) = @_;
973
974 return join "", $templater->get_parms($args, $acts);
975}
7238940a
TC
976
977package TestClass;
978
979sub foo {
980 return "[TestClass.foo]";
981}