/test/ConfigDiscoveryTest.php

https://github.com/zendframework/zend-component-installer · PHP · 299 lines · 245 code · 35 blank · 19 comment · 8 complexity · 2ffe236eff3a72ea278b9c3ef398dea0 MD5 · raw file

  1. <?php
  2. /**
  3. * @see https://github.com/zendframework/zend-component-installer for the canonical source repository
  4. * @copyright Copyright (c) 2016-2017 Zend Technologies USA Inc. (http://www.zend.com)
  5. * @license https://github.com/zendframework/zend-component-installer/blob/master/LICENSE.md New BSD License
  6. */
  7. namespace ZendTest\ComponentInstaller;
  8. use org\bovigo\vfs\vfsStream;
  9. use org\bovigo\vfs\vfsStreamDirectory;
  10. use PHPUnit\Framework\ExpectationFailedException;
  11. use PHPUnit\Framework\TestCase;
  12. use Zend\ComponentInstaller\Collection;
  13. use Zend\ComponentInstaller\ConfigDiscovery;
  14. use Zend\ComponentInstaller\ConfigOption;
  15. use Zend\ComponentInstaller\Injector;
  16. use Zend\ComponentInstaller\Injector\InjectorInterface;
  17. use Zend\ComponentInstaller\Injector\NoopInjector;
  18. use function array_shift;
  19. use function get_class;
  20. use function gettype;
  21. use function is_object;
  22. use function sprintf;
  23. class ConfigDiscoveryTest extends TestCase
  24. {
  25. /** @var vfsStreamDirectory */
  26. private $projectRoot;
  27. /** @var ConfigDiscovery\ */
  28. private $discovery;
  29. /** @var Collection */
  30. private $allTypes;
  31. /** @var string[] */
  32. private $injectorTypes;
  33. protected function setUp() : void
  34. {
  35. $this->projectRoot = vfsStream::setup('project');
  36. $this->discovery = new ConfigDiscovery();
  37. $this->allTypes = new Collection([
  38. InjectorInterface::TYPE_CONFIG_PROVIDER,
  39. InjectorInterface::TYPE_COMPONENT,
  40. InjectorInterface::TYPE_MODULE,
  41. ]);
  42. $this->injectorTypes = [
  43. Injector\ApplicationConfigInjector::class,
  44. // Injector\ConfigAggregatorInjector::class,
  45. Injector\ConfigInjectorChain::class,
  46. // Injector\ExpressiveConfigInjector::class,
  47. Injector\ModulesConfigInjector::class,
  48. ];
  49. }
  50. public function createApplicationConfig()
  51. {
  52. vfsStream::newFile('config/application.config.php')
  53. ->at($this->projectRoot)
  54. ->setContent('<' . "?php\nreturn [\n 'modules' => [\n ]\n];");
  55. }
  56. public function createDevelopmentConfig($dist = true)
  57. {
  58. $configFileName = 'config/development.config.php' . ($dist ? '.dist' : '');
  59. vfsStream::newFile($configFileName)
  60. ->at($this->projectRoot)
  61. ->setContent('<' . "?php\nreturn [\n 'modules' => [\n ]\n];");
  62. }
  63. public function createDevelopmentWorkConfig()
  64. {
  65. $this->createDevelopmentConfig(false);
  66. }
  67. public function createAggregatorConfig()
  68. {
  69. vfsStream::newFile('config/config.php')
  70. ->at($this->projectRoot)
  71. ->setContent('<' . "?php\n\$aggregator = new ConfigAggregator([\n]);");
  72. }
  73. public function createExpressiveConfig()
  74. {
  75. vfsStream::newFile('config/config.php')
  76. ->at($this->projectRoot)
  77. ->setContent('<' . "?php\n\$configManager = new ConfigManager([\n]);");
  78. }
  79. public function createModulesConfig()
  80. {
  81. vfsStream::newFile('config/modules.config.php')
  82. ->at($this->projectRoot)
  83. ->setContent('<' . "?php\nreturn [\n]);");
  84. }
  85. public function assertOptionsContainsNoopInjector(Collection $options)
  86. {
  87. if ($options->isEmpty()) {
  88. throw new ExpectationFailedException('Options array is empty; no NoopInjector found!');
  89. }
  90. $options = $options->toArray();
  91. $injector = array_shift($options)->getInjector();
  92. if (! $injector instanceof NoopInjector) {
  93. throw new ExpectationFailedException('Options array does not contain a NoopInjector!');
  94. }
  95. }
  96. public function assertOptionsContainsInjector($injectorType, Collection $options)
  97. {
  98. foreach ($options as $option) {
  99. if (! $option instanceof ConfigOption) {
  100. throw new ExpectationFailedException(sprintf(
  101. 'Invalid option returned: %s',
  102. is_object($option) ? get_class($option) : gettype($option)
  103. ));
  104. }
  105. if ($injectorType === get_class($option->getInjector())) {
  106. return $option->getInjector();
  107. }
  108. }
  109. throw new ExpectationFailedException(sprintf(
  110. 'Injector of type %s was not found in the options',
  111. $injectorType
  112. ));
  113. }
  114. public function assertOptionsContainsInjectorInChain($injectorType, Collection $options)
  115. {
  116. $chain = $this->assertOptionsContainsInjector(Injector\ConfigInjectorChain::class, $options);
  117. foreach ($chain->getCollection() as $injector) {
  118. if (! $injector instanceof InjectorInterface) {
  119. throw new ExpectationFailedException(sprintf(
  120. 'Invalid Injector returned: %s',
  121. is_object($injector) ? get_class($injector) : gettype($injector)
  122. ));
  123. }
  124. if ($injectorType === get_class($injector)) {
  125. return;
  126. }
  127. }
  128. throw new ExpectationFailedException(sprintf(
  129. 'Injector of type %s was not found in the options',
  130. $injectorType
  131. ));
  132. }
  133. public function testGetAvailableConfigOptionsReturnsEmptyArrayWhenNoConfigFilesPresent()
  134. {
  135. $result = $this->discovery->getAvailableConfigOptions($this->allTypes);
  136. $this->assertInstanceOf(Collection::class, $result);
  137. $this->assertTrue($result->isEmpty());
  138. }
  139. public function testGetAvailableConfigOptionsReturnsOptionsForEachSupportedPackageType()
  140. {
  141. $this->createApplicationConfig();
  142. $this->createDevelopmentConfig();
  143. $this->createAggregatorConfig();
  144. $this->createExpressiveConfig();
  145. $this->createModulesConfig();
  146. $options = $this->discovery->getAvailableConfigOptions($this->allTypes, vfsStream::url('project'));
  147. $this->assertCount(5, $options);
  148. $this->assertOptionsContainsNoopInjector($options);
  149. foreach ($this->injectorTypes as $injector) {
  150. $this->assertOptionsContainsInjector($injector, $options);
  151. }
  152. }
  153. public function configFileSubset()
  154. {
  155. return [
  156. [
  157. 'seedMethod' => 'createApplicationConfig',
  158. 'type' => InjectorInterface::TYPE_COMPONENT,
  159. 'expected' => Injector\ApplicationConfigInjector::class,
  160. 'chain' => false,
  161. ],
  162. [
  163. 'seedMethod' => 'createApplicationConfig',
  164. 'type' => InjectorInterface::TYPE_MODULE,
  165. 'expected' => Injector\ApplicationConfigInjector::class,
  166. 'chain' => false,
  167. ],
  168. [
  169. 'seedMethod' => 'createAggregatorConfig',
  170. 'type' => InjectorInterface::TYPE_CONFIG_PROVIDER,
  171. 'expected' => Injector\ConfigAggregatorInjector::class,
  172. 'chain' => true,
  173. ],
  174. [
  175. 'seedMethod' => 'createAggregatorConfig',
  176. 'type' => InjectorInterface::TYPE_CONFIG_PROVIDER,
  177. 'expected' => Injector\ConfigAggregatorInjector::class,
  178. 'chain' => true,
  179. ],
  180. [
  181. 'seedMethod' => 'createDevelopmentConfig',
  182. 'type' => InjectorInterface::TYPE_COMPONENT,
  183. 'expected' => Injector\DevelopmentConfigInjector::class,
  184. 'chain' => true,
  185. ],
  186. [
  187. 'seedMethod' => 'createDevelopmentConfig',
  188. 'type' => InjectorInterface::TYPE_MODULE,
  189. 'expected' => Injector\DevelopmentConfigInjector::class,
  190. 'chain' => true,
  191. ],
  192. [
  193. 'seedMethod' => 'createDevelopmentWorkConfig',
  194. 'type' => InjectorInterface::TYPE_COMPONENT,
  195. 'expected' => Injector\DevelopmentWorkConfigInjector::class,
  196. 'chain' => true,
  197. ],
  198. [
  199. 'seedMethod' => 'createDevelopmentWorkConfig',
  200. 'type' => InjectorInterface::TYPE_MODULE,
  201. 'expected' => Injector\DevelopmentWorkConfigInjector::class,
  202. 'chain' => true,
  203. ],
  204. [
  205. 'seedMethod' => 'createExpressiveConfig',
  206. 'type' => InjectorInterface::TYPE_CONFIG_PROVIDER,
  207. 'expected' => Injector\ExpressiveConfigInjector::class,
  208. 'chain' => true,
  209. ],
  210. [
  211. 'seedMethod' => 'createExpressiveConfig',
  212. 'type' => InjectorInterface::TYPE_CONFIG_PROVIDER,
  213. 'expected' => Injector\ExpressiveConfigInjector::class,
  214. 'chain' => true,
  215. ],
  216. [
  217. 'seedMethod' => 'createModulesConfig',
  218. 'type' => InjectorInterface::TYPE_COMPONENT,
  219. 'expected' => Injector\ModulesConfigInjector::class,
  220. 'chain' => false,
  221. ],
  222. [
  223. 'seedMethod' => 'createModulesConfig',
  224. 'type' => InjectorInterface::TYPE_MODULE,
  225. 'expected' => Injector\ModulesConfigInjector::class,
  226. 'chain' => false,
  227. ],
  228. ];
  229. }
  230. /**
  231. * @dataProvider configFileSubset
  232. *
  233. * @param string $seedMethod
  234. * @param string $type
  235. * @param string $expected
  236. * @param bool $chain
  237. */
  238. public function testGetAvailableConfigOptionsCanReturnsSubsetOfOptionsBaseOnPackageType(
  239. $seedMethod,
  240. $type,
  241. $expected,
  242. $chain
  243. ) {
  244. $this->{$seedMethod}();
  245. $options = $this->discovery->getAvailableConfigOptions(new Collection([$type]), vfsStream::url('project'));
  246. $this->assertCount(2, $options);
  247. $this->assertOptionsContainsNoopInjector($options);
  248. if ($chain) {
  249. $this->assertOptionsContainsInjectorInChain($expected, $options);
  250. } else {
  251. $this->assertOptionsContainsInjector($expected, $options);
  252. }
  253. }
  254. public function testNoOptionReturnedIfInjectorCannotRegisterType()
  255. {
  256. $this->createApplicationConfig();
  257. $options = $this->discovery->getAvailableConfigOptions(
  258. new Collection([InjectorInterface::TYPE_CONFIG_PROVIDER]),
  259. vfsStream::url('project')
  260. );
  261. $this->assertInstanceOf(Collection::class, $options);
  262. $this->assertTrue($options->isEmpty());
  263. }
  264. }