ConfigTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Config\Test\Unit\Model;
  7. use PHPUnit\Framework\MockObject\MockObject;
  8. /**
  9. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  10. */
  11. class ConfigTest extends \PHPUnit\Framework\TestCase
  12. {
  13. /**
  14. * @var \Magento\Config\Model\Config
  15. */
  16. private $model;
  17. /**
  18. * @var \Magento\Framework\Event\ManagerInterface|MockObject
  19. */
  20. private $eventManagerMock;
  21. /**
  22. * @var \Magento\Config\Model\Config\Structure\Reader|MockObject
  23. */
  24. private $structureReaderMock;
  25. /**
  26. * @var \Magento\Framework\DB\TransactionFactory|MockObject
  27. */
  28. private $transFactoryMock;
  29. /**
  30. * @var \Magento\Framework\App\Config\ReinitableConfigInterface|MockObject
  31. */
  32. private $appConfigMock;
  33. /**
  34. * @var \Magento\Config\Model\Config\Loader|MockObject
  35. */
  36. private $configLoaderMock;
  37. /**
  38. * @var \Magento\Framework\App\Config\ValueFactory|MockObject
  39. */
  40. private $dataFactoryMock;
  41. /**
  42. * @var \Magento\Store\Model\StoreManagerInterface|MockObject
  43. */
  44. private $storeManager;
  45. /**
  46. * @var \Magento\Config\Model\Config\Structure|MockObject
  47. */
  48. private $configStructure;
  49. /**
  50. * @var \Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker|MockObject
  51. */
  52. private $settingsChecker;
  53. /**
  54. * @var \Magento\Framework\App\ScopeResolverPool|MockObject
  55. */
  56. private $scopeResolverPool;
  57. /**
  58. * @var \Magento\Framework\App\ScopeResolverInterface|MockObject
  59. */
  60. private $scopeResolver;
  61. /**
  62. * @var \Magento\Framework\App\ScopeInterface|MockObject
  63. */
  64. private $scope;
  65. /**
  66. * @var \Magento\Store\Model\ScopeTypeNormalizer|MockObject
  67. */
  68. private $scopeTypeNormalizer;
  69. protected function setUp()
  70. {
  71. $this->eventManagerMock = $this->createMock(\Magento\Framework\Event\ManagerInterface::class);
  72. $this->structureReaderMock = $this->createPartialMock(
  73. \Magento\Config\Model\Config\Structure\Reader::class,
  74. ['getConfiguration']
  75. );
  76. $this->configStructure = $this->createMock(\Magento\Config\Model\Config\Structure::class);
  77. $this->structureReaderMock->expects(
  78. $this->any()
  79. )->method(
  80. 'getConfiguration'
  81. )->will(
  82. $this->returnValue($this->configStructure)
  83. );
  84. $this->transFactoryMock = $this->createPartialMock(
  85. \Magento\Framework\DB\TransactionFactory::class,
  86. ['create', 'addObject']
  87. );
  88. $this->appConfigMock = $this->createMock(\Magento\Framework\App\Config\ReinitableConfigInterface::class);
  89. $this->configLoaderMock = $this->createPartialMock(
  90. \Magento\Config\Model\Config\Loader::class,
  91. ['getConfigByPath']
  92. );
  93. $this->dataFactoryMock = $this->createMock(\Magento\Framework\App\Config\ValueFactory::class);
  94. $this->storeManager = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class);
  95. $this->settingsChecker = $this
  96. ->createMock(\Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker::class);
  97. $this->scopeResolverPool = $this->createMock(\Magento\Framework\App\ScopeResolverPool::class);
  98. $this->scopeResolver = $this->createMock(\Magento\Framework\App\ScopeResolverInterface::class);
  99. $this->scopeResolverPool->method('get')
  100. ->willReturn($this->scopeResolver);
  101. $this->scope = $this->createMock(\Magento\Framework\App\ScopeInterface::class);
  102. $this->scopeResolver->method('getScope')
  103. ->willReturn($this->scope);
  104. $this->scopeTypeNormalizer = $this->createMock(\Magento\Store\Model\ScopeTypeNormalizer::class);
  105. $this->model = new \Magento\Config\Model\Config(
  106. $this->appConfigMock,
  107. $this->eventManagerMock,
  108. $this->configStructure,
  109. $this->transFactoryMock,
  110. $this->configLoaderMock,
  111. $this->dataFactoryMock,
  112. $this->storeManager,
  113. $this->settingsChecker,
  114. [],
  115. $this->scopeResolverPool,
  116. $this->scopeTypeNormalizer
  117. );
  118. }
  119. public function testSaveDoesNotDoAnythingIfGroupsAreNotPassed()
  120. {
  121. $this->configLoaderMock->expects($this->never())->method('getConfigByPath');
  122. $this->model->save();
  123. }
  124. public function testSaveEmptiesNonSetArguments()
  125. {
  126. $this->structureReaderMock->expects($this->never())->method('getConfiguration');
  127. $this->assertNull($this->model->getSection());
  128. $this->assertNull($this->model->getWebsite());
  129. $this->assertNull($this->model->getStore());
  130. $this->model->save();
  131. $this->assertSame('', $this->model->getSection());
  132. $this->assertSame('', $this->model->getWebsite());
  133. $this->assertSame('', $this->model->getStore());
  134. }
  135. public function testSaveToCheckAdminSystemConfigChangedSectionEvent()
  136. {
  137. $transactionMock = $this->createMock(\Magento\Framework\DB\Transaction::class);
  138. $this->transFactoryMock->expects($this->any())->method('create')->will($this->returnValue($transactionMock));
  139. $this->configLoaderMock->expects($this->any())->method('getConfigByPath')->will($this->returnValue([]));
  140. $this->eventManagerMock->expects(
  141. $this->at(0)
  142. )->method(
  143. 'dispatch'
  144. )->with(
  145. $this->equalTo('admin_system_config_changed_section_'),
  146. $this->arrayHasKey('website')
  147. );
  148. $this->eventManagerMock->expects(
  149. $this->at(0)
  150. )->method(
  151. 'dispatch'
  152. )->with(
  153. $this->equalTo('admin_system_config_changed_section_'),
  154. $this->arrayHasKey('store')
  155. );
  156. $this->model->setGroups(['1' => ['data']]);
  157. $this->model->save();
  158. }
  159. public function testDoNotSaveReadOnlyFields()
  160. {
  161. $transactionMock = $this->createMock(\Magento\Framework\DB\Transaction::class);
  162. $this->transFactoryMock->expects($this->any())->method('create')->will($this->returnValue($transactionMock));
  163. $this->settingsChecker->expects($this->any())->method('isReadOnly')->will($this->returnValue(true));
  164. $this->configLoaderMock->expects($this->any())->method('getConfigByPath')->will($this->returnValue([]));
  165. $this->model->setGroups(['1' => ['fields' => ['key' => ['data']]]]);
  166. $this->model->setSection('section');
  167. $group = $this->createMock(\Magento\Config\Model\Config\Structure\Element\Group::class);
  168. $group->method('getPath')->willReturn('section/1');
  169. $field = $this->createMock(\Magento\Config\Model\Config\Structure\Element\Field::class);
  170. $field->method('getGroupPath')->willReturn('section/1');
  171. $field->method('getId')->willReturn('key');
  172. $this->configStructure->expects($this->at(0))
  173. ->method('getElement')
  174. ->with('section/1')
  175. ->will($this->returnValue($group));
  176. $this->configStructure->expects($this->at(1))
  177. ->method('getElement')
  178. ->with('section/1')
  179. ->will($this->returnValue($group));
  180. $this->configStructure->expects($this->at(2))
  181. ->method('getElement')
  182. ->with('section/1/key')
  183. ->will($this->returnValue($field));
  184. $backendModel = $this->createPartialMock(
  185. \Magento\Framework\App\Config\Value::class,
  186. ['addData']
  187. );
  188. $this->dataFactoryMock->expects($this->any())->method('create')->will($this->returnValue($backendModel));
  189. $this->transFactoryMock->expects($this->never())->method('addObject');
  190. $backendModel->expects($this->never())->method('addData');
  191. $this->model->save();
  192. }
  193. public function testSaveToCheckScopeDataSet()
  194. {
  195. $transactionMock = $this->createMock(\Magento\Framework\DB\Transaction::class);
  196. $this->transFactoryMock->expects($this->any())->method('create')->will($this->returnValue($transactionMock));
  197. $this->configLoaderMock->expects($this->any())->method('getConfigByPath')->will($this->returnValue([]));
  198. $this->eventManagerMock->expects($this->at(0))
  199. ->method('dispatch')
  200. ->with(
  201. $this->equalTo('admin_system_config_changed_section_section'),
  202. $this->arrayHasKey('website')
  203. );
  204. $this->eventManagerMock->expects($this->at(0))
  205. ->method('dispatch')
  206. ->with(
  207. $this->equalTo('admin_system_config_changed_section_section'),
  208. $this->arrayHasKey('store')
  209. );
  210. $group = $this->createMock(\Magento\Config\Model\Config\Structure\Element\Group::class);
  211. $group->method('getPath')->willReturn('section/1');
  212. $field = $this->createMock(\Magento\Config\Model\Config\Structure\Element\Field::class);
  213. $field->method('getGroupPath')->willReturn('section/1');
  214. $field->method('getId')->willReturn('key');
  215. $this->configStructure->expects($this->at(0))
  216. ->method('getElement')
  217. ->with('section/1')
  218. ->will($this->returnValue($group));
  219. $this->configStructure->expects($this->at(1))
  220. ->method('getElement')
  221. ->with('section/1')
  222. ->will($this->returnValue($group));
  223. $this->configStructure->expects($this->at(2))
  224. ->method('getElement')
  225. ->with('section/1/key')
  226. ->will($this->returnValue($field));
  227. $this->configStructure->expects($this->at(3))
  228. ->method('getElement')
  229. ->with('section/1')
  230. ->will($this->returnValue($group));
  231. $this->configStructure->expects($this->at(4))
  232. ->method('getElement')
  233. ->with('section/1/key')
  234. ->will($this->returnValue($field));
  235. $this->scopeResolver->expects($this->atLeastOnce())
  236. ->method('getScope')
  237. ->with('1')
  238. ->willReturn($this->scope);
  239. $this->scope->expects($this->atLeastOnce())
  240. ->method('getScopeType')
  241. ->willReturn('website');
  242. $this->scope->expects($this->atLeastOnce())
  243. ->method('getId')
  244. ->willReturn(1);
  245. $this->scope->expects($this->atLeastOnce())
  246. ->method('getCode')
  247. ->willReturn('website_code');
  248. $this->scopeTypeNormalizer->expects($this->atLeastOnce())
  249. ->method('normalize')
  250. ->with('website')
  251. ->willReturn('websites');
  252. $website = $this->createMock(\Magento\Store\Model\Website::class);
  253. $this->storeManager->expects($this->any())->method('getWebsites')->will($this->returnValue([$website]));
  254. $this->storeManager->expects($this->any())->method('isSingleStoreMode')->will($this->returnValue(true));
  255. $this->model->setWebsite('1');
  256. $this->model->setSection('section');
  257. $this->model->setGroups(['1' => ['fields' => ['key' => ['data']]]]);
  258. $backendModel = $this->createPartialMock(
  259. \Magento\Framework\App\Config\Value::class,
  260. ['setPath', 'addData', '__sleep', '__wakeup']
  261. );
  262. $backendModel->expects($this->once())
  263. ->method('addData')
  264. ->with([
  265. 'field' => 'key',
  266. 'groups' => [1 => ['fields' => ['key' => ['data']]]],
  267. 'group_id' => null,
  268. 'scope' => 'websites',
  269. 'scope_id' => 1,
  270. 'scope_code' => 'website_code',
  271. 'field_config' => null,
  272. 'fieldset_data' => ['key' => null],
  273. ]);
  274. $backendModel->expects($this->once())
  275. ->method('setPath')
  276. ->with('section/1/key')
  277. ->will($this->returnValue($backendModel));
  278. $this->dataFactoryMock->expects($this->any())->method('create')->will($this->returnValue($backendModel));
  279. $this->model->save();
  280. }
  281. /**
  282. * @param string $path
  283. * @param string $value
  284. * @param string $section
  285. * @param array $groups
  286. * @dataProvider setDataByPathDataProvider
  287. */
  288. public function testSetDataByPath(string $path, string $value, string $section, array $groups)
  289. {
  290. $this->model->setDataByPath($path, $value);
  291. $this->assertEquals($section, $this->model->getData('section'));
  292. $this->assertEquals($groups, $this->model->getData('groups'));
  293. }
  294. /**
  295. * @return array
  296. */
  297. public function setDataByPathDataProvider(): array
  298. {
  299. return [
  300. 'depth 3' => [
  301. 'a/b/c',
  302. 'value1',
  303. 'a',
  304. [
  305. 'b' => [
  306. 'fields' => [
  307. 'c' => ['value' => 'value1'],
  308. ],
  309. ],
  310. ],
  311. ],
  312. 'depth 5' => [
  313. 'a/b/c/d/e',
  314. 'value1',
  315. 'a',
  316. [
  317. 'b' => [
  318. 'groups' => [
  319. 'c' => [
  320. 'groups' => [
  321. 'd' => [
  322. 'fields' => [
  323. 'e' => ['value' => 'value1'],
  324. ],
  325. ],
  326. ],
  327. ],
  328. ],
  329. ],
  330. ],
  331. ],
  332. ];
  333. }
  334. /**
  335. * @expectedException \UnexpectedValueException
  336. * @expectedExceptionMessage Path must not be empty
  337. */
  338. public function testSetDataByPathEmpty()
  339. {
  340. $this->model->setDataByPath('', 'value');
  341. }
  342. /**
  343. * @param string $path
  344. * @dataProvider setDataByPathWrongDepthDataProvider
  345. */
  346. public function testSetDataByPathWrongDepth(string $path)
  347. {
  348. $currentDepth = count(explode('/', $path));
  349. $expectedException = 'Minimal depth of configuration is 3. Your configuration depth is ' . $currentDepth;
  350. $this->expectException(\UnexpectedValueException::class);
  351. $this->expectExceptionMessage($expectedException);
  352. $value = 'value';
  353. $this->model->setDataByPath($path, $value);
  354. }
  355. /**
  356. * @return array
  357. */
  358. public function setDataByPathWrongDepthDataProvider(): array
  359. {
  360. return [
  361. 'depth 2' => ['section/group'],
  362. 'depth 1' => ['section'],
  363. ];
  364. }
  365. }