Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
23.37% covered (danger)
23.37%
179 / 766
76.47% covered (warning)
76.47%
13 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
phpbb_template_template_test
23.37% covered (danger)
23.37%
179 / 766
76.47% covered (warning)
76.47%
13 / 17
219.46
0.00% covered (danger)
0.00%
0 / 1
 template_data
0.00% covered (danger)
0.00%
0 / 469
0.00% covered (danger)
0.00%
0 / 1
2
 test_missing_file
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 test_invalid_handle
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 test_template
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 test_assign_display
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 test_append_var_without_assign_var
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 test_append_var_with_assign_var
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 test_retrieve_data
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
1
 alter_block_array_data
0.00% covered (danger)
0.00%
0 / 102
0.00% covered (danger)
0.00%
0 / 1
2
 test_alter_block_array
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 test_more_alter_block_array
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
1
 test_find_key_index
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
1 / 1
1
 test_delete_alter_block_array
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
1
 test_indexed_assign_block_vars
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
1
 assign_block_vars_array_data
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
2
 test_assign_block_vars_array
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 test_define_error
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14require_once __DIR__ . '/template_test_case.php';
15
16class phpbb_template_template_test extends phpbb_template_template_test_case
17{
18    /**
19     * @todo put test data into templates/xyz.test
20     */
21    public static function template_data()
22    {
23        return array(
24            /*
25            array(
26                '', // File
27                array(), // vars
28                array(), // block vars
29                array(), // destroy
30                '', // Expected result
31            ),
32            */
33            array(
34                'basic.html',
35                array(),
36                array(),
37                array(),
38                "pass\npass\npass\n<!-- DUMMY var -->",
39            ),
40            array(
41                'variable.html',
42                array('VARIABLE' => 'value'),
43                array(),
44                array(),
45                'value',
46            ),
47            array(
48                'if.html',
49                array(),
50                array(),
51                array(),
52                '03!false',
53            ),
54            array(
55                'if.html',
56                array('S_VALUE' => true),
57                array(),
58                array(),
59                '1!false',
60            ),
61            array(
62                'if.html',
63                array('S_VALUE' => true, 'S_OTHER_VALUE' => true),
64                array(),
65                array(),
66                '1!false',
67            ),
68            array(
69                'if.html',
70                array('S_OTHER_OTHER_VALUE' => true),
71                array(),
72                array(),
73                '|S_OTHER_OTHER_VALUE|!false',
74            ),
75            array(
76                'if.html',
77                array('S_VALUE' => false, 'S_OTHER_VALUE' => true),
78                array(),
79                array(),
80                '2!false',
81            ),
82            array(
83                'if.html',
84                array('S_TEST' => false),
85                array(),
86                array(),
87                '03false',
88            ),
89            array(
90                'if.html',
91                array('S_TEST' => 0),
92                array(),
93                array(),
94                '03!false',
95            ),
96            array(
97                'if.html',
98                array('VALUE_TEST' => 'value'),
99                array(),
100                array(),
101                '03!falsevalue',
102            ),
103            array(
104                'loop.html',
105                array(),
106                array(),
107                array(),
108                "noloop\nnoloop",
109            ),
110            array(
111                'loop.html',
112                array(),
113                array('test_loop' => array(array())),
114                array(),
115                "loop\nloop",
116            ),
117            array(
118                'loop.html',
119                array(),
120                array('test_loop' => array(array(), array()), 'test_loop.block' => array(array())),
121                array(),
122                "loop\nloop\nloop\nloop",
123            ),
124            array(
125                'loop.html',
126                array(),
127                array('test_loop' => array(array(), array()), 'test_loop.block' => array(array()), 'block' => array(array(), array())),
128                array(),
129                "loop\nloop\nloop\nloop\nloop#0-block#0\nloop#0-block#1\nloop#1-block#0\nloop#1-block#1",
130            ),
131            array(
132                'loop_twig.html',
133                array(),
134                array(),
135                array(),
136                "noloop\nnoloop",
137            ),
138            array(
139                'loop_twig.html',
140                array(),
141                array('test_loop' => array(array())),
142                array(),
143                "loop\nloop",
144            ),
145            array(
146                'loop_twig.html',
147                array(),
148                array('test_loop' => array(array(), array()), 'test_loop.block' => array(array())),
149                array(),
150                "loop\nloop\nloop\nloop",
151            ),
152            array(
153                'loop_twig.html',
154                array(),
155                array('test_loop' => array(array(), array()), 'test_loop.block' => array(array()), 'block' => array(array(), array())),
156                array(),
157                "loop\nloop\nloop\nloop\nloop#0-block#0\nloop#0-block#1\nloop#1-block#0\nloop#1-block#1",
158            ),
159            array(
160                'loop_vars.html',
161                array(),
162                array('test_loop' => array(array('VARIABLE' => 'x'))),
163                array(),
164                "first\n0 - a\nx - b\nset\nlast",
165            ),
166            array(
167                'loop_vars.html',
168                array(),
169                array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y'))),
170                array(),
171                "first\n0 - a\nx - b\nset\n1 - a\ny - b\nset\nlast",
172            ),
173            array(
174                'loop_vars.html',
175                array(),
176                array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'test_loop.inner' => array(array(), array())),
177                array(),
178                "first\n0 - a\nx - b\nset\n1 - a\ny - b\nset\nlast\n0 - c\n1 - c\nlast inner",
179            ),
180            array(
181                'loop_vars_twig.html',
182                array(),
183                array('test_loop' => array(array('VARIABLE' => 'x'))),
184                array(),
185                "first\n0 - a\nx - b\nset\nlast",
186            ),
187            array(
188                'loop_vars_twig.html',
189                array(),
190                array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y'))),
191                array(),
192                "first\n0 - a\nx - b\nset\n1 - a\ny - b\nset\nlast",
193            ),
194            array(
195                'loop_vars_twig.html',
196                array(),
197                array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'test_loop.inner' => array(array(), array())),
198                array(),
199                "first\n0 - a\nx - b\nset\n1 - a\ny - b\nset\nlast\n0 - c\n1 - c\nlast inner",
200            ),
201            array(
202                'loop_advanced.html',
203                array(),
204                array('test_loop' => array(array(), array(), array(), array(), array(), array(), array())),
205                array(),
206                "101234561\nx\n101234561\nx\n101234561\nx\n1234561\nx\n1\nx\n101\nx\n234\nx\n10\nx\n561\nx\n561",
207            ),
208            array(
209                'loop_advanced_twig.html',
210                array(),
211                array('test_loop' => array(array(), array(), array(), array(), array(), array(), array())),
212                array(),
213                "101234561\nx\n101234561\nx\n101234561\nx\n1234561\nx\n1\nx\n101\nx\n234\nx\n10\nx\n561\nx\n561",
214            ),
215            array(
216                'loop_nested2.html',
217                array(),
218                array('outer' => array(array(), array()), 'outer.middle' => array(array(), array())),
219                array(),
220                "o0o1m01m11",
221            ),
222            array(
223                'loop_nested2_twig.html',
224                array(),
225                array('outer' => array(array(), array()), 'outer.middle' => array(array(), array())),
226                array(),
227                "o0o1m01m11",
228            ),
229            array(
230                'define.html',
231                array(),
232                array('test_loop' => array(array(), array(), array(), array(), array(), array(), array()), 'test' => array(array()), 'test.deep' => array(array()), 'test.deep.defines' => array(array())),
233                array(),
234                "xyz\nabc\n\$VALUE == 'abc'\n(\$VALUE == 'abc')\n((\$VALUE == 'abc'))\n!\$DOESNT_EXIST\n(!\$DOESNT_EXIST)\nabc\nbar\nbar\nabc\ntest!@#$%^&*()_-=+{}[]:;\",<.>/?[]|foobar|false",
235            ),
236            array(
237                'define_advanced.html',
238                array(),
239                array('test_loop' => array(array(), array(), array(), array(), array(), array(), array()), 'test' => array(array()), 'test.deep' => array(array()), 'test.deep.defines' => array(array())),
240                array(),
241                "abc\nzxc\ncde\nbcd",
242            ),
243            array(
244                'expressions.html',
245                array(),
246                array(),
247                array(),
248                trim(str_repeat("pass\n", 10) . "\n"
249                    . str_repeat("pass\n", 4) . "\n"
250                    . str_repeat("pass\n", 2) . "\n"
251                    . str_repeat("pass\n", 6) . "\n"
252                    . str_repeat("pass\n", 2) . "\n"
253                    . str_repeat("pass\n", 6) . "\n"
254                    . str_repeat("pass\n", 2) . "\n"
255                    . str_repeat("pass\n", 2) . "\n"
256                    . str_repeat("pass\n", 3) . "\n"
257                    . str_repeat("pass\n", 2) . "\n"),
258            ),
259            array(
260                'include.html',
261                array('VARIABLE' => 'value'),
262                array(),
263                array(),
264                'value',
265            ),
266            array(
267                'include_define.html',
268                array('VARIABLE' => 'value'),
269                array(),
270                array(),
271                'value',
272            ),
273            array(
274                'include_loop.html',
275                array(),
276                array('test_loop' => array(array('NESTED_FILE' => 'include_loop1.html')), 'test_loop.inner' => array(array('NESTED_FILE' => 'include_loop1.html'), array('NESTED_FILE' => 'include_loop2.html'), array('NESTED_FILE' => 'include_loop3.html'))),
277                array(),
278                "1\n_1\n_02\n_3",
279            ),
280            array(
281                'include_variable.html',
282                array('FILE' => 'variable.html', 'VARIABLE' => 'value'),
283                array(),
284                array(),
285                'value',
286            ),
287            array(
288                'include_variables.html',
289                array('SUBDIR' => 'subdir', 'VARIABLE' => 'value'),
290                array(),
291                array(),
292                'value',
293            ),
294            array(
295                'loop_vars.html',
296                array(),
297                array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'test_loop.inner' => array(array(), array())),
298                array('test_loop'),
299                '',
300            ),
301            array(
302                'loop_vars_twig.html',
303                array(),
304                array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'test_loop.inner' => array(array(), array())),
305                array('test_loop'),
306                '',
307            ),
308            array(
309                'include_define_variable.html',
310                array('VARIABLE' => 'variable.html'),
311                array(),
312                array(),
313                "variable.html\nvariable.html\nvariable.html",
314            ),
315            array(
316                'include_loop_define.html',
317                array('VARIABLE' => 'value'),
318                array('test_loop' => array(array('NESTED_FILE' => 'variable.html'))),
319                array(),
320                'value',
321            ),
322            /* no top level nested loops
323            array(
324                'loop_vars.html',
325                array(),
326                array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'test_loop.inner' => array(array(), array())),
327                array('test_loop.inner'),
328                "first\n0\n0\n2\nx\nset\n1\n1\n2\ny\nset\nlast",
329            ),*/
330            array(
331                // Just like a regular loop but the name begins
332                // with an underscore
333                'loop_underscore.html',
334                array(),
335                array(),
336                array(),
337                "noloop\nnoloop",
338            ),
339            array(
340                // Just like a regular loop but the name begins
341                // with an underscore
342                'loop_underscore_twig.html',
343                array(),
344                array(),
345                array(),
346                "noloop\nnoloop",
347            ),
348            array(
349                'lang.html',
350                array(),
351                array(),
352                array(),
353                "VARIABLE\n1_VARIABLE\nVARIABLE\n1_VARIABLE",
354            ),
355            array(
356                'lang.html',
357                array(),
358                array(),
359                array(),
360                "Value'\n1 O'Clock\nValue\\u0027\n1\\u0020O\\u0027Clock",
361                array('VARIABLE' => "Value'", '1_VARIABLE' => "1 O'Clock"),
362            ),
363            array(
364                'lang_twig.html',
365                array(),
366                array(),
367                array(),
368                "VARIABLE\n1_VARIABLE\nVARIABLE\n1_VARIABLE\nVARIABLE\n1_VARIABLE\nARY_VARIABLE",
369            ),
370            array(
371                'lang_twig.html',
372                array(),
373                array(),
374                array(),
375                "Value'\n1 O'Clock\nValue\\u0027\n1\\u0020O\\u0027Clock\nValue'\n1 O'Clock\nfoo|bar",
376                array('VARIABLE' => "Value'", '1_VARIABLE' => "1 O'Clock", 'ARY_VARIABLE' => ['foo', 'bar']),
377            ),
378            array(
379                'loop_nested_multilevel_ref.html',
380                array(),
381                array(),
382                array(),
383                "top-level content",
384            ),
385            array(
386                'loop_nested_multilevel_ref_twig.html',
387                array(),
388                array(),
389                array(),
390                "top-level content",
391            ),
392            array(
393                'loop_nested_multilevel_ref.html',
394                array(),
395                array('outer' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'outer.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))),
396                array(),
397                "top-level content\nouter x\nouter y\ninner z\nfirst row\n\ninner zz",
398            ),
399            array(
400                'loop_nested_multilevel_ref_twig.html',
401                array(),
402                array('outer' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'outer.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))),
403                array(),
404                "top-level content\nouter x\nouter y\ninner z\nfirst row\n\ninner zz",
405            ),
406            array(
407                'loop_nested_deep_multilevel_ref.html',
408                array(),
409                array('outer' => array(array()), 'outer.middle' => array(array()), 'outer.middle.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))),
410                array(),
411                "top-level content\nouter\nmiddle\ninner z\nfirst row of 2 in inner\n\ninner zz",
412            ),
413            array(
414                'loop_nested_deep_multilevel_ref_twig.html',
415                array(),
416                array('outer' => array(array()), 'outer.middle' => array(array()), 'outer.middle.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))),
417                array(),
418                "top-level content\nouter\nmiddle\ninner z\nfirst row of 2 in inner\n\ninner zz",
419            ),
420            array(
421                'loop_size.html',
422                array(),
423                array('test_loop' => array(array()), 'empty_loop' => array()),
424                array(),
425                "nonexistent = 0\n! nonexistent\n\nempty = 0\n! empty\nloop\n\nin loop",
426            ),
427            array(
428                'loop_size_twig.html',
429                array(),
430                array('test_loop' => array(array()), 'empty_loop' => array()),
431                array(),
432                "nonexistent = 0\n! nonexistent\n\nempty = 0\n! empty\nloop\n\nin loop",
433            ),
434            array(
435                'loop_include.html',
436                array(),
437                array('test_loop' => array(array('foo' => 'bar'), array('foo' => 'bar1'))),
438                array(),
439                "barbarbar1bar1",
440            ),
441            array(
442                'loop_include_twig.html',
443                array(),
444                array('test_loop' => array(array('foo' => 'bar'), array('foo' => 'bar1'))),
445                array(),
446                "barbarbar1bar1",
447            ),
448            array(
449                'loop_nested_include.html',
450                array(),
451                array(
452                    'test_loop' => array(array('foo' => 'bar'), array('foo' => 'bar1')),
453                    'test_loop.inner' => array(array('myinner' => 'works')),
454                ),
455                array(),
456                "[bar|[bar|]][bar1|[bar1|[bar1|works]]]",
457                array(),
458            ),
459            array(
460                'loop_nested_include_twig.html',
461                array(),
462                array(
463                    'test_loop' => array(array('foo' => 'bar'), array('foo' => 'bar1')),
464                    'test_loop.inner' => array(array('myinner' => 'works')),
465                ),
466                array(),
467                "[bar|[bar|]][bar1|[bar1|[bar1|works]]]",
468                array(),
469            ),
470            /* Does not pass with the current implementation.
471            array(
472                'loop_reuse.html',
473                array(),
474                array('one' => array(array('VAR' => 'a'), array('VAR' => 'b')), 'one.one' => array(array('VAR' => 'c'), array('VAR' => 'd'))),
475                array(),
476                // Not entirely sure what should be outputted but the current output of "a" is most certainly wrong
477                "a\nb\nc\nd",
478            ),*/
479            array(
480                'loop_reuse_twig.html',
481                array(),
482                array('one' => array(array('VAR' => 'a'), array('VAR' => 'b')), 'one.one' => array(array('VAR' => 'c'), array('VAR' => 'd'))),
483                array(),
484                // Not entirely sure what should be outputted but the current output of "a" is most certainly wrong
485                "a\nb\nc\nd",
486            ),
487            array(
488                'twig.html',
489                array('VARIABLE' => 'FOObar',),
490                array(),
491                array(),
492                "13FOOBAR|foobar",
493            ),
494            array(
495                'if_nested_tags.html',
496                array('S_VALUE' => true,),
497                array(),
498                array(),
499                'inner_value',
500            ),
501            array(
502                'loop_expressions.html',
503                array(),
504                // Do not use 'loop' as a block name to not override Twig's internal 'loop' object
505                array('loop1' => array(array(),array(),array(),array(),array(),array()),),
506                array(),
507                'yesnononoyesnoyesnonoyesnono',
508            ),
509            array(
510                'loop_expressions_twig.html',
511                array(),
512                array('loop' => array(array(),array(),array(),array(),array(),array()),),
513                array(),
514                'yesnononoyesnoyesnonoyesnono',
515            ),
516            array(
517                'loop_expressions_twig2.html',
518                array('loop' => array(array(),array(),array(),array(),array(),array()),),
519                array(),
520                array(),
521                'yesnononoyesnoyesnonoyesnono',
522            ),
523        );
524    }
525
526    public function test_missing_file()
527    {
528        $filename = 'file_not_found.html';
529
530        $this->template->set_filenames(array('test' => $filename));
531        $this->assertFileDoesNotExist($this->template_path . '/' . $filename, 'Testing missing file, file cannot exist');
532
533        $this->expectException(\Twig\Error\LoaderError::class);
534
535        $this->display('test');
536    }
537
538
539    public function test_invalid_handle()
540    {
541        $this->expectException(\Twig\Error\LoaderError::class);
542
543        $this->display('test');
544    }
545
546    /**
547    * @dataProvider template_data
548    */
549    public function test_template($file, array $vars, array $block_vars, array $destroy, $expected, $lang_vars = array(), $incomplete_message = '')
550    {
551        if ($incomplete_message)
552        {
553            $this->markTestIncomplete($incomplete_message);
554        }
555
556        $this->run_template($file, $vars, $block_vars, $destroy, $expected, $lang_vars);
557    }
558
559    public function test_assign_display()
560    {
561        $this->run_template('basic.html', array(), array(), array(), "pass\npass\npass\n<!-- DUMMY var -->");
562
563        $this->template->set_filenames(array(
564            'test'        => 'basic.html',
565            'container'    => 'variable.html',
566        ));
567
568        $this->template->assign_display('test', 'VARIABLE', false);
569
570        $this->assertEquals("pass\npass\npass\n<!-- DUMMY var -->", $this->display('container'), "Testing assign_display(\$file)");
571    }
572
573    public function test_append_var_without_assign_var()
574    {
575        $this->template->set_filenames(array(
576            'append_var'    => 'variable.html'
577        ));
578
579        $items = array('This ', 'is ', 'a ', 'test');
580        $expecting = implode('', $items);
581
582        foreach ($items as $word)
583        {
584            $this->template->append_var('VARIABLE', $word);
585        }
586
587        $this->assertEquals($expecting, $this->display('append_var'));
588    }
589
590    public function test_append_var_with_assign_var()
591    {
592        $this->template->set_filenames(array(
593            'append_var'    => 'variable.html'
594        ));
595
596        $start = 'This ';
597        $items = array('is ', 'a ', 'test');
598        $expecting = $start . implode('', $items);
599
600        $this->template->assign_var('VARIABLE', $start);
601        foreach ($items as $word)
602        {
603            $this->template->append_var('VARIABLE', $word);
604        }
605
606        $this->assertEquals($expecting, $this->display('append_var'));
607    }
608
609    public function test_retrieve_data()
610    {
611        $this->template->set_filenames(array('test' => 'loop_nested.html'));
612
613        $this->template->assign_var('TEST_MORE', false);
614
615        // @todo Change this
616        $this->template->assign_vars(array('ONE' => true, 'TWO' => 'two', 'THREE' => 3));
617        $this->template->assign_block_vars('outer', array('POSITION' => 'O1'));
618        $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O1M1'));
619        $this->template->assign_block_vars('outer', array('POSITION' => 'O2'));
620        $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O2M1'));
621        $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O2M2'));
622        $this->template->assign_block_vars('outer', array('POSITION' => 'O3'));
623        $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O3M1'));
624        $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O3M2', 'ONE' => true, 'TWO' => 'two', 'THREE' => 3));
625        $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O3M3'));
626
627        $expect = 'outer - 0middle - 0outer - 1middle - 0middle - 1outer - 2middle - 0middle - 1middle - 2';
628        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring template is built correctly before modification');
629
630        $this->assertEquals(true, $this->template->retrieve_var('ONE'), 'Retrieve a single value from the template');
631        $this->assertEquals(null, $this->template->retrieve_var('FOUR'), 'Retrieve a non_existent value from the template');
632        $this->assertEquals(array('TWO' => 'two', 'THREE' => 3, 'FOUR' => null), $this->template->retrieve_vars(array('TWO','THREE', 'FOUR')), 'Retrieve several variables from the template');
633
634        $this->assertEquals(array('POSITION' => 'O3', 'SIZE' => null), $this->template->retrieve_block_vars('outer', array('POSITION', 'SIZE')), 'Retrieve vars from a block in the template');
635        $this->assertEquals(array('POSITION' => 'O2M1'), $this->template->retrieve_block_vars('outer[1].middle[0]', array('POSITION')), 'Retrieve single var from a nested indexed block in the template');
636        $this->assertEquals(array('S_ROW_NUM' => 2), $this->template->retrieve_block_vars('outer.middle', array('S_ROW_NUM')), 'Retrieve automatic var from a block in the template');
637        $this->assertEquals(array('POSITION' => 'O3M2', 'ONE' => true, 'TWO' => 'two', 'THREE' => 3), $this->template->retrieve_block_vars('outer[2].middle[1]', array()), 'Retrieve all vars from a block in the template');
638    }
639
640    public static function alter_block_array_data()
641    {
642        return array(
643            array(
644                'outer',
645                array('VARIABLE' => 'before'),
646                false,
647                'insert',
648                <<<EOT
649outer - 0 - before
650outer - 1
651middle - 0
652middle - 1
653outer - 2
654middle - 0
655middle - 1
656outer - 3
657middle - 0
658middle - 1
659EOT
660,
661                'Test inserting before on top level block',
662            ),
663            array(
664                'outer',
665                array('VARIABLE' => 'after'),
666                true,
667                'insert',
668                <<<EOT
669outer - 0
670middle - 0
671middle - 1
672outer - 1
673middle - 0
674middle - 1
675outer - 2
676middle - 0
677middle - 1
678outer - 3 - after
679EOT
680,
681                'Test inserting after on top level block',
682            ),
683            array(
684                'outer',
685                array('VARIABLE' => 'pos #1'),
686                1,
687                'insert',
688                <<<EOT
689outer - 0
690middle - 0
691middle - 1
692outer - 1 - pos #1
693outer - 2
694middle - 0
695middle - 1
696outer - 3
697middle - 0
698middle - 1
699EOT
700,
701                'Test inserting at 1 on top level block',
702            ),
703            array(
704                'outer',
705                array('VARIABLE' => 'changed'),
706                0,
707                'change',
708                <<<EOT
709outer - 0 - changed
710middle - 0
711middle - 1
712outer - 1
713middle - 0
714middle - 1
715outer - 2
716middle - 0
717middle - 1
718EOT
719,
720                'Test changing at 0 on top level block',
721            ),
722            array(
723                'outer',
724                array('VARIABLE' => 'changed'),
725                array('S_ROW_NUM' => 2),
726                'change',
727                <<<EOT
728outer - 0
729middle - 0
730middle - 1
731outer - 1
732middle - 0
733middle - 1
734outer - 2 - changed
735middle - 0
736middle - 1
737EOT
738,
739                'Test changing at KEY on top level block',
740            ),
741            array(
742                'outer.middle',
743                array('VARIABLE' => 'before'),
744                false,
745                'insert',
746                <<<EOT
747outer - 0
748middle - 0
749middle - 1
750outer - 1
751middle - 0
752middle - 1
753outer - 2
754middle - 0 - before
755middle - 1
756middle - 2
757EOT
758,
759                'Test inserting before on middle level block',
760            ),
761            array(
762                'outer.middle',
763                array('VARIABLE' => 'after'),
764                true,
765                'insert',
766                <<<EOT
767outer - 0
768middle - 0
769middle - 1
770outer - 1
771middle - 0
772middle - 1
773outer - 2
774middle - 0
775middle - 1
776middle - 2 - after
777EOT
778,
779                'Test inserting after on middle level block',
780            ),
781            array(
782                'outer[1].middle',
783                array('VARIABLE' => 'pos #1'),
784                1,
785                'insert',
786                <<<EOT
787outer - 0
788middle - 0
789middle - 1
790outer - 1
791middle - 0
792middle - 1 - pos #1
793middle - 2
794outer - 2
795middle - 0
796middle - 1
797EOT
798,
799                'Test inserting at 1 on middle level block',
800            ),
801            array(
802                'outer[].middle',
803                array('VARIABLE' => 'changed'),
804                0,
805                'change',
806                <<<EOT
807outer - 0
808middle - 0
809middle - 1
810outer - 1
811middle - 0
812middle - 1
813outer - 2
814middle - 0 - changed
815middle - 1
816EOT
817,
818                'Test changing at beginning of last top level block',
819            ),
820            array(
821                'outer.middle',
822                array('VARIABLE' => 'changed'),
823                array('S_ROW_NUM' => 1),
824                'change',
825                <<<EOT
826outer - 0
827middle - 0
828middle - 1
829outer - 1
830middle - 0
831middle - 1
832outer - 2
833middle - 0
834middle - 1 - changed
835EOT
836,
837                'Test changing at beginning of last top level block',
838            ),
839        );
840    }
841
842    /**
843    * @dataProvider alter_block_array_data
844    */
845    public function test_alter_block_array($alter_block, array $vararray, $key, $mode, $expect, $description)
846    {
847        $this->template->set_filenames(array('test' => 'loop_nested.html'));
848
849        // @todo Change this
850        $this->template->assign_block_vars('outer', array());
851        $this->template->assign_block_vars('outer.middle', array());
852        $this->template->assign_block_vars('outer.middle', array());
853        $this->template->assign_block_vars('outer', array());
854        $this->template->assign_block_vars('outer.middle', array());
855        $this->template->assign_block_vars('outer.middle', array());
856        $this->template->assign_block_vars('outer', array());
857        $this->template->assign_block_vars('outer.middle', array());
858        $this->template->assign_block_vars('outer.middle', array());
859
860        $this->assertEquals("outer - 0middle - 0middle - 1outer - 1middle - 0middle - 1outer - 2middle - 0middle - 1", $this->display('test'), 'Ensuring template is built correctly before modification');
861
862        $this->template->alter_block_array($alter_block, $vararray, $key, $mode);
863        $this->assertEquals(str_replace(array("\n", "\r", "\t"), '', $expect), str_replace(array("\n", "\r", "\t"), '', $this->display('test')), $description);
864    }
865
866    public function test_more_alter_block_array()
867    {
868        $this->template->set_filenames(array('test' => 'loop_nested.html'));
869
870        $this->template->assign_var('TEST_MORE', true);
871
872        // @todo Change this
873        $this->template->assign_block_vars('outer', array());
874        $this->template->assign_block_vars('outer.middle', array());
875        $this->template->assign_block_vars('outer', array());
876        $this->template->assign_block_vars('outer.middle', array());
877        $this->template->assign_block_vars('outer.middle', array());
878        $this->template->assign_block_vars('outer', array());
879        $this->template->assign_block_vars('outer.middle', array());
880        $this->template->assign_block_vars('outer.middle', array());
881        $this->template->assign_block_vars('outer.middle', array());
882
883        $expect = 'outer - 0[outer|3]middle - 0[middle|1]outer - 1[outer|3]middle - 0[middle|2]middle - 1[middle|2]outer - 2[outer|3]middle - 0[middle|3]middle - 1[middle|3]middle - 2[middle|3]';
884        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring template is built correctly before modification');
885
886        $this->template->alter_block_array('outer', array());
887
888        $expect = 'outer - 0[outer|4]outer - 1[outer|4]middle - 0[middle|1]outer - 2[outer|4]middle - 0[middle|2]middle - 1[middle|2]outer - 3[outer|4]middle - 0[middle|3]middle - 1[middle|3]middle - 2[middle|3]';
889        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring S_NUM_ROWS is correct after insertion');
890
891        $this->template->alter_block_array('outer', array('VARIABLE' => 'test'), 2, 'change');
892
893        $expect = 'outer - 0[outer|4]outer - 1[outer|4]middle - 0[middle|1]outer - 2 - test[outer|4]middle - 0[middle|2]middle - 1[middle|2]outer - 3[outer|4]middle - 0[middle|3]middle - 1[middle|3]middle - 2[middle|3]';
894        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring S_NUM_ROWS is correct after modification');
895
896        $this->template->alter_block_array('outer.middle', array());
897
898        $expect = 'outer - 0[outer|4]outer - 1[outer|4]middle - 0[middle|1]outer - 2 - test[outer|4]middle - 0[middle|2]middle - 1[middle|2]outer - 3[outer|4]middle - 0[middle|4]middle - 1[middle|4]middle - 2[middle|4]middle - 3[middle|4]';
899        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring S_NUM_ROWS is correct after insertion at middle level');
900
901        $this->template->alter_block_array('outer.middle', array('VARIABLE' => 'test'), 2, 'change');
902
903        $expect = 'outer - 0[outer|4]outer - 1[outer|4]middle - 0[middle|1]outer - 2 - test[outer|4]middle - 0[middle|2]middle - 1[middle|2]outer - 3[outer|4]middle - 0[middle|4]middle - 1[middle|4]middle - 2 - test[middle|4]middle - 3[middle|4]';
904        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring S_NUM_ROWS is correct after modification at middle level');
905    }
906
907    public function test_find_key_index()
908    {
909        $this->template->set_filenames(array('test' => 'loop_nested.html'));
910
911        $this->template->assign_var('TEST_MORE', true);
912
913        // @todo Change this
914        $this->template->assign_block_vars('outer', array('VARIABLE' => 'zero'));
915        $this->template->assign_block_vars('outer', array('VARIABLE' => 'one'));
916        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '1A'));
917        $this->template->assign_block_vars('outer', array('VARIABLE' => 'two'));
918        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '2A'));
919        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '2B'));
920        $this->template->assign_block_vars('outer', array('VARIABLE' => 'three'));
921        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3A'));
922        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3B'));
923        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3C'));
924
925        $expect = 'outer - 0 - zero[outer|4]outer - 1 - one[outer|4]middle - 0 - 1A[middle|1]outer - 2 - two[outer|4]middle - 0 - 2A[middle|2]middle - 1 - 2B[middle|2]outer - 3 - three[outer|4]middle - 0 - 3A[middle|3]middle - 1 - 3B[middle|3]middle - 2 - 3C[middle|3]';
926        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring template is built correctly before modification');
927
928        $this->template->find_key_index('outer', false);
929
930        $this->assertEquals(0, $this->template->find_key_index('outer', false), 'Find index at the beginning of outer loop');
931        $this->assertEquals(1, $this->template->find_key_index('outer', 1), 'Find index by index in outer loop');
932        $this->assertEquals(2, $this->template->find_key_index('outer', array('VARIABLE' => 'two')), 'Find index by key in outer loop');
933        $this->assertEquals(3, $this->template->find_key_index('outer', true), 'Find index at the end of outer loop');
934        $this->assertEquals(false, $this->template->find_key_index('outer', 7), 'Find index out of bounds of outer loop');
935
936        $this->assertEquals(false, $this->template->find_key_index('outer[0].middle', false), 'Find index at the beginning of middle loop, no middle block');
937        $this->assertEquals(false, $this->template->find_key_index('outer[1].middle', 1), 'Find index by index in inner loop, out of bounds');
938        $this->assertEquals(1, $this->template->find_key_index('outer[2].middle', array('VARIABLE' => '2B')), 'Find index by key in middle loop');
939        $this->assertEquals(2, $this->template->find_key_index('outer.middle', true), 'Find index at the end of middle loop');
940
941        $this->assertEquals(false, $this->template->find_key_index('outer.wrong', true), 'Wrong middle block name');
942        $this->assertEquals(false, $this->template->find_key_index('wrong.middle', false), 'Wrong outer block name');
943    }
944
945    public function test_delete_alter_block_array()
946    {
947        $this->template->set_filenames(array('test' => 'loop_nested.html'));
948
949        $this->template->assign_var('TEST_MORE', true);
950
951        // @todo Change this
952        $this->template->assign_block_vars('outer', array('VARIABLE' => 'zero'));
953        $this->template->assign_block_vars('outer', array('VARIABLE' => 'one'));
954        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '1A'));
955        $this->template->assign_block_vars('outer', array('VARIABLE' => 'two'));
956        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '2A'));
957        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '2B'));
958        $this->template->assign_block_vars('outer', array('VARIABLE' => 'three'));
959        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3A'));
960        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3B'));
961        $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3C'));
962
963        $expect = 'outer - 0 - zero[outer|4]outer - 1 - one[outer|4]middle - 0 - 1A[middle|1]outer - 2 - two[outer|4]middle - 0 - 2A[middle|2]middle - 1 - 2B[middle|2]outer - 3 - three[outer|4]middle - 0 - 3A[middle|3]middle - 1 - 3B[middle|3]middle - 2 - 3C[middle|3]';
964        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring template is built correctly before modification');
965
966        $this->template->alter_block_array('outer', array(), false, 'delete');
967
968        $expect = 'outer - 0 - one[outer|3]middle - 0 - 1A[middle|1]outer - 1 - two[outer|3]middle - 0 - 2A[middle|2]middle - 1 - 2B[middle|2]outer - 2 - three[outer|3]middle - 0 - 3A[middle|3]middle - 1 - 3B[middle|3]middle - 2 - 3C[middle|3]';
969        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Deleting at the beginning of outer loop');
970
971        $this->template->alter_block_array('outer[0].middle', array(), true, 'delete');
972
973        $expect = 'outer - 0 - one[outer|3]outer - 1 - two[outer|3]middle - 0 - 2A[middle|2]middle - 1 - 2B[middle|2]outer - 2 - three[outer|3]middle - 0 - 3A[middle|3]middle - 1 - 3B[middle|3]middle - 2 - 3C[middle|3]';
974        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Deleting at the end of first middle loop, delete complete loop');
975
976        $this->template->alter_block_array('outer', array(), 1, 'delete');
977
978        $expect = 'outer - 0 - one[outer|2]outer - 1 - three[outer|2]middle - 0 - 3A[middle|3]middle - 1 - 3B[middle|3]middle - 2 - 3C[middle|3]';
979        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Deleting by index at top level');
980
981        $this->template->alter_block_array('outer.middle', array(), 1, 'delete');
982
983        $expect = 'outer - 0 - one[outer|2]outer - 1 - three[outer|2]middle - 0 - 3A[middle|2]middle - 1 - 3C[middle|2]';
984        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Deleting by index at middle level');
985
986        $this->template->alter_block_array('outer', array(), 4, 'delete');
987
988        $expect = 'outer - 0 - one[outer|2]outer - 1 - three[outer|2]middle - 0 - 3A[middle|2]middle - 1 - 3C[middle|2]';
989        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Deleting by index out of bounds, ignored');
990    }
991
992    public function test_indexed_assign_block_vars()
993    {
994        $this->template->set_filenames(array('test' => 'loop_nested.html'));
995
996        $this->template->assign_var('TEST_MORE', true);
997
998        // @todo Change this
999        $this->template->assign_block_vars('outer', array());
1000        $this->template->assign_block_vars('outer.middle', array());
1001        $this->template->assign_block_vars('outer', array());
1002        $this->template->assign_block_vars('outer.middle', array());
1003        $this->template->assign_block_vars('outer.middle', array());
1004        $this->template->assign_block_vars('outer', array());
1005        $this->template->assign_block_vars('outer.middle', array());
1006        $this->template->assign_block_vars('outer.middle', array());
1007        $this->template->assign_block_vars('outer.middle', array());
1008
1009        $expect = 'outer - 0[outer|3]middle - 0[middle|1]outer - 1[outer|3]middle - 0[middle|2]middle - 1[middle|2]outer - 2[outer|3]middle - 0[middle|3]middle - 1[middle|3]middle - 2[middle|3]';
1010        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring template is built correctly before modification');
1011
1012        $this->template->assign_block_vars('outer[0].middle', array('VARIABLE' => 'test'));
1013
1014        $expect = 'outer - 0[outer|3]middle - 0[middle|2]middle - 1 - test[middle|2]outer - 1[outer|3]middle - 0[middle|2]middle - 1[middle|2]outer - 2[outer|3]middle - 0[middle|3]middle - 1[middle|3]middle - 2[middle|3]';
1015        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Inserting at the first outer block');
1016
1017        $this->template->assign_block_vars('outer[1].middle[0].inner', array());
1018
1019        $expect = 'outer - 0[outer|3]middle - 0[middle|2]middle - 1 - test[middle|2]outer - 1[outer|3]middle - 0[middle|2]inner - 0[inner|1]middle - 1[middle|2]outer - 2[outer|3]middle - 0[middle|3]middle - 1[middle|3]middle - 2[middle|3]';
1020        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Creating an inner block at the first middle block in the second outer block');
1021
1022        $this->template->assign_block_vars('outer[1].middle[0].inner', array());
1023
1024        $expect = 'outer - 0[outer|3]middle - 0[middle|2]middle - 1 - test[middle|2]outer - 1[outer|3]middle - 0[middle|2]inner - 0[inner|2]inner - 1[inner|2]middle - 1[middle|2]outer - 2[outer|3]middle - 0[middle|3]middle - 1[middle|3]middle - 2[middle|3]';
1025        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Inserting another inner block in the same place');
1026
1027        $this->template->assign_block_vars('outer.middle[1].inner', array('VARIABLE' => 'test'));
1028
1029        $expect = 'outer - 0[outer|3]middle - 0[middle|2]middle - 1 - test[middle|2]outer - 1[outer|3]middle - 0[middle|2]inner - 0[inner|2]inner - 1[inner|2]middle - 1[middle|2]outer - 2[outer|3]middle - 0[middle|3]middle - 1[middle|3]inner - 0 - test[inner|1]middle - 2[middle|3]';
1030        $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Inserting another inner block in the same place');
1031    }
1032
1033    public static function assign_block_vars_array_data()
1034    {
1035        return array(
1036            array(
1037                array(
1038                    'outer' => array(
1039                        array('VARIABLE' => 'Test assigning block vars array loop 0:'),
1040                        array('VARIABLE' => 'Test assigning block vars array loop 1:'),
1041                    ),
1042                    'outer.middle' => array(
1043                        array('VARIABLE' => '1st iteration',),
1044                        array('VARIABLE' => '2nd iteration',),
1045                        array('VARIABLE' => '3rd iteration',),
1046                    ),
1047                )
1048            )
1049        );
1050    }
1051
1052    /**
1053    * @dataProvider assign_block_vars_array_data
1054    */
1055    public function test_assign_block_vars_array($block_data)
1056    {
1057        $this->template->set_filenames(array('test' => 'loop_nested.html'));
1058
1059        foreach ($block_data as $blockname => $block_vars_array)
1060        {
1061            $this->template->assign_block_vars_array($blockname, $block_vars_array);
1062        }
1063
1064        $this->assertEquals("outer - 0 - Test assigning block vars array loop 0:outer - 1 - Test assigning block vars array loop 1:middle - 0 - 1st iterationmiddle - 1 - 2nd iterationmiddle - 2 - 3rd iteration", $this->display('test'), 'Ensuring assigning block vars array to template is working correctly');
1065    }
1066
1067    public function test_define_error()
1068    {
1069        $this->expectException(\Twig\Error\SyntaxError::class);
1070        $this->run_template('define_error.html', array(), array(), array(), '');
1071    }
1072}