diff --git a/src/Setup/Actions.php b/src/Setup/Actions.php index 8dc1a68..76b64cb 100644 --- a/src/Setup/Actions.php +++ b/src/Setup/Actions.php @@ -15,23 +15,35 @@ declare(strict_types=1); namespace D3\Webauthn\Setup; +use D3\TestingTools\Production\IsMockable; use Doctrine\DBAL\Driver\Exception as DoctrineDriverException; -use Doctrine\DBAL\Exception as DoctrineException; -use Doctrine\DBAL\Query\QueryBuilder; use Exception; +use OxidEsales\Eshop\Application\Controller\FrontendController; +use OxidEsales\Eshop\Core\Config; +use OxidEsales\Eshop\Core\Database\Adapter\DatabaseInterface; use OxidEsales\Eshop\Core\DatabaseProvider; use OxidEsales\Eshop\Core\DbMetaDataHandler; use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; use OxidEsales\Eshop\Core\Exception\DatabaseErrorException; -use OxidEsales\Eshop\Core\Registry; +use OxidEsales\Eshop\Core\SeoEncoder; +use OxidEsales\Eshop\Core\Utils; use OxidEsales\Eshop\Core\UtilsView; use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory; -use OxidEsales\EshopCommunity\Internal\Framework\Database\QueryBuilderFactoryInterface; +use OxidEsales\EshopCommunity\Internal\Framework\Module\Configuration\Bridge\ShopConfigurationDaoBridgeInterface; +use OxidEsales\EshopCommunity\Internal\Framework\Module\Configuration\DataObject\ModuleConfiguration; +use OxidEsales\EshopCommunity\Internal\Framework\Module\Configuration\Exception\ModuleConfigurationNotFoundException; use Psr\Container\ContainerExceptionInterface; +use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; class Actions { + use IsMockable; + + public $seo_de = 'sicherheitsschluessel'; + public $seo_en = 'en/key-authentication'; + public $stdClassName = 'd3_account_webauthn'; + /** * SQL statement, that will be executed only at the first time of module installation. * @@ -73,11 +85,19 @@ class Actions */ public function tableExists(string $sTableName): bool { - $oDbMetaDataHandler = oxNew(DbMetaDataHandler::class ); - + $oDbMetaDataHandler = $this->d3GetMockableOxNewObject(DbMetaDataHandler::class); return $oDbMetaDataHandler->tableExists($sTableName); } + /** + * @return DatabaseInterface|null + * @throws DatabaseConnectionException + */ + protected function d3GetDb(): ?DatabaseInterface + { + return DatabaseProvider::getDb(); + } + /** * Executes given sql statement. * @@ -87,7 +107,7 @@ class Actions */ public function executeSQL(string $sSQL) { - DatabaseProvider::getDb()->execute($sSQL); + $this->d3GetDb()->execute($sSQL); } /** @@ -100,8 +120,7 @@ class Actions */ public function fieldExists(string $sFieldName, string $sTableName): bool { - $oDbMetaDataHandler = oxNew(DbMetaDataHandler::class ); - + $oDbMetaDataHandler = $this->d3GetMockableOxNewObject(DbMetaDataHandler::class); return $oDbMetaDataHandler->fieldExists($sFieldName, $sTableName); } @@ -110,7 +129,7 @@ class Actions */ public function regenerateViews() { - $oDbMetaDataHandler = oxNew(DbMetaDataHandler::class ); + $oDbMetaDataHandler = $this->d3GetMockableOxNewObject(DbMetaDataHandler::class); $oDbMetaDataHandler->updateViews(); } @@ -119,64 +138,94 @@ class Actions */ public function clearCache() { - /** @var UtilsView $oUtilsView */ - $oUtilsView = Registry::getUtilsView(); - $sSmartyDir = $oUtilsView->getSmartyDir(); - - if ($sSmartyDir && is_readable($sSmartyDir)) { - foreach (glob($sSmartyDir . '*') as $sFile) { - if (!is_dir($sFile)) { - @unlink($sFile); - } - } + try { + $oUtils = $this->d3GetMockableRegistryObject( Utils::class ); + $oUtils->resetTemplateCache( $this->getModuleTemplates() ); + $oUtils->resetLanguageCache(); + } catch (ContainerExceptionInterface|NotFoundExceptionInterface|ModuleConfigurationNotFoundException $e) { + $this->d3GetMockableLogger()->error($e->getMessage(), [$this]); + $this->d3GetMockableRegistryObject(UtilsView::class)->addErrorToDisplay($e); } } + /** + * @return array + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + * @throws ModuleConfigurationNotFoundException + */ + protected function getModuleTemplates(): array + { + $container = $this->getDIContainer(); + $shopConfiguration = $container->get(ShopConfigurationDaoBridgeInterface::class)->get(); + $moduleConfiguration = $shopConfiguration->getModuleConfiguration('d3webauthn'); + + return array_unique(array_merge( + $this->getModuleTemplatesFromTemplates($moduleConfiguration), + $this->getModuleTemplatesFromBlocks($moduleConfiguration) + )); + } + + /** + * @param ModuleConfiguration $moduleConfiguration + * + * @return array + */ + protected function getModuleTemplatesFromTemplates(ModuleConfiguration $moduleConfiguration): array + { + /** @var $template ModuleConfiguration\Template */ + return array_map( + function($template) { + return $template->getTemplateKey(); + }, + $moduleConfiguration->getTemplates() + ); + } + + /** + * @param ModuleConfiguration $moduleConfiguration + * + * @return array + */ + protected function getModuleTemplatesFromBlocks(ModuleConfiguration $moduleConfiguration): array + { + /** @var $templateBlock ModuleConfiguration\TemplateBlock */ + return array_map( + function($templateBlock) { + return basename($templateBlock->getShopTemplatePath()); + }, + $moduleConfiguration->getTemplateBlocks() + ); + } + /** * @return void */ public function seoUrl() { try { - if (!self::hasSeoUrl()) { - self::createSeoUrl(); + if (!$this->hasSeoUrl()) { + $this->createSeoUrl(); } } catch (Exception|NotFoundExceptionInterface|DoctrineDriverException|ContainerExceptionInterface $e) { - Registry::getUtilsView()->addErrorToDisplay('error wile creating SEO URLs: '.$e->getMessage()); + $this->d3GetMockableLogger()->error($e->getMessage(), [$this]); + $this->d3GetMockableRegistryObject(UtilsView::class) + ->addErrorToDisplay('error wile creating SEO URLs: '.$e->getMessage()); } } /** * @return bool - * @throws DoctrineDriverException - * @throws DoctrineException - * @throws ContainerExceptionInterface - * @throws NotFoundExceptionInterface */ public function hasSeoUrl(): bool { - /** @var QueryBuilder $qb */ - $qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create(); - $qb->select('1') - ->from('oxseo') - ->where( - $qb->expr()->and( - $qb->expr()->eq( - 'oxstdurl', - $qb->createNamedParameter('index.php?cl=d3_account_webauthn') - ), - $qb->expr()->eq( - 'oxshopid', - $qb->createNamedParameter(Registry::getConfig()->getShopId()) - ), - $qb->expr()->eq( - 'oxlang', - $qb->createNamedParameter('1') - ) - ) - ) - ->setMaxResults(1); - return (bool) $qb->execute()->fetchOne(); + $seoEncoder = $this->d3GetMockableOxNewObject(SeoEncoder::class); + $seoUrl = $seoEncoder->getStaticUrl( + $this->d3GetMockableOxNewObject(FrontendController::class)->getViewConfig()->getSelfLink() . + "cl=".$this->stdClassName + ); + + return (bool) strlen($seoUrl); } /** @@ -186,10 +235,32 @@ class Actions */ public function createSeoUrl() { - $query = "INSERT INTO `oxseo` (`OXOBJECTID`, `OXIDENT`, `OXSHOPID`, `OXLANG`, `OXSTDURL`, `OXSEOURL`, `OXTYPE`, `OXFIXED`, `OXEXPIRED`, `OXPARAMS`, `OXTIMESTAMP`) VALUES - ('ff57646b47249ee33c6b672741ac371a', 'bd3b6183c9a2f94682f4c62e714e4d6b', 1, 1, 'index.php?cl=d3_account_webauthn', 'en/key-authentication/', 'static', 0, 0, '', NOW()), - ('ff57646b47249ee33c6b672741ac371a', '94d0d3ec07f10e8838a71e54084be885', 1, 0, 'index.php?cl=d3_account_webauthn', 'sicherheitsschluessel/', 'static', 0, 0, '', NOW());"; + $seoEncoder = $this->d3GetMockableOxNewObject(SeoEncoder::class); + $seoEncoder->addSeoEntry( + 'ff57646b47249ee33c6b672741ac371a', + $this->d3GetMockableRegistryObject(Config::class)->getShopId(), + 0, + 'index.php?cl='.$this->stdClassName, + $this->seo_de, + 'static', + 0 + ); + $seoEncoder->addSeoEntry( + 'ff57646b47249ee33c6b672741ac371a', + $this->d3GetMockableRegistryObject(Config::class)->getShopId(), + 1, + 'index.php?cl='.$this->stdClassName, + $this->seo_en, + 'static', + 0 + ); + } - DatabaseProvider::getDb()->execute($query); + /** + * @return ContainerInterface|null + */ + protected function getDIContainer(): ?ContainerInterface + { + return ContainerFactory::getInstance()->getContainer(); } } \ No newline at end of file diff --git a/src/tests/unit/Setup/ActionsTest.php b/src/tests/unit/Setup/ActionsTest.php new file mode 100644 index 0000000..98e4015 --- /dev/null +++ b/src/tests/unit/Setup/ActionsTest.php @@ -0,0 +1,627 @@ + + * @link https://www.oxidmodule.com + */ + +declare(strict_types=1); + +namespace D3\Webauthn\tests\unit\Setup; + +use D3\TestingTools\Development\CanAccessRestricted; +use D3\Webauthn\Setup\Actions; +use OxidEsales\Eshop\Application\Controller\FrontendController; +use OxidEsales\Eshop\Core\Database\Adapter\DatabaseInterface; +use OxidEsales\Eshop\Core\Database\Adapter\Doctrine\Database; +use OxidEsales\Eshop\Core\DbMetaDataHandler; +use OxidEsales\Eshop\Core\Registry; +use OxidEsales\Eshop\Core\SeoEncoder; +use OxidEsales\Eshop\Core\Utils; +use OxidEsales\Eshop\Core\UtilsView; +use OxidEsales\Eshop\Core\ViewConfig; +use OxidEsales\EshopCommunity\Internal\Framework\Module\Configuration\Bridge\ShopConfigurationDaoBridge; +use OxidEsales\EshopCommunity\Internal\Framework\Module\Configuration\Bridge\ShopConfigurationDaoBridgeInterface; +use OxidEsales\EshopCommunity\Internal\Framework\Module\Configuration\DataObject\ModuleConfiguration; +use OxidEsales\EshopCommunity\Internal\Framework\Module\Configuration\DataObject\ShopConfiguration; +use OxidEsales\EshopCommunity\Internal\Framework\Module\Configuration\Exception\ModuleConfigurationNotFoundException; +use OxidEsales\TestingLibrary\UnitTestCase; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; +use ReflectionException; +use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +class ActionsTest extends UnitTestCase +{ + use CanAccessRestricted; + + public function setUp(): void + { + parent::setUp(); + + //$seoEncoder = oxNew(SeoEncoder::class); + //$seoEncoder->addSeoEntry(); + } + + /** + * @test + * @param $tableExist + * @param $expectedInvocation + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Setup\Actions::setupModule + * @dataProvider canSetupModuleDataProvider + */ + public function canSetupModule($tableExist, $expectedInvocation) + { + /** @var Actions|MockObject $sut */ + $sut = $this->getMockBuilder(Actions::class) + ->onlyMethods(['tableExists', 'executeSQL']) + ->getMock(); + $sut->method('tableExists')->willReturn($tableExist); + $sut->expects($expectedInvocation)->method('executeSQL')->willReturn(true); + + $this->callMethod( + $sut, + 'setupModule' + ); + } + + /** + * @return array[] + */ + public function canSetupModuleDataProvider(): array + { + return [ + 'table exist' => [true, $this->never()], + 'table not exist' => [false, $this->once()], + ]; + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Setup\Actions::tableExists + */ + public function canCheckTableExists() + { + $expected = true; + + /** @var DbMetaDataHandler|MockObject $DbMetaDataMock */ + $DbMetaDataMock = $this->getMockBuilder(DbMetaDataHandler::class) + ->onlyMethods(['tableExists']) + ->getMock(); + $DbMetaDataMock->expects($this->once())->method('tableExists')->willReturn($expected); + + /** @var Actions|MockObject $sut */ + $sut = $this->getMockBuilder(Actions::class) + ->onlyMethods(['d3GetMockableOxNewObject']) + ->getMock(); + $sut->method('d3GetMockableOxNewObject')->willReturnCallback( + function () use ($DbMetaDataMock) { + $args = func_get_args(); + switch ($args[0]) { + case DbMetaDataHandler::class: + return $DbMetaDataMock; + default: + return call_user_func_array("oxNew", $args); + } + } + ); + + $this->assertSame( + $expected, + $this->callMethod( + $sut, + 'tableExists', + ['testTable'] + ) + ); + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Setup\Actions::d3GetDb + */ + public function d3GetDbReturnsRightInstance() + { + $sut = oxNew(Actions::class); + + $this->assertInstanceOf( + DatabaseInterface::class, + $this->callMethod( + $sut, + 'd3GetDb' + ) + ); + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Setup\Actions::executeSQL + */ + public function canExecuteSQL() + { + /** @var Database|MockObject $dbMock */ + $dbMock = $this->getMockBuilder(Database::class) + ->onlyMethods(['execute']) + ->getMock(); + $dbMock->expects($this->once())->method('execute'); + + $sut = $this->getMockBuilder(Actions::class) + ->onlyMethods(['d3GetDb']) + ->getMock(); + $sut->method('d3GetDb')->willReturn($dbMock); + + $this->callMethod( + $sut, + 'executeSQL', + ['query'] + ); + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Setup\Actions::fieldExists + */ + public function canCheckFieldExists() + { + $expected = true; + + /** @var DbMetaDataHandler|MockObject $DbMetaDataMock */ + $DbMetaDataMock = $this->getMockBuilder(DbMetaDataHandler::class) + ->onlyMethods(['fieldExists']) + ->getMock(); + $DbMetaDataMock->expects($this->once())->method('fieldExists')->willReturn($expected); + + /** @var Actions|MockObject $sut */ + $sut = $this->getMockBuilder(Actions::class) + ->onlyMethods(['d3GetMockableOxNewObject']) + ->getMock(); + $sut->method('d3GetMockableOxNewObject')->willReturnCallback( + function () use ($DbMetaDataMock) { + $args = func_get_args(); + switch ($args[0]) { + case DbMetaDataHandler::class: + return $DbMetaDataMock; + default: + return call_user_func_array("oxNew", $args); + } + } + ); + + $this->assertSame( + $expected, + $this->callMethod( + $sut, + 'fieldExists', + ['testField', 'testTable'] + ) + ); + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Setup\Actions::regenerateViews + */ + public function canRegenerateViews() + { + /** @var DbMetaDataHandler|MockObject $DbMetaDataMock */ + $DbMetaDataMock = $this->getMockBuilder(DbMetaDataHandler::class) + ->onlyMethods(['updateViews']) + ->getMock(); + $DbMetaDataMock->expects($this->once())->method('updateViews'); + + /** @var Actions|MockObject $sut */ + $sut = $this->getMockBuilder(Actions::class) + ->onlyMethods(['d3GetMockableOxNewObject']) + ->getMock(); + $sut->method('d3GetMockableOxNewObject')->willReturnCallback( + function () use ($DbMetaDataMock) { + $args = func_get_args(); + switch ($args[0]) { + case DbMetaDataHandler::class: + return $DbMetaDataMock; + default: + return call_user_func_array("oxNew", $args); + } + } + ); + + $this->callMethod( + $sut, + 'regenerateViews' + ); + } + + /** + * @test + * @throws ReflectionException + * @dataProvider canClearCacheDataProvider + * @covers \D3\Webauthn\Setup\Actions::clearCache + */ + public function canClearCache($throwException) + { + /** @var LoggerInterface|MockObject $loggerMock */ + $loggerMock = $this->getMockForAbstractClass(LoggerInterface::class, [], '', true, true, true, ['error', 'debug']); + $loggerMock->expects($throwException ? $this->atLeastOnce() : $this->never()) + ->method('error')->willReturn(true); + + /** @var UtilsView|MockObject $utilsViewMock */ + $utilsViewMock = $this->getMockBuilder(UtilsView::class) + ->onlyMethods(['addErrorToDisplay']) + ->getMock(); + $utilsViewMock->expects($throwException ? $this->atLeastOnce() : $this->never()) + ->method('addErrorToDisplay'); + + /** @var Utils|MockObject $utilsMock */ + $utilsMock = $this->getMockBuilder(Utils::class) + ->onlyMethods(['resetTemplateCache', 'resetLanguageCache']) + ->getMock(); + $utilsMock->expects($throwException ? $this->never() : $this->once()) + ->method('resetTemplateCache'); + $utilsMock->expects($throwException ? $this->never() : $this->once()) + ->method('resetLanguageCache'); + + /** @var Actions|MockObject $sut */ + $sut = $this->getMockBuilder(Actions::class) + ->onlyMethods(['d3GetMockableRegistryObject', 'getModuleTemplates', 'd3GetMockableLogger']) + ->getMock(); + $sut->method('d3GetMockableRegistryObject')->willReturnCallback( + function () use ($utilsMock, $utilsViewMock) { + $args = func_get_args(); + switch ($args[0]) { + case Utils::class: + return $utilsMock; + case UtilsView::class: + return $utilsViewMock; + default: + return Registry::get($args[0]); + } + } + ); + $sut->method('getModuleTemplates')->will( + $throwException ? + $this->throwException(oxNew(ModuleConfigurationNotFoundException::class)) : + $this->returnValue([]) + ); + $sut->method('d3GetMockableLogger')->willReturn($loggerMock); + + $this->callMethod( + $sut, + 'clearCache' + ); + } + + /** + * @return array + */ + public function canClearCacheDataProvider(): array + { + return [ + 'throws exception' => [true], + 'dont throws exception' => [false], + ]; + } + + /** + * @test + * @throws ReflectionException + * @covers \D3\Webauthn\Setup\Actions::getModuleTemplates + */ + public function canGetModuleTemplates() + { + /** @var ModuleConfiguration|MockObject $moduleConfigurationMock */ + $moduleConfigurationMock = $this->getMockBuilder(ModuleConfiguration::class) + ->getMock(); + + /** @var ShopConfiguration|MockObject $shopConfigurationMock */ + $shopConfigurationMock = $this->getMockBuilder(ShopConfiguration::class) + ->onlyMethods(['getModuleConfiguration']) + ->getMock(); + $shopConfigurationMock->method('getModuleConfiguration')->willReturn($moduleConfigurationMock); + + /** @var ShopConfigurationDaoBridge|MockObject $shopConfigurationDaoBridgeMock */ + $shopConfigurationDaoBridgeMock = $this->getMockBuilder(ShopConfigurationDaoBridge::class) + ->disableOriginalConstructor() + ->onlyMethods(['get']) + ->getMock(); + $shopConfigurationDaoBridgeMock->method('get')->willReturn($shopConfigurationMock); + + /** @var Container|MockObject $dicMock */ + $dicMock = $this->getMockBuilder(Container::class) + ->onlyMethods(['get']) + ->getMock(); + $dicMock->method('get')->willReturnCallback( + function () use ($shopConfigurationDaoBridgeMock) { + $args = func_get_args(); + switch ($args[0]) { + case ShopConfigurationDaoBridgeInterface::class: + return $shopConfigurationDaoBridgeMock; + default: + return Registry::get($args[0]); + } + } + ); + + /** @var Actions|MockObject $sut */ + $sut = $this->getMockBuilder(Actions::class) + ->onlyMethods(['getDIContainer', 'getModuleTemplatesFromTemplates', 'getModuleTemplatesFromBlocks']) + ->getMock(); + $sut->method('getDIContainer')->willReturn($dicMock); + $sut->expects($this->once())->method('getModuleTemplatesFromTemplates')->willReturn([1, 2]); + $sut->expects($this->once())->method('getModuleTemplatesFromBlocks')->willReturn([2, 3]); + + $this->assertSame( + [0 => 1, 1 => 2, 3 => 3], + $this->callMethod( + $sut, + 'getModuleTemplates' + ) + ); + } + + /** + * @test + * @throws ReflectionException + * @covers \D3\Webauthn\Setup\Actions::getModuleTemplatesFromTemplates + */ + public function canGetModuleTemplatesFromTemplates() + { + $expected = "templateKeyFixture"; + + /** @var ModuleConfiguration\Template|MockObject $templateMock */ + $templateMock = $this->getMockBuilder(ModuleConfiguration\Template::class) + ->disableOriginalConstructor() + ->onlyMethods(['getTemplateKey']) + ->getMock(); + $templateMock->method('getTemplateKey')->willReturn($expected); + + /** @var ModuleConfiguration|MockObject $moduleConfigurationMock */ + $moduleConfigurationMock = $this->getMockBuilder(ModuleConfiguration::class) + ->onlyMethods(['getTemplates']) + ->getMock(); + $moduleConfigurationMock->method('getTemplates')->willReturn([$templateMock]); + + $sut = oxNew(Actions::class); + + $this->assertSame( + [$expected], + $this->callMethod( + $sut, + 'getModuleTemplatesFromTemplates', + [$moduleConfigurationMock] + ) + ); + } + + /** + * @test + * @throws ReflectionException + * @covers \D3\Webauthn\Setup\Actions::getModuleTemplatesFromBlocks + */ + public function canGetModuleTemplatesFromBlocks() + { + /** @var ModuleConfiguration\TemplateBlock|MockObject $templateBlockMock */ + $templateBlockMock = $this->getMockBuilder(ModuleConfiguration\TemplateBlock::class) + ->disableOriginalConstructor() + ->onlyMethods(['getShopTemplatePath']) + ->getMock(); + $templateBlockMock->method('getShopTemplatePath')->willReturn('mypath/myFile.tpl'); + + /** @var ModuleConfiguration|MockObject $moduleConfigurationMock */ + $moduleConfigurationMock = $this->getMockBuilder(ModuleConfiguration::class) + ->onlyMethods(['getTemplateBlocks']) + ->getMock(); + $moduleConfigurationMock->method('getTemplateBlocks')->willReturn([$templateBlockMock]); + + $sut = oxNew(Actions::class); + + $this->assertSame( + ['myFile.tpl'], + $this->callMethod( + $sut, + 'getModuleTemplatesFromBlocks', + [$moduleConfigurationMock] + ) + ); + } + + /** + * @test + * + * @param $hasSeoUrl + * @param $throwException + * + * @throws ReflectionException + * @dataProvider canCheckSeoUrlDataProvider + * @covers \D3\Webauthn\Setup\Actions::seoUrl + */ + public function canCheckSeoUrl($hasSeoUrl, $throwException) + { + /** @var UtilsView|MockObject $utilsViewMock */ + $utilsViewMock = $this->getMockBuilder(UtilsView::class) + ->onlyMethods(['addErrorToDisplay']) + ->getMock(); + $utilsViewMock->expects($throwException ? $this->atLeastOnce() : $this->never()) + ->method('addErrorToDisplay'); + + /** @var LoggerInterface|MockObject $loggerMock */ + $loggerMock = $this->getMockForAbstractClass(LoggerInterface::class, [], '', true, true, true, ['error', 'debug']); + $loggerMock->expects($throwException ? $this->atLeastOnce() : $this->never()) + ->method('error')->willReturn(true); + + /** @var Actions|MockObject $sut */ + $sut = $this->getMockBuilder(Actions::class) + ->onlyMethods(['hasSeoUrl', 'createSeoUrl', 'd3GetMockableLogger', 'd3GetMockableRegistryObject']) + ->getMock(); + $sut->method('hasSeoUrl')->willReturn($hasSeoUrl); + $sut->expects($hasSeoUrl ? $this->never() : $this->once())->method('createSeoUrl')->will( + $throwException ? + $this->throwException(oxNew(\Exception::class)) : + $this->returnValue(true) + ); + $sut->method('d3GetMockableLogger')->willReturn($loggerMock); + $sut->method('d3GetMockableRegistryObject')->willReturnCallback( + function () use ($utilsViewMock) { + $args = func_get_args(); + switch ($args[0]) { + case UtilsView::class: + return $utilsViewMock; + default: + return Registry::get($args[0]); + } + } + ); + + $this->callMethod( + $sut, + 'seoUrl' + ); + } + + /** + * @return array + */ + public function canCheckSeoUrlDataProvider(): array + { + return [ + 'already has SEO url' => [true, false], + 'has no SEO url' => [false, false], + 'has no SEO url throw exception' => [false, true], + ]; + } + + /** + * @test + * @throws ReflectionException + * @dataProvider canCheckHasSeoUrlDataProvider + * @covers \D3\Webauthn\Setup\Actions::hasSeoUrl + */ + public function canCheckHasSeoUrl($staticUrl, $expected) + { + /** @var SeoEncoder|MockObject $seoEncoderMock */ + $seoEncoderMock = $this->getMockBuilder(SeoEncoder::class) + ->onlyMethods(['getStaticUrl']) + ->getMock(); + $seoEncoderMock->method('getStaticUrl')->willReturn($staticUrl); + + /** @var ViewConfig|MockObject $viewConfigMock */ + $viewConfigMock = $this->getMockBuilder(ViewConfig::class) + ->onlyMethods(['getSelfLink']) + ->getMock(); + $viewConfigMock->method('getSelfLink')->willReturn('https://testshop.dev/'); + + /** @var FrontendController|MockObject $controllerMock */ + $controllerMock = $this->getMockBuilder(FrontendController::class) + ->onlyMethods(['getViewConfig']) + ->getMock(); + $controllerMock->method('getViewConfig')->willReturn($viewConfigMock); + + /** @var Actions|MockObject $sut */ + $sut = $this->getMockBuilder(Actions::class) + ->onlyMethods(['d3GetMockableOxNewObject']) + ->getMock(); + $sut->method('d3GetMockableOxNewObject')->willReturnCallback( + function () use ($controllerMock, $seoEncoderMock) { + $args = func_get_args(); + switch ($args[0]) { + case FrontendController::class: + return $controllerMock; + case SeoEncoder::class: + return $seoEncoderMock; + default: + return call_user_func_array("oxNew", $args); + } + } + ); + + $this->assertSame( + $expected, + $this->callMethod( + $sut, + 'hasSeoUrl' + ) + ); + } + + /** + * @return array[] + */ + public function canCheckHasSeoUrlDataProvider(): array + { + return [ + 'has SEO url' => ['https://testshop.dev/securitykeys', true], + 'has no SEO url'=> ['', false] + ]; + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Setup\Actions::createSeoUrl + */ + public function canCreateSeoUrl() + { + /** @var SeoEncoder|MockObject $seoEncoderMock */ + $seoEncoderMock = $this->getMockBuilder(SeoEncoder::class) + ->onlyMethods(['addSeoEntry']) + ->getMock(); + $seoEncoderMock->expects($this->exactly(2))->method('addSeoEntry'); + + /** @var Actions|MockObject $sut */ + $sut = $this->getMockBuilder(Actions::class) + ->onlyMethods(['d3GetMockableOxNewObject']) + ->getMock(); + $sut->method('d3GetMockableOxNewObject')->willReturnCallback( + function () use ($seoEncoderMock) { + $args = func_get_args(); + switch ($args[0]) { + case SeoEncoder::class: + return $seoEncoderMock; + default: + return call_user_func_array("oxNew", $args); + } + } + ); + + $this->callMethod( + $sut, + 'createSeoUrl' + ); + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Setup\Actions::getDIContainer + */ + public function canGetDIContainer() + { + $this->assertInstanceOf( + ContainerBuilder::class, + $this->callMethod( + oxNew(Actions::class), + 'getDIContainer' + ) + ); + } +} \ No newline at end of file