[BUGFIX] Allow array of paths in psr-4 autoload definition
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Core / ClassLoadingInformationGeneratorTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Core;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Composer\Autoload\ClassLoader;
18 use TYPO3\CMS\Core\Core\ClassLoadingInformationGenerator;
19 use TYPO3\CMS\Core\Package\PackageInterface;
20 use TYPO3\CMS\Core\Tests\UnitTestCase;
21
22 /**
23 * Testcase for the ClassLoadingInformationGenerator class
24 */
25 class ClassLoadingInformationGeneratorTest extends UnitTestCase
26 {
27 /**
28 * @test
29 */
30 public function buildClassAliasMapForPackageThrowsExceptionForWrongComposerManifestInformation()
31 {
32 $this->expectException(\TYPO3\CMS\Core\Error\Exception::class);
33 $this->expectExceptionCode(1444142481);
34
35 $packageMock = $this->createPackageMock([
36 'extra' => [
37 'typo3/class-alias-loader' => [
38 'class-alias-maps' => [
39 'foo' => Fixtures\test_extension\Resources\PHP\Test::class,
40 'bar' => Fixtures\test_extension\Resources\PHP\AnotherTestFile::class,
41 ],
42 ],
43 ],
44 ]);
45 /** @var ClassLoader|\PHPUnit_Framework_MockObject_MockObject $classLoaderMock */
46 $classLoaderMock = $this->createMock(ClassLoader::class);
47 $generator = new ClassLoadingInformationGenerator($classLoaderMock, [], __DIR__);
48 $generator->buildClassAliasMapForPackage($packageMock);
49 }
50
51 /**
52 * @test
53 */
54 public function buildClassAliasMapForPackageThrowsExceptionForWrongClassAliasMapFile()
55 {
56 $this->expectException(\TYPO3\CMS\Core\Error\Exception::class);
57 $this->expectExceptionCode(1422625075);
58
59 $packageMock = $this->createPackageMock([
60 'extra' => [
61 'typo3/class-alias-loader' => [
62 'class-alias-maps' => [
63 'Migrations/Code/WrongClassAliasMap.php',
64 ],
65 ],
66 ],
67 ]);
68 /** @var ClassLoader|\PHPUnit_Framework_MockObject_MockObject $classLoaderMock */
69 $classLoaderMock = $this->createMock(ClassLoader::class);
70 $generator = new ClassLoadingInformationGenerator($classLoaderMock, [], __DIR__);
71 $generator->buildClassAliasMapForPackage($packageMock);
72 }
73
74 /**
75 * @test
76 */
77 public function buildClassAliasMapForPackageReturnsClassAliasMapForClassAliasMapFile()
78 {
79 $expectedClassMap = [
80 'aliasToClassNameMapping' => [
81 'foo' => Fixtures\test_extension\Resources\PHP\Test::class,
82 'bar' => Fixtures\test_extension\Resources\PHP\AnotherTestFile::class,
83 ],
84 'classNameToAliasMapping' => [
85 Fixtures\test_extension\Resources\PHP\Test::class => [
86 'foo' => 'foo',
87 ],
88 Fixtures\test_extension\Resources\PHP\AnotherTestFile::class => [
89 'bar' => 'bar',
90 ]
91 ],
92 ];
93 $packageMock = $this->createPackageMock(array());
94 /** @var ClassLoader|\PHPUnit_Framework_MockObject_MockObject $classLoaderMock */
95 $classLoaderMock = $this->createMock(ClassLoader::class);
96 $generator = new ClassLoadingInformationGenerator($classLoaderMock, [], __DIR__);
97 $this->assertEquals($expectedClassMap, $generator->buildClassAliasMapForPackage($packageMock));
98 }
99
100 /**
101 * @test
102 */
103 public function buildClassAliasMapForPackageReturnsClassAliasMapForComposerManifestInformation()
104 {
105 $expectedClassMap = [
106 'aliasToClassNameMapping' => [
107 'foo' => Fixtures\test_extension\Resources\PHP\Test::class,
108 'bar' => Fixtures\test_extension\Resources\PHP\AnotherTestFile::class,
109 ],
110 'classNameToAliasMapping' => [
111 Fixtures\test_extension\Resources\PHP\Test::class => [
112 'foo' => 'foo',
113 ],
114 Fixtures\test_extension\Resources\PHP\AnotherTestFile::class => [
115 'bar' => 'bar',
116 ]
117 ],
118 ];
119 $packageMock = $this->createPackageMock([
120 'extra' => [
121 'typo3/class-alias-loader' => [
122 'class-alias-maps' => [
123 'Resources/PHP/ClassAliasMap.php',
124 ],
125 ],
126 ],
127 ]);
128 /** @var ClassLoader|\PHPUnit_Framework_MockObject_MockObject $classLoaderMock */
129 $classLoaderMock = $this->createMock(ClassLoader::class);
130 $generator = new ClassLoadingInformationGenerator($classLoaderMock, [], __DIR__);
131 $this->assertEquals($expectedClassMap, $generator->buildClassAliasMapForPackage($packageMock));
132 }
133
134 /**
135 * Data provider for different autoload information
136 *
137 * @return array
138 */
139 public function autoloadFilesAreBuildCorrectlyDataProvider()
140 {
141 return [
142 'Psr-4 section' => [
143 [
144 'autoload' => [
145 'psr-4' => [
146 'TYPO3\\CMS\\TestExtension\\' => 'Classes/',
147 ],
148 ],
149 ],
150 [
151 '\'TYPO3\\\\CMS\\\\TestExtension\\\\\' => array($typo3InstallDir . \'/Fixtures/test_extension/Classes\')',
152 ],
153 [],
154 ],
155 'Psr-4 section with array' => [
156 [
157 'autoload' => [
158 'psr-4' => [
159 'TYPO3\\CMS\\TestExtension\\' => ['Classes/', 'Resources/PHP/'],
160 ],
161 ],
162 ],
163 [
164 '\'TYPO3\\\\CMS\\\\TestExtension\\\\\' => array($typo3InstallDir . \'/Fixtures/test_extension/Classes\',$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP\')',
165 ],
166 [],
167 ],
168 'Psr-4 section without trailing slash' => [
169 [
170 'autoload' => [
171 'psr-4' => [
172 'TYPO3\\CMS\\TestExtension\\' => 'Classes',
173 ],
174 ],
175 ],
176 [
177 '\'TYPO3\\\\CMS\\\\TestExtension\\\\\' => array($typo3InstallDir . \'/Fixtures/test_extension/Classes\')',
178 ],
179 [],
180 ],
181 'Classmap section' => [
182 [
183 'autoload' => [
184 'classmap' => [
185 'Resources/PHP/',
186 ],
187 ],
188 ],
189 [],
190 [
191 '$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Test.php\'',
192 '$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/AnotherTestFile.php\'',
193 '$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Subdirectory/SubdirectoryTest.php\'',
194 ],
195 ],
196 'Classmap section without trailing slash' => [
197 [
198 'autoload' => [
199 'classmap' => [
200 'Resources/PHP',
201 ],
202 ],
203 ],
204 [],
205 [
206 '$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Test.php\'',
207 '$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/AnotherTestFile.php\'',
208 '$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Subdirectory/SubdirectoryTest.php\'',
209 ],
210 ],
211 'Classmap section pointing to a file' => [
212 [
213 'autoload' => [
214 'classmap' => [
215 'Resources/PHP/Test.php',
216 ],
217 ],
218 ],
219 [],
220 [
221 '$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Test.php\'',
222 '!$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/AnotherTestFile.php\'',
223 '!$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Subdirectory/SubdirectoryTest.php\'',
224 ],
225 ],
226 'No autoload section' => [
227 [],
228 [],
229 [
230 '!$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Test.php\'',
231 '!$typo3InstallDir . \'/Fixtures/test_extension/Tests/TestClass.php\'',
232 '!$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/AnotherTestFile.php\'',
233 '!$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Subdirectory/SubdirectoryTest.php\'',
234 '!$typo3InstallDir . \'/Fixtures/test_extension/class.ext_update.php\'',
235 ],
236 ],
237 'Classmap section pointing to two files' => [
238 [
239 'autoload' => [
240 'classmap' => [
241 'Resources/PHP/Test.php',
242 'Resources/PHP/AnotherTestFile.php',
243 ],
244 ],
245 ],
246 [],
247 [
248 '$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Test.php\'',
249 '$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/AnotherTestFile.php\'',
250 '!$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Subdirectory/SubdirectoryTest.php\'',
251 ],
252 ],
253 ];
254 }
255
256 /**
257 * @test
258 * @dataProvider autoloadFilesAreBuildCorrectlyDataProvider
259 *
260 * @param string $packageManifest
261 * @param array $expectedPsr4Files
262 * @param array $expectedClassMapFiles
263 */
264 public function autoloadFilesAreBuildCorrectly($packageManifest, $expectedPsr4Files, $expectedClassMapFiles)
265 {
266 /** @var ClassLoader|\PHPUnit_Framework_MockObject_MockObject $classLoaderMock */
267 $classLoaderMock = $this->createMock(ClassLoader::class);
268 $generator = new ClassLoadingInformationGenerator($classLoaderMock, [$this->createPackageMock($packageManifest)], __DIR__);
269 $files = $generator->buildAutoloadInformationFiles();
270
271 $this->assertArrayHasKey('psr-4File', $files);
272 $this->assertArrayHasKey('classMapFile', $files);
273 foreach ($expectedPsr4Files as $expectation) {
274 if ($expectation[0] === '!') {
275 $expectedCount = 0;
276 $expectation = substr($expectation, 1);
277 $message = sprintf('File "%s" is NOT expected to be in psr-4, but is.', $expectation);
278 } else {
279 $expectedCount = 1;
280 $message = sprintf('File "%s" is expected to be in psr-4, but is not.', $expectation);
281 }
282 $this->assertSame($expectedCount, substr_count($files['psr-4File'], $expectation), $message);
283 }
284 foreach ($expectedClassMapFiles as $expectation) {
285 if ($expectation[0] === '!') {
286 $expectedCount = 0;
287 $expectation = substr($expectation, 1);
288 $message = sprintf('File "%s" is NOT expected to be in class map, but is.', $expectation);
289 } else {
290 $expectedCount = 1;
291 $message = sprintf('File "%s" is expected to be in class map, but is not.', $expectation);
292 }
293 $this->assertSame($expectedCount, substr_count($files['classMapFile'], $expectation), $message);
294 }
295 }
296
297 /**
298 * Data provider for different autoload information
299 *
300 * @return array
301 */
302 public function autoloadDevFilesAreBuildCorrectlyDataProvider()
303 {
304 return [
305 'Psr-4 sections' => [
306 [
307 'autoload' => [
308 'psr-4' => [
309 'TYPO3\\CMS\\TestExtension\\' => 'Classes',
310 ],
311 ],
312 'autoload-dev' => [
313 'psr-4' => [
314 'TYPO3\\CMS\\TestExtension\\Tests\\' => 'Tests',
315 ],
316 ],
317 ],
318 [
319 '\'TYPO3\\\\CMS\\\\TestExtension\\\\\' => array($typo3InstallDir . \'/Fixtures/test_extension/Classes\')',
320 '\'TYPO3\\\\CMS\\\\TestExtension\\\\Tests\\\\\' => array($typo3InstallDir . \'/Fixtures/test_extension/Tests\')',
321 ],
322 [],
323 ],
324 'Psr-4 sections with override' => [
325 [
326 'autoload' => [
327 'psr-4' => [
328 'TYPO3\\CMS\\TestExtension\\' => 'Classes',
329 ],
330 ],
331 'autoload-dev' => [
332 'psr-4' => [
333 'TYPO3\\CMS\\TestExtension\\' => 'Tests',
334 ],
335 ],
336 ],
337 [
338 '!\'TYPO3\\\\CMS\\\\TestExtension\\\\\' => array($typo3InstallDir . \'/Fixtures/test_extension/Classes\')',
339 '\'TYPO3\\\\CMS\\\\TestExtension\\\\\' => array($typo3InstallDir . \'/Fixtures/test_extension/Tests\')',
340 ],
341 [],
342 ],
343 'Classmap section pointing to two files, one in dev and one not' => [
344 [
345 'autoload' => [
346 'classmap' => [
347 'Resources/PHP/Test.php',
348 ],
349 ],
350 'autoload-dev' => [
351 'classmap' => [
352 'Resources/PHP/AnotherTestFile.php',
353 ],
354 ],
355 ],
356 [],
357 [
358 '$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Test.php\'',
359 '$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/AnotherTestFile.php\'',
360 '!$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Subdirectory/SubdirectoryTest.php\'',
361 ],
362 ],
363 ];
364 }
365
366 /**
367 * @test
368 * @dataProvider autoloadDevFilesAreBuildCorrectlyDataProvider
369 *
370 * @param array $packageManifest
371 * @param array $expectedPsr4Files
372 * @param array $expectedClassMapFiles
373 */
374 public function autoloadDevFilesAreBuildCorrectly($packageManifest, $expectedPsr4Files, $expectedClassMapFiles)
375 {
376 /** @var ClassLoader|\PHPUnit_Framework_MockObject_MockObject $classLoaderMock */
377 $classLoaderMock = $this->createMock(ClassLoader::class);
378 $generator = new ClassLoadingInformationGenerator($classLoaderMock, [$this->createPackageMock($packageManifest)], __DIR__, true);
379 $files = $generator->buildAutoloadInformationFiles();
380
381 $this->assertArrayHasKey('psr-4File', $files);
382 $this->assertArrayHasKey('classMapFile', $files);
383 foreach ($expectedPsr4Files as $expectation) {
384 if ($expectation[0] === '!') {
385 $expectedCount = 0;
386 } else {
387 $expectedCount = 1;
388 }
389 $this->assertSame($expectedCount, substr_count($files['psr-4File'], $expectation), '' . $expectation);
390 }
391 foreach ($expectedClassMapFiles as $expectation) {
392 if ($expectation[0] === '!') {
393 $expectedCount = 0;
394 } else {
395 $expectedCount = 1;
396 }
397 $this->assertSame($expectedCount, substr_count($files['classMapFile'], $expectation), '' . $expectation);
398 }
399 }
400
401 /**
402 * @param array Array which should be returned as composer manifest
403 * @return PackageInterface
404 */
405 protected function createPackageMock($packageManifest)
406 {
407 $packageMock = $this->createMock(PackageInterface::class);
408 $packageMock->expects($this->any())->method('getPackagePath')->willReturn(__DIR__ . '/Fixtures/test_extension/');
409 $packageMock->expects($this->any())->method('getValueFromComposerManifest')->willReturn(
410 json_decode(json_encode($packageManifest))
411 );
412
413 return $packageMock;
414 }
415 }