mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 13:12:41 +00:00
Remove last uses of Phake
This commit is contained in:
parent
75148bfbc6
commit
3a1fcaac39
11 changed files with 385 additions and 417 deletions
|
@ -22,32 +22,37 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
self::setConf();
|
self::setConf();
|
||||||
// create a mock user manager
|
// create a mock user manager
|
||||||
Arsse::$user = \Phake::mock(User::class);
|
$this->userMock = $this->mock(User::class);
|
||||||
\Phake::when(Arsse::$user)->auth->thenReturn(true);
|
$this->userMock->auth->returns(true);
|
||||||
// create a mock database interface
|
// create a mock database interface
|
||||||
Arsse::$db = \Phake::mock(Database::class);
|
$this->dbMock = $this->mock(Database::class);
|
||||||
\Phake::when(Arsse::$db)->begin->thenReturn(\Phake::mock(Transaction::class));
|
$this->dbMock->begin->returns($this->mock(Transaction::class));
|
||||||
// instantiate the handler
|
|
||||||
$this->u = new FeverUser();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function prepTest(): FeverUser {
|
||||||
|
Arsse::$user = $this->userMock->get();
|
||||||
|
Arsse::$db = $this->dbMock->get();
|
||||||
|
// instantiate the handler
|
||||||
|
return new FeverUser;
|
||||||
|
}
|
||||||
|
|
||||||
/** @dataProvider providePasswordCreations */
|
/** @dataProvider providePasswordCreations */
|
||||||
public function testRegisterAUserPassword(string $user, string $password = null, $exp): void {
|
public function testRegisterAUserPassword(string $user, string $password = null, $exp): void {
|
||||||
\Phake::when(Arsse::$user)->generatePassword->thenReturn("RANDOM_PASSWORD");
|
$this->userMock->generatePassword->returns("RANDOM_PASSWORD");
|
||||||
\Phake::when(Arsse::$db)->tokenCreate->thenReturnCallback(function($user, $class, $id = null) {
|
$this->dbMock->tokenCreate->does(function($user, $class, $id = null) {
|
||||||
return $id ?? "RANDOM_TOKEN";
|
return $id ?? "RANDOM_TOKEN";
|
||||||
});
|
});
|
||||||
\Phake::when(Arsse::$db)->tokenCreate("john.doe@example.org", $this->anything(), $this->anything())->thenThrow(new UserException("doesNotExist"));
|
$this->dbMock->tokenCreate->with("john.doe@example.org", $this->anything(), $this->anything())->throws(new UserException("doesNotExist"));
|
||||||
try {
|
try {
|
||||||
if ($exp instanceof \JKingWeb\Arsse\AbstractException) {
|
if ($exp instanceof \JKingWeb\Arsse\AbstractException) {
|
||||||
$this->assertException($exp);
|
$this->assertException($exp);
|
||||||
$this->u->register($user, $password);
|
$this->prepTest()->register($user, $password);
|
||||||
} else {
|
} else {
|
||||||
$this->assertSame($exp, $this->u->register($user, $password));
|
$this->assertSame($exp, $this->prepTest()->register($user, $password));
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify(Arsse::$db)->tokenRevoke($user, "fever.login");
|
$this->dbMock->tokenRevoke->calledWith($user, "fever.login");
|
||||||
\Phake::verify(Arsse::$db)->tokenCreate($user, "fever.login", md5($user.":".($password ?? "RANDOM_PASSWORD")));
|
$this->dbMock->tokenCreate->calledWith($user, "fever.login", md5($user.":".($password ?? "RANDOM_PASSWORD")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,20 +68,20 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUnregisterAUser(): void {
|
public function testUnregisterAUser(): void {
|
||||||
\Phake::when(Arsse::$db)->tokenRevoke->thenReturn(3);
|
$this->dbMock->tokenRevoke->returns(3);
|
||||||
$this->assertTrue($this->u->unregister("jane.doe@example.com"));
|
$this->assertTrue($this->prepTest()->unregister("jane.doe@example.com"));
|
||||||
\Phake::verify(Arsse::$db)->tokenRevoke("jane.doe@example.com", "fever.login");
|
$this->dbMock->tokenRevoke->calledWith("jane.doe@example.com", "fever.login");
|
||||||
\Phake::when(Arsse::$db)->tokenRevoke->thenReturn(0);
|
$this->dbMock->tokenRevoke->returns(0);
|
||||||
$this->assertFalse($this->u->unregister("john.doe@example.com"));
|
$this->assertFalse($this->prepTest()->unregister("john.doe@example.com"));
|
||||||
\Phake::verify(Arsse::$db)->tokenRevoke("john.doe@example.com", "fever.login");
|
$this->dbMock->tokenRevoke->calledWith("john.doe@example.com", "fever.login");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @dataProvider provideUserAuthenticationRequests */
|
/** @dataProvider provideUserAuthenticationRequests */
|
||||||
public function testAuthenticateAUserName(string $user, string $password, bool $exp): void {
|
public function testAuthenticateAUserName(string $user, string $password, bool $exp): void {
|
||||||
\Phake::when(Arsse::$db)->tokenLookup->thenThrow(new ExceptionInput("constraintViolation"));
|
$this->dbMock->tokenLookup->throws(new ExceptionInput("constraintViolation"));
|
||||||
\Phake::when(Arsse::$db)->tokenLookup("fever.login", md5("jane.doe@example.com:secret"))->thenReturn(['user' => "jane.doe@example.com"]);
|
$this->dbMock->tokenLookup->with("fever.login", md5("jane.doe@example.com:secret"))->returns(['user' => "jane.doe@example.com"]);
|
||||||
\Phake::when(Arsse::$db)->tokenLookup("fever.login", md5("john.doe@example.com:superman"))->thenReturn(['user' => "john.doe@example.com"]);
|
$this->dbMock->tokenLookup->with("fever.login", md5("john.doe@example.com:superman"))->returns(['user' => "john.doe@example.com"]);
|
||||||
$this->assertSame($exp, $this->u->authenticate($user, $password));
|
$this->assertSame($exp, $this->prepTest()->authenticate($user, $password));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function provideUserAuthenticationRequests(): iterable {
|
public function provideUserAuthenticationRequests(): iterable {
|
||||||
|
|
|
@ -17,17 +17,21 @@ class TestToken extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
protected const NOW = "2020-12-09T22:35:10.023419Z";
|
protected const NOW = "2020-12-09T22:35:10.023419Z";
|
||||||
protected const TOKEN = "Tk2o9YubmZIL2fm2w8Z4KlDEQJz532fNSOcTG0s2_xc=";
|
protected const TOKEN = "Tk2o9YubmZIL2fm2w8Z4KlDEQJz532fNSOcTG0s2_xc=";
|
||||||
|
|
||||||
protected $h;
|
|
||||||
protected $transaction;
|
protected $transaction;
|
||||||
|
|
||||||
public function setUp(): void {
|
public function setUp(): void {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
self::setConf();
|
self::setConf();
|
||||||
// create a mock database interface
|
// create a mock database interface
|
||||||
Arsse::$db = \Phake::mock(Database::class);
|
$this->dbMock = $this->mock(Database::class);
|
||||||
$this->transaction = \Phake::mock(Transaction::class);
|
$this->transaction = $this->mock(Transaction::class);
|
||||||
\Phake::when(Arsse::$db)->begin->thenReturn($this->transaction);
|
$this->dbMock->begin->returns($this->transaction);
|
||||||
$this->h = new Token();
|
}
|
||||||
|
|
||||||
|
protected function prepTest(): Token {
|
||||||
|
Arsse::$db = $this->dbMock->get();
|
||||||
|
// instantiate the handler
|
||||||
|
return new Token;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function v($value) {
|
protected function v($value) {
|
||||||
|
@ -35,9 +39,10 @@ class TestToken extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGenerateTokens(): void {
|
public function testGenerateTokens(): void {
|
||||||
\Phake::when(Arsse::$db)->tokenCreate->thenReturn("RANDOM TOKEN");
|
$this->dbMock->tokenCreate->returns("RANDOM TOKEN");
|
||||||
$this->assertSame("RANDOM TOKEN", $this->h->tokenGenerate("ook", "Eek"));
|
$this->assertSame("RANDOM TOKEN", $this->prepTest()->tokenGenerate("ook", "Eek"));
|
||||||
\Phake::verify(Arsse::$db)->tokenCreate("ook", "miniflux.login", \Phake::capture($token), null, "Eek");
|
$this->dbMock->tokenCreate->calledWith("ook", "miniflux.login", "~", null, "Eek");
|
||||||
|
$token = $this->dbMock->tokenCreate->firstCall()->argument(2);
|
||||||
$this->assertRegExp("/^[A-Za-z0-9_\-]{43}=$/", $token);
|
$this->assertRegExp("/^[A-Za-z0-9_\-]{43}=$/", $token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,15 +57,15 @@ class TestToken extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
['label' => "Eek", 'id' => "TOKEN 2"],
|
['label' => "Eek", 'id' => "TOKEN 2"],
|
||||||
['label' => "Ack", 'id' => "TOKEN 3"],
|
['label' => "Ack", 'id' => "TOKEN 3"],
|
||||||
];
|
];
|
||||||
\Phake::when(Arsse::$db)->tokenList->thenReturn(new Result($this->v($out)));
|
$this->dbMock->tokenList->returns(new Result($this->v($out)));
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$this->dbMock->userExists->returns(true);
|
||||||
$this->assertSame($exp, $this->h->tokenList("john.doe@example.com"));
|
$this->assertSame($exp, $this->prepTest()->tokenList("john.doe@example.com"));
|
||||||
\Phake::verify(Arsse::$db)->tokenList("john.doe@example.com", "miniflux.login");
|
$this->dbMock->tokenList->calledWith("john.doe@example.com", "miniflux.login");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testListTheTokensOfAMissingUser(): void {
|
public function testListTheTokensOfAMissingUser(): void {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$this->dbMock->userExists->returns(false);
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
$this->h->tokenList("john.doe@example.com");
|
$this->prepTest()->tokenList("john.doe@example.com");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,14 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function setUp(): void {
|
public function setUp(): void {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
self::setConf();
|
self::setConf();
|
||||||
// create a mock user manager
|
Arsse::$user = $this->mock(User::class)->get();
|
||||||
Arsse::$user = \Phake::mock(User::class);
|
|
||||||
// create a mock database interface
|
// create a mock database interface
|
||||||
Arsse::$db = \Phake::mock(Database::class);
|
$this->dbMock = $this->mock(Database::class);
|
||||||
$this->h = new Icon();
|
$this->h = new Icon();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function req(string $target, string $method = "GET", string $user = null): ResponseInterface {
|
protected function req(string $target, string $method = "GET", string $user = null): ResponseInterface {
|
||||||
|
Arsse::$db = $this->dbMock->get();
|
||||||
$prefix = "/tt-rss/feed-icons/";
|
$prefix = "/tt-rss/feed-icons/";
|
||||||
$url = $prefix.$target;
|
$url = $prefix.$target;
|
||||||
$req = $this->serverRequest($method, $url, $prefix, [], [], null, "", [], $user);
|
$req = $this->serverRequest($method, $url, $prefix, [], [], null, "", [], $user);
|
||||||
|
@ -45,11 +45,11 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRetrieveFavion(): void {
|
public function testRetrieveFavion(): void {
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon->thenReturn(['url' => null]);
|
$this->dbMock->subscriptionIcon->returns(['url' => null]);
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon($this->anything(), 1123, false)->thenThrow(new ExceptionInput("subjectMissing"));
|
$this->dbMock->subscriptionIcon->with($this->anything(), 1123, false)->throws(new ExceptionInput("subjectMissing"));
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon($this->anything(), 42, false)->thenReturn(['url' => "http://example.com/favicon.ico"]);
|
$this->dbMock->subscriptionIcon->with($this->anything(), 42, false)->returns(['url' => "http://example.com/favicon.ico"]);
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon($this->anything(), 2112, false)->thenReturn(['url' => "http://example.net/logo.png"]);
|
$this->dbMock->subscriptionIcon->with($this->anything(), 2112, false)->returns(['url' => "http://example.net/logo.png"]);
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon($this->anything(), 1337, false)->thenReturn(['url' => "http://example.org/icon.gif\r\nLocation: http://bad.example.com/"]);
|
$this->dbMock->subscriptionIcon->with($this->anything(), 1337, false)->returns(['url' => "http://example.org/icon.gif\r\nLocation: http://bad.example.com/"]);
|
||||||
// these requests should succeed
|
// these requests should succeed
|
||||||
$exp = new Response(301, ['Location' => "http://example.com/favicon.ico"]);
|
$exp = new Response(301, ['Location' => "http://example.com/favicon.ico"]);
|
||||||
$this->assertMessage($exp, $this->req("42.ico"));
|
$this->assertMessage($exp, $this->req("42.ico"));
|
||||||
|
@ -71,13 +71,13 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
||||||
public function testRetrieveFavionWithHttpAuthentication(): void {
|
public function testRetrieveFavionWithHttpAuthentication(): void {
|
||||||
$url = ['url' => "http://example.org/icon.gif\r\nLocation: http://bad.example.com/"];
|
$url = ['url' => "http://example.org/icon.gif\r\nLocation: http://bad.example.com/"];
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon->thenReturn(['url' => null]);
|
$this->dbMock->subscriptionIcon->returns(['url' => null]);
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon($this->user, 42, false)->thenReturn($url);
|
$this->dbMock->subscriptionIcon->with($this->user, 42, false)->returns($url);
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon("jane.doe", 2112, false)->thenReturn($url);
|
$this->dbMock->subscriptionIcon->with("jane.doe", 2112, false)->returns($url);
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon($this->user, 1337, false)->thenReturn($url);
|
$this->dbMock->subscriptionIcon->with($this->user, 1337, false)->returns($url);
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon(null, 42, false)->thenReturn($url);
|
$this->dbMock->subscriptionIcon->with(null, 42, false)->returns($url);
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon(null, 2112, false)->thenReturn($url);
|
$this->dbMock->subscriptionIcon->with(null, 2112, false)->returns($url);
|
||||||
\Phake::when(Arsse::$db)->subscriptionIcon(null, 1337, false)->thenReturn($url);
|
$this->dbMock->subscriptionIcon->with(null, 1337, false)->returns($url);
|
||||||
// these requests should succeed
|
// these requests should succeed
|
||||||
$exp = new Response(301, ['Location' => "http://example.org/icon.gif"]);
|
$exp = new Response(301, ['Location' => "http://example.org/icon.gif"]);
|
||||||
$this->assertMessage($exp, $this->req("42.ico"));
|
$this->assertMessage($exp, $this->req("42.ico"));
|
||||||
|
|
|
@ -16,7 +16,8 @@ class TestSerial extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function setUp(): void {
|
public function setUp(): void {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
self::setConf();
|
self::setConf();
|
||||||
Arsse::$db = \Phake::mock(Database::class);
|
$this->dbMock = $this->mock(Database::class);
|
||||||
|
Arsse::$db = $this->dbMock->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testConstruct(): void {
|
public function testConstruct(): void {
|
||||||
|
@ -40,8 +41,8 @@ class TestSerial extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$d = new Driver;
|
$d = new Driver;
|
||||||
$d->queue(1, 4, 3);
|
$d->queue(1, 4, 3);
|
||||||
$this->assertSame(Arsse::$conf->serviceQueueWidth, $d->exec());
|
$this->assertSame(Arsse::$conf->serviceQueueWidth, $d->exec());
|
||||||
\Phake::verify(Arsse::$db)->feedUpdate(1);
|
$this->dbMock->feedUpdate->calledWith(1);
|
||||||
\Phake::verify(Arsse::$db)->feedUpdate(4);
|
$this->dbMock->feedUpdate->calledWith(4);
|
||||||
\Phake::verify(Arsse::$db)->feedUpdate(3);
|
$this->dbMock->feedUpdate->calledWith(3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,17 @@ class TestService extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function setUp(): void {
|
public function setUp(): void {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
self::setConf();
|
self::setConf();
|
||||||
Arsse::$db = \Phake::mock(Database::class);
|
$this->dbMock = $this->mock(Database::class);
|
||||||
|
Arsse::$db = $this->dbMock->get();
|
||||||
$this->srv = new Service();
|
$this->srv = new Service();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testCheckIn(): void {
|
public function testCheckIn(): void {
|
||||||
$now = time();
|
$now = time();
|
||||||
$this->srv->checkIn();
|
$this->srv->checkIn();
|
||||||
\Phake::verify(Arsse::$db)->metaSet("service_last_checkin", \Phake::capture($then), "datetime");
|
$this->dbMock->metaSet->calledWith("service_last_checkin", "~", "datetime");
|
||||||
|
$then = $this->dbMock->metaSet->firstCall()->argument(1);
|
||||||
$this->assertTime($now, $then);
|
$this->assertTime($now, $then);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,51 +38,55 @@ class TestService extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$interval = Arsse::$conf->serviceFrequency;
|
$interval = Arsse::$conf->serviceFrequency;
|
||||||
$valid = (new \DateTimeImmutable("now", new \DateTimezone("UTC")))->sub($interval);
|
$valid = (new \DateTimeImmutable("now", new \DateTimezone("UTC")))->sub($interval);
|
||||||
$invalid = $valid->sub($interval)->sub($interval);
|
$invalid = $valid->sub($interval)->sub($interval);
|
||||||
\Phake::when(Arsse::$db)->metaGet("service_last_checkin")->thenReturn(Date::transform($valid, "sql"))->thenReturn(Date::transform($invalid, "sql"));
|
$this->dbMock->metaGet->with("service_last_checkin")->returns(Date::transform($valid, "sql"), Date::transform($invalid, "sql"));
|
||||||
|
Arsse::$db = $this->dbMock->get();
|
||||||
$this->assertTrue(Service::hasCheckedIn());
|
$this->assertTrue(Service::hasCheckedIn());
|
||||||
$this->assertFalse(Service::hasCheckedIn());
|
$this->assertFalse(Service::hasCheckedIn());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPerformPreCleanup(): void {
|
public function testPerformPreCleanup(): void {
|
||||||
$this->assertTrue(Service::cleanupPre());
|
$this->assertTrue(Service::cleanupPre());
|
||||||
\Phake::verify(Arsse::$db)->feedCleanup();
|
$this->dbMock->feedCleanup->called();
|
||||||
\Phake::verify(Arsse::$db)->iconCleanup();
|
$this->dbMock->iconCleanup->called();
|
||||||
\Phake::verify(Arsse::$db)->sessionCleanup();
|
$this->dbMock->sessionCleanup->called();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPerformShortPostCleanup(): void {
|
public function testPerformShortPostCleanup(): void {
|
||||||
\Phake::when(Arsse::$db)->articleCleanup()->thenReturn(0);
|
$this->dbMock->articleCleanup->returns(0);
|
||||||
|
Arsse::$db = $this->dbMock->get();
|
||||||
$this->assertTrue(Service::cleanupPost());
|
$this->assertTrue(Service::cleanupPost());
|
||||||
\Phake::verify(Arsse::$db)->articleCleanup();
|
$this->dbMock->articleCleanup->Called();
|
||||||
\Phake::verify(Arsse::$db, \Phake::times(0))->driverMaintenance();
|
$this->dbMock->driverMaintenance->never()->called();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPerformFullPostCleanup(): void {
|
public function testPerformFullPostCleanup(): void {
|
||||||
\Phake::when(Arsse::$db)->articleCleanup()->thenReturn(1);
|
$this->dbMock->articleCleanup->returns(1);
|
||||||
|
Arsse::$db = $this->dbMock->get();
|
||||||
$this->assertTrue(Service::cleanupPost());
|
$this->assertTrue(Service::cleanupPost());
|
||||||
\Phake::verify(Arsse::$db)->articleCleanup();
|
$this->dbMock->articleCleanup->called();
|
||||||
\Phake::verify(Arsse::$db)->driverMaintenance();
|
$this->dbMock->driverMaintenance->called();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRefreshFeeds(): void {
|
public function testRefreshFeeds(): void {
|
||||||
// set up mock database actions
|
// set up mock database actions
|
||||||
\Phake::when(Arsse::$db)->metaSet->thenReturn(true);
|
$this->dbMock->metaSet->returns(true);
|
||||||
\Phake::when(Arsse::$db)->feedCleanup->thenReturn(true);
|
$this->dbMock->feedCleanup->returns(true);
|
||||||
\Phake::when(Arsse::$db)->sessionCleanup->thenReturn(true);
|
$this->dbMock->sessionCleanup->returns(true);
|
||||||
\Phake::when(Arsse::$db)->articleCleanup->thenReturn(0);
|
$this->dbMock->articleCleanup->returns(0);
|
||||||
\Phake::when(Arsse::$db)->feedListStale->thenReturn([1,2,3]);
|
$this->dbMock->feedListStale->returns([1,2,3]);
|
||||||
// perform the test
|
// perform the test
|
||||||
$d = \Phake::mock(\JKingWeb\Arsse\Service\Driver::class);
|
Arsse::$db = $this->dbMock->get();
|
||||||
$s = new \JKingWeb\Arsse\Test\Service($d);
|
$d = $this->mock(\JKingWeb\Arsse\Service\Driver::class);
|
||||||
|
$s = new \JKingWeb\Arsse\Test\Service($d->get());
|
||||||
$this->assertInstanceOf(\DateTimeInterface::class, $s->watch(false));
|
$this->assertInstanceOf(\DateTimeInterface::class, $s->watch(false));
|
||||||
// verify invocations
|
// verify invocations
|
||||||
\Phake::verify($d)->queue(1, 2, 3);
|
$d->queue->calledWith(1, 2, 3);
|
||||||
\Phake::verify($d)->exec();
|
$d->exec->called();
|
||||||
\Phake::verify($d)->clean();
|
$d->clean->called();
|
||||||
\Phake::verify(Arsse::$db)->feedCleanup();
|
$this->dbMock->feedCleanup->called();
|
||||||
\Phake::verify(Arsse::$db)->iconCleanup();
|
$this->dbMock->iconCleanup->called();
|
||||||
\Phake::verify(Arsse::$db)->sessionCleanup();
|
$this->dbMock->sessionCleanup->called();
|
||||||
\Phake::verify(Arsse::$db)->articleCleanup();
|
$this->dbMock->articleCleanup->called();
|
||||||
\Phake::verify(Arsse::$db)->metaSet("service_last_checkin", $this->anything(), "datetime");
|
$this->dbMock->metaSet->calledWith("service_last_checkin", $this->anything(), "datetime");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,13 +35,14 @@ class TestSubprocess extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRefreshFeeds(): void {
|
public function testRefreshFeeds(): void {
|
||||||
$d = \Phake::partialMock(Driver::class);
|
$dMock = $this->partialMock(Driver::class);
|
||||||
\Phake::when($d)->execCmd->thenReturnCallback(function(string $cmd) {
|
$dMock->execCmd->does(function(string $cmd) {
|
||||||
// FIXME: Does this work in Windows?
|
// FIXME: Does this work in Windows?
|
||||||
return popen("echo ".escapeshellarg($cmd), "r");
|
return popen("echo ".escapeshellarg($cmd), "r");
|
||||||
});
|
});
|
||||||
|
$d = $dMock->get();
|
||||||
$this->assertSame(3, $d->queue(1, 4, 3));
|
$this->assertSame(3, $d->queue(1, 4, 3));
|
||||||
$this->assertSame(Arsse::$conf->serviceQueueWidth, $d->exec());
|
$this->assertSame(Arsse::$conf->serviceQueueWidth, $d->exec());
|
||||||
\Phake::verify($d, \Phake::times(3))->execCmd;
|
$dMock->execCmd->times(3)->called();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,13 @@ class TestInternal extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
self::setConf();
|
self::setConf();
|
||||||
// create a mock database interface
|
// create a mock database interface
|
||||||
Arsse::$db = \Phake::mock(Database::class);
|
$this->dbMock = $this->mock(Database::class);
|
||||||
\Phake::when(Arsse::$db)->begin->thenReturn(\Phake::mock(\JKingWeb\Arsse\Db\Transaction::class));
|
$this->dbMock->begin->returns($this->mock(\JKingWeb\Arsse\Db\Transaction::class));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function prepTest(): Driver {
|
||||||
|
Arsse::$db = $this->dbMock->get();
|
||||||
|
return new Driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testConstruct(): void {
|
public function testConstruct(): void {
|
||||||
|
@ -34,12 +39,12 @@ class TestInternal extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
* @group slow
|
* @group slow
|
||||||
*/
|
*/
|
||||||
public function testAuthenticateAUser(string $user, $password, bool $exp): void {
|
public function testAuthenticateAUser(string $user, $password, bool $exp): void {
|
||||||
\Phake::when(Arsse::$db)->userPasswordGet("john.doe@example.com")->thenReturn('$2y$10$1zbqRJhxM8uUjeSBPp4IhO90xrqK0XjEh9Z16iIYEFRV4U.zeAFom'); // hash of "secret"
|
$this->dbMock->userPasswordGet->with("john.doe@example.com")->returns('$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"
|
$this->dbMock->userPasswordGet->with("jane.doe@example.com")->returns('$2y$10$bK1ljXfTSyc2D.NYvT.Eq..OpehLRXVbglW.23ihVuyhgwJCd.7Im'); // hash of "superman"
|
||||||
\Phake::when(Arsse::$db)->userPasswordGet("owen.hardy@example.com")->thenReturn("");
|
$this->dbMock->userPasswordGet->with("owen.hardy@example.com")->returns("");
|
||||||
\Phake::when(Arsse::$db)->userPasswordGet("kira.nerys@example.com")->thenThrow(new \JKingWeb\Arsse\User\ExceptionConflict("doesNotExist"));
|
$this->dbMock->userPasswordGet->with("kira.nerys@example.com")->throws(new \JKingWeb\Arsse\User\ExceptionConflict("doesNotExist"));
|
||||||
\Phake::when(Arsse::$db)->userPasswordGet("007@example.com")->thenReturn(null);
|
$this->dbMock->userPasswordGet->with("007@example.com")->returns(null);
|
||||||
$this->assertSame($exp, (new Driver)->auth($user, $password));
|
$this->assertSame($exp, $this->prepTest()->auth($user, $password));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function provideAuthentication(): iterable {
|
public function provideAuthentication(): iterable {
|
||||||
|
@ -68,115 +73,111 @@ class TestInternal extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function testListUsers(): void {
|
public function testListUsers(): void {
|
||||||
$john = "john.doe@example.com";
|
$john = "john.doe@example.com";
|
||||||
$jane = "jane.doe@example.com";
|
$jane = "jane.doe@example.com";
|
||||||
\Phake::when(Arsse::$db)->userList->thenReturn([$john, $jane])->thenReturn([$jane, $john]);
|
$this->dbMock->userList->returns([$john, $jane])->returns([$jane, $john]);
|
||||||
$driver = new Driver;
|
$driver = $this->prepTest();
|
||||||
$this->assertSame([$john, $jane], $driver->userList());
|
$this->assertSame([$john, $jane], $driver->userList());
|
||||||
$this->assertSame([$jane, $john], $driver->userList());
|
$this->assertSame([$jane, $john], $driver->userList());
|
||||||
\Phake::verify(Arsse::$db, \Phake::times(2))->userList;
|
$this->dbMock->userList->times(2)->called();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAddAUser(): void {
|
public function testAddAUser(): void {
|
||||||
$john = "john.doe@example.com";
|
$john = "john.doe@example.com";
|
||||||
\Phake::when(Arsse::$db)->userAdd->thenReturnCallback(function($user, $pass) {
|
$this->dbMock->userAdd->does(function($user, $pass) {
|
||||||
return $pass;
|
return $pass;
|
||||||
});
|
});
|
||||||
$driver = new Driver;
|
$driver = $this->prepTest();
|
||||||
$this->assertNull($driver->userAdd($john));
|
$this->assertNull($driver->userAdd($john));
|
||||||
$this->assertNull($driver->userAdd($john, null));
|
$this->assertNull($driver->userAdd($john, null));
|
||||||
$this->assertSame("secret", $driver->userAdd($john, "secret"));
|
$this->assertSame("secret", $driver->userAdd($john, "secret"));
|
||||||
\Phake::verify(Arsse::$db)->userAdd($john, "secret");
|
$this->dbMock->userAdd->calledWith($john, "secret");
|
||||||
\Phake::verify(Arsse::$db)->userAdd;
|
$this->dbMock->userAdd->called();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRenameAUser(): void {
|
public function testRenameAUser(): void {
|
||||||
$john = "john.doe@example.com";
|
$john = "john.doe@example.com";
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$this->dbMock->userExists->returns(true);
|
||||||
$this->assertTrue((new Driver)->userRename($john, "jane.doe@example.com"));
|
$this->assertTrue($this->prepTest()->userRename($john, "jane.doe@example.com"));
|
||||||
$this->assertFalse((new Driver)->userRename($john, $john));
|
$this->assertFalse($this->prepTest()->userRename($john, $john));
|
||||||
\Phake::verify(Arsse::$db, \Phake::times(2))->userExists($john);
|
$this->dbMock->userExists->times(2)->calledWith($john);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRenameAMissingUser(): void {
|
public function testRenameAMissingUser(): void {
|
||||||
$john = "john.doe@example.com";
|
$john = "john.doe@example.com";
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$this->dbMock->userExists->returns(false);
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
(new Driver)->userRename($john, "jane.doe@example.com");
|
$this->prepTest()->userRename($john, "jane.doe@example.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRemoveAUser(): void {
|
public function testRemoveAUser(): void {
|
||||||
$john = "john.doe@example.com";
|
$john = "john.doe@example.com";
|
||||||
\Phake::when(Arsse::$db)->userRemove->thenReturn(true)->thenThrow(new \JKingWeb\Arsse\User\ExceptionConflict("doesNotExist"));
|
$this->dbMock->userRemove->returns(true)->throws(new \JKingWeb\Arsse\User\ExceptionConflict("doesNotExist"));
|
||||||
$driver = new Driver;
|
$driver = $this->prepTest();
|
||||||
$this->assertTrue($driver->userRemove($john));
|
$this->assertTrue($driver->userRemove($john));
|
||||||
\Phake::verify(Arsse::$db, \Phake::times(1))->userRemove($john);
|
$this->dbMock->userRemove->calledWith($john);
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
try {
|
try {
|
||||||
$this->assertFalse($driver->userRemove($john));
|
$this->assertFalse($driver->userRemove($john));
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify(Arsse::$db, \Phake::times(2))->userRemove($john);
|
$this->dbMock->userRemove->times(2)->calledWith($john);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetAPassword(): void {
|
public function testSetAPassword(): void {
|
||||||
$john = "john.doe@example.com";
|
$john = "john.doe@example.com";
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$this->dbMock->userExists->returns(true);
|
||||||
$this->assertSame("superman", (new Driver)->userPasswordSet($john, "superman"));
|
$this->assertSame("superman", $this->prepTest()->userPasswordSet($john, "superman"));
|
||||||
$this->assertSame(null, (new Driver)->userPasswordSet($john, null));
|
$this->assertSame(null, $this->prepTest()->userPasswordSet($john, null));
|
||||||
\Phake::verify(Arsse::$db, \Phake::times(0))->userPasswordSet;
|
$this->dbMock->userPasswordSet->never()->called();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetAPasswordForAMssingUser(): void {
|
public function testSetAPasswordForAMssingUser(): void {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$this->dbMock->userExists->returns(false);
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
(new Driver)->userPasswordSet("john.doe@example.com", "secret");
|
$this->prepTest()->userPasswordSet("john.doe@example.com", "secret");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUnsetAPassword(): void {
|
public function testUnsetAPassword(): void {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$this->dbMock->userExists->returns(true);
|
||||||
$this->assertTrue((new Driver)->userPasswordUnset("john.doe@example.com"));
|
$this->assertTrue($this->prepTest()->userPasswordUnset("john.doe@example.com"));
|
||||||
\Phake::verify(Arsse::$db, \Phake::times(0))->userPasswordUnset;
|
$this->dbMock->userPasswordSet->never()->called();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUnsetAPasswordForAMssingUser(): void {
|
public function testUnsetAPasswordForAMssingUser(): void {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$this->dbMock->userExists->returns(false);
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
(new Driver)->userPasswordUnset("john.doe@example.com");
|
$this->prepTest()->userPasswordUnset("john.doe@example.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetUserProperties(): void {
|
public function testGetUserProperties(): void {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$this->dbMock->userExists->returns(true);
|
||||||
$this->assertSame([], (new Driver)->userPropertiesGet("john.doe@example.com"));
|
$this->assertSame([], $this->prepTest()->userPropertiesGet("john.doe@example.com"));
|
||||||
\Phake::verify(Arsse::$db)->userExists("john.doe@example.com");
|
$this->dbMock->userExists->calledWith("john.doe@example.com");
|
||||||
\Phake::verifyNoFurtherInteraction(Arsse::$db);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetPropertiesForAMissingUser(): void {
|
public function testGetPropertiesForAMissingUser(): void {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$this->dbMock->userExists->returns(false);
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
try {
|
try {
|
||||||
(new Driver)->userPropertiesGet("john.doe@example.com");
|
$this->prepTest()->userPropertiesGet("john.doe@example.com");
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify(Arsse::$db)->userExists("john.doe@example.com");
|
$this->dbMock->userExists->calledWith("john.doe@example.com");
|
||||||
\Phake::verifyNoFurtherInteraction(Arsse::$db);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetUserProperties(): void {
|
public function testSetUserProperties(): void {
|
||||||
$in = ['admin' => true];
|
$in = ['admin' => true];
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$this->dbMock->userExists->returns(true);
|
||||||
$this->assertSame($in, (new Driver)->userPropertiesSet("john.doe@example.com", $in));
|
$this->assertSame($in, $this->prepTest()->userPropertiesSet("john.doe@example.com", $in));
|
||||||
\Phake::verify(Arsse::$db)->userExists("john.doe@example.com");
|
$this->dbMock->userExists->calledWith("john.doe@example.com");
|
||||||
\Phake::verifyNoFurtherInteraction(Arsse::$db);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetPropertiesForAMissingUser(): void {
|
public function testSetPropertiesForAMissingUser(): void {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$this->dbMock->userExists->returns(false);
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
try {
|
try {
|
||||||
(new Driver)->userPropertiesSet("john.doe@example.com", ['admin' => true]);
|
$this->prepTest()->userPropertiesSet("john.doe@example.com", ['admin' => true]);
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify(Arsse::$db)->userExists("john.doe@example.com");
|
$this->dbMock->userExists->calledWith("john.doe@example.com");
|
||||||
\Phake::verifyNoFurtherInteraction(Arsse::$db);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
namespace JKingWeb\Arsse\TestCase\User;
|
namespace JKingWeb\Arsse\TestCase\User;
|
||||||
|
|
||||||
|
use Eloquent\Phony\Phpunit\Phony;
|
||||||
use JKingWeb\Arsse\Arsse;
|
use JKingWeb\Arsse\Arsse;
|
||||||
use JKingWeb\Arsse\Database;
|
use JKingWeb\Arsse\Database;
|
||||||
use JKingWeb\Arsse\User;
|
use JKingWeb\Arsse\User;
|
||||||
|
@ -20,19 +21,25 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
self::setConf();
|
self::setConf();
|
||||||
// create a mock database interface
|
// create a mock database interface
|
||||||
Arsse::$db = \Phake::mock(Database::class);
|
$this->dbMock= $this->mock(Database::class);
|
||||||
\Phake::when(Arsse::$db)->begin->thenReturn(\Phake::mock(\JKingWeb\Arsse\Db\Transaction::class));
|
$this->dbMock->begin->returns($this->mock(\JKingWeb\Arsse\Db\Transaction::class));
|
||||||
// create a mock user driver
|
// create a mock user driver
|
||||||
$this->drv = \Phake::mock(Driver::class);
|
$this->drv = $this->mock(Driver::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tearDown(): void {
|
protected function prepTest(?\Closure $partialMockDef = null): User {
|
||||||
\Phake::verifyNoOtherInteractions($this->drv);
|
Arsse::$db = $this->dbMock->get();
|
||||||
\Phake::verifyNoOtherInteractions(Arsse::$db);
|
if ($partialMockDef) {
|
||||||
|
$this->userMock = $this->partialMock(User::class, $this->drv->get());
|
||||||
|
$partialMockDef($this->userMock);
|
||||||
|
return $this->userMock->get();
|
||||||
|
} else {
|
||||||
|
return new User($this->drv->get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testConstruct(): void {
|
public function testConstruct(): void {
|
||||||
$this->assertInstanceOf(User::class, new User($this->drv));
|
$this->assertInstanceOf(User::class, new User($this->drv->get()));
|
||||||
$this->assertInstanceOf(User::class, new User);
|
$this->assertInstanceOf(User::class, new User);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,14 +52,13 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testStartATransaction(): void {
|
public function testStartATransaction(): void {
|
||||||
\Phake::when(Arsse::$db)->begin->thenReturn(\Phake::mock(Transaction::class));
|
$u = $this->prepTest();
|
||||||
$u = new User($this->drv);
|
|
||||||
$this->assertInstanceOf(Transaction::class, $u->begin());
|
$this->assertInstanceOf(Transaction::class, $u->begin());
|
||||||
\Phake::verify(Arsse::$db)->begin();
|
$this->dbMock->begin->calledWith();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGeneratePasswords(): void {
|
public function testGeneratePasswords(): void {
|
||||||
$u = new User($this->drv);
|
$u = $this->prepTest();
|
||||||
$pass1 = $u->generatePassword();
|
$pass1 = $u->generatePassword();
|
||||||
$pass2 = $u->generatePassword();
|
$pass2 = $u->generatePassword();
|
||||||
$this->assertNotEquals($pass1, $pass2);
|
$this->assertNotEquals($pass1, $pass2);
|
||||||
|
@ -61,18 +67,18 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
/** @dataProvider provideAuthentication */
|
/** @dataProvider provideAuthentication */
|
||||||
public function testAuthenticateAUser(bool $preAuth, string $user, string $password, bool $exp): void {
|
public function testAuthenticateAUser(bool $preAuth, string $user, string $password, bool $exp): void {
|
||||||
Arsse::$conf->userPreAuth = $preAuth;
|
Arsse::$conf->userPreAuth = $preAuth;
|
||||||
\Phake::when($this->drv)->auth->thenReturn(false);
|
$this->drv->auth->returns(false);
|
||||||
\Phake::when($this->drv)->auth("john.doe@example.com", "secret")->thenReturn(true);
|
$this->drv->auth->with("john.doe@example.com", "secret")->returns(true);
|
||||||
\Phake::when($this->drv)->auth("jane.doe@example.com", "superman")->thenReturn(true);
|
$this->drv->auth->with("jane.doe@example.com", "superman")->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userExists("john.doe@example.com")->thenReturn(true);
|
$this->dbMock->userExists->with("john.doe@example.com")->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userExists("jane.doe@example.com")->thenReturn(false);
|
$this->dbMock->userExists->with("jane.doe@example.com")->returns(false);
|
||||||
\Phake::when(Arsse::$db)->userAdd->thenReturn("");
|
$this->dbMock->userAdd->returns("");
|
||||||
$u = new User($this->drv);
|
$u = $this->prepTest();
|
||||||
$this->assertSame($exp, $u->auth($user, $password));
|
$this->assertSame($exp, $u->auth($user, $password));
|
||||||
$this->assertNull($u->id);
|
$this->assertNull($u->id);
|
||||||
\Phake::verify($this->drv, \Phake::times((int) !$preAuth))->auth($user, $password);
|
$this->drv->auth->times((int) !$preAuth)->called();
|
||||||
\Phake::verify(Arsse::$db, \Phake::times($exp ? 1 : 0))->userExists($user);
|
$this->dbMock->userExists->times($exp ? 1 : 0)->calledWith($user);
|
||||||
\Phake::verify(Arsse::$db, \Phake::times($exp && $user === "jane.doe@example.com" ? 1 : 0))->userAdd($user, $password);
|
$this->dbMock->userAdd->times($exp && $user === "jane.doe@example.com" ? 1 : 0)->calledWith($user, $password);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function provideAuthentication(): iterable {
|
public function provideAuthentication(): iterable {
|
||||||
|
@ -92,77 +98,77 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
||||||
public function testListUsers(): void {
|
public function testListUsers(): void {
|
||||||
$exp = ["john.doe@example.com", "jane.doe@example.com"];
|
$exp = ["john.doe@example.com", "jane.doe@example.com"];
|
||||||
$u = new User($this->drv);
|
$this->drv->userList->returns(["john.doe@example.com", "jane.doe@example.com"]);
|
||||||
\Phake::when($this->drv)->userList->thenReturn(["john.doe@example.com", "jane.doe@example.com"]);
|
$u = $this->prepTest();
|
||||||
$this->assertSame($exp, $u->list());
|
$this->assertSame($exp, $u->list());
|
||||||
\Phake::verify($this->drv)->userList();
|
$this->drv->userList->calledWith();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLookUpAUserByNumber(): void {
|
public function testLookUpAUserByNumber(): void {
|
||||||
$exp = "john.doe@example.com";
|
$exp = "john.doe@example.com";
|
||||||
$u = new User($this->drv);
|
$this->dbMock->userLookup->returns($exp);
|
||||||
\Phake::when(Arsse::$db)->userLookup->thenReturn($exp);
|
$u = $this->prepTest();
|
||||||
$this->assertSame($exp, $u->lookup(2112));
|
$this->assertSame($exp, $u->lookup(2112));
|
||||||
\Phake::verify(Arsse::$db)->userLookup(2112);
|
$this->dbMock->userLookup->calledWith(2112);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAddAUser(): void {
|
public function testAddAUser(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "secret";
|
$pass = "secret";
|
||||||
$u = new User($this->drv);
|
$this->drv->userAdd->returns($pass);
|
||||||
\Phake::when($this->drv)->userAdd->thenReturn($pass);
|
$this->dbMock->userExists->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$u = $this->prepTest();
|
||||||
$this->assertSame($pass, $u->add($user, $pass));
|
$this->assertSame($pass, $u->add($user, $pass));
|
||||||
\Phake::verify($this->drv)->userAdd($user, $pass);
|
$this->drv->userAdd->calledWith($user, $pass);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAddAUserWeDoNotKnow(): void {
|
public function testAddAUserWeDoNotKnow(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "secret";
|
$pass = "secret";
|
||||||
$u = new User($this->drv);
|
$this->drv->userAdd->returns($pass);
|
||||||
\Phake::when($this->drv)->userAdd->thenReturn($pass);
|
$this->dbMock->userExists->returns(false);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$u = $this->prepTest();
|
||||||
$this->assertSame($pass, $u->add($user, $pass));
|
$this->assertSame($pass, $u->add($user, $pass));
|
||||||
\Phake::verify($this->drv)->userAdd($user, $pass);
|
$this->drv->userAdd->calledWith($user, $pass);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
\Phake::verify(Arsse::$db)->userAdd($user, $pass);
|
$this->dbMock->userAdd->calledWith($user, $pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAddADuplicateUser(): void {
|
public function testAddADuplicateUser(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "secret";
|
$pass = "secret";
|
||||||
$u = new User($this->drv);
|
$this->drv->userAdd->throws(new ExceptionConflict("alreadyExists"));
|
||||||
\Phake::when($this->drv)->userAdd->thenThrow(new ExceptionConflict("alreadyExists"));
|
$this->dbMock->userExists->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$u = $this->prepTest();
|
||||||
$this->assertException("alreadyExists", "User", "ExceptionConflict");
|
$this->assertException("alreadyExists", "User", "ExceptionConflict");
|
||||||
try {
|
try {
|
||||||
$u->add($user, $pass);
|
$u->add($user, $pass);
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
\Phake::verify($this->drv)->userAdd($user, $pass);
|
$this->drv->userAdd->calledWith($user, $pass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAddADuplicateUserWeDoNotKnow(): void {
|
public function testAddADuplicateUserWeDoNotKnow(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "secret";
|
$pass = "secret";
|
||||||
$u = new User($this->drv);
|
$this->drv->userAdd->throws(new ExceptionConflict("alreadyExists"));
|
||||||
\Phake::when($this->drv)->userAdd->thenThrow(new ExceptionConflict("alreadyExists"));
|
$this->dbMock->userExists->returns(false);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$u = $this->prepTest();
|
||||||
$this->assertException("alreadyExists", "User", "ExceptionConflict");
|
$this->assertException("alreadyExists", "User", "ExceptionConflict");
|
||||||
try {
|
try {
|
||||||
$u->add($user, $pass);
|
$u->add($user, $pass);
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
\Phake::verify(Arsse::$db)->userAdd($user, null);
|
$this->dbMock->userAdd->calledWith($user, null);
|
||||||
\Phake::verify($this->drv)->userAdd($user, $pass);
|
$this->drv->userAdd->calledWith($user, $pass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @dataProvider provideInvalidUserNames */
|
/** @dataProvider provideInvalidUserNames */
|
||||||
public function testAddAnInvalidUser(string $user): void {
|
public function testAddAnInvalidUser(string $user): void {
|
||||||
$u = new User($this->drv);
|
$u = $this->prepTest();
|
||||||
$this->assertException("invalidUsername", "User", "ExceptionInput");
|
$this->assertException("invalidUsername", "User", "ExceptionInput");
|
||||||
$u->add($user, "secret");
|
$u->add($user, "secret");
|
||||||
}
|
}
|
||||||
|
@ -181,233 +187,237 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function testAddAUserWithARandomPassword(): void {
|
public function testAddAUserWithARandomPassword(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "random password";
|
$pass = "random password";
|
||||||
$u = \Phake::partialMock(User::class, $this->drv);
|
$this->drv->userAdd->returns(null)->returns($pass);
|
||||||
\Phake::when($u)->generatePassword->thenReturn($pass);
|
$this->dbMock->userExists->returns(true);
|
||||||
\Phake::when($this->drv)->userAdd->thenReturn(null)->thenReturn($pass);
|
$u = $this->prepTest(function ($u) use ($pass) {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$u->generatePassword->returns($pass);
|
||||||
|
});
|
||||||
$this->assertSame($pass, $u->add($user));
|
$this->assertSame($pass, $u->add($user));
|
||||||
\Phake::verify($this->drv)->userAdd($user, null);
|
$this->drv->userAdd->calledWith($user, null);
|
||||||
\Phake::verify($this->drv)->userAdd($user, $pass);
|
$this->drv->userAdd->calledWith($user, $pass);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRenameAUser(): void {
|
public function testRenameAUser(): void {
|
||||||
$tr = \Phake::mock(Transaction::class);
|
$tr = $this->mock(Transaction::class);
|
||||||
\Phake::when(Arsse::$db)->begin->thenReturn($tr);
|
$this->dbMock->begin->returns($tr);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$this->dbMock->userExists->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userAdd->thenReturn(true);
|
$this->dbMock->userAdd->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userRename->thenReturn(true);
|
$this->dbMock->userRename->returns(true);
|
||||||
\Phake::when($this->drv)->userRename->thenReturn(true);
|
$this->drv->userRename->returns(true);
|
||||||
$u = new User($this->drv);
|
$u = $this->prepTest();
|
||||||
$old = "john.doe@example.com";
|
$old = "john.doe@example.com";
|
||||||
$new = "jane.doe@example.com";
|
$new = "jane.doe@example.com";
|
||||||
$this->assertTrue($u->rename($old, $new));
|
$this->assertTrue($u->rename($old, $new));
|
||||||
\Phake::inOrder(
|
Phony::inOrder(
|
||||||
\Phake::verify($this->drv)->userRename($old, $new),
|
$this->drv->userRename->calledWith($old, $new),
|
||||||
\Phake::verify(Arsse::$db)->begin(),
|
$this->dbMock->begin->calledWith(),
|
||||||
\Phake::verify(Arsse::$db)->userExists($old),
|
$this->dbMock->userExists->calledWith($old),
|
||||||
\Phake::verify(Arsse::$db)->userRename($old, $new),
|
$this->dbMock->userRename->calledWith($old, $new),
|
||||||
\Phake::verify(Arsse::$db)->sessionDestroy($new),
|
$this->dbMock->sessionDestroy->calledWith($new),
|
||||||
\Phake::verify(Arsse::$db)->tokenRevoke($new, "fever.login"),
|
$this->dbMock->tokenRevoke->calledWith($new, "fever.login"),
|
||||||
\Phake::verify($tr)->commit()
|
$tr->commit->called()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRenameAUserWeDoNotKnow(): void {
|
public function testRenameAUserWeDoNotKnow(): void {
|
||||||
$tr = \Phake::mock(Transaction::class);
|
$tr = $this->mock(Transaction::class);
|
||||||
\Phake::when(Arsse::$db)->begin->thenReturn($tr);
|
$this->dbMock->begin->returns($tr);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$this->dbMock->userExists->returns(false);
|
||||||
\Phake::when(Arsse::$db)->userAdd->thenReturn(true);
|
$this->dbMock->userAdd->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userRename->thenReturn(true);
|
$this->dbMock->userRename->returns(true);
|
||||||
\Phake::when($this->drv)->userRename->thenReturn(true);
|
$this->drv->userRename->returns(true);
|
||||||
$u = new User($this->drv);
|
$u = $this->prepTest();
|
||||||
$old = "john.doe@example.com";
|
$old = "john.doe@example.com";
|
||||||
$new = "jane.doe@example.com";
|
$new = "jane.doe@example.com";
|
||||||
$this->assertTrue($u->rename($old, $new));
|
$this->assertTrue($u->rename($old, $new));
|
||||||
\Phake::inOrder(
|
Phony::inOrder(
|
||||||
\Phake::verify($this->drv)->userRename($old, $new),
|
$this->drv->userRename->calledWith($old, $new),
|
||||||
\Phake::verify(Arsse::$db)->begin(),
|
$this->dbMock->begin->calledWith(),
|
||||||
\Phake::verify(Arsse::$db)->userExists($old),
|
$this->dbMock->userExists->calledWith($old),
|
||||||
\Phake::verify(Arsse::$db)->userAdd($new, null),
|
$this->dbMock->userAdd->calledWith($new, null),
|
||||||
\Phake::verify($tr)->commit()
|
$tr->commit->called()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRenameAUserWithoutEffect(): void {
|
public function testRenameAUserWithoutEffect(): void {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$this->dbMock->userExists->returns(false);
|
||||||
\Phake::when(Arsse::$db)->userAdd->thenReturn(true);
|
$this->dbMock->userAdd->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userRename->thenReturn(true);
|
$this->dbMock->userRename->returns(true);
|
||||||
\Phake::when($this->drv)->userRename->thenReturn(false);
|
$this->drv->userRename->returns(false);
|
||||||
$u = new User($this->drv);
|
$u = $this->prepTest();
|
||||||
$old = "john.doe@example.com";
|
$old = "john.doe@example.com";
|
||||||
$this->assertFalse($u->rename($old, $old));
|
$this->assertFalse($u->rename($old, $old));
|
||||||
\Phake::verify($this->drv)->userRename($old, $old);
|
$this->drv->userRename->calledWith($old, $old);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @dataProvider provideInvalidUserNames */
|
/** @dataProvider provideInvalidUserNames */
|
||||||
public function testRenameAUserToAnInvalidName(string $new): void {
|
public function testRenameAUserToAnInvalidName(string $new): void {
|
||||||
$u = new User($this->drv);
|
$u = $this->prepTest();
|
||||||
$this->assertException("invalidUsername", "User", "ExceptionInput");
|
$this->assertException("invalidUsername", "User", "ExceptionInput");
|
||||||
$u->rename("john.doe@example.com", $new);
|
$u->rename("john.doe@example.com", $new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRemoveAUser(): void {
|
public function testRemoveAUser(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$u = new User($this->drv);
|
$this->drv->userRemove->returns(true);
|
||||||
\Phake::when($this->drv)->userRemove->thenReturn(true);
|
$this->dbMock->userExists->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$u = $this->prepTest();
|
||||||
$this->assertTrue($u->remove($user));
|
$this->assertTrue($u->remove($user));
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
\Phake::verify(Arsse::$db)->userRemove($user);
|
$this->dbMock->userRemove->calledWith($user);
|
||||||
\Phake::verify($this->drv)->userRemove($user);
|
$this->drv->userRemove->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRemoveAUserWeDoNotKnow(): void {
|
public function testRemoveAUserWeDoNotKnow(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$u = new User($this->drv);
|
$this->drv->userRemove->returns(true);
|
||||||
\Phake::when($this->drv)->userRemove->thenReturn(true);
|
$this->dbMock->userExists->returns(false);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$u = $this->prepTest();
|
||||||
$this->assertTrue($u->remove($user));
|
$this->assertTrue($u->remove($user));
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
\Phake::verify($this->drv)->userRemove($user);
|
$this->drv->userRemove->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRemoveAMissingUser(): void {
|
public function testRemoveAMissingUser(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "secret";
|
$pass = "secret";
|
||||||
$u = new User($this->drv);
|
$this->drv->userRemove->throws(new ExceptionConflict("doesNotExist"));
|
||||||
\Phake::when($this->drv)->userRemove->thenThrow(new ExceptionConflict("doesNotExist"));
|
$this->dbMock->userExists->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$u = $this->prepTest();
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
try {
|
try {
|
||||||
$u->remove($user);
|
$u->remove($user);
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
\Phake::verify(Arsse::$db)->userRemove($user);
|
$this->dbMock->userRemove->calledWith($user);
|
||||||
\Phake::verify($this->drv)->userRemove($user);
|
$this->drv->userRemove->calledWith($user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRemoveAMissingUserWeDoNotKnow(): void {
|
public function testRemoveAMissingUserWeDoNotKnow(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "secret";
|
$pass = "secret";
|
||||||
$u = new User($this->drv);
|
$this->drv->userRemove->throws(new ExceptionConflict("doesNotExist"));
|
||||||
\Phake::when($this->drv)->userRemove->thenThrow(new ExceptionConflict("doesNotExist"));
|
$this->dbMock->userExists->returns(false);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$u = $this->prepTest();
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
try {
|
try {
|
||||||
$u->remove($user);
|
$u->remove($user);
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
\Phake::verify($this->drv)->userRemove($user);
|
$this->drv->userRemove->calledWith($user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetAPassword(): void {
|
public function testSetAPassword(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "secret";
|
$pass = "secret";
|
||||||
$u = new User($this->drv);
|
$this->drv->userPasswordSet->returns($pass);
|
||||||
\Phake::when($this->drv)->userPasswordSet->thenReturn($pass);
|
$this->dbMock->userPasswordSet->returns($pass);
|
||||||
\Phake::when(Arsse::$db)->userPasswordSet->thenReturn($pass);
|
$this->dbMock->userExists->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$u = $this->prepTest();
|
||||||
$this->assertSame($pass, $u->passwordSet($user, $pass));
|
$this->assertSame($pass, $u->passwordSet($user, $pass));
|
||||||
\Phake::verify($this->drv)->userPasswordSet($user, $pass, null);
|
$this->drv->userPasswordSet->calledWith($user, $pass, null);
|
||||||
\Phake::verify(Arsse::$db)->userPasswordSet($user, $pass, null);
|
$this->dbMock->userPasswordSet->calledWith($user, $pass);
|
||||||
\Phake::verify(Arsse::$db)->sessionDestroy($user);
|
$this->dbMock->sessionDestroy->calledWith($user);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetARandomPassword(): void {
|
public function testSetARandomPassword(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "random password";
|
$pass = "random password";
|
||||||
$u = \Phake::partialMock(User::class, $this->drv);
|
$this->drv->userPasswordSet->returns(null)->returns($pass);
|
||||||
\Phake::when($u)->generatePassword->thenReturn($pass);
|
$this->dbMock->userPasswordSet->returns($pass);
|
||||||
\Phake::when($this->drv)->userPasswordSet->thenReturn(null)->thenReturn($pass);
|
$this->dbMock->userExists->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userPasswordSet->thenReturn($pass);
|
$u = $this->prepTest(function ($u) use ($pass) {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$u->generatePassword->returns($pass);
|
||||||
|
});
|
||||||
$this->assertSame($pass, $u->passwordSet($user, null));
|
$this->assertSame($pass, $u->passwordSet($user, null));
|
||||||
\Phake::verify($this->drv)->userPasswordSet($user, null, null);
|
$this->drv->userPasswordSet->calledWith($user, null, null);
|
||||||
\Phake::verify($this->drv)->userPasswordSet($user, $pass, null);
|
$this->drv->userPasswordSet->calledWith($user, $pass, null);
|
||||||
\Phake::verify(Arsse::$db)->userPasswordSet($user, $pass, null);
|
$this->dbMock->userPasswordSet->calledWith($user, $pass);
|
||||||
\Phake::verify(Arsse::$db)->sessionDestroy($user);
|
$this->dbMock->sessionDestroy->calledWith($user);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetAPasswordForAUserWeDoNotKnow(): void {
|
public function testSetAPasswordForAUserWeDoNotKnow(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "secret";
|
$pass = "secret";
|
||||||
$u = new User($this->drv);
|
$this->drv->userPasswordSet->returns($pass);
|
||||||
\Phake::when($this->drv)->userPasswordSet->thenReturn($pass);
|
$this->dbMock->userPasswordSet->returns($pass);
|
||||||
\Phake::when(Arsse::$db)->userPasswordSet->thenReturn($pass);
|
$this->dbMock->userExists->returns(false);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$u = $this->prepTest();
|
||||||
$this->assertSame($pass, $u->passwordSet($user, $pass));
|
$this->assertSame($pass, $u->passwordSet($user, $pass));
|
||||||
\Phake::verify($this->drv)->userPasswordSet($user, $pass, null);
|
$this->drv->userPasswordSet->calledWith($user, $pass, null);
|
||||||
\Phake::verify(Arsse::$db)->userAdd($user, $pass);
|
$this->dbMock->userAdd->calledWith($user, $pass);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetARandomPasswordForAUserWeDoNotKnow(): void {
|
public function testSetARandomPasswordForAUserWeDoNotKnow(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "random password";
|
$pass = "random password";
|
||||||
$u = \Phake::partialMock(User::class, $this->drv);
|
$this->drv->userPasswordSet->returns(null)->returns($pass);
|
||||||
\Phake::when($u)->generatePassword->thenReturn($pass);
|
$this->dbMock->userPasswordSet->returns($pass);
|
||||||
\Phake::when($this->drv)->userPasswordSet->thenReturn(null)->thenReturn($pass);
|
$this->dbMock->userExists->returns(false);
|
||||||
\Phake::when(Arsse::$db)->userPasswordSet->thenReturn($pass);
|
$u = $this->prepTest(function ($u) use ($pass) {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$u->generatePassword->returns($pass);
|
||||||
|
});
|
||||||
$this->assertSame($pass, $u->passwordSet($user, null));
|
$this->assertSame($pass, $u->passwordSet($user, null));
|
||||||
\Phake::verify($this->drv)->userPasswordSet($user, null, null);
|
$this->drv->userPasswordSet->calledWith($user, null, null);
|
||||||
\Phake::verify($this->drv)->userPasswordSet($user, $pass, null);
|
$this->drv->userPasswordSet->calledWith($user, $pass, null);
|
||||||
\Phake::verify(Arsse::$db)->userAdd($user, $pass);
|
$this->dbMock->userAdd->calledWith($user, $pass);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetARandomPasswordForAMissingUser(): void {
|
public function testSetARandomPasswordForAMissingUser(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$pass = "random password";
|
$pass = "random password";
|
||||||
$u = \Phake::partialMock(User::class, $this->drv);
|
$this->drv->userPasswordSet->throws(new ExceptionConflict("doesNotExist"));
|
||||||
\Phake::when($u)->generatePassword->thenReturn($pass);
|
$u = $this->prepTest(function ($u) use ($pass) {
|
||||||
\Phake::when($this->drv)->userPasswordSet->thenThrow(new ExceptionConflict("doesNotExist"));
|
$u->generatePassword->returns($pass);
|
||||||
|
});
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
try {
|
try {
|
||||||
$u->passwordSet($user, null);
|
$u->passwordSet($user, null);
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify($this->drv)->userPasswordSet($user, null, null);
|
$this->drv->userPasswordSet->calledWith($user, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUnsetAPassword(): void {
|
public function testUnsetAPassword(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$u = new User($this->drv);
|
$this->drv->userPasswordUnset->returns(true);
|
||||||
\Phake::when($this->drv)->userPasswordUnset->thenReturn(true);
|
$this->dbMock->userPasswordSet->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userPasswordUnset->thenReturn(true);
|
$this->dbMock->userExists->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$u = $this->prepTest();
|
||||||
$this->assertTrue($u->passwordUnset($user));
|
$this->assertTrue($u->passwordUnset($user));
|
||||||
\Phake::verify($this->drv)->userPasswordUnset($user, null);
|
$this->drv->userPasswordUnset->calledWith($user, null);
|
||||||
\Phake::verify(Arsse::$db)->userPasswordSet($user, null);
|
$this->dbMock->userPasswordSet->calledWith($user, null);
|
||||||
\Phake::verify(Arsse::$db)->sessionDestroy($user);
|
$this->dbMock->sessionDestroy->calledWith($user);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUnsetAPasswordForAUserWeDoNotKnow(): void {
|
public function testUnsetAPasswordForAUserWeDoNotKnow(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$u = new User($this->drv);
|
$this->drv->userPasswordUnset->returns(true);
|
||||||
\Phake::when($this->drv)->userPasswordUnset->thenReturn(true);
|
$this->dbMock->userPasswordSet->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userPasswordUnset->thenReturn(true);
|
$this->dbMock->userExists->returns(false);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$u = $this->prepTest();
|
||||||
$this->assertTrue($u->passwordUnset($user));
|
$this->assertTrue($u->passwordUnset($user));
|
||||||
\Phake::verify($this->drv)->userPasswordUnset($user, null);
|
$this->drv->userPasswordUnset->calledWith($user, null);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUnsetAPasswordForAMissingUser(): void {
|
public function testUnsetAPasswordForAMissingUser(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$u = new User($this->drv);
|
$this->drv->userPasswordUnset->throws(new ExceptionConflict("doesNotExist"));
|
||||||
\Phake::when($this->drv)->userPasswordUnset->thenThrow(new ExceptionConflict("doesNotExist"));
|
$u = $this->prepTest();
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
try {
|
try {
|
||||||
$u->passwordUnset($user);
|
$u->passwordUnset($user);
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify($this->drv)->userPasswordUnset($user, null);
|
$this->drv->userPasswordUnset->calledWith($user, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,14 +425,14 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function testGetThePropertiesOfAUser(array $exp, array $base, array $extra): void {
|
public function testGetThePropertiesOfAUser(array $exp, array $base, array $extra): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$exp = array_merge(['num' => null], array_combine(array_keys(User::PROPERTIES), array_fill(0, sizeof(User::PROPERTIES), null)), $exp);
|
$exp = array_merge(['num' => null], array_combine(array_keys(User::PROPERTIES), array_fill(0, sizeof(User::PROPERTIES), null)), $exp);
|
||||||
$u = new User($this->drv);
|
$this->drv->userPropertiesGet->returns($extra);
|
||||||
\Phake::when($this->drv)->userPropertiesGet->thenReturn($extra);
|
$this->dbMock->userPropertiesGet->returns($base);
|
||||||
\Phake::when(Arsse::$db)->userPropertiesGet->thenReturn($base);
|
$this->dbMock->userExists->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$u = $this->prepTest();
|
||||||
$this->assertSame($exp, $u->propertiesGet($user));
|
$this->assertSame($exp, $u->propertiesGet($user));
|
||||||
\Phake::verify($this->drv)->userPropertiesGet($user, true);
|
$this->drv->userPropertiesGet->calledWith($user, true);
|
||||||
\Phake::verify(Arsse::$db)->userPropertiesGet($user, true);
|
$this->dbMock->userPropertiesGet->calledWith($user, true);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function provideProperties(): iterable {
|
public function provideProperties(): iterable {
|
||||||
|
@ -441,65 +451,67 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$base = ['num' => 47, 'admin' => false, 'lang' => null, 'tz' => "Etc/UTC", 'sort_asc' => false];
|
$base = ['num' => 47, 'admin' => false, 'lang' => null, 'tz' => "Etc/UTC", 'sort_asc' => false];
|
||||||
$exp = ['num' => 47, 'admin' => false, 'lang' => null, 'tz' => "Europe/Istanbul", 'sort_asc' => false];
|
$exp = ['num' => 47, 'admin' => false, 'lang' => null, 'tz' => "Europe/Istanbul", 'sort_asc' => false];
|
||||||
$exp = array_merge(['num' => null], array_combine(array_keys(User::PROPERTIES), array_fill(0, sizeof(User::PROPERTIES), null)), $exp);
|
$exp = array_merge(['num' => null], array_combine(array_keys(User::PROPERTIES), array_fill(0, sizeof(User::PROPERTIES), null)), $exp);
|
||||||
$u = new User($this->drv);
|
$this->drv->userPropertiesGet->returns($extra);
|
||||||
\Phake::when($this->drv)->userPropertiesGet->thenReturn($extra);
|
$this->dbMock->userPropertiesGet->returns($base);
|
||||||
\Phake::when(Arsse::$db)->userPropertiesGet->thenReturn($base);
|
$this->dbMock->userAdd->returns(true);
|
||||||
\Phake::when(Arsse::$db)->userAdd->thenReturn(true);
|
$this->dbMock->userExists->returns(false);
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$u = $this->prepTest();
|
||||||
$this->assertSame($exp, $u->propertiesGet($user));
|
$this->assertSame($exp, $u->propertiesGet($user));
|
||||||
\Phake::verify($this->drv)->userPropertiesGet($user, true);
|
$this->drv->userPropertiesGet->calledWith($user, true);
|
||||||
\Phake::verify(Arsse::$db)->userPropertiesGet($user, true);
|
$this->dbMock->userPropertiesGet->calledWith($user, true);
|
||||||
\Phake::verify(Arsse::$db)->userPropertiesSet($user, $extra);
|
$this->dbMock->userPropertiesSet->calledWith($user, $extra);
|
||||||
\Phake::verify(Arsse::$db)->userAdd($user, null);
|
$this->dbMock->userAdd->calledWith($user, null);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetThePropertiesOfAMissingUser(): void {
|
public function testGetThePropertiesOfAMissingUser(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$u = new User($this->drv);
|
$this->drv->userPropertiesGet->throws(new ExceptionConflict("doesNotExist"));
|
||||||
\Phake::when($this->drv)->userPropertiesGet->thenThrow(new ExceptionConflict("doesNotExist"));
|
$u = $this->prepTest();
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
try {
|
try {
|
||||||
$u->propertiesGet($user);
|
$u->propertiesGet($user);
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify($this->drv)->userPropertiesGet($user, true);
|
$this->drv->userPropertiesGet->calledWith($user, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @dataProvider providePropertyChanges */
|
/** @dataProvider providePropertyChanges */
|
||||||
public function testSetThePropertiesOfAUser(array $in, $out): void {
|
public function testSetThePropertiesOfAUser(array $in, $out): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$u = new User($this->drv);
|
|
||||||
if ($out instanceof \Exception) {
|
if ($out instanceof \Exception) {
|
||||||
|
$u = $this->prepTest();
|
||||||
$this->assertException($out);
|
$this->assertException($out);
|
||||||
$u->propertiesSet($user, $in);
|
$u->propertiesSet($user, $in);
|
||||||
} else {
|
} else {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(true);
|
$this->dbMock->userExists->returns(true);
|
||||||
\Phake::when($this->drv)->userPropertiesSet->thenReturn($out);
|
$this->drv->userPropertiesSet->returns($out);
|
||||||
\Phake::when(Arsse::$db)->userPropertiesSet->thenReturn(true);
|
$this->dbMock->userPropertiesSet->returns(true);
|
||||||
|
$u = $this->prepTest();
|
||||||
$this->assertSame($out, $u->propertiesSet($user, $in));
|
$this->assertSame($out, $u->propertiesSet($user, $in));
|
||||||
\Phake::verify($this->drv)->userPropertiesSet($user, $in);
|
$this->drv->userPropertiesSet->calledWith($user, $in);
|
||||||
\Phake::verify(Arsse::$db)->userPropertiesSet($user, $out);
|
$this->dbMock->userPropertiesSet->calledWith($user, $out);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @dataProvider providePropertyChanges */
|
/** @dataProvider providePropertyChanges */
|
||||||
public function testSetThePropertiesOfAUserWeDoNotKnow(array $in, $out): void {
|
public function testSetThePropertiesOfAUserWeDoNotKnow(array $in, $out): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$u = new User($this->drv);
|
|
||||||
if ($out instanceof \Exception) {
|
if ($out instanceof \Exception) {
|
||||||
|
$u = $this->prepTest();
|
||||||
$this->assertException($out);
|
$this->assertException($out);
|
||||||
$u->propertiesSet($user, $in);
|
$u->propertiesSet($user, $in);
|
||||||
} else {
|
} else {
|
||||||
\Phake::when(Arsse::$db)->userExists->thenReturn(false);
|
$this->dbMock->userExists->returns(false);
|
||||||
\Phake::when($this->drv)->userPropertiesSet->thenReturn($out);
|
$this->drv->userPropertiesSet->returns($out);
|
||||||
\Phake::when(Arsse::$db)->userPropertiesSet->thenReturn(true);
|
$this->dbMock->userPropertiesSet->returns(true);
|
||||||
|
$u = $this->prepTest();
|
||||||
$this->assertSame($out, $u->propertiesSet($user, $in));
|
$this->assertSame($out, $u->propertiesSet($user, $in));
|
||||||
\Phake::verify($this->drv)->userPropertiesSet($user, $in);
|
$this->drv->userPropertiesSet->calledWith($user, $in);
|
||||||
\Phake::verify(Arsse::$db)->userPropertiesSet($user, $out);
|
$this->dbMock->userPropertiesSet->calledWith($user, $out);
|
||||||
\Phake::verify(Arsse::$db)->userExists($user);
|
$this->dbMock->userExists->calledWith($user);
|
||||||
\Phake::verify(Arsse::$db)->userAdd($user, null);
|
$this->dbMock->userAdd->calledWith($user, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,13 +532,13 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function testSetThePropertiesOfAMissingUser(): void {
|
public function testSetThePropertiesOfAMissingUser(): void {
|
||||||
$user = "john.doe@example.com";
|
$user = "john.doe@example.com";
|
||||||
$in = ['admin' => true];
|
$in = ['admin' => true];
|
||||||
$u = new User($this->drv);
|
$this->drv->userPropertiesSet->throws(new ExceptionConflict("doesNotExist"));
|
||||||
\Phake::when($this->drv)->userPropertiesSet->thenThrow(new ExceptionConflict("doesNotExist"));
|
$u = $this->prepTest();
|
||||||
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
$this->assertException("doesNotExist", "User", "ExceptionConflict");
|
||||||
try {
|
try {
|
||||||
$u->propertiesSet($user, $in);
|
$u->propertiesSet($user, $in);
|
||||||
} finally {
|
} finally {
|
||||||
\Phake::verify($this->drv)->userPropertiesSet($user, $in);
|
$this->drv->userPropertiesSet->calledWith($user, $in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,14 +37,16 @@ trait Setup {
|
||||||
// set up a file without read access
|
// set up a file without read access
|
||||||
chmod($this->path."ru.php", 0000);
|
chmod($this->path."ru.php", 0000);
|
||||||
// make the test Lang class use the vfs files
|
// make the test Lang class use the vfs files
|
||||||
$this->l = \Phake::partialMock(Lang::class, $this->path);
|
$this->l = $this->partialMock(Lang::class, $this->path);
|
||||||
\Phake::when($this->l)->globFiles->thenReturnCallback(function(string $path): array {
|
$this->l->globFiles->does(function(string $path): array {
|
||||||
return Glob::glob($this->path."*.php");
|
return Glob::glob($this->path."*.php");
|
||||||
});
|
});
|
||||||
|
$this->l = $this->l->get();
|
||||||
// create a mock Lang object so as not to create a dependency loop
|
// create a mock Lang object so as not to create a dependency loop
|
||||||
self::clearData(false);
|
self::clearData(false);
|
||||||
Arsse::$lang = \Phake::mock(Lang::class);
|
Arsse::$lang = $this->mock(Lang::class);
|
||||||
\Phake::when(Arsse::$lang)->msg->thenReturn("");
|
Arsse::$lang->msg->returns("");
|
||||||
|
Arsse::$lang = Arsse::$lang->get();
|
||||||
// call the additional setup method if it exists
|
// call the additional setup method if it exists
|
||||||
if (method_exists($this, "setUpSeries")) {
|
if (method_exists($this, "setUpSeries")) {
|
||||||
$this->setUpSeries();
|
$this->setUpSeries();
|
||||||
|
@ -52,9 +54,6 @@ trait Setup {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tearDown(): void {
|
public function tearDown(): void {
|
||||||
// verify calls to the mock Lang object
|
|
||||||
\Phake::verify(Arsse::$lang, \Phake::atLeast(0))->msg($this->isType("string"), $this->anything());
|
|
||||||
\Phake::verifyNoOtherInteractions(Arsse::$lang);
|
|
||||||
// clean up
|
// clean up
|
||||||
self::clearData(true);
|
self::clearData(true);
|
||||||
// call the additional teardiwn method if it exists
|
// call the additional teardiwn method if it exists
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^8.0 || ^9.0",
|
"phpunit/phpunit": "^8.0 || ^9.0",
|
||||||
"dms/phpunit-arraysubset-asserts": "^0.1 || ^0.2",
|
"dms/phpunit-arraysubset-asserts": "^0.1 || ^0.2",
|
||||||
"phake/phake": "^3.0",
|
|
||||||
"clue/arguments": "^2.0",
|
"clue/arguments": "^2.0",
|
||||||
"mikey179/vfsstream": "^1.6",
|
"mikey179/vfsstream": "^1.6",
|
||||||
"webmozart/glob": "^4.1",
|
"webmozart/glob": "^4.1",
|
||||||
|
|
64
vendor-bin/phpunit/composer.lock
generated
64
vendor-bin/phpunit/composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "fda9bd2446005dfe56a223890cad0849",
|
"content-hash": "ee93856e05f6ce1cc763b474c94dad6c",
|
||||||
"packages": [],
|
"packages": [],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
|
@ -500,68 +500,6 @@
|
||||||
},
|
},
|
||||||
"time": "2020-12-20T10:01:03+00:00"
|
"time": "2020-12-20T10:01:03+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "phake/phake",
|
|
||||||
"version": "v3.1.8",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/mlively/Phake.git",
|
|
||||||
"reference": "9f9dfb12c9ce6e38c73de9631ea2ab0f0ea36a65"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/mlively/Phake/zipball/9f9dfb12c9ce6e38c73de9631ea2ab0f0ea36a65",
|
|
||||||
"reference": "9f9dfb12c9ce6e38c73de9631ea2ab0f0ea36a65",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=7",
|
|
||||||
"sebastian/comparator": "^1.1|^2.0|^3.0|^4.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"codeclimate/php-test-reporter": "dev-master",
|
|
||||||
"doctrine/common": "2.3.*",
|
|
||||||
"ext-soap": "*",
|
|
||||||
"hamcrest/hamcrest-php": "1.1.*",
|
|
||||||
"phpunit/phpunit": "^7.0"
|
|
||||||
},
|
|
||||||
"suggest": {
|
|
||||||
"doctrine/common": "Allows mock annotations to use import statements for classes.",
|
|
||||||
"hamcrest/hamcrest-php": "Use Hamcrest matchers."
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "3.0.0-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-0": {
|
|
||||||
"Phake": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"BSD-3-Clause"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Mike Lively",
|
|
||||||
"email": "m@digitalsandwich.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "The Phake mock testing library",
|
|
||||||
"homepage": "https://github.com/mlively/Phake",
|
|
||||||
"keywords": [
|
|
||||||
"mock",
|
|
||||||
"testing"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/mlively/Phake/issues",
|
|
||||||
"source": "https://github.com/mlively/Phake/tree/v3.1.8"
|
|
||||||
},
|
|
||||||
"time": "2020-05-11T18:43:26+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "phar-io/manifest",
|
"name": "phar-io/manifest",
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
|
|
Loading…
Reference in a new issue