1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-22 21:22:40 +00:00

Start on replacing Phake with Phony

This commit is contained in:
J. King 2021-02-27 15:24:02 -05:00
parent 9b369d902f
commit 2348786a92
41 changed files with 574 additions and 487 deletions

View file

@ -12,7 +12,7 @@ const DOCROOT = BASE."tests".DIRECTORY_SEPARATOR."docroot".DIRECTORY_SEPARATOR;
ini_set("memory_limit", "-1"); ini_set("memory_limit", "-1");
ini_set("zend.assertions", "1"); ini_set("zend.assertions", "1");
ini_set("assert.exception", "true"); ini_set("assert.exception", "true");
error_reporting(\E_ALL); error_reporting(\E_ALL ^ \E_DEPRECATED);
require_once BASE."vendor".DIRECTORY_SEPARATOR."autoload.php"; require_once BASE."vendor".DIRECTORY_SEPARATOR."autoload.php";
if (function_exists("xdebug_set_filter")) { if (function_exists("xdebug_set_filter")) {

View file

@ -20,13 +20,16 @@ use JKingWeb\Arsse\ImportExport\OPML;
/** @covers \JKingWeb\Arsse\CLI */ /** @covers \JKingWeb\Arsse\CLI */
class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest { class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
$this->cli = \Phake::partialMock(CLI::class); $this->cli = $this->partialMock(CLI::class);
\Phake::when($this->cli)->logError->thenReturn(null); $this->cli->logError->returns(null);
\Phake::when($this->cli)->loadConf->thenReturn(true); $this->cli->loadConf->returns(true);
$this->dbMock = $this->mock(Database::class);
} }
public function assertConsole(CLI $cli, string $command, int $exitStatus, string $output = "", bool $pattern = false): void { public function assertConsole(string $command, int $exitStatus, string $output = "", bool $pattern = false): void {
Arsse::$obj = $this->objMock->get();
Arsse::$db = $this->dbMock->get();
$argv = \Clue\Arguments\split($command); $argv = \Clue\Arguments\split($command);
$output = strlen($output) ? $output.\PHP_EOL : ""; $output = strlen($output) ? $output.\PHP_EOL : "";
if ($pattern) { if ($pattern) {
@ -34,18 +37,18 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
} else { } else {
$this->expectOutputString($output); $this->expectOutputString($output);
} }
$this->assertSame($exitStatus, $cli->dispatch($argv)); $this->assertSame($exitStatus, $this->cli->get()->dispatch($argv));
} }
public function testPrintVersion(): void { public function testPrintVersion(): void {
$this->assertConsole($this->cli, "arsse.php --version", 0, Arsse::VERSION); $this->assertConsole("arsse.php --version", 0, Arsse::VERSION);
\Phake::verify($this->cli, \Phake::times(0))->loadConf; $this->cli->loadConf->never()->called();
} }
/** @dataProvider provideHelpText */ /** @dataProvider provideHelpText */
public function testPrintHelp(string $cmd, string $name): void { public function testPrintHelp(string $cmd, string $name): void {
$this->assertConsole($this->cli, $cmd, 0, str_replace("arsse.php", $name, CLI::USAGE)); $this->assertConsole($cmd, 0, str_replace("arsse.php", $name, CLI::USAGE));
\Phake::verify($this->cli, \Phake::times(0))->loadConf; $this->cli->loadConf->never()->called();
} }
public function provideHelpText(): iterable { public function provideHelpText(): iterable {
@ -60,31 +63,30 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
} }
public function testStartTheDaemon(): void { public function testStartTheDaemon(): void {
$srv = \Phake::mock(Service::class); $srv = $this->mock(Service::class);
\Phake::when(Arsse::$obj)->get(Service::class)->thenReturn($srv); $srv->watch->returns(new \DateTimeImmutable);
\Phake::when($srv)->watch->thenReturn(new \DateTimeImmutable); $this->objMock->get->with(Service::class)->returns($srv->get());
$this->assertConsole($this->cli, "arsse.php daemon", 0); $this->assertConsole("arsse.php daemon", 0);
\Phake::verify($this->cli)->loadConf; $this->cli->loadConf->called();
\Phake::verify($srv)->watch(true); $srv->watch->calledWith(true);
} }
public function testRefreshAllFeeds(): void { public function testRefreshAllFeeds(): void {
$srv = \Phake::mock(Service::class); $srv = $this->mock(Service::class);
\Phake::when(Arsse::$obj)->get(Service::class)->thenReturn($srv); $srv->watch->returns(new \DateTimeImmutable);
\Phake::when($srv)->watch->thenReturn(new \DateTimeImmutable); $this->objMock->get->with(Service::class)->returns($srv->get());
$this->assertConsole($this->cli, "arsse.php feed refresh-all", 0); $this->assertConsole("arsse.php feed refresh-all", 0);
\Phake::verify($this->cli)->loadConf; $this->cli->loadConf->called();
\Phake::verify($srv)->watch(false); $srv->watch->calledWith(false);
} }
/** @dataProvider provideFeedUpdates */ /** @dataProvider provideFeedUpdates */
public function testRefreshAFeed(string $cmd, int $exitStatus, string $output): void { public function testRefreshAFeed(string $cmd, int $exitStatus, string $output): void {
Arsse::$db = \Phake::mock(Database::class); $this->dbMock->feedUpdate->with(1, true)->returns(true);
\Phake::when(Arsse::$db)->feedUpdate(1, true)->thenReturn(true); $this->dbMock->feedUpdate->with(2, true)->throws(new \JKingWeb\Arsse\Feed\Exception("", ['url' => "http://example.com/"], $this->mockGuzzleException(ClientException::class, "", 404)));
\Phake::when(Arsse::$db)->feedUpdate(2, true)->thenThrow(new \JKingWeb\Arsse\Feed\Exception("", ['url' => "http://example.com/"], $this->mockGuzzleException(ClientException::class, "", 404))); $this->assertConsole($cmd, $exitStatus, $output);
$this->assertConsole($this->cli, $cmd, $exitStatus, $output); $this->cli->loadConf->called();
\Phake::verify($this->cli)->loadConf; $this->dbMock->feedUpdate->called();
\Phake::verify(Arsse::$db)->feedUpdate;
} }
public function provideFeedUpdates(): iterable { public function provideFeedUpdates(): iterable {
@ -96,14 +98,14 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideDefaultConfigurationSaves */ /** @dataProvider provideDefaultConfigurationSaves */
public function testSaveTheDefaultConfiguration(string $cmd, int $exitStatus, string $file): void { public function testSaveTheDefaultConfiguration(string $cmd, int $exitStatus, string $file): void {
$conf = \Phake::mock(Conf::class); $conf = $this->mock(Conf::class);
\Phake::when(Arsse::$obj)->get(Conf::class)->thenReturn($conf); $conf->exportFile->with("php://output", true)->returns(true);
\Phake::when($conf)->exportFile("php://output", true)->thenReturn(true); $conf->exportFile->with("good.conf", true)->returns(true);
\Phake::when($conf)->exportFile("good.conf", true)->thenReturn(true); $conf->exportFile->with("bad.conf", true)->throws(new \JKingWeb\Arsse\Conf\Exception("fileUnwritable"));
\Phake::when($conf)->exportFile("bad.conf", true)->thenThrow(new \JKingWeb\Arsse\Conf\Exception("fileUnwritable")); $this->objMock->get->with(Conf::class)->returns($conf->get());
$this->assertConsole($this->cli, $cmd, $exitStatus); $this->assertConsole($cmd, $exitStatus);
\Phake::verify($this->cli, \Phake::times(0))->loadConf; $this->cli->loadConf->never()->called();
\Phake::verify($conf)->exportFile($file, true); $conf->exportFile->calledWith($file, true);
} }
public function provideDefaultConfigurationSaves(): iterable { public function provideDefaultConfigurationSaves(): iterable {
@ -120,7 +122,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead // FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
Arsse::$user = $this->createMock(User::class); Arsse::$user = $this->createMock(User::class);
Arsse::$user->method("list")->willReturn($list); Arsse::$user->method("list")->willReturn($list);
$this->assertConsole($this->cli, $cmd, $exitStatus, $output); $this->assertConsole($cmd, $exitStatus, $output);
} }
public function provideUserList(): iterable { public function provideUserList(): iterable {
@ -146,7 +148,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
return is_null($pass) ? "random password" : $pass; return is_null($pass) ? "random password" : $pass;
} }
})); }));
$this->assertConsole($this->cli, $cmd, $exitStatus, $output); $this->assertConsole($cmd, $exitStatus, $output);
} }
public function provideUserAdditions(): iterable { public function provideUserAdditions(): iterable {
@ -163,7 +165,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
Arsse::$user->method("propertiesSet")->willReturn([]); Arsse::$user->method("propertiesSet")->willReturn([]);
Arsse::$user->expects($this->exactly(1))->method("add")->with("jane.doe@example.com", null); Arsse::$user->expects($this->exactly(1))->method("add")->with("jane.doe@example.com", null);
Arsse::$user->expects($this->exactly(1))->method("propertiesSet")->with("jane.doe@example.com", ['admin' => true]); Arsse::$user->expects($this->exactly(1))->method("propertiesSet")->with("jane.doe@example.com", ['admin' => true]);
$this->assertConsole($this->cli, "arsse.php user add jane.doe@example.com --admin", 0, "random password"); $this->assertConsole("arsse.php user add jane.doe@example.com --admin", 0, "random password");
} }
/** @dataProvider provideUserAuthentication */ /** @dataProvider provideUserAuthentication */
@ -176,12 +178,12 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
($user === "jane.doe@example.com" && $pass === "superman") ($user === "jane.doe@example.com" && $pass === "superman")
; ;
})); }));
$fever = \Phake::mock(FeverUser::class); $fever = $this->mock(FeverUser::class);
\Phake::when(Arsse::$obj)->get(FeverUser::class)->thenReturn($fever); $fever->authenticate->returns(false);
\Phake::when($fever)->authenticate->thenReturn(false); $fever->authenticate->with("john.doe@example.com", "ashalla")->returns(true);
\Phake::when($fever)->authenticate("john.doe@example.com", "ashalla")->thenReturn(true); $fever->authenticate->with("jane.doe@example.com", "thx1138")->returns(true);
\Phake::when($fever)->authenticate("jane.doe@example.com", "thx1138")->thenReturn(true); $this->objMock->get->with(FeverUser::class)->returns($fever->get());
$this->assertConsole($this->cli, $cmd, $exitStatus, $output); $this->assertConsole($cmd, $exitStatus, $output);
} }
public function provideUserAuthentication(): iterable { public function provideUserAuthentication(): iterable {
@ -210,7 +212,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
} }
throw new \JKingWeb\Arsse\User\ExceptionConflict("doesNotExist"); throw new \JKingWeb\Arsse\User\ExceptionConflict("doesNotExist");
})); }));
$this->assertConsole($this->cli, $cmd, $exitStatus, $output); $this->assertConsole($cmd, $exitStatus, $output);
} }
public function provideUserRemovals(): iterable { public function provideUserRemovals(): iterable {
@ -233,10 +235,10 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead // FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
Arsse::$user = $this->createMock(User::class); Arsse::$user = $this->createMock(User::class);
Arsse::$user->method("passwordSet")->will($this->returnCallback($passwordChange)); Arsse::$user->method("passwordSet")->will($this->returnCallback($passwordChange));
$fever = \Phake::mock(FeverUser::class); $fever = $this->mock(FeverUser::class);
\Phake::when(Arsse::$obj)->get(FeverUser::class)->thenReturn($fever); $fever->register->does($passwordChange);
\Phake::when($fever)->register->thenReturnCallback($passwordChange); $this->objMock->get->with(FeverUser::class)->returns($fever->get());
$this->assertConsole($this->cli, $cmd, $exitStatus, $output); $this->assertConsole($cmd, $exitStatus, $output);
} }
public function provideUserPasswordChanges(): iterable { public function provideUserPasswordChanges(): iterable {
@ -263,10 +265,10 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead // FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
Arsse::$user = $this->createMock(User::class); Arsse::$user = $this->createMock(User::class);
Arsse::$user->method("passwordUnset")->will($this->returnCallback($passwordClear)); Arsse::$user->method("passwordUnset")->will($this->returnCallback($passwordClear));
$fever = \Phake::mock(FeverUser::class); $fever = $this->mock(FeverUser::class);
\Phake::when(Arsse::$obj)->get(FeverUser::class)->thenReturn($fever); $fever->unregister->does($passwordClear);
\Phake::when($fever)->unregister->thenReturnCallback($passwordClear); $this->objMock->get->with(FeverUser::class)->returns($fever->get());
$this->assertConsole($this->cli, $cmd, $exitStatus, $output); $this->assertConsole($cmd, $exitStatus, $output);
} }
public function provideUserPasswordClearings(): iterable { public function provideUserPasswordClearings(): iterable {
@ -280,14 +282,14 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideOpmlExports */ /** @dataProvider provideOpmlExports */
public function testExportToOpml(string $cmd, int $exitStatus, string $file, string $user, bool $flat): void { public function testExportToOpml(string $cmd, int $exitStatus, string $file, string $user, bool $flat): void {
$opml = \Phake::mock(OPML::class); $opml = $this->mock(OPML::class);
\Phake::when(Arsse::$obj)->get(OPML::class)->thenReturn($opml); $opml->exportFile->with("php://output", $user, $flat)->returns(true);
\Phake::when($opml)->exportFile("php://output", $user, $flat)->thenReturn(true); $opml->exportFile->with("good.opml", $user, $flat)->returns(true);
\Phake::when($opml)->exportFile("good.opml", $user, $flat)->thenReturn(true); $opml->exportFile->with("bad.opml", $user, $flat)->throws(new \JKingWeb\Arsse\ImportExport\Exception("fileUnwritable"));
\Phake::when($opml)->exportFile("bad.opml", $user, $flat)->thenThrow(new \JKingWeb\Arsse\ImportExport\Exception("fileUnwritable")); $this->objMock->get->with(OPML::class)->returns($opml->get());
$this->assertConsole($this->cli, $cmd, $exitStatus); $this->assertConsole($cmd, $exitStatus);
\Phake::verify($this->cli)->loadConf; $this->cli->loadConf->called();
\Phake::verify($opml)->exportFile($file, $user, $flat); $opml->exportFile->calledWith($file, $user, $flat);
} }
public function provideOpmlExports(): iterable { public function provideOpmlExports(): iterable {
@ -321,14 +323,14 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideOpmlImports */ /** @dataProvider provideOpmlImports */
public function testImportFromOpml(string $cmd, int $exitStatus, string $file, string $user, bool $flat, bool $replace): void { public function testImportFromOpml(string $cmd, int $exitStatus, string $file, string $user, bool $flat, bool $replace): void {
$opml = \Phake::mock(OPML::class); $opml = $this->mock(OPML::class);
\Phake::when(Arsse::$obj)->get(OPML::class)->thenReturn($opml); $opml->importFile->with("php://input", $user, $flat, $replace)->returns(true);
\Phake::when($opml)->importFile("php://input", $user, $flat, $replace)->thenReturn(true); $opml->importFile->with("good.opml", $user, $flat, $replace)->returns(true);
\Phake::when($opml)->importFile("good.opml", $user, $flat, $replace)->thenReturn(true); $opml->importFile->with("bad.opml", $user, $flat, $replace)->throws(new \JKingWeb\Arsse\ImportExport\Exception("fileUnreadable"));
\Phake::when($opml)->importFile("bad.opml", $user, $flat, $replace)->thenThrow(new \JKingWeb\Arsse\ImportExport\Exception("fileUnreadable")); $this->objMock->get->with(OPML::class)->returns($opml->get());
$this->assertConsole($this->cli, $cmd, $exitStatus); $this->assertConsole($cmd, $exitStatus);
\Phake::verify($this->cli)->loadConf; $this->cli->loadConf->called();
\Phake::verify($opml)->importFile($file, $user, $flat, $replace); $opml->importFile->calledWith($file, $user, $flat, $replace);
} }
public function provideOpmlImports(): iterable { public function provideOpmlImports(): iterable {
@ -400,7 +402,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
Arsse::$user = $this->createMock(User::class); Arsse::$user = $this->createMock(User::class);
Arsse::$user->method("propertiesGet")->willReturn($data); Arsse::$user->method("propertiesGet")->willReturn($data);
Arsse::$user->expects($this->once())->method("propertiesGet")->with("john.doe@example.com", true); Arsse::$user->expects($this->once())->method("propertiesGet")->with("john.doe@example.com", true);
$this->assertConsole($this->cli, "arsse.php user show john.doe@example.com", 0, $exp); $this->assertConsole("arsse.php user show john.doe@example.com", 0, $exp);
} }
/** @dataProvider provideMetadataChanges */ /** @dataProvider provideMetadataChanges */
@ -408,7 +410,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
Arsse::$user = $this->createMock(User::class); Arsse::$user = $this->createMock(User::class);
Arsse::$user->method("propertiesSet")->willReturn($out); Arsse::$user->method("propertiesSet")->willReturn($out);
Arsse::$user->expects($this->once())->method("propertiesSet")->with($user, $in); Arsse::$user->expects($this->once())->method("propertiesSet")->with($user, $in);
$this->assertConsole($this->cli, $cmd, $exp, ""); $this->assertConsole($cmd, $exp, "");
} }
public function provideMetadataChanges(): iterable { public function provideMetadataChanges(): iterable {
@ -433,40 +435,38 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
"TOKEN 2 Eek", "TOKEN 2 Eek",
"TOKEN 1 Ook", "TOKEN 1 Ook",
]); ]);
$t = \Phake::mock(MinifluxToken::class); $t = $this->mock(MinifluxToken::class);
\Phake::when(Arsse::$obj)->get(MinifluxToken::class)->thenReturn($t); $t->tokenList->returns($data);
\Phake::when($t)->tokenList->thenReturn($data); $this->objMock->get->with(MinifluxToken::class)->returns($t->get());
$this->assertConsole($this->cli, "arsse.php token list john", 0, $exp); $this->assertConsole("arsse.php token list john", 0, $exp);
\Phake::verify($t)->tokenList("john"); $t->tokenList->calledWith("john");
} }
public function testCreateToken(): void { public function testCreateToken(): void {
$t = \Phake::mock(MinifluxToken::class); $t = $this->mock(MinifluxToken::class);
\Phake::when(Arsse::$obj)->get(MinifluxToken::class)->thenReturn($t); $t->tokenGenerate->returns("RANDOM TOKEN");
\Phake::when($t)->tokenGenerate->thenReturn("RANDOM TOKEN"); $this->objMock->get->with(MinifluxToken::class)->returns($t->get());
$this->assertConsole($this->cli, "arse.php token create jane", 0, "RANDOM TOKEN"); $this->assertConsole("arse.php token create jane", 0, "RANDOM TOKEN");
\Phake::verify($t)->tokenGenerate("jane", null); $t->tokenGenerate->calledWith("jane", null);
} }
public function testCreateTokenWithLabel(): void { public function testCreateTokenWithLabel(): void {
$t = \Phake::mock(MinifluxToken::class); $t = $this->mock(MinifluxToken::class);
\Phake::when(Arsse::$obj)->get(MinifluxToken::class)->thenReturn($t); $t->tokenGenerate->returns("RANDOM TOKEN");
\Phake::when($t)->tokenGenerate->thenReturn("RANDOM TOKEN"); $this->objMock->get->with(MinifluxToken::class)->returns($t->get());
$this->assertConsole($this->cli, "arse.php token create jane Ook", 0, "RANDOM TOKEN"); $this->assertConsole("arse.php token create jane Ook", 0, "RANDOM TOKEN");
\Phake::verify($t)->tokenGenerate("jane", "Ook"); $t->tokenGenerate->calledWith("jane", "Ook");
} }
public function testRevokeAToken(): void { public function testRevokeAToken(): void {
Arsse::$db = \Phake::mock(Database::class); $this->dbMock->tokenRevoke->returns(true);
\Phake::when(Arsse::$db)->tokenRevoke->thenReturn(true); $this->assertConsole("arse.php token revoke jane TOKEN_ID", 0);
$this->assertConsole($this->cli, "arse.php token revoke jane TOKEN_ID", 0); $this->dbMock->tokenRevoke->calledWith("jane", "miniflux.login", "TOKEN_ID");
\Phake::verify(Arsse::$db)->tokenRevoke("jane", "miniflux.login", "TOKEN_ID");
} }
public function testRevokeAllTokens(): void { public function testRevokeAllTokens(): void {
Arsse::$db = \Phake::mock(Database::class); $this->dbMock->tokenRevoke->returns(true);
\Phake::when(Arsse::$db)->tokenRevoke->thenReturn(true); $this->assertConsole("arse.php token revoke jane", 0);
$this->assertConsole($this->cli, "arse.php token revoke jane", 0); $this->dbMock->tokenRevoke->calledWith("jane", "miniflux.login", null);
\Phake::verify(Arsse::$db)->tokenRevoke("jane", "miniflux.login", null);
} }
} }

