Last tests for article querying
This commit is contained in:
parent
d4a6909cf6
commit
00ad1cc5b9
2 changed files with 64 additions and 40 deletions
|
@ -33,6 +33,8 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
protected const ACCEPTED_TYPES_OPML = ["application/xml", "text/xml", "text/x-opml"];
|
||||
protected const ACCEPTED_TYPES_JSON = ["application/json"];
|
||||
protected const TOKEN_LENGTH = 32;
|
||||
protected const DEFAULT_ENTRY_LIMIT = 100;
|
||||
protected const DEFAULT_ORDER_COL = "modified_date";
|
||||
protected const DATE_FORMAT_SEC = "Y-m-d\TH:i:sP";
|
||||
protected const DATE_FORMAT_MICRO = "Y-m-d\TH:i:s.uP";
|
||||
protected const VALID_QUERY = [
|
||||
|
@ -903,7 +905,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
|
||||
protected function computeContext(array $query, Context $c = null): Context {
|
||||
$c = ($c ?? new Context)
|
||||
->limit($query['limit'])
|
||||
->limit($query['limit'] ?? self::DEFAULT_ENTRY_LIMIT) // NOTE: This does not honour user preferences
|
||||
->offset($query['offset'])
|
||||
->starred($query['starred'])
|
||||
->modifiedSince($query['after']) // FIXME: This may not be the correct date field
|
||||
|
@ -951,10 +953,10 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
return ["modified_date".$desc];
|
||||
} elseif ($query['order'] === "category_title") {
|
||||
return ["top_folder_name".$desc];
|
||||
} elseif ($query['order'] === "catgory_id") {
|
||||
} elseif ($query['order'] === "category_id") {
|
||||
return ["top_folder".$desc];
|
||||
} else {
|
||||
return [];
|
||||
return [self::DEFAULT_ORDER_COL.$desc];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1028,11 +1030,10 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
$out[$a]['feed'] = $feeds[$out[$a]['feed_id']];
|
||||
}
|
||||
}
|
||||
// finally compute the total number of entries match the query, if the query hs a limit or offset
|
||||
if ($c->limit || $c->offset) {
|
||||
// finally compute the total number of entries match the query, where necessary
|
||||
$count = sizeof($out);
|
||||
if ($c->offset || ($c->limit && $count >= $c->limit)) {
|
||||
$count = Arsse::$db->articleCount(Arsse::$user->id, (clone $c)->limit(0)->offset(0));
|
||||
} else {
|
||||
$count = sizeof($out);
|
||||
}
|
||||
return new Response(['total' => $count, 'entries' => $out]);
|
||||
}
|
||||
|
|
|
@ -721,8 +721,9 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
}
|
||||
|
||||
/** @dataProvider provideEntryQueries */
|
||||
public function testGetEntries(string $url, ?Context $c, ?array $order, $out, ResponseInterface $exp) {
|
||||
public function testGetEntries(string $url, ?Context $c, ?array $order, $out, bool $count, ResponseInterface $exp) {
|
||||
\Phake::when(Arsse::$db)->subscriptionList->thenReturn(new Result($this->v(self::FEEDS)));
|
||||
\Phake::when(Arsse::$db)->articleCount->thenReturn(2112);
|
||||
if ($out instanceof \Exception) {
|
||||
\Phake::when(Arsse::$db)->articleList->thenThrow($out);
|
||||
} else {
|
||||
|
@ -734,47 +735,69 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
} else {
|
||||
\Phake::verify(Arsse::$db, \Phake::times(0))->articleList;
|
||||
}
|
||||
if ($out) {
|
||||
if ($out && !$out instanceof \Exception) {
|
||||
\Phake::verify(Arsse::$db)->subscriptionList(Arsse::$user->id);
|
||||
} else {
|
||||
\Phake::verify(Arsse::$db, \Phake::times(0))->subscriptionList;
|
||||
}
|
||||
if ($count) {
|
||||
\Phake::verify(Arsse::$db)->articleCount(Arsse::$user->id, (clone $c)->limit(0)->offset(0));
|
||||
} else {
|
||||
\Phake::verify(Arsse::$db, \Phake::times(0))->articleCount;
|
||||
}
|
||||
}
|
||||
|
||||
public function provideEntryQueries(): iterable {
|
||||
self::clearData();
|
||||
$c = new Context;
|
||||
$c = (new Context)->limit(100);
|
||||
$o = ["modified_date"]; // the default sort order
|
||||
return [
|
||||
["/entries?after=A", null, null, [], new ErrorResponse(["InvalidInputValue", 'field' => "after"], 400)],
|
||||
["/entries?before=B", null, null, [], new ErrorResponse(["InvalidInputValue", 'field' => "before"], 400)],
|
||||
["/entries?category_id=0", null, null, [], new ErrorResponse(["InvalidInputValue", 'field' => "category_id"], 400)],
|
||||
["/entries?after_entry_id=0", null, null, [], new ErrorResponse(["InvalidInputValue", 'field' => "after_entry_id"], 400)],
|
||||
["/entries?before_entry_id=0", null, null, [], new ErrorResponse(["InvalidInputValue", 'field' => "before_entry_id"], 400)],
|
||||
["/entries?limit=-1", null, null, [], new ErrorResponse(["InvalidInputValue", 'field' => "limit"], 400)],
|
||||
["/entries?offset=-1", null, null, [], new ErrorResponse(["InvalidInputValue", 'field' => "offset"], 400)],
|
||||
["/entries?direction=sideways", null, null, [], new ErrorResponse(["InvalidInputValue", 'field' => "direction"], 400)],
|
||||
["/entries?order=false", null, null, [], new ErrorResponse(["InvalidInputValue", 'field' => "order"], 400)],
|
||||
["/entries?starred&starred", null, null, [], new ErrorResponse(["DuplicateInputValue", 'field' => "starred"], 400)],
|
||||
["/entries?after&after=0", null, null, [], new ErrorResponse(["DuplicateInputValue", 'field' => "after"], 400)],
|
||||
["/entries", $c, [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?category_id=47", (clone $c)->folder(46), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?category_id=1", (clone $c)->folderShallow(0), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=unread", (clone $c)->unread(true)->hidden(false), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=read", (clone $c)->unread(false)->hidden(false), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=removed", (clone $c)->hidden(true), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=unread&status=read", (clone $c)->hidden(false), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=unread&status=removed", (clone $c)->unread(true), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=removed&status=read", (clone $c)->unread(false), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=removed&status=read&status=removed", (clone $c)->unread(false), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=removed&status=read&status=unread", $c, [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?starred", (clone $c)->starred(true), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?starred=", (clone $c)->starred(true), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?starred=true", (clone $c)->starred(true), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?starred=false", (clone $c)->starred(true), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?after=0", (clone $c)->modifiedSince(0), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?before=0", (clone $c)->notModifiedSince(0), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?after_entry_id=42", (clone $c)->oldestArticle(43), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?before_entry_id=47", (clone $c)->latestArticle(46), [], self::ENTRIES, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?after=A", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "after"], 400)],
|
||||
["/entries?before=B", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "before"], 400)],
|
||||
["/entries?category_id=0", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "category_id"], 400)],
|
||||
["/entries?after_entry_id=0", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "after_entry_id"], 400)],
|
||||
["/entries?before_entry_id=0", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "before_entry_id"], 400)],
|
||||
["/entries?limit=-1", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "limit"], 400)],
|
||||
["/entries?offset=-1", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "offset"], 400)],
|
||||
["/entries?direction=sideways", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "direction"], 400)],
|
||||
["/entries?order=false", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "order"], 400)],
|
||||
["/entries?starred&starred", null, null, [], false, new ErrorResponse(["DuplicateInputValue", 'field' => "starred"], 400)],
|
||||
["/entries?after&after=0", null, null, [], false, new ErrorResponse(["DuplicateInputValue", 'field' => "after"], 400)],
|
||||
["/entries", $c, $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?category_id=47", (clone $c)->folder(46), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?category_id=1", (clone $c)->folderShallow(0), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=unread", (clone $c)->unread(true)->hidden(false), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=read", (clone $c)->unread(false)->hidden(false), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=removed", (clone $c)->hidden(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=unread&status=read", (clone $c)->hidden(false), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=unread&status=removed", (clone $c)->unread(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=removed&status=read", (clone $c)->unread(false), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=removed&status=read&status=removed", (clone $c)->unread(false), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?status=removed&status=read&status=unread", $c, $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?starred", (clone $c)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?starred=", (clone $c)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?starred=true", (clone $c)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?starred=false", (clone $c)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?after=0", (clone $c)->modifiedSince(0), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?before=0", (clone $c)->notModifiedSince(0), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?after_entry_id=42", (clone $c)->oldestArticle(43), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?before_entry_id=47", (clone $c)->latestArticle(46), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?search=alpha%20beta", (clone $c)->searchTerms(["alpha", "beta"]), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?limit=4", (clone $c)->limit(4), $o, self::ENTRIES, true, new Response(['total' => 2112, 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?offset=20", (clone $c)->offset(20), $o, [], true, new Response(['total' => 2112, 'entries' => []])],
|
||||
["/entries?direction=asc", $c, $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=id", $c, ["id"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=published_at", $c, ["modified_date"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=category_id", $c, ["top_folder"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=category_title", $c, ["top_folder_name"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=status", $c, ["hidden", "unread desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?direction=desc", $c, ["modified_date desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=id&direction=desc", $c, ["id desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=published_at&direction=desc", $c, ["modified_date desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=category_id&direction=desc", $c, ["top_folder desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=category_title&direction=desc", $c, ["top_folder_name desc"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=status&direction=desc", $c, ["hidden desc", "unread"], self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?category_id=2112", (clone $c)->folder(2111), $o, new ExceptionInput("idMissing"), false, new ErrorResponse("MissingCategory")],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue