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