4 * This file is part of Twig.
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 class Twig_Tests_Extension_CoreTest extends \PHPUnit\Framework\TestCase
15 * @dataProvider getRandomFunctionTestData
17 public function testRandomFunction($value, $expectedInArray)
19 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
21 for ($i = 0; $i < 100; ++$i) {
22 $this->assertTrue(in_array(twig_random($env, $value), $expectedInArray, true)); // assertContains() would not consider the type
26 public function getRandomFunctionTestData()
30 array('apple', 'orange', 'citrus'),
31 array('apple', 'orange', 'citrus'),
34 new ArrayObject(array('apple', 'orange', 'citrus')),
35 array('apple', 'orange', 'citrus'),
37 array(// unicode string
41 array(// numeric but string
60 public function testRandomFunctionWithoutParameter()
62 $max = mt_getrandmax();
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);
70 public function testRandomFunctionReturnsAsIs()
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)), ''));
75 $instance = new stdClass();
76 $this->assertSame($instance, twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), $instance));
80 * @expectedException Twig_Error_Runtime
82 public function testRandomFunctionOfEmptyArrayThrowsException()
84 twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), array());
87 public function testRandomFunctionOnNonUTF8String()
89 if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
90 $this->markTestSkipped('needs iconv or mbstring');
93 $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
94 $twig->setCharset('ISO-8859-1');
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));
103 public function testReverseFilterOnNonUTF8String()
105 if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
106 $this->markTestSkipped('needs iconv or mbstring');
109 $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
110 $twig->setCharset('ISO-8859-1');
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');
115 $this->assertEquals($output, 'éÄ');
119 * @dataProvider provideCustomEscaperCases
121 public function testCustomEscaper($expected, $string, $strategy)
123 $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
124 $twig->getExtension('Twig_Extension_Core')->setEscaper('foo', 'foo_escaper_for_test');
126 $this->assertSame($expected, twig_escape_filter($twig, $string, $strategy));
129 public function provideCustomEscaperCases()
132 array('fooUTF-8', 'foo', 'foo'),
133 array('UTF-8', null, 'foo'),
134 array('42UTF-8', 42, 'foo'),
139 * @expectedException Twig_Error_Runtime
141 public function testUnknownCustomEscaper()
143 twig_escape_filter(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), 'foo', 'bar');
147 * @dataProvider provideTwigFirstCases
149 public function testTwigFirst($expected, $input)
151 $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
152 $this->assertSame($expected, twig_first($twig, $input));
155 public function provideTwigFirstCases()
157 $i = array(1 => 'a', 2 => 'b', 3 => 'c');
161 array(1, array(1, 2, 3)),
164 array('a', new CoreTestIterator($i, array_keys($i), true, 3)),
169 * @dataProvider provideTwigLastCases
171 public function testTwigLast($expected, $input)
173 $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
174 $this->assertSame($expected, twig_last($twig, $input));
177 public function provideTwigLastCases()
179 $i = array(1 => 'a', 2 => 'b', 3 => 'c');
183 array(3, array(1, 2, 3)),
186 array('c', new CoreTestIterator($i, array_keys($i), true)),
191 * @dataProvider provideArrayKeyCases
193 public function testArrayKeysFilter(array $expected, $input)
195 $this->assertSame($expected, twig_get_array_keys_filter($input));
198 public function provideArrayKeyCases()
200 $array = array('a' => 'a1', 'b' => 'b1', 'c' => 'c1');
201 $keys = array_keys($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>')),
214 * @dataProvider provideInFilterCases
216 public function testInFilter($expected, $value, $compare)
218 $this->assertSame($expected, twig_in_filter($value, $compare));
221 public function provideInFilterCases()
223 $array = array(1, 2, 'a' => 3, 5, 6, 7);
224 $keys = array_keys($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)),
237 array(true, 'b', new SimpleXMLElement('<xml><a>b</a></xml>')),
242 * @dataProvider provideSliceFilterCases
244 public function testSliceFilter($expected, $input, $start, $length = null, $preserveKeys = false)
246 $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
247 $this->assertSame($expected, twig_slice($twig, $input, $start, $length, $preserveKeys));
250 public function provideSliceFilterCases()
252 $i = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4);
253 $keys = array_keys($i);
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),
272 function foo_escaper_for_test(Twig_Environment $env, $string, $charset)
274 return $string.$charset;
277 final class CoreTestIteratorAggregate implements IteratorAggregate
281 public function __construct(array $array, array $keys, $allowAccess = false, $maxPosition = false)
283 $this->iterator = new CoreTestIterator($array, $keys, $allowAccess, $maxPosition);
286 public function getIterator()
288 return $this->iterator;
292 final class CoreTestIteratorAggregateAggregate implements IteratorAggregate
296 public function __construct(array $array, array $keys, $allowValueAccess = false, $maxPosition = false)
298 $this->iterator = new CoreTestIteratorAggregate($array, $keys, $allowValueAccess, $maxPosition);
301 public function getIterator()
303 return $this->iterator;
307 final class CoreTestIterator implements Iterator
312 private $allowValueAccess;
313 private $maxPosition;
315 public function __construct(array $values, array $keys, $allowValueAccess = false, $maxPosition = false)
317 $this->array = $values;
318 $this->arrayKeys = $keys;
320 $this->allowValueAccess = $allowValueAccess;
321 $this->maxPosition = false === $maxPosition ? count($values) + 1 : $maxPosition;
324 public function rewind()
329 public function current()
331 if ($this->allowValueAccess) {
332 return $this->array[$this->key()];
335 throw new LogicException('Code should only use the keys, not the values provided by iterator.');
338 public function key()
340 return $this->arrayKeys[$this->position];
343 public function next()
346 if ($this->position === $this->maxPosition) {
347 throw new LogicException(sprintf('Code should not iterate beyond %d.', $this->maxPosition));
351 public function valid()
353 return isset($this->arrayKeys[$this->position]);