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