summaryrefslogtreecommitdiffstats
path: root/apps/twofactor_backupcodes/tests
diff options
context:
space:
mode:
authorChristoph Wurst <christoph@winzerhof-wurst.at>2016-08-29 19:19:44 +0200
committerRoeland Jago Douma <roeland@famdouma.nl>2016-09-05 08:51:13 +0200
commit8acb734854484e2ffd235929f6e7d0ba4c273844 (patch)
tree3269bc6cc60b51d4fd507d91e8eca3a4ecc262cd /apps/twofactor_backupcodes/tests
parent8b484eedf029b8e1a9dcef0efb09db381888c4b0 (diff)
downloadnextcloud-server-8acb734854484e2ffd235929f6e7d0ba4c273844.tar.gz
nextcloud-server-8acb734854484e2ffd235929f6e7d0ba4c273844.zip
add 2fa backup codes app
* add backup codes app unit tests * add integration tests for the backup codes app
Diffstat (limited to 'apps/twofactor_backupcodes/tests')
-rw-r--r--apps/twofactor_backupcodes/tests/Integration/Db/BackupCodeMapperTest.php113
-rw-r--r--apps/twofactor_backupcodes/tests/Integration/Service/BackupCodeStorageTest.php90
-rw-r--r--apps/twofactor_backupcodes/tests/Unit/Controller/SettingsControllerTest.php95
-rw-r--r--apps/twofactor_backupcodes/tests/Unit/Provider/BackupCodesProviderTest.php103
-rw-r--r--apps/twofactor_backupcodes/tests/Unit/Service/BackupCodeStorageTest.php228
5 files changed, 629 insertions, 0 deletions
diff --git a/apps/twofactor_backupcodes/tests/Integration/Db/BackupCodeMapperTest.php b/apps/twofactor_backupcodes/tests/Integration/Db/BackupCodeMapperTest.php
new file mode 100644
index 00000000000..5d7d71dd17a
--- /dev/null
+++ b/apps/twofactor_backupcodes/tests/Integration/Db/BackupCodeMapperTest.php
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\TwoFactor_BackupCodes\Tests\Integration\Db;
+
+use OC;
+use OCA\TwoFactor_BackupCodes\Db\BackupCode;
+use OCA\TwoFactor_BackupCodes\Db\BackupCodeMapper;
+use OCP\IDBConnection;
+use OCP\IUser;
+use Test\TestCase;
+
+/**
+ * @group DB
+ */
+class BackupCodeMapperTest extends TestCase {
+
+ /** @var IDBConnection */
+ private $db;
+
+ /** @var BackupCodeMapper */
+ private $mapper;
+
+ /** @var string */
+ private $testUID = 'test123456';
+
+ private function resetDB() {
+ $qb = $this->db->getQueryBuilder();
+ $qb->delete($this->mapper->getTableName())
+ ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($this->testUID)));
+ $qb->execute();
+ }
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->db = OC::$server->getDatabaseConnection();
+ $this->mapper = OC::$server->query(BackupCodeMapper::class);
+
+ $this->resetDB();
+ }
+
+ protected function tearDown() {
+ parent::tearDown();
+
+ $this->resetDB();
+ }
+
+ public function testGetBackupCodes() {
+ $code1 = new BackupCode();
+ $code1->setUserId($this->testUID);
+ $code1->setCode('1|$2y$10$Fyo.DkMtkaHapVvRVbQBeeIdi5x/6nmPnxiBzD0GDKa08NMus5xze');
+ $code1->setUsed(1);
+
+ $code2 = new BackupCode();
+ $code2->setUserId($this->testUID);
+ $code2->setCode('1|$2y$10$nj3sZaCqGN8t6.SsnNADt.eX34UCkdX6FPx.r.rIwE6Jj3vi5wyt2');
+ $code2->setUsed(0);
+
+ $this->mapper->insert($code1);
+ $this->mapper->insert($code2);
+
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue($this->testUID));
+
+ $dbCodes = $this->mapper->getBackupCodes($user);
+
+ $this->assertCount(2, $dbCodes);
+ $this->assertInstanceOf(BackupCode::class, $dbCodes[0]);
+ $this->assertInstanceOf(BackupCode::class, $dbCodes[1]);
+ }
+
+ public function testDeleteCodes() {
+ $code = new BackupCode();
+ $code->setUserId($this->testUID);
+ $code->setCode('1|$2y$10$CagG8pEhZL.xDirtCCP/KuuWtnsAasgq60zY9rU46dBK4w8yW0Z/y');
+ $code->setUsed(1);
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+ $user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue($this->testUID));
+
+ $this->mapper->insert($code);
+
+ $this->assertCount(1, $this->mapper->getBackupCodes($user));
+
+ $this->mapper->deleteCodes($user);
+
+ $this->assertCount(0, $this->mapper->getBackupCodes($user));
+ }
+
+}
diff --git a/apps/twofactor_backupcodes/tests/Integration/Service/BackupCodeStorageTest.php b/apps/twofactor_backupcodes/tests/Integration/Service/BackupCodeStorageTest.php
new file mode 100644
index 00000000000..5517af5ce0d
--- /dev/null
+++ b/apps/twofactor_backupcodes/tests/Integration/Service/BackupCodeStorageTest.php
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\TwoFactor_BackupCodes\Tests\Integration\Service;
+
+use OC;
+use OCA\TwoFactor_BackupCodes\Service\BackupCodeStorage;
+use Test\TestCase;
+
+/**
+ * @group DB
+ */
+class BackupCodeStorageTest extends TestCase {
+
+ /** @var BackupCodeStorage */
+ private $storage;
+
+ /** @var string */
+ private $testUID = 'test123456789';
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->storage = OC::$server->query(BackupCodeStorage::class);
+ }
+
+ public function testSimpleWorkFlow() {
+ $user = $this->getMockBuilder(\OCP\IUser::class)->getMock();
+ $user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue($this->testUID));
+
+ // Create codes
+ $codes = $this->storage->createCodes($user, 5);
+ $this->assertCount(5, $codes);
+ $this->assertTrue($this->storage->hasBackupCodes($user));
+ $initialState = [
+ 'enabled' => true,
+ 'total' => 5,
+ 'used' => 0,
+ ];
+ $this->assertEquals($initialState, $this->storage->getBackupCodesState($user));
+
+ // Use codes
+ $code = $codes[2];
+ $this->assertTrue($this->storage->validateCode($user, $code));
+ // Code must not be used twice
+ $this->assertFalse($this->storage->validateCode($user, $code));
+ // Invalid codes are invalid
+ $this->assertFalse($this->storage->validateCode($user, 'I DO NOT EXIST'));
+ $stateAfter = [
+ 'enabled' => true,
+ 'total' => 5,
+ 'used' => 1,
+ ];
+ $this->assertEquals($stateAfter, $this->storage->getBackupCodesState($user));
+
+ // Deplete codes
+ $this->assertTrue($this->storage->validateCode($user, $codes[0]));
+ $this->assertTrue($this->storage->validateCode($user, $codes[1]));
+ $this->assertTrue($this->storage->validateCode($user, $codes[3]));
+ $this->assertTrue($this->storage->validateCode($user, $codes[4]));
+ $stateAllUsed = [
+ 'enabled' => true,
+ 'total' => 5,
+ 'used' => 5,
+ ];
+ $this->assertEquals($stateAllUsed, $this->storage->getBackupCodesState($user));
+ }
+
+}
diff --git a/apps/twofactor_backupcodes/tests/Unit/Controller/SettingsControllerTest.php b/apps/twofactor_backupcodes/tests/Unit/Controller/SettingsControllerTest.php
new file mode 100644
index 00000000000..918d1a8c64d
--- /dev/null
+++ b/apps/twofactor_backupcodes/tests/Unit/Controller/SettingsControllerTest.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\TwoFactor_BackupCodes\Tests\Unit\Controller;
+
+use OCA\TwoFactor_BackupCodes\Controller\SettingsController;
+use OCA\TwoFactor_BackupCodes\Service\BackupCodeStorage;
+use OCP\IRequest;
+use OCP\IUser;
+use OCP\IUserSession;
+use Test\TestCase;
+
+class SettingsControllerTest extends TestCase {
+
+ /** @var IRequest|PHPUnit_Framework_MockObject_MockObject */
+ private $request;
+
+ /** @var BackupCodeStorage|PHPUnit_Framework_MockObject_MockObject */
+ private $storage;
+
+ /** @var IUserSession|PHPUnit_Framework_MockObject_MockObject */
+ private $userSession;
+
+ /** @var SettingsController */
+ private $controller;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->request = $this->getMockBuilder(IRequest::class)->getMock();
+ $this->storage = $this->getMockBuilder(BackupCodeStorage::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->userSession = $this->getMockBuilder(IUserSession::class)->getMock();
+
+ $this->controller = new SettingsController('twofactor_backupcodes', $this->request, $this->storage, $this->userSession);
+ }
+
+ public function testState() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+ $this->storage->expects($this->once())
+ ->method('getBackupCodesState')
+ ->with($user)
+ ->will($this->returnValue('state'));
+
+ $this->assertEquals('state', $this->controller->state());
+ }
+
+ public function testCreateCodes() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+
+ $codes = ['a', 'b'];
+ $this->userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+ $this->storage->expects($this->once())
+ ->method('createCodes')
+ ->with($user)
+ ->will($this->returnValue($codes));
+ $this->storage->expects($this->once())
+ ->method('getBackupCodesState')
+ ->with($user)
+ ->will($this->returnValue('state'));
+
+ $expected = [
+ 'codes' => $codes,
+ 'state' => 'state',
+ ];
+ $this->assertEquals($expected, $this->controller->createCodes());
+ }
+
+}
diff --git a/apps/twofactor_backupcodes/tests/Unit/Provider/BackupCodesProviderTest.php b/apps/twofactor_backupcodes/tests/Unit/Provider/BackupCodesProviderTest.php
new file mode 100644
index 00000000000..a744a44e609
--- /dev/null
+++ b/apps/twofactor_backupcodes/tests/Unit/Provider/BackupCodesProviderTest.php
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\TwoFactor_BackupCodes\Tests\Unit\Provider;
+
+use OCA\TwoFactor_BackupCodes\Provider\BackupCodesProvider;
+use OCA\TwoFactor_BackupCodes\Service\BackupCodeStorage;
+use OCP\IL10N;
+use OCP\IUser;
+use OCP\Template;
+use Test\TestCase;
+
+class BackupCodesProviderTest extends TestCase {
+
+ /** @var BackupCodeStorage|PHPUnit_Framework_MockObject_MockObject */
+ private $storage;
+
+ /** @var IL10N|PHPUnit_Framework_MockObject_MockObject */
+ private $l10n;
+
+ /** @var BackupCodesProvider */
+ private $provider;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->storage = $this->getMockBuilder(BackupCodeStorage::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->l10n = $this->getMockBuilder(IL10N::class)->getMock();
+ $this->provider = new BackupCodesProvider($this->storage, $this->l10n);
+ }
+
+ public function testGetId() {
+ $this->assertEquals('backup_codes', $this->provider->getId());
+ }
+
+ public function testGetDisplayName() {
+ $this->l10n->expects($this->once())
+ ->method('t')
+ ->with('Backup code')
+ ->will($this->returnValue('l10n backup code'));
+ $this->assertSame('l10n backup code', $this->provider->getDisplayName());
+ }
+
+ public function testGetDescription() {
+ $this->l10n->expects($this->once())
+ ->method('t')
+ ->with('Use backup code')
+ ->will($this->returnValue('l10n use backup code'));
+ $this->assertSame('l10n use backup code', $this->provider->getDescription());
+ }
+
+ public function testGetTempalte() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+ $expected = new Template('twofactor_backupcodes', 'challenge');
+
+ $this->assertEquals($expected, $this->provider->getTemplate($user));
+ }
+
+ public function testVerfiyChallenge() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+ $challenge = 'xyz';
+
+ $this->storage->expects($this->once())
+ ->method('validateCode')
+ ->with($user, $challenge)
+ ->will($this->returnValue(false));
+
+ $this->assertFalse($this->provider->verifyChallenge($user, $challenge));
+ }
+
+ public function testIsTwoFactorEnabledForUser() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+
+ $this->storage->expects($this->once())
+ ->method('hasBackupCodes')
+ ->with($user)
+ ->will($this->returnValue(true));
+
+ $this->assertTrue($this->provider->isTwoFactorAuthEnabledForUser($user));
+ }
+
+}
diff --git a/apps/twofactor_backupcodes/tests/Unit/Service/BackupCodeStorageTest.php b/apps/twofactor_backupcodes/tests/Unit/Service/BackupCodeStorageTest.php
new file mode 100644
index 00000000000..04c51fa7e14
--- /dev/null
+++ b/apps/twofactor_backupcodes/tests/Unit/Service/BackupCodeStorageTest.php
@@ -0,0 +1,228 @@
+<?php
+
+/**
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\TwoFactor_BackupCodes\Tests\Unit\Service;
+
+use OCA\TwoFactor_BackupCodes\Db\BackupCode;
+use OCA\TwoFactor_BackupCodes\Db\BackupCodeMapper;
+use OCA\TwoFactor_BackupCodes\Service\BackupCodeStorage;
+use OCP\IUser;
+use OCP\Security\IHasher;
+use OCP\Security\ISecureRandom;
+use Test\TestCase;
+
+class BackupCodeStorageTest extends TestCase {
+
+ /** @var BackupCodeMapper|PHPUnit_Framework_MockObject_MockObject */
+ private $mapper;
+
+ /** @var ISecureRandom|PHPUnit_Framework_MockObject_MockObject */
+ private $random;
+
+ /** @var IHasher|PHPUnit_Framework_MockObject_MockObject */
+ private $hasher;
+
+ /** @var BackupCodeStorage */
+ private $storage;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->mapper = $this->getMockBuilder(BackupCodeMapper::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->random = $this->getMockBuilder(ISecureRandom::class)->getMock();
+ $this->hasher = $this->getMockBuilder(IHasher::class)->getMock();
+ $this->storage = new BackupCodeStorage($this->mapper, $this->random, $this->hasher);
+ }
+
+ public function testCreateCodes() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+ $number = 5;
+
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('fritz'));
+ $this->random->expects($this->exactly($number))
+ ->method('generate')
+ ->with(10, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
+ ->will($this->returnValue('CODEABCDEF'));
+ $this->hasher->expects($this->exactly($number))
+ ->method('hash')
+ ->with('CODEABCDEF')
+ ->will($this->returnValue('HASHEDCODE'));
+ $row = new BackupCode();
+ $row->setUserId('fritz');
+ $row->setCode('HASHEDCODE');
+ $row->setUsed(0);
+ $this->mapper->expects($this->exactly($number))
+ ->method('insert')
+ ->with($this->equalTo($row));
+
+ $codes = $this->storage->createCodes($user, $number);
+ $this->assertCount($number, $codes);
+ foreach ($codes as $code) {
+ $this->assertEquals('CODEABCDEF', $code);
+ }
+ }
+
+ public function testHasBackupCodes() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+ $codes = [
+ new BackupCode(),
+ new BackupCode(),
+ ];
+
+ $this->mapper->expects($this->once())
+ ->method('getBackupCodes')
+ ->with($user)
+ ->will($this->returnValue($codes));
+
+ $this->assertTrue($this->storage->hasBackupCodes($user));
+ }
+
+ public function testHasBackupCodesNoCodes() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+ $codes = [];
+
+ $this->mapper->expects($this->once())
+ ->method('getBackupCodes')
+ ->with($user)
+ ->will($this->returnValue($codes));
+
+ $this->assertFalse($this->storage->hasBackupCodes($user));
+ }
+
+ public function testGetBackupCodeState() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+
+ $code1 = new BackupCode();
+ $code1->setUsed(1);
+ $code2 = new BackupCode();
+ $code2->setUsed('0');
+ $codes = [
+ $code1,
+ $code2,
+ ];
+
+ $this->mapper->expects($this->once())
+ ->method('getBackupCodes')
+ ->with($user)
+ ->will($this->returnValue($codes));
+
+ $expected = [
+ 'enabled' => true,
+ 'total' => 2,
+ 'used' => 1,
+ ];
+ $this->assertEquals($expected, $this->storage->getBackupCodesState($user));
+ }
+
+ public function testGetBackupCodeDisabled() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+
+ $codes = [];
+
+ $this->mapper->expects($this->once())
+ ->method('getBackupCodes')
+ ->with($user)
+ ->will($this->returnValue($codes));
+
+ $expected = [
+ 'enabled' => false,
+ 'total' => 0,
+ 'used' => 0,
+ ];
+ $this->assertEquals($expected, $this->storage->getBackupCodesState($user));
+ }
+
+ public function testValidateCode() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+ $code = new BackupCode();
+ $code->setUsed(0);
+ $code->setCode('HASHEDVALUE');
+ $codes = [
+ $code,
+ ];
+
+ $this->mapper->expects($this->once())
+ ->method('getBackupCodes')
+ ->with($user)
+ ->will($this->returnValue($codes));
+ $this->hasher->expects($this->once())
+ ->method('verify')
+ ->with('CHALLENGE', 'HASHEDVALUE')
+ ->will($this->returnValue(true));
+ $this->mapper->expects($this->once())
+ ->method('update')
+ ->with($code);
+
+ $this->assertTrue($this->storage->validateCode($user, 'CHALLENGE'));
+
+ $this->assertEquals(1, $code->getUsed());
+ }
+
+ public function testValidateUsedCode() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+ $code = new BackupCode();
+ $code->setUsed('1');
+ $code->setCode('HASHEDVALUE');
+ $codes = [
+ $code,
+ ];
+
+ $this->mapper->expects($this->once())
+ ->method('getBackupCodes')
+ ->with($user)
+ ->will($this->returnValue($codes));
+ $this->hasher->expects($this->never())
+ ->method('verifiy');
+ $this->mapper->expects($this->never())
+ ->method('update');
+
+ $this->assertFalse($this->storage->validateCode($user, 'CHALLENGE'));
+ }
+
+ public function testValidateCodeWithWrongHash() {
+ $user = $this->getMockBuilder(IUser::class)->getMock();
+ $code = new BackupCode();
+ $code->setUsed(0);
+ $code->setCode('HASHEDVALUE');
+ $codes = [
+ $code,
+ ];
+
+ $this->mapper->expects($this->once())
+ ->method('getBackupCodes')
+ ->with($user)
+ ->will($this->returnValue($codes));
+ $this->hasher->expects($this->once())
+ ->method('verify')
+ ->with('CHALLENGE', 'HASHEDVALUE')
+ ->will($this->returnValue(false));
+ $this->mapper->expects($this->never())
+ ->method('update');
+
+ $this->assertFalse($this->storage->validateCode($user, 'CHALLENGE'));
+ }
+
+}