[TASK] Refactor class information generator to be testable 68/43668/2
authorHelmut Hummel <helmut.hummel@typo3.org>
Wed, 30 Sep 2015 17:56:47 +0000 (19:56 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Wed, 30 Sep 2015 19:05:15 +0000 (21:05 +0200)
Add a simple test as benefit.

Resolves: #70233
Releases: master
Change-Id: I92d093261d6c5909dbe91cf3661ae8cfa852216d
Reviewed-on: http://review.typo3.org/43668
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/core/Classes/Core/ClassLoadingInformation.php
typo3/sysext/core/Classes/Core/ClassLoadingInformationGenerator.php
typo3/sysext/core/Tests/Unit/Core/ClassLoadingInformationGeneratorTest.php
typo3/sysext/core/Tests/Unit/Core/Fixtures/test_extension/Resources/PHP/Test.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Core/Fixtures/test_extension/composer.json [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Core/Fixtures/test_extension/ext_emconf.php [new file with mode: 0644]

index e3704e3..1525c36 100644 (file)
@@ -14,9 +14,10 @@ namespace TYPO3\CMS\Core\Core;
  * The TYPO3 project - inspiring people to share!
  */
 
-use Composer\Autoload\ClassLoader as ComposerClassLoader;
+use Composer\Autoload\ClassLoader;
 use Helhum\ClassAliasLoader\ClassAliasMap;
 use TYPO3\CMS\Core\Package\PackageInterface;
+use TYPO3\CMS\Core\Package\PackageManager;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -69,8 +70,11 @@ class ClassLoadingInformation {
         */
        static public function dumpClassLoadingInformation() {
                self::ensureAutoloadInfoDirExists();
+               $composerClassLoader = static::getClassLoader();
+               $activeExtensionPackages = static::getActiveExtensionPackages();
+
                /** @var ClassLoadingInformationGenerator  $generator */
-               $generator = GeneralUtility::makeInstance(ClassLoadingInformationGenerator::class);
+               $generator = GeneralUtility::makeInstance(ClassLoadingInformationGenerator::class, $composerClassLoader, $activeExtensionPackages, PATH_site);
                $classInfoFiles = $generator->buildAutoloadInformationFiles();
                GeneralUtility::writeFile(self::getClassLoadingInformationDirectory() . self::AUTOLOAD_CLASSMAP_FILENAME, $classInfoFiles['classMapFile']);
                GeneralUtility::writeFile(self::getClassLoadingInformationDirectory() . self::AUTOLOAD_PSR4_FILENAME, $classInfoFiles['psr-4File']);
@@ -121,9 +125,10 @@ class ClassLoadingInformation {
         */
        static public function registerTransientClassLoadingInformationForPackage(PackageInterface $package) {
                $composerClassLoader = static::getClassLoader();
+               $activeExtensionPackages = static::getActiveExtensionPackages();
 
                /** @var ClassLoadingInformationGenerator  $generator */
-               $generator = GeneralUtility::makeInstance(ClassLoadingInformationGenerator::class);
+               $generator = GeneralUtility::makeInstance(ClassLoadingInformationGenerator::class, $composerClassLoader, $activeExtensionPackages, PATH_site);
 
                $classInformation = $generator->buildClassLoadingInformationForPackage($package);
                $composerClassLoader->addClassMap($classInformation['classMap']);
@@ -173,11 +178,30 @@ class ClassLoadingInformation {
        /**
         * Internal method calling the bootstrap to fetch the composer class loader
         *
-        * @return ComposerClassLoader
+        * @return ClassLoader
         * @throws \TYPO3\CMS\Core\Exception
         */
        static protected function getClassLoader() {
-               return Bootstrap::getInstance()->getEarlyInstance(ComposerClassLoader::class);
+               return Bootstrap::getInstance()->getEarlyInstance(ClassLoader::class);
+       }
+
+       /**
+        * Get all packages except the protected ones, as they are covered already
+        *
+        * @return PackageInterface[]
+        */
+       static protected function getActiveExtensionPackages() {
+               $activeExtensionPackages = [];
+               /** @var PackageManager $packageManager */
+               $packageManager = Bootstrap::getInstance()->getEarlyInstance(PackageManager::class);
+               foreach ($packageManager->getActivePackages() as $package) {
+                       if ($package->getValueFromComposerManifest('type') === 'typo3-cms-framework') {
+                               // Skip all core packages as the class loading info is prepared for them already
+                               continue;
+                       }
+                       $activeExtensionPackages[] = $package;
+               }
+               return $activeExtensionPackages;
        }
 
 }
index 6920091..05e5116 100644 (file)
@@ -15,15 +15,14 @@ namespace TYPO3\CMS\Core\Core;
  */
 
 use Composer\Autoload\ClassMapGenerator;
-use Composer\Autoload\ClassLoader as ComposerClassLoader;
+use Composer\Autoload\ClassLoader;
 use TYPO3\CMS\Core\Package\PackageInterface;
-use TYPO3\CMS\Core\Package\PackageManager;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Utility\PathUtility;
 
 /**
  * Generates class loading information (class maps, class aliases etc.) and writes it to files
  * for further inclusion in the bootstrap
+ * @internal
  */
 class ClassLoadingInformationGenerator {
 
@@ -33,6 +32,27 @@ class ClassLoadingInformationGenerator {
        protected $activeExtensionPackages;
 
        /**
+        * @var ClassLoader
+        */
+       protected $classLoader;
+
+       /**
+        * @var string
+        */
+       protected $installationRoot;
+
+       /**
+        * @param ClassLoader $classLoader
+        * @param array $activeExtensionPackages
+        * @param string $installationRoot
+        */
+       public function __construct(ClassLoader $classLoader, array $activeExtensionPackages = array(), $installationRoot) {
+               $this->classLoader = $classLoader;
+               $this->activeExtensionPackages = $activeExtensionPackages;
+               $this->installationRoot = $installationRoot;
+       }
+
+       /**
         * Returns class loading information for a single package
         *
         * @param PackageInterface $package The package to generate the class loading info for
@@ -43,8 +63,7 @@ class ClassLoadingInformationGenerator {
                $classMap = array();
                $psr4 = array();
                $packagePath = $package->getPackagePath();
-
-               $manifest = $this->getPackageManager()->getComposerManifest($packagePath);
+               $manifest = $package->getValueFromComposerManifest();
 
                if (empty($manifest->autoload)) {
                        // Legacy mode: Scan the complete extension directory for class files
@@ -52,7 +71,7 @@ class ClassLoadingInformationGenerator {
                } else {
                        $autoloadDefinition = json_decode(json_encode($manifest->autoload), TRUE);
                        if (!empty($autoloadDefinition['psr-4']) && is_array($autoloadDefinition['psr-4'])) {
-                               $classLoaderPrefixesPsr4 = $this->getClassLoader()->getPrefixesPsr4();
+                               $classLoaderPrefixesPsr4 = $this->classLoader->getPrefixesPsr4();
                                foreach ($autoloadDefinition['psr-4'] as $namespacePrefix => $path) {
                                        $namespacePath = $packagePath . $path;
                                        if ($useRelativePaths) {
@@ -182,7 +201,7 @@ return array(
 EOF;
                $classMap = array();
                $psr4 = array();
-               foreach ($this->getActiveExtensionPackages() as $package) {
+               foreach ($this->activeExtensionPackages as $package) {
                        $classLoadingInformation = $this->buildClassLoadingInformationForPackage($package, TRUE);
                        $classMap = array_merge($classMap, $classLoadingInformation['classMap']);
                        $psr4 = array_merge($psr4, $classLoadingInformation['psr-4']);
@@ -214,7 +233,7 @@ EOF;
        protected function makePathRelative($packagePath, $realPathOfClassFile, $relativeToRoot = TRUE) {
                $realPathOfClassFile = GeneralUtility::fixWindowsFilePath($realPathOfClassFile);
                $packageRealPath = GeneralUtility::fixWindowsFilePath(realpath($packagePath));
-               $relativePackagePath = rtrim(PathUtility::stripPathSitePrefix($packagePath), '/');
+               $relativePackagePath = rtrim(substr($packagePath, strlen($this->installationRoot)), '/');
                if ($relativeToRoot) {
                        $relativePathToClassFile = $relativePackagePath . '/' . ltrim(substr($realPathOfClassFile, strlen($packageRealPath)), '/');
                } else {
@@ -244,7 +263,7 @@ EOF;
        public function buildClassAliasMapFile() {
                $aliasToClassNameMapping = array();
                $classNameToAliasMapping = array();
-               foreach ($this->getActiveExtensionPackages() as $package) {
+               foreach ($this->activeExtensionPackages as $package) {
                        $aliasMappingForPackage = $this->buildClassAliasMapForPackage($package);
                        $aliasToClassNameMapping = array_merge($aliasToClassNameMapping, $aliasMappingForPackage['aliasToClassNameMapping']);
                        $classNameToAliasMapping = array_merge($classNameToAliasMapping, $aliasMappingForPackage['classNameToAliasMapping']);
@@ -259,51 +278,4 @@ EOF;
                return $fileContent;
        }
 
-       /**
-        * Get all packages except the protected ones, as they are covered already
-        *
-        * @return PackageInterface[]
-        */
-       protected function getActiveExtensionPackages() {
-               if ($this->activeExtensionPackages === NULL) {
-                       $this->activeExtensionPackages = array();
-                       foreach ($this->getPackageManager()->getActivePackages() as $package) {
-                               if ($this->isFrameworkPackage($package)) {
-                                       // Skip all core packages as the class loading info is prepared for them already
-                                       continue;
-                               }
-                               $this->activeExtensionPackages[] = $package;
-                       }
-               }
-
-               return $this->activeExtensionPackages;
-       }
-
-       /**
-        * Check if the package is a framework package (located in typo3/sysext)
-        *
-        * @param PackageInterface $package
-        * @return bool
-        */
-       protected function isFrameworkPackage(PackageInterface $package) {
-               return $package->getValueFromComposerManifest('type') === 'typo3-cms-framework';
-       }
-
-       /**
-        * @return PackageManager
-        * @throws \TYPO3\CMS\Core\Exception
-        */
-       protected function getPackageManager() {
-               return Bootstrap::getInstance()->getEarlyInstance(PackageManager::class);
-       }
-
-       /**
-        * Internal method calling the bootstrap to fetch the composer class loader
-        *
-        * @return ComposerClassLoader
-        * @throws \TYPO3\CMS\Core\Exception
-        */
-       protected function getClassLoader() {
-               return Bootstrap::getInstance()->getEarlyInstance(ComposerClassLoader::class);
-       }
 }
index cb0536a..7015471 100644 (file)
@@ -10,7 +10,10 @@ namespace TYPO3\CMS\Core\Tests\Unit\Core;
  *                                                                        *
  * The TYPO3 project - inspiring people to share!                         *
  *                                                                        */
+
+use Composer\Autoload\ClassLoader;
 use TYPO3\CMS\Core\Core\ClassLoadingInformationGenerator;
+use TYPO3\CMS\Core\Package\PackageInterface;
 use TYPO3\CMS\Core\Tests\UnitTestCase;
 
 
@@ -48,9 +51,41 @@ class ClassLoadingInformationGeneratorTest extends UnitTestCase {
         * @param bool $expectedResult
         */
        public function isIgnoredClassNameIgnoresTestClasses($className, $expectedResult) {
-               $generator = $this->getAccessibleMock(ClassLoadingInformationGenerator::class, ['dummy']);
+               $generator = $this->getAccessibleMock(
+                       ClassLoadingInformationGenerator::class,
+                       ['dummy'],
+                       [$this->getMock(ClassLoader::class), $this->createPackagesMock(), __DIR__]
+               );
 
                $this->assertEquals($expectedResult, $generator->_call('isIgnoredClassName', $className));
        }
 
+       /**
+        * @test
+        */
+       public function autoloadFilesAreBuildCorrectly() {
+               /** @var ClassLoader|\PHPUnit_Framework_MockObject_MockObject $classLoaderMock */
+               $classLoaderMock = $this->getMock(ClassLoader::class);
+               $generator = new ClassLoadingInformationGenerator($classLoaderMock, $this->createPackagesMock(), __DIR__);
+               $files = $generator->buildAutoloadInformationFiles();
+
+               $this->assertArrayHasKey('psr-4File', $files);
+               $this->assertArrayHasKey('classMapFile', $files);
+               $this->assertContains('\'TYPO3\\\\CMS\\\\TestExtension\\\\\' => array($typo3InstallDir . \'/Fixtures/test_extension/Classes/\')', $files['psr-4File']);
+               $this->assertContains('$typo3InstallDir . \'/Fixtures/test_extension/Resources/PHP/Test.php\'', $files['classMapFile']);
+       }
+
+       /**
+        * @return PackageInterface[]
+        */
+       protected function createPackagesMock() {
+               $packageStub = $this->getMock(PackageInterface::class);
+               $packageStub->expects($this->any())->method('getPackagePath')->willReturn(__DIR__ . '/Fixtures/test_extension/');
+               $packageStub->expects($this->any())->method('getValueFromComposerManifest')->willReturn(
+                       json_decode(file_get_contents(__DIR__ . '/Fixtures/test_extension/composer.json'))
+               );
+
+               return [$packageStub];
+       }
+
 }
diff --git a/typo3/sysext/core/Tests/Unit/Core/Fixtures/test_extension/Resources/PHP/Test.php b/typo3/sysext/core/Tests/Unit/Core/Fixtures/test_extension/Resources/PHP/Test.php
new file mode 100644 (file)
index 0000000..304459e
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Core\Fixtures\test_extension\Resources\PHP;
+
+/*                                                                        *
+ * This script belongs to the TYPO3 Flow framework.                       *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License, either version 3   *
+ * of the License, or (at your option) any later version.                 *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+/**
+ * Class Test
+ */
+class Test {
+
+}
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Unit/Core/Fixtures/test_extension/composer.json b/typo3/sysext/core/Tests/Unit/Core/Fixtures/test_extension/composer.json
new file mode 100644 (file)
index 0000000..fb6d1c8
--- /dev/null
@@ -0,0 +1,20 @@
+{
+       "name": "typo3/cms-core-test",
+       "type": "typo3-cms-extension",
+       "description": "TYPO3 Core Test",
+       "homepage": "https://typo3.org",
+       "license": ["GPL-2.0+"],
+
+       "require": {
+               "php" : ">=5.5.0"
+       },
+       "replace": {
+               "core": "*"
+       },
+       "autoload": {
+               "psr-4": {
+                       "TYPO3\\CMS\\TestExtension\\": "Classes/"
+               },
+               "classmap": ["Resources/PHP/"]
+       }
+}
diff --git a/typo3/sysext/core/Tests/Unit/Core/Fixtures/test_extension/ext_emconf.php b/typo3/sysext/core/Tests/Unit/Core/Fixtures/test_extension/ext_emconf.php
new file mode 100644 (file)
index 0000000..29fcff4
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+$EM_CONF[$_EXTKEY] = array(
+       'title' => 'TYPO3 Core Test',
+       'description' => 'Test Extension',
+       'category' => 'be',
+       'state' => 'stable',
+       'uploadfolder' => 0,
+       'createDirs' => '',
+       'clearCacheOnLoad' => 0,
+       'author' => 'Helmut Hummel',
+       'author_email' => 'helmut@typo3.org',
+       'author_company' => '',
+       'version' => '7.6.0',
+       'constraints' => array(
+               'depends' => array(),
+               'conflicts' => array(),
+               'suggests' => array(),
+       ),
+);