CopyServiceTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Theme\Test\Unit\Model;
  7. use Magento\Framework\App\Filesystem\DirectoryList;
  8. /**
  9. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  10. */
  11. class CopyServiceTest extends \PHPUnit\Framework\TestCase
  12. {
  13. /**#@+
  14. * @var \Magento\Theme\Model\CopyService
  15. */
  16. protected $object;
  17. /**
  18. * @var \PHPUnit_Framework_MockObject_MockObject
  19. */
  20. protected $fileFactory;
  21. /**
  22. * @var \PHPUnit_Framework_MockObject_MockObject
  23. */
  24. protected $filesystem;
  25. /**
  26. * @var \PHPUnit_Framework_MockObject_MockObject
  27. */
  28. protected $sourceTheme;
  29. /**
  30. * @var \PHPUnit_Framework_MockObject_MockObject
  31. */
  32. protected $targetTheme;
  33. /**
  34. * @var \PHPUnit_Framework_MockObject_MockObject
  35. */
  36. protected $link;
  37. /**
  38. * @var \PHPUnit_Framework_MockObject_MockObject
  39. */
  40. protected $linkCollection;
  41. /**
  42. * @var \PHPUnit_Framework_MockObject_MockObject
  43. */
  44. protected $update;
  45. /**
  46. * @var \PHPUnit_Framework_MockObject_MockObject
  47. */
  48. protected $updateCollection;
  49. /**
  50. * @var \PHPUnit_Framework_MockObject_MockObject
  51. */
  52. protected $updateFactory;
  53. /**
  54. * @var \PHPUnit_Framework_MockObject_MockObject
  55. */
  56. protected $customizationPath;
  57. /**
  58. * @var \PHPUnit_Framework_MockObject_MockObject[]
  59. */
  60. protected $targetFiles = [];
  61. /**
  62. * @var \PHPUnit_Framework_MockObject_MockObject[]
  63. */
  64. protected $sourceFiles = [];
  65. /**
  66. * @var \PHPUnit_Framework_MockObject_MockObject
  67. */
  68. protected $dirWriteMock;
  69. /**
  70. * @return void
  71. * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
  72. */
  73. protected function setUp()
  74. {
  75. $sourceFileOne = $this->createPartialMock(\Magento\Theme\Model\Theme\File::class, ['__wakeup', 'delete']);
  76. $sourceFileOne->setData(
  77. [
  78. 'file_path' => 'fixture_file_path_one',
  79. 'file_type' => 'fixture_file_type_one',
  80. 'content' => 'fixture_content_one',
  81. 'sort_order' => 10,
  82. ]
  83. );
  84. $sourceFileTwo = $this->createPartialMock(\Magento\Theme\Model\Theme\File::class, ['__wakeup', 'delete']);
  85. $sourceFileTwo->setData(
  86. [
  87. 'file_path' => 'fixture_file_path_two',
  88. 'file_type' => 'fixture_file_type_two',
  89. 'content' => 'fixture_content_two',
  90. 'sort_order' => 20,
  91. ]
  92. );
  93. $this->sourceFiles = [$sourceFileOne, $sourceFileTwo];
  94. $this->sourceTheme = $this->createPartialMock(
  95. \Magento\Theme\Model\Theme::class,
  96. ['__wakeup', 'getCustomization']
  97. );
  98. $this->targetFiles = [
  99. $this->createPartialMock(\Magento\Theme\Model\Theme\File::class, ['__wakeup', 'delete']),
  100. $this->createPartialMock(\Magento\Theme\Model\Theme\File::class, ['__wakeup', 'delete']),
  101. ];
  102. $this->targetTheme = $this->createPartialMock(
  103. \Magento\Theme\Model\Theme::class,
  104. ['__wakeup', 'getCustomization']
  105. );
  106. $this->targetTheme->setId(123);
  107. $this->customizationPath = $this->createMock(\Magento\Framework\View\Design\Theme\Customization\Path::class);
  108. $this->fileFactory = $this->createPartialMock(
  109. \Magento\Framework\View\Design\Theme\FileFactory::class,
  110. ['create']
  111. );
  112. $this->filesystem =
  113. $this->createPartialMock(\Magento\Framework\Filesystem::class, ['getDirectoryWrite']);
  114. $this->dirWriteMock = $this->createPartialMock(
  115. \Magento\Framework\Filesystem\Directory\Write::class,
  116. ['isDirectory', 'search', 'copy', 'delete', 'read', 'copyFile', 'isExist']
  117. );
  118. $this->filesystem->expects(
  119. $this->any()
  120. )->method(
  121. 'getDirectoryWrite'
  122. )->with(
  123. DirectoryList::MEDIA
  124. )->will(
  125. $this->returnValue($this->dirWriteMock)
  126. );
  127. /* Init \Magento\Widget\Model\ResourceModel\Layout\Update\Collection model */
  128. $this->updateFactory = $this->createPartialMock(\Magento\Widget\Model\Layout\UpdateFactory::class, ['create']);
  129. $this->update = $this->createPartialMock(
  130. \Magento\Widget\Model\Layout\Update::class,
  131. ['__wakeup', 'getCollection']
  132. );
  133. $this->updateFactory->expects($this->at(0))->method('create')->will($this->returnValue($this->update));
  134. $this->updateCollection = $this->createPartialMock(
  135. \Magento\Widget\Model\ResourceModel\Layout\Update\Collection::class,
  136. ['addThemeFilter', 'delete', 'getIterator']
  137. );
  138. $this->update->expects(
  139. $this->any()
  140. )->method(
  141. 'getCollection'
  142. )->will(
  143. $this->returnValue($this->updateCollection)
  144. );
  145. /* Init Link an Link_Collection model */
  146. $this->link = $this->createPartialMock(\Magento\Widget\Model\Layout\Link::class, ['__wakeup', 'getCollection']);
  147. $this->linkCollection = $this->createPartialMock(
  148. \Magento\Widget\Model\ResourceModel\Layout\Link\Collection::class,
  149. ['addThemeFilter', 'getIterator', 'addFieldToFilter']
  150. );
  151. $this->link->expects($this->any())->method('getCollection')->will($this->returnValue($this->linkCollection));
  152. $eventManager = $this->createPartialMock(\Magento\Framework\Event\ManagerInterface::class, ['dispatch']);
  153. $this->object = new \Magento\Theme\Model\CopyService(
  154. $this->filesystem,
  155. $this->fileFactory,
  156. $this->link,
  157. $this->updateFactory,
  158. $eventManager,
  159. $this->customizationPath
  160. );
  161. }
  162. protected function tearDown()
  163. {
  164. $this->object = null;
  165. $this->filesystem = null;
  166. $this->fileFactory = null;
  167. $this->sourceTheme = null;
  168. $this->targetTheme = null;
  169. $this->link = null;
  170. $this->linkCollection = null;
  171. $this->updateCollection = null;
  172. $this->updateFactory = null;
  173. $this->sourceFiles = [];
  174. $this->targetFiles = [];
  175. }
  176. /**
  177. * cover \Magento\Theme\Model\CopyService::_copyLayoutCustomization
  178. */
  179. public function testCopyLayoutUpdates()
  180. {
  181. $customization = $this->createPartialMock(
  182. \Magento\Framework\View\Design\Theme\Customization::class,
  183. ['getFiles']
  184. );
  185. $customization->expects($this->atLeastOnce())->method('getFiles')->will($this->returnValue([]));
  186. $this->sourceTheme->expects(
  187. $this->once()
  188. )->method(
  189. 'getCustomization'
  190. )->will(
  191. $this->returnValue($customization)
  192. );
  193. $this->targetTheme->expects(
  194. $this->once()
  195. )->method(
  196. 'getCustomization'
  197. )->will(
  198. $this->returnValue($customization)
  199. );
  200. $this->updateCollection->expects($this->once())->method('delete');
  201. $this->linkCollection->expects($this->once())->method('addThemeFilter');
  202. $targetLinkOne = $this->createPartialMock(
  203. \Magento\Widget\Model\Layout\Link::class,
  204. ['__wakeup', 'setId', 'setThemeId', 'save', 'setLayoutUpdateId']
  205. );
  206. $targetLinkOne->setData(['id' => 1, 'layout_update_id' => 1]);
  207. $targetLinkTwo = $this->createPartialMock(
  208. \Magento\Widget\Model\Layout\Link::class,
  209. ['__wakeup', 'setId', 'setThemeId', 'save', 'setLayoutUpdateId']
  210. );
  211. $targetLinkTwo->setData(['id' => 2, 'layout_update_id' => 2]);
  212. $targetLinkOne->expects($this->at(0))->method('setThemeId')->with(123);
  213. $targetLinkOne->expects($this->at(1))->method('setLayoutUpdateId')->with(1);
  214. $targetLinkOne->expects($this->at(2))->method('setId')->with(null);
  215. $targetLinkOne->expects($this->at(3))->method('save');
  216. $targetLinkTwo->expects($this->at(0))->method('setThemeId')->with(123);
  217. $targetLinkTwo->expects($this->at(1))->method('setLayoutUpdateId')->with(2);
  218. $targetLinkTwo->expects($this->at(2))->method('setId')->with(null);
  219. $targetLinkTwo->expects($this->at(3))->method('save');
  220. $linkReturnValues = $this->onConsecutiveCalls(new \ArrayIterator([$targetLinkOne, $targetLinkTwo]));
  221. $this->linkCollection->expects($this->any())->method('getIterator')->will($linkReturnValues);
  222. $targetUpdateOne = $this->createPartialMock(
  223. \Magento\Widget\Model\Layout\Update::class,
  224. ['__wakeup', 'setId', 'load', 'save']
  225. );
  226. $targetUpdateOne->setData(['id' => 1]);
  227. $targetUpdateTwo = $this->createPartialMock(
  228. \Magento\Widget\Model\Layout\Update::class,
  229. ['__wakeup', 'setId', 'load', 'save']
  230. );
  231. $targetUpdateTwo->setData(['id' => 2]);
  232. $updateReturnValues = $this->onConsecutiveCalls($this->update, $targetUpdateOne, $targetUpdateTwo);
  233. $this->updateFactory->expects($this->any())->method('create')->will($updateReturnValues);
  234. $this->object->copy($this->sourceTheme, $this->targetTheme);
  235. }
  236. /**
  237. * cover \Magento\Theme\Model\CopyService::_copyDatabaseCustomization
  238. * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
  239. */
  240. public function testCopyDatabaseCustomization()
  241. {
  242. $sourceCustom = $this->createPartialMock(
  243. \Magento\Framework\View\Design\Theme\Customization::class,
  244. ['getFiles']
  245. );
  246. $sourceCustom->expects(
  247. $this->atLeastOnce()
  248. )->method(
  249. 'getFiles'
  250. )->will(
  251. $this->returnValue($this->sourceFiles)
  252. );
  253. $this->sourceTheme->expects(
  254. $this->once()
  255. )->method(
  256. 'getCustomization'
  257. )->will(
  258. $this->returnValue($sourceCustom)
  259. );
  260. $targetCustom = $this->createPartialMock(
  261. \Magento\Framework\View\Design\Theme\Customization::class,
  262. ['getFiles']
  263. );
  264. $targetCustom->expects(
  265. $this->atLeastOnce()
  266. )->method(
  267. 'getFiles'
  268. )->will(
  269. $this->returnValue($this->targetFiles)
  270. );
  271. $this->targetTheme->expects(
  272. $this->once()
  273. )->method(
  274. 'getCustomization'
  275. )->will(
  276. $this->returnValue($targetCustom)
  277. );
  278. $this->linkCollection->expects(
  279. $this->any()
  280. )->method(
  281. 'addFieldToFilter'
  282. )->will(
  283. $this->returnValue($this->linkCollection)
  284. );
  285. $this->linkCollection->expects(
  286. $this->any()
  287. )->method(
  288. 'getIterator'
  289. )->will(
  290. $this->returnValue(new \ArrayIterator([]))
  291. );
  292. foreach ($this->targetFiles as $targetFile) {
  293. $targetFile->expects($this->once())->method('delete');
  294. }
  295. $newFileOne = $this->createPartialMock(\Magento\Theme\Model\Theme\File::class, ['__wakeup', 'setData', 'save']);
  296. $newFileTwo = $this->createPartialMock(\Magento\Theme\Model\Theme\File::class, ['__wakeup', 'setData', 'save']);
  297. $newFileOne->expects(
  298. $this->at(0)
  299. )->method(
  300. 'setData'
  301. )->with(
  302. [
  303. 'theme_id' => 123,
  304. 'file_path' => 'fixture_file_path_one',
  305. 'file_type' => 'fixture_file_type_one',
  306. 'content' => 'fixture_content_one',
  307. 'sort_order' => 10,
  308. ]
  309. );
  310. $newFileOne->expects($this->at(1))->method('save');
  311. $newFileTwo->expects(
  312. $this->at(0)
  313. )->method(
  314. 'setData'
  315. )->with(
  316. [
  317. 'theme_id' => 123,
  318. 'file_path' => 'fixture_file_path_two',
  319. 'file_type' => 'fixture_file_type_two',
  320. 'content' => 'fixture_content_two',
  321. 'sort_order' => 20,
  322. ]
  323. );
  324. $newFileTwo->expects($this->at(1))->method('save');
  325. $this->fileFactory->expects(
  326. $this->any()
  327. )->method(
  328. 'create'
  329. )->with(
  330. []
  331. )->will(
  332. $this->onConsecutiveCalls($newFileOne, $newFileTwo)
  333. );
  334. $this->object->copy($this->sourceTheme, $this->targetTheme);
  335. }
  336. /**
  337. * cover \Magento\Theme\Model\CopyService::_copyFilesystemCustomization
  338. *
  339. * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
  340. */
  341. public function testCopyFilesystemCustomization()
  342. {
  343. $customization = $this->createPartialMock(
  344. \Magento\Framework\View\Design\Theme\Customization::class,
  345. ['getFiles']
  346. );
  347. $customization->expects($this->atLeastOnce())->method('getFiles')->will($this->returnValue([]));
  348. $this->sourceTheme->expects(
  349. $this->once()
  350. )->method(
  351. 'getCustomization'
  352. )->will(
  353. $this->returnValue($customization)
  354. );
  355. $this->targetTheme->expects(
  356. $this->once()
  357. )->method(
  358. 'getCustomization'
  359. )->will(
  360. $this->returnValue($customization)
  361. );
  362. $this->linkCollection->expects(
  363. $this->any()
  364. )->method(
  365. 'addFieldToFilter'
  366. )->will(
  367. $this->returnValue($this->linkCollection)
  368. );
  369. $this->linkCollection->expects(
  370. $this->any()
  371. )->method(
  372. 'getIterator'
  373. )->will(
  374. $this->returnValue(new \ArrayIterator([]))
  375. );
  376. $this->customizationPath->expects(
  377. $this->at(0)
  378. )->method(
  379. 'getCustomizationPath'
  380. )->will(
  381. $this->returnValue('source/path')
  382. );
  383. $this->customizationPath->expects(
  384. $this->at(1)
  385. )->method(
  386. 'getCustomizationPath'
  387. )->will(
  388. $this->returnValue('target/path')
  389. );
  390. $this->dirWriteMock->expects(
  391. $this->any()
  392. )->method(
  393. 'isDirectory'
  394. )->will(
  395. $this->returnValueMap([['source/path', true], ['source/path/subdir', true]])
  396. );
  397. $this->dirWriteMock->expects(
  398. $this->any()
  399. )->method(
  400. 'isExist'
  401. )->will(
  402. $this->returnValueMap(
  403. [
  404. ['target/path', true]
  405. ]
  406. )
  407. );
  408. $this->dirWriteMock->expects(
  409. $this->any()
  410. )->method(
  411. 'read'
  412. )->will(
  413. $this->returnValueMap(
  414. [
  415. ['target/path', ['target/path/subdir']],
  416. ['source/path', ['source/path/subdir']],
  417. ['source/path/subdir', ['source/path/subdir/file_one.jpg', 'source/path/subdir/file_two.png']],
  418. ]
  419. )
  420. );
  421. $expectedCopyEvents = [
  422. ['source/path/subdir/file_one.jpg', 'target/path/subdir/file_one.jpg', null],
  423. ['source/path/subdir/file_two.png', 'target/path/subdir/file_two.png', null],
  424. ];
  425. $actualCopyEvents = [];
  426. $recordCopyEvent = function () use (&$actualCopyEvents) {
  427. $actualCopyEvents[] = func_get_args();
  428. };
  429. $this->dirWriteMock->expects($this->any())->method('copyFile')->will($this->returnCallback($recordCopyEvent));
  430. $this->object->copy($this->sourceTheme, $this->targetTheme);
  431. $this->assertEquals($expectedCopyEvents, $actualCopyEvents);
  432. }
  433. }