[TASK] Streamline expressionLanguage usage in core
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Tests / Unit / Configuration / TypoScript / ConditionMatching / ConditionMatcherTest.php
1 <?php
2 namespace TYPO3\CMS\Backend\Tests\Unit\Configuration\TypoScript\ConditionMatching;
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 TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher;
19 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
20 use TYPO3\CMS\Core\Cache\CacheManager;
21 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
22 use TYPO3\CMS\Core\Context\Context;
23 use TYPO3\CMS\Core\Context\UserAspect;
24 use TYPO3\CMS\Core\Http\ServerRequest;
25 use TYPO3\CMS\Core\Log\Logger;
26 use TYPO3\CMS\Core\Package\PackageInterface;
27 use TYPO3\CMS\Core\Package\PackageManager;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29
30 /**
31 * Testcase for class \TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher.
32 */
33 class ConditionMatcherTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
34 {
35 /**
36 * @var array
37 */
38 protected $rootline;
39
40 /**
41 * @var \TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher
42 */
43 protected $matchCondition;
44
45 /**
46 * @var string
47 */
48 protected $testGlobalNamespace;
49
50 /**
51 * @var string
52 */
53 protected $testTableName;
54
55 /**
56 * @var bool Reset singletons
57 */
58 protected $resetSingletonInstances = true;
59
60 /**
61 * Set up tests
62 */
63 protected function setUp()
64 {
65 $GLOBALS['TYPO3_REQUEST'] = new ServerRequest();
66 $cacheFrontendProphecy = $this->prophesize(FrontendInterface::class);
67 $cacheFrontendProphecy->has(Argument::any())->willReturn(false);
68 $cacheFrontendProphecy->set(Argument::any(), Argument::any())->willReturn(null);
69 $cacheManagerProphecy = $this->prophesize(CacheManager::class);
70 $cacheManagerProphecy->getCache('cache_core')->willReturn($cacheFrontendProphecy->reveal());
71 GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
72
73 $packageManagerProphecy = $this->prophesize(PackageManager::class);
74 $corePackageProphecy = $this->prophesize(PackageInterface::class);
75 $corePackageProphecy->getPackagePath()->willReturn(__DIR__ . '/../../../../../../../sysext/core/');
76 $packageManagerProphecy->getActivePackages()->willReturn([
77 $corePackageProphecy->reveal()
78 ]);
79 GeneralUtility::setSingletonInstance(PackageManager::class, $packageManagerProphecy->reveal());
80
81 $this->testTableName = 'conditionMatcherTestTable';
82 $this->testGlobalNamespace = $this->getUniqueId('TEST');
83 $GLOBALS['TCA'][$this->testTableName] = ['ctrl' => []];
84 $GLOBALS[$this->testGlobalNamespace] = [];
85 $this->setUpBackend();
86 $this->matchCondition = $this->getAccessibleMock(ConditionMatcher::class, ['determineRootline'], [], '', false);
87 $this->matchCondition->method('determineRootline')->willReturn([
88 2 => ['uid' => 121, 'pid' => 111],
89 1 => ['uid' => 111, 'pid' => 101],
90 0 => ['uid' => 101, 'pid' => 0]
91 ]);
92 $this->matchCondition->__construct();
93 $loggerProphecy = $this->prophesize(Logger::class);
94 $this->matchCondition->setLogger($loggerProphecy->reveal());
95 }
96
97 /**
98 * Set up a backend
99 */
100 private function setUpBackend()
101 {
102 $this->rootline = [
103 2 => ['uid' => 121, 'pid' => 111],
104 1 => ['uid' => 111, 'pid' => 101],
105 0 => ['uid' => 101, 'pid' => 0]
106 ];
107 $GLOBALS['BE_USER'] = $this->getMockBuilder(BackendUserAuthentication::class)
108 ->setMethods(['dummy'])
109 ->disableOriginalConstructor()
110 ->getMock();
111 $GLOBALS['BE_USER']->groupList = '13,14,15';
112 $GLOBALS['BE_USER']->user['uid'] = 13;
113 $GLOBALS['BE_USER']->user['admin'] = 1;
114
115 GeneralUtility::makeInstance(Context::class)
116 ->setAspect('backend.user', new UserAspect($GLOBALS['BE_USER']));
117 }
118
119 /**
120 * Set up database mock
121 */
122 private function setUpDatabaseMockForDeterminePageId()
123 {
124 $this->matchCondition = $this->getAccessibleMock(ConditionMatcher::class, ['determineRootline', 'determinePageId'], [], '', false);
125 $this->matchCondition->method('determineRootline')->willReturn([
126 2 => ['uid' => 121, 'pid' => 111],
127 1 => ['uid' => 111, 'pid' => 101],
128 0 => ['uid' => 101, 'pid' => 0]
129 ]);
130 $this->matchCondition->__construct();
131 $loggerProphecy = $this->prophesize(Logger::class);
132 $this->matchCondition->setLogger($loggerProphecy->reveal());
133
134 $this->matchCondition->expects($this->once())->method('determinePageId')->willReturn(999);
135 }
136
137 /**
138 * Tests whether usergroup comparison matches.
139 *
140 * @test
141 */
142 public function usergroupConditionMatchesSingleGroupId()
143 {
144 $this->assertTrue($this->matchCondition->match('[usergroup(13)]'));
145 $this->assertTrue($this->matchCondition->match('[usergroup("13")]'));
146 $this->assertTrue($this->matchCondition->match('[usergroup(\'13\')]'));
147 }
148
149 /**
150 * Tests whether usergroup comparison matches.
151 *
152 * @test
153 */
154 public function usergroupConditionMatchesMultipleUserGroupId()
155 {
156 $this->assertTrue($this->matchCondition->match('[usergroup("999,15,14,13")]'));
157 $this->assertTrue($this->matchCondition->match('[usergroup(\'999,15,14,13\')]'));
158 }
159
160 /**
161 * Tests whether user comparison matches.
162 *
163 * @test
164 */
165 public function loginUserConditionMatchesAnyLoggedInUser()
166 {
167 $this->assertTrue($this->matchCondition->match('[loginUser("*")]'));
168 $this->assertTrue($this->matchCondition->match('[loginUser(\'*\')]'));
169 }
170
171 /**
172 * Tests whether user comparison matches.
173 *
174 * @test
175 */
176 public function loginUserConditionMatchesSingleLoggedInUser()
177 {
178 $this->assertTrue($this->matchCondition->match('[loginUser(13)]'));
179 $this->assertTrue($this->matchCondition->match('[loginUser("13")]'));
180 $this->assertTrue($this->matchCondition->match('[loginUser(\'13\')]'));
181 }
182
183 /**
184 * Tests whether user comparison matches.
185 *
186 * @test
187 */
188 public function loginUserConditionDoesNotMatchSingleLoggedInUser()
189 {
190 $GLOBALS['BE_USER']->user['uid'] = 13;
191 $this->assertFalse($this->matchCondition->match('[loginUser(999)]'));
192 $this->assertFalse($this->matchCondition->match('[loginUser("999")]'));
193 $this->assertFalse($this->matchCondition->match('[loginUser(\'999\')]'));
194 }
195
196 /**
197 * Tests whether user comparison matches.
198 *
199 * @test
200 */
201 public function loginUserConditionMatchesMultipleLoggedInUsers()
202 {
203 $this->assertTrue($this->matchCondition->match('[loginUser("999,13")]'));
204 $this->assertTrue($this->matchCondition->match('[loginUser(\'999,13\')]'));
205 }
206
207 /**
208 * Tests whether checkinf for an admin user matches
209 *
210 * @test
211 */
212 public function adminUserConditionMatchesAdminUser()
213 {
214 $this->assertTrue($this->matchCondition->match('[backend.user.isAdmin == true]'));
215 $this->assertTrue($this->matchCondition->match('[backend.user.isAdmin != false]'));
216 $this->assertTrue($this->matchCondition->match('[backend.user.isAdmin]'));
217 }
218
219 /**
220 * Tests whether treeLevel comparison matches.
221 *
222 * @test
223 */
224 public function treeLevelConditionMatchesSingleValue()
225 {
226 $this->matchCondition->setRootline($this->rootline);
227 $this->assertTrue($this->matchCondition->match('[tree.level == 2]'));
228 }
229
230 /**
231 * Tests whether treeLevel comparison matches.
232 *
233 * @test
234 */
235 public function treeLevelConditionMatchesMultipleValues()
236 {
237 $this->matchCondition->setRootline($this->rootline);
238 $this->assertTrue($this->matchCondition->match('[tree.level in [999,998,2]]'));
239 }
240
241 /**
242 * Tests whether treeLevel comparison matches.
243 *
244 * @test
245 */
246 public function treeLevelConditionDoesNotMatchFaultyValue()
247 {
248 $this->matchCondition->setRootline($this->rootline);
249 $this->assertFalse($this->matchCondition->match('[tree.level == 999]'));
250 }
251
252 /**
253 * Tests whether a page Id is found in the previous rootline entries.
254 *
255 * @test
256 */
257 public function PIDupinRootlineConditionMatchesSinglePageIdInRootline()
258 {
259 $this->matchCondition->setRootline($this->rootline);
260 $this->matchCondition->setPageId(121);
261 $this->assertTrue($this->matchCondition->match('[111 in tree.rootLineIds]'));
262 $this->assertTrue($this->matchCondition->match('["111" in tree.rootLineIds]'));
263 $this->assertTrue($this->matchCondition->match('[\'111\' in tree.rootLineIds]'));
264 }
265
266 /**
267 * Tests whether a page Id is found in the previous rootline entries.
268 *
269 * @test
270 */
271 public function PIDupinRootlineConditionDoesNotMatchPageIdNotInRootline()
272 {
273 $this->matchCondition->setRootline($this->rootline);
274 $this->matchCondition->setPageId(121);
275 $this->assertFalse($this->matchCondition->match('[999 in tree.rootLineIds]'));
276 }
277
278 /**
279 * Tests whether a page Id is found in all rootline entries.
280 *
281 * @test
282 */
283 public function PIDinRootlineConditionMatchesSinglePageIdInRootline()
284 {
285 $this->matchCondition->setRootline($this->rootline);
286 $this->matchCondition->setPageId(121);
287 $this->assertTrue($this->matchCondition->match('[111 in tree.rootLineIds]'));
288 }
289
290 /**
291 * Tests whether a page Id is found in all rootline entries.
292 *
293 * @test
294 */
295 public function PIDinRootlineConditionMatchesLastPageIdInRootline()
296 {
297 $this->matchCondition->setRootline($this->rootline);
298 $this->matchCondition->setPageId(121);
299 $this->assertTrue($this->matchCondition->match('[121 in tree.rootLineIds]'));
300 }
301
302 /**
303 * Tests whether a page Id is found in all rootline entries.
304 *
305 * @test
306 */
307 public function PIDinRootlineConditionDoesNotMatchPageIdNotInRootline()
308 {
309 $this->matchCondition->setRootline($this->rootline);
310 $this->matchCondition->setPageId(121);
311 $this->assertFalse($this->matchCondition->match('[999 in tree.rootLineIds]'));
312 }
313
314 /**
315 * Tests whether the compatibility version can be evaluated.
316 * (e.g. 7.9 is compatible to 7.0 but not to 15.0)
317 *
318 * @test
319 */
320 public function compatVersionConditionMatchesOlderRelease()
321 {
322 $this->assertTrue($this->matchCondition->match('[compatVersion(7.0)]'));
323 $this->assertTrue($this->matchCondition->match('[compatVersion("7.0")]'));
324 $this->assertTrue($this->matchCondition->match('[compatVersion(\'7.0\')]'));
325 }
326
327 /**
328 * Tests whether the compatibility version can be evaluated.
329 * (e.g. 7.9 is compatible to 7.0 but not to 15.0)
330 *
331 * @test
332 */
333 public function compatVersionConditionMatchesSameRelease()
334 {
335 $this->assertTrue($this->matchCondition->match('[compatVersion(' . TYPO3_branch . ')]'));
336 $this->assertTrue($this->matchCondition->match('[compatVersion("' . TYPO3_branch . '")]'));
337 $this->assertTrue($this->matchCondition->match('[compatVersion(\'' . TYPO3_branch . '\')]'));
338 }
339
340 /**
341 * Tests whether the compatibility version can be evaluated.
342 * (e.g. 7.9 is compatible to 7.0 but not to 15.0)
343 *
344 * @test
345 */
346 public function compatVersionConditionDoesNotMatchNewerRelease()
347 {
348 $this->assertFalse($this->matchCondition->match('[compatVersion(15.0)]'));
349 $this->assertFalse($this->matchCondition->match('[compatVersion("15.0")]'));
350 $this->assertFalse($this->matchCondition->match('[compatVersion(\'15.0\')]'));
351 }
352
353 /**
354 * Tests whether the generic fetching of variables works with the namespace 'ENV'.
355 *
356 * @test
357 */
358 public function genericGetVariablesSucceedsWithNamespaceENV()
359 {
360 $testKey = $this->getUniqueId('test');
361 putenv($testKey . '=testValue');
362 $this->assertTrue($this->matchCondition->match('[getenv("' . $testKey . '") == "testValue"]'));
363 }
364 }