diff --git a/typo3/sysext/core/Tests/Functional/Utility/File/ExtendedFileUtilityTest.php b/typo3/sysext/core/Tests/Functional/Utility/File/ExtendedFileUtilityTest.php index dba6efe0d743cb1421f66f0065faebd7733d1a20..93a09966711be2e1b2dd9e8c417076babfd260ec 100644 --- a/typo3/sysext/core/Tests/Functional/Utility/File/ExtendedFileUtilityTest.php +++ b/typo3/sysext/core/Tests/Functional/Utility/File/ExtendedFileUtilityTest.php @@ -27,14 +27,14 @@ use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; final class ExtendedFileUtilityTest extends FunctionalTestCase { protected array $pathsToProvideInTestInstance = [ - 'typo3/sysext/core/Tests/Functional/Utility/Fixtures/Folders/' => 'fileadmin/', + 'typo3/sysext/core/Tests/Functional/Utility/File/Fixtures/Folders/' => 'fileadmin/', ]; public function setUp(): void { parent::setUp(); - $this->importCSVDataSet(__DIR__ . '/../Fixtures/DataSet/sys_refindex.csv'); - $this->importCSVDataSet(__DIR__ . '/../Fixtures/DataSet/sys_file.csv'); + $this->importCSVDataSet(__DIR__ . '/Fixtures/DataSet/sys_refindex.csv'); + $this->importCSVDataSet(__DIR__ . '/Fixtures/DataSet/sys_file.csv'); $GLOBALS['LANG'] = GeneralUtility::makeInstance(LanguageServiceFactory::class)->create('default'); } diff --git a/typo3/sysext/core/Tests/Functional/Utility/Fixtures/DataSet/sys_file.csv b/typo3/sysext/core/Tests/Functional/Utility/File/Fixtures/DataSet/sys_file.csv similarity index 100% rename from typo3/sysext/core/Tests/Functional/Utility/Fixtures/DataSet/sys_file.csv rename to typo3/sysext/core/Tests/Functional/Utility/File/Fixtures/DataSet/sys_file.csv diff --git a/typo3/sysext/core/Tests/Functional/Utility/Fixtures/DataSet/sys_refindex.csv b/typo3/sysext/core/Tests/Functional/Utility/File/Fixtures/DataSet/sys_refindex.csv similarity index 100% rename from typo3/sysext/core/Tests/Functional/Utility/Fixtures/DataSet/sys_refindex.csv rename to typo3/sysext/core/Tests/Functional/Utility/File/Fixtures/DataSet/sys_refindex.csv diff --git a/typo3/sysext/core/Tests/Functional/Utility/Fixtures/Folders/FolderWithUnusedFile/unused.txt b/typo3/sysext/core/Tests/Functional/Utility/File/Fixtures/Folders/FolderWithUnusedFile/unused.txt similarity index 100% rename from typo3/sysext/core/Tests/Functional/Utility/Fixtures/Folders/FolderWithUnusedFile/unused.txt rename to typo3/sysext/core/Tests/Functional/Utility/File/Fixtures/Folders/FolderWithUnusedFile/unused.txt diff --git a/typo3/sysext/core/Tests/Functional/Utility/Fixtures/Folders/FolderWithUsedFile/used.txt b/typo3/sysext/core/Tests/Functional/Utility/File/Fixtures/Folders/FolderWithUsedFile/used.txt similarity index 100% rename from typo3/sysext/core/Tests/Functional/Utility/Fixtures/Folders/FolderWithUsedFile/used.txt rename to typo3/sysext/core/Tests/Functional/Utility/File/Fixtures/Folders/FolderWithUsedFile/used.txt diff --git a/typo3/sysext/core/Tests/Functional/Utility/Fixtures/RootlineScenario.yaml b/typo3/sysext/core/Tests/Functional/Utility/Fixtures/RootlineScenario.yaml deleted file mode 100644 index 6f4a1a8bdc076e7e36f657bbfdc9b5209428948c..0000000000000000000000000000000000000000 --- a/typo3/sysext/core/Tests/Functional/Utility/Fixtures/RootlineScenario.yaml +++ /dev/null @@ -1,58 +0,0 @@ -__variables: - - &pageStandard 0 - - &pageShortcut 4 - - &pageMount 7 - -entitySettings: - '*': - nodeColumnName: 'pid' - columnNames: {id: 'uid', language: 'sys_language_uid'} - defaultValues: {pid: 0} - page: - isNode: true - tableName: 'pages' - parentColumnName: 'pid' - languageColumnNames: ['l10n_parent', 'l10n_source'] - columnNames: {type: 'doktype', root: 'is_siteroot', mount: 'mount_pid', showContentOfMountedPage: 'mount_pid_ol', visitorGroups: 'fe_group'} - defaultValues: {hidden: 0, doktype: *pageStandard} - valueInstructions: - shortcut: - first: {shortcut: 0, shortcut_mode: 1} - workspace: - tableName: 'sys_workspace' - -entities: - workspace: - - self: {id: 1, title: 'My Personal Workspace' } - - self: {id: 2, title: 'Another Workspace' } - page: - - self: {id: 1000, title: 'ACME Global', type: *pageShortcut, shortcut: 'first', root: true, slug: '/'} - versionVariants: - - version: { workspace: 1, title: 'ACME Global modified in Workspace 1' } - children: - - self: {id: 1100, title: 'EN: Welcome', slug: '/welcome' } - languageVariants: - - self: {id: 1101, title: 'FR: Welcome', language: 1, slug: '/bienvenue' } - - self: {id: 1102, title: 'FR-CA: Welcome', language: 2, slug: '/bienvenue' } - - self: {id: 1200, title: 'EN: Features', slug: '/features'} - children: - - self: {id: 1210, title: 'EN: Frontend Editing', slug: '/features/frontend-editing'} - - self: {id: 1300, title: 'EN: Products', slug: '/products'} - versionVariants: - - version: { workspace: 2 } - actions: - - { action: 'delete' } - children: - - self: {id: 1310, title: 'EN: Toys', slug: '/products/toys'} - - self: {id: 1320, title: 'EN: Card Games', slug: '/products/card-games'} - - self: {id: 1330, title: 'EN: Board Games', slug: '/products/board-games'} - children: - - self: {id: 1331, title: 'EN: Monopoly', slug: '/products/monopoly'} - - self: {id: 1332, title: 'EN: Catan', slug: '/products/board-games/catan'} - - self: {id: 1333, title: 'EN: Risk', slug: '/risk'} - versionVariants: - - version: { workspace: 1 } - actions: - - { action: 'move', type: 'toPage', target: 1320 } - - version: {id: 1400, title: 'EN: A new page in workspace', slug: '/a-new-page', workspace: 1 } - - self: {id: 9999, title: 'Another root page as dummy to incremental numbers', root: true, slug: '/'} diff --git a/typo3/sysext/core/Tests/Functional/Utility/Fixtures/RootlineUtilityImport.csv b/typo3/sysext/core/Tests/Functional/Utility/Fixtures/RootlineUtilityImport.csv new file mode 100644 index 0000000000000000000000000000000000000000..40c388c886f9fd6009d5f4a4a10c99f67e741bb6 --- /dev/null +++ b/typo3/sysext/core/Tests/Functional/Utility/Fixtures/RootlineUtilityImport.csv @@ -0,0 +1,26 @@ +"sys_workspace" +,"uid","pid","deleted","title" +,1,0,0,"My Personal Workspace" +,2,0,0,"Another Workspace" +"pages" +,"uid","pid","deleted","sys_language_uid","l10n_parent","t3ver_wsid","t3ver_oid","t3ver_state","media","mount_pid","mount_pid_ol","fe_group","slug","title" +,1000,0,0,0,0,0,0,0,0,0,0,0,"/","ACME Global" +,1100,1000,0,0,0,0,0,0,0,0,0,0,"/welcome","EN: Welcome" +,1101,1000,0,1,1100,0,0,0,0,0,0,0,"/bienvenue","FR: Welcome" +,1102,1000,0,2,1100,0,0,0,0,0,0,0,"/bienvenue-ca","FR-CA: Welcome" +,1200,1000,0,0,0,0,0,0,0,0,0,0,"/features","EN: Features" +,1300,1000,0,0,0,0,0,0,0,0,0,0,"/products","EN: Products" +,1310,1300,0,0,0,0,0,0,0,0,0,0,"/products/toys","EN: Toys" +,1320,1300,0,0,0,0,0,0,0,0,0,0,"/products/card-games","EN: Card Games" +,1330,1300,0,0,0,0,0,0,0,0,0,0,"/products/board-games","EN: Board Games" +,1331,1330,0,0,0,0,0,0,0,0,0,0,"/products/monopoly","EN: Monopoly" +,1332,1330,0,0,0,0,0,0,0,0,0,0,"/products/board-games/catan","EN: Catan" +,1333,1330,0,0,0,0,0,0,0,0,0,0,"/risk","EN: Risk" +,1400,1000,0,0,0,1,0,1,0,0,0,0,"/a-new-page","EN: A new page in workspace" +,10000,0,0,0,0,1,1000,0,0,0,0,,"/","ACME Global modified in Workspace 1" +,10001,1320,0,0,0,1,1333,4,0,0,0,,"/risk","EN: Risk" +,10002,1000,0,0,0,2,1300,2,0,0,0,,"/products","EN: Products" +"sys_refindex" +,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_string" +,"d82e8687cecaf87aef30a619370d74c9","pages",1101,"l10n_parent",,,,0,0,"pages",1100, +,"83405f026c17228bef16c5eb0e4349c6","pages",1102,"l10n_parent",,,,0,0,"pages",1100, diff --git a/typo3/sysext/core/Tests/Functional/Utility/RootlineUtilityTest.php b/typo3/sysext/core/Tests/Functional/Utility/RootlineUtilityTest.php index b2e593ada54104128d0f6ef11cfc5a0ae8926760..14d8932b562b906662b0b9036c27f45f335637cb 100644 --- a/typo3/sysext/core/Tests/Functional/Utility/RootlineUtilityTest.php +++ b/typo3/sysext/core/Tests/Functional/Utility/RootlineUtilityTest.php @@ -18,15 +18,17 @@ declare(strict_types=1); namespace TYPO3\CMS\Core\Tests\Functional\Utility; use PHPUnit\Framework\Attributes\Test; +use TYPO3\CMS\Core\Cache\Frontend\NullFrontend; use TYPO3\CMS\Core\Context\Context; +use TYPO3\CMS\Core\Context\LanguageAspect; +use TYPO3\CMS\Core\Context\VisibilityAspect; use TYPO3\CMS\Core\Context\WorkspaceAspect; -use TYPO3\CMS\Core\Core\Bootstrap; +use TYPO3\CMS\Core\Database\ReferenceIndex; +use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Core\Exception\Page\PageNotFoundException; use TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\RootlineUtility; -use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory; -use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; final class RootlineUtilityTest extends FunctionalTestCase @@ -45,7 +47,6 @@ final class RootlineUtilityTest extends FunctionalTestCase protected function setUp(): void { parent::setUp(); - $this->writeSiteConfiguration( 'main', $this->buildSiteConfiguration(1000, 'https://acme.com/'), @@ -55,51 +56,296 @@ final class RootlineUtilityTest extends FunctionalTestCase $this->buildLanguageConfiguration('FR-CA', '/fr-ca/', ['FR', 'EN']), ] ); - $this->withDatabaseSnapshot(function () { - $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv'); - $backendUser = $this->setUpBackendUser(1); - Bootstrap::initializeLanguageObject(); - $factory = DataHandlerFactory::fromYamlFile(__DIR__ . '/Fixtures/RootlineScenario.yaml'); - $writer = DataHandlerWriter::withBackendUser($backendUser); - $writer->invokeFactory($factory); - static::failIfArrayIsNotEmpty($writer->getErrors()); - }); + self::importCSVDataSet(__DIR__ . '/Fixtures/RootlineUtilityImport.csv'); + } + + private function filterExpectedValues(array $incomingData, array $fields): array + { + $result = []; + foreach ($incomingData as $pos => $values) { + $filteredValues = []; + foreach ($fields as $field) { + if (isset($values[$field])) { + $filteredValues[$field] = $values[$field]; + } + } + $result[$pos] = $filteredValues; + } + return $result; } #[Test] - public function getForRootPageOnlyReturnsRootPageInformation(): void + public function verifyCleanReferenceIndex() { - $rootPageUid = 1000; - $subject = new RootlineUtility($rootPageUid); + $referenceIndexFixResult = GeneralUtility::makeInstance(ReferenceIndex::class)->updateIndex(true); + if (count($referenceIndexFixResult['errors']) > 0) { + self::fail('Reference index not clean. ' . LF . implode(LF, $referenceIndexFixResult['errors'])); + } + } - $result = $subject->get(); + #[Test] + public function isMountedPageWithoutMountPointsReturnsFalse(): void + { + $subject = new RootlineUtility(1, '', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'isMountedPage')); + self::assertFalse($subjectMethodReflection->invoke($subject)); + } - self::assertCount(1, $result); - self::assertSame($rootPageUid, (int)$result[0]['uid']); + #[Test] + public function isMountedPageWithMatchingMountPointParameterReturnsTrue(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'isMountedPage')); + self::assertTrue($subjectMethodReflection->invoke($subject)); } #[Test] - public function getForRootPageAndWithMissingTableColumnsTcaReturnsEmptyArray(): void + public function isMountedPageWithNonMatchingMountPointParameterReturnsFalse(): void { - $rootPageUid = 1000; - $subject = new RootlineUtility($rootPageUid); + $subject = new RootlineUtility(1, '99-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'isMountedPage')); + self::assertFalse($subjectMethodReflection->invoke($subject)); + } - unset($GLOBALS['TCA']['pages']['columns']); - $result = $subject->get(); + #[Test] + public function processMountedPageWithNonMountedPageThrowsException(): void + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionCode(1343464100); + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'processMountedPage')); + $subjectMethodReflection->invoke($subject, ['uid' => 1], ['uid' => 99, 'doktype' => PageRepository::DOKTYPE_DEFAULT]); + } - self::assertCount(1, $result); - self::assertSame($rootPageUid, (int)$result[0]['uid']); + #[Test] + public function processMountedPageWithMountedPageNotThrowsException(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'processMountedPage')); + $result = $subjectMethodReflection->invoke( + $subject, + ['uid' => 1], + ['uid' => 99, 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1] + ); + self::assertNotEmpty($result); } #[Test] - public function getForRootPageAndWithNonArrayTableColumnsTcaReturnsEmptyArray(): void + public function processMountedPageWithMountedPageAddsMountedFromParameter(): void { - $rootPageUid = 1000; - $subject = new RootlineUtility($rootPageUid); + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'processMountedPage')); + $result = $subjectMethodReflection->invoke( + $subject, + ['uid' => 1], + ['uid' => 99, 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1] + ); + self::assertTrue(isset($result['_MOUNTED_FROM'])); + self::assertSame(1, $result['_MOUNTED_FROM']); + } + + #[Test] + public function processMountedPageWithMountedPageAddsMountPointParameterToReturnValue(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'processMountedPage')); + $result = $subjectMethodReflection->invoke( + $subject, + ['uid' => 1], + ['uid' => 99, 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1] + ); + self::assertTrue(isset($result['_MP_PARAM'])); + self::assertSame('1-99', $result['_MP_PARAM']); + } + + #[Test] + public function processMountedPageForMountPageIsOverlayAddsMountOLParameter(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'processMountedPage')); + $result = $subjectMethodReflection->invoke( + $subject, + ['uid' => 1], + ['uid' => 99, 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1, 'mount_pid_ol' => 1] + ); + self::assertTrue(isset($result['_MOUNT_OL'])); + self::assertTrue($result['_MOUNT_OL']); + } + + #[Test] + public function processMountedPageForMountPageIsOverlayAddsDataInformationAboutMountPage(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'processMountedPage')); + $result = $subjectMethodReflection->invoke( + $subject, + ['uid' => 1], + [ + 'uid' => 99, + 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, + 'mount_pid' => 1, + 'mount_pid_ol' => 1, + 'pid' => 5, + 'title' => 'TestCase', + ] + ); + self::assertTrue(isset($result['_MOUNT_PAGE'])); + self::assertSame(['uid' => 99, 'pid' => 5, 'title' => 'TestCase'], $result['_MOUNT_PAGE']); + } + + #[Test] + public function processMountedPageForMountPageWithoutOverlayReplacesMountedPageWithMountPage(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'processMountedPage')); + $mountPointPageData = [ + 'uid' => 99, + 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, + 'mount_pid' => 1, + 'mount_pid_ol' => 0, + ]; + $result = $subjectMethodReflection->invoke( + $subject, + ['uid' => 1], + $mountPointPageData + ); + // Tests that $mountPointPageData is completely part of $result and keys match. + self::assertSame($mountPointPageData, array_intersect_assoc($mountPointPageData, $result)); + } + + #[Test] + public function columnHasRelationToResolveDetectsGroupFieldAsLocal(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'columnHasRelationToResolve')); + self::assertFalse($subjectMethodReflection->invoke( + $subject, + [ + 'config' => [ + 'type' => 'group', + ], + ] + )); + } + + #[Test] + public function columnHasRelationToResolveDetectsGroupFieldWithMMAsRemote(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'columnHasRelationToResolve')); + self::assertTrue($subjectMethodReflection->invoke( + $subject, + [ + 'config' => [ + 'type' => 'group', + 'MM' => 'tx_xyz', + ], + ] + )); + } + + #[Test] + public function columnHasRelationToResolveDetectsInlineFieldAsLocal(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'columnHasRelationToResolve')); + self::assertFalse($subjectMethodReflection->invoke( + $subject, + [ + 'config' => [ + 'type' => 'inline', + ], + ] + )); + } + + #[Test] + public function columnHasRelationToResolveDetectsInlineFieldWithForeignKeyAsRemote(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'columnHasRelationToResolve')); + self::assertTrue($subjectMethodReflection->invoke( + $subject, + [ + 'config' => [ + 'type' => 'inline', + 'foreign_field' => 'xyz', + ], + ] + )); + } + + #[Test] + public function columnHasRelationToResolveDetectsInlineFieldWithFMMAsRemote(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'columnHasRelationToResolve')); + self::assertTrue($subjectMethodReflection->invoke( + $subject, + [ + 'config' => [ + 'type' => 'inline', + 'MM' => 'xyz', + ], + ] + )); + } + + #[Test] + public function columnHasRelationToResolveDetectsSelectFieldAsLocal(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'columnHasRelationToResolve')); + self::assertFalse($subjectMethodReflection->invoke( + $subject, + [ + 'config' => [ + 'type' => 'select', + ], + ] + )); + } - $GLOBALS['TCA']['pages']['columns'] = 'This is not an array.'; - $result = $subject->get(); + #[Test] + public function columnHasRelationToResolveDetectsSelectFieldWithMMAsRemote(): void + { + $subject = new RootlineUtility(1, '1-99', new Context()); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'columnHasRelationToResolve')); + self::assertTrue($subjectMethodReflection->invoke( + $subject, + [ + 'config' => [ + 'type' => 'select', + 'MM' => 'xyz', + ], + ] + )); + } + #[Test] + public function getCacheIdentifierContainsAllContextParameters(): void + { + $cacheFrontend = new NullFrontend('some-frontend'); + $context = new Context(); + $context->setAspect('workspace', new WorkspaceAspect(15)); + $context->setAspect('visibility', new VisibilityAspect(true)); + $context->setAspect('language', new LanguageAspect(8, 8, LanguageAspect::OVERLAYS_OFF)); + $subject = new RootlineUtility(42, '47-11', $context); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'getCacheIdentifier')); + self::assertSame('42_47-11_8_15_0_1', $subjectMethodReflection->invoke($subject)); + self::assertTrue($cacheFrontend->isValidEntryIdentifier($subjectMethodReflection->invoke($subject))); + $context->setAspect('workspace', new WorkspaceAspect(0)); + $subject = new RootlineUtility(42, '47-11', $context); + $subjectMethodReflection = (new \ReflectionMethod($subject, 'getCacheIdentifier')); + self::assertSame('42_47-11_8_0_0_1', $subjectMethodReflection->invoke($subject)); + self::assertTrue($cacheFrontend->isValidEntryIdentifier($subjectMethodReflection->invoke($subject))); + } + + #[Test] + public function getForRootPageOnlyReturnsRootPageInformation(): void + { + $rootPageUid = 1000; + $result = (new RootlineUtility($rootPageUid))->get(); self::assertCount(1, $result); self::assertSame($rootPageUid, (int)$result[0]['uid']); } @@ -107,11 +353,9 @@ final class RootlineUtilityTest extends FunctionalTestCase #[Test] public function resolveLivePagesAndSkipWorkspacedVersions(): void { - $context = GeneralUtility::makeInstance(Context::class); + $context = new Context(); $context->setAspect('workspace', new WorkspaceAspect(0)); - $subject = new RootlineUtility(1330, '', $context); - $result = $subject->get(); - + $result = (new RootlineUtility(1330, '', $context))->get(); $expected = [ 2 => [ 'pid' => 1300, @@ -144,11 +388,9 @@ final class RootlineUtilityTest extends FunctionalTestCase #[Test] public function resolveWorkspaceOverlaysOfNewPageInWorkspace(): void { - $context = GeneralUtility::makeInstance(Context::class); + $context = new Context(); $context->setAspect('workspace', new WorkspaceAspect(1)); - $subject = new RootlineUtility(1400, '', $context); - $result = $subject->get(); - + $result = (new RootlineUtility(1400, '', $context))->get(); $expected = [ 1 => [ 'pid' => 1000, @@ -174,11 +416,9 @@ final class RootlineUtilityTest extends FunctionalTestCase #[Test] public function resolveLiveRootLineForMovedPage(): void { - $context = GeneralUtility::makeInstance(Context::class); + $context = new Context(); $context->setAspect('workspace', new WorkspaceAspect(0)); - $subject = new RootlineUtility(1333, '', $context); - $result = $subject->get(); - + $result = (new RootlineUtility(1333, '', $context))->get(); $expected = [ 3 => [ 'pid' => 1330, @@ -219,11 +459,9 @@ final class RootlineUtilityTest extends FunctionalTestCase #[Test] public function resolveWorkspaceOverlaysOfMovedPage(): void { - $context = GeneralUtility::makeInstance(Context::class); + $context = new Context(); $context->setAspect('workspace', new WorkspaceAspect(1)); - $subject = new RootlineUtility(1333, '', $context); - $result = $subject->get(); - + $result = (new RootlineUtility(1333, '', $context))->get(); $expected = [ 3 => [ 'pid' => 1320, @@ -232,8 +470,8 @@ final class RootlineUtilityTest extends FunctionalTestCase 't3ver_wsid' => 1, 't3ver_state' => 4, 'title' => 'EN: Risk', - '_ORIG_pid' => 1330, // Pointing to the LIVE pid! WHY? All others point to the same PID! @todo '_ORIG_uid' => 10001, + '_ORIG_pid' => 1330, // Pointing to the LIVE pid! WHY? All others point to the same PID! @todo ], 2 => [ 'pid' => 1300, @@ -264,8 +502,7 @@ final class RootlineUtilityTest extends FunctionalTestCase self::assertSame($expected, $this->filterExpectedValues($result, ['pid', 'uid', 't3ver_oid', 't3ver_wsid', 't3ver_state', 'title', '_ORIG_uid', '_ORIG_pid'])); // Now explicitly requesting the versioned ID, which holds the same result - $subject = new RootlineUtility(10001, '', $context); - $result = $subject->get(); + $result = (new RootlineUtility(10001, '', $context))->get(); self::assertSame($expected, $this->filterExpectedValues($result, ['pid', 'uid', 't3ver_oid', 't3ver_wsid', 't3ver_state', 'title', '_ORIG_uid', '_ORIG_pid'])); } @@ -274,25 +511,8 @@ final class RootlineUtilityTest extends FunctionalTestCase { $this->expectException(PageNotFoundException::class); $this->expectExceptionCode(1343464101); - $context = GeneralUtility::makeInstance(Context::class); + $context = new Context(); $context->setAspect('workspace', new WorkspaceAspect(2)); - $subject = new RootlineUtility(1310, '', $context); - $subject->get(); - } - - protected function filterExpectedValues(array $incomingData, array $fields): array - { - $result = []; - foreach ($incomingData as $pos => $values) { - array_walk($values, static function (&$val) { - if (is_numeric($val)) { - $val = (int)$val; - } - }); - $result[$pos] = array_filter($values, static function ($fieldName) use ($fields) { - return in_array($fieldName, $fields, true); - }, ARRAY_FILTER_USE_KEY); - } - return $result; + (new RootlineUtility(1310, '', $context))->get(); } } diff --git a/typo3/sysext/core/Tests/Unit/Utility/RootlineUtilityTest.php b/typo3/sysext/core/Tests/Unit/Utility/RootlineUtilityTest.php deleted file mode 100644 index f09e01bb333dc70d2d9652d032230ebf5c807f6e..0000000000000000000000000000000000000000 --- a/typo3/sysext/core/Tests/Unit/Utility/RootlineUtilityTest.php +++ /dev/null @@ -1,291 +0,0 @@ -<?php - -declare(strict_types=1); - -/* - * This file is part of the TYPO3 CMS project. - * - * It is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, either version 2 - * of the License, or any later version. - * - * For the full copyright and license information, please read the - * LICENSE.txt file that was distributed with this source code. - * - * The TYPO3 project - inspiring people to share! - */ - -namespace TYPO3\CMS\Core\Tests\Unit\Utility; - -use PHPUnit\Framework\Attributes\Test; -use PHPUnit\Framework\MockObject\MockObject; -use TYPO3\CMS\Core\Cache\CacheManager; -use TYPO3\CMS\Core\Cache\Frontend\NullFrontend; -use TYPO3\CMS\Core\Context\Context; -use TYPO3\CMS\Core\Context\LanguageAspect; -use TYPO3\CMS\Core\Context\VisibilityAspect; -use TYPO3\CMS\Core\Context\WorkspaceAspect; -use TYPO3\CMS\Core\Domain\Repository\PageRepository; -use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Core\Utility\RootlineUtility; -use TYPO3\TestingFramework\Core\AccessibleObjectInterface; -use TYPO3\TestingFramework\Core\Unit\UnitTestCase; - -final class RootlineUtilityTest extends UnitTestCase -{ - protected RootlineUtility&MockObject&AccessibleObjectInterface $subject; - - protected function setUp(): void - { - parent::setUp(); - $cacheManager = new CacheManager(); - $cacheManager->registerCache(new NullFrontend('rootline')); - $cacheManager->registerCache(new NullFrontend('runtime')); - GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManager); - - $this->subject = $this->getAccessibleMock( - RootlineUtility::class, - ['enrichWithRelationFields', 'resolvePageId'], - [1, '', new Context()] - ); - - $this->subject->method('resolvePageId')->willReturnArgument(0); - } - - protected function tearDown(): void - { - GeneralUtility::purgeInstances(); - parent::tearDown(); - } - - /** - * Tests that $subsetCandidate is completely part of $superset - * and keys match. - * - * See (A ^ B) = A <=> A c B - * @param array $subsetCandidate - * @param array $superset - */ - protected function assertIsSubset(array $subsetCandidate, array $superset): void - { - self::assertSame($subsetCandidate, array_intersect_assoc($subsetCandidate, $superset)); - } - - #[Test] - public function isMountedPageWithoutMountPointsReturnsFalse(): void - { - $this->subject->__construct(1, '', new Context()); - self::assertFalse($this->subject->isMountedPage()); - } - - #[Test] - public function isMountedPageWithMatchingMountPointParameterReturnsTrue(): void - { - $this->subject->__construct(1, '1-99', new Context()); - self::assertTrue($this->subject->isMountedPage()); - } - - #[Test] - public function isMountedPageWithNonMatchingMountPointParameterReturnsFalse(): void - { - $this->subject->__construct(1, '99-99', new Context()); - self::assertFalse($this->subject->isMountedPage()); - } - - #[Test] - public function processMountedPageWithNonMountedPageThrowsException(): void - { - $this->expectException(\RuntimeException::class); - $this->expectExceptionCode(1343464100); - - $this->subject->__construct(1, '1-99', new Context()); - $this->subject->_call( - 'processMountedPage', - ['uid' => 1], - ['uid' => 99, 'doktype' => PageRepository::DOKTYPE_DEFAULT] - ); - } - - #[Test] - public function processMountedPageWithMountedPageNotThrowsException(): void - { - $this->subject->__construct(1, '1-99', new Context()); - self::assertNotEmpty($this->subject->_call( - 'processMountedPage', - ['uid' => 1], - ['uid' => 99, 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1] - )); - } - - #[Test] - public function processMountedPageWithMountedPageAddsMountedFromParameter(): void - { - $this->subject->__construct(1, '1-99', new Context()); - $result = $this->subject->_call( - 'processMountedPage', - ['uid' => 1], - ['uid' => 99, 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1] - ); - self::assertTrue(isset($result['_MOUNTED_FROM'])); - self::assertSame(1, $result['_MOUNTED_FROM']); - } - - #[Test] - public function processMountedPageWithMountedPageAddsMountPointParameterToReturnValue(): void - { - $this->subject->__construct(1, '1-99', new Context()); - $result = $this->subject->_call( - 'processMountedPage', - ['uid' => 1], - ['uid' => 99, 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1] - ); - self::assertTrue(isset($result['_MP_PARAM'])); - self::assertSame('1-99', $result['_MP_PARAM']); - } - - #[Test] - public function processMountedPageForMountPageIsOverlayAddsMountOLParameter(): void - { - $this->subject->__construct(1, '1-99', new Context()); - $result = $this->subject->_call( - 'processMountedPage', - ['uid' => 1], - ['uid' => 99, 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1, 'mount_pid_ol' => 1] - ); - self::assertTrue(isset($result['_MOUNT_OL'])); - self::assertTrue($result['_MOUNT_OL']); - } - - #[Test] - public function processMountedPageForMountPageIsOverlayAddsDataInformationAboutMountPage(): void - { - $this->subject->__construct(1, '1-99', new Context()); - $result = $this->subject->_call('processMountedPage', ['uid' => 1], [ - 'uid' => 99, - 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, - 'mount_pid' => 1, - 'mount_pid_ol' => 1, - 'pid' => 5, - 'title' => 'TestCase', - ]); - self::assertTrue(isset($result['_MOUNT_PAGE'])); - self::assertSame(['uid' => 99, 'pid' => 5, 'title' => 'TestCase'], $result['_MOUNT_PAGE']); - } - - #[Test] - public function processMountedPageForMountPageWithoutOverlayReplacesMountedPageWithMountPage(): void - { - $mountPointPageData = [ - 'uid' => 99, - 'doktype' => PageRepository::DOKTYPE_MOUNTPOINT, - 'mount_pid' => 1, - 'mount_pid_ol' => 0, - ]; - $this->subject->__construct(1, '1-99', new Context()); - $result = $this->subject->_call('processMountedPage', ['uid' => 1], $mountPointPageData); - $this->assertIsSubset($mountPointPageData, $result); - } - - #[Test] - public function columnHasRelationToResolveDetectsGroupFieldAsLocal(): void - { - self::assertFalse($this->subject->_call('columnHasRelationToResolve', [ - 'type' => 'group', - ])); - } - - #[Test] - public function columnHasRelationToResolveDetectsGroupFieldWithMMAsRemote2(): void - { - self::assertTrue($this->subject->_call('columnHasRelationToResolve', [ - 'config' => [ - 'type' => 'group', - 'MM' => 'tx_xyz', - ], - ])); - } - - #[Test] - public function columnHasRelationToResolveDetectsInlineFieldAsLocal(): void - { - self::assertFalse($this->subject->_call('columnHasRelationToResolve', [ - 'config' => [ - 'type' => 'inline', - ], - ])); - } - - #[Test] - public function columnHasRelationToResolveDetectsInlineFieldWithForeignKeyAsRemote(): void - { - self::assertTrue($this->subject->_call('columnHasRelationToResolve', [ - 'config' => [ - 'type' => 'inline', - 'foreign_field' => 'xyz', - ], - ])); - } - - #[Test] - public function columnHasRelationToResolveDetectsInlineFieldWithFMMAsRemote(): void - { - self::assertTrue($this->subject->_call('columnHasRelationToResolve', [ - 'config' => [ - 'type' => 'inline', - 'MM' => 'xyz', - ], - ])); - } - - #[Test] - public function columnHasRelationToResolveDetectsSelectFieldAsLocal(): void - { - self::assertFalse($this->subject->_call('columnHasRelationToResolve', [ - 'config' => [ - 'type' => 'select', - ], - ])); - } - - #[Test] - public function columnHasRelationToResolveDetectsSelectFieldWithMMAsRemote(): void - { - self::assertTrue($this->subject->_call('columnHasRelationToResolve', [ - 'config' => [ - 'type' => 'select', - 'MM' => 'xyz', - ], - ])); - } - - #[Test] - public function getCacheIdentifierContainsAllContextParameters(): void - { - $this->subject->method('resolvePageId')->willReturn(42); - - $context = new Context(); - $context->setAspect('workspace', new WorkspaceAspect(15)); - $context->setAspect('visibility', new VisibilityAspect(true)); - $context->setAspect('language', new LanguageAspect(8, 8, LanguageAspect::OVERLAYS_OFF)); - $this->subject->__construct(42, '47-11', $context); - self::assertSame('42_47-11_8_15_0_1', $this->subject->getCacheIdentifier()); - $this->subject->__construct(42, '47-11', $context); - self::assertSame('42_47-11_8_15_0_1', $this->subject->getCacheIdentifier()); - - $context->setAspect('workspace', new WorkspaceAspect(0)); - $this->subject->__construct(42, '47-11', $context); - self::assertSame('42_47-11_8_0_0_1', $this->subject->getCacheIdentifier()); - } - - #[Test] - public function getCacheIdentifierReturnsValidIdentifierWithCommasInMountPointParameter(): void - { - $this->subject->method('resolvePageId')->willReturn(42); - $cacheFrontend = new NullFrontend('some-frontend'); - $context = new Context(); - $context->setAspect('workspace', new WorkspaceAspect(15)); - $context->setAspect('language', new LanguageAspect(8, 8, LanguageAspect::OVERLAYS_OFF)); - $this->subject->__construct(42, '47-11,48-12', $context); - self::assertTrue($cacheFrontend->isValidEntryIdentifier($this->subject->getCacheIdentifier())); - } -}