diff --git a/lib/User/Internal/Driver.php b/lib/User/Internal/Driver.php index e5928a28..4c730257 100644 --- a/lib/User/Internal/Driver.php +++ b/lib/User/Internal/Driver.php @@ -7,6 +7,7 @@ declare(strict_types=1); namespace JKingWeb\Arsse\User\Internal; use JKingWeb\Arsse\Arsse; +use JKingWeb\Arsse\User\Exception; class Driver implements \JKingWeb\Arsse\User\Driver { public function __construct() { @@ -18,7 +19,7 @@ class Driver implements \JKingWeb\Arsse\User\Driver { public function auth(string $user, string $password): bool { try { - $hash = Arsse::$db->userPasswordGet($user); + $hash = $this->userPasswordGet($user); } catch (Exception $e) { return false; } @@ -56,4 +57,8 @@ class Driver implements \JKingWeb\Arsse\User\Driver { // do nothing: the internal database is updated regardless of what the driver does (assuming it does not throw an exception) return $newPassword; } + + protected function userPasswordGet(string $user): string { + return Arsse::$db->userPasswordGet($user); + } } diff --git a/tests/cases/User/TestInternal.php b/tests/cases/User/TestInternal.php new file mode 100644 index 00000000..68b597d4 --- /dev/null +++ b/tests/cases/User/TestInternal.php @@ -0,0 +1,137 @@ +clearData(); + $this->setConf(); + // create a mock database interface + Arsse::$db = Phake::mock(Database::class); + Phake::when(Arsse::$db)->begin->thenReturn(Phake::mock(\JKingWeb\Arsse\Db\Transaction::class)); + } + + public function testConstruct() { + $this->assertInstanceOf(DriverInterface::class, new Driver); + } + + public function testFetchDriverName() { + $this->assertTrue(strlen(Driver::driverName()) > 0); + } + + /** + * @dataProvider provideAuthentication + * @group slow + */ + public function testAuthenticateAUser(bool $authorized, string $user, string $password, bool $exp) { + if ($authorized) { + Phake::when(Arsse::$db)->userPasswordGet("john.doe@example.com")->thenReturn('$2y$10$1zbqRJhxM8uUjeSBPp4IhO90xrqK0XjEh9Z16iIYEFRV4U.zeAFom'); // hash of "secret" + Phake::when(Arsse::$db)->userPasswordGet("jane.doe@example.com")->thenReturn('$2y$10$bK1ljXfTSyc2D.NYvT.Eq..OpehLRXVbglW.23ihVuyhgwJCd.7Im'); // hash of "superman" + Phake::when(Arsse::$db)->userPasswordGet("owen.hardy@example.com")->thenReturn(""); + Phake::when(Arsse::$db)->userPasswordGet("kira.nerys@example.com")->thenThrow(new \JKingWeb\Arsse\User\Exception("doesNotExist")); + } else { + Phake::when(Arsse::$db)->userPasswordGet->thenThrow(new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")); + } + $this->assertSame($exp, (new Driver)->auth($user, $password)); + } + + public function provideAuthentication() { + $john = "john.doe@example.com"; + $jane = "jane.doe@example.com"; + $owen = "owen.hardy@example.com"; + $kira = "kira.nerys@example.com"; + return [ + [false, $john, "secret", false], + [false, $jane, "superman", false], + [false, $owen, "", false], + [false, $kira, "ashalla", false], + [true, $john, "secret", true], + [true, $jane, "superman", true], + [true, $owen, "", true], + [true, $kira, "ashalla", false], + [true, $john, "top secret", false], + [true, $jane, "clark kent", false], + [true, $owen, "watchmaker", false], + [true, $kira, "singha", false], + [true, $john, "", false], + [true, $jane, "", false], + [true, $kira, "", false], + ]; + } + + public function testAuthorizeAnAction() { + Phake::verifyNoFurtherInteraction(Arsse::$db); + $this->assertTrue((new Driver)->authorize("someone", "something")); + } + + public function testListUsers() { + $john = "john.doe@example.com"; + $jane = "jane.doe@example.com"; + Phake::when(Arsse::$db)->userList->thenReturn([$john, $jane])->thenReturn([$jane, $john]); + $driver = new Driver; + $this->assertSame([$john, $jane], $driver->userList()); + $this->assertSame([$jane, $john], $driver->userList()); + Phake::verify(Arsse::$db, Phake::times(2))->userList; + } + + public function testCheckThatAUserExists() { + $john = "john.doe@example.com"; + $jane = "jane.doe@example.com"; + Phake::when(Arsse::$db)->userExists($john)->thenReturn(true); + Phake::when(Arsse::$db)->userExists($jane)->thenReturn(false); + $driver = new Driver; + $this->assertTrue($driver->userExists($john)); + Phake::verify(Arsse::$db)->userExists($john); + $this->assertFalse($driver->userExists($jane)); + Phake::verify(Arsse::$db)->userExists($jane); + } + + public function testAddAUser() { + $john = "john.doe@example.com"; + Phake::when(Arsse::$db)->userAdd->thenReturnCallback(function($user, $pass) { + return $pass; + }); + $driver = new Driver; + $this->assertNull($driver->userAdd($john)); + $this->assertNull($driver->userAdd($john, null)); + $this->assertSame("secret", $driver->userAdd($john, "secret")); + Phake::verify(Arsse::$db)->userAdd($john, "secret"); + Phake::verify(Arsse::$db)->userAdd; + } + + public function testRemoveAUser() { + $john = "john.doe@example.com"; + Phake::when(Arsse::$db)->userRemove->thenReturn(true)->thenThrow(new \JKingWeb\Arsse\User\Exception("doesNotExist")); + $driver = new Driver; + $this->assertTrue($driver->userRemove($john)); + Phake::verify(Arsse::$db, Phake::times(1))->userRemove($john); + $this->assertException("doesNotExist", "User"); + try { + $this->assertFalse($driver->userRemove($john)); + } finally { + Phake::verify(Arsse::$db, Phake::times(2))->userRemove($john); + } + } + + public function testSetAPassword() { + $john = "john.doe@example.com"; + Phake::verifyNoFurtherInteraction(Arsse::$db); + $this->assertSame("superman", (new Driver)->userPasswordSet($john, "superman")); + $this->assertSame(null, (new Driver)->userPasswordSet($john, null)); + } +} diff --git a/tests/cases/User/TestUser.php b/tests/cases/User/TestUser.php index bdb5d032..806bfff2 100644 --- a/tests/cases/User/TestUser.php +++ b/tests/cases/User/TestUser.php @@ -20,13 +20,14 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest { public function setUp() { $this->clearData(); - Arsse::$conf = new Conf; + $this->setConf(); // create a mock database interface Arsse::$db = Phake::mock(Database::class); Phake::when(Arsse::$db)->begin->thenReturn(Phake::mock(\JKingWeb\Arsse\Db\Transaction::class)); // create a mock user driver $this->drv = Phake::mock(Driver::class); } + public function testListDrivers() { $exp = [ 'JKingWeb\\Arsse\\User\\Internal\\Driver' => Arsse::$lang->msg("Driver.User.Internal.Name"), diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 2a653ec2..0cbb54bc 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -34,8 +34,8 @@ cases/Misc/TestContext.php - cases/User/TestUser.php cases/User/TestInternal.php + cases/User/TestUser.php cases/Feed/TestFetching.php