diff --git a/src/Application/Controller/Admin/d3user_totp.php b/src/Application/Controller/Admin/d3user_totp.php index 38ec75d..04b7b81 100644 --- a/src/Application/Controller/Admin/d3user_totp.php +++ b/src/Application/Controller/Admin/d3user_totp.php @@ -44,7 +44,7 @@ class d3user_totp extends AdminDetailsController if (isset($soxId) && $soxId != "-1") { /** @var d3_totp_user $oUser */ - $oUser = oxNew(User::class); + $oUser = $this->getUserObject(); if ($oUser->load($soxId)) { $this->addTplParam("oxid", $oUser->getId()); } else { @@ -60,6 +60,30 @@ class d3user_totp extends AdminDetailsController return $this->_sThisTemplate; } + /** + * @return User + */ + public function getUserObject() + { + return oxNew(User::class); + } + + /** + * @return d3totp + */ + public function getTotpObject() + { + return oxNew(d3totp::class); + } + + /** + * @return d3backupcodelist + */ + public function getBackupcodeListObject() + { + return oxNew(d3backupcodelist::class); + } + /** * @throws Exception */ @@ -73,7 +97,7 @@ class d3user_totp extends AdminDetailsController $pwd = Registry::getRequest()->getRequestEscapedParameter("pwd"); /** @var d3_totp_user $oUser */ - $oUser = oxNew(User::class); + $oUser = $this->getUserObject(); $oUser->load($this->getEditObjectId()); if (false == $oUser->isSamePassword($pwd)) { @@ -82,8 +106,8 @@ class d3user_totp extends AdminDetailsController } /** @var d3totp $oTotp */ - $oTotp = oxNew(d3totp::class); - $oTotpBackupCodes = oxNew(d3backupcodelist::class); + $oTotp = $this->getTotpObject(); + $oTotpBackupCodes = $this->getBackupcodeListObject(); if ($aParams['d3totp__oxid']) { $oTotp->load($aParams['d3totp__oxid']); } else { @@ -112,7 +136,7 @@ class d3user_totp extends AdminDetailsController $aParams = Registry::getRequest()->getRequestEscapedParameter("editval"); /** @var d3totp $oTotp */ - $oTotp = oxNew(d3totp::class); + $oTotp = $this->getTotpObject(); if ($aParams['d3totp__oxid']) { $oTotp->load($aParams['d3totp__oxid']); $oTotp->delete(); @@ -141,7 +165,7 @@ class d3user_totp extends AdminDetailsController */ public function getAvailableBackupCodeCount() { - $oBackupCodeList = oxNew(d3backupcodelist::class); + $oBackupCodeList = $this->getBackupcodeListObject(); return $oBackupCodeList->getAvailableCodeCount($this->getUser()->getId()); } } \ No newline at end of file diff --git a/src/Application/Controller/d3_account_totp.php b/src/Application/Controller/d3_account_totp.php index 3e1a144..23e0f77 100644 --- a/src/Application/Controller/d3_account_totp.php +++ b/src/Application/Controller/d3_account_totp.php @@ -1,5 +1,17 @@ + * @link http://www.oxidmodule.com + */ namespace D3\Totp\Application\Controller; @@ -9,9 +21,7 @@ use D3\Totp\Modules\Application\Model\d3_totp_user; use Doctrine\DBAL\DBALException; use Exception; use OxidEsales\Eshop\Application\Controller\AccountController; -use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; -use OxidEsales\Eshop\Core\Exception\StandardException; use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\UtilsView; @@ -39,7 +49,7 @@ class d3_account_totp extends AccountController /** * @param $aCodes */ - public function setBackupCodes($aCodes) + public function setBackupCodes(array $aCodes) { $this->aBackupCodes = $aCodes; } @@ -52,16 +62,32 @@ class d3_account_totp extends AccountController return implode(PHP_EOL, $this->aBackupCodes); } + /** + * @return d3backupcodelist + */ + public function getBackupCodeListObject() + { + return oxNew(d3backupcodelist::class); + } + /** * @return int * @throws DatabaseConnectionException */ public function getAvailableBackupCodeCount() { - $oBackupCodeList = oxNew(d3backupcodelist::class); + $oBackupCodeList = $this->getBackupCodeListObject(); return $oBackupCodeList->getAvailableCodeCount($this->getUser()->getId()); } + /** + * @return d3totp + */ + public function getTotpObject() + { + return oxNew(d3totp::class); + } + public function create() { if (Registry::getRequest()->getRequestEscapedParameter('totp_use') === '1') { @@ -70,8 +96,8 @@ class d3_account_totp extends AccountController $oUser = $this->getUser(); /** @var d3totp $oTotp */ - $oTotp = oxNew(d3totp::class); - $oTotpBackupCodes = oxNew(d3backupcodelist::class); + $oTotp = $this->getTotpObject(); + $oTotpBackupCodes = $this->getBackupCodeListObject(); $aParams = [ 'd3totp__usetotp' => 1, @@ -79,7 +105,6 @@ class d3_account_totp extends AccountController ]; $seed = Registry::getRequest()->getRequestEscapedParameter("secret"); $otp = Registry::getRequest()->getRequestEscapedParameter("otp"); - $oTotp->saveSecret($seed); $oTotp->assign($aParams); $oTotp->verify($otp, $seed); @@ -100,11 +125,10 @@ class d3_account_totp extends AccountController */ public function delete() { - if (Registry::getRequest()->getRequestEscapedParameter('totp_use') != 1) { - + if (Registry::getRequest()->getRequestEscapedParameter('totp_use') !== '1') { $oUser = $this->getUser(); /** @var d3totp $oTotp */ - $oTotp = oxNew(d3totp::class); + $oTotp = $this->getTotpObject(); if ($oUser && $oUser->getId()) { $oTotp->loadByUserId($oUser->getId()); $oTotp->delete(); diff --git a/src/tests/additional.inc.php b/src/tests/additional.inc.php new file mode 100644 index 0000000..2b70801 --- /dev/null +++ b/src/tests/additional.inc.php @@ -0,0 +1,40 @@ + + * @link http://www.oxidmodule.com + */ + +// Include totp test config +namespace D3\Totp\tests; + +use D3\ModCfg\Tests\additional_abstract; +use OxidEsales\Eshop\Core\Exception\StandardException; + +include(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'd3totp_config.php'); + +class additional extends additional_abstract +{ + /** + * additional constructor. + * @throws StandardException + */ + public function __construct() + { + if (D3TOTP_REQUIRE_MODCFG) { + $this->reactivateModCfg(); + } + } +} + +oxNew(additional::class); \ No newline at end of file diff --git a/src/tests/d3totp_config.php b/src/tests/d3totp_config.php new file mode 100644 index 0000000..0b4ea5c --- /dev/null +++ b/src/tests/d3totp_config.php @@ -0,0 +1,19 @@ + + * @link http://www.oxidmodule.com + */ + +define('D3TOTP_REQUIRE_MODCFG', true); + diff --git a/src/tests/unit/Application/Controller/Admin/d3user_totpTest.php b/src/tests/unit/Application/Controller/Admin/d3user_totpTest.php new file mode 100644 index 0000000..772153c --- /dev/null +++ b/src/tests/unit/Application/Controller/Admin/d3user_totpTest.php @@ -0,0 +1,398 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\Totp\tests\unit\Application\Controller; + +use D3\Totp\Application\Controller\Admin\d3user_totp; +use D3\Totp\Application\Model\d3backupcodelist; +use D3\Totp\Application\Model\d3totp; +use D3\Totp\tests\unit\d3TotpUnitTestCase; +use Doctrine\DBAL\DBALException; +use Exception; +use OxidEsales\Eshop\Application\Model\User; +use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; +use OxidEsales\Eshop\Core\Exception\DatabaseErrorException; +use PHPUnit_Framework_MockObject_MockObject; +use ReflectionException; + +class d3user_totpTest extends d3TotpUnitTestCase +{ + /** @var d3user_totp */ + protected $_oController; + + /** + * setup basic requirements + * @throws DBALException + * @throws DatabaseConnectionException + * @throws DatabaseErrorException + */ + public function setUp() + { + parent::setUp(); + + $this->_oController = oxNew(d3user_totp::class); + } + + public function tearDown() + { + parent::tearDown(); + + unset($this->_oController); + } + + /** + * @test + * @throws ReflectionException + */ + public function canRenderNoSelectedUser() + { + /** @var d3user_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3user_totp::class, array( + 'getEditObjectId', + 'getUserObject' + )); + $oControllerMock->method('getEditObjectId')->willReturn('-1'); + $oControllerMock->expects($this->never())->method('getUserObject')->willReturn(false); + + $this->_oController = $oControllerMock; + + $sTpl = $this->callMethod($this->_oController, 'render'); + $tplUser = $this->callMethod($this->_oController, 'getViewDataElement', array('edit')); + + $this->assertSame('d3user_totp.tpl', $sTpl); + $this->assertSame($tplUser, null); + } + + /** + * @test + * @throws ReflectionException + */ + public function canRenderSelectedUser() + { + /** @var User|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oUserMock = $this->getMock(User::class, array( + 'getId', + 'load', + )); + $oUserMock->expects($this->atLeast(1))->method('getId')->willReturn('foobar'); + $oUserMock->expects($this->atLeast(1))->method('load')->willReturn(true); + + /** @var d3user_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3user_totp::class, array( + 'getEditObjectId', + 'getUserObject' + )); + $oControllerMock->method('getEditObjectId')->willReturn('foobar'); + $oControllerMock->expects($this->once())->method('getUserObject')->willReturn($oUserMock); + + $this->_oController = $oControllerMock; + + $sTpl = $this->callMethod($this->_oController, 'render'); + $tplUser = $this->callMethod($this->_oController, 'getViewDataElement', array('edit')); + $oxid = $this->callMethod($this->_oController, 'getViewDataElement', array('oxid')); + + $this->assertSame('d3user_totp.tpl', $sTpl); + $this->assertSame($tplUser, $oUserMock); + $this->assertSame($oxid, 'foobar'); + } + + /** + * @test + * @throws ReflectionException + */ + public function getUserObjectReturnsRightInstance() + { + $this->assertInstanceOf( + User::class, + $this->callMethod($this->_oController, 'getUserObject') + ); + } + + /** + * @test + * @throws ReflectionException + */ + public function getTotpObjectReturnsRightInstance() + { + $this->assertInstanceOf( + d3totp::class, + $this->callMethod($this->_oController, 'getTotpObject') + ); + } + + /** + * @test + * @throws ReflectionException + */ + public function getBackupCodeListObjectReturnsRightInstance() + { + $this->assertInstanceOf( + d3backupcodelist::class, + $this->callMethod($this->_oController, 'getBackupCodeListObject') + ); + } + + /** + * @test + * @throws ReflectionException + */ + public function cantSaveBecauseOfWrongPassword() + { + /** @var d3backupcodelist|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oBackupCodeListMock = $this->getMock(d3backupcodelist::class, array( + 'save', + )); + $oBackupCodeListMock->expects($this->never())->method('save')->willReturn(true); + + /** @var d3totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oTotpMock = $this->getMock(d3totp::class, array( + 'save', + )); + $oTotpMock->expects($this->never())->method('save')->willReturn(true); + + /** @var User|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oUserMock = $this->getMock(User::class, array( + 'load', + 'isSamePassword', + )); + $oUserMock->expects($this->atLeast(1))->method('load')->willReturn(true); + $oUserMock->expects($this->atLeast(1))->method('isSamePassword')->willReturn(false); + + /** @var d3user_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3user_totp::class, array( + 'getEditObjectId', + 'getUserObject', + 'getTotpObject', + 'getBackupcodeListObject' + )); + $oControllerMock->method('getEditObjectId')->willReturn('foobar'); + $oControllerMock->expects($this->once())->method('getUserObject')->willReturn($oUserMock); + $oControllerMock->method('getTotpObject')->willReturn($oTotpMock); + $oControllerMock->method('getBackupcodeListObject')->willReturn($oBackupCodeListMock); + + $this->_oController = $oControllerMock; + + $this->callMethod($this->_oController, 'save'); + } + + /** + * @test + * @throws ReflectionException + */ + public function cantSaveBecauseOfNotVerifiable() + { + /** @var d3backupcodelist|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oBackupCodeListMock = $this->getMock(d3backupcodelist::class, array( + 'save', + )); + $oBackupCodeListMock->expects($this->never())->method('save')->willReturn(true); + + /** @var d3totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oTotpMock = $this->getMock(d3totp::class, array( + 'load', + 'save', + 'verify', + 'saveSecret', + 'assign' + )); + $oTotpMock->method('load')->willReturn(true); + $oTotpMock->expects($this->never())->method('save')->willReturn(true); + $oTotpMock->expects($this->once())->method('verify')->willThrowException(new Exception()); + $oTotpMock->method('saveSecret')->willReturn(true); + $oTotpMock->method('assign')->willReturn(true); + + /** @var User|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oUserMock = $this->getMock(User::class, array( + 'load', + 'isSamePassword', + )); + $oUserMock->expects($this->once())->method('load')->willReturn(true); + $oUserMock->expects($this->once())->method('isSamePassword')->willReturn(true); + + /** @var d3user_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3user_totp::class, array( + 'getEditObjectId', + 'getUserObject', + 'getTotpObject', + 'getBackupcodeListObject' + )); + $oControllerMock->method('getEditObjectId')->willReturn('foobar'); + $oControllerMock->expects($this->once())->method('getUserObject')->willReturn($oUserMock); + $oControllerMock->method('getTotpObject')->willReturn($oTotpMock); + $oControllerMock->method('getBackupcodeListObject')->willReturn($oBackupCodeListMock); + + $this->_oController = $oControllerMock; + + $this->callMethod($this->_oController, 'save'); + } + + /** + * @test + * @throws ReflectionException + */ + public function canSave() + { + /** @var d3backupcodelist|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oBackupCodeListMock = $this->getMock(d3backupcodelist::class, array( + 'save', + 'generateBackupCodes' + )); + $oBackupCodeListMock->expects($this->once())->method('save')->willReturn(true); + $oBackupCodeListMock->method('generateBackupCodes')->willReturn(true); + + /** @var d3totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oTotpMock = $this->getMock(d3totp::class, array( + 'load', + 'save', + 'verify', + 'saveSecret', + 'assign' + )); + $oTotpMock->method('load')->willReturn(true); + $oTotpMock->expects($this->once())->method('save')->willReturn(true); + $oTotpMock->expects($this->once())->method('verify')->willReturn(true); + $oTotpMock->method('saveSecret')->willReturn(true); + $oTotpMock->method('assign')->willReturn(true); + + /** @var User|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oUserMock = $this->getMock(User::class, array( + 'load', + 'isSamePassword', + )); + $oUserMock->expects($this->atLeast(1))->method('load')->willReturn(true); + $oUserMock->expects($this->atLeast(1))->method('isSamePassword')->willReturn(true); + + /** @var d3user_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3user_totp::class, array( + 'getEditObjectId', + 'getUserObject', + 'getTotpObject', + 'getBackupcodeListObject' + )); + $oControllerMock->method('getEditObjectId')->willReturn('foobar'); + $oControllerMock->expects($this->once())->method('getUserObject')->willReturn($oUserMock); + $oControllerMock->method('getTotpObject')->willReturn($oTotpMock); + $oControllerMock->method('getBackupcodeListObject')->willReturn($oBackupCodeListMock); + + $this->_oController = $oControllerMock; + + $this->callMethod($this->_oController, 'save'); + } + + /** + * @test + * @throws ReflectionException + */ + public function canSetAndGetBackupCodes() + { + $aBackupList = [ + 'foo1', + 'bar2' + ]; + + $this->callMethod($this->_oController, 'setBackupCodes', array($aBackupList)); + + $aReturn = $this->callMethod($this->_oController, 'getBackupCodes'); + + $this->assertSame('foo1'.PHP_EOL.'bar2', $aReturn); + } + + /** + * @te__st + * @throws ReflectionException + */ + public function cantDeleteIfNotSetOxid() + { + $editval = []; + $_GET['editval'] = $editval; + + /** @var d3totp|PHPUnit_Framework_MockObject_MockObject $oTotpMock */ + $oTotpMock = $this->getMock(d3totp::class, array( + 'delete' + )); + $oTotpMock->expects($this->never())->method('delete'); + + /** @var d3user_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3user_totp::class, array( + 'getTotpObject' + )); + $oControllerMock->expects($this->never())->method('getTotpObject')->willReturn($oTotpMock); + + $this->_oController = $oControllerMock; + + $this->callMethod($this->_oController, 'delete'); + } + + /** + * @test + * @throws ReflectionException + */ + public function canDelete() + { + $editval = [ + 'd3totp__oxid' => 'foo' + ]; + $_GET['editval'] = $editval; + + /** @var d3totp|PHPUnit_Framework_MockObject_MockObject $oTotpMock */ + $oTotpMock = $this->getMock(d3totp::class, array( + 'delete' + )); + $oTotpMock->expects($this->once())->method('delete')->willReturn(true); + + /** @var d3user_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3user_totp::class, array( + 'getTotpObject' + )); + $oControllerMock->method('getTotpObject')->willReturn($oTotpMock); + + $this->_oController = $oControllerMock; + + $this->callMethod($this->_oController, 'delete'); + } + + /** + * @test + * @throws ReflectionException + */ + public function canGetAvailableBackupCodeCount() + { + /** @var d3backupcodelist|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oBackupCodeListMock = $this->getMock(d3backupcodelist::class, array( + 'getAvailableCodeCount', + )); + $oBackupCodeListMock->method('getAvailableCodeCount')->willReturn(25); + + $oUser = oxNew(User::class); + $oUser->setId('foo'); + + /** @var d3user_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3user_totp::class, array( + 'getBackupCodeListObject', + 'getUser' + )); + $oControllerMock->method('getBackupCodeListObject')->willReturn($oBackupCodeListMock); + $oControllerMock->method('getUser')->willReturn($oUser); + + $this->_oController = $oControllerMock; + + $this->assertSame( + 25, + $this->callMethod($this->_oController, 'getAvailableBackupCodeCount') + ); + } +} \ No newline at end of file diff --git a/src/tests/unit/Application/Controller/d3_account_totpTest.php b/src/tests/unit/Application/Controller/d3_account_totpTest.php new file mode 100644 index 0000000..2aa72b4 --- /dev/null +++ b/src/tests/unit/Application/Controller/d3_account_totpTest.php @@ -0,0 +1,359 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\Totp\tests\unit\Application\Controller; + +use D3\Totp\Application\Controller\d3_account_totp; +use D3\Totp\Application\Model\d3backupcodelist; +use D3\Totp\Application\Model\d3totp; +use D3\Totp\tests\unit\d3TotpUnitTestCase; +use Doctrine\DBAL\DBALException; +use Exception; +use OxidEsales\Eshop\Application\Model\User; +use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; +use OxidEsales\Eshop\Core\Exception\DatabaseErrorException; +use PHPUnit_Framework_MockObject_MockObject; +use ReflectionException; + +class d3_account_totpTest extends d3TotpUnitTestCase +{ + /** @var d3_account_totp */ + protected $_oController; + + /** + * setup basic requirements + * @throws DBALException + * @throws DatabaseConnectionException + * @throws DatabaseErrorException + */ + public function setUp() + { + parent::setUp(); + + $this->_oController = oxNew(d3_account_totp::class); + } + + public function tearDown() + { + parent::tearDown(); + + unset($this->_oController); + } + + /** + * @test + * @throws ReflectionException + */ + public function renderReturnsDefaultTemplate() + { + $oUser = oxNew(User::class); + $oUser->setId('foo'); + $oUser->assign( + [ + 'oxpassword' => 'foo' + ] + ); + + /** @var d3_account_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3_account_totp::class, array( + 'getUser' + )); + $oControllerMock->method('getUser')->willReturn($oUser); + + $this->_oController = $oControllerMock; + + $sTpl = $this->callMethod($this->_oController, 'render'); + $tplUser = $this->callMethod($this->_oController, 'getViewDataElement', array('user')); + + $this->assertSame('d3_account_totp.tpl', $sTpl); + $this->assertSame($tplUser, $oUser); + } + + /** + * @test + * @throws ReflectionException + */ + public function renderReturnsLoginTemplateIfNotLoggedIn() + { + $oUser = false; + + /** @var d3_account_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3_account_totp::class, array( + 'getUser' + )); + $oControllerMock->method('getUser')->willReturn($oUser); + + $this->_oController = $oControllerMock; + + $sTpl = $this->callMethod($this->_oController, 'render'); + $tplUser = $this->callMethod($this->_oController, 'getViewDataElement', array('user')); + + $this->assertSame('page/account/login.tpl', $sTpl); + $this->assertNull($tplUser); + } + + /** + * @test + * @throws ReflectionException + */ + public function canSetAndGetBackupCodes() + { + $aBackupList = [ + 'foo1', + 'bar2' + ]; + + $this->callMethod($this->_oController, 'setBackupCodes', array($aBackupList)); + + $aReturn = $this->callMethod($this->_oController, 'getBackupCodes'); + + $this->assertSame('foo1'.PHP_EOL.'bar2', $aReturn); + } + + /** + * @test + * @throws ReflectionException + */ + public function canGetBackupCodeListReturnsRightInstance() + { + $this->assertInstanceOf( + d3backupcodelist::class, + $this->callMethod($this->_oController, 'getBackupCodeListObject') + ); + } + + /** + * @test + * @throws ReflectionException + */ + public function canGetAvailableBackupCodeCount() + { + /** @var d3backupcodelist|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oBackupCodeListMock = $this->getMock(d3backupcodelist::class, array( + 'getAvailableCodeCount', + )); + $oBackupCodeListMock->method('getAvailableCodeCount')->willReturn(25); + + $oUser = oxNew(User::class); + $oUser->setId('foo'); + + /** @var d3_account_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3_account_totp::class, array( + 'getBackupCodeListObject', + 'getUser' + )); + $oControllerMock->method('getBackupCodeListObject')->willReturn($oBackupCodeListMock); + $oControllerMock->method('getUser')->willReturn($oUser); + + $this->_oController = $oControllerMock; + + $this->assertSame( + 25, + $this->callMethod($this->_oController, 'getAvailableBackupCodeCount') + ); + } + + /** + * @test + * @throws ReflectionException + */ + public function cantCreateIfTotpNotActive() + { + $_GET['totp_use'] = 0; + + /** @var d3_account_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3_account_totp::class, array( + 'getTotpObject' + )); + $oControllerMock->expects($this->never())->method('getTotpObject')->willReturn(true); + + $this->_oController = $oControllerMock; + + $this->callMethod($this->_oController, 'create'); + } + + /** + * @test + * @throws ReflectionException + */ + public function cantCreateIfTotpNotVerfiable() + { + $_GET['totp_use'] = '1'; + + /** @var d3backupcodelist|PHPUnit_Framework_MockObject_MockObject $oBackupCodeListMock */ + $oBackupCodeListMock = $this->getMock(d3backupcodelist::class, array( + 'generateBackupCodes', + 'save' + )); + $oBackupCodeListMock->expects($this->never())->method('generateBackupCodes'); + $oBackupCodeListMock->expects($this->never())->method('save'); + + /** @var d3totp|PHPUnit_Framework_MockObject_MockObject $oTotpMock */ + $oTotpMock = $this->getMock(d3totp::class, array( + 'saveSecret', + 'assign', + 'verify', + 'save' + )); + $oTotpMock->method('saveSecret')->willReturn(true); + $oTotpMock->method('assign')->willReturn(true); + $oTotpMock->expects($this->once())->method('verify')->willThrowException(new Exception('foo')); + $oTotpMock->expects($this->never())->method('save'); + + $oUser = oxNew(User::class); + $oUser->setId('foo'); + + /** @var d3_account_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3_account_totp::class, array( + 'getTotpObject', + 'getUser', + 'getBackupCodeListObject' + )); + $oControllerMock->method('getTotpObject')->willReturn($oTotpMock); + $oControllerMock->method('getUser')->willReturn($oUser); + $oControllerMock->method('getBackupCodeListObject')->willReturn($oBackupCodeListMock); + + $this->_oController = $oControllerMock; + + $this->callMethod($this->_oController, 'create'); + } + + /** + * @test + * @throws ReflectionException + */ + public function canCreate() + { + $_GET['totp_use'] = '1'; + + /** @var d3backupcodelist|PHPUnit_Framework_MockObject_MockObject $oBackupCodeListMock */ + $oBackupCodeListMock = $this->getMock(d3backupcodelist::class, array( + 'generateBackupCodes', + 'save' + )); + $oBackupCodeListMock->method('generateBackupCodes')->willReturn(['0123', '1234']); + $oBackupCodeListMock->expects($this->once())->method('save')->willReturn(true); + $oBackupCodeListMock->method('save')->willReturn(true); + + /** @var d3totp|PHPUnit_Framework_MockObject_MockObject $oTotpMock */ + $oTotpMock = $this->getMock(d3totp::class, array( + 'saveSecret', + 'assign', + 'verify', + 'save', + 'setId', + )); + $oTotpMock->method('saveSecret')->willReturn(true); + $oTotpMock->method('assign')->willReturn(true); + $oTotpMock->method('verify')->willReturn(true); + $oTotpMock->method('setId')->willReturn(true); + $oTotpMock->expects($this->once())->method('save')->willReturn(true); + + $oUser = oxNew(User::class); + $oUser->setId('foo'); + + /** @var d3_account_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3_account_totp::class, array( + 'getTotpObject', + 'getUser', + 'getBackupCodeListObject' + )); + $oControllerMock->method('getTotpObject')->willReturn($oTotpMock); + $oControllerMock->method('getUser')->willReturn($oUser); + $oControllerMock->method('getBackupCodeListObject')->willReturn($oBackupCodeListMock); + + $this->_oController = $oControllerMock; + + $this->callMethod($this->_oController, 'create'); + } + + /** + * @test + * @throws ReflectionException + */ + public function cantDeleteIfTotpActive() + { + $_GET['totp_use'] = '1'; + + /** @var d3_account_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3_account_totp::class, array( + 'getTotpObject' + )); + $oControllerMock->expects($this->never())->method('getTotpObject')->willReturn(true); + + $this->_oController = $oControllerMock; + + $this->callMethod($this->_oController, 'delete'); + } + + /** + * @test + * @throws ReflectionException + */ + public function cantDeleteIfNoUser() + { + $_GET['totp_use'] = '0'; + + /** @var d3totp|PHPUnit_Framework_MockObject_MockObject $oTotpMock */ + $oTotpMock = $this->getMock(d3totp::class, array( + 'delete' + )); + $oTotpMock->expects($this->never())->method('delete'); + + /** @var d3_account_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3_account_totp::class, array( + 'getTotpObject', + 'getUser' + )); + $oControllerMock->method('getTotpObject')->willReturn($oTotpMock); + $oControllerMock->expects($this->once())->method('getUser')->willReturn(false); + + $this->_oController = $oControllerMock; + + $this->callMethod($this->_oController, 'delete'); + } + + /** + * @test + * @throws ReflectionException + */ + public function canDelete() + { + $_GET['totp_use'] = '0'; + + /** @var d3totp|PHPUnit_Framework_MockObject_MockObject $oTotpMock */ + $oTotpMock = $this->getMock(d3totp::class, array( + 'delete' + )); + $oTotpMock->expects($this->once())->method('delete')->willReturn(true); + + $oUser = oxNew(User::class); + $oUser->setId('foo'); + + /** @var d3_account_totp|PHPUnit_Framework_MockObject_MockObject $oControllerMock */ + $oControllerMock = $this->getMock(d3_account_totp::class, array( + 'getTotpObject', + 'getUser' + )); + $oControllerMock->method('getTotpObject')->willReturn($oTotpMock); + $oControllerMock->expects($this->once())->method('getUser')->willReturn($oUser); + + $this->_oController = $oControllerMock; + + $this->callMethod($this->_oController, 'delete'); + } +} \ No newline at end of file diff --git a/src/tests/unit/d3TotpUnitTestCase.php b/src/tests/unit/d3TotpUnitTestCase.php new file mode 100644 index 0000000..0ca8192 --- /dev/null +++ b/src/tests/unit/d3TotpUnitTestCase.php @@ -0,0 +1,23 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\Totp\tests\unit; + +use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase; + +abstract class d3TotpUnitTestCase extends d3ModCfgUnitTestCase +{ +} \ No newline at end of file