From 318338552ca65eca176e9dd938e28ba56593a792 Mon Sep 17 00:00:00 2001 From: Daniel Seifert Date: Mon, 5 Dec 2022 23:45:12 +0100 Subject: [PATCH] add further tests --- .../Model/Exceptions/WebauthnException.php | 22 ++- .../Component/d3_webauthn_UserComponent.php | 6 +- .../Application/Model/d3_User_Webauthn.php | 37 ++-- .../WebauthnCreateExceptionTest.php | 49 ++++++ .../Exceptions/WebauthnExceptionTest.php | 155 +++++++++++++++++ .../Exceptions/WebauthnGetExceptionTest.php | 49 ++++++ .../Component/UserComponentWebauthnTest.php | 164 ++++++++++++++++++ .../Application/Model/UserWebauthnTest.php | 66 +++++++ 8 files changed, 528 insertions(+), 20 deletions(-) create mode 100644 src/tests/unit/Application/Model/Exceptions/WebauthnCreateExceptionTest.php create mode 100644 src/tests/unit/Application/Model/Exceptions/WebauthnExceptionTest.php create mode 100644 src/tests/unit/Application/Model/Exceptions/WebauthnGetExceptionTest.php create mode 100644 src/tests/unit/Modules/Application/Component/UserComponentWebauthnTest.php create mode 100644 src/tests/unit/Modules/Application/Model/UserWebauthnTest.php diff --git a/src/Application/Model/Exceptions/WebauthnException.php b/src/Application/Model/Exceptions/WebauthnException.php index cca37f0..5826b6b 100644 --- a/src/Application/Model/Exceptions/WebauthnException.php +++ b/src/Application/Model/Exceptions/WebauthnException.php @@ -15,25 +15,39 @@ declare(strict_types=1); namespace D3\Webauthn\Application\Model\Exceptions; +use D3\TestingTools\Production\IsMockable; use D3\Webauthn\Application\Model\WebauthnErrors; use Exception; use OxidEsales\Eshop\Core\Exception\StandardException; class WebauthnException extends StandardException { + use IsMockable; + public $detailedErrorMessage = null; public function __construct( $sMessage = "not set", $iCode = 0, Exception $previous = null ) { $this->setDetailedErrorMessage($sMessage); - parent::__construct( - (oxNew(WebauthnErrors::class))->translateError($sMessage, $this->getRequestType()), - $iCode, - $previous + $this->d3CallMockableParent( + '__construct', + [ + $this->getErrorMessageTranslator()->translateError($sMessage, $this->getRequestType()), + $iCode, + $previous + ] ); } + /** + * @return WebauthnErrors + */ + protected function getErrorMessageTranslator(): WebauthnErrors + { + return oxNew(WebauthnErrors::class); + } + /** * @return string|null */ diff --git a/src/Modules/Application/Component/d3_webauthn_UserComponent.php b/src/Modules/Application/Component/d3_webauthn_UserComponent.php index caa1c9a..899c091 100755 --- a/src/Modules/Application/Component/d3_webauthn_UserComponent.php +++ b/src/Modules/Application/Component/d3_webauthn_UserComponent.php @@ -29,6 +29,7 @@ use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Request; use OxidEsales\Eshop\Core\Session; use OxidEsales\Eshop\Core\Utils; +use OxidEsales\Eshop\Core\UtilsView; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; @@ -82,6 +83,9 @@ class d3_webauthn_UserComponent extends d3_webauthn_UserComponent_parent return parent::login(); } + /** + * @return void + */ public function d3CancelWebauthnLogin(): void { $this->d3WebauthnClearSessionVariables(); @@ -113,7 +117,7 @@ class d3_webauthn_UserComponent extends d3_webauthn_UserComponent_parent ->getRequestParameter('lgn_cook')); $this->_afterLogin($this->getUser()); } catch (WebauthnGetException $e) { - Registry::getUtilsView()->addErrorToDisplay($e); + $this->d3GetMockableRegistryObject(UtilsView::class)->addErrorToDisplay($e); } catch (WebauthnLoginErrorException $e) {} } } \ No newline at end of file diff --git a/src/Modules/Application/Model/d3_User_Webauthn.php b/src/Modules/Application/Model/d3_User_Webauthn.php index 6f04fd4..053c409 100755 --- a/src/Modules/Application/Model/d3_User_Webauthn.php +++ b/src/Modules/Application/Model/d3_User_Webauthn.php @@ -15,12 +15,14 @@ declare(strict_types=1); namespace D3\Webauthn\Modules\Application\Model; +use D3\TestingTools\Production\IsMockable; use D3\Webauthn\Application\Model\WebauthnConf; use Doctrine\DBAL\Driver\Exception as DoctrineDriverException; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Query\QueryBuilder; use OxidEsales\Eshop\Core\Exception\UserException; use OxidEsales\Eshop\Core\Registry; +use OxidEsales\Eshop\Core\Session; use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory; use OxidEsales\EshopCommunity\Internal\Framework\Database\QueryBuilderFactoryInterface; use Psr\Container\ContainerExceptionInterface; @@ -30,23 +32,26 @@ use ReflectionException; class d3_User_Webauthn extends d3_User_Webauthn_parent { + use IsMockable; + public function logout() { - $return = parent::logout(); + $return = $this->d3CallMockableParent('logout'); - Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH); - Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_LOGIN_OBJECT); - Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTUSER); - Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_SESSION_LOGINUSER); - Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTCLASS); + $session = $this->d3GetMockableRegistryObject(Session::class); + $session->deleteVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH); + $session->deleteVariable(WebauthnConf::WEBAUTHN_LOGIN_OBJECT); + $session->deleteVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTUSER); + $session->deleteVariable(WebauthnConf::WEBAUTHN_SESSION_LOGINUSER); + $session->deleteVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTCLASS); - Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_AUTH); - Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_LOGIN_OBJECT); - Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_CURRENTUSER); - Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_LOGINUSER); - Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_CURRENTCLASS); + $session->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_AUTH); + $session->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_LOGIN_OBJECT); + $session->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_CURRENTUSER); + $session->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_LOGINUSER); + $session->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_CURRENTCLASS); - Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_SESSION_NAVFORMPARAMS); + $session->deleteVariable(WebauthnConf::WEBAUTHN_SESSION_NAVFORMPARAMS); return $return; } @@ -61,8 +66,10 @@ class d3_User_Webauthn extends d3_User_Webauthn_parent */ public function login($userName, $password, $setSessionCookie = false) { - if (Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH)) { - $userName = $userName ?: Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_LOGINUSER); + $session = $this->d3GetMockableRegistryObject(Session::class); + + if ($session->getVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH)) { + $userName = $userName ?: $session->getVariable(WebauthnConf::WEBAUTHN_SESSION_LOGINUSER); $config = Registry::getConfig(); $shopId = $config->getShopId(); @@ -73,7 +80,7 @@ class d3_User_Webauthn extends d3_User_Webauthn_parent $method->invokeArgs( $this, [ - Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_LOGINUSER), + $session->getVariable(WebauthnConf::WEBAUTHN_SESSION_LOGINUSER), $shopId ] ); diff --git a/src/tests/unit/Application/Model/Exceptions/WebauthnCreateExceptionTest.php b/src/tests/unit/Application/Model/Exceptions/WebauthnCreateExceptionTest.php new file mode 100644 index 0000000..a89170f --- /dev/null +++ b/src/tests/unit/Application/Model/Exceptions/WebauthnCreateExceptionTest.php @@ -0,0 +1,49 @@ + + * @link https://www.oxidmodule.com + */ + +declare(strict_types=1); + +namespace D3\Webauthn\tests\unit\Application\Model\Exceptions; + +use D3\TestingTools\Development\CanAccessRestricted; +use D3\Webauthn\Application\Model\Exceptions\WebauthnCreateException; +use OxidEsales\TestingLibrary\UnitTestCase; +use PHPUnit\Framework\MockObject\MockObject; +use ReflectionException; + +class WebauthnCreateExceptionTest extends UnitTestCase +{ + use CanAccessRestricted; + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Application\Model\Exceptions\WebauthnCreateException::getRequestType + */ + public function canGetRequestType() + { + /** @var WebauthnCreateException|MockObject $sut */ + $sut = $this->getMockBuilder(WebauthnCreateException::class) + ->onlyMethods(['getErrorMessageTranslator']) + ->getMock(); + $sut->method('getErrorMessageTranslator'); + + $this->assertIsString( + $this->callMethod( + $sut, + 'getRequestType' + ) + ); + } +} \ No newline at end of file diff --git a/src/tests/unit/Application/Model/Exceptions/WebauthnExceptionTest.php b/src/tests/unit/Application/Model/Exceptions/WebauthnExceptionTest.php new file mode 100644 index 0000000..fd34a1f --- /dev/null +++ b/src/tests/unit/Application/Model/Exceptions/WebauthnExceptionTest.php @@ -0,0 +1,155 @@ + + * @link https://www.oxidmodule.com + */ + +declare(strict_types=1); + +namespace D3\Webauthn\tests\unit\Application\Model\Exceptions; + +use D3\TestingTools\Development\CanAccessRestricted; +use D3\Webauthn\Application\Model\Exceptions\WebauthnException; +use D3\Webauthn\Application\Model\WebauthnErrors; +use OxidEsales\TestingLibrary\UnitTestCase; +use PHPUnit\Framework\MockObject\MockObject; +use ReflectionException; + +class WebauthnExceptionTest extends UnitTestCase +{ + use CanAccessRestricted; + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Application\Model\Exceptions\WebauthnException::__construct + */ + public function canConstruct() + { + /** @var \Exception|MockObject $previousMock */ + $previousMock = $this->getMockBuilder(\Exception::class) + ->getMock(); + + /** @var WebauthnErrors|MockObject $translatorMock */ + $translatorMock = $this->getMockBuilder(WebauthnErrors::class) + ->onlyMethods(['translateError']) + ->getMock(); + $translatorMock->method('translateError')->willReturn('translatedError'); + + /** @var WebauthnException|MockObject $sut */ + $sut = $this->getMockBuilder(WebauthnException::class) + ->onlyMethods(['setDetailedErrorMessage', 'getErrorMessageTranslator', 'getRequestType', + 'd3CallMockableParent']) + ->disableOriginalConstructor() + ->getMock(); + $sut->expects($this->once())->method('setDetailedErrorMessage'); + $sut->method('getErrorMessageTranslator')->willReturn($translatorMock); + $sut->method('getRequestType')->willReturn('requestType'); + $sut->expects($this->once())->method('d3CallMockableParent')->with( + $this->anything(), + $this->identicalTo(['translatedError', 255, $previousMock]) + ); + + $this->callMethod( + $sut, + '__construct', + ['myMessage', 255, $previousMock] + ); + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Application\Model\Exceptions\WebauthnException::getErrorMessageTranslator + */ + public function canGetErrorMessageTranslator() + { + /** @var WebauthnException|MockObject $sut */ + $sut = $this->getMockBuilder(WebauthnException::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->assertInstanceOf( + WebauthnErrors::class, + $this->callMethod( + $sut, + 'getErrorMessageTranslator' + ) + ); + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Application\Model\Exceptions\WebauthnException::getRequestType + */ + public function canGetRequestType() + { + /** @var WebauthnException|MockObject $sut */ + $sut = $this->getMockBuilder(WebauthnException::class) + ->onlyMethods(['getErrorMessageTranslator']) + ->getMock(); + $sut->method('getErrorMessageTranslator'); + + $this->assertNull( + $this->callMethod( + $sut, + 'getRequestType' + ) + ); + } + + /** + * @test + * @param $messageFixture + * @return void + * @throws ReflectionException + * @dataProvider canSetAndGetDetailedErrorMessageDataProvider + * @covers \D3\Webauthn\Application\Model\Exceptions\WebauthnException::setDetailedErrorMessage + * @covers \D3\Webauthn\Application\Model\Exceptions\WebauthnException::getDetailedErrorMessage + */ + public function canSetAndGetDetailedErrorMessage($messageFixture) + { + /** @var WebauthnException|MockObject $sut */ + $sut = $this->getMockBuilder(WebauthnException::class) + ->disableOriginalConstructor() + ->onlyMethods(['getRequestType']) + ->getMock(); + $sut->method('getRequestType'); + + $this->callMethod( + $sut, + 'setDetailedErrorMessage', + [$messageFixture] + ); + + $this->assertSame( + 'Webauthn: '.$messageFixture, + $this->callMethod( + $sut, + 'getDetailedErrorMessage' + ) + ); + } + + /** + * @return array + */ + public function canSetAndGetDetailedErrorMessageDataProvider(): array + { + return [ + 'message is string' => ['errorMessageFixture'], + 'message is null' => [null] + ]; + } +} \ No newline at end of file diff --git a/src/tests/unit/Application/Model/Exceptions/WebauthnGetExceptionTest.php b/src/tests/unit/Application/Model/Exceptions/WebauthnGetExceptionTest.php new file mode 100644 index 0000000..83de142 --- /dev/null +++ b/src/tests/unit/Application/Model/Exceptions/WebauthnGetExceptionTest.php @@ -0,0 +1,49 @@ + + * @link https://www.oxidmodule.com + */ + +declare(strict_types=1); + +namespace D3\Webauthn\tests\unit\Application\Model\Exceptions; + +use D3\TestingTools\Development\CanAccessRestricted; +use D3\Webauthn\Application\Model\Exceptions\WebauthnGetException; +use OxidEsales\TestingLibrary\UnitTestCase; +use PHPUnit\Framework\MockObject\MockObject; +use ReflectionException; + +class WebauthnGetExceptionTest extends UnitTestCase +{ + use CanAccessRestricted; + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Application\Model\Exceptions\WebauthnGetException::getRequestType + */ + public function canGetRequestType() + { + /** @var WebauthnGetException|MockObject $sut */ + $sut = $this->getMockBuilder(WebauthnGetException::class) + ->onlyMethods(['getErrorMessageTranslator']) + ->getMock(); + $sut->method('getErrorMessageTranslator'); + + $this->assertIsString( + $this->callMethod( + $sut, + 'getRequestType' + ) + ); + } +} \ No newline at end of file diff --git a/src/tests/unit/Modules/Application/Component/UserComponentWebauthnTest.php b/src/tests/unit/Modules/Application/Component/UserComponentWebauthnTest.php new file mode 100644 index 0000000..1b7b7a2 --- /dev/null +++ b/src/tests/unit/Modules/Application/Component/UserComponentWebauthnTest.php @@ -0,0 +1,164 @@ + + * @link https://www.oxidmodule.com + */ + +declare(strict_types=1); + +namespace D3\Webauthn\tests\unit\Modules\Application\Component; + +use D3\TestingTools\Development\CanAccessRestricted; +use D3\Webauthn\Application\Model\Exceptions\WebauthnException; +use D3\Webauthn\Application\Model\Exceptions\WebauthnGetException; +use D3\Webauthn\Application\Model\Exceptions\WebauthnLoginErrorException; +use D3\Webauthn\Application\Model\WebauthnLogin; +use OxidEsales\Eshop\Application\Component\UserComponent; +use OxidEsales\Eshop\Core\Registry; +use OxidEsales\Eshop\Core\Session; +use OxidEsales\Eshop\Core\UtilsView; +use OxidEsales\TestingLibrary\UnitTestCase; +use PHPUnit\Framework\MockObject\MockObject; +use ReflectionException; + +class UserComponentWebauthnTest extends UnitTestCase +{ + use CanAccessRestricted; + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Modules\Application\Component\d3_webauthn_UserComponent::d3CancelWebauthnLogin + */ + public function canCancelWebauthnLogin() + { + /** @var UserComponent|MockObject $sut */ + $sut = $this->getMockBuilder(UserComponent::class) + ->onlyMethods(['d3WebauthnClearSessionVariables']) + ->getMock(); + $sut->expects($this->once())->method('d3WebauthnClearSessionVariables'); + + $this->callMethod( + $sut, + 'd3CancelWebauthnLogin' + ); + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Modules\Application\Component\d3_webauthn_UserComponent::d3WebauthnClearSessionVariables + */ + public function canClearSessionVariables() + { + /** @var Session|MockObject $sessionMock */ + $sessionMock = $this->getMockBuilder(Session::class) + ->onlyMethods(['deleteVariable']) + ->getMock(); + $sessionMock->expects($this->atLeast(4))->method('deleteVariable')->willReturn(true); + + /** @var UserComponent|MockObject $sut */ + $sut = $this->getMockBuilder(UserComponent::class) + ->onlyMethods(['d3GetMockableRegistryObject']) + ->getMock(); + $sut->method('d3GetMockableRegistryObject')->willReturnCallback( + function () use ($sessionMock) { + $args = func_get_args(); + switch ($args[0]) { + case Session::class: + return $sessionMock; + default: + return Registry::get($args[0]); + } + } + ); + + $this->callMethod( + $sut, + 'd3WebauthnClearSessionVariables' + ); + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Modules\Application\Component\d3_webauthn_UserComponent::d3AssertAuthn + * @dataProvider canAssertAuthnDataProvider + */ + public function canAssertAuthn($thrownExcecption, $afterLoginInvocationCount, $addErrorInvocationCount) + { + /** @var UtilsView|MockObject $utilsViewMock */ + $utilsViewMock = $this->getMockBuilder(UtilsView::class) + ->onlyMethods(['addErrorToDisplay']) + ->getMock(); + $utilsViewMock->expects($addErrorInvocationCount)->method('addErrorToDisplay'); + + /** @var WebauthnLogin|MockObject $webauthnLoginMock */ + $webauthnLoginMock = $this->getMockBuilder(WebauthnLogin::class) + ->disableOriginalConstructor() + ->onlyMethods(['frontendLogin']) + ->getMock(); + if ($thrownExcecption) { + $webauthnLoginMock->expects($this->once())->method('frontendLogin')->willThrowException( + oxNew($thrownExcecption) + ); + } else { + $webauthnLoginMock->expects($this->once())->method('frontendLogin'); + } + + /** @var UserComponent|MockObject $sut */ + $sut = $this->getMockBuilder(UserComponent::class) + ->onlyMethods(['d3GetMockableOxNewObject', 'd3GetMockableRegistryObject', '_afterLogin']) + ->getMock(); + $sut->method('d3GetMockableOxNewObject')->willReturnCallback( + function () use ($webauthnLoginMock) { + $args = func_get_args(); + switch ($args[0]) { + case WebauthnLogin::class: + return $webauthnLoginMock; + default: + return call_user_func_array("oxNew", $args); + } + } + ); + $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]); + } + } + ); + $sut->expects($afterLoginInvocationCount)->method('_afterLogin'); + + $this->callMethod( + $sut, + 'd3AssertAuthn' + ); + } + + /** + * @return array[] + */ + public function canAssertAuthnDataProvider(): array + { + return [ + 'passed' => [null, $this->once(), $this->never()], + 'webauthnException' => [WebauthnGetException::class, $this->never(), $this->once()], + 'webauthnLoginError' => [WebauthnLoginErrorException::class, $this->never(), $this->never()] + ]; + } +} \ No newline at end of file diff --git a/src/tests/unit/Modules/Application/Model/UserWebauthnTest.php b/src/tests/unit/Modules/Application/Model/UserWebauthnTest.php new file mode 100644 index 0000000..8f94e1a --- /dev/null +++ b/src/tests/unit/Modules/Application/Model/UserWebauthnTest.php @@ -0,0 +1,66 @@ + + * @link https://www.oxidmodule.com + */ + +declare(strict_types=1); + +namespace D3\Webauthn\tests\unit\Modules\Application\Model; + +use D3\TestingTools\Development\CanAccessRestricted; +use OxidEsales\Eshop\Application\Model\User; +use OxidEsales\Eshop\Core\Registry; +use OxidEsales\Eshop\Core\Session; +use OxidEsales\TestingLibrary\UnitTestCase; +use PHPUnit\Framework\MockObject\MockObject; +use ReflectionException; + +class UserWebauthnTest extends UnitTestCase +{ + use CanAccessRestricted; + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Modules\Application\Model\d3_User_Webauthn::logout + */ + public function canLogout() + { + /** @var Session|MockObject $sessionMock */ + $sessionMock = $this->getMockBuilder(Session::class) + ->onlyMethods(['deleteVariable']) + ->getMock(); + $sessionMock->expects($this->atLeast(11))->method('deleteVariable')->willReturn(true); + + /** @var User|MockObject $sut */ + $sut = $this->getMockBuilder(User::class) + ->onlyMethods(['d3CallMockableParent', 'd3GetMockableRegistryObject']) + ->getMock(); + $sut->method('d3CallMockableParent')->willReturn(true); + $sut->method('d3GetMockableRegistryObject')->willReturnCallback( + function () use ($sessionMock) { + $args = func_get_args(); + switch ($args[0]) { + case Session::class: + return $sessionMock; + default: + return Registry::get($args[0]); + } + } + ); + + $this->callMethod( + $sut, + 'logout' + ); + } +} \ No newline at end of file