‪TYPO3CMS  ‪main
ModuleRegistryTest.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\Test;
26 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
27 
28 final class ‪ModuleRegistryTest extends UnitTestCase
29 {
31 
32  protected function ‪setUp(): void
33  {
34  parent::setUp();
35 
36  $this->moduleFactory = new ‪ModuleFactory(
37  $this->createMock(IconRegistry::class),
39  );
40  }
41 
42  #[Test]
44  {
45  $this->expectException(\LogicException::class);
46  $this->expectExceptionCode(1642174843);
47 
48  new ‪ModuleRegistry([
49  $this->‪createModule('a_module'),
50  $this->‪createModule('a_module'),
51  ]);
52  }
53 
54  #[Test]
56  {
57  $this->expectException(\InvalidArgumentException::class);
58  $this->expectExceptionCode(1642375889);
59 
60  (new ‪ModuleRegistry([]))->getModule('a_module');
61  }
62 
63  #[Test]
64  public function ‪accessRegisteredModulesWork(): void
65  {
66  $aModule = $this->‪createModule('a_module', ['aliases' => ['a_old_module']]);
67  $bModule = $this->‪createModule('b_module', ['parent' => 'a_module']);
68 
69  $registry = new ‪ModuleRegistry([$aModule, $bModule]);
70 
71  self::assertTrue($registry->hasModule('a_module'));
72  self::assertFalse($registry->hasModule('c_module'));
73  self::assertEquals($aModule, $registry->getModule('a_module'));
74  self::assertEquals($aModule, $registry->getModule('a_old_module'));
75  self::assertEquals('a_module', $registry->getModule('b_module')->getParentIdentifier());
76  self::assertEquals(['a_module' => $aModule, 'b_module' => $bModule], $registry->getModules());
77  self::assertEquals(['a_old_module' => 'a_module'], $registry->getModuleAliases());
78  }
79 
80  #[Test]
81  public function ‪moduleAliasOverwriteStrategy(): void
82  {
83  $aModule = $this->‪createModule('a_module', ['aliases' => ['duplicate_alias']]);
84  $bModule = $this->‪createModule('b_module', ['aliases' => ['duplicate_alias']]);
85 
86  $registry = new ‪ModuleRegistry([$aModule, $bModule]);
87 
88  self::assertEquals($bModule, $registry->getModule('duplicate_alias'));
89  self::assertEquals(['duplicate_alias' => 'b_module'], $registry->getModuleAliases());
90  }
91 
92  #[Test]
94  {
95  $modules = $random = [
96  'a' => $this->‪createModule('a', ['position' => ['top']]),
97  'b' => $this->‪createModule('b', ['position' => ['after' => 'a']]),
98  'b_a' => $this->‪createModule('b_a', ['parent' => 'b', 'position' => ['top']]),
99  'b_a_a' => $this->‪createModule('b_a_a', ['parent' => 'b_a', 'position' => ['top']]),
100  'b_a_b' => $this->‪createModule('b_a_b', ['parent' => 'b_a', 'position' => ['after' => 'b_a_a']]),
101  'b_a_c' => $this->‪createModule('b_a_c', ['parent' => 'b_a', 'position' => ['before' => 'b_a_d']]),
102  'b_a_c_a' => $this->‪createModule('b_a_c_a', ['parent' => 'b_a_c', 'position' => ['bottom']]),
103  'b_a_c_b' => $this->‪createModule('b_a_c_b', ['parent' => 'b_a_c']),
104  'b_a_d' => $this->‪createModule('b_a_d', ['parent' => 'b_a', 'position' => ['before' => 'b_a_e']]),
105  'b_a_d_a' => $this->‪createModule('b_a_d_a', ['parent' => 'b_a_d', 'position' => ['top']]),
106  'b_a_d_b' => $this->‪createModule('b_a_d_b', ['parent' => 'b_a_d']),
107  'b_a_d_c' => $this->‪createModule('b_a_d_c', ['parent' => 'b_a_d', 'position' => ['after' => 'b_a_d_b']]),
108  'b_a_e' => $this->‪createModule('b_a_e', ['parent' => 'b_a', 'position' => ['after' => '*']]),
109  'b_b' => $this->‪createModule('b_b', ['parent' => 'b', 'position' => ['before' => 'b_c']]),
110  'b_c' => $this->‪createModule('b_c', ['parent' => 'b', 'position' => ['bottom']]),
111  'b_d' => $this->‪createModule('b_d', ['parent' => 'b', 'position' => ['after' => 'b_c']]),
112  // @todo Shouldn't the explicit "position => bottom" enforce the bottom
113  // position over a module ("e") not defining the position at all?
114  'c' => $this->‪createModule('c', ['position' => ['bottom']]),
115  'd' => $this->‪createModule('d', ['position' => ['before' => 'e']]),
116  'd_a' => $this->‪createModule('d_a', ['parent' => 'd', 'position' => ['before' => 'd_b']]),
117  'd_b' => $this->‪createModule('d_b', ['parent' => 'd', 'position' => ['before' => '*']]),
118  'd_c' => $this->‪createModule('d_c', ['parent' => 'd', 'position' => ['before' => 'd_d']]),
119  'd_d' => $this->‪createModule('d_d', ['parent' => 'd']),
120  'e' => $this->‪createModule('e'),
121  'e_a' => $this->‪createModule('e_a', ['parent' => 'e', 'position' => ['before' => '*']]),
122  'e_b' => $this->‪createModule('e_b', ['parent' => 'e', 'position' => ['after' => 'e_a']]),
123  'e_c' => $this->‪createModule('e_c', ['parent' => 'e', 'position' => ['after' => '*']]),
124  'e_e' => $this->‪createModule('e_e', ['parent' => 'e', 'position' => ['after' => 'invalid']]),
125  ];
126 
127  // Add modules in random order to ensure the result does not depend on the input order
128  shuffle($random);
129  $registry = new ‪ModuleRegistry($random);
130 
131  // Asser correct sorting (flat)
132  self::assertEquals(array_keys($modules), array_keys($registry->getModules()));
133 
134  // Assert correct hierarchy
135  self::assertEquals(['b_a', 'b_b', 'b_c', 'b_d'], array_keys($registry->getModule('b')->getSubModules()));
136  self::assertEquals('b', $registry->getModule('b_a')->getParentIdentifier());
137  self::assertTrue($registry->getModule('b_a')->getParentModule()->hasSubModule('b_a'));
138  self::assertEquals('b', $registry->getModule('b_b')->getParentIdentifier());
139  self::assertTrue($registry->getModule('b_b')->getParentModule()->hasSubModule('b_b'));
140  self::assertEquals('b', $registry->getModule('b_c')->getParentIdentifier());
141  self::assertTrue($registry->getModule('b_c')->getParentModule()->hasSubModule('b_c'));
142  self::assertEquals('b', $registry->getModule('b_d')->getParentIdentifier());
143  self::assertTrue($registry->getModule('b_d')->getParentModule()->hasSubModule('b_d'));
144 
145  self::assertEquals(['b_a_a', 'b_a_b', 'b_a_c', 'b_a_d', 'b_a_e'], array_keys($registry->getModule('b_a')->getSubModules()));
146  self::assertEquals('b_a', $registry->getModule('b_a_a')->getParentIdentifier());
147  self::assertEquals('b', $registry->getModule('b_a_a')->getParentModule()->getParentIdentifier());
148  self::assertEquals('b_a', $registry->getModule('b_a_b')->getParentIdentifier());
149  self::assertEquals('b', $registry->getModule('b_a_a')->getParentModule()->getParentIdentifier());
150  self::assertEquals('b_a', $registry->getModule('b_a_c')->getParentIdentifier());
151  self::assertEquals('b', $registry->getModule('b_a_a')->getParentModule()->getParentIdentifier());
152  self::assertEquals('b_a', $registry->getModule('b_a_d')->getParentIdentifier());
153  self::assertEquals('b', $registry->getModule('b_a_a')->getParentModule()->getParentIdentifier());
154  self::assertEquals('b_a', $registry->getModule('b_a_e')->getParentIdentifier());
155  self::assertEquals('b', $registry->getModule('b_a_a')->getParentModule()->getParentIdentifier());
156 
157  self::assertEquals(['b_a_c_a', 'b_a_c_b'], array_keys($registry->getModule('b_a_c')->getSubModules()));
158  self::assertEquals('b_a_c', $registry->getModule('b_a_c_a')->getParentIdentifier());
159  self::assertEquals('b_a', $registry->getModule('b_a_c_a')->getParentModule()->getParentIdentifier());
160  self::assertEquals('b', $registry->getModule('b_a_c_a')->getParentModule()->getParentModule()->getParentIdentifier());
161  self::assertEquals('b_a_c', $registry->getModule('b_a_c_b')->getParentIdentifier());
162  self::assertEquals('b_a', $registry->getModule('b_a_c_b')->getParentModule()->getParentIdentifier());
163  self::assertEquals('b', $registry->getModule('b_a_c_b')->getParentModule()->getParentModule()->getParentIdentifier());
164 
165  self::assertEquals(['b_a_d_a', 'b_a_d_b', 'b_a_d_c'], array_keys($registry->getModule('b_a_d')->getSubModules()));
166  self::assertEquals('b_a_d', $registry->getModule('b_a_d_a')->getParentIdentifier());
167  self::assertEquals('b_a', $registry->getModule('b_a_d_a')->getParentModule()->getParentIdentifier());
168  self::assertEquals('b', $registry->getModule('b_a_d_a')->getParentModule()->getParentModule()->getParentIdentifier());
169  self::assertEquals('b_a_d', $registry->getModule('b_a_d_b')->getParentIdentifier());
170  self::assertEquals('b_a', $registry->getModule('b_a_d_b')->getParentModule()->getParentIdentifier());
171  self::assertEquals('b', $registry->getModule('b_a_d_b')->getParentModule()->getParentModule()->getParentIdentifier());
172  self::assertEquals('b_a_d', $registry->getModule('b_a_d_c')->getParentIdentifier());
173  self::assertEquals('b_a', $registry->getModule('b_a_d_c')->getParentModule()->getParentIdentifier());
174  self::assertEquals('b', $registry->getModule('b_a_d_c')->getParentModule()->getParentModule()->getParentIdentifier());
175  }
176 
177  #[Test]
179  {
180  self::assertEquals(
181  ['a', 'b', 'b_a', 'b_b', 'c'],
182  array_keys((new ‪ModuleRegistry([
183  $this->‪createModule('a'),
184  $this->‪createModule('b'),
185  $this->‪createModule('b_a', ['parent' => 'b']),
186  $this->‪createModule('b_b', ['parent' => 'b']),
187  $this->‪createModule('c'),
188  ]))->getModules())
189  );
190  }
191 
192  #[Test]
194  {
195  self::assertEquals(
196  ['a', 'b', 'c', 'd', 'f', 'e'],
197  array_keys((new ‪ModuleRegistry([
198  $this->‪createModule('f'),
199  $this->‪createModule('c', ['position' => ['after' => '*']]),
200  $this->‪createModule('d', ['position' => ['bottom']]),
201  $this->‪createModule('a', ['position' => ['top']]),
202  $this->‪createModule('b', ['position' => ['before' => '*']]),
203  $this->‪createModule('e'),
204  ]))->getModules())
205  );
206  }
207 
208  #[Test]
210  {
211  self::assertEquals(
212  // @todo Shouldn't this better be: "a", "a_a", "a_a_a", "b", "c", "d", "e" ?
213  ['a', 'a_a', 'a_a_a', 'b', 'd', 'c', 'e'],
214  array_keys((new ‪ModuleRegistry([
215  $this->‪createModule('a'),
216  $this->‪createModule('a_a', ['parent' => 'a']),
217  $this->‪createModule('a_a_a', ['parent' => 'a_a']),
218  $this->‪createModule('b', ['position' => ['after' => 'a']]),
219  $this->‪createModule('c', ['position' => ['after' => 'a']]),
220  $this->‪createModule('d', ['position' => ['after' => 'b']]),
221  $this->‪createModule('e'),
222  ]))->getModules())
223  );
224  }
225 
226  #[Test]
227  public function ‪dependencyChainsAreRespected(): void
228  {
229  self::assertEquals(
230  // @todo Shouldn't this better be: "a", "e", "c", "b", "d" ?
231  ['a', 'b', 'd', 'c', 'e'],
232  array_keys((new ‪ModuleRegistry([
233  $this->‪createModule('a'),
234  $this->‪createModule('b', ['position' => ['after' => 'a']]),
235  $this->‪createModule('c', ['position' => ['after' => 'a']]),
236  $this->‪createModule('d', ['position' => ['after' => 'b']]),
237  $this->‪createModule('e', ['position' => ['before' => 'c']]),
238  ]))->getModules())
239  );
240  }
241 
242  protected function ‪createModule(‪$identifier, $configuration = []): ‪ModuleInterface
243  {
244  return $this->moduleFactory->createModule(
246  $configuration
247  );
248  }
249 }
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\addModuleAppliesSortingAndHierarchy
‪addModuleAppliesSortingAndHierarchy()
Definition: ModuleRegistryTest.php:93
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\dependencyChainsAreRespected
‪dependencyChainsAreRespected()
Definition: ModuleRegistryTest.php:227
‪TYPO3\CMS\Backend\Module\ModuleRegistry
Definition: ModuleRegistry.php:28
‪TYPO3\CMS\Backend\Module\ModuleFactory
Definition: ModuleFactory.php:29
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\subModulesAndDependencyChainOverruleFirstLevelDependencies
‪subModulesAndDependencyChainOverruleFirstLevelDependencies()
Definition: ModuleRegistryTest.php:209
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\throwsExceptionOnNonExistingModuleIdentifier
‪throwsExceptionOnNonExistingModuleIdentifier()
Definition: ModuleRegistryTest.php:55
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\setUp
‪setUp()
Definition: ModuleRegistryTest.php:32
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\moduleAliasOverwriteStrategy
‪moduleAliasOverwriteStrategy()
Definition: ModuleRegistryTest.php:81
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\createModule
‪createModule($identifier, $configuration=[])
Definition: ModuleRegistryTest.php:242
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\accessRegisteredModulesWork
‪accessRegisteredModulesWork()
Definition: ModuleRegistryTest.php:64
‪TYPO3\CMS\Core\Imaging\IconRegistry
Definition: IconRegistry.php:32
‪TYPO3\CMS\Backend\Module\ModuleInterface
Definition: ModuleInterface.php:24
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\throwsExceptionOnDuplicateModuleIdentifier
‪throwsExceptionOnDuplicateModuleIdentifier()
Definition: ModuleRegistryTest.php:43
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\firstModuleDeclaringTopWillBeOnTop
‪firstModuleDeclaringTopWillBeOnTop()
Definition: ModuleRegistryTest.php:193
‪TYPO3\CMS\Core\EventDispatcher\NoopEventDispatcher
Definition: NoopEventDispatcher.php:29
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\keepsInputOrderWithoutPositionDefinition
‪keepsInputOrderWithoutPositionDefinition()
Definition: ModuleRegistryTest.php:178
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest\$moduleFactory
‪ModuleFactory $moduleFactory
Definition: ModuleRegistryTest.php:30
‪TYPO3\CMS\Backend\Tests\Unit\Module
Definition: ModuleFactoryTest.php:18
‪TYPO3\CMS\Backend\Tests\Unit\Module\ModuleRegistryTest
Definition: ModuleRegistryTest.php:29