ParserTest.php 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <?php
  2. /*
  3. * This file is part of Twig.
  4. *
  5. * (c) Fabien Potencier
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. class Twig_Tests_ParserTest extends PHPUnit_Framework_TestCase
  11. {
  12. /**
  13. * @expectedException Twig_Error_Syntax
  14. */
  15. public function testSetMacroThrowsExceptionOnReservedMethods()
  16. {
  17. $parser = new Twig_Parser(new Twig_Environment());
  18. $parser->setMacro('display', $this->getMock('Twig_Node_Macro', array(), array(), '', null));
  19. }
  20. /**
  21. * @expectedException Twig_Error_Syntax
  22. * @expectedExceptionMessage Unknown tag name "foo". Did you mean "for" at line 0
  23. */
  24. public function testUnkownTag()
  25. {
  26. $stream = new Twig_TokenStream(array(
  27. new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 0),
  28. new Twig_Token(Twig_Token::NAME_TYPE, 'foo', 0),
  29. new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 0),
  30. new Twig_Token(Twig_Token::EOF_TYPE, '', 0),
  31. ));
  32. $parser = new Twig_Parser(new Twig_Environment());
  33. $parser->parse($stream);
  34. }
  35. /**
  36. * @dataProvider getFilterBodyNodesData
  37. */
  38. public function testFilterBodyNodes($input, $expected)
  39. {
  40. $parser = $this->getParserForFilterBodyNodes();
  41. $this->assertEquals($expected, $parser->filterBodyNodes($input));
  42. }
  43. public function getFilterBodyNodesData()
  44. {
  45. return array(
  46. array(
  47. new Twig_Node(array(new Twig_Node_Text(' ', 0))),
  48. new Twig_Node(array()),
  49. ),
  50. array(
  51. $input = new Twig_Node(array(new Twig_Node_Set(false, new Twig_Node(), new Twig_Node(), 0))),
  52. $input,
  53. ),
  54. array(
  55. $input = new Twig_Node(array(new Twig_Node_Set(true, new Twig_Node(), new Twig_Node(array(new Twig_Node(array(new Twig_Node_Text('foo', 0))))), 0))),
  56. $input,
  57. ),
  58. );
  59. }
  60. /**
  61. * @dataProvider getFilterBodyNodesDataThrowsException
  62. * @expectedException Twig_Error_Syntax
  63. */
  64. public function testFilterBodyNodesThrowsException($input)
  65. {
  66. $parser = $this->getParserForFilterBodyNodes();
  67. $parser->filterBodyNodes($input);
  68. }
  69. public function getFilterBodyNodesDataThrowsException()
  70. {
  71. return array(
  72. array(new Twig_Node_Text('foo', 0)),
  73. array(new Twig_Node(array(new Twig_Node(array(new Twig_Node_Text('foo', 0)))))),
  74. );
  75. }
  76. /**
  77. * @expectedException Twig_Error_Syntax
  78. * @expectedExceptionMessage A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed at line 0.
  79. */
  80. public function testFilterBodyNodesWithBOM()
  81. {
  82. $parser = $this->getParserForFilterBodyNodes();
  83. $parser->filterBodyNodes(new Twig_Node_Text(chr(0xEF).chr(0xBB).chr(0xBF), 0));
  84. }
  85. public function testParseIsReentrant()
  86. {
  87. $twig = new Twig_Environment(null, array(
  88. 'autoescape' => false,
  89. 'optimizations' => 0,
  90. ));
  91. $twig->addTokenParser(new TestTokenParser());
  92. $parser = new Twig_Parser($twig);
  93. $parser->parse(new Twig_TokenStream(array(
  94. new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 0),
  95. new Twig_Token(Twig_Token::NAME_TYPE, 'test', 0),
  96. new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 0),
  97. new Twig_Token(Twig_Token::VAR_START_TYPE, '', 0),
  98. new Twig_Token(Twig_Token::NAME_TYPE, 'foo', 0),
  99. new Twig_Token(Twig_Token::VAR_END_TYPE, '', 0),
  100. new Twig_Token(Twig_Token::EOF_TYPE, '', 0),
  101. )));
  102. $this->assertEquals(null, $parser->getParent());
  103. }
  104. // The getVarName() must not depend on the template loaders,
  105. // If this test does not throw any exception, that's good.
  106. // see https://github.com/symfony/symfony/issues/4218
  107. public function testGetVarName()
  108. {
  109. $twig = new Twig_Environment(null, array(
  110. 'autoescape' => false,
  111. 'optimizations' => 0,
  112. ));
  113. $twig->parse($twig->tokenize(<<<EOF
  114. {% from _self import foo %}
  115. {% macro foo() %}
  116. {{ foo }}
  117. {% endmacro %}
  118. EOF
  119. ));
  120. }
  121. protected function getParserForFilterBodyNodes()
  122. {
  123. $parser = new TestParser(new Twig_Environment());
  124. $parser->setParent(new Twig_Node());
  125. $parser->stream = $this->getMockBuilder('Twig_TokenStream')->disableOriginalConstructor()->getMock();
  126. return $parser;
  127. }
  128. }
  129. class TestParser extends Twig_Parser
  130. {
  131. public $stream;
  132. public function filterBodyNodes(Twig_NodeInterface $node)
  133. {
  134. return parent::filterBodyNodes($node);
  135. }
  136. }
  137. class TestTokenParser extends Twig_TokenParser
  138. {
  139. public function parse(Twig_Token $token)
  140. {
  141. // simulate the parsing of another template right in the middle of the parsing of the current template
  142. $this->parser->parse(new Twig_TokenStream(array(
  143. new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 0),
  144. new Twig_Token(Twig_Token::NAME_TYPE, 'extends', 0),
  145. new Twig_Token(Twig_Token::STRING_TYPE, 'base', 0),
  146. new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 0),
  147. new Twig_Token(Twig_Token::EOF_TYPE, '', 0),
  148. )));
  149. $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
  150. return new Twig_Node(array());
  151. }
  152. public function getTag()
  153. {
  154. return 'test';
  155. }
  156. }