‪TYPO3CMS  ‪main
DatabaseIntegrityControllerTest.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 PHPUnit\Framework\Attributes\DataProvider;
21 use PHPUnit\Framework\Attributes\Test;
32 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
33 
34 final class ‪DatabaseIntegrityControllerTest extends FunctionalTestCase
35 {
36  protected array ‪$coreExtensionsToLoad = [
37  'lowlevel',
38  ];
39 
40  protected function ‪setUp(): void
41  {
42  parent::setUp();
43  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
44  $this->setUpBackendUser(1);
45  ‪$GLOBALS['LANG'] = $this->get(LanguageServiceFactory::class)->create('default');
46  }
47 
48  #[Test]
50  {
51  $id = 1;
52  $depth = 0;
53  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
54  $treeList = $subject->_call('getTreeList', $id, $depth);
55  self::assertEquals($id, $treeList);
56  }
57 
58  #[Test]
60  {
61  $id = 0;
62  $depth = 1;
63  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
64  $treeList = $subject->_call('getTreeList', $id, $depth);
65  self::assertEquals($id, $treeList);
66  }
67 
68  #[Test]
70  {
71  $id = -1;
72  $depth = 0;
73  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
74  $treeList = $subject->_call('getTreeList', $id, $depth);
75  self::assertEquals(1, $treeList);
76  }
77 
78  #[Test]
80  {
81  $id = 0;
82  $depth = 0;
83  $begin = 1;
84  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
85  $treeList = $subject->_call('getTreeList', $id, $depth, $begin);
86  self::assertSame('', $treeList);
87  }
88 
89  #[Test]
91  {
92  $id = 1;
93  $depth = 1;
94  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
95  $treeList = $subject->_call('getTreeList', $id, $depth);
96  self::assertEquals($id, $treeList);
97  }
98 
99  #[Test]
100  public function ‪getTreeListRespectsPermClauses(): void
101  {
102  $this->importCSVDataSet(__DIR__ . '/Fixtures/TestGetPageTreeStraightTreeSet.csv');
103  $id = 1;
104  $depth = 99;
105  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
106  $treeList = $subject->_call('getTreeList', $id, $depth, 0, 'hidden=0');
107  self::assertSame('1,2,3,4,5', $treeList);
108  }
109 
111  {
112  return [
113  [
114  1, // id
115  1, // depth
116  '1,2', // expectation
117  ],
118  [
119  1,
120  2,
121  '1,2,3',
122  ],
123  [
124  1,
125  99,
126  '1,2,3,4,5,6',
127  ],
128  [
129  2,
130  1,
131  '2,3',
132  ],
133  ];
134  }
135 
136  #[DataProvider('dataForGetTreeListReturnsListOfIdsWithBeginSetToZero')]
137  #[Test]
138  public function ‪getTreeListReturnsListOfIdsWithBeginSetToZero(int $id, int $depth, string $expectation): void
139  {
140  $this->importCSVDataSet(__DIR__ . '/Fixtures/TestGetPageTreeStraightTreeSet.csv');
141  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
142  $treeList = $subject->_call('getTreeList', $id, $depth);
143  self::assertSame($expectation, $treeList);
144  }
145 
147  {
148  return [
149  [
150  1, // id
151  1, // depth
152  ',2', // expectation
153  ],
154  [
155  1,
156  2,
157  ',2,3',
158  ],
159  [
160  1,
161  99,
162  ',2,3,4,5,6',
163  ],
164  [
165  2,
166  1,
167  ',3',
168  ],
169  ];
170  }
171 
172  #[DataProvider('dataForGetTreeListReturnsListOfIdsWithBeginSetToMinusOne')]
173  #[Test]
174  public function ‪getTreeListReturnsListOfIdsWithBeginSetToMinusOne(int $id, int $depth, string $expectation): void
175  {
176  $this->importCSVDataSet(__DIR__ . '/Fixtures/TestGetPageTreeStraightTreeSet.csv');
177  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
178  $treeList = $subject->_call('getTreeList', $id, $depth, -1);
179  self::assertSame($expectation, $treeList);
180  }
181 
182  #[Test]
184  {
185  $id = 1;
186  $depth = 3;
187  $this->importCSVDataSet(__DIR__ . '/Fixtures/TestGetPageTreeBranchedTreeSet.csv');
188  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
189  $treeList = $subject->_call('getTreeList', $id, $depth);
190  self::assertSame('1,2,3,4,5', $treeList);
191  }
192 
193  #[Test]
195  {
196  $id = 1;
197  $depth = 3;
198  $begin = 1;
199  $this->importCSVDataSet(__DIR__ . '/Fixtures/TestGetPageTreeBranchedTreeSet.csv');
200  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
201  $treeList = $subject->_call('getTreeList', $id, $depth, $begin);
202  self::assertSame('2,3,4,5', $treeList);
203  }
204 
205  #[Test]
207  {
208  $id = 1;
209  $depth = 3;
210  $begin = 2;
211  $this->importCSVDataSet(__DIR__ . '/Fixtures/TestGetPageTreeBranchedTreeSet.csv');
212  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
213  $treeList = $subject->_call('getTreeList', $id, $depth, $begin);
214  self::assertSame('3,5', $treeList);
215  }
216 
217  public static function ‪getQueryWithIdOrDateDataProvider(): array
218  {
219  return [
220  'pid 5134' => [
221  5134,
222  null,
223  "pid = '5134'",
224  ],
225  'unix timestamp' => [
226  1522863047,
227  null,
228  "pid = '1522863047'",
229  ],
230  'pid 5134 as string' => [
231  '5134',
232  null,
233  "pid = '5134'",
234  ],
235  'unix timestamp as string' => [
236  '1522863047',
237  null,
238  "pid = '1522863047'",
239  ],
240  'ISO 8601 date string' => [
241  '2018-04-04T17:30:47Z',
242  null,
243  "pid = '1522863047'",
244  ],
245  'pid 5134 and second input value 5135' => [
246  5134,
247  5135,
248  'pid >= 5134 AND pid <= 5135',
249  'comparison' => 100,
250  ],
251  'ISO 8601 date string as first and second input' => [
252  '2018-04-04T17:30:47Z',
253  '2018-04-04T17:30:48Z',
254  'pid >= 1522863047 AND pid <= 1522863048',
255  'comparison' => 100,
256  ],
257  ];
258  }
259 
260  #[DataProvider('getQueryWithIdOrDateDataProvider')]
261  #[Test]
262  public function ‪getQueryWithIdOrDate(mixed $inputValue, mixed $inputValue1, string $expected, int $comparison = 64): void
263  {
264  ‪$GLOBALS['TCA'] = [
265  'aTable' => [
266  'columns' => [],
267  ],
268  ];
269  $inputConf = [
270  [
271  'operator' => '',
272  'type' => 'FIELD_pid',
273  'comparison' => $comparison,
274  'inputValue' => $inputValue,
275  'inputValue1' => $inputValue1,
276  ],
277  ];
278  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [], '', false);
279  $subject->_call('init', 'queryConfig', 'aTable');
280  self::assertSame($expected, trim($subject->_call('getQuery', $inputConf), "\n\r"));
281  }
282 
283  public static function ‪arbitraryDataIsEscapedDataProvider(): array
284  {
285  $dataSet = [];
286  $injectors = [
287  // INJ'ECT
288  'INJ%quoteCharacter%ECT',
289  // INJ '--
290  // ' ECT
291  'INJ %quoteCharacter%%commentStart% %commentEnd%%quoteCharacter% ECT',
292  ];
293  $subjectReflection = new \ReflectionClass(DatabaseIntegrityController::class);
294  $comparisons = array_keys($subjectReflection->getProperty('compSQL')->getDefaultValue());
295  foreach ($injectors as $injector) {
296  foreach ($comparisons as $comparison) {
297  $dataSet[] = [
298  $injector,
299  [
300  'queryTable' => 'tt_content',
301  'queryFields' => 'uid,' . $injector,
302  'queryGroup' => $injector,
303  'queryOrder' => $injector,
304  'queryLimit' => $injector,
305  'queryConfig' => [
306  [
307  'operator' => $injector,
308  'type' => 'FIELD_category_field', // falls back to CType (first field)
309  'comparison' => $comparison,
310  'inputValue' => $injector,
311  ],
312  [
313  'operator' => $injector,
314  'type' => 'FIELD_category_field',
315  'comparison' => $comparison,
316  'inputValue' => $injector,
317  ],
318  ],
319  ],
320  ];
321  }
322  }
323  return $dataSet;
324  }
325 
326  #[DataProvider('arbitraryDataIsEscapedDataProvider')]
327  #[Test]
328  public function ‪arbitraryDataIsEscaped(string $injector, array $settings): void
329  {
330  $replacements = [
331  '%quoteCharacter%' => "'",
332  '%commentStart%' => '--',
333  '%commentEnd%' => "\n",
334  ];
335  $injector = str_replace(array_keys($replacements), $replacements, $injector);
336  $settings = $this->‪prepareSettings($settings, $replacements);
337  $settings['queryConfig'] = serialize($settings['queryConfig']);
338 
339  $iconMock = $this->getMockBuilder(Icon::class)->getMock();
340  $iconMock->method('render')->willReturn('');
341 
342  $iconFactoryMock = $this->getMockBuilder(IconFactory::class)->disableOriginalConstructor()->getMock();
343  $iconFactoryMock->method('getIcon')->willReturn($iconMock);
344 
345  $route = GeneralUtility::makeInstance(Router::class)->getRoute('system_dbint');
346  $route->setOption('_identifier', 'system_dbint');
347  $request = (new ‪ServerRequest())->withAttribute('route', $route);
348 
349  $subject = $this->getAccessibleMock(DatabaseIntegrityController::class, null, [
350  $iconFactoryMock,
351  GeneralUtility::makeInstance(UriBuilder::class),
352  GeneralUtility::makeInstance(ModuleTemplateFactory::class),
353  GeneralUtility::makeInstance(PlatformHelper::class),
354  ]);
355  $subject->_call('init', 'queryConfig', $settings['queryTable']);
356  $subject->_call('makeSelectorTable', $settings, $request);
357  $subject->_set('enablePrefix', true);
358 
359  $queryString = $subject->_call('getQuery', $subject->_get('queryConfig'));
360  $query = $subject->_call('getSelectQuery', $queryString);
361 
362  self::assertStringNotContainsString($injector, $query);
363  }
364 
365  private function ‪prepareSettings(array $settings, array $replacements): array
366  {
367  foreach ($settings as $settingKey => &$settingValue) {
368  if (is_string($settingValue)) {
369  $settingValue = str_replace(array_keys($replacements), $replacements, $settingValue);
370  }
371  if (is_array($settingValue)) {
372  $settingValue = $this->‪prepareSettings($settingValue, $replacements);
373  }
374  }
375  return $settings;
376  }
377 }
‪TYPO3\CMS\Core\Localization\LanguageServiceFactory
Definition: LanguageServiceFactory.php:25
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\arbitraryDataIsEscaped
‪arbitraryDataIsEscaped(string $injector, array $settings)
Definition: DatabaseIntegrityControllerTest.php:328
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getTreeListReturnsIngoingIdIfIdIsZero
‪getTreeListReturnsIngoingIdIfIdIsZero()
Definition: DatabaseIntegrityControllerTest.php:59
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getTreeListReturnsListOfIdsWithBeginSetToZero
‪getTreeListReturnsListOfIdsWithBeginSetToZero(int $id, int $depth, string $expectation)
Definition: DatabaseIntegrityControllerTest.php:138
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:27
‪TYPO3\CMS\Backend\Template\ModuleTemplateFactory
Definition: ModuleTemplateFactory.php:33
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\arbitraryDataIsEscapedDataProvider
‪static arbitraryDataIsEscapedDataProvider()
Definition: DatabaseIntegrityControllerTest.php:283
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest
Definition: DatabaseIntegrityControllerTest.php:35
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\prepareSettings
‪prepareSettings(array $settings, array $replacements)
Definition: DatabaseIntegrityControllerTest.php:365
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getQueryWithIdOrDate
‪getQueryWithIdOrDate(mixed $inputValue, mixed $inputValue1, string $expected, int $comparison=64)
Definition: DatabaseIntegrityControllerTest.php:262
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:34
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\setUp
‪setUp()
Definition: DatabaseIntegrityControllerTest.php:40
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getTreeListReturnsEmptyStringIfIdAndDepthAreZeroAndBeginDoesNotEqualZero
‪getTreeListReturnsEmptyStringIfIdAndDepthAreZeroAndBeginDoesNotEqualZero()
Definition: DatabaseIntegrityControllerTest.php:79
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\$coreExtensionsToLoad
‪array $coreExtensionsToLoad
Definition: DatabaseIntegrityControllerTest.php:36
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\dataForGetTreeListReturnsListOfIdsWithBeginSetToMinusOne
‪static dataForGetTreeListReturnsListOfIdsWithBeginSetToMinusOne()
Definition: DatabaseIntegrityControllerTest.php:146
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getQueryWithIdOrDateDataProvider
‪static getQueryWithIdOrDateDataProvider()
Definition: DatabaseIntegrityControllerTest.php:217
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getTreeListRespectsPermClauses
‪getTreeListRespectsPermClauses()
Definition: DatabaseIntegrityControllerTest.php:100
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getTreeListReturnsPositiveIngoingIdIfIdIsNegative
‪getTreeListReturnsPositiveIngoingIdIfIdIsNegative()
Definition: DatabaseIntegrityControllerTest.php:69
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller
Definition: DatabaseIntegrityControllerTest.php:18
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getTreeListReturnsListOfPageIdsOfABranchedTreeWithBeginSetToZero
‪getTreeListReturnsListOfPageIdsOfABranchedTreeWithBeginSetToZero()
Definition: DatabaseIntegrityControllerTest.php:183
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getTreeListReturnsIncomingIdIfNoSubPageRecordsOfThatIdExist
‪getTreeListReturnsIncomingIdIfNoSubPageRecordsOfThatIdExist()
Definition: DatabaseIntegrityControllerTest.php:90
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:44
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:39
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getTreeListReturnsListOfPageIdsOfABranchedTreeWithBeginSetToOne
‪getTreeListReturnsListOfPageIdsOfABranchedTreeWithBeginSetToOne()
Definition: DatabaseIntegrityControllerTest.php:194
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getTreeListReturnsListOfPageIdsOfABranchedTreeWithBeginSetToTwo
‪getTreeListReturnsListOfPageIdsOfABranchedTreeWithBeginSetToTwo()
Definition: DatabaseIntegrityControllerTest.php:206
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getTreeListReturnsListOfIdsWithBeginSetToMinusOne
‪getTreeListReturnsListOfIdsWithBeginSetToMinusOne(int $id, int $depth, string $expectation)
Definition: DatabaseIntegrityControllerTest.php:174
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\getTreeListReturnsIngoingIdIfDepthIsZero
‪getTreeListReturnsIngoingIdIfDepthIsZero()
Definition: DatabaseIntegrityControllerTest.php:49
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Backend\Routing\Router
Definition: Router.php:40
‪TYPO3\CMS\Lowlevel\Controller\DatabaseIntegrityController
Definition: DatabaseIntegrityController.php:69
‪TYPO3\CMS\Lowlevel\Tests\Functional\Controller\DatabaseIntegrityControllerTest\dataForGetTreeListReturnsListOfIdsWithBeginSetToZero
‪static dataForGetTreeListReturnsListOfIdsWithBeginSetToZero()
Definition: DatabaseIntegrityControllerTest.php:110
‪TYPO3\CMS\Core\Database\Platform\PlatformHelper
Definition: PlatformHelper.php:26