‪TYPO3CMS  ‪main
AbstractMenuContentObjectTest.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 Doctrine\DBAL\Result;
21 use PHPUnit\Framework\Attributes\DataProvider;
22 use PHPUnit\Framework\Attributes\Test;
36 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
37 
38 final class ‪AbstractMenuContentObjectTest extends UnitTestCase
39 {
40  protected function ‪tearDown(): void
41  {
42  GeneralUtility::purgeInstances();
43  parent::tearDown();
44  }
45 
46  private function ‪prepareSectionIndexTest(): void
47  {
48  $connectionMock = $this->createMock(Connection::class);
49  $connectionMock->method('getExpressionBuilder')->willReturn(new ‪ExpressionBuilder($connectionMock));
50  $connectionMock->method('quoteIdentifier')->willReturnArgument(0)->withAnyParameters();
51  $connectionPoolMock = $this->createMock(ConnectionPool::class);
52  $connectionPoolMock->method('getConnectionForTable')->with('tt_content')->willReturn($connectionMock);
53  GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolMock);
54  }
55 
56  #[Test]
58  {
60  $pageRepository = $this->createMock(PageRepository::class);
61  $pageRepository->expects(self::once())->method('getPage')->willReturn([]);
62  $subject = new ‪AbstractMenuContentObjectFixture();
63  $subject->sys_page = $pageRepository;
64  self::assertEquals([], $subject->sectionIndex('field'));
65  }
66 
67  #[Test]
69  {
71  $pageRepository = $this->createMock(PageRepository::class);
72  $pageRepository->expects(self::once())->method('getPage')->with(10)->willReturn([]);
73  $subject = new ‪AbstractMenuContentObjectFixture();
74  $subject->sys_page = $pageRepository;
75  $subject->id = 10;
76  self::assertEquals([], $subject->sectionIndex('field'));
77  }
78 
79  #[Test]
81  {
82  $this->expectException(\UnexpectedValueException::class);
83  $this->expectExceptionCode(1337334849);
85  $pageRepository = $this->createMock(PageRepository::class);
86  $pageRepository->expects(self::once())->method('getPage')->willReturn(['uid' => 10]);
87  $cObject = $this->createMock(ContentObjectRenderer::class);
88  $cObject->expects(self::once())->method('exec_getQuery')->willReturn(0);
89  $subject = new ‪AbstractMenuContentObjectFixture();
90  $subject->sys_page = $pageRepository;
91  $subject->id = 10;
92  $subject->parent_cObj = $cObject;
93  $subject->sectionIndex('field');
94  }
95 
96  #[Test]
98  {
100  $statementMock = $this->createMock(Result::class);
101  $statementMock->expects(self::exactly(2))->method('fetchAssociative')->willReturn(['uid' => 0, 'header' => 'NOT_OVERLAID'], false);
102  $subject = new ‪AbstractMenuContentObjectFixture();
103  $subject->mconf = [
104  'sectionIndex.' => [
105  'type' => 'all',
106  ],
107  ];
108  $context = new ‪Context();
109  $context->setAspect('language', new ‪LanguageAspect(1, 1, ‪LanguageAspect::OVERLAYS_MIXED));
110  GeneralUtility::setSingletonInstance(Context::class, $context);
111  $pageRepository = $this->getMockBuilder(PageRepository::class)->setConstructorArgs([$context])->onlyMethods(['init', 'getPage', 'getLanguageOverlay'])->getMock();
112  $pageRepository->expects(self::once())->method('getPage')->willReturn(['sys_language_uid' => 1]);
113  $pageRepository->expects(self::once())->method('getLanguageOverlay')->willReturn(['uid' => 0, 'header' => 'OVERLAID']);
114  $subject->sys_page = $pageRepository;
115  $cObject = $this->createMock(ContentObjectRenderer::class);
116  $cObject->expects(self::once())->method('exec_getQuery')->willReturn($statementMock);
117  $subject->parent_cObj = $cObject;
118  $result = $subject->sectionIndex('field');
119  self::assertEquals('OVERLAID', $result[0]['title']);
120  }
121 
122  public static function ‪sectionIndexFiltersDataProvider(): array
123  {
124  return [
125  'unfiltered fields' => [
126  1,
127  [
128  'sectionIndex' => 1,
129  'header' => 'foo',
130  'header_layout' => 1,
131  ],
132  ],
133  'with unset section index' => [
134  0,
135  [
136  'sectionIndex' => 0,
137  'header' => 'foo',
138  'header_layout' => 1,
139  ],
140  ],
141  'with unset header' => [
142  0,
143  [
144  'sectionIndex' => 1,
145  'header' => '',
146  'header_layout' => 1,
147  ],
148  ],
149  'with header layout 100' => [
150  0,
151  [
152  'sectionIndex' => 1,
153  'header' => 'foo',
154  'header_layout' => 100,
155  ],
156  ],
157  ];
158  }
159 
160  #[DataProvider('sectionIndexFiltersDataProvider')]
161  #[Test]
162  public function ‪sectionIndexFilters(int $expectedAmount, array $dataRow): void
163  {
165  $statementMock = $this->createMock(Result::class);
166  $statementMock->method('fetchAssociative')->willReturn($dataRow, false);
167  $subject = new ‪AbstractMenuContentObjectFixture();
168  $subject->mconf = [
169  'sectionIndex.' => [
170  'type' => 'header',
171  ],
172  ];
173  $pageRepository = $this->createMock(PageRepository::class);
174  $pageRepository->expects(self::once())->method('getPage')->willReturn(['sys_language_uid' => 1]);
175  $pageRepository->expects(self::once())->method('getPage')->willReturn([]);
176  $subject->sys_page = $pageRepository;
177  $cObject = $this->createMock(ContentObjectRenderer::class);
178  $cObject->expects(self::once())->method('exec_getQuery')->willReturn($statementMock);
179  $subject->parent_cObj = $cObject;
180  self::assertCount($expectedAmount, $subject->sectionIndex('field'));
181  }
182 
184  {
185  return [
186  'no configuration' => [
187  [],
188  '0',
189  'colPos = 0',
190  ],
191  'with useColPos 2' => [
192  [
193  'useColPos' => 2,
194  ],
195  '2',
196  'colPos = 2',
197  ],
198  'with useColPos -1' => [
199  [
200  'useColPos' => -1,
201  ],
202  '-1',
203  '',
204  ],
205  'with stdWrap useColPos' => [
206  [
207  'useColPos.' => [
208  'wrap' => '2|',
209  ],
210  ],
211  '2',
212  'colPos = 2',
213  ],
214  ];
215  }
216 
217  #[DataProvider('sectionIndexQueriesWithDifferentColPosDataProvider')]
218  #[Test]
219  public function ‪sectionIndexQueriesWithDifferentColPos(array $configuration, string $colPosFromStdWrapValue, string $whereClausePrefix): void
220  {
222  $statementMock = $this->createMock(Result::class);
223  $statementMock->method('fetchAssociative')->willReturn([]);
224  $subject = new ‪AbstractMenuContentObjectFixture();
225  $subject->mconf = ['sectionIndex.' => $configuration];
226  $pageRepository = $this->getMockBuilder(PageRepository::class)->disableOriginalConstructor()->getMock();
227  $pageRepository->expects(self::once())->method('getPage')->willReturn(['uid' => 12]);
228  $subject->sys_page = $pageRepository;
229  $queryConfiguration = [
230  'pidInList' => 12,
231  'orderBy' => 'field',
232  'languageField' => 'sys_language_uid',
233  'where' => $whereClausePrefix,
234  ];
235  $cObject = $this->createMock(ContentObjectRenderer::class);
236  $cObject->expects(self::once())->method('stdWrapValue')->with('useColPos', $configuration)->willReturn($colPosFromStdWrapValue);
237  $cObject->expects(self::once())->method('exec_getQuery')->with('tt_content', $queryConfiguration)->willReturn($statementMock);
238  $subject->parent_cObj = $cObject;
239  $subject->sectionIndex('field', 12);
240  }
241 
242  public static function ‪isItemStateChecksExcludeUidListDataProvider(): array
243  {
244  return [
245  'none excluded' => [
246  [
247  [
248  'uid' => 12,
249  'pid' => 42,
250  ],
251  [
252  'uid' => 34,
253  'pid' => 42,
254  ],
255  [
256  'uid' => 56,
257  'pid' => 42,
258  ],
259  ],
260  '1, 23, 456',
261  true,
262  ],
263  'one excluded' => [
264  [
265  [
266  'uid' => 1,
267  'pid' => 42,
268  ],
269  [
270  'uid' => 234,
271  'pid' => 42,
272  ],
273  [
274  'uid' => 567,
275  'pid' => 42,
276  ],
277  ],
278  '1, 23, 456',
279  true,
280  ],
281  'three excluded' => [
282  [
283  [
284  'uid' => 1,
285  'pid' => 42,
286  ],
287  [
288  'uid' => 23,
289  'pid' => 42,
290  ],
291  [
292  'uid' => 456,
293  'pid' => 42,
294  ],
295  ],
296  '1, 23, 456',
297  false,
298  ],
299  'empty excludeList' => [
300  [
301  [
302  'uid' => 1,
303  'pid' => 42,
304  ],
305  [
306  'uid' => 123,
307  'pid' => 42,
308  ],
309  [
310  'uid' => 45,
311  'pid' => 42,
312  ],
313  ],
314  '',
315  true,
316  ],
317  'empty menu' => [
318  [],
319  '1, 23, 456',
320  false,
321  ],
322  ];
323  }
324 
325  #[DataProvider('isItemStateChecksExcludeUidListDataProvider')]
326  #[Test]
327  public function ‪isItemStateChecksExcludeUidList(array $menuItems, string $excludeUidList, bool $expectedResult): void
328  {
330  $request = new ‪ServerRequest();
331  $pageInformation = new ‪PageInformation();
332  $pageInformation->setPageRecord([]);
333  $request = $request->withAttribute('frontend.page.information', $pageInformation);
334  $subject = new ‪AbstractMenuContentObjectFixture();
335  $subject->request = $request;
336  $cObjectMock = $this->createMock(ContentObjectRenderer::class);
337  $cObjectMock->expects(self::once())->method('stdWrapValue')->with('excludeUidList', ['excludeUidList' => $excludeUidList])->willReturn($excludeUidList);
338  $typoScriptFrontendControllerMock = $this->createMock(TypoScriptFrontendController::class);
339  $cObjectMock->method('getTypoScriptFrontendController')->willReturn($typoScriptFrontendControllerMock);
340  $subject->parent_cObj = $cObjectMock;
341  $pageRepository = $this->createMock(PageRepository::class);
342  $pageRepository->expects(self::once())->method('getMenu')->willReturn($menuItems);
343  $subject->sys_page = $pageRepository;
344  $subject->menuArr = [
345  0 => ['uid' => 42],
346  ];
347  $subject->conf = ['excludeUidList' => $excludeUidList];
348  self::assertEquals($expectedResult, $subject->isItemState('IFSUB', 0));
349  }
350 
352  {
353  return [
354  'standard parameter without access protected setting' => [
355  [
356  'parameter' => 1,
357  ],
358  [
359  'showAccessRestrictedPages' => false,
360  ],
361  ['uid' => 1],
362  '',
363  0,
364  '',
365  ],
366  'standard parameter with access protected setting' => [
367  [
368  'parameter' => 10,
369  ],
370  [
371  'showAccessRestrictedPages' => true,
372  ],
373  ['uid' => 10],
374  '',
375  0,
376  '',
377  ],
378  'standard parameter with access protected setting "NONE" casts to boolean linkAccessRestrictedPages (delegates resolving to typoLink method internals)' => [
379  [
380  'parameter' => 10,
381  ],
382  [
383  'showAccessRestrictedPages' => 'NONE',
384  ],
385  ['uid' => 10],
386  '',
387  0,
388  '',
389  ],
390  'standard parameter with access protected setting (int)67 casts to boolean linkAccessRestrictedPages (delegates resolving to typoLink method internals)' => [
391  [
392  'parameter' => 10,
393  ],
394  [
395  'showAccessRestrictedPages' => 67,
396  ],
397  ['uid' => 10],
398  '',
399  0,
400  '',
401  ],
402  'standard parameter with target' => [
403  [
404  'parameter' => 1,
405  'target' => '_blank',
406  ],
407  [
408  'showAccessRestrictedPages' => false,
409  ],
410  ['uid' => 1],
411  '_blank',
412  0,
413  '',
414  ],
415  'parameter with typeOverride=10' => [
416  [
417  'parameter' => '10,10',
418  ],
419  [
420  'showAccessRestrictedPages' => false,
421  ],
422  ['uid' => 10],
423  '',
424  '',
425  10,
426  ],
427  'parameter with target and typeOverride=10' => [
428  [
429  'parameter' => '10,10',
430  'target' => '_self',
431  ],
432  [
433  'showAccessRestrictedPages' => false,
434  ],
435  ['uid' => 10],
436  '_self',
437  '',
438  '10',
439  ],
440  'parameter with invalid value in typeOverride=foobar ignores typeOverride' => [
441  [
442  'parameter' => 20,
443  'target' => '_self',
444  ],
445  [
446  'showAccessRestrictedPages' => false,
447  ],
448  ['uid' => 20],
449  '_self',
450  '',
451  'foobar',
452  20,
453  ],
454  'standard parameter with section name' => [
455  [
456  'parameter' => 10,
457  'target' => '_blank',
458  'section' => 'section-name',
459  ],
460  [
461  'showAccessRestrictedPages' => false,
462  ],
463  [
464  'uid' => 10,
465  'sectionIndex_uid' => 'section-name',
466  ],
467  '_blank',
468  '',
469  '',
470  ],
471  'standard parameter with additional parameters' => [
472  [
473  'parameter' => 10,
474  'section' => 'section-name',
475  'additionalParams' => '&test=foobar',
476  ],
477  [
478  'showAccessRestrictedPages' => false,
479  ],
480  [
481  'uid' => 10,
482  'sectionIndex_uid' => 'section-name',
483  ],
484  '',
485  '&test=foobar',
486  '',
487  ],
488  'overridden page array uid value gets used as parameter' => [
489  [
490  'parameter' => 99,
491  'section' => 'section-name',
492  ],
493  [
494  'showAccessRestrictedPages' => false,
495  ],
496  [
497  'uid' => 10,
498  'sectionIndex_uid' => 'section-name',
499  ],
500  '',
501  '',
502  '',
503  99,
504  ],
505  ];
506  }
507 
508  #[DataProvider('menuTypoLinkCreatesExpectedTypoLinkConfigurationDataProvider')]
509  #[Test]
510  public function ‪menuTypoLinkCreatesExpectedTypoLinkConfiguration(array $expected, array $mconf, array $page, string $oTarget, string|int $addParams = '', string|int $typeOverride = '', int|string|null $overrideId = null): void
511  {
512  $expected['page'] = new ‪Page($page);
513  $cObject = $this->createMock(ContentObjectRenderer::class);
514  $cObject->expects(self::once())->method('createLink')->with('|', $expected);
515  $subject = new ‪AbstractMenuContentObjectFixture();
516  $subject->parent_cObj = $cObject;
517  $subject->mconf = $mconf;
518  $subject->menuTypoLink($page, $oTarget, $addParams, $typeOverride, $overrideId);
519  }
520 }
‪TYPO3\CMS\Core\Domain\Page
Definition: Page.php:24
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:40
‪TYPO3\CMS\Core\Context\LanguageAspect\OVERLAYS_MIXED
‪const OVERLAYS_MIXED
Definition: LanguageAspect.php:75
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\sectionIndexReturnsOverlaidRowBasedOnTheLanguageOfTheGivenPage
‪sectionIndexReturnsOverlaidRowBasedOnTheLanguageOfTheGivenPage()
Definition: AbstractMenuContentObjectTest.php:97
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\isItemStateChecksExcludeUidList
‪isItemStateChecksExcludeUidList(array $menuItems, string $excludeUidList, bool $expectedResult)
Definition: AbstractMenuContentObjectTest.php:327
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\sectionIndexUsesTheInternalIdIfNoPageIdWasGiven
‪sectionIndexUsesTheInternalIdIfNoPageIdWasGiven()
Definition: AbstractMenuContentObjectTest.php:68
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:54
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\sectionIndexFiltersDataProvider
‪static sectionIndexFiltersDataProvider()
Definition: AbstractMenuContentObjectTest.php:122
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\sectionIndexFilters
‪sectionIndexFilters(int $expectedAmount, array $dataRow)
Definition: AbstractMenuContentObjectTest.php:162
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\menuTypoLinkCreatesExpectedTypoLinkConfigurationDataProvider
‪static menuTypoLinkCreatesExpectedTypoLinkConfigurationDataProvider()
Definition: AbstractMenuContentObjectTest.php:351
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\tearDown
‪tearDown()
Definition: AbstractMenuContentObjectTest.php:40
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\Fixtures\AbstractMenuContentObjectFixture
Definition: AbstractMenuContentObjectFixture.php:25
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:39
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\sectionIndexReturnsEmptyArrayIfTheRequestedPageCouldNotBeFetched
‪sectionIndexReturnsEmptyArrayIfTheRequestedPageCouldNotBeFetched()
Definition: AbstractMenuContentObjectTest.php:57
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\isItemStateChecksExcludeUidListDataProvider
‪static isItemStateChecksExcludeUidListDataProvider()
Definition: AbstractMenuContentObjectTest.php:242
‪TYPO3\CMS\Core\Context\LanguageAspect
Definition: LanguageAspect.php:57
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest
Definition: AbstractMenuContentObjectTest.php:39
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\menuTypoLinkCreatesExpectedTypoLinkConfiguration
‪menuTypoLinkCreatesExpectedTypoLinkConfiguration(array $expected, array $mconf, array $page, string $oTarget, string|int $addParams='', string|int $typeOverride='', int|string|null $overrideId=null)
Definition: AbstractMenuContentObjectTest.php:510
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:58
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\sectionIndexQueriesWithDifferentColPosDataProvider
‪static sectionIndexQueriesWithDifferentColPosDataProvider()
Definition: AbstractMenuContentObjectTest.php:183
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\sectionIndexQueriesWithDifferentColPos
‪sectionIndexQueriesWithDifferentColPos(array $configuration, string $colPosFromStdWrapValue, string $whereClausePrefix)
Definition: AbstractMenuContentObjectTest.php:219
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:103
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\prepareSectionIndexTest
‪prepareSectionIndexTest()
Definition: AbstractMenuContentObjectTest.php:46
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:69
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu\AbstractMenuContentObjectTest\sectionIndexThrowsAnExceptionIfTheInternalQueryFails
‪sectionIndexThrowsAnExceptionIfTheInternalQueryFails()
Definition: AbstractMenuContentObjectTest.php:80
‪TYPO3\CMS\Frontend\Tests\Unit\ContentObject\Menu
Definition: AbstractMenuContentObjectTest.php:18
‪TYPO3\CMS\Frontend\Page\PageInformation
Definition: PageInformation.php:30