MediaWiki  REL1_24
AutoLoaderTest.php
Go to the documentation of this file.
00001 <?php
00002 
00003 class AutoLoaderTest extends MediaWikiTestCase {
00004     protected function setUp() {
00005         global $wgAutoloadLocalClasses, $wgAutoloadClasses;
00006 
00007         parent::setUp();
00008 
00009         // Fancy dance to trigger a rebuild of AutoLoader::$autoloadLocalClassesLower
00010         $this->testLocalClasses = array(
00011             'TestAutoloadedLocalClass' => __DIR__ . '/../data/autoloader/TestAutoloadedLocalClass.php',
00012             'TestAutoloadedCamlClass' => __DIR__ . '/../data/autoloader/TestAutoloadedCamlClass.php',
00013             'TestAutoloadedSerializedClass' =>
00014                 __DIR__ . '/../data/autoloader/TestAutoloadedSerializedClass.php',
00015         );
00016         $this->setMwGlobals(
00017             'wgAutoloadLocalClasses',
00018             $this->testLocalClasses + $wgAutoloadLocalClasses
00019         );
00020         AutoLoader::resetAutoloadLocalClassesLower();
00021 
00022         $this->testExtensionClasses = array(
00023             'TestAutoloadedClass' => __DIR__ . '/../data/autoloader/TestAutoloadedClass.php',
00024         );
00025         $this->setMwGlobals( 'wgAutoloadClasses', $this->testExtensionClasses + $wgAutoloadClasses );
00026     }
00027 
00034     public function testAutoLoadConfig() {
00035         $results = self::checkAutoLoadConf();
00036 
00037         $this->assertEquals(
00038             $results['expected'],
00039             $results['actual']
00040         );
00041     }
00042 
00043     protected static function checkAutoLoadConf() {
00044         global $wgAutoloadLocalClasses, $wgAutoloadClasses, $IP;
00045 
00046         // wgAutoloadLocalClasses has precedence, just like in includes/AutoLoader.php
00047         $expected = $wgAutoloadLocalClasses + $wgAutoloadClasses;
00048         $actual = array();
00049 
00050         $files = array_unique( $expected );
00051 
00052         foreach ( $files as $file ) {
00053             // Only prefix $IP if it doesn't have it already.
00054             // Generally local classes don't have it, and those from extensions and test suites do.
00055             if ( substr( $file, 0, 1 ) != '/' && substr( $file, 1, 1 ) != ':' ) {
00056                 $filePath = "$IP/$file";
00057             } else {
00058                 $filePath = $file;
00059             }
00060 
00061             $contents = file_get_contents( $filePath );
00062 
00063             // We could use token_get_all() here, but this is faster
00064             $matches = array();
00065             preg_match_all( '/
00066                 ^ [\t ]* (?:
00067                     (?:final\s+)? (?:abstract\s+)? (?:class|interface) \s+
00068                     (?P<class> [a-zA-Z0-9_]+)
00069                 |
00070                     class_alias \s* \( \s*
00071                         ([\'"]) (?P<original> [^\'"]+) \g{-2} \s* , \s*
00072                         ([\'"]) (?P<alias> [^\'"]+ ) \g{-2} \s*
00073                     \) \s* ;
00074                 )
00075             /imx', $contents, $matches, PREG_SET_ORDER );
00076 
00077             $namespaceMatch = array();
00078             preg_match( '/
00079                 ^ [\t ]*
00080                     namespace \s+
00081                         ([a-zA-Z0-9_]+(\\\\[a-zA-Z0-9_]+)*)
00082                     \s* ;
00083             /imx', $contents, $namespaceMatch );
00084             $fileNamespace = $namespaceMatch ? $namespaceMatch[1] . '\\' : '';
00085 
00086             $classesInFile = array();
00087             $aliasesInFile = array();
00088 
00089             foreach ( $matches as $match ) {
00090                 if ( !empty( $match['class'] ) ) {
00091                     $class = $fileNamespace . $match['class'];
00092                     $actual[$class] = $file;
00093                     $classesInFile[$class] = true;
00094                 } else {
00095                     $aliasesInFile[$match['alias']] = $match['original'];
00096                 }
00097             }
00098 
00099             // Only accept aliases for classes in the same file, because for correct
00100             // behavior, all aliases for a class must be set up when the class is loaded
00101             // (see <https://bugs.php.net/bug.php?id=61422>).
00102             foreach ( $aliasesInFile as $alias => $class ) {
00103                 if ( isset( $classesInFile[$class] ) ) {
00104                     $actual[$alias] = $file;
00105                 } else {
00106                     $actual[$alias] = "[original class not in $file]";
00107                 }
00108             }
00109         }
00110 
00111         return array(
00112             'expected' => $expected,
00113             'actual' => $actual,
00114         );
00115     }
00116 
00117     function testCoreClass() {
00118         $this->assertTrue( class_exists( 'TestAutoloadedLocalClass' ) );
00119     }
00120 
00121     function testExtensionClass() {
00122         $this->assertTrue( class_exists( 'TestAutoloadedClass' ) );
00123     }
00124 
00125     function testWrongCaseClass() {
00126         $this->assertTrue( class_exists( 'testautoLoadedcamlCLASS' ) );
00127     }
00128 
00129     function testWrongCaseSerializedClass() {
00130         $dummyCereal = 'O:29:"testautoloadedserializedclass":0:{}';
00131         $uncerealized = unserialize( $dummyCereal );
00132         $this->assertFalse( $uncerealized instanceof __PHP_Incomplete_Class,
00133             "unserialize() can load classes case-insensitively." );
00134     }
00135 }