/vendor/magento/module-catalog-search/Test/Unit/Model/Search/TableMapperTest.php

https://gitlab.com/yousafsyed/easternglamor · PHP · 594 lines · 486 code · 33 blank · 75 comment · 0 complexity · 6fb74a8c245901a67746929b4dd3eb2f MD5 · raw file

  1. <?php
  2. /**
  3. * Copyright © 2016 Magento. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\CatalogSearch\Test\Unit\Model\Search;
  7. use Magento\Framework\Search\Request\FilterInterface;
  8. use Magento\Framework\Search\Request\QueryInterface;
  9. use \Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
  10. /**
  11. * Test for \Magento\CatalogSearch\Model\Search\TableMapper
  12. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  13. */
  14. class TableMapperTest extends \PHPUnit_Framework_TestCase
  15. {
  16. const WEBSITE_ID = 4512;
  17. const STORE_ID = 2514;
  18. /**
  19. * @var \Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection|\PHPUnit_Framework_MockObject_MockObject
  20. */
  21. private $attributeCollection;
  22. /**
  23. * @var \Magento\Store\Api\Data\WebsiteInterface|\PHPUnit_Framework_MockObject_MockObject
  24. */
  25. private $website;
  26. /**
  27. * @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject
  28. */
  29. private $connection;
  30. /**
  31. * @var \Magento\Framework\Search\RequestInterface|\PHPUnit_Framework_MockObject_MockObject
  32. */
  33. private $request;
  34. /**
  35. * @var \Magento\Framework\DB\Select|\PHPUnit_Framework_MockObject_MockObject
  36. */
  37. private $select;
  38. /**
  39. * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject
  40. */
  41. private $storeManager;
  42. /**
  43. * @var \Magento\Framework\App\ResourceConnection|\PHPUnit_Framework_MockObject_MockObject
  44. */
  45. private $resource;
  46. /**
  47. * @var \Magento\Store\Api\Data\StoreInterface|\PHPUnit_Framework_MockObject_MockObject
  48. */
  49. private $store;
  50. /**
  51. * @var \Magento\CatalogSearch\Model\Search\TableMapper
  52. */
  53. private $target;
  54. protected function setUp()
  55. {
  56. $objectManager = new ObjectManager($this);
  57. $this->connection = $this->getMockBuilder('\Magento\Framework\DB\Adapter\AdapterInterface')
  58. ->disableOriginalConstructor()
  59. ->getMock();
  60. $this->connection->expects($this->any())
  61. ->method('quoteInto')
  62. ->willReturnCallback(
  63. function ($query, $expression) {
  64. return str_replace('?', $expression, $query);
  65. }
  66. );
  67. $this->resource = $this->getMockBuilder('\Magento\Framework\App\ResourceConnection')
  68. ->disableOriginalConstructor()
  69. ->getMock();
  70. $this->resource->method('getTableName')
  71. ->willReturnCallback(
  72. function ($table) {
  73. return 'prefix_' . $table;
  74. }
  75. );
  76. $this->resource->expects($this->any())
  77. ->method('getConnection')
  78. ->willReturn($this->connection);
  79. $this->website = $this->getMockBuilder('\Magento\Store\Api\Data\WebsiteInterface')
  80. ->disableOriginalConstructor()
  81. ->getMockForAbstractClass();
  82. $this->website->expects($this->any())
  83. ->method('getId')
  84. ->willReturn(self::WEBSITE_ID);
  85. $this->store = $this->getMockBuilder('\Magento\Store\Api\Data\StoreInterface')
  86. ->disableOriginalConstructor()
  87. ->getMockForAbstractClass();
  88. $this->store->expects($this->any())
  89. ->method('getId')
  90. ->willReturn(self::STORE_ID);
  91. $this->storeManager = $this->getMockBuilder('\Magento\Store\Model\StoreManagerInterface')
  92. ->disableOriginalConstructor()
  93. ->getMock();
  94. $this->storeManager->expects($this->any())
  95. ->method('getWebsite')
  96. ->willReturn($this->website);
  97. $this->storeManager->expects($this->any())
  98. ->method('getStore')
  99. ->willReturn($this->store);
  100. $this->attributeCollection = $this->getMockBuilder(
  101. '\Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection'
  102. )
  103. ->disableOriginalConstructor()
  104. ->getMock();
  105. $attributeCollectionFactory = $this->getMockBuilder(
  106. '\Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory'
  107. )
  108. ->setMethods(['create'])
  109. ->disableOriginalConstructor()
  110. ->getMock();
  111. $attributeCollectionFactory->expects($this->once())
  112. ->method('create')
  113. ->willReturn($this->attributeCollection);
  114. $this->target = $objectManager->getObject(
  115. '\Magento\CatalogSearch\Model\Search\TableMapper',
  116. [
  117. 'resource' => $this->resource,
  118. 'storeManager' => $this->storeManager,
  119. 'attributeCollectionFactory' => $attributeCollectionFactory
  120. ]
  121. );
  122. $this->select = $this->getMockBuilder('\Magento\Framework\DB\Select')
  123. ->disableOriginalConstructor()
  124. ->getMock();
  125. $this->request = $this->getMockBuilder('\Magento\Framework\Search\RequestInterface')
  126. ->disableOriginalConstructor()
  127. ->getMock();
  128. }
  129. public function testAddPriceFilter()
  130. {
  131. $priceFilter = $this->createRangeFilter('price');
  132. $query = $this->createFilterQuery($priceFilter);
  133. $this->request->expects($this->once())
  134. ->method('getQuery')
  135. ->willReturn($query);
  136. $this->select->expects($this->once())
  137. ->method('joinLeft')
  138. ->with(
  139. ['price_index' => 'prefix_catalog_product_index_price'],
  140. 'search_index.entity_id = price_index.entity_id AND price_index.website_id = ' . self::WEBSITE_ID,
  141. []
  142. )
  143. ->willReturnSelf();
  144. $select = $this->target->addTables($this->select, $this->request);
  145. $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
  146. }
  147. public function testAddStaticAttributeFilter()
  148. {
  149. $priceFilter = $this->createRangeFilter('static');
  150. $query = $this->createFilterQuery($priceFilter);
  151. $this->createAttributeMock('static', 'static', 'backend_table', 0, 'select');
  152. $this->request->expects($this->once())
  153. ->method('getQuery')
  154. ->willReturn($query);
  155. $this->select->expects($this->once())
  156. ->method('joinLeft')
  157. ->with(
  158. ['static_filter' => 'backend_table'],
  159. 'search_index.entity_id = static_filter.entity_id',
  160. null
  161. )
  162. ->willReturnSelf();
  163. $select = $this->target->addTables($this->select, $this->request);
  164. $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
  165. }
  166. public function testAddCategoryIds()
  167. {
  168. $categoryIdsFilter = $this->createTermFilter('category_ids');
  169. $query = $this->createFilterQuery($categoryIdsFilter);
  170. $this->request->expects($this->once())
  171. ->method('getQuery')
  172. ->willReturn($query);
  173. $this->select->expects($this->once())
  174. ->method('joinLeft')
  175. ->with(
  176. ['category_ids_index' => 'prefix_catalog_category_product_index'],
  177. 'search_index.entity_id = category_ids_index.product_id',
  178. []
  179. )
  180. ->willReturnSelf();
  181. $select = $this->target->addTables($this->select, $this->request);
  182. $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
  183. }
  184. public function testAddTermFilter()
  185. {
  186. $this->createAttributeMock('color', null, null, 132, 'select', 0);
  187. $categoryIdsFilter = $this->createTermFilter('color');
  188. $query = $this->createFilterQuery($categoryIdsFilter);
  189. $this->request->expects($this->once())
  190. ->method('getQuery')
  191. ->willReturn($query);
  192. $this->select->expects($this->once())
  193. ->method('joinLeft')
  194. ->with(
  195. ['color_filter' => 'prefix_catalog_product_index_eav'],
  196. 'search_index.entity_id = color_filter.entity_id'
  197. . ' AND color_filter.attribute_id = 132'
  198. . ' AND color_filter.store_id = 2514',
  199. []
  200. )
  201. ->willReturnSelf();
  202. $select = $this->target->addTables($this->select, $this->request);
  203. $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
  204. }
  205. public function testAddBoolQueryWithTermFiltersInside()
  206. {
  207. $this->createAttributeMock('must1', null, null, 101, 'select', 0);
  208. $this->createAttributeMock('should1', null, null, 102, 'select', 1);
  209. $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2);
  210. $query = $this->createBoolQuery(
  211. [
  212. $this->createFilterQuery($this->createTermFilter('must1')),
  213. ],
  214. [
  215. $this->createFilterQuery($this->createTermFilter('should1')),
  216. ],
  217. [
  218. $this->createFilterQuery($this->createTermFilter('mustNot1')),
  219. ]
  220. );
  221. $this->request->expects($this->once())
  222. ->method('getQuery')
  223. ->willReturn($query);
  224. $this->select->expects($this->at(0))
  225. ->method('joinLeft')
  226. ->with(
  227. ['must1_filter' => 'prefix_catalog_product_index_eav'],
  228. 'search_index.entity_id = must1_filter.entity_id'
  229. . ' AND must1_filter.attribute_id = 101'
  230. . ' AND must1_filter.store_id = 2514',
  231. []
  232. )
  233. ->willReturnSelf();
  234. $this->select->expects($this->at(1))
  235. ->method('joinLeft')
  236. ->with(
  237. ['should1_filter' => 'prefix_catalog_product_index_eav'],
  238. 'search_index.entity_id = should1_filter.entity_id'
  239. . ' AND should1_filter.attribute_id = 102'
  240. . ' AND should1_filter.store_id = 2514',
  241. []
  242. )
  243. ->willReturnSelf();
  244. $this->select->expects($this->at(2))
  245. ->method('joinLeft')
  246. ->with(
  247. ['mustNot1_filter' => 'prefix_catalog_product_index_eav'],
  248. 'search_index.entity_id = mustNot1_filter.entity_id'
  249. . ' AND mustNot1_filter.attribute_id = 103'
  250. . ' AND mustNot1_filter.store_id = 2514',
  251. []
  252. )
  253. ->willReturnSelf();
  254. $select = $this->target->addTables($this->select, $this->request);
  255. $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
  256. }
  257. public function testAddBoolQueryWithTermAndPriceFiltersInside()
  258. {
  259. $this->createAttributeMock('must1', null, null, 101, 'select', 0);
  260. $this->createAttributeMock('should1', null, null, 102, 'select', 1);
  261. $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2);
  262. $query = $this->createBoolQuery(
  263. [
  264. $this->createFilterQuery($this->createTermFilter('must1')),
  265. $this->createFilterQuery($this->createRangeFilter('price')),
  266. ],
  267. [
  268. $this->createFilterQuery($this->createTermFilter('should1')),
  269. ],
  270. [
  271. $this->createFilterQuery($this->createTermFilter('mustNot1')),
  272. ]
  273. );
  274. $this->request->expects($this->once())
  275. ->method('getQuery')
  276. ->willReturn($query);
  277. $this->select->expects($this->at(0))
  278. ->method('joinLeft')
  279. ->with(
  280. ['must1_filter' => 'prefix_catalog_product_index_eav'],
  281. 'search_index.entity_id = must1_filter.entity_id'
  282. . ' AND must1_filter.attribute_id = 101'
  283. . ' AND must1_filter.store_id = 2514',
  284. []
  285. )
  286. ->willReturnSelf();
  287. $this->select->expects($this->at(1))
  288. ->method('joinLeft')
  289. ->with(
  290. ['price_index' => 'prefix_catalog_product_index_price'],
  291. 'search_index.entity_id = price_index.entity_id AND price_index.website_id = ' . self::WEBSITE_ID,
  292. []
  293. )
  294. ->willReturnSelf();
  295. $this->select->expects($this->at(2))
  296. ->method('joinLeft')
  297. ->with(
  298. ['should1_filter' => 'prefix_catalog_product_index_eav'],
  299. 'search_index.entity_id = should1_filter.entity_id'
  300. . ' AND should1_filter.attribute_id = 102'
  301. . ' AND should1_filter.store_id = 2514',
  302. []
  303. )
  304. ->willReturnSelf();
  305. $this->select->expects($this->at(3))
  306. ->method('joinLeft')
  307. ->with(
  308. ['mustNot1_filter' => 'prefix_catalog_product_index_eav'],
  309. 'search_index.entity_id = mustNot1_filter.entity_id'
  310. . ' AND mustNot1_filter.attribute_id = 103'
  311. . ' AND mustNot1_filter.store_id = 2514',
  312. []
  313. )
  314. ->willReturnSelf();
  315. $select = $this->target->addTables($this->select, $this->request);
  316. $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
  317. }
  318. public function testAddBoolFilterWithTermFiltersInside()
  319. {
  320. $this->createAttributeMock('must1', null, null, 101, 'select', 0);
  321. $this->createAttributeMock('should1', null, null, 102, 'select', 1);
  322. $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2);
  323. $query = $this->createFilterQuery(
  324. $this->createBoolFilter(
  325. [
  326. $this->createTermFilter('must1'),
  327. ],
  328. [
  329. $this->createTermFilter('should1'),
  330. ],
  331. [
  332. $this->createTermFilter('mustNot1'),
  333. ]
  334. )
  335. );
  336. $this->request->expects($this->once())
  337. ->method('getQuery')
  338. ->willReturn($query);
  339. $this->select->expects($this->at(0))
  340. ->method('joinLeft')
  341. ->with(
  342. ['must1_filter' => 'prefix_catalog_product_index_eav'],
  343. 'search_index.entity_id = must1_filter.entity_id'
  344. . ' AND must1_filter.attribute_id = 101'
  345. . ' AND must1_filter.store_id = 2514',
  346. []
  347. )
  348. ->willReturnSelf();
  349. $this->select->expects($this->at(1))
  350. ->method('joinLeft')
  351. ->with(
  352. ['should1_filter' => 'prefix_catalog_product_index_eav'],
  353. 'search_index.entity_id = should1_filter.entity_id'
  354. . ' AND should1_filter.attribute_id = 102'
  355. . ' AND should1_filter.store_id = 2514',
  356. []
  357. )
  358. ->willReturnSelf();
  359. $this->select->expects($this->at(2))
  360. ->method('joinLeft')
  361. ->with(
  362. ['mustNot1_filter' => 'prefix_catalog_product_index_eav'],
  363. 'search_index.entity_id = mustNot1_filter.entity_id'
  364. . ' AND mustNot1_filter.attribute_id = 103'
  365. . ' AND mustNot1_filter.store_id = 2514',
  366. []
  367. )
  368. ->willReturnSelf();
  369. $select = $this->target->addTables($this->select, $this->request);
  370. $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
  371. }
  372. public function testAddBoolFilterWithBoolFiltersInside()
  373. {
  374. $this->createAttributeMock('must1', null, null, 101, 'select', 0);
  375. $this->createAttributeMock('should1', null, null, 102, 'select', 1);
  376. $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2);
  377. $query = $this->createFilterQuery(
  378. $this->createBoolFilter(
  379. [
  380. $this->createBoolFilter([$this->createTermFilter('must1')], [], []),
  381. ],
  382. [
  383. $this->createBoolFilter([$this->createTermFilter('should1')], [], []),
  384. ],
  385. [
  386. $this->createBoolFilter([$this->createTermFilter('mustNot1')], [], []),
  387. ]
  388. )
  389. );
  390. $this->request->expects($this->once())
  391. ->method('getQuery')
  392. ->willReturn($query);
  393. $this->select->expects($this->at(0))
  394. ->method('joinLeft')
  395. ->with(
  396. ['must1_filter' => 'prefix_catalog_product_index_eav'],
  397. 'search_index.entity_id = must1_filter.entity_id'
  398. . ' AND must1_filter.attribute_id = 101'
  399. . ' AND must1_filter.store_id = 2514',
  400. []
  401. )
  402. ->willReturnSelf();
  403. $this->select->expects($this->at(1))
  404. ->method('joinLeft')
  405. ->with(
  406. ['should1_filter' => 'prefix_catalog_product_index_eav'],
  407. 'search_index.entity_id = should1_filter.entity_id'
  408. . ' AND should1_filter.attribute_id = 102'
  409. . ' AND should1_filter.store_id = 2514',
  410. []
  411. )
  412. ->willReturnSelf();
  413. $this->select->expects($this->at(2))
  414. ->method('joinLeft')
  415. ->with(
  416. ['mustNot1_filter' => 'prefix_catalog_product_index_eav'],
  417. 'search_index.entity_id = mustNot1_filter.entity_id'
  418. . ' AND mustNot1_filter.attribute_id = 103'
  419. . ' AND mustNot1_filter.store_id = 2514',
  420. []
  421. )
  422. ->willReturnSelf();
  423. $select = $this->target->addTables($this->select, $this->request);
  424. $this->assertEquals($this->select, $select, 'Returned results isn\'t equal to passed select');
  425. }
  426. /**
  427. * @param $filter
  428. * @return \Magento\Framework\Search\Request\Query\Filter|\PHPUnit_Framework_MockObject_MockObject
  429. */
  430. private function createFilterQuery($filter)
  431. {
  432. $query = $this->getMockBuilder('\Magento\Framework\Search\Request\Query\Filter')
  433. ->disableOriginalConstructor()
  434. ->getMock();
  435. $query->method('getType')
  436. ->willReturn(QueryInterface::TYPE_FILTER);
  437. $query->method('getReference')
  438. ->willReturn($filter);
  439. return $query;
  440. }
  441. /**
  442. * @param array $must
  443. * @param array $should
  444. * @param array $mustNot
  445. * @return \Magento\Framework\Search\Request\Query\BoolExpression|\PHPUnit_Framework_MockObject_MockObject
  446. * @internal param $filter
  447. */
  448. private function createBoolQuery(array $must, array $should, array $mustNot)
  449. {
  450. $query = $this->getMockBuilder('\Magento\Framework\Search\Request\Query\BoolExpression')
  451. ->disableOriginalConstructor()
  452. ->getMock();
  453. $query->method('getType')
  454. ->willReturn(QueryInterface::TYPE_BOOL);
  455. $query->method('getMust')
  456. ->willReturn($must);
  457. $query->method('getShould')
  458. ->willReturn($should);
  459. $query->method('getMustNot')
  460. ->willReturn($mustNot);
  461. return $query;
  462. }
  463. /**
  464. * @param array $must
  465. * @param array $should
  466. * @param array $mustNot
  467. * @return \Magento\Framework\Search\Request\Filter\BoolExpression|\PHPUnit_Framework_MockObject_MockObject
  468. * @internal param $filter
  469. */
  470. private function createBoolFilter(array $must, array $should, array $mustNot)
  471. {
  472. $query = $this->getMockBuilder('\Magento\Framework\Search\Request\Filter\BoolExpression')
  473. ->disableOriginalConstructor()
  474. ->getMock();
  475. $query->method('getType')
  476. ->willReturn(FilterInterface::TYPE_BOOL);
  477. $query->method('getMust')
  478. ->willReturn($must);
  479. $query->method('getShould')
  480. ->willReturn($should);
  481. $query->method('getMustNot')
  482. ->willReturn($mustNot);
  483. return $query;
  484. }
  485. /**
  486. * @param string $field
  487. * @return \Magento\Framework\Search\Request\Filter\Range|\PHPUnit_Framework_MockObject_MockObject
  488. */
  489. private function createRangeFilter($field)
  490. {
  491. $filter = $this->createFilterMock(
  492. '\Magento\Framework\Search\Request\Filter\Range',
  493. FilterInterface::TYPE_RANGE,
  494. $field
  495. );
  496. return $filter;
  497. }
  498. /**
  499. * @param string $field
  500. * @return \Magento\Framework\Search\Request\Filter\Term|\PHPUnit_Framework_MockObject_MockObject
  501. */
  502. private function createTermFilter($field)
  503. {
  504. $filter = $this->createFilterMock(
  505. '\Magento\Framework\Search\Request\Filter\Term',
  506. FilterInterface::TYPE_TERM,
  507. $field
  508. );
  509. return $filter;
  510. }
  511. /**
  512. * @param string $class
  513. * @param string $type
  514. * @param string $field
  515. * @return \PHPUnit_Framework_MockObject_MockObject
  516. */
  517. private function createFilterMock($class, $type, $field)
  518. {
  519. $filter = $this->getMockBuilder($class)
  520. ->disableOriginalConstructor()
  521. ->getMock();
  522. $filter->method('getType')
  523. ->willReturn($type);
  524. $filter->method('getField')
  525. ->willReturn($field);
  526. return $filter;
  527. }
  528. /**
  529. * @param string $code
  530. * @param string $backendType
  531. * @param string $backendTable
  532. * @param int $attributeId
  533. * @param string $frontendInput
  534. * @param int $positionInCollection
  535. */
  536. private function createAttributeMock(
  537. $code,
  538. $backendType = null,
  539. $backendTable = null,
  540. $attributeId = 120,
  541. $frontendInput = 'select',
  542. $positionInCollection = 0
  543. ) {
  544. $attribute = $this->getMockBuilder('\Magento\Catalog\Model\ResourceModel\Eav\Attribute')
  545. ->setMethods(['getBackendType', 'getBackendTable', 'getId', 'getFrontendInput'])
  546. ->disableOriginalConstructor()
  547. ->getMock();
  548. $attribute->method('getId')
  549. ->willReturn($attributeId);
  550. $attribute->method('getBackendType')
  551. ->willReturn($backendType);
  552. $attribute->method('getBackendTable')
  553. ->willReturn($backendTable);
  554. $attribute->method('getFrontendInput')
  555. ->willReturn($frontendInput);
  556. $this->attributeCollection->expects($this->at($positionInCollection))
  557. ->method('getItemByColumnValue')
  558. ->with('attribute_code', $code)
  559. ->willReturn($attribute);
  560. }
  561. }