‪TYPO3CMS  11.5
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 Prophecy\PhpUnit\ProphecyTrait;
22 use Psr\Log\NullLogger;
37 use TYPO3\CMS\Core\Package\PackageManager;
39 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
40 
44 class ‪AbstractConditionMatcherTest extends UnitTestCase
45 {
46  use ProphecyTrait;
47 
48  protected ‪$backupEnvironment = true;
49 
54 
55  protected ?\ReflectionMethod ‪$evaluateExpressionMethod;
56 
60  protected function ‪setUp(): void
61  {
62  parent::setUp();
63  require_once 'Fixtures/ConditionMatcherUserFuncs.php';
64 
65  $this->resetSingletonInstances = true;
66  ‪$GLOBALS['TYPO3_REQUEST'] = new ‪ServerRequest();
67  $coreCacheProphecy = $this->prophesize(PhpFrontend::class);
68  $coreCacheProphecy->require(Argument::any())->willReturn(false);
69  $coreCacheProphecy->set(Argument::any(), Argument::any())->willReturn(null);
70  $cacheFrontendProphecy = $this->prophesize(FrontendInterface::class);
71  $cacheFrontendProphecy->set(Argument::any(), Argument::any())->willReturn(null);
72  $cacheFrontendProphecy->get('backendUtilityBeGetRootLine')->willReturn([]);
73  $cacheManagerProphecy = $this->prophesize(CacheManager::class);
74  $cacheManagerProphecy->getCache('core')->willReturn($coreCacheProphecy->reveal());
75  $cacheManagerProphecy->getCache('runtime')->willReturn($cacheFrontendProphecy->reveal());
76  GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
77 
78  $packageManagerProphecy = $this->prophesize(PackageManager::class);
79  $corePackageProphecy = $this->prophesize(PackageInterface::class);
80  $corePackageProphecy->getPackagePath()->willReturn(__DIR__ . '/../../../../../../../sysext/core/');
81  $packageManagerProphecy->getActivePackages()->willReturn([
82  $corePackageProphecy->reveal(),
83  ]);
84  GeneralUtility::setSingletonInstance(PackageManager::class, $packageManagerProphecy->reveal());
85 
86  $this->‪initConditionMatcher();
87  }
88 
89  protected function ‪initConditionMatcher(): void
90  {
91  GeneralUtility::addInstance(ProviderConfigurationLoader::class, new ‪ProviderConfigurationLoader(
92  GeneralUtility::makeInstance(PackageManager::class),
93  GeneralUtility::makeInstance(CacheManager::class)->getCache('core'),
94  'ExpressionLanguageProviders'
95  ));
96  // test the abstract methods via the backend condition matcher
97  $this->evaluateExpressionMethod = new \ReflectionMethod(AbstractConditionMatcher::class, 'evaluateExpression');
98  $this->evaluateExpressionMethod->setAccessible(true);
99  $this->conditionMatcher = new ‪ConditionMatcher();
100  $this->conditionMatcher->setLogger(new NullLogger());
101  }
102 
106  public function ‪requestFunctionDataProvider(): array
107  {
108  return [
109  // GET tests
110  // getQueryParams()
111  'request.getQueryParams()[\'foo\'] > 0' => ['request.getQueryParams()[\'foo\'] > 0', true],
112  'request.getQueryParams()[\'foo\'][\'bar\'] > 0' => ['request.getQueryParams()[\'foo\'][\'bar\'] > 0', false],
113  'request.getQueryParams()[\'bar\'][\'foo\'] > 0' => ['request.getQueryParams()[\'bar\'][\'foo\'] > 0', false],
114  'request.getQueryParams()[\'foo\'] == 0' => ['request.getQueryParams()[\'foo\'] == 0', false],
115  'request.getQueryParams()[\'foo\'][\'bar\'] == 0' => ['request.getQueryParams()[\'foo\'][\'bar\'] == 0', false],
116  // POST tests
117  // getParsedBody()
118  'request.getParsedBody()[\'foo\'] > 0' => ['request.getParsedBody()[\'foo\'] > 0', true],
119  'request.getParsedBody()[\'foo\'][\'bar\'] > 0' => ['request.getParsedBody()[\'foo\'][\'bar\'] > 0', false],
120  'request.getParsedBody()[\'bar\'][\'foo\'] > 0' => ['request.getParsedBody()[\'bar\'][\'foo\'] > 0', false],
121  'request.getParsedBody()[\'foo\'] == 0' => ['request.getParsedBody()[\'foo\'] == 0', false],
122  'request.getParsedBody()[\'foo\'][\'bar\'] == 0' => ['request.getParsedBody()[\'foo\'][\'bar\'] == 0', false],
123  // HEADERS tests
124  // getHeaders()
125  'request.getHeaders()[\'foo\'] == [\'1\']' => ['request.getHeaders()[\'foo\'] == [\'1\']', true],
126  'request.getHeaders()[\'foo\'] == [\'0\']' => ['request.getHeaders()[\'foo\'] == [\'0\']', false],
127  'request.getHeaders()[\'foo\'] == [\'bar\']' => ['request.getHeaders()[\'foo\'] == [\'bar\']', false],
128  // COOKIES tests
129  // getCookieParams()
130  'request.getCookieParams()[\'foo\'] > 0' => ['request.getCookieParams()[\'foo\'] > 0', true],
131  'request.getCookieParams()[\'foo\'] > 1' => ['request.getCookieParams()[\'foo\'] > 1', false],
132  ];
133  }
134 
141  public function ‪checkConditionMatcherForRequestFunction(string $expression, bool $expected): void
142  {
143  $request = (new ServerRequest())
144  ->withParsedBody(['foo' => 1])
145  ->withQueryParams(['foo' => 1])
146  ->withCookieParams(['foo' => 1])
147  ->withHeader('foo', '1')
148  ->withAttribute('applicationType', ‪SystemEnvironmentBuilder::REQUESTTYPE_BE);
149  ‪$GLOBALS['TYPO3_REQUEST'] = $request;
150  $this->‪initConditionMatcher();
151  self::assertSame(
152  $expected,
153  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, [$expression])
154  );
155  }
156 
160  public function ‪datesFunctionDataProvider(): array
161  {
162  return [
163  '[dayofmonth = 17]' => ['j', 17, true],
164  '[dayofweek = 3]' => ['w', 3, true],
165  '[dayofyear = 16]' => ['z', 16, true],
166  '[hour = 11]' => ['G', 11, true],
167  '[minute = 4]' => ['i', 4, true],
168  '[month = 1]' => ['n', 1, true],
169  '[year = 1945]' => ['Y', 1945, true],
170  ];
171  }
172 
180  public function ‪checkConditionMatcherForDateFunction(string $format, int $expressionValue, bool $expected): void
181  {
182  ‪$GLOBALS['SIM_EXEC_TIME'] = gmmktime(11, 4, 0, 1, 17, 1945);
183  GeneralUtility::makeInstance(Context::class)
184  ->setAspect('date', new DateTimeAspect(new \DateTimeImmutable('@' . ‪$GLOBALS['SIM_EXEC_TIME'])));
185  self::assertSame(
186  $expected,
187  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['date("' . $format . '") == ' . $expressionValue])
188  );
189  }
190 
194  public function ‪checkConditionMatcherForFeatureFunction(): void
195  {
196  $featureName = 'test.testFeature';
197  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['features'][$featureName] = true;
198  self::assertTrue(
199  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '")'])
200  );
201  self::assertTrue(
202  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") == true'])
203  );
204  self::assertTrue(
205  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") === true'])
206  );
207  self::assertFalse(
208  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") == false'])
209  );
210  self::assertFalse(
211  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") === false'])
212  );
213 
214  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['features'][$featureName] = false;
215  self::assertFalse(
216  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '")'])
217  );
218  self::assertFalse(
219  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") == true'])
220  );
221  self::assertFalse(
222  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") === true'])
223  );
224  self::assertTrue(
225  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") == false'])
226  );
227  self::assertTrue(
228  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['feature("' . $featureName . '") === false'])
229  );
230  }
231 
238  {
239  return [
240  ['Production*'],
241  ['Production/Staging/*'],
242  ['Production/Staging/Server2'],
243  ['/^Production.*$/'],
244  ['/^Production\\/.+\\/Server\\d+$/'],
245  ];
246  }
247 
252  public function ‪evaluateConditionCommonReturnsTrueForMatchingContexts($matchingContextCondition): void
253  {
255  new ApplicationContext('Production/Staging/Server2'),
256  true,
257  false,
262  ‪Environment::getBackendPath() . '/index.php',
263  ‪Environment::isWindows() ? 'WINDOWS' : 'UNIX'
264  );
265 
266  $this->‪initConditionMatcher();
267 
268  // Test expression language
269  self::assertTrue(
270  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['like(applicationContext, "' . preg_quote($matchingContextCondition, '/') . '")'])
271  );
272  }
273 
280  {
281  return [
282  ['Production'],
283  ['Testing*'],
284  ['Development/Profiling, Testing/Unit'],
285  ['Testing/Staging/Server2'],
286  ['/^Testing.*$/'],
287  ['/^Production\\/.+\\/Host\\d+$/'],
288  ];
289  }
290 
295  public function ‪evaluateConditionCommonReturnsNullForNotMatchingApplicationContexts($notMatchingApplicationContextCondition): void
296  {
298  new ApplicationContext('Production/Staging/Server2'),
299  true,
300  false,
305  ‪Environment::getBackendPath() . '/index.php',
306  ‪Environment::isWindows() ? 'WINDOWS' : 'UNIX'
307  );
308  $this->‪initConditionMatcher();
309 
310  // Test expression language
311  self::assertFalse(
312  $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['like(applicationContext, "' . preg_quote($notMatchingApplicationContextCondition, '/') . '")'])
313  );
314  }
315 
321  public function ‪evaluateConditionCommonDevIpMaskDataProvider(): array
322  {
323  return [
324  // [0] $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']
325  // [1] Actual IP
326  // [2] Expected condition result
327  'IP matches' => [
328  '127.0.0.1',
329  '127.0.0.1',
330  true,
331  ],
332  'ipv4 wildcard subnet' => [
333  '127.0.0.1/24',
334  '127.0.0.2',
335  true,
336  ],
337  'ipv6 wildcard subnet' => [
338  '0:0::1/128',
339  '::1',
340  true,
341  ],
342  'List of addresses matches' => [
343  '1.2.3.4, 5.6.7.8',
344  '5.6.7.8',
345  true,
346  ],
347  'IP does not match' => [
348  '127.0.0.1',
349  '127.0.0.2',
350  false,
351  ],
352  'ipv4 subnet does not match' => [
353  '127.0.0.1/8',
354  '126.0.0.1',
355  false,
356  ],
357  'ipv6 subnet does not match' => [
358  '::1/127',
359  '::2',
360  false,
361  ],
362  'List of addresses does not match' => [
363  '127.0.0.1, ::1',
364  '::2',
365  false,
366  ],
367  ];
368  }
369 
374  public function ‪evaluateConditionCommonEvaluatesIpAddressesCorrectly($devIpMask, $actualIp, $expectedResult): void
375  {
376  // Do not trigger proxy stuff of GeneralUtility::getIndPEnv
377  unset(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP']);
378 
379  GeneralUtility::setIndpEnv('REMOTE_ADDR', $actualIp);
380  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'] = $devIpMask;
381  $this->‪initConditionMatcher();
382  $result = $this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['ip("devIP")']);
383  self::assertSame($expectedResult, $result);
384  }
385 
390  {
391  $this->‪initConditionMatcher();
392  $expressionProperty = new \ReflectionProperty(AbstractConditionMatcher::class, 'expressionLanguageResolver');
393  $expressionProperty->setAccessible(true);
394  $resolverProphecy = $this->prophesize(Resolver::class);
395  $resolverProphecy->evaluate(Argument::cetera())->shouldNotBeCalled();
396  $expressionProperty->setValue($this->conditionMatcher, $resolverProphecy->reveal());
397  self::assertFalse($this->evaluateExpressionMethod->invokeArgs($this->conditionMatcher, ['ELSE']));
398  }
399 }
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest
Definition: AbstractConditionMatcherTest.php:45
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\$conditionMatcher
‪AbstractConditionMatcher PHPUnit Framework MockObject MockObject TYPO3 TestingFramework Core AccessibleObjectInterface $conditionMatcher
Definition: AbstractConditionMatcherTest.php:51
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:206
‪TYPO3\CMS\Core\Core\ApplicationContext
Definition: ApplicationContext.php:39
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\typoScriptElseConditionIsNotEvaluatedAndAlwaysReturnsFalse
‪typoScriptElseConditionIsNotEvaluatedAndAlwaysReturnsFalse()
Definition: AbstractConditionMatcherTest.php:387
‪TYPO3\CMS\Core\Core\SystemEnvironmentBuilder
Definition: SystemEnvironmentBuilder.php:41
‪TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher
Definition: ConditionMatcher.php:31
‪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:250
‪TYPO3\CMS\Core\Core\Environment\isWindows
‪static bool isWindows()
Definition: Environment.php:318
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\$evaluateExpressionMethod
‪ReflectionMethod $evaluateExpressionMethod
Definition: AbstractConditionMatcherTest.php:53
‪TYPO3\CMS\Core\Core\SystemEnvironmentBuilder\REQUESTTYPE_BE
‪const REQUESTTYPE_BE
Definition: SystemEnvironmentBuilder.php:45
‪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:139
‪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:47
‪TYPO3\CMS\Core\Core\Environment\getProjectPath
‪static string getProjectPath()
Definition: Environment.php:177
‪TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher
Definition: AbstractConditionMatcher.php:36
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\initConditionMatcher
‪initConditionMatcher()
Definition: AbstractConditionMatcherTest.php:87
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\requestFunctionDataProvider
‪array requestFunctionDataProvider()
Definition: AbstractConditionMatcherTest.php:104
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\notMatchingApplicationContextConditionsDataProvider
‪array notMatchingApplicationContextConditionsDataProvider()
Definition: AbstractConditionMatcherTest.php:277
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\setUp
‪setUp()
Definition: AbstractConditionMatcherTest.php:58
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\checkConditionMatcherForDateFunction
‪checkConditionMatcherForDateFunction(string $format, int $expressionValue, bool $expected)
Definition: AbstractConditionMatcherTest.php:178
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\matchingApplicationContextConditionsDataProvider
‪array matchingApplicationContextConditionsDataProvider()
Definition: AbstractConditionMatcherTest.php:235
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪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:111
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:37
‪TYPO3\CMS\Core\Core\Environment\getBackendPath
‪static string getBackendPath()
Definition: Environment.php:276
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\evaluateConditionCommonEvaluatesIpAddressesCorrectly
‪evaluateConditionCommonEvaluatesIpAddressesCorrectly($devIpMask, $actualIp, $expectedResult)
Definition: AbstractConditionMatcherTest.php:372
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\datesFunctionDataProvider
‪array datesFunctionDataProvider()
Definition: AbstractConditionMatcherTest.php:158
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:22
‪TYPO3\CMS\Core\ExpressionLanguage\ProviderConfigurationLoader
Definition: ProviderConfigurationLoader.php:29
‪TYPO3\CMS\Core\ExpressionLanguage\Resolver
Definition: Resolver.php:28
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:43
‪TYPO3\CMS\Core\Core\Environment\getConfigPath
‪static string getConfigPath()
Definition: Environment.php:236
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\evaluateConditionCommonDevIpMaskDataProvider
‪array evaluateConditionCommonDevIpMaskDataProvider()
Definition: AbstractConditionMatcherTest.php:319
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\evaluateConditionCommonReturnsNullForNotMatchingApplicationContexts
‪evaluateConditionCommonReturnsNullForNotMatchingApplicationContexts($notMatchingApplicationContextCondition)
Definition: AbstractConditionMatcherTest.php:293
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Context\DateTimeAspect
Definition: DateTimeAspect.php:35
‪TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcherTest\checkConditionMatcherForFeatureFunction
‪checkConditionMatcherForFeatureFunction()
Definition: AbstractConditionMatcherTest.php:192
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static string getVarPath()
Definition: Environment.php:218