2018-11-06 17:32:28 +00:00
|
|
|
<?php
|
|
|
|
/** @license MIT
|
|
|
|
* Copyright 2017 J. King, Dustin Wilson et al.
|
|
|
|
* See LICENSE and AUTHORS files for details */
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace JKingWeb\Arsse\TestCase\CLI;
|
|
|
|
|
2021-06-25 15:08:56 +00:00
|
|
|
use Eloquent\Phony\Phpunit\Phony;
|
2020-01-24 20:54:08 +00:00
|
|
|
use GuzzleHttp\Exception\ClientException;
|
2018-11-06 17:32:28 +00:00
|
|
|
use JKingWeb\Arsse\Arsse;
|
|
|
|
use JKingWeb\Arsse\Conf;
|
|
|
|
use JKingWeb\Arsse\User;
|
|
|
|
use JKingWeb\Arsse\Database;
|
|
|
|
use JKingWeb\Arsse\Service;
|
|
|
|
use JKingWeb\Arsse\CLI;
|
2019-03-25 14:45:05 +00:00
|
|
|
use JKingWeb\Arsse\REST\Fever\User as FeverUser;
|
2021-02-11 02:40:51 +00:00
|
|
|
use JKingWeb\Arsse\REST\Miniflux\Token as MinifluxToken;
|
2019-04-01 21:24:19 +00:00
|
|
|
use JKingWeb\Arsse\ImportExport\OPML;
|
2021-06-25 15:08:56 +00:00
|
|
|
use JKingWeb\Arsse\Service\Daemon;
|
2018-11-06 17:32:28 +00:00
|
|
|
|
|
|
|
/** @covers \JKingWeb\Arsse\CLI */
|
|
|
|
class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
|
2023-01-27 20:33:34 +00:00
|
|
|
protected $cli;
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function setUp(): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
parent::setUp();
|
|
|
|
$this->cli = $this->partialMock(CLI::class);
|
|
|
|
$this->cli->logError->returns(null);
|
|
|
|
$this->cli->loadConf->returns(true);
|
|
|
|
$this->dbMock = $this->mock(Database::class);
|
2018-11-06 17:32:28 +00:00
|
|
|
}
|
|
|
|
|
2021-02-27 20:24:02 +00:00
|
|
|
public function assertConsole(string $command, int $exitStatus, string $output = "", bool $pattern = false): void {
|
|
|
|
Arsse::$obj = $this->objMock->get();
|
|
|
|
Arsse::$db = $this->dbMock->get();
|
2018-11-06 17:32:28 +00:00
|
|
|
$argv = \Clue\Arguments\split($command);
|
|
|
|
$output = strlen($output) ? $output.\PHP_EOL : "";
|
|
|
|
if ($pattern) {
|
2018-12-05 22:28:11 +00:00
|
|
|
$this->expectOutputRegex($output);
|
2018-11-06 17:32:28 +00:00
|
|
|
} else {
|
|
|
|
$this->expectOutputString($output);
|
|
|
|
}
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->assertSame($exitStatus, $this->cli->get()->dispatch($argv));
|
2018-11-06 17:32:28 +00:00
|
|
|
}
|
|
|
|
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testPrintVersion(): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->assertConsole("arsse.php --version", 0, Arsse::VERSION);
|
|
|
|
$this->cli->loadConf->never()->called();
|
2018-11-06 17:32:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @dataProvider provideHelpText */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testPrintHelp(string $cmd, string $name): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->assertConsole($cmd, 0, str_replace("arsse.php", $name, CLI::USAGE));
|
|
|
|
$this->cli->loadConf->never()->called();
|
2018-11-06 17:32:28 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideHelpText(): iterable {
|
2018-11-06 17:32:28 +00:00
|
|
|
return [
|
|
|
|
["arsse.php --help", "arsse.php"],
|
|
|
|
["arsse --help", "arsse"],
|
|
|
|
["thearsse --help", "thearsse"],
|
2019-05-06 04:02:59 +00:00
|
|
|
["arsse.php -h", "arsse.php"],
|
|
|
|
["arsse -h", "arsse"],
|
|
|
|
["thearsse -h", "thearsse"],
|
2018-11-06 17:32:28 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testStartTheDaemon(): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
$srv = $this->mock(Service::class);
|
|
|
|
$srv->watch->returns(new \DateTimeImmutable);
|
|
|
|
$this->objMock->get->with(Service::class)->returns($srv->get());
|
|
|
|
$this->assertConsole("arsse.php daemon", 0);
|
|
|
|
$this->cli->loadConf->called();
|
|
|
|
$srv->watch->calledWith(true);
|
2018-11-06 17:32:28 +00:00
|
|
|
}
|
|
|
|
|
2021-06-25 15:08:56 +00:00
|
|
|
public function testStartTheForkingDaemon(): void {
|
|
|
|
$f = tempnam(sys_get_temp_dir(), "arsse");
|
|
|
|
$srv = $this->mock(Service::class);
|
|
|
|
$srv->watch->returns(new \DateTimeImmutable);
|
|
|
|
$daemon = $this->mock(Daemon::class);
|
|
|
|
$daemon->checkPIDFilePath->returns($f);
|
|
|
|
$daemon->fork->returns(null);
|
|
|
|
$this->objMock->get->with(Service::class)->returns($srv->get());
|
|
|
|
$this->objMock->get->with(Daemon::class)->returns($daemon->get());
|
|
|
|
$this->assertConsole("arsse.php daemon --fork=arsse.pid", 0);
|
|
|
|
$this->assertFileDoesNotExist($f);
|
|
|
|
Phony::inOrder(
|
|
|
|
$daemon->checkPIDFilePath->calledWith("arsse.pid"),
|
|
|
|
$daemon->fork->calledWith($f),
|
|
|
|
$this->cli->loadConf->called(),
|
|
|
|
$srv->watch->calledWith(true)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testFailToStartTheForkingDaemon(): void {
|
|
|
|
$srv = $this->mock(Service::class);
|
|
|
|
$srv->watch->returns(new \DateTimeImmutable);
|
|
|
|
$daemon = $this->mock(Daemon::class);
|
2021-06-30 18:36:00 +00:00
|
|
|
$daemon->checkPIDFilePath->throws(new Service\Exception("pidDuplicate", ['pid' => 2112]));
|
2021-06-25 15:08:56 +00:00
|
|
|
$daemon->fork->returns(null);
|
|
|
|
$this->objMock->get->with(Service::class)->returns($srv->get());
|
|
|
|
$this->objMock->get->with(Daemon::class)->returns($daemon->get());
|
2021-06-25 22:34:01 +00:00
|
|
|
$this->assertConsole("arsse.php daemon --fork=arsse.pid", 10809);
|
|
|
|
$daemon->checkPIDFilePath->calledWith("arsse.pid");
|
2021-07-06 01:47:44 +00:00
|
|
|
$daemon->fork->never()->called();
|
2021-06-25 22:34:01 +00:00
|
|
|
$this->cli->loadConf->never()->called();
|
|
|
|
$srv->watch->never()->called();
|
2021-06-25 15:08:56 +00:00
|
|
|
}
|
|
|
|
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testRefreshAllFeeds(): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
$srv = $this->mock(Service::class);
|
|
|
|
$srv->watch->returns(new \DateTimeImmutable);
|
|
|
|
$this->objMock->get->with(Service::class)->returns($srv->get());
|
|
|
|
$this->assertConsole("arsse.php feed refresh-all", 0);
|
|
|
|
$this->cli->loadConf->called();
|
|
|
|
$srv->watch->calledWith(false);
|
2019-03-02 19:59:44 +00:00
|
|
|
}
|
|
|
|
|
2018-11-06 17:32:28 +00:00
|
|
|
/** @dataProvider provideFeedUpdates */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testRefreshAFeed(string $cmd, int $exitStatus, string $output): void {
|
2022-12-30 17:41:12 +00:00
|
|
|
$this->dbMock->subscriptionUpdate->with(null, 1, true)->returns(true);
|
|
|
|
$this->dbMock->subscriptionUpdate->with(null, 2, true)->throws(new \JKingWeb\Arsse\Feed\Exception("", ['url' => "http://example.com/"], $this->mockGuzzleException(ClientException::class, "", 404)));
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->assertConsole($cmd, $exitStatus, $output);
|
|
|
|
$this->cli->loadConf->called();
|
2022-12-30 17:41:12 +00:00
|
|
|
$this->dbMock->subscriptionUpdate->called();
|
2018-11-06 17:32:28 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideFeedUpdates(): iterable {
|
2018-11-06 17:32:28 +00:00
|
|
|
return [
|
|
|
|
["arsse.php feed refresh 1", 0, ""],
|
|
|
|
["arsse.php feed refresh 2", 10502, ""],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @dataProvider provideDefaultConfigurationSaves */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testSaveTheDefaultConfiguration(string $cmd, int $exitStatus, string $file): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
$conf = $this->mock(Conf::class);
|
|
|
|
$conf->exportFile->with("php://output", true)->returns(true);
|
|
|
|
$conf->exportFile->with("good.conf", true)->returns(true);
|
|
|
|
$conf->exportFile->with("bad.conf", true)->throws(new \JKingWeb\Arsse\Conf\Exception("fileUnwritable"));
|
|
|
|
$this->objMock->get->with(Conf::class)->returns($conf->get());
|
|
|
|
$this->assertConsole($cmd, $exitStatus);
|
|
|
|
$this->cli->loadConf->never()->called();
|
|
|
|
$conf->exportFile->calledWith($file, true);
|
2018-11-06 17:32:28 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideDefaultConfigurationSaves(): iterable {
|
2018-11-06 17:32:28 +00:00
|
|
|
return [
|
|
|
|
["arsse.php conf save-defaults", 0, "php://output"],
|
|
|
|
["arsse.php conf save-defaults -", 0, "php://output"],
|
|
|
|
["arsse.php conf save-defaults good.conf", 0, "good.conf"],
|
|
|
|
["arsse.php conf save-defaults bad.conf", 10304, "bad.conf"],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @dataProvider provideUserList */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testListUsers(string $cmd, array $list, int $exitStatus, string $output): void {
|
2018-12-08 00:21:44 +00:00
|
|
|
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
|
2018-11-06 21:35:33 +00:00
|
|
|
Arsse::$user = $this->createMock(User::class);
|
|
|
|
Arsse::$user->method("list")->willReturn($list);
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->assertConsole($cmd, $exitStatus, $output);
|
2018-11-06 17:32:28 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideUserList(): iterable {
|
2018-11-06 17:32:28 +00:00
|
|
|
$list = ["john.doe@example.com", "jane.doe@example.com"];
|
|
|
|
$str = implode(PHP_EOL, $list);
|
|
|
|
return [
|
|
|
|
["arsse.php user list", $list, 0, $str],
|
|
|
|
["arsse.php user", $list, 0, $str],
|
|
|
|
["arsse.php user list", [], 0, ""],
|
|
|
|
["arsse.php user", [], 0, ""],
|
|
|
|
];
|
|
|
|
}
|
2018-11-06 21:35:33 +00:00
|
|
|
|
|
|
|
/** @dataProvider provideUserAdditions */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testAddAUser(string $cmd, int $exitStatus, string $output): void {
|
2018-12-08 00:21:44 +00:00
|
|
|
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
|
2018-11-06 21:35:33 +00:00
|
|
|
Arsse::$user = $this->createMock(User::class);
|
|
|
|
Arsse::$user->method("add")->will($this->returnCallback(function($user, $pass = null) {
|
|
|
|
switch ($user) {
|
|
|
|
case "john.doe@example.com":
|
2020-11-15 21:24:26 +00:00
|
|
|
throw new \JKingWeb\Arsse\User\ExceptionConflict("alreadyExists");
|
2018-11-06 21:35:33 +00:00
|
|
|
case "jane.doe@example.com":
|
|
|
|
return is_null($pass) ? "random password" : $pass;
|
|
|
|
}
|
|
|
|
}));
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->assertConsole($cmd, $exitStatus, $output);
|
2018-11-06 21:35:33 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideUserAdditions(): iterable {
|
2018-11-06 21:35:33 +00:00
|
|
|
return [
|
|
|
|
["arsse.php user add john.doe@example.com", 10403, ""],
|
|
|
|
["arsse.php user add jane.doe@example.com", 0, "random password"],
|
|
|
|
["arsse.php user add jane.doe@example.com superman", 0, ""],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2021-02-10 16:24:01 +00:00
|
|
|
public function testAddAUserAsAdministrator(): void {
|
|
|
|
Arsse::$user = $this->createMock(User::class);
|
|
|
|
Arsse::$user->method("add")->willReturn("random password");
|
|
|
|
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("propertiesSet")->with("jane.doe@example.com", ['admin' => true]);
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->assertConsole("arsse.php user add jane.doe@example.com --admin", 0, "random password");
|
2021-02-10 16:24:01 +00:00
|
|
|
}
|
|
|
|
|
2018-11-06 21:35:33 +00:00
|
|
|
/** @dataProvider provideUserAuthentication */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testAuthenticateAUser(string $cmd, int $exitStatus, string $output): void {
|
2018-12-08 00:21:44 +00:00
|
|
|
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
|
2018-11-06 21:35:33 +00:00
|
|
|
Arsse::$user = $this->createMock(User::class);
|
|
|
|
Arsse::$user->method("auth")->will($this->returnCallback(function($user, $pass) {
|
2020-03-01 20:16:50 +00:00
|
|
|
return
|
2019-01-11 15:38:06 +00:00
|
|
|
($user === "john.doe@example.com" && $pass === "secret") ||
|
|
|
|
($user === "jane.doe@example.com" && $pass === "superman")
|
2020-03-01 20:16:50 +00:00
|
|
|
;
|
2018-11-06 21:35:33 +00:00
|
|
|
}));
|
2021-02-27 20:24:02 +00:00
|
|
|
$fever = $this->mock(FeverUser::class);
|
|
|
|
$fever->authenticate->returns(false);
|
|
|
|
$fever->authenticate->with("john.doe@example.com", "ashalla")->returns(true);
|
|
|
|
$fever->authenticate->with("jane.doe@example.com", "thx1138")->returns(true);
|
|
|
|
$this->objMock->get->with(FeverUser::class)->returns($fever->get());
|
|
|
|
$this->assertConsole($cmd, $exitStatus, $output);
|
2018-11-06 21:35:33 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideUserAuthentication(): iterable {
|
2018-11-06 21:35:33 +00:00
|
|
|
$l = new \JKingWeb\Arsse\Lang;
|
2019-03-25 14:45:05 +00:00
|
|
|
$success = $l("CLI.Auth.Success");
|
|
|
|
$failure = $l("CLI.Auth.Failure");
|
2018-11-06 21:35:33 +00:00
|
|
|
return [
|
2019-03-25 14:45:05 +00:00
|
|
|
["arsse.php user auth john.doe@example.com secret", 0, $success],
|
|
|
|
["arsse.php user auth john.doe@example.com superman", 1, $failure],
|
|
|
|
["arsse.php user auth jane.doe@example.com secret", 1, $failure],
|
|
|
|
["arsse.php user auth jane.doe@example.com superman", 0, $success],
|
|
|
|
["arsse.php user auth john.doe@example.com ashalla --fever", 0, $success],
|
|
|
|
["arsse.php user auth john.doe@example.com thx1138 --fever", 1, $failure],
|
|
|
|
["arsse.php user auth --fever jane.doe@example.com ashalla", 1, $failure],
|
|
|
|
["arsse.php user auth --fever jane.doe@example.com thx1138", 0, $success],
|
2018-11-06 21:35:33 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @dataProvider provideUserRemovals */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testRemoveAUser(string $cmd, int $exitStatus, string $output): void {
|
2018-12-08 00:21:44 +00:00
|
|
|
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
|
2018-11-06 21:35:33 +00:00
|
|
|
Arsse::$user = $this->createMock(User::class);
|
|
|
|
Arsse::$user->method("remove")->will($this->returnCallback(function($user) {
|
2019-01-11 15:38:06 +00:00
|
|
|
if ($user === "john.doe@example.com") {
|
2018-11-06 21:35:33 +00:00
|
|
|
return true;
|
|
|
|
}
|
2020-11-15 21:24:26 +00:00
|
|
|
throw new \JKingWeb\Arsse\User\ExceptionConflict("doesNotExist");
|
2018-11-06 21:35:33 +00:00
|
|
|
}));
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->assertConsole($cmd, $exitStatus, $output);
|
2018-11-06 21:35:33 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideUserRemovals(): iterable {
|
2018-11-06 21:35:33 +00:00
|
|
|
return [
|
|
|
|
["arsse.php user remove john.doe@example.com", 0, ""],
|
|
|
|
["arsse.php user remove jane.doe@example.com", 10402, ""],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @dataProvider provideUserPasswordChanges */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testChangeAUserPassword(string $cmd, int $exitStatus, string $output): void {
|
2019-03-25 19:03:41 +00:00
|
|
|
$passwordChange = function($user, $pass = null) {
|
2018-11-06 21:35:33 +00:00
|
|
|
switch ($user) {
|
|
|
|
case "jane.doe@example.com":
|
2020-11-15 21:24:26 +00:00
|
|
|
throw new \JKingWeb\Arsse\User\ExceptionConflict("doesNotExist");
|
2018-11-06 21:35:33 +00:00
|
|
|
case "john.doe@example.com":
|
|
|
|
return is_null($pass) ? "random password" : $pass;
|
|
|
|
}
|
2019-03-25 19:03:41 +00:00
|
|
|
};
|
|
|
|
// 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->method("passwordSet")->will($this->returnCallback($passwordChange));
|
2021-02-27 20:24:02 +00:00
|
|
|
$fever = $this->mock(FeverUser::class);
|
|
|
|
$fever->register->does($passwordChange);
|
|
|
|
$this->objMock->get->with(FeverUser::class)->returns($fever->get());
|
|
|
|
$this->assertConsole($cmd, $exitStatus, $output);
|
2018-11-06 21:35:33 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideUserPasswordChanges(): iterable {
|
2018-11-06 21:35:33 +00:00
|
|
|
return [
|
2019-03-25 19:03:41 +00:00
|
|
|
["arsse.php user set-pass john.doe@example.com", 0, "random password"],
|
|
|
|
["arsse.php user set-pass john.doe@example.com superman", 0, ""],
|
|
|
|
["arsse.php user set-pass jane.doe@example.com", 10402, ""],
|
|
|
|
["arsse.php user set-pass john.doe@example.com --fever", 0, "random password"],
|
|
|
|
["arsse.php user set-pass --fever john.doe@example.com superman", 0, ""],
|
|
|
|
["arsse.php user set-pass jane.doe@example.com --fever", 10402, ""],
|
2018-11-06 21:35:33 +00:00
|
|
|
];
|
|
|
|
}
|
2019-03-25 14:45:05 +00:00
|
|
|
|
2019-03-25 19:03:41 +00:00
|
|
|
/** @dataProvider provideUserPasswordClearings */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testClearAUserPassword(string $cmd, int $exitStatus, string $output): void {
|
2019-03-25 19:03:41 +00:00
|
|
|
$passwordClear = function($user) {
|
|
|
|
switch ($user) {
|
|
|
|
case "jane.doe@example.com":
|
2020-11-15 21:24:26 +00:00
|
|
|
throw new \JKingWeb\Arsse\User\ExceptionConflict("doesNotExist");
|
2019-03-25 19:03:41 +00:00
|
|
|
case "john.doe@example.com":
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
|
|
|
|
Arsse::$user = $this->createMock(User::class);
|
2019-03-25 21:07:28 +00:00
|
|
|
Arsse::$user->method("passwordUnset")->will($this->returnCallback($passwordClear));
|
2021-02-27 20:24:02 +00:00
|
|
|
$fever = $this->mock(FeverUser::class);
|
|
|
|
$fever->unregister->does($passwordClear);
|
|
|
|
$this->objMock->get->with(FeverUser::class)->returns($fever->get());
|
|
|
|
$this->assertConsole($cmd, $exitStatus, $output);
|
2019-03-25 19:03:41 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideUserPasswordClearings(): iterable {
|
2019-03-25 19:03:41 +00:00
|
|
|
return [
|
|
|
|
["arsse.php user unset-pass john.doe@example.com", 0, ""],
|
|
|
|
["arsse.php user unset-pass jane.doe@example.com", 10402, ""],
|
|
|
|
["arsse.php user unset-pass john.doe@example.com --fever", 0, ""],
|
|
|
|
["arsse.php user unset-pass jane.doe@example.com --fever", 10402, ""],
|
|
|
|
];
|
2019-03-25 14:45:05 +00:00
|
|
|
}
|
2019-04-01 21:24:19 +00:00
|
|
|
|
|
|
|
/** @dataProvider provideOpmlExports */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testExportToOpml(string $cmd, int $exitStatus, string $file, string $user, bool $flat): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
$opml = $this->mock(OPML::class);
|
|
|
|
$opml->exportFile->with("php://output", $user, $flat)->returns(true);
|
|
|
|
$opml->exportFile->with("good.opml", $user, $flat)->returns(true);
|
|
|
|
$opml->exportFile->with("bad.opml", $user, $flat)->throws(new \JKingWeb\Arsse\ImportExport\Exception("fileUnwritable"));
|
|
|
|
$this->objMock->get->with(OPML::class)->returns($opml->get());
|
|
|
|
$this->assertConsole($cmd, $exitStatus);
|
|
|
|
$this->cli->loadConf->called();
|
|
|
|
$opml->exportFile->calledWith($file, $user, $flat);
|
2019-04-01 21:24:19 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideOpmlExports(): iterable {
|
2019-04-01 21:24:19 +00:00
|
|
|
return [
|
|
|
|
["arsse.php export john.doe@example.com", 0, "php://output", "john.doe@example.com", false],
|
|
|
|
["arsse.php export john.doe@example.com -", 0, "php://output", "john.doe@example.com", false],
|
|
|
|
["arsse.php export john.doe@example.com good.opml", 0, "good.opml", "john.doe@example.com", false],
|
|
|
|
["arsse.php export john.doe@example.com bad.opml", 10604, "bad.opml", "john.doe@example.com", false],
|
|
|
|
["arsse.php export john.doe@example.com --flat", 0, "php://output", "john.doe@example.com", true],
|
|
|
|
["arsse.php export john.doe@example.com - --flat", 0, "php://output", "john.doe@example.com", true],
|
|
|
|
["arsse.php export --flat john.doe@example.com good.opml", 0, "good.opml", "john.doe@example.com", true],
|
|
|
|
["arsse.php export john.doe@example.com bad.opml --flat", 10604, "bad.opml", "john.doe@example.com", true],
|
|
|
|
["arsse.php export jane.doe@example.com", 0, "php://output", "jane.doe@example.com", false],
|
|
|
|
["arsse.php export jane.doe@example.com -", 0, "php://output", "jane.doe@example.com", false],
|
|
|
|
["arsse.php export jane.doe@example.com good.opml", 0, "good.opml", "jane.doe@example.com", false],
|
|
|
|
["arsse.php export jane.doe@example.com bad.opml", 10604, "bad.opml", "jane.doe@example.com", false],
|
|
|
|
["arsse.php export jane.doe@example.com --flat", 0, "php://output", "jane.doe@example.com", true],
|
|
|
|
["arsse.php export jane.doe@example.com - --flat", 0, "php://output", "jane.doe@example.com", true],
|
|
|
|
["arsse.php export --flat jane.doe@example.com good.opml", 0, "good.opml", "jane.doe@example.com", true],
|
|
|
|
["arsse.php export jane.doe@example.com bad.opml --flat", 10604, "bad.opml", "jane.doe@example.com", true],
|
2019-07-25 19:45:18 +00:00
|
|
|
["arsse.php export john.doe@example.com -f", 0, "php://output", "john.doe@example.com", true],
|
|
|
|
["arsse.php export john.doe@example.com - -f", 0, "php://output", "john.doe@example.com", true],
|
|
|
|
["arsse.php export -f john.doe@example.com good.opml", 0, "good.opml", "john.doe@example.com", true],
|
|
|
|
["arsse.php export john.doe@example.com bad.opml -f", 10604, "bad.opml", "john.doe@example.com", true],
|
|
|
|
["arsse.php export jane.doe@example.com -f", 0, "php://output", "jane.doe@example.com", true],
|
|
|
|
["arsse.php export jane.doe@example.com - -f", 0, "php://output", "jane.doe@example.com", true],
|
|
|
|
["arsse.php export -f jane.doe@example.com good.opml", 0, "good.opml", "jane.doe@example.com", true],
|
|
|
|
["arsse.php export jane.doe@example.com bad.opml -f", 10604, "bad.opml", "jane.doe@example.com", true],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @dataProvider provideOpmlImports */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testImportFromOpml(string $cmd, int $exitStatus, string $file, string $user, bool $flat, bool $replace): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
$opml = $this->mock(OPML::class);
|
|
|
|
$opml->importFile->with("php://input", $user, $flat, $replace)->returns(true);
|
|
|
|
$opml->importFile->with("good.opml", $user, $flat, $replace)->returns(true);
|
|
|
|
$opml->importFile->with("bad.opml", $user, $flat, $replace)->throws(new \JKingWeb\Arsse\ImportExport\Exception("fileUnreadable"));
|
|
|
|
$this->objMock->get->with(OPML::class)->returns($opml->get());
|
|
|
|
$this->assertConsole($cmd, $exitStatus);
|
|
|
|
$this->cli->loadConf->called();
|
|
|
|
$opml->importFile->calledWith($file, $user, $flat, $replace);
|
2019-07-25 19:45:18 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideOpmlImports(): iterable {
|
2019-07-25 19:45:18 +00:00
|
|
|
return [
|
|
|
|
["arsse.php import john.doe@example.com", 0, "php://input", "john.doe@example.com", false, false],
|
|
|
|
["arsse.php import john.doe@example.com -", 0, "php://input", "john.doe@example.com", false, false],
|
|
|
|
["arsse.php import john.doe@example.com good.opml", 0, "good.opml", "john.doe@example.com", false, false],
|
|
|
|
["arsse.php import john.doe@example.com bad.opml", 10603, "bad.opml", "john.doe@example.com", false, false],
|
|
|
|
["arsse.php import john.doe@example.com --flat", 0, "php://input", "john.doe@example.com", true, false],
|
|
|
|
["arsse.php import john.doe@example.com - --flat", 0, "php://input", "john.doe@example.com", true, false],
|
|
|
|
["arsse.php import --flat john.doe@example.com good.opml", 0, "good.opml", "john.doe@example.com", true, false],
|
|
|
|
["arsse.php import john.doe@example.com bad.opml --flat", 10603, "bad.opml", "john.doe@example.com", true, false],
|
|
|
|
["arsse.php import jane.doe@example.com", 0, "php://input", "jane.doe@example.com", false, false],
|
|
|
|
["arsse.php import jane.doe@example.com -", 0, "php://input", "jane.doe@example.com", false, false],
|
|
|
|
["arsse.php import jane.doe@example.com good.opml", 0, "good.opml", "jane.doe@example.com", false, false],
|
|
|
|
["arsse.php import jane.doe@example.com bad.opml", 10603, "bad.opml", "jane.doe@example.com", false, false],
|
|
|
|
["arsse.php import jane.doe@example.com --flat", 0, "php://input", "jane.doe@example.com", true, false],
|
|
|
|
["arsse.php import jane.doe@example.com - --flat", 0, "php://input", "jane.doe@example.com", true, false],
|
|
|
|
["arsse.php import --flat jane.doe@example.com good.opml", 0, "good.opml", "jane.doe@example.com", true, false],
|
|
|
|
["arsse.php import jane.doe@example.com bad.opml --flat", 10603, "bad.opml", "jane.doe@example.com", true, false],
|
|
|
|
["arsse.php import john.doe@example.com --replace", 0, "php://input", "john.doe@example.com", false, true],
|
|
|
|
["arsse.php import john.doe@example.com - -r", 0, "php://input", "john.doe@example.com", false, true],
|
|
|
|
["arsse.php import --replace john.doe@example.com good.opml", 0, "good.opml", "john.doe@example.com", false, true],
|
|
|
|
["arsse.php import -r john.doe@example.com bad.opml", 10603, "bad.opml", "john.doe@example.com", false, true],
|
|
|
|
["arsse.php import --replace john.doe@example.com --flat", 0, "php://input", "john.doe@example.com", true, true],
|
|
|
|
["arsse.php import -r john.doe@example.com - --flat", 0, "php://input", "john.doe@example.com", true, true],
|
|
|
|
["arsse.php import --flat john.doe@example.com good.opml -r", 0, "good.opml", "john.doe@example.com", true, true],
|
|
|
|
["arsse.php import --replace john.doe@example.com bad.opml --flat", 10603, "bad.opml", "john.doe@example.com", true, true],
|
|
|
|
["arsse.php import jane.doe@example.com -r ", 0, "php://input", "jane.doe@example.com", false, true],
|
|
|
|
["arsse.php import jane.doe@example.com - --replace", 0, "php://input", "jane.doe@example.com", false, true],
|
|
|
|
["arsse.php import -r jane.doe@example.com good.opml", 0, "good.opml", "jane.doe@example.com", false, true],
|
|
|
|
["arsse.php import --replace jane.doe@example.com bad.opml", 10603, "bad.opml", "jane.doe@example.com", false, true],
|
|
|
|
["arsse.php import jane.doe@example.com --flat -r", 0, "php://input", "jane.doe@example.com", true, true],
|
|
|
|
["arsse.php import jane.doe@example.com - --flat --replace", 0, "php://input", "jane.doe@example.com", true, true],
|
|
|
|
["arsse.php import --flat jane.doe@example.com good.opml -r", 0, "good.opml", "jane.doe@example.com", true, true],
|
|
|
|
["arsse.php import jane.doe@example.com bad.opml --replace --flat", 10603, "bad.opml", "jane.doe@example.com", true, true],
|
2019-04-01 21:24:19 +00:00
|
|
|
];
|
|
|
|
}
|
2021-02-10 16:24:01 +00:00
|
|
|
|
|
|
|
public function testShowMetadataOfAUser(): void {
|
|
|
|
$data = [
|
|
|
|
'num' => 42,
|
|
|
|
'admin' => false,
|
|
|
|
'lang' => "en-ca",
|
|
|
|
'tz' => "America/Toronto",
|
|
|
|
'root_folder_name' => null,
|
|
|
|
'sort_asc' => true,
|
|
|
|
'theme' => null,
|
|
|
|
'page_size' => 50,
|
|
|
|
'shortcuts' => true,
|
|
|
|
'gestures' => null,
|
|
|
|
'reading_time' => false,
|
|
|
|
'stylesheet' => "body {color:gray}",
|
|
|
|
];
|
|
|
|
$exp = implode(\PHP_EOL, [
|
|
|
|
"num 42",
|
|
|
|
"admin false",
|
|
|
|
"lang 'en-ca'",
|
|
|
|
"tz 'America/Toronto'",
|
|
|
|
"root_folder_name NULL",
|
|
|
|
"sort_asc true",
|
|
|
|
"theme NULL",
|
|
|
|
"page_size 50",
|
|
|
|
"shortcuts true",
|
|
|
|
"gestures NULL",
|
|
|
|
"reading_time false",
|
|
|
|
"stylesheet 'body {color:gray}'",
|
|
|
|
]);
|
|
|
|
Arsse::$user = $this->createMock(User::class);
|
|
|
|
Arsse::$user->method("propertiesGet")->willReturn($data);
|
|
|
|
Arsse::$user->expects($this->once())->method("propertiesGet")->with("john.doe@example.com", true);
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->assertConsole("arsse.php user show john.doe@example.com", 0, $exp);
|
2021-02-10 16:24:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @dataProvider provideMetadataChanges */
|
|
|
|
public function testSetMetadataOfAUser(string $cmd, string $user, array $in, array $out, int $exp): void {
|
|
|
|
Arsse::$user = $this->createMock(User::class);
|
|
|
|
Arsse::$user->method("propertiesSet")->willReturn($out);
|
|
|
|
Arsse::$user->expects($this->once())->method("propertiesSet")->with($user, $in);
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->assertConsole($cmd, $exp, "");
|
2021-02-10 16:24:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function provideMetadataChanges(): iterable {
|
|
|
|
return [
|
|
|
|
["arsse.php user set john admin true", "john", ['admin' => "true"], ['admin' => "true"], 0],
|
|
|
|
["arsse.php user set john bogus 1", "john", ['bogus' => "1"], [], 1],
|
|
|
|
["arsse.php user unset john admin", "john", ['admin' => null], ['admin' => null], 0],
|
|
|
|
["arsse.php user unset john bogus", "john", ['bogus' => null], [], 1],
|
|
|
|
];
|
|
|
|
}
|
2021-02-11 02:40:51 +00:00
|
|
|
|
|
|
|
public function testListTokens(): void {
|
|
|
|
$data = [
|
|
|
|
['label' => 'Ook', 'id' => "TOKEN 1"],
|
|
|
|
['label' => 'Eek', 'id' => "TOKEN 2"],
|
|
|
|
['label' => null, 'id' => "TOKEN 3"],
|
|
|
|
['label' => 'Ack', 'id' => "TOKEN 4"],
|
|
|
|
];
|
|
|
|
$exp = implode(\PHP_EOL, [
|
|
|
|
"TOKEN 3 ",
|
|
|
|
"TOKEN 4 Ack",
|
|
|
|
"TOKEN 2 Eek",
|
|
|
|
"TOKEN 1 Ook",
|
|
|
|
]);
|
2021-02-27 20:24:02 +00:00
|
|
|
$t = $this->mock(MinifluxToken::class);
|
|
|
|
$t->tokenList->returns($data);
|
|
|
|
$this->objMock->get->with(MinifluxToken::class)->returns($t->get());
|
|
|
|
$this->assertConsole("arsse.php token list john", 0, $exp);
|
|
|
|
$t->tokenList->calledWith("john");
|
2021-02-11 02:40:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testCreateToken(): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
$t = $this->mock(MinifluxToken::class);
|
|
|
|
$t->tokenGenerate->returns("RANDOM TOKEN");
|
|
|
|
$this->objMock->get->with(MinifluxToken::class)->returns($t->get());
|
|
|
|
$this->assertConsole("arse.php token create jane", 0, "RANDOM TOKEN");
|
|
|
|
$t->tokenGenerate->calledWith("jane", null);
|
2021-02-11 02:40:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testCreateTokenWithLabel(): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
$t = $this->mock(MinifluxToken::class);
|
|
|
|
$t->tokenGenerate->returns("RANDOM TOKEN");
|
|
|
|
$this->objMock->get->with(MinifluxToken::class)->returns($t->get());
|
|
|
|
$this->assertConsole("arse.php token create jane Ook", 0, "RANDOM TOKEN");
|
|
|
|
$t->tokenGenerate->calledWith("jane", "Ook");
|
2021-02-11 02:40:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testRevokeAToken(): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->dbMock->tokenRevoke->returns(true);
|
|
|
|
$this->assertConsole("arse.php token revoke jane TOKEN_ID", 0);
|
|
|
|
$this->dbMock->tokenRevoke->calledWith("jane", "miniflux.login", "TOKEN_ID");
|
2021-02-11 02:40:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testRevokeAllTokens(): void {
|
2021-02-27 20:24:02 +00:00
|
|
|
$this->dbMock->tokenRevoke->returns(true);
|
|
|
|
$this->assertConsole("arse.php token revoke jane", 0);
|
|
|
|
$this->dbMock->tokenRevoke->calledWith("jane", "miniflux.login", null);
|
2021-02-11 02:40:51 +00:00
|
|
|
}
|
2018-11-06 17:32:28 +00:00
|
|
|
}
|