‪TYPO3CMS  10.4
AbstractConditionMatcherTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
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 
19 
20 use Prophecy\Argument;
21 use Psr\Log\NullLogger;
34 use TYPO3\CMS\Core\Package\PackageManager;
36 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
37 
41 class ‪AbstractConditionMatcherTest extends UnitTestCase
42 {
43  protected ‪$backupEnvironment = true;
44 
48  protected ‪$conditionMatcher;
49 
54 
58  protected function ‪setUp(): void
59  {
60  parent::setUp();
61  require_once 'Fixtures/ConditionMatcherUserFuncs.php';
62 
63  $this->resetSingletonInstances = true;
64  ‪$GLOBALS['TYPO3_REQUEST'] = new ‪ServerRequest();
65  $coreCacheProphecy = $this->prophesize(PhpFrontend::class);
66  $coreCacheProphecy->require(Argument::any())->willReturn(false);
67  $coreCacheProphecy->set(Argument::any(), Argument::any())->willReturn(null);
68  $cacheFrontendProphecy = $this->prophesize(FrontendInterface::class);
69  $cacheFrontendProphecy->set(Argument::any(), Argument::any())->willReturn(null);
70  $cacheFrontendProphecy->get('backendUtilityBeGetRootLine')->willReturn([]);
71  $cacheManagerProphecy = $this->prophesize(CacheManager::class);
72  $cacheManagerProphecy->getCache('core')->willReturn($coreCacheProphecy->reveal());
73  $cacheManagerProphecy->getCache('runtime')->willReturn($cacheFrontendProphecy->reveal());
74  GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
75 
76  $packageManagerProphecy = $this->prophesize(PackageManager::class);
77  $corePackageProphecy = $this->prophesize(PackageInterface::class);
78  $corePackageProphecy->getPackagePath()->willReturn(__DIR__ . '/../../../../../../../sysext/core/');
79  $packageManagerProphecy->getActivePackages()->willReturn([
80  $corePackageProphecy->reveal()
81  ]);
82  GeneralUtility::setSingletonInstance(PackageManager::class, $packageManagerProphecy->reveal());
83 
84  $this->‪initConditionMatcher();
85  }
86 
87  protected function ‪initConditionMatcher()
88  {
89  // test the abstract methods via the backend condition matcher
90  $this->evaluateExpressionMethod = new \ReflectionMethod(AbstractConditionMatcher::class, 'evaluateExpression');
91  $this->evaluateExpressionMethod->setAccessible(true);
92  $this->conditionMatcher = new ‪ConditionMatcher();
93  $this->conditionMatcher->setLogger(new NullLogger());
94  }
95 
99  public function ‪requestFunctionDataProvider(): array
100  {
101  return [
102  // GET tests
103  // getQueryParams()
104  'request.getQueryParams()[\'foo\'] > 0' => ['request.getQueryParams()[\'foo\'] > 0', true],
105  'request.getQueryParams()[\'foo\'][\'bar\'] > 0' => ['request.getQueryParams()[\'foo\'][\'bar\'] > 0', false],
106  'request.getQueryParams()[\'bar\'][\'foo\'] > 0' => ['request.getQueryParams()[\'bar\'][\'foo\'] > 0', false],
107  'request.getQueryParams()[\'foo\'] == 0' => ['request.getQueryParams()[\'foo\'] == 0', false],
108  'request.getQueryParams()[\'foo\'][\'bar\'] == 0' => ['request.getQueryParams()[\'foo\'][\'bar\'] == 0', false],
109  // POST tests
110  // getParsedBody()
111  'request.getParsedBody()[\'foo\'] > 0' => ['request.getParsedBody()[\'foo\'] > 0', true],
112  'request.getParsedBody()[\'foo\'][\'bar\'] > 0' => ['request.getParsedBody()[\'foo\'][\'bar\'] > 0', false],
113  'request.getParsedBody()[\'bar\'][\'foo\'] > 0' => ['request.getParsedBody()[\'bar\'][\'foo\'] > 0', false],
114  'request.getParsedBody()[\'foo\'] == 0' => ['request.getParsedBody()[\'foo\'] == 0', false],
115  'request.getParsedBody()[\'foo\'][\'bar\'] == 0' => ['request.getParsedBody()[\'foo\'][\'bar\'] == 0', false],
116  // HEADERS tests
117  // getHeaders()
118  'request.getHeaders()[\'foo\'] == [\'1\']' => ['request.getHeaders()[\'foo\'] == [\'1\']', true],
119  'request.getHeaders()[\'foo\'] == [\'0\']' => ['request.getHeaders()[\'foo\'] == [\'0\']', false],
120  'request.getHeaders()[\'foo\'] == [\'bar\']' => ['request.getHeaders()[\'foo\'] == [\'bar\']', false],
121  // COOKIES tests
122  // getCookieParams()
123  'request.getCookieParams()[\'foo\'] > 0' => ['request.getCookieParams()[\'foo\'] > 0', true],
124  'request.getCookieParams()[\'foo\'] > 1' => ['request.getCookieParams()[\'foo\'] > 1', false],
125  ];
126  }
127 
134  public function ‪checkConditionMatcherForRequestFunction(string $expression, bool $expected): void
135  {
136  $request = (new ServerRequest())
137  ->withParsedBody(['foo' => 1])
138  ->withQueryParams(['foo' => 1])
139  ->withCookieParams(['foo' => 1])
140  ->withHeader('foo', '1');
141  ‪$GLOBALS['TYPO3_REQUEST'] = $request;
142  $this->‪initConditionMatcher();
143  self::assertSame(
144  $expected,
145  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, [$expression])
146  );
147  }
148 
152  public function ‪datesFunctionDataProvider(): array
153  {
154  return [
155  '[dayofmonth = 17]' => ['j', 17, true],
156  '[dayofweek = 3]' => ['w', 3, true],
157  '[dayofyear = 16]' => ['z', 16, true],
158  '[hour = 11]' => ['G', 11, true],
159  '[minute = 4]' => ['i', 4, true],
160  '[month = 1]' => ['n', 1, true],
161  '[year = 1945]' => ['Y', 1945, true],
162  ];
163  }
164 
172  public function ‪checkConditionMatcherForDateFunction(string $format, int $expressionValue, bool $expected): void
173  {
174  ‪$GLOBALS['SIM_EXEC_TIME'] = gmmktime(11, 4, 0, 1, 17, 1945);
175  GeneralUtility::makeInstance(Context::class)
176  ->setAspect('date', new DateTimeAspect(new \DateTimeImmutable('@' . ‪$GLOBALS['SIM_EXEC_TIME'])));
177  self::assertSame(
178  $expected,
179  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['date("' . $format . '") == ' . $expressionValue])
180  );
181  }
182 
186  public function ‪checkConditionMatcherForFeatureFunction(): void
187  {
188  $featureName = 'test.testFeature';
189  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['features'][$featureName] = true;
190  self::assertTrue(
191  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '")'])
192  );
193  self::assertTrue(
194  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") == true'])
195  );
196  self::assertTrue(
197  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") === true'])
198  );
199  self::assertFalse(
200  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") == false'])
201  );
202  self::assertFalse(
203  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") === false'])
204  );
205 
206  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['features'][$featureName] = false;
207  self::assertFalse(
208  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '")'])
209  );
210  self::assertFalse(
211  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") == true'])
212  );
213  self::assertFalse(
214  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") === true'])
215  );
216  self::assertTrue(
217  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") == false'])
218  );
219  self::assertTrue(
220  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") === false'])
221  );
222  }
223 
230  {
231  return [
232  ['Production*'],
233  ['Production/Staging/*'],
234  ['Production/Staging/Server2'],
235  ['/^Production.*$/'],
236  ['/^Production\\/.+\\/Server\\d+$/'],
237  ];
238  }
239 
244  public function ‪evaluateConditionCommonReturnsTrueForMatchingContexts($matchingContextCondition): void
245  {
247  new ApplicationContext('Production/Staging/Server2'),
248  true,
249  false,
254  ‪Environment::getBackendPath() . '/index.php',
255  ‪Environment::isWindows() ? 'WINDOWS' : 'UNIX'
256  );
257 
258  $this->‪initConditionMatcher();
259 
260  // Test expression language
261  self::assertTrue(
262  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['like(applicationContext, "' . preg_quote($matchingContextCondition, '/') . '")'])
263  );
264  }
265 
272  {
273  return [
274  ['Production'],
275  ['Testing*'],
276  ['Development/Profiling, Testing/Unit'],
277  ['Testing/Staging/Server2'],
278  ['/^Testing.*$/'],
279  ['/^Production\\/.+\\/Host\\d+$/'],
280  ];
281  }
282 
287  public function ‪evaluateConditionCommonReturnsNullForNotMatchingApplicationContexts($notMatchingApplicationContextCondition): void
288  {
290  new ApplicationContext('Production/Staging/Server2'),
291  true,
292  false,
297  ‪Environment::getBackendPath() . '/index.php',
298  ‪Environment::isWindows() ? 'WINDOWS' : 'UNIX'
299  );
300  $this->‪initConditionMatcher();
301 
302  // Test expression language
303  self::assertFalse(
304  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['like(applicationContext, "' . preg_quote($notMatchingApplicationContextCondition, '/') . '")'])
305  );
306  }
307 
313  public function ‪evaluateConditionCommonDevIpMaskDataProvider(): array
314  {
315  return [
316  // [0] $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']
317  // [1] Actual IP
318  // [2] Expected condition result
319  'IP matches' => [
320  '127.0.0.1',
321  '127.0.0.1',
322  true,
323  ],
324  'ipv4 wildcard subnet' => [
325  '127.0.0.1/24',
326  '127.0.0.2',
327  true,
328  ],
329  'ipv6 wildcard subnet' => [
330  '0:0::1/128',
331  '::1',
332  true,
333  ],
334  'List of addresses matches' => [
335  '1.2.3.4, 5.6.7.8',
336  '5.6.7.8',
337  true,
338  ],
339  'IP does not match' => [
340  '127.0.0.1',
341  '127.0.0.2',
342  false,
343  ],
344  'ipv4 subnet does not match' => [
345  '127.0.0.1/8',
346  '126.0.0.1',
347  false,
348  ],
349  'ipv6 subnet does not match' => [
350  '::1/127',
351  '::2',
352  false
353  ],
354  'List of addresses does not match' => [
355  '127.0.0.1, ::1',
356  '::2',
357  false,
358  ],
359  ];
360  }
361 
366  public function ‪evaluateConditionCommonEvaluatesIpAddressesCorrectly($devIpMask, $actualIp, $expectedResult): void
367  {
368  // Do not trigger proxy stuff of GeneralUtility::getIndPEnv
369  unset(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP']);
370 
371  GeneralUtility::setIndpEnv('REMOTE_ADDR', $actualIp);
372  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'] = $devIpMask;
373  $this->‪initConditionMatcher();
374  $result = $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['ip("devIP")']);
375  self::assertSame($expectedResult, $result);
376  }
377 
382  {
383  $this->‪initConditionMatcher();
384  $expressionProperty = new \ReflectionProperty(AbstractConditionMatcher::class, 'expressionLanguageResolver');
385  $expressionProperty->setAccessible(true);
386  $resolverProphecy = $this->prophesize(Resolver::class);
387  $resolverProphecy->evaluate(Argument::cetera())->shouldNotBeCalled();
388  $expressionProperty->setValue($this->conditionMatcher, $resolverProphecy->reveal());
389  self::assertFalse($this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['ELSE']));
390  }
391 }
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest
Definition: AbstractConditionMatcherTest.php:42
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\$conditionMatcher
‪AbstractConditionMatcher PHPUnit Framework MockObject MockObject TYPO3 TestingFramework Core AccessibleObjectInterface $conditionMatcher
Definition: AbstractConditionMatcherTest.php:47
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:180
‪TYPO3\CMS\Core\Core\ApplicationContext
Definition: ApplicationContext.php:37
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\typoScriptElseConditionIsNotEvaluatedAndAlwaysReturnsFalse
‪typoScriptElseConditionIsNotEvaluatedAndAlwaysReturnsFalse()
Definition: AbstractConditionMatcherTest.php:379
‪TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher
Definition: ConditionMatcher.php:30
‪TYPO3\CMS\Core\Cache\Frontend\PhpFrontend
Definition: PhpFrontend.php:25
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\evaluateConditionCommonReturnsTrueForMatchingContexts
‪evaluateConditionCommonReturnsTrueForMatchingContexts($matchingContextCondition)
Definition: AbstractConditionMatcherTest.php:242
‪TYPO3\CMS\Core\Core\Environment\isWindows
‪static bool isWindows()
Definition: Environment.php:292
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\$evaluateExpressionMethod
‪ReflectionMethod $evaluateExpressionMethod
Definition: AbstractConditionMatcherTest.php:51
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching
Definition: AbstractConditionMatcherTest.php:18
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\checkConditionMatcherForRequestFunction
‪checkConditionMatcherForRequestFunction(string $expression, bool $expected)
Definition: AbstractConditionMatcherTest.php:132
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:53
‪TYPO3\CMS\Core\Package\PackageInterface
Definition: PackageInterface.php:22
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\$backupEnvironment
‪$backupEnvironment
Definition: AbstractConditionMatcherTest.php:43
‪TYPO3\CMS\Core\Core\Environment\getProjectPath
‪static string getProjectPath()
Definition: Environment.php:169
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher
Definition: AbstractConditionMatcher.php:34
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\initConditionMatcher
‪initConditionMatcher()
Definition: AbstractConditionMatcherTest.php:85
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\requestFunctionDataProvider
‪array requestFunctionDataProvider()
Definition: AbstractConditionMatcherTest.php:97
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\notMatchingApplicationContextConditionsDataProvider
‪array notMatchingApplicationContextConditionsDataProvider()
Definition: AbstractConditionMatcherTest.php:269
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\setUp
‪setUp()
Definition: AbstractConditionMatcherTest.php:56
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\checkConditionMatcherForDateFunction
‪checkConditionMatcherForDateFunction(string $format, int $expressionValue, bool $expected)
Definition: AbstractConditionMatcherTest.php:170
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\matchingApplicationContextConditionsDataProvider
‪array matchingApplicationContextConditionsDataProvider()
Definition: AbstractConditionMatcherTest.php:227
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:35
‪TYPO3\CMS\Core\Core\Environment\initialize
‪static initialize(ApplicationContext $context, bool $cli, bool $composerMode, string $projectPath, string $publicPath, string $varPath, string $configPath, string $currentScript, string $os)
Definition: Environment.php:104
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:37
‪TYPO3\CMS\Core\Core\Environment\getBackendPath
‪static string getBackendPath()
Definition: Environment.php:250
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\evaluateConditionCommonEvaluatesIpAddressesCorrectly
‪evaluateConditionCommonEvaluatesIpAddressesCorrectly($devIpMask, $actualIp, $expectedResult)
Definition: AbstractConditionMatcherTest.php:364
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\datesFunctionDataProvider
‪array datesFunctionDataProvider()
Definition: AbstractConditionMatcherTest.php:150
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:22
‪TYPO3\CMS\Core\ExpressionLanguage\Resolver
Definition: Resolver.php:27
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:40
‪TYPO3\CMS\Core\Core\Environment\getConfigPath
‪static string getConfigPath()
Definition: Environment.php:210
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\evaluateConditionCommonDevIpMaskDataProvider
‪array evaluateConditionCommonDevIpMaskDataProvider()
Definition: AbstractConditionMatcherTest.php:311
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\evaluateConditionCommonReturnsNullForNotMatchingApplicationContexts
‪evaluateConditionCommonReturnsNullForNotMatchingApplicationContexts($notMatchingApplicationContextCondition)
Definition: AbstractConditionMatcherTest.php:285
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Context\DateTimeAspect
Definition: DateTimeAspect.php:35
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\checkConditionMatcherForFeatureFunction
‪checkConditionMatcherForFeatureFunction()
Definition: AbstractConditionMatcherTest.php:184
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static string getVarPath()
Definition: Environment.php:192