AppTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The MIT License
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 2.0.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Core;
  16. use Cake\Core\App;
  17. use Cake\Core\Configure;
  18. use Cake\Core\Exception\CakeException;
  19. use Cake\Database\Driver\Mysql;
  20. use Cake\TestSuite\TestCase;
  21. use TestApp\Core\TestApp;
  22. /**
  23. * AppTest class
  24. */
  25. class AppTest extends TestCase
  26. {
  27. /**
  28. * tearDown method
  29. */
  30. public function tearDown(): void
  31. {
  32. parent::tearDown();
  33. $this->clearPlugins();
  34. }
  35. /**
  36. * testClassName
  37. *
  38. * $checkCake and $existsInCake are derived from the input parameters
  39. *
  40. * @param string $class Class name
  41. * @param string $type Class type
  42. * @param string $suffix Class suffix
  43. * @param bool $existsInBase Whether class exists in base.
  44. * @param mixed $expected Expected value.
  45. * @dataProvider classNameProvider
  46. */
  47. public function testClassName($class, $type, $suffix = '', $existsInBase = false, $expected = false): void
  48. {
  49. static::setAppNamespace();
  50. $i = 0;
  51. TestApp::$existsInBaseCallback = function ($name, $namespace) use ($existsInBase, $class, $expected, &$i) {
  52. if ($i++ === 0) {
  53. return $existsInBase;
  54. }
  55. $checkCake = (!$existsInBase || strpos('.', $class));
  56. if ($checkCake) {
  57. return (bool)$expected;
  58. }
  59. return false;
  60. };
  61. $return = TestApp::className($class, $type, $suffix);
  62. $this->assertSame($expected === false ? null : $expected, $return);
  63. }
  64. public function testClassNameWithFqcn(): void
  65. {
  66. $this->assertSame(TestCase::class, App::className(TestCase::class));
  67. $this->assertNull(App::className('\Foo'));
  68. }
  69. /**
  70. * @link https://github.com/cakephp/cakephp/issues/16258
  71. */
  72. public function testClassNameWithAppNamespaceUnset(): void
  73. {
  74. Configure::delete('App.namespace');
  75. $result = App::className('Mysql', 'Database/Driver');
  76. $this->assertSame(Mysql::class, $result);
  77. }
  78. /**
  79. * testShortName
  80. *
  81. * @param string $class Class name
  82. * @param string $type Class type
  83. * @param string $suffix Class suffix
  84. * @param mixed $expected Expected value.
  85. * @dataProvider shortNameProvider
  86. */
  87. public function testShortName($class, $type, $suffix = '', $expected = false): void
  88. {
  89. static::setAppNamespace();
  90. $return = TestApp::shortName($class, $type, $suffix);
  91. $this->assertSame($expected, $return);
  92. }
  93. /**
  94. * testShortNameWithNestedAppNamespace
  95. */
  96. public function testShortNameWithNestedAppNamespace(): void
  97. {
  98. static::setAppNamespace('TestApp/Nested');
  99. $return = TestApp::shortName(
  100. 'TestApp/Nested/Controller/PagesController',
  101. 'Controller',
  102. 'Controller'
  103. );
  104. $this->assertSame('Pages', $return);
  105. static::setAppNamespace();
  106. }
  107. /**
  108. * @link https://github.com/cakephp/cakephp/issues/15415
  109. */
  110. public function testShortNameWithAppNamespaceUnset(): void
  111. {
  112. Configure::delete('App.namespace');
  113. $result = App::shortName(Mysql::class, 'Database/Driver');
  114. $this->assertSame('Mysql', $result);
  115. }
  116. /**
  117. * classNameProvider
  118. *
  119. * Return test permutations for testClassName method. Format:
  120. * className
  121. * type
  122. * suffix
  123. * existsInBase (Base meaning App or plugin namespace)
  124. * expected return value
  125. *
  126. * @return array
  127. */
  128. public function classNameProvider(): array
  129. {
  130. return [
  131. ['Does', 'Not', 'Exist'],
  132. ['Exists', 'In', 'App', true, 'TestApp\In\ExistsApp'],
  133. ['Also/Exists', 'In', 'App', true, 'TestApp\In\Also\ExistsApp'],
  134. ['Also', 'Exists/In', 'App', true, 'TestApp\Exists\In\AlsoApp'],
  135. ['Also', 'Exists/In/Subfolder', 'App', true, 'TestApp\Exists\In\Subfolder\AlsoApp'],
  136. ['No', 'Suffix', '', true, 'TestApp\Suffix\No'],
  137. ['MyPlugin.Exists', 'In', 'Suffix', true, 'MyPlugin\In\ExistsSuffix'],
  138. ['MyPlugin.Also/Exists', 'In', 'Suffix', true, 'MyPlugin\In\Also\ExistsSuffix'],
  139. ['MyPlugin.Also', 'Exists/In', 'Suffix', true, 'MyPlugin\Exists\In\AlsoSuffix'],
  140. ['MyPlugin.Also', 'Exists/In/Subfolder', 'Suffix', true, 'MyPlugin\Exists\In\Subfolder\AlsoSuffix'],
  141. ['MyPlugin.No', 'Suffix', '', true, 'MyPlugin\Suffix\No'],
  142. ['Vend/MPlugin.Exists', 'In', 'Suffix', true, 'Vend\MPlugin\In\ExistsSuffix'],
  143. ['Vend/MPlugin.Also/Exists', 'In', 'Suffix', true, 'Vend\MPlugin\In\Also\ExistsSuffix'],
  144. ['Vend/MPlugin.Also', 'Exists/In', 'Suffix', true, 'Vend\MPlugin\Exists\In\AlsoSuffix'],
  145. ['Vend/MPlugin.Also', 'Exists/In/Subfolder', 'Suffix', true, 'Vend\MPlugin\Exists\In\Subfolder\AlsoSuffix'],
  146. ['Vend/MPlugin.No', 'Suffix', '', true, 'Vend\MPlugin\Suffix\No'],
  147. ['Exists', 'In', 'Cake', false, 'Cake\In\ExistsCake'],
  148. ['Also/Exists', 'In', 'Cake', false, 'Cake\In\Also\ExistsCake'],
  149. ['Also', 'Exists/In', 'Cake', false, 'Cake\Exists\In\AlsoCake'],
  150. ['Also', 'Exists/In/Subfolder', 'Cake', false, 'Cake\Exists\In\Subfolder\AlsoCake'],
  151. ['No', 'Suffix', '', false, 'Cake\Suffix\No'],
  152. // Realistic examples returning nothing
  153. ['App', 'Core', 'Suffix'],
  154. ['Auth', 'Controller/Component'],
  155. ['Unknown', 'Controller', 'Controller'],
  156. // Real examples returning class names
  157. ['App', 'Core', '', false, 'Cake\Core\App'],
  158. ['Auth', 'Controller/Component', 'Component', false, 'Cake\Controller\Component\AuthComponent'],
  159. ['File', 'Cache/Engine', 'Engine', false, 'Cake\Cache\Engine\FileEngine'],
  160. ['Command', 'Shell/Task', 'Task', false, 'Cake\Shell\Task\CommandTask'],
  161. ['Upgrade/Locations', 'Shell/Task', 'Task', false, 'Cake\Shell\Task\Upgrade\LocationsTask'],
  162. ['Pages', 'Controller', 'Controller', true, 'TestApp\Controller\PagesController'],
  163. ];
  164. }
  165. /**
  166. * pluginSplitNameProvider
  167. *
  168. * Return test permutations for testClassName method. Format:
  169. * className
  170. * type
  171. * suffix
  172. * expected return value
  173. *
  174. * @return array
  175. */
  176. public function shortNameProvider(): array
  177. {
  178. return [
  179. ['TestApp\In\ExistsApp', 'In', 'App', 'Exists'],
  180. ['TestApp\In\Also\ExistsApp', 'In', 'App', 'Also/Exists'],
  181. ['TestApp\Exists\In\AlsoApp', 'Exists/In', 'App', 'Also'],
  182. ['TestApp\Exists\In\Subfolder\AlsoApp', 'Exists/In/Subfolder', 'App', 'Also'],
  183. ['TestApp\Suffix\No', 'Suffix', '', 'No'],
  184. ['MyPlugin\In\ExistsSuffix', 'In', 'Suffix', 'MyPlugin.Exists'],
  185. ['MyPlugin\In\Also\ExistsSuffix', 'In', 'Suffix', 'MyPlugin.Also/Exists'],
  186. ['MyPlugin\Exists\In\AlsoSuffix', 'Exists/In', 'Suffix', 'MyPlugin.Also'],
  187. ['MyPlugin\Exists\In\Subfolder\AlsoSuffix', 'Exists/In/Subfolder', 'Suffix', 'MyPlugin.Also'],
  188. ['MyPlugin\Suffix\No', 'Suffix', '', 'MyPlugin.No'],
  189. ['Vend\MPlugin\In\ExistsSuffix', 'In', 'Suffix', 'Vend/MPlugin.Exists'],
  190. ['Vend\MPlugin\In\Also\ExistsSuffix', 'In', 'Suffix', 'Vend/MPlugin.Also/Exists'],
  191. ['Vend\MPlugin\Exists\In\AlsoSuffix', 'Exists/In', 'Suffix', 'Vend/MPlugin.Also'],
  192. ['Vend\MPlugin\Exists\In\Subfolder\AlsoSuffix', 'Exists/In/Subfolder', 'Suffix', 'Vend/MPlugin.Also'],
  193. ['Vend\MPlugin\Suffix\No', 'Suffix', '', 'Vend/MPlugin.No'],
  194. ['Cake\In\ExistsCake', 'In', 'Cake', 'Exists'],
  195. ['Cake\In\Also\ExistsCake', 'In', 'Cake', 'Also/Exists'],
  196. ['Cake\Exists\In\AlsoCake', 'Exists/In', 'Cake', 'Also'],
  197. ['Cake\Exists\In\Subfolder\AlsoCake', 'Exists/In/Subfolder', 'Cake', 'Also'],
  198. ['Cake\Suffix\No', 'Suffix', '', 'No'],
  199. ['Muffin\Webservice\Webservice\EndpointWebservice', 'Webservice', 'Webservice', 'Muffin/Webservice.Endpoint'],
  200. // Real examples returning class names
  201. ['Cake\Core\App', 'Core', '', 'App'],
  202. ['Cake\Controller\Component\AuthComponent', 'Controller/Component', 'Component', 'Auth'],
  203. ['Cake\Cache\Engine\FileEngine', 'Cache/Engine', 'Engine', 'File'],
  204. ['Cake\Shell\Task\CommandTask', 'Shell/Task', 'Task', 'Command'],
  205. ['Cake\Shell\Task\Upgrade\LocationsTask', 'Shell/Task', 'Task', 'Upgrade/Locations'],
  206. ['TestApp\Controller\PagesController', 'Controller', 'Controller', 'Pages'],
  207. ];
  208. }
  209. /**
  210. * test classPath() with a plugin.
  211. */
  212. public function testClassPathWithPlugins(): void
  213. {
  214. $basepath = TEST_APP . 'Plugin' . DS;
  215. $this->loadPlugins(['TestPlugin', 'Company/TestPluginThree']);
  216. $result = App::classPath('Controller', 'TestPlugin');
  217. $this->assertPathEquals($basepath . 'TestPlugin' . DS . 'src' . DS . 'Controller' . DS, $result[0]);
  218. $result = App::classPath('Controller', 'Company/TestPluginThree');
  219. $expected = $basepath . 'Company' . DS . 'TestPluginThree' . DS . 'src' . DS . 'Controller' . DS;
  220. $this->assertPathEquals($expected, $result[0]);
  221. }
  222. /**
  223. * test path() with a plugin.
  224. */
  225. public function testPathWithPlugins(): void
  226. {
  227. $basepath = TEST_APP . 'Plugin' . DS;
  228. $this->loadPlugins(['TestPlugin', 'Company/TestPluginThree']);
  229. $result = App::path('locales', 'TestPlugin');
  230. $this->assertPathEquals($basepath . 'TestPlugin' . DS . 'resources' . DS . 'locales' . DS, $result[0]);
  231. $result = App::path('locales', 'Company/TestPluginThree');
  232. $expected = $basepath . 'Company' . DS . 'TestPluginThree' . DS . 'resources' . DS . 'locales' . DS;
  233. $this->assertPathEquals($expected, $result[0]);
  234. }
  235. public function testPathWithPluginsException(): void
  236. {
  237. $this->expectException(CakeException::class);
  238. App::path('invalid', 'TestPlugin');
  239. }
  240. /**
  241. * testCore method
  242. */
  243. public function testCore(): void
  244. {
  245. $model = App::core('Model');
  246. $this->assertEquals([CAKE . 'Model' . DS], $model);
  247. $view = App::core('View');
  248. $this->assertEquals([CAKE . 'View' . DS], $view);
  249. $controller = App::core('Controller');
  250. $this->assertEquals([CAKE . 'Controller' . DS], $controller);
  251. $component = App::core('Controller/Component');
  252. $this->assertEquals([CAKE . 'Controller' . DS . 'Component' . DS], str_replace('/', DS, $component));
  253. $auth = App::core('Controller/Component/Auth');
  254. $this->assertEquals([CAKE . 'Controller' . DS . 'Component' . DS . 'Auth' . DS], str_replace('/', DS, $auth));
  255. $datasource = App::core('Model/Datasource');
  256. $this->assertEquals([CAKE . 'Model' . DS . 'Datasource' . DS], str_replace('/', DS, $datasource));
  257. }
  258. }