diff --git a/lib/Database.php b/lib/Database.php index b9717e6..43eaae8 100644 --- a/lib/Database.php +++ b/lib/Database.php @@ -362,7 +362,7 @@ class Database { // if a parent is specified, make sure it exists and belongs to the user; get its root (first-level) folder if it's a nested folder $p = $this->db->prepare( "WITH RECURSIVE folders(id) as (SELECT id from arsse_folders where owner is ? and id is ? union select arsse_folders.id from arsse_folders join folders on arsse_folders.parent=folders.id) ". - "SELECT id,(id not in (select id from folders)) as valid from arsse_folders where owner is ? and id is ?", + "SELECT id,(id not in (select id from folders)) as valid from arsse_folders where owner is ? and id is ?", "str", "int", "str", "int")->run($user, $id, $user, $parent)->getRow(); if(!$p) { throw new Db\ExceptionInput("idMissing", ["action" => __FUNCTION__, "field" => "parent", 'id' => $parent]); diff --git a/lib/Db/AbstractStatement.php b/lib/Db/AbstractStatement.php index 93322b9..28d02ba 100644 --- a/lib/Db/AbstractStatement.php +++ b/lib/Db/AbstractStatement.php @@ -5,7 +5,7 @@ namespace JKingWeb\Arsse\Db; abstract class AbstractStatement implements Statement { abstract function runArray(array $values): Result; - abstract static function dateFormat(int $part = self::TS_BOTH): string; + abstract static function dateFormat(int $part = self::TS_BOTH): string; public function run(...$values): Result { return $this->runArray($values); @@ -30,41 +30,41 @@ abstract class AbstractStatement implements Statement { return true; } - protected function cast($v, string $t) { - switch($t) { - case "date": - return $this->formatDate($v, self::TS_DATE); - case "time": - return $this->formatDate($v, self::TS_TIME); - case "datetime": - return $this->formatDate($v, self::TS_BOTH); - case "null": - case "integer": - case "float": - case "binary": - case "string": - case "boolean": - if($t=="binary") $t = "string"; - $value = $v; - try{ - settype($value, $t); - } catch(\Throwable $e) { - // handle objects - $value = $v; - if($value instanceof \DateTimeInterface) { - $value = $value->getTimestamp(); - if($t=="string") $value = $this->formatDate($value, self::TS_BOTH); - settype($value, $t); - } else { - $value = null; - settype($value, $t); - } - } - return $value; - default: - throw new Exception("paramTypeUnknown", $type); - } - } + protected function cast($v, string $t) { + switch($t) { + case "date": + return $this->formatDate($v, self::TS_DATE); + case "time": + return $this->formatDate($v, self::TS_TIME); + case "datetime": + return $this->formatDate($v, self::TS_BOTH); + case "null": + case "integer": + case "float": + case "binary": + case "string": + case "boolean": + if($t=="binary") $t = "string"; + $value = $v; + try{ + settype($value, $t); + } catch(\Throwable $e) { + // handle objects + $value = $v; + if($value instanceof \DateTimeInterface) { + $value = $value->getTimestamp(); + if($t=="string") $value = $this->formatDate($value, self::TS_BOTH); + settype($value, $t); + } else { + $value = null; + settype($value, $t); + } + } + return $value; + default: + throw new Exception("paramTypeUnknown", $type); + } + } protected function formatDate($date, int $part = self::TS_BOTH) { // Force UTC. @@ -82,7 +82,7 @@ abstract class AbstractStatement implements Statement { $time = strtotime($date); if($time===false) return null; } else if (is_bool($date)) { - return null; + return null; } else { $time = (int) $date; } diff --git a/lib/Db/Result.php b/lib/Db/Result.php index dca03e0..012041b 100644 --- a/lib/Db/Result.php +++ b/lib/Db/Result.php @@ -12,7 +12,7 @@ interface Result extends \Iterator { function getRow(); function getAll(): array; function getValue(); - + function changes(); function lastId(); } \ No newline at end of file diff --git a/lib/Db/SQLite3/Statement.php b/lib/Db/SQLite3/Statement.php index 3f14df9..21f8a22 100644 --- a/lib/Db/SQLite3/Statement.php +++ b/lib/Db/SQLite3/Statement.php @@ -12,17 +12,17 @@ class Statement extends \JKingWeb\Arsse\Db\AbstractStatement { const SQLITE_CONSTRAINT = 19; const SQLITE_MISMATCH = 20; const BINDINGS = [ - "null" => \SQLITE3_NULL, - "integer" => \SQLITE3_INTEGER, - "float" => \SQLITE3_FLOAT, - "date" => \SQLITE3_TEXT, - "time" => \SQLITE3_TEXT, - "datetime" => \SQLITE3_TEXT, - "binary" => \SQLITE3_BLOB, - "string" => \SQLITE3_TEXT, - "boolean" => \SQLITE3_INTEGER, + "null" => \SQLITE3_NULL, + "integer" => \SQLITE3_INTEGER, + "float" => \SQLITE3_FLOAT, + "date" => \SQLITE3_TEXT, + "time" => \SQLITE3_TEXT, + "datetime" => \SQLITE3_TEXT, + "binary" => \SQLITE3_BLOB, + "string" => \SQLITE3_TEXT, + "boolean" => \SQLITE3_INTEGER, ]; - + protected $db; protected $st; protected $types; diff --git a/lib/Db/Statement.php b/lib/Db/Statement.php index 7cc3c3d..3a74d54 100644 --- a/lib/Db/Statement.php +++ b/lib/Db/Statement.php @@ -6,32 +6,32 @@ interface Statement { const TS_TIME = -1; const TS_DATE = 0; const TS_BOTH = 1; - const TYPES = [ - "null" => "null", - "nil" => "null", - "int" => "integer", - "integer" => "integer", - "float" => "float", - "double" => "float", - "real" => "float", - "numeric" => "float", - "date" => "date", - "time" => "time", - "datetime" => "datetime", - "timestamp" => "datetime", - "blob" => "binary", - "bin" => "binary", - "binary" => "binary", - "text" => "string", - "string" => "string", - "str" => "string", - "bool" => "boolean", - "boolean" => "boolean", - "bit" => "boolean", - ]; + const TYPES = [ + "null" => "null", + "nil" => "null", + "int" => "integer", + "integer" => "integer", + "float" => "float", + "double" => "float", + "real" => "float", + "numeric" => "float", + "date" => "date", + "time" => "time", + "datetime" => "datetime", + "timestamp" => "datetime", + "blob" => "binary", + "bin" => "binary", + "binary" => "binary", + "text" => "string", + "string" => "string", + "str" => "string", + "bool" => "boolean", + "boolean" => "boolean", + "bit" => "boolean", + ]; static function dateFormat(int $part = self::TS_BOTH): string; - + function run(...$values): Result; function runArray(array $values): Result; function rebind(...$bindings): bool; diff --git a/lib/REST.php b/lib/REST.php index 6c9b865..e45eb30 100644 --- a/lib/REST.php +++ b/lib/REST.php @@ -24,7 +24,7 @@ class REST { // Fever https://feedafever.com/api // NewsBlur http://www.newsblur.com/api ]; - + function __construct() { } diff --git a/lib/REST/AbstractHandler.php b/lib/REST/AbstractHandler.php index d218ffc..7a93521 100644 --- a/lib/REST/AbstractHandler.php +++ b/lib/REST/AbstractHandler.php @@ -3,6 +3,6 @@ declare(strict_types=1); namespace JKingWeb\Arsse\REST; abstract class AbstractHandler implements Handler { - abstract function __construct(); - abstract function dispatch(Request $req): Response; + abstract function __construct(); + abstract function dispatch(Request $req): Response; } \ No newline at end of file diff --git a/lib/REST/Handler.php b/lib/REST/Handler.php index a07bcd1..6ac7290 100644 --- a/lib/REST/Handler.php +++ b/lib/REST/Handler.php @@ -4,5 +4,5 @@ namespace JKingWeb\Arsse\REST; interface Handler { function __construct(); - function dispatch(Request $req): Response; + function dispatch(Request $req): Response; } \ No newline at end of file diff --git a/lib/REST/NextCloudNews/V1_2.php b/lib/REST/NextCloudNews/V1_2.php index fd5dc7c..19d17ff 100644 --- a/lib/REST/NextCloudNews/V1_2.php +++ b/lib/REST/NextCloudNews/V1_2.php @@ -29,7 +29,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { $data = []; } // FIXME: Do query parameters take precedence in NextCloud? Is there a conflict error when values differ? - $data = array_merge($data, $req->query); + $data = array_merge($data, $req->query); // match the path if(preg_match("<^/(items|folders|feeds|cleanup|version|status|user)(?:/([^/]+))?(?:/([^/]+))?(?:/([^/]+))?/?$>", $req->path, $url)) { // clean up the path diff --git a/lib/REST/NextCloudNews/Versions.php b/lib/REST/NextCloudNews/Versions.php index c561d59..5fcbec3 100644 --- a/lib/REST/NextCloudNews/Versions.php +++ b/lib/REST/NextCloudNews/Versions.php @@ -4,25 +4,25 @@ namespace JKingWeb\Arsse\REST\NextCloudNews; use JKingWeb\Arsse\REST\Response; class Versions extends \JKingWeb\Arsse\REST\AbstractHandler { - function __construct() { - } + function __construct() { + } - function dispatch(\JKingWeb\Arsse\REST\Request $req): \JKingWeb\Arsse\REST\Response { - // if a method other than GET was used, this is an error - if($req->method != "GET") { - return new Response(405); - } - if(preg_match("<^/?$>",$req->path)) { - // if the request path is an empty string or just a slash, return the supported versions - $out = [ - 'apiLevels' => [ - 'v1-2', - ] - ]; - return new Response(200, $out); - } else { - // if the URL path was anything else, the client is probably trying a version we don't support - return new Response(404); - } - } + function dispatch(\JKingWeb\Arsse\REST\Request $req): \JKingWeb\Arsse\REST\Response { + // if a method other than GET was used, this is an error + if($req->method != "GET") { + return new Response(405); + } + if(preg_match("<^/?$>",$req->path)) { + // if the request path is an empty string or just a slash, return the supported versions + $out = [ + 'apiLevels' => [ + 'v1-2', + ] + ]; + return new Response(200, $out); + } else { + // if the URL path was anything else, the client is probably trying a version we don't support + return new Response(404); + } + } } \ No newline at end of file diff --git a/lib/REST/Request.php b/lib/REST/Request.php index a8848cd..0dada44 100644 --- a/lib/REST/Request.php +++ b/lib/REST/Request.php @@ -3,59 +3,59 @@ declare(strict_types=1); namespace JKingWeb\Arsse\REST; class Request { - public $method = "GET"; - public $url = ""; - public $path =""; - public $query = ""; - public $type =""; - public $body = ""; + public $method = "GET"; + public $url = ""; + public $path =""; + public $query = ""; + public $type =""; + public $body = ""; - function __construct(string $method = null, string $url = null, string $body = null, string $contentType = null) { - if(is_null($method)) $method = $_SERVER['REQUEST_METHOD']; - if(is_null($url)) $url = $_SERVER['REQUEST_URI']; - if(is_null($body)) $body = file_get_contents("php://input"); - if(is_null($contentType)) { - if(isset($_SERVER['HTTP_CONTENT_TYPE'])) { - $contentType = $_SERVER['HTTP_CONTENT_TYPE']; - } else { - $contentType = ""; - } - } - $this->method = strtoupper($method); - $this->url = $url; - $this->body = $body; - $this->type = $contentType; - $this->refreshURL(); - } + function __construct(string $method = null, string $url = null, string $body = null, string $contentType = null) { + if(is_null($method)) $method = $_SERVER['REQUEST_METHOD']; + if(is_null($url)) $url = $_SERVER['REQUEST_URI']; + if(is_null($body)) $body = file_get_contents("php://input"); + if(is_null($contentType)) { + if(isset($_SERVER['HTTP_CONTENT_TYPE'])) { + $contentType = $_SERVER['HTTP_CONTENT_TYPE']; + } else { + $contentType = ""; + } + } + $this->method = strtoupper($method); + $this->url = $url; + $this->body = $body; + $this->type = $contentType; + $this->refreshURL(); + } - public function refreshURL() { - $url = $this->parseURL($this->url); - $this->path = $url['path']; - $this->query = $url['query']; - } + public function refreshURL() { + $url = $this->parseURL($this->url); + $this->path = $url['path']; + $this->query = $url['query']; + } - protected function parseURL(string $url): array { - // split the query string from the path - $parts = explode("?", $url); - $out = ['path' => $parts[0], 'query' => []]; - // if there is a query string, parse it - if(isset($parts[1])) { - // split along & to get key-value pairs - $query = explode("&", $parts[1]); - for($a = 0; $a < sizeof($query); $a++) { - // split each pair, into no more than two parts - $data = explode("=", $query[$a], 2); - // decode the key - $key = rawurldecode($data[0]); - // decode the value if there is one - $value = ""; - if(isset($data[1])) { - $value = rawurldecode($data[1]); - } - // add the pair to the query output, overwriting earlier values for the same key, is present - $out['query'][$key] = $value; - } - } - return $out; - } + protected function parseURL(string $url): array { + // split the query string from the path + $parts = explode("?", $url); + $out = ['path' => $parts[0], 'query' => []]; + // if there is a query string, parse it + if(isset($parts[1])) { + // split along & to get key-value pairs + $query = explode("&", $parts[1]); + for($a = 0; $a < sizeof($query); $a++) { + // split each pair, into no more than two parts + $data = explode("=", $query[$a], 2); + // decode the key + $key = rawurldecode($data[0]); + // decode the value if there is one + $value = ""; + if(isset($data[1])) { + $value = rawurldecode($data[1]); + } + // add the pair to the query output, overwriting earlier values for the same key, is present + $out['query'][$key] = $value; + } + } + return $out; + } } \ No newline at end of file diff --git a/lib/REST/Response.php b/lib/REST/Response.php index a30026f..bfa90f5 100644 --- a/lib/REST/Response.php +++ b/lib/REST/Response.php @@ -3,20 +3,20 @@ declare(strict_types=1); namespace JKingWeb\Arsse\REST; class Response { - const T_JSON = "application/json"; - const T_XML = "application/xml"; - const T_TEXT = "text/plain"; + const T_JSON = "application/json"; + const T_XML = "application/xml"; + const T_TEXT = "text/plain"; - public $code; - public $payload; - public $type; - public $fields; + public $code; + public $payload; + public $type; + public $fields; - - function __construct(int $code, $payload = null, string $type = self::T_JSON, array $extraFields = []) { - $this->code = $code; - $this->payload = $payload; - $this->type = $type; - $this->fields = $extraFields; - } + + function __construct(int $code, $payload = null, string $type = self::T_JSON, array $extraFields = []) { + $this->code = $code; + $this->payload = $payload; + $this->type = $type; + $this->fields = $extraFields; + } } \ No newline at end of file diff --git a/lib/User.php b/lib/User.php index 9b9a45a..20c347e 100644 --- a/lib/User.php +++ b/lib/User.php @@ -9,7 +9,7 @@ class User { protected $authz = true; protected $authzSupported = 0; protected $actor = []; - + static public function listDrivers(): array { $sep = \DIRECTORY_SEPARATOR; $path = __DIR__.$sep."User".$sep; @@ -75,7 +75,7 @@ class User { if(!in_array($affectedRights,[User\Driver::RIGHTS_NONE,User\Driver::RIGHTS_DOMAIN_MANAGER,User\Driver::RIGHTS_DOMAIN_ADMIN])) return false; return true; } - + public function credentials(): array { if(Data::$conf->userAuthPreferHTTP) { return $this->credentialsHTTP(); @@ -142,7 +142,7 @@ class User { public function driverFunctions(string $function = null) { return $this->u->driverFunctions($function); } - + public function list(string $domain = null): array { $func = "userList"; switch($this->u->driverFunctions($func)) { @@ -166,7 +166,7 @@ class User { $this->authz = $setting; return $setting; } - + public function exists(string $user): bool { $func = "userExists"; switch($this->u->driverFunctions($func)) { @@ -321,7 +321,7 @@ class User { return User\Driver::RIGHTS_NONE; } } - + public function rightsSet(string $user, int $level): bool { $func = "userRightsSet"; switch($this->u->driverFunctions($func)) { @@ -346,7 +346,7 @@ class User { throw new User\ExceptionNotImplemented("notImplemented", ["action" => $func, "user" => $user]); } } - + // FIXME: stubs public function challenge(): bool {throw new User\Exception("authFailed");} public function challengeForm(): bool {throw new User\Exception("authFailed");} diff --git a/lib/User/Internal/InternalFunctions.php b/lib/User/Internal/InternalFunctions.php index ef5f2ee..8ade735 100644 --- a/lib/User/Internal/InternalFunctions.php +++ b/lib/User/Internal/InternalFunctions.php @@ -3,7 +3,7 @@ declare(strict_types=1); namespace JKingWeb\Arsse\User\Internal; use JKingWeb\Arsse\Data; -trait InternalFunctions { +trait InternalFunctions { protected $actor = []; public function __construct() { @@ -32,7 +32,7 @@ trait InternalFunctions { function userList(string $domain = null): array { return $this->db->userList($domain); } - + function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string { return $this->db->userPasswordSet($user, $newPassword); } @@ -48,8 +48,8 @@ trait InternalFunctions { function userRightsGet(string $user): int { return $this->db->userRightsGet($user); } - + function userRightsSet(string $user, int $level): bool { return $this->db->userRightsSet($user, $level); - } + } } \ No newline at end of file diff --git a/tests/Conf/TestConf.php b/tests/Conf/TestConf.php index aafd35b..b53ad72 100644 --- a/tests/Conf/TestConf.php +++ b/tests/Conf/TestConf.php @@ -6,7 +6,7 @@ use org\bovigo\vfs\vfsStream; class TestConf extends \PHPUnit\Framework\TestCase { use Test\Tools; - + static $vfs; static $path; @@ -30,11 +30,11 @@ class TestConf extends \PHPUnit\Framework\TestCase { self::$vfs = null; $this->clearData(); } - + function testLoadDefaultValues() { $this->assertInstanceOf(Conf::class, new Conf()); } - + /** * @depends testLoadDefaultValues */ diff --git a/tests/Db/SQLite3/TestDbDriverSQLite3.php b/tests/Db/SQLite3/TestDbDriverSQLite3.php index 0e0300c..54047b9 100644 --- a/tests/Db/SQLite3/TestDbDriverSQLite3.php +++ b/tests/Db/SQLite3/TestDbDriverSQLite3.php @@ -7,279 +7,279 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase { use Test\Tools; protected $data; - protected $drv; + protected $drv; function setUp() { - $this->clearData(); - $conf = new Conf(); - $conf->dbDriver = Db\SQLite3\Driver::class; - $conf->dbSQLite3File = tempnam(sys_get_temp_dir(), 'ook'); - Data::$conf = $conf; - $this->drv = new Db\SQLite3\Driver(true); + $this->clearData(); + $conf = new Conf(); + $conf->dbDriver = Db\SQLite3\Driver::class; + $conf->dbSQLite3File = tempnam(sys_get_temp_dir(), 'ook'); + Data::$conf = $conf; + $this->drv = new Db\SQLite3\Driver(true); } function tearDown() { unset($this->drv); - unlink(Data::$conf->dbSQLite3File); - $this->clearData(); + unlink(Data::$conf->dbSQLite3File); + $this->clearData(); } - function testFetchDriverName() { - $class = Data::$conf->dbDriver; - $this->assertTrue(strlen($class::driverName()) > 0); - } - - function testExecAValidStatement() { - $this->assertTrue($this->drv->exec("CREATE TABLE test(id integer primary key)")); - } + function testFetchDriverName() { + $class = Data::$conf->dbDriver; + $this->assertTrue(strlen($class::driverName()) > 0); + } - function testExecAnInvalidStatement() { - $this->assertException("engineErrorGeneral", "Db"); - $this->drv->exec("And the meek shall inherit the earth..."); - } + function testExecAValidStatement() { + $this->assertTrue($this->drv->exec("CREATE TABLE test(id integer primary key)")); + } - function testExecMultipleStatements() { - $this->assertTrue($this->drv->exec("CREATE TABLE test(id integer primary key); INSERT INTO test(id) values(2112)")); - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $this->assertEquals(2112, $ch->querySingle("SELECT id from test")); - } + function testExecAnInvalidStatement() { + $this->assertException("engineErrorGeneral", "Db"); + $this->drv->exec("And the meek shall inherit the earth..."); + } - function testExecTimeout() { - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $ch->exec("BEGIN EXCLUSIVE TRANSACTION"); - $this->assertException("general", "Db", "ExceptionTimeout"); - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - } + function testExecMultipleStatements() { + $this->assertTrue($this->drv->exec("CREATE TABLE test(id integer primary key); INSERT INTO test(id) values(2112)")); + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $this->assertEquals(2112, $ch->querySingle("SELECT id from test")); + } - function testExecConstraintViolation() { - $this->drv->exec("CREATE TABLE test(id integer not null)"); - $this->assertException("constraintViolation", "Db", "ExceptionInput"); - $this->drv->exec("INSERT INTO test(id) values(null)"); - } + function testExecTimeout() { + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $ch->exec("BEGIN EXCLUSIVE TRANSACTION"); + $this->assertException("general", "Db", "ExceptionTimeout"); + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + } - function testExecTypeViolation() { - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - $this->assertException("typeViolation", "Db", "ExceptionInput"); - $this->drv->exec("INSERT INTO test(id) values('ook')"); - } + function testExecConstraintViolation() { + $this->drv->exec("CREATE TABLE test(id integer not null)"); + $this->assertException("constraintViolation", "Db", "ExceptionInput"); + $this->drv->exec("INSERT INTO test(id) values(null)"); + } - function testMakeAValidQuery() { - $this->assertInstanceOf(Db\SQLite3\Result::class, $this->drv->query("SELECT 1")); - } + function testExecTypeViolation() { + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + $this->assertException("typeViolation", "Db", "ExceptionInput"); + $this->drv->exec("INSERT INTO test(id) values('ook')"); + } - function testMakeAnInvalidQuery() { - $this->assertException("engineErrorGeneral", "Db"); - $this->drv->query("Apollo was astonished; Dionysus thought me mad"); - } + function testMakeAValidQuery() { + $this->assertInstanceOf(Db\SQLite3\Result::class, $this->drv->query("SELECT 1")); + } + + function testMakeAnInvalidQuery() { + $this->assertException("engineErrorGeneral", "Db"); + $this->drv->query("Apollo was astonished; Dionysus thought me mad"); + } - function testQueryTimeout() { - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $ch->exec("BEGIN EXCLUSIVE TRANSACTION"); - $this->assertException("general", "Db", "ExceptionTimeout"); - $this->drv->query("CREATE TABLE test(id integer primary key)"); - } + function testQueryTimeout() { + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $ch->exec("BEGIN EXCLUSIVE TRANSACTION"); + $this->assertException("general", "Db", "ExceptionTimeout"); + $this->drv->query("CREATE TABLE test(id integer primary key)"); + } - function testQueryConstraintViolation() { - $this->drv->exec("CREATE TABLE test(id integer not null)"); - $this->assertException("constraintViolation", "Db", "ExceptionInput"); - $this->drv->query("INSERT INTO test(id) values(null)"); - } + function testQueryConstraintViolation() { + $this->drv->exec("CREATE TABLE test(id integer not null)"); + $this->assertException("constraintViolation", "Db", "ExceptionInput"); + $this->drv->query("INSERT INTO test(id) values(null)"); + } - function testQueryTypeViolation() { - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - $this->assertException("typeViolation", "Db", "ExceptionInput"); - $this->drv->query("INSERT INTO test(id) values('ook')"); - } + function testQueryTypeViolation() { + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + $this->assertException("typeViolation", "Db", "ExceptionInput"); + $this->drv->query("INSERT INTO test(id) values('ook')"); + } - function testPrepareAValidQuery() { - $s = $this->drv->prepare("SELECT ?, ?", "int", "int"); - $this->assertInstanceOf(Db\SQLite3\Statement::class, $s); - } + function testPrepareAValidQuery() { + $s = $this->drv->prepare("SELECT ?, ?", "int", "int"); + $this->assertInstanceOf(Db\SQLite3\Statement::class, $s); + } - function testPrepareAnInvalidQuery() { - $this->assertException("engineErrorGeneral", "Db"); - $s = $this->drv->prepare("This is an invalid query", "int", "int"); - } + function testPrepareAnInvalidQuery() { + $this->assertException("engineErrorGeneral", "Db"); + $s = $this->drv->prepare("This is an invalid query", "int", "int"); + } - function testBeginTransaction() { - $select = "SELECT count(*) FROM test"; - $insert = "INSERT INTO test(id) values(null)"; - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->query($insert); - $this->assertEquals(2, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - } + function testBeginTransaction() { + $select = "SELECT count(*) FROM test"; + $insert = "INSERT INTO test(id) values(null)"; + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->query($insert); + $this->assertEquals(2, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + } - function testCommitTransaction() { - $select = "SELECT count(*) FROM test"; - $insert = "INSERT INTO test(id) values(null)"; - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->commit(); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(1, $ch->querySingle($select)); - } + function testCommitTransaction() { + $select = "SELECT count(*) FROM test"; + $insert = "INSERT INTO test(id) values(null)"; + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->commit(); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(1, $ch->querySingle($select)); + } - function testRollbackTransaction() { - $select = "SELECT count(*) FROM test"; - $insert = "INSERT INTO test(id) values(null)"; - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->rollback(); - $this->assertEquals(0, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - } + function testRollbackTransaction() { + $select = "SELECT count(*) FROM test"; + $insert = "INSERT INTO test(id) values(null)"; + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->rollback(); + $this->assertEquals(0, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + } - function testBeginChainedTransactions() { - $select = "SELECT count(*) FROM test"; - $insert = "INSERT INTO test(id) values(null)"; - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(2, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - } + function testBeginChainedTransactions() { + $select = "SELECT count(*) FROM test"; + $insert = "INSERT INTO test(id) values(null)"; + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(2, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + } - function testCommitChainedTransactions() { - $select = "SELECT count(*) FROM test"; - $insert = "INSERT INTO test(id) values(null)"; - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(2, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->commit(); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->commit(); - $this->assertEquals(2, $ch->querySingle($select)); - } + function testCommitChainedTransactions() { + $select = "SELECT count(*) FROM test"; + $insert = "INSERT INTO test(id) values(null)"; + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(2, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->commit(); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->commit(); + $this->assertEquals(2, $ch->querySingle($select)); + } - function testRollbackChainedTransactions() { - $select = "SELECT count(*) FROM test"; - $insert = "INSERT INTO test(id) values(null)"; - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(2, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->rollback(); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->rollback(); - $this->assertEquals(0, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - } + function testRollbackChainedTransactions() { + $select = "SELECT count(*) FROM test"; + $insert = "INSERT INTO test(id) values(null)"; + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(2, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->rollback(); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->rollback(); + $this->assertEquals(0, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + } - function testPartiallyRollbackChainedTransactions() { - $select = "SELECT count(*) FROM test"; - $insert = "INSERT INTO test(id) values(null)"; - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(2, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->rollback(); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->commit(); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(1, $ch->querySingle($select)); - } + function testPartiallyRollbackChainedTransactions() { + $select = "SELECT count(*) FROM test"; + $insert = "INSERT INTO test(id) values(null)"; + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(2, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->rollback(); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->commit(); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(1, $ch->querySingle($select)); + } - function testFullyRollbackChainedTransactions() { - $select = "SELECT count(*) FROM test"; - $insert = "INSERT INTO test(id) values(null)"; - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(2, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->rollback(true); - $this->assertEquals(0, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - } + function testFullyRollbackChainedTransactions() { + $select = "SELECT count(*) FROM test"; + $insert = "INSERT INTO test(id) values(null)"; + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(2, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->rollback(true); + $this->assertEquals(0, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + } - function testFullyCommitChainedTransactions() { - $select = "SELECT count(*) FROM test"; - $insert = "INSERT INTO test(id) values(null)"; - $ch = new \SQLite3(Data::$conf->dbSQLite3File); - $this->drv->exec("CREATE TABLE test(id integer primary key)"); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(1, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->begin(); - $this->drv->query($insert); - $this->assertEquals(2, $this->drv->query($select)->getValue()); - $this->assertEquals(0, $ch->querySingle($select)); - $this->drv->commit(true); - $this->assertEquals(2, $this->drv->query($select)->getValue()); - $this->assertEquals(2, $ch->querySingle($select)); - } + function testFullyCommitChainedTransactions() { + $select = "SELECT count(*) FROM test"; + $insert = "INSERT INTO test(id) values(null)"; + $ch = new \SQLite3(Data::$conf->dbSQLite3File); + $this->drv->exec("CREATE TABLE test(id integer primary key)"); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(1, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->begin(); + $this->drv->query($insert); + $this->assertEquals(2, $this->drv->query($select)->getValue()); + $this->assertEquals(0, $ch->querySingle($select)); + $this->drv->commit(true); + $this->assertEquals(2, $this->drv->query($select)->getValue()); + $this->assertEquals(2, $ch->querySingle($select)); + } - function testFetchSchemaVersion() { - $this->assertSame(0, $this->drv->schemaVersion()); - $this->drv->exec("PRAGMA user_version=1"); - $this->assertSame(1, $this->drv->schemaVersion()); - $this->drv->exec("PRAGMA user_version=2"); - $this->assertSame(2, $this->drv->schemaVersion()); + function testFetchSchemaVersion() { + $this->assertSame(0, $this->drv->schemaVersion()); + $this->drv->exec("PRAGMA user_version=1"); + $this->assertSame(1, $this->drv->schemaVersion()); + $this->drv->exec("PRAGMA user_version=2"); + $this->assertSame(2, $this->drv->schemaVersion()); - } + } - function testManipulateAdvisoryLock() { - $this->assertTrue($this->drv->unlock()); - $this->assertFalse($this->drv->isLocked()); - $this->assertTrue($this->drv->lock()); - $this->assertFalse($this->drv->isLocked()); - $this->drv->exec("CREATE TABLE arsse_settings(key primary key, value, type) without rowid; PRAGMA user_version=1"); - $this->assertTrue($this->drv->lock()); - $this->assertTrue($this->drv->isLocked()); - $this->assertFalse($this->drv->lock()); - $this->drv->exec("PRAGMA user_version=0"); - $this->assertFalse($this->drv->isLocked()); - $this->assertTrue($this->drv->lock()); - $this->assertFalse($this->drv->isLocked()); - $this->drv->exec("PRAGMA user_version=1"); - $this->assertTrue($this->drv->isLocked()); - $this->assertTrue($this->drv->unlock()); - $this->assertFalse($this->drv->isLocked()); - } + function testManipulateAdvisoryLock() { + $this->assertTrue($this->drv->unlock()); + $this->assertFalse($this->drv->isLocked()); + $this->assertTrue($this->drv->lock()); + $this->assertFalse($this->drv->isLocked()); + $this->drv->exec("CREATE TABLE arsse_settings(key primary key, value, type) without rowid; PRAGMA user_version=1"); + $this->assertTrue($this->drv->lock()); + $this->assertTrue($this->drv->isLocked()); + $this->assertFalse($this->drv->lock()); + $this->drv->exec("PRAGMA user_version=0"); + $this->assertFalse($this->drv->isLocked()); + $this->assertTrue($this->drv->lock()); + $this->assertFalse($this->drv->isLocked()); + $this->drv->exec("PRAGMA user_version=1"); + $this->assertTrue($this->drv->isLocked()); + $this->assertTrue($this->drv->unlock()); + $this->assertFalse($this->drv->isLocked()); + } } \ No newline at end of file diff --git a/tests/Db/SQLite3/TestDbStatementSQLite3.php b/tests/Db/SQLite3/TestDbStatementSQLite3.php index 09a24e8..77ea9aa 100644 --- a/tests/Db/SQLite3/TestDbStatementSQLite3.php +++ b/tests/Db/SQLite3/TestDbStatementSQLite3.php @@ -8,88 +8,88 @@ class TestDbStatementSQLite3 extends \PHPUnit\Framework\TestCase { use Test\Tools, Test\Db\BindingTests; protected $c; - static protected $imp = Db\SQLite3\Statement::class; + static protected $imp = Db\SQLite3\Statement::class; function setUp() { - date_default_timezone_set("UTC"); + date_default_timezone_set("UTC"); $c = new \SQLite3(":memory:"); $c->enableExceptions(true); $this->c = $c; } function tearDown() { - try {$this->s->close();} catch(\Exception $e) {} + try {$this->s->close();} catch(\Exception $e) {} $this->c->close(); unset($this->c); } - protected function checkBinding($input, array $expectations) { - $nativeStatement = $this->c->prepare("SELECT ? as value"); - $s = new self::$imp($this->c, $nativeStatement); - $types = array_unique(Statement::TYPES); - foreach($types as $type) { - $s->rebindArray([$type]); - $val = $s->runArray([$input])->getRow()['value']; - $this->assertSame($expectations[$type], $val, "Type $type failed comparison."); - } - } + protected function checkBinding($input, array $expectations) { + $nativeStatement = $this->c->prepare("SELECT ? as value"); + $s = new self::$imp($this->c, $nativeStatement); + $types = array_unique(Statement::TYPES); + foreach($types as $type) { + $s->rebindArray([$type]); + $val = $s->runArray([$input])->getRow()['value']; + $this->assertSame($expectations[$type], $val, "Type $type failed comparison."); + } + } - function testConstructStatement() { + function testConstructStatement() { $nativeStatement = $this->c->prepare("SELECT ? as value"); - $this->assertInstanceOf(Statement::class, new Db\SQLite3\Statement($this->c, $nativeStatement)); - } - - function testBindMissingValue() { - $nativeStatement = $this->c->prepare("SELECT ? as value"); - $s = new self::$imp($this->c, $nativeStatement); - $val = $s->runArray()->getRow()['value']; - $this->assertSame(null, $val); - } + $this->assertInstanceOf(Statement::class, new Db\SQLite3\Statement($this->c, $nativeStatement)); + } + + function testBindMissingValue() { + $nativeStatement = $this->c->prepare("SELECT ? as value"); + $s = new self::$imp($this->c, $nativeStatement); + $val = $s->runArray()->getRow()['value']; + $this->assertSame(null, $val); + } function testBindMultipleValues() { $exp = [ 'one' => 1, 'two' => 2, ]; - $nativeStatement = $this->c->prepare("SELECT ? as one, ? as two"); - $s = new self::$imp($this->c, $nativeStatement, ["int", "int"]); - $val = $s->runArray([1,2])->getRow(); - $this->assertSame($exp, $val); + $nativeStatement = $this->c->prepare("SELECT ? as one, ? as two"); + $s = new self::$imp($this->c, $nativeStatement, ["int", "int"]); + $val = $s->runArray([1,2])->getRow(); + $this->assertSame($exp, $val); } - function testBindRecursively() { + function testBindRecursively() { $exp = [ 'one' => 1, 'two' => 2, 'three' => 3, - 'four' => 4, + 'four' => 4, ]; - $nativeStatement = $this->c->prepare("SELECT ? as one, ? as two, ? as three, ? as four"); - $s = new self::$imp($this->c, $nativeStatement, ["int", ["int", "int"], "int"]); - $val = $s->runArray([1, [2, 3], 4])->getRow(); - $this->assertSame($exp, $val); - } + $nativeStatement = $this->c->prepare("SELECT ? as one, ? as two, ? as three, ? as four"); + $s = new self::$imp($this->c, $nativeStatement, ["int", ["int", "int"], "int"]); + $val = $s->runArray([1, [2, 3], 4])->getRow(); + $this->assertSame($exp, $val); + } function testBindWithoutType() { $nativeStatement = $this->c->prepare("SELECT ? as value"); - $this->assertException("paramTypeMissing", "Db"); - $s = new self::$imp($this->c, $nativeStatement, []); - $s->runArray([1]); + $this->assertException("paramTypeMissing", "Db"); + $s = new self::$imp($this->c, $nativeStatement, []); + $s->runArray([1]); } - function testViolateConstraint() { - $this->c->exec("CREATE TABLE test(id integer not null)"); - $nativeStatement = $this->c->prepare("INSERT INTO test(id) values(?)"); - $s = new self::$imp($this->c, $nativeStatement, ["int"]); - $this->assertException("constraintViolation", "Db", "ExceptionInput"); - $s->runArray([null]); - } + function testViolateConstraint() { + $this->c->exec("CREATE TABLE test(id integer not null)"); + $nativeStatement = $this->c->prepare("INSERT INTO test(id) values(?)"); + $s = new self::$imp($this->c, $nativeStatement, ["int"]); + $this->assertException("constraintViolation", "Db", "ExceptionInput"); + $s->runArray([null]); + } - function testMismatchTypes() { - $this->c->exec("CREATE TABLE test(id integer primary key)"); - $nativeStatement = $this->c->prepare("INSERT INTO test(id) values(?)"); - $s = new self::$imp($this->c, $nativeStatement, ["str"]); - $this->assertException("typeViolation", "Db", "ExceptionInput"); - $s->runArray(['ook']); - } + function testMismatchTypes() { + $this->c->exec("CREATE TABLE test(id integer primary key)"); + $nativeStatement = $this->c->prepare("INSERT INTO test(id) values(?)"); + $s = new self::$imp($this->c, $nativeStatement, ["str"]); + $this->assertException("typeViolation", "Db", "ExceptionInput"); + $s->runArray(['ook']); + } } \ No newline at end of file diff --git a/tests/Db/SQLite3/TestDbUpdateSQLite3.php b/tests/Db/SQLite3/TestDbUpdateSQLite3.php index 8400675..3fe66d7 100644 --- a/tests/Db/SQLite3/TestDbUpdateSQLite3.php +++ b/tests/Db/SQLite3/TestDbUpdateSQLite3.php @@ -8,84 +8,84 @@ class TestDbUpdateSQLite3 extends \PHPUnit\Framework\TestCase { use Test\Tools; protected $data; - protected $drv; - protected $vfs; - protected $base; + protected $drv; + protected $vfs; + protected $base; - const MINIMAL1 = "create table arsse_settings(key text primary key not null, value text, type text not null); pragma user_version=1"; - const MINIMAL2 = "pragma user_version=2"; + const MINIMAL1 = "create table arsse_settings(key text primary key not null, value text, type text not null); pragma user_version=1"; + const MINIMAL2 = "pragma user_version=2"; function setUp() { - $this->clearData(); + $this->clearData(); $this->vfs = vfsStream::setup("schemata", null, ['SQLite3' => []]); - $conf = new Conf(); - $conf->dbDriver = Db\SQLite3\Driver::class; - $conf->dbSchemaBase = $this->vfs->url(); - $this->base = $this->vfs->url()."/SQLite3/"; - $conf->dbSQLite3File = ":memory:"; - Data::$conf = $conf; - $this->drv = new Db\SQLite3\Driver(true); + $conf = new Conf(); + $conf->dbDriver = Db\SQLite3\Driver::class; + $conf->dbSchemaBase = $this->vfs->url(); + $this->base = $this->vfs->url()."/SQLite3/"; + $conf->dbSQLite3File = ":memory:"; + Data::$conf = $conf; + $this->drv = new Db\SQLite3\Driver(true); } function tearDown() { unset($this->drv); unset($this->data); unset($this->vfs); - $this->clearData(); + $this->clearData(); } - function testLoadMissingFile() { - $this->assertException("updateFileMissing", "Db"); - $this->drv->schemaUpdate(1); - } + function testLoadMissingFile() { + $this->assertException("updateFileMissing", "Db"); + $this->drv->schemaUpdate(1); + } - function testLoadUnreadableFile() { - touch($this->base."0.sql"); - chmod($this->base."0.sql", 0000); - $this->assertException("updateFileUnreadable", "Db"); - $this->drv->schemaUpdate(1); - } + function testLoadUnreadableFile() { + touch($this->base."0.sql"); + chmod($this->base."0.sql", 0000); + $this->assertException("updateFileUnreadable", "Db"); + $this->drv->schemaUpdate(1); + } - function testLoadCorruptFile() { - file_put_contents($this->base."0.sql", "This is a corrupt file"); - $this->assertException("updateFileError", "Db"); - $this->drv->schemaUpdate(1); - } + function testLoadCorruptFile() { + file_put_contents($this->base."0.sql", "This is a corrupt file"); + $this->assertException("updateFileError", "Db"); + $this->drv->schemaUpdate(1); + } - function testLoadIncompleteFile() { - file_put_contents($this->base."0.sql", "create table arsse_settings(key text primary key not null, value text, type text not null);"); - $this->assertException("updateFileIncomplete", "Db"); - $this->drv->schemaUpdate(1); - } + function testLoadIncompleteFile() { + file_put_contents($this->base."0.sql", "create table arsse_settings(key text primary key not null, value text, type text not null);"); + $this->assertException("updateFileIncomplete", "Db"); + $this->drv->schemaUpdate(1); + } - function testLoadCorrectFile() { - file_put_contents($this->base."0.sql", self::MINIMAL1); - $this->drv->schemaUpdate(1); - $this->assertEquals(1, $this->drv->schemaVersion()); - } + function testLoadCorrectFile() { + file_put_contents($this->base."0.sql", self::MINIMAL1); + $this->drv->schemaUpdate(1); + $this->assertEquals(1, $this->drv->schemaVersion()); + } - function testPerformPartialUpdate() { - file_put_contents($this->base."0.sql", self::MINIMAL1); - file_put_contents($this->base."1.sql", ""); - $this->assertException("updateFileIncomplete", "Db"); - try { - $this->drv->schemaUpdate(2); - } catch(Exception $e) { - $this->assertEquals(1, $this->drv->schemaVersion()); - throw $e; - } - } + function testPerformPartialUpdate() { + file_put_contents($this->base."0.sql", self::MINIMAL1); + file_put_contents($this->base."1.sql", ""); + $this->assertException("updateFileIncomplete", "Db"); + try { + $this->drv->schemaUpdate(2); + } catch(Exception $e) { + $this->assertEquals(1, $this->drv->schemaVersion()); + throw $e; + } + } - function testPerformSequentialUpdate() { - file_put_contents($this->base."0.sql", self::MINIMAL1); - file_put_contents($this->base."1.sql", self::MINIMAL2); - $this->drv->schemaUpdate(2); - $this->assertEquals(2, $this->drv->schemaVersion()); - } + function testPerformSequentialUpdate() { + file_put_contents($this->base."0.sql", self::MINIMAL1); + file_put_contents($this->base."1.sql", self::MINIMAL2); + $this->drv->schemaUpdate(2); + $this->assertEquals(2, $this->drv->schemaVersion()); + } - function testPerformActualUpdate() { - Data::$conf->dbSchemaBase = (new Conf())->dbSchemaBase; - $this->drv->schemaUpdate(Database::SCHEMA_VERSION); - $this->assertEquals(Database::SCHEMA_VERSION, $this->drv->schemaVersion()); - } + function testPerformActualUpdate() { + Data::$conf->dbSchemaBase = (new Conf())->dbSchemaBase; + $this->drv->schemaUpdate(Database::SCHEMA_VERSION); + $this->assertEquals(Database::SCHEMA_VERSION, $this->drv->schemaVersion()); + } } \ No newline at end of file diff --git a/tests/Exception/TestException.php b/tests/Exception/TestException.php index 21f8270..27c1318 100644 --- a/tests/Exception/TestException.php +++ b/tests/Exception/TestException.php @@ -21,7 +21,7 @@ class TestException extends \PHPUnit\Framework\TestCase { // clean up $this->clearData(true); } - + function testBaseClass() { $this->assertException("unknown"); throw new Exception("unknown"); @@ -34,7 +34,7 @@ class TestException extends \PHPUnit\Framework\TestCase { $this->assertException("unknown"); throw new Exception(); } - + /** * @depends testBaseClass */ diff --git a/tests/Lang/testLangComplex.php b/tests/Lang/testLangComplex.php index 72ab416..253d141 100644 --- a/tests/Lang/testLangComplex.php +++ b/tests/Lang/testLangComplex.php @@ -19,7 +19,7 @@ class TestLangComplex extends \PHPUnit\Framework\TestCase { $this->l->set("ja"); $this->assertArrayNotHasKey('Test.absentText', $this->l->dump()); } - + /** * @depends testLazyLoad */ @@ -29,7 +29,7 @@ class TestLangComplex extends \PHPUnit\Framework\TestCase { $this->assertEquals("ja", $this->l->get()); $this->assertEquals("en", $this->l->get(true)); } - + function testLoadCascadeOfFiles() { $this->l->set("ja", true); $this->assertEquals("de", $this->l->set("de", true)); @@ -44,7 +44,7 @@ class TestLangComplex extends \PHPUnit\Framework\TestCase { function testLoadSubtag() { $this->assertEquals("en_ca", $this->l->set("en_ca", true)); } - + function testFetchAMessage() { $this->l->set("de", true); $this->assertEquals('und der Stein der Weisen', $this->l->msg('Test.presentText')); diff --git a/tests/REST/NextCloudNews/TestNCNV1_2.php b/tests/REST/NextCloudNews/TestNCNV1_2.php index 1df79ad..b0f3b9b 100644 --- a/tests/REST/NextCloudNews/TestNCNV1_2.php +++ b/tests/REST/NextCloudNews/TestNCNV1_2.php @@ -10,161 +10,161 @@ use Phake; class TestNCNV1_2 extends \PHPUnit\Framework\TestCase { use Test\Tools; - protected $h; + protected $h; - function setUp() { - $this->clearData(); + function setUp() { + $this->clearData(); // create a mock user manager Data::$user = Phake::mock(User::class); - Phake::when(Data::$user)->authHTTP->thenReturn(true); - Data::$user->id = "john.doe@example.com"; - // create a mock database interface - Data::$db = Phake::mock(Database::Class); - $this->h = new REST\NextCloudNews\V1_2(); - } + Phake::when(Data::$user)->authHTTP->thenReturn(true); + Data::$user->id = "john.doe@example.com"; + // create a mock database interface + Data::$db = Phake::mock(Database::Class); + $this->h = new REST\NextCloudNews\V1_2(); + } - function tearDown() { - $this->clearData(); - } + function tearDown() { + $this->clearData(); + } - function testRespondToInvalidPaths() { - $errs = [ - 404 => [ - ['GET', "/"], - ['PUT', "/"], - ['POST', "/"], - ['DELETE', "/"], - ['GET', "/folders/1/invalid"], - ['PUT', "/folders/1/invalid"], - ['POST', "/folders/1/invalid"], - ['DELETE', "/folders/1/invalid"], - ['GET', "/version/invalid"], - ['PUT', "/version/invalid"], - ['POST', "/version/invalid"], - ['DELETE', "/version/invalid"], - ], - 405 => [ - 'GET' => [ - ['PUT', "/version"], - ['POST', "/version"], - ['DELETE', "/version"], - ], - 'GET, POST' => [ - ['PUT', "/folders"], - ['DELETE', "/folders"], - ], - 'PUT, DELETE' => [ - ['GET', "/folders/1"], - ['POST', "/folders/1"], - ], - ], - ]; - foreach($errs[404] as $req) { - $exp = new Response(404); - list($method, $path) = $req; - $this->assertEquals($exp, $this->h->dispatch(new Request($method, $path)), "$method call to $path did not return 404."); - } - foreach($errs[405] as $allow => $cases) { - $exp = new Response(405, "", "", ['Allow: '.$allow]); - foreach($cases as $req) { - list($method, $path) = $req; - $this->assertEquals($exp, $this->h->dispatch(new Request($method, $path)), "$method call to $path did not return 405."); - } - } - } + function testRespondToInvalidPaths() { + $errs = [ + 404 => [ + ['GET', "/"], + ['PUT', "/"], + ['POST', "/"], + ['DELETE', "/"], + ['GET', "/folders/1/invalid"], + ['PUT', "/folders/1/invalid"], + ['POST', "/folders/1/invalid"], + ['DELETE', "/folders/1/invalid"], + ['GET', "/version/invalid"], + ['PUT', "/version/invalid"], + ['POST', "/version/invalid"], + ['DELETE', "/version/invalid"], + ], + 405 => [ + 'GET' => [ + ['PUT', "/version"], + ['POST', "/version"], + ['DELETE', "/version"], + ], + 'GET, POST' => [ + ['PUT', "/folders"], + ['DELETE', "/folders"], + ], + 'PUT, DELETE' => [ + ['GET', "/folders/1"], + ['POST', "/folders/1"], + ], + ], + ]; + foreach($errs[404] as $req) { + $exp = new Response(404); + list($method, $path) = $req; + $this->assertEquals($exp, $this->h->dispatch(new Request($method, $path)), "$method call to $path did not return 404."); + } + foreach($errs[405] as $allow => $cases) { + $exp = new Response(405, "", "", ['Allow: '.$allow]); + foreach($cases as $req) { + list($method, $path) = $req; + $this->assertEquals($exp, $this->h->dispatch(new Request($method, $path)), "$method call to $path did not return 405."); + } + } + } - function testListFolders() { - $list = [ - ['id' => 1, 'name' => "Software", 'parent' => null], - ['id' => 12, 'name' => "Hardware", 'parent' => null], - ]; - Phake::when(Data::$db)->folderList(Data::$user->id, null, false)->thenReturn(new Result($list)); - $exp = new Response(200, ['folders' => $list]); - $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/folders"))); - } + function testListFolders() { + $list = [ + ['id' => 1, 'name' => "Software", 'parent' => null], + ['id' => 12, 'name' => "Hardware", 'parent' => null], + ]; + Phake::when(Data::$db)->folderList(Data::$user->id, null, false)->thenReturn(new Result($list)); + $exp = new Response(200, ['folders' => $list]); + $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/folders"))); + } - function testAddAFolder() { - $in = [ - ["name" => "Software"], - ["name" => "Hardware"], - ]; - $out = [ - ['id' => 1, 'name' => "Software", 'parent' => null], - ['id' => 2, 'name' => "Hardware", 'parent' => null], - ]; - // set of various mocks for testing - Phake::when(Data::$db)->folderAdd(Data::$user->id, $in[0])->thenReturn(1)->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("constraintViolation")); // error on the second call - Phake::when(Data::$db)->folderAdd(Data::$user->id, $in[1])->thenReturn(2)->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("constraintViolation")); // error on the second call - Phake::when(Data::$db)->folderPropertiesGet(Data::$user->id, 1)->thenReturn($out[0]); - Phake::when(Data::$db)->folderPropertiesGet(Data::$user->id, 2)->thenReturn($out[1]); - // set up mocks that produce errors - Phake::when(Data::$db)->folderAdd(Data::$user->id, [])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("missing")); - Phake::when(Data::$db)->folderAdd(Data::$user->id, ['name' => ""])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("missing")); - Phake::when(Data::$db)->folderAdd(Data::$user->id, ['name' => " "])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("whitespace")); - // correctly add two folders, using different means - $exp = new Response(200, ['folders' => [$out[0]]]); - $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders", json_encode($in[0]), 'application/json'))); - $exp = new Response(200, ['folders' => [$out[1]]]); - $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders?name=Hardware"))); - Phake::verify(Data::$db)->folderAdd(Data::$user->id, $in[0]); - Phake::verify(Data::$db)->folderAdd(Data::$user->id, $in[1]); - Phake::verify(Data::$db)->folderPropertiesGet(Data::$user->id, 1); - Phake::verify(Data::$db)->folderPropertiesGet(Data::$user->id, 2); - // test bad folder names - $exp = new Response(422); - $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders"))); - $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders", '{"name":""}', 'application/json'))); - $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders", '{"name":" "}', 'application/json'))); - // try adding the same two folders again - $exp = new Response(409); - $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders?name=Software"))); - $exp = new Response(409); - $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders", json_encode($in[1]), 'application/json'))); - } + function testAddAFolder() { + $in = [ + ["name" => "Software"], + ["name" => "Hardware"], + ]; + $out = [ + ['id' => 1, 'name' => "Software", 'parent' => null], + ['id' => 2, 'name' => "Hardware", 'parent' => null], + ]; + // set of various mocks for testing + Phake::when(Data::$db)->folderAdd(Data::$user->id, $in[0])->thenReturn(1)->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("constraintViolation")); // error on the second call + Phake::when(Data::$db)->folderAdd(Data::$user->id, $in[1])->thenReturn(2)->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("constraintViolation")); // error on the second call + Phake::when(Data::$db)->folderPropertiesGet(Data::$user->id, 1)->thenReturn($out[0]); + Phake::when(Data::$db)->folderPropertiesGet(Data::$user->id, 2)->thenReturn($out[1]); + // set up mocks that produce errors + Phake::when(Data::$db)->folderAdd(Data::$user->id, [])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("missing")); + Phake::when(Data::$db)->folderAdd(Data::$user->id, ['name' => ""])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("missing")); + Phake::when(Data::$db)->folderAdd(Data::$user->id, ['name' => " "])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("whitespace")); + // correctly add two folders, using different means + $exp = new Response(200, ['folders' => [$out[0]]]); + $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders", json_encode($in[0]), 'application/json'))); + $exp = new Response(200, ['folders' => [$out[1]]]); + $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders?name=Hardware"))); + Phake::verify(Data::$db)->folderAdd(Data::$user->id, $in[0]); + Phake::verify(Data::$db)->folderAdd(Data::$user->id, $in[1]); + Phake::verify(Data::$db)->folderPropertiesGet(Data::$user->id, 1); + Phake::verify(Data::$db)->folderPropertiesGet(Data::$user->id, 2); + // test bad folder names + $exp = new Response(422); + $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders"))); + $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders", '{"name":""}', 'application/json'))); + $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders", '{"name":" "}', 'application/json'))); + // try adding the same two folders again + $exp = new Response(409); + $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders?name=Software"))); + $exp = new Response(409); + $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders", json_encode($in[1]), 'application/json'))); + } - function testRemoveAFolder() { - Phake::when(Data::$db)->folderRemove(Data::$user->id, 1)->thenReturn(true)->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("idMissing")); - $exp = new Response(204); - $this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/folders/1"))); - // fail on the second invocation because it no longer exists - $exp = new Response(404); - $this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/folders/1"))); - Phake::verify(Data::$db, Phake::times(2))->folderRemove(Data::$user->id, 1); - // use a non-integer folder ID - $exp = new Response(404); - $this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/folders/invalid"))); - } + function testRemoveAFolder() { + Phake::when(Data::$db)->folderRemove(Data::$user->id, 1)->thenReturn(true)->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("idMissing")); + $exp = new Response(204); + $this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/folders/1"))); + // fail on the second invocation because it no longer exists + $exp = new Response(404); + $this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/folders/1"))); + Phake::verify(Data::$db, Phake::times(2))->folderRemove(Data::$user->id, 1); + // use a non-integer folder ID + $exp = new Response(404); + $this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/folders/invalid"))); + } - function testRenameAFolder() { - $in = [ - ["name" => "Software"], - ["name" => "Software"], - ["name" => ""], - ["name" => " "], - [], - ]; - Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[0])->thenReturn(true); - Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 2, $in[1])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("constraintViolation")); - Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[2])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("missing")); - Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[3])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("whitespace")); - Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[4])->thenReturn(true); // this should be stopped by the handler before the request gets to the database - Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 3, $this->anything())->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("idMissing")); // folder ID 3 does not exist - $exp = new Response(204); - $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[0]), 'application/json'))); - $exp = new Response(409); - $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/2", json_encode($in[1]), 'application/json'))); - $exp = new Response(422); - $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[2]), 'application/json'))); - $exp = new Response(422); - $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[3]), 'application/json'))); - $exp = new Response(422); - $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[4]), 'application/json'))); - $exp = new Response(404); - $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/3", json_encode($in[0]), 'application/json'))); - } + function testRenameAFolder() { + $in = [ + ["name" => "Software"], + ["name" => "Software"], + ["name" => ""], + ["name" => " "], + [], + ]; + Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[0])->thenReturn(true); + Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 2, $in[1])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("constraintViolation")); + Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[2])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("missing")); + Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[3])->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("whitespace")); + Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[4])->thenReturn(true); // this should be stopped by the handler before the request gets to the database + Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 3, $this->anything())->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("idMissing")); // folder ID 3 does not exist + $exp = new Response(204); + $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[0]), 'application/json'))); + $exp = new Response(409); + $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/2", json_encode($in[1]), 'application/json'))); + $exp = new Response(422); + $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[2]), 'application/json'))); + $exp = new Response(422); + $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[3]), 'application/json'))); + $exp = new Response(422); + $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[4]), 'application/json'))); + $exp = new Response(404); + $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/3", json_encode($in[0]), 'application/json'))); + } - function testRetrieveServerVersion() { - $exp = new Response(200, ['version' => \JKingWeb\Arsse\VERSION]); - $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/version"))); - } + function testRetrieveServerVersion() { + $exp = new Response(200, ['version' => \JKingWeb\Arsse\VERSION]); + $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/version"))); + } } \ No newline at end of file diff --git a/tests/REST/NextCloudNews/TestNCNVersionDiscovery.php b/tests/REST/NextCloudNews/TestNCNVersionDiscovery.php index f44b67e..3a049b7 100644 --- a/tests/REST/NextCloudNews/TestNCNVersionDiscovery.php +++ b/tests/REST/NextCloudNews/TestNCNVersionDiscovery.php @@ -8,37 +8,37 @@ use JKingWeb\Arsse\Rest\Response; class TestNCNVersionDiscovery extends \PHPUnit\Framework\TestCase { use Test\Tools; - function setUp() { - $this->clearData(); - } + function setUp() { + $this->clearData(); + } - function testFetchVersionList() { - $exp = new Response(200, ['apiLevels' => ['v1-2']]); - $h = new Rest\NextCloudNews\Versions(); - $req = new Request("GET", "/"); - $res = $h->dispatch($req); - $this->assertEquals($exp, $res); - $req = new Request("GET", ""); - $res = $h->dispatch($req); - $this->assertEquals($exp, $res); - $req = new Request("GET", "/?id=1827"); - $res = $h->dispatch($req); - $this->assertEquals($exp, $res); - } + function testFetchVersionList() { + $exp = new Response(200, ['apiLevels' => ['v1-2']]); + $h = new Rest\NextCloudNews\Versions(); + $req = new Request("GET", "/"); + $res = $h->dispatch($req); + $this->assertEquals($exp, $res); + $req = new Request("GET", ""); + $res = $h->dispatch($req); + $this->assertEquals($exp, $res); + $req = new Request("GET", "/?id=1827"); + $res = $h->dispatch($req); + $this->assertEquals($exp, $res); + } - function testUseIncorrectMethod() { - $exp = new Response(405); - $h = new Rest\NextCloudNews\Versions(); - $req = new Request("POST", "/"); - $res = $h->dispatch($req); - $this->assertEquals($exp, $res); - } + function testUseIncorrectMethod() { + $exp = new Response(405); + $h = new Rest\NextCloudNews\Versions(); + $req = new Request("POST", "/"); + $res = $h->dispatch($req); + $this->assertEquals($exp, $res); + } - function testUseIncorrectPath() { - $exp = new Response(404); - $h = new Rest\NextCloudNews\Versions(); - $req = new Request("GET", "/ook"); - $res = $h->dispatch($req); - $this->assertEquals($exp, $res); - } + function testUseIncorrectPath() { + $exp = new Response(404); + $h = new Rest\NextCloudNews\Versions(); + $req = new Request("GET", "/ook"); + $res = $h->dispatch($req); + $this->assertEquals($exp, $res); + } } \ No newline at end of file diff --git a/tests/User/TestAuthorization.php b/tests/User/TestAuthorization.php index e1870a3..058b241 100644 --- a/tests/User/TestAuthorization.php +++ b/tests/User/TestAuthorization.php @@ -5,297 +5,297 @@ namespace JKingWeb\Arsse; class TestAuthorization extends \PHPUnit\Framework\TestCase { use Test\Tools; - - const USERS = [ - 'user@example.com' => User\Driver::RIGHTS_NONE, - 'user@example.org' => User\Driver::RIGHTS_NONE, - 'dman@example.com' => User\Driver::RIGHTS_DOMAIN_MANAGER, - 'dman@example.org' => User\Driver::RIGHTS_DOMAIN_MANAGER, - 'dadm@example.com' => User\Driver::RIGHTS_DOMAIN_ADMIN, - 'dadm@example.org' => User\Driver::RIGHTS_DOMAIN_ADMIN, - 'gman@example.com' => User\Driver::RIGHTS_GLOBAL_MANAGER, - 'gman@example.org' => User\Driver::RIGHTS_GLOBAL_MANAGER, - 'gadm@example.com' => User\Driver::RIGHTS_GLOBAL_ADMIN, - 'gadm@example.org' => User\Driver::RIGHTS_GLOBAL_ADMIN, - // invalid rights levels - 'bad1@example.com' => User\Driver::RIGHTS_NONE+1, - 'bad1@example.org' => User\Driver::RIGHTS_NONE+1, - 'bad2@example.com' => User\Driver::RIGHTS_DOMAIN_MANAGER+1, - 'bad2@example.org' => User\Driver::RIGHTS_DOMAIN_MANAGER+1, - 'bad3@example.com' => User\Driver::RIGHTS_DOMAIN_ADMIN+1, - 'bad3@example.org' => User\Driver::RIGHTS_DOMAIN_ADMIN+1, - 'bad4@example.com' => User\Driver::RIGHTS_GLOBAL_MANAGER+1, - 'bad4@example.org' => User\Driver::RIGHTS_GLOBAL_MANAGER+1, - 'bad5@example.com' => User\Driver::RIGHTS_GLOBAL_ADMIN+1, - 'bad5@example.org' => User\Driver::RIGHTS_GLOBAL_ADMIN+1, - ]; - const LEVELS = [ - User\Driver::RIGHTS_NONE, - User\Driver::RIGHTS_DOMAIN_MANAGER, - User\Driver::RIGHTS_DOMAIN_ADMIN, - User\Driver::RIGHTS_GLOBAL_MANAGER, - User\Driver::RIGHTS_GLOBAL_ADMIN, - ]; - const DOMAINS = [ - '@example.com', - '@example.org', - "", - ]; + const USERS = [ + 'user@example.com' => User\Driver::RIGHTS_NONE, + 'user@example.org' => User\Driver::RIGHTS_NONE, + 'dman@example.com' => User\Driver::RIGHTS_DOMAIN_MANAGER, + 'dman@example.org' => User\Driver::RIGHTS_DOMAIN_MANAGER, + 'dadm@example.com' => User\Driver::RIGHTS_DOMAIN_ADMIN, + 'dadm@example.org' => User\Driver::RIGHTS_DOMAIN_ADMIN, + 'gman@example.com' => User\Driver::RIGHTS_GLOBAL_MANAGER, + 'gman@example.org' => User\Driver::RIGHTS_GLOBAL_MANAGER, + 'gadm@example.com' => User\Driver::RIGHTS_GLOBAL_ADMIN, + 'gadm@example.org' => User\Driver::RIGHTS_GLOBAL_ADMIN, + // invalid rights levels + 'bad1@example.com' => User\Driver::RIGHTS_NONE+1, + 'bad1@example.org' => User\Driver::RIGHTS_NONE+1, + 'bad2@example.com' => User\Driver::RIGHTS_DOMAIN_MANAGER+1, + 'bad2@example.org' => User\Driver::RIGHTS_DOMAIN_MANAGER+1, + 'bad3@example.com' => User\Driver::RIGHTS_DOMAIN_ADMIN+1, + 'bad3@example.org' => User\Driver::RIGHTS_DOMAIN_ADMIN+1, + 'bad4@example.com' => User\Driver::RIGHTS_GLOBAL_MANAGER+1, + 'bad4@example.org' => User\Driver::RIGHTS_GLOBAL_MANAGER+1, + 'bad5@example.com' => User\Driver::RIGHTS_GLOBAL_ADMIN+1, + 'bad5@example.org' => User\Driver::RIGHTS_GLOBAL_ADMIN+1, - protected $data; + ]; + const LEVELS = [ + User\Driver::RIGHTS_NONE, + User\Driver::RIGHTS_DOMAIN_MANAGER, + User\Driver::RIGHTS_DOMAIN_ADMIN, + User\Driver::RIGHTS_GLOBAL_MANAGER, + User\Driver::RIGHTS_GLOBAL_ADMIN, + ]; + const DOMAINS = [ + '@example.com', + '@example.org', + "", + ]; + + protected $data; function setUp(string $drv = Test\User\DriverInternalMock::class, string $db = null) { - $this->clearData(); - $conf = new Conf(); - $conf->userDriver = $drv; - $conf->userAuthPreferHTTP = true; - $conf->userComposeNames = true; - Data::$conf = $conf; - if($db !== null) { - Data::$db = new $db(); - } - Data::$user = new User(); - Data::$user->authorizationEnabled(false); - foreach(self::USERS as $user => $level) { - Data::$user->add($user, ""); - Data::$user->rightsSet($user, $level); - } - Data::$user->authorizationEnabled(true); - } + $this->clearData(); + $conf = new Conf(); + $conf->userDriver = $drv; + $conf->userAuthPreferHTTP = true; + $conf->userComposeNames = true; + Data::$conf = $conf; + if($db !== null) { + Data::$db = new $db(); + } + Data::$user = new User(); + Data::$user->authorizationEnabled(false); + foreach(self::USERS as $user => $level) { + Data::$user->add($user, ""); + Data::$user->rightsSet($user, $level); + } + Data::$user->authorizationEnabled(true); + } - function tearDown() { - $this->clearData(); - } + function tearDown() { + $this->clearData(); + } - function testSelfActionLogic() { - foreach(array_keys(self::USERS) as $user) { - Data::$user->auth($user, ""); - // users should be able to do basic actions for themselves - $this->assertTrue(Data::$user->authorize($user, "userExists"), "User $user could not act for themselves."); - $this->assertTrue(Data::$user->authorize($user, "userRemove"), "User $user could not act for themselves."); - } - } + function testSelfActionLogic() { + foreach(array_keys(self::USERS) as $user) { + Data::$user->auth($user, ""); + // users should be able to do basic actions for themselves + $this->assertTrue(Data::$user->authorize($user, "userExists"), "User $user could not act for themselves."); + $this->assertTrue(Data::$user->authorize($user, "userRemove"), "User $user could not act for themselves."); + } + } - function testRegularUserLogic() { - foreach(self::USERS as $actor => $rights) { - if($rights != User\Driver::RIGHTS_NONE) continue; - Data::$user->auth($actor, ""); - foreach(array_keys(self::USERS) as $affected) { - // regular users should only be able to act for themselves - if($actor==$affected) { - $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); - $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); - $this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); - } - // they should never be able to set rights - foreach(self::LEVELS as $level) { - $this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); - } - } - // they should not be able to list users - foreach(self::DOMAINS as $domain) { - $this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); - } - } - } + function testRegularUserLogic() { + foreach(self::USERS as $actor => $rights) { + if($rights != User\Driver::RIGHTS_NONE) continue; + Data::$user->auth($actor, ""); + foreach(array_keys(self::USERS) as $affected) { + // regular users should only be able to act for themselves + if($actor==$affected) { + $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); + $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); + $this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); + } + // they should never be able to set rights + foreach(self::LEVELS as $level) { + $this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); + } + } + // they should not be able to list users + foreach(self::DOMAINS as $domain) { + $this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); + } + } + } - function testDomainManagerLogic() { - foreach(self::USERS as $actor => $actorRights) { - if($actorRights != User\Driver::RIGHTS_DOMAIN_MANAGER) continue; - $actorDomain = substr($actor,strrpos($actor,"@")+1); - Data::$user->auth($actor, ""); - foreach(self::USERS as $affected => $affectedRights) { - $affectedDomain = substr($affected,strrpos($affected,"@")+1); - // domain managers should be able to check any user on the same domain - if($actorDomain==$affectedDomain) { - $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); - } - // they should only be able to act for regular users on the same domain - if($actor==$affected || ($actorDomain==$affectedDomain && $affectedRights==User\Driver::RIGHTS_NONE)) { - $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); - } - // and they should only be able to set their own rights to regular user - foreach(self::LEVELS as $level) { - if($actor==$affected && in_array($level, [User\Driver::RIGHTS_NONE, User\Driver::RIGHTS_DOMAIN_MANAGER])) { - $this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); - } - } - } - // they should also be able to list all users on their own domain - foreach(self::DOMAINS as $domain) { - if($domain=="@".$actorDomain) { - $this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); - } - } - } - } + function testDomainManagerLogic() { + foreach(self::USERS as $actor => $actorRights) { + if($actorRights != User\Driver::RIGHTS_DOMAIN_MANAGER) continue; + $actorDomain = substr($actor,strrpos($actor,"@")+1); + Data::$user->auth($actor, ""); + foreach(self::USERS as $affected => $affectedRights) { + $affectedDomain = substr($affected,strrpos($affected,"@")+1); + // domain managers should be able to check any user on the same domain + if($actorDomain==$affectedDomain) { + $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); + } + // they should only be able to act for regular users on the same domain + if($actor==$affected || ($actorDomain==$affectedDomain && $affectedRights==User\Driver::RIGHTS_NONE)) { + $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); + } + // and they should only be able to set their own rights to regular user + foreach(self::LEVELS as $level) { + if($actor==$affected && in_array($level, [User\Driver::RIGHTS_NONE, User\Driver::RIGHTS_DOMAIN_MANAGER])) { + $this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); + } + } + } + // they should also be able to list all users on their own domain + foreach(self::DOMAINS as $domain) { + if($domain=="@".$actorDomain) { + $this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); + } + } + } + } - function testDomainAdministratorLogic() { - foreach(self::USERS as $actor => $actorRights) { - if($actorRights != User\Driver::RIGHTS_DOMAIN_ADMIN) continue; - $actorDomain = substr($actor,strrpos($actor,"@")+1); - Data::$user->auth($actor, ""); - $allowed = [User\Driver::RIGHTS_NONE,User\Driver::RIGHTS_DOMAIN_MANAGER,User\Driver::RIGHTS_DOMAIN_ADMIN]; - foreach(self::USERS as $affected => $affectedRights) { - $affectedDomain = substr($affected,strrpos($affected,"@")+1); - // domain admins should be able to check any user on the same domain - if($actorDomain==$affectedDomain) { - $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); - } - // they should be able to act for any user on the same domain who is not a global manager or admin - if($actorDomain==$affectedDomain && in_array($affectedRights, $allowed)) { - $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); - } - // they should be able to set rights for any user on their domain who is not a global manager or admin, up to domain admin level - foreach(self::LEVELS as $level) { - if($actorDomain==$affectedDomain && in_array($affectedRights, $allowed) && in_array($level, $allowed)) { - $this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); - } - } - } - // they should also be able to list all users on their own domain - foreach(self::DOMAINS as $domain) { - if($domain=="@".$actorDomain) { - $this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); - } - } - } - } + function testDomainAdministratorLogic() { + foreach(self::USERS as $actor => $actorRights) { + if($actorRights != User\Driver::RIGHTS_DOMAIN_ADMIN) continue; + $actorDomain = substr($actor,strrpos($actor,"@")+1); + Data::$user->auth($actor, ""); + $allowed = [User\Driver::RIGHTS_NONE,User\Driver::RIGHTS_DOMAIN_MANAGER,User\Driver::RIGHTS_DOMAIN_ADMIN]; + foreach(self::USERS as $affected => $affectedRights) { + $affectedDomain = substr($affected,strrpos($affected,"@")+1); + // domain admins should be able to check any user on the same domain + if($actorDomain==$affectedDomain) { + $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); + } + // they should be able to act for any user on the same domain who is not a global manager or admin + if($actorDomain==$affectedDomain && in_array($affectedRights, $allowed)) { + $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); + } + // they should be able to set rights for any user on their domain who is not a global manager or admin, up to domain admin level + foreach(self::LEVELS as $level) { + if($actorDomain==$affectedDomain && in_array($affectedRights, $allowed) && in_array($level, $allowed)) { + $this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); + } + } + } + // they should also be able to list all users on their own domain + foreach(self::DOMAINS as $domain) { + if($domain=="@".$actorDomain) { + $this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); + } + } + } + } - function testGlobalManagerLogic() { - foreach(self::USERS as $actor => $actorRights) { - if($actorRights != User\Driver::RIGHTS_GLOBAL_MANAGER) continue; - $actorDomain = substr($actor,strrpos($actor,"@")+1); - Data::$user->auth($actor, ""); - foreach(self::USERS as $affected => $affectedRights) { - $affectedDomain = substr($affected,strrpos($affected,"@")+1); - // global managers should be able to check any user - $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); - // they should only be able to act for regular users - if($actor==$affected || $affectedRights==User\Driver::RIGHTS_NONE) { - $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); - } - // and they should only be able to set their own rights to regular user - foreach(self::LEVELS as $level) { - if($actor==$affected && in_array($level, [User\Driver::RIGHTS_NONE, User\Driver::RIGHTS_GLOBAL_MANAGER])) { - $this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); - } - } - } - // they should also be able to list all users - foreach(self::DOMAINS as $domain) { - $this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); - } - } - } + function testGlobalManagerLogic() { + foreach(self::USERS as $actor => $actorRights) { + if($actorRights != User\Driver::RIGHTS_GLOBAL_MANAGER) continue; + $actorDomain = substr($actor,strrpos($actor,"@")+1); + Data::$user->auth($actor, ""); + foreach(self::USERS as $affected => $affectedRights) { + $affectedDomain = substr($affected,strrpos($affected,"@")+1); + // global managers should be able to check any user + $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); + // they should only be able to act for regular users + if($actor==$affected || $affectedRights==User\Driver::RIGHTS_NONE) { + $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); + } + // and they should only be able to set their own rights to regular user + foreach(self::LEVELS as $level) { + if($actor==$affected && in_array($level, [User\Driver::RIGHTS_NONE, User\Driver::RIGHTS_GLOBAL_MANAGER])) { + $this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); + } + } + } + // they should also be able to list all users + foreach(self::DOMAINS as $domain) { + $this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); + } + } + } - function testGlobalAdministratorLogic() { - foreach(self::USERS as $actor => $actorRights) { - if($actorRights != User\Driver::RIGHTS_GLOBAL_ADMIN) continue; - Data::$user->auth($actor, ""); - // global admins can do anything - foreach(self::USERS as $affected => $affectedRights) { - $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); - $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); - foreach(self::LEVELS as $level) { - $this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); - } - } - foreach(self::DOMAINS as $domain) { - $this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); - } - } - } + function testGlobalAdministratorLogic() { + foreach(self::USERS as $actor => $actorRights) { + if($actorRights != User\Driver::RIGHTS_GLOBAL_ADMIN) continue; + Data::$user->auth($actor, ""); + // global admins can do anything + foreach(self::USERS as $affected => $affectedRights) { + $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); + $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); + foreach(self::LEVELS as $level) { + $this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); + } + } + foreach(self::DOMAINS as $domain) { + $this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); + } + } + } - function testInvalidLevelLogic() { - foreach(self::USERS as $actor => $rights) { - if(in_array($rights, self::LEVELS)) continue; - Data::$user->auth($actor, ""); - foreach(array_keys(self::USERS) as $affected) { - // users with unknown/invalid rights should be treated just like regular users and only be able to act for themselves - if($actor==$affected) { - $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); - $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); - } else { - $this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); - $this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); - } - // they should never be able to set rights - foreach(self::LEVELS as $level) { - $this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); - } - } - // they should not be able to list users - foreach(self::DOMAINS as $domain) { - $this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); - } - } - } + function testInvalidLevelLogic() { + foreach(self::USERS as $actor => $rights) { + if(in_array($rights, self::LEVELS)) continue; + Data::$user->auth($actor, ""); + foreach(array_keys(self::USERS) as $affected) { + // users with unknown/invalid rights should be treated just like regular users and only be able to act for themselves + if($actor==$affected) { + $this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); + $this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); + } else { + $this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); + $this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); + } + // they should never be able to set rights + foreach(self::LEVELS as $level) { + $this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); + } + } + // they should not be able to list users + foreach(self::DOMAINS as $domain) { + $this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); + } + } + } - function testInternalExceptionLogic() { - $tests = [ - // methods of User class to test, with parameters besides affected user - 'exists' => [], - 'remove' => [], - 'add' => [''], - 'passwordSet' => [''], - 'propertiesGet' => [], - 'propertiesSet' => [[]], - 'rightsGet' => [], - 'rightsSet' => [User\Driver::RIGHTS_GLOBAL_ADMIN], - 'list' => [], - ]; - // try first with a global admin (there should be no exception) - Data::$user->auth("gadm@example.com", ""); - $this->assertCount(0, $this->checkExceptions("user@example.org", $tests)); - // next try with a regular user acting on another user (everything should fail) - Data::$user->auth("user@example.com", ""); - $this->assertCount(sizeof($tests), $this->checkExceptions("user@example.org", $tests)); - } + function testInternalExceptionLogic() { + $tests = [ + // methods of User class to test, with parameters besides affected user + 'exists' => [], + 'remove' => [], + 'add' => [''], + 'passwordSet' => [''], + 'propertiesGet' => [], + 'propertiesSet' => [[]], + 'rightsGet' => [], + 'rightsSet' => [User\Driver::RIGHTS_GLOBAL_ADMIN], + 'list' => [], + ]; + // try first with a global admin (there should be no exception) + Data::$user->auth("gadm@example.com", ""); + $this->assertCount(0, $this->checkExceptions("user@example.org", $tests)); + // next try with a regular user acting on another user (everything should fail) + Data::$user->auth("user@example.com", ""); + $this->assertCount(sizeof($tests), $this->checkExceptions("user@example.org", $tests)); + } - function testExternalExceptionLogic() { - // set up the test for an external driver - $this->setUp(Test\User\DriverExternalMock::class, Test\User\Database::class); - // run the previous test with the external driver set up - $this->testInternalExceptionLogic(); - } + function testExternalExceptionLogic() { + // set up the test for an external driver + $this->setUp(Test\User\DriverExternalMock::class, Test\User\Database::class); + // run the previous test with the external driver set up + $this->testInternalExceptionLogic(); + } - // meat of testInternalExceptionLogic and testExternalExceptionLogic - // calls each requested function with supplied arguments, catches authorization exceptions, and returns an array of caught failed calls - protected function checkExceptions(string $user, $tests): array { - $err = []; - foreach($tests as $func => $args) { - // list method does not take an affected user, so do not unshift for that one - if($func != "list") array_unshift($args, $user); - try { - call_user_func_array(array(Data::$user, $func), $args); - } catch(User\ExceptionAuthz $e) { - $err[] = $func; - } - } - return $err; - } + // meat of testInternalExceptionLogic and testExternalExceptionLogic + // calls each requested function with supplied arguments, catches authorization exceptions, and returns an array of caught failed calls + protected function checkExceptions(string $user, $tests): array { + $err = []; + foreach($tests as $func => $args) { + // list method does not take an affected user, so do not unshift for that one + if($func != "list") array_unshift($args, $user); + try { + call_user_func_array(array(Data::$user, $func), $args); + } catch(User\ExceptionAuthz $e) { + $err[] = $func; + } + } + return $err; + } } \ No newline at end of file diff --git a/tests/User/TestUserInternalDriver.php b/tests/User/TestUserInternalDriver.php index cd36c4a..03d8b3a 100644 --- a/tests/User/TestUserInternalDriver.php +++ b/tests/User/TestUserInternalDriver.php @@ -5,9 +5,9 @@ namespace JKingWeb\Arsse; class TestUserInternalDriver extends \PHPUnit\Framework\TestCase { use Test\Tools, Test\User\CommonTests; - - const USER1 = "john.doe@example.com"; - const USER2 = "jane.doe@example.com"; - public $drv = User\Internal\Driver::class; + const USER1 = "john.doe@example.com"; + const USER2 = "jane.doe@example.com"; + + public $drv = User\Internal\Driver::class; } diff --git a/tests/User/TestUserMockExternal.php b/tests/User/TestUserMockExternal.php index 98a3d4c..a399013 100644 --- a/tests/User/TestUserMockExternal.php +++ b/tests/User/TestUserMockExternal.php @@ -5,9 +5,9 @@ namespace JKingWeb\Arsse; class TestUserMockExternal extends \PHPUnit\Framework\TestCase { use Test\Tools, Test\User\CommonTests; - - const USER1 = "john.doe@example.com"; - const USER2 = "jane.doe@example.com"; - public $drv = Test\User\DriverExternalMock::class; + const USER1 = "john.doe@example.com"; + const USER2 = "jane.doe@example.com"; + + public $drv = Test\User\DriverExternalMock::class; } \ No newline at end of file diff --git a/tests/User/TestUserMockInternal.php b/tests/User/TestUserMockInternal.php index 3278d4d..1574434 100644 --- a/tests/User/TestUserMockInternal.php +++ b/tests/User/TestUserMockInternal.php @@ -5,13 +5,13 @@ namespace JKingWeb\Arsse; class TestUserMockInternal extends \PHPUnit\Framework\TestCase { use Test\Tools, Test\User\CommonTests; - - const USER1 = "john.doe@example.com"; - const USER2 = "jane.doe@example.com"; - public $drv = Test\User\DriverInternalMock::class; + const USER1 = "john.doe@example.com"; + const USER2 = "jane.doe@example.com"; + + public $drv = Test\User\DriverInternalMock::class; function setUpSeries() { - Data::$db = null; - } + Data::$db = null; + } } diff --git a/tests/lib/Database/Setup.php b/tests/lib/Database/Setup.php index a40bdab..d9ed531 100644 --- a/tests/lib/Database/Setup.php +++ b/tests/lib/Database/Setup.php @@ -9,8 +9,8 @@ use JKingWeb\Arsse\Database; use Phake; trait Setup { - protected $drv; - protected $data = [ + protected $drv; + protected $data = [ 'arsse_users' => [ 'columns' => [ 'id' => 'str', @@ -32,7 +32,7 @@ trait Setup { // create a default configuration Data::$conf = new Conf(); // configure and create the relevant database driver - $this->setUpDriver(); + $this->setUpDriver(); // create the database interface with the suitable driver Data::$db = new Database($this->drv); Data::$db->schemaUpdate(); @@ -43,77 +43,77 @@ trait Setup { if(method_exists($this, "setUpSeries")) $this->setUpSeries(); } - function tearDown() { + function tearDown() { // call the additional teardiwn method if it exists if(method_exists($this, "tearDownSeries")) $this->tearDownSeries(); // clean up - $this->drv = null; + $this->drv = null; $this->clearData(); - } + } - function primeDatabase(array $data): bool { - $this->drv->begin(); - foreach($data as $table => $info) { - $cols = implode(",", array_keys($info['columns'])); - $bindings = array_values($info['columns']); - $params = implode(",", array_fill(0, sizeof($info['columns']), "?")); - $s = $this->drv->prepareArray("INSERT INTO $table($cols) values($params)", $bindings); - foreach($info['rows'] as $row) { - $this->assertEquals(1, $s->runArray($row)->changes()); - } - } - $this->drv->commit(); - return true; - } + function primeDatabase(array $data): bool { + $this->drv->begin(); + foreach($data as $table => $info) { + $cols = implode(",", array_keys($info['columns'])); + $bindings = array_values($info['columns']); + $params = implode(",", array_fill(0, sizeof($info['columns']), "?")); + $s = $this->drv->prepareArray("INSERT INTO $table($cols) values($params)", $bindings); + foreach($info['rows'] as $row) { + $this->assertEquals(1, $s->runArray($row)->changes()); + } + } + $this->drv->commit(); + return true; + } - function compareExpectations(array $expected): bool { - foreach($expected as $table => $info) { - $cols = implode(",", array_keys($info['columns'])); - $data = $this->drv->prepare("SELECT $cols from $table")->run()->getAll(); - $cols = array_keys($info['columns']); - foreach($info['rows'] as $index => $values) { - $row = []; - foreach($values as $key => $value) { - $row[$cols[$key]] = $value; - } - $found = array_search($row, $data); - $this->assertNotSame(false, $found, "Table $table does not contain record at array index $index."); - unset($data[$found]); - } - $this->assertSame([], $data); - } - return true; - } + function compareExpectations(array $expected): bool { + foreach($expected as $table => $info) { + $cols = implode(",", array_keys($info['columns'])); + $data = $this->drv->prepare("SELECT $cols from $table")->run()->getAll(); + $cols = array_keys($info['columns']); + foreach($info['rows'] as $index => $values) { + $row = []; + foreach($values as $key => $value) { + $row[$cols[$key]] = $value; + } + $found = array_search($row, $data); + $this->assertNotSame(false, $found, "Table $table does not contain record at array index $index."); + unset($data[$found]); + } + $this->assertSame([], $data); + } + return true; + } - function primeExpectations(array $source, array $tableSpecs = null): array { - $out = []; - foreach($tableSpecs as $table => $columns) { - if(!isset($source[$table])) { - $this->assertTrue(false, "Source for expectations does not contain requested table $table."); - return []; - } - $out[$table] = [ - 'columns' => [], - 'rows' => [], - ]; - $transformations = []; - foreach($columns as $target => $col) { - if(!isset($source[$table]['columns'][$col])) { - $this->assertTrue(false, "Source for expectations does not contain requested column $col of table $table."); - return []; - } - $found = array_search($col, array_keys($source[$table]['columns'])); - $transformations[$found] = $target; - $out[$table]['columns'][$col] = $source[$table]['columns'][$col]; - } - foreach($source[$table]['rows'] as $sourceRow) { - $newRow = []; - foreach($transformations as $from => $to) { - $newRow[$to] = $sourceRow[$from]; - } - $out[$table]['rows'][] = $newRow; - } - } - return $out; - } + function primeExpectations(array $source, array $tableSpecs = null): array { + $out = []; + foreach($tableSpecs as $table => $columns) { + if(!isset($source[$table])) { + $this->assertTrue(false, "Source for expectations does not contain requested table $table."); + return []; + } + $out[$table] = [ + 'columns' => [], + 'rows' => [], + ]; + $transformations = []; + foreach($columns as $target => $col) { + if(!isset($source[$table]['columns'][$col])) { + $this->assertTrue(false, "Source for expectations does not contain requested column $col of table $table."); + return []; + } + $found = array_search($col, array_keys($source[$table]['columns'])); + $transformations[$found] = $target; + $out[$table]['columns'][$col] = $source[$table]['columns'][$col]; + } + foreach($source[$table]['rows'] as $sourceRow) { + $newRow = []; + foreach($transformations as $from => $to) { + $newRow[$to] = $sourceRow[$from]; + } + $out[$table]['rows'][] = $newRow; + } + } + return $out; + } } \ No newline at end of file diff --git a/tests/lib/Db/BindingTests.php b/tests/lib/Db/BindingTests.php index 3c8140c..599d314 100644 --- a/tests/lib/Db/BindingTests.php +++ b/tests/lib/Db/BindingTests.php @@ -4,219 +4,219 @@ namespace JKingWeb\Arsse\Test\Db; use JKingWeb\Arsse\Db\Statement; trait BindingTests { - function testBindNull() { - $input = null; - $exp = [ - "null" => null, - "integer" => null, - "float" => null, - "date" => null, - "time" => null, - "datetime" => null, - "binary" => null, - "string" => null, - "boolean" => null, - ]; - $this->checkBinding($input, $exp); - } + function testBindNull() { + $input = null; + $exp = [ + "null" => null, + "integer" => null, + "float" => null, + "date" => null, + "time" => null, + "datetime" => null, + "binary" => null, + "string" => null, + "boolean" => null, + ]; + $this->checkBinding($input, $exp); + } - function testBindTrue() { - $input = true; - $exp = [ - "null" => null, - "integer" => 1, - "float" => 1.0, - "date" => null, - "time" => null, - "datetime" => null, - "binary" => "1", - "string" => "1", - "boolean" => 1, - ]; - $this->checkBinding($input, $exp); - } + function testBindTrue() { + $input = true; + $exp = [ + "null" => null, + "integer" => 1, + "float" => 1.0, + "date" => null, + "time" => null, + "datetime" => null, + "binary" => "1", + "string" => "1", + "boolean" => 1, + ]; + $this->checkBinding($input, $exp); + } - function testBindFalse() { - $input = false; - $exp = [ - "null" => null, - "integer" => 0, - "float" => 0.0, - "date" => null, - "time" => null, - "datetime" => null, - "binary" => "", - "string" => "", - "boolean" => 0, - ]; - $this->checkBinding($input, $exp); - } + function testBindFalse() { + $input = false; + $exp = [ + "null" => null, + "integer" => 0, + "float" => 0.0, + "date" => null, + "time" => null, + "datetime" => null, + "binary" => "", + "string" => "", + "boolean" => 0, + ]; + $this->checkBinding($input, $exp); + } - function testBindInteger() { - $input = 2112; - $exp = [ - "null" => null, - "integer" => 2112, - "float" => 2112.0, - "date" => date(self::$imp::dateFormat(Statement::TS_DATE), 2112), - "time" => date(self::$imp::dateFormat(Statement::TS_TIME), 2112), - "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 2112), - "binary" => "2112", - "string" => "2112", - "boolean" => 1, - ]; - $this->checkBinding($input, $exp); - } + function testBindInteger() { + $input = 2112; + $exp = [ + "null" => null, + "integer" => 2112, + "float" => 2112.0, + "date" => date(self::$imp::dateFormat(Statement::TS_DATE), 2112), + "time" => date(self::$imp::dateFormat(Statement::TS_TIME), 2112), + "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 2112), + "binary" => "2112", + "string" => "2112", + "boolean" => 1, + ]; + $this->checkBinding($input, $exp); + } - function testBindIntegerZero() { - $input = 0; - $exp = [ - "null" => null, - "integer" => 0, - "float" => 0.0, - "date" => date(self::$imp::dateFormat(Statement::TS_DATE), 0), - "time" => date(self::$imp::dateFormat(Statement::TS_TIME), 0), - "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 0), - "binary" => "0", - "string" => "0", - "boolean" => 0, - ]; - $this->checkBinding($input, $exp); - } + function testBindIntegerZero() { + $input = 0; + $exp = [ + "null" => null, + "integer" => 0, + "float" => 0.0, + "date" => date(self::$imp::dateFormat(Statement::TS_DATE), 0), + "time" => date(self::$imp::dateFormat(Statement::TS_TIME), 0), + "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 0), + "binary" => "0", + "string" => "0", + "boolean" => 0, + ]; + $this->checkBinding($input, $exp); + } - function testBindFloat() { - $input = 2112.0; - $exp = [ - "null" => null, - "integer" => 2112, - "float" => 2112.0, - "date" => date(self::$imp::dateFormat(Statement::TS_DATE), 2112), - "time" => date(self::$imp::dateFormat(Statement::TS_TIME), 2112), - "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 2112), - "binary" => "2112", - "string" => "2112", - "boolean" => 1, - ]; - $this->checkBinding($input, $exp); - } + function testBindFloat() { + $input = 2112.0; + $exp = [ + "null" => null, + "integer" => 2112, + "float" => 2112.0, + "date" => date(self::$imp::dateFormat(Statement::TS_DATE), 2112), + "time" => date(self::$imp::dateFormat(Statement::TS_TIME), 2112), + "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 2112), + "binary" => "2112", + "string" => "2112", + "boolean" => 1, + ]; + $this->checkBinding($input, $exp); + } - function testBindFloatZero() { - $input = 0.0; - $exp = [ - "null" => null, - "integer" => 0, - "float" => 0.0, - "date" => date(self::$imp::dateFormat(Statement::TS_DATE), 0), - "time" => date(self::$imp::dateFormat(Statement::TS_TIME), 0), - "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 0), - "binary" => "0", - "string" => "0", - "boolean" => 0, - ]; - $this->checkBinding($input, $exp); - } + function testBindFloatZero() { + $input = 0.0; + $exp = [ + "null" => null, + "integer" => 0, + "float" => 0.0, + "date" => date(self::$imp::dateFormat(Statement::TS_DATE), 0), + "time" => date(self::$imp::dateFormat(Statement::TS_TIME), 0), + "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 0), + "binary" => "0", + "string" => "0", + "boolean" => 0, + ]; + $this->checkBinding($input, $exp); + } - function testBindAsciiString() { - $input = "Random string"; - $exp = [ - "null" => null, - "integer" => 0, - "float" => 0.0, - "date" => null, - "time" => null, - "datetime" => null, - "binary" => $input, - "string" => $input, - "boolean" => 1, - ]; - $this->checkBinding($input, $exp); - } + function testBindAsciiString() { + $input = "Random string"; + $exp = [ + "null" => null, + "integer" => 0, + "float" => 0.0, + "date" => null, + "time" => null, + "datetime" => null, + "binary" => $input, + "string" => $input, + "boolean" => 1, + ]; + $this->checkBinding($input, $exp); + } - function testBindUtf8String() { - $input = "é"; - $exp = [ - "null" => null, - "integer" => 0, - "float" => 0.0, - "date" => null, - "time" => null, - "datetime" => null, - "binary" => $input, - "string" => $input, - "boolean" => 1, - ]; - $this->checkBinding($input, $exp); - } + function testBindUtf8String() { + $input = "é"; + $exp = [ + "null" => null, + "integer" => 0, + "float" => 0.0, + "date" => null, + "time" => null, + "datetime" => null, + "binary" => $input, + "string" => $input, + "boolean" => 1, + ]; + $this->checkBinding($input, $exp); + } - function testBindBinaryString() { - // FIXME: This test may be unreliable; SQLite happily stores invalid UTF-8 text as bytes untouched, but other engines probably don't do this - $input = chr(233); - $exp = [ - "null" => null, - "integer" => 0, - "float" => 0.0, - "date" => null, - "time" => null, - "datetime" => null, - "binary" => $input, - "string" => $input, - "boolean" => 1, - ]; - $this->checkBinding($input, $exp); - } + function testBindBinaryString() { + // FIXME: This test may be unreliable; SQLite happily stores invalid UTF-8 text as bytes untouched, but other engines probably don't do this + $input = chr(233); + $exp = [ + "null" => null, + "integer" => 0, + "float" => 0.0, + "date" => null, + "time" => null, + "datetime" => null, + "binary" => $input, + "string" => $input, + "boolean" => 1, + ]; + $this->checkBinding($input, $exp); + } - function testBindIso8601DateString() { - $input = "2017-01-09T13:11:17"; - $time = strtotime($input); - $exp = [ - "null" => null, - "integer" => 2017, - "float" => 2017.0, - "date" => date(self::$imp::dateFormat(Statement::TS_DATE), $time), - "time" => date(self::$imp::dateFormat(Statement::TS_TIME), $time), - "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time), - "binary" => $input, - "string" => $input, - "boolean" => 1, - ]; - $this->checkBinding($input, $exp); - } + function testBindIso8601DateString() { + $input = "2017-01-09T13:11:17"; + $time = strtotime($input); + $exp = [ + "null" => null, + "integer" => 2017, + "float" => 2017.0, + "date" => date(self::$imp::dateFormat(Statement::TS_DATE), $time), + "time" => date(self::$imp::dateFormat(Statement::TS_TIME), $time), + "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time), + "binary" => $input, + "string" => $input, + "boolean" => 1, + ]; + $this->checkBinding($input, $exp); + } - function testBindArbitraryDateString() { - $input = "Today"; - $time = strtotime($input); - $exp = [ - "null" => null, - "integer" => 0, - "float" => 0.0, - "date" => date(self::$imp::dateFormat(Statement::TS_DATE), $time), - "time" => date(self::$imp::dateFormat(Statement::TS_TIME), $time), - "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time), - "binary" => $input, - "string" => $input, - "boolean" => 1, - ]; - $this->checkBinding($input, $exp); - } + function testBindArbitraryDateString() { + $input = "Today"; + $time = strtotime($input); + $exp = [ + "null" => null, + "integer" => 0, + "float" => 0.0, + "date" => date(self::$imp::dateFormat(Statement::TS_DATE), $time), + "time" => date(self::$imp::dateFormat(Statement::TS_TIME), $time), + "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time), + "binary" => $input, + "string" => $input, + "boolean" => 1, + ]; + $this->checkBinding($input, $exp); + } - function testBindMutableDateObject($class = '\DateTime') { - $input = new $class("Noon Today"); - $time = $input->getTimestamp(); - $exp = [ - "null" => null, - "integer" => $time, - "float" => (float) $time, - "date" => date(self::$imp::dateFormat(Statement::TS_DATE), $time), - "time" => date(self::$imp::dateFormat(Statement::TS_TIME), $time), - "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time), - "binary" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time), - "string" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time), - "boolean" => 1, - ]; - $this->checkBinding($input, $exp); - } + function testBindMutableDateObject($class = '\DateTime') { + $input = new $class("Noon Today"); + $time = $input->getTimestamp(); + $exp = [ + "null" => null, + "integer" => $time, + "float" => (float) $time, + "date" => date(self::$imp::dateFormat(Statement::TS_DATE), $time), + "time" => date(self::$imp::dateFormat(Statement::TS_TIME), $time), + "datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time), + "binary" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time), + "string" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time), + "boolean" => 1, + ]; + $this->checkBinding($input, $exp); + } - function testBindImmutableDateObject() { - $this->testBindMutableDateObject('\DateTimeImmutable'); - } + function testBindImmutableDateObject() { + $this->testBindMutableDateObject('\DateTimeImmutable'); + } } \ No newline at end of file diff --git a/tests/lib/User/CommonTests.php b/tests/lib/User/CommonTests.php index 146db9c..7122fd2 100644 --- a/tests/lib/User/CommonTests.php +++ b/tests/lib/User/CommonTests.php @@ -9,135 +9,135 @@ use JKingWeb\Arsse\User\Driver; trait CommonTests { function setUp() { - $this->clearData(); - $conf = new Conf(); - $conf->userDriver = $this->drv; - $conf->userAuthPreferHTTP = true; - Data::$conf = $conf; - Data::$db = new Database(); - Data::$user = new User(); - Data::$user->authorizationEnabled(false); - $_SERVER['PHP_AUTH_USER'] = self::USER1; - $_SERVER['PHP_AUTH_PW'] = "secret"; + $this->clearData(); + $conf = new Conf(); + $conf->userDriver = $this->drv; + $conf->userAuthPreferHTTP = true; + Data::$conf = $conf; + Data::$db = new Database(); + Data::$user = new User(); + Data::$user->authorizationEnabled(false); + $_SERVER['PHP_AUTH_USER'] = self::USER1; + $_SERVER['PHP_AUTH_PW'] = "secret"; // call the additional setup method if it exists if(method_exists($this, "setUpSeries")) $this->setUpSeries(); - } + } - function tearDown() { - $this->clearData(); + function tearDown() { + $this->clearData(); // call the additional teardiwn method if it exists if(method_exists($this, "tearDownSeries")) $this->tearDownSeries(); - } - - function testListUsers() { - $this->assertCount(0,Data::$user->list()); - } - - function testCheckIfAUserDoesNotExist() { - $this->assertFalse(Data::$user->exists(self::USER1)); - } - - function testAddAUser() { - Data::$user->add(self::USER1, ""); - $this->assertCount(1,Data::$user->list()); - } - - function testCheckIfAUserDoesExist() { - Data::$user->add(self::USER1, ""); - $this->assertTrue(Data::$user->exists(self::USER1)); - } - - function testAddADuplicateUser() { - Data::$user->add(self::USER1, ""); - $this->assertException("alreadyExists", "User"); - Data::$user->add(self::USER1, ""); - } - - function testAddMultipleUsers() { - Data::$user->add(self::USER1, ""); - Data::$user->add(self::USER2, ""); - $this->assertCount(2,Data::$user->list()); - } - - function testRemoveAUser() { - Data::$user->add(self::USER1, ""); - $this->assertCount(1,Data::$user->list()); - Data::$user->remove(self::USER1); - $this->assertCount(0,Data::$user->list()); - } - - function testRemoveAMissingUser() { - $this->assertException("doesNotExist", "User"); - Data::$user->remove(self::USER1); - } - - function testAuthenticateAUser() { - $_SERVER['PHP_AUTH_USER'] = self::USER1; - $_SERVER['PHP_AUTH_PW'] = "secret"; - Data::$user->add(self::USER1, "secret"); - Data::$user->add(self::USER2, ""); - $this->assertTrue(Data::$user->auth()); - $this->assertTrue(Data::$user->auth(self::USER1, "secret")); - $this->assertFalse(Data::$user->auth(self::USER1, "superman")); - $this->assertTrue(Data::$user->auth(self::USER2, "")); - } - - function testChangeAPassword() { - Data::$user->add(self::USER1, "secret"); - $this->assertEquals("superman", Data::$user->passwordSet(self::USER1, "superman")); - $this->assertTrue(Data::$user->auth(self::USER1, "superman")); - $this->assertFalse(Data::$user->auth(self::USER1, "secret")); - $this->assertEquals("", Data::$user->passwordSet(self::USER1, "")); - $this->assertTrue(Data::$user->auth(self::USER1, "")); - $this->assertEquals(Data::$conf->userTempPasswordLength, strlen(Data::$user->passwordSet(self::USER1))); - } - - function testChangeAPasswordForAMissingUser() { - $this->assertException("doesNotExist", "User"); - Data::$user->passwordSet(self::USER1, "superman"); - } - - function testGetThePropertiesOfAUser() { - Data::$user->add(self::USER1, "secret"); - $p = Data::$user->propertiesGet(self::USER1); - $this->assertArrayHasKey('id', $p); - $this->assertArrayHasKey('name', $p); - $this->assertArrayHasKey('domain', $p); - $this->assertArrayHasKey('rights', $p); - $this->assertArrayNotHasKey('password', $p); - $this->assertEquals(self::USER1, $p['name']); - } - - function testSetThePropertiesOfAUser() { - $pSet = [ - 'name' => 'John Doe', - 'id' => 'invalid', - 'domain' => 'localhost', - 'rights' => Driver::RIGHTS_GLOBAL_ADMIN, - 'password' => 'superman', - ]; - $pGet = [ - 'name' => 'John Doe', - 'id' => self::USER1, - 'domain' => 'example.com', - 'rights' => Driver::RIGHTS_NONE, - ]; - Data::$user->add(self::USER1, "secret"); - Data::$user->propertiesSet(self::USER1, $pSet); - $p = Data::$user->propertiesGet(self::USER1); - $this->assertArraySubset($pGet, $p); - $this->assertArrayNotHasKey('password', $p); - $this->assertFalse(Data::$user->auth(self::USER1, "superman")); - } - - function testGetTheRightsOfAUser() { - Data::$user->add(self::USER1, ""); - $this->assertEquals(Driver::RIGHTS_NONE, Data::$user->rightsGet(self::USER1)); - } - - function testSetTheRightsOfAUser() { - Data::$user->add(self::USER1, ""); - Data::$user->rightsSet(self::USER1, Driver::RIGHTS_GLOBAL_ADMIN); - $this->assertEquals(Driver::RIGHTS_GLOBAL_ADMIN, Data::$user->rightsGet(self::USER1)); - } + } + + function testListUsers() { + $this->assertCount(0,Data::$user->list()); + } + + function testCheckIfAUserDoesNotExist() { + $this->assertFalse(Data::$user->exists(self::USER1)); + } + + function testAddAUser() { + Data::$user->add(self::USER1, ""); + $this->assertCount(1,Data::$user->list()); + } + + function testCheckIfAUserDoesExist() { + Data::$user->add(self::USER1, ""); + $this->assertTrue(Data::$user->exists(self::USER1)); + } + + function testAddADuplicateUser() { + Data::$user->add(self::USER1, ""); + $this->assertException("alreadyExists", "User"); + Data::$user->add(self::USER1, ""); + } + + function testAddMultipleUsers() { + Data::$user->add(self::USER1, ""); + Data::$user->add(self::USER2, ""); + $this->assertCount(2,Data::$user->list()); + } + + function testRemoveAUser() { + Data::$user->add(self::USER1, ""); + $this->assertCount(1,Data::$user->list()); + Data::$user->remove(self::USER1); + $this->assertCount(0,Data::$user->list()); + } + + function testRemoveAMissingUser() { + $this->assertException("doesNotExist", "User"); + Data::$user->remove(self::USER1); + } + + function testAuthenticateAUser() { + $_SERVER['PHP_AUTH_USER'] = self::USER1; + $_SERVER['PHP_AUTH_PW'] = "secret"; + Data::$user->add(self::USER1, "secret"); + Data::$user->add(self::USER2, ""); + $this->assertTrue(Data::$user->auth()); + $this->assertTrue(Data::$user->auth(self::USER1, "secret")); + $this->assertFalse(Data::$user->auth(self::USER1, "superman")); + $this->assertTrue(Data::$user->auth(self::USER2, "")); + } + + function testChangeAPassword() { + Data::$user->add(self::USER1, "secret"); + $this->assertEquals("superman", Data::$user->passwordSet(self::USER1, "superman")); + $this->assertTrue(Data::$user->auth(self::USER1, "superman")); + $this->assertFalse(Data::$user->auth(self::USER1, "secret")); + $this->assertEquals("", Data::$user->passwordSet(self::USER1, "")); + $this->assertTrue(Data::$user->auth(self::USER1, "")); + $this->assertEquals(Data::$conf->userTempPasswordLength, strlen(Data::$user->passwordSet(self::USER1))); + } + + function testChangeAPasswordForAMissingUser() { + $this->assertException("doesNotExist", "User"); + Data::$user->passwordSet(self::USER1, "superman"); + } + + function testGetThePropertiesOfAUser() { + Data::$user->add(self::USER1, "secret"); + $p = Data::$user->propertiesGet(self::USER1); + $this->assertArrayHasKey('id', $p); + $this->assertArrayHasKey('name', $p); + $this->assertArrayHasKey('domain', $p); + $this->assertArrayHasKey('rights', $p); + $this->assertArrayNotHasKey('password', $p); + $this->assertEquals(self::USER1, $p['name']); + } + + function testSetThePropertiesOfAUser() { + $pSet = [ + 'name' => 'John Doe', + 'id' => 'invalid', + 'domain' => 'localhost', + 'rights' => Driver::RIGHTS_GLOBAL_ADMIN, + 'password' => 'superman', + ]; + $pGet = [ + 'name' => 'John Doe', + 'id' => self::USER1, + 'domain' => 'example.com', + 'rights' => Driver::RIGHTS_NONE, + ]; + Data::$user->add(self::USER1, "secret"); + Data::$user->propertiesSet(self::USER1, $pSet); + $p = Data::$user->propertiesGet(self::USER1); + $this->assertArraySubset($pGet, $p); + $this->assertArrayNotHasKey('password', $p); + $this->assertFalse(Data::$user->auth(self::USER1, "superman")); + } + + function testGetTheRightsOfAUser() { + Data::$user->add(self::USER1, ""); + $this->assertEquals(Driver::RIGHTS_NONE, Data::$user->rightsGet(self::USER1)); + } + + function testSetTheRightsOfAUser() { + Data::$user->add(self::USER1, ""); + Data::$user->rightsSet(self::USER1, Driver::RIGHTS_GLOBAL_ADMIN); + $this->assertEquals(Driver::RIGHTS_GLOBAL_ADMIN, Data::$user->rightsGet(self::USER1)); + } } \ No newline at end of file diff --git a/tests/lib/User/Database.php b/tests/lib/User/Database.php index 0e3d761..8b9df01 100644 --- a/tests/lib/User/Database.php +++ b/tests/lib/User/Database.php @@ -13,7 +13,7 @@ class Database extends DriverSkeleton { public function __construct() { } - + function userExists(string $user): bool { if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); return parent::userExists($user); @@ -42,7 +42,7 @@ class Database extends DriverSkeleton { return parent::userList($domain); } } - + function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string { if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); @@ -70,7 +70,7 @@ class Database extends DriverSkeleton { if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); return parent::userRightsGet($user); } - + function userRightsSet(string $user, int $level): bool { if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); diff --git a/tests/lib/User/DriverExternalMock.php b/tests/lib/User/DriverExternalMock.php index 5de6eb2..2fa3ad7 100644 --- a/tests/lib/User/DriverExternalMock.php +++ b/tests/lib/User/DriverExternalMock.php @@ -44,7 +44,7 @@ class DriverExternalMock extends DriverSkeleton implements Driver { if(password_verify($password, $this->db[$user]['password'])) return true; return false; } - + function userExists(string $user): bool { return parent::userExists($user); } @@ -67,7 +67,7 @@ class DriverExternalMock extends DriverSkeleton implements Driver { return parent::userList($domain); } } - + function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string { if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if($newPassword===null) $newPassword = (new PassGen)->length(Data::$conf->userTempPasswordLength)->get(); @@ -89,7 +89,7 @@ class DriverExternalMock extends DriverSkeleton implements Driver { if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); return parent::userRightsGet($user); } - + function userRightsSet(string $user, int $level): bool { if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); return parent::userRightsSet($user, $level); diff --git a/tests/lib/User/DriverSkeleton.php b/tests/lib/User/DriverSkeleton.php index 8d49a26..643a53e 100644 --- a/tests/lib/User/DriverSkeleton.php +++ b/tests/lib/User/DriverSkeleton.php @@ -9,9 +9,9 @@ use PasswordGenerator\Generator as PassGen; abstract class DriverSkeleton { - protected $db = []; - - function userExists(string $user): bool { + protected $db = []; + + function userExists(string $user): bool { return array_key_exists($user, $this->db); } @@ -41,7 +41,7 @@ abstract class DriverSkeleton { }); } } - + function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string { $this->db[$user]['password'] = password_hash($newPassword, \PASSWORD_DEFAULT); return $newPassword; @@ -60,7 +60,7 @@ abstract class DriverSkeleton { function userRightsGet(string $user): int { return $this->db[$user]['rights']; } - + function userRightsSet(string $user, int $level): bool { $this->db[$user]['rights'] = $level; return true;