[BUGFIX] Fatal errors for interfaces with PHP version < 5.3.7
authorNicole Cordes <n.cordes@biz-design.biz>
Wed, 5 Sep 2012 13:14:00 +0000 (15:14 +0200)
committerHelmut Hummel <helmut.hummel@typo3.org>
Tue, 18 Sep 2012 17:51:39 +0000 (19:51 +0200)
This bugfix rewrites function type hints to match the new ones as long as
PHP versions of OS Venders are not up to date.
Fatal errors are thrown when using an old interface with the new
TYPO3 6.0 beta 1. This only happens with PHP versions below 5.3.7 as
there are some type hinting issues.

Raise the Extbase submodule pointer at the same time to be in line
with the renaming of the Autoloader to ClassLoader.

Change-Id: I87da4bb2ef0420a94d1d155edde500c1aa96894a
Fixes: #40653
Related: #40095
Releases: 6.0
Reviewed-on: http://review.typo3.org/14376
Reviewed-by: Helmut Hummel
Tested-by: Helmut Hummel
typo3/sysext/core/Classes/Autoloader.php [deleted file]
typo3/sysext/core/Classes/Compatibility/CompatbilityClassLoaderPhpBelow50307.php [new file with mode: 0644]
typo3/sysext/core/Classes/Core/Bootstrap.php
typo3/sysext/core/Classes/Core/ClassLoader.php [new file with mode: 0644]
typo3/sysext/core/Classes/Core/SystemEnvironmentBuilder.php
typo3/sysext/core/Classes/Utility/GeneralUtility.php
typo3/sysext/core/Migrations/Code/ClassAliasMap201208221700.php
typo3/sysext/core/Tests/Unit/AutoloaderTest.php [deleted file]
typo3/sysext/core/Tests/Unit/Core/ClassLoaderTest.php [new file with mode: 0644]
typo3/sysext/extbase

