mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 21:22:40 +00:00
Fix most subscription tests
Two tests depend upon article functions which will be addressed in due course.
This commit is contained in:
parent
9f784251e8
commit
6958c24be2
4 changed files with 148 additions and 119 deletions
|
@ -818,17 +818,17 @@ class Database {
|
|||
$url = URL::normalize($url, $fetchUser, $fetchPassword);
|
||||
// if discovery is enabled, check to see if the feed already exists; this will save us some network latency if it does
|
||||
if ($discover) {
|
||||
$id = $this->db->prepare("SELECT id from arsse_subscriptions where ownerr = ? and url = ?", "str", "str")->run($user, $url)->getValue();
|
||||
$id = $this->db->prepare("SELECT id from arsse_subscriptions where owner = ? and url = ?", "str", "str")->run($user, $url)->getValue();
|
||||
if (!$id) {
|
||||
// if it doesn't exist, perform discovery
|
||||
$url = Feed::discover($url);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return (int) $this->db->prepare('INSERT INTO arsse_feeds(owner, url, deleted) values(?,?,?)', 'str', 'str', 'bool')->run($user, $url, 1)->lastId();
|
||||
return (int) $this->db->prepare('INSERT INTO arsse_subscriptions(owner, url, deleted) values(?,?,?)', 'str', 'str', 'bool')->run($user, $url, 1)->lastId();
|
||||
} catch (Db\ExceptionInput $e) {
|
||||
// if the insertion fails, throw if the delete flag is not set, otherwise return the existing ID
|
||||
$id = (int) $this->db->prepare("SELECT id from arsse_subscriptions where owner = ? and url = ? and deleted = 1")->run($user, $url)->getValue();
|
||||
$id = (int) $this->db->prepare("SELECT id from arsse_subscriptions where owner = ? and url = ? and deleted = 1", "str", "str")->run($user, $url)->getValue();
|
||||
if (!$id) {
|
||||
throw $e;
|
||||
} else {
|
||||
|
@ -857,7 +857,7 @@ class Database {
|
|||
*/
|
||||
public function subscriptionReveal(string $user, int ...$id): void {
|
||||
[$inClause, $inTypes, $inValues] = $this->generateIn($id, "int");
|
||||
$this->db->prepare("UPDATE arsse_subscriptions set deleted = 0, modified = CURRENT_TIMESTAMP where deleted = 1 and user = ? and id in ($inClause)", "str", $inTypes)->run($user, $inValues);
|
||||
$this->db->prepare("UPDATE arsse_subscriptions set deleted = 0, modified = CURRENT_TIMESTAMP where deleted = 1 and owner = ? and id in ($inClause)", "str", $inTypes)->run($user, $inValues);
|
||||
}
|
||||
|
||||
/** Lists a user's subscriptions, returning various data
|
||||
|
@ -865,7 +865,7 @@ class Database {
|
|||
* Each record has the following keys:
|
||||
*
|
||||
* - "id": The numeric identifier of the subscription
|
||||
* - "feed": The numeric identifier of the underlying newsfeed
|
||||
* - "feed": The numeric identifier of the subscription (historical)
|
||||
* - "url": The URL of the newsfeed, after discovery and HTTP redirects
|
||||
* - "title": The title of the newsfeed
|
||||
* - "source": The URL of the source of the newsfeed i.e. its parent Web site
|
||||
|
@ -908,43 +908,43 @@ class Database {
|
|||
)
|
||||
select
|
||||
s.id as id,
|
||||
s.feed as feed,
|
||||
f.url,source,pinned,err_count,err_msg,order_type,added,keep_rule,block_rule,f.etag,s.scrape,
|
||||
f.updated as updated,
|
||||
f.modified as edited,
|
||||
s.id as feed,
|
||||
s.url,source,pinned,err_count,err_msg,order_type,added,keep_rule,block_rule,s.etag,s.scrape,
|
||||
s.updated as updated,
|
||||
s.modified as edited,
|
||||
s.modified as modified,
|
||||
f.next_fetch,
|
||||
s.next_fetch,
|
||||
case when i.data is not null then i.id end as icon_id,
|
||||
i.url as icon_url,
|
||||
folder, t.top as top_folder, d.name as folder_name, dt.name as top_folder_name,
|
||||
coalesce(s.title, f.title) as title,
|
||||
coalesce(s.title, s.feed_title) as title,
|
||||
cast(coalesce((articles - hidden - marked), coalesce(articles,0)) as $integerType) as unread -- this cast is required for MySQL for unclear reasons
|
||||
from arsse_subscriptions as s
|
||||
join arsse_feeds as f on f.id = s.feed
|
||||
left join topmost as t on t.f_id = s.folder
|
||||
left join arsse_folders as d on s.folder = d.id
|
||||
left join arsse_folders as dt on t.top = dt.id
|
||||
left join arsse_icons as i on i.id = f.icon
|
||||
left join arsse_icons as i on i.id = s.icon
|
||||
left join (
|
||||
select
|
||||
feed,
|
||||
subscription,
|
||||
count(*) as articles
|
||||
from arsse_articles
|
||||
group by feed
|
||||
) as article_stats on article_stats.feed = s.feed
|
||||
group by subscription
|
||||
) as article_stats on article_stats.subscription = s.id
|
||||
left join (
|
||||
select
|
||||
subscription,
|
||||
sum(hidden) as hidden,
|
||||
sum(case when \"read\" = 1 and hidden = 0 then 1 else 0 end) as marked
|
||||
from arsse_marks group by subscription
|
||||
from arsse_articles group by subscription
|
||||
) as mark_stats on mark_stats.subscription = s.id",
|
||||
["str", "int"],
|
||||
[$user, $folder]
|
||||
);
|
||||
$q->setWhere("s.owner = ?", ["str"], [$user]);
|
||||
$q->setWhere("s.deleted = 0");
|
||||
$nocase = $this->db->sqlToken("nocase");
|
||||
$q->setOrder("pinned desc, coalesce(s.title, f.title) collate $nocase");
|
||||
$q->setOrder("pinned desc, coalesce(s.title, s.feed_title) collate $nocase");
|
||||
if ($id) {
|
||||
// if an ID is specified, add a suitable WHERE condition and bindings
|
||||
// this condition facilitates the implementation of subscriptionPropertiesGet, which would otherwise have to duplicate the complex query; it takes precedence over a specified folder
|
||||
|
@ -978,6 +978,7 @@ class Database {
|
|||
[$folder]
|
||||
);
|
||||
$q->setWhere("owner = ?", "str", $user);
|
||||
$q->setWhere("deleted = 0");
|
||||
if ($folder) {
|
||||
// if the specified folder exists, add a suitable WHERE condition
|
||||
$q->setWhere("folder in (select folder from folders)");
|
||||
|
@ -996,7 +997,7 @@ class Database {
|
|||
if (!V::id($id)) {
|
||||
throw new Db\ExceptionInput("typeViolation", ["action" => __FUNCTION__, "field" => "feed", 'type' => "int > 0"]);
|
||||
}
|
||||
$changes = $this->db->prepare("DELETE from arsse_subscriptions where owner = ? and id = ?", "str", "int")->run($user, $id)->changes();
|
||||
$changes = $this->db->prepare("UPDATE arsse_subscriptions set deleted = 1, modified = CURRENT_TIMESTAMP where owner = ? and id = ? and deleted = 0", "str", "int")->run($user, $id)->changes();
|
||||
if (!$changes) {
|
||||
throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "feed", 'id' => $id]);
|
||||
}
|
||||
|
@ -1119,8 +1120,9 @@ class Database {
|
|||
*/
|
||||
public function subscriptionIcon(?string $user, int $id, bool $includeData = true): ?array {
|
||||
$data = $includeData ? "i.data" : "null as data";
|
||||
$q = new Query("SELECT i.id, i.url, i.type, $data from arsse_subscriptions as s join arsse_feeds as f on s.feed = f.id left join arsse_icons as i on f.icon = i.id");
|
||||
$q = new Query("SELECT i.id, i.url, i.type, $data from arsse_subscriptions as s left join arsse_icons as i on s.icon = i.id");
|
||||
$q->setWhere("s.id = ?", "int", $id);
|
||||
$q->setWhere("s.deleted = 0");
|
||||
if (isset($user)) {
|
||||
$q->setWhere("s.owner = ?", "str", $user);
|
||||
}
|
||||
|
@ -1135,10 +1137,11 @@ class Database {
|
|||
|
||||
/** Returns the time at which any of a user's subscriptions (or a specific subscription) was last refreshed, as a DateTimeImmutable object */
|
||||
public function subscriptionRefreshed(string $user, int $id = null): ?\DateTimeImmutable {
|
||||
$q = new Query("SELECT max(arsse_feeds.updated) from arsse_feeds join arsse_subscriptions on arsse_subscriptions.feed = arsse_feeds.id");
|
||||
$q->setWhere("arsse_subscriptions.owner = ?", "str", $user);
|
||||
$q = new Query("SELECT max(updated) from arsse_subscriptions");
|
||||
$q->setWhere("owner = ?", "str", $user);
|
||||
$q->setWhere("deleted = 0");
|
||||
if ($id) {
|
||||
$q->setWhere("arsse_subscriptions.id = ?", "int", $id);
|
||||
$q->setWhere("id = ?", "int", $id);
|
||||
}
|
||||
$out = $this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues())->getValue();
|
||||
if (!$out && $id) {
|
||||
|
@ -1155,17 +1158,17 @@ class Database {
|
|||
protected function subscriptionRulesApply(string $user, int $id): void {
|
||||
// start a transaction for read isolation
|
||||
$tr = $this->begin();
|
||||
$sub = $this->db->prepare("SELECT feed, coalesce(keep_rule, '') as keep, coalesce(block_rule, '') as block from arsse_subscriptions where owner = ? and id = ?", "str", "int")->run($user, $id)->getRow();
|
||||
$sub = $this->db->prepare("SELECT id, coalesce(keep_rule, '') as keep, coalesce(block_rule, '') as block from arsse_subscriptions where owner = ? and id = ?", "str", "int")->run($user, $id)->getRow();
|
||||
try {
|
||||
$keep = Rule::prep($sub['keep']);
|
||||
$block = Rule::prep($sub['block']);
|
||||
$feed = $sub['feed'];
|
||||
$feed = $sub['id'];
|
||||
} catch (RuleException $e) { // @codeCoverageIgnore
|
||||
// invalid rules should not normally appear in the database, but it's possible
|
||||
// in this case we should halt evaluation and just leave things as they are
|
||||
return; // @codeCoverageIgnore
|
||||
}
|
||||
$articles = $this->db->prepare("SELECT id, title, coalesce(categories, 0) as categories from arsse_articles as a left join (select article, count(*) as categories from arsse_categories group by article) as c on a.id = c.article where a.feed = ?", "int")->run($feed)->getAll();
|
||||
$articles = $this->db->prepare("SELECT id, title, coalesce(categories, 0) as categories from arsse_articles as a left join (select article, count(*) as categories from arsse_categories group by article) as c on a.id = c.article where a.subscription = ?", "int")->run($id)->getAll();
|
||||
$hide = [];
|
||||
$unhide = [];
|
||||
foreach ($articles as $r) {
|
||||
|
@ -1196,12 +1199,14 @@ class Database {
|
|||
* @param string $user The user who owns the subscription to be validated
|
||||
* @param integer $id The identifier of the subscription to validate
|
||||
* @param boolean $subject Whether the subscription is the subject (true) rather than the object (false) of the operation being performed; this only affects the semantics of the error message if validation fails
|
||||
* @param boolean $acceptDeleted Whether to consider a soft-deleted subscription as valid
|
||||
*/
|
||||
protected function subscriptionValidateId(string $user, $id, bool $subject = false): array {
|
||||
protected function subscriptionValidateId(string $user, $id, bool $subject = false, bool $acceptDeleted = false): array {
|
||||
if (!V::id($id)) {
|
||||
throw new Db\ExceptionInput("typeViolation", ["action" => $this->caller(), "field" => "feed", 'type' => "int > 0"]);
|
||||
}
|
||||
$out = $this->db->prepare("SELECT id,feed from arsse_subscriptions where id = ? and owner = ?", "int", "str")->run($id, $user)->getRow();
|
||||
$deleted = $acceptDeleted ? "deleted" : "0";
|
||||
$out = $this->db->prepare("SELECT id, id from arsse_subscriptions where id = ? and owner = ? and deleted = $deleted", "int", "str")->run($id, $user)->getRow();
|
||||
if (!$out) {
|
||||
throw new Db\ExceptionInput($subject ? "subjectMissing" : "idMissing", ["action" => $this->caller(), "field" => "subscription", 'id' => $id]);
|
||||
}
|
||||
|
@ -2175,7 +2180,7 @@ class Database {
|
|||
"SELECT articles.article as article, max(arsse_editions.id) as edition from (
|
||||
select arsse_articles.id as article
|
||||
FROM arsse_articles
|
||||
join arsse_subscriptions on arsse_subscriptions.feed = arsse_articles.feed
|
||||
join arsse_subscriptions on arsse_subscriptions.id = arsse_articles.subscription
|
||||
WHERE arsse_articles.id = ? and arsse_subscriptions.owner = ?
|
||||
) as articles left join arsse_editions on arsse_editions.article = articles.article group by articles.article",
|
||||
["int", "str"]
|
||||
|
|
|
@ -19,7 +19,7 @@ abstract class AbstractTest extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
use SeriesFolder;
|
||||
//use SeriesFeed;
|
||||
use SeriesIcon;
|
||||
//use SeriesSubscription;
|
||||
use SeriesSubscription;
|
||||
//use SeriesLabel;
|
||||
use SeriesTag;
|
||||
//use SeriesArticle;
|
||||
|
|
|
@ -10,6 +10,7 @@ use GuzzleHttp\Exception\ClientException;
|
|||
use JKingWeb\Arsse\Arsse;
|
||||
use JKingWeb\Arsse\Test\Database;
|
||||
use JKingWeb\Arsse\Feed\Exception as FeedException;
|
||||
use JKingWeb\Arsse\Misc\Date;
|
||||
|
||||
trait SeriesSubscription {
|
||||
public function setUpSeriesSubscription(): void {
|
||||
|
@ -42,14 +43,15 @@ trait SeriesSubscription {
|
|||
],
|
||||
],
|
||||
'arsse_subscriptions' => [
|
||||
'columns' => ["id", "owner", "url", "feed_title", "updated", "next_fetch", "icon", "title", "folder", "pinned", "order_type", "keep_rule", "block_rule", "scrape"],
|
||||
'columns' => ["id", "owner", "url", "feed_title", "updated", "next_fetch", "icon", "title", "folder", "pinned", "order_type", "keep_rule", "block_rule", "scrape", "deleted", "modified"],
|
||||
'rows' => [
|
||||
[1, "john.doe@example.com", "http://example.com/feed2", "eek", strtotime("now - 1 hour"), strtotime("now - 1 hour"), 1, null, null, 1, 2, null, null, 0],
|
||||
[2, "jane.doe@example.com", "http://example.com/feed2", "eek", strtotime("now - 1 hour"), strtotime("now - 1 hour"), 1, null, null, 0, 0, null, null, 0],
|
||||
[3, "john.doe@example.com", "http://example.com/feed3", "Ack", strtotime("now + 1 hour"), strtotime("now + 1 hour"), 2, "Ook", 2, 0, 1, null, null, 0],
|
||||
[4, "jill.doe@example.com", "http://example.com/feed2", "eek", strtotime("now - 1 hour"), strtotime("now - 1 hour"), 1, null, null, 0, 0, null, null, 0],
|
||||
[5, "jack.doe@example.com", "http://example.com/feed2", "eek", strtotime("now - 1 hour"), strtotime("now - 1 hour"), 1, null, null, 1, 2, "", "3|E", 0],
|
||||
[6, "john.doe@example.com", "http://example.com/feed4", "Foo", strtotime("now + 1 hour"), strtotime("now + 1 hour"), null, "Bar", 3, 0, 0, null, null, 0],
|
||||
[1, "john.doe@example.com", "http://example.com/feed2", "eek", Date::transform("now - 1 hour", "sql"), Date::transform("now - 1 hour", "sql"), 1, null, null, 1, 2, null, null, 0, 0, Date::transform("now - 1 hour", "sql")],
|
||||
[2, "jane.doe@example.com", "http://example.com/feed2", "eek", Date::transform("now - 1 hour", "sql"), Date::transform("now - 1 hour", "sql"), 1, null, null, 0, 0, null, null, 0, 0, Date::transform("now - 1 hour", "sql")],
|
||||
[3, "john.doe@example.com", "http://example.com/feed3", "Ack", Date::transform("now + 1 hour", "sql"), Date::transform("now + 1 hour", "sql"), 2, "Ook", 2, 0, 1, null, null, 0, 0, Date::transform("now - 1 hour", "sql")],
|
||||
[4, "jill.doe@example.com", "http://example.com/feed2", "eek", Date::transform("now - 1 hour", "sql"), Date::transform("now - 1 hour", "sql"), 1, null, null, 0, 0, null, null, 0, 0, Date::transform("now - 1 hour", "sql")],
|
||||
[5, "jack.doe@example.com", "http://example.com/feed2", "eek", Date::transform("now - 1 hour", "sql"), Date::transform("now - 1 hour", "sql"), 1, null, null, 1, 2, "", "3|E", 0, 0, Date::transform("now - 1 hour", "sql")],
|
||||
[6, "john.doe@example.com", "http://example.com/feed4", "Foo", Date::transform("now + 1 hour", "sql"), Date::transform("now + 1 hour", "sql"), null, "Bar", 3, 0, 0, null, null, 0, 0, Date::transform("now - 1 hour", "sql")],
|
||||
[7, "john.doe@example.com", "http://example.com/feed1", "ook", Date::transform("now + 6 hour", "sql"), Date::transform("now - 1 hour", "sql"), null, null, null, 0, 0, null, null, 0, 1, Date::transform("now - 1 hour", "sql")],
|
||||
],
|
||||
],
|
||||
'arsse_tags' => [
|
||||
|
@ -159,102 +161,99 @@ trait SeriesSubscription {
|
|||
unset($this->data, $this->user);
|
||||
}
|
||||
|
||||
public function testAddASubscriptionToAnExistingFeed(): void {
|
||||
public function testReserveASubscription(): void {
|
||||
$url = "http://example.com/feed5";
|
||||
$exp = $this->nextID("arsse_subscriptions");
|
||||
$act = Arsse::$db->subscriptionReserve($this->user, $url, "", "", false);
|
||||
$this->assertSame($exp, $act);
|
||||
$state = $this->primeExpectations($this->data, ['arsse_subscriptions' => ["id", "owner", "url", "deleted", "modified"]]);
|
||||
$state['arsse_subscriptions']['rows'][] = [$exp, $this->user, $url, 1, Date::transform("now", "sql")];
|
||||
$this->compareExpectations(static::$drv, $state);
|
||||
}
|
||||
|
||||
public function testReserveADeletedSubscription(): void {
|
||||
$url = "http://example.com/feed1";
|
||||
$subID = $this->nextID("arsse_subscriptions");
|
||||
$db = $this->partialMock(Database::class, static::$drv);
|
||||
$db->feedUpdate->returns(true);
|
||||
Arsse::$db = $db->get();
|
||||
$this->assertSame($subID, Arsse::$db->subscriptionAdd($this->user, $url));
|
||||
$db->feedUpdate->never()->called();
|
||||
$state = $this->primeExpectations($this->data, ['arsse_subscriptions' => ['id', 'owner', 'feed', 'url']]);
|
||||
$state['arsse_subscriptions']['rows'][] = [$subID, $this->user, "http://example.com/feed1"];
|
||||
$exp = 7;
|
||||
$act = Arsse::$db->subscriptionReserve($this->user, $url, "", "", false);
|
||||
$this->assertSame($exp, $act);
|
||||
$state = $this->primeExpectations($this->data, ['arsse_subscriptions' => ["id", "owner", "url", "deleted", "modified"]]);
|
||||
$state['arsse_subscriptions']['rows'][6] = [$exp, $this->user, $url, 1, Date::transform("now", "sql")];
|
||||
$this->compareExpectations(static::$drv, $state);
|
||||
}
|
||||
|
||||
public function testAddASubscriptionToANewFeed(): void {
|
||||
$url = "http://example.org/feed1";
|
||||
$feedID = $this->nextID("arsse_feeds");
|
||||
$subID = $this->nextID("arsse_subscriptions");
|
||||
$db = $this->partialMock(Database::class, static::$drv);
|
||||
$db->feedUpdate->returns(true);
|
||||
Arsse::$db = $db->get();
|
||||
$this->assertSame($subID, Arsse::$db->subscriptionAdd($this->user, $url, "", "", false));
|
||||
$db->feedUpdate->calledWith($feedID, true, false);
|
||||
$state = $this->primeExpectations($this->data, [
|
||||
'arsse_feeds' => ['id','url','username','password'],
|
||||
'arsse_subscriptions' => ['id','owner','feed'],
|
||||
]);
|
||||
$state['arsse_feeds']['rows'][] = [$feedID,$url,"",""];
|
||||
$state['arsse_subscriptions']['rows'][] = [$subID,$this->user,$feedID];
|
||||
public function testReserveASubscriptionWithPassword(): void {
|
||||
$url = "http://john:secret@example.com/feed5";
|
||||
$exp = $this->nextID("arsse_subscriptions");
|
||||
$act = Arsse::$db->subscriptionReserve($this->user, "http://example.com/feed5", "john", "secret", false);
|
||||
$this->assertSame($exp, $act);
|
||||
$state = $this->primeExpectations($this->data, ['arsse_subscriptions' => ["id", "owner", "url", "deleted", "modified"]]);
|
||||
$state['arsse_subscriptions']['rows'][] = [$exp, $this->user, $url, 1, Date::transform("now", "sql")];
|
||||
$this->compareExpectations(static::$drv, $state);
|
||||
}
|
||||
|
||||
public function testAddASubscriptionToANewFeedViaDiscovery(): void {
|
||||
$url = "http://localhost:8000/Feed/Discovery/Valid";
|
||||
$discovered = "http://localhost:8000/Feed/Discovery/Feed";
|
||||
$feedID = $this->nextID("arsse_feeds");
|
||||
$subID = $this->nextID("arsse_subscriptions");
|
||||
$db = $this->partialMock(Database::class, static::$drv);
|
||||
$db->feedUpdate->returns(true);
|
||||
Arsse::$db = $db->get();
|
||||
$this->assertSame($subID, Arsse::$db->subscriptionAdd($this->user, $url, "", "", true));
|
||||
$db->feedUpdate->calledWith($feedID, true, false);
|
||||
$state = $this->primeExpectations($this->data, [
|
||||
'arsse_feeds' => ['id','url','username','password'],
|
||||
'arsse_subscriptions' => ['id','owner','feed'],
|
||||
]);
|
||||
$state['arsse_feeds']['rows'][] = [$feedID,$discovered,"",""];
|
||||
$state['arsse_subscriptions']['rows'][] = [$subID,$this->user,$feedID];
|
||||
public function testReserveADuplicateSubscription(): void {
|
||||
$url = "http://example.com/feed2";
|
||||
$this->assertException("constraintViolation", "Db", "ExceptionInput");
|
||||
Arsse::$db->subscriptionReserve($this->user, $url, "", "", false);
|
||||
}
|
||||
|
||||
public function testReserveASubscriptionWithDiscovery(): void {
|
||||
$exp = $this->nextID("arsse_subscriptions");
|
||||
$act = Arsse::$db->subscriptionReserve($this->user, "http://localhost:8000/Feed/Discovery/Valid");
|
||||
$this->assertSame($exp, $act);
|
||||
$state = $this->primeExpectations($this->data, ['arsse_subscriptions' => ["id", "owner", "url", "deleted", "modified"]]);
|
||||
$state['arsse_subscriptions']['rows'][] = [$exp, $this->user, "http://localhost:8000/Feed/Discovery/Feed", 1, Date::transform("now", "sql")];
|
||||
$this->compareExpectations(static::$drv, $state);
|
||||
}
|
||||
|
||||
public function testAddASubscriptionToAnInvalidFeed(): void {
|
||||
$url = "http://example.org/feed1";
|
||||
$feedID = $this->nextID("arsse_feeds");
|
||||
public function testRevealASubscription(): void {
|
||||
$url = "http://example.com/feed1";
|
||||
$this->assertNull(Arsse::$db->subscriptionReveal($this->user, 1, 7));
|
||||
$state = $this->primeExpectations($this->data, ['arsse_subscriptions' => ["id", "owner", "url", "deleted", "modified"]]);
|
||||
$state['arsse_subscriptions']['rows'][6] = [7, $this->user, $url, 0, Date::transform("now", "sql")];
|
||||
$this->compareExpectations(static::$drv, $state);
|
||||
}
|
||||
|
||||
public function testAddASubscription(): void {
|
||||
$url = "http://example.org/feed5";
|
||||
$id = $this->nextID("arsse_subscriptions");
|
||||
$db = $this->partialMock(Database::class, static::$drv);
|
||||
$db->feedUpdate->throws(new FeedException("", ['url' => $url], $this->mockGuzzleException(ClientException::class, "", 404)));
|
||||
$db->subscriptionUpdate->returns(true);
|
||||
$db->subscriptionPropertiesSet->returns(true);
|
||||
Arsse::$db = $db->get();
|
||||
$this->assertException("invalidUrl", "Feed");
|
||||
try {
|
||||
Arsse::$db->subscriptionAdd($this->user, $url, "", "", false);
|
||||
$this->assertSame($id, Arsse::$db->subscriptionAdd($this->user, $url, "", "", false, ['order_type' => 2]));
|
||||
} finally {
|
||||
$db->feedUpdate->calledWith($feedID, true, false);
|
||||
$state = $this->primeExpectations($this->data, [
|
||||
'arsse_feeds' => ['id','url','username','password'],
|
||||
'arsse_subscriptions' => ['id','owner','feed'],
|
||||
]);
|
||||
$db->subscriptionUpdate->calledWith($this->user, $id, true);
|
||||
$db->subscriptionPropertiesSet->calledWith($this->user, $id, ['order_type' => 2]);
|
||||
$state = $this->primeExpectations($this->data, ['arsse_subscriptions' => ["id", "owner", "url", "deleted", "modified"]]);
|
||||
$state['arsse_subscriptions']['rows'][] = [$id, $this->user, $url, 0, Date::transform("now", "sql")];
|
||||
$this->compareExpectations(static::$drv, $state);
|
||||
}
|
||||
}
|
||||
|
||||
public function testAddADuplicateSubscription(): void {
|
||||
$url = "http://example.com/feed2";
|
||||
$this->assertException("constraintViolation", "Db", "ExceptionInput");
|
||||
Arsse::$db->subscriptionAdd($this->user, $url);
|
||||
}
|
||||
|
||||
public function testAddADuplicateSubscriptionWithEquivalentUrl(): void {
|
||||
$url = "http://EXAMPLE.COM/feed2";
|
||||
$this->assertException("constraintViolation", "Db", "ExceptionInput");
|
||||
Arsse::$db->subscriptionAdd($this->user, $url);
|
||||
}
|
||||
|
||||
public function testAddADuplicateSubscriptionViaRedirection(): void {
|
||||
$url = "http://localhost:8000/Feed/Parsing/Valid";
|
||||
Arsse::$db->subscriptionAdd($this->user, $url);
|
||||
$subID = $this->nextID("arsse_subscriptions");
|
||||
$url = "http://localhost:8000/Feed/Fetching/RedirectionDuplicate";
|
||||
$this->assertSame($subID, Arsse::$db->subscriptionAdd($this->user, $url));
|
||||
public function testAddASubscriptionToAnInvalidFeed(): void {
|
||||
$url = "http://example.org/feed5";
|
||||
$id = $this->nextID("arsse_subscriptions");
|
||||
$db = $this->partialMock(Database::class, static::$drv);
|
||||
$db->subscriptionUpdate->throws(new FeedException("", ['url' => $url], $this->mockGuzzleException(ClientException::class, "", 404)));
|
||||
$db->subscriptionPropertiesSet->returns(true);
|
||||
Arsse::$db = $db->get();
|
||||
$this->assertException("invalidUrl", "Feed");
|
||||
try {
|
||||
Arsse::$db->subscriptionAdd($this->user, $url, "", "", false, ['order_type' => 2]);
|
||||
} finally {
|
||||
$db->subscriptionUpdate->calledWith($this->user, $id, true);
|
||||
$db->subscriptionPropertiesSet->calledWith($this->user, $id, ['order_type' => 2]);
|
||||
$state = $this->primeExpectations($this->data, ['arsse_subscriptions' => ["id", "owner", "url", "deleted", "modified"]]);
|
||||
$this->compareExpectations(static::$drv, $state);
|
||||
}
|
||||
}
|
||||
|
||||
public function testRemoveASubscription(): void {
|
||||
$this->assertTrue(Arsse::$db->subscriptionRemove($this->user, 1));
|
||||
$state = $this->primeExpectations($this->data, [
|
||||
'arsse_feeds' => ['id','url','username','password'],
|
||||
'arsse_subscriptions' => ['id','owner','feed'],
|
||||
]);
|
||||
array_shift($state['arsse_subscriptions']['rows']);
|
||||
$state = $this->primeExpectations($this->data, ['arsse_subscriptions' => ["id", "owner", "url", "deleted", "modified"]]);
|
||||
$state['arsse_subscriptions']['rows'][0] = [1, $this->user, "http://example.com/feed2", 1, Date::transform("now", "sql")];
|
||||
$this->compareExpectations(static::$drv, $state);
|
||||
}
|
||||
|
||||
|
@ -263,6 +262,11 @@ trait SeriesSubscription {
|
|||
Arsse::$db->subscriptionRemove($this->user, 2112);
|
||||
}
|
||||
|
||||
public function testRemoveADeletedSubscription(): void {
|
||||
$this->assertException("subjectMissing", "Db", "ExceptionInput");
|
||||
Arsse::$db->subscriptionRemove($this->user, 7);
|
||||
}
|
||||
|
||||
public function testRemoveAnInvalidSubscription(): void {
|
||||
$this->assertException("typeViolation", "Db", "ExceptionInput");
|
||||
Arsse::$db->subscriptionRemove($this->user, -1);
|
||||
|
@ -384,12 +388,18 @@ trait SeriesSubscription {
|
|||
Arsse::$db->subscriptionPropertiesGet($this->user, 2112);
|
||||
}
|
||||
|
||||
public function testGetThePropertiesOfADeletedSubscription(): void {
|
||||
$this->assertException("subjectMissing", "Db", "ExceptionInput");
|
||||
Arsse::$db->subscriptionPropertiesGet($this->user, 7);
|
||||
}
|
||||
|
||||
public function testGetThePropertiesOfAnInvalidSubscription(): void {
|
||||
$this->assertException("typeViolation", "Db", "ExceptionInput");
|
||||
Arsse::$db->subscriptionPropertiesGet($this->user, -1);
|
||||
}
|
||||
|
||||
public function testSetThePropertiesOfASubscription(): void {
|
||||
$this->markTestIncomplete();
|
||||
Arsse::$db->subscriptionPropertiesSet($this->user, 1, [
|
||||
'title' => "Ook Ook",
|
||||
'folder' => 3,
|
||||
|
@ -400,17 +410,16 @@ trait SeriesSubscription {
|
|||
'block_rule' => "eek",
|
||||
]);
|
||||
$state = $this->primeExpectations($this->data, [
|
||||
'arsse_feeds' => ['id','url','username','password','title'],
|
||||
'arsse_subscriptions' => ['id','owner','feed','title','folder','pinned','order_type','keep_rule','block_rule','scrape'],
|
||||
'arsse_subscriptions' => ['id','owner','feed_title', 'title','folder','pinned','order_type','keep_rule','block_rule','scrape'],
|
||||
]);
|
||||
$state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com",2,"Ook Ook",3,0,0,"ook","eek",1];
|
||||
$state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com","eek","Ook Ook",3,0,0,"ook","eek",1];
|
||||
$this->compareExpectations(static::$drv, $state);
|
||||
Arsse::$db->subscriptionPropertiesSet($this->user, 1, [
|
||||
'title' => null,
|
||||
'keep_rule' => null,
|
||||
'block_rule' => null,
|
||||
]);
|
||||
$state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com",2,null,3,0,0,null,null,1];
|
||||
$state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com","eek",null,3,0,0,null,null,1];
|
||||
$this->compareExpectations(static::$drv, $state);
|
||||
// making no changes is a valid result
|
||||
Arsse::$db->subscriptionPropertiesSet($this->user, 1, ['unhinged' => true]);
|
||||
|
@ -470,6 +479,11 @@ trait SeriesSubscription {
|
|||
Arsse::$db->subscriptionIcon(null, -2112);
|
||||
}
|
||||
|
||||
public function testRetrieveTheFaviconOfADeletedSubscription(): void {
|
||||
$this->assertException("subjectMissing", "Db", "ExceptionInput");
|
||||
Arsse::$db->subscriptionIcon(null, 7);
|
||||
}
|
||||
|
||||
public function testRetrieveTheFaviconOfASubscriptionWithUser(): void {
|
||||
$exp = "http://example.com/favicon.ico";
|
||||
$user = "john.doe@example.com";
|
||||
|
@ -497,6 +511,11 @@ trait SeriesSubscription {
|
|||
Arsse::$db->subscriptionTagsGet($this->user, 101);
|
||||
}
|
||||
|
||||
public function testListTheTagsOfADeletedSubscription(): void {
|
||||
$this->assertException("subjectMissing", "Db", "ExceptionInput");
|
||||
Arsse::$db->subscriptionTagsGet($this->user, 7);
|
||||
}
|
||||
|
||||
public function testGetRefreshTimeOfASubscription(): void {
|
||||
$user = "john.doe@example.com";
|
||||
$this->assertTime(strtotime("now + 1 hour"), Arsse::$db->subscriptionRefreshed($user));
|
||||
|
@ -505,10 +524,16 @@ trait SeriesSubscription {
|
|||
|
||||
public function testGetRefreshTimeOfAMissingSubscription(): void {
|
||||
$this->assertException("subjectMissing", "Db", "ExceptionInput");
|
||||
$this->assertTime(strtotime("now - 1 hour"), Arsse::$db->subscriptionRefreshed("john.doe@example.com", 2));
|
||||
Arsse::$db->subscriptionRefreshed("john.doe@example.com", 2);
|
||||
}
|
||||
|
||||
public function testGetRefreshTimeOfADeletedSubscription(): void {
|
||||
$this->assertException("subjectMissing", "Db", "ExceptionInput");
|
||||
Arsse::$db->subscriptionRefreshed("john.doe@example.com", 7);
|
||||
}
|
||||
|
||||
public function testSetTheFilterRulesOfASubscriptionCheckingMarks(): void {
|
||||
$this->markTestIncomplete();
|
||||
Arsse::$db->subscriptionPropertiesSet("jack.doe@example.com", 5, ['keep_rule' => "1|B|3|D", 'block_rule' => "4"]);
|
||||
$state = $this->primeExpectations($this->data, ['arsse_marks' => ['article', 'subscription', 'hidden']]);
|
||||
$state['arsse_marks']['rows'][9][2] = 0;
|
||||
|
|
|
@ -508,7 +508,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
|||
foreach ($tableSpecs as $table => $columns) {
|
||||
// make sure the source has the table we want
|
||||
if (!isset($source[$table])) {
|
||||
throw new Exception("Source for expectations does not contain requested table $table.");
|
||||
throw new \Exception("Source for expectations does not contain requested table $table.");
|
||||
}
|
||||
// fill the output, particularly the correct number of (empty) rows
|
||||
$rows = sizeof($source[$table]['rows']);
|
||||
|
@ -519,7 +519,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
|||
// fill the rows with the requested data, column-wise
|
||||
foreach ($columns as $c) {
|
||||
if (($index = array_search($c, $source[$table]['columns'], true)) === false) {
|
||||
throw new exception("Expected column $table.$c is not present in test data");
|
||||
throw new \Exception("Expected column $table.$c is not present in test data");
|
||||
}
|
||||
for ($a = 0; $a < $rows; $a++) {
|
||||
$out[$table]['rows'][$a][] = $source[$table]['rows'][$a][$index];
|
||||
|
@ -535,7 +535,6 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
|||
if (static::$stringOutput ?? false) {
|
||||
$expected = $this->stringify($expected);
|
||||
}
|
||||
$this->assertCount(sizeof($expected), $data, "Number of result rows (".sizeof($data).") differs from number of expected rows (".sizeof($expected).")");
|
||||
if (sizeof($expected)) {
|
||||
// make sure the expectations are consistent
|
||||
foreach ($expected as $exp) {
|
||||
|
|
Loading…
Reference in a new issue