2b814572b5f31966912e99f1580be137167c7098
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Core / ClassLoaderTest.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 org\bovigo\vfs\vfsStream;
18
19 /**
20 * Testcase for TYPO3\CMS\Core\Core\ClassLoader
21 *
22 * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
23 */
24 class ClassLoaderTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
25
26 /**
27 * @var array Backup of typo3CacheManager
28 */
29 protected $typo3CacheManager = NULL;
30
31 /**
32 * @var array Register of temporary extensions in typo3temp
33 */
34 protected $fakedExtensions = array();
35
36 /**
37 * @var \TYPO3\CMS\Core\Core\ClassLoader
38 */
39 protected $classLoader;
40
41 /**
42 * @var \TYPO3\CMS\Core\Core\ClassAliasMap
43 */
44 protected $orinalClassAliasMap;
45
46 /**
47 * Test flag used in in this test case
48 *
49 * @var bool
50 */
51 public static $testClassWasLoaded = FALSE;
52
53 /**
54 * Fix a race condition that GeneralUtility is not available
55 * during tearDown if fiddling with the autoloader where
56 * backupGlobals is not set up again yet
57 */
58 protected function setUp() {
59 vfsStream::setup('Test');
60
61 mkdir('vfs://Test/Packages/Application/Acme.MyApp/Classes/', 0770, TRUE);
62 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/composer.json', '{"name": "acme/myapp", "type": "flow-test"}');
63 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/ext_emconf.php', '');
64 $packageManager = $this->getMock(\TYPO3\CMS\Core\Package\PackageManager::class, array('isPackageKeyValid'));
65 $packageManager->expects($this->any())->method('isPackageKeyValid')->willReturn(TRUE);
66 $package1 = new \TYPO3\CMS\Core\Package\Package($packageManager, 'Acme.MyApp', 'vfs://Test/Packages/Application/Acme.MyApp/', 'Classes');
67
68 mkdir('vfs://Test/Packages/Application/Acme.MyAppAddon/Classes/', 0770, TRUE);
69 file_put_contents('vfs://Test/Packages/Application/Acme.MyAppAddon/composer.json', '{"name": "acme/myappaddon", "type": "flow-test"}');
70 file_put_contents('vfs://Test/Packages/Application/Acme.MyAppAddon/ext_emconf.php', '');
71 $package2 = new \TYPO3\CMS\Core\Package\Package($packageManager, 'Acme.MyAppAddon', 'vfs://Test/Packages/Application/Acme.MyAppAddon/', 'Classes');
72
73 $mockClassAliasMap = $this->getMock(\TYPO3\CMS\Core\Core\ClassAliasMap::class, array('setPackagesButDontBuildMappingFilesReturnClassNameToAliasMappingInstead', 'buildMappingFiles'), array(), '', FALSE);
74 $mockClassAliasMap->expects($this->any())->method('setPackagesButDontBuildMappingFilesReturnClassNameToAliasMappingInstead')->will($this->returnValue(array()));
75
76 $this->orinalClassAliasMap = \TYPO3\CMS\Core\Core\Bootstrap::getInstance()->getEarlyInstance(\TYPO3\CMS\Core\Core\ClassAliasMap::class);
77 $this->classLoader = new \TYPO3\CMS\Core\Core\ClassLoader(\TYPO3\CMS\Core\Core\Bootstrap::getInstance()->getApplicationContext());
78 $this->classLoader->injectClassAliasMap($mockClassAliasMap);
79 $this->classLoader->setPackages(array('Acme.MyApp' => $package1, 'Acme.MyAppAddon' => $package2));
80 }
81
82 /**
83 * The class alias map is kept static in the class loader for legacy reasons
84 * and has to be reset after mocking.
85 */
86 protected function tearDown() {
87 $this->classLoader->injectClassAliasMap($this->orinalClassAliasMap);
88 parent::tearDown();
89 }
90
91 /**
92 * Creates a fake extension inside typo3temp/. No configuration is created,
93 * just the folder, plus the extension is registered in $TYPO3_LOADED_EXT
94 *
95 * @return string The extension key
96 */
97 protected function createFakeExtension() {
98 $extKey = strtolower($this->getUniqueId('testing'));
99 $absExtPath = PATH_site . 'typo3temp/' . $extKey . '/';
100 $relPath = 'typo3temp/' . $extKey . '/';
101 \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir($absExtPath);
102 $GLOBALS['TYPO3_LOADED_EXT'][$extKey] = array(
103 'siteRelPath' => $relPath
104 );
105 $this->fakedExtensions[] = $extKey;
106 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::clearExtensionKeyMap();
107 return $extKey;
108 }
109
110 /**
111 * Checks if the package autoloader loads classes from subdirectories.
112 *
113 * @test
114 */
115 public function classesFromSubDirectoriesAreLoaded() {
116 mkdir('vfs://Test/Packages/Application/Acme.MyApp/Classes/SubDirectory', 0770, TRUE);
117 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/Classes/SubDirectory/ClassInSubDirectory.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
118
119 self::$testClassWasLoaded = FALSE;
120 $this->classLoader->loadClass('Acme\MyApp\SubDirectory\ClassInSubDirectory');
121 $this->assertTrue(self::$testClassWasLoaded);
122 }
123
124 /**
125 * @test
126 */
127 public function classesFromDeeplyNestedSubDirectoriesAreLoaded() {
128 mkdir('vfs://Test/Packages/Application/Acme.MyApp/Classes/SubDirectory/A/B/C/D', 0770, TRUE);
129 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/Classes/SubDirectory/A/B/C/D/E.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
130
131 self::$testClassWasLoaded = FALSE;
132 $this->classLoader->loadClass('Acme\MyApp\SubDirectory\A\B\C\D\E');
133 $this->assertTrue(self::$testClassWasLoaded);
134 }
135
136 /**
137 * Checks if the package autoloader loads classes from packages that match a
138 * substring of another package (e.g. TYPO3CR vs TYPO3).
139 *
140 * @test
141 */
142 public function classesFromSubMatchingPackagesAreLoaded() {
143 file_put_contents('vfs://Test/Packages/Application/Acme.MyAppAddon/Classes/Class.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
144
145 self::$testClassWasLoaded = FALSE;
146 $this->classLoader->loadClass('Acme\MyAppAddon\Class');
147 $this->assertTrue(self::$testClassWasLoaded);
148 }
149
150 /**
151 * Checks if the package autoloader loads classes from subdirectories with underscores.
152 *
153 * @test
154 */
155 public function namespaceWithUnderscoresAreLoaded() {
156 mkdir('vfs://Test/Packages/Application/Acme.MyApp/Classes/My_Underscore', 0770, TRUE);
157 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/Classes/My_Underscore/Foo.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
158
159 self::$testClassWasLoaded = FALSE;
160 $this->classLoader->loadClass('Acme\MyApp\My_Underscore\Foo');
161 $this->assertTrue(self::$testClassWasLoaded);
162 }
163
164 /**
165 * @test
166 */
167 public function classesWithLeadingBackslashAreLoaded() {
168 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/Classes/WithLeadingBackslash.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
169
170 self::$testClassWasLoaded = FALSE;
171 $this->classLoader->loadClass('\Acme\MyApp\WithLeadingBackslash');
172 $this->assertTrue(self::$testClassWasLoaded);
173 }
174
175 }