@@ -17,6 +17,7 @@ $paths = [ | |||
$rules = [ | |||
'@PSR2' => true, | |||
'braces' => ['position_after_functions_and_oop_constructs' => "same"], | |||
'function_declaration' => ['closure_function_spacing' => "none"], | |||
]; | |||
$finder = \PhpCsFixer\Finder::create(); |
@@ -61,7 +61,7 @@ class RoboFile extends \Robo\Tasks { | |||
* coverage may be skipped, while working alternatives are normally | |||
* suppressed for reasons of time. This coverage report will try to | |||
* run all tests which may cover code. | |||
* | |||
* | |||
* See also help for the "coverage" task for more details. | |||
*/ | |||
public function coverageFull(array $args): Result { |
@@ -808,20 +808,20 @@ class Database { | |||
$greatest = $this->db->sqlToken("greatest"); | |||
// prepare the output column list | |||
$colDefs = [ | |||
'id' => "arsse_articles.id", | |||
'edition' => "latest_editions.edition", | |||
'url' => "arsse_articles.url", | |||
'title' => "arsse_articles.title", | |||
'author' => "arsse_articles.author", | |||
'content' => "arsse_articles.content", | |||
'guid' => "arsse_articles.guid", | |||
'id' => "arsse_articles.id", | |||
'edition' => "latest_editions.edition", | |||
'url' => "arsse_articles.url", | |||
'title' => "arsse_articles.title", | |||
'author' => "arsse_articles.author", | |||
'content' => "arsse_articles.content", | |||
'guid' => "arsse_articles.guid", | |||
'fingerprint' => "arsse_articles.url_title_hash || ':' || arsse_articles.url_content_hash || ':' || arsse_articles.title_content_hash", | |||
'subscription' => "arsse_subscriptions.id", | |||
'feed' => "arsse_subscriptions.feed", | |||
'starred' => "coalesce(arsse_marks.starred,0)", | |||
'unread' => "abs(coalesce(arsse_marks.read,0) - 1)", | |||
'note' => "coalesce(arsse_marks.note,'')", | |||
'published_date' => "arsse_articles.published", | |||
'published_date' => "arsse_articles.published", | |||
'edited_date' => "arsse_articles.edited", | |||
'modified_date' => "arsse_articles.modified", | |||
'marked_date' => "$greatest(arsse_articles.modified, coalesce(arsse_marks.modified, '0001-01-01 00:00:00'), coalesce(arsse_label_members.modified, '0001-01-01 00:00:00'))", | |||
@@ -855,7 +855,8 @@ class Database { | |||
left join arsse_enclosures on arsse_enclosures.article = arsse_articles.id | |||
left join arsse_label_members on arsse_label_members.subscription = arsse_subscriptions.id and arsse_label_members.article = arsse_articles.id and arsse_label_members.assigned = 1 | |||
left join arsse_labels on arsse_labels.owner = arsse_subscriptions.owner and arsse_label_members.label = arsse_labels.id", | |||
["str"], [$user] | |||
["str"], | |||
[$user] | |||
); | |||
$q->setCTE("latest_editions(article,edition)", "SELECT article,max(id) from arsse_editions group by article", [], [], "join latest_editions on arsse_articles.id = latest_editions.article"); | |||
if ($cols) { |
@@ -16,7 +16,7 @@ class ResultAggregate extends AbstractResult { | |||
// actual public methods | |||
public function changes(): int { | |||
return array_reduce($this->data, function ($sum, $value) { | |||
return array_reduce($this->data, function($sum, $value) { | |||
return $sum + $value->changes(); | |||
}, 0); | |||
} |
@@ -104,7 +104,7 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver { | |||
} | |||
public function sqlToken(string $token): string { | |||
switch(strtolower($token)) { | |||
switch (strtolower($token)) { | |||
case "greatest": | |||
return "max"; | |||
default: |
@@ -140,7 +140,7 @@ class Lang { | |||
protected function listFiles(): array { | |||
$out = $this->globFiles($this->path."*.php"); | |||
// trim the returned file paths to return just the language tag | |||
$out = array_map(function ($file) { | |||
$out = array_map(function($file) { | |||
$file = str_replace(DIRECTORY_SEPARATOR, "/", $file); // we replace the directory separator because we don't use native paths in testing | |||
$file = substr($file, strrpos($file, "/")+1); | |||
return strtolower(substr($file, 0, strrpos($file, "."))); |
@@ -97,7 +97,7 @@ class REST { | |||
public function apiMatch(string $url): array { | |||
$map = $this->apis; | |||
// sort the API list so the longest URL prefixes come first | |||
uasort($map, function ($a, $b) { | |||
uasort($map, function($a, $b) { | |||
return (strlen($a['match']) <=> strlen($b['match'])) * -1; | |||
}); | |||
// normalize the target URL | |||
@@ -270,7 +270,7 @@ class REST { | |||
} else { | |||
// if the host is a domain name or IP address, split it along dots and just perform URL decoding | |||
$host = explode(".", $host); | |||
$host = array_map(function ($segment) { | |||
$host = array_map(function($segment) { | |||
return str_replace(".", "%2E", rawurlencode(strtolower(rawurldecode($segment)))); | |||
}, $host); | |||
$host = implode(".", $host); |
@@ -330,7 +330,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { | |||
'id' => "FEED:".self::FEED_ALL, | |||
'bare_id' => self::FEED_ALL, | |||
'icon' => "images/folder.png", | |||
'unread' => array_reduce($subs, function ($sum, $value) { | |||
'unread' => array_reduce($subs, function($sum, $value) { | |||
return $sum + $value['unread']; | |||
}, 0), // the sum of all feeds' unread is the total unread | |||
], $tSpecial), |
@@ -9,7 +9,6 @@ namespace JKingWeb\Arsse; | |||
use PasswordGenerator\Generator as PassGen; | |||
class User { | |||
public $id = null; | |||
/** |
@@ -16,7 +16,6 @@ use Phake; | |||
/** @covers \JKingWeb\Arsse\CLI */ | |||
class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest { | |||
public function setUp() { | |||
self::clearData(false); | |||
} | |||
@@ -25,7 +24,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest { | |||
$argv = \Clue\Arguments\split($command); | |||
$output = strlen($output) ? $output.\PHP_EOL : ""; | |||
if ($pattern) { | |||
$this->expectOutputRegex($output); | |||
$this->expectOutputRegex($output); | |||
} else { | |||
$this->expectOutputString($output); | |||
} |
@@ -15,7 +15,7 @@ use JKingWeb\Arsse\Db\Result; | |||
use JKingWeb\Arsse\Test\DatabaseInformation; | |||
use Phake; | |||
abstract class Base extends \JKingWeb\Arsse\Test\AbstractTest{ | |||
abstract class Base extends \JKingWeb\Arsse\Test\AbstractTest { | |||
use SeriesMiscellany; | |||
use SeriesMeta; | |||
use SeriesUser; | |||
@@ -34,7 +34,7 @@ abstract class Base extends \JKingWeb\Arsse\Test\AbstractTest{ | |||
protected static $failureReason = ""; | |||
protected $primed = false; | |||
protected abstract function nextID(string $table): int; | |||
abstract protected function nextID(string $table): int; | |||
protected function findTraitOfTest(string $test): string { | |||
$class = new \ReflectionClass(self::class); | |||
@@ -50,7 +50,7 @@ abstract class Base extends \JKingWeb\Arsse\Test\AbstractTest{ | |||
// establish a clean baseline | |||
static::clearData(); | |||
// perform an initial connection to the database to reset its version to zero | |||
// in the case of SQLite this will always be the case (we use a memory database), | |||
// in the case of SQLite this will always be the case (we use a memory database), | |||
// but other engines should clean up from potentially interrupted prior tests | |||
static::$dbInfo = new DatabaseInformation(static::$implementation); | |||
static::setConf(); |
@@ -411,7 +411,7 @@ trait SeriesArticle { | |||
305 => 105, | |||
1001 => 20, | |||
]; | |||
$this->assertEquals($exp, Arsse::$db->editionArticle(...range(1,1001))); | |||
$this->assertEquals($exp, Arsse::$db->editionArticle(...range(1, 1001))); | |||
} | |||
public function testListArticlesCheckingContext() { |
@@ -12,7 +12,6 @@ use JKingWeb\Arsse\Feed\Exception as FeedException; | |||
use Phake; | |||
trait SeriesSubscription { | |||
public function setUpSeriesSubscription() { | |||
$this->data = [ | |||
'arsse_users' => [ |
@@ -76,7 +76,7 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest { | |||
return static::$interface->query($q)->fetchColumn(); | |||
} | |||
# TESTS | |||
# TESTS | |||
public function testFetchDriverName() { | |||
$class = get_class($this->drv); | |||
@@ -115,7 +115,7 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest { | |||
$this->exec($this->create); | |||
$this->exec($this->lock); | |||
$this->assertException("general", "Db", "ExceptionTimeout"); | |||
$lock = is_array($this->lock) ? implode("; ",$this->lock) : $this->lock; | |||
$lock = is_array($this->lock) ? implode("; ", $this->lock) : $this->lock; | |||
$this->drv->exec($lock); | |||
} | |||
@@ -144,7 +144,7 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest { | |||
$this->exec($this->create); | |||
$this->exec($this->lock); | |||
$this->assertException("general", "Db", "ExceptionTimeout"); | |||
$lock = is_array($this->lock) ? implode("; ",$this->lock) : $this->lock; | |||
$lock = is_array($this->lock) ? implode("; ", $this->lock) : $this->lock; | |||
$this->drv->exec($lock); | |||
} | |||
@@ -275,7 +275,6 @@ abstract class BaseStatement extends \JKingWeb\Arsse\Test\AbstractTest { | |||
]; | |||
foreach ($tests as $index => list($value, $type, $exp)) { | |||
$t = preg_replace("<^strict >", "", $type); | |||
if (gettype($exp) != "string") var_export($index); | |||
$exp = ($exp=="null") ? $exp : $this->decorateTypeSyntax($exp, $t); | |||
yield $index => [$value, $type, $exp]; | |||
} | |||
@@ -327,7 +326,6 @@ abstract class BaseStatement extends \JKingWeb\Arsse\Test\AbstractTest { | |||
]; | |||
foreach ($tests as $index => list($value, $type, $exp)) { | |||
$t = preg_replace("<^strict >", "", $type); | |||
if (gettype($exp) != "string") var_export($index); | |||
$exp = ($exp=="null") ? $exp : $this->decorateTypeSyntax($exp, $t); | |||
yield $index => [$value, $type, $exp]; | |||
} |
@@ -21,7 +21,7 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest { | |||
if ($act==$postfix) { | |||
$this->assertSame($exp, ""); | |||
} else { | |||
$test = substr($act, 0, strlen($act) - (strlen($postfix) + 1) ); | |||
$test = substr($act, 0, strlen($act) - (strlen($postfix) + 1)); | |||
$check = substr($act, strlen($test) + 1); | |||
$this->assertSame($postfix, $check); | |||
$this->assertSame($exp, $test); |
@@ -6,7 +6,7 @@ | |||
declare(strict_types=1); | |||
namespace JKingWeb\Arsse\TestCase\Db\PosgreSQL; | |||
/** | |||
/** | |||
* @group excludeFromCoverage | |||
* @covers \JKingWeb\Arsse\Database<extended> | |||
* @covers \JKingWeb\Arsse\Misc\Query<extended> | |||
@@ -20,7 +20,7 @@ class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\Base { | |||
public function setUp() { | |||
parent::setUp(); | |||
$seqList = | |||
$seqList = | |||
"select | |||
replace(substring(column_default, 10), right(column_default, 12), '') as seq, | |||
table_name as table, | |||
@@ -30,7 +30,7 @@ class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\Base { | |||
and table_name like 'arsse_%' | |||
and column_default like 'nextval(%' | |||
"; | |||
foreach(static::$drv->query($seqList) as $r) { | |||
foreach (static::$drv->query($seqList) as $r) { | |||
$num = (int) static::$drv->query("SELECT max({$r['col']}) from {$r['table']}")->getValue(); | |||
if (!$num) { | |||
continue; |
@@ -23,9 +23,8 @@ class TestStatement extends \JKingWeb\Arsse\TestCase\Db\BaseStatement { | |||
case "string": | |||
if (preg_match("<^char\((\d+)\)$>", $value, $match)) { | |||
return "U&'\\+".str_pad(dechex((int) $match[1]), 6, "0", \STR_PAD_LEFT)."'"; | |||
} else { | |||
return $value; | |||
} | |||
return $value; | |||
default: | |||
return $value; | |||
} |
@@ -6,7 +6,7 @@ | |||
declare(strict_types=1); | |||
namespace JKingWeb\Arsse\TestCase\Db\SQLite3; | |||
/** | |||
/** | |||
* @covers \JKingWeb\Arsse\Database<extended> | |||
* @covers \JKingWeb\Arsse\Misc\Query<extended> | |||
*/ |
@@ -8,8 +8,8 @@ namespace JKingWeb\Arsse\TestCase\Db\SQLite3; | |||
use JKingWeb\Arsse\Test\DatabaseInformation; | |||
/** | |||
* @covers \JKingWeb\Arsse\Db\SQLite3\Result<extended> | |||
/** | |||
* @covers \JKingWeb\Arsse\Db\SQLite3\Result<extended> | |||
*/ | |||
class TestResult extends \JKingWeb\Arsse\TestCase\Db\BaseResult { | |||
protected static $implementation = "SQLite 3"; |
@@ -6,7 +6,7 @@ | |||
declare(strict_types=1); | |||
namespace JKingWeb\Arsse\TestCase\Db\SQLite3PDO; | |||
/** | |||
/** | |||
* @covers \JKingWeb\Arsse\Database<extended> | |||
* @covers \JKingWeb\Arsse\Misc\Query<extended> | |||
*/ |
@@ -8,8 +8,8 @@ namespace JKingWeb\Arsse\TestCase\Db; | |||
use JKingWeb\Arsse\Test\DatabaseInformation; | |||
/** | |||
* @covers \JKingWeb\Arsse\Db\PDOResult<extended> | |||
/** | |||
* @covers \JKingWeb\Arsse\Db\PDOResult<extended> | |||
*/ | |||
class TestResultPDO extends \JKingWeb\Arsse\TestCase\Db\BaseResult { | |||
protected static $implementation; |
@@ -153,7 +153,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { | |||
public function testNegotiateCors($origin, bool $exp, string $allowed = null, string $denied = null) { | |||
self::setConf(); | |||
$r = Phake::partialMock(REST::class); | |||
Phake::when($r)->corsNormalizeOrigin->thenReturnCallback(function ($origin) { | |||
Phake::when($r)->corsNormalizeOrigin->thenReturnCallback(function($origin) { | |||
return $origin; | |||
}); | |||
$headers = isset($origin) ? ['Origin' => $origin] : []; | |||
@@ -255,10 +255,10 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { | |||
public function testNormalizeHttpResponses(ResponseInterface $res, ResponseInterface $exp, RequestInterface $req = null) { | |||
$r = Phake::partialMock(REST::class); | |||
Phake::when($r)->corsNegotiate->thenReturn(true); | |||
Phake::when($r)->challenge->thenReturnCallback(function ($res) { | |||
Phake::when($r)->challenge->thenReturnCallback(function($res) { | |||
return $res->withHeader("WWW-Authenticate", "Fake Value"); | |||
}); | |||
Phake::when($r)->corsApply->thenReturnCallback(function ($res) { | |||
Phake::when($r)->corsApply->thenReturnCallback(function($res) { | |||
return $res; | |||
}); | |||
$act = $r->normalizeResponse($res, $req); | |||
@@ -298,10 +298,10 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { | |||
/** @dataProvider provideMockRequests */ | |||
public function testDispatchRequests(ServerRequest $req, string $method, bool $called, string $class = "", string $target ="") { | |||
$r = Phake::partialMock(REST::class); | |||
Phake::when($r)->normalizeResponse->thenReturnCallback(function ($res) { | |||
Phake::when($r)->normalizeResponse->thenReturnCallback(function($res) { | |||
return $res; | |||
}); | |||
Phake::when($r)->authenticateRequest->thenReturnCallback(function ($req) { | |||
Phake::when($r)->authenticateRequest->thenReturnCallback(function($req) { | |||
return $req; | |||
}); | |||
if ($called) { |
@@ -1516,13 +1516,13 @@ LONG_STRING; | |||
} | |||
protected function filterFolders(int $id = null): array { | |||
return array_filter($this->folders, function ($value) use ($id) { | |||
return array_filter($this->folders, function($value) use ($id) { | |||
return $value['parent']==$id; | |||
}); | |||
} | |||
protected function filterSubs(int $folder = null): array { | |||
return array_filter($this->subscriptions, function ($value) use ($folder) { | |||
return array_filter($this->subscriptions, function($value) use ($folder) { | |||
return $value['folder']==$folder; | |||
}); | |||
} | |||
@@ -1532,9 +1532,9 @@ LONG_STRING; | |||
foreach ($this->filterFolders($id) as $f) { | |||
$out += $this->reduceFolders($f['id']); | |||
} | |||
$out += array_reduce(array_filter($this->subscriptions, function ($value) use ($id) { | |||
$out += array_reduce(array_filter($this->subscriptions, function($value) use ($id) { | |||
return $value['folder']==$id; | |||
}), function ($sum, $value) { | |||
}), function($sum, $value) { | |||
return $sum + $value['unread']; | |||
}, 0); | |||
return $out; |
@@ -17,7 +17,6 @@ use Phake; | |||
/** @covers \JKingWeb\Arsse\User\Internal\Driver */ | |||
class TestInternal extends \JKingWeb\Arsse\Test\AbstractTest { | |||
public function setUp() { | |||
self::clearData(); | |||
self::setConf(); | |||
@@ -34,8 +33,8 @@ class TestInternal extends \JKingWeb\Arsse\Test\AbstractTest { | |||
$this->assertTrue(strlen(Driver::driverName()) > 0); | |||
} | |||
/** | |||
* @dataProvider provideAuthentication | |||
/** | |||
* @dataProvider provideAuthentication | |||
* @group slow | |||
*/ | |||
public function testAuthenticateAUser(bool $authorized, string $user, string $password, bool $exp) { |
@@ -17,7 +17,6 @@ use Phake; | |||
/** @covers \JKingWeb\Arsse\User */ | |||
class TestUser extends \JKingWeb\Arsse\Test\AbstractTest { | |||
public function setUp() { | |||
self::clearData(); | |||
self::setConf(); | |||
@@ -236,7 +235,7 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest { | |||
$this->assertException("doesNotExist", "User"); | |||
} | |||
$calls = 0; | |||
} else{ | |||
} else { | |||
$calls = 1; | |||
} | |||
try { |
@@ -80,7 +80,7 @@ class DatabaseInformation { | |||
// rollback any pending transaction | |||
try { | |||
$db->exec("ROLLBACK"); | |||
} catch(\Throwable $e) { | |||
} catch (\Throwable $e) { | |||
} | |||
foreach ($sqlite3TableList($db) as $table) { | |||
if ($table == "arsse_meta") { | |||
@@ -97,7 +97,7 @@ class DatabaseInformation { | |||
// rollback any pending transaction | |||
try { | |||
$db->exec("ROLLBACK"); | |||
} catch(\Throwable $e) { | |||
} catch (\Throwable $e) { | |||
} | |||
$db->exec("PRAGMA foreign_keys=0"); | |||
foreach ($sqlite3TableList($db) as $table) { | |||
@@ -181,7 +181,7 @@ class DatabaseInformation { | |||
// rollback any pending transaction | |||
try { | |||
$db->exec("ROLLBACK"); | |||
} catch(\Throwable $e) { | |||
} catch (\Throwable $e) { | |||
} | |||
foreach ($pgObjectList($db) as $obj) { | |||
if ($obj['type'] != "TABLE") { | |||
@@ -200,7 +200,7 @@ class DatabaseInformation { | |||
// rollback any pending transaction | |||
try { | |||
$db->exec("ROLLBACK"); | |||
} catch(\Throwable $e) { | |||
} catch (\Throwable $e) { | |||
} | |||
foreach ($pgObjectList($db) as $obj) { | |||
$db->exec("DROP {$obj['type']} IF EXISTS {$obj['name']} cascade"); |