14
14
use Magento \Catalog \Model \ProductRepository ;
15
15
use Magento \Catalog \Model \ResourceModel \Eav \Attribute ;
16
16
use Magento \Eav \Model \Config ;
17
+ use Magento \Framework \App \Filesystem \DirectoryList ;
17
18
use Magento \Framework \DataObject ;
18
19
use Magento \Framework \Event \ManagerInterface ;
19
20
use Magento \Framework \Exception \LocalizedException ;
21
+ use Magento \Framework \File \Uploader ;
22
+ use Magento \Framework \File \UploaderFactory ;
20
23
use Magento \Framework \Filesystem ;
24
+ use Magento \Framework \HTTP \Adapter \FileTransferFactory ;
21
25
use Magento \Framework \Registry ;
22
26
use Magento \Framework \Serialize \Serializer \Json ;
23
27
use Magento \MediaStorage \Helper \File \Storage \Database ;
24
28
use Magento \TestFramework \Helper \Bootstrap ;
29
+ use Magento \TestFramework \ObjectManager ;
25
30
use PHPUnit \Framework \TestCase ;
26
31
use Psr \Log \LoggerInterface ;
32
+ use ReflectionMethod ;
33
+ use StdClass ;
27
34
28
35
/**
29
36
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -35,35 +42,41 @@ class AbstractTypeTest extends TestCase
35
42
*/
36
43
protected $ _model ;
37
44
45
+ /** @var ObjectManager */
46
+ private $ objectManager ;
47
+
48
+ /** @var ProductRepositoryInterface */
49
+ private $ productRepository ;
50
+
51
+ /**
52
+ * @inheritdoc
53
+ */
38
54
protected function setUp (): void
39
55
{
40
- $ productRepository = Bootstrap::getObjectManager ()->get (
41
- ProductRepositoryInterface::class
42
- );
43
- $ catalogProductOption = Bootstrap::getObjectManager ()->get (
44
- Option::class
45
- );
56
+ $ this ->objectManager = Bootstrap::getObjectManager ();
57
+ $ this ->productRepository = $ this ->objectManager ->get (ProductRepositoryInterface::class);
58
+ $ catalogProductOption = $ this ->objectManager ->get (Option::class);
46
59
$ catalogProductType = $ this ->createMock (Type::class);
47
60
$ eventManager = $ this ->createPartialMock (ManagerInterface::class, ['dispatch ' ]);
48
61
$ fileStorageDb = $ this ->createMock (Database::class);
49
62
$ filesystem = $ this ->createMock (Filesystem::class);
50
63
$ registry = $ this ->createMock (Registry::class);
51
64
$ logger = $ this ->createMock (LoggerInterface::class);
52
- $ serializer = Bootstrap:: getObjectManager () ->get (
65
+ $ serializer = $ this -> objectManager ->get (
53
66
Json::class
54
67
);
55
68
$ this ->_model = $ this ->getMockForAbstractClass (
56
69
AbstractType::class,
57
70
[
58
71
$ catalogProductOption ,
59
- Bootstrap:: getObjectManager () ->get (Config::class),
72
+ $ this -> objectManager ->get (Config::class),
60
73
$ catalogProductType ,
61
74
$ eventManager ,
62
75
$ fileStorageDb ,
63
76
$ filesystem ,
64
77
$ registry ,
65
78
$ logger ,
66
- $ productRepository ,
79
+ $ this -> productRepository ,
67
80
$ serializer
68
81
]
69
82
);
@@ -384,7 +397,7 @@ public function testGetSetStoreFilter()
384
397
{
385
398
$ product = new DataObject ();
386
399
$ this ->assertNull ($ this ->_model ->getStoreFilter ($ product ));
387
- $ store = new \ StdClass ();
400
+ $ store = new StdClass ();
388
401
$ this ->_model ->setStoreFilter ($ store , $ product );
389
402
$ this ->assertSame ($ store , $ this ->_model ->getStoreFilter ($ product ));
390
403
}
@@ -473,7 +486,7 @@ public function testGetSearchableData()
473
486
474
487
public function testGetProductsToPurchaseByReqGroups ()
475
488
{
476
- $ product = new \ StdClass ();
489
+ $ product = new StdClass ();
477
490
$ this ->assertSame ([[$ product ]], $ this ->_model ->getProductsToPurchaseByReqGroups ($ product ));
478
491
$ this ->_model ->setConfig (['composite ' => 1 ]);
479
492
$ this ->assertEquals ([], $ this ->_model ->getProductsToPurchaseByReqGroups ($ product ));
@@ -509,7 +522,7 @@ public function testPrepareOptions(): void
509
522
);
510
523
$ product ->load (1 );
511
524
$ buyRequest = new DataObject (['product ' => 1 ]);
512
- $ method = new \ ReflectionMethod (
525
+ $ method = new ReflectionMethod (
513
526
AbstractType::class,
514
527
'_prepareOptions '
515
528
);
@@ -523,4 +536,150 @@ public function testPrepareOptions(): void
523
536
}
524
537
$ this ->assertTrue ($ exceptionIsThrown );
525
538
}
539
+
540
+ /**
541
+ * Test if product can be prepared for cart with more than one custom file option
542
+ *
543
+ * @magentoAppIsolation enabled
544
+ * @magentoDataFixture Magento/Catalog/_files/product_simple_with_two_custom_file_options.php
545
+ * @return void
546
+ */
547
+ public function testPrepareForCartAdvancedWithMultipleCustomFileOptions (): void
548
+ {
549
+ /** @var $product Product */
550
+ $ product = $ this ->productRepository ->get ('simple_with_custom_file_option ' );
551
+ $ optionIds = array_reduce ($ product ->getOptions (), function ($ result , $ item ) {
552
+ $ result [] = $ item ->getOptionId ();
553
+ return $ result ;
554
+ }, []);
555
+ $ this ->prepareEnv ($ optionIds );
556
+
557
+ $ buyRequest = new DataObject (
558
+ [
559
+ 'qty ' => 5 ,
560
+ 'options ' => ['files_prefix ' => 'item_simple_with_custom_file_option_ ' ],
561
+ ]
562
+ );
563
+ $ model = $ this ->objectManager ->create (Simple::class);
564
+ $ product ->setTypeInstance ($ model );
565
+ $ result = $ model ->prepareForCartAdvanced ($ buyRequest , $ product );
566
+
567
+ //result is exception string value in case if exception occurs
568
+ self ::assertTrue (is_array ($ result ));
569
+ $ product = reset ($ result );
570
+ $ options = $ product ->getOptions ();
571
+ self ::assertCount (2 , $ options );
572
+ }
573
+
574
+ /**
575
+ * Test if exception occurs in case if file is not uploaded
576
+ *
577
+ * @magentoAppIsolation enabled
578
+ * @magentoDataFixture Magento/Catalog/_files/product_simple_with_two_custom_file_options.php
579
+ * @return void
580
+ */
581
+ public function testPrepareForCartAdvancedFileOptionFailedToUpload (): void
582
+ {
583
+ /** @var $product Product */
584
+ $ product = $ this ->productRepository ->get ('simple_with_custom_file_option ' );
585
+ $ optionIds = array_reduce ($ product ->getOptions (), function ($ result , $ item ) {
586
+ $ result [] = $ item ->getOptionId ();
587
+ return $ result ;
588
+ }, []);
589
+ $ this ->prepareEnv ($ optionIds );
590
+
591
+ $ uploaderFactory = $ this ->createPartialMock (UploaderFactory::class, ['create ' ]);
592
+ $ uploader = $ this ->createPartialMock (Uploader::class, ['save ' ]);
593
+ $ uploaderFactory ->method ('create ' )->willReturn ($ uploader );
594
+ $ this ->objectManager ->addSharedInstance ($ uploaderFactory , UploaderFactory::class);
595
+
596
+ $ buyRequest = new DataObject (
597
+ [
598
+ 'qty ' => 5 ,
599
+ 'options ' => ['files_prefix ' => 'item_simple_with_custom_file_option_ ' ],
600
+ ]
601
+ );
602
+ $ model = $ this ->objectManager ->create (Simple::class);
603
+ $ product ->setTypeInstance ($ model );
604
+ $ this ->expectException (LocalizedException::class);
605
+ $ model ->prepareForCartAdvanced ($ buyRequest , $ product );
606
+ }
607
+
608
+ /**
609
+ * Prepare file upload environment
610
+ *
611
+ * @param array $optionIds
612
+ * @return void
613
+ */
614
+ private function prepareEnv (array $ optionIds ): void
615
+ {
616
+ $ file = 'magento_thumbnail.jpg ' ;
617
+ $ fixtureDir = realpath (__DIR__ . '/../../../_files/ ' );
618
+
619
+ /** @var Filesystem $filesystem */
620
+ $ filesystem = $ this ->objectManager ->get (Filesystem::class);
621
+ $ tmpDirectory = $ filesystem ->getDirectoryWrite (DirectoryList::SYS_TMP );
622
+ $ filePath = $ tmpDirectory ->getAbsolutePath ($ file );
623
+ copy ($ fixtureDir . DIRECTORY_SEPARATOR . $ file , $ filePath );
624
+ copy ($ fixtureDir . DIRECTORY_SEPARATOR . $ file , $ filePath . '_1 ' );
625
+
626
+ $ _FILES ["item_simple_with_custom_file_option_options_ $ optionIds [0 ]_file " ] = [
627
+ 'name ' => 'test.jpg ' ,
628
+ 'type ' => 'image/jpeg ' ,
629
+ 'tmp_name ' => $ filePath ,
630
+ 'error ' => 0 ,
631
+ 'size ' => '3046 ' ,
632
+ ];
633
+ $ _FILES ["item_simple_with_custom_file_option_options_ $ optionIds [1 ]_file " ] = [
634
+ 'name ' => 'test.jpg ' ,
635
+ 'type ' => 'image/jpeg ' ,
636
+ 'tmp_name ' => $ filePath . '_1 ' ,
637
+ 'error ' => 0 ,
638
+ 'size ' => '3046 ' ,
639
+ ];
640
+ $ this ->prepareUploaderFactoryMock ();
641
+ }
642
+
643
+ /**
644
+ * Prepare file upload validator mock
645
+ *
646
+ * @return void
647
+ */
648
+ private function prepareUploaderFactoryMock (): void
649
+ {
650
+ $ uploaderMock = $ this ->getPreparedUploader ();
651
+ /** @var FileTransferFactory $httpFactory */
652
+ $ httpFactoryMock = $ this ->createPartialMock (FileTransferFactory::class, ['create ' ]);
653
+ $ httpFactoryMock ->expects ($ this ->at (0 ))
654
+ ->method ('create ' )
655
+ ->willReturn ($ uploaderMock );
656
+ $ httpFactoryMock ->expects ($ this ->at (1 ))
657
+ ->method ('create ' )
658
+ ->willReturn (clone $ uploaderMock );
659
+ $ this ->objectManager ->addSharedInstance ($ httpFactoryMock , FileTransferFactory::class);
660
+ }
661
+
662
+ /**
663
+ * Create prepared uploader instance for test
664
+ *
665
+ * @return \Zend_File_Transfer_Adapter_Http
666
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
667
+ */
668
+ private function getPreparedUploader (): \Zend_File_Transfer_Adapter_Http
669
+ {
670
+ $ uploader = new \Zend_File_Transfer_Adapter_Http ();
671
+ $ refObject = new \ReflectionObject ($ uploader );
672
+ $ validators = $ refObject ->getProperty ('_validators ' );
673
+ $ validators ->setAccessible (true );
674
+ $ validators ->setValue ($ uploader , []);
675
+ $ files = $ refObject ->getProperty ('_files ' );
676
+ $ files ->setAccessible (true );
677
+ $ filesValues = $ files ->getValue ($ uploader );
678
+ foreach (array_keys ($ filesValues ) as $ value ) {
679
+ $ filesValues [$ value ]['validators ' ] = [];
680
+ }
681
+ $ files ->setValue ($ uploader , $ filesValues );
682
+
683
+ return $ uploader ;
684
+ }
526
685
}
0 commit comments