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_ExpressionParserTest extends PHPUnit_Framework_TestCase
15 * @expectedException Twig_Error_Syntax
16 * @dataProvider getFailingTestsForAssignment
18 public function testCanOnlyAssignToNames($template)
20 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
21 $parser = new Twig_Parser($env);
23 $parser->parse($env->tokenize(new Twig_Source($template, 'index')));
26 public function getFailingTestsForAssignment()
29 array('{% set false = "foo" %}'),
30 array('{% set FALSE = "foo" %}'),
31 array('{% set true = "foo" %}'),
32 array('{% set TRUE = "foo" %}'),
33 array('{% set none = "foo" %}'),
34 array('{% set NONE = "foo" %}'),
35 array('{% set null = "foo" %}'),
36 array('{% set NULL = "foo" %}'),
37 array('{% set 3 = "foo" %}'),
38 array('{% set 1 + 2 = "foo" %}'),
39 array('{% set "bar" = "foo" %}'),
40 array('{% set %}{% endset %}'),
45 * @dataProvider getTestsForArray
47 public function testArrayExpression($template, $expected)
49 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
50 $stream = $env->tokenize(new Twig_Source($template, ''));
51 $parser = new Twig_Parser($env);
53 $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr'));
57 * @expectedException Twig_Error_Syntax
58 * @dataProvider getFailingTestsForArray
60 public function testArraySyntaxError($template)
62 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
63 $parser = new Twig_Parser($env);
65 $parser->parse($env->tokenize(new Twig_Source($template, 'index')));
68 public function getFailingTestsForArray()
71 array('{{ [1, "a": "b"] }}'),
72 array('{{ {"a": "b", 2} }}'),
76 public function getTestsForArray()
80 array('{{ [1, 2] }}', new Twig_Node_Expression_Array(array(
81 new Twig_Node_Expression_Constant(0, 1),
82 new Twig_Node_Expression_Constant(1, 1),
84 new Twig_Node_Expression_Constant(1, 1),
85 new Twig_Node_Expression_Constant(2, 1),
89 // array with trailing ,
90 array('{{ [1, 2, ] }}', new Twig_Node_Expression_Array(array(
91 new Twig_Node_Expression_Constant(0, 1),
92 new Twig_Node_Expression_Constant(1, 1),
94 new Twig_Node_Expression_Constant(1, 1),
95 new Twig_Node_Expression_Constant(2, 1),
100 array('{{ {"a": "b", "b": "c"} }}', new Twig_Node_Expression_Array(array(
101 new Twig_Node_Expression_Constant('a', 1),
102 new Twig_Node_Expression_Constant('b', 1),
104 new Twig_Node_Expression_Constant('b', 1),
105 new Twig_Node_Expression_Constant('c', 1),
109 // hash with trailing ,
110 array('{{ {"a": "b", "b": "c", } }}', new Twig_Node_Expression_Array(array(
111 new Twig_Node_Expression_Constant('a', 1),
112 new Twig_Node_Expression_Constant('b', 1),
114 new Twig_Node_Expression_Constant('b', 1),
115 new Twig_Node_Expression_Constant('c', 1),
120 array('{{ [1, {"a": "b", "b": "c"}] }}', new Twig_Node_Expression_Array(array(
121 new Twig_Node_Expression_Constant(0, 1),
122 new Twig_Node_Expression_Constant(1, 1),
124 new Twig_Node_Expression_Constant(1, 1),
125 new Twig_Node_Expression_Array(array(
126 new Twig_Node_Expression_Constant('a', 1),
127 new Twig_Node_Expression_Constant('b', 1),
129 new Twig_Node_Expression_Constant('b', 1),
130 new Twig_Node_Expression_Constant('c', 1),
136 array('{{ {"a": [1, 2], "b": "c"} }}', new Twig_Node_Expression_Array(array(
137 new Twig_Node_Expression_Constant('a', 1),
138 new Twig_Node_Expression_Array(array(
139 new Twig_Node_Expression_Constant(0, 1),
140 new Twig_Node_Expression_Constant(1, 1),
142 new Twig_Node_Expression_Constant(1, 1),
143 new Twig_Node_Expression_Constant(2, 1),
145 new Twig_Node_Expression_Constant('b', 1),
146 new Twig_Node_Expression_Constant('c', 1),
153 * @expectedException Twig_Error_Syntax
155 public function testStringExpressionDoesNotConcatenateTwoConsecutiveStrings()
157 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
158 $stream = $env->tokenize(new Twig_Source('{{ "a" "b" }}', 'index'));
159 $parser = new Twig_Parser($env);
161 $parser->parse($stream);
165 * @dataProvider getTestsForString
167 public function testStringExpression($template, $expected)
169 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
170 $stream = $env->tokenize(new Twig_Source($template, ''));
171 $parser = new Twig_Parser($env);
173 $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr'));
176 public function getTestsForString()
180 '{{ "foo" }}', new Twig_Node_Expression_Constant('foo', 1),
183 '{{ "foo #{bar}" }}', new Twig_Node_Expression_Binary_Concat(
184 new Twig_Node_Expression_Constant('foo ', 1),
185 new Twig_Node_Expression_Name('bar', 1),
190 '{{ "foo #{bar} baz" }}', new Twig_Node_Expression_Binary_Concat(
191 new Twig_Node_Expression_Binary_Concat(
192 new Twig_Node_Expression_Constant('foo ', 1),
193 new Twig_Node_Expression_Name('bar', 1),
196 new Twig_Node_Expression_Constant(' baz', 1),
202 '{{ "foo #{"foo #{bar} baz"} baz" }}', new Twig_Node_Expression_Binary_Concat(
203 new Twig_Node_Expression_Binary_Concat(
204 new Twig_Node_Expression_Constant('foo ', 1),
205 new Twig_Node_Expression_Binary_Concat(
206 new Twig_Node_Expression_Binary_Concat(
207 new Twig_Node_Expression_Constant('foo ', 1),
208 new Twig_Node_Expression_Name('bar', 1),
211 new Twig_Node_Expression_Constant(' baz', 1),
216 new Twig_Node_Expression_Constant(' baz', 1),
224 * @expectedException Twig_Error_Syntax
226 public function testAttributeCallDoesNotSupportNamedArguments()
228 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
229 $parser = new Twig_Parser($env);
231 $parser->parse($env->tokenize(new Twig_Source('{{ foo.bar(name="Foo") }}', 'index')));
235 * @expectedException Twig_Error_Syntax
237 public function testMacroCallDoesNotSupportNamedArguments()
239 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
240 $parser = new Twig_Parser($env);
242 $parser->parse($env->tokenize(new Twig_Source('{% from _self import foo %}{% macro foo() %}{% endmacro %}{{ foo(name="Foo") }}', 'index')));
246 * @expectedException Twig_Error_Syntax
247 * @expectedExceptionMessage An argument must be a name. Unexpected token "string" of value "a" ("name" expected) in "index" at line 1.
249 public function testMacroDefinitionDoesNotSupportNonNameVariableName()
251 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
252 $parser = new Twig_Parser($env);
254 $parser->parse($env->tokenize(new Twig_Source('{% macro foo("a") %}{% endmacro %}', 'index')));
258 * @expectedException Twig_Error_Syntax
259 * @expectedExceptionMessage A default value for an argument must be a constant (a boolean, a string, a number, or an array) in "index" at line 1
260 * @dataProvider getMacroDefinitionDoesNotSupportNonConstantDefaultValues
262 public function testMacroDefinitionDoesNotSupportNonConstantDefaultValues($template)
264 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
265 $parser = new Twig_Parser($env);
267 $parser->parse($env->tokenize(new Twig_Source($template, 'index')));
270 public function getMacroDefinitionDoesNotSupportNonConstantDefaultValues()
273 array('{% macro foo(name = "a #{foo} a") %}{% endmacro %}'),
274 array('{% macro foo(name = [["b", "a #{foo} a"]]) %}{% endmacro %}'),
279 * @dataProvider getMacroDefinitionSupportsConstantDefaultValues
281 public function testMacroDefinitionSupportsConstantDefaultValues($template)
283 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
284 $parser = new Twig_Parser($env);
286 $parser->parse($env->tokenize(new Twig_Source($template, 'index')));
288 // add a dummy assertion here to satisfy PHPUnit, the only thing we want to test is that the code above
289 // can be executed without throwing any exceptions
290 $this->addToAssertionCount(1);
293 public function getMacroDefinitionSupportsConstantDefaultValues()
296 array('{% macro foo(name = "aa") %}{% endmacro %}'),
297 array('{% macro foo(name = 12) %}{% endmacro %}'),
298 array('{% macro foo(name = true) %}{% endmacro %}'),
299 array('{% macro foo(name = ["a"]) %}{% endmacro %}'),
300 array('{% macro foo(name = [["a"]]) %}{% endmacro %}'),
301 array('{% macro foo(name = {a: "a"}) %}{% endmacro %}'),
302 array('{% macro foo(name = {a: {b: "a"}}) %}{% endmacro %}'),
307 * @expectedException Twig_Error_Syntax
308 * @expectedExceptionMessage Unknown "cycl" function. Did you mean "cycle" in "index" at line 1?
310 public function testUnknownFunction()
312 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
313 $parser = new Twig_Parser($env);
315 $parser->parse($env->tokenize(new Twig_Source('{{ cycl() }}', 'index')));
319 * @expectedException Twig_Error_Syntax
320 * @expectedExceptionMessage Unknown "foobar" function in "index" at line 1.
322 public function testUnknownFunctionWithoutSuggestions()
324 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
325 $parser = new Twig_Parser($env);
327 $parser->parse($env->tokenize(new Twig_Source('{{ foobar() }}', 'index')));
331 * @expectedException Twig_Error_Syntax
332 * @expectedExceptionMessage Unknown "lowe" filter. Did you mean "lower" in "index" at line 1?
334 public function testUnknownFilter()
336 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
337 $parser = new Twig_Parser($env);
339 $parser->parse($env->tokenize(new Twig_Source('{{ 1|lowe }}', 'index')));
343 * @expectedException Twig_Error_Syntax
344 * @expectedExceptionMessage Unknown "foobar" filter in "index" at line 1.
346 public function testUnknownFilterWithoutSuggestions()
348 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
349 $parser = new Twig_Parser($env);
351 $parser->parse($env->tokenize(new Twig_Source('{{ 1|foobar }}', 'index')));
355 * @expectedException Twig_Error_Syntax
356 * @expectedExceptionMessage Unknown "nul" test. Did you mean "null" in "index" at line 1
358 public function testUnknownTest()
360 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
361 $parser = new Twig_Parser($env);
362 $stream = $env->tokenize(new Twig_Source('{{ 1 is nul }}', 'index'));
363 $parser->parse($stream);
367 * @expectedException Twig_Error_Syntax
368 * @expectedExceptionMessage Unknown "foobar" test in "index" at line 1.
370 public function testUnknownTestWithoutSuggestions()
372 $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
373 $parser = new Twig_Parser($env);
375 $parser->parse($env->tokenize(new Twig_Source('{{ 1 is foobar }}', 'index')));