mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 21:22:40 +00:00
Fix whitespace
Also fixed my editor so tabs won't happen again!
This commit is contained in:
parent
b02abec250
commit
a67fe30408
32 changed files with 1402 additions and 1402 deletions
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ interface Result extends \Iterator {
|
|||
function getRow();
|
||||
function getAll(): array;
|
||||
function getValue();
|
||||
|
||||
|
||||
function changes();
|
||||
function lastId();
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -24,7 +24,7 @@ class REST {
|
|||
// Fever https://feedafever.com/api
|
||||
// NewsBlur http://www.newsblur.com/api
|
||||
];
|
||||
|
||||
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -4,5 +4,5 @@ namespace JKingWeb\Arsse\REST;
|
|||
|
||||
interface Handler {
|
||||
function __construct();
|
||||
function dispatch(Request $req): Response;
|
||||
function dispatch(Request $req): Response;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
12
lib/User.php
12
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");}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 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 testMakeAnInvalidQuery() {
|
||||
$this->assertException("engineErrorGeneral", "Db");
|
||||
$this->drv->query("Apollo was astonished; Dionysus thought me mad");
|
||||
}
|
||||
|
||||
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 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 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 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 testPrepareAValidQuery() {
|
||||
$s = $this->drv->prepare("SELECT ?, ?", "int", "int");
|
||||
$this->assertInstanceOf(Db\SQLite3\Statement::class, $s);
|
||||
}
|
||||
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 testPrepareAnInvalidQuery() {
|
||||
$this->assertException("engineErrorGeneral", "Db");
|
||||
$s = $this->drv->prepare("This is an invalid query", "int", "int");
|
||||
}
|
||||
function testPrepareAValidQuery() {
|
||||
$s = $this->drv->prepare("SELECT ?, ?", "int", "int");
|
||||
$this->assertInstanceOf(Db\SQLite3\Statement::class, $s);
|
||||
}
|
||||
|
||||
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 testPrepareAnInvalidQuery() {
|
||||
$this->assertException("engineErrorGeneral", "Db");
|
||||
$s = $this->drv->prepare("This is an invalid query", "int", "int");
|
||||
}
|
||||
|
||||
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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());
|
||||
}
|
||||
}
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
function testConstructStatement() {
|
||||
protected function checkBinding($input, array $expectations) {
|
||||
$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);
|
||||
}
|
||||
$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() {
|
||||
$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);
|
||||
}
|
||||
|
||||
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']);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -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")));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
}
|
||||
}
|
|
@ -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 testListUsers() {
|
||||
$this->assertCount(0,Data::$user->list());
|
||||
}
|
||||
|
||||
function testAddAUser() {
|
||||
Data::$user->add(self::USER1, "");
|
||||
$this->assertCount(1,Data::$user->list());
|
||||
}
|
||||
function testCheckIfAUserDoesNotExist() {
|
||||
$this->assertFalse(Data::$user->exists(self::USER1));
|
||||
}
|
||||
|
||||
function testCheckIfAUserDoesExist() {
|
||||
Data::$user->add(self::USER1, "");
|
||||
$this->assertTrue(Data::$user->exists(self::USER1));
|
||||
}
|
||||
function testAddAUser() {
|
||||
Data::$user->add(self::USER1, "");
|
||||
$this->assertCount(1,Data::$user->list());
|
||||
}
|
||||
|
||||
function testAddADuplicateUser() {
|
||||
Data::$user->add(self::USER1, "");
|
||||
$this->assertException("alreadyExists", "User");
|
||||
Data::$user->add(self::USER1, "");
|
||||
}
|
||||
function testCheckIfAUserDoesExist() {
|
||||
Data::$user->add(self::USER1, "");
|
||||
$this->assertTrue(Data::$user->exists(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 testAddADuplicateUser() {
|
||||
Data::$user->add(self::USER1, "");
|
||||
$this->assertException("alreadyExists", "User");
|
||||
Data::$user->add(self::USER1, "");
|
||||
}
|
||||
|
||||
function testRemoveAMissingUser() {
|
||||
$this->assertException("doesNotExist", "User");
|
||||
Data::$user->remove(self::USER1);
|
||||
}
|
||||
function testAddMultipleUsers() {
|
||||
Data::$user->add(self::USER1, "");
|
||||
Data::$user->add(self::USER2, "");
|
||||
$this->assertCount(2,Data::$user->list());
|
||||
}
|
||||
|
||||
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 testRemoveAUser() {
|
||||
Data::$user->add(self::USER1, "");
|
||||
$this->assertCount(1,Data::$user->list());
|
||||
Data::$user->remove(self::USER1);
|
||||
$this->assertCount(0,Data::$user->list());
|
||||
}
|
||||
|
||||
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 testRemoveAMissingUser() {
|
||||
$this->assertException("doesNotExist", "User");
|
||||
Data::$user->remove(self::USER1);
|
||||
}
|
||||
|
||||
function testChangeAPasswordForAMissingUser() {
|
||||
$this->assertException("doesNotExist", "User");
|
||||
Data::$user->passwordSet(self::USER1, "superman");
|
||||
}
|
||||
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 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 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 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 testChangeAPasswordForAMissingUser() {
|
||||
$this->assertException("doesNotExist", "User");
|
||||
Data::$user->passwordSet(self::USER1, "superman");
|
||||
}
|
||||
|
||||
function testGetTheRightsOfAUser() {
|
||||
Data::$user->add(self::USER1, "");
|
||||
$this->assertEquals(Driver::RIGHTS_NONE, Data::$user->rightsGet(self::USER1));
|
||||
}
|
||||
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 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 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));
|
||||
}
|
||||
}
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue