diff --git a/app/code/Magento/Captcha/Observer/CheckContactUsFormObserver.php b/app/code/Magento/Captcha/Observer/CheckContactUsFormObserver.php index 8c1da0e1ef104..2d0a6479bbcd6 100644 --- a/app/code/Magento/Captcha/Observer/CheckContactUsFormObserver.php +++ b/app/code/Magento/Captcha/Observer/CheckContactUsFormObserver.php @@ -3,34 +3,41 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Captcha\Observer; +use Magento\Captcha\Helper\Data; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\ActionFlag; +use Magento\Framework\App\Response\RedirectInterface; +use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\App\Request\DataPersistorInterface; -use Magento\Framework\App\ObjectManager; +use Magento\Framework\Message\ManagerInterface; /** - * Class CheckContactUsFormObserver + * Check captcha on contact us form submit observer. */ class CheckContactUsFormObserver implements ObserverInterface { /** - * @var \Magento\Captcha\Helper\Data + * @var Data */ protected $_helper; /** - * @var \Magento\Framework\App\ActionFlag + * @var ActionFlag */ protected $_actionFlag; /** - * @var \Magento\Framework\Message\ManagerInterface + * @var ManagerInterface */ protected $messageManager; /** - * @var \Magento\Framework\App\Response\RedirectInterface + * @var RedirectInterface */ protected $redirect; @@ -45,60 +52,48 @@ class CheckContactUsFormObserver implements ObserverInterface private $dataPersistor; /** - * @param \Magento\Captcha\Helper\Data $helper - * @param \Magento\Framework\App\ActionFlag $actionFlag - * @param \Magento\Framework\Message\ManagerInterface $messageManager - * @param \Magento\Framework\App\Response\RedirectInterface $redirect + * @param Data $helper + * @param ActionFlag $actionFlag + * @param ManagerInterface $messageManager + * @param RedirectInterface $redirect * @param CaptchaStringResolver $captchaStringResolver + * @param DataPersistorInterface $dataPersistor */ public function __construct( - \Magento\Captcha\Helper\Data $helper, - \Magento\Framework\App\ActionFlag $actionFlag, - \Magento\Framework\Message\ManagerInterface $messageManager, - \Magento\Framework\App\Response\RedirectInterface $redirect, - CaptchaStringResolver $captchaStringResolver + Data $helper, + ActionFlag $actionFlag, + ManagerInterface $messageManager, + RedirectInterface $redirect, + CaptchaStringResolver $captchaStringResolver, + DataPersistorInterface $dataPersistor ) { $this->_helper = $helper; $this->_actionFlag = $actionFlag; $this->messageManager = $messageManager; $this->redirect = $redirect; $this->captchaStringResolver = $captchaStringResolver; + $this->dataPersistor = $dataPersistor; } /** * Check CAPTCHA on Contact Us page * - * @param \Magento\Framework\Event\Observer $observer + * @param Observer $observer * @return void */ - public function execute(\Magento\Framework\Event\Observer $observer) + public function execute(Observer $observer) { $formId = 'contact_us'; $captcha = $this->_helper->getCaptcha($formId); if ($captcha->isRequired()) { - /** @var \Magento\Framework\App\Action\Action $controller */ + /** @var Action $controller */ $controller = $observer->getControllerAction(); if (!$captcha->isCorrect($this->captchaStringResolver->resolve($controller->getRequest(), $formId))) { $this->messageManager->addErrorMessage(__('Incorrect CAPTCHA.')); - $this->getDataPersistor()->set($formId, $controller->getRequest()->getPostValue()); - $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true); + $this->dataPersistor->set($formId, $controller->getRequest()->getPostValue()); + $this->_actionFlag->set('', Action::FLAG_NO_DISPATCH, true); $this->redirect->redirect($controller->getResponse(), 'contact/index/index'); } } } - - /** - * Get Data Persistor - * - * @return DataPersistorInterface - */ - private function getDataPersistor() - { - if ($this->dataPersistor === null) { - $this->dataPersistor = ObjectManager::getInstance() - ->get(DataPersistorInterface::class); - } - - return $this->dataPersistor; - } } diff --git a/app/code/Magento/Captcha/Observer/ResetAttemptForBackendObserver.php b/app/code/Magento/Captcha/Observer/ResetAttemptForBackendObserver.php index 376bffbd9a6a5..165aef3d7f587 100644 --- a/app/code/Magento/Captcha/Observer/ResetAttemptForBackendObserver.php +++ b/app/code/Magento/Captcha/Observer/ResetAttemptForBackendObserver.php @@ -5,20 +5,27 @@ */ namespace Magento\Captcha\Observer; +use Magento\Captcha\Model\ResourceModel\Log; +use Magento\Captcha\Model\ResourceModel\LogFactory; +use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; +use Magento\Framework\Exception\LocalizedException; +/** + * Reset captcha attempts for Backend + */ class ResetAttemptForBackendObserver implements ObserverInterface { /** - * @var \Magento\Captcha\Model\ResourceModel\LogFactory + * @var LogFactory */ public $resLogFactory; /** - * @param \Magento\Captcha\Model\ResourceModel\LogFactory $resLogFactory + * @param LogFactory $resLogFactory */ public function __construct( - \Magento\Captcha\Model\ResourceModel\LogFactory $resLogFactory + LogFactory $resLogFactory ) { $this->resLogFactory = $resLogFactory; } @@ -26,10 +33,11 @@ public function __construct( /** * Reset Attempts For Backend * - * @param \Magento\Framework\Event\Observer $observer - * @return \Magento\Captcha\Observer\ResetAttemptForBackendObserver + * @param Observer $observer + * @return Log + * @throws LocalizedException */ - public function execute(\Magento\Framework\Event\Observer $observer) + public function execute(Observer $observer) { return $this->resLogFactory->create()->deleteUserAttempts($observer->getUser()->getUsername()); } diff --git a/app/code/Magento/Captcha/Observer/ResetAttemptForFrontendObserver.php b/app/code/Magento/Captcha/Observer/ResetAttemptForFrontendObserver.php index dedb57ad52581..e65793cd3508e 100644 --- a/app/code/Magento/Captcha/Observer/ResetAttemptForFrontendObserver.php +++ b/app/code/Magento/Captcha/Observer/ResetAttemptForFrontendObserver.php @@ -5,20 +5,28 @@ */ namespace Magento\Captcha\Observer; +use Magento\Captcha\Model\ResourceModel\Log; +use Magento\Captcha\Model\ResourceModel\LogFactory; +use Magento\Customer\Model\Customer; +use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; +use Magento\Framework\Exception\LocalizedException; +/** + * Reset captcha attempts for Frontend + */ class ResetAttemptForFrontendObserver implements ObserverInterface { /** - * @var \Magento\Captcha\Model\ResourceModel\LogFactory + * @var LogFactory */ public $resLogFactory; /** - * @param \Magento\Captcha\Model\ResourceModel\LogFactory $resLogFactory + * @param LogFactory $resLogFactory */ public function __construct( - \Magento\Captcha\Model\ResourceModel\LogFactory $resLogFactory + LogFactory $resLogFactory ) { $this->resLogFactory = $resLogFactory; } @@ -26,12 +34,13 @@ public function __construct( /** * Reset Attempts For Frontend * - * @param \Magento\Framework\Event\Observer $observer - * @return \Magento\Captcha\Observer\ResetAttemptForFrontendObserver + * @param Observer $observer + * @return Log + * @throws LocalizedException */ - public function execute(\Magento\Framework\Event\Observer $observer) + public function execute(Observer $observer) { - /** @var \Magento\Customer\Model\Customer $model */ + /** @var Customer $model */ $model = $observer->getModel(); return $this->resLogFactory->create()->deleteUserAttempts($model->getEmail()); diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckContactUsFormObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckContactUsFormObserverTest.php index 83bfb2910f9f8..6bb21e9432d70 100644 --- a/app/code/Magento/Captcha/Test/Unit/Observer/CheckContactUsFormObserverTest.php +++ b/app/code/Magento/Captcha/Test/Unit/Observer/CheckContactUsFormObserverTest.php @@ -5,94 +5,108 @@ */ namespace Magento\Captcha\Test\Unit\Observer; +use Magento\Captcha\Helper\Data; +use Magento\Captcha\Model\DefaultModel; +use Magento\Captcha\Observer\CaptchaStringResolver; +use Magento\Captcha\Observer\CheckContactUsFormObserver; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\ActionFlag; +use Magento\Framework\App\Request\DataPersistorInterface; +use Magento\Framework\App\Request\Http; +use Magento\Framework\App\Response\RedirectInterface; +use Magento\Framework\Event\Observer; +use Magento\Framework\Message\ManagerInterface; +use Magento\Framework\Session\SessionManager; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + /** + * Test class for \Magento\Captcha\Observer\CheckContactUsFormObserver + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class CheckContactUsFormObserverTest extends \PHPUnit\Framework\TestCase +class CheckContactUsFormObserverTest extends TestCase { /** - * @var \Magento\Captcha\Observer\CheckContactUsFormObserver + * @var ObjectManager */ - protected $checkContactUsFormObserver; + private $objectManagerHelper; /** - * @var \Magento\Captcha\Helper\Data|\PHPUnit_Framework_MockObject_MockObject + * @var CheckContactUsFormObserver */ - protected $helperMock; + private $checkContactUsFormObserver; /** - * @var \Magento\Framework\App\ActionFlag|\PHPUnit_Framework_MockObject_MockObject + * @var Data|MockObject */ - protected $actionFlagMock; + private $helperMock; - /* - * @var \Magento\Framework\Message\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject + /** + * @var ActionFlag|MockObject */ - protected $messageManagerMock; + private $actionFlagMock; /** - * @var \Magento\Framework\App\Response\RedirectInterface|\PHPUnit_Framework_MockObject_MockObject + * @var ManagerInterface|MockObject */ - protected $redirectMock; + private $messageManagerMock; /** - * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + * @var RedirectInterface|MockObject */ - protected $objectManagerHelper; + private $redirectMock; /** - * @var \Magento\Captcha\Observer\CaptchaStringResolver|\PHPUnit_Framework_MockObject_MockObject + * @var CaptchaStringResolver|MockObject */ - protected $captchaStringResolverMock; + private $captchaStringResolverMock; /** - * @var \Magento\Framework\Session\SessionManager|\PHPUnit_Framework_MockObject_MockObject + * @var DataPersistorInterface|MockObject */ - protected $sessionMock; + private $dataPersistorMock; /** - * @var \Magento\Captcha\Model\DefaultModel|\PHPUnit_Framework_MockObject_MockObject + * @var SessionManager|MockObject */ - protected $captchaMock; + private $sessionMock; /** - * @var \Magento\Framework\App\Request\DataPersistorInterface|\PHPUnit_Framework_MockObject_MockObject + * @var DefaultModel|MockObject */ - protected $dataPersistorMock; + private $captchaMock; protected function setUp() { - $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->objectManagerHelper = new ObjectManager($this); + + $this->helperMock = $this->createMock(Data::class); + $this->actionFlagMock = $this->createMock(ActionFlag::class); + $this->messageManagerMock = $this->createMock(ManagerInterface::class); + $this->redirectMock = $this->createMock(RedirectInterface::class); + $this->captchaStringResolverMock = $this->createMock(CaptchaStringResolver::class); + $this->dataPersistorMock = $this->getMockBuilder(DataPersistorInterface::class) + ->getMockForAbstractClass(); - $this->helperMock = $this->createMock(\Magento\Captcha\Helper\Data::class); - $this->actionFlagMock = $this->createMock(\Magento\Framework\App\ActionFlag::class); - $this->messageManagerMock = $this->createMock(\Magento\Framework\Message\ManagerInterface::class); - $this->redirectMock = $this->createMock(\Magento\Framework\App\Response\RedirectInterface::class); - $this->captchaStringResolverMock = $this->createMock(\Magento\Captcha\Observer\CaptchaStringResolver::class); $this->sessionMock = $this->createPartialMock( - \Magento\Framework\Session\SessionManager::class, + SessionManager::class, ['addErrorMessage'] ); - $this->dataPersistorMock = $this->getMockBuilder(\Magento\Framework\App\Request\DataPersistorInterface::class) - ->getMockForAbstractClass(); + $this->captchaMock = $this->createMock(DefaultModel::class); $this->checkContactUsFormObserver = $this->objectManagerHelper->getObject( - \Magento\Captcha\Observer\CheckContactUsFormObserver::class, + CheckContactUsFormObserver::class, [ 'helper' => $this->helperMock, 'actionFlag' => $this->actionFlagMock, 'messageManager' => $this->messageManagerMock, 'redirect' => $this->redirectMock, - 'captchaStringResolver' => $this->captchaStringResolverMock + 'captchaStringResolver' => $this->captchaStringResolverMock, + 'dataPersistor' => $this->dataPersistorMock ] ); - $this->objectManagerHelper->setBackwardCompatibleProperty( - $this->checkContactUsFormObserver, - 'dataPersistor', - $this->dataPersistorMock - ); - - $this->captchaMock = $this->createMock(\Magento\Captcha\Model\DefaultModel::class); } public function testCheckContactUsFormWhenCaptchaIsRequiredAndValid() @@ -100,14 +114,13 @@ public function testCheckContactUsFormWhenCaptchaIsRequiredAndValid() $formId = 'contact_us'; $captchaValue = 'some-value'; - $controller = $this->createMock(\Magento\Framework\App\Action\Action::class); - $request = $this->createMock(\Magento\Framework\App\Request\Http::class); - $request->expects($this->any()) - ->method('getPost') - ->with(\Magento\Captcha\Helper\Data::INPUT_NAME_FIELD_VALUE, null) + $controller = $this->createMock(Action::class); + $request = $this->createMock(Http::class); + $request->method('getPost') + ->with(Data::INPUT_NAME_FIELD_VALUE, null) ->willReturn([$formId => $captchaValue]); - $controller->expects($this->any())->method('getRequest')->willReturn($request); - $this->captchaMock->expects($this->any())->method('isRequired')->willReturn(true); + $controller->method('getRequest')->willReturn($request); + $this->captchaMock->method('isRequired')->willReturn(true); $this->captchaMock->expects($this->once()) ->method('isCorrect') ->with($captchaValue) @@ -116,13 +129,13 @@ public function testCheckContactUsFormWhenCaptchaIsRequiredAndValid() ->method('resolve') ->with($request, $formId) ->willReturn($captchaValue); - $this->helperMock->expects($this->any()) - ->method('getCaptcha') - ->with($formId)->willReturn($this->captchaMock); + $this->helperMock->method('getCaptcha') + ->with($formId) + ->willReturn($this->captchaMock); $this->sessionMock->expects($this->never())->method('addErrorMessage'); $this->checkContactUsFormObserver->execute( - new \Magento\Framework\Event\Observer(['controller_action' => $controller]) + new Observer(['controller_action' => $controller]) ); } @@ -135,11 +148,10 @@ public function testCheckContactUsFormRedirectsCustomerWithWarningMessageWhenCap $redirectUrl = 'http://magento.com/contacts/'; $postData = ['name' => 'Some Name']; - $request = $this->createMock(\Magento\Framework\App\Request\Http::class); + $request = $this->createMock(Http::class); $response = $this->createMock(\Magento\Framework\App\Response\Http::class); - $request->expects($this->any()) - ->method('getPost') - ->with(\Magento\Captcha\Helper\Data::INPUT_NAME_FIELD_VALUE, null) + $request->method('getPost') + ->with(Data::INPUT_NAME_FIELD_VALUE, null) ->willReturn([$formId => $captchaValue]); $request->expects($this->once()) ->method('getPostValue') @@ -150,10 +162,10 @@ public function testCheckContactUsFormRedirectsCustomerWithWarningMessageWhenCap ->with($response, $redirectRoutePath, []) ->willReturn($redirectUrl); - $controller = $this->createMock(\Magento\Framework\App\Action\Action::class); - $controller->expects($this->any())->method('getRequest')->willReturn($request); - $controller->expects($this->any())->method('getResponse')->willReturn($response); - $this->captchaMock->expects($this->any())->method('isRequired')->willReturn(true); + $controller = $this->createMock(Action::class); + $controller->method('getRequest')->willReturn($request); + $controller->method('getResponse')->willReturn($response); + $this->captchaMock->method('isRequired')->willReturn(true); $this->captchaMock->expects($this->once()) ->method('isCorrect') ->with($captchaValue) @@ -162,32 +174,32 @@ public function testCheckContactUsFormRedirectsCustomerWithWarningMessageWhenCap ->method('resolve') ->with($request, $formId) ->willReturn($captchaValue); - $this->helperMock->expects($this->any()) - ->method('getCaptcha') + $this->helperMock->method('getCaptcha') ->with($formId) ->willReturn($this->captchaMock); - $this->messageManagerMock->expects($this->once())->method('addErrorMessage')->with($warningMessage); + $this->messageManagerMock->expects($this->once()) + ->method('addErrorMessage') + ->with($warningMessage); $this->actionFlagMock->expects($this->once()) ->method('set') - ->with('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true); + ->with('', Action::FLAG_NO_DISPATCH, true); $this->dataPersistorMock->expects($this->once()) ->method('set') ->with($formId, $postData); $this->checkContactUsFormObserver->execute( - new \Magento\Framework\Event\Observer(['controller_action' => $controller]) + new Observer(['controller_action' => $controller]) ); } public function testCheckContactUsFormDoesNotCheckCaptchaWhenItIsNotRequired() { - $this->helperMock->expects($this->any()) - ->method('getCaptcha') + $this->helperMock->method('getCaptcha') ->with('contact_us') ->willReturn($this->captchaMock); - $this->captchaMock->expects($this->any())->method('isRequired')->willReturn(false); + $this->captchaMock->method('isRequired')->willReturn(false); $this->captchaMock->expects($this->never())->method('isCorrect'); - $this->checkContactUsFormObserver->execute(new \Magento\Framework\Event\Observer()); + $this->checkContactUsFormObserver->execute(new Observer()); } } diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php new file mode 100644 index 0000000000000..584e7eb2e215f --- /dev/null +++ b/app/code/Magento/Captcha/Test/Unit/Observer/CheckUserForgotPasswordBackendObserverTest.php @@ -0,0 +1,230 @@ +helperMock = $this->createMock(DataHelper::class); + $this->captchaStringResolverMock = $this->createMock(CaptchaStringResolver::class); + $this->sessionMock = $this->getMockBuilder(SessionManagerInterface::class) + ->setMethods(['setEmail']) + ->getMockForAbstractClass(); + $this->actionFlagMock = $this->createMock(ActionFlag::class); + $this->messageManagerMock = $this->createMock(ManagerInterface::class); + + $objectManager = new ObjectManagerHelper($this); + $this->observer = $objectManager->getObject( + CheckUserForgotPasswordBackendObserver::class, + [ + '_helper' => $this->helperMock, + 'captchaStringResolver' => $this->captchaStringResolverMock, + '_session' => $this->sessionMock, + '_actionFlag' => $this->actionFlagMock, + 'messageManager' => $this->messageManagerMock + ] + ); + + $this->captchaMock = $this->getMockBuilder(CaptchaInterface::class) + ->setMethods(['isRequired', 'isCorrect']) + ->getMockForAbstractClass(); + $this->helperMock->expects($this->once()) + ->method('getCaptcha') + ->with($formId) + ->willReturn($this->captchaMock); + + $this->requestMock = $this->createMock(HttpRequest::class); + $this->httpResponseMock = $this->createMock(HttpResponse::class); + + $this->controllerMock = $this->getMockBuilder(Action::class) + ->disableOriginalConstructor() + ->setMethods(['getUrl', 'getRequest', 'getResponse']) + ->getMockForAbstractClass(); + $this->controllerMock->expects($this->any()) + ->method('getRequest') + ->willReturn($this->requestMock); + $this->controllerMock->expects($this->any()) + ->method('getResponse') + ->willReturn($this->httpResponseMock); + + $this->eventObserverMock = $this->createPartialMock(Observer::class, ['getControllerAction']); + $this->eventObserverMock->expects($this->any()) + ->method('getControllerAction') + ->willReturn($this->controllerMock); + } + + /** + * Test case when Captcha is required and was entered correctly. + */ + public function testExecuteWhenCaptchaIsCorrect() + { + $this->configureRequestMockWithStubValues(); + $this->captchaMock->expects($this->once())->method('isRequired')->willReturn(true); + $this->captchaMock->expects($this->once())->method('isCorrect')->willReturn(true); + + $this->executeOriginalMethodExpectsNoError(); + } + + /** + * Test case when Captcha is required and was entered incorrectly. + */ + public function testExecuteWhenCaptchaIsIncorrect() + { + $this->configureRequestMockWithStubValues(); + $this->captchaMock->expects($this->once())->method('isRequired')->willReturn(true); + $this->captchaMock->expects($this->once())->method('isCorrect')->willReturn(false); + + $this->sessionMock->expects($this->once())->method('setEmail'); + $this->actionFlagMock->expects($this->once())->method('set'); + $this->controllerMock->expects($this->once())->method('getUrl'); + $this->messageManagerMock->expects($this->once()) + ->method('addErrorMessage') + ->with(__('Incorrect CAPTCHA')); + $this->httpResponseMock->expects($this->once())->method('setRedirect')->willReturnSelf(); + + $this->observer->execute($this->eventObserverMock); + } + + /** + * Test case when Captcha is not required. + */ + public function testExecuteWhenCaptchaIsNotRequired() + { + $this->configureRequestMockWithStubValues(); + $this->captchaMock->expects($this->once())->method('isRequired')->willReturn(false); + + $this->executeOriginalMethodExpectsNoError(); + } + + /** + * Test case when email is not provided + */ + public function testExecuteWhenEmailParamIsNotPresent() + { + $this->requestMock->expects($this->any()) + ->method('getParam') + ->with('email') + ->willReturn(null); + $this->requestMock->expects($this->any()) + ->method('getParams') + ->willReturn(self::STUB_REQUEST_PARAMS); + $this->captchaMock->expects($this->never())->method('isRequired'); + $this->captchaMock->expects($this->never())->method('isCorrect'); + + $this->executeOriginalMethodExpectsNoError(); + } + + /** + * Stub params for Request Mock + */ + private function configureRequestMockWithStubValues() + { + $this->requestMock->expects($this->any()) + ->method('getParam') + ->with('email') + ->willReturn(self::STUB_EMAIL); + $this->requestMock->expects($this->any()) + ->method('getParams') + ->willReturn(self::STUB_REQUEST_PARAMS); + } + + /** + * Run original method, expect there is no error + */ + private function executeOriginalMethodExpectsNoError() + { + $this->messageManagerMock->expects($this->never())->method('addErrorMessage'); + $this->httpResponseMock->expects($this->never())->method('setRedirect'); + + $this->observer->execute($this->eventObserverMock); + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Copier.php b/app/code/Magento/Catalog/Model/Product/Copier.php index 91fb5213281ec..b04d3da8f0223 100644 --- a/app/code/Magento/Catalog/Model/Product/Copier.php +++ b/app/code/Magento/Catalog/Model/Product/Copier.php @@ -8,10 +8,12 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\Attribute\ScopeOverriddenValue; use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\Catalog\Model\Product\Option\Repository as OptionRepository; use Magento\Catalog\Model\ProductFactory; use Magento\Framework\App\ObjectManager; use Magento\Framework\EntityManager\MetadataPool; +use Magento\Store\Model\Store; use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException; /** @@ -72,40 +74,37 @@ public function __construct( /** * Create product duplicate * - * @param \Magento\Catalog\Model\Product $product - * - * @return \Magento\Catalog\Model\Product - * - * @throws \Exception + * @param Product $product + * @return Product */ - public function copy(Product $product) + public function copy(Product $product): Product { $product->getWebsiteIds(); $product->getCategoryIds(); $metadata = $this->metadataPool->getMetadata(ProductInterface::class); - /** @var \Magento\Catalog\Model\Product $duplicate */ + /** @var Product $duplicate */ $duplicate = $this->productFactory->create(); $productData = $product->getData(); $productData = $this->removeStockItem($productData); $duplicate->setData($productData); $duplicate->setOptions([]); + $duplicate->setMetaTitle(null); + $duplicate->setMetaKeyword(null); + $duplicate->setMetaDescription(null); $duplicate->setIsDuplicate(true); $duplicate->setOriginalLinkId($product->getData($metadata->getLinkField())); - $duplicate->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED); + $duplicate->setStatus(Status::STATUS_DISABLED); $duplicate->setCreatedAt(null); $duplicate->setUpdatedAt(null); $duplicate->setId(null); - $duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID); + $duplicate->setStoreId(Store::DEFAULT_STORE_ID); $this->copyConstructor->build($product, $duplicate); $this->setDefaultUrl($product, $duplicate); $this->setStoresUrl($product, $duplicate); $this->optionRepository->duplicate($product, $duplicate); - $product->getResource()->duplicate( - $product->getData($metadata->getLinkField()), - $duplicate->getData($metadata->getLinkField()) - ); + return $duplicate; } @@ -118,11 +117,11 @@ public function copy(Product $product) */ private function setDefaultUrl(Product $product, Product $duplicate) : void { - $duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID); + $duplicate->setStoreId(Store::DEFAULT_STORE_ID); $resource = $product->getResource(); $attribute = $resource->getAttribute('url_key'); $productId = $product->getId(); - $urlKey = $resource->getAttributeRawValue($productId, 'url_key', \Magento\Store\Model\Store::DEFAULT_STORE_ID); + $urlKey = $resource->getAttributeRawValue($productId, 'url_key', Store::DEFAULT_STORE_ID); do { $urlKey = $this->modifyUrl($urlKey); $duplicate->setUrlKey($urlKey); @@ -175,7 +174,7 @@ private function setStoresUrl(Product $product, Product $duplicate) : void $productResource->saveAttribute($duplicate, 'url_path'); $productResource->saveAttribute($duplicate, 'url_key'); } - $duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID); + $duplicate->setStoreId(Store::DEFAULT_STORE_ID); } /** @@ -197,7 +196,7 @@ private function modifyUrl(string $urlKey) : string * @param array $productData * @return array */ - private function removeStockItem(array $productData) + private function removeStockItem(array $productData): array { if (isset($productData[ProductInterface::EXTENSION_ATTRIBUTES_KEY])) { $extensionAttributes = $productData[ProductInterface::EXTENSION_ATTRIBUTES_KEY]; diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php index b72ecbf195d39..91441890e83b1 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php @@ -3,77 +3,91 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Catalog\Test\Unit\Model\Product; +use Magento\Catalog\Api\Data\ProductExtension; use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Attribute\ScopeOverriddenValue; use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\Catalog\Model\Product\Copier; +use Magento\Catalog\Model\Product\CopyConstructorInterface; +use Magento\Catalog\Model\Product\Option\Repository; +use Magento\Catalog\Model\ProductFactory; +use Magento\Catalog\Model\ResourceModel\Product as ProductResourceModel; +use Magento\CatalogInventory\Api\Data\StockItemInterface; +use Magento\Eav\Model\Entity\AbstractEntity; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Framework\EntityManager\EntityMetadata; +use Magento\Framework\EntityManager\MetadataPool; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; /** * Test for Magento\Catalog\Model\Product\Copier class. * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class CopierTest extends \PHPUnit\Framework\TestCase +class CopierTest extends TestCase { /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var Copier */ - private $optionRepositoryMock; + private $_model; /** - * @var Copier + * @var Repository|MockObject */ - private $_model; + private $optionRepositoryMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var CopyConstructorInterface|MockObject */ private $copyConstructorMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var ProductFactory|MockObject */ private $productFactoryMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var ScopeOverriddenValue|MockObject */ private $scopeOverriddenValueMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var Product|MockObject */ private $productMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var EntityMetadata|MockObject */ private $metadata; + /** + * @ingeritdoc + */ protected function setUp() { - $this->copyConstructorMock = $this->createMock(\Magento\Catalog\Model\Product\CopyConstructorInterface::class); - $this->productFactoryMock = $this->createPartialMock( - \Magento\Catalog\Model\ProductFactory::class, - ['create'] - ); - $this->scopeOverriddenValueMock = $this->createMock( - \Magento\Catalog\Model\Attribute\ScopeOverriddenValue::class - ); - $this->optionRepositoryMock = $this->createMock( - \Magento\Catalog\Model\Product\Option\Repository::class - ); + $this->copyConstructorMock = $this->createMock(CopyConstructorInterface::class); + $this->productFactoryMock = $this->createPartialMock(ProductFactory::class, ['create']); + $this->scopeOverriddenValueMock = $this->createMock(ScopeOverriddenValue::class); + $this->optionRepositoryMock = $this->createMock(Repository::class); $this->productMock = $this->createMock(Product::class); - $this->productMock->expects($this->any())->method('getEntityId')->willReturn(1); - $this->metadata = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadata::class) + $this->metadata = $this->getMockBuilder(EntityMetadata::class) ->disableOriginalConstructor() ->getMock(); - $metadataPool = $this->getMockBuilder(\Magento\Framework\EntityManager\MetadataPool::class) + + /** @var MetadataPool|MockObject $metadataPool */ + $metadataPool = $this->getMockBuilder(MetadataPool::class) ->disableOriginalConstructor() ->getMock(); - $metadataPool->expects($this->any())->method('getMetadata')->willReturn($this->metadata); + $metadataPool->expects($this->once()) + ->method('getMetadata') + ->willReturn($this->metadata); $this->_model = new Copier( $this->copyConstructorMock, $this->productFactoryMock, @@ -84,13 +98,15 @@ protected function setUp() } /** + * Test duplicate product + * + * @return void * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function testCopy() + public function testCopy(): void { - $stockItem = $this->getMockBuilder(\Magento\CatalogInventory\Api\Data\StockItemInterface::class) - ->getMock(); - $extensionAttributes = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductExtension::class) + $stockItem = $this->createMock(StockItemInterface::class); + $extensionAttributes = $this->getMockBuilder(ProductExtension::class) ->setMethods(['getStockItem', 'setData']) ->getMock(); $extensionAttributes @@ -106,15 +122,19 @@ public function testCopy() 'product data' => ['product data'], ProductInterface::EXTENSION_ATTRIBUTES_KEY => $extensionAttributes, ]; - $this->productMock->expects($this->atLeastOnce())->method('getWebsiteIds'); - $this->productMock->expects($this->atLeastOnce())->method('getCategoryIds'); - $this->productMock->expects($this->any())->method('getData')->willReturnMap([ - ['', null, $productData], - ['linkField', null, '1'], - ]); + $this->productMock->expects($this->atLeastOnce()) + ->method('getWebsiteIds'); + $this->productMock->expects($this->atLeastOnce()) + ->method('getCategoryIds'); + $this->productMock->expects($this->exactly(2)) + ->method('getData') + ->willReturnMap([ + ['', null, $productData], + ['linkField', null, '1'], + ]); $entityMock = $this->getMockForAbstractClass( - \Magento\Eav\Model\Entity\AbstractEntity::class, + AbstractEntity::class, [], '', false, @@ -122,12 +142,12 @@ public function testCopy() true, ['checkAttributeUniqueValue'] ); - $entityMock->expects($this->any()) + $entityMock->expects($this->once()) ->method('checkAttributeUniqueValue') ->willReturn(true); $attributeMock = $this->getMockForAbstractClass( - \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class, + AbstractAttribute::class, [], '', false, @@ -135,22 +155,24 @@ public function testCopy() true, ['getEntity'] ); - $attributeMock->expects($this->any()) + $attributeMock->expects($this->once()) ->method('getEntity') ->willReturn($entityMock); - $resourceMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product::class) + $resourceMock = $this->getMockBuilder(ProductResourceModel::class) ->disableOriginalConstructor() ->setMethods(['getAttributeRawValue', 'duplicate', 'getAttribute']) ->getMock(); - $resourceMock->expects($this->any()) + $resourceMock->expects($this->once()) ->method('getAttributeRawValue') ->willReturn('urk-key-1'); - $resourceMock->expects($this->any()) + $resourceMock->expects($this->exactly(2)) ->method('getAttribute') ->willReturn($attributeMock); - $this->productMock->expects($this->any())->method('getResource')->will($this->returnValue($resourceMock)); + $this->productMock->expects($this->exactly(2)) + ->method('getResource') + ->willReturn($resourceMock); $duplicateMock = $this->createPartialMock( Product::class, @@ -170,51 +192,77 @@ public function testCopy() 'setUrlKey', 'setStoreId', 'getStoreIds', + 'setMetaTitle', + 'setMetaKeyword', + 'setMetaDescription', ] ); - $this->productFactoryMock->expects($this->once())->method('create')->will($this->returnValue($duplicateMock)); + $this->productFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($duplicateMock); $duplicateMock->expects($this->once())->method('setOptions')->with([]); $duplicateMock->expects($this->once())->method('setIsDuplicate')->with(true); $duplicateMock->expects($this->once())->method('setOriginalLinkId')->with(1); - $duplicateMock->expects( - $this->once() - )->method( - 'setStatus' - )->with( - \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED - ); + $duplicateMock->expects($this->once()) + ->method('setStatus') + ->with(Status::STATUS_DISABLED); $duplicateMock->expects($this->atLeastOnce())->method('setStoreId'); - $duplicateMock->expects($this->once())->method('setCreatedAt')->with(null); - $duplicateMock->expects($this->once())->method('setUpdatedAt')->with(null); - $duplicateMock->expects($this->once())->method('setId')->with(null); - $duplicateMock->expects($this->atLeastOnce())->method('getStoreIds')->willReturn([]); - $duplicateMock->expects($this->atLeastOnce())->method('setData')->willReturn($duplicateMock); - $this->copyConstructorMock->expects($this->once())->method('build')->with($this->productMock, $duplicateMock); - $duplicateMock->expects($this->once())->method('setUrlKey')->with('urk-key-2')->willReturn($duplicateMock); - $duplicateMock->expects($this->once())->method('save'); - - $this->metadata->expects($this->any())->method('getLinkField')->willReturn('linkField'); - - $duplicateMock->expects($this->any())->method('getData')->willReturnMap([ - ['linkField', null, '2'], - ]); + $duplicateMock->expects($this->once()) + ->method('setCreatedAt') + ->with(null); + $duplicateMock->expects($this->once()) + ->method('setUpdatedAt') + ->with(null); + $duplicateMock->expects($this->once()) + ->method('setId') + ->with(null); + $duplicateMock->expects($this->once()) + ->method('setMetaTitle') + ->with(null); + $duplicateMock->expects($this->once()) + ->method('setMetaKeyword') + ->with(null); + $duplicateMock->expects($this->once()) + ->method('setMetaDescription') + ->with(null); + $duplicateMock->expects($this->atLeastOnce()) + ->method('getStoreIds')->willReturn([]); + $duplicateMock->expects($this->atLeastOnce()) + ->method('setData') + ->willReturn($duplicateMock); + $this->copyConstructorMock->expects($this->once()) + ->method('build') + ->with($this->productMock, $duplicateMock); + $duplicateMock->expects($this->once()) + ->method('setUrlKey') + ->with('urk-key-2') + ->willReturn($duplicateMock); + $duplicateMock->expects($this->once()) + ->method('save'); + $this->metadata->expects($this->once()) + ->method('getLinkField') + ->willReturn('linkField'); + $duplicateMock->expects($this->never()) + ->method('getData'); $this->optionRepositoryMock->expects($this->once()) ->method('duplicate') ->with($this->productMock, $duplicateMock); - $resourceMock->expects($this->once())->method('duplicate')->with(1, 2); $this->assertEquals($duplicateMock, $this->_model->copy($this->productMock)); } /** + * Test duplicate product with `UrlAlreadyExistsException` while copy stores url + * + * @return void * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function testUrlAlreadyExistsExceptionWhileCopyStoresUrl() + public function testUrlAlreadyExistsExceptionWhileCopyStoresUrl(): void { - $stockItem = $this->getMockBuilder(\Magento\CatalogInventory\Api\Data\StockItemInterface::class) + $stockItem = $this->getMockBuilder(StockItemInterface::class) ->getMock(); - $extensionAttributes = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductExtension::class) + $extensionAttributes = $this->getMockBuilder(ProductExtension::class) ->setMethods(['getStockItem', 'setData']) ->getMock(); $extensionAttributes diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml new file mode 100644 index 0000000000000..685385382027b --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminFillCmsBlockFormActionGroup.xml @@ -0,0 +1,25 @@ + + + + + + + Fills in the Block Title, Identifier with marginal space, Store View and Content. PLEASE NOTE: The values are passed through arguments in test. + + + + + + + + + + + + diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml index 33d7b06a064e4..6867560551915 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockTest.xml @@ -42,4 +42,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml new file mode 100644 index 0000000000000..0399d0eb3ab28 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminCreateCmsBlockWithMarginalSpaceTest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + <description value="Admin can not able create a CMS block with marginal space in identifier field"/> + <severity value="CRITICAL"/> + <group value="Cms"/> + </annotations> + <before> + <actionGroup ref="LoginActionGroup" stepKey="loginGetFromGeneralFile"/> + <actionGroup ref="DisabledWYSIWYGActionGroup" stepKey="disableWYSIWYG"/> + </before> + <amOnPage url="{{CmsNewBlock.url}}" stepKey="amOnBlocksCreationForm"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <!--Verify Save&Duplicate button and Save&Close button--> + <click selector="{{BlockNewPagePageActionsSection.expandSplitButton}}" stepKey="expandSplitBtn1" /> + <see selector="{{BlockNewPagePageActionsSection.saveAndDuplicate}}" userInput="Save & Duplicate" stepKey="seeSaveAndDuplicate"/> + <see selector="{{BlockNewPagePageActionsSection.saveAndClose}}" userInput="Save & Close" stepKey="seeSaveAndClose"/> + <!--Create new CMS Block page with marginal space in identifier field--> + <actionGroup ref="AdminFillCmsBlockFormActionGroup" stepKey="FillOutBlockContent"> + <argument name="cmsBlockDataTitle" value="Default Block" /> + <argument name="cmsBlockDataIdentifier" value=" block " /> + <argument name="cmsBlockDataContent" value="Here is a block test. Yeah!" /> + </actionGroup> + <click selector="{{BlockNewPagePageActionsSection.expandSplitButton}}" stepKey="expandSplitBtn2" /> + <click selector="{{BlockNewPagePageActionsSection.saveAndClose}}" stepKey="clicksaveAndClose" /> + <waitForPageLoad stepKey="waitForPageLoad3"/> + <see userInput="No marginal white space please" stepKey="seeNoMarginalSpaceMsgOnIdentifierField"/> + </test> +</tests> diff --git a/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml b/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml index 793fc7d26cb4a..af54df24b64f5 100644 --- a/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml +++ b/app/code/Magento/Cms/view/adminhtml/ui_component/cms_block_listing.xml @@ -146,6 +146,7 @@ <editor> <validation> <rule name="required-entry" xsi:type="boolean">true</rule> + <rule name="no-marginal-whitespace" xsi:type="boolean">true</rule> </validation> <editorType>text</editorType> </editor> diff --git a/app/code/Magento/Customer/Model/Account/Redirect.php b/app/code/Magento/Customer/Model/Account/Redirect.php index 2ccaaea45680c..0389a380b36dc 100644 --- a/app/code/Magento/Customer/Model/Account/Redirect.php +++ b/app/code/Magento/Customer/Model/Account/Redirect.php @@ -7,24 +7,28 @@ use Magento\Customer\Model\Session; use Magento\Customer\Model\Url as CustomerUrl; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\ObjectManager; use Magento\Framework\App\RequestInterface; +use Magento\Framework\Controller\Result\Forward as ResultForward; +use Magento\Framework\Controller\Result\Redirect as ResultRedirect; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; +use Magento\Framework\Stdlib\CookieManagerInterface; +use Magento\Framework\Url\DecoderInterface; use Magento\Framework\Url\HostChecker; use Magento\Framework\UrlInterface; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; -use Magento\Framework\App\Config\ScopeConfigInterface; -use Magento\Framework\Controller\Result\Redirect as ResultRedirect; -use Magento\Framework\Controller\Result\Forward as ResultForward; -use Magento\Framework\Url\DecoderInterface; -use Magento\Framework\App\ObjectManager; -use Magento\Framework\Stdlib\CookieManagerInterface; /** + * Account Redirect * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) */ class Redirect { + /** URL to redirect user on successful login or registration */ const LOGIN_REDIRECT_URL = 'login_redirect'; @@ -64,10 +68,15 @@ class Redirect */ protected $resultFactory; + /** + * @var CookieMetadataFactory + */ + protected $cookieMetadataFactory; + /** * @var CookieManagerInterface */ - protected $cookieManager; + private $cookieManager; /** * @var HostChecker @@ -80,6 +89,7 @@ class Redirect private $session; /** + * @SuppressWarnings(PHPMD.ExcessiveParameterList) * @param RequestInterface $request * @param Session $customerSession * @param ScopeConfigInterface $scopeConfig @@ -88,6 +98,7 @@ class Redirect * @param DecoderInterface $urlDecoder * @param CustomerUrl $customerUrl * @param ResultFactory $resultFactory + * @param CookieMetadataFactory $cookieMetadataFactory * @param HostChecker|null $hostChecker */ public function __construct( @@ -99,6 +110,7 @@ public function __construct( DecoderInterface $urlDecoder, CustomerUrl $customerUrl, ResultFactory $resultFactory, + CookieMetadataFactory $cookieMetadataFactory, HostChecker $hostChecker = null ) { $this->request = $request; @@ -108,6 +120,7 @@ public function __construct( $this->url = $url; $this->urlDecoder = $urlDecoder; $this->customerUrl = $customerUrl; + $this->cookieMetadataFactory = $cookieMetadataFactory; $this->resultFactory = $resultFactory; $this->hostChecker = $hostChecker ?: ObjectManager::getInstance()->get(HostChecker::class); } @@ -238,7 +251,8 @@ private function applyRedirect($url) /** * Get Cookie manager. For release backward compatibility. * - * @deprecated 100.0.10 + * @deprecated 100.0.10 This is legacy method to pass login_redirect cookie + * @see Magento/Checkout/view/frontend/web/js/sidebar.js * @return CookieManagerInterface */ protected function getCookieManager() @@ -252,7 +266,8 @@ protected function getCookieManager() /** * Set cookie manager. For unit tests. * - * @deprecated 100.0.10 + * @deprecated 100.0.10 This is legacy method to pass login_redirect cookie + * @see Magento/Checkout/view/frontend/web/js/sidebar.js * @param object $value * @return void */ @@ -264,6 +279,8 @@ public function setCookieManager($value) /** * Get redirect route from cookie for case of successful login/registration * + * @deprecated 100.0.10 This is legacy method to pass login_redirect cookie + * @see Magento/Checkout/view/frontend/web/js/sidebar.js * @return null|string */ public function getRedirectCookie() @@ -274,21 +291,36 @@ public function getRedirectCookie() /** * Save redirect route to cookie for case of successful login/registration * + * @deprecated 100.0.10 This is legacy method to pass login_redirect cookie + * @see Magento/Checkout/view/frontend/web/js/sidebar.js * @param string $route * @return void */ public function setRedirectCookie($route) { - $this->getCookieManager()->setPublicCookie(self::LOGIN_REDIRECT_URL, $route); + $this->getCookieManager()->setPublicCookie( + self::LOGIN_REDIRECT_URL, + $route, + $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setHttpOnly(true) + ->setDuration(3600) + ->setPath($this->storeManager->getStore()->getStorePath()) + ); } /** * Clear cookie with requested route * + * @deprecated 100.0.10 This is legacy method to pass login_redirect cookie + * @see Magento/Checkout/view/frontend/web/js/sidebar.js * @return void */ public function clearRedirectCookie() { - $this->getCookieManager()->deleteCookie(self::LOGIN_REDIRECT_URL); + $this->getCookieManager()->deleteCookie( + self::LOGIN_REDIRECT_URL, + $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setPath($this->storeManager->getStore()->getStorePath()) + ); } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php index 0138c6c709b7c..5c57012e0505c 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php @@ -11,14 +11,19 @@ use Magento\Customer\Model\Account\Redirect; use Magento\Customer\Model\Url as CustomerUrl; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; +use Magento\Framework\Stdlib\Cookie\PublicCookieMetadata; +use Magento\Framework\Stdlib\CookieManagerInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Framework\Url\HostChecker; use Magento\Store\Model\ScopeInterface; +use PHPUnit\Framework\TestCase; +use PHPUnit\FrameworkMockObject\MockObject; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class RedirectTest extends \PHPUnit\Framework\TestCase +class RedirectTest extends TestCase { /** * @var Redirect @@ -26,123 +31,119 @@ class RedirectTest extends \PHPUnit\Framework\TestCase protected $model; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\App\RequestInterface + * @var MockObject|\Magento\Framework\App\RequestInterface */ protected $request; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Customer\Model\Session + * @var MockObject|\Magento\Customer\Model\Session */ protected $customerSession; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\App\Config\ScopeConfigInterface + * @var MockObject|\Magento\Framework\App\Config\ScopeConfigInterface */ protected $scopeConfig; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Store\Model\StoreManagerInterface + * @var MockObject|\Magento\Store\Model\StoreManagerInterface */ protected $storeManager; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Store\Model\Store + * @var MockObject|\Magento\Store\Model\Store */ protected $store; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\UrlInterface + * @var MockObject|\Magento\Framework\UrlInterface */ protected $url; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Url\DecoderInterface + * @var MockObject|\Magento\Framework\Url\DecoderInterface */ protected $urlDecoder; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Customer\Model\Url + * @var MockObject|\Magento\Customer\Model\Url */ protected $customerUrl; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Controller\Result\Redirect + * @var MockObject|\Magento\Framework\Controller\Result\Redirect */ protected $resultRedirect; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Controller\Result\Forward + * @var MockObject|\Magento\Framework\Controller\Result\Forward */ protected $resultForward; /** - * @var ResultFactory | \PHPUnit_Framework_MockObject_MockObject + * @var ResultFactory|MockObject */ protected $resultFactory; /** - * @var HostChecker | \PHPUnit_Framework_MockObject_MockObject + * @var CookieMetadataFactory|MockObject + */ + protected $cookieMetadataFactory; + + /** + * @var HostChecker|MockObject */ private $hostChecker; + /** + * @inheritdoc + */ protected function setUp() { $this->request = $this->getMockForAbstractClass(\Magento\Framework\App\RequestInterface::class); - $this->customerSession = $this->getMockBuilder(\Magento\Customer\Model\Session::class) ->disableOriginalConstructor() - ->setMethods([ - 'getLastCustomerId', - 'isLoggedIn', - 'getId', - 'setLastCustomerId', - 'unsBeforeAuthUrl', - 'getBeforeAuthUrl', - 'setBeforeAuthUrl', - 'getAfterAuthUrl', - 'setAfterAuthUrl', - 'getBeforeRequestParams', - 'getBeforeModuleName', - 'getBeforeControllerName', - 'getBeforeAction', - ]) + ->setMethods( + [ + 'getLastCustomerId', + 'isLoggedIn', + 'getId', + 'setLastCustomerId', + 'unsBeforeAuthUrl', + 'getBeforeAuthUrl', + 'setBeforeAuthUrl', + 'getAfterAuthUrl', + 'setAfterAuthUrl', + 'getBeforeRequestParams', + 'getBeforeModuleName', + 'getBeforeControllerName', + 'getBeforeAction', + ] + ) ->getMock(); $this->scopeConfig = $this->getMockForAbstractClass(\Magento\Framework\App\Config\ScopeConfigInterface::class); - - $this->store = $this->getMockBuilder(\Magento\Store\Model\Store::class) - ->disableOriginalConstructor() - ->getMock(); - + $this->store = $this->createMock(\Magento\Store\Model\Store::class); $this->storeManager = $this->getMockForAbstractClass(\Magento\Store\Model\StoreManagerInterface::class); - $this->storeManager->expects($this->once()) - ->method('getStore') - ->willReturn($this->store); - $this->url = $this->getMockForAbstractClass(\Magento\Framework\UrlInterface::class); $this->urlDecoder = $this->getMockForAbstractClass(\Magento\Framework\Url\DecoderInterface::class); - $this->customerUrl = $this->getMockBuilder(\Magento\Customer\Model\Url::class) - ->setMethods(['DashboardUrl', 'getAccountUrl', 'getLoginUrl', 'getLogoutUrl', 'getDashboardUrl']) - ->disableOriginalConstructor() - ->getMock(); - - $this->resultRedirect = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->resultForward = $this->getMockBuilder(\Magento\Framework\Controller\Result\Forward::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->resultFactory = $this->getMockBuilder(\Magento\Framework\Controller\ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->hostChecker = $this->getMockBuilder(HostChecker::class) - ->disableOriginalConstructor() + ->setMethods( + [ + 'DashboardUrl', + 'getAccountUrl', + 'getLoginUrl', + 'getLogoutUrl', + 'getDashboardUrl' + ] + )->disableOriginalConstructor() ->getMock(); + $this->resultRedirect = $this->createMock(\Magento\Framework\Controller\Result\Redirect::class); + $this->resultForward = $this->createMock(\Magento\Framework\Controller\Result\Forward::class); + $this->resultFactory = $this->createMock(\Magento\Framework\Controller\ResultFactory::class); + $this->cookieMetadataFactory = $this->createMock(CookieMetadataFactory::class); + $this->hostChecker = $this->createMock(HostChecker::class); $objectManager = new ObjectManager($this); $this->model = $objectManager->getObject( \Magento\Customer\Model\Account\Redirect::class, @@ -155,12 +156,15 @@ protected function setUp() 'urlDecoder' => $this->urlDecoder, 'customerUrl' => $this->customerUrl, 'resultFactory' => $this->resultFactory, + 'cookieMetadataFactory' => $this->cookieMetadataFactory, 'hostChecker' => $this->hostChecker, ] ); } /** + * Verify get redirect method + * * @param int $customerId * @param int $lastCustomerId * @param string $referer @@ -201,6 +205,9 @@ public function testGetRedirect( ->willReturnSelf(); // Preparations for method prepareRedirectUrl() + $this->storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($this->store); $this->store->expects($this->once())->method('getBaseUrl')->willReturn($baseUrl); $this->customerSession->expects($this->any())->method('getBeforeAuthUrl')->willReturn($beforeAuthUrl); @@ -244,6 +251,8 @@ public function testGetRedirect( } /** + * Redirect data provider + * * @return array */ public function getRedirectDataProvider() @@ -292,7 +301,12 @@ public function getRedirectDataProvider() ]; } - public function testBeforeRequestParams() + /** + * Verify before request params + * + * @return void + */ + public function testBeforeRequestParams(): void { $requestParams = [ 'param1' => 'value1', @@ -302,6 +316,9 @@ public function testBeforeRequestParams() $controller = 'controller'; $action = 'action'; + $this->storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($this->store); $this->customerSession->expects($this->exactly(2)) ->method('getBeforeRequestParams') ->willReturn($requestParams); @@ -314,7 +331,6 @@ public function testBeforeRequestParams() $this->customerSession->expects($this->once()) ->method('getBeforeAction') ->willReturn($action); - $this->resultForward->expects($this->once()) ->method('setParams') ->with($requestParams) @@ -331,7 +347,6 @@ public function testBeforeRequestParams() ->method('forward') ->with($action) ->willReturnSelf(); - $this->resultFactory->expects($this->once()) ->method('create') ->with(ResultFactory::TYPE_FORWARD) @@ -340,4 +355,82 @@ public function testBeforeRequestParams() $result = $this->model->getRedirect(); $this->assertSame($this->resultForward, $result); } + + /** + * Verify set redirect cokkie method + * + * @return void + */ + public function testSetRedirectCookie(): void + { + $coockieManagerMock = $this->createMock(CookieManagerInterface::class); + $publicMetadataMock = $this->createMock(PublicCookieMetadata::class); + $routeMock = 'route'; + + $this->model->setCookieManager($coockieManagerMock); + + $this->storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($this->store); + $this->store->expects($this->once()) + ->method('getStorePath') + ->willReturn('storePath'); + $this->cookieMetadataFactory->expects($this->once()) + ->method('createPublicCookieMetadata') + ->willReturn($publicMetadataMock); + $publicMetadataMock->expects($this->once()) + ->method('setHttpOnly') + ->with(true) + ->willReturnSelf(); + $publicMetadataMock->expects($this->once()) + ->method('setDuration') + ->with(3600) + ->willReturnSelf(); + $publicMetadataMock->expects($this->once()) + ->method('setPath') + ->with('storePath') + ->willReturnSelf(); + $coockieManagerMock->expects($this->once()) + ->method('setPublicCookie') + ->with( + Redirect::LOGIN_REDIRECT_URL, + $routeMock, + $publicMetadataMock + ); + $this->model->setRedirectCookie($routeMock); + } + + /** + * Verify clear redirect cookie + * + * @return void + */ + public function testClearRedirectCookie(): void + { + $coockieManagerMock = $this->createMock(CookieManagerInterface::class); + $publicMetadataMock = $this->createMock(PublicCookieMetadata::class); + + $this->model->setCookieManager($coockieManagerMock); + + $this->storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($this->store); + $this->store->expects($this->once()) + ->method('getStorePath') + ->willReturn('storePath'); + $this->cookieMetadataFactory->expects($this->once()) + ->method('createPublicCookieMetadata') + ->willReturn($publicMetadataMock); + $publicMetadataMock->expects($this->once()) + ->method('setPath') + ->with('storePath') + ->willReturnSelf(); + $coockieManagerMock->expects($this->once()) + ->method('deleteCookie') + ->with( + Redirect::LOGIN_REDIRECT_URL, + $publicMetadataMock + ); + $this->model->clearRedirectCookie(); + } } diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Sample/DeleteHandlerTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Sample/DeleteHandlerTest.php new file mode 100644 index 0000000000000..b633c843138c5 --- /dev/null +++ b/app/code/Magento/Downloadable/Test/Unit/Model/Sample/DeleteHandlerTest.php @@ -0,0 +1,100 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Downloadable\Test\Unit\Model\Sample; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Product; +use Magento\Downloadable\Api\Data\SampleInterface; +use Magento\Downloadable\Api\SampleRepositoryInterface as SampleRepository; +use Magento\Downloadable\Model\Product\Type; +use Magento\Downloadable\Model\Sample\DeleteHandler; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +/** + * Unit Test for \Magento\Downloadable\Model\Sample\DeleteHandler + */ +class DeleteHandlerTest extends TestCase +{ + const STUB_PRODUCT_TYPE = 'simple'; + const STUB_PRODUCT_SKU = 'sku'; + const STUB_SAMPLE_ID = 1; + + /** + * @var ProductInterface|MockObject + */ + private $entityMock; + + /** + * @var SampleRepository|MockObject + */ + private $sampleRepositoryMock; + + /** + * @var DeleteHandler + */ + private $deleteHandler; + + /** + * @inheritDoc + */ + protected function setUp() + { + $this->entityMock = $this->createMock(Product::class); + $this->sampleRepositoryMock = $this->getMockBuilder(SampleRepository::class) + ->disableOriginalConstructor() + ->setMethods(['getList', 'delete']) + ->getMockForAbstractClass(); + + $this->deleteHandler = (new ObjectManagerHelper($this))->getObject( + DeleteHandler::class, + ['sampleRepository' => $this->sampleRepositoryMock] + ); + } + + /** + * Test case when provided Product has type Downloadable. + */ + public function testExecuteWithDownloadableProduct() + { + $this->entityMock->expects($this->once()) + ->method('getTypeId') + ->willReturn(Type::TYPE_DOWNLOADABLE); + $this->entityMock->expects($this->once()) + ->method('getSku') + ->willReturn(self::STUB_PRODUCT_SKU); + + $sampleMock = $this->createMock(SampleInterface::class); + $sampleMock->expects($this->once()) + ->method('getId') + ->willReturn(self::STUB_SAMPLE_ID); + + $this->sampleRepositoryMock->expects($this->once())->method('delete'); + $this->sampleRepositoryMock->expects($this->once()) + ->method('getList') + ->willReturn([$sampleMock]); + + $this->assertSame($this->entityMock, $this->deleteHandler->execute($this->entityMock)); + } + + /** + * Test case when provided Product is not Downloadable. + */ + public function testExecuteWithOtherProduct() + { + $this->entityMock->expects($this->once()) + ->method('getTypeId') + ->willReturn(self::STUB_PRODUCT_TYPE); + + $this->sampleRepositoryMock->expects($this->never())->method('getList'); + $this->sampleRepositoryMock->expects($this->never())->method('delete'); + $this->assertSame($this->entityMock, $this->deleteHandler->execute($this->entityMock)); + } +} diff --git a/app/code/Magento/MediaGallery/Test/Unit/Plugin/Wysiwyg/Images/StorageTest.php b/app/code/Magento/MediaGallery/Test/Unit/Plugin/Wysiwyg/Images/StorageTest.php new file mode 100644 index 0000000000000..0c653a9543b19 --- /dev/null +++ b/app/code/Magento/MediaGallery/Test/Unit/Plugin/Wysiwyg/Images/StorageTest.php @@ -0,0 +1,176 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\MediaGallery\Test\Unit\Plugin\Wysiwyg\Images; + +use Magento\Cms\Model\Wysiwyg\Images\Storage as StorageSubject; +use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Directory\ReadInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\MediaGallery\Plugin\Wysiwyg\Images\Storage; +use Magento\MediaGalleryApi\Model\Asset\Command\DeleteByPathInterface; +use Magento\MediaGalleryApi\Model\Asset\Command\GetByPathInterface; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; + +/** + * Unit test for \Magento\MediaGallery\Plugin\Wysiwyg\Images\Storage + */ +class StorageTest extends TestCase +{ + const STUB_TARGET = '/stub/test.png'; + const STUB_RELATIVE_PATH = 'test.png'; + + /** + * @var Storage + */ + private $storage; + + /** + * @var GetByPathInterface|MockObject + */ + private $getMediaAssetByPathMock; + + /** + * @var DeleteByPathInterface|MockObject + */ + private $deleteMediaAssetByPathMock; + + /** + * @var Filesystem|MockObject + */ + private $filesystemMock; + + /** + * @var LoggerInterface|MockObject + */ + private $loggerMock; + + /** + * @var StorageSubject|MockObject + */ + private $storageSubjectMock; + + /** + * @var ReadInterface|MockObject + */ + private $readInterfaceMock; + + /** + * @inheritDoc + */ + protected function setUp() + { + $this->storageSubjectMock = $this->createMock(StorageSubject::class); + $this->filesystemMock = $this->createMock(Filesystem::class); + $this->getMediaAssetByPathMock = $this->createMock(GetByPathInterface::class); + $this->deleteMediaAssetByPathMock = $this->getMockBuilder(DeleteByPathInterface::class) + ->disableOriginalConstructor() + ->setMethods(['execute']) + ->getMockForAbstractClass(); + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->setMethods(['critical']) + ->getMockForAbstractClass(); + $this->readInterfaceMock = $this->getMockBuilder(ReadInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getRelativePath']) + ->getMockForAbstractClass(); + + $this->storage = (new ObjectManagerHelper($this))->getObject( + Storage::class, + [ + 'getMediaAssetByPath' => $this->getMediaAssetByPathMock, + 'deleteMediaAssetByPath' => $this->deleteMediaAssetByPathMock, + 'filesystem' => $this->filesystemMock, + 'logger' => $this->loggerMock + ] + ); + } + + /** + * Test case when an exception is thrown during the method execution. + */ + public function testAfterDeleteFileExpectsDeleteMediaAssetExecuted() + { + $this->setupMocksToReturnCorrectRelativePath(); + $this->deleteMediaAssetByPathMock->expects($this->once())->method('execute'); + $this->loggerMock->expects($this->never())->method('critical'); + + $this->executeOriginalMethodWithCorrectTarget(); + } + + /** + * Test case when an exception is thrown during the method execution. + */ + public function testAfterDeleteFileWithException() + { + $this->setupMocksToReturnCorrectRelativePath(); + $this->deleteMediaAssetByPathMock->expects($this->once()) + ->method('execute') + ->willThrowException(new \Exception()); + $this->loggerMock->expects($this->once())->method('critical'); + + $this->executeOriginalMethodWithCorrectTarget(); + } + + /** + * Test case when the target is not a string. + */ + public function testAfterDeleteFileWhenTargetIsNotString() + { + $target = []; + $this->filesystemMock->expects($this->never())->method('getDirectoryRead'); + $this->deleteMediaAssetByPathMock->expects($this->never())->method('execute'); + $this->assertSame( + $this->storageSubjectMock, + $this->storage->afterDeleteFile($this->storageSubjectMock, $this->storageSubjectMock, $target) + ); + } + + /** + * Test case when there is no Relative Path which is need to be deleted. + */ + public function testAfterDeleteFileWhenRelativePathIsEmpty() + { + $this->readInterfaceMock->expects($this->once()) + ->method('getRelativePath') + ->willReturn(''); + $this->filesystemMock->expects($this->once()) + ->method('getDirectoryRead') + ->willReturn($this->readInterfaceMock); + + $this->deleteMediaAssetByPathMock->expects($this->never())->method('execute'); + $this->executeOriginalMethodWithCorrectTarget(); + } + + /** + * Call the tested method + */ + private function executeOriginalMethodWithCorrectTarget() + { + $this->assertSame( + $this->storageSubjectMock, + $this->storage->afterDeleteFile($this->storageSubjectMock, $this->storageSubjectMock, self::STUB_TARGET) + ); + } + + /** + * Set mocks in order to return the relative path + */ + private function setupMocksToReturnCorrectRelativePath() + { + $this->readInterfaceMock->expects($this->once()) + ->method('getRelativePath') + ->willReturn(self::STUB_RELATIVE_PATH); + $this->filesystemMock->expects($this->once()) + ->method('getDirectoryRead') + ->willReturn($this->readInterfaceMock); + } +} diff --git a/app/code/Magento/Msrp/view/base/web/js/msrp.js b/app/code/Magento/Msrp/view/base/web/js/msrp.js index 65af87d85de51..db407fbb22ce0 100644 --- a/app/code/Magento/Msrp/view/base/web/js/msrp.js +++ b/app/code/Magento/Msrp/view/base/web/js/msrp.js @@ -299,8 +299,9 @@ define([ * @param {Event} event * @param {mixed} priceIndex * @param {Object} prices + * @param {Object|undefined} $priceBox */ - onUpdateMsrpPrice: function onUpdateMsrpPrice(event, priceIndex, prices) { + onUpdateMsrpPrice: function onUpdateMsrpPrice(event, priceIndex, prices, $priceBox) { var defaultMsrp, defaultPrice, @@ -322,18 +323,20 @@ define([ finalPrice = prices[priceIndex].finalPrice.amount; if (msrpPrice === null || msrpPrice <= finalPrice) { - this.updateNonMsrpPrice(priceUtils.formatPrice(finalPrice)); + this.updateNonMsrpPrice(priceUtils.formatPrice(finalPrice), $priceBox); } else { this.updateMsrpPrice( priceUtils.formatPrice(finalPrice), priceUtils.formatPrice(msrpPrice), - false); + false, + $priceBox); } } else { this.updateMsrpPrice( priceUtils.formatPrice(defaultPrice), priceUtils.formatPrice(defaultMsrp), - true); + true, + $priceBox); } }, @@ -343,13 +346,14 @@ define([ * @param {String} finalPrice * @param {String} msrpPrice * @param {Boolean} useDefaultPrice + * @param {Object|undefined} $priceBox */ - updateMsrpPrice: function (finalPrice, msrpPrice, useDefaultPrice) { + updateMsrpPrice: function (finalPrice, msrpPrice, useDefaultPrice, $priceBox) { var options = this.tierOptions || this.options; - $(this.options.fallbackPriceContainer).hide(); - $(this.options.displayPriceContainer).show(); - $(this.options.mapInfoLinks).show(); + $(this.options.fallbackPriceContainer, $priceBox).hide(); + $(this.options.displayPriceContainer, $priceBox).show(); + $(this.options.mapInfoLinks, $priceBox).show(); if (useDefaultPrice || !this.wasOpened) { if (this.$popup) { @@ -357,14 +361,14 @@ define([ this.$popup.find(this.options.priceLabelId).html(options.realPrice); } - $(this.options.displayPriceElement).html(msrpPrice); + $(this.options.displayPriceElement, $priceBox).html(msrpPrice); this.wasOpened = true; } if (!useDefaultPrice) { this.$popup.find(this.options.msrpPriceElement).html(msrpPrice); this.$popup.find(this.options.priceElement).html(finalPrice); - $(this.options.displayPriceElement).html(msrpPrice); + $(this.options.displayPriceElement, $priceBox).html(msrpPrice); } }, @@ -372,12 +376,13 @@ define([ * Display non MAP price for irrelevant products * * @param {String} price + * @param {Object|undefined} $priceBox */ - updateNonMsrpPrice: function (price) { - $(this.options.fallbackPriceElement).html(price); - $(this.options.displayPriceContainer).hide(); - $(this.options.mapInfoLinks).hide(); - $(this.options.fallbackPriceContainer).show(); + updateNonMsrpPrice: function (price, $priceBox) { + $(this.options.fallbackPriceElement, $priceBox).html(price); + $(this.options.displayPriceContainer, $priceBox).hide(); + $(this.options.mapInfoLinks, $priceBox).hide(); + $(this.options.fallbackPriceContainer, $priceBox).show(); }, /** diff --git a/app/code/Magento/Reports/Test/Unit/Observer/SendfriendProductObserverTest.php b/app/code/Magento/Reports/Test/Unit/Observer/SendfriendProductObserverTest.php new file mode 100644 index 0000000000000..88c30ec5bc236 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Observer/SendfriendProductObserverTest.php @@ -0,0 +1,93 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Reports\Test\Unit\Observer; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Framework\Event\Observer; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Reports\Model\Event; +use Magento\Reports\Model\ReportStatus; +use Magento\Reports\Observer\EventSaver; +use Magento\Reports\Observer\SendfriendProductObserver; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +/** + * Unit test for \Magento\Reports\Observer\SendfriendProductObserver + */ +class SendfriendProductObserverTest extends TestCase +{ + /** + * @var Observer|MockObject + */ + private $eventObserverMock; + + /** + * @var EventSaver|MockObject + */ + private $eventSaverMock; + + /** + * @var ReportStatus|MockObject + */ + private $reportStatusMock; + + /** + * @var SendfriendProductObserver + */ + private $observer; + + /** + * @inheritDoc + */ + protected function setUp() + { + $this->eventObserverMock = $this->createMock(Observer::class); + $this->eventSaverMock = $this->createMock(EventSaver::class); + $this->reportStatusMock = $this->createMock(ReportStatus::class); + + $this->observer = (new ObjectManagerHelper($this))->getObject( + SendfriendProductObserver::class, + ['eventSaver' => $this->eventSaverMock, 'reportStatus' => $this->reportStatusMock] + ); + } + + /** + * Test case when report is disabled in config. + */ + public function testExecuteWhenReportIsDisabled() + { + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_PRODUCT_SEND) + ->willReturn(false); + + $this->eventSaverMock->expects($this->never())->method('save'); + $this->observer->execute($this->eventObserverMock); + } + + /** + * Test case when report is enabled in config. + */ + public function testExecuteWhenReportIsEnabled() + { + $eventMock = $this->createPartialMock(Event::class, ['getProduct']); + $eventMock->expects($this->once()) + ->method('getProduct') + ->willReturn($this->createMock(ProductInterface::class)); + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_PRODUCT_SEND) + ->willReturn(true); + $this->eventObserverMock->expects($this->once())->method('getEvent')->willReturn($eventMock); + + $this->eventSaverMock->expects($this->once())->method('save'); + $this->observer->execute($this->eventObserverMock); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Observer/WishlistAddProductObserverTest.php b/app/code/Magento/Reports/Test/Unit/Observer/WishlistAddProductObserverTest.php new file mode 100644 index 0000000000000..5b282bb60ece2 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Observer/WishlistAddProductObserverTest.php @@ -0,0 +1,93 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Reports\Test\Unit\Observer; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Framework\Event\Observer; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Reports\Model\Event; +use Magento\Reports\Model\ReportStatus; +use Magento\Reports\Observer\EventSaver; +use Magento\Reports\Observer\WishlistAddProductObserver; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +/** + * Unit test for \Magento\Reports\Observer\WishlistAddProductObserver + */ +class WishlistAddProductObserverTest extends TestCase +{ + /** + * @var Observer|MockObject + */ + private $eventObserverMock; + + /** + * @var EventSaver|MockObject + */ + private $eventSaverMock; + + /** + * @var ReportStatus|MockObject + */ + private $reportStatusMock; + + /** + * @var WishlistAddProductObserver + */ + private $observer; + + /** + * @inheritDoc + */ + protected function setUp() + { + $this->eventObserverMock = $this->createMock(Observer::class); + $this->eventSaverMock = $this->createMock(EventSaver::class); + $this->reportStatusMock = $this->createMock(ReportStatus::class); + + $this->observer = (new ObjectManagerHelper($this))->getObject( + WishlistAddProductObserver::class, + ['eventSaver' => $this->eventSaverMock, 'reportStatus' => $this->reportStatusMock] + ); + } + + /** + * Test case when report is disabled in config. + */ + public function testExecuteWhenReportIsDisabled() + { + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_PRODUCT_TO_WISHLIST) + ->willReturn(false); + $this->eventSaverMock->expects($this->never())->method('save'); + $this->observer->execute($this->eventObserverMock); + } + + /** + * Test case when report is enabled in config. + */ + public function testExecuteWhenReportIsEnabled() + { + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_PRODUCT_TO_WISHLIST) + ->willReturn(true); + + $eventMock = $this->createPartialMock(Event::class, ['getProduct']); + $eventMock->expects($this->once()) + ->method('getProduct') + ->willReturn($this->createMock(ProductInterface::class)); + $this->eventObserverMock->expects($this->once())->method('getEvent')->willReturn($eventMock); + + $this->eventSaverMock->expects($this->once())->method('save'); + $this->observer->execute($this->eventObserverMock); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Observer/WishlistShareObserverTest.php b/app/code/Magento/Reports/Test/Unit/Observer/WishlistShareObserverTest.php new file mode 100644 index 0000000000000..d432fe013b138 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Observer/WishlistShareObserverTest.php @@ -0,0 +1,93 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Reports\Test\Unit\Observer; + +use Magento\Framework\Event\Observer; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Reports\Model\Event; +use Magento\Reports\Model\ReportStatus; +use Magento\Reports\Observer\EventSaver; +use Magento\Reports\Observer\WishlistShareObserver; +use Magento\Wishlist\Model\Wishlist; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +/** + * Unit test for \Magento\Reports\Observer\WishlistShareObserver + */ +class WishlistShareObserverTest extends TestCase +{ + /** + * @var Observer|MockObject + */ + private $eventObserverMock; + + /** + * @var EventSaver|MockObject + */ + private $eventSaverMock; + + /** + * @var ReportStatus|MockObject + */ + private $reportStatusMock; + + /** + * @var WishlistShareObserver + */ + private $observer; + + /** + * @inheritDoc + */ + protected function setUp() + { + $this->eventObserverMock = $this->createMock(Observer::class); + $this->eventSaverMock = $this->createMock(EventSaver::class); + $this->reportStatusMock = $this->createMock(ReportStatus::class); + + $this->observer = (new ObjectManagerHelper($this))->getObject( + WishlistShareObserver::class, + ['eventSaver' => $this->eventSaverMock, 'reportStatus' => $this->reportStatusMock] + ); + } + + /** + * Test case when report is disabled in config. + */ + public function testExecuteWhenReportIsDisabled() + { + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_WISHLIST_SHARE) + ->willReturn(false); + $this->eventSaverMock->expects($this->never())->method('save'); + $this->observer->execute($this->eventObserverMock); + } + + /** + * Test case when report is enabled in config. + */ + public function testExecuteWhenReportIsEnabled() + { + $this->reportStatusMock->expects($this->once()) + ->method('isReportEnabled') + ->with(Event::EVENT_WISHLIST_SHARE) + ->willReturn(true); + + $eventMock = $this->createPartialMock(Event::class, ['getWishlist']); + $eventMock->expects($this->once()) + ->method('getWishlist') + ->willReturn($this->createMock(Wishlist::class)); + $this->eventObserverMock->expects($this->once())->method('getEvent')->willReturn($eventMock); + + $this->eventSaverMock->expects($this->once())->method('save'); + $this->observer->execute($this->eventObserverMock); + } +} diff --git a/app/code/Magento/Swatches/view/base/web/js/swatch-renderer.js b/app/code/Magento/Swatches/view/base/web/js/swatch-renderer.js index aa7b6c7a076ea..8b5dfcd80deb4 100644 --- a/app/code/Magento/Swatches/view/base/web/js/swatch-renderer.js +++ b/app/code/Magento/Swatches/view/base/web/js/swatch-renderer.js @@ -723,7 +723,9 @@ define([ $label = $parent.find('.' + $widget.options.classes.attributeSelectedOptionLabelClass), attributeId = $parent.attr('attribute-id'), $input = $parent.find('.' + $widget.options.classes.attributeInput), - checkAdditionalData = JSON.parse(this.options.jsonSwatchConfig[attributeId]['additional_data']); + checkAdditionalData = JSON.parse(this.options.jsonSwatchConfig[attributeId]['additional_data']), + $priceBox = $widget.element.parents($widget.options.selectorProduct) + .find(this.options.selectorProductPrice); if ($widget.inProductList) { $input = $widget.productForm.find( @@ -751,16 +753,15 @@ define([ $widget._Rebuild(); - if ($widget.element.parents($widget.options.selectorProduct) - .find(this.options.selectorProductPrice).is(':data(mage-priceBox)') - ) { + if ($priceBox.is(':data(mage-priceBox)')) { $widget._UpdatePrice(); } $(document).trigger('updateMsrpPriceBlock', [ this._getSelectedOptionPriceIndex(), - $widget.options.jsonConfig.optionPrices + $widget.options.jsonConfig.optionPrices, + $priceBox ]); if (parseInt(checkAdditionalData['update_product_preview_image'], 10) === 1) { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php index 57aeda3295268..74f8e3c2e37dd 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php @@ -233,6 +233,10 @@ public function testSetDisabledPaymentOnCart() public function dataProviderSetPaymentMethodWithoutRequiredParameters(): array { return [ + 'missed_cart_id' => [ + 'cart_id: "", payment_method: {code: "' . Checkmo::PAYMENT_METHOD_CHECKMO_CODE . '"}', + 'Required parameter "cart_id" is missing.' + ], 'missed_payment_method_code' => [ 'cart_id: "cart_id_value", payment_method: {code: ""}', 'Required parameter "code" for "payment_method" is missing.' diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php index c3e35f0bf80e8..08c7bdd8dbc52 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php @@ -183,6 +183,10 @@ public function testSetPaymentMethodWithoutRequiredParameters(string $input, str public function dataProviderSetPaymentMethodWithoutRequiredParameters(): array { return [ + 'missed_cart_id' => [ + 'cart_id: "", payment_method: {code: "' . Checkmo::PAYMENT_METHOD_CHECKMO_CODE . '"}', + 'Required parameter "cart_id" is missing.' + ], 'missed_payment_method_code' => [ 'cart_id: "cart_id_value", payment_method: {code: ""}', 'Required parameter "code" for "payment_method" is missing.' diff --git a/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Driver/FileTest.php b/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Driver/FileTest.php index 5f53e62165502..c8719ea7e0a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Driver/FileTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Driver/FileTest.php @@ -5,11 +5,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Framework\Filesystem\Driver; use Magento\Framework\Exception\FileSystemException; +use PHPUnit\Framework\TestCase; -class FileTest extends \PHPUnit\Framework\TestCase +/** + * Verify File class + */ +class FileTest extends TestCase { /** * @var File @@ -50,16 +56,20 @@ public function setUp() /** * @inheritdoc + * + * @return void */ - protected function tearDown() + protected function tearDown(): void { $this->removeGeneratedDirectory(); } /** * Tests directory recursive read. + * + * @return void */ - public function testReadDirectoryRecursively() + public function testReadDirectoryRecursively(): void { $paths = [ 'foo/bar', @@ -77,9 +87,10 @@ public function testReadDirectoryRecursively() /** * Tests directory reading exception. * + * @return void * @expectedException \Magento\Framework\Exception\FileSystemException */ - public function testReadDirectoryRecursivelyFailure() + public function testReadDirectoryRecursivelyFailure(): void { $this->driver->readDirectoryRecursively($this->getTestPath('not-existing-directory')); } @@ -88,8 +99,9 @@ public function testReadDirectoryRecursivelyFailure() * Tests of directory creating. * * @throws FileSystemException + * @return void */ - public function testCreateDirectory() + public function testCreateDirectory(): void { $generatedPath = $this->getTestPath('generated/roo/bar/baz/foo'); $generatedPathBase = $this->getTestPath('generated'); @@ -123,6 +135,18 @@ public function testSymlinks(): void self::assertTrue($this->driver->deleteDirectory($linkName)); } + /** + * Verify file put content without content. + * + * @return void + * @throws FileSystemException + */ + public function testFilePutWithoutContents(): void + { + $path = $this->absolutePath . 'foo/file_three.txt'; + $this->assertEquals(0, $this->driver->filePutContents($path, '')); + } + /** * Remove generated directories. * diff --git a/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Io/FileTest.php b/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Io/FileTest.php new file mode 100644 index 0000000000000..39503ec87f8e6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Io/FileTest.php @@ -0,0 +1,92 @@ +<?php +/** + * Test for \Magento\Framework\Filesystem\Io\File + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\Filesystem\Io; + +use Magento\Framework\Exception\FileSystemException; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Verify filesystem client + */ +class FileTest extends TestCase +{ + + /** + * @var File + */ + private $io; + + /** + * @var String + */ + private $absolutePath; + + /** + * @var String + */ + private $generatedPath; + + /** + * @inheritDoc + */ + public function setUp() + { + $this->io = new File(); + $this->absolutePath = Bootstrap::getInstance()->getAppTempDir(); + $this->generatedPath = $this->getTestPath('/rollback_test_'); + $this->io->mkdir($this->generatedPath); + } + + /** + * @inheritdoc + * + * @return void + */ + protected function tearDown(): void + { + $this->removeGeneratedDirectory(); + } + + /** + * Verify file put without content. + * + * @return void + */ + public function testWrite(): void + { + $path = $this->generatedPath . '/file_three.txt'; + $this->assertEquals(0, $this->io->write($path, '', 0444)); + $this->assertEquals(false, is_writable($path)); + } + + /** + * Returns relative path for the test. + * + * @param $relativePath + * @return string + */ + protected function getTestPath($relativePath): string + { + return $this->absolutePath . $relativePath . time(); + } + + /** + * Remove generated directories. + * + * @return void + */ + private function removeGeneratedDirectory(): void + { + if (is_dir($this->generatedPath)) { + $this->io->rmdir($this->generatedPath, true); + } + } +} diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/File.php b/lib/internal/Magento/Framework/Filesystem/Driver/File.php index 59c9775d73a0a..4d5ba7a1918ce 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/File.php @@ -13,9 +13,8 @@ use Magento\Framework\Filesystem\Glob; /** - * Class File + * Driver file class * - * @package Magento\Framework\Filesystem\Driver * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ class File implements DriverInterface @@ -552,7 +551,7 @@ public function touch($path, $modificationTime = null) public function filePutContents($path, $content, $mode = null) { $result = @file_put_contents($this->getScheme() . $path, $content, $mode); - if (!$result) { + if ($result === false) { throw new FileSystemException( new \Magento\Framework\Phrase( 'The specified "%1" file couldn\'t be written. %2', @@ -593,12 +592,15 @@ public function fileOpen($path, $mode) */ public function fileReadLine($resource, $length, $ending = null) { + // phpcs:disable $result = @stream_get_line($resource, $length, $ending); + // phpcs:enable if (false === $result) { throw new FileSystemException( new \Magento\Framework\Phrase('File cannot be read %1', [$this->getWarningMessage()]) ); } + return $result; } @@ -976,7 +978,7 @@ public function getRealPathSafety($path) //Removing redundant directory separators. $path = preg_replace( - '/\\' .DIRECTORY_SEPARATOR .'\\' .DIRECTORY_SEPARATOR .'+/', + '/\\' . DIRECTORY_SEPARATOR . '\\' . DIRECTORY_SEPARATOR . '+/', DIRECTORY_SEPARATOR, $path ); diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/Http.php b/lib/internal/Magento/Framework/Filesystem/Driver/Http.php index f32624f4e7513..0191d5d8a3040 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/Http.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/Http.php @@ -11,7 +11,7 @@ use Magento\Framework\Exception\FileSystemException; /** - * Class Http + * Http driver file class. */ class Http extends File { @@ -109,7 +109,7 @@ public function fileGetContents($path, $flags = null, $context = null) public function filePutContents($path, $content, $mode = null, $context = null) { $result = @file_put_contents($this->getScheme() . $path, $content, $mode, $context); - if (!$result) { + if ($result === false) { throw new FileSystemException( new \Magento\Framework\Phrase( 'The specified "%1" file couldn\'t be written. %2', @@ -196,8 +196,13 @@ public function fileOpen($path, $mode) */ public function fileReadLine($resource, $length, $ending = null) { - $result = @stream_get_line($resource, $length, $ending); - + try { + $result = @stream_get_line($resource, $length, $ending); + } catch (\Exception $e) { + throw new FileSystemException( + new \Magento\Framework\Phrase('Stream get line failed %1', [$e->getMessage()]) + ); + } return $result; } diff --git a/lib/internal/Magento/Framework/Filesystem/Io/File.php b/lib/internal/Magento/Framework/Filesystem/Io/File.php index 8fec7f7630257..2e81325c8ec57 100644 --- a/lib/internal/Magento/Framework/Filesystem/Io/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Io/File.php @@ -3,10 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Framework\Filesystem\Io; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Phrase; + /** * Filesystem client + * * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ class File extends AbstractIo @@ -186,7 +191,7 @@ public function streamWriteCsv(array $row, $delimiter = ',', $enclosure = '"') * Security enhancement for CSV data processing by Excel-like applications. * @see https://bugzilla.mozilla.org/show_bug.cgi?id=1054702 * - * @var $value string|\Magento\Framework\Phrase + * @var $value string|Phrase */ foreach ($row as $key => $value) { if (!is_string($value)) { @@ -201,6 +206,7 @@ public function streamWriteCsv(array $row, $delimiter = ',', $enclosure = '"') /** * Close an open file pointer + * * Set chmod on a file * * @return bool @@ -328,6 +334,7 @@ public function rmdir($dir, $recursive = false) /** * Delete a directory recursively + * * @param string $dir * @param bool $recursive * @return bool @@ -405,8 +412,8 @@ public function pwd() * * @param string $dir * @return true - * @throws \Exception * @SuppressWarnings(PHPMD.ShortMethodName) + * @throws LocalizedException */ public function cd($dir) { @@ -415,7 +422,9 @@ public function cd($dir) $this->_cwd = realpath($dir); return true; } else { - throw new \Exception('Unable to list current working directory.'); + throw new LocalizedException( + new Phrase('Unable to list current working directory.') + ); } } @@ -479,7 +488,7 @@ public function write($filename, $src, $mode = null) } else { $result = @file_put_contents($filename, $src); } - if ($mode !== null && $result) { + if ($mode !== null && $result !== false) { @chmod($filename, $mode); } $this->_iwd(); @@ -553,7 +562,7 @@ public function createDestinationDir($path) * @param string $folder * @param int $mode * @return true - * @throws \Exception + * @throws LocalizedException */ public function checkAndCreateFolder($folder, $mode = 0777) { @@ -564,7 +573,9 @@ public function checkAndCreateFolder($folder, $mode = 0777) $this->checkAndCreateFolder(dirname($folder), $mode); } if (!is_dir($folder) && !$this->mkdir($folder, $mode)) { - throw new \Exception("Unable to create directory '{$folder}'. Access forbidden."); + throw new LocalizedException( + new Phrase("Unable to create directory '{$folder}'. Access forbidden.") + ); } return true; } @@ -672,7 +683,7 @@ public static function chmodRecursive($dir, $mode) * * @param string|null $grep * @return array - * @throws \Exception + * @throws LocalizedException * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.ShortMethodName) */ @@ -685,7 +696,9 @@ public function ls($grep = null) } elseif (is_dir($this->_iwd)) { $dir = $this->_iwd; } else { - throw new \Exception('Unable to list current working directory.'); + throw new LocalizedException( + new Phrase('Unable to list current working directory.') + ); } $list = []; @@ -742,7 +755,9 @@ public function ls($grep = null) } closedir($dirHandler); } else { - throw new \Exception('Unable to list current working directory. Access forbidden.'); + throw new LocalizedException( + new Phrase('Unable to list current working directory. Access forbidden.') + ); } return $list; diff --git a/lib/internal/Magento/Framework/Filesystem/Test/Unit/Driver/HttpTest.php b/lib/internal/Magento/Framework/Filesystem/Test/Unit/Driver/HttpTest.php index 8fc57f458334e..a851d30ef930e 100644 --- a/lib/internal/Magento/Framework/Filesystem/Test/Unit/Driver/HttpTest.php +++ b/lib/internal/Magento/Framework/Filesystem/Test/Unit/Driver/HttpTest.php @@ -3,12 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Framework\Filesystem\Test\Unit\Driver; -use \Magento\Framework\Filesystem\Driver\Http; +use Magento\Framework\Filesystem\Driver\Http; +use PHPUnit\Framework\TestCase; -class HttpTest extends \PHPUnit\Framework\TestCase +/** + * Verify HttpTest class. + */ +class HttpTest extends TestCase { /** @var array Result of get_headers() function */ public static $headers; @@ -22,6 +27,9 @@ class HttpTest extends \PHPUnit\Framework\TestCase /** @var bool Result of fsockopen() function */ public static $fsockopen; + /** + * @inheritDoc + */ protected function setUp() { require_once __DIR__ . '/../_files/http_mock.php'; @@ -33,35 +41,49 @@ protected function setUp() } /** + * Verify IsExists. + * + * @param string $status + * @param bool $result * @dataProvider dataProviderForTestIsExists + * @return void */ - public function testIsExists($status, $result) + public function testIsExists(string $status, bool $result): void { self::$headers = [$status]; $this->assertEquals($result, (new Http())->isExists('')); } /** + * Data provider fot test IsExists. + * * @return array */ - public function dataProviderForTestIsExists() + public function dataProviderForTestIsExists(): array { return [['200 OK', true], ['404 Not Found', false]]; } /** + * Verify Stat. + * + * @param array $headers + * @param array $result * @dataProvider dataProviderForTestStat + * @return void */ - public function testStat($headers, $result) + public function testStat(array $headers, array $result): void { self::$headers = $headers; $this->assertEquals($result, (new Http())->stat('')); } /** + * Data provider for test Stat. + * * @return array */ - public function dataProviderForTestStat() + public function dataProviderForTestStat(): array { $headers1 = [ 'Content-Length' => 128, @@ -106,45 +128,87 @@ protected function _resultForStat($nonEmptyValues = []) return array_merge($result, $nonEmptyValues); } - public function testFileGetContents() + /** + * Verify File get contents. + * + * @throws \Magento\Framework\Exception\FileSystemException + * @return void + */ + public function testFileGetContents(): void { $content = 'some content'; self::$fileGetContents = $content; $this->assertEquals($content, (new Http())->fileGetContents('')); } - public function testFileGetContentsNoContent() + /** + * Verify File get contents without content. + * + * @throws \Magento\Framework\Exception\FileSystemException + * @return void + */ + public function testFileGetContentsNoContent(): void { $content = ''; self::$fileGetContents = ''; $this->assertEquals($content, (new Http())->fileGetContents('')); } - public function testFilePutContents() + /** + * Verify File put contents. + * + * @throws \Magento\Framework\Exception\FileSystemException + * @return void + */ + public function testFilePutContents(): void { self::$filePutContents = true; $this->assertTrue((new Http())->filePutContents('', '')); } /** + * Verify file put contents without content. + * + * @throws \Magento\Framework\Exception\FileSystemException + * @return void + */ + public function testFilePutContentsNoContent(): void + { + self::$filePutContents = 0; + $this->assertEquals(0, (new Http())->filePutContents('', '')); + } + + /** + * Verify File put contents if is fail. + * * @expectedException \Magento\Framework\Exception\FileSystemException + * @return void */ - public function testFilePutContentsFail() + public function testFilePutContentsFail(): void { self::$filePutContents = false; (new Http())->filePutContents('', ''); } /** + * Verify File open invalid url. + * * @expectedException \Magento\Framework\Exception\FileSystemException * @expectedExceptionMessage The download URL is incorrect. Verify and try again. + * @return void */ - public function testFileOpenInvalidUrl() + public function testFileOpenInvalidUrl(): void { (new Http())->fileOpen('', ''); } - public function testFileOpen() + /** + * Verify File open. + * + * @throws \Magento\Framework\Exception\FileSystemException + * @return void + */ + public function testFileOpen(): void { $fsockopenResult = 'resource'; self::$fsockopen = $fsockopenResult; diff --git a/lib/internal/Magento/Framework/Locale/Config.php b/lib/internal/Magento/Framework/Locale/Config.php index c2d0147c7fdc8..08f66e25be773 100644 --- a/lib/internal/Magento/Framework/Locale/Config.php +++ b/lib/internal/Magento/Framework/Locale/Config.php @@ -108,6 +108,7 @@ class Config implements \Magento\Framework\Locale\ConfigInterface 'es_VE', /*Spanish (Venezuela)*/ 'en_IE', /*English (Ireland)*/ 'es_BO', /*Spanish (Bolivia)*/ + 'es_US', /*Spanish (United States)*/ ]; /**