Security update for Core, with self-updated composer
[yaffs-website] / vendor / twig / twig / test / Twig / Tests / Extension / CoreTest.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 class Twig_Tests_Extension_CoreTest extends \PHPUnit\Framework\TestCase
13 {
14     /**
15      * @dataProvider getRandomFunctionTestData
16      */
17     public function testRandomFunction($value, $expectedInArray)
18     {
19         $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
20
21         for ($i = 0; $i < 100; ++$i) {
22             $this->assertTrue(in_array(twig_random($env, $value), $expectedInArray, true)); // assertContains() would not consider the type
23         }
24     }
25
26     public function getRandomFunctionTestData()
27     {
28         return array(
29             array(// array
30                 array('apple', 'orange', 'citrus'),
31                 array('apple', 'orange', 'citrus'),
32             ),
33             array(// Traversable
34                 new ArrayObject(array('apple', 'orange', 'citrus')),
35                 array('apple', 'orange', 'citrus'),
36             ),
37             array(// unicode string
38                 'Ä€é',
39                 array('Ä', '€', 'é'),
40             ),
41             array(// numeric but string
42                 '123',
43                 array('1', '2', '3'),
44             ),
45             array(// integer
46                 5,
47                 range(0, 5, 1),
48             ),
49             array(// float
50                 5.9,
51                 range(0, 5, 1),
52             ),
53             array(// negative
54                 -2,
55                 array(0, -1, -2),
56             ),
57         );
58     }
59
60     public function testRandomFunctionWithoutParameter()
61     {
62         $max = mt_getrandmax();
63
64         for ($i = 0; $i < 100; ++$i) {
65             $val = twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
66             $this->assertTrue(is_int($val) && $val >= 0 && $val <= $max);
67         }
68     }
69
70     public function testRandomFunctionReturnsAsIs()
71     {
72         $this->assertSame('', twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), ''));
73         $this->assertSame('', twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('charset' => null)), ''));
74
75         $instance = new stdClass();
76         $this->assertSame($instance, twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), $instance));
77     }
78
79     /**
80      * @expectedException Twig_Error_Runtime
81      */
82     public function testRandomFunctionOfEmptyArrayThrowsException()
83     {
84         twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), array());
85     }
86
87     public function testRandomFunctionOnNonUTF8String()
88     {
89         if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
90             $this->markTestSkipped('needs iconv or mbstring');
91         }
92
93         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
94         $twig->setCharset('ISO-8859-1');
95
96         $text = twig_convert_encoding('Äé', 'ISO-8859-1', 'UTF-8');
97         for ($i = 0; $i < 30; ++$i) {
98             $rand = twig_random($twig, $text);
99             $this->assertTrue(in_array(twig_convert_encoding($rand, 'UTF-8', 'ISO-8859-1'), array('Ä', 'é'), true));
100         }
101     }
102
103     public function testReverseFilterOnNonUTF8String()
104     {
105         if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
106             $this->markTestSkipped('needs iconv or mbstring');
107         }
108
109         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
110         $twig->setCharset('ISO-8859-1');
111
112         $input = twig_convert_encoding('Äé', 'ISO-8859-1', 'UTF-8');
113         $output = twig_convert_encoding(twig_reverse_filter($twig, $input), 'UTF-8', 'ISO-8859-1');
114
115         $this->assertEquals($output, 'éÄ');
116     }
117
118     /**
119      * @dataProvider provideCustomEscaperCases
120      */
121     public function testCustomEscaper($expected, $string, $strategy)
122     {
123         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
124         $twig->getExtension('Twig_Extension_Core')->setEscaper('foo', 'foo_escaper_for_test');
125
126         $this->assertSame($expected, twig_escape_filter($twig, $string, $strategy));
127     }
128
129     public function provideCustomEscaperCases()
130     {
131         return array(
132             array('fooUTF-8', 'foo', 'foo'),
133             array('UTF-8', null, 'foo'),
134             array('42UTF-8', 42, 'foo'),
135         );
136     }
137
138     /**
139      * @expectedException Twig_Error_Runtime
140      */
141     public function testUnknownCustomEscaper()
142     {
143         twig_escape_filter(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), 'foo', 'bar');
144     }
145
146     /**
147      * @dataProvider provideTwigFirstCases
148      */
149     public function testTwigFirst($expected, $input)
150     {
151         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
152         $this->assertSame($expected, twig_first($twig, $input));
153     }
154
155     public function provideTwigFirstCases()
156     {
157         $i = array(1 => 'a', 2 => 'b', 3 => 'c');
158
159         return array(
160             array('a', 'abc'),
161             array(1, array(1, 2, 3)),
162             array('', null),
163             array('', ''),
164             array('a', new CoreTestIterator($i, array_keys($i), true, 3)),
165         );
166     }
167
168     /**
169      * @dataProvider provideTwigLastCases
170      */
171     public function testTwigLast($expected, $input)
172     {
173         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
174         $this->assertSame($expected, twig_last($twig, $input));
175     }
176
177     public function provideTwigLastCases()
178     {
179         $i = array(1 => 'a', 2 => 'b', 3 => 'c');
180
181         return array(
182             array('c', 'abc'),
183             array(3, array(1, 2, 3)),
184             array('', null),
185             array('', ''),
186             array('c', new CoreTestIterator($i, array_keys($i), true)),
187         );
188     }
189
190     /**
191      * @dataProvider provideArrayKeyCases
192      */
193     public function testArrayKeysFilter(array $expected, $input)
194     {
195         $this->assertSame($expected, twig_get_array_keys_filter($input));
196     }
197
198     public function provideArrayKeyCases()
199     {
200         $array = array('a' => 'a1', 'b' => 'b1', 'c' => 'c1');
201         $keys = array_keys($array);
202
203         return array(
204             array($keys, $array),
205             array($keys, new CoreTestIterator($array, $keys)),
206             array($keys, new CoreTestIteratorAggregate($array, $keys)),
207             array($keys, new CoreTestIteratorAggregateAggregate($array, $keys)),
208             array(array(), null),
209             array(array('a'), new SimpleXMLElement('<xml><a></a></xml>')),
210         );
211     }
212
213     /**
214      * @dataProvider provideInFilterCases
215      */
216     public function testInFilter($expected, $value, $compare)
217     {
218         $this->assertSame($expected, twig_in_filter($value, $compare));
219     }
220
221     public function provideInFilterCases()
222     {
223         $array = array(1, 2, 'a' => 3, 5, 6, 7);
224         $keys = array_keys($array);
225
226         return array(
227             array(true, 1, $array),
228             array(true, '3', $array),
229             array(true, '3', 'abc3def'),
230             array(true, 1, new CoreTestIterator($array, $keys, true, 1)),
231             array(true, '3', new CoreTestIterator($array, $keys, true, 3)),
232             array(true, '3', new CoreTestIteratorAggregateAggregate($array, $keys, true, 3)),
233             array(false, 4, $array),
234             array(false, 4, new CoreTestIterator($array, $keys, true)),
235             array(false, 4, new CoreTestIteratorAggregateAggregate($array, $keys, true)),
236             array(false, 1, 1),
237             array(true, 'b', new SimpleXMLElement('<xml><a>b</a></xml>')),
238         );
239     }
240
241     /**
242      * @dataProvider provideSliceFilterCases
243      */
244     public function testSliceFilter($expected, $input, $start, $length = null, $preserveKeys = false)
245     {
246         $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
247         $this->assertSame($expected, twig_slice($twig, $input, $start, $length, $preserveKeys));
248     }
249
250     public function provideSliceFilterCases()
251     {
252         $i = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4);
253         $keys = array_keys($i);
254
255         return array(
256             array(array('a' => 1), $i, 0, 1, true),
257             array(array('a' => 1), $i, 0, 1, false),
258             array(array('b' => 2, 'c' => 3), $i, 1, 2),
259             array(array(1), array(1, 2, 3, 4), 0, 1),
260             array(array(2, 3), array(1, 2, 3, 4), 1, 2),
261             array(array(2, 3), new CoreTestIterator($i, $keys, true), 1, 2),
262             array(array('c' => 3, 'd' => 4), new CoreTestIteratorAggregate($i, $keys, true), 2, null, true),
263             array($i, new CoreTestIterator($i, $keys, true), 0, count($keys) + 10, true),
264             array(array(), new CoreTestIterator($i, $keys, true), count($keys) + 10),
265             array('de', 'abcdef', 3, 2),
266             array(array(), new SimpleXMLElement('<items><item>1</item><item>2</item></items>'), 3),
267             array(array(), new ArrayIterator(array(1, 2)), 3),
268         );
269     }
270 }
271
272 function foo_escaper_for_test(Twig_Environment $env, $string, $charset)
273 {
274     return $string.$charset;
275 }
276
277 final class CoreTestIteratorAggregate implements IteratorAggregate
278 {
279     private $iterator;
280
281     public function __construct(array $array, array $keys, $allowAccess = false, $maxPosition = false)
282     {
283         $this->iterator = new CoreTestIterator($array, $keys, $allowAccess, $maxPosition);
284     }
285
286     public function getIterator()
287     {
288         return $this->iterator;
289     }
290 }
291
292 final class CoreTestIteratorAggregateAggregate implements IteratorAggregate
293 {
294     private $iterator;
295
296     public function __construct(array $array, array $keys, $allowValueAccess = false, $maxPosition = false)
297     {
298         $this->iterator = new CoreTestIteratorAggregate($array, $keys, $allowValueAccess, $maxPosition);
299     }
300
301     public function getIterator()
302     {
303         return $this->iterator;
304     }
305 }
306
307 final class CoreTestIterator implements Iterator
308 {
309     private $position;
310     private $array;
311     private $arrayKeys;
312     private $allowValueAccess;
313     private $maxPosition;
314
315     public function __construct(array $values, array $keys, $allowValueAccess = false, $maxPosition = false)
316     {
317         $this->array = $values;
318         $this->arrayKeys = $keys;
319         $this->position = 0;
320         $this->allowValueAccess = $allowValueAccess;
321         $this->maxPosition = false === $maxPosition ? count($values) + 1 : $maxPosition;
322     }
323
324     public function rewind()
325     {
326         $this->position = 0;
327     }
328
329     public function current()
330     {
331         if ($this->allowValueAccess) {
332             return $this->array[$this->key()];
333         }
334
335         throw new LogicException('Code should only use the keys, not the values provided by iterator.');
336     }
337
338     public function key()
339     {
340         return $this->arrayKeys[$this->position];
341     }
342
343     public function next()
344     {
345         ++$this->position;
346         if ($this->position === $this->maxPosition) {
347             throw new LogicException(sprintf('Code should not iterate beyond %d.', $this->maxPosition));
348         }
349     }
350
351     public function valid()
352     {
353         return isset($this->arrayKeys[$this->position]);
354     }
355 }