AppTest.php 11 KB

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