diff --git a/typo3/sysext/core/Classes/Autoloader.php b/typo3/sysext/core/Classes/Autoloader.php
deleted file mode 100644 (file)
index 6a11c09..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-<?php
-namespace TYPO3\CMS\Core;
-
-/***************************************************************
- *  Copyright notice
- *
- *  (c) 2008-2011 Dmitry Dulepov <dmitry@typo3.org>
- *  All rights reserved
- *
- *  This script is part of the TYPO3 project. The TYPO3 project is
- *  free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  The GNU General Public License can be found at
- *  http://www.gnu.org/copyleft/gpl.html.
- *  A copy is found in the textfile GPL.txt and important notices to the license
- *  from the author is found in LICENSE.txt distributed with these scripts.
- *
- *
- *  This script is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  This copyright notice MUST APPEAR in all copies of the script!
- ***************************************************************/
-/**
- * This class contains TYPO3 autoloader for classes.
- * It handles:
- * - The core of TYPO3
- * - All extensions with an ext_autoload.php file
- * - All extensions that stick to the 'extbase' like naming convention
- * - Resolves registered XCLASSes
- *
- * @author Dmitry Dulepov <dmitry@typo3.org>
- * @author Martin Kutschker <masi@typo3.org>
- * @author Oliver Hader <oliver@typo3.org>
- * @author Sebastian Kurfürst <sebastian@typo3.org>
- * @author Christian Kuhn <lolli@schwarzbu.ch>
- */
-class Autoloader {
-
-       /**
-        * Class name to file mapping. Key: class name. Value: fully qualified file name.
-        *
-        * @var array
-        */
-       static protected $classNameToFileMapping = array();
-
-       /**
-        * @var boolean TRUE, if old to new and new to old mapping was populated to PHP
-        */
-       static protected $mappingLoaded = FALSE;
-
-       /**
-        * Old class name to new class name mapping
-        *
-        * @var array
-        */
-       static protected $aliasToClassNameMapping = array();
-
-       /**
-        * New class name to old class name mapping
-        *
-        * @var array
-        */
-       static protected $classNameToAliasMapping = array();
-
-       /**
-        * Name of cache entry identifier in autoload cache
-        *
-        * @var string
-        */
-       static protected $autoloadCacheIdentifier = NULL;
-
-       /**
-        * Track if the cache file written to disk should be updated.
-        * This is set to TRUE if during script run new classes are
-        * found (for example due to new requested extbase classes)
-        * and is used in unregisterAutoloader() to decide whether or not
-        * the cache file should be re-written.
-        *
-        * @var bool True if mapping changed
-        */
-       static protected $cacheUpdateRequired = FALSE;
-
-
-
-       /**
-        * The autoloader is static, thus we do not allow instances of this class.
-        */
-       private function __construct() {
-
-       }
-
-       /**
-        * Installs TYPO3 autoloader, and loads the autoload registry for the core.
-        *
-        * @return boolean TRUE in case of success
-        */
-       static public function registerAutoloader() {
-               if (!self::$mappingLoaded) {
-                       self::loadCoreClassAliasMapping();
-                       self::$mappingLoaded = TRUE;
-               }
-               self::loadCoreAndExtensionRegistry();
-               return spl_autoload_register('TYPO3\\CMS\\Core\\Autoloader::autoload', TRUE, TRUE);
-       }
-
-       /**
-        * Unload TYPO3 autoloader and write any additional classes
-        * found during the script run to the cache file.
-        *
-        * This method is called during shutdown of the framework.
-        *
-        * @return boolean TRUE in case of success
-        */
-       static public function unregisterAutoloader() {
-               if (self::$cacheUpdateRequired) {
-                       self::updateRegistryCacheEntry(self::$classNameToFileMapping);
-                       self::$cacheUpdateRequired = FALSE;
-               }
-               self::$classNameToFileMapping = array();
-               return spl_autoload_unregister('TYPO3\\CMS\\Core\\Autoloader::autoload');
-       }
-
-       /**
-        * Autoload function for TYPO3.
-        *
-        * This method looks up class names in the registry
-        * (which contains extensions and core files)
-        *
-        * @param string $className Class name
-        * @return void
-        */
-       static public function autoload($className) {
-               $className = ltrim($className, '\\');
-               $realClassName = self::getClassNameForAlias($className);
-               $lookUpClassName = ($hasRealClassName = $className !== $realClassName) ? $realClassName : $className;
-               // Use core and extension registry
-               $classPath = self::getClassPathByRegistryLookup($lookUpClassName);
-               if ($classPath && !class_exists($realClassName, FALSE)) {
-                       // Include the required file that holds the class
-                       \TYPO3\CMS\Core\Utility\GeneralUtility::requireOnce($classPath);
-               } else {
-                       try {
-                               // Regular expression for a valid classname taken from
-                               // http://www.php.net/manual/en/language.oop5.basic.php
-                               if (preg_match('/^[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*$/', $className)) {
-                                       spl_autoload($className);
-                               }
-                       } catch (\LogicException $exception) {
-
-                       }
-               }
-               if ($hasRealClassName && !class_exists($className, FALSE)) {
-                       class_alias($realClassName, $className);
-               }
-       }
-
-       /**
-        * Load registry from cache file if available or search
-        * for all loaded extensions and create a cache file
-        *
-        * @return void
-        */
-       static protected function loadCoreAndExtensionRegistry() {
-               /** @var $phpCodeCache \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend */
-               $phpCodeCache = $GLOBALS['typo3CacheManager']->getCache('cache_core');
-               // Create autoload cache file if it does not exist yet
-               if ($phpCodeCache->has(self::getAutoloadCacheIdentifier())) {
-                       $classRegistry = $phpCodeCache->requireOnce(self::getAutoloadCacheIdentifier());
-               } else {
-                       self::$cacheUpdateRequired = TRUE;
-                       $classRegistry = self::lowerCaseClassRegistry(self::createCoreAndExtensionRegistry());
-               }
-               // This can only happen if the autoloader was already registered
-               // in the same call once, the requireOnce of the cache file then
-               // does not give the cached array back. In this case we just read
-               // all cache entries manually again.
-               // This can happen in unit tests and if the cache backend was
-               // switched to NullBackend for example to simplify development
-               if (!is_array($classRegistry)) {
-                       self::$cacheUpdateRequired = TRUE;
-                       $classRegistry = self::lowerCaseClassRegistry(self::createCoreAndExtensionRegistry());
-               }
-               self::$classNameToFileMapping = $classRegistry;
-       }
-
-       static public function loadCoreClassAliasMapping() {
-               self::$aliasToClassNameMapping = require __DIR__ . '/../Migrations/Code/ClassAliasMap201208221700.php';
-               // Create aliases for early loaded classes
-               $classedLoadedPriorToAutoloader = array_intersect(self::$aliasToClassNameMapping, get_declared_classes());
-               if (!empty($classedLoadedPriorToAutoloader)) {
-                       foreach ($classedLoadedPriorToAutoloader as $oldClassName => $newClassName) {
-                               class_alias($newClassName, $oldClassName);
-                       }
-               }
-               foreach (self::$aliasToClassNameMapping as $oldClassName => $newClassName) {
-                       self::$aliasToClassNameMapping[strtolower($oldClassName)] = $newClassName;
-               }
-               self::$classNameToAliasMapping = array_flip(self::$aliasToClassNameMapping);
-       }
-
-       static public function getClassNameForAlias($className) {
-               $lookUpClassName = strtolower($className);
-               return isset(self::$aliasToClassNameMapping[$lookUpClassName]) ? self::$aliasToClassNameMapping[$lookUpClassName] : $className;
-       }
-
-       static public function getAliasForClassName($alias) {
-               return isset(self::$classNameToAliasMapping[$alias]) ? self::$classNameToAliasMapping[$alias] : $alias;
-       }
-
-       /**
-        * Get the full path to a class by looking it up in the registry.
-        * If not found, returns NULL.
-        *
-        * Warning: This method is public as it is needed by t3lib_div::makeInstance(),
-        * but it is _not_ part of the public API and should not be used in own extensions!
-        *
-        * @param string $className Class name to find source file of
-        * @return mixed If String: Full name of the file where $className is declared, NULL if no entry is found
-        * @internal
-        */
-       static public function getClassPathByRegistryLookup($className) {
-               $classPath = NULL;
-               $classNameLower = \TYPO3\CMS\Core\Utility\GeneralUtility::strtolower($className);
-               // Try to resolve extbase naming scheme if class is not already in cache file
-               if (substr($classNameLower, 0, 3) !== 'ux_' && !array_key_exists($classNameLower, self::$classNameToFileMapping)) {
-                       self::attemptToLoadRegistryWithNamingConventionForGivenClassName($className);
-               }
-               // Look up class name in cache file
-               if (array_key_exists($classNameLower, self::$classNameToFileMapping)) {
-                       $classPath = self::$classNameToFileMapping[$classNameLower];
-               }
-               if ($classPath === NULL && substr($classNameLower, 0, 3) === 'ux_' && !array_key_exists($classNameLower, self::$classNameToFileMapping)) {
-                       self::$cacheUpdateRequired = TRUE;
-                       self::$classNameToFileMapping[$classNameLower] = NULL;
-               }
-               return $classPath;
-       }
-
-       /**
-        * Find all ext_autoload files and merge with core_autoload.
-        *
-        * @return array
-        */
-       static protected function createCoreAndExtensionRegistry() {
-               $classRegistry = require(PATH_t3lib . 'core_autoload.php');
-               // At this point during bootstrap the local configuration is initialized,
-               // extMgm is ready to get the list of enabled extensions
-               foreach (\TYPO3\CMS\Core\Extension\ExtensionManager::getLoadedExtensionListArray() as $extensionKey) {
-                       try {
-                               $extensionAutoloadFile = \TYPO3\CMS\Core\Extension\ExtensionManager::extPath($extensionKey, 'ext_autoload.php');
-                               if (@file_exists($extensionAutoloadFile)) {
-                                       $classRegistry = array_merge($classRegistry, require $extensionAutoloadFile);
-                               }
-                       } catch (\BadFunctionCallException $e) {
-
-                       }
-               }
-               return $classRegistry;
-       }
-
-       /**
-        * Try to load a given class name based on 'extbase' naming convention into the registry.
-        * If the file is found it writes an entry to $classNameToFileMapping and re-caches the
-        * array to the file system to save this lookup for next call.
-        *
-        * @param string $className Class name to find source file of
-        * @return void
-        */
-       static protected function attemptToLoadRegistryWithNamingConventionForGivenClassName($className) {
-               $delimiter = '_';
-               $tempClassName = $className;
-               // To handle namespaced class names, get rid of the first backslash
-               // and replace the remaining ones with underscore. This will simulate
-               // a 'usual' "extbase" structure like 'Tx_ExtensionName_Foo_bar'
-               if (strpos($className, '\\') !== FALSE) {
-                       $tempClassName = ltrim($className, '\\');
-                       $delimiter = '\\';
-               }
-               $classNameParts = explode($delimiter, $tempClassName, 4);
-               if (isset($classNameParts[0]) && $classNameParts[0] === 'TYPO3' && (isset($classNameParts[1]) && $classNameParts[1] === 'CMS')) {
-                       $extensionKey = \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($classNameParts[2]);
-                       $classNameWithoutVendorAndProduct = $classNameParts[3];
-               } else {
-                       $extensionKey = \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($classNameParts[1]);
-                       $classNameWithoutVendorAndProduct = $classNameParts[2];
-
-                       if (isset($classNameParts[3])) {
-                               $classNameWithoutVendorAndProduct .= $delimiter . $classNameParts[3];
-                       }
-               }
-
-               if ($extensionKey) {
-                       try {
-                               // This will throw a BadFunctionCallException if the extension is not loaded
-                               $extensionPath = \TYPO3\CMS\Core\Extension\ExtensionManager::extPath($extensionKey);
-                               $classPath = (substr(strtolower($classNameWithoutVendorAndProduct), 0, 5) === 'tests') ? '' : 'Classes/';
-                               $classFilePathAndName = $extensionPath . $classPath . strtr($classNameWithoutVendorAndProduct, $delimiter, '/') . '.php';
-                               self::addClassToCache($classFilePathAndName, $className);
-                       } catch (\BadFunctionCallException $exception) {
-
-                       }
-               }
-       }
-
-       /**
-        * Adds a single class to autoloader cache.
-        *
-        * @static
-        * @param string $classFilePathAndName Physical path of file containing $className
-        * @param string $className Class name
-        * @return void
-        */
-       static protected function addClassToCache($classFilePathAndName, $className) {
-               if (file_exists($classFilePathAndName)) {
-                       self::$cacheUpdateRequired = TRUE;
-                       self::$classNameToFileMapping[\TYPO3\CMS\Core\Utility\GeneralUtility::strtolower($className)] = $classFilePathAndName;
-               }
-       }
-
-       /**
-        * Set or update autoloader cache entry.
-        * It is expected that all class names (keys) are already lowercased!
-        *
-        * @param array $registry Current registry entries
-        * @return void
-        */
-       static protected function updateRegistryCacheEntry(array $registry) {
-               $cachedFileContent = 'return array(';
-               foreach ($registry as $className => $classLocation) {
-                       $nullOrLocation = is_string($classLocation) ? '\'' . $classLocation . '\',' : 'NULL,';
-                       $cachedFileContent .= LF . '\'' . $className . '\' => ' . $nullOrLocation;
-               }
-               $cachedFileContent .= LF . ');';
-               $GLOBALS['typo3CacheManager']->getCache('cache_core')->set(self::getAutoloadCacheIdentifier(), $cachedFileContent);
-       }
-
-       /**
-        * Gets the identifier used for caching the registry files.
-        * The identifier depends on the current TYPO3 version and the
-        * installation path of the TYPO3 site (PATH_site).
-        *
-        * In effect, a new registry cache file will be created
-        * when moving to a newer version with possible new core classes
-        * or moving the webroot to another absolute path.
-        *
-        * @return string identifier
-        */
-       static protected function getAutoloadCacheIdentifier() {
-               if (is_null(self::$autoloadCacheIdentifier)) {
-                       self::$autoloadCacheIdentifier = 'autoload_' . sha1((TYPO3_version . PATH_site . 'autoload'));
-               }
-               return self::$autoloadCacheIdentifier;
-       }
-
-       /**
-        * Lowercase all keys of the class registry.
-        *
-        * Use the multi byte safe version of strtolower from t3lib_div,
-        * so array_change_key_case() can not be used
-        *
-        * @param array $registry Given registry entries
-        * @return array with lower cased keys
-        */
-       static protected function lowerCaseClassRegistry($registry) {
-               $lowerCasedClassRegistry = array();
-               foreach ($registry as $className => $classFile) {
-                       $lowerCasedClassRegistry[\TYPO3\CMS\Core\Utility\GeneralUtility::strtolower($className)] = $classFile;
-               }
-               return $lowerCasedClassRegistry;
-       }
-
-}
-
-
-?>
diff --git a/typo3/sysext/core/Classes/Compatibility/CompatbilityClassLoaderPhpBelow50307.php b/typo3/sysext/core/Classes/Compatibility/CompatbilityClassLoaderPhpBelow50307.php
new file mode 100644 (file)
index 0000000..b2d4a87
--- /dev/null
@@ -0,0 +1,159 @@
+<?php
+namespace TYPO3\CMS\Core\Compatibility;
+use \TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Thomas Maroschik <tmaroschik@dfau.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * This is a compatibility layer for systems running PHP < 5.3.7
+ * It rewrites the type hints in method definitions so that they are identical to the
+ * core interface definition
+ *
+ * @author Thomas Maroschik <tmaroschik@dfau.de>
+ */
+class CompatbilityClassLoaderPhpBelow50307 extends \TYPO3\CMS\Core\Core\ClassLoader {
+
+       /**
+        * Contains the class loaders class name
+        *
+        * @var string
+        */
+       static protected $className = __CLASS__;
+
+       /**
+        * Installs TYPO3 autoloader, and loads the autoload registry for the core.
+        *
+        * @return boolean TRUE in case of success
+        */
+       static public function registerAutoloader() {
+               return parent::registerAutoloader();
+       }
+
+       /**
+        * Unload TYPO3 autoloader and write any additional classes
+        * found during the script run to the cache file.
+        *
+        * This method is called during shutdown of the framework.
+        *
+        * @return boolean TRUE in case of success
+        */
+       static public function unregisterAutoloader() {
+               return parent::unregisterAutoloader();
+       }
+
+       /**
+        * Require the class file and rewrite non sysext files transparently
+        *
+        * @static
+        * @param string $classPath
+        */
+       static public function requireClassFileOnce($classPath) {
+               if (GeneralUtility::isFirstPartOfStr($classPath, PATH_typo3 . 'sysext/')) {
+                               // Do nothing for sysextensions. They are already using the proper type hints.
+                       GeneralUtility::requireOnce($classPath);
+               } else {
+                       $cacheIdentifier = static::getClassPathCacheIdentifier($classPath);
+                       /** @var $phpCodeCache \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend */
+                       $phpCodeCache = $GLOBALS['typo3CacheManager']->getCache('cache_phpcode');
+                       if (!$phpCodeCache->has($cacheIdentifier)) {
+                               $classCode = static::rewriteMethodTypeHintsFromClassPath($classPath);
+                               $phpCodeCache->set($cacheIdentifier, $classCode, array(), 0);
+                       }
+                       $phpCodeCache->requireOnce($cacheIdentifier);
+               }
+       }
+
+       /**
+        * Generates the cache identifier from the relative class path and the files sha1 hash
+        *
+        * @static
+        * @param string $classPath
+        * @return string
+        */
+       static protected function getClassPathCacheIdentifier($classPath) {
+                       // The relative class path is part of the cache identifier
+               $relativeClassPath = (GeneralUtility::isFirstPartOfStr($classPath, PATH_site)) ? substr($classPath, strlen(PATH_site)) : $classPath;
+               $fileExtension = strrchr($classPath, '.');
+               $fileNameWithoutExtension = substr(basename($classPath), 0, strlen($fileExtension) * -1);
+                       // The class content has to be part of the identifier too
+                       // otherwise the old class files get loaded from cache
+               $fileSha1 = sha1_file($classPath);
+               $cacheIdentifier = $fileNameWithoutExtension . '_' . substr(sha1($fileSha1 . '|' . $relativeClassPath), 0, 20);
+                       // Clean up identifier to be a valid cache entry identifier
+               $cacheIdentifier = preg_replace('/[^a-zA-Z0-9_%\-&]/i', '_', $cacheIdentifier);
+               return $cacheIdentifier;
+       }
+
+       /**
+        * Loads the class path and rewrites the type hints
+        *
+        * @static
+        * @param string $classPath
+        * @return string rewritten php code
+        */
+       static protected function rewriteMethodTypeHintsFromClassPath($classPath) {
+               $pcreBacktrackLimitOriginal = ini_get('pcre.backtrack_limit');
+               $classAliasMap = static::$aliasToClassNameMapping;
+               $fileContent = file_get_contents($classPath);
+               $fileLength = strlen($fileContent);
+               // when the class file is bigger than the original pcre backtrace limit increase the limit
+               if ($pcreBacktrackLimitOriginal < $fileLength) {
+                       ini_set('pcre.backtrack_limit', $fileLength);
+               }
+               $fileContent = preg_replace_callback(
+                       '/function\s+([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\((.*?\$.*?)\)\s*\{/im',
+                       function($matches) use($classAliasMap) {
+                       if (isset($matches[1]) && isset($matches[2])) {
+                               list($functionName, $argumentList) = array_slice($matches, 1, 2);
+                               $arguments = explode(',', $argumentList);
+                               $arguments = array_map('trim', $arguments);
+                               $arguments = preg_replace_callback('/([\\a-z0-9_]+\s+)?((\s*[&]*\s*\$[a-z0-9_]+)(\s*=\s*.+)?)/im', function($argumentMatches) use($classAliasMap) {
+                                       if (isset($argumentMatches[1]) && isset($argumentMatches[2])) {
+                                               $typeHint = strtolower(ltrim(trim($argumentMatches[1]), '\\'));
+                                               if (isset($classAliasMap[$typeHint])) {
+                                                       return '\\' . $classAliasMap[$typeHint] . ' ' . $argumentMatches[2];
+                                               }
+                                       }
+                                       return $argumentMatches[0];
+                               }, $arguments);
+                               return 'function ' . $functionName . ' (' . implode(', ', $arguments) . ') {';
+                       }
+                       return $matches[0];
+               }, $fileContent);
+               $fileContent = preg_replace(array(
+                       '/^\s*<\?php/',
+                       '/\?>\s*$/'
+               ), '', $fileContent);
+               if ($pcreBacktrackLimitOriginal < $fileLength) {
+                       ini_set('pcre.backtrack_limit', $pcreBacktrackLimitOriginal);
+               }
+               return $fileContent;
+       }
+
+}
+
+?>
\ No newline at end of file
index f6399bd..2c088e9 100644 (file)
@@ -203,7 +203,11 @@ class Bootstrap {
         * @return \TYPO3\CMS\Core\Core\Bootstrap
         */
        public function registerAutoloader() {
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
+               if (PHP_VERSION_ID < 50307) {
+                       \TYPO3\CMS\Core\Compatibility\CompatbilityClassLoaderPhpBelow50307::registerAutoloader();
+               } else {
+                       \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+               }
                return $this;
        }
 
@@ -838,7 +842,11 @@ class Bootstrap {
         * @return \TYPO3\CMS\Core\Core\Bootstrap
         */
        public function shutdown() {
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
+               if (PHP_VERSION_ID < 50307) {
+                       \TYPO3\CMS\Core\Compatibility\CompatbilityClassLoaderPhpBelow50307::unregisterAutoloader();
+               } else {
+                       \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               }
                return $this;
        }
 
diff --git a/typo3/sysext/core/Classes/Core/ClassLoader.php b/typo3/sysext/core/Classes/Core/ClassLoader.php
new file mode 100644 (file)
index 0000000..d855c15
--- /dev/null
@@ -0,0 +1,397 @@
+<?php
+namespace TYPO3\CMS\Core\Core;
+use \TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2008-2011 Dmitry Dulepov <dmitry@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * This class contains TYPO3 autoloader for classes.
+ * It handles:
+ * - The core of TYPO3
+ * - All extensions with an ext_autoload.php file
+ * - All extensions that stick to the 'extbase' like naming convention
+ * - Resolves registered XCLASSes
+ *
+ * @author Dmitry Dulepov <dmitry@typo3.org>
+ * @author Martin Kutschker <masi@typo3.org>
+ * @author Oliver Hader <oliver@typo3.org>
+ * @author Sebastian Kurfürst <sebastian@typo3.org>
+ * @author Christian Kuhn <lolli@schwarzbu.ch>
+ */
+class ClassLoader {
+
+       /**
+        * Contains the class loaders class name
+        *
+        * @var string
+        */
+       static protected $className = __CLASS__;
+
+       /**
+        * Class name to file mapping. Key: class name. Value: fully qualified file name.
+        *
+        * @var array
+        */
+       static protected $classNameToFileMapping = array();
+
+       /**
+        * @var boolean TRUE, if old to new and new to old mapping was populated to PHP
+        */
+       static protected $mappingLoaded = FALSE;
+
+       /**
+        * Old class name to new class name mapping
+        *
+        * @var array
+        */
+       static protected $aliasToClassNameMapping = array();
+
+       /**
+        * New class name to old class name mapping
+        *
+        * @var array
+        */
+       static protected $classNameToAliasMapping = array();
+
+       /**
+        * Name of cache entry identifier in autoload cache
+        *
+        * @var string
+        */
+       static protected $autoloadCacheIdentifier = NULL;
+
+       /**
+        * Track if the cache file written to disk should be updated.
+        * This is set to TRUE if during script run new classes are
+        * found (for example due to new requested extbase classes)
+        * and is used in unregisterAutoloader() to decide whether or not
+        * the cache file should be re-written.
+        *
+        * @var bool True if mapping changed
+        */
+       static protected $cacheUpdateRequired = FALSE;
+
+       /**
+        * The autoloader is static, thus we do not allow instances of this class.
+        */
+       private function __construct() {
+
+       }
+
+       /**
+        * Installs TYPO3 autoloader, and loads the autoload registry for the core.
+        *
+        * @return boolean TRUE in case of success
+        */
+       static public function registerAutoloader() {
+               if (!static::$mappingLoaded) {
+                       static::loadCoreClassAliasMapping();
+                       static::$mappingLoaded = TRUE;
+               }
+               static::loadCoreAndExtensionRegistry();
+               return spl_autoload_register(static::$className . '::autoload', TRUE, TRUE);
+       }
+
+       /**
+        * Unload TYPO3 autoloader and write any additional classes
+        * found during the script run to the cache file.
+        *
+        * This method is called during shutdown of the framework.
+        *
+        * @return boolean TRUE in case of success
+        */
+       static public function unregisterAutoloader() {
+               if (static::$cacheUpdateRequired) {
+                       static::updateRegistryCacheEntry(static::$classNameToFileMapping);
+                       static::$cacheUpdateRequired = FALSE;
+               }
+               static::$classNameToFileMapping = array();
+               return spl_autoload_unregister(static::$className . '::autoload');
+       }
+
+       /**
+        * Autoload function for TYPO3.
+        *
+        * This method looks up class names in the registry
+        * (which contains extensions and core files)
+        *
+        * @param string $className Class name
+        * @return void
+        */
+       static public function autoload($className) {
+               $className = ltrim($className, '\\');
+               $realClassName = static::getClassNameForAlias($className);
+               $lookUpClassName = ($hasRealClassName = $className !== $realClassName) ? $realClassName : $className;
+               // Use core and extension registry
+               $classPath = static::getClassPathByRegistryLookup($lookUpClassName);
+               if ($classPath && !class_exists($realClassName, FALSE)) {
+                       // Include the required file that holds the class
+                       static::requireClassFileOnce($classPath);
+                       try {
+                               // Regular expression for a valid classname taken from
+                               // http://www.php.net/manual/en/language.oop5.basic.php
+                               if (preg_match('/^[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*$/', $className)) {
+                                       spl_autoload($className);
+                               }
+                       } catch (\LogicException $exception) {
+
+                       }
+               }
+               if ($hasRealClassName && !class_exists($className, FALSE)) {
+                       class_alias($realClassName, $className);
+               }
+       }
+
+       /**
+        * Require the class file
+        *
+        * @static
+        * @param string $classPath
+        */
+       static protected function requireClassFileOnce($classPath) {
+               GeneralUtility::requireOnce($classPath);
+       }
+
+       /**
+        * Load registry from cache file if available or search
+        * for all loaded extensions and create a cache file
+        *
+        * @return void
+        */
+       static protected function loadCoreAndExtensionRegistry() {
+               /** @var $phpCodeCache \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend */
+               $phpCodeCache = $GLOBALS['typo3CacheManager']->getCache('cache_core');
+               // Create autoload cache file if it does not exist yet
+               if ($phpCodeCache->has(static::getAutoloadCacheIdentifier())) {
+                       $classRegistry = $phpCodeCache->requireOnce(static::getAutoloadCacheIdentifier());
+               } else {
+                       static::$cacheUpdateRequired = TRUE;
+                       $classRegistry = static::lowerCaseClassRegistry(static::createCoreAndExtensionRegistry());
+               }
+               // This can only happen if the autoloader was already registered
+               // in the same call once, the requireOnce of the cache file then
+               // does not give the cached array back. In this case we just read
+               // all cache entries manually again.
+               // This can happen in unit tests and if the cache backend was
+               // switched to NullBackend for example to simplify development
+               if (!is_array($classRegistry)) {
+                       static::$cacheUpdateRequired = TRUE;
+                       $classRegistry = static::lowerCaseClassRegistry(static::createCoreAndExtensionRegistry());
+               }
+               static::$classNameToFileMapping = $classRegistry;
+       }
+
+       static public function loadCoreClassAliasMapping() {
+               static::$aliasToClassNameMapping = require __DIR__ . '/../../Migrations/Code/ClassAliasMap201208221700.php';
+               // Create aliases for early loaded classes
+               $classedLoadedPriorToAutoloader = array_intersect(static::$aliasToClassNameMapping, get_declared_classes());
+               if (!empty($classedLoadedPriorToAutoloader)) {
+                       foreach ($classedLoadedPriorToAutoloader as $oldClassName => $newClassName) {
+                               class_alias($newClassName, $oldClassName);
+                       }
+               }
+               foreach (static::$aliasToClassNameMapping as $oldClassName => $newClassName) {
+                       static::$aliasToClassNameMapping[strtolower($oldClassName)] = $newClassName;
+               }
+               static::$classNameToAliasMapping = array_flip(static::$aliasToClassNameMapping);
+       }
+
+       static public function getClassNameForAlias($className) {
+               $lookUpClassName = strtolower($className);
+               return isset(static::$aliasToClassNameMapping[$lookUpClassName]) ? static::$aliasToClassNameMapping[$lookUpClassName] : $className;
+       }
+
+       static public function getAliasForClassName($alias) {
+               return isset(static::$classNameToAliasMapping[$alias]) ? static::$classNameToAliasMapping[$alias] : $alias;
+       }
+
+       /**
+        * Get the full path to a class by looking it up in the registry.
+        * If not found, returns NULL.
+        *
+        * Warning: This method is public as it is needed by t3lib_div::makeInstance(),
+        * but it is _not_ part of the public API and should not be used in own extensions!
+        *
+        * @param string $className Class name to find source file of
+        * @return mixed If String: Full name of the file where $className is declared, NULL if no entry is found
+        * @internal
+        */
+       static public function getClassPathByRegistryLookup($className) {
+               $classPath = NULL;
+               $classNameLower = GeneralUtility::strtolower($className);
+               // Try to resolve extbase naming scheme if class is not already in cache file
+               if (substr($classNameLower, 0, 3) !== 'ux_' && !array_key_exists($classNameLower, static::$classNameToFileMapping)) {
+                       static::attemptToLoadRegistryWithNamingConventionForGivenClassName($className);
+               }
+               // Look up class name in cache file
+               if (array_key_exists($classNameLower, static::$classNameToFileMapping)) {
+                       $classPath = static::$classNameToFileMapping[$classNameLower];
+               }
+               if ($classPath === NULL && substr($classNameLower, 0, 3) === 'ux_' && !array_key_exists($classNameLower, static::$classNameToFileMapping)) {
+                       static::$cacheUpdateRequired = TRUE;
+                       static::$classNameToFileMapping[$classNameLower] = NULL;
+               }
+               return $classPath;
+       }
+
+       /**
+        * Find all ext_autoload files and merge with core_autoload.
+        *
+        * @return array
+        */
+       static protected function createCoreAndExtensionRegistry() {
+               $classRegistry = require(PATH_t3lib . 'core_autoload.php');
+               // At this point during bootstrap the local configuration is initialized,
+               // extMgm is ready to get the list of enabled extensions
+               foreach (\TYPO3\CMS\Core\Extension\ExtensionManager::getLoadedExtensionListArray() as $extensionKey) {
+                       try {
+                               $extensionAutoloadFile = \TYPO3\CMS\Core\Extension\ExtensionManager::extPath($extensionKey, 'ext_autoload.php');
+                               if (@file_exists($extensionAutoloadFile)) {
+                                       $classRegistry = array_merge($classRegistry, require $extensionAutoloadFile);
+                               }
+                       } catch (\BadFunctionCallException $e) {
+
+                       }
+               }
+               return $classRegistry;
+       }
+
+       /**
+        * Try to load a given class name based on 'extbase' naming convention into the registry.
+        * If the file is found it writes an entry to $classNameToFileMapping and re-caches the
+        * array to the file system to save this lookup for next call.
+        *
+        * @param string $className Class name to find source file of
+        * @return void
+        */
+       static protected function attemptToLoadRegistryWithNamingConventionForGivenClassName($className) {
+               $delimiter = '_';
+               $tempClassName = $className;
+               // To handle namespaced class names, get rid of the first backslash
+               // and replace the remaining ones with underscore. This will simulate
+               // a 'usual' "extbase" structure like 'Tx_ExtensionName_Foo_bar'
+               if (strpos($className, '\\') !== FALSE) {
+                       $tempClassName = ltrim($className, '\\');
+                       $delimiter = '\\';
+               }
+               $classNameParts = explode($delimiter, $tempClassName, 4);
+               if (isset($classNameParts[0]) && $classNameParts[0] === 'TYPO3' && (isset($classNameParts[1]) && $classNameParts[1] === 'CMS')) {
+                       $extensionKey = GeneralUtility::camelCaseToLowerCaseUnderscored($classNameParts[2]);
+                       $classNameWithoutVendorAndProduct = $classNameParts[3];
+               } else {
+                       $extensionKey = GeneralUtility::camelCaseToLowerCaseUnderscored($classNameParts[1]);
+                       $classNameWithoutVendorAndProduct = $classNameParts[2];
+
+                       if (isset($classNameParts[3])) {
+                               $classNameWithoutVendorAndProduct .= $delimiter . $classNameParts[3];
+                       }
+               }
+
+               if ($extensionKey) {
+                       try {
+                               // This will throw a BadFunctionCallException if the extension is not loaded
+                               $extensionPath = \TYPO3\CMS\Core\Extension\ExtensionManager::extPath($extensionKey);
+                               $classPath = (substr(strtolower($classNameWithoutVendorAndProduct), 0, 5) === 'tests') ? '' : 'Classes/';
+                               $classFilePathAndName = $extensionPath . $classPath . strtr($classNameWithoutVendorAndProduct, $delimiter, '/') . '.php';
+                               static::addClassToCache($classFilePathAndName, $className);
+                       } catch (\BadFunctionCallException $exception) {
+
+                       }
+               }
+       }
+
+       /**
+        * Adds a single class to autoloader cache.
+        *
+        * @static
+        * @param string $classFilePathAndName Physical path of file containing $className
+        * @param string $className Class name
+        * @return void
+        */
+       static protected function addClassToCache($classFilePathAndName, $className) {
+               if (file_exists($classFilePathAndName)) {
+                       static::$cacheUpdateRequired = TRUE;
+                       static::$classNameToFileMapping[GeneralUtility::strtolower($className)] = $classFilePathAndName;
+               }
+       }
+
+       /**
+        * Set or update autoloader cache entry.
+        * It is expected that all class names (keys) are already lowercased!
+        *
+        * @param array $registry Current registry entries
+        * @return void
+        */
+       static protected function updateRegistryCacheEntry(array $registry) {
+               $cachedFileContent = 'return array(';
+               foreach ($registry as $className => $classLocation) {
+                       $nullOrLocation = is_string($classLocation) ? '\'' . $classLocation . '\',' : 'NULL,';
+                       $cachedFileContent .= LF . '\'' . $className . '\' => ' . $nullOrLocation;
+               }
+               $cachedFileContent .= LF . ');';
+               $GLOBALS['typo3CacheManager']->getCache('cache_core')->set(static::getAutoloadCacheIdentifier(), $cachedFileContent);
+       }
+
+       /**
+        * Gets the identifier used for caching the registry files.
+        * The identifier depends on the current TYPO3 version and the
+        * installation path of the TYPO3 site (PATH_site).
+        *
+        * In effect, a new registry cache file will be created
+        * when moving to a newer version with possible new core classes
+        * or moving the webroot to another absolute path.
+        *
+        * @return string identifier
+        */
+       static protected function getAutoloadCacheIdentifier() {
+               if (is_null(static::$autoloadCacheIdentifier)) {
+                       static::$autoloadCacheIdentifier = 'autoload_' . sha1((TYPO3_version . PATH_site . 'autoload'));
+               }
+               return static::$autoloadCacheIdentifier;
+       }
+
+       /**
+        * Lowercase all keys of the class registry.
+        *
+        * Use the multi byte safe version of strtolower from t3lib_div,
+        * so array_change_key_case() can not be used
+        *
+        * @param array $registry Given registry entries
+        * @return array with lower cased keys
+        */
+       static protected function lowerCaseClassRegistry($registry) {
+               $lowerCasedClassRegistry = array();
+               foreach ($registry as $className => $classFile) {
+                       $lowerCasedClassRegistry[GeneralUtility::strtolower($className)] = $classFile;
+               }
+               return $lowerCasedClassRegistry;
+       }
+
+}
+
+
+?>
index b791d77..f723793 100644 (file)
@@ -228,7 +228,10 @@ class SystemEnvironmentBuilder {
                require_once __DIR__ . '/../Cache/Backend/NullBackend.php';
                require_once __DIR__ . '/../Log/LogLevel.php';
                require_once __DIR__ . '/../Utility/MathUtility.php';
-               require_once __DIR__ . '/../Autoloader.php';
+               require_once __DIR__ . '/ClassLoader.php';
+               if (PHP_VERSION_ID < 50307) {
+                       require_once __DIR__ . '/../Compatibility/CompatbilityClassLoaderPhpBelow50307.php';
+               }
        }
 
        /**
index d90f899..65b2c83 100644 (file)
@@ -4154,7 +4154,7 @@ Connection: close
                        $instance = new $fullyQualifiedClassName();
                }
                // Create alias if not present
-               $alias = \TYPO3\CMS\Core\Autoloader::getAliasForClassName($finalClassName);
+               $alias = \TYPO3\CMS\Core\Core\ClassLoader::getAliasForClassName($finalClassName);
                if (substr($finalClassName, 0, 3) !== 'ux_' && $finalClassName !== $alias && !class_exists($alias, FALSE)) {
                        class_alias($finalClassName, $alias);
                }
@@ -4174,11 +4174,11 @@ Connection: close
         */
        static protected function getClassName($className) {
                if (class_exists($className)) {
-                       while (\TYPO3\CMS\Core\Autoloader::getClassPathByRegistryLookup('ux_' . $className) !== NULL) {
+                       while (\TYPO3\CMS\Core\Core\ClassLoader::getClassPathByRegistryLookup('ux_' . $className) !== NULL) {
                                $className = 'ux_' . $className;
                        }
                }
-               return \TYPO3\CMS\Core\Autoloader::getClassNameForAlias($className);
+               return \TYPO3\CMS\Core\Core\ClassLoader::getClassNameForAlias($className);
        }
 
        /**
index 22785cb..6c72dd7 100644 (file)
@@ -167,7 +167,7 @@ return array(
        'extDirect_DataProvider_ContextHelp' => 'TYPO3\\CMS\\ContextHelp\\ExtDirect\\ContextHelpDataProvider',
        't3lib_userAuth' => 'TYPO3\\CMS\\Core\\Authentication\\AbstractUserAuthentication',
        't3lib_beUserAuth' => 'TYPO3\\CMS\\Core\\Authentication\\BackendUserAuthentication',
-       't3lib_autoloader' => 'TYPO3\\CMS\\Core\\Autoloader',
+       't3lib_autoloader' => 'TYPO3\\CMS\\Core\\Core\\ClassLoader',
        't3lib_cache_backend_AbstractBackend' => 'TYPO3\\CMS\\Core\\Cache\\Backend\\AbstractBackend',
        't3lib_cache_backend_ApcBackend' => 'TYPO3\\CMS\\Core\\Cache\\Backend\\ApcBackend',
        't3lib_cache_backend_Backend' => 'TYPO3\\CMS\\Core\\Cache\\Backend\\BackendInterface',
diff --git a/typo3/sysext/core/Tests/Unit/AutoloaderTest.php b/typo3/sysext/core/Tests/Unit/AutoloaderTest.php
deleted file mode 100644 (file)
index ea98665..0000000
+++ /dev/null
@@ -1,443 +0,0 @@
-<?php
-namespace TYPO3\CMS\Core\Tests\Unit;
-
-/***************************************************************
- * Copyright notice
- *
- * (c) 2011 Andreas Wolf <andreas.wolf@ikt-werk.de>
- * All rights reserved
- *
- * This script is part of the TYPO3 project. The TYPO3 project is
- * free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * The GNU General Public License can be found at
- * http://www.gnu.org/copyleft/gpl.html.
- *
- * This script is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * This copyright notice MUST APPEAR in all copies of the script!
- ***************************************************************/
-
-/**
- * Testcase for TYPO3\CMS\Core\Autoloader
- *
- * @package TYPO3
- * @subpackage t3lib
- * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
- */
-class AutoloaderTest extends \Tx_Phpunit_TestCase {
-
-       /**
-        * @var boolean Enable backup of global and system variables
-        */
-       protected $backupGlobals = TRUE;
-
-       /**
-        * Exclude TYPO3_DB from backup/ restore of $GLOBALS
-        * because resource types cannot be handled during serializing
-        *
-        * @var array
-        */
-       protected $backupGlobalsBlacklist = array('TYPO3_DB');
-
-       /**
-        * @var array Backup of typo3CacheManager
-        */
-       protected $typo3CacheManager = NULL;
-
-       /**
-        * @var array Register of temporary extensions in typo3temp
-        */
-       protected $fakedExtensions = array();
-
-       /**
-        * Fix a race condition that t3lib_div is not available
-        * during tearDown if fiddling with the autoloader where
-        * backupGlobals is not set up again yet
-        */
-       public function setUp() {
-               $this->typo3CacheManager = $GLOBALS['typo3CacheManager'];
-       }
-
-       /**
-        * Clean up
-        * Warning: Since phpunit itself is php and we are fiddling with php
-        * autoloader code here, the tests are a bit fragile. This tearDown
-        * method ensures that all main classes are available again during
-        * tear down of a testcase.
-        * This construct will fail if the class under test is changed and
-        * not compatible anymore. Make sure to always run the whole test
-        * suite if fiddling with the autoloader unit tests to ensure that
-        * there is no fatal error thrown in other unit test classes triggered
-        * by errors in this one.
-        */
-       public function tearDown() {
-               $GLOBALS['typo3CacheManager'] = $this->typo3CacheManager;
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
-               foreach ($this->fakedExtensions as $extension) {
-                       \TYPO3\CMS\Core\Utility\GeneralUtility::rmdir(PATH_site . 'typo3temp/' . $extension, TRUE);
-               }
-       }
-
-       /**
-        * Creates a fake extension inside typo3temp/. No configuration is created,
-        * just the folder, plus the extension is registered in $TYPO3_LOADED_EXT
-        *
-        * @return string The extension key
-        */
-       protected function createFakeExtension() {
-               $extKey = strtolower(uniqid('testing'));
-               $absExtPath = PATH_site . 'typo3temp/' . $extKey . '/';
-               $relPath = 'typo3temp/' . $extKey . '/';
-               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir($absExtPath);
-               $GLOBALS['TYPO3_LOADED_EXT'][$extKey] = array(
-                       'siteRelPath' => $relPath
-               );
-               $GLOBALS['TYPO3_CONF_VARS']['EXT']['extListArray'][] = $extKey;
-               $this->fakedExtensions[] = $extKey;
-               \TYPO3\CMS\Core\Extension\ExtensionManager::clearExtensionKeyMap();
-               return $extKey;
-       }
-
-       /**
-        * @test
-        */
-       public function unregisterAndRegisterAgainDoesNotFatal() {
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
-                       // If this fatals the autoload re registering went wrong
-               \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\TimeTracker\\NullTimeTracker');
-       }
-
-       /**
-        * @test
-        */
-       public function unregisterAutoloaderSetsCacheEntryWithT3libNoTags() {
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-                       // Expect the mock cache set method to be called
-                       // once with t3lib_autoloader as third parameter
-               $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->anything(), array());
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-       }
-
-       /**
-        * @test
-        * @expectedException \RuntimeException
-        */
-       public function autoloadFindsClassFileDefinedInExtAutoloadFile() {
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-               $autoloaderFile = $extPath . 'ext_autoload.php';
-               $class = strtolower("tx_{$extKey}_" . uniqid(''));
-               $file = $extPath . uniqid('') . '.php';
-               file_put_contents($file, '<?php' . LF . 'throw new \\RuntimeException(\'\', 1310203812);' . LF . '?>');
-               file_put_contents($autoloaderFile, '<?php' . LF . 'return array(\'' . $class . '\' => \'' . $file . '\');' . LF . '?>');
-                       // Inject a dummy for the core_phpcode cache to force the autoloader
-                       // to re calculate the registry
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-                       // Re-initialize autoloader registry to force it to recognize the new extension
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
-                       // Expect the exception of the file to be thrown
-               \TYPO3\CMS\Core\Autoloader::autoload($class);
-       }
-
-       /**
-        * @test
-        */
-       public function unregisterAutoloaderWritesLowerCasedClassFileToCache() {
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-               $autoloaderFile = $extPath . 'ext_autoload.php';
-                       // A case sensitive key (FooBar) in ext_autoload file
-               $class = "tx_{$extKey}_" . uniqid('FooBar');
-               $file = $extPath . uniqid('') . '.php';
-               file_put_contents($autoloaderFile, '<?php' . LF . 'return array(\'' . $class . '\' => \'' . $file . '\');' . LF . '?>');
-                       // Inject a dummy for the core_phpcode cache to force the autoloader
-                       // to re calculate the registry
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-                       // Expect that the lower case version of the class name is written to cache
-               $mockCache->expects($this->at(2))->method('set')->with($this->anything(), $this->stringContains(strtolower($class), FALSE));
-                       // Re-initialize autoloader registry to force it to recognize the new extension
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-       }
-
-       /**
-        * @test
-        * @expectedException \RuntimeException
-        */
-       public function autoloadFindsClassFileIfExtAutoloadEntryIsCamelCased() {
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-                       // A case sensitive key (FooBar) in ext_autoload file
-               $class = "tx_{$extKey}_" . uniqid('FooBar');
-               $file = $extPath . uniqid('') . '.php';
-               file_put_contents($file, '<?php' . LF . 'throw new \\RuntimeException(\'\', 1336756850);' . LF . '?>');
-               $extAutoloadFile = $extPath . 'ext_autoload.php';
-               file_put_contents($extAutoloadFile, '<?php' . LF . 'return array(\'' . $class . '\' => \'' . $file . '\');' . LF . '?>');
-                       // Inject cache and return false, so autoloader is forced to read ext_autoloads from extensions
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-               $mockCache->expects($this->any())->method('has')->will($this->returnValue(FALSE));
-                       // Re-initialize autoloader registry to force it to recognize the new extension
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
-               \TYPO3\CMS\Core\Autoloader::autoload($class);
-       }
-
-       /**
-        * @test
-        * @expectedException \RuntimeException
-        */
-       public function autoloadFindsCamelCasedClassFileIfExtAutoloadEntryIsReadLowerCasedFromCache() {
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-                       // A case sensitive key (FooBar) in ext_autoload file
-               $class = "tx_{$extKey}_" . uniqid('FooBar');
-               $file = $extPath . uniqid('') . '.php';
-               file_put_contents($file, '<?php' . LF . 'throw new \RuntimeException(\'\', 1336756850);' . LF . '?>');
-                       // Inject cache mock and let the cache entry return the lowercased class name as key
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-               $mockCache->expects($this->any())->method('has')->will($this->returnValue(TRUE));
-               $mockCache->expects($this->once())->method('requireOnce')->will($this->returnValue(array(strtolower($class) => $file)));
-                       // Re-initialize autoloader registry to force it to recognize the new extension
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
-               \TYPO3\CMS\Core\Autoloader::autoload($class);
-       }
-
-       /**
-        * @test
-        * @expectedException \RuntimeException
-        */
-       public function autoloadFindsClassFileThatRespectsExtbaseNamingSchemeWithoutExtAutoloadFile() {
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-                       // Create a class named Tx_Extension_Foo123_Bar456
-                       // to find file extension/Classes/Foo123/Bar456.php
-               $pathSegment = 'Foo' . uniqid();
-               $fileName = 'Bar' . uniqid();
-               $class = 'Tx_' . ucfirst($extKey) . '_' . $pathSegment . '_' . $fileName;
-
-               $file = $extPath . 'Classes/' . $pathSegment . '/' . $fileName . '.php';
-               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($extPath . 'Classes/' . $pathSegment);
-               file_put_contents($file, '<?php' . LF . 'throw new \\RuntimeException(\'\', 1310203813);' . LF . '?>');
-                       // Inject a dummy for the core_phpcode cache to cache
-                       // the calculated cache entry to a dummy cache
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-                       // Expect the exception of the file to be thrown
-               \TYPO3\CMS\Core\Autoloader::autoload($class);
-       }
-
-       /**
-        * @test
-        */
-       public function unregisterAutoloaderWritesClassFileThatRespectsExtbaseNamingSchemeToCacheFile() {
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-               $pathSegment = 'Foo' . uniqid();
-               $fileName = 'Bar' . uniqid();
-               $class = 'Tx_' . $extKey . '_' . $pathSegment . '_' . $fileName;
-               $file = $extPath . 'Classes/' . $pathSegment . '/' . $fileName . '.php';
-               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($extPath . 'Classes/' . $pathSegment);
-               file_put_contents($file, '<?php' . LF . '$foo = \'bar\';' . LF . '?>');
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-                       // Expect that an entry to the cache is written containing the newly found class
-               $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains(strtolower($class), $this->anything()));
-               \TYPO3\CMS\Core\Autoloader::autoload($class);
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-       }
-
-       /**
-        * @test
-        */
-       public function unregisterAutoloaderWritesClassFileLocationOfClassRespectingExtbaseNamingSchemeToCacheFile() {
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-               $pathSegment = 'Foo' . uniqid();
-               $fileName = 'Bar' . uniqid();
-               $class = 'Tx_' . $extKey . '_' . $pathSegment . '_' . $fileName;
-               $file = $extPath . 'Classes/' . $pathSegment . '/' . $fileName . '.php';
-               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($extPath . 'Classes/' . $pathSegment);
-               file_put_contents($file, '<?php' . LF . '$foo = \'bar\';' . LF . '?>');
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-                       // Expect that an entry to the cache is written containing the newly found class
-               $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains(strtolower($file), $this->anything()));
-               \TYPO3\CMS\Core\Autoloader::autoload($class);
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-       }
-
-       /**
-        * @test
-        */
-       public function getClassPathByRegistryLookupFindsClassPrefixedWithUxRegisteredInExtAutoloadFile() {
-                       // Create a dummy extension with a path to a 'ux_' prefixed php file
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-               $autoloaderFile = $extPath . 'ext_autoload.php';
-               $class = strtolower("ux_tx_{$extKey}_" . uniqid(''));
-               $file = $extPath . uniqid('') . '.php';
-               file_put_contents($autoloaderFile, '<?php' . LF . 'return array(\'' . $class . '\' => \'' . $file . '\');' . LF . '?>');
-                       // Inject a dummy for the core_phpcode cache to force the autoloader
-                       // to re calculate the registry
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-                       // Re-initialize autoloader registry to force it to recognize the new extension with the ux_ autoload definition
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
-               $this->assertSame($file, \TYPO3\CMS\Core\Autoloader::getClassPathByRegistryLookup($class));
-       }
-
-       /**
-        * @test
-        */
-       public function unregisterAutoloaderWritesNotExistingUxCLassLookupFromGetClassPathByRegistryLookupToCache() {
-               $uxClassName = 'ux_Tx_Foo' . uniqid();
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
-                       // Class is not found by returning NULL
-               $this->assertSame(NULL, \TYPO3\CMS\Core\Autoloader::getClassPathByRegistryLookup($uxClassName));
-               // Expect NULL lookup is cached
-               $expectedCacheString = '\'' . strtolower($uxClassName) . '\' => NULL,';
-               $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains($expectedCacheString));
-                       // Trigger writing new cache file
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-       }
-
-       /**
-        * @test
-        */
-       public function unregisterAutoloaderWritesDeprecatedTypo3ConfVarsRegisteredXclassClassFoundByGetClassPathByRegistryLookupToCache() {
-                       // Create a fake extension
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-               $autoloaderFile = $extPath . 'ext_autoload.php';
-                       // Feed ext_autoload with a base file and the class file
-               $class = strtolower("tx_{$extKey}_" . uniqid(''));
-               $fileName = uniqid('') . '.php';
-               $file = $extPath . $fileName;
-               $xClassFile = 'typo3temp/' . $extKey . '/xclassFile';
-               file_put_contents($autoloaderFile, '<?php' . LF . 'return array(\'' . $class . '\' => \'' . $file . '\');' . LF . '?>');
-               file_put_contents(PATH_site . $xClassFile, '<?php' . LF . 'die();' . LF . '?>');
-                       // Register a xclass for the base file
-               $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3temp/' . $extKey . '/' . $fileName] = $xClassFile;
-                       // Inject a dummy for the core_phpcode cache to force the autoloader
-                       // to re calculate the registry
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-                       // Excpect the cache entry to be called once with the new class name
-               $mockCache->expects($this->at(2))->method('set')->with($this->anything(), $this->stringContains('ux_' . $class));
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
-               \TYPO3\CMS\Core\Autoloader::getClassPathByRegistryLookup('ux_' . $class);
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-       }
-
-       /**
-        * @test
-        * @expectedException \RuntimeException
-        */
-       public function autoloadFindsClassFileThatRespectsExtbaseNamingSchemeWithNamespace() {
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-                       // Create a class named \Tx\Extension\Foo123\Bar456
-                       // to find file extension/Classes/Foo123/Bar456.php
-               $pathSegment = 'Foo' . uniqid();
-               $fileName = 'Bar' . uniqid();
-               $namespacedClass = '\\Vendor\\' . ucfirst($extKey) . '\\' . $pathSegment . '\\' . $fileName;
-               $file = $extPath . 'Classes/' . $pathSegment . '/' . $fileName . '.php';
-               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($extPath . 'Classes/' . $pathSegment);
-               file_put_contents($file, '<?php' . LF . 'throw new \\RuntimeException(\'\', 1342800577);' . LF . '?>');
-                       // Re-initialize autoloader registry to force it to recognize the new extension
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
-                       // Expect the exception of the file to be thrown
-               \TYPO3\CMS\Core\Autoloader::autoload($namespacedClass);
-       }
-
-       /**
-        * @test
-        */
-       public function unregisterAutoloaderWritesClassFileLocationOfClassRespectingExtbaseNamingSchemeWithNamespaceToCacheFile() {
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-               $pathSegment = 'Foo' . uniqid();
-               $fileName = 'Bar' . uniqid();
-               $namespacedClass = '\\Tx\\' . $extKey . '\\' . $pathSegment . '\\' . $fileName;
-               $file = $extPath . 'Classes/' . $pathSegment . '/' . $fileName . '.php';
-               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($extPath . 'Classes/' . $pathSegment);
-               file_put_contents($file, "<?php\n\n\$foo = 'bar';\n\n?>");
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-                       // Expect that an entry to the cache is written containing the newly found class
-               $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains(strtolower($file), $this->anything()));
-               \TYPO3\CMS\Core\Autoloader::autoload($namespacedClass);
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-       }
-
-       /**
-        * @test
-        */
-       public function checkClassNamesNotExtbaseSchemePassAutoloaderUntouched() {
-               $class = '\\Symfony\\Foo\\Bar';
-               $this->assertNull(\TYPO3\CMS\Core\Autoloader::getClassPathByRegistryLookup($class));
-       }
-
-       /**
-        * @test
-        */
-       public function checkAutoloaderSetsNamespacedClassnamesInExtAutoloadAreWrittenToCache() {
-               $extKey = $this->createFakeExtension();
-               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
-               $pathSegment = 'Foo' . uniqid();
-               $fileName = 'Bar' . uniqid();
-               $autoloaderFile = $extPath . 'ext_autoload.php';
-                       // A case sensitive key (FooBar) in ext_autoload file
-               $namespacedClass = '\\Tx\\' . $extKey . '\\' . $pathSegment . '\\' . $fileName;
-               file_put_contents($autoloaderFile, '<?php' . LF . 'return array(\'' . $namespacedClass . '\' =>   \'EXT:someExt/Classes/Foo/bar.php\');' . LF . '?>');
-                       // Inject a dummy for the core_phpcode cache to force the autoloader
-                       // to re calculate the registry
-               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
-               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
-               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
-                       // Expect that the lower case version of the class name is written to cache
-               $mockCache->expects($this->at(2))->method('set')->with($this->anything(), $this->stringContains(strtolower($namespacedClass), FALSE));
-                       // Re-initialize autoloader registry to force it to recognize the new extension
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-               \TYPO3\CMS\Core\Autoloader::registerAutoloader();
-               \TYPO3\CMS\Core\Autoloader::unregisterAutoloader();
-       }
-
-}
-
-?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Unit/Core/ClassLoaderTest.php b/typo3/sysext/core/Tests/Unit/Core/ClassLoaderTest.php
new file mode 100644 (file)
index 0000000..b6bdb1a
--- /dev/null
@@ -0,0 +1,443 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Core;
+
+/***************************************************************
+ * Copyright notice
+ *
+ * (c) 2011 Andreas Wolf <andreas.wolf@ikt-werk.de>
+ * All rights reserved
+ *
+ * This script is part of the TYPO3 project. The TYPO3 project is
+ * free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The GNU General Public License can be found at
+ * http://www.gnu.org/copyleft/gpl.html.
+ *
+ * This script is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Testcase for TYPO3\CMS\Core\Core\ClassLoader
+ *
+ * @package TYPO3
+ * @subpackage t3lib
+ * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
+ */
+class ClassLoaderTest extends \Tx_Phpunit_TestCase {
+
+       /**
+        * @var boolean Enable backup of global and system variables
+        */
+       protected $backupGlobals = TRUE;
+
+       /**
+        * Exclude TYPO3_DB from backup/ restore of $GLOBALS
+        * because resource types cannot be handled during serializing
+        *
+        * @var array
+        */
+       protected $backupGlobalsBlacklist = array('TYPO3_DB');
+
+       /**
+        * @var array Backup of typo3CacheManager
+        */
+       protected $typo3CacheManager = NULL;
+
+       /**
+        * @var array Register of temporary extensions in typo3temp
+        */
+       protected $fakedExtensions = array();
+
+       /**
+        * Fix a race condition that t3lib_div is not available
+        * during tearDown if fiddling with the autoloader where
+        * backupGlobals is not set up again yet
+        */
+       public function setUp() {
+               $this->typo3CacheManager = $GLOBALS['typo3CacheManager'];
+       }
+
+       /**
+        * Clean up
+        * Warning: Since phpunit itself is php and we are fiddling with php
+        * autoloader code here, the tests are a bit fragile. This tearDown
+        * method ensures that all main classes are available again during
+        * tear down of a testcase.
+        * This construct will fail if the class under test is changed and
+        * not compatible anymore. Make sure to always run the whole test
+        * suite if fiddling with the autoloader unit tests to ensure that
+        * there is no fatal error thrown in other unit test classes triggered
+        * by errors in this one.
+        */
+       public function tearDown() {
+               $GLOBALS['typo3CacheManager'] = $this->typo3CacheManager;
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+               foreach ($this->fakedExtensions as $extension) {
+                       \TYPO3\CMS\Core\Utility\GeneralUtility::rmdir(PATH_site . 'typo3temp/' . $extension, TRUE);
+               }
+       }
+
+       /**
+        * Creates a fake extension inside typo3temp/. No configuration is created,
+        * just the folder, plus the extension is registered in $TYPO3_LOADED_EXT
+        *
+        * @return string The extension key
+        */
+       protected function createFakeExtension() {
+               $extKey = strtolower(uniqid('testing'));
+               $absExtPath = PATH_site . 'typo3temp/' . $extKey . '/';
+               $relPath = 'typo3temp/' . $extKey . '/';
+               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir($absExtPath);
+               $GLOBALS['TYPO3_LOADED_EXT'][$extKey] = array(
+                       'siteRelPath' => $relPath
+               );
+               $GLOBALS['TYPO3_CONF_VARS']['EXT']['extListArray'][] = $extKey;
+               $this->fakedExtensions[] = $extKey;
+               \TYPO3\CMS\Core\Extension\ExtensionManager::clearExtensionKeyMap();
+               return $extKey;
+       }
+
+       /**
+        * @test
+        */
+       public function unregisterAndRegisterAgainDoesNotFatal() {
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+                       // If this fatals the autoload re registering went wrong
+               \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\TimeTracker\\NullTimeTracker');
+       }
+
+       /**
+        * @test
+        */
+       public function unregisterAutoloaderSetsCacheEntryWithT3libNoTags() {
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+                       // Expect the mock cache set method to be called
+                       // once with t3lib_autoloader as third parameter
+               $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->anything(), array());
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+       }
+
+       /**
+        * @test
+        * @expectedException \RuntimeException
+        */
+       public function autoloadFindsClassFileDefinedInExtAutoloadFile() {
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+               $autoloaderFile = $extPath . 'ext_autoload.php';
+               $class = strtolower("tx_{$extKey}_" . uniqid(''));
+               $file = $extPath . uniqid('') . '.php';
+               file_put_contents($file, '<?php' . LF . 'throw new \\RuntimeException(\'\', 1310203812);' . LF . '?>');
+               file_put_contents($autoloaderFile, '<?php' . LF . 'return array(\'' . $class . '\' => \'' . $file . '\');' . LF . '?>');
+                       // Inject a dummy for the core_phpcode cache to force the autoloader
+                       // to re calculate the registry
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+                       // Re-initialize autoloader registry to force it to recognize the new extension
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+                       // Expect the exception of the file to be thrown
+               \TYPO3\CMS\Core\Core\ClassLoader::autoload($class);
+       }
+
+       /**
+        * @test
+        */
+       public function unregisterAutoloaderWritesLowerCasedClassFileToCache() {
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+               $autoloaderFile = $extPath . 'ext_autoload.php';
+                       // A case sensitive key (FooBar) in ext_autoload file
+               $class = "tx_{$extKey}_" . uniqid('FooBar');
+               $file = $extPath . uniqid('') . '.php';
+               file_put_contents($autoloaderFile, '<?php' . LF . 'return array(\'' . $class . '\' => \'' . $file . '\');' . LF . '?>');
+                       // Inject a dummy for the core_phpcode cache to force the autoloader
+                       // to re calculate the registry
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+                       // Expect that the lower case version of the class name is written to cache
+               $mockCache->expects($this->at(2))->method('set')->with($this->anything(), $this->stringContains(strtolower($class), FALSE));
+                       // Re-initialize autoloader registry to force it to recognize the new extension
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+       }
+
+       /**
+        * @test
+        * @expectedException \RuntimeException
+        */
+       public function autoloadFindsClassFileIfExtAutoloadEntryIsCamelCased() {
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+                       // A case sensitive key (FooBar) in ext_autoload file
+               $class = "tx_{$extKey}_" . uniqid('FooBar');
+               $file = $extPath . uniqid('') . '.php';
+               file_put_contents($file, '<?php' . LF . 'throw new \\RuntimeException(\'\', 1336756850);' . LF . '?>');
+               $extAutoloadFile = $extPath . 'ext_autoload.php';
+               file_put_contents($extAutoloadFile, '<?php' . LF . 'return array(\'' . $class . '\' => \'' . $file . '\');' . LF . '?>');
+                       // Inject cache and return false, so autoloader is forced to read ext_autoloads from extensions
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+               $mockCache->expects($this->any())->method('has')->will($this->returnValue(FALSE));
+                       // Re-initialize autoloader registry to force it to recognize the new extension
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::autoload($class);
+       }
+
+       /**
+        * @test
+        * @expectedException \RuntimeException
+        */
+       public function autoloadFindsCamelCasedClassFileIfExtAutoloadEntryIsReadLowerCasedFromCache() {
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+                       // A case sensitive key (FooBar) in ext_autoload file
+               $class = "tx_{$extKey}_" . uniqid('FooBar');
+               $file = $extPath . uniqid('') . '.php';
+               file_put_contents($file, '<?php' . LF . 'throw new \RuntimeException(\'\', 1336756850);' . LF . '?>');
+                       // Inject cache mock and let the cache entry return the lowercased class name as key
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+               $mockCache->expects($this->any())->method('has')->will($this->returnValue(TRUE));
+               $mockCache->expects($this->once())->method('requireOnce')->will($this->returnValue(array(strtolower($class) => $file)));
+                       // Re-initialize autoloader registry to force it to recognize the new extension
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::autoload($class);
+       }
+
+       /**
+        * @test
+        * @expectedException \RuntimeException
+        */
+       public function autoloadFindsClassFileThatRespectsExtbaseNamingSchemeWithoutExtAutoloadFile() {
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+                       // Create a class named Tx_Extension_Foo123_Bar456
+                       // to find file extension/Classes/Foo123/Bar456.php
+               $pathSegment = 'Foo' . uniqid();
+               $fileName = 'Bar' . uniqid();
+               $class = 'Tx_' . ucfirst($extKey) . '_' . $pathSegment . '_' . $fileName;
+
+               $file = $extPath . 'Classes/' . $pathSegment . '/' . $fileName . '.php';
+               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($extPath . 'Classes/' . $pathSegment);
+               file_put_contents($file, '<?php' . LF . 'throw new \\RuntimeException(\'\', 1310203813);' . LF . '?>');
+                       // Inject a dummy for the core_phpcode cache to cache
+                       // the calculated cache entry to a dummy cache
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+                       // Expect the exception of the file to be thrown
+               \TYPO3\CMS\Core\Core\ClassLoader::autoload($class);
+       }
+
+       /**
+        * @test
+        */
+       public function unregisterAutoloaderWritesClassFileThatRespectsExtbaseNamingSchemeToCacheFile() {
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+               $pathSegment = 'Foo' . uniqid();
+               $fileName = 'Bar' . uniqid();
+               $class = 'Tx_' . $extKey . '_' . $pathSegment . '_' . $fileName;
+               $file = $extPath . 'Classes/' . $pathSegment . '/' . $fileName . '.php';
+               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($extPath . 'Classes/' . $pathSegment);
+               file_put_contents($file, '<?php' . LF . '$foo = \'bar\';' . LF . '?>');
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+                       // Expect that an entry to the cache is written containing the newly found class
+               $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains(strtolower($class), $this->anything()));
+               \TYPO3\CMS\Core\Core\ClassLoader::autoload($class);
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+       }
+
+       /**
+        * @test
+        */
+       public function unregisterAutoloaderWritesClassFileLocationOfClassRespectingExtbaseNamingSchemeToCacheFile() {
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+               $pathSegment = 'Foo' . uniqid();
+               $fileName = 'Bar' . uniqid();
+               $class = 'Tx_' . $extKey . '_' . $pathSegment . '_' . $fileName;
+               $file = $extPath . 'Classes/' . $pathSegment . '/' . $fileName . '.php';
+               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($extPath . 'Classes/' . $pathSegment);
+               file_put_contents($file, '<?php' . LF . '$foo = \'bar\';' . LF . '?>');
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+                       // Expect that an entry to the cache is written containing the newly found class
+               $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains(strtolower($file), $this->anything()));
+               \TYPO3\CMS\Core\Core\ClassLoader::autoload($class);
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+       }
+
+       /**
+        * @test
+        */
+       public function getClassPathByRegistryLookupFindsClassPrefixedWithUxRegisteredInExtAutoloadFile() {
+                       // Create a dummy extension with a path to a 'ux_' prefixed php file
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+               $autoloaderFile = $extPath . 'ext_autoload.php';
+               $class = strtolower("ux_tx_{$extKey}_" . uniqid(''));
+               $file = $extPath . uniqid('') . '.php';
+               file_put_contents($autoloaderFile, '<?php' . LF . 'return array(\'' . $class . '\' => \'' . $file . '\');' . LF . '?>');
+                       // Inject a dummy for the core_phpcode cache to force the autoloader
+                       // to re calculate the registry
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+                       // Re-initialize autoloader registry to force it to recognize the new extension with the ux_ autoload definition
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+               $this->assertSame($file, \TYPO3\CMS\Core\Core\ClassLoader::getClassPathByRegistryLookup($class));
+       }
+
+       /**
+        * @test
+        */
+       public function unregisterAutoloaderWritesNotExistingUxCLassLookupFromGetClassPathByRegistryLookupToCache() {
+               $uxClassName = 'ux_Tx_Foo' . uniqid();
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+                       // Class is not found by returning NULL
+               $this->assertSame(NULL, \TYPO3\CMS\Core\Core\ClassLoader::getClassPathByRegistryLookup($uxClassName));
+               // Expect NULL lookup is cached
+               $expectedCacheString = '\'' . strtolower($uxClassName) . '\' => NULL,';
+               $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains($expectedCacheString));
+                       // Trigger writing new cache file
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+       }
+
+       /**
+        * @test
+        */
+       public function unregisterAutoloaderWritesDeprecatedTypo3ConfVarsRegisteredXclassClassFoundByGetClassPathByRegistryLookupToCache() {
+                       // Create a fake extension
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+               $autoloaderFile = $extPath . 'ext_autoload.php';
+                       // Feed ext_autoload with a base file and the class file
+               $class = strtolower("tx_{$extKey}_" . uniqid(''));
+               $fileName = uniqid('') . '.php';
+               $file = $extPath . $fileName;
+               $xClassFile = 'typo3temp/' . $extKey . '/xclassFile';
+               file_put_contents($autoloaderFile, '<?php' . LF . 'return array(\'' . $class . '\' => \'' . $file . '\');' . LF . '?>');
+               file_put_contents(PATH_site . $xClassFile, '<?php' . LF . 'die();' . LF . '?>');
+                       // Register a xclass for the base file
+               $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3temp/' . $extKey . '/' . $fileName] = $xClassFile;
+                       // Inject a dummy for the core_phpcode cache to force the autoloader
+                       // to re calculate the registry
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+                       // Excpect the cache entry to be called once with the new class name
+               $mockCache->expects($this->at(2))->method('set')->with($this->anything(), $this->stringContains('ux_' . $class));
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::getClassPathByRegistryLookup('ux_' . $class);
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+       }
+
+       /**
+        * @test
+        * @expectedException \RuntimeException
+        */
+       public function autoloadFindsClassFileThatRespectsExtbaseNamingSchemeWithNamespace() {
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+                       // Create a class named \Tx\Extension\Foo123\Bar456
+                       // to find file extension/Classes/Foo123/Bar456.php
+               $pathSegment = 'Foo' . uniqid();
+               $fileName = 'Bar' . uniqid();
+               $namespacedClass = '\\Vendor\\' . ucfirst($extKey) . '\\' . $pathSegment . '\\' . $fileName;
+               $file = $extPath . 'Classes/' . $pathSegment . '/' . $fileName . '.php';
+               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($extPath . 'Classes/' . $pathSegment);
+               file_put_contents($file, '<?php' . LF . 'throw new \\RuntimeException(\'\', 1342800577);' . LF . '?>');
+                       // Re-initialize autoloader registry to force it to recognize the new extension
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+                       // Expect the exception of the file to be thrown
+               \TYPO3\CMS\Core\Core\ClassLoader::autoload($namespacedClass);
+       }
+
+       /**
+        * @test
+        */
+       public function unregisterAutoloaderWritesClassFileLocationOfClassRespectingExtbaseNamingSchemeWithNamespaceToCacheFile() {
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+               $pathSegment = 'Foo' . uniqid();
+               $fileName = 'Bar' . uniqid();
+               $namespacedClass = '\\Tx\\' . $extKey . '\\' . $pathSegment . '\\' . $fileName;
+               $file = $extPath . 'Classes/' . $pathSegment . '/' . $fileName . '.php';
+               \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($extPath . 'Classes/' . $pathSegment);
+               file_put_contents($file, "<?php\n\n\$foo = 'bar';\n\n?>");
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+                       // Expect that an entry to the cache is written containing the newly found class
+               $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains(strtolower($file), $this->anything()));
+               \TYPO3\CMS\Core\Core\ClassLoader::autoload($namespacedClass);
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+       }
+
+       /**
+        * @test
+        */
+       public function checkClassNamesNotExtbaseSchemePassAutoloaderUntouched() {
+               $class = '\\Symfony\\Foo\\Bar';
+               $this->assertNull(\TYPO3\CMS\Core\Core\ClassLoader::getClassPathByRegistryLookup($class));
+       }
+
+       /**
+        * @test
+        */
+       public function checkAutoloaderSetsNamespacedClassnamesInExtAutoloadAreWrittenToCache() {
+               $extKey = $this->createFakeExtension();
+               $extPath = PATH_site . 'typo3temp/' . $extKey . '/';
+               $pathSegment = 'Foo' . uniqid();
+               $fileName = 'Bar' . uniqid();
+               $autoloaderFile = $extPath . 'ext_autoload.php';
+                       // A case sensitive key (FooBar) in ext_autoload file
+               $namespacedClass = '\\Tx\\' . $extKey . '\\' . $pathSegment . '\\' . $fileName;
+               file_put_contents($autoloaderFile, '<?php' . LF . 'return array(\'' . $namespacedClass . '\' =>   \'EXT:someExt/Classes/Foo/bar.php\');' . LF . '?>');
+                       // Inject a dummy for the core_phpcode cache to force the autoloader
+                       // to re calculate the registry
+               $mockCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'), array(), '', FALSE);
+               $GLOBALS['typo3CacheManager'] = $this->getMock('TYPO3\\CMS\\Core\\Cache\\CacheManager', array('getCache'));
+               $GLOBALS['typo3CacheManager']->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
+                       // Expect that the lower case version of the class name is written to cache
+               $mockCache->expects($this->at(2))->method('set')->with($this->anything(), $this->stringContains(strtolower($namespacedClass), FALSE));
+                       // Re-initialize autoloader registry to force it to recognize the new extension
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::registerAutoloader();
+               \TYPO3\CMS\Core\Core\ClassLoader::unregisterAutoloader();
+       }
+
+}
+
+?>
\ No newline at end of file
index d7d9c6e..5030d29 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d7d9c6e99a9f8fe20a5dedaad175062c94da2607
+Subproject commit 5030d29146481af1304fc5508370e91ad3ee75f7