[TASK] Move all marker-based logic from cObj to MarkerBasedTemplateService
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Service / MarkerBasedTemplateServiceTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Service;
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 use Prophecy\Argument;
18 use Prophecy\Prophecy\ObjectProphecy;
19 use TYPO3\CMS\Core\Cache\CacheManager;
20 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
21 use TYPO3\CMS\Core\Service\MarkerBasedTemplateService;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23
24 /**
25 * Unit test for marker utility
26 */
27 class MarkerBasedTemplateServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
28 {
29 /**
30 * @var MarkerBasedTemplateService
31 */
32 protected $templateService;
33
34 /**
35 * @var array A backup of registered singleton instances
36 */
37 protected $singletonInstances = [];
38
39 protected function setUp()
40 {
41 $this->singletonInstances = GeneralUtility::getSingletonInstances();
42
43 /** @var CacheManager|ObjectProphecy $cacheManagerProphecy */
44 $cacheManagerProphecy = $this->prophesize(CacheManager::class);
45 GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
46 $cacheFrontendProphecy = $this->prophesize(FrontendInterface::class);
47 $cacheManagerProphecy->getCache(Argument::cetera())->willReturn($cacheFrontendProphecy->reveal());
48
49 $this->templateService = new MarkerBasedTemplateService();
50 }
51
52 protected function tearDown()
53 {
54 GeneralUtility::purgeInstances();
55 GeneralUtility::resetSingletonInstances($this->singletonInstances);
56 parent::tearDown();
57 }
58
59 /**
60 * Data provider for getSubpart
61 *
62 * @return array
63 */
64 public function getSubpartDataProvider()
65 {
66 return [
67 'No start marker' => [
68 '<body>text</body>',
69 '###SUBPART###',
70 ''
71 ],
72 'No stop marker' => [
73 '<body>
74 <!-- ###SUBPART### Start -->
75 text
76 </body>',
77 '###SUBPART###',
78 ''
79 ],
80 'Start and stop marker in HTML comment' => [
81 '<body>
82 <!-- ###SUBPART### Start -->
83 text
84 <!-- ###SUBPART### End -->
85 </body>',
86 '###SUBPART###',
87 '
88 text
89 '
90 ],
91 'Stop marker in HTML comment' => [
92 '<body>
93 ###SUBPART###
94 text
95 <!-- ###SUBPART### End -->
96 </body>',
97 '###SUBPART###',
98 '
99 text
100 '
101 ],
102 'Start marker in HTML comment' => [
103 '<body>
104 <!-- ###SUBPART### Start -->
105 text
106 ###SUBPART###
107 </body>',
108 '###SUBPART###',
109 '
110 text
111 '
112 ],
113 'Start and stop marker direct' => [
114 '<body>
115 ###SUBPART###
116 text
117 ###SUBPART###
118 </body>',
119 '###SUBPART###',
120 '
121 text
122 '
123 ],
124 ];
125 }
126
127 /**
128 * @test
129 * @param string $content
130 * @param string $marker
131 * @param string $expected
132 * @dataProvider getSubpartDataProvider
133 */
134 public function getSubpart($content, $marker, $expected)
135 {
136 $this->assertSame($expected, $this->templateService->getSubpart($content, $marker));
137 }
138
139 /**
140 * Data provider for substituteSubpart
141 *
142 * @return array
143 */
144 public function substituteSubpartDataProvider()
145 {
146 return [
147 'No start marker' => [
148 '<body>text</body>',
149 '###SUBPART###',
150 'hello',
151 false,
152 false,
153 '<body>text</body>'
154 ],
155 'No stop marker' => [
156 '<body>
157 <!-- ###SUBPART### Start -->
158 text
159 </body>',
160 '###SUBPART###',
161 'hello',
162 false,
163 false,
164 '<body>
165 <!-- ###SUBPART### Start -->
166 text
167 </body>',
168 ],
169 'Start and stop marker in HTML comment' => [
170 '<body>
171 <!-- ###SUBPART### Start -->
172 text
173 <!-- ###SUBPART### End -->
174 </body>',
175 '###SUBPART###',
176 'hello',
177 false,
178 false,
179 '<body>
180 hello
181 </body>'
182 ],
183 'Recursive subpart' => [
184 '<body>
185 <!-- ###SUBPART### Start -->text1<!-- ###SUBPART### End -->
186 <!-- ###SUBPART### Start -->text2<!-- ###SUBPART### End -->
187 </body>',
188 '###SUBPART###',
189 'hello',
190 true,
191 false,
192 '<body>
193 hello
194 hello
195 </body>'
196 ],
197 'Keep HTML marker' => [
198 '<body>
199 <!-- ###SUBPART### Start -->text<!-- ###SUBPART### End -->
200 </body>',
201 '###SUBPART###',
202 'hello',
203 false,
204 true,
205 '<body>
206 <!-- ###SUBPART### Start -->hello<!-- ###SUBPART### End -->
207 </body>'
208 ],
209 'Keep HTML begin marker' => [
210 '<body>
211 <!-- ###SUBPART### Start -->text###SUBPART###
212 </body>',
213 '###SUBPART###',
214 'hello',
215 false,
216 true,
217 '<body>
218 <!-- ###SUBPART### Start -->hello###SUBPART###
219 </body>'
220 ],
221 'Keep HTML end marker' => [
222 '<body>
223 ###SUBPART###text<!-- ###SUBPART### End -->
224 </body>',
225 '###SUBPART###',
226 'hello',
227 false,
228 true,
229 '<body>
230 ###SUBPART###hello<!-- ###SUBPART### End -->
231 </body>'
232 ],
233 'Keep plain marker' => [
234 '<body>
235 ###SUBPART###text###SUBPART###
236 </body>',
237 '###SUBPART###',
238 'hello',
239 false,
240 true,
241 '<body>
242 ###SUBPART###hello###SUBPART###
243 </body>'
244 ],
245 'Wrap around' => [
246 '<body>
247 ###SUBPART###text###SUBPART###
248 </body>',
249 '###SUBPART###',
250 ['before-', '-after'],
251 false,
252 true,
253 '<body>
254 ###SUBPART###before-text-after###SUBPART###
255 </body>'
256 ],
257 ];
258 }
259
260 /**
261 * @test
262 * @param string $content
263 * @param string $marker
264 * @param array $subpartContent
265 * @param bool $recursive
266 * @param bool $keepMarker
267 * @param string $expected
268 * @dataProvider substituteSubpartDataProvider
269 */
270 public function substituteSubpart($content, $marker, $subpartContent, $recursive, $keepMarker, $expected)
271 {
272 $this->assertSame($expected, $this->templateService->substituteSubpart($content, $marker, $subpartContent, $recursive, $keepMarker));
273 }
274
275 /**
276 * Data provider for substituteMarkerArray
277 */
278 public function substituteMarkerArrayDataProvider()
279 {
280 return [
281 'Upper case marker' => [
282 'This is ###MARKER1### and this is ###MARKER2###',
283 ['###MARKER1###' => 'marker 1',
284 '###MARKER2###' => 'marker 2'],
285 '',
286 false,
287 false,
288 'This is marker 1 and this is marker 2'
289 ],
290 'Lower case marker' => [
291 'This is ###MARKER1### and this is ###MARKER2###',
292 ['###marker1###' => 'marker 1',
293 '###marker2###' => 'marker 2'],
294 '',
295 true,
296 false,
297 'This is marker 1 and this is marker 2'
298 ],
299 'Upper case marker without hash mark' => [
300 'This is ###MARKER1### and this is ###MARKER2###',
301 ['MARKER1' => 'marker 1',
302 'MARKER2' => 'marker 2'],
303 '###|###',
304 false,
305 false,
306 'This is marker 1 and this is marker 2'
307 ],
308 'Upper case marker with another hash mark' => [
309 'This is *MARKER1* and this is *MARKER2*',
310 ['MARKER1' => 'marker 1',
311 'MARKER2' => 'marker 2'],
312 '*|*',
313 false,
314 false,
315 'This is marker 1 and this is marker 2'
316 ],
317 'Upper case marker with unused marker' => [
318 'This is ###MARKER1### and this is ###MARKER2### ###UNUSED###',
319 ['###MARKER1###' => 'marker 1',
320 '###MARKER2###' => 'marker 2'],
321 '',
322 false,
323 false,
324 'This is marker 1 and this is marker 2 ###UNUSED###'
325 ],
326 'Upper case marker with unused marker deleted' => [
327 'This is ###MARKER1### and this is ###MARKER2### ###UNUSED###',
328 ['###MARKER1###' => 'marker 1',
329 '###MARKER2###' => 'marker 2'],
330 '',
331 false,
332 true,
333 'This is marker 1 and this is marker 2 '
334 ],
335 ];
336 }
337
338 /**
339 * @test
340 * @dataProvider substituteMarkerArrayDataProvider
341 * @param string $content The content stream, typically HTML template content.
342 * @param array $markContentArray The array of key/value pairs being marker/content values used in the substitution. For each element in this array the function will substitute a marker in the content stream with the content.
343 * @param string $wrap A wrap value - [part 1] | [part 2] - for the markers before substitution
344 * @param bool $uppercase If set, all marker string substitution is done with upper-case markers.
345 * @param bool $deleteUnused If set, all unused marker are deleted.
346 * @param string $expected
347 */
348 public function substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused, $expected)
349 {
350 $this->assertSame($expected, $this->templateService->substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused));
351 }
352
353 /**
354 * Data provider for substituteMarker
355 */
356 public function substituteMarkerDataProvider()
357 {
358 return [
359 'Single marker' => [
360 'This is a ###SAMPLE### text',
361 '###SAMPLE###',
362 'simple',
363 'This is a simple text'
364 ],
365 'Double marker' => [
366 'This is a ###SAMPLE### text with a ###SAMPLE### content',
367 '###SAMPLE###',
368 'simple',
369 'This is a simple text with a simple content'
370 ],
371 ];
372 }
373
374 /**
375 * @dataProvider substituteMarkerDataProvider
376 * @param string $content The content stream, typically HTML template content.
377 * @param string $marker The marker string, typically on the form "###[the marker string]###
378 * @param mixed $markContent The content to insert instead of the marker string found.
379 * @param string $expected The expected result of the substitution
380 */
381 public function substituteMarker($content, $marker, $markContent, $expected)
382 {
383 $this->assertSame($expected, $this->templateService->substituteMarker($content, $marker, $markContent));
384 }
385
386 /**
387 * Data provider for substituteSubpartArray
388 *
389 * @return array
390 */
391 public function substituteSubpartArrayDataProvider()
392 {
393 return [
394 'Substitute multiple subparts at once with plain marker' => [
395 '<body>
396 ###SUBPART1###text1###SUBPART1###
397 ###SUBPART2###text2###SUBPART2###
398 </body>',
399 ['###SUBPART1###' => 'hello',
400 '###SUBPART2###' => 'world'],
401 '<body>
402 hello
403 world
404 </body>'
405 ],
406 ];
407 }
408
409 /**
410 * @test
411 * @param string $content
412 * @param array $subpartsContent
413 * @param string $expected
414 * @dataProvider substituteSubpartArrayDataProvider
415 */
416 public function substituteSubpartArray($content, array $subpartsContent, $expected)
417 {
418 $this->assertSame($expected, $this->templateService->substituteSubpartArray($content, $subpartsContent));
419 }
420
421 /**
422 * Data provider for substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArray
423 *
424 * @return array
425 */
426 public function substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArrayDataProvider()
427 {
428 $template = '###SINGLEMARKER1###
429 <!-- ###FOO### begin -->
430 <!-- ###BAR### begin -->
431 ###SINGLEMARKER2###
432 <!-- ###BAR### end -->
433 <!-- ###FOOTER### begin -->
434 ###SINGLEMARKER3###
435 <!-- ###FOOTER### end -->
436 <!-- ###FOO### end -->';
437
438 $expected ='Value 1
439
440
441 Value 2.1
442
443 Value 2.2
444
445
446 Value 3.1
447
448 Value 3.2
449
450 ';
451
452 return [
453 'Single marker' => [
454 '###SINGLEMARKER###',
455 [
456 '###SINGLEMARKER###' => 'Value 1'
457 ],
458 '',
459 false,
460 false,
461 'Value 1'
462 ],
463 'Subpart marker' => [
464 $template,
465 [
466 '###SINGLEMARKER1###' => 'Value 1',
467 '###FOO###' => [
468 [
469 '###BAR###' => [
470 [
471 '###SINGLEMARKER2###' => 'Value 2.1'
472 ],
473 [
474 '###SINGLEMARKER2###' => 'Value 2.2'
475 ]
476 ],
477 '###FOOTER###' => [
478 [
479 '###SINGLEMARKER3###' => 'Value 3.1'
480 ],
481 [
482 '###SINGLEMARKER3###' => 'Value 3.2'
483 ]
484 ]
485 ]
486 ]
487 ],
488 '',
489 false,
490 false,
491 $expected
492 ],
493 'Subpart marker with wrap' => [
494 $template,
495 [
496 'SINGLEMARKER1' => 'Value 1',
497 'FOO' => [
498 [
499 'BAR' => [
500 [
501 'SINGLEMARKER2' => 'Value 2.1'
502 ],
503 [
504 'SINGLEMARKER2' => 'Value 2.2'
505 ]
506 ],
507 'FOOTER' => [
508 [
509 'SINGLEMARKER3' => 'Value 3.1'
510 ],
511 [
512 'SINGLEMARKER3' => 'Value 3.2'
513 ]
514 ]
515 ]
516 ]
517 ],
518 '###|###',
519 false,
520 false,
521 $expected
522 ],
523 'Subpart marker with lower marker array keys' => [
524 $template,
525 [
526 '###singlemarker1###' => 'Value 1',
527 '###foo###' => [
528 [
529 '###bar###' => [
530 [
531 '###singlemarker2###' => 'Value 2.1'
532 ],
533 [
534 '###singlemarker2###' => 'Value 2.2'
535 ]
536 ],
537 '###footer###' => [
538 [
539 '###singlemarker3###' => 'Value 3.1'
540 ],
541 [
542 '###singlemarker3###' => 'Value 3.2'
543 ]
544 ]
545 ]
546 ]
547 ],
548 '',
549 true,
550 false,
551 $expected
552 ],
553 'Subpart marker with unused markers' => [
554 $template,
555 [
556 '###FOO###' => [
557 [
558 '###BAR###' => [
559 [
560 '###SINGLEMARKER2###' => 'Value 2.1'
561 ]
562 ],
563 '###FOOTER###' => [
564 [
565 '###SINGLEMARKER3###' => 'Value 3.1'
566 ]
567 ]
568 ]
569 ]
570 ],
571 '',
572 false,
573 true,
574 '
575
576
577 Value 2.1
578
579
580 Value 3.1
581
582 '
583 ],
584 'Subpart marker with empty subpart' => [
585 $template,
586 [
587 '###SINGLEMARKER1###' => 'Value 1',
588 '###FOO###' => [
589 [
590 '###BAR###' => [
591 [
592 '###SINGLEMARKER2###' => 'Value 2.1'
593 ],
594 [
595 '###SINGLEMARKER2###' => 'Value 2.2'
596 ]
597 ],
598 '###FOOTER###' => []
599 ]
600 ]
601 ],
602 '',
603 false,
604 false,
605 'Value 1
606
607
608 Value 2.1
609
610 Value 2.2
611
612
613 '
614 ]
615 ];
616 }
617
618 /**
619 * @test
620 * @param string $template
621 * @param array $markersAndSubparts
622 * @param string $wrap
623 * @param bool $uppercase
624 * @param bool $deleteUnused
625 * @param string $expected
626 * @dataProvider substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArrayDataProvider
627 */
628 public function substituteMarkerAndSubpartArrayRecursiveResolvesMarkersAndSubpartsArray($template, $markersAndSubparts, $wrap, $uppercase, $deleteUnused, $expected)
629 {
630 $this->assertSame($expected, $this->templateService->substituteMarkerAndSubpartArrayRecursive($template, $markersAndSubparts, $wrap, $uppercase, $deleteUnused));
631 }
632
633 /**
634 * @return array
635 */
636 public function substituteMarkerArrayCachedReturnsExpectedContentDataProvider()
637 {
638 return [
639 'no markers defined' => [
640 'dummy content with ###UNREPLACED### marker',
641 [],
642 [],
643 [],
644 'dummy content with ###UNREPLACED### marker',
645 ],
646 'no markers used' => [
647 'dummy content with no marker',
648 [
649 '###REPLACED###' => '_replaced_'
650 ],
651 [],
652 [],
653 'dummy content with no marker',
654 ],
655 'one marker' => [
656 'dummy content with ###REPLACED### marker',
657 [
658 '###REPLACED###' => '_replaced_'
659 ],
660 [],
661 [],
662 'dummy content with _replaced_ marker'
663 ],
664 'one marker with lots of chars' => [
665 'dummy content with ###RE.:##-=_()LACED### marker',
666 [
667 '###RE.:##-=_()LACED###' => '_replaced_'
668 ],
669 [],
670 [],
671 'dummy content with _replaced_ marker'
672 ],
673 'markers which are special' => [
674 'dummy ###aa##.#######A### ######',
675 [
676 '###aa##.###' => 'content ',
677 '###A###' => 'is',
678 '######' => '-is not considered-'
679 ],
680 [],
681 [],
682 'dummy content #is ######'
683 ],
684 'two markers in content, but more defined' => [
685 'dummy ###CONTENT### with ###REPLACED### marker',
686 [
687 '###REPLACED###' => '_replaced_',
688 '###CONTENT###' => 'content',
689 '###NEVERUSED###' => 'bar'
690 ],
691 [],
692 [],
693 'dummy content with _replaced_ marker'
694 ],
695 'one subpart' => [
696 'dummy content with ###ASUBPART### around some text###ASUBPART###.',
697 [],
698 [
699 '###ASUBPART###' => 'some other text'
700 ],
701 [],
702 'dummy content with some other text.'
703 ],
704 'one wrapped subpart' => [
705 'dummy content with ###AWRAPPEDSUBPART### around some text###AWRAPPEDSUBPART###.',
706 [],
707 [],
708 [
709 '###AWRAPPEDSUBPART###' => [
710 'more content',
711 'content'
712 ]
713 ],
714 'dummy content with more content around some textcontent.'
715 ],
716 'one subpart with markers, not replaced recursively' => [
717 'dummy ###CONTENT### with ###ASUBPART### around ###SOME### text###ASUBPART###.',
718 [
719 '###CONTENT###' => 'content',
720 '###SOME###' => '-this should never make it into output-',
721 '###OTHER_NOT_REPLACED###' => '-this should never make it into output-'
722 ],
723 [
724 '###ASUBPART###' => 'some ###OTHER_NOT_REPLACED### text'
725 ],
726 [],
727 'dummy content with some ###OTHER_NOT_REPLACED### text.'
728 ],
729 ];
730 }
731
732 /**
733 * @test
734 * @dataProvider substituteMarkerArrayCachedReturnsExpectedContentDataProvider
735 *
736 * @param string $content
737 * @param array $markContentArray
738 * @param array $subpartContentArray
739 * @param array $wrappedSubpartContentArray
740 * @param string $expectedContent
741 * @param bool $shouldQueryCache
742 * @param bool $shouldStoreCache
743 */
744 public function substituteMarkerArrayCachedReturnsExpectedContent($content, array $markContentArray, array $subpartContentArray, array $wrappedSubpartContentArray, $expectedContent)
745 {
746 $resultContent = $this->templateService->substituteMarkerArrayCached($content, $markContentArray, $subpartContentArray, $wrappedSubpartContentArray);
747 $this->assertSame($expectedContent, $resultContent);
748 }
749 }