06a8494c6823ab62b25ed8a9f236e10a604798e7
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / UnitDeprecated / Configuration / TypoScript / ConditionMatching / ConditionMatcherTest.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Frontend\Tests\UnitDeprecated\Configuration\TypoScript\ConditionMatching;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Prophecy\Argument;
19 use TYPO3\CMS\Core\Configuration\TypoScript\Exception\InvalidTypoScriptConditionException;
20 use TYPO3\CMS\Core\Context\Context;
21 use TYPO3\CMS\Core\Context\UserAspect;
22 use TYPO3\CMS\Core\Http\ServerRequest;
23 use TYPO3\CMS\Core\Log\Logger;
24 use TYPO3\CMS\Core\Site\Entity\Site;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26 use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
27 use TYPO3\CMS\Frontend\Configuration\TypoScript\ConditionMatching\ConditionMatcher;
28 use TYPO3\CMS\Frontend\Tests\UnitDeprecated\Configuration\TypoScript\ConditionMatching\Fixtures\TestConditionException;
29 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
30
31 /**
32 * Test case
33 */
34 class ConditionMatcherTest extends UnitTestCase
35 {
36 /**
37 * @var ConditionMatcher
38 */
39 protected $subject;
40
41 /**
42 * @var string
43 */
44 protected $testGlobalNamespace;
45
46 /**
47 * @var bool Reset singletons
48 */
49 protected $resetSingletonInstances = true;
50
51 protected function setUp(): void
52 {
53 $GLOBALS['TYPO3_REQUEST'] = new ServerRequest();
54
55 $this->testGlobalNamespace = $this->getUniqueId('TEST');
56 $GLOBALS[$this->testGlobalNamespace] = [];
57 $GLOBALS['TSFE'] = new \stdClass();
58 $GLOBALS['TSFE']->page = [];
59 $GLOBALS['TSFE']->tmpl = new \stdClass();
60 $GLOBALS['TSFE']->tmpl->rootLine = [
61 2 => ['uid' => 121, 'pid' => 111],
62 1 => ['uid' => 111, 'pid' => 101],
63 0 => ['uid' => 101, 'pid' => 0]
64 ];
65
66 $frontedUserAuthentication = $this->getMockBuilder(FrontendUserAuthentication::class)
67 ->setMethods(['dummy'])
68 ->getMock();
69
70 $frontedUserAuthentication->user['uid'] = 13;
71 $frontedUserAuthentication->groupData['uid'] = [14];
72 $GLOBALS['TSFE']->fe_user = $frontedUserAuthentication;
73 $this->getFreshConditionMatcher();
74 }
75
76 protected function getFreshConditionMatcher()
77 {
78 $this->subject = new ConditionMatcher(new Context([
79 'frontend.user' => new UserAspect($GLOBALS['TSFE']->fe_user)
80 ]));
81 $this->subject->setLogger($this->prophesize(Logger::class)->reveal());
82 }
83
84 /**
85 * Tests whether a faulty expression fails.
86 *
87 * @test
88 */
89 public function simulateDisabledMatchAllConditionsFailsOnFaultyExpression(): void
90 {
91 $this->getFreshConditionMatcher();
92 $this->assertFalse($this->subject->match('[nullCondition = This expression would return FALSE in general]'));
93 }
94
95 /**
96 * Tests whether simulating positive matches for all conditions succeeds.
97 *
98 * @test
99 */
100 public function simulateEnabledMatchAllConditionsSucceeds(): void
101 {
102 $this->getFreshConditionMatcher();
103 $this->subject->setSimulateMatchResult(true);
104 $this->assertTrue($this->subject->match('[nullCondition = This expression would return FALSE in general]'));
105 }
106
107 /**
108 * Tests whether simulating positive matches for specific conditions succeeds.
109 *
110 * @test
111 */
112 public function simulateEnabledMatchSpecificConditionsSucceeds(): void
113 {
114 $this->getFreshConditionMatcher();
115 $testCondition = '[' . $this->getUniqueId('test') . ' = Any condition to simulate a positive match]';
116 $this->subject->setSimulateMatchConditions([$testCondition]);
117 $this->assertTrue($this->subject->match($testCondition));
118 }
119
120 /**
121 * Tests whether the language comparison matches.
122 *
123 * @test
124 */
125 public function languageConditionMatchesSingleLanguageExpression(): void
126 {
127 $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3';
128 $this->getFreshConditionMatcher();
129 $this->assertTrue($this->subject->match('[language = *de*]'));
130 $this->assertTrue($this->subject->match('[language = *de-de*]'));
131 // Test expression language
132 // @TODO: not work yet, looks like test setup issue
133 // $this->assertTrue($this->subject->match('[like(request.getNormalizedParams().getHttpAcceptLanguage(), "**de*")]'));
134 // $this->assertTrue($this->subject->match('[like(request.getNormalizedParams().getHttpAcceptLanguage(), "**de-de*")]'));
135 }
136
137 /**
138 * Tests whether the language comparison matches.
139 *
140 * @test
141 */
142 public function languageConditionMatchesMultipleLanguagesExpression(): void
143 {
144 $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3';
145 $this->getFreshConditionMatcher();
146 $this->assertTrue($this->subject->match('[language = *en*,*de*]'));
147 $this->assertTrue($this->subject->match('[language = *en-us*,*de-de*]'));
148 // Test expression language
149 // @TODO: not work yet, looks like test setup issue
150 // $this->assertTrue($this->subject->match('[like(request.getNormalizedParams().getHttpAcceptLanguage(), "*en*,*de*")]'));
151 // $this->assertTrue($this->subject->match('[like(request.getNormalizedParams().getHttpAcceptLanguage(), "*en-us*,*de-de*")]'));
152 }
153
154 /**
155 * Tests whether the language comparison matches.
156 *
157 * @test
158 */
159 public function languageConditionMatchesCompleteLanguagesExpression(): void
160 {
161 $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3';
162 $this->getFreshConditionMatcher();
163 $this->assertTrue($this->subject->match('[language = de-de,de;q=0.8,en-us;q=0.5,en;q=0.3]'));
164 // Test expression language
165 // @TODO: not work yet, looks like test setup issue
166 // $this->assertTrue($this->subject->match('[request.getNormalizedParams().getHttpAcceptLanguage() == "de-de,de;q=0.8,en-us;q=0.5,en;q=0.3"]'));
167 }
168
169 /**
170 * Tests whether usergroup comparison matches.
171 *
172 * @test
173 */
174 public function usergroupConditionMatchesSingleGroupId(): void
175 {
176 $subject = new ConditionMatcher(new Context([
177 'frontend.user' => new UserAspect(new FrontendUserAuthentication(), [13, 14, 15])
178 ]));
179 $loggerProphecy = $this->prophesize(Logger::class);
180 $subject->setLogger($loggerProphecy->reveal());
181 $this->assertTrue($subject->match('[usergroup = 13]'));
182 // Test expression language
183 $this->assertTrue($subject->match('[usergroup(13)]'));
184 $this->assertTrue($subject->match('[usergroup("13")]'));
185 $this->assertTrue($subject->match('[usergroup(\'13\')]'));
186 }
187
188 /**
189 * Tests whether usergroup comparison matches.
190 *
191 * @test
192 */
193 public function usergroupConditionMatchesMultipleUserGroupId(): void
194 {
195 $subject = new ConditionMatcher(new Context([
196 'frontend.user' => new UserAspect(new FrontendUserAuthentication(), [13, 14, 15])
197 ]));
198 $loggerProphecy = $this->prophesize(Logger::class);
199 $subject->setLogger($loggerProphecy->reveal());
200 $this->assertTrue($subject->match('[usergroup = 999,15,14,13]'));
201 // Test expression language
202 $this->assertFalse($subject->match('[usergroup(999,15,14,13)]'));
203 $this->assertTrue($subject->match('[usergroup("999,15,14,13")]'));
204 $this->assertTrue($subject->match('[usergroup(\'999,15,14,13\')]'));
205 }
206
207 /**
208 * Tests whether usergroup comparison matches.
209 *
210 * @test
211 */
212 public function usergroupConditionDoesNotMatchDefaulUserGroupIds(): void
213 {
214 $subject = new ConditionMatcher(new Context([
215 'frontend.user' => new UserAspect(new FrontendUserAuthentication(), [0, -1])
216 ]));
217 $loggerProphecy = $this->prophesize(Logger::class);
218 $subject->setLogger($loggerProphecy->reveal());
219 $this->assertFalse($subject->match('[usergroup = 0,-1]'));
220 // Test expression language
221 $this->assertFalse($subject->match('[usergroup("0,-1")]'));
222 $this->assertFalse($subject->match('[usergroup(\'0,-1\')]'));
223 }
224
225 /**
226 * Tests whether user comparison matches.
227 *
228 * @test
229 */
230 public function loginUserConditionMatchesAnyLoggedInUser(): void
231 {
232 $this->getFreshConditionMatcher();
233 // @TODO: not work yet, looks like test setup issue
234 $this->assertTrue($this->subject->match('[loginUser = *]'));
235 // Test expression language
236 $this->assertTrue($this->subject->match('[loginUser("*")]'));
237 $this->assertTrue($this->subject->match('[loginUser(\'*\')]'));
238 }
239
240 /**
241 * Tests whether user comparison matches.
242 *
243 * @test
244 */
245 public function loginUserConditionMatchesSingleLoggedInUser(): void
246 {
247 $this->getFreshConditionMatcher();
248 // @TODO: not work yet, looks like test setup issue
249 $this->assertTrue($this->subject->match('[loginUser = 13]'));
250 // Test expression language
251 $this->assertTrue($this->subject->match('[loginUser(13)]'));
252 $this->assertTrue($this->subject->match('[loginUser("13")]'));
253 $this->assertTrue($this->subject->match('[loginUser(\'13\')]'));
254 }
255
256 /**
257 * Tests whether user comparison matches.
258 *
259 * @test
260 */
261 public function loginUserConditionMatchesMultipleLoggedInUsers(): void
262 {
263 $this->getFreshConditionMatcher();
264 // @TODO: not work yet, looks like test setup issue
265 $this->assertTrue($this->subject->match('[loginUser = 999,13]'));
266 // Test expression language
267 $this->assertTrue($this->subject->match('[loginUser("999,13")]'));
268 $this->assertTrue($this->subject->match('[loginUser(\'999,13\')]'));
269 }
270
271 /**
272 * Tests whether user comparison matches.
273 *
274 * @test
275 */
276 public function loginUserConditionDoesNotMatchIfNotUserIsLoggedId(): void
277 {
278 $user = new FrontendUserAuthentication();
279 $user->user['uid'] = 13;
280 $subject = new ConditionMatcher(new Context([
281 'frontend.user' => new UserAspect($user)
282 ]));
283 $loggerProphecy = $this->prophesize(Logger::class);
284 $subject->setLogger($loggerProphecy->reveal());
285 $this->assertFalse($subject->match('[loginUser = *]'));
286 $this->assertFalse($subject->match('[loginUser = 13]'));
287 // Test expression language
288 $this->assertFalse($subject->match('[loginUser("*")]'));
289 $this->assertTrue($subject->match('[loginUser("*") == false]'));
290 $this->assertFalse($subject->match('[loginUser("13")]'));
291 $this->assertFalse($subject->match('[loginUser(\'*\')]'));
292 $this->assertFalse($subject->match('[loginUser(\'13\')]'));
293 }
294
295 /**
296 * Tests whether user is not logged in
297 *
298 * @test
299 */
300 public function loginUserConditionMatchIfUserIsNotLoggedIn(): void
301 {
302 $user = new FrontendUserAuthentication();
303 $subject = new ConditionMatcher(new Context([
304 'frontend.user' => new UserAspect($user)
305 ]));
306 $loggerProphecy = $this->prophesize(Logger::class);
307 $subject->setLogger($loggerProphecy->reveal());
308 $this->assertTrue($subject->match('[loginUser = ]'));
309 // Test expression language
310 $this->assertTrue($subject->match('[loginUser(\'*\') == false]'));
311 $this->assertTrue($subject->match('[loginUser("*") == false]'));
312 }
313
314 /**
315 * Tests whether numerical comparison matches.
316 *
317 * @test
318 */
319 public function globalVarConditionMatchesOnEqualExpression(): void
320 {
321 $this->assertTrue($this->subject->match('[globalVar = LIT:10 = 10]'));
322 $this->assertTrue($this->subject->match('[globalVar = LIT:10.1 = 10.1]'));
323 $this->assertTrue($this->subject->match('[globalVar = LIT:10 == 10]'));
324 $this->assertTrue($this->subject->match('[globalVar = LIT:10.1 == 10.1]'));
325 // Test expression language
326 // Access with LIT is not possible in expression language, because constants available as variable
327 }
328
329 /**
330 * Tests whether numerical comparison matches.
331 *
332 * @test
333 */
334 public function globalVarConditionMatchesOnEqualExpressionWithMultipleValues(): void
335 {
336 $this->assertTrue($this->subject->match('[globalVar = LIT:10 = 10|20|30]'));
337 $this->assertTrue($this->subject->match('[globalVar = LIT:10.1 = 10.1|20.2|30.3]'));
338 $this->assertTrue($this->subject->match('[globalVar = LIT:20 = 10|20|30]'));
339 $this->assertTrue($this->subject->match('[globalVar = LIT:20.2 = 10.1|20.2|30.3]'));
340 $this->assertTrue($this->subject->match('[globalVar = LIT:10 == 10|20|30]'));
341 $this->assertTrue($this->subject->match('[globalVar = LIT:10.1 == 10.1|20.2|30.3]'));
342 $this->assertTrue($this->subject->match('[globalVar = LIT:20 == 10|20|30]'));
343 $this->assertTrue($this->subject->match('[globalVar = LIT:20.2 == 10.1|20.2|30.3]'));
344 // Test expression language
345 // Access with LIT is not possible in expression language, because constants available as variable
346 }
347
348 /**
349 * Tests whether numerical comparison matches.
350 *
351 * @test
352 */
353 public function globalVarConditionMatchesOnNotEqualExpression(): void
354 {
355 $this->assertTrue($this->subject->match('[globalVar = LIT:10 != 20]'));
356 $this->assertTrue($this->subject->match('[globalVar = LIT:10.1 != 10.2]'));
357 // Test expression language
358 // Access with LIT is not possible in expression language, because constants available as variable
359 }
360
361 /**
362 * Tests whether numerical comparison does not match.
363 *
364 * @test
365 */
366 public function globalVarConditionDoesNotMatchOnNotEqualExpression(): void
367 {
368 $this->assertFalse($this->subject->match('[globalVar = LIT:10 != 10]'));
369 // Test expression language
370 // Access with LIT is not possible in expression language, because constants available as variable
371 }
372
373 /**
374 * Tests whether numerical comparison matches.
375 *
376 * @test
377 */
378 public function globalVarConditionMatchesOnNotEqualExpressionWithMultipleValues(): void
379 {
380 $this->assertTrue($this->subject->match('[globalVar = LIT:10 != 20|30]'));
381 $this->assertTrue($this->subject->match('[globalVar = LIT:10.1 != 10.2|20.3]'));
382 // Test expression language
383 // Access with LIT is not possible in expression language, because constants available as variable
384 }
385
386 /**
387 * Tests whether numerical comparison matches.
388 *
389 * @test
390 */
391 public function globalVarConditionMatchesOnLowerThanExpression(): void
392 {
393 $this->assertTrue($this->subject->match('[globalVar = LIT:10 < 20]'));
394 $this->assertTrue($this->subject->match('[globalVar = LIT:10.1 < 10.2]'));
395 // Test expression language
396 // Access with LIT is not possible in expression language, because constants available as variable
397 }
398
399 /**
400 * Tests whether numerical comparison matches.
401 *
402 * @test
403 */
404 public function globalVarConditionMatchesOnLowerThanOrEqualExpression(): void
405 {
406 $this->assertTrue($this->subject->match('[globalVar = LIT:10 <= 10]'));
407 $this->assertTrue($this->subject->match('[globalVar = LIT:10 <= 20]'));
408 $this->assertTrue($this->subject->match('[globalVar = LIT:10.1 <= 10.1]'));
409 $this->assertTrue($this->subject->match('[globalVar = LIT:10.1 <= 10.2]'));
410 // Test expression language
411 // Access with LIT is not possible in expression language, because constants available as variable
412 }
413
414 /**
415 * Tests whether numerical comparison matches.
416 *
417 * @test
418 */
419 public function globalVarConditionMatchesOnGreaterThanExpression(): void
420 {
421 $this->assertTrue($this->subject->match('[globalVar = LIT:20 > 10]'));
422 $this->assertTrue($this->subject->match('[globalVar = LIT:10.2 > 10.1]'));
423 // Test expression language
424 // Access with LIT is not possible in expression language, because constants available as variable
425 }
426
427 /**
428 * Tests whether numerical comparison matches.
429 *
430 * @test
431 */
432 public function globalVarConditionMatchesOnGreaterThanOrEqualExpression(): void
433 {
434 $this->assertTrue($this->subject->match('[globalVar = LIT:10 >= 10]'));
435 $this->assertTrue($this->subject->match('[globalVar = LIT:20 >= 10]'));
436 $this->assertTrue($this->subject->match('[globalVar = LIT:10.1 >= 10.1]'));
437 $this->assertTrue($this->subject->match('[globalVar = LIT:10.2 >= 10.1]'));
438 // Test expression language
439 // Access with LIT is not possible in expression language, because constants available as variable
440 }
441
442 /**
443 * Tests whether numerical comparison matches.
444 *
445 * @test
446 */
447 public function globalVarConditionMatchesOnEmptyExpressionWithNoValueSet(): void
448 {
449 $testKey = $this->getUniqueId('test');
450 $this->assertTrue($this->subject->match('[globalVar = GP:' . $testKey . '=]'));
451 $this->assertTrue($this->subject->match('[globalVar = GP:' . $testKey . ' = ]'));
452 }
453
454 /**
455 * Tests whether numerical comparison matches.
456 *
457 * @test
458 */
459 public function globalVarConditionDoesNotMatchOnEmptyExpressionWithValueSetToZero(): void
460 {
461 $testKey = $this->getUniqueId('test');
462 $_GET = [];
463 $_POST = [$testKey => 0];
464 $this->assertFalse($this->subject->match('[globalVar = GP:' . $testKey . '=]'));
465 $this->assertFalse($this->subject->match('[globalVar = GP:' . $testKey . ' = ]'));
466 }
467
468 /**
469 * Tests whether an array with zero as key matches its value
470 *
471 * @test
472 */
473 public function globalVarConditionMatchesOnArrayExpressionWithZeroAsKey(): void
474 {
475 $testKey = $this->getUniqueId('test');
476 $testValue = '1';
477 $_GET = [];
478 $_POST = [$testKey => ['0' => $testValue]];
479 $this->assertTrue($this->subject->match('[globalVar = GP:' . $testKey . '|0=' . $testValue . ']'));
480 }
481
482 /**
483 * Tests whether string comparison matches.
484 *
485 * @test
486 */
487 public function globalStringConditionMatchesOnEqualExpression(): void
488 {
489 $this->assertTrue($this->subject->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3.Test.Condition]'));
490 $this->assertFalse($this->subject->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3]'));
491 // Test expression language
492 // Access with LIT is not possible in expression language, because constants available as variable
493 }
494
495 /**
496 * Tests whether string comparison matches.
497 *
498 * @test
499 */
500 public function globalStringConditionMatchesOnEmptyExpressionWithValueSetToEmptyString(): void
501 {
502 $testKey = $this->getUniqueId('test');
503 $_GET = [];
504 $_POST = [$testKey => ''];
505 $this->assertTrue($this->subject->match('[globalString = GP:' . $testKey . '=]'));
506 $this->assertTrue($this->subject->match('[globalString = GP:' . $testKey . ' = ]'));
507 }
508
509 /**
510 * Tests whether string comparison matches.
511 *
512 * @test
513 */
514 public function globalStringConditionMatchesOnEmptyLiteralExpressionWithValueSetToEmptyString(): void
515 {
516 $this->assertTrue($this->subject->match('[globalString = LIT:=]'));
517 $this->assertTrue($this->subject->match('[globalString = LIT: = ]'));
518 // Test expression language
519 // Access with LIT is not possible in expression language, because constants available as variable
520 }
521
522 /**
523 * Tests whether string comparison matches.
524 *
525 * @test
526 */
527 public function globalStringConditionMatchesWildcardExpression(): void
528 {
529 $this->assertTrue($this->subject->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3?Test?Condition]'));
530 $this->assertTrue($this->subject->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3.T*t.Condition]'));
531 $this->assertTrue($this->subject->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3?T*t?Condition]'));
532 // Test expression language
533 // Access with LIT is not possible in expression language, because constants available as variable
534 }
535
536 /**
537 * Tests whether string comparison matches.
538 *
539 * @test
540 */
541 public function globalStringConditionMatchesRegularExpression(): void
542 {
543 $this->assertTrue($this->subject->match('[globalString = LIT:TYPO3.Test.Condition = /^[A-Za-z3.]+$/]'));
544 $this->assertTrue($this->subject->match('[globalString = LIT:TYPO3.Test.Condition = /^TYPO3\\..+Condition$/]'));
545 $this->assertFalse($this->subject->match('[globalString = LIT:TYPO3.Test.Condition = /^FALSE/]'));
546 // Test expression language
547 // Access with LIT is not possible in expression language, because constants available as variable
548 }
549
550 /**
551 * Tests whether string comparison matches.
552 *
553 * @test
554 */
555 public function globalStringConditionMatchesEmptyRegularExpression(): void
556 {
557 $testKey = $this->getUniqueId('test');
558 $GLOBALS['_SERVER'][$testKey] = '';
559 $this->assertTrue($this->subject->match('[globalString = _SERVER|' . $testKey . ' = /^$/]'));
560 // Test expression language
561 // Access request by request() method
562 }
563
564 /**
565 * Tests whether treeLevel comparison matches.
566 *
567 * @test
568 */
569 public function treeLevelConditionMatchesSingleValue(): void
570 {
571 $this->assertTrue($this->subject->match('[treeLevel = 2]'));
572 // Test expression language
573 $this->assertTrue($this->subject->match('[tree.level == 2]'));
574 }
575
576 /**
577 * Tests whether treeLevel comparison matches.
578 *
579 * @test
580 */
581 public function treeLevelConditionMatchesMultipleValues(): void
582 {
583 $this->assertTrue($this->subject->match('[treeLevel = 999,998,2]'));
584 // Test expression language
585 $this->assertTrue($this->subject->match('[tree.level in [999,998,2]]'));
586 }
587
588 /**
589 * Tests whether treeLevel comparison matches.
590 *
591 * @test
592 */
593 public function treeLevelConditionDoesNotMatchFaultyValue(): void
594 {
595 $this->assertFalse($this->subject->match('[treeLevel = 999]'));
596 // Test expression language
597 $this->assertFalse($this->subject->match('[tree.level == 999]'));
598 }
599
600 /**
601 * @return array
602 */
603 public function pageDataProvider(): array
604 {
605 return [
606 '[page|layout = 0]' => ['[page|layout = 0]', true],
607 '[page|layout = 1]' => ['[page|layout = 1]', false],
608 '[page|title = Foo]' => ['[page|title = Foo]', true],
609 ];
610 }
611
612 /**
613 * @test
614 * @dataProvider pageDataProvider
615 * @param string $expression
616 * @param bool $expected
617 */
618 public function checkConditionMatcherForPage(string $expression, bool $expected): void
619 {
620 $GLOBALS['TSFE']->page = ['title' => 'Foo', 'layout' => 0];
621 $this->getFreshConditionMatcher();
622 $this->assertSame($expected, $this->subject->match($expression));
623 }
624
625 /**
626 * Tests whether a page Id is found in the previous rootline entries.
627 *
628 * @test
629 */
630 public function PIDupinRootlineConditionMatchesSinglePageIdInRootline(): void
631 {
632 $GLOBALS['TSFE']->id = 121;
633 $this->getFreshConditionMatcher();
634 $this->assertTrue($this->subject->match('[PIDupinRootline = 111]'));
635 // Test expression language
636 $this->assertTrue($this->subject->match('[111 in tree.rootLineIds]'));
637 $this->assertTrue($this->subject->match('["111" in tree.rootLineIds]'));
638 $this->assertTrue($this->subject->match('[\'111\' in tree.rootLineIds]'));
639 }
640
641 /**
642 * Tests whether a page Id is found in the previous rootline entries.
643 *
644 * @test
645 */
646 public function PIDupinRootlineConditionMatchesMultiplePageIdsInRootline(): void
647 {
648 $GLOBALS['TSFE']->id = 121;
649 $this->getFreshConditionMatcher();
650 $this->assertTrue($this->subject->match('[PIDupinRootline = 999,111,101]'));
651 // Test expression language
652 $this->assertTrue($this->subject->match('[999 in tree.rootLineIds][111 in tree.rootLineIds][101 in tree.rootLineIds]'));
653 }
654
655 /**
656 * Tests whether a page Id is found in the previous rootline entries.
657 *
658 * @test
659 */
660 public function PIDupinRootlineConditionDoesNotMatchPageIdNotInRootline(): void
661 {
662 $GLOBALS['TSFE']->id = 121;
663 $this->getFreshConditionMatcher();
664 $this->assertFalse($this->subject->match('[PIDupinRootline = 999]'));
665 // Test expression language
666 $this->assertFalse($this->subject->match('[999 in tree.rootLineIds]'));
667 }
668
669 /**
670 * Tests whether a page Id is found in the previous rootline entries.
671 *
672 * @test
673 */
674 public function PIDupinRootlineConditionDoesNotMatchLastPageIdInRootline(): void
675 {
676 $GLOBALS['TSFE']->id = 121;
677 $this->getFreshConditionMatcher();
678 $this->assertFalse($this->subject->match('[PIDupinRootline = 121]'));
679 // Test expression language
680 $this->assertFalse($this->subject->match('[page.uid != 121 && 121 in rootLineUids]'));
681 }
682
683 /**
684 * Tests whether a page Id is found in all rootline entries.
685 *
686 * @test
687 */
688 public function PIDinRootlineConditionMatchesSinglePageIdInRootline(): void
689 {
690 $GLOBALS['TSFE']->id = 121;
691 $this->getFreshConditionMatcher();
692 $this->assertTrue($this->subject->match('[PIDinRootline = 111]'));
693 // Test expression language
694 $this->assertTrue($this->subject->match('[111 in tree.rootLineIds]'));
695 }
696
697 /**
698 * Tests whether a page Id is found in all rootline entries.
699 *
700 * @test
701 */
702 public function PIDinRootlineConditionMatchesMultiplePageIdsInRootline(): void
703 {
704 $GLOBALS['TSFE']->id = 121;
705 $this->getFreshConditionMatcher();
706 $this->assertTrue($this->subject->match('[PIDinRootline = 999,111,101]'));
707 // Test expression language
708 $this->assertTrue($this->subject->match('[999 in tree.rootLineIds][111 in tree.rootLineIds][101 in tree.rootLineIds]'));
709 }
710
711 /**
712 * Tests whether a page Id is found in all rootline entries.
713 *
714 * @test
715 */
716 public function PIDinRootlineConditionMatchesLastPageIdInRootline(): void
717 {
718 $GLOBALS['TSFE']->id = 121;
719 $this->getFreshConditionMatcher();
720 $this->assertTrue($this->subject->match('[PIDinRootline = 121]'));
721 // Test expression language
722 $this->assertTrue($this->subject->match('[121 in tree.rootLineIds]'));
723 }
724
725 /**
726 * Tests whether a page Id is found in all rootline entries.
727 *
728 * @test
729 */
730 public function PIDinRootlineConditionDoesNotMatchPageIdNotInRootline(): void
731 {
732 $GLOBALS['TSFE']->id = 121;
733 $this->assertFalse($this->subject->match('[PIDinRootline = 999]'));
734 // Test expression language
735 $this->assertFalse($this->subject->match('[999 in tree.rootLineIds]'));
736 }
737
738 /**
739 * Tests whether the compatibility version can be evaluated.
740 * (e.g. 7.9 is compatible to 7.0 but not to 15.0)
741 *
742 * @test
743 */
744 public function compatVersionConditionMatchesOlderRelease(): void
745 {
746 $this->assertTrue($this->subject->match('[compatVersion = 7.0]'));
747 // Test expression language
748 $this->assertTrue($this->subject->match('[compatVersion(7.0)]'));
749 $this->assertTrue($this->subject->match('[compatVersion("7.0")]'));
750 $this->assertTrue($this->subject->match('[compatVersion(\'7.0\')]'));
751 }
752
753 /**
754 * Tests whether the compatibility version can be evaluated.
755 * (e.g. 7.9 is compatible to 7.0 but not to 15.0)
756 *
757 * @test
758 */
759 public function compatVersionConditionMatchesSameRelease(): void
760 {
761 $this->assertTrue($this->subject->match('[compatVersion = ' . TYPO3_branch . ']'));
762 // Test expression language
763 $this->assertTrue($this->subject->match('[compatVersion(' . TYPO3_branch . ')]'));
764 }
765
766 /**
767 * Tests whether the compatibility version can be evaluated.
768 * (e.g. 7.9 is compatible to 7.0 but not to 15.0)
769 *
770 * @test
771 */
772 public function compatVersionConditionDoesNotMatchNewerRelease(): void
773 {
774 $this->assertFalse($this->subject->match('[compatVersion = 15.0]'));
775 // Test expression language
776 $this->assertFalse($this->subject->match('[compatVersion(15.0)]'));
777 $this->assertFalse($this->subject->match('[compatVersion("15.0")]'));
778 $this->assertFalse($this->subject->match('[compatVersion(\'15.0\')]'));
779 }
780
781 /**
782 * Tests whether the generic fetching of variables works with the namespace 'GP'.
783 *
784 * @test
785 */
786 public function genericGetVariablesSucceedsWithNamespaceGP(): void
787 {
788 $_GET = ['testGet' => 'getTest'];
789 $_POST = ['testPost' => 'postTest'];
790 $this->getFreshConditionMatcher();
791 $this->assertTrue($this->subject->match('[globalString = GP:testGet = getTest]'));
792 $this->assertTrue($this->subject->match('[globalString = GP:testPost = postTest]'));
793 }
794
795 /**
796 * Tests whether the generic fetching of variables works with the namespace 'TSFE'.
797 *
798 * @test
799 */
800 public function genericGetVariablesSucceedsWithNamespaceTSFE(): void
801 {
802 $GLOBALS['TSFE']->id = 1234567;
803 $GLOBALS['TSFE']->testSimpleObject = new \stdClass();
804 $GLOBALS['TSFE']->testSimpleObject->testSimpleVariable = 'testValue';
805
806 $this->getFreshConditionMatcher();
807 $this->assertTrue($this->subject->match('[globalString = TSFE:id = 1234567]'));
808 $this->assertTrue($this->subject->match('[globalString = TSFE:testSimpleObject|testSimpleVariable = testValue]'));
809 // Test expression language
810 $this->assertTrue($this->subject->match('[getTSFE().id == 1234567]'));
811 $this->assertTrue($this->subject->match('[getTSFE().testSimpleObject.testSimpleVariable == "testValue"]'));
812 }
813
814 /**
815 * Tests whether the generic fetching of variables works with the namespace 'session'.
816 *
817 * @test
818 */
819 public function genericGetVariablesSucceedsWithNamespaceSession(): void
820 {
821 $prophecy = $this->prophesize(FrontendUserAuthentication::class);
822 $prophecy->getSessionData(Argument::exact('foo'))->willReturn(['bar' => 1234567]);
823 $GLOBALS['TSFE']->fe_user = $prophecy->reveal();
824
825 $this->getFreshConditionMatcher();
826 $this->assertTrue($this->subject->match('[globalString = session:foo|bar = 1234567]'));
827 // Test expression language
828 $this->assertTrue($this->subject->match('[session("foo|bar") == 1234567]'));
829 }
830
831 /**
832 * Tests whether the generic fetching of variables works with the namespace 'ENV'.
833 *
834 * @test
835 */
836 public function genericGetVariablesSucceedsWithNamespaceENV(): void
837 {
838 $testKey = $this->getUniqueId('test');
839 putenv($testKey . '=testValue');
840 $this->getFreshConditionMatcher();
841 $this->assertTrue($this->subject->match('[globalString = ENV:' . $testKey . ' = testValue]'));
842 // Test expression language
843 $this->assertTrue($this->subject->match('[getenv("' . $testKey . '") == "testValue"]'));
844 }
845
846 /**
847 * Tests whether the generic fetching of variables works with the namespace 'IENV'.
848 *
849 * @test
850 */
851 public function genericGetVariablesSucceedsWithNamespaceIENV(): void
852 {
853 $_SERVER['HTTP_HOST'] = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY') . ':1234567';
854 // getIndpEnv() is polluted after above call, clear cache to have it recalculate for subject execption
855 GeneralUtility::flushInternalRuntimeCaches();
856 $this->getFreshConditionMatcher();
857 $this->assertTrue($this->subject->match('[globalString = IENV:TYPO3_PORT = 1234567]'));
858 // Test expression language
859 // @TODO: not work yet, looks like test setup issue
860 // $this->assertTrue($this->subject->match('[request.getNormalizedParams().getRequestPort() == 1234567]'));
861 }
862
863 /**
864 * Tests whether the generic fetching of variables works with any global namespace.
865 *
866 * @test
867 */
868 public function genericGetVariablesSucceedsWithAnyGlobalNamespace(): void
869 {
870 $GLOBALS[$this->testGlobalNamespace] = [
871 'first' => 'testFirst',
872 'second' => ['third' => 'testThird']
873 ];
874 $this->getFreshConditionMatcher();
875 $this->assertTrue($this->subject->match('[globalString = ' . $this->testGlobalNamespace . '|first = testFirst]'));
876 $this->assertTrue($this->subject->match('[globalString = ' . $this->testGlobalNamespace . '|second|third = testThird]'));
877 }
878
879 /**
880 * Tests whether any property of a site language matches the request
881 *
882 * @test
883 */
884 public function siteLanguageMatchesCondition(): void
885 {
886 $site = new Site('angelo', 13, [
887 'languages' => [
888 [
889 'languageId' => 0,
890 'title' => 'United States',
891 'locale' => 'en_US.UTF-8',
892 ],
893 [
894 'languageId' => 2,
895 'title' => 'UK',
896 'locale' => 'en_UK.UTF-8',
897 ]
898 ]
899 ]);
900 $GLOBALS['TYPO3_REQUEST'] = new ServerRequest();
901 $GLOBALS['TYPO3_REQUEST'] = $GLOBALS['TYPO3_REQUEST']->withAttribute('language', $site->getLanguageById(0));
902 $this->getFreshConditionMatcher();
903 $this->assertTrue($this->subject->match('[siteLanguage = locale = en_US.UTF-8]'));
904 $this->assertTrue($this->subject->match('[siteLanguage = locale = de_DE, locale = en_US.UTF-8]'));
905 // Test expression language
906 $this->assertTrue($this->subject->match('[siteLanguage("locale") == "en_US.UTF-8"]'));
907 $this->assertTrue($this->subject->match('[siteLanguage("locale") in ["de_DE", "en_US.UTF-8"]]'));
908 }
909
910 /**
911 * Tests whether any property of a site language does NOT match the request
912 *
913 * @test
914 */
915 public function siteLanguageDoesNotMatchCondition(): void
916 {
917 $site = new Site('angelo', 13, [
918 'languages' => [
919 [
920 'languageId' => 0,
921 'title' => 'United States',
922 'locale' => 'en_US.UTF-8',
923 ],
924 [
925 'languageId' => 2,
926 'title' => 'UK',
927 'locale' => 'en_UK.UTF-8',
928 ]
929 ]
930 ]);
931 $GLOBALS['TYPO3_REQUEST'] = new ServerRequest();
932 $GLOBALS['TYPO3_REQUEST'] = $GLOBALS['TYPO3_REQUEST']->withAttribute('language', $site->getLanguageById(0));
933 $this->getFreshConditionMatcher();
934 $this->assertFalse($this->subject->match('[siteLanguage = locale = en_UK.UTF-8]'));
935 $this->assertFalse($this->subject->match('[siteLanguage = locale = de_DE, title = UK]'));
936 // Test expression language
937 $this->assertFalse($this->subject->match('[siteLanguage("locale") == "en_UK.UTF-8"]'));
938 $this->assertFalse($this->subject->match('[siteLanguage("locale") == "de_DE" && siteLanguage("title") == "UK"]'));
939 }
940
941 /**
942 * Tests whether any property of a site matches the request
943 *
944 * @test
945 */
946 public function siteMatchesCondition(): void
947 {
948 $site = new Site('angelo', 13, ['languages' => [], 'base' => 'https://typo3.org/']);
949 $GLOBALS['TYPO3_REQUEST'] = new ServerRequest();
950 $GLOBALS['TYPO3_REQUEST'] = $GLOBALS['TYPO3_REQUEST']->withAttribute('site', $site);
951 $this->getFreshConditionMatcher();
952 $this->assertTrue($this->subject->match('[site = identifier = angelo]'));
953 $this->assertTrue($this->subject->match('[site = rootPageId = 13]'));
954 $this->assertTrue($this->subject->match('[site = base = https://typo3.org/]'));
955 // Test expression language
956 $this->assertTrue($this->subject->match('[site("identifier") == "angelo"]'));
957 $this->assertTrue($this->subject->match('[site("rootPageId") == 13]'));
958 $this->assertTrue($this->subject->match('[site("base") == "https://typo3.org/"]'));
959 }
960
961 /**
962 * Tests whether any property of a site that does NOT match the request
963 *
964 * @test
965 */
966 public function siteDoesNotMatchCondition(): void
967 {
968 $site = new Site('angelo', 13, [
969 'languages' => [
970 [
971 'languageId' => 0,
972 'title' => 'United States',
973 'locale' => 'en_US.UTF-8',
974 ],
975 [
976 'languageId' => 2,
977 'title' => 'UK',
978 'locale' => 'en_UK.UTF-8',
979 ]
980 ]
981 ]);
982 $GLOBALS['TYPO3_REQUEST'] = new ServerRequest();
983 $GLOBALS['TYPO3_REQUEST'] = $GLOBALS['TYPO3_REQUEST']->withAttribute('site', $site);
984 $this->getFreshConditionMatcher();
985 $this->assertFalse($this->subject->match('[site = identifier = berta]'));
986 $this->assertFalse($this->subject->match('[site = rootPageId = 14, rootPageId=23]'));
987 // Test expression language
988 $this->assertFalse($this->subject->match('[site("identifier") == "berta"]'));
989 $this->assertFalse($this->subject->match('[site("rootPageId") == 14 && site("rootPageId") == 23]'));
990 }
991
992 /**
993 * @test
994 */
995 public function matchThrowsExceptionIfConditionClassDoesNotInheritFromAbstractCondition(): void
996 {
997 $this->expectException(InvalidTypoScriptConditionException::class);
998 $this->expectExceptionCode(1410286153);
999 $this->getFreshConditionMatcher();
1000 $loggerProphecy = $this->prophesize(Logger::class);
1001 $this->subject->setLogger($loggerProphecy->reveal());
1002 $this->subject->match('[stdClass = foo]');
1003 }
1004
1005 /**
1006 * @test
1007 */
1008 public function matchCallsTestConditionAndHandsOverParameters(): void
1009 {
1010 $this->expectException(TestConditionException::class);
1011 $this->expectExceptionCode(1411581139);
1012 $this->getFreshConditionMatcher();
1013 $loggerProphecy = $this->prophesize(Logger::class);
1014 $this->subject->setLogger($loggerProphecy->reveal());
1015 $this->subject->match('[TYPO3\\CMS\\Frontend\\Tests\\UnitDeprecated\\Configuration\\TypoScript\\ConditionMatching\\Fixtures\\TestCondition = 7, != 6]');
1016 }
1017 }