5b07c40e8e7419097c95ff106c4769cea3dc6fb2
[yaffs-website] / vendor / twig / twig / test / Twig / Tests / EnvironmentTest.php
1 <?php
2
3 /*
4  * This file is part of Twig.
5  *
6  * (c) Fabien Potencier
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 require_once dirname(__FILE__).'/FilesystemHelper.php';
13
14 class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
15 {
16     private $deprecations = array();
17
18     /**
19      * @group legacy
20      */
21     public function testLegacyTokenizeSignature()
22     {
23         $env = new Twig_Environment();
24         $stream = $env->tokenize('{{ foo }}', 'foo');
25         $this->assertEquals('{{ foo }}', $stream->getSource());
26         $this->assertEquals('foo', $stream->getFilename());
27     }
28
29     /**
30      * @group legacy
31      */
32     public function testLegacyCompileSourceSignature()
33     {
34         $loader = new Twig_Loader_Array(array('foo' => '{{ foo }}'));
35         $env = new Twig_Environment($loader);
36         $this->assertContains('getTemplateName', $env->compileSource('{{ foo }}', 'foo'));
37     }
38
39     /**
40      * @expectedException        LogicException
41      * @expectedExceptionMessage You must set a loader first.
42      * @group legacy
43      */
44     public function testRenderNoLoader()
45     {
46         $env = new Twig_Environment();
47         $env->render('test');
48     }
49
50     public function testAutoescapeOption()
51     {
52         $loader = new Twig_Loader_Array(array(
53             'html' => '{{ foo }} {{ foo }}',
54             'js' => '{{ bar }} {{ bar }}',
55         ));
56
57         $twig = new Twig_Environment($loader, array(
58             'debug' => true,
59             'cache' => false,
60             'autoescape' => array($this, 'escapingStrategyCallback'),
61         ));
62
63         $this->assertEquals('foo&lt;br/ &gt; foo&lt;br/ &gt;', $twig->render('html', array('foo' => 'foo<br/ >')));
64         $this->assertEquals('foo\x3Cbr\x2F\x20\x3E foo\x3Cbr\x2F\x20\x3E', $twig->render('js', array('bar' => 'foo<br/ >')));
65     }
66
67     public function escapingStrategyCallback($name)
68     {
69         return $name;
70     }
71
72     public function testGlobals()
73     {
74         // to be removed in 2.0
75         $loader = $this->getMockBuilder('Twig_EnvironmentTestLoaderInterface')->getMock();
76         //$loader = $this->getMockBuilder(array('Twig_LoaderInterface', 'Twig_SourceContextLoaderInterface'))->getMock();
77         $loader->expects($this->any())->method('getSourceContext')->will($this->returnValue(new Twig_Source('', '')));
78
79         // globals can be added after calling getGlobals
80
81         $twig = new Twig_Environment($loader);
82         $twig->addGlobal('foo', 'foo');
83         $twig->getGlobals();
84         $twig->addGlobal('foo', 'bar');
85         $globals = $twig->getGlobals();
86         $this->assertEquals('bar', $globals['foo']);
87
88         // globals can be modified after a template has been loaded
89         $twig = new Twig_Environment($loader);
90         $twig->addGlobal('foo', 'foo');
91         $twig->getGlobals();
92         $twig->loadTemplate('index');
93         $twig->addGlobal('foo', 'bar');
94         $globals = $twig->getGlobals();
95         $this->assertEquals('bar', $globals['foo']);
96
97         // globals can be modified after extensions init
98         $twig = new Twig_Environment($loader);
99         $twig->addGlobal('foo', 'foo');
100         $twig->getGlobals();
101         $twig->getFunctions();
102         $twig->addGlobal('foo', 'bar');
103         $globals = $twig->getGlobals();
104         $this->assertEquals('bar', $globals['foo']);
105
106         // globals can be modified after extensions and a template has been loaded
107         $arrayLoader = new Twig_Loader_Array(array('index' => '{{foo}}'));
108         $twig = new Twig_Environment($arrayLoader);
109         $twig->addGlobal('foo', 'foo');
110         $twig->getGlobals();
111         $twig->getFunctions();
112         $twig->loadTemplate('index');
113         $twig->addGlobal('foo', 'bar');
114         $globals = $twig->getGlobals();
115         $this->assertEquals('bar', $globals['foo']);
116
117         $twig = new Twig_Environment($arrayLoader);
118         $twig->getGlobals();
119         $twig->addGlobal('foo', 'bar');
120         $template = $twig->loadTemplate('index');
121         $this->assertEquals('bar', $template->render(array()));
122
123         /* to be uncomment in Twig 2.0
124         // globals cannot be added after a template has been loaded
125         $twig = new Twig_Environment($loader);
126         $twig->addGlobal('foo', 'foo');
127         $twig->getGlobals();
128         $twig->loadTemplate('index');
129         try {
130             $twig->addGlobal('bar', 'bar');
131             $this->fail();
132         } catch (LogicException $e) {
133             $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
134         }
135
136         // globals cannot be added after extensions init
137         $twig = new Twig_Environment($loader);
138         $twig->addGlobal('foo', 'foo');
139         $twig->getGlobals();
140         $twig->getFunctions();
141         try {
142             $twig->addGlobal('bar', 'bar');
143             $this->fail();
144         } catch (LogicException $e) {
145             $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
146         }
147
148         // globals cannot be added after extensions and a template has been loaded
149         $twig = new Twig_Environment($loader);
150         $twig->addGlobal('foo', 'foo');
151         $twig->getGlobals();
152         $twig->getFunctions();
153         $twig->loadTemplate('index');
154         try {
155             $twig->addGlobal('bar', 'bar');
156             $this->fail();
157         } catch (LogicException $e) {
158             $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
159         }
160
161         // test adding globals after a template has been loaded without call to getGlobals
162         $twig = new Twig_Environment($loader);
163         $twig->loadTemplate('index');
164         try {
165             $twig->addGlobal('bar', 'bar');
166             $this->fail();
167         } catch (LogicException $e) {
168             $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
169         }
170         */
171     }
172
173     public function testExtensionsAreNotInitializedWhenRenderingACompiledTemplate()
174     {
175         $cache = new Twig_Cache_Filesystem($dir = sys_get_temp_dir().'/twig');
176         $options = array('cache' => $cache, 'auto_reload' => false, 'debug' => false);
177
178         // force compilation
179         $twig = new Twig_Environment($loader = new Twig_Loader_Array(array('index' => '{{ foo }}')), $options);
180
181         $key = $cache->generateKey('index', $twig->getTemplateClass('index'));
182         $cache->write($key, $twig->compileSource(new Twig_Source('{{ foo }}', 'index')));
183
184         // check that extensions won't be initialized when rendering a template that is already in the cache
185         $twig = $this
186             ->getMockBuilder('Twig_Environment')
187             ->setConstructorArgs(array($loader, $options))
188             ->setMethods(array('initExtensions'))
189             ->getMock()
190         ;
191
192         $twig->expects($this->never())->method('initExtensions');
193
194         // render template
195         $output = $twig->render('index', array('foo' => 'bar'));
196         $this->assertEquals('bar', $output);
197
198         Twig_Tests_FilesystemHelper::removeDir($dir);
199     }
200
201     public function testAutoReloadCacheMiss()
202     {
203         $templateName = __FUNCTION__;
204         $templateContent = __FUNCTION__;
205
206         $cache = $this->getMockBuilder('Twig_CacheInterface')->getMock();
207         $loader = $this->getMockLoader($templateName, $templateContent);
208         $twig = new Twig_Environment($loader, array('cache' => $cache, 'auto_reload' => true, 'debug' => false));
209
210         // Cache miss: getTimestamp returns 0 and as a result the load() is
211         // skipped.
212         $cache->expects($this->once())
213             ->method('generateKey')
214             ->will($this->returnValue('key'));
215         $cache->expects($this->once())
216             ->method('getTimestamp')
217             ->will($this->returnValue(0));
218         $loader->expects($this->never())
219             ->method('isFresh');
220         $cache->expects($this->once())
221             ->method('write');
222         $cache->expects($this->once())
223             ->method('load');
224
225         $twig->loadTemplate($templateName);
226     }
227
228     public function testAutoReloadCacheHit()
229     {
230         $templateName = __FUNCTION__;
231         $templateContent = __FUNCTION__;
232
233         $cache = $this->getMockBuilder('Twig_CacheInterface')->getMock();
234         $loader = $this->getMockLoader($templateName, $templateContent);
235         $twig = new Twig_Environment($loader, array('cache' => $cache, 'auto_reload' => true, 'debug' => false));
236
237         $now = time();
238
239         // Cache hit: getTimestamp returns something > extension timestamps and
240         // the loader returns true for isFresh().
241         $cache->expects($this->once())
242             ->method('generateKey')
243             ->will($this->returnValue('key'));
244         $cache->expects($this->once())
245             ->method('getTimestamp')
246             ->will($this->returnValue($now));
247         $loader->expects($this->once())
248             ->method('isFresh')
249             ->will($this->returnValue(true));
250         $cache->expects($this->atLeastOnce())
251             ->method('load');
252
253         $twig->loadTemplate($templateName);
254     }
255
256     public function testAutoReloadOutdatedCacheHit()
257     {
258         $templateName = __FUNCTION__;
259         $templateContent = __FUNCTION__;
260
261         $cache = $this->getMockBuilder('Twig_CacheInterface')->getMock();
262         $loader = $this->getMockLoader($templateName, $templateContent);
263         $twig = new Twig_Environment($loader, array('cache' => $cache, 'auto_reload' => true, 'debug' => false));
264
265         $now = time();
266
267         $cache->expects($this->once())
268             ->method('generateKey')
269             ->will($this->returnValue('key'));
270         $cache->expects($this->once())
271             ->method('getTimestamp')
272             ->will($this->returnValue($now));
273         $loader->expects($this->once())
274             ->method('isFresh')
275             ->will($this->returnValue(false));
276         $cache->expects($this->once())
277             ->method('write');
278         $cache->expects($this->once())
279             ->method('load');
280
281         $twig->loadTemplate($templateName);
282     }
283
284     /**
285      * @group legacy
286      */
287     public function testHasGetExtensionWithDynamicName()
288     {
289         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
290
291         $ext1 = new Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName('ext1');
292         $ext2 = new Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName('ext2');
293         $twig->addExtension($ext1);
294         $twig->addExtension($ext2);
295
296         $this->assertTrue($twig->hasExtension('ext1'));
297         $this->assertTrue($twig->hasExtension('ext2'));
298
299         $this->assertTrue($twig->hasExtension('Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName'));
300
301         $this->assertSame($ext1, $twig->getExtension('ext1'));
302         $this->assertSame($ext2, $twig->getExtension('ext2'));
303     }
304
305     public function testHasGetExtensionByClassName()
306     {
307         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
308         $twig->addExtension($ext = new Twig_Tests_EnvironmentTest_Extension());
309         $this->assertTrue($twig->hasExtension('Twig_Tests_EnvironmentTest_Extension'));
310         $this->assertTrue($twig->hasExtension('\Twig_Tests_EnvironmentTest_Extension'));
311
312         $this->assertSame($ext, $twig->getExtension('Twig_Tests_EnvironmentTest_Extension'));
313         $this->assertSame($ext, $twig->getExtension('\Twig_Tests_EnvironmentTest_Extension'));
314
315         $this->assertTrue($twig->hasExtension('Twig\Tests\EnvironmentTest\Extension'));
316         $this->assertSame($ext, $twig->getExtension('Twig\Tests\EnvironmentTest\Extension'));
317     }
318
319     public function testAddExtension()
320     {
321         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
322         $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension());
323
324         $this->assertArrayHasKey('test', $twig->getTags());
325         $this->assertArrayHasKey('foo_filter', $twig->getFilters());
326         $this->assertArrayHasKey('foo_function', $twig->getFunctions());
327         $this->assertArrayHasKey('foo_test', $twig->getTests());
328         $this->assertArrayHasKey('foo_unary', $twig->getUnaryOperators());
329         $this->assertArrayHasKey('foo_binary', $twig->getBinaryOperators());
330         $this->assertArrayHasKey('foo_global', $twig->getGlobals());
331         $visitors = $twig->getNodeVisitors();
332         $found = false;
333         foreach ($visitors as $visitor) {
334             if ($visitor instanceof Twig_Tests_EnvironmentTest_NodeVisitor) {
335                 $found = true;
336             }
337         }
338         $this->assertTrue($found);
339     }
340
341     /**
342      * @requires PHP 5.3
343      */
344     public function testAddExtensionWithDeprecatedGetGlobals()
345     {
346         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
347         $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension_WithGlobals());
348
349         $this->deprecations = array();
350         set_error_handler(array($this, 'handleError'));
351
352         $this->assertArrayHasKey('foo_global', $twig->getGlobals());
353
354         $this->assertCount(1, $this->deprecations);
355         $this->assertContains('Defining the getGlobals() method in the "Twig_Tests_EnvironmentTest_Extension_WithGlobals" extension ', $this->deprecations[0]);
356
357         restore_error_handler();
358     }
359
360     /**
361      * @group legacy
362      */
363     public function testRemoveExtension()
364     {
365         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
366         $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension_WithDeprecatedName());
367         $twig->removeExtension('environment_test');
368
369         $this->assertArrayNotHasKey('test', $twig->getTags());
370         $this->assertArrayNotHasKey('foo_filter', $twig->getFilters());
371         $this->assertArrayNotHasKey('foo_function', $twig->getFunctions());
372         $this->assertArrayNotHasKey('foo_test', $twig->getTests());
373         $this->assertArrayNotHasKey('foo_unary', $twig->getUnaryOperators());
374         $this->assertArrayNotHasKey('foo_binary', $twig->getBinaryOperators());
375         $this->assertArrayNotHasKey('foo_global', $twig->getGlobals());
376         $this->assertCount(2, $twig->getNodeVisitors());
377     }
378
379     public function testAddMockExtension()
380     {
381         // should be replaced by the following in 2.0 (this current code is just to avoid a dep notice)
382         // $extension = $this->getMockBuilder('Twig_Extension')->getMock();
383         $extension = eval(<<<EOF
384 class Twig_Tests_EnvironmentTest_ExtensionInEval extends Twig_Extension
385 {
386 }
387 EOF
388         );
389         $extension = new Twig_Tests_EnvironmentTest_ExtensionInEval();
390
391         $loader = new Twig_Loader_Array(array('page' => 'hey'));
392
393         $twig = new Twig_Environment($loader);
394         $twig->addExtension($extension);
395
396         $this->assertInstanceOf('Twig_ExtensionInterface', $twig->getExtension(get_class($extension)));
397         $this->assertTrue($twig->isTemplateFresh('page', time()));
398     }
399
400     public function testInitRuntimeWithAnExtensionUsingInitRuntimeNoDeprecation()
401     {
402         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
403         $twig->addExtension(new Twig_Tests_EnvironmentTest_ExtensionWithoutDeprecationInitRuntime());
404         $twig->initRuntime();
405
406         // add a dummy assertion here to satisfy PHPUnit, the only thing we want to test is that the code above
407         // can be executed without throwing any deprecations
408         $this->addToAssertionCount(1);
409     }
410
411     /**
412      * @requires PHP 5.3
413      */
414     public function testInitRuntimeWithAnExtensionUsingInitRuntimeDeprecation()
415     {
416         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
417         $twig->addExtension(new Twig_Tests_EnvironmentTest_ExtensionWithDeprecationInitRuntime());
418
419         $this->deprecations = array();
420         set_error_handler(array($this, 'handleError'));
421
422         $twig->initRuntime();
423
424         $this->assertCount(1, $this->deprecations);
425         $this->assertContains('Defining the initRuntime() method in the "Twig_Tests_EnvironmentTest_ExtensionWithDeprecationInitRuntime" extension is deprecated since version 1.23.', $this->deprecations[0]);
426
427         restore_error_handler();
428     }
429
430     public function handleError($type, $msg)
431     {
432         if (E_USER_DEPRECATED === $type) {
433             $this->deprecations[] = $msg;
434         }
435     }
436
437     /**
438      * @requires PHP 5.3
439      */
440     public function testOverrideExtension()
441     {
442         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
443         $twig->addExtension(new Twig_Tests_EnvironmentTest_ExtensionWithDeprecationInitRuntime());
444
445         $this->deprecations = array();
446         set_error_handler(array($this, 'handleError'));
447
448         $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension_WithDeprecatedName());
449         $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension_WithDeprecatedName());
450
451         $this->assertCount(1, $this->deprecations);
452         $this->assertContains('The possibility to register the same extension twice', $this->deprecations[0]);
453
454         restore_error_handler();
455     }
456
457     public function testAddRuntimeLoader()
458     {
459         $runtimeLoader = $this->getMockBuilder('Twig_RuntimeLoaderInterface')->getMock();
460         $runtimeLoader->expects($this->any())->method('load')->will($this->returnValue(new Twig_Tests_EnvironmentTest_Runtime()));
461
462         $loader = new Twig_Loader_Array(array(
463             'func_array' => '{{ from_runtime_array("foo") }}',
464             'func_array_default' => '{{ from_runtime_array() }}',
465             'func_array_named_args' => '{{ from_runtime_array(name="foo") }}',
466             'func_string' => '{{ from_runtime_string("foo") }}',
467             'func_string_default' => '{{ from_runtime_string() }}',
468             'func_string_named_args' => '{{ from_runtime_string(name="foo") }}',
469         ));
470
471         $twig = new Twig_Environment($loader);
472         $twig->addExtension(new Twig_Tests_EnvironmentTest_ExtensionWithoutRuntime());
473         $twig->addRuntimeLoader($runtimeLoader);
474
475         $this->assertEquals('foo', $twig->render('func_array'));
476         $this->assertEquals('bar', $twig->render('func_array_default'));
477         $this->assertEquals('foo', $twig->render('func_array_named_args'));
478         $this->assertEquals('foo', $twig->render('func_string'));
479         $this->assertEquals('bar', $twig->render('func_string_default'));
480         $this->assertEquals('foo', $twig->render('func_string_named_args'));
481     }
482
483     protected function getMockLoader($templateName, $templateContent)
484     {
485         // to be removed in 2.0
486         $loader = $this->getMockBuilder('Twig_EnvironmentTestLoaderInterface')->getMock();
487         //$loader = $this->getMockBuilder(array('Twig_LoaderInterface', 'Twig_SourceContextLoaderInterface'))->getMock();
488         $loader->expects($this->any())
489           ->method('getSourceContext')
490           ->with($templateName)
491           ->will($this->returnValue(new Twig_Source($templateContent, $templateName)));
492         $loader->expects($this->any())
493           ->method('getCacheKey')
494           ->with($templateName)
495           ->will($this->returnValue($templateName));
496
497         return $loader;
498     }
499 }
500
501 class Twig_Tests_EnvironmentTest_Extension_WithGlobals extends Twig_Extension
502 {
503     public function getGlobals()
504     {
505         return array(
506             'foo_global' => 'foo_global',
507         );
508     }
509 }
510
511 class Twig_Tests_EnvironmentTest_Extension extends Twig_Extension implements Twig_Extension_GlobalsInterface
512 {
513     public function getTokenParsers()
514     {
515         return array(
516             new Twig_Tests_EnvironmentTest_TokenParser(),
517         );
518     }
519
520     public function getNodeVisitors()
521     {
522         return array(
523             new Twig_Tests_EnvironmentTest_NodeVisitor(),
524         );
525     }
526
527     public function getFilters()
528     {
529         return array(
530             new Twig_SimpleFilter('foo_filter', 'foo_filter'),
531         );
532     }
533
534     public function getTests()
535     {
536         return array(
537             new Twig_SimpleTest('foo_test', 'foo_test'),
538         );
539     }
540
541     public function getFunctions()
542     {
543         return array(
544             new Twig_SimpleFunction('foo_function', 'foo_function'),
545         );
546     }
547
548     public function getOperators()
549     {
550         return array(
551             array('foo_unary' => array()),
552             array('foo_binary' => array()),
553         );
554     }
555
556     public function getGlobals()
557     {
558         return array(
559             'foo_global' => 'foo_global',
560         );
561     }
562 }
563 class_alias('Twig_Tests_EnvironmentTest_Extension', 'Twig\Tests\EnvironmentTest\Extension', false);
564
565 class Twig_Tests_EnvironmentTest_Extension_WithDeprecatedName extends Twig_Extension
566 {
567     public function getName()
568     {
569         return 'environment_test';
570     }
571 }
572
573 class Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName extends Twig_Extension
574 {
575     private $name;
576
577     public function __construct($name)
578     {
579         $this->name = $name;
580     }
581
582     public function getName()
583     {
584         return $this->name;
585     }
586 }
587
588 class Twig_Tests_EnvironmentTest_TokenParser extends Twig_TokenParser
589 {
590     public function parse(Twig_Token $token)
591     {
592     }
593
594     public function getTag()
595     {
596         return 'test';
597     }
598 }
599
600 class Twig_Tests_EnvironmentTest_NodeVisitor implements Twig_NodeVisitorInterface
601 {
602     public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
603     {
604         return $node;
605     }
606
607     public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
608     {
609         return $node;
610     }
611
612     public function getPriority()
613     {
614         return 0;
615     }
616 }
617
618 class Twig_Tests_EnvironmentTest_ExtensionWithDeprecationInitRuntime extends Twig_Extension
619 {
620     public function initRuntime(Twig_Environment $env)
621     {
622     }
623 }
624
625 class Twig_Tests_EnvironmentTest_ExtensionWithoutDeprecationInitRuntime extends Twig_Extension implements Twig_Extension_InitRuntimeInterface
626 {
627     public function initRuntime(Twig_Environment $env)
628     {
629     }
630 }
631
632 class Twig_Tests_EnvironmentTest_ExtensionWithoutRuntime extends Twig_Extension
633 {
634     public function getFunctions()
635     {
636         return array(
637             new Twig_SimpleFunction('from_runtime_array', array('Twig_Tests_EnvironmentTest_Runtime', 'fromRuntime')),
638             new Twig_SimpleFunction('from_runtime_string', 'Twig_Tests_EnvironmentTest_Runtime::fromRuntime'),
639         );
640     }
641
642     public function getName()
643     {
644         return 'from_runtime';
645     }
646 }
647
648 class Twig_Tests_EnvironmentTest_Runtime
649 {
650     public function fromRuntime($name = 'bar')
651     {
652         return $name;
653     }
654 }
655
656 // to be removed in 2.0
657 interface Twig_EnvironmentTestLoaderInterface extends Twig_LoaderInterface, Twig_SourceContextLoaderInterface
658 {
659 }