TYPO3 CMS  TYPO3_7-6
TemplateParserTest.php
Go to the documentation of this file.
1 <?php
3 
4 /* *
5  * This script is backported from the TYPO3 Flow package "TYPO3.Fluid". *
6  * *
7  * It is free software; you can redistribute it and/or modify it under *
8  * the terms of the GNU Lesser General Public License, either version 3 *
9  * of the License, or (at your option) any later version. *
10  * *
11  * The TYPO3 project - inspiring people to share! *
12  * */
15 
23 {
29  {
30  $templateParser = new \TYPO3\CMS\Fluid\Core\Parser\TemplateParser();
31  $templateParser->parse(123);
32  }
33 
38  {
39  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
40  $templateParser->_call('extractNamespaceDefinitions', ' \\{namespace f4=F7\\Rocks} {namespace f4=TYPO3\Rocks\Really}');
41  $expected = [
42  'f' => \TYPO3\CMS\Fluid\ViewHelpers::class,
43  'f4' => 'TYPO3\Rocks\Really'
44  ];
45  $this->assertEquals($expected, $templateParser->getNamespaces(), 'Namespaces do not match.');
46  }
47 
52  {
53  $mockSettings = [
54  'namespaces' => [
55  'http://domain.tld/ns/my/viewhelpers' => 'My\Namespace',
56  'http://otherdomain.tld/ns/other/viewhelpers' => 'My\Other\Namespace'
57  ]
58  ];
59  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
60  $templateParser->injectSettings($mockSettings);
61  $templateParser->_call('extractNamespaceDefinitions', 'Some content <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f5="http://domain.tld/ns/my/viewhelpers"
62  xmlns:xyz="http://otherdomain.tld/ns/other/viewhelpers" />');
63  $expected = [
64  'f' => \TYPO3\CMS\Fluid\ViewHelpers::class,
65  'f5' => 'My\Namespace',
66  'xyz' => 'My\Other\Namespace'
67  ];
68  $this->assertEquals($expected, $templateParser->getNamespaces(), 'Namespaces do not match.');
69  }
70 
75  {
76  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
77  $templateParser->_call('extractNamespaceDefinitions', '<xml xmlns="http://www.w3.org/1999/xhtml" xmlns:xyz="http://typo3.org/ns/Some/Package/ViewHelpers" />');
78  $expected = [
79  'f' => \TYPO3\CMS\Fluid\ViewHelpers::class,
80  'xyz' => 'Some\Package\ViewHelpers'
81  ];
82  $this->assertEquals($expected, $templateParser->getNamespaces(), 'Namespaces do not match.');
83  }
84 
89  {
90  $mockSettings = [
91  'namespaces' => [
92  'http://domain.tld/ns/my/viewhelpers' => 'My\Namespace'
93  ]
94  ];
95  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
96  $templateParser->injectSettings($mockSettings);
97  $templateParser->_call('extractNamespaceDefinitions', '<xml xmlns="http://www.w3.org/1999/xhtml" xmlns:f5="http://domain.tld/ns/my/viewhelpers"
98  xmlns:xyz="http://otherdomain.tld/ns/other/viewhelpers" />');
99  $expected = [
100  'f' => \TYPO3\CMS\Fluid\ViewHelpers::class,
101  'f5' => 'My\Namespace'
102  ];
103  $this->assertEquals($expected, $templateParser->getNamespaces(), 'Namespaces do not match.');
104  }
105 
110  {
111  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
112  $templateParser->_call('extractNamespaceDefinitions', '<foo xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://domain.tld/this/will/be/ignored" />');
113  $expected = [
114  'f' => \TYPO3\CMS\Fluid\ViewHelpers::class
115  ];
116  $this->assertEquals($expected, $templateParser->getNamespaces(), 'Namespaces do not match.');
117  }
118 
124  {
125  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
126  $templateParser->_call('extractNamespaceDefinitions', '{namespace typo3=TYPO3\CMS\Fluid\Blablubb} {namespace typo3= TYPO3\Rocks\Blu}');
127  }
128 
134  {
135  $mockSettings = [
136  'namespaces' => [
137  'http://domain.tld/ns/my/viewhelpers' => 'My\Namespace'
138  ]
139  ];
140  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
141  $templateParser->injectSettings($mockSettings);
142  $templateParser->_call('extractNamespaceDefinitions', '<foo xmlns="http://www.w3.org/1999/xhtml" xmlns:typo3="http://domain.tld/ns/my/viewhelpers" />{namespace typo3=TYPO3\CMS\Fluid\Blablubb}');
143  }
144 
150  {
151  $mockSettings = [
152  'namespaces' => [
153  'http://domain.tld/ns/my/viewhelpers' => 'My\Namespace'
154  ]
155  ];
156  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
157  $templateParser->injectSettings($mockSettings);
158  $templateParser->_call('extractNamespaceDefinitions', '{namespace typo3=TYPO3\CMS\Fluid\Blablubb} <foo xmlns="http://www.w3.org/1999/xhtml" xmlns:typo3="http://domain.tld/ns/my/viewhelpers" />');
159  }
160 
168  public function extractNamespaceDefinitionsCallsRemoveXmlnsViewHelperNamespaceDeclarationsWithCorrectFoundIdentifiers(array $expectedFoundIdentifiers, $templateString, array $namespaces)
169  {
170  $mockSettings = [
171  'namespaces' => $namespaces
172  ];
173 
175  $templateParser = $this->getAccessibleMock(TemplateParser::class, ['removeXmlnsViewHelperNamespaceDeclarations']);
176  $templateParser->injectSettings($mockSettings);
177 
178  // this verifies that the method is called with the correct found identifiers
179  // and also that the templateString was not modified before calling removeXmlnsViewHelperNamespaceDeclarations
180  $templateParser
181  ->expects($this->once())
182  ->method('removeXmlnsViewHelperNamespaceDeclarations')
183  ->with($templateString, $expectedFoundIdentifiers)
184  ->willReturnArgument(0);
185  $templateParser->_call('extractNamespaceDefinitions', $templateString);
186  }
187 
192  {
193  return [
194  'bothViewHelperNamespacesDefinitionsOnlyProvideXmlnsViewHelpersUsingNonDefaultPatternViewHelpers' => [
195  ['foo'],
196  '{namespace typo3=TYPO3\\CMS\\Fluid\\Blablubb} <div xmlns:foo="http://domain.tld/ns/foo/viewhelpers">Content</div>',
197  ['http://domain.tld/ns/foo/viewhelpers' => 'My\\Namespace']
198  ],
199  'bothViewHelperNamespacesDefinitionsOnlyProvideXmlnsViewHelpersUsingDefaultPatternViewHelpers' => [
200  ['xyz'],
201  '{namespace typo3=TYPO3\\CMS\\Fluid\\Blablubb} <div xmlns:xyz="http://typo3.org/ns/Some/Package/ViewHelpers">Content</div>',
202  []
203  ],
204  'xmlnsIdentifiersWithWhitespaces' => [
205  [' ', 'foo bar', '"x y z"'],
206  '
207  <div xmlns: ="http://typo3.org/ns/Some/Package/ViewHelpers"
208  xmlns:foo bar="http://domain.tld/ns/foobar/viewhelpers"
209  xmlns:"x y z"="http://typo3.org/ns/My/Xyz/ViewHelpers">
210 
211  Content
212  </div>
213  ',
214  ['http://domain.tld/ns/foobar/viewhelpers' => 'My\\Namespace']
215  ],
216  'xmlnsWithEqualsSign' => [
217  ['=', 'foo=bar', '"x=y=z"'],
218  '
219  <div xmlns:=="http://typo3.org/ns/Some/Package/ViewHelpers"
220  xmlns:foo=bar="http://domain.tld/ns/foobar/viewhelpers"
221  xmlns:"x=y=z"="http://typo3.org/ns/My/Xyz/ViewHelpers">
222 
223  Content
224  </div>
225  ',
226  ['http://domain.tld/ns/foobar/viewhelpers' => 'My\\Namespace']
227  ],
228  'nonViewHelpersXmlnsAreNotIncludedButDefaultPatternAndNonDefaultAreIncluded' => [
229  ['xyz', 'foo'],
230  '<div xmlns:xyz="http://typo3.org/ns/Some/Package/ViewHelpers"
231  xmlns:foo="http://domain.tld/ns/foo/viewhelpers"
232  xmlns:bar="http://typo3.org/foo/bar">
233 
234  Content
235  </div>',
236  ['http://domain.tld/ns/foo/viewhelpers' => 'My\\Namespace']
237  ],
238  'nonViewHelpersInBetweenViewHelperXmlnsAreNotIncludedButDefaultPatternAndNonDefaultAreIncluded' => [
239  ['xyz', 'foo'],
240  '<div xmlns:xyz="http://typo3.org/ns/Some/Package/ViewHelpers"
241  xmlns:bar="http://typo3.org/foo/bar"
242  xmlns:foo="http://domain.tld/ns/foo/viewhelpers">
243 
244  Content
245  </div>',
246  ['http://domain.tld/ns/foo/viewhelpers' => 'My\\Namespace']
247  ],
248  'fluidNamespaceIsFound' => [
249  ['f'],
250  '<div xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers">Content</div>',
251  []
252  ],
253  'xmlnsWithoutIdentifierIsIgnored' => [
254  [],
255  '<div xmlns="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers">Content</div>',
256  []
257  ],
258  'htmlTagAlsoFindsIdentifiers' => [
259  ['f', 'xyz'],
260  '<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
261  xmlns:xyz="http://typo3.org/ns/Some/Package/ViewHelpers">
262 
263  Content
264  </html>',
265  []
266  ],
267  'htmlTagWithNamespaceTypo3FluidAttributeTagAlsoFindsIdentifiers' => [
268  ['f', 'xyz'],
269  '<html data-namespace-typo3-fluid="true"
270  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
271  xmlns:xyz="http://typo3.org/ns/Some/Package/ViewHelpers">
272 
273  Content
274  </html>',
275  []
276  ],
277  'nonHtmlTagAlsoFindsIdentifiers' => [
278  ['f', 'xyz'],
279  '<typo3-root
280  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
281  xmlns:xyz="http://typo3.org/ns/Some/Package/ViewHelpers">
282 
283  Content
284  </typo3-root>',
285  []
286  ],
287  ];
288  }
289 
297  public function removeXmlnsViewHelperNamespaceDeclarationsWorks($expectedOut, array $foundIdentifiers, $templateString)
298  {
299  $templateParser = $this->getAccessibleMock(TemplateParser::class, ['dummy']);
300  $templateString = $templateParser->_call('removeXmlnsViewHelperNamespaceDeclarations', $templateString, $foundIdentifiers);
301 
302  // remove tabs and trim because expected result and given have a different tab count in dataProvider which is not relevant for the parser (xml and html)
303  $this->assertSame(trim(str_replace("\t", '', $expectedOut)), trim(str_replace("\t", '', $templateString)));
304  }
305 
312  {
313  return [
314  'onlyViewHelperXmlns' => [
315  '
316  <div >
317  <f:if condition="{demo}">Hello World</f:if>
318  </div>
319  ',
320  ['f', 'fe'],
321  '<div xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
322  xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers">
323  <f:if condition="{demo}">Hello World</f:if>
324  </div>'
325  ],
326  'xmlnsViewHelpersFoundWithNonViewHelperXmlnsAtBeginning' => [
327  '
328  <div xmlns:z="http://www.typo3.org/foo" >
329  <f:if condition="{demo}">Hello World</f:if>
330  </div>
331  ',
332  ['f', 'fe'],
333  '
334  <div xmlns:z="http://www.typo3.org/foo"
335  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
336  xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers">
337  <f:if condition="{demo}">Hello World</f:if>
338  </div>
339  '
340  ],
341  'xmlnsViewHelpersFoundWithNonViewHelperXmlnsAtEnd' => [
342  '
343  <div xmlns:z="http://www.typo3.org/foo">
344  <f:if condition="{demo}">Hello World</f:if>
345  </div>
346  ',
347  ['f', 'fe'],
348  '
349  <div xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
350  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
351  xmlns:z="http://www.typo3.org/foo">
352  <f:if condition="{demo}">Hello World</f:if>
353  </div>
354  '
355  ],
356  'xmlnsViewHelpersFoundWithMultipleNonViewHelperXmlns' => [
357  '
358  <div xmlns:y="http://www.typo3.org/bar" xmlns:z="http://www.typo3.org/foo">
359  <f:if condition="{demo}">Hello World</f:if>
360  </div>
361  ',
362  ['f', 'fe'],
363  '
364  <div xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
365  xmlns:y="http://www.typo3.org/bar"
366  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
367  xmlns:z="http://www.typo3.org/foo">
368  <f:if condition="{demo}">Hello World</f:if>
369  </div>
370  '
371  ],
372  'xmlnsViewHelpersFoundWithNonViewHelperXmlnsBetween' => [
373  '
374  <div xmlns:z="http://www.typo3.org/foo" >
375  <f:if condition="{demo}">Hello World</f:if>
376  </div>
377  ',
378  ['fe', 'f'],
379  '
380  <div xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
381  xmlns:z="http://www.typo3.org/foo"
382  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers">
383  <f:if condition="{demo}">Hello World</f:if>
384  </div>
385  '
386  ],
387  'removeHtmlTagWithAttributeButNoXmlnsViewHelpersFound' => [
388  '<f:if condition="{demo}">Hello World</f:if>',
389  [],
390  '
391  <html data-namespace-typo3-fluid="true">
392  <f:if condition="{demo}">Hello World</f:if>
393  </html>
394  '
395  ],
396  'doNotRemoveHtmlTagBecauseHtmlTagNotMarkedAsFluidNamespaceDefinitionTag' => [
397  '
398  <html xmlns:z="http://www.typo3.org/foo">
399  <f:if condition="{demo}">Hello World</f:if>
400  </html>
401  ',
402  ['fe', 'f'],
403  '
404  <html xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
405  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
406  xmlns:z="http://www.typo3.org/foo">
407  <f:if condition="{demo}">Hello World</f:if>
408  </html>
409  '
410  ],
411  'doNotModifyHtmlTagBecauseViewHelperXmlnsNotFoundInTagAndNotMarkedForRemoval' => [
412  '
413  <html xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
414  xmlns:z="http://www.typo3.org/foo">
415  <f:if condition="{demo}">Hello World</f:if>
416  </html>
417  ',
418  ['f'], // required because without any found namespaces the method will not do any replacements
419  '
420  <html xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
421  xmlns:z="http://www.typo3.org/foo">
422  <f:if condition="{demo}">Hello World</f:if>
423  </html>
424  '
425  ],
426  'removeHtmlTagBecauseXmlnsFoundInTagAndMarkedAsFluidViewHelperDefinitionTag' => [
427  '<f:if condition="{demo}">Hello World</f:if>',
428  ['fe'],
429  '
430  <html data-namespace-typo3-fluid="true"
431  xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
432  xmlns:z="http://www.typo3.org/foo">
433  <f:if condition="{demo}">Hello World</f:if>
434  </html>
435  '
436  ],
437  'removeHtmlTagBecauseXmlnsFoundInDifferentTagAndMarkedAsFluidViewHelperDefinitionTag' => [
438  '<f:if condition="{demo}">Hello World</f:if>',
439  ['f'],
440  '
441  <html data-namespace-typo3-fluid="true" xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
442  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
443  xmlns:z="http://www.typo3.org/foo">
444  <f:if condition="{demo}">Hello World</f:if>
445  </html>
446  '
447  ],
448  'producesExcpedtedOutputIfFouundIdentifiersAreWrongButContainNoExistingNonViewHelperXmlns' => [
449  '
450  <div xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers" xmlns:z="http://www.typo3.org/foo">
451  <f:if condition="{demo}">Hello World</f:if>
452  </div>
453  ',
454  ['f', 'i'],
455  '
456  <div xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
457  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
458  xmlns:z="http://www.typo3.org/foo">
459  <f:if condition="{demo}">Hello World</f:if>
460  </div>
461  '
462  ],
463  // this test verifies that the expected output can be wrong if the foundNameSpaces are incorrect
464  // which is why extractNamespaceDefinitionsCallsRemoveXmlnsViewHelperNamespaceDeclarationsWithCorrectFoundIdentifiers
465  // tests if the correct identifiers are found
466  'removesNonViewHelperNamespaceIfFoundIdentifiersAreWrong' => [
467  '
468  <div xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers" >
469  <f:if condition="{demo}">Hello World</f:if>
470  </div>
471  ',
472  ['f', 'z'],
473  '
474  <div xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
475  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
476  xmlns:z="http://www.typo3.org/foo">
477  <f:if condition="{demo}">Hello World</f:if>
478  </div>
479  '
480  ],
481  // this verifies that the scan pattern was correctly quoted for the regular expression
482  // because if the regular expression delimiter were to be modified in the pattern,
483  // the corresponding preg_quote will fail without adaptions
484  'xmlnsWithScanPatternAsIdentifier' => [
485  '
486  <div >
487  <f:if condition="{demo}">Hello World</f:if>
488  </div>
489  ',
491  '
492  <div xmlns:' . TemplateParser::$SCAN_PATTERN_REMOVE_VIEWHELPERS_XMLNSDECLARATIONS . '="http://typo3.org/ns/TYPO3/CMS\Demo/ViewHelpers">
493  <f:if condition="{demo}">Hello World</f:if>
494  </div>
495  '
496  ],
497  // these scenarios also need to because even if the foundIdentifiers are
498  // invalid the method should still work as expected,
499  // Furthermore, currently these patterns are allowed for foundIdentifiers
500  // see also test extractNamespaceDefinitionsCallsRemoveXmlnsViewHelperNamespaceDeclarationsWithCorrectFoundIdentifiers
501  'xmlnsIdentifiersWithWhitespaces' => [
502  '
503  <div xmlns:none xyz="http://domain.tld/ns/NoneXyz/viewhelpers" >
504 
505  <f:if condition="{demo}">Hello World</f:if>
506  </div>
507  ',
508  [' ', 'foo bar', '"x y z"'],
509  '
510  <div xmlns: ="http://typo3.org/ns/Some/Package/ViewHelpers"
511  xmlns:foo bar="http://domain.tld/ns/foobar/viewhelpers"
512  xmlns:none xyz="http://domain.tld/ns/NoneXyz/viewhelpers"
513  xmlns:"x y z"="http://typo3.org/ns/My/Xyz/ViewHelpers">
514 
515  <f:if condition="{demo}">Hello World</f:if>
516  </div>
517  '
518  ],
519  'xmlnsWithRegularExpressionAsIdentifier' => [
520  '
521  <div xmlns:z="http://www.typo3.org/foo">
522  <f:if condition="{demo}">Hello World</f:if>
523  </div>
524  ',
525  ['f', 'fe', '.*.?\\s'],
526  '
527  <div xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
528  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
529  xmlns:.*.?\\s="http://typo3.org/ns/TYPO3/CMS\Demo/ViewHelpers"
530  xmlns:z="http://www.typo3.org/foo">
531  <f:if condition="{demo}">Hello World</f:if>
532  </div>
533  '
534  ],
535  'xmlnsWithRegularExpressionDelimiterAsIdentifier' => [
536  '
537  <div xmlns:z="http://www.typo3.org/foo">
538  <f:if condition="{demo}">Hello World</f:if>
539  </div>
540  ',
541  ['f', 'fe', '/'],
542  '
543  <div xmlns:fe="http://typo3.org/ns/TYPO3/CMS/Frontend/ViewHelpers"
544  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
545  xmlns:/="http://typo3.org/ns/TYPO3/CMS\Demo/ViewHelpers"
546  xmlns:z="http://www.typo3.org/foo">
547  <f:if condition="{demo}">Hello World</f:if>
548  </div>
549  '
550  ],
551  'xmlnsWithEqualsSign' => [
552  '
553  <div xmlns:none=xyz="http://domain.tld/ns/NoneXyz/viewhelpers" >
554 
555  <f:if condition="{demo}">Hello World</f:if>
556  </div>
557  ',
558  ['=', 'foo=bar', '"x=y=z"'],
559  '
560  <div xmlns:=="http://typo3.org/ns/Some/Package/ViewHelpers"
561  xmlns:foo=bar="http://domain.tld/ns/foobar/viewhelpers"
562  xmlns:none=xyz="http://domain.tld/ns/NoneXyz/viewhelpers"
563  xmlns:"x=y=z"="http://typo3.org/ns/My/Xyz/ViewHelpers">
564 
565  <f:if condition="{demo}">Hello World</f:if>
566  </div>
567  '
568  ]
569  ];
570  }
571 
576  {
577  $mockTemplateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy'], [], '', false);
578  $result = $mockTemplateParser->_call('resolveViewHelperName', 'f', 'foo.bar.baz');
579  $expected = 'TYPO3\CMS\Fluid\ViewHelpers\Foo\Bar\BazViewHelper';
580  $this->assertEquals($expected, $result, 'The name of the View Helper Name could not be resolved.');
581  }
582 
587  {
588  $mockTemplateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy'], [], '', false);
589  $actual = $mockTemplateParser->_call('resolveViewHelperName', 'f', 'myown');
590  $expected = 'TYPO3\CMS\Fluid\ViewHelpers\MyownViewHelper';
591  $this->assertEquals($expected, $actual);
592  }
593 
596  public function quotedStrings()
597  {
598  return [
599  ['"no quotes here"', 'no quotes here'],
600  ["'no quotes here'", 'no quotes here'],
601  ["'this \"string\" had \\'quotes\\' in it'", 'this "string" had \'quotes\' in it'],
602  ['"this \\"string\\" had \'quotes\' in it"', 'this "string" had \'quotes\' in it'],
603  ['"a weird \"string\" \'with\' *freaky* \\\\stuff', 'a weird "string" \'with\' *freaky* \\stuff'],
604  ['\'\\\'escaped quoted string in string\\\'\'', '\'escaped quoted string in string\'']
605  ];
606  }
607 
612  public function unquoteStringReturnsUnquotedStrings($quoted, $unquoted)
613  {
614  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
615  $this->assertEquals($unquoted, $templateParser->_call('unquoteString', $quoted));
616  }
617 
620  public function templatesToSplit()
621  {
622  return [
623  ['TemplateParserTestFixture01-shorthand'],
624  ['TemplateParserTestFixture06'],
625  ['TemplateParserTestFixture14']
626  ];
627  }
628 
634  {
635  $template = file_get_contents(__DIR__ . '/Fixtures/' . $templateName . '.html', FILE_TEXT);
636  $expectedResult = require(__DIR__ . '/Fixtures/' . $templateName . '-split.php');
637  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
638  $this->assertSame($expectedResult, $templateParser->_call('splitTemplateAtDynamicTags', $template), 'Filed for ' . $templateName);
639  }
640 
645  {
646  $mockRootNode = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\RootNode::class);
647 
648  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
649  $mockState->expects($this->once())->method('setRootNode')->with($mockRootNode);
650  $mockState->expects($this->once())->method('pushNodeToStack')->with($mockRootNode);
651  $mockState->expects($this->once())->method('countNodeStack')->will($this->returnValue(1));
652 
653  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
654  $mockObjectManager->expects($this->at(0))->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class)->will($this->returnValue($mockState));
655  $mockObjectManager->expects($this->at(1))->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\RootNode::class)->will($this->returnValue($mockRootNode));
656 
657  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
658  $templateParser->_set('objectManager', $mockObjectManager);
659  $templateParser->_call('buildObjectTree', [], \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::CONTEXT_OUTSIDE_VIEWHELPER_ARGUMENTS);
660  }
661 
667  {
668  $mockRootNode = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\RootNode::class);
669 
670  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
671  $mockState->expects($this->once())->method('countNodeStack')->will($this->returnValue(2));
672 
673  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
674  $mockObjectManager->expects($this->at(0))->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class)->will($this->returnValue($mockState));
675  $mockObjectManager->expects($this->at(1))->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\RootNode::class)->will($this->returnValue($mockRootNode));
676 
677  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
678  $templateParser->_set('objectManager', $mockObjectManager);
679  $templateParser->_call('buildObjectTree', [], \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::CONTEXT_OUTSIDE_VIEWHELPER_ARGUMENTS);
680  }
681 
686  {
687  $mockRootNode = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\RootNode::class);
688  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
689  $mockState->expects($this->once())->method('countNodeStack')->will($this->returnValue(1));
690  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
691  $mockObjectManager->expects($this->at(0))->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class)->will($this->returnValue($mockState));
692  $mockObjectManager->expects($this->at(1))->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\RootNode::class)->will($this->returnValue($mockRootNode));
693 
694  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['textHandler', 'openingViewHelperTagHandler', 'closingViewHelperTagHandler', 'textAndShorthandSyntaxHandler']);
695  $templateParser->_set('objectManager', $mockObjectManager);
696  $templateParser->expects($this->at(0))->method('textAndShorthandSyntaxHandler')->with($mockState, 'The first part is simple');
697  $templateParser->expects($this->at(1))->method('textHandler')->with($mockState, '<f:for each="{a: {a: 0, b: 2, c: 4}}" as="array"><f:for each="{array}" as="value">{value} </f:for>');
698  $templateParser->expects($this->at(2))->method('openingViewHelperTagHandler')->with($mockState, 'f', 'format.printf', ' arguments="{number : 362525200}"', false);
699  $templateParser->expects($this->at(3))->method('textAndShorthandSyntaxHandler')->with($mockState, '%.3e');
700  $templateParser->expects($this->at(4))->method('closingViewHelperTagHandler')->with($mockState, 'f', 'format.printf');
701  $templateParser->expects($this->at(5))->method('textAndShorthandSyntaxHandler')->with($mockState, 'and here goes some {text} that could have {shorthand}');
702 
703  $splitTemplate = $templateParser->_call('splitTemplateAtDynamicTags', 'The first part is simple<![CDATA[<f:for each="{a: {a: 0, b: 2, c: 4}}" as="array"><f:for each="{array}" as="value">{value} </f:for>]]><f:format.printf arguments="{number : 362525200}">%.3e</f:format.printf>and here goes some {text} that could have {shorthand}');
704  $templateParser->_call('buildObjectTree', $splitTemplate, \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::CONTEXT_OUTSIDE_VIEWHELPER_ARGUMENTS);
705  }
706 
711  {
712  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
713  $mockState->expects($this->never())->method('popNodeFromStack');
714 
715  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['parseArguments', 'initializeViewHelperAndAddItToStack']);
716  $templateParser->expects($this->once())->method('parseArguments')->with(['arguments'])->will($this->returnValue(['parsedArguments']));
717  $templateParser->expects($this->once())->method('initializeViewHelperAndAddItToStack')->with($mockState, 'namespaceIdentifier', 'methodIdentifier', ['parsedArguments']);
718 
719  $templateParser->_call('openingViewHelperTagHandler', $mockState, 'namespaceIdentifier', 'methodIdentifier', ['arguments'], false);
720  }
721 
726  {
727  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
728  $mockState->expects($this->once())->method('popNodeFromStack')->will($this->returnValue($this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\NodeInterface::class)));
729 
730  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['parseArguments', 'initializeViewHelperAndAddItToStack']);
731 
732  $templateParser->_call('openingViewHelperTagHandler', $mockState, '', '', [], true);
733  }
734 
739  {
740  $mockViewHelper = $this->getMock(\TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper::class);
741  $mockViewHelperNode = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode::class, [], [], '', false);
742 
743  $mockNodeOnStack = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\NodeInterface::class);
744  $mockNodeOnStack->expects($this->once())->method('addChildNode')->with($mockViewHelperNode);
745 
746  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
747  $mockObjectManager->expects($this->at(0))->method('get')->with('TYPO3\\CMS\\Fluid\\ViewHelpers\\MyownViewHelper')->will($this->returnValue($mockViewHelper));
748  $mockObjectManager->expects($this->at(1))->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode::class)->will($this->returnValue($mockViewHelperNode));
749 
750  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
751  $mockState->expects($this->once())->method('getNodeFromStack')->will($this->returnValue($mockNodeOnStack));
752  $mockState->expects($this->once())->method('pushNodeToStack')->with($mockViewHelperNode);
753 
754  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['abortIfUnregisteredArgumentsExist', 'abortIfRequiredArgumentsAreMissing', 'rewriteBooleanNodesInArgumentsObjectTree']);
755  $templateParser->_set('objectManager', $mockObjectManager);
756 
757  $templateParser->_call('initializeViewHelperAndAddItToStack', $mockState, 'f', 'myown', ['arguments']);
758  }
759 
764  {
765  $expectedArguments = ['expectedArguments'];
766  $argumentsObjectTree = ['arguments'];
767 
768  $mockViewHelper = $this->getMock(\TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper::class);
769  $mockViewHelper->expects($this->once())->method('prepareArguments')->will($this->returnValue($expectedArguments));
770  $mockViewHelperNode = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode::class, [], [], '', false);
771 
772  $mockNodeOnStack = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\NodeInterface::class);
773 
774  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
775  $mockObjectManager->expects($this->at(0))->method('get')->with('TYPO3\\CMS\\Fluid\\ViewHelpers\\MyownViewHelper')->will($this->returnValue($mockViewHelper));
776  $mockObjectManager->expects($this->at(1))->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode::class)->will($this->returnValue($mockViewHelperNode));
777 
778  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
779  $mockState->expects($this->once())->method('getNodeFromStack')->will($this->returnValue($mockNodeOnStack));
780 
781  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['abortIfUnregisteredArgumentsExist', 'abortIfRequiredArgumentsAreMissing', 'rewriteBooleanNodesInArgumentsObjectTree']);
782  $templateParser->_set('objectManager', $mockObjectManager);
783  $templateParser->expects($this->once())->method('abortIfUnregisteredArgumentsExist')->with($expectedArguments, $argumentsObjectTree);
784  $templateParser->expects($this->once())->method('abortIfRequiredArgumentsAreMissing')->with($expectedArguments, $argumentsObjectTree);
785 
786  $templateParser->_call('initializeViewHelperAndAddItToStack', $mockState, 'f', 'myown', $argumentsObjectTree);
787  }
788 
793  {
794  $mockViewHelper = $this->getMock(\TYPO3\CMS\Fluid\Tests\Unit\Core\Parser\Fixtures\PostParseFacetViewHelper::class, ['prepareArguments']);
795  $mockViewHelperNode = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode::class, [], [], '', false);
796 
797  $mockNodeOnStack = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\NodeInterface::class);
798  $mockNodeOnStack->expects($this->once())->method('addChildNode')->with($mockViewHelperNode);
799 
800  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
801  $mockObjectManager->expects($this->at(0))->method('get')->with('TYPO3\\CMS\\Fluid\\ViewHelpers\\MyownViewHelper')->will($this->returnValue($mockViewHelper));
802  $mockObjectManager->expects($this->at(1))->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode::class)->will($this->returnValue($mockViewHelperNode));
803 
804  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
805  $mockState->expects($this->once())->method('getNodeFromStack')->will($this->returnValue($mockNodeOnStack));
806  $mockState->expects($this->once())->method('getVariableContainer')->will($this->returnValue($this->getMock(\TYPO3\CMS\Fluid\Core\ViewHelper\TemplateVariableContainer::class)));
807 
808  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['abortIfUnregisteredArgumentsExist', 'abortIfRequiredArgumentsAreMissing', 'rewriteBooleanNodesInArgumentsObjectTree']);
809  $templateParser->_set('objectManager', $mockObjectManager);
810 
811  $templateParser->_call('initializeViewHelperAndAddItToStack', $mockState, 'f', 'myown', ['arguments']);
812  $this->assertTrue(\TYPO3\CMS\Fluid\Tests\Unit\Core\Parser\Fixtures\PostParseFacetViewHelper::$wasCalled, 'PostParse was not called!');
813  }
814 
820  {
821  $expected = [new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition('firstArgument', 'string', '', false)];
822  $actual = ['firstArgument' => 'foo', 'secondArgument' => 'bar'];
823 
824  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
825 
826  $templateParser->_call('abortIfUnregisteredArgumentsExist', $expected, $actual);
827  }
828 
833  {
834  $expectedArguments = [
835  new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition('name1', 'string', 'desc', false),
836  new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition('name2', 'string', 'desc', true)
837  ];
838  $actualArguments = [
839  'name1' => 'bla'
840  ];
841 
842  $mockTemplateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
843 
844  $mockTemplateParser->_call('abortIfUnregisteredArgumentsExist', $expectedArguments, $actualArguments);
845  // dummy assertion to avoid "did not perform any assertions" error
846  $this->assertTrue(true);
847  }
848 
854  {
855  $expected = [
856  new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition('firstArgument', 'string', '', false),
857  new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition('secondArgument', 'string', '', true)
858  ];
859 
860  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
861 
862  $templateParser->_call('abortIfRequiredArgumentsAreMissing', $expected, []);
863  }
864 
869  {
870  $expectedArguments = [
871  new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition('name1', 'string', 'desc', false),
872  new \TYPO3\CMS\Fluid\Core\ViewHelper\ArgumentDefinition('name2', 'string', 'desc', true)
873  ];
874  $actualArguments = [
875  'name2' => 'bla'
876  ];
877 
878  $mockTemplateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
879 
880  $mockTemplateParser->_call('abortIfRequiredArgumentsAreMissing', $expectedArguments, $actualArguments);
881  // dummy assertion to avoid "did not perform any assertions" error
882  $this->assertTrue(true);
883  }
884 
890  {
891  $mockNodeOnStack = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\NodeInterface::class, [], [], '', false);
892  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
893  $mockState->expects($this->once())->method('popNodeFromStack')->will($this->returnValue($mockNodeOnStack));
894 
895  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
896 
897  $templateParser->_call('closingViewHelperTagHandler', $mockState, 'f', 'method');
898  }
899 
905  {
906  $mockNodeOnStack = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ViewHelperNode::class, [], [], '', false);
907  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
908  $mockState->expects($this->once())->method('popNodeFromStack')->will($this->returnValue($mockNodeOnStack));
909 
910  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
911 
912  $templateParser->_call('closingViewHelperTagHandler', $mockState, 'f', 'method');
913  }
914 
919  {
920  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
921  $mockState->expects($this->exactly(2))->method('popNodeFromStack')->will($this->returnValue($this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\NodeInterface::class)));
922 
923  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['recursiveArrayHandler', 'postProcessArgumentsForObjectAccessor', 'initializeViewHelperAndAddItToStack']);
924  $templateParser->expects($this->at(0))->method('recursiveArrayHandler')->with('format: "H:i"')->will($this->returnValue(['format' => 'H:i']));
925  $templateParser->expects($this->at(1))->method('postProcessArgumentsForObjectAccessor')->with(['format' => 'H:i'])->will($this->returnValue(['processedArguments']));
926  $templateParser->expects($this->at(2))->method('initializeViewHelperAndAddItToStack')->with($mockState, 'f', 'format.date', ['processedArguments']);
927  $templateParser->expects($this->at(3))->method('initializeViewHelperAndAddItToStack')->with($mockState, 'f', 'base', []);
928 
929  $templateParser->_call('objectAccessorHandler', $mockState, '', '', 'f:base() f:format.date(format: "H:i")', '');
930  }
931 
936  {
937  $objectAccessorNode = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ObjectAccessorNode::class, [], [], '', false);
938 
939  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
940  $mockObjectManager->expects($this->once())->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ObjectAccessorNode::class, 'objectAccessorString')->will($this->returnValue($objectAccessorNode));
941 
942  $mockNodeOnStack = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode::class, [], [], '', false);
943  $mockNodeOnStack->expects($this->once())->method('addChildNode')->with($objectAccessorNode);
944  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
945  $mockState->expects($this->once())->method('getNodeFromStack')->will($this->returnValue($mockNodeOnStack));
946 
947  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
948  $templateParser->_set('objectManager', $mockObjectManager);
949 
950  $templateParser->_call('objectAccessorHandler', $mockState, 'objectAccessorString', '', '', '');
951  }
952 
957  {
958  $objectAccessorNode = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ObjectAccessorNode::class, [], [], '', false);
959  $objectAccessorNodeInterceptor = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\InterceptorInterface::class);
960  $objectAccessorNodeInterceptor->expects($this->once())->method('process')->with($objectAccessorNode)->will($this->returnArgument(0));
961 
962  $parserConfiguration = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\Configuration::class);
963  $parserConfiguration->expects($this->once())->method('getInterceptors')->with(\TYPO3\CMS\Fluid\Core\Parser\InterceptorInterface::INTERCEPT_OBJECTACCESSOR)->will($this->returnValue([$objectAccessorNodeInterceptor]));
964 
965  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
966  $mockObjectManager->expects($this->once())->method('get')->will($this->returnValue($objectAccessorNode));
967 
968  $mockNodeOnStack = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode::class, [], [], '', false);
969  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
970  $mockState->expects($this->once())->method('getNodeFromStack')->will($this->returnValue($mockNodeOnStack));
971 
972  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
973  $templateParser->_set('objectManager', $mockObjectManager);
974  $templateParser->_set('configuration', $parserConfiguration);
975 
976  $templateParser->_call('objectAccessorHandler', $mockState, 'objectAccessorString', '', '', '');
977  }
978 
981  public function argumentsStrings()
982  {
983  return [
984  ['a="2"', ['a' => '2']],
985  ['a="2" b="foobar \' with \\" quotes"', ['a' => '2', 'b' => 'foobar \' with " quotes']],
986  [' arguments="{number : 362525200}"', ['arguments' => '{number : 362525200}']]
987  ];
988  }
989 
996  public function parseArgumentsWorksAsExpected($argumentsString, array $expected)
997  {
998  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['buildArgumentObjectTree']);
999  $templateParser->expects($this->any())->method('buildArgumentObjectTree')->will($this->returnArgument(0));
1000 
1001  $this->assertSame($expected, $templateParser->_call('parseArguments', $argumentsString));
1002  }
1003 
1008  {
1009  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
1010  $mockObjectManager->expects($this->once())->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\TextNode::class, 'a very plain string')->will($this->returnValue('theTextNode'));
1011 
1012  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['dummy']);
1013  $templateParser->_set('objectManager', $mockObjectManager);
1014 
1015  $this->assertEquals('theTextNode', $templateParser->_call('buildArgumentObjectTree', 'a very plain string'));
1016  }
1017 
1022  {
1023  $objectTree = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
1024  $objectTree->expects($this->once())->method('getRootNode')->will($this->returnValue('theRootNode'));
1025 
1026  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['splitTemplateAtDynamicTags', 'buildObjectTree']);
1027  $templateParser->expects($this->at(0))->method('splitTemplateAtDynamicTags')->with('a <very> {complex} string')->will($this->returnValue('split string'));
1028  $templateParser->expects($this->at(1))->method('buildObjectTree')->with('split string')->will($this->returnValue($objectTree));
1029 
1030  $this->assertEquals('theRootNode', $templateParser->_call('buildArgumentObjectTree', 'a <very> {complex} string'));
1031  }
1032 
1037  {
1038  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
1039  $mockObjectManager->expects($this->any())->method('get')->will($this->returnArgument(1));
1040  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
1041 
1042  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['objectAccessorHandler', 'arrayHandler', 'textHandler']);
1043  $templateParser->_set('objectManager', $mockObjectManager);
1044  $templateParser->expects($this->at(0))->method('objectAccessorHandler')->with($mockState, 'someThing.absolutely', '', '', '');
1045  $templateParser->expects($this->at(1))->method('textHandler')->with($mockState, ' "fishy" is \'going\' ');
1046  $templateParser->expects($this->at(2))->method('arrayHandler')->with($mockState, 'on: "here"');
1047 
1048  $text = '{someThing.absolutely} "fishy" is \'going\' {on: "here"}';
1049  $templateParser->_call('textAndShorthandSyntaxHandler', $mockState, $text, \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::CONTEXT_INSIDE_VIEWHELPER_ARGUMENTS);
1050  }
1051 
1056  {
1057  $arrayNode = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ArrayNode::class, [], [[]]);
1058  $mockNodeOnStack = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode::class, [], [], '', false);
1059  $mockNodeOnStack->expects($this->once())->method('addChildNode')->with($arrayNode);
1060  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
1061  $mockState->expects($this->once())->method('getNodeFromStack')->will($this->returnValue($mockNodeOnStack));
1062 
1063  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
1064  $mockObjectManager->expects($this->once())->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ArrayNode::class, 'processedArrayText')->will($this->returnValue($arrayNode));
1065 
1066  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['recursiveArrayHandler']);
1067  $templateParser->_set('objectManager', $mockObjectManager);
1068  $templateParser->expects($this->once())->method('recursiveArrayHandler')->with('arrayText')->will($this->returnValue('processedArrayText'));
1069 
1070  $templateParser->_call('arrayHandler', $mockState, 'arrayText');
1071  }
1072 
1075  public function arrayTexts()
1076  {
1077  return [
1078  [
1079  'key1: "foo", key2: \'bar\', key3: someVar, key4: 123, key5: { key6: "baz" }',
1080  ['key1' => 'foo', 'key2' => 'bar', 'key3' => 'someVar', 'key4' => 123.0, 'key5' => ['key6' => 'baz']]
1081  ],
1082  [
1083  'key1: "\'foo\'", key2: \'\\\'bar\\\'\'',
1084  ['key1' => '\'foo\'', 'key2' => '\'bar\'']
1085  ]
1086  ];
1087  }
1088 
1093  public function recursiveArrayHandlerReturnsExpectedArray($arrayText, $expectedArray)
1094  {
1095  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
1096  $mockObjectManager->expects($this->any())->method('get')->will($this->returnArgument(1));
1097 
1098  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['buildArgumentObjectTree']);
1099  $templateParser->_set('objectManager', $mockObjectManager);
1100  $templateParser->expects($this->any())->method('buildArgumentObjectTree')->will($this->returnArgument(0));
1101 
1102  $this->assertSame($expectedArray, $templateParser->_call('recursiveArrayHandler', $arrayText));
1103  }
1104 
1109  {
1110  $textNode = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\TextNode::class, [], [], '', false);
1111  $textInterceptor = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\InterceptorInterface::class);
1112  $textInterceptor->expects($this->once())->method('process')->with($textNode)->will($this->returnArgument(0));
1113 
1114  $parserConfiguration = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\Configuration::class);
1115  $parserConfiguration->expects($this->once())->method('getInterceptors')->with(\TYPO3\CMS\Fluid\Core\Parser\InterceptorInterface::INTERCEPT_TEXT)->will($this->returnValue([$textInterceptor]));
1116 
1117  $mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
1118  $mockObjectManager->expects($this->once())->method('get')->with(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\TextNode::class, 'string')->will($this->returnValue($textNode));
1119 
1120  $mockNodeOnStack = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode::class, [], [], '', false);
1121  $mockNodeOnStack->expects($this->once())->method('addChildNode')->with($textNode);
1122  $mockState = $this->getMock(\TYPO3\CMS\Fluid\Core\Parser\ParsingState::class);
1123  $mockState->expects($this->once())->method('getNodeFromStack')->will($this->returnValue($mockNodeOnStack));
1124 
1125  $templateParser = $this->getAccessibleMock(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::class, ['splitTemplateAtDynamicTags', 'buildObjectTree']);
1126  $templateParser->_set('objectManager', $mockObjectManager);
1127  $templateParser->_set('configuration', $parserConfiguration);
1128 
1129  $templateParser->_call('textHandler', $mockState, 'string');
1130  }
1131 }
parseArgumentsWorksAsExpected($argumentsString, array $expected)
removeXmlnsViewHelperNamespaceDeclarationsWorks($expectedOut, array $foundIdentifiers, $templateString)
getAccessibleMock( $originalClassName, $methods=[], array $arguments=[], $mockClassName='', $callOriginalConstructor=true, $callOriginalClone=true, $callAutoload=true)