[TASK] Removes extra empty lines
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / TypoScript / Parser / TypoScriptParserTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\TypoScript\Parser;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * Test case for \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser
19 */
20 class TypoScriptParserTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
21 {
22 /**
23 * @var \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface
24 */
25 protected $typoScriptParser = null;
26
27 /**
28 * Set up
29 *
30 * @return void
31 */
32 protected function setUp()
33 {
34 $accessibleClassName = $this->buildAccessibleProxy(\TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::class);
35 $this->typoScriptParser = new $accessibleClassName();
36 }
37
38 /**
39 * Data provider for executeValueModifierReturnsModifiedResult
40 *
41 * @return array modifier name, modifier arguments, current value, expected result
42 */
43 public function executeValueModifierDataProvider()
44 {
45 return array(
46 'prependString with string' => array(
47 'prependString',
48 'abc',
49 '!',
50 '!abc'
51 ),
52 'prependString with empty string' => array(
53 'prependString',
54 'foo',
55 '',
56 'foo',
57 ),
58 'appendString with string' => array(
59 'appendString',
60 'abc',
61 '!',
62 'abc!',
63 ),
64 'appendString with empty string' => array(
65 'appendString',
66 'abc',
67 '',
68 'abc',
69 ),
70 'removeString removes simple string' => array(
71 'removeString',
72 'abcdef',
73 'bc',
74 'adef',
75 ),
76 'removeString removes nothing if no match' => array(
77 'removeString',
78 'abcdef',
79 'foo',
80 'abcdef',
81 ),
82 'removeString removes multiple matches' => array(
83 'removeString',
84 'FooBarFoo',
85 'Foo',
86 'Bar',
87 ),
88 'replaceString replaces simple match' => array(
89 'replaceString',
90 'abcdef',
91 'bc|123',
92 'a123def',
93 ),
94 'replaceString replaces simple match with nothing' => array(
95 'replaceString',
96 'abcdef',
97 'bc',
98 'adef',
99 ),
100 'replaceString replaces multiple matches' => array(
101 'replaceString',
102 'FooBarFoo',
103 'Foo|Bar',
104 'BarBarBar',
105 ),
106 'addToList adds at end of existing list' => array(
107 'addToList',
108 '123,456',
109 '789',
110 '123,456,789',
111 ),
112 'addToList adds at end of existing list including white-spaces' => array(
113 'addToList',
114 '123,456',
115 ' 789 , 32 , 12 ',
116 '123,456, 789 , 32 , 12 ',
117 ),
118 'addToList adds nothing' => array(
119 'addToList',
120 '123,456',
121 '',
122 '123,456,', // This result is probably not what we want (appended comma) ... fix it?
123 ),
124 'addToList adds to empty list' => array(
125 'addToList',
126 '',
127 'foo',
128 'foo',
129 ),
130 'removeFromList removes value from list' => array(
131 'removeFromList',
132 '123,456,789,abc',
133 '456',
134 '123,789,abc',
135 ),
136 'removeFromList removes value at beginning of list' => array(
137 'removeFromList',
138 '123,456,abc',
139 '123',
140 '456,abc',
141 ),
142 'removeFromList removes value at end of list' => array(
143 'removeFromList',
144 '123,456,abc',
145 'abc',
146 '123,456',
147 ),
148 'removeFromList removes multiple values from list' => array(
149 'removeFromList',
150 'foo,123,bar,123',
151 '123',
152 'foo,bar',
153 ),
154 'removeFromList removes empty values' => array(
155 'removeFromList',
156 'foo,,bar',
157 '',
158 'foo,bar',
159 ),
160 'uniqueList removes duplicates' => array(
161 'uniqueList',
162 '123,456,abc,456,456',
163 '',
164 '123,456,abc',
165 ),
166 'uniqueList removes duplicate empty list values' => array(
167 'uniqueList',
168 '123,,456,,abc',
169 '',
170 '123,,456,abc',
171 ),
172 'reverseList returns list reversed' => array(
173 'reverseList',
174 '123,456,abc,456',
175 '',
176 '456,abc,456,123',
177 ),
178 'reverseList keeps empty values' => array(
179 'reverseList',
180 ',123,,456,abc,,456',
181 '',
182 '456,,abc,456,,123,',
183 ),
184 'reverseList does not change single element' => array(
185 'reverseList',
186 '123',
187 '',
188 '123',
189 ),
190 'sortList sorts a list' => array(
191 'sortList',
192 '10,100,0,20,abc',
193 '',
194 '0,10,20,100,abc',
195 ),
196 'sortList sorts a list numeric' => array(
197 'sortList',
198 '10,0,100,-20',
199 'numeric',
200 '-20,0,10,100',
201 ),
202 'sortList sorts a list descending' => array(
203 'sortList',
204 '10,100,0,20,abc,-20',
205 'descending',
206 'abc,100,20,10,0,-20',
207 ),
208 'sortList sorts a list numeric descending' => array(
209 'sortList',
210 '10,100,0,20,-20',
211 'descending,numeric',
212 '100,20,10,0,-20',
213 ),
214 'sortList ignores invalid modifier arguments' => array(
215 'sortList',
216 '10,100,20',
217 'foo,descending,bar',
218 '100,20,10',
219 ),
220 );
221 }
222
223 /**
224 * @test
225 * @dataProvider executeValueModifierDataProvider
226 */
227 public function executeValueModifierReturnsModifiedResult($modifierName, $currentValue, $modifierArgument, $expected)
228 {
229 $actualValue = $this->typoScriptParser->_call('executeValueModifier', $modifierName, $modifierArgument, $currentValue);
230 $this->assertEquals($expected, $actualValue);
231 }
232
233 /**
234 * Data provider for executeValueModifierThrowsException
235 *
236 * @return array modifier name, modifier arguments, current value, expected result
237 */
238 public function executeValueModifierInvalidDataProvider()
239 {
240 return array(
241 'sortList sorts a list numeric' => array(
242 'sortList',
243 '10,0,100,-20,abc',
244 'numeric',
245 ),
246 'sortList sorts a list numeric descending' => array(
247 'sortList',
248 '10,100,0,20,abc,-20',
249 'descending,numeric',
250 ),
251 );
252 }
253
254 /**
255 * @test
256 * @dataProvider executeValueModifierInvalidDataProvider
257 */
258 public function executeValueModifierThrowsException($modifierName, $currentValue, $modifierArgument)
259 {
260 $this->setExpectedException('InvalidArgumentException', 'The list "' . $currentValue . '" should be sorted numerically but contains a non-numeric value');
261 $this->typoScriptParser->_call('executeValueModifier', $modifierName, $modifierArgument, $currentValue);
262 }
263
264 /**
265 * @param string $typoScript
266 * @param array $expected
267 * @dataProvider typoScriptIsParsedToArrayDataProvider
268 * @test
269 */
270 public function typoScriptIsParsedToArray($typoScript, array $expected)
271 {
272 $this->typoScriptParser->parse($typoScript);
273 $this->assertEquals($expected, $this->typoScriptParser->setup);
274 }
275
276 /**
277 * @return array
278 */
279 public function typoScriptIsParsedToArrayDataProvider()
280 {
281 return array(
282 'simple assignment' => array(
283 'key = value',
284 array(
285 'key' => 'value',
286 )
287 ),
288 'simple assignment with escaped dot at the beginning' => array(
289 '\\.key = value',
290 array(
291 '.key' => 'value',
292 )
293 ),
294 'simple assignment with protected escaped dot at the beginning' => array(
295 '\\\\.key = value',
296 array(
297 '\\.' => array(
298 'key' => 'value',
299 ),
300 )
301 ),
302 'nested assignment' => array(
303 'lib.key = value',
304 array(
305 'lib.' => array(
306 'key' => 'value',
307 ),
308 ),
309 ),
310 'nested assignment with escaped key' => array(
311 'lib\\.key = value',
312 array(
313 'lib.key' => 'value',
314 ),
315 ),
316 'nested assignment with escaped key and escaped dot at the beginning' => array(
317 '\\.lib\\.key = value',
318 array(
319 '.lib.key' => 'value',
320 ),
321 ),
322 'nested assignment with protected escaped key' => array(
323 'lib\\\\.key = value',
324 array(
325 'lib\\.' => array('key' => 'value'),
326 ),
327 ),
328 'nested assignment with protected escaped key and protected escaped dot at the beginning' => array(
329 '\\\\.lib\\\\.key = value',
330 array(
331 '\\.' => array(
332 'lib\\.' => array('key' => 'value'),
333 ),
334 ),
335 ),
336 'assignment with escaped an non escaped keys' => array(
337 'firstkey.secondkey\\.thirdkey.setting = value',
338 array(
339 'firstkey.' => array(
340 'secondkey.thirdkey.' => array(
341 'setting' => 'value'
342 )
343 )
344 )
345 ),
346 'nested structured assignment' => array(
347 'lib {' . LF .
348 'key = value' . LF .
349 '}',
350 array(
351 'lib.' => array(
352 'key' => 'value',
353 ),
354 ),
355 ),
356 'nested structured assignment with escaped key inside' => array(
357 'lib {' . LF .
358 'key\\.nextkey = value' . LF .
359 '}',
360 array(
361 'lib.' => array(
362 'key.nextkey' => 'value',
363 ),
364 ),
365 ),
366 'nested structured assignment with escaped key inside and escaped dots at the beginning' => array(
367 '\\.lib {' . LF .
368 '\\.key\\.nextkey = value' . LF .
369 '}',
370 array(
371 '.lib.' => array(
372 '.key.nextkey' => 'value',
373 ),
374 ),
375 ),
376 'nested structured assignment with protected escaped key inside' => array(
377 'lib {' . LF .
378 'key\\\\.nextkey = value' . LF .
379 '}',
380 array(
381 'lib.' => array(
382 'key\\.' => array('nextkey' => 'value'),
383 ),
384 ),
385 ),
386 'nested structured assignment with protected escaped key inside and protected escaped dots at the beginning' => array(
387 '\\\\.lib {' . LF .
388 '\\\\.key\\\\.nextkey = value' . LF .
389 '}',
390 array(
391 '\\.' => array(
392 'lib.' => array(
393 '\\.' => array(
394 'key\\.' => array('nextkey' => 'value'),
395 ),
396 ),
397 ),
398 ),
399 ),
400 'nested structured assignment with escaped key' => array(
401 'lib\\.anotherkey {' . LF .
402 'key = value' . LF .
403 '}',
404 array(
405 'lib.anotherkey.' => array(
406 'key' => 'value',
407 ),
408 ),
409 ),
410 'nested structured assignment with protected escaped key' => array(
411 'lib\\\\.anotherkey {' . LF .
412 'key = value' . LF .
413 '}',
414 array(
415 'lib\\.' => array(
416 'anotherkey.' => array(
417 'key' => 'value',
418 ),
419 ),
420 ),
421 ),
422 'multiline assignment' => array(
423 'key (' . LF .
424 'first' . LF .
425 'second' . LF .
426 ')',
427 array(
428 'key' => 'first' . LF . 'second',
429 ),
430 ),
431 'multiline assignment with escaped key' => array(
432 'key\\.nextkey (' . LF .
433 'first' . LF .
434 'second' . LF .
435 ')',
436 array(
437 'key.nextkey' => 'first' . LF . 'second',
438 ),
439 ),
440 'multiline assignment with protected escaped key' => array(
441 'key\\\\.nextkey (' . LF .
442 'first' . LF .
443 'second' . LF .
444 ')',
445 array(
446 'key\\.' => array('nextkey' => 'first' . LF . 'second'),
447 ),
448 ),
449 'copying values' => array(
450 'lib.default = value' . LF .
451 'lib.copy < lib.default',
452 array(
453 'lib.' => array(
454 'default' => 'value',
455 'copy' => 'value',
456 ),
457 ),
458 ),
459 'copying values with escaped key' => array(
460 'lib\\.default = value' . LF .
461 'lib.copy < lib\\.default',
462 array(
463 'lib.default' => 'value',
464 'lib.' => array(
465 'copy' => 'value',
466 ),
467 ),
468 ),
469 'copying values with protected escaped key' => array(
470 'lib\\\\.default = value' . LF .
471 'lib.copy < lib\\\\.default',
472 array(
473 'lib\\.' => array('default' => 'value'),
474 'lib.' => array(
475 'copy' => 'value',
476 ),
477 ),
478 ),
479 'one-line hash comment' => array(
480 'first = 1' . LF .
481 '# ignore = me' . LF .
482 'second = 2',
483 array(
484 'first' => '1',
485 'second' => '2',
486 ),
487 ),
488 'one-line slash comment' => array(
489 'first = 1' . LF .
490 '// ignore = me' . LF .
491 'second = 2',
492 array(
493 'first' => '1',
494 'second' => '2',
495 ),
496 ),
497 'multi-line slash comment' => array(
498 'first = 1' . LF .
499 '/*' . LF .
500 'ignore = me' . LF .
501 '*/' . LF .
502 'second = 2',
503 array(
504 'first' => '1',
505 'second' => '2',
506 ),
507 ),
508 'nested assignment repeated segment names' => array(
509 'test.test.test = 1',
510 array(
511 'test.' => array(
512 'test.' => array(
513 'test' => '1',
514 ),
515 )
516 ),
517 ),
518 'simple assignment operator with tab character before "="' => array(
519 'test = someValue',
520 array(
521 'test' => 'someValue',
522 ),
523 ),
524 'simple assignment operator character as value "="' => array(
525 'test ==TEST=',
526 array(
527 'test' => '=TEST=',
528 ),
529 ),
530 'nested assignment operator character as value "="' => array(
531 'test.test ==TEST=',
532 array(
533 'test.' => array(
534 'test' => '=TEST=',
535 ),
536 ),
537 ),
538 'simple assignment character as value "<"' => array(
539 'test =<TEST>',
540 array(
541 'test' => '<TEST>',
542 ),
543 ),
544 'nested assignment character as value "<"' => array(
545 'test.test =<TEST>',
546 array(
547 'test.' => array(
548 'test' => '<TEST>',
549 ),
550 ),
551 ),
552 'simple assignment character as value ">"' => array(
553 'test =>TEST<',
554 array(
555 'test' => '>TEST<',
556 ),
557 ),
558 'nested assignment character as value ">"' => array(
559 'test.test =>TEST<',
560 array(
561 'test.' => array(
562 'test' => '>TEST<',
563 ),
564 ),
565 ),
566 'nested assignment repeated segment names with whitespaces' => array(
567 'test.test.test = 1' . " \t",
568 array(
569 'test.' => array(
570 'test.' => array(
571 'test' => '1',
572 ),
573 )
574 ),
575 ),
576 'simple assignment operator character as value "=" with whitespaces' => array(
577 'test = =TEST=' . " \t",
578 array(
579 'test' => '=TEST=',
580 ),
581 ),
582 'nested assignment operator character as value "=" with whitespaces' => array(
583 'test.test = =TEST=' . " \t",
584 array(
585 'test.' => array(
586 'test' => '=TEST=',
587 ),
588 ),
589 ),
590 'simple assignment character as value "<" with whitespaces' => array(
591 'test = <TEST>' . " \t",
592 array(
593 'test' => '<TEST>',
594 ),
595 ),
596 'nested assignment character as value "<" with whitespaces' => array(
597 'test.test = <TEST>' . " \t",
598 array(
599 'test.' => array(
600 'test' => '<TEST>',
601 ),
602 ),
603 ),
604 'simple assignment character as value ">" with whitespaces' => array(
605 'test = >TEST<' . " \t",
606 array(
607 'test' => '>TEST<',
608 ),
609 ),
610 'nested assignment character as value ">" with whitespaces' => array(
611 'test.test = >TEST<',
612 array(
613 'test.' => array(
614 'test' => '>TEST<',
615 ),
616 ),
617 ),
618 'CSC example #1' => array(
619 'linkParams.ATagParams.dataWrap = class="{$styles.content.imgtext.linkWrap.lightboxCssClass}" rel="{$styles.content.imgtext.linkWrap.lightboxRelAttribute}"',
620 array(
621 'linkParams.' => array(
622 'ATagParams.' => array(
623 'dataWrap' => 'class="{$styles.content.imgtext.linkWrap.lightboxCssClass}" rel="{$styles.content.imgtext.linkWrap.lightboxRelAttribute}"',
624 ),
625 ),
626 ),
627 ),
628 'CSC example #2' => array(
629 'linkParams.ATagParams {' . LF .
630 'dataWrap = class="{$styles.content.imgtext.linkWrap.lightboxCssClass}" rel="{$styles.content.imgtext.linkWrap.lightboxRelAttribute}"' . LF .
631 '}',
632 array(
633 'linkParams.' => array(
634 'ATagParams.' => array(
635 'dataWrap' => 'class="{$styles.content.imgtext.linkWrap.lightboxCssClass}" rel="{$styles.content.imgtext.linkWrap.lightboxRelAttribute}"',
636 ),
637 ),
638 ),
639 ),
640 'CSC example #3' => array(
641 'linkParams.ATagParams.dataWrap (' . LF .
642 'class="{$styles.content.imgtext.linkWrap.lightboxCssClass}" rel="{$styles.content.imgtext.linkWrap.lightboxRelAttribute}"' . LF .
643 ')',
644 array(
645 'linkParams.' => array(
646 'ATagParams.' => array(
647 'dataWrap' => 'class="{$styles.content.imgtext.linkWrap.lightboxCssClass}" rel="{$styles.content.imgtext.linkWrap.lightboxRelAttribute}"',
648 ),
649 ),
650 ),
651 ),
652 'key with colon' => array(
653 'some:key = is valid',
654 array(
655 'some:key' => 'is valid'
656 )
657 ),
658 'special operator' => array(
659 'some := addToList(a)',
660 array(
661 'some' => 'a'
662 )
663 ),
664 'special operator with white-spaces' => array(
665 'some := addToList (a)',
666 array(
667 'some' => 'a'
668 )
669 ),
670 'special operator with tabs' => array(
671 'some := addToList (a)',
672 array(
673 'some' => 'a'
674 )
675 ),
676 'special operator with white-spaces and tabs in value' => array(
677 'some := addToList( a, b, c )',
678 array(
679 'some' => 'a, b, c'
680 )
681 ),
682 'special operator and colon, no spaces' => array(
683 'some:key:=addToList(a)',
684 array(
685 'some:key' => 'a'
686 )
687 ),
688 'key with all special symbols' => array(
689 'someSpecial\\_:-\\.Chars = is valid',
690 array(
691 'someSpecial\\_:-.Chars' => 'is valid'
692 )
693 ),
694 );
695 }
696
697 /**
698 * @test
699 */
700 public function setValCanBeCalledWithArrayValueParameter()
701 {
702 $string = '';
703 $setup = array();
704 $value = array();
705 $this->typoScriptParser->setVal($string, $setup, $value);
706 }
707
708 /**
709 * @test
710 */
711 public function setValCanBeCalledWithStringValueParameter()
712 {
713 $string = '';
714 $setup = array();
715 $value = '';
716 $this->typoScriptParser->setVal($string, $setup, $value);
717 }
718
719 /**
720 * @test
721 * @dataProvider parseNextKeySegmentReturnsCorrectNextKeySegmentDataProvider
722 */
723 public function parseNextKeySegmentReturnsCorrectNextKeySegment($key, $expectedKeySegment, $expectedRemainingKey)
724 {
725 list($keySegment, $remainingKey) = $this->typoScriptParser->_call('parseNextKeySegment', $key);
726 $this->assertSame($expectedKeySegment, $keySegment);
727 $this->assertSame($expectedRemainingKey, $remainingKey);
728 }
729
730 /**
731 * @return array
732 */
733 public function parseNextKeySegmentReturnsCorrectNextKeySegmentDataProvider()
734 {
735 return array(
736 'key without separator' => array(
737 'testkey',
738 'testkey',
739 ''
740 ),
741 'key with normal separator' => array(
742 'test.key',
743 'test',
744 'key'
745 ),
746 'key with multiple normal separators' => array(
747 'test.key.subkey',
748 'test',
749 'key.subkey'
750 ),
751 'key with separator and escape character' => array(
752 'te\\st.test',
753 'te\\st',
754 'test'
755 ),
756 'key with escaped separators' => array(
757 'test\\.key\\.subkey',
758 'test.key.subkey',
759 ''
760 ),
761 'key with escaped and unescaped separator 1' => array(
762 'test.test\\.key',
763 'test',
764 'test\\.key'
765 ),
766 'key with escaped and unescaped separator 2' => array(
767 'test\\.test.key\\.key2',
768 'test.test',
769 'key\\.key2'
770 ),
771 'key with escaped escape character' => array(
772 'test\\\\.key',
773 'test\\',
774 'key'
775 ),
776 'key with escaped separator and additional escape character' => array(
777 'test\\\\\\.key',
778 'test\\\\',
779 'key'
780 ),
781
782 'multiple escape characters within the key are preserved' => array(
783 'te\\\\st\\\\.key',
784 'te\\\\st\\',
785 'key'
786 )
787 );
788 }
789 }