[FEATURE] Integrate preliminary PackageManager API
[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 * Copyright notice
6 *
7 * (c) 2011-2013 Andreas Wolf <andreas.wolf@ikt-werk.de>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 use org\bovigo\vfs\vfsStream;
28
29 /**
30 * Testcase for TYPO3\CMS\Core\Core\ClassLoader
31 *
32 * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
33 */
34 class ClassLoaderTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
35
36 /**
37 * @var array Backup of typo3CacheManager
38 */
39 protected $typo3CacheManager = NULL;
40
41 /**
42 * @var array Register of temporary extensions in typo3temp
43 */
44 protected $fakedExtensions = array();
45
46
47 /**
48 * @var \TYPO3\CMS\Core\Core\ClassLoader
49 */
50 protected $classLoader;
51
52 /**
53 * @var \TYPO3\CMS\Core\Core\ClassAliasMap
54 */
55 protected $orinalClassAliasMap;
56
57 /**
58 * Test flag used in in this test case
59 *
60 * @var boolean
61 */
62 public static $testClassWasLoaded = FALSE;
63
64 /**
65 * Fix a race condition that GeneralUtility is not available
66 * during tearDown if fiddling with the autoloader where
67 * backupGlobals is not set up again yet
68 */
69 public function setUp() {
70 vfsStream::setup('Test');
71
72 mkdir('vfs://Test/Packages/Application/Acme.MyApp/Classes/', 0770, TRUE);
73 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/composer.json', '{"name": "acme/myapp", "type": "flow-test"}');
74 $package1 = new \TYPO3\Flow\Package\Package($this->getMock('TYPO3\Flow\Package\PackageManager'), 'Acme.MyApp', 'vfs://Test/Packages/Application/Acme.MyApp/', 'Classes');
75
76 mkdir('vfs://Test/Packages/Application/Acme.MyAppAddon/Classes/', 0770, TRUE);
77 file_put_contents('vfs://Test/Packages/Application/Acme.MyAppAddon/composer.json', '{"name": "acme/myappaddon", "type": "flow-test"}');
78 $package2 = new \TYPO3\Flow\Package\Package($this->getMock('TYPO3\Flow\Package\PackageManager'), 'Acme.MyAppAddon', 'vfs://Test/Packages/Application/Acme.MyAppAddon/', 'Classes');
79
80 $mockClassAliasMap = $this->getMock('TYPO3\\CMS\\Core\\Core\\ClassAliasMap', array('setPackagesButDontBuildMappingFilesReturnClassNameToAliasMappingInstead', 'buildMappingFiles'), array(), '', FALSE);
81 $mockClassAliasMap->expects($this->any())->method('setPackagesButDontBuildMappingFilesReturnClassNameToAliasMappingInstead')->will($this->returnValue(array()));
82
83 $this->orinalClassAliasMap = \TYPO3\CMS\Core\Core\Bootstrap::getInstance()->getEarlyInstance('TYPO3\\CMS\\Core\\Core\\ClassAliasMap');
84 $this->classLoader = new \TYPO3\CMS\Core\Core\ClassLoader();
85 $this->classLoader->injectClassAliasMap($mockClassAliasMap);
86 $this->classLoader->setPackages(array('Acme.MyApp' => $package1, 'Acme.MyAppAddon' => $package2));
87 }
88
89 /**
90 * The class alias map is kept static in the class loader for legacy reasons
91 * and has to be reset after mocking.
92 */
93 public function tearDown() {
94 $this->classLoader->injectClassAliasMap($this->orinalClassAliasMap);
95 }
96
97 /**
98 * Creates a fake extension inside typo3temp/. No configuration is created,
99 * just the folder, plus the extension is registered in $TYPO3_LOADED_EXT
100 *
101 * @return string The extension key
102 */
103 protected function createFakeExtension() {
104 $extKey = strtolower(uniqid('testing'));
105 $absExtPath = PATH_site . 'typo3temp/' . $extKey . '/';
106 $relPath = 'typo3temp/' . $extKey . '/';
107 \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir($absExtPath);
108 $GLOBALS['TYPO3_LOADED_EXT'][$extKey] = array(
109 'siteRelPath' => $relPath
110 );
111 $GLOBALS['TYPO3_CONF_VARS']['EXT']['extListArray'][] = $extKey;
112 $this->fakedExtensions[] = $extKey;
113 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::clearExtensionKeyMap();
114 return $extKey;
115 }
116
117 /**
118 * Checks if the package autoloader loads classes from subdirectories.
119 *
120 * @test
121 */
122 public function classesFromSubDirectoriesAreLoaded() {
123 mkdir('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp/SubDirectory', 0770, TRUE);
124 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp/SubDirectory/ClassInSubDirectory.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
125
126 self::$testClassWasLoaded = FALSE;
127 $this->classLoader->loadClass('Acme\MyApp\SubDirectory\ClassInSubDirectory');
128 $this->assertTrue(self::$testClassWasLoaded);
129 }
130
131 /**
132 * @test
133 */
134 public function classesFromDeeplyNestedSubDirectoriesAreLoaded() {
135 mkdir('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp/SubDirectory/A/B/C/D', 0770, TRUE);
136 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp/SubDirectory/A/B/C/D/E.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
137
138 self::$testClassWasLoaded = FALSE;
139 $this->classLoader->loadClass('Acme\MyApp\SubDirectory\A\B\C\D\E');
140 $this->assertTrue(self::$testClassWasLoaded);
141 }
142
143 /**
144 * Checks if the package autoloader loads classes from packages that match a
145 * substring of another package (e.g. TYPO3CR vs TYPO3).
146 *
147 * @test
148 */
149 public function classesFromSubMatchingPackagesAreLoaded() {
150 mkdir('vfs://Test/Packages/Application/Acme.MyAppAddon/Classes/Acme/MyAppAddon', 0770, TRUE);
151 file_put_contents('vfs://Test/Packages/Application/Acme.MyAppAddon/Classes/Acme/MyAppAddon/Class.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
152
153 self::$testClassWasLoaded = FALSE;
154 $this->classLoader->loadClass('Acme\MyAppAddon\Class');
155 $this->assertTrue(self::$testClassWasLoaded);
156 }
157
158 /**
159 * Checks if the package autoloader loads classes from subdirectories.
160 *
161 * @test
162 */
163 public function classesWithUnderscoresAreLoaded() {
164 mkdir('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp', 0770, TRUE);
165 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp/Foo.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
166
167 self::$testClassWasLoaded = FALSE;
168 $this->classLoader->loadClass('Acme\MyApp_Foo');
169 $this->assertTrue(self::$testClassWasLoaded);
170 }
171
172 /**
173 * Checks if the package autoloader loads classes from subdirectories with underscores.
174 *
175 * @test
176 */
177 public function namespaceWithUnderscoresAreLoaded() {
178 mkdir('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp/My_Underscore', 0770, TRUE);
179 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp/My_Underscore/Foo.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
180
181 self::$testClassWasLoaded = FALSE;
182 $this->classLoader->loadClass('Acme\MyApp\My_Underscore\Foo');
183 $this->assertTrue(self::$testClassWasLoaded);
184 }
185
186 /**
187 * Checks if the package autoloader loads classes from subdirectories.
188 *
189 * @test
190 */
191 public function classesWithOnlyUnderscoresAreLoaded() {
192 mkdir('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp', 0770, TRUE);
193 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp/UnderscoredOnly.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
194
195 self::$testClassWasLoaded = FALSE;
196 $this->classLoader->loadClass('Acme_MyApp_UnderscoredOnly');
197 $this->assertTrue(self::$testClassWasLoaded);
198 }
199
200 /**
201 * @test
202 */
203 public function classesWithLeadingBackslashAreLoaded() {
204 mkdir('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp', 0770, TRUE);
205 file_put_contents('vfs://Test/Packages/Application/Acme.MyApp/Classes/Acme/MyApp/WithLeadingBackslash.php', '<?php ' . __CLASS__ . '::$testClassWasLoaded = TRUE; ?>');
206
207 self::$testClassWasLoaded = FALSE;
208 $this->classLoader->loadClass('\Acme\MyApp\WithLeadingBackslash');
209 $this->assertTrue(self::$testClassWasLoaded);
210 }
211
212 }