LexerTest.php 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  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_LexerTest extends PHPUnit_Framework_TestCase
  11. {
  12. public function testNameLabelForTag()
  13. {
  14. $template = '{% ☃ %}';
  15. $lexer = new Twig_Lexer(new Twig_Environment());
  16. $stream = $lexer->tokenize($template);
  17. $stream->expect(Twig_Token::BLOCK_START_TYPE);
  18. $this->assertSame('☃', $stream->expect(Twig_Token::NAME_TYPE)->getValue());
  19. }
  20. public function testNameLabelForFunction()
  21. {
  22. $template = '{{ ☃() }}';
  23. $lexer = new Twig_Lexer(new Twig_Environment());
  24. $stream = $lexer->tokenize($template);
  25. $stream->expect(Twig_Token::VAR_START_TYPE);
  26. $this->assertSame('☃', $stream->expect(Twig_Token::NAME_TYPE)->getValue());
  27. }
  28. public function testBracketsNesting()
  29. {
  30. $template = '{{ {"a":{"b":"c"}} }}';
  31. $this->assertEquals(2, $this->countToken($template, Twig_Token::PUNCTUATION_TYPE, '{'));
  32. $this->assertEquals(2, $this->countToken($template, Twig_Token::PUNCTUATION_TYPE, '}'));
  33. }
  34. protected function countToken($template, $type, $value = null)
  35. {
  36. $lexer = new Twig_Lexer(new Twig_Environment());
  37. $stream = $lexer->tokenize($template);
  38. $count = 0;
  39. $tokens = array();
  40. while (!$stream->isEOF()) {
  41. $token = $stream->next();
  42. if ($type === $token->getType()) {
  43. if (null === $value || $value === $token->getValue()) {
  44. ++$count;
  45. }
  46. }
  47. }
  48. return $count;
  49. }
  50. public function testLineDirective()
  51. {
  52. $template = "foo\n"
  53. . "bar\n"
  54. . "{% line 10 %}\n"
  55. . "{{\n"
  56. . "baz\n"
  57. . "}}\n";
  58. $lexer = new Twig_Lexer(new Twig_Environment());
  59. $stream = $lexer->tokenize($template);
  60. // foo\nbar\n
  61. $this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
  62. // \n (after {% line %})
  63. $this->assertSame(10, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
  64. // {{
  65. $this->assertSame(11, $stream->expect(Twig_Token::VAR_START_TYPE)->getLine());
  66. // baz
  67. $this->assertSame(12, $stream->expect(Twig_Token::NAME_TYPE)->getLine());
  68. }
  69. public function testLineDirectiveInline()
  70. {
  71. $template = "foo\n"
  72. . "bar{% line 10 %}{{\n"
  73. . "baz\n"
  74. . "}}\n";
  75. $lexer = new Twig_Lexer(new Twig_Environment());
  76. $stream = $lexer->tokenize($template);
  77. // foo\nbar
  78. $this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
  79. // {{
  80. $this->assertSame(10, $stream->expect(Twig_Token::VAR_START_TYPE)->getLine());
  81. // baz
  82. $this->assertSame(11, $stream->expect(Twig_Token::NAME_TYPE)->getLine());
  83. }
  84. public function testLongComments()
  85. {
  86. $template = '{# '.str_repeat('*', 100000).' #}';
  87. $lexer = new Twig_Lexer(new Twig_Environment());
  88. $lexer->tokenize($template);
  89. // should not throw an exception
  90. }
  91. public function testLongRaw()
  92. {
  93. $template = '{% raw %}'.str_repeat('*', 100000).'{% endraw %}';
  94. $lexer = new Twig_Lexer(new Twig_Environment());
  95. $stream = $lexer->tokenize($template);
  96. // should not throw an exception
  97. }
  98. public function testLongVar()
  99. {
  100. $template = '{{ '.str_repeat('x', 100000).' }}';
  101. $lexer = new Twig_Lexer(new Twig_Environment());
  102. $stream = $lexer->tokenize($template);
  103. // should not throw an exception
  104. }
  105. public function testLongBlock()
  106. {
  107. $template = '{% '.str_repeat('x', 100000).' %}';
  108. $lexer = new Twig_Lexer(new Twig_Environment());
  109. $stream = $lexer->tokenize($template);
  110. // should not throw an exception
  111. }
  112. public function testBigNumbers()
  113. {
  114. $template = '{{ 922337203685477580700 }}';
  115. $lexer = new Twig_Lexer(new Twig_Environment());
  116. $stream = $lexer->tokenize($template);
  117. $node = $stream->next();
  118. $node = $stream->next();
  119. $this->assertEquals(922337203685477580700, $node->getValue());
  120. }
  121. public function testString()
  122. {
  123. $template = 'foo {{ "bar #{ baz + 1 }" }}';
  124. $lexer = new Twig_Lexer(new Twig_Environment());
  125. $stream = $lexer->tokenize($template);
  126. $stream->expect(Twig_Token::TEXT_TYPE, 'foo ');
  127. $stream->expect(Twig_Token::VAR_START_TYPE);
  128. $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
  129. $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
  130. $stream->expect(Twig_Token::NAME_TYPE, 'baz');
  131. $stream->expect(Twig_Token::OPERATOR_TYPE, '+');
  132. $stream->expect(Twig_Token::NUMBER_TYPE, '1');
  133. $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
  134. $stream->expect(Twig_Token::VAR_END_TYPE);
  135. }
  136. public function testStringWithEscapedInterpolation()
  137. {
  138. $template = '{{ "bar \#{baz+1}" }}';
  139. $lexer = new Twig_Lexer(new Twig_Environment());
  140. $stream = $lexer->tokenize($template);
  141. $stream->expect(Twig_Token::VAR_START_TYPE);
  142. $stream->expect(Twig_Token::STRING_TYPE, 'bar #{baz+1}');
  143. $stream->expect(Twig_Token::VAR_END_TYPE);
  144. }
  145. public function testStringWithHash()
  146. {
  147. $template = '{{ "bar # baz" }}';
  148. $lexer = new Twig_Lexer(new Twig_Environment());
  149. $stream = $lexer->tokenize($template);
  150. $stream->expect(Twig_Token::VAR_START_TYPE);
  151. $stream->expect(Twig_Token::STRING_TYPE, 'bar # baz');
  152. $stream->expect(Twig_Token::VAR_END_TYPE);
  153. }
  154. /**
  155. * @expectedException Twig_Error_Syntax
  156. * @expectedExceptionMessage Unclosed """
  157. */
  158. public function testStringWithUnterminatedInterpolation()
  159. {
  160. $template = '{{ "bar #{x" }}';
  161. $lexer = new Twig_Lexer(new Twig_Environment());
  162. $stream = $lexer->tokenize($template);
  163. }
  164. public function testStringWithNestedInterpolations()
  165. {
  166. $template = '{{ "bar #{ "foo#{bar}" }" }}';
  167. $lexer = new Twig_Lexer(new Twig_Environment());
  168. $stream = $lexer->tokenize($template);
  169. $stream->expect(Twig_Token::VAR_START_TYPE);
  170. $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
  171. $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
  172. $stream->expect(Twig_Token::STRING_TYPE, 'foo');
  173. $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
  174. $stream->expect(Twig_Token::NAME_TYPE, 'bar');
  175. $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
  176. $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
  177. $stream->expect(Twig_Token::VAR_END_TYPE);
  178. }
  179. public function testStringWithNestedInterpolationsInBlock()
  180. {
  181. $template = '{% foo "bar #{ "foo#{bar}" }" %}';
  182. $lexer = new Twig_Lexer(new Twig_Environment());
  183. $stream = $lexer->tokenize($template);
  184. $stream->expect(Twig_Token::BLOCK_START_TYPE);
  185. $stream->expect(Twig_Token::NAME_TYPE, 'foo');
  186. $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
  187. $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
  188. $stream->expect(Twig_Token::STRING_TYPE, 'foo');
  189. $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
  190. $stream->expect(Twig_Token::NAME_TYPE, 'bar');
  191. $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
  192. $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
  193. $stream->expect(Twig_Token::BLOCK_END_TYPE);
  194. }
  195. public function testOperatorEndingWithALetterAtTheEndOfALine()
  196. {
  197. $template = "{{ 1 and\n0}}";
  198. $lexer = new Twig_Lexer(new Twig_Environment());
  199. $stream = $lexer->tokenize($template);
  200. $stream->expect(Twig_Token::VAR_START_TYPE);
  201. $stream->expect(Twig_Token::NUMBER_TYPE, 1);
  202. $stream->expect(Twig_Token::OPERATOR_TYPE, 'and');
  203. }
  204. }