PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/typo3/sysext/backend/Tests/Unit/Module/ModuleRegistryTest.php

https://github.com/TYPO3/TYPO3.CMS
PHP | 256 lines | 185 code | 28 blank | 43 comment | 0 complexity | e39c8404bdd3372437991027ac4e7ee3 MD5 | raw file
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of the TYPO3 CMS project.
  5. *
  6. * It is free software; you can redistribute it and/or modify it under
  7. * the terms of the GNU General Public License, either version 2
  8. * of the License, or any later version.
  9. *
  10. * For the full copyright and license information, please read the
  11. * LICENSE.txt file that was distributed with this source code.
  12. *
  13. * The TYPO3 project - inspiring people to share!
  14. */
  15. namespace TYPO3\CMS\Backend\Tests\Unit\Module;
  16. use Prophecy\Argument;
  17. use Prophecy\PhpUnit\ProphecyTrait;
  18. use Psr\EventDispatcher\EventDispatcherInterface;
  19. use TYPO3\CMS\Backend\Module\ModuleFactory;
  20. use TYPO3\CMS\Backend\Module\ModuleInterface;
  21. use TYPO3\CMS\Backend\Module\ModuleRegistry;
  22. use TYPO3\CMS\Core\Imaging\IconRegistry;
  23. use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
  24. class ModuleRegistryTest extends UnitTestCase
  25. {
  26. use ProphecyTrait;
  27. protected ModuleFactory $moduleFactory;
  28. protected function setUp(): void
  29. {
  30. parent::setUp();
  31. $eventDispatcherProphecy = $this->prophesize(EventDispatcherInterface::class);
  32. $eventDispatcherProphecy->dispatch(Argument::any())->willReturnArgument();
  33. $this->moduleFactory = new ModuleFactory(
  34. $this->prophesize(IconRegistry::class)->reveal(),
  35. $eventDispatcherProphecy->reveal()
  36. );
  37. }
  38. /**
  39. * @test
  40. */
  41. public function throwsExceptionOnDuplicateModuleIdentifier(): void
  42. {
  43. $this->expectException(\LogicException::class);
  44. $this->expectExceptionCode(1642174843);
  45. new ModuleRegistry([
  46. $this->createModule('a_module'),
  47. $this->createModule('a_module'),
  48. ]);
  49. }
  50. /**
  51. * @test
  52. */
  53. public function throwsExceptionOnNonExistingModuleIdentifier(): void
  54. {
  55. $this->expectException(\InvalidArgumentException::class);
  56. $this->expectExceptionCode(1642375889);
  57. (new ModuleRegistry([]))->getModule('a_module');
  58. }
  59. /**
  60. * @test
  61. */
  62. public function accessReegisteredModulesWork(): void
  63. {
  64. $aModule = $this->createModule('a_module');
  65. $bModule = $this->createModule('b_module');
  66. $registry = new ModuleRegistry([$aModule, $bModule]);
  67. self::assertTrue($registry->hasModule('a_module'));
  68. self::assertFalse($registry->hasModule('c_module'));
  69. self::assertEquals($aModule, $registry->getModule('a_module'));
  70. self::assertEquals(['a_module' => $aModule, 'b_module' => $bModule], $registry->getModules());
  71. }
  72. /**
  73. * @test
  74. */
  75. public function addModuleAppliesSortingAndHierarchy(): void
  76. {
  77. $modules = $random = [
  78. 'a' => $this->createModule('a', ['position' => ['top']]),
  79. 'b' => $this->createModule('b', ['position' => ['after' => 'a']]),
  80. 'b_a' => $this->createModule('b_a', ['parent' => 'b', 'position' => ['top']]),
  81. 'b_a_a' => $this->createModule('b_a_a', ['parent' => 'b_a', 'position' => ['top']]),
  82. 'b_a_b' => $this->createModule('b_a_b', ['parent' => 'b_a', 'position' => ['after' => 'b_a_a']]),
  83. 'b_a_c' => $this->createModule('b_a_c', ['parent' => 'b_a', 'position' => ['before' => 'b_a_d']]),
  84. 'b_a_c_a' => $this->createModule('b_a_c_a', ['parent' => 'b_a_c', 'position' => ['bottom']]),
  85. 'b_a_c_b' => $this->createModule('b_a_c_b', ['parent' => 'b_a_c']),
  86. 'b_a_d' => $this->createModule('b_a_d', ['parent' => 'b_a', 'position' => ['before' => 'b_a_e']]),
  87. 'b_a_d_a' => $this->createModule('b_a_d_a', ['parent' => 'b_a_d', 'position' => ['top']]),
  88. 'b_a_d_b' => $this->createModule('b_a_d_b', ['parent' => 'b_a_d']),
  89. 'b_a_d_c' => $this->createModule('b_a_d_c', ['parent' => 'b_a_d', 'position' => ['after' => 'b_a_d_b']]),
  90. 'b_a_e' => $this->createModule('b_a_e', ['parent' => 'b_a', 'position' => ['after' => '*']]),
  91. 'b_b' => $this->createModule('b_b', ['parent' => 'b', 'position' => ['before' => 'b_c']]),
  92. 'b_c' => $this->createModule('b_c', ['parent' => 'b', 'position' => ['bottom']]),
  93. 'b_d' => $this->createModule('b_d', ['parent' => 'b', 'position' => ['after' => 'b_c']]),
  94. // @todo Shouldn't the explicit "position => bottom" enforce the bottom
  95. // position over a module ("e") not defining the position at all?
  96. 'c' => $this->createModule('c', ['position' => ['bottom']]),
  97. 'd' => $this->createModule('d', ['position' => ['before' => 'e']]),
  98. 'd_a' => $this->createModule('d_a', ['parent' => 'd', 'position' => ['before' => 'd_b']]),
  99. 'd_b' => $this->createModule('d_b', ['parent' => 'd', 'position' => ['before' => '*']]),
  100. 'd_c' => $this->createModule('d_c', ['parent' => 'd', 'position' => ['before' => 'd_d']]),
  101. 'd_d' => $this->createModule('d_d', ['parent' => 'd']),
  102. 'e' => $this->createModule('e'),
  103. 'e_a' => $this->createModule('e_a', ['parent' => 'e', 'position' => ['before' => '*']]),
  104. 'e_b' => $this->createModule('e_b', ['parent' => 'e', 'position' => ['after' => 'e_a']]),
  105. 'e_c' => $this->createModule('e_c', ['parent' => 'e', 'position' => ['after' => '*']]),
  106. 'e_e' => $this->createModule('e_e', ['parent' => 'e', 'position' => ['after' => 'invalid']]),
  107. ];
  108. // Add modules in random order to ensure the result does not depend on the input order
  109. shuffle($random);
  110. $registry = new ModuleRegistry($random);
  111. // Asser correct sorting (flat)
  112. self::assertEquals(array_keys($modules), array_keys($registry->getModules()));
  113. // Assert correct hierarchy
  114. self::assertEquals(['b_a', 'b_b', 'b_c', 'b_d'], array_keys($registry->getModule('b')->getSubModules()));
  115. self::assertEquals('b', $registry->getModule('b_a')->getParentIdentifier());
  116. self::assertTrue($registry->getModule('b_a')->getParentModule()->hasSubModule('b_a'));
  117. self::assertEquals('b', $registry->getModule('b_b')->getParentIdentifier());
  118. self::assertTrue($registry->getModule('b_b')->getParentModule()->hasSubModule('b_b'));
  119. self::assertEquals('b', $registry->getModule('b_c')->getParentIdentifier());
  120. self::assertTrue($registry->getModule('b_c')->getParentModule()->hasSubModule('b_c'));
  121. self::assertEquals('b', $registry->getModule('b_d')->getParentIdentifier());
  122. self::assertTrue($registry->getModule('b_d')->getParentModule()->hasSubModule('b_d'));
  123. self::assertEquals(['b_a_a', 'b_a_b', 'b_a_c', 'b_a_d', 'b_a_e'], array_keys($registry->getModule('b_a')->getSubModules()));
  124. self::assertEquals('b_a', $registry->getModule('b_a_a')->getParentIdentifier());
  125. self::assertEquals('b', $registry->getModule('b_a_a')->getParentModule()->getParentIdentifier());
  126. self::assertEquals('b_a', $registry->getModule('b_a_b')->getParentIdentifier());
  127. self::assertEquals('b', $registry->getModule('b_a_a')->getParentModule()->getParentIdentifier());
  128. self::assertEquals('b_a', $registry->getModule('b_a_c')->getParentIdentifier());
  129. self::assertEquals('b', $registry->getModule('b_a_a')->getParentModule()->getParentIdentifier());
  130. self::assertEquals('b_a', $registry->getModule('b_a_d')->getParentIdentifier());
  131. self::assertEquals('b', $registry->getModule('b_a_a')->getParentModule()->getParentIdentifier());
  132. self::assertEquals('b_a', $registry->getModule('b_a_e')->getParentIdentifier());
  133. self::assertEquals('b', $registry->getModule('b_a_a')->getParentModule()->getParentIdentifier());
  134. self::assertEquals(['b_a_c_a', 'b_a_c_b'], array_keys($registry->getModule('b_a_c')->getSubModules()));
  135. self::assertEquals('b_a_c', $registry->getModule('b_a_c_a')->getParentIdentifier());
  136. self::assertEquals('b_a', $registry->getModule('b_a_c_a')->getParentModule()->getParentIdentifier());
  137. self::assertEquals('b', $registry->getModule('b_a_c_a')->getParentModule()->getParentModule()->getParentIdentifier());
  138. self::assertEquals('b_a_c', $registry->getModule('b_a_c_b')->getParentIdentifier());
  139. self::assertEquals('b_a', $registry->getModule('b_a_c_b')->getParentModule()->getParentIdentifier());
  140. self::assertEquals('b', $registry->getModule('b_a_c_b')->getParentModule()->getParentModule()->getParentIdentifier());
  141. self::assertEquals(['b_a_d_a', 'b_a_d_b', 'b_a_d_c'], array_keys($registry->getModule('b_a_d')->getSubModules()));
  142. self::assertEquals('b_a_d', $registry->getModule('b_a_d_a')->getParentIdentifier());
  143. self::assertEquals('b_a', $registry->getModule('b_a_d_a')->getParentModule()->getParentIdentifier());
  144. self::assertEquals('b', $registry->getModule('b_a_d_a')->getParentModule()->getParentModule()->getParentIdentifier());
  145. self::assertEquals('b_a_d', $registry->getModule('b_a_d_b')->getParentIdentifier());
  146. self::assertEquals('b_a', $registry->getModule('b_a_d_b')->getParentModule()->getParentIdentifier());
  147. self::assertEquals('b', $registry->getModule('b_a_d_b')->getParentModule()->getParentModule()->getParentIdentifier());
  148. self::assertEquals('b_a_d', $registry->getModule('b_a_d_c')->getParentIdentifier());
  149. self::assertEquals('b_a', $registry->getModule('b_a_d_c')->getParentModule()->getParentIdentifier());
  150. self::assertEquals('b', $registry->getModule('b_a_d_c')->getParentModule()->getParentModule()->getParentIdentifier());
  151. }
  152. /**
  153. * @test
  154. */
  155. public function keepsInputOrderWithoutPositionDefinition(): void
  156. {
  157. self::assertEquals(
  158. ['a', 'b', 'b_a', 'b_b', 'c'],
  159. array_keys((new ModuleRegistry([
  160. $this->createModule('a'),
  161. $this->createModule('b'),
  162. $this->createModule('b_a', ['parent' => 'b']),
  163. $this->createModule('b_b', ['parent' => 'b']),
  164. $this->createModule('c'),
  165. ]))->getModules())
  166. );
  167. }
  168. /**
  169. * @test
  170. */
  171. public function firstModuleDeclaringTopWillBeOnTop(): void
  172. {
  173. self::assertEquals(
  174. ['a', 'b', 'c', 'd', 'f', 'e'],
  175. array_keys((new ModuleRegistry([
  176. $this->createModule('f'),
  177. $this->createModule('c', ['position' => ['after' => '*']]),
  178. $this->createModule('d', ['position' => ['bottom']]),
  179. $this->createModule('a', ['position' => ['top']]),
  180. $this->createModule('b', ['position' => ['before' => '*']]),
  181. $this->createModule('e'),
  182. ]))->getModules())
  183. );
  184. }
  185. /**
  186. * @test
  187. */
  188. public function subModulesAndDependencyChainOverruleFirstLevelDependencies(): void
  189. {
  190. self::assertEquals(
  191. // @todo Shouldn't this better be: "a", "a_a", "a_a_a", "b", "c", "d", "e" ?
  192. ['a', 'a_a', 'a_a_a', 'b', 'd', 'c', 'e'],
  193. array_keys((new ModuleRegistry([
  194. $this->createModule('a'),
  195. $this->createModule('a_a', ['parent' => 'a']),
  196. $this->createModule('a_a_a', ['parent' => 'a_a']),
  197. $this->createModule('b', ['position' => ['after' => 'a']]),
  198. $this->createModule('c', ['position' => ['after' => 'a']]),
  199. $this->createModule('d', ['position' => ['after' => 'b']]),
  200. $this->createModule('e'),
  201. ]))->getModules())
  202. );
  203. }
  204. /**
  205. * @test
  206. */
  207. public function dependencyChainsAreRespected(): void
  208. {
  209. self::assertEquals(
  210. // @todo Shouldn't this better be: "a", "e", "c", "b", "d" ?
  211. ['a', 'b', 'd', 'c', 'e'],
  212. array_keys((new ModuleRegistry([
  213. $this->createModule('a'),
  214. $this->createModule('b', ['position' => ['after' => 'a']]),
  215. $this->createModule('c', ['position' => ['after' => 'a']]),
  216. $this->createModule('d', ['position' => ['after' => 'b']]),
  217. $this->createModule('e', ['position' => ['before' => 'c']]),
  218. ]))->getModules())
  219. );
  220. }
  221. protected function createModule($identifier, $configuration = []): ModuleInterface
  222. {
  223. return $this->moduleFactory->createModule(
  224. $identifier,
  225. $configuration
  226. );
  227. }
  228. }