diff --git a/Cake/Core/App.php b/Cake/Core/App.php index f1a00a4a718..e9068478e48 100644 --- a/Cake/Core/App.php +++ b/Cake/Core/App.php @@ -89,20 +89,33 @@ public static function classname($class, $type = '', $suffix = '') { } $base = rtrim($base, '\\'); - $fullname = '\\' . str_replace('/', '\\', $type) . '\\' . $name . $suffix; - if (class_exists($base . $fullname)) { + $fullname = '\\' . str_replace('/', '\\', $type . '\\' . $name) . $suffix; + + if (static::_classExistsInBase($fullname, $base)) { return $base . $fullname; } if ($plugin) { return false; } - - if (class_exists('Cake' . $fullname)) { + if (static::_classExistsInBase($fullname, 'Cake')) { return 'Cake' . $fullname; } return false; } +/** + * _classExistsInBase + * + * Test isolation wrapper + * + * @param string $name + * @param string $namespace + * @return bool + */ + protected static function _classExistsInBase($name, $namespace) { + return class_exists($namespace . $name); + } + /** * Used to read information stored path * diff --git a/Cake/Test/TestCase/Core/AppTest.php b/Cake/Test/TestCase/Core/AppTest.php index 6f96004cc34..806471e6e6a 100644 --- a/Cake/Test/TestCase/Core/AppTest.php +++ b/Cake/Test/TestCase/Core/AppTest.php @@ -37,36 +37,77 @@ public function tearDown() { } /** - * testClassname method + * testClassname * + * $checkCake and $existsInCake are derived from the input parameters + * + * @dataProvider classnameProvider * @return void */ - public function testClassname() { + public function testClassname($class, $type, $suffix = '', $existsInBase = false, $expected = false) { Configure::write('App.namespace', 'TestApp'); + $mock = $this->getMockClass('Cake\Core\App', ['_classExistsInBase']); + + $mock::staticExpects($this->at(0)) + ->method('_classExistsInBase') + ->will($this->returnValue($existsInBase)); + + $checkCake = (!$existsInBase || strpos('.', $class)); + if ($checkCake) { + $existsInCake = (bool)$expected; + $mock::staticExpects($this->at(1)) + ->method('_classExistsInBase') + ->will($this->returnValue($existsInCake)); + } + + $return = $mock::classname($class, $type, $suffix); + $this->assertSame($expected, $return); + } - // Test core - $this->assertEquals('Cake\Core\App', App::classname('App', 'Core')); - $this->assertFalse(App::classname('App', 'Core', 'Suffix')); - - // Assert prefix - $this->assertFalse(App::classname('Auth', 'Controller/Component')); - $this->assertEquals('Cake\Controller\Component\AuthComponent', App::classname('Auth', 'Controller/Component', 'Component')); - - // Test app - $this->assertEquals('TestApp\Controller\PagesController', App::classname('Pages', 'Controller', 'Controller')); - $this->assertFalse(App::classname('Unknown', 'Controller', 'Controller')); - - // Test plugin - Plugin::load('TestPlugin'); - $this->assertEquals('TestPlugin\Utility\TestPluginEngine', App::classname('TestPlugin.TestPlugin', 'Utility', 'Engine')); - $this->assertFalse(App::classname('TestPlugin.Unknown', 'Utility')); - - $this->assertFalse(Plugin::loaded('TestPluginTwo'), 'TestPluginTwo should not be loaded.'); - // Test unknown plugin - $this->assertEquals( - 'TestPluginTwo\Console\Command\ExampleShell', - App::classname('TestPluginTwo.Example', 'Console/Command', 'Shell') - ); +/** + * classnameProvider + * + * Return test permutations for testClassname method. Format: + * classname + * type + * suffix + * existsInBase (Base meaning App or plugin namespace) + * expected return value + * + * @return void + */ + public function classnameProvider() { + return [ + ['Does', 'Not', 'Exist'], + + ['Exists', 'In', 'App', true, 'TestApp\In\ExistsApp'], + ['Also/Exists', 'In', 'App', true, 'TestApp\In\Also\ExistsApp'], + ['Also', 'Exists/In', 'App', true, 'TestApp\Exists\In\AlsoApp'], + ['Also', 'Exists/In/Subfolder', 'App', true, 'TestApp\Exists\In\Subfolder\AlsoApp'], + + ['MyPlugin.Exists', 'In', 'Suffix', true, 'MyPlugin\In\ExistsSuffix'], + ['MyPlugin.Also/Exists', 'In', 'Suffix', true, 'MyPlugin\In\Also\ExistsSuffix'], + ['MyPlugin.Also', 'Exists/In', 'Suffix', true, 'MyPlugin\Exists\In\AlsoSuffix'], + ['MyPlugin.Also', 'Exists/In/Subfolder', 'Suffix', true, 'MyPlugin\Exists\In\Subfolder\AlsoSuffix'], + + ['Exists', 'In', 'Cake', false, 'Cake\In\ExistsCake'], + ['Also/Exists', 'In', 'Cake', false, 'Cake\In\Also\ExistsCake'], + ['Also', 'Exists/In', 'Cake', false, 'Cake\Exists\In\AlsoCake'], + ['Also', 'Exists/In/Subfolder', 'Cake', false, 'Cake\Exists\In\Subfolder\AlsoCake'], + + // Realistic examples returning nothing + ['App', 'Core', 'Suffix'], + ['Auth', 'Controller/Component'], + ['Unknown', 'Controller', 'Controller'], + + // Real examples returning classnames + ['App', 'Core', '', false, 'Cake\Core\App'], + ['Auth', 'Controller/Component', 'Component', false, 'Cake\Controller\Component\AuthComponent'], + ['File', 'Cache/Engine', 'Engine', false, 'Cake\Cache\Engine\FileEngine'], + ['Command', 'Console/Command/Task', 'Task', false, 'Cake\Console\Command\Task\CommandTask'], + ['Upgrade/Locations', 'Console/Command/Task', 'Task', false, 'Cake\Console\Command\Task\Upgrade\LocationsTask'], + ['Pages', 'Controller', 'Controller', true, 'TestApp\Controller\PagesController'], + ]; } /**