Security update for Core, with self-updated composer
[yaffs-website] / vendor / twig / twig / test / Twig / Tests / TemplateTest.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 class Twig_Tests_TemplateTest extends \PHPUnit\Framework\TestCase
12 {
13     /**
14      * @expectedException LogicException
15      */
16     public function testDisplayBlocksAcceptTemplateOnlyAsBlocks()
17     {
18         $template = $this->getMockForAbstractClass('Twig_Template', array(), '', false);
19         $template->displayBlock('foo', array(), array('foo' => array(new stdClass(), 'foo')));
20     }
21
22     /**
23      * @dataProvider getAttributeExceptions
24      */
25     public function testGetAttributeExceptions($template, $message)
26     {
27         $templates = array('index' => $template);
28         $env = new Twig_Environment(new Twig_Loader_Array($templates), array('strict_variables' => true));
29         $template = $env->loadTemplate('index');
30
31         $context = array(
32             'string' => 'foo',
33             'null' => null,
34             'empty_array' => array(),
35             'array' => array('foo' => 'foo'),
36             'array_access' => new Twig_TemplateArrayAccessObject(),
37             'magic_exception' => new Twig_TemplateMagicPropertyObjectWithException(),
38             'object' => new stdClass(),
39         );
40
41         try {
42             $template->render($context);
43             $this->fail('Accessing an invalid attribute should throw an exception.');
44         } catch (Twig_Error_Runtime $e) {
45             $this->assertSame(sprintf($message, 'index'), $e->getMessage());
46         }
47     }
48
49     public function getAttributeExceptions()
50     {
51         return array(
52             array('{{ string["a"] }}', 'Impossible to access a key ("a") on a string variable ("foo") in "%s" at line 1.'),
53             array('{{ null["a"] }}', 'Impossible to access a key ("a") on a null variable in "%s" at line 1.'),
54             array('{{ empty_array["a"] }}', 'Key "a" does not exist as the array is empty in "%s" at line 1.'),
55             array('{{ array["a"] }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1.'),
56             array('{{ array_access["a"] }}', 'Key "a" in object with ArrayAccess of class "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1.'),
57             array('{{ string.a }}', 'Impossible to access an attribute ("a") on a string variable ("foo") in "%s" at line 1.'),
58             array('{{ string.a() }}', 'Impossible to invoke a method ("a") on a string variable ("foo") in "%s" at line 1.'),
59             array('{{ null.a }}', 'Impossible to access an attribute ("a") on a null variable in "%s" at line 1.'),
60             array('{{ null.a() }}', 'Impossible to invoke a method ("a") on a null variable in "%s" at line 1.'),
61             array('{{ array.a() }}', 'Impossible to invoke a method ("a") on an array in "%s" at line 1.'),
62             array('{{ empty_array.a }}', 'Key "a" does not exist as the array is empty in "%s" at line 1.'),
63             array('{{ array.a }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1.'),
64             array('{{ attribute(array, -10) }}', 'Key "-10" for array with keys "foo" does not exist in "%s" at line 1.'),
65             array('{{ array_access.a }}', 'Neither the property "a" nor one of the methods "a()", "geta()"/"isa()" or "__call()" exist and have public access in class "Twig_TemplateArrayAccessObject" in "%s" at line 1.'),
66             array('{% from _self import foo %}{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ foo(array_access) }}', 'Neither the property "missing_method" nor one of the methods "missing_method()", "getmissing_method()"/"ismissing_method()" or "__call()" exist and have public access in class "Twig_TemplateArrayAccessObject" in "%s" at line 1.'),
67             array('{{ magic_exception.test }}', 'An exception has been thrown during the rendering of a template ("Hey! Don\'t try to isset me!") in "%s" at line 1.'),
68             array('{{ object["a"] }}', 'Impossible to access a key "a" on an object of class "stdClass" that does not implement ArrayAccess interface in "%s" at line 1.'),
69         );
70     }
71
72     /**
73      * @dataProvider getGetAttributeWithSandbox
74      */
75     public function testGetAttributeWithSandbox($object, $item, $allowed)
76     {
77         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
78         $policy = new Twig_Sandbox_SecurityPolicy(array(), array(), array(/*method*/), array(/*prop*/), array());
79         $twig->addExtension(new Twig_Extension_Sandbox($policy, !$allowed));
80         $template = new Twig_TemplateTest($twig);
81
82         try {
83             $template->getAttribute($object, $item, array(), 'any');
84
85             if (!$allowed) {
86                 $this->fail();
87             } else {
88                 $this->addToAssertionCount(1);
89             }
90         } catch (Twig_Sandbox_SecurityError $e) {
91             if ($allowed) {
92                 $this->fail();
93             } else {
94                 $this->addToAssertionCount(1);
95             }
96
97             $this->assertContains('is not allowed', $e->getMessage());
98         }
99     }
100
101     public function getGetAttributeWithSandbox()
102     {
103         return array(
104             array(new Twig_TemplatePropertyObject(), 'defined', false),
105             array(new Twig_TemplatePropertyObject(), 'defined', true),
106             array(new Twig_TemplateMethodObject(), 'defined', false),
107             array(new Twig_TemplateMethodObject(), 'defined', true),
108         );
109     }
110
111     /**
112      * @group legacy
113      */
114     public function testGetAttributeWithTemplateAsObject()
115     {
116         // to be removed in 2.0
117         $twig = new Twig_Environment($this->getMockBuilder('Twig_TemplateTestLoaderInterface')->getMock());
118         //$twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface', 'Twig_SourceContextLoaderInterface')->getMock());
119
120         $template = new Twig_TemplateTest($twig, 'index.twig');
121         $template1 = new Twig_TemplateTest($twig, 'index1.twig');
122
123         $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'string'));
124         $this->assertEquals('some_string', $template->getAttribute($template1, 'string'));
125
126         $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'true'));
127         $this->assertEquals('1', $template->getAttribute($template1, 'true'));
128
129         $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'zero'));
130         $this->assertEquals('0', $template->getAttribute($template1, 'zero'));
131
132         $this->assertNotInstanceof('Twig_Markup', $template->getAttribute($template1, 'empty'));
133         $this->assertSame('', $template->getAttribute($template1, 'empty'));
134
135         $this->assertFalse($template->getAttribute($template1, 'env', array(), Twig_Template::ANY_CALL, true));
136         $this->assertFalse($template->getAttribute($template1, 'environment', array(), Twig_Template::ANY_CALL, true));
137         $this->assertFalse($template->getAttribute($template1, 'getEnvironment', array(), Twig_Template::METHOD_CALL, true));
138         $this->assertFalse($template->getAttribute($template1, 'displayWithErrorHandling', array(), Twig_Template::METHOD_CALL, true));
139     }
140
141     /**
142      * @group legacy
143      * @expectedDeprecation Calling "string" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
144      * @expectedDeprecation Calling "string" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
145      * @expectedDeprecation Calling "true" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
146      * @expectedDeprecation Calling "true" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
147      * @expectedDeprecation Calling "zero" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
148      * @expectedDeprecation Calling "zero" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
149      * @expectedDeprecation Calling "empty" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
150      * @expectedDeprecation Calling "empty" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
151      * @expectedDeprecation Calling "renderBlock" on template "index.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use block("name") instead).
152      * @expectedDeprecation Calling "displayBlock" on template "index.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use block("name") instead).
153      * @expectedDeprecation Calling "hasBlock" on template "index.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use "block("name") is defined" instead).
154      * @expectedDeprecation Calling "render" on template "index.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use include("index.twig") instead).
155      * @expectedDeprecation Calling "display" on template "index.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use include("index.twig") instead).
156      * @expectedDeprecation Calling "renderBlock" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use block("name", template) instead).
157      * @expectedDeprecation Calling "displayBlock" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use block("name", template) instead).
158      * @expectedDeprecation Calling "hasBlock" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use "block("name", template) is defined" instead).
159      * @expectedDeprecation Calling "render" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use include("index1.twig") instead).
160      * @expectedDeprecation Calling "display" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use include("index1.twig") instead).
161      */
162     public function testGetAttributeWithTemplateAsObjectForDeprecations()
163     {
164         // to be removed in 2.0
165         $twig = new Twig_Environment($this->getMockBuilder('Twig_TemplateTestLoaderInterface')->getMock());
166         //$twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface', 'Twig_SourceContextLoaderInterface')->getMock());
167
168         $template = new Twig_TemplateTest($twig, 'index.twig');
169         $template1 = new Twig_TemplateTest($twig, 'index1.twig');
170
171         $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'string'));
172         $this->assertEquals('some_string', $template->getAttribute($template1, 'string'));
173
174         $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'true'));
175         $this->assertEquals('1', $template->getAttribute($template1, 'true'));
176
177         $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'zero'));
178         $this->assertEquals('0', $template->getAttribute($template1, 'zero'));
179
180         $this->assertNotInstanceof('Twig_Markup', $template->getAttribute($template1, 'empty'));
181         $this->assertSame('', $template->getAttribute($template1, 'empty'));
182
183         $blocks = array('name' => array($template1, 'block_name'));
184
185         // trigger some deprecation notice messages to check them with @expectedDeprecation
186         $template->getAttribute($template, 'renderBlock', array('name', array(), $blocks));
187         $template->getAttribute($template, 'displayBlock', array('name', array(), $blocks));
188         $template->getAttribute($template, 'hasBlock', array('name', array()));
189         $template->getAttribute($template, 'render', array(array()));
190         $template->getAttribute($template, 'display', array(array()));
191
192         $template->getAttribute($template1, 'renderBlock', array('name', array(), $blocks));
193         $template->getAttribute($template1, 'displayBlock', array('name', array(), $blocks));
194         $template->getAttribute($template1, 'hasBlock', array('name', array()));
195         $template->getAttribute($template1, 'render', array(array()));
196         $template->getAttribute($template1, 'display', array(array()));
197
198         $this->assertFalse($template->getAttribute($template1, 'env', array(), Twig_Template::ANY_CALL, true));
199         $this->assertFalse($template->getAttribute($template1, 'environment', array(), Twig_Template::ANY_CALL, true));
200         $this->assertFalse($template->getAttribute($template1, 'getEnvironment', array(), Twig_Template::METHOD_CALL, true));
201         $this->assertFalse($template->getAttribute($template1, 'displayWithErrorHandling', array(), Twig_Template::METHOD_CALL, true));
202     }
203
204     /**
205      * @group legacy
206      * @expectedDeprecation Silent display of undefined block "unknown" in template "index.twig" is deprecated since version 1.29 and will throw an exception in 2.0. Use the "block('unknown') is defined" expression to test for block existence.
207      * @expectedDeprecation Silent display of undefined block "unknown" in template "index.twig" is deprecated since version 1.29 and will throw an exception in 2.0. Use the "block('unknown') is defined" expression to test for block existence.
208      */
209     public function testRenderBlockWithUndefinedBlock()
210     {
211         $twig = new Twig_Environment($this->getMockBuilder('Twig_TemplateTestLoaderInterface')->getMock());
212
213         $template = new Twig_TemplateTest($twig, 'index.twig');
214         $template->renderBlock('unknown', array());
215         $template->displayBlock('unknown', array());
216     }
217
218     public function testGetAttributeOnArrayWithConfusableKey()
219     {
220         $template = new Twig_TemplateTest(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
221
222         $array = array('Zero', 'One', -1 => 'MinusOne', '' => 'EmptyString', '1.5' => 'FloatButString', '01' => 'IntegerButStringWithLeadingZeros');
223
224         $this->assertSame('Zero', $array[false]);
225         $this->assertSame('One', $array[true]);
226         $this->assertSame('One', $array[1.5]);
227         $this->assertSame('One', $array['1']);
228         $this->assertSame('MinusOne', $array[-1.5]);
229         $this->assertSame('FloatButString', $array['1.5']);
230         $this->assertSame('IntegerButStringWithLeadingZeros', $array['01']);
231         $this->assertSame('EmptyString', $array[null]);
232
233         $this->assertSame('Zero', $template->getAttribute($array, false), 'false is treated as 0 when accessing an array (equals PHP behavior)');
234         $this->assertSame('One', $template->getAttribute($array, true), 'true is treated as 1 when accessing an array (equals PHP behavior)');
235         $this->assertSame('One', $template->getAttribute($array, 1.5), 'float is casted to int when accessing an array (equals PHP behavior)');
236         $this->assertSame('One', $template->getAttribute($array, '1'), '"1" is treated as integer 1 when accessing an array (equals PHP behavior)');
237         $this->assertSame('MinusOne', $template->getAttribute($array, -1.5), 'negative float is casted to int when accessing an array (equals PHP behavior)');
238         $this->assertSame('FloatButString', $template->getAttribute($array, '1.5'), '"1.5" is treated as-is when accessing an array (equals PHP behavior)');
239         $this->assertSame('IntegerButStringWithLeadingZeros', $template->getAttribute($array, '01'), '"01" is treated as-is when accessing an array (equals PHP behavior)');
240         $this->assertSame('EmptyString', $template->getAttribute($array, null), 'null is treated as "" when accessing an array (equals PHP behavior)');
241     }
242
243     /**
244      * @dataProvider getGetAttributeTests
245      */
246     public function testGetAttribute($defined, $value, $object, $item, $arguments, $type)
247     {
248         $template = new Twig_TemplateTest(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
249
250         $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
251     }
252
253     /**
254      * @dataProvider getGetAttributeTests
255      */
256     public function testGetAttributeStrict($defined, $value, $object, $item, $arguments, $type, $exceptionMessage = null)
257     {
258         $template = new Twig_TemplateTest(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('strict_variables' => true)));
259
260         if ($defined) {
261             $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
262         } else {
263             if (method_exists($this, 'expectException')) {
264                 $this->expectException('Twig_Error_Runtime');
265                 if (null !== $exceptionMessage) {
266                     $this->expectExceptionMessage($exceptionMessage);
267                 }
268             } else {
269                 $this->setExpectedException('Twig_Error_Runtime', $exceptionMessage);
270             }
271             $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
272         }
273     }
274
275     /**
276      * @dataProvider getGetAttributeTests
277      */
278     public function testGetAttributeDefined($defined, $value, $object, $item, $arguments, $type)
279     {
280         $template = new Twig_TemplateTest(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
281
282         $this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true));
283     }
284
285     /**
286      * @dataProvider getGetAttributeTests
287      */
288     public function testGetAttributeDefinedStrict($defined, $value, $object, $item, $arguments, $type)
289     {
290         $template = new Twig_TemplateTest(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('strict_variables' => true)));
291
292         $this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true));
293     }
294
295     public function testGetAttributeCallExceptions()
296     {
297         $template = new Twig_TemplateTest(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
298
299         $object = new Twig_TemplateMagicMethodExceptionObject();
300
301         $this->assertNull($template->getAttribute($object, 'foo'));
302     }
303
304     public function getGetAttributeTests()
305     {
306         $array = array(
307             'defined' => 'defined',
308             'zero' => 0,
309             'null' => null,
310             '1' => 1,
311             'bar' => true,
312             'baz' => 'baz',
313             '09' => '09',
314             '+4' => '+4',
315         );
316
317         $objectArray = new Twig_TemplateArrayAccessObject();
318         $stdObject = (object) $array;
319         $magicPropertyObject = new Twig_TemplateMagicPropertyObject();
320         $propertyObject = new Twig_TemplatePropertyObject();
321         $propertyObject1 = new Twig_TemplatePropertyObjectAndIterator();
322         $propertyObject2 = new Twig_TemplatePropertyObjectAndArrayAccess();
323         $propertyObject3 = new Twig_TemplatePropertyObjectDefinedWithUndefinedValue();
324         $methodObject = new Twig_TemplateMethodObject();
325         $magicMethodObject = new Twig_TemplateMagicMethodObject();
326
327         $anyType = Twig_Template::ANY_CALL;
328         $methodType = Twig_Template::METHOD_CALL;
329         $arrayType = Twig_Template::ARRAY_CALL;
330
331         $basicTests = array(
332             // array(defined, value, property to fetch)
333             array(true,  'defined', 'defined'),
334             array(false, null,      'undefined'),
335             array(false, null,      'protected'),
336             array(true,  0,         'zero'),
337             array(true,  1,         1),
338             array(true,  1,         1.0),
339             array(true,  null,      'null'),
340             array(true,  true,      'bar'),
341             array(true,  'baz',     'baz'),
342             array(true,  '09',      '09'),
343             array(true,  '+4',      '+4'),
344         );
345         $testObjects = array(
346             // array(object, type of fetch)
347             array($array,               $arrayType),
348             array($objectArray,         $arrayType),
349             array($stdObject,           $anyType),
350             array($magicPropertyObject, $anyType),
351             array($methodObject,        $methodType),
352             array($methodObject,        $anyType),
353             array($propertyObject,      $anyType),
354             array($propertyObject1,     $anyType),
355             array($propertyObject2,     $anyType),
356         );
357
358         $tests = array();
359         foreach ($testObjects as $testObject) {
360             foreach ($basicTests as $test) {
361                 // properties cannot be numbers
362                 if (($testObject[0] instanceof stdClass || $testObject[0] instanceof Twig_TemplatePropertyObject) && is_numeric($test[2])) {
363                     continue;
364                 }
365
366                 if ('+4' === $test[2] && $methodObject === $testObject[0]) {
367                     continue;
368                 }
369
370                 $tests[] = array($test[0], $test[1], $testObject[0], $test[2], array(), $testObject[1]);
371             }
372         }
373
374         // additional properties tests
375         $tests = array_merge($tests, array(
376             array(true, null, $propertyObject3, 'foo', array(), $anyType),
377         ));
378
379         // additional method tests
380         $tests = array_merge($tests, array(
381             array(true, 'defined', $methodObject, 'defined',    array(), $methodType),
382             array(true, 'defined', $methodObject, 'DEFINED',    array(), $methodType),
383             array(true, 'defined', $methodObject, 'getDefined', array(), $methodType),
384             array(true, 'defined', $methodObject, 'GETDEFINED', array(), $methodType),
385             array(true, 'static',  $methodObject, 'static',     array(), $methodType),
386             array(true, 'static',  $methodObject, 'getStatic',  array(), $methodType),
387
388             array(true, '__call_undefined', $magicMethodObject, 'undefined', array(), $methodType),
389             array(true, '__call_UNDEFINED', $magicMethodObject, 'UNDEFINED', array(), $methodType),
390         ));
391
392         // add the same tests for the any type
393         foreach ($tests as $test) {
394             if ($anyType !== $test[5]) {
395                 $test[5] = $anyType;
396                 $tests[] = $test;
397             }
398         }
399
400         $methodAndPropObject = new Twig_TemplateMethodAndPropObject();
401
402         // additional method tests
403         $tests = array_merge($tests, array(
404             array(true, 'a', $methodAndPropObject, 'a', array(), $anyType),
405             array(true, 'a', $methodAndPropObject, 'a', array(), $methodType),
406             array(false, null, $methodAndPropObject, 'a', array(), $arrayType),
407
408             array(true, 'b_prop', $methodAndPropObject, 'b', array(), $anyType),
409             array(true, 'b', $methodAndPropObject, 'B', array(), $anyType),
410             array(true, 'b', $methodAndPropObject, 'b', array(), $methodType),
411             array(true, 'b', $methodAndPropObject, 'B', array(), $methodType),
412             array(false, null, $methodAndPropObject, 'b', array(), $arrayType),
413
414             array(false, null, $methodAndPropObject, 'c', array(), $anyType),
415             array(false, null, $methodAndPropObject, 'c', array(), $methodType),
416             array(false, null, $methodAndPropObject, 'c', array(), $arrayType),
417         ));
418
419         // tests when input is not an array or object
420         $tests = array_merge($tests, array(
421             array(false, null, 42, 'a', array(), $anyType, 'Impossible to access an attribute ("a") on a integer variable ("42") in "index.twig".'),
422             array(false, null, 'string', 'a', array(), $anyType, 'Impossible to access an attribute ("a") on a string variable ("string") in "index.twig".'),
423             array(false, null, array(), 'a', array(), $anyType, 'Key "a" does not exist as the array is empty in "index.twig".'),
424         ));
425
426         return $tests;
427     }
428
429     /**
430      * @expectedException Twig_Error_Runtime
431      */
432     public function testGetIsMethods()
433     {
434         $getIsObject = new Twig_TemplateGetIsMethods();
435         $template = new Twig_TemplateTest(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('strict_variables' => true)));
436         // first time should not create a cache for "get"
437         $this->assertNull($template->getAttribute($getIsObject, 'get'));
438         // 0 should be in the method cache now, so this should fail
439         $this->assertNull($template->getAttribute($getIsObject, 0));
440     }
441 }
442
443 class Twig_TemplateTest extends Twig_Template
444 {
445     private $name;
446
447     public function __construct(Twig_Environment $env, $name = 'index.twig')
448     {
449         parent::__construct($env);
450         self::$cache = array();
451         $this->name = $name;
452     }
453
454     public function getZero()
455     {
456         return 0;
457     }
458
459     public function getEmpty()
460     {
461         return '';
462     }
463
464     public function getString()
465     {
466         return 'some_string';
467     }
468
469     public function getTrue()
470     {
471         return true;
472     }
473
474     public function getTemplateName()
475     {
476         return $this->name;
477     }
478
479     public function getDebugInfo()
480     {
481         return array();
482     }
483
484     protected function doGetParent(array $context)
485     {
486         return false;
487     }
488
489     protected function doDisplay(array $context, array $blocks = array())
490     {
491     }
492
493     public function getAttribute($object, $item, array $arguments = array(), $type = Twig_Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
494     {
495         if (function_exists('twig_template_get_attributes')) {
496             return twig_template_get_attributes($this, $object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
497         } else {
498             return parent::getAttribute($object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
499         }
500     }
501
502     public function block_name($context, array $blocks = array())
503     {
504     }
505 }
506
507 class Twig_TemplateArrayAccessObject implements ArrayAccess
508 {
509     protected $protected = 'protected';
510
511     public $attributes = array(
512         'defined' => 'defined',
513         'zero' => 0,
514         'null' => null,
515         '1' => 1,
516         'bar' => true,
517         'baz' => 'baz',
518         '09' => '09',
519         '+4' => '+4',
520     );
521
522     public function offsetExists($name)
523     {
524         return array_key_exists($name, $this->attributes);
525     }
526
527     public function offsetGet($name)
528     {
529         return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null;
530     }
531
532     public function offsetSet($name, $value)
533     {
534     }
535
536     public function offsetUnset($name)
537     {
538     }
539 }
540
541 class Twig_TemplateMagicPropertyObject
542 {
543     public $defined = 'defined';
544
545     public $attributes = array(
546         'zero' => 0,
547         'null' => null,
548         '1' => 1,
549         'bar' => true,
550         'baz' => 'baz',
551         '09' => '09',
552         '+4' => '+4',
553     );
554
555     protected $protected = 'protected';
556
557     public function __isset($name)
558     {
559         return array_key_exists($name, $this->attributes);
560     }
561
562     public function __get($name)
563     {
564         return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null;
565     }
566 }
567
568 class Twig_TemplateMagicPropertyObjectWithException
569 {
570     public function __isset($key)
571     {
572         throw new Exception('Hey! Don\'t try to isset me!');
573     }
574 }
575
576 class Twig_TemplatePropertyObject
577 {
578     public $defined = 'defined';
579     public $zero = 0;
580     public $null = null;
581     public $bar = true;
582     public $baz = 'baz';
583
584     protected $protected = 'protected';
585 }
586
587 class Twig_TemplatePropertyObjectAndIterator extends Twig_TemplatePropertyObject implements IteratorAggregate
588 {
589     public function getIterator()
590     {
591         return new ArrayIterator(array('foo', 'bar'));
592     }
593 }
594
595 class Twig_TemplatePropertyObjectAndArrayAccess extends Twig_TemplatePropertyObject implements ArrayAccess
596 {
597     private $data = array(
598         'defined' => 'defined',
599         'zero' => 0,
600         'null' => null,
601         'bar' => true,
602         'baz' => 'baz',
603     );
604
605     public function offsetExists($offset)
606     {
607         return array_key_exists($offset, $this->data);
608     }
609
610     public function offsetGet($offset)
611     {
612         return $this->offsetExists($offset) ? $this->data[$offset] : 'n/a';
613     }
614
615     public function offsetSet($offset, $value)
616     {
617     }
618
619     public function offsetUnset($offset)
620     {
621     }
622 }
623
624 class Twig_TemplatePropertyObjectDefinedWithUndefinedValue
625 {
626     public $foo;
627
628     public function __construct()
629     {
630         $this->foo = @$notExist;
631     }
632 }
633
634 class Twig_TemplateMethodObject
635 {
636     public function getDefined()
637     {
638         return 'defined';
639     }
640
641     public function get1()
642     {
643         return 1;
644     }
645
646     public function get09()
647     {
648         return '09';
649     }
650
651     public function getZero()
652     {
653         return 0;
654     }
655
656     public function getNull()
657     {
658     }
659
660     public function isBar()
661     {
662         return true;
663     }
664
665     public function isBaz()
666     {
667         return 'should never be returned';
668     }
669
670     public function getBaz()
671     {
672         return 'baz';
673     }
674
675     protected function getProtected()
676     {
677         return 'protected';
678     }
679
680     public static function getStatic()
681     {
682         return 'static';
683     }
684 }
685
686 class Twig_TemplateGetIsMethods
687 {
688     public function get()
689     {
690     }
691
692     public function is()
693     {
694     }
695 }
696
697 class Twig_TemplateMethodAndPropObject
698 {
699     private $a = 'a_prop';
700
701     public function getA()
702     {
703         return 'a';
704     }
705
706     public $b = 'b_prop';
707
708     public function getB()
709     {
710         return 'b';
711     }
712
713     private $c = 'c_prop';
714
715     private function getC()
716     {
717         return 'c';
718     }
719 }
720
721 class Twig_TemplateMagicMethodObject
722 {
723     public function __call($method, $arguments)
724     {
725         return '__call_'.$method;
726     }
727 }
728
729 class Twig_TemplateMagicMethodExceptionObject
730 {
731     public function __call($method, $arguments)
732     {
733         throw new BadMethodCallException(sprintf('Unknown method "%s".', $method));
734     }
735 }
736
737 class CExtDisablingNodeVisitor implements Twig_NodeVisitorInterface
738 {
739     public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
740     {
741         if ($node instanceof Twig_Node_Expression_GetAttr) {
742             $node->setAttribute('disable_c_ext', true);
743         }
744
745         return $node;
746     }
747
748     public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
749     {
750         return $node;
751     }
752
753     public function getPriority()
754     {
755         return 0;
756     }
757 }
758
759 // to be removed in 2.0
760 interface Twig_TemplateTestLoaderInterface extends Twig_LoaderInterface, Twig_SourceContextLoaderInterface
761 {
762 }