mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-23 17:12:41 +00:00
Merge branch 'master' into microsub
This commit is contained in:
commit
38a2776ae9
29 changed files with 415 additions and 123 deletions
|
@ -264,6 +264,7 @@ class Conf {
|
||||||
$type |= Value::M_NULL;
|
$type |= Value::M_NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// catch-all for custom properties
|
||||||
$type = Value::T_MIXED; // @codeCoverageIgnore
|
$type = Value::T_MIXED; // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
$out[$p->name] = ['name' => $match[0], 'const' => $type];
|
$out[$p->name] = ['name' => $match[0], 'const' => $type];
|
||||||
|
@ -286,6 +287,7 @@ class Conf {
|
||||||
}
|
}
|
||||||
switch (self::EXPECTED_TYPES[$key] ?? gettype($this->$key)) {
|
switch (self::EXPECTED_TYPES[$key] ?? gettype($this->$key)) {
|
||||||
case "integer":
|
case "integer":
|
||||||
|
// no properties are currently typed as integers
|
||||||
return Value::normalize($value, Value::T_INT | $mode); // @codeCoverageIgnore
|
return Value::normalize($value, Value::T_INT | $mode); // @codeCoverageIgnore
|
||||||
case "double":
|
case "double":
|
||||||
return Value::normalize($value, Value::T_FLOAT | $mode);
|
return Value::normalize($value, Value::T_FLOAT | $mode);
|
||||||
|
@ -293,6 +295,7 @@ class Conf {
|
||||||
case "object":
|
case "object":
|
||||||
return $value;
|
return $value;
|
||||||
default:
|
default:
|
||||||
|
// this should never occur
|
||||||
throw new Conf\Exception("ambiguousDefault", ['param' => $key]); // @codeCoverageIgnore
|
throw new Conf\Exception("ambiguousDefault", ['param' => $key]); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,21 +78,6 @@ class Database {
|
||||||
return debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]['function'];
|
return debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]['function'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Lists the available database drivers, as an associative array with
|
|
||||||
* fully-qualified class names as keys, and human-readable descriptions as values
|
|
||||||
*/
|
|
||||||
public static function driverList(): array {
|
|
||||||
$sep = \DIRECTORY_SEPARATOR;
|
|
||||||
$path = __DIR__.$sep."Db".$sep;
|
|
||||||
$classes = [];
|
|
||||||
foreach (glob($path."*".$sep."Driver.php") as $file) {
|
|
||||||
$name = basename(dirname($file));
|
|
||||||
$class = NS_BASE."Db\\$name\\Driver";
|
|
||||||
$classes[$class] = $class::driverName();
|
|
||||||
}
|
|
||||||
return $classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the current (actual) schema version of the database; compared against self::SCHEMA_VERSION to know when an upgrade is required */
|
/** Returns the current (actual) schema version of the database; compared against self::SCHEMA_VERSION to know when an upgrade is required */
|
||||||
public function driverSchemaVersion(): int {
|
public function driverSchemaVersion(): int {
|
||||||
return $this->db->schemaVersion();
|
return $this->db->schemaVersion();
|
||||||
|
|
|
@ -46,23 +46,14 @@ abstract class AbstractStatement implements Statement {
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function retypeArray(array $bindings, bool $append = false): bool {
|
public function retypeArray(array $bindings): bool {
|
||||||
if (!$append) {
|
|
||||||
$this->types = [];
|
$this->types = [];
|
||||||
}
|
foreach (ValueInfo::flatten($bindings) as $binding) { // recursively flatten any arrays, which may be provided for SET or IN() clauses
|
||||||
foreach ($bindings as $binding) {
|
|
||||||
if (is_array($binding)) {
|
|
||||||
// recursively flatten any arrays, which may be provided for SET or IN() clauses
|
|
||||||
$this->retypeArray($binding, true);
|
|
||||||
} else {
|
|
||||||
$bindId = self::TYPES[trim(strtolower($binding))] ?? 0;
|
$bindId = self::TYPES[trim(strtolower($binding))] ?? 0;
|
||||||
assert($bindId, new Exception("paramTypeInvalid", $binding));
|
assert($bindId, new Exception("paramTypeInvalid", $binding));
|
||||||
$this->types[] = $bindId;
|
$this->types[] = $bindId;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!$append) {
|
|
||||||
$this->prepare(static::mungeQuery($this->query, $this->types));
|
$this->prepare(static::mungeQuery($this->query, $this->types));
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,26 +70,22 @@ abstract class AbstractStatement implements Statement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function bindValues(array $values, int $offset = null): int {
|
protected function bindValues(array $values): bool {
|
||||||
$a = (int) $offset;
|
|
||||||
foreach ($values as $value) {
|
|
||||||
if (is_array($value)) {
|
|
||||||
// recursively flatten any arrays, which may be provided for SET or IN() clauses
|
// recursively flatten any arrays, which may be provided for SET or IN() clauses
|
||||||
$a += $this->bindValues($value, $a);
|
$values = ValueInfo::flatten($values);
|
||||||
} elseif (array_key_exists($a, $this->types)) {
|
foreach ($values as $a => $value) {
|
||||||
|
if (array_key_exists($a, $this->types)) {
|
||||||
$value = $this->cast($value, $this->types[$a]);
|
$value = $this->cast($value, $this->types[$a]);
|
||||||
$this->bindValue($value, $this->types[$a] % self::T_NOT_NULL, ++$a);
|
$this->bindValue($value, $this->types[$a] % self::T_NOT_NULL, ++$a);
|
||||||
} else {
|
} else {
|
||||||
throw new Exception("paramTypeMissing", $a+1);
|
throw new Exception("paramTypeMissing", $a+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// once the last value is bound, check that all parameters have been supplied values and bind null for any missing ones
|
// once all values are bound, check that all parameters have been supplied values and bind null for any missing ones
|
||||||
// SQLite will happily substitute null for a missing value, but other engines (viz. PostgreSQL) produce an error
|
// SQLite will happily substitute null for a missing value, but other engines (viz. PostgreSQL) produce an error
|
||||||
if (is_null($offset)) {
|
for ($a = sizeof($values); $a < sizeof($this->types); $a++) {
|
||||||
while ($a < sizeof($this->types)) {
|
$this->bindValue(null, $this->types[$a] % self::T_NOT_NULL, $a + 1);
|
||||||
$this->bindValue(null, $this->types[$a] % self::T_NOT_NULL, ++$a);
|
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
return $a - $offset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,5 +7,7 @@ declare(strict_types=1);
|
||||||
namespace JKingWeb\Arsse\Db\SQLite3;
|
namespace JKingWeb\Arsse\Db\SQLite3;
|
||||||
|
|
||||||
abstract class AbstractPDODriver extends Driver {
|
abstract class AbstractPDODriver extends Driver {
|
||||||
|
// this class exists solely so SQLite's PDO driver can call methods of the generic PDO driver via parent::method()
|
||||||
|
// if there's a better way to do this, please FIXME ;)
|
||||||
use \JKingWeb\Arsse\Db\PDODriver;
|
use \JKingWeb\Arsse\Db\PDODriver;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,61 +29,63 @@ class Query {
|
||||||
$this->setBody($body, $types, $values);
|
$this->setBody($body, $types, $values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setBody(string $body = "", $types = null, $values = null): bool {
|
public function setBody(string $body = "", $types = null, $values = null): self {
|
||||||
$this->qBody = $body;
|
$this->qBody = $body;
|
||||||
if (!is_null($types)) {
|
if (!is_null($types)) {
|
||||||
$this->tBody[] = $types;
|
$this->tBody[] = $types;
|
||||||
$this->vBody[] = $values;
|
$this->vBody[] = $values;
|
||||||
}
|
}
|
||||||
return true;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCTE(string $tableSpec, string $body, $types = null, $values = null): bool {
|
public function setCTE(string $tableSpec, string $body, $types = null, $values = null): self {
|
||||||
$this->qCTE[] = "$tableSpec as ($body)";
|
$this->qCTE[] = "$tableSpec as ($body)";
|
||||||
if (!is_null($types)) {
|
if (!is_null($types)) {
|
||||||
$this->tCTE[] = $types;
|
$this->tCTE[] = $types;
|
||||||
$this->vCTE[] = $values;
|
$this->vCTE[] = $values;
|
||||||
}
|
}
|
||||||
return true;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setWhere(string $where, $types = null, $values = null): bool {
|
public function setWhere(string $where, $types = null, $values = null): self {
|
||||||
$this->qWhere[] = $where;
|
$this->qWhere[] = $where;
|
||||||
if (!is_null($types)) {
|
if (!is_null($types)) {
|
||||||
$this->tWhere[] = $types;
|
$this->tWhere[] = $types;
|
||||||
$this->vWhere[] = $values;
|
$this->vWhere[] = $values;
|
||||||
}
|
}
|
||||||
return true;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setWhereNot(string $where, $types = null, $values = null): bool {
|
public function setWhereNot(string $where, $types = null, $values = null): self {
|
||||||
$this->qWhereNot[] = $where;
|
$this->qWhereNot[] = $where;
|
||||||
if (!is_null($types)) {
|
if (!is_null($types)) {
|
||||||
$this->tWhereNot[] = $types;
|
$this->tWhereNot[] = $types;
|
||||||
$this->vWhereNot[] = $values;
|
$this->vWhereNot[] = $values;
|
||||||
}
|
}
|
||||||
return true;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setGroup(string ...$column): bool {
|
public function setGroup(string ...$column): self {
|
||||||
foreach ($column as $col) {
|
foreach ($column as $col) {
|
||||||
$this->group[] = $col;
|
$this->group[] = $col;
|
||||||
}
|
}
|
||||||
return true;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setOrder(string $order): bool {
|
public function setOrder(string ...$order): self {
|
||||||
$this->order[] = $order;
|
foreach ($order as $o) {
|
||||||
return true;
|
$this->order[] = $o;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setLimit(int $limit, int $offset = 0): bool {
|
public function setLimit(int $limit, int $offset = 0): self {
|
||||||
$this->limit = $limit;
|
$this->limit = $limit;
|
||||||
$this->offset = $offset;
|
$this->offset = $offset;
|
||||||
return true;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function pushCTE(string $tableSpec): bool {
|
public function pushCTE(string $tableSpec): self {
|
||||||
// this function takes the query body and converts it to a common table expression, putting it at the bottom of the existing CTE stack
|
// this function takes the query body and converts it to a common table expression, putting it at the bottom of the existing CTE stack
|
||||||
// all WHERE, ORDER BY, and LIMIT parts belong to the new CTE and are removed from the main query
|
// all WHERE, ORDER BY, and LIMIT parts belong to the new CTE and are removed from the main query
|
||||||
$this->setCTE($tableSpec, $this->buildQueryBody(), [$this->tBody, $this->tWhere, $this->tWhereNot], [$this->vBody, $this->vWhere, $this->vWhereNot]);
|
$this->setCTE($tableSpec, $this->buildQueryBody(), [$this->tBody, $this->tWhere, $this->tWhereNot], [$this->vBody, $this->vWhere, $this->vWhereNot]);
|
||||||
|
@ -98,7 +100,7 @@ class Query {
|
||||||
$this->order = [];
|
$this->order = [];
|
||||||
$this->group = [];
|
$this->group = [];
|
||||||
$this->setLimit(0, 0);
|
$this->setLimit(0, 0);
|
||||||
return true;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string {
|
public function __toString(): string {
|
||||||
|
@ -117,11 +119,11 @@ class Query {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTypes(): array {
|
public function getTypes(): array {
|
||||||
return [$this->tCTE, $this->tBody, $this->tWhere, $this->tWhereNot];
|
return ValueInfo::flatten([$this->tCTE, $this->tBody, $this->tWhere, $this->tWhereNot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValues(): array {
|
public function getValues(): array {
|
||||||
return [$this->vCTE, $this->vBody, $this->vWhere, $this->vWhereNot];
|
return ValueInfo::flatten([$this->vCTE, $this->vBody, $this->vWhere, $this->vWhereNot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildQueryBody(): string {
|
protected function buildQueryBody(): string {
|
||||||
|
@ -144,9 +146,9 @@ class Query {
|
||||||
if (sizeof($this->order)) {
|
if (sizeof($this->order)) {
|
||||||
$out .= " ORDER BY ".implode(", ", $this->order);
|
$out .= " ORDER BY ".implode(", ", $this->order);
|
||||||
}
|
}
|
||||||
// add LIMIT and OFFSET if the former is specified
|
// add LIMIT and OFFSET if either is specified
|
||||||
if ($this->limit > 0) {
|
if ($this->limit > 0 || $this->offset > 0) {
|
||||||
$out .= " LIMIT ".$this->limit;
|
$out .= " LIMIT ".($this->limit < 1 ? -1 : $this->limit);
|
||||||
if ($this->offset > 0) {
|
if ($this->offset > 0) {
|
||||||
$out .= " OFFSET ".$this->offset;
|
$out .= " OFFSET ".$this->offset;
|
||||||
}
|
}
|
||||||
|
|
|
@ -397,6 +397,17 @@ class ValueInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function flatten(array $arr): array {
|
||||||
|
$arr = array_values($arr);
|
||||||
|
for ($a = 0; $a < sizeof($arr); $a++) {
|
||||||
|
if (is_array($arr[$a])) {
|
||||||
|
array_splice($arr, $a, 1, $arr[$a]);
|
||||||
|
$a--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $arr;
|
||||||
|
}
|
||||||
|
|
||||||
public static function int($value): int {
|
public static function int($value): int {
|
||||||
$out = 0;
|
$out = 0;
|
||||||
if (is_null($value)) {
|
if (is_null($value)) {
|
||||||
|
|
|
@ -209,7 +209,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
// indexed arrays
|
// indexed arrays
|
||||||
$p->appendChild($this->makeXMLIndexed($v, $d->createElement($k), substr($k, 0, strlen($k) - 1)));
|
$p->appendChild($this->makeXMLIndexed($v, $d->createElement($k), substr($k, 0, strlen($k) - 1)));
|
||||||
} else {
|
} else {
|
||||||
// this case does not actually occur in a proper Fever response
|
// this case is never encountered with Fever's output
|
||||||
$p->appendChild($this->makeXMLAssoc($v, $d->createElement($k))); // @codeCoverageIgnore
|
$p->appendChild($this->makeXMLAssoc($v, $d->createElement($k))); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,30 +12,14 @@ class Service {
|
||||||
const DRIVER_NAMES = [
|
const DRIVER_NAMES = [
|
||||||
'serial' => \JKingWeb\Arsse\Service\Serial\Driver::class,
|
'serial' => \JKingWeb\Arsse\Service\Serial\Driver::class,
|
||||||
'subprocess' => \JKingWeb\Arsse\Service\Subprocess\Driver::class,
|
'subprocess' => \JKingWeb\Arsse\Service\Subprocess\Driver::class,
|
||||||
'curl' => \JKingWeb\Arsse\Service\Curl\Driver::class,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @var Service\Driver */
|
/** @var Service\Driver */
|
||||||
protected $drv;
|
protected $drv;
|
||||||
/** @var \DateInterval */
|
|
||||||
protected $interval;
|
|
||||||
|
|
||||||
public static function driverList(): array {
|
|
||||||
$sep = \DIRECTORY_SEPARATOR;
|
|
||||||
$path = __DIR__.$sep."Service".$sep;
|
|
||||||
$classes = [];
|
|
||||||
foreach (glob($path."*".$sep."Driver.php") as $file) {
|
|
||||||
$name = basename(dirname($file));
|
|
||||||
$class = NS_BASE."User\\$name\\Driver";
|
|
||||||
$classes[$class] = $class::driverName();
|
|
||||||
}
|
|
||||||
return $classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$driver = Arsse::$conf->serviceDriver;
|
$driver = Arsse::$conf->serviceDriver;
|
||||||
$this->drv = new $driver();
|
$this->drv = new $driver();
|
||||||
$this->interval = Arsse::$conf->serviceFrequency;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function watch(bool $loop = true): \DateTimeInterface {
|
public function watch(bool $loop = true): \DateTimeInterface {
|
||||||
|
@ -46,17 +30,19 @@ class Service {
|
||||||
$list = Arsse::$db->feedListStale();
|
$list = Arsse::$db->feedListStale();
|
||||||
if ($list) {
|
if ($list) {
|
||||||
$this->drv->queue(...$list);
|
$this->drv->queue(...$list);
|
||||||
|
unset($list);
|
||||||
$this->drv->exec();
|
$this->drv->exec();
|
||||||
$this->drv->clean();
|
$this->drv->clean();
|
||||||
unset($list);
|
|
||||||
}
|
}
|
||||||
static::cleanupPost();
|
static::cleanupPost();
|
||||||
$t->add($this->interval);
|
$t->add(Arsse::$conf->serviceFrequency);
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
if ($loop) {
|
if ($loop) {
|
||||||
do {
|
do {
|
||||||
@time_sleep_until($t->getTimestamp());
|
@time_sleep_until($t->getTimestamp());
|
||||||
} while ($t->getTimestamp() > time());
|
} while ($t->getTimestamp() > time());
|
||||||
}
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
} while ($loop);
|
} while ($loop);
|
||||||
return $t;
|
return $t;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,5 @@ interface Driver {
|
||||||
public static function requirementsMet(): bool;
|
public static function requirementsMet(): bool;
|
||||||
public function queue(int ...$feeds): int;
|
public function queue(int ...$feeds): int;
|
||||||
public function exec(): int;
|
public function exec(): int;
|
||||||
public function clean(): bool;
|
public function clean(): int;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,9 @@ class Driver implements \JKingWeb\Arsse\Service\Driver {
|
||||||
return Arsse::$conf->serviceQueueWidth - sizeof($this->queue);
|
return Arsse::$conf->serviceQueueWidth - sizeof($this->queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function clean(): bool {
|
public function clean(): int {
|
||||||
|
$out = sizeof($this->queue);
|
||||||
$this->queue = [];
|
$this->queue = [];
|
||||||
return true;
|
return $out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ class Driver implements \JKingWeb\Arsse\Service\Driver {
|
||||||
$id = (int) array_shift($this->queue);
|
$id = (int) array_shift($this->queue);
|
||||||
$php = escapeshellarg(\PHP_BINARY);
|
$php = escapeshellarg(\PHP_BINARY);
|
||||||
$arsse = escapeshellarg($_SERVER['argv'][0]);
|
$arsse = escapeshellarg($_SERVER['argv'][0]);
|
||||||
array_push($pp, popen("$php $arsse feed refresh $id", "r"));
|
array_push($pp, $this->execCmd("$php $arsse feed refresh $id"));
|
||||||
}
|
}
|
||||||
while ($pp) {
|
while ($pp) {
|
||||||
$p = array_pop($pp);
|
$p = array_pop($pp);
|
||||||
|
@ -43,8 +43,14 @@ class Driver implements \JKingWeb\Arsse\Service\Driver {
|
||||||
return Arsse::$conf->serviceQueueWidth - sizeof($this->queue);
|
return Arsse::$conf->serviceQueueWidth - sizeof($this->queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function clean(): bool {
|
/** @codeCoverageIgnore */
|
||||||
|
protected function execCmd(string $cmd) {
|
||||||
|
return popen($cmd, "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clean(): int {
|
||||||
|
$out = sizeof($this->queue);
|
||||||
$this->queue = [];
|
$this->queue = [];
|
||||||
return true;
|
return $out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
lib/User.php
12
lib/User.php
|
@ -20,18 +20,6 @@ class User {
|
||||||
*/
|
*/
|
||||||
protected $u;
|
protected $u;
|
||||||
|
|
||||||
public static function driverList(): array {
|
|
||||||
$sep = \DIRECTORY_SEPARATOR;
|
|
||||||
$path = __DIR__.$sep."User".$sep;
|
|
||||||
$classes = [];
|
|
||||||
foreach (glob($path."*".$sep."Driver.php") as $file) {
|
|
||||||
$name = basename(dirname($file));
|
|
||||||
$class = NS_BASE."User\\$name\\Driver";
|
|
||||||
$classes[$class] = $class::driverName();
|
|
||||||
}
|
|
||||||
return $classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct(\JKingWeb\Arsse\User\Driver $driver = null) {
|
public function __construct(\JKingWeb\Arsse\User\Driver $driver = null) {
|
||||||
$this->u = $driver ?? new Arsse::$conf->userDriver;
|
$this->u = $driver ?? new Arsse::$conf->userDriver;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,6 @@ trait SeriesMiscellany {
|
||||||
protected function tearDownSeriesMiscellany() {
|
protected function tearDownSeriesMiscellany() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testListDrivers() {
|
|
||||||
$exp = [
|
|
||||||
'JKingWeb\\Arsse\\Db\\SQLite3\\Driver' => Arsse::$lang->msg("Driver.Db.SQLite3.Name"),
|
|
||||||
];
|
|
||||||
$this->assertArraySubset($exp, Database::driverList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testInitializeDatabase() {
|
public function testInitializeDatabase() {
|
||||||
static::dbRaze(static::$drv);
|
static::dbRaze(static::$drv);
|
||||||
$d = new Database(true);
|
$d = new Database(true);
|
||||||
|
|
|
@ -10,7 +10,6 @@ namespace JKingWeb\Arsse\TestCase\Db\MySQL;
|
||||||
* @group slow
|
* @group slow
|
||||||
* @group coverageOptional
|
* @group coverageOptional
|
||||||
* @covers \JKingWeb\Arsse\Database<extended>
|
* @covers \JKingWeb\Arsse\Database<extended>
|
||||||
* @covers \JKingWeb\Arsse\Misc\Query<extended>
|
|
||||||
*/
|
*/
|
||||||
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
||||||
use \JKingWeb\Arsse\Test\DatabaseDrivers\MySQL;
|
use \JKingWeb\Arsse\Test\DatabaseDrivers\MySQL;
|
||||||
|
|
|
@ -11,7 +11,6 @@ namespace JKingWeb\Arsse\TestCase\Db\MySQLPDO;
|
||||||
* @group optional
|
* @group optional
|
||||||
* @group coverageOptional
|
* @group coverageOptional
|
||||||
* @covers \JKingWeb\Arsse\Database<extended>
|
* @covers \JKingWeb\Arsse\Database<extended>
|
||||||
* @covers \JKingWeb\Arsse\Misc\Query<extended>
|
|
||||||
*/
|
*/
|
||||||
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
||||||
use \JKingWeb\Arsse\Test\DatabaseDrivers\MySQLPDO;
|
use \JKingWeb\Arsse\Test\DatabaseDrivers\MySQLPDO;
|
||||||
|
|
|
@ -10,7 +10,6 @@ namespace JKingWeb\Arsse\TestCase\Db\PostgreSQL;
|
||||||
* @group slow
|
* @group slow
|
||||||
* @group coverageOptional
|
* @group coverageOptional
|
||||||
* @covers \JKingWeb\Arsse\Database<extended>
|
* @covers \JKingWeb\Arsse\Database<extended>
|
||||||
* @covers \JKingWeb\Arsse\Misc\Query<extended>
|
|
||||||
*/
|
*/
|
||||||
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
||||||
use \JKingWeb\Arsse\Test\DatabaseDrivers\PostgreSQL;
|
use \JKingWeb\Arsse\Test\DatabaseDrivers\PostgreSQL;
|
||||||
|
|
|
@ -11,7 +11,6 @@ namespace JKingWeb\Arsse\TestCase\Db\PostgreSQLPDO;
|
||||||
* @group optional
|
* @group optional
|
||||||
* @group coverageOptional
|
* @group coverageOptional
|
||||||
* @covers \JKingWeb\Arsse\Database<extended>
|
* @covers \JKingWeb\Arsse\Database<extended>
|
||||||
* @covers \JKingWeb\Arsse\Misc\Query<extended>
|
|
||||||
*/
|
*/
|
||||||
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
||||||
use \JKingWeb\Arsse\Test\DatabaseDrivers\PostgreSQLPDO;
|
use \JKingWeb\Arsse\Test\DatabaseDrivers\PostgreSQLPDO;
|
||||||
|
|
|
@ -9,7 +9,6 @@ namespace JKingWeb\Arsse\TestCase\Db\SQLite3;
|
||||||
/**
|
/**
|
||||||
* @group optional
|
* @group optional
|
||||||
* @covers \JKingWeb\Arsse\Database<extended>
|
* @covers \JKingWeb\Arsse\Database<extended>
|
||||||
* @covers \JKingWeb\Arsse\Misc\Query<extended>
|
|
||||||
*/
|
*/
|
||||||
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
||||||
use \JKingWeb\Arsse\Test\DatabaseDrivers\SQLite3;
|
use \JKingWeb\Arsse\Test\DatabaseDrivers\SQLite3;
|
||||||
|
|
|
@ -8,7 +8,6 @@ namespace JKingWeb\Arsse\TestCase\Db\SQLite3PDO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers \JKingWeb\Arsse\Database<extended>
|
* @covers \JKingWeb\Arsse\Database<extended>
|
||||||
* @covers \JKingWeb\Arsse\Misc\Query<extended>
|
|
||||||
*/
|
*/
|
||||||
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\AbstractTest {
|
||||||
use \JKingWeb\Arsse\Test\DatabaseDrivers\SQLite3PDO;
|
use \JKingWeb\Arsse\Test\DatabaseDrivers\SQLite3PDO;
|
||||||
|
|
115
tests/cases/Misc/TestQuery.php
Normal file
115
tests/cases/Misc/TestQuery.php
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
<?php
|
||||||
|
/** @license MIT
|
||||||
|
* Copyright 2017 J. King, Dustin Wilson et al.
|
||||||
|
* See LICENSE and AUTHORS files for details */
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
namespace JKingWeb\Arsse\TestCase\Misc;
|
||||||
|
|
||||||
|
use JKingWeb\Arsse\Misc\Query;
|
||||||
|
use JKingWeb\Arsse\Misc\ValueInfo;
|
||||||
|
|
||||||
|
/** @covers \JKingWeb\Arsse\Misc\Query */
|
||||||
|
class TestQuery extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
public function testBasicQuery() {
|
||||||
|
$q = new Query("select * from table where a = ?", "int", 3);
|
||||||
|
$this->assertSame("select * from table where a = ?", $q->getQuery());
|
||||||
|
$this->assertSame(["int"], $q->getTypes());
|
||||||
|
$this->assertSame([3], $q->getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWhereQuery() {
|
||||||
|
// simple where clause
|
||||||
|
$q = (new Query("select * from table"))->setWhere("a = ?", "int", 3);
|
||||||
|
$this->assertSame("select * from table WHERE a = ?", $q->getQuery());
|
||||||
|
$this->assertSame(["int"], $q->getTypes());
|
||||||
|
$this->assertSame([3], $q->getValues());
|
||||||
|
// compound where clause
|
||||||
|
$q = (new Query("select * from table"))->setWhere("a = ?", "int", 3)->setWhere("b = ?", "str", 4);
|
||||||
|
$this->assertSame("select * from table WHERE a = ? AND b = ?", $q->getQuery());
|
||||||
|
$this->assertSame(["int", "str"], $q->getTypes());
|
||||||
|
$this->assertSame([3, 4], $q->getValues());
|
||||||
|
// negative where clause
|
||||||
|
$q = (new Query("select * from table"))->setWhereNot("a = ?", "int", 3);
|
||||||
|
$this->assertSame("select * from table WHERE NOT (a = ?)", $q->getQuery());
|
||||||
|
$this->assertSame(["int"], $q->getTypes());
|
||||||
|
$this->assertSame([3], $q->getValues());
|
||||||
|
// compound negative where clause
|
||||||
|
$q = (new Query("select * from table"))->setWhereNot("a = ?", "int", 3)->setWhereNot("b = ?", "str", 4);
|
||||||
|
$this->assertSame("select * from table WHERE NOT (a = ? OR b = ?)", $q->getQuery());
|
||||||
|
$this->assertSame(["int", "str"], $q->getTypes());
|
||||||
|
$this->assertSame([3, 4], $q->getValues());
|
||||||
|
// mixed where clause
|
||||||
|
$q = (new Query("select * from table"))->setWhereNot("a = ?", "int", 1)->setWhere("b = ?", "str", 2)->setWhereNot("c = ?", "int", 3)->setWhere("d = ?", "str", 4);
|
||||||
|
$this->assertSame("select * from table WHERE b = ? AND d = ? AND NOT (a = ? OR c = ?)", $q->getQuery());
|
||||||
|
$this->assertSame(["str", "str", "int", "int"], $q->getTypes());
|
||||||
|
$this->assertSame([2, 4, 1, 3], $q->getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGroupedQuery() {
|
||||||
|
$q = (new Query("select col1, col2, count(*) as count from table"))->setGroup("col1", "col2");
|
||||||
|
$this->assertSame("select col1, col2, count(*) as count from table GROUP BY col1, col2", $q->getQuery());
|
||||||
|
$this->assertSame([], $q->getTypes());
|
||||||
|
$this->assertSame([], $q->getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOrderedQuery() {
|
||||||
|
$q = (new Query("select col1, col2, col3 from table"))->setOrder("col1 desc", "col2")->setOrder("col3 asc");
|
||||||
|
$this->assertSame("select col1, col2, col3 from table ORDER BY col1 desc, col2, col3 asc", $q->getQuery());
|
||||||
|
$this->assertSame([], $q->getTypes());
|
||||||
|
$this->assertSame([], $q->getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLimitedQuery() {
|
||||||
|
// no offset
|
||||||
|
$q = (new Query("select * from table"))->setLimit(5);
|
||||||
|
$this->assertSame("select * from table LIMIT 5", $q->getQuery());
|
||||||
|
$this->assertSame([], $q->getTypes());
|
||||||
|
$this->assertSame([], $q->getValues());
|
||||||
|
// with offset
|
||||||
|
$q = (new Query("select * from table"))->setLimit(5, 10);
|
||||||
|
$this->assertSame("select * from table LIMIT 5 OFFSET 10", $q->getQuery());
|
||||||
|
$this->assertSame([], $q->getTypes());
|
||||||
|
$this->assertSame([], $q->getValues());
|
||||||
|
// no limit with offset
|
||||||
|
$q = (new Query("select * from table"))->setLimit(0, 10);
|
||||||
|
$this->assertSame("select * from table LIMIT -1 OFFSET 10", $q->getQuery());
|
||||||
|
$this->assertSame([], $q->getTypes());
|
||||||
|
$this->assertSame([], $q->getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testQueryWithCommonTableExpression() {
|
||||||
|
$q = (new Query("select * from table where a in (select * from cte where a = ?)", "int", 1))->setCTE("cte", "select * from other_table where a = ? and b = ?", ["str", "str"], [2, 3]);
|
||||||
|
$this->assertSame("WITH RECURSIVE cte as (select * from other_table where a = ? and b = ?) select * from table where a in (select * from cte where a = ?)", $q->getQuery());
|
||||||
|
$this->assertSame(["str", "str", "int"], $q->getTypes());
|
||||||
|
$this->assertSame([2, 3, 1], $q->getValues());
|
||||||
|
// multiple CTEs
|
||||||
|
$q = (new Query("select * from table where a in (select * from cte1 join cte2 using (a) where a = ?)", "int", 1))->setCTE("cte1", "select * from other_table where a = ? and b = ?", ["str", "str"], [2, 3])->setCTE("cte2", "select * from other_table where c between ? and ?", ["datetime", "datetime"], [4, 5]);
|
||||||
|
$this->assertSame("WITH RECURSIVE cte1 as (select * from other_table where a = ? and b = ?), cte2 as (select * from other_table where c between ? and ?) select * from table where a in (select * from cte1 join cte2 using (a) where a = ?)", $q->getQuery());
|
||||||
|
$this->assertSame(["str", "str", "datetime", "datetime", "int"], $q->getTypes());
|
||||||
|
$this->assertSame([2, 3, 4, 5, 1], $q->getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testQueryWithPushedCommonTableExpression() {
|
||||||
|
$q = (new Query("select * from table1"))->setWhere("a between ? and ?", ["datetime", "datetime"], [1, 2])
|
||||||
|
->setCTE("cte1", "select * from table2 where a = ? and b = ?", ["str", "str"], [3, 4])
|
||||||
|
->pushCTE("cte2")
|
||||||
|
->setBody("select * from table3 join cte1 using (a) join cte2 using (a) where a = ?", "int", 5);
|
||||||
|
$this->assertSame("WITH RECURSIVE cte1 as (select * from table2 where a = ? and b = ?), cte2 as (select * from table1 WHERE a between ? and ?) select * from table3 join cte1 using (a) join cte2 using (a) where a = ?", $q->getQuery());
|
||||||
|
$this->assertSame(["str", "str", "datetime", "datetime", "int"], $q->getTypes());
|
||||||
|
$this->assertSame([3, 4, 1, 2, 5], $q->getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testComplexQuery() {
|
||||||
|
$q = (new query("select *, ? as const from table", "datetime", 1))
|
||||||
|
->setWhereNot("b = ?", "bool", 2)
|
||||||
|
->setGroup("col1", "col2")
|
||||||
|
->setWhere("a = ?", "str", 3)
|
||||||
|
->setLimit(4, 5)
|
||||||
|
->setOrder("col3")
|
||||||
|
->setCTE("cte", "select ? as const", "int", 6);
|
||||||
|
$this->assertSame("WITH RECURSIVE cte as (select ? as const) select *, ? as const from table WHERE a = ? AND NOT (b = ?) GROUP BY col1, col2 ORDER BY col3 LIMIT 4 OFFSET 5", $q->getQuery());
|
||||||
|
$this->assertSame(["int", "datetime", "str", "bool"], $q->getTypes());
|
||||||
|
$this->assertSame([6, 1, 3, 2], $q->getValues());
|
||||||
|
}
|
||||||
|
}
|
|
@ -92,4 +92,21 @@ class TestURL extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
["/#ack", "", "/#ack"],
|
["/#ack", "", "/#ack"],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @dataProvider provideAbsolutes */
|
||||||
|
public function testDetermineAbsoluteness(bool $exp, string $url) {
|
||||||
|
$this->assertSame($exp, URL::absolute($url));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideAbsolutes() {
|
||||||
|
return [
|
||||||
|
[true, "http://example.com/"],
|
||||||
|
[true, "HTTP://example.com/"],
|
||||||
|
[false, "//example.com/"],
|
||||||
|
[false, "/example"],
|
||||||
|
[false, "example.com/"],
|
||||||
|
[false, "example.com"],
|
||||||
|
[false, "http:///example"],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -639,4 +639,10 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$out->f = $msec;
|
$out->f = $msec;
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFlattenArray() {
|
||||||
|
$arr = [1, [2, 3, [4, 5]], 6, [[7, 8], 9, 10]];
|
||||||
|
$exp = range(1,10);
|
||||||
|
$this->assertSame($exp, I::flatten($arr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
47
tests/cases/Service/TestSerial.php
Normal file
47
tests/cases/Service/TestSerial.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
/** @license MIT
|
||||||
|
* Copyright 2017 J. King, Dustin Wilson et al.
|
||||||
|
* See LICENSE and AUTHORS files for details */
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
namespace JKingWeb\Arsse\TestCase\Service;
|
||||||
|
|
||||||
|
use JKingWeb\Arsse\Arsse;
|
||||||
|
use JKingWeb\Arsse\Database;
|
||||||
|
use JKingWeb\Arsse\Service\Driver as DriverInterface;
|
||||||
|
use JKingWeb\Arsse\Service\Serial\Driver;
|
||||||
|
|
||||||
|
/** @covers \JKingWeb\Arsse\Service\Serial\Driver */
|
||||||
|
class TestSerial extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
public function setUp() {
|
||||||
|
self::clearData();
|
||||||
|
self::setConf();
|
||||||
|
Arsse::$db = \Phake::mock(Database::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConstruct() {
|
||||||
|
$this->assertTrue(Driver::requirementsMet());
|
||||||
|
$this->assertInstanceOf(DriverInterface::class, new Driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFetchDriverName() {
|
||||||
|
$this->assertTrue(strlen(Driver::driverName()) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEnqueueFeeds() {
|
||||||
|
$d = new Driver;
|
||||||
|
$this->assertSame(3, $d->queue(1, 2, 3));
|
||||||
|
$this->assertSame(5, $d->queue(4, 5));
|
||||||
|
$this->assertSame(5, $d->clean());
|
||||||
|
$this->assertSame(1, $d->queue(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRefreshFeeds() {
|
||||||
|
$d = new Driver;
|
||||||
|
$d->queue(1, 4, 3);
|
||||||
|
$this->assertSame(Arsse::$conf->serviceQueueWidth, $d->exec());
|
||||||
|
\Phake::verify(Arsse::$db)->feedUpdate(1);
|
||||||
|
\Phake::verify(Arsse::$db)->feedUpdate(4);
|
||||||
|
\Phake::verify(Arsse::$db)->feedUpdate(3);
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,4 +39,45 @@ class TestService extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$this->assertTrue(Service::hasCheckedIn());
|
$this->assertTrue(Service::hasCheckedIn());
|
||||||
$this->assertFalse(Service::hasCheckedIn());
|
$this->assertFalse(Service::hasCheckedIn());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testPerformPreCleanup() {
|
||||||
|
$this->assertTrue(Service::cleanupPre());
|
||||||
|
\Phake::verify(Arsse::$db)->feedCleanup();
|
||||||
|
\Phake::verify(Arsse::$db)->sessionCleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPerformShortPostCleanup() {
|
||||||
|
\Phake::when(Arsse::$db)->articleCleanup()->thenReturn(0);
|
||||||
|
$this->assertTrue(Service::cleanupPost());
|
||||||
|
\Phake::verify(Arsse::$db)->articleCleanup();
|
||||||
|
\Phake::verify(Arsse::$db, \Phake::times(0))->driverMaintenance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPerformFullPostCleanup() {
|
||||||
|
\Phake::when(Arsse::$db)->articleCleanup()->thenReturn(1);
|
||||||
|
$this->assertTrue(Service::cleanupPost());
|
||||||
|
\Phake::verify(Arsse::$db)->articleCleanup();
|
||||||
|
\Phake::verify(Arsse::$db)->driverMaintenance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRefreshFeeds() {
|
||||||
|
// set up mock database actions
|
||||||
|
\Phake::when(Arsse::$db)->metaSet->thenReturn(true);
|
||||||
|
\Phake::when(Arsse::$db)->feedCleanup->thenReturn(true);
|
||||||
|
\Phake::when(Arsse::$db)->sessionCleanup->thenReturn(true);
|
||||||
|
\Phake::when(Arsse::$db)->articleCleanup->thenReturn(0);
|
||||||
|
\Phake::when(Arsse::$db)->feedListStale->thenReturn([1,2,3]);
|
||||||
|
// perform the test
|
||||||
|
$d = \Phake::mock(\JKingWeb\Arsse\Service\Driver::class);
|
||||||
|
$s = new \JKingWeb\Arsse\Test\Service($d);
|
||||||
|
$this->assertInstanceOf(\DateTimeInterface::class, $s->watch(false));
|
||||||
|
// verify invocations
|
||||||
|
\Phake::verify($d)->queue(1, 2, 3);
|
||||||
|
\Phake::verify($d)->exec();
|
||||||
|
\Phake::verify($d)->clean();
|
||||||
|
\Phake::verify(Arsse::$db)->feedCleanup();
|
||||||
|
\Phake::verify(Arsse::$db)->sessionCleanup();
|
||||||
|
\Phake::verify(Arsse::$db)->articleCleanup();
|
||||||
|
\Phake::verify(Arsse::$db)->metaSet("service_last_checkin", $this->anything(), "datetime");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
48
tests/cases/Service/TestSubprocess.php
Normal file
48
tests/cases/Service/TestSubprocess.php
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
/** @license MIT
|
||||||
|
* Copyright 2017 J. King, Dustin Wilson et al.
|
||||||
|
* See LICENSE and AUTHORS files for details */
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
namespace JKingWeb\Arsse\TestCase\Service;
|
||||||
|
|
||||||
|
use JKingWeb\Arsse\Arsse;
|
||||||
|
use JKingWeb\Arsse\Database;
|
||||||
|
use JKingWeb\Arsse\Service\Driver as DriverInterface;
|
||||||
|
use JKingWeb\Arsse\Service\Subprocess\Driver;
|
||||||
|
|
||||||
|
/** @covers \JKingWeb\Arsse\Service\Subprocess\Driver */
|
||||||
|
class TestSubprocess extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
public function setUp() {
|
||||||
|
self::clearData();
|
||||||
|
self::setConf();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConstruct() {
|
||||||
|
$this->assertTrue(Driver::requirementsMet());
|
||||||
|
$this->assertInstanceOf(DriverInterface::class, new Driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFetchDriverName() {
|
||||||
|
$this->assertTrue(strlen(Driver::driverName()) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEnqueueFeeds() {
|
||||||
|
$d = new Driver;
|
||||||
|
$this->assertSame(3, $d->queue(1, 2, 3));
|
||||||
|
$this->assertSame(5, $d->queue(4, 5));
|
||||||
|
$this->assertSame(5, $d->clean());
|
||||||
|
$this->assertSame(1, $d->queue(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRefreshFeeds() {
|
||||||
|
$d = \Phake::partialMock(Driver::class);
|
||||||
|
\Phake::when($d)->execCmd->thenReturnCallback(function(string $cmd) {
|
||||||
|
// FIXME: Does this work in Windows?
|
||||||
|
return popen("echo ".escapeshellarg($cmd), "r");
|
||||||
|
});
|
||||||
|
$this->assertSame(3, $d->queue(1, 4, 3));
|
||||||
|
$this->assertSame(Arsse::$conf->serviceQueueWidth, $d->exec());
|
||||||
|
\Phake::verify($d, \Phake::times(3))->execCmd;
|
||||||
|
}
|
||||||
|
}
|
50
tests/cases/TestArsse.php
Normal file
50
tests/cases/TestArsse.php
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
/** @license MIT
|
||||||
|
* Copyright 2017 J. King, Dustin Wilson et al.
|
||||||
|
* See LICENSE and AUTHORS files for details */
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
namespace JKingWeb\Arsse\TestCase;
|
||||||
|
|
||||||
|
use JKingWeb\Arsse\Arsse;
|
||||||
|
use JKingWeb\Arsse\Conf;
|
||||||
|
use JKingWeb\Arsse\Lang;
|
||||||
|
use JKingWeb\Arsse\User;
|
||||||
|
use JKingWeb\Arsse\Database;
|
||||||
|
use JKingWeb\Arsse\Service;
|
||||||
|
|
||||||
|
/** @covers \JKingWeb\Arsse\Arsse */
|
||||||
|
class TestArsse extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
public function setUp() {
|
||||||
|
self::clearData(false);
|
||||||
|
}
|
||||||
|
public function tearDown() {
|
||||||
|
self::clearData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLoadExistingData() {
|
||||||
|
$lang = Arsse::$lang = \Phake::mock(Lang::class);
|
||||||
|
$db = Arsse::$db = \Phake::mock(Database::class);
|
||||||
|
$user = Arsse::$user = \Phake::mock(User::class);
|
||||||
|
$conf1 = Arsse::$conf = \Phake::mock(Conf::class);
|
||||||
|
$conf2 = (new Conf)->import(['lang' => "test"]);
|
||||||
|
Arsse::load($conf2);
|
||||||
|
$this->assertSame($conf2, Arsse::$conf);
|
||||||
|
$this->assertSame($lang, Arsse::$lang);
|
||||||
|
$this->assertSame($db, Arsse::$db);
|
||||||
|
$this->assertSame($user, Arsse::$user);
|
||||||
|
\Phake::verify($lang)->set("test");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLoadNewData() {
|
||||||
|
if (!\JKingWeb\Arsse\Db\SQLite3\Driver::requirementsMet() && !\JKingWeb\Arsse\Db\SQLite3\PDODriver::requirementsMet()) {
|
||||||
|
$this->markTestSkipped("A functional SQLite interface is required for this test");
|
||||||
|
}
|
||||||
|
$conf = (new Conf)->import(['dbSQLite3File' => ":memory:"]);
|
||||||
|
Arsse::load($conf);
|
||||||
|
$this->assertInstanceOf(Conf::class, Arsse::$conf);
|
||||||
|
$this->assertInstanceOf(Lang::class, Arsse::$lang);
|
||||||
|
$this->assertInstanceOf(Database::class, Arsse::$db);
|
||||||
|
$this->assertInstanceOf(User::class, Arsse::$user);
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,13 +24,6 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$this->drv = \Phake::mock(Driver::class);
|
$this->drv = \Phake::mock(Driver::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testListDrivers() {
|
|
||||||
$exp = [
|
|
||||||
'JKingWeb\\Arsse\\User\\Internal\\Driver' => Arsse::$lang->msg("Driver.User.Internal.Name"),
|
|
||||||
];
|
|
||||||
$this->assertArraySubset($exp, User::driverList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testConstruct() {
|
public function testConstruct() {
|
||||||
$this->assertInstanceOf(User::class, new User($this->drv));
|
$this->assertInstanceOf(User::class, new User($this->drv));
|
||||||
$this->assertInstanceOf(User::class, new User);
|
$this->assertInstanceOf(User::class, new User);
|
||||||
|
|
13
tests/lib/Service.php
Normal file
13
tests/lib/Service.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
/** @license MIT
|
||||||
|
* Copyright 2017 J. King, Dustin Wilson et al.
|
||||||
|
* See LICENSE and AUTHORS files for details */
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
namespace JKingWeb\Arsse\Test;
|
||||||
|
|
||||||
|
class Service extends \JKingWeb\Arsse\Service {
|
||||||
|
public function __construct(\JKingWeb\Arsse\Service\Driver $drv) {
|
||||||
|
$this->drv = $drv;
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,7 @@
|
||||||
<testsuite name="Sundry">
|
<testsuite name="Sundry">
|
||||||
<file>cases/Misc/TestValueInfo.php</file>
|
<file>cases/Misc/TestValueInfo.php</file>
|
||||||
<file>cases/Misc/TestDate.php</file>
|
<file>cases/Misc/TestDate.php</file>
|
||||||
|
<file>cases/Misc/TestQuery.php</file>
|
||||||
<file>cases/Misc/TestContext.php</file>
|
<file>cases/Misc/TestContext.php</file>
|
||||||
<file>cases/Misc/TestURL.php</file>
|
<file>cases/Misc/TestURL.php</file>
|
||||||
<file>cases/Misc/TestHTTP.php</file>
|
<file>cases/Misc/TestHTTP.php</file>
|
||||||
|
@ -131,7 +132,10 @@
|
||||||
</testsuite>
|
</testsuite>
|
||||||
<testsuite name="Admin tools">
|
<testsuite name="Admin tools">
|
||||||
<file>cases/Service/TestService.php</file>
|
<file>cases/Service/TestService.php</file>
|
||||||
|
<file>cases/Service/TestSerial.php</file>
|
||||||
|
<file>cases/Service/TestSubprocess.php</file>
|
||||||
<file>cases/CLI/TestCLI.php</file>
|
<file>cases/CLI/TestCLI.php</file>
|
||||||
|
<file>cases/TestArsse.php</file>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
<testsuite name="Import/Export">
|
<testsuite name="Import/Export">
|
||||||
<file>cases/ImportExport/TestFile.php</file>
|
<file>cases/ImportExport/TestFile.php</file>
|
||||||
|
|
Loading…
Reference in a new issue