View file

@ -15,7 +15,7 @@ class TestConf extends \JKingWeb\Arsse\Test\AbstractTest {
public static $path; public static $path;
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::$vfs = vfsStream::setup("root", null, [ self::$vfs = vfsStream::setup("root", null, [
'confGood' => '<?php return Array("lang" => "xx");', 'confGood' => '<?php return Array("lang" => "xx");',
'confNotArray' => '<?php return 0;', 'confNotArray' => '<?php return 0;',
@ -35,7 +35,7 @@ class TestConf extends \JKingWeb\Arsse\Test\AbstractTest {
public function tearDown(): void { public function tearDown(): void {
self::$path = null; self::$path = null;
self::$vfs = null; self::$vfs = null;
self::clearData(); parent::tearDown();
} }
public function testLoadDefaultValues(): void { public function testLoadDefaultValues(): void {

View file

@ -73,7 +73,8 @@ abstract class AbstractTest extends \JKingWeb\Arsse\Test\AbstractTest {
Arsse::$db = new Database(static::$drv); Arsse::$db = new Database(static::$drv);
Arsse::$db->driverSchemaUpdate(); Arsse::$db->driverSchemaUpdate();
// create a mock user manager // create a mock user manager
Arsse::$user = \Phake::mock(User::class); $this->userMock = $this->mock(User::class);
Arsse::$user = $this->userMock->get();
// call the series-specific setup method // call the series-specific setup method
$setUp = "setUp".$this->series; $setUp = "setUp".$this->series;
$this->$setUp(); $this->$setUp();

View file

@ -192,8 +192,6 @@ trait SeriesSubscription {
], ],
], ],
]; ];
// initialize a partial mock of the Database object to later manipulate the feedUpdate method
Arsse::$db = \Phake::partialMock(Database::class, static::$drv);
$this->user = "john.doe@example.com"; $this->user = "john.doe@example.com";
} }
@ -204,9 +202,11 @@ trait SeriesSubscription {
public function testAddASubscriptionToAnExistingFeed(): void { public function testAddASubscriptionToAnExistingFeed(): void {
$url = "http://example.com/feed1"; $url = "http://example.com/feed1";
$subID = $this->nextID("arsse_subscriptions"); $subID = $this->nextID("arsse_subscriptions");
\Phake::when(Arsse::$db)->feedUpdate->thenReturn(true); $db = $this->partialMock(Database::class, static::$drv);
$db->feedUpdate->returns(true);
Arsse::$db = $db->get();
$this->assertSame($subID, Arsse::$db->subscriptionAdd($this->user, $url)); $this->assertSame($subID, Arsse::$db->subscriptionAdd($this->user, $url));
\Phake::verify(Arsse::$db, \Phake::times(0))->feedUpdate(1, true); $db->feedUpdate->never()->called();
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_feeds' => ['id','url','username','password'], 'arsse_feeds' => ['id','url','username','password'],
'arsse_subscriptions' => ['id','owner','feed'], 'arsse_subscriptions' => ['id','owner','feed'],
@ -219,9 +219,11 @@ trait SeriesSubscription {
$url = "http://example.org/feed1"; $url = "http://example.org/feed1";
$feedID = $this->nextID("arsse_feeds"); $feedID = $this->nextID("arsse_feeds");
$subID = $this->nextID("arsse_subscriptions"); $subID = $this->nextID("arsse_subscriptions");
\Phake::when(Arsse::$db)->feedUpdate->thenReturn(true); $db = $this->partialMock(Database::class, static::$drv);
$db->feedUpdate->returns(true);
Arsse::$db = $db->get();
$this->assertSame($subID, Arsse::$db->subscriptionAdd($this->user, $url, "", "", false)); $this->assertSame($subID, Arsse::$db->subscriptionAdd($this->user, $url, "", "", false));
\Phake::verify(Arsse::$db)->feedUpdate($feedID, true, false); $db->feedUpdate->calledWith($feedID, true, false);
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_feeds' => ['id','url','username','password'], 'arsse_feeds' => ['id','url','username','password'],
'arsse_subscriptions' => ['id','owner','feed'], 'arsse_subscriptions' => ['id','owner','feed'],
@ -236,9 +238,11 @@ trait SeriesSubscription {
$discovered = "http://localhost:8000/Feed/Discovery/Feed"; $discovered = "http://localhost:8000/Feed/Discovery/Feed";
$feedID = $this->nextID("arsse_feeds"); $feedID = $this->nextID("arsse_feeds");
$subID = $this->nextID("arsse_subscriptions"); $subID = $this->nextID("arsse_subscriptions");
\Phake::when(Arsse::$db)->feedUpdate->thenReturn(true); $db = $this->partialMock(Database::class, static::$drv);
$db->feedUpdate->returns(true);
Arsse::$db = $db->get();
$this->assertSame($subID, Arsse::$db->subscriptionAdd($this->user, $url, "", "", true)); $this->assertSame($subID, Arsse::$db->subscriptionAdd($this->user, $url, "", "", true));
\Phake::verify(Arsse::$db)->feedUpdate($feedID, true, false); $db->feedUpdate->calledWith($feedID, true, false);
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_feeds' => ['id','url','username','password'], 'arsse_feeds' => ['id','url','username','password'],
'arsse_subscriptions' => ['id','owner','feed'], 'arsse_subscriptions' => ['id','owner','feed'],
@ -251,12 +255,14 @@ trait SeriesSubscription {
public function testAddASubscriptionToAnInvalidFeed(): void { public function testAddASubscriptionToAnInvalidFeed(): void {
$url = "http://example.org/feed1"; $url = "http://example.org/feed1";
$feedID = $this->nextID("arsse_feeds"); $feedID = $this->nextID("arsse_feeds");
\Phake::when(Arsse::$db)->feedUpdate->thenThrow(new FeedException("", ['url' => $url], $this->mockGuzzleException(ClientException::class, "", 404))); $db = $this->partialMock(Database::class, static::$drv);
$db->feedUpdate->throws(new FeedException("", ['url' => $url], $this->mockGuzzleException(ClientException::class, "", 404)));
Arsse::$db = $db->get();
$this->assertException("invalidUrl", "Feed"); $this->assertException("invalidUrl", "Feed");
try { try {
Arsse::$db->subscriptionAdd($this->user, $url, "", "", false); Arsse::$db->subscriptionAdd($this->user, $url, "", "", false);
} finally { } finally {
\Phake::verify(Arsse::$db)->feedUpdate($feedID, true, false); $db->feedUpdate->calledWith($feedID, true, false);
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_feeds' => ['id','url','username','password'], 'arsse_feeds' => ['id','url','username','password'],
'arsse_subscriptions' => ['id','owner','feed'], 'arsse_subscriptions' => ['id','owner','feed'],

View file

@ -13,10 +13,10 @@ class TestDatabase extends \JKingWeb\Arsse\Test\AbstractTest {
protected $db = null; protected $db = null;
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
try { try {
$this->db = \Phake::makeVisible(\Phake::partialMock(Database::class)); $this->db = new Database;
} catch (\JKingWeb\Arsse\Db\Exception $e) { } catch (\JKingWeb\Arsse\Db\Exception $e) {
$this->markTestSkipped("SQLite 3 database driver not available"); $this->markTestSkipped("SQLite 3 database driver not available");
} }
@ -24,14 +24,20 @@ class TestDatabase extends \JKingWeb\Arsse\Test\AbstractTest {
public function tearDown(): void { public function tearDown(): void {
$this->db = null; $this->db = null;
self::clearData(); parent::tearDown();
}
protected function invoke(string $method, ...$arg) {
$m = new \ReflectionMethod($this->db, $method);
$m->setAccessible(true);
return $m->invoke($this->db, ...$arg);
} }
/** @dataProvider provideInClauses */ /** @dataProvider provideInClauses */
public function testGenerateInClause(string $clause, array $values, array $inV, string $inT): void { public function testGenerateInClause(string $clause, array $values, array $inV, string $inT): void {
$types = array_fill(0, sizeof($values), $inT); $types = array_fill(0, sizeof($values), $inT);
$exp = [$clause, $types, $values]; $exp = [$clause, $types, $values];
$this->assertSame($exp, $this->db->generateIn($inV, $inT)); $this->assertSame($exp, $this->invoke("generateIn", $inV, $inT));
} }
public function provideInClauses(): iterable { public function provideInClauses(): iterable {
@ -66,7 +72,7 @@ class TestDatabase extends \JKingWeb\Arsse\Test\AbstractTest {
// this is not an exhaustive test; integration tests already cover the ins and outs of the functionality // this is not an exhaustive test; integration tests already cover the ins and outs of the functionality
$types = array_fill(0, sizeof($values), "str"); $types = array_fill(0, sizeof($values), "str");
$exp = [$clause, $types, $values]; $exp = [$clause, $types, $values];
$this->assertSame($exp, $this->db->generateSearch($inV, $inC, $inAny)); $this->assertSame($exp, $this->invoke("generateSearch", $inV, $inC, $inAny));
} }
public function provideSearchClauses(): iterable { public function provideSearchClauses(): iterable {

View file

@ -31,7 +31,7 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest {
} }
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(static::$conf); self::setConf(static::$conf);
if (!static::$interface) { if (!static::$interface) {
$this->markTestSkipped(static::$implementation." database driver not available"); $this->markTestSkipped(static::$implementation." database driver not available");
@ -48,7 +48,7 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest {
public function tearDown(): void { public function tearDown(): void {
// deconstruct the driver // deconstruct the driver
unset($this->drv); unset($this->drv);
self::clearData(); parent::tearDown();
} }
public static function tearDownAfterClass(): void { public static function tearDownAfterClass(): void {
@ -57,7 +57,7 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest {
static::dbRaze(static::$interface); static::dbRaze(static::$interface);
} }
static::$interface = null; static::$interface = null;
self::clearData(); self::clearData(true);
} }
protected function exec($q): bool { protected function exec($q): bool {

View file

@ -25,7 +25,7 @@ abstract class BaseResult extends \JKingWeb\Arsse\Test\AbstractTest {
} }
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
if (!static::$interface) { if (!static::$interface) {
$this->markTestSkipped(static::$implementation." database driver not available"); $this->markTestSkipped(static::$implementation." database driver not available");
@ -35,17 +35,13 @@ abstract class BaseResult extends \JKingWeb\Arsse\Test\AbstractTest {
$this->resultClass = static::$dbResultClass; $this->resultClass = static::$dbResultClass;
} }
public function tearDown(): void {
self::clearData();
}
public static function tearDownAfterClass(): void { public static function tearDownAfterClass(): void {
if (static::$interface) { if (static::$interface) {
// completely clear the database // completely clear the database
static::dbRaze(static::$interface); static::dbRaze(static::$interface);
} }
static::$interface = null; static::$interface = null;
self::clearData(); self::clearData(true);
} }
public function testConstructResult(): void { public function testConstructResult(): void {

View file

@ -23,7 +23,7 @@ abstract class BaseStatement extends \JKingWeb\Arsse\Test\AbstractTest {
} }
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
if (!static::$interface) { if (!static::$interface) {
$this->markTestSkipped(static::$implementation." database driver not available"); $this->markTestSkipped(static::$implementation." database driver not available");
@ -33,17 +33,13 @@ abstract class BaseStatement extends \JKingWeb\Arsse\Test\AbstractTest {
$this->statementClass = static::$dbStatementClass; $this->statementClass = static::$dbStatementClass;
} }
public function tearDown(): void {
self::clearData();
}
public static function tearDownAfterClass(): void { public static function tearDownAfterClass(): void {
if (static::$interface) { if (static::$interface) {
// completely clear the database // completely clear the database
static::dbRaze(static::$interface); static::dbRaze(static::$interface);
} }
static::$interface = null; static::$interface = null;
self::clearData(); self::clearData(true);
} }
public function testConstructStatement(): void { public function testConstructStatement(): void {

View file

@ -29,7 +29,7 @@ class BaseUpdate extends \JKingWeb\Arsse\Test\AbstractTest {
if (!static::$interface) { if (!static::$interface) {
$this->markTestSkipped(static::$implementation." database driver not available"); $this->markTestSkipped(static::$implementation." database driver not available");
} }
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
// construct a fresh driver for each test // construct a fresh driver for each test
$this->drv = new static::$dbDriverClass; $this->drv = new static::$dbDriverClass;
@ -46,7 +46,7 @@ class BaseUpdate extends \JKingWeb\Arsse\Test\AbstractTest {
// deconstruct the driver // deconstruct the driver
unset($this->drv); unset($this->drv);
unset($this->path, $this->base, $this->vfs); unset($this->path, $this->base, $this->vfs);
self::clearData(); parent::tearDown();
} }
public static function tearDownAfterClass(): void { public static function tearDownAfterClass(): void {
@ -55,7 +55,7 @@ class BaseUpdate extends \JKingWeb\Arsse\Test\AbstractTest {
static::dbRaze(static::$interface); static::dbRaze(static::$interface);
} }
static::$interface = null; static::$interface = null;
self::clearData(); self::clearData(true);
} }
public function testLoadMissingFile(): void { public function testLoadMissingFile(): void {

View file

@ -22,7 +22,7 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest {
if (!Driver::requirementsMet()) { if (!Driver::requirementsMet()) {
$this->markTestSkipped("SQLite extension not loaded"); $this->markTestSkipped("SQLite extension not loaded");
} }
self::clearData(); parent::setUp();
// test files // test files
$this->files = [ $this->files = [
// cannot create files // cannot create files
@ -108,10 +108,6 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest {
self::setConf(); self::setConf();
} }
public function tearDown(): void {
self::clearData();
}
public function testFailToCreateDatabase(): void { public function testFailToCreateDatabase(): void {
Arsse::$conf->dbSQLite3File = $this->path."Cmain/arsse.db"; Arsse::$conf->dbSQLite3File = $this->path."Cmain/arsse.db";
$this->assertException("fileUncreatable", "Db"); $this->assertException("fileUncreatable", "Db");

View file

@ -24,7 +24,7 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest {
if (!Driver::requirementsMet()) { if (!Driver::requirementsMet()) {
$this->markTestSkipped("PDO-SQLite extension not loaded"); $this->markTestSkipped("PDO-SQLite extension not loaded");
} }
self::clearData(); parent::setUp();
// test files // test files
$this->files = [ $this->files = [
// cannot create files // cannot create files
@ -110,10 +110,6 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest {
self::setConf(); self::setConf();
} }
public function tearDown(): void {
self::clearData();
}
public function testFailToCreateDatabase(): void { public function testFailToCreateDatabase(): void {
Arsse::$conf->dbSQLite3File = $this->path."Cmain/arsse.db"; Arsse::$conf->dbSQLite3File = $this->path."Cmain/arsse.db";
$this->assertException("fileUncreatable", "Db"); $this->assertException("fileUncreatable", "Db");

View file

@ -15,47 +15,50 @@ class TestTransaction extends \JKingWeb\Arsse\Test\AbstractTest {
protected $drv; protected $drv;
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
$drv = \Phake::mock(\JKingWeb\Arsse\Db\SQLite3\Driver::class); $drv = $this->mock(\JKingWeb\Arsse\Db\SQLite3\Driver::class);
\Phake::when($drv)->savepointRelease->thenReturn(true); $drv->savepointRelease->returns(true);
\Phake::when($drv)->savepointUndo->thenReturn(true); $drv->savepointUndo->returns(true);
\Phake::when($drv)->savepointCreate->thenReturn(1)->thenReturn(2); $drv->savepointCreate->returns(1, 2);
$this->drv = $drv; $this->drv = $drv;
} }
public function testManipulateTransactions(): void { public function testManipulateTransactions(): void {
$tr1 = new Transaction($this->drv); $drv = $this->drv->get();
$tr2 = new Transaction($this->drv); $tr1 = new Transaction($drv);
\Phake::verify($this->drv, \Phake::times(2))->savepointCreate; $tr2 = new Transaction($drv);
$this->drv->savepointCreate->twice()->called();
$this->assertSame(1, $tr1->getIndex()); $this->assertSame(1, $tr1->getIndex());
$this->assertSame(2, $tr2->getIndex()); $this->assertSame(2, $tr2->getIndex());
unset($tr1); unset($tr1);
\Phake::verify($this->drv)->savepointUndo(1); $this->drv->savepointUndo->calledWith(1);
unset($tr2); unset($tr2);
\Phake::verify($this->drv)->savepointUndo(2); $this->drv->savepointUndo->calledWith(2);
} }
public function testCloseTransactions(): void { public function testCloseTransactions(): void {
$tr1 = new Transaction($this->drv); $drv = $this->drv->get();
$tr2 = new Transaction($this->drv); $tr1 = new Transaction($drv);
$tr2 = new Transaction($drv);
$this->assertTrue($tr1->isPending()); $this->assertTrue($tr1->isPending());
$this->assertTrue($tr2->isPending()); $this->assertTrue($tr2->isPending());
$tr1->commit(); $tr1->commit();
$this->assertFalse($tr1->isPending()); $this->assertFalse($tr1->isPending());
$this->assertTrue($tr2->isPending()); $this->assertTrue($tr2->isPending());
\Phake::verify($this->drv)->savepointRelease(1); $this->drv->savepointRelease->calledWith(1);
$tr2->rollback(); $tr2->rollback();
$this->assertFalse($tr1->isPending()); $this->assertFalse($tr1->isPending());
$this->assertFalse($tr2->isPending()); $this->assertFalse($tr2->isPending());
\Phake::verify($this->drv)->savepointUndo(2); $this->drv->savepointUndo->calledWith(2);
} }
public function testIgnoreRollbackErrors(): void { public function testIgnoreRollbackErrors(): void {
\Phake::when($this->drv)->savepointUndo->thenThrow(new Exception("savepointStale")); $this->drv->savepointUndo->throws(new Exception("savepointStale"));
$tr1 = new Transaction($this->drv); $drv = $this->drv->get();
$tr2 = new Transaction($this->drv); $tr1 = new Transaction($drv);
$tr2 = new Transaction($drv);
unset($tr1, $tr2); // no exception should bubble up unset($tr1, $tr2); // no exception should bubble up
\Phake::verify($this->drv)->savepointUndo(1); $this->drv->savepointUndo->calledWith(1);
\Phake::verify($this->drv)->savepointUndo(2); $this->drv->savepointUndo->calledWith(2);
} }
} }

View file

@ -16,16 +16,9 @@ class TestException extends \JKingWeb\Arsse\Test\AbstractTest {
public function setUp(): void { public function setUp(): void {
self::clearData(false); self::clearData(false);
// 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
Arsse::$lang = \Phake::mock(Lang::class); $this->langMock = $this->mock(Lang::class);
\Phake::when(Arsse::$lang)->msg->thenReturn(""); $this->langMock->msg->returns("");
} Arsse::$lang = $this->langMock->get();
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
self::clearData(true);
} }
public function testBaseClass(): void { public function testBaseClass(): void {

View file

@ -11,6 +11,7 @@ use JKingWeb\Arsse\Feed;
use JKingWeb\Arsse\Database; use JKingWeb\Arsse\Database;
use JKingWeb\Arsse\Misc\Date; use JKingWeb\Arsse\Misc\Date;
use JKingWeb\Arsse\Test\Result; use JKingWeb\Arsse\Test\Result;
use Eloquent\Phony\Phpunit\Phony;
/** /**
* @covers \JKingWeb\Arsse\Feed * @covers \JKingWeb\Arsse\Feed
@ -92,12 +93,15 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
$this->markTestSkipped("Test Web server is not accepting requests"); $this->markTestSkipped("Test Web server is not accepting requests");
} }
$this->base = self::$host."Feed/"; $this->base = self::$host."Feed/";
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
Arsse::$db = \Phake::mock(Database::class); $this->dbMock = $this->mock(Database::class);
\Phake::when(Arsse::$db)->feedMatchLatest->thenReturn(new Result([])); $this->dbMock->feedMatchLatest->with(Phony::wildcard())->returns(new Result([]));
\Phake::when(Arsse::$db)->feedMatchIds->thenReturn(new Result([])); $this->dbMock->feedMatchLatest->with(1, Phony::any())->returns(new Result($this->latest));
\Phake::when(Arsse::$db)->feedRulesGet->thenReturn([]); $this->dbMock->feedMatchIds->with(Phony::wildcard())->returns(new Result([]));
$this->dbMock->feedMatchIds->with(1, Phony::wildcard())->returns(new Result($this->others));
$this->dbMock->feedRulesGet->returns([]);
Arsse::$db = $this->dbMock->get();
} }
public function testParseAFeed(): void { public function testParseAFeed(): void {
@ -338,7 +342,10 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
} }
public function testMatchLatestArticles(): void { public function testMatchLatestArticles(): void {
\Phake::when(Arsse::$db)->feedMatchLatest(1, $this->anything())->thenReturn(new Result($this->latest)); $this->dbMock = $this->mock(Database::class);
$this->dbMock->feedMatchLatest->with(Phony::wildcard())->returns(new Result([]));
$this->dbMock->feedMatchLatest->with(1, Phony::any())->returns(new Result($this->latest));
Arsse::$db = $this->dbMock->get();
$f = new Feed(1, $this->base."Matching/1"); $f = new Feed(1, $this->base."Matching/1");
$this->assertCount(0, $f->newItems); $this->assertCount(0, $f->newItems);
$this->assertCount(0, $f->changedItems); $this->assertCount(0, $f->changedItems);
@ -354,8 +361,6 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
} }
public function testMatchHistoricalArticles(): void { public function testMatchHistoricalArticles(): void {
\Phake::when(Arsse::$db)->feedMatchLatest(1, $this->anything())->thenReturn(new Result($this->latest));
\Phake::when(Arsse::$db)->feedMatchIds(1, $this->anything(), $this->anything(), $this->anything(), $this->anything())->thenReturn(new Result($this->others));
$f = new Feed(1, $this->base."Matching/5"); $f = new Feed(1, $this->base."Matching/5");
$this->assertCount(0, $f->newItems); $this->assertCount(0, $f->newItems);
$this->assertCount(0, $f->changedItems); $this->assertCount(0, $f->changedItems);
@ -383,7 +388,11 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
} }
public function testApplyFilterRules(): void { public function testApplyFilterRules(): void {
\Phake::when(Arsse::$db)->feedMatchIds->thenReturn(new Result([ $exp = [
'jack' => ['new' => [false, true, true, false, true], 'changed' => [7 => true, 47 => true, 2112 => false, 1 => true, 42 => false]],
'sam' => ['new' => [false, true, false, false, false], 'changed' => [7 => false, 47 => true, 2112 => false, 1 => false, 42 => false]],
];
$this->dbMock->feedMatchIds->returns(new Result([
// these are the sixth through tenth entries in the feed; the title hashes have been omitted for brevity // these are the sixth through tenth entries in the feed; the title hashes have been omitted for brevity
['id' => 7, 'guid' => '0f2a218c311e3d8105f1b075142a5d26dabf056ffc61abe77e96c8f071bbf4a7', 'edited' => null, 'url_title_hash' => "", 'url_content_hash' => '', 'title_content_hash' => ''], ['id' => 7, 'guid' => '0f2a218c311e3d8105f1b075142a5d26dabf056ffc61abe77e96c8f071bbf4a7', 'edited' => null, 'url_title_hash' => "", 'url_content_hash' => '', 'title_content_hash' => ''],
['id' => 47, 'guid' => '1c19e3b9018bc246b7414ae919ddebc88d0c575129e8c4a57b84b826c00f6db5', 'edited' => null, 'url_title_hash' => "", 'url_content_hash' => '', 'title_content_hash' => ''], ['id' => 47, 'guid' => '1c19e3b9018bc246b7414ae919ddebc88d0c575129e8c4a57b84b826c00f6db5', 'edited' => null, 'url_title_hash' => "", 'url_content_hash' => '', 'title_content_hash' => ''],
@ -391,15 +400,12 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
['id' => 1, 'guid' => '436070cda5713a0d9a8fdc8652c7ab142f0550697acfd5206a16c18aee355039', 'edited' => null, 'url_title_hash' => "", 'url_content_hash' => '', 'title_content_hash' => ''], ['id' => 1, 'guid' => '436070cda5713a0d9a8fdc8652c7ab142f0550697acfd5206a16c18aee355039', 'edited' => null, 'url_title_hash' => "", 'url_content_hash' => '', 'title_content_hash' => ''],
['id' => 42, 'guid' => '1a731433a1904220ef26e731ada7262e1d5bcecae53e7b5df9e1f5713af6e5d3', 'edited' => null, 'url_title_hash' => "", 'url_content_hash' => '', 'title_content_hash' => ''], ['id' => 42, 'guid' => '1a731433a1904220ef26e731ada7262e1d5bcecae53e7b5df9e1f5713af6e5d3', 'edited' => null, 'url_title_hash' => "", 'url_content_hash' => '', 'title_content_hash' => ''],
])); ]));
\Phake::when(Arsse::$db)->feedRulesGet->thenReturn([ $this->dbMock->feedRulesGet->returns([
'jack' => ['keep' => "", 'block' => '`A|W|J|S`u'], 'jack' => ['keep' => "", 'block' => '`A|W|J|S`u'],
'sam' => ['keep' => "`B|T|X`u", 'block' => '`C`u'], 'sam' => ['keep' => "`B|T|X`u", 'block' => '`C`u'],
]); ]);
Arsse::$db = $this->dbMock->get();
$f = new Feed(5, $this->base."Filtering/1"); $f = new Feed(5, $this->base."Filtering/1");
$exp = [
'jack' => ['new' => [false, true, true, false, true], 'changed' => [7 => true, 47 => true, 2112 => false, 1 => true, 42 => false]],
'sam' => ['new' => [false, true, false, false, false], 'changed' => [7 => false, 47 => true, 2112 => false, 1 => false, 42 => false]],
];
$this->assertSame($exp, $f->filteredItems); $this->assertSame($exp, $f->filteredItems);
} }
} }

View file

@ -23,7 +23,7 @@ class TestFetching extends \JKingWeb\Arsse\Test\AbstractTest {
$this->markTestSkipped("Test Web server is not accepting requests"); $this->markTestSkipped("Test Web server is not accepting requests");
} }
$this->base = self::$host."Feed/"; $this->base = self::$host."Feed/";
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
} }

View file

@ -17,11 +17,11 @@ class TestFile extends \JKingWeb\Arsse\Test\AbstractTest {
protected $proc; protected $proc;
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
// create a mock Import/Export processor with stubbed underlying import/export routines // create a mock Import/Export processor with stubbed underlying import/export routines
$this->proc = \Phake::partialMock(AbstractImportExport::class); $this->proc = $this->partialMock(AbstractImportExport::class);
\Phake::when($this->proc)->export->thenReturn("EXPORT_FILE"); $this->proc->export->returns("EXPORT_FILE");
\Phake::when($this->proc)->import->thenReturn(true); $this->proc->import->returns(true);
$this->vfs = vfsStream::setup("root", null, [ $this->vfs = vfsStream::setup("root", null, [
'exportGoodFile' => "", 'exportGoodFile' => "",
'exportGoodDir' => [], 'exportGoodDir' => [],
@ -41,7 +41,7 @@ class TestFile extends \JKingWeb\Arsse\Test\AbstractTest {
$this->path = null; $this->path = null;
$this->vfs = null; $this->vfs = null;
$this->proc = null; $this->proc = null;
self::clearData(); parent::tearDown();
} }
/** @dataProvider provideFileExports */ /** @dataProvider provideFileExports */
@ -50,13 +50,13 @@ class TestFile extends \JKingWeb\Arsse\Test\AbstractTest {
try { try {
if ($exp instanceof \JKingWeb\Arsse\AbstractException) { if ($exp instanceof \JKingWeb\Arsse\AbstractException) {
$this->assertException($exp); $this->assertException($exp);
$this->proc->exportFile($path, $user, $flat); $this->proc->get()->exportFile($path, $user, $flat);
} else { } else {
$this->assertSame($exp, $this->proc->exportFile($path, $user, $flat)); $this->assertSame($exp, $this->proc->get()->exportFile($path, $user, $flat));
$this->assertSame("EXPORT_FILE", $this->vfs->getChild($file)->getContent()); $this->assertSame("EXPORT_FILE", $this->vfs->getChild($file)->getContent());
} }
} finally { } finally {
\Phake::verify($this->proc)->export($user, $flat); $this->proc->export->calledWith($user, $flat);
} }
} }
@ -89,12 +89,12 @@ class TestFile extends \JKingWeb\Arsse\Test\AbstractTest {
try { try {
if ($exp instanceof \JKingWeb\Arsse\AbstractException) { if ($exp instanceof \JKingWeb\Arsse\AbstractException) {
$this->assertException($exp); $this->assertException($exp);
$this->proc->importFile($path, $user, $flat, $replace); $this->proc->get()->importFile($path, $user, $flat, $replace);
} else { } else {
$this->assertSame($exp, $this->proc->importFile($path, $user, $flat, $replace)); $this->assertSame($exp, $this->proc->get()->importFile($path, $user, $flat, $replace));
} }
} finally { } finally {
\Phake::verify($this->proc, \Phake::times((int) ($exp === true)))->import($user, "GOOD_FILE", $flat, $replace); $this->proc->import->times((int) ($exp === true))->calledWith($user, "GOOD_FILE", $flat, $replace);
} }
} }

View file

@ -24,11 +24,11 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
]; ];
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
// create a mock user manager // create a mock user manager
Arsse::$user = \Phake::mock(\JKingWeb\Arsse\User::class); Arsse::$user = $this->mock(\JKingWeb\Arsse\User::class)->get();
// create a mock Import/Export processor // create a mock Import/Export processor
$this->proc = \Phake::partialMock(AbstractImportExport::class); $this->proc = $this->partialMock(AbstractImportExport::class);
// initialize an SQLite memeory database // initialize an SQLite memeory database
static::setConf(); static::setConf();
try { try {
@ -142,12 +142,12 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
public function tearDown(): void { public function tearDown(): void {
$this->drv = null; $this->drv = null;
$this->proc = null; $this->proc = null;
self::clearData(); parent::tearDown();
} }
public function testImportForAMissingUser(): void { public function testImportForAMissingUser(): void {
$this->assertException("doesNotExist", "User", "ExceptionConflict"); $this->assertException("doesNotExist", "User", "ExceptionConflict");
$this->proc->import("no.one@example.com", "", false, false); $this->proc->get()->import("no.one@example.com", "", false, false);
} }
public function testImportWithInvalidFolder(): void { public function testImportWithInvalidFolder(): void {
@ -155,9 +155,9 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
], [1 => ], [1 =>
['id' => 1, 'name' => "", 'parent' => 0], ['id' => 1, 'name' => "", 'parent' => 0],
]]; ]];
\Phake::when($this->proc)->parse->thenReturn($in); $this->proc->parse->returns($in);
$this->assertException("invalidFolderName", "ImportExport"); $this->assertException("invalidFolderName", "ImportExport");
$this->proc->import("john.doe@example.com", "", false, false); $this->proc->get()->import("john.doe@example.com", "", false, false);
} }
public function testImportWithDuplicateFolder(): void { public function testImportWithDuplicateFolder(): void {
@ -166,9 +166,9 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
['id' => 1, 'name' => "New", 'parent' => 0], ['id' => 1, 'name' => "New", 'parent' => 0],
['id' => 2, 'name' => "New", 'parent' => 0], ['id' => 2, 'name' => "New", 'parent' => 0],
]]; ]];
\Phake::when($this->proc)->parse->thenReturn($in); $this->proc->parse->returns($in);
$this->assertException("invalidFolderCopy", "ImportExport"); $this->assertException("invalidFolderCopy", "ImportExport");
$this->proc->import("john.doe@example.com", "", false, false); $this->proc->get()->import("john.doe@example.com", "", false, false);
} }
public function testMakeNoEffectiveChanges(): void { public function testMakeNoEffectiveChanges(): void {
@ -187,11 +187,11 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
['id' => 5, 'name' => "Local", 'parent' => 4], ['id' => 5, 'name' => "Local", 'parent' => 4],
['id' => 6, 'name' => "National", 'parent' => 4], ['id' => 6, 'name' => "National", 'parent' => 4],
]]; ]];
\Phake::when($this->proc)->parse->thenReturn($in); $this->proc->parse->returns($in);
$exp = $this->primeExpectations($this->data, $this->checkTables); $exp = $this->primeExpectations($this->data, $this->checkTables);
$this->proc->import("john.doe@example.com", "", false, false); $this->proc->get()->import("john.doe@example.com", "", false, false);
$this->compareExpectations($this->drv, $exp); $this->compareExpectations($this->drv, $exp);
$this->proc->import("john.doe@example.com", "", false, true); $this->proc->get()->import("john.doe@example.com", "", false, true);
$this->compareExpectations($this->drv, $exp); $this->compareExpectations($this->drv, $exp);
} }
@ -212,8 +212,8 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
['id' => 6, 'name' => "National", 'parent' => 4], ['id' => 6, 'name' => "National", 'parent' => 4],
['id' => 7, 'name' => "Nature", 'parent' => 0], // new folder ['id' => 7, 'name' => "Nature", 'parent' => 0], // new folder
]]; ]];
\Phake::when($this->proc)->parse->thenReturn($in); $this->proc->parse->returns($in);
$this->proc->import("john.doe@example.com", "", false, true); $this->proc->get()->import("john.doe@example.com", "", false, true);
$exp = $this->primeExpectations($this->data, $this->checkTables); $exp = $this->primeExpectations($this->data, $this->checkTables);
$exp['arsse_subscriptions']['rows'][3] = [4, "john.doe@example.com", null, 4, "CBC"]; $exp['arsse_subscriptions']['rows'][3] = [4, "john.doe@example.com", null, 4, "CBC"];
$exp['arsse_folders']['rows'][] = [7, "john.doe@example.com", null, "Nature"]; $exp['arsse_folders']['rows'][] = [7, "john.doe@example.com", null, "Nature"];
@ -224,8 +224,8 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
$in = [[ $in = [[
['url' => "http://localhost:8000/Import/some-feed", 'title' => "Some Feed", 'folder' => 0, 'tags' => ["frequent", "cryptic"]], //one existing tag and one new one ['url' => "http://localhost:8000/Import/some-feed", 'title' => "Some Feed", 'folder' => 0, 'tags' => ["frequent", "cryptic"]], //one existing tag and one new one
], []]; ], []];
\Phake::when($this->proc)->parse->thenReturn($in); $this->proc->parse->returns($in);
$this->proc->import("john.doe@example.com", "", false, false); $this->proc->get()->import("john.doe@example.com", "", false, false);
$exp = $this->primeExpectations($this->data, $this->checkTables); $exp = $this->primeExpectations($this->data, $this->checkTables);
$exp['arsse_feeds']['rows'][] = [7, "http://localhost:8000/Import/some-feed", "Some feed"]; // author-supplied and user-supplied titles differ $exp['arsse_feeds']['rows'][] = [7, "http://localhost:8000/Import/some-feed", "Some feed"]; // author-supplied and user-supplied titles differ
$exp['arsse_subscriptions']['rows'][] = [7, "john.doe@example.com", null, 7, "Some Feed"]; $exp['arsse_subscriptions']['rows'][] = [7, "john.doe@example.com", null, 7, "Some Feed"];
@ -239,9 +239,9 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
$in = [[ $in = [[
['url' => "http://localhost:8000/Import/some-feed", 'title' => "Some Feed", 'folder' => 0, 'tags' => [""]], ['url' => "http://localhost:8000/Import/some-feed", 'title' => "Some Feed", 'folder' => 0, 'tags' => [""]],
], []]; ], []];
\Phake::when($this->proc)->parse->thenReturn($in); $this->proc->parse->returns($in);
$this->assertException("invalidTagName", "ImportExport"); $this->assertException("invalidTagName", "ImportExport");
$this->proc->import("john.doe@example.com", "", false, false); $this->proc->get()->import("john.doe@example.com", "", false, false);
} }
public function testReplaceData(): void { public function testReplaceData(): void {
@ -250,8 +250,8 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
], [1 => ], [1 =>
['id' => 1, 'name' => "Photography", 'parent' => 0], ['id' => 1, 'name' => "Photography", 'parent' => 0],
]]; ]];
\Phake::when($this->proc)->parse->thenReturn($in); $this->proc->parse->returns($in);
$this->proc->import("john.doe@example.com", "", false, true); $this->proc->get()->import("john.doe@example.com", "", false, true);
$exp = $this->primeExpectations($this->data, $this->checkTables); $exp = $this->primeExpectations($this->data, $this->checkTables);
$exp['arsse_feeds']['rows'][] = [7, "http://localhost:8000/Import/some-feed", "Some feed"]; // author-supplied and user-supplied titles differ $exp['arsse_feeds']['rows'][] = [7, "http://localhost:8000/Import/some-feed", "Some feed"]; // author-supplied and user-supplied titles differ
$exp['arsse_subscriptions']['rows'] = [[7, "john.doe@example.com", 4, 7, "Some Feed"]]; $exp['arsse_subscriptions']['rows'] = [[7, "john.doe@example.com", 4, 7, "Some Feed"]];

View file

@ -7,9 +7,11 @@ declare(strict_types=1);
namespace JKingWeb\Arsse\TestCase\ImportExport; namespace JKingWeb\Arsse\TestCase\ImportExport;
use JKingWeb\Arsse\Arsse; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Database;
use JKingWeb\Arsse\Test\Result; use JKingWeb\Arsse\Test\Result;
use JKingWeb\Arsse\ImportExport\OPML; use JKingWeb\Arsse\ImportExport\OPML;
use JKingWeb\Arsse\ImportExport\Exception; use JKingWeb\Arsse\ImportExport\Exception;
use ReflectionMethod;
/** @covers \JKingWeb\Arsse\ImportExport\OPML<extended> */ /** @covers \JKingWeb\Arsse\ImportExport\OPML<extended> */
class TestOPML extends \JKingWeb\Arsse\Test\AbstractTest { class TestOPML extends \JKingWeb\Arsse\Test\AbstractTest {
@ -80,27 +82,25 @@ OPML_EXPORT_SERIALIZATION;
OPML_EXPORT_SERIALIZATION; OPML_EXPORT_SERIALIZATION;
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
Arsse::$db = \Phake::mock(\JKingWeb\Arsse\Database::class); $this->dbMock = $this->mock(Database::class);
\Phake::when(Arsse::$db)->userExists->thenReturn(true); $this->dbMock->userExists->returns(true);
$this->dbMock->folderList->with("john.doe@example.com")->returns(new Result($this->folders));
$this->dbMock->subscriptionList->with("john.doe@example.com")->returns(new Result($this->subscriptions));
$this->dbMock->tagSummarize->with("john.doe@example.com")->returns(new Result($this->tags));
Arsse::$db = $this->dbMock->get();
} }
public function testExportToOpml(): void { public function testExportToOpml(): void {
\Phake::when(Arsse::$db)->folderList("john.doe@example.com")->thenReturn(new Result($this->folders));
\Phake::when(Arsse::$db)->subscriptionList("john.doe@example.com")->thenReturn(new Result($this->subscriptions));
\Phake::when(Arsse::$db)->tagSummarize("john.doe@example.com")->thenReturn(new Result($this->tags));
$this->assertXmlStringEqualsXmlString($this->serialization, (new OPML)->export("john.doe@example.com")); $this->assertXmlStringEqualsXmlString($this->serialization, (new OPML)->export("john.doe@example.com"));
} }
public function testExportToFlatOpml(): void { public function testExportToFlatOpml(): void {
\Phake::when(Arsse::$db)->folderList("john.doe@example.com")->thenReturn(new Result($this->folders));
\Phake::when(Arsse::$db)->subscriptionList("john.doe@example.com")->thenReturn(new Result($this->subscriptions));
\Phake::when(Arsse::$db)->tagSummarize("john.doe@example.com")->thenReturn(new Result($this->tags));
$this->assertXmlStringEqualsXmlString($this->serializationFlat, (new OPML)->export("john.doe@example.com", true)); $this->assertXmlStringEqualsXmlString($this->serializationFlat, (new OPML)->export("john.doe@example.com", true));
} }
public function testExportToOpmlAMissingUser(): void { public function testExportToOpmlAMissingUser(): void {
\Phake::when(Arsse::$db)->userExists->thenReturn(false); $this->dbMock->userExists->returns(false);
$this->assertException("doesNotExist", "User", "ExceptionConflict"); $this->assertException("doesNotExist", "User", "ExceptionConflict");
(new OPML)->export("john.doe@example.com"); (new OPML)->export("john.doe@example.com");
} }
@ -108,13 +108,15 @@ OPML_EXPORT_SERIALIZATION;
/** @dataProvider provideParserData */ /** @dataProvider provideParserData */
public function testParseOpmlForImport(string $file, bool $flat, $exp): void { public function testParseOpmlForImport(string $file, bool $flat, $exp): void {
$data = file_get_contents(\JKingWeb\Arsse\DOCROOT."Import/OPML/$file"); $data = file_get_contents(\JKingWeb\Arsse\DOCROOT."Import/OPML/$file");
// set up a partial mock to make the ImportExport::parse() method visible // make the ImportExport::parse() method visible
$parser = \Phake::makeVisible(\Phake::partialMock(OPML::class)); $parser = new OPML;
if ($exp instanceof \JKingWeb\Arsse\AbstractException) { $parseFunc = new \ReflectionMethod($parser, "parse");
$parseFunc->setAccessible(true);
if ($exp instanceof \Exception) {
$this->assertException($exp); $this->assertException($exp);
$parser->parse($data, $flat); $parseFunc->invoke($parser, $data, $flat);
} else { } else {
$this->assertSame($exp, $parser->parse($data, $flat)); $this->assertSame($exp, $parseFunc->invoke($parser, $data, $flat));
} }
} }

View file

@ -10,10 +10,6 @@ use JKingWeb\Arsse\Misc\Date;
/** @covers \JKingWeb\Arsse\Misc\Date */ /** @covers \JKingWeb\Arsse\Misc\Date */
class TestDate extends \JKingWeb\Arsse\Test\AbstractTest { class TestDate extends \JKingWeb\Arsse\Test\AbstractTest {
public function setUp(): void {
self::clearData();
}
public function testNormalizeADate(): void { public function testNormalizeADate(): void {
$exp = new \DateTimeImmutable("2018-01-01T00:00:00Z"); $exp = new \DateTimeImmutable("2018-01-01T00:00:00Z");
$this->assertEquals($exp, Date::normalize(1514764800)); $this->assertEquals($exp, Date::normalize(1514764800));

View file

@ -10,9 +10,6 @@ use JKingWeb\Arsse\Misc\URL;
/** @covers \JKingWeb\Arsse\Misc\URL */ /** @covers \JKingWeb\Arsse\Misc\URL */
class TestURL extends \JKingWeb\Arsse\Test\AbstractTest { class TestURL extends \JKingWeb\Arsse\Test\AbstractTest {
public function setUp(): void {
self::clearData();
}
/** @dataProvider provideNormalizations */ /** @dataProvider provideNormalizations */
public function testNormalizeAUrl(string $url, string $exp, string $user = null, string $pass = null): void { public function testNormalizeAUrl(string $url, string $exp, string $user = null, string $pass = null): void {

View file

@ -12,9 +12,6 @@ use JKingWeb\Arsse\Test\Result;
/** @covers \JKingWeb\Arsse\Misc\ValueInfo */ /** @covers \JKingWeb\Arsse\Misc\ValueInfo */
class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest { class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
public function setUp(): void {
self::clearData();
}
public function testGetIntegerInfo(): void { public function testGetIntegerInfo(): void {
$tests = [ $tests = [

View file

@ -24,7 +24,8 @@ use Laminas\Diactoros\Response\EmptyResponse;
class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
/** @var \JKingWeb\Arsse\REST\Fever\API */ /** @var \JKingWeb\Arsse\REST\Fever\API */
protected $h; protected $h;
protected $hMock;
protected $userId = "john.doe@example.com";
protected $articles = [ protected $articles = [
'db' => [ 'db' => [
[ [
@ -141,35 +142,35 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
], ],
], ],
]; ];
protected function v($value) { protected function v($value) {
return $value; return $value;
} }
protected function req($dataGet, $dataPost = "", string $method = "POST", string $type = null, string $target = "", string $user = null): ServerRequest { protected function req($dataGet, $dataPost = "", string $method = "POST", ?string $type = null, string $target = "", ?string $user = null): ResponseInterface {
Arsse::$db = $this->dbMock->get();
$this->h = $this->hMock->get();
$prefix = "/fever/"; $prefix = "/fever/";
$url = $prefix.$target; $url = $prefix.$target;
$type = $type ?? "application/x-www-form-urlencoded"; $type = $type ?? "application/x-www-form-urlencoded";
return $this->serverRequest($method, $url, $prefix, [], [], $dataPost, $type, $dataGet, $user); return $this->h->dispatch($this->serverRequest($method, $url, $prefix, [], [], $dataPost, $type, $dataGet, $user));
} }
public function setUp(): void { public function setUp(): void {
self::clearData(); self::clearData();
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);
Arsse::$user->id = "john.doe@example.com"; Arsse::$user = $this->userMock->get();
Arsse::$user->id = $this->userId;
// 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));
\Phake::when(Arsse::$db)->tokenLookup->thenReturn(['user' => "john.doe@example.com"]); $this->dbMock->tokenLookup->returns(['user' => "john.doe@example.com"]);
// instantiate the handler as a partial mock to simplify testing // instantiate the handler as a partial mock to simplify testing
$this->h = \Phake::partialMock(API::class); $this->hMock = $this->partialMock(API::class);
\Phake::when($this->h)->baseResponse->thenReturn([]); $this->hMock->baseResponse->returns([]);
}
public function tearDown(): void {
self::clearData();
} }
/** @dataProvider provideTokenAuthenticationRequests */ /** @dataProvider provideTokenAuthenticationRequests */
@ -179,17 +180,16 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
'userSessionEnforced' => $tokenEnforced, 'userSessionEnforced' => $tokenEnforced,
], true); ], true);
Arsse::$user->id = null; Arsse::$user->id = null;
\Phake::when(Arsse::$db)->tokenLookup->thenThrow(new ExceptionInput("subjectMissing")); $this->dbMock->tokenLookup->throws(new ExceptionInput("subjectMissing"));
\Phake::when(Arsse::$db)->tokenLookup("fever.login", "validtoken")->thenReturn(['user' => "jane.doe@example.com"]); $this->dbMock->tokenLookup->with("fever.login", "validtoken")->returns(['user' => "jane.doe@example.com"]);
// test only the authentication process // test only the authentication process
\Phake::when($this->h)->baseResponse->thenReturnCallback(function(bool $authenticated) { $this->hMock->baseResponse->does(function(bool $authenticated) {
return ['auth' => (int) $authenticated]; return ['auth' => (int) $authenticated];
}); });
\Phake::when($this->h)->processRequest->thenReturnCallback(function($out, $G, $P) { $this->hMock->processRequest->does(function($out, $G, $P) {
return $out; return $out;
}); });
$act = $this->h->dispatch($this->req($dataGet, $dataPost, "POST", null, "", $httpUser)); $this->assertMessage($exp, $this->req($dataGet, $dataPost, "POST", null, "", $httpUser));
$this->assertMessage($exp, $act);
} }
public function provideTokenAuthenticationRequests(): iterable { public function provideTokenAuthenticationRequests(): iterable {
@ -245,12 +245,12 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
} }
public function testListGroups(): void { public function testListGroups(): void {
\Phake::when(Arsse::$db)->tagList(Arsse::$user->id)->thenReturn(new Result([ $this->dbMock->tagList->with($this->userId)->returns(new Result([
['id' => 1, 'name' => "Fascinating", 'subscriptions' => 2], ['id' => 1, 'name' => "Fascinating", 'subscriptions' => 2],
['id' => 2, 'name' => "Interesting", 'subscriptions' => 2], ['id' => 2, 'name' => "Interesting", 'subscriptions' => 2],
['id' => 3, 'name' => "Boring", 'subscriptions' => 0], ['id' => 3, 'name' => "Boring", 'subscriptions' => 0],
])); ]));
\Phake::when(Arsse::$db)->tagSummarize(Arsse::$user->id)->thenReturn(new Result([ $this->dbMock->tagSummarize->with($this->userId)->returns(new Result([
['id' => 1, 'name' => "Fascinating", 'subscription' => 1], ['id' => 1, 'name' => "Fascinating", 'subscription' => 1],
['id' => 1, 'name' => "Fascinating", 'subscription' => 2], ['id' => 1, 'name' => "Fascinating", 'subscription' => 2],
['id' => 2, 'name' => "Interesting", 'subscription' => 1], ['id' => 2, 'name' => "Interesting", 'subscription' => 1],
@ -267,17 +267,16 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
['group_id' => 2, 'feed_ids' => "1,3"], ['group_id' => 2, 'feed_ids' => "1,3"],
], ],
]); ]);
$act = $this->h->dispatch($this->req("api&groups")); $this->assertMessage($exp, $this->req("api&groups"));
$this->assertMessage($exp, $act);
} }
public function testListFeeds(): void { public function testListFeeds(): void {
\Phake::when(Arsse::$db)->subscriptionList(Arsse::$user->id)->thenReturn(new Result([ $this->dbMock->subscriptionList->with($this->userId)->returns(new Result([
['id' => 1, 'feed' => 5, 'title' => "Ankh-Morpork News", 'url' => "http://example.com/feed", 'source' => "http://example.com/", 'edited' => "2019-01-01 21:12:00", 'icon_url' => "http://example.com/favicon.ico", 'icon_id' => 42], ['id' => 1, 'feed' => 5, 'title' => "Ankh-Morpork News", 'url' => "http://example.com/feed", 'source' => "http://example.com/", 'edited' => "2019-01-01 21:12:00", 'icon_url' => "http://example.com/favicon.ico", 'icon_id' => 42],
['id' => 2, 'feed' => 9, 'title' => "Ook, Ook Eek Ook!", 'url' => "http://example.net/feed", 'source' => "http://example.net/", 'edited' => "1988-06-24 12:21:00", 'icon_url' => "", 'icon_id' => null], ['id' => 2, 'feed' => 9, 'title' => "Ook, Ook Eek Ook!", 'url' => "http://example.net/feed", 'source' => "http://example.net/", 'edited' => "1988-06-24 12:21:00", 'icon_url' => "", 'icon_id' => null],
['id' => 3, 'feed' => 1, 'title' => "The Last Soul", 'url' => "http://example.org/feed", 'source' => "http://example.org/", 'edited' => "1991-08-12 03:22:00", 'icon_url' => "http://example.org/favicon.ico", 'icon_id' => 42], ['id' => 3, 'feed' => 1, 'title' => "The Last Soul", 'url' => "http://example.org/feed", 'source' => "http://example.org/", 'edited' => "1991-08-12 03:22:00", 'icon_url' => "http://example.org/favicon.ico", 'icon_id' => 42],
])); ]));
\Phake::when(Arsse::$db)->tagSummarize(Arsse::$user->id)->thenReturn(new Result([ $this->dbMock->tagSummarize->with($this->userId)->returns(new Result([
['id' => 1, 'name' => "Fascinating", 'subscription' => 1], ['id' => 1, 'name' => "Fascinating", 'subscription' => 1],
['id' => 1, 'name' => "Fascinating", 'subscription' => 2], ['id' => 1, 'name' => "Fascinating", 'subscription' => 2],
['id' => 2, 'name' => "Interesting", 'subscription' => 1], ['id' => 2, 'name' => "Interesting", 'subscription' => 1],
@ -294,23 +293,21 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
['group_id' => 2, 'feed_ids' => "1,3"], ['group_id' => 2, 'feed_ids' => "1,3"],
], ],
]); ]);
$act = $this->h->dispatch($this->req("api&feeds")); $this->assertMessage($exp, $this->req("api&feeds"));
$this->assertMessage($exp, $act);
} }
/** @dataProvider provideItemListContexts */ /** @dataProvider provideItemListContexts */
public function testListItems(string $url, Context $c, bool $desc): void { public function testListItems(string $url, Context $c, bool $desc): void {
$fields = ["id", "subscription", "title", "author", "content", "url", "starred", "unread", "published_date"]; $fields = ["id", "subscription", "title", "author", "content", "url", "starred", "unread", "published_date"];
$order = [$desc ? "id desc" : "id"]; $order = [$desc ? "id desc" : "id"];
\Phake::when(Arsse::$db)->articleList->thenReturn(new Result($this->articles['db'])); $this->dbMock->articleList->returns(new Result($this->articles['db']));
\Phake::when(Arsse::$db)->articleCount(Arsse::$user->id, (new Context)->hidden(false))->thenReturn(1024); $this->dbMock->articleCount->with($this->userId, (new Context)->hidden(false))->returns(1024);
$exp = new JsonResponse([ $exp = new JsonResponse([
'items' => $this->articles['rest'], 'items' => $this->articles['rest'],
'total_items' => 1024, 'total_items' => 1024,
]); ]);
$act = $this->h->dispatch($this->req("api&$url")); $this->assertMessage($exp, $this->req("api&$url"));
$this->assertMessage($exp, $act); $this->dbMock->articleList->calledWith($this->userId, $this->equalTo($c), $fields, $order);
\Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, $c, $fields, $order);
} }
public function provideItemListContexts(): iterable { public function provideItemListContexts(): iterable {
@ -332,35 +329,34 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
public function testListItemIds(): void { public function testListItemIds(): void {
$saved = [['id' => 1],['id' => 2],['id' => 3]]; $saved = [['id' => 1],['id' => 2],['id' => 3]];
$unread = [['id' => 4],['id' => 5],['id' => 6]]; $unread = [['id' => 4],['id' => 5],['id' => 6]];
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->starred(true)->hidden(false))->thenReturn(new Result($saved)); $this->dbMock->articleList->with($this->userId, (new Context)->starred(true)->hidden(false))->returns(new Result($saved));
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->unread(true)->hidden(false))->thenReturn(new Result($unread)); $this->dbMock->articleList->with($this->userId, (new Context)->unread(true)->hidden(false))->returns(new Result($unread));
$exp = new JsonResponse(['saved_item_ids' => "1,2,3"]); $exp = new JsonResponse(['saved_item_ids' => "1,2,3"]);
$this->assertMessage($exp, $this->h->dispatch($this->req("api&saved_item_ids"))); $this->assertMessage($exp, $this->req("api&saved_item_ids"));
$exp = new JsonResponse(['unread_item_ids' => "4,5,6"]); $exp = new JsonResponse(['unread_item_ids' => "4,5,6"]);
$this->assertMessage($exp, $this->h->dispatch($this->req("api&unread_item_ids"))); $this->assertMessage($exp, $this->req("api&unread_item_ids"));
} }
public function testListHotLinks(): void { public function testListHotLinks(): void {
// hot links are not actually implemented, so an empty array should be all we get // hot links are not actually implemented, so an empty array should be all we get
$exp = new JsonResponse(['links' => []]); $exp = new JsonResponse(['links' => []]);
$this->assertMessage($exp, $this->h->dispatch($this->req("api&links"))); $this->assertMessage($exp, $this->req("api&links"));
} }
/** @dataProvider provideMarkingContexts */ /** @dataProvider provideMarkingContexts */
public function testSetMarks(string $post, Context $c, array $data, array $out): void { public function testSetMarks(string $post, Context $c, array $data, array $out): void {
$saved = [['id' => 1],['id' => 2],['id' => 3]]; $saved = [['id' => 1],['id' => 2],['id' => 3]];
$unread = [['id' => 4],['id' => 5],['id' => 6]]; $unread = [['id' => 4],['id' => 5],['id' => 6]];
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->starred(true)->hidden(false))->thenReturn(new Result($saved)); $this->dbMock->articleList->with($this->userId, (new Context)->starred(true)->hidden(false))->returns(new Result($saved));
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->unread(true)->hidden(false))->thenReturn(new Result($unread)); $this->dbMock->articleList->with($this->userId, (new Context)->unread(true)->hidden(false))->returns(new Result($unread));
\Phake::when(Arsse::$db)->articleMark->thenReturn(0); $this->dbMock->articleMark->returns(0);
\Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), (new Context)->article(2112))->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("subjectMissing")); $this->dbMock->articleMark->with($this->userId, $this->anything(), (new Context)->article(2112))->throws(new \JKingWeb\Arsse\Db\ExceptionInput("subjectMissing"));
$exp = new JsonResponse($out); $exp = new JsonResponse($out);
$act = $this->h->dispatch($this->req("api", $post)); $this->assertMessage($exp, $this->req("api", $post));
$this->assertMessage($exp, $act);
if ($c && $data) { if ($c && $data) {
\Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $data, $c); $this->dbMock->articleMark->calledWith($this->userId, $data, $this->equalTo($c));
} else { } else {
\Phake::verify(Arsse::$db, \Phake::times(0))->articleMark; $this->dbMock->articleMark->never()->called();
} }
} }
@ -368,17 +364,16 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
public function testSetMarksWithQuery(string $get, Context $c, array $data, array $out): void { public function testSetMarksWithQuery(string $get, Context $c, array $data, array $out): void {
$saved = [['id' => 1],['id' => 2],['id' => 3]]; $saved = [['id' => 1],['id' => 2],['id' => 3]];
$unread = [['id' => 4],['id' => 5],['id' => 6]]; $unread = [['id' => 4],['id' => 5],['id' => 6]];
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->starred(true)->hidden(false))->thenReturn(new Result($saved)); $this->dbMock->articleList->with($this->userId, (new Context)->starred(true)->hidden(false))->returns(new Result($saved));
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->unread(true)->hidden(false))->thenReturn(new Result($unread)); $this->dbMock->articleList->with($this->userId, (new Context)->unread(true)->hidden(false))->returns(new Result($unread));
\Phake::when(Arsse::$db)->articleMark->thenReturn(0); $this->dbMock->articleMark->returns(0);
\Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), (new Context)->article(2112))->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("subjectMissing")); $this->dbMock->articleMark->with($this->userId, $this->anything(), (new Context)->article(2112))->throws(new \JKingWeb\Arsse\Db\ExceptionInput("subjectMissing"));
$exp = new JsonResponse($out); $exp = new JsonResponse($out);
$act = $this->h->dispatch($this->req("api&$get")); $this->assertMessage($exp, $this->req("api&$get"));
$this->assertMessage($exp, $act);
if ($c && $data) { if ($c && $data) {
\Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $data, $c); $this->dbMock->articleMark->calledWith($this->userId, $data, $this->equalTo($c));
} else { } else {
\Phake::verify(Arsse::$db, \Phake::times(0))->articleMark; $this->dbMock->articleMark->never()->called();
} }
} }
@ -421,97 +416,89 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
} }
/** @dataProvider provideInvalidRequests */ /** @dataProvider provideInvalidRequests */
public function testSendInvalidRequests(ServerRequest $req, ResponseInterface $exp): void { public function testSendInvalidRequests(string $get, string $post, string $method, ?string $type, ResponseInterface $exp): void {
$this->assertMessage($exp, $this->h->dispatch($req)); $this->assertMessage($exp, $this->req($get, $post, $method, $type));
} }
public function provideInvalidRequests(): iterable { public function provideInvalidRequests(): iterable {
return [ return [
'Not an API request' => [$this->req(""), new EmptyResponse(404)], 'Not an API request' => ["", "", "POST", null, new EmptyResponse(404)],
'Wrong method' => [$this->req("api", "", "PUT"), new EmptyResponse(405, ['Allow' => "OPTIONS,POST"])], 'Wrong method' => ["api", "", "PUT", null, new EmptyResponse(405, ['Allow' => "OPTIONS,POST"])],
'Non-standard method' => [$this->req("api", "", "GET"), new JsonResponse([])], 'Non-standard method' => ["api", "", "GET", null, new JsonResponse([])],
'Wrong content type' => [$this->req("api", '{"api_key":"validToken"}', "POST", "application/json"), new EmptyResponse(415, ['Accept' => "application/x-www-form-urlencoded, multipart/form-data"])], 'Wrong content type' => ["api", '{"api_key":"validToken"}', "POST", "application/json", new EmptyResponse(415, ['Accept' => "application/x-www-form-urlencoded, multipart/form-data"])],
'Non-standard content type' => [$this->req("api", '{"api_key":"validToken"}', "POST", "multipart/form-data; boundary=33b68964f0de4c1f-5144aa6caaa6e4a8-18bfaf416a1786c8-5c5053a45f221bc1"), new JsonResponse([])], 'Non-standard content type' => ["api", '{"api_key":"validToken"}', "POST", "multipart/form-data; boundary=33b68964f0de4c1f-5144aa6caaa6e4a8-18bfaf416a1786c8-5c5053a45f221bc1", new JsonResponse([])],
]; ];
} }
public function testMakeABaseQuery(): void { public function testMakeABaseQuery(): void {
$this->h = \Phake::partialMock(API::class); $this->hMock->baseResponse->forwards();
\Phake::when($this->h)->logIn->thenReturn(true); $this->hMock->logIn->returns(true);
\Phake::when(Arsse::$db)->subscriptionRefreshed(Arsse::$user->id)->thenReturn(new \DateTimeImmutable("2000-01-01T00:00:00Z")); $this->dbMock->subscriptionRefreshed->with($this->userId)->returns(new \DateTimeImmutable("2000-01-01T00:00:00Z"));
$exp = new JsonResponse([ $exp = new JsonResponse([
'api_version' => API::LEVEL, 'api_version' => API::LEVEL,
'auth' => 1, 'auth' => 1,
'last_refreshed_on_time' => 946684800, 'last_refreshed_on_time' => 946684800,
]); ]);
$act = $this->h->dispatch($this->req("api")); $this->assertMessage($exp, $this->req("api"));
$this->assertMessage($exp, $act); $this->dbMock->subscriptionRefreshed->with($this->userId)->returns(null); // no subscriptions
\Phake::when(Arsse::$db)->subscriptionRefreshed(Arsse::$user->id)->thenReturn(null); // no subscriptions
$exp = new JsonResponse([ $exp = new JsonResponse([
'api_version' => API::LEVEL, 'api_version' => API::LEVEL,
'auth' => 1, 'auth' => 1,
'last_refreshed_on_time' => null, 'last_refreshed_on_time' => null,
]); ]);
$act = $this->h->dispatch($this->req("api")); $this->assertMessage($exp, $this->req("api"));
$this->assertMessage($exp, $act); $this->hMock->logIn->returns(false);
\Phake::when($this->h)->logIn->thenReturn(false);
$exp = new JsonResponse([ $exp = new JsonResponse([
'api_version' => API::LEVEL, 'api_version' => API::LEVEL,
'auth' => 0, 'auth' => 0,
]); ]);
$act = $this->h->dispatch($this->req("api")); $this->assertMessage($exp, $this->req("api"));
$this->assertMessage($exp, $act);
} }
public function testUndoReadMarks(): void { public function testUndoReadMarks(): void {
$unread = [['id' => 4],['id' => 5],['id' => 6]]; $unread = [['id' => 4],['id' => 5],['id' => 6]];
$out = ['unread_item_ids' => "4,5,6"]; $out = ['unread_item_ids' => "4,5,6"];
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->limit(1)->hidden(false), ["marked_date"], ["marked_date desc"])->thenReturn(new Result([['marked_date' => "2000-01-01 00:00:00"]])); $this->dbMock->articleList->with($this->userId, $this->equalTo((new Context)->limit(1)->hidden(false)), ["marked_date"], ["marked_date desc"])->returns(new Result([['marked_date' => "2000-01-01 00:00:00"]]));
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->unread(true)->hidden(false))->thenReturn(new Result($unread)); $this->dbMock->articleList->with($this->userId, $this->equalTo((new Context)->unread(true)->hidden(false)))->returns(new Result($unread));
\Phake::when(Arsse::$db)->articleMark->thenReturn(0); $this->dbMock->articleMark->returns(0);
$exp = new JsonResponse($out); $exp = new JsonResponse($out);
$act = $this->h->dispatch($this->req("api", ['unread_recently_read' => 1])); $this->assertMessage($exp, $this->req("api", ['unread_recently_read' => 1]));
$this->assertMessage($exp, $act); $this->dbMock->articleMark->calledWith($this->userId, ['read' => false], $this->equalTo((new Context)->unread(false)->markedSince("1999-12-31T23:59:45Z")->hidden(false)));
\Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, ['read' => false], (new Context)->unread(false)->markedSince("1999-12-31T23:59:45Z")->hidden(false)); $this->dbMock->articleList->with($this->userId, (new Context)->limit(1)->hidden(false), ["marked_date"], ["marked_date desc"])->returns(new Result([]));
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->limit(1)->hidden(false), ["marked_date"], ["marked_date desc"])->thenReturn(new Result([])); $this->assertMessage($exp, $this->req("api", ['unread_recently_read' => 1]));
$act = $this->h->dispatch($this->req("api", ['unread_recently_read' => 1])); $this->dbMock->articleMark->once()->called(); // only called one time, above
$this->assertMessage($exp, $act);
\Phake::verify(Arsse::$db)->articleMark; // only called one time, above
} }
public function testOutputToXml(): void { public function testOutputToXml(): void {
\Phake::when($this->h)->processRequest->thenReturn([ $this->hMock->processRequest->returns([
'items' => $this->articles['rest'], 'items' => $this->articles['rest'],
'total_items' => 1024, 'total_items' => 1024,
]); ]);
$exp = new XmlResponse("<response><items><item><id>101</id><feed_id>8</feed_id><title>Article title 1</title><author></author><html>&lt;p&gt;Article content 1&lt;/p&gt;</html><url>http://example.com/1</url><is_saved>0</is_saved><is_read>0</is_read><created_on_time>946684800</created_on_time></item><item><id>102</id><feed_id>8</feed_id><title>Article title 2</title><author></author><html>&lt;p&gt;Article content 2&lt;/p&gt;</html><url>http://example.com/2</url><is_saved>0</is_saved><is_read>1</is_read><created_on_time>946771200</created_on_time></item><item><id>103</id><feed_id>9</feed_id><title>Article title 3</title><author></author><html>&lt;p&gt;Article content 3&lt;/p&gt;</html><url>http://example.com/3</url><is_saved>1</is_saved><is_read>0</is_read><created_on_time>946857600</created_on_time></item><item><id>104</id><feed_id>9</feed_id><title>Article title 4</title><author></author><html>&lt;p&gt;Article content 4&lt;/p&gt;</html><url>http://example.com/4</url><is_saved>1</is_saved><is_read>1</is_read><created_on_time>946944000</created_on_time></item><item><id>105</id><feed_id>10</feed_id><title>Article title 5</title><author></author><html>&lt;p&gt;Article content 5&lt;/p&gt;</html><url>http://example.com/5</url><is_saved>0</is_saved><is_read>0</is_read><created_on_time>947030400</created_on_time></item></items><total_items>1024</total_items></response>"); $exp = new XmlResponse("<response><items><item><id>101</id><feed_id>8</feed_id><title>Article title 1</title><author></author><html>&lt;p&gt;Article content 1&lt;/p&gt;</html><url>http://example.com/1</url><is_saved>0</is_saved><is_read>0</is_read><created_on_time>946684800</created_on_time></item><item><id>102</id><feed_id>8</feed_id><title>Article title 2</title><author></author><html>&lt;p&gt;Article content 2&lt;/p&gt;</html><url>http://example.com/2</url><is_saved>0</is_saved><is_read>1</is_read><created_on_time>946771200</created_on_time></item><item><id>103</id><feed_id>9</feed_id><title>Article title 3</title><author></author><html>&lt;p&gt;Article content 3&lt;/p&gt;</html><url>http://example.com/3</url><is_saved>1</is_saved><is_read>0</is_read><created_on_time>946857600</created_on_time></item><item><id>104</id><feed_id>9</feed_id><title>Article title 4</title><author></author><html>&lt;p&gt;Article content 4&lt;/p&gt;</html><url>http://example.com/4</url><is_saved>1</is_saved><is_read>1</is_read><created_on_time>946944000</created_on_time></item><item><id>105</id><feed_id>10</feed_id><title>Article title 5</title><author></author><html>&lt;p&gt;Article content 5&lt;/p&gt;</html><url>http://example.com/5</url><is_saved>0</is_saved><is_read>0</is_read><created_on_time>947030400</created_on_time></item></items><total_items>1024</total_items></response>");
$act = $this->h->dispatch($this->req("api=xml")); $this->assertMessage($exp, $this->req("api=xml"));
$this->assertMessage($exp, $act);
} }
public function testListFeedIcons(): void { public function testListFeedIcons(): void {
$iconType = (new \ReflectionClassConstant(API::class, "GENERIC_ICON_TYPE"))->getValue(); $iconType = (new \ReflectionClassConstant(API::class, "GENERIC_ICON_TYPE"))->getValue();
$iconData = (new \ReflectionClassConstant(API::class, "GENERIC_ICON_DATA"))->getValue(); $iconData = (new \ReflectionClassConstant(API::class, "GENERIC_ICON_DATA"))->getValue();
\Phake::when(Arsse::$db)->iconList->thenReturn(new Result($this->v([ $this->dbMock->iconList->returns(new Result($this->v([
['id' => 42, 'type' => "image/svg+xml", 'data' => "<svg/>"], ['id' => 42, 'type' => "image/svg+xml", 'data' => "<svg/>"],
['id' => 44, 'type' => null, 'data' => "IMAGE DATA"], ['id' => 44, 'type' => null, 'data' => "IMAGE DATA"],
['id' => 47, 'type' => null, 'data' => null], ['id' => 47, 'type' => null, 'data' => null],
]))); ])));
$act = $this->h->dispatch($this->req("api&favicons"));
$exp = new JsonResponse(['favicons' => [ $exp = new JsonResponse(['favicons' => [
['id' => 0, 'data' => $iconType.",".$iconData], ['id' => 0, 'data' => $iconType.",".$iconData],
['id' => 42, 'data' => "image/svg+xml;base64,PHN2Zy8+"], ['id' => 42, 'data' => "image/svg+xml;base64,PHN2Zy8+"],
['id' => 44, 'data' => "application/octet-stream;base64,SU1BR0UgREFUQQ=="], ['id' => 44, 'data' => "application/octet-stream;base64,SU1BR0UgREFUQQ=="],
]]); ]]);
$this->assertMessage($exp, $act); $this->assertMessage($exp, $this->req("api&favicons"));
} }
public function testAnswerOptionsRequest(): void { public function testAnswerOptionsRequest(): void {
$act = $this->h->dispatch($this->req("api", "", "OPTIONS"));
$exp = new EmptyResponse(204, [ $exp = new EmptyResponse(204, [
'Allow' => "POST", 'Allow' => "POST",
'Accept' => "application/x-www-form-urlencoded, multipart/form-data", 'Accept' => "application/x-www-form-urlencoded, multipart/form-data",
]); ]);
$this->assertMessage($exp, $act); $this->assertMessage($exp, $this->req("api", "", "OPTIONS"));
} }
} }

View file

@ -19,7 +19,7 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
protected $u; protected $u;
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
// create a mock user manager // create a mock user manager
Arsse::$user = \Phake::mock(User::class); Arsse::$user = \Phake::mock(User::class);
@ -31,10 +31,6 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
$this->u = new FeverUser(); $this->u = new FeverUser();
} }
public function tearDown(): void {
self::clearData();
}
/** @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"); \Phake::when(Arsse::$user)->generatePassword->thenReturn("RANDOM_PASSWORD");

View file

@ -21,7 +21,7 @@ class TestToken extends \JKingWeb\Arsse\Test\AbstractTest {
protected $transaction; protected $transaction;
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
// create a mock database interface // create a mock database interface
Arsse::$db = \Phake::mock(Database::class); Arsse::$db = \Phake::mock(Database::class);
@ -30,10 +30,6 @@ class TestToken extends \JKingWeb\Arsse\Test\AbstractTest {
$this->h = new Token(); $this->h = new Token();
} }
public function tearDown(): void {
self::clearData();
}
protected function v($value) { protected function v($value) {
return $value; return $value;
} }

View file

@ -71,7 +71,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
} }
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
// create a mock database interface // create a mock database interface
Arsse::$db = \Phake::mock(Database::class); Arsse::$db = \Phake::mock(Database::class);
@ -85,10 +85,6 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
$this->h = new V1(); $this->h = new V1();
} }
public function tearDown(): void {
self::clearData();
}
protected function v($value) { protected function v($value) {
return $value; return $value;
} }

View file

@ -312,7 +312,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
} }
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
// create a mock user manager // create a mock user manager
Arsse::$user = \Phake::mock(User::class); Arsse::$user = \Phake::mock(User::class);
@ -326,10 +326,6 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
$this->h = new V1_2(); $this->h = new V1_2();
} }
public function tearDown(): void {
self::clearData();
}
protected function v($value) { protected function v($value) {
return $value; return $value;
} }

View file

@ -14,7 +14,7 @@ use Laminas\Diactoros\Response\EmptyResponse;
/** @covers \JKingWeb\Arsse\REST\NextcloudNews\Versions */ /** @covers \JKingWeb\Arsse\REST\NextcloudNews\Versions */
class TestVersions extends \JKingWeb\Arsse\Test\AbstractTest { class TestVersions extends \JKingWeb\Arsse\Test\AbstractTest {
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
} }
protected function req(string $method, string $target): ResponseInterface { protected function req(string $method, string $target): ResponseInterface {

View file

@ -63,11 +63,12 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest {
public function testAuthenticateRequests(array $serverParams, array $expAttr): void { public function testAuthenticateRequests(array $serverParams, array $expAttr): void {
$r = new REST(); $r = new REST();
// 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(false); $this->userMock->auth->returns(false);
\Phake::when(Arsse::$user)->auth("john.doe@example.com", "secret")->thenReturn(true); $this->userMock->auth->with("john.doe@example.com", "secret")->returns(true);
\Phake::when(Arsse::$user)->auth("john.doe@example.com", "")->thenReturn(true); $this->userMock->auth->with("john.doe@example.com", "")->returns(true);
\Phake::when(Arsse::$user)->auth("someone.else@example.com", "")->thenReturn(true); $this->userMock->auth->with("someone.else@example.com", "")->returns(true);
Arsse::$user = $this->userMock->get();
// create an input server request // create an input server request
$req = new ServerRequest($serverParams); $req = new ServerRequest($serverParams);
// create the expected output // create the expected output
@ -150,13 +151,13 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideCorsNegotiations */ /** @dataProvider provideCorsNegotiations */
public function testNegotiateCors($origin, bool $exp, string $allowed = null, string $denied = null): void { public function testNegotiateCors($origin, bool $exp, string $allowed = null, string $denied = null): void {
self::setConf(); self::setConf();
$r = \Phake::partialMock(REST::class); $rMock = $this->partialMock(REST::class);
\Phake::when($r)->corsNormalizeOrigin->thenReturnCallback(function($origin) { $rMock->corsNormalizeOrigin->does(function($origin) {
return $origin; return $origin;
}); });
$headers = isset($origin) ? ['Origin' => $origin] : []; $headers = isset($origin) ? ['Origin' => $origin] : [];
$req = new Request("", "GET", "php://memory", $headers); $req = new Request("", "GET", "php://memory", $headers);
$act = $r->corsNegotiate($req, $allowed, $denied); $act = $rMock->get()->corsNegotiate($req, $allowed, $denied);
$this->assertSame($exp, $act); $this->assertSame($exp, $act);
} }
@ -251,15 +252,15 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideUnnormalizedResponses */ /** @dataProvider provideUnnormalizedResponses */
public function testNormalizeHttpResponses(ResponseInterface $res, ResponseInterface $exp, RequestInterface $req = null): void { public function testNormalizeHttpResponses(ResponseInterface $res, ResponseInterface $exp, RequestInterface $req = null): void {
$r = \Phake::partialMock(REST::class); $rMock = $this->partialMock(REST::class);
\Phake::when($r)->corsNegotiate->thenReturn(true); $rMock->corsNegotiate->returns(true);
\Phake::when($r)->challenge->thenReturnCallback(function($res) { $rMock->challenge->does(function($res) {
return $res->withHeader("WWW-Authenticate", "Fake Value"); return $res->withHeader("WWW-Authenticate", "Fake Value");
}); });
\Phake::when($r)->corsApply->thenReturnCallback(function($res) { $rMock->corsApply->does(function($res) {
return $res; return $res;
}); });
$act = $r->normalizeResponse($res, $req); $act = $rMock->get()->normalizeResponse($res, $req);
$this->assertMessage($exp, $act); $this->assertMessage($exp, $act);
} }
@ -287,30 +288,32 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideMockRequests */ /** @dataProvider provideMockRequests */
public function testDispatchRequests(ServerRequest $req, string $method, bool $called, string $class = "", string $target = ""): void { public function testDispatchRequests(ServerRequest $req, string $method, bool $called, string $class = "", string $target = ""): void {
$r = \Phake::partialMock(REST::class); $rMock = $this->partialMock(REST::class);
\Phake::when($r)->normalizeResponse->thenReturnCallback(function($res) { $rMock->normalizeResponse->does(function($res) {
return $res; return $res;
}); });
\Phake::when($r)->authenticateRequest->thenReturnCallback(function($req) { $rMock->authenticateRequest->does(function($req) {
return $req; return $req;
}); });
if ($called) { if ($called) {
$h = \Phake::mock($class); $hMock = $this->mock($class);
\Phake::when(Arsse::$obj)->get($class)->thenReturn($h); $hMock->dispatch->returns(new EmptyResponse(204));
\Phake::when($h)->dispatch->thenReturn(new EmptyResponse(204)); $this->objMock->get->with($class)->returns($hMock);
Arsse::$obj = $this->objMock->get();
} }
$out = $r->dispatch($req); $out = $rMock->get()->dispatch($req);
$this->assertInstanceOf(ResponseInterface::class, $out); $this->assertInstanceOf(ResponseInterface::class, $out);
if ($called) { if ($called) {
\Phake::verify($r)->authenticateRequest; $rMock->authenticateRequest->called();
\Phake::verify($h)->dispatch(\Phake::capture($in)); $hMock->dispatch->once()->called();
$in = $hMock->dispatch->firstCall()->argument();;
$this->assertSame($method, $in->getMethod()); $this->assertSame($method, $in->getMethod());
$this->assertSame($target, $in->getRequestTarget()); $this->assertSame($target, $in->getRequestTarget());
} else { } else {
$this->assertSame(501, $out->getStatusCode()); $this->assertSame(501, $out->getStatusCode());
} }
\Phake::verify($r)->apiMatch; $rMock->apiMatch->called();
\Phake::verify($r)->normalizeResponse; $rMock->normalizeResponse->called();
} }
public function provideMockRequests(): iterable { public function provideMockRequests(): iterable {

View file

@ -20,7 +20,7 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest {
protected $user = "john.doe@example.com"; protected $user = "john.doe@example.com";
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
// create a mock user manager // create a mock user manager
Arsse::$user = \Phake::mock(User::class); Arsse::$user = \Phake::mock(User::class);
@ -29,10 +29,6 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest {
$this->h = new Icon(); $this->h = new Icon();
} }
public function tearDown(): void {
self::clearData();
}
protected function req(string $target, string $method = "GET", string $user = null): ResponseInterface { protected function req(string $target, string $method = "GET", string $user = null): ResponseInterface {
$prefix = "/tt-rss/feed-icons/"; $prefix = "/tt-rss/feed-icons/";
$url = $prefix.$target; $url = $prefix.$target;

View file

@ -14,7 +14,7 @@ use JKingWeb\Arsse\Service\Serial\Driver;
/** @covers \JKingWeb\Arsse\Service\Serial\Driver */ /** @covers \JKingWeb\Arsse\Service\Serial\Driver */
class TestSerial extends \JKingWeb\Arsse\Test\AbstractTest { class TestSerial extends \JKingWeb\Arsse\Test\AbstractTest {
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
Arsse::$db = \Phake::mock(Database::class); Arsse::$db = \Phake::mock(Database::class);
} }

View file

@ -16,7 +16,7 @@ class TestService extends \JKingWeb\Arsse\Test\AbstractTest {
protected $srv; protected $srv;
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
Arsse::$db = \Phake::mock(Database::class); Arsse::$db = \Phake::mock(Database::class);
$this->srv = new Service(); $this->srv = new Service();

View file

@ -13,7 +13,7 @@ use JKingWeb\Arsse\Service\Subprocess\Driver;
/** @covers \JKingWeb\Arsse\Service\Subprocess\Driver */ /** @covers \JKingWeb\Arsse\Service\Subprocess\Driver */
class TestSubprocess extends \JKingWeb\Arsse\Test\AbstractTest { class TestSubprocess extends \JKingWeb\Arsse\Test\AbstractTest {
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
} }

View file

@ -17,22 +17,23 @@ class TestArsse extends \JKingWeb\Arsse\Test\AbstractTest {
public function setUp(): void { public function setUp(): void {
self::clearData(false); self::clearData(false);
} }
public function tearDown(): void {
self::clearData();
}
public function testLoadExistingData(): void { public function testLoadExistingData(): void {
$lang = Arsse::$lang = \Phake::mock(Lang::class); $lang = $this->mock(Lang::class);
$db = Arsse::$db = \Phake::mock(Database::class); $db = $this->mock(Database::class);
$user = Arsse::$user = \Phake::mock(User::class); $user = $this->mock(User::class);
$conf1 = Arsse::$conf = \Phake::mock(Conf::class); $conf1 = $this->mock(Conf::class);
Arsse::$lang = $lang->get();
Arsse::$db = $db->get();
Arsse::$user = $user->get();
Arsse::$conf = $conf1->get();
$conf2 = (new Conf)->import(['lang' => "test"]); $conf2 = (new Conf)->import(['lang' => "test"]);
Arsse::load($conf2); Arsse::load($conf2);
$this->assertSame($conf2, Arsse::$conf); $this->assertSame($conf2, Arsse::$conf);
$this->assertSame($lang, Arsse::$lang); $this->assertSame($lang->get(), Arsse::$lang);
$this->assertSame($db, Arsse::$db); $this->assertSame($db->get(), Arsse::$db);
$this->assertSame($user, Arsse::$user); $this->assertSame($user->get(), Arsse::$user);
\Phake::verify($lang)->set("test"); $lang->set->calledWith("test");
} }
public function testLoadNewData(): void { public function testLoadNewData(): void {

View file

@ -14,7 +14,7 @@ use JKingWeb\Arsse\User\Internal\Driver;
/** @covers \JKingWeb\Arsse\User\Internal\Driver */ /** @covers \JKingWeb\Arsse\User\Internal\Driver */
class TestInternal extends \JKingWeb\Arsse\Test\AbstractTest { class TestInternal extends \JKingWeb\Arsse\Test\AbstractTest {
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
// create a mock database interface // create a mock database interface
Arsse::$db = \Phake::mock(Database::class); Arsse::$db = \Phake::mock(Database::class);

View file

@ -17,7 +17,7 @@ use JKingWeb\Arsse\User\Driver;
/** @covers \JKingWeb\Arsse\User */ /** @covers \JKingWeb\Arsse\User */
class TestUser extends \JKingWeb\Arsse\Test\AbstractTest { class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
public function setUp(): void { public function setUp(): void {
self::clearData(); parent::setUp();
self::setConf(); self::setConf();
// create a mock database interface // create a mock database interface
Arsse::$db = \Phake::mock(Database::class); Arsse::$db = \Phake::mock(Database::class);

View file

@ -6,6 +6,8 @@
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test; namespace JKingWeb\Arsse\Test;
use Eloquent\Phony\Mock\Handle\InstanceHandle;
use Eloquent\Phony\Phpunit\Phony;
use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException; use GuzzleHttp\Exception\RequestException;
use JKingWeb\Arsse\Exception; use JKingWeb\Arsse\Exception;
@ -29,12 +31,20 @@ use Laminas\Diactoros\Response\XmlResponse;
abstract class AbstractTest extends \PHPUnit\Framework\TestCase { abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
use \DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; use \DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
protected $objMock;
protected $confMock;
protected $langMock;
protected $dbMock;
protected $userMock;
public function setUp(): void { public function setUp(): void {
self::clearData(); self::clearData();
} // create the object factory as a mock
$this->objMock = Arsse::$obj = $this->mock(Factory::class);
public function tearDown(): void { $this->objMock->get->does(function(string $class) {
self::clearData(); return new $class;
});
} }
public static function clearData(bool $loadLang = true): void { public static function clearData(bool $loadLang = true): void {
@ -46,11 +56,6 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
} }
if ($loadLang) { if ($loadLang) {
Arsse::$lang = new \JKingWeb\Arsse\Lang(); Arsse::$lang = new \JKingWeb\Arsse\Lang();
// also create the object factory as a mock
Arsse::$obj = \Phake::mock(Factory::class);
\Phake::when(Arsse::$obj)->get->thenReturnCallback(function(string $class) {
return new $class;
});
} }
} }
@ -340,12 +345,20 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
/** Guzzle's exception classes require some fairly complicated construction; this abstracts it all away so that only message and code need be supplied */ /** Guzzle's exception classes require some fairly complicated construction; this abstracts it all away so that only message and code need be supplied */
protected function mockGuzzleException(string $class, ?string $message = null, ?int $code = null, ?\Throwable $e = null): GuzzleException { protected function mockGuzzleException(string $class, ?string $message = null, ?int $code = null, ?\Throwable $e = null): GuzzleException {
if (is_a($class, RequestException::class, true)) { if (is_a($class, RequestException::class, true)) {
$req = \Phake::mock(RequestInterface::class); $req = $this->mock(RequestInterface::class);
$res = \Phake::mock(ResponseInterface::class); $res = $this->mock(ResponseInterface::class);
\Phake::when($res)->getStatusCode->thenReturn($code ?? 0); $res->getStatusCode->returns($code ?? 0);
return new $class($message ?? "", $req, $res, $e); return new $class($message ?? "", $req->get(), $res->get(), $e);
} else { } else {
return new $class($message ?? "", $code ?? 0, $e); return new $class($message ?? "", $code ?? 0, $e);
} }
} }
protected function mock(string $class): InstanceHandle {
return Phony::mock($class);
}
protected function partialMock(string $class, ...$argument): InstanceHandle {
return Phony::partialMock($class, $argument);
}
} }

View file

@ -5,6 +5,7 @@
"phake/phake": "^3.0", "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",
"eloquent/phony-phpunit": "^6.0 || ^7.0"
} }
} }

View file

@ -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": "9c0d657e9fcab3d3be0467bbdc300a0a", "content-hash": "fda9bd2446005dfe56a223890cad0849",
"packages": [], "packages": [],
"packages-dev": [ "packages-dev": [
{ {
@ -188,6 +188,153 @@
], ],
"time": "2020-11-10T18:47:58+00:00" "time": "2020-11-10T18:47:58+00:00"
}, },
{
"name": "eloquent/phony",
"version": "5.0.2",
"source": {
"type": "git",
"url": "https://github.com/eloquent/phony.git",
"reference": "f34d67d6db6b6f351ea7e8aa8066107e756ec26b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/eloquent/phony/zipball/f34d67d6db6b6f351ea7e8aa8066107e756ec26b",
"reference": "f34d67d6db6b6f351ea7e8aa8066107e756ec26b",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8"
},
"require-dev": {
"eloquent/code-style": "^1.0",
"eloquent/phpstan-phony": "^0.7",
"errors/exceptions": "^0.2",
"ext-pdo": "*",
"friendsofphp/php-cs-fixer": "^2",
"hamcrest/hamcrest-php": "^2",
"phpstan/extension-installer": "^1",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"phpunit/phpunit": "^9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Eloquent\\Phony\\": "src"
},
"files": [
"src/initialize.php",
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Erin Millard",
"email": "ezzatron@gmail.com",
"homepage": "http://ezzatron.com/"
}
],
"description": "Mocks, stubs, and spies for PHP.",
"homepage": "http://eloquent-software.com/phony/",
"keywords": [
"Double",
"Dummy",
"fake",
"mock",
"mocking",
"spy",
"stub",
"stubbing",
"test"
],
"support": {
"issues": "https://github.com/eloquent/phony/issues",
"source": "https://github.com/eloquent/phony/tree/5.0.2"
},
"time": "2021-02-17T01:45:10+00:00"
},
{
"name": "eloquent/phony-phpunit",
"version": "7.1.0",
"source": {
"type": "git",
"url": "https://github.com/eloquent/phony-phpunit.git",
"reference": "e77ff95ea6235211d4aae7e5f53488a5faebc2e0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/eloquent/phony-phpunit/zipball/e77ff95ea6235211d4aae7e5f53488a5faebc2e0",
"reference": "e77ff95ea6235211d4aae7e5f53488a5faebc2e0",
"shasum": ""
},
"require": {
"eloquent/phony": "^5",
"php": "^7.3 || ^8",
"phpunit/phpunit": "^9"
},
"require-dev": {
"eloquent/code-style": "^1",
"eloquent/phpstan-phony": "^0.7",
"errors/exceptions": "^0.2",
"friendsofphp/php-cs-fixer": "^2",
"phpstan/extension-installer": "^1",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-phpunit": "^0.12"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "7.2.x-dev"
}
},
"autoload": {
"psr-4": {
"Eloquent\\Phony\\Phpunit\\": "src"
},
"files": [
"src/initialize.php",
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Erin Millard",
"email": "ezzatron@gmail.com",
"homepage": "http://ezzatron.com/"
}
],
"description": "Phony for PHPUnit.",
"homepage": "http://eloquent-software.com/phony/",
"keywords": [
"Double",
"Dummy",
"fake",
"mock",
"mocking",
"spy",
"stub",
"stubbing",
"test"
],
"support": {
"issues": "https://github.com/eloquent/phony-phpunit/issues",
"source": "https://github.com/eloquent/phony-phpunit/tree/7.1.0"
},
"time": "2020-12-21T09:36:47+00:00"
},
{ {
"name": "mikey179/vfsstream", "name": "mikey179/vfsstream",
"version": "v1.6.8", "version": "v1.6.8",

View file

@ -1,6 +1,6 @@
{ {
"require-dev": { "require-dev": {
"consolidation/robo": "^2.2", "consolidation/robo": "^3.0",
"pear/archive_tar": "^1.4" "pear/archive_tar": "^1.4"
} }
} }

View file

@ -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": "1bd6e46df17a215ef177f27dadac115f", "content-hash": "ee0b828426eaa5ff905ef60d9a4b9aca",
"packages": [], "packages": [],
"packages-dev": [ "packages-dev": [
{ {
@ -235,51 +235,49 @@
}, },
{ {
"name": "consolidation/robo", "name": "consolidation/robo",
"version": "2.2.2", "version": "3.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/consolidation/Robo.git", "url": "https://github.com/consolidation/Robo.git",
"reference": "b365df174d9cfb0f5814e4f3275a1c558b17bc4c" "reference": "734620ad3f9bb457fda1a52338b42439115cf941"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/consolidation/Robo/zipball/b365df174d9cfb0f5814e4f3275a1c558b17bc4c", "url": "https://api.github.com/repos/consolidation/Robo/zipball/734620ad3f9bb457fda1a52338b42439115cf941",
"reference": "b365df174d9cfb0f5814e4f3275a1c558b17bc4c", "reference": "734620ad3f9bb457fda1a52338b42439115cf941",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"consolidation/annotated-command": "^4.2.1", "consolidation/annotated-command": "^4.2.4",
"consolidation/config": "^1.2.1|^2", "consolidation/config": "^1.2.1|^2.0.1",
"consolidation/log": "^1.1.1|^2.0.1", "consolidation/log": "^1.1.1|^2.0.2",
"consolidation/output-formatters": "^4.1.1", "consolidation/output-formatters": "^4.1.2",
"consolidation/self-update": "^1.2", "consolidation/self-update": "^1.2",
"league/container": "^2.4.1", "league/container": "^3.3.1",
"php": ">=7.1.3", "php": ">=7.1.3",
"symfony/console": "^4.4.11|^5", "symfony/console": "^4.4.19 || ^5",
"symfony/event-dispatcher": "^4.4.11|^5", "symfony/event-dispatcher": "^4.4.19 || ^5",
"symfony/filesystem": "^4.4.11|^5", "symfony/filesystem": "^4.4.9 || ^5",
"symfony/finder": "^4.4.11|^5", "symfony/finder": "^4.4.9 || ^5",
"symfony/process": "^4.4.11|^5", "symfony/process": "^4.4.9 || ^5",
"symfony/yaml": "^4.0 || ^5.0" "symfony/yaml": "^4.4 || ^5"
}, },
"conflict": { "conflict": {
"codegyre/robo": "*" "codegyre/robo": "*"
}, },
"require-dev": { "require-dev": {
"g1a/composer-test-scenarios": "^3",
"natxet/cssmin": "3.0.4", "natxet/cssmin": "3.0.4",
"patchwork/jsqueeze": "^2", "patchwork/jsqueeze": "^2",
"pear/archive_tar": "^1.4.4", "pear/archive_tar": "^1.4.4",
"php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^7.5.20 | ^8",
"phpdocumentor/reflection-docblock": "^4.3.2", "squizlabs/php_codesniffer": "^3",
"phpunit/phpunit": "^6.5.14", "yoast/phpunit-polyfills": "^0.2.0"
"squizlabs/php_codesniffer": "^3"
}, },
"suggest": { "suggest": {
"henrikbjorn/lurker": "For monitoring filesystem changes in taskWatch",
"natxet/cssmin": "For minifying CSS files in taskMinify", "natxet/cssmin": "For minifying CSS files in taskMinify",
"patchwork/jsqueeze": "For minifying JS files in taskMinify", "patchwork/jsqueeze": "For minifying JS files in taskMinify",
"pear/archive_tar": "Allows tar archives to be created and extracted in taskPack and taskExtract, respectively." "pear/archive_tar": "Allows tar archives to be created and extracted in taskPack and taskExtract, respectively.",
"totten/lurkerlite": "For monitoring filesystem changes in taskWatch"
}, },
"bin": [ "bin": [
"robo" "robo"
@ -330,9 +328,9 @@
"description": "Modern task runner", "description": "Modern task runner",
"support": { "support": {
"issues": "https://github.com/consolidation/Robo/issues", "issues": "https://github.com/consolidation/Robo/issues",
"source": "https://github.com/consolidation/Robo/tree/2.2.2" "source": "https://github.com/consolidation/Robo/tree/3.0.3"
}, },
"time": "2020-12-18T22:09:18+00:00" "time": "2021-02-21T19:19:43+00:00"
}, },
{ {
"name": "consolidation/self-update", "name": "consolidation/self-update",
@ -388,42 +386,6 @@
}, },
"time": "2020-04-13T02:49:20+00:00" "time": "2020-04-13T02:49:20+00:00"
}, },
{
"name": "container-interop/container-interop",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/container-interop/container-interop.git",
"reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8",
"reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8",
"shasum": ""
},
"require": {
"psr/container": "^1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Interop\\Container\\": "src/Interop/Container/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
"homepage": "https://github.com/container-interop/container-interop",
"support": {
"issues": "https://github.com/container-interop/container-interop/issues",
"source": "https://github.com/container-interop/container-interop/tree/master"
},
"abandoned": "psr/container",
"time": "2017-02-14T19:40:03+00:00"
},
{ {
"name": "dflydev/dot-access-data", "name": "dflydev/dot-access-data",
"version": "v1.1.0", "version": "v1.1.0",
@ -540,37 +502,39 @@
}, },
{ {
"name": "league/container", "name": "league/container",
"version": "2.5.0", "version": "3.3.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/container.git", "url": "https://github.com/thephpleague/container.git",
"reference": "8438dc47a0674e3378bcce893a0a04d79a2c22b3" "reference": "40aed0f11d16bc23f9d04a27acc3549cd1bb42ab"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/container/zipball/8438dc47a0674e3378bcce893a0a04d79a2c22b3", "url": "https://api.github.com/repos/thephpleague/container/zipball/40aed0f11d16bc23f9d04a27acc3549cd1bb42ab",
"reference": "8438dc47a0674e3378bcce893a0a04d79a2c22b3", "reference": "40aed0f11d16bc23f9d04a27acc3549cd1bb42ab",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"container-interop/container-interop": "^1.2", "php": "^7.0 || ^8.0",
"php": "^5.4 || ^7.0 || ^8.0" "psr/container": "^1.0"
}, },
"provide": { "provide": {
"container-interop/container-interop-implementation": "^1.2",
"psr/container-implementation": "^1.0" "psr/container-implementation": "^1.0"
}, },
"replace": { "replace": {
"orno/di": "~2.0" "orno/di": "~2.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.8.36", "phpunit/phpunit": "^6.0",
"scrutinizer/ocular": "^1.3", "roave/security-advisories": "dev-master",
"scrutinizer/ocular": "^1.8",
"squizlabs/php_codesniffer": "^3.5" "squizlabs/php_codesniffer": "^3.5"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "3.x-dev",
"dev-3.x": "3.x-dev",
"dev-2.x": "2.x-dev", "dev-2.x": "2.x-dev",
"dev-1.x": "1.x-dev" "dev-1.x": "1.x-dev"
} }
@ -605,7 +569,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/thephpleague/container/issues", "issues": "https://github.com/thephpleague/container/issues",
"source": "https://github.com/thephpleague/container/tree/2.5.0" "source": "https://github.com/thephpleague/container/tree/3.3.4"
}, },
"funding": [ "funding": [
{ {
@ -613,7 +577,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-02-22T09:20:06+00:00" "time": "2021-02-22T10:35:05+00:00"
}, },
{ {
"name": "pear/archive_tar", "name": "pear/archive_tar",