diff --git a/lib/Database.php b/lib/Database.php index 6f63395..5781f77 100644 --- a/lib/Database.php +++ b/lib/Database.php @@ -1579,7 +1579,16 @@ class Database { continue; } elseif ($op === "between") { // option is a range - $q->setWhereNot("{$colDefs[$col]} BETWEEN ? AND ?", [$type, $type], $context->$m); + if ($context->$m[0] === null) { + // range is open at the low end + $q->setWhere("{$colDefs[$col]} <= ?", $type, $context->$m[1]); + } elseif ($context->$m[1] === null) { + // range is open at the high end + $q->setWhere("{$colDefs[$col]} >= ?", $type, $context->$m[0]); + } else { + // range is bounded in both directions + $q->setWhere("{$colDefs[$col]} BETWEEN ? AND ?", [$type, $type], $context->$m); + } } elseif (is_array($context->$m)) { // context option is an array of values if (!$context->$m) { @@ -1598,7 +1607,16 @@ class Database { continue; } elseif ($op === "between") { // option is a range - $q->setWhereNot("{$colDefs[$col]} BETWEEN ? AND ?", [$type, $type], $context->not->$m); + if ($context->not->$m[0] === null) { + // range is open at the low end + $q->setWhereNot("{$colDefs[$col]} <= ?", $type, $context->not->$m[1]); + } elseif ($context->not->$m[1] === null) { + // range is open at the high end + $q->setWhereNot("{$colDefs[$col]} >= ?", $type, $context->not->$m[0]); + } else { + // range is bounded in both directions + $q->setWhereNot("{$colDefs[$col]} BETWEEN ? AND ?", [$type, $type], $context->not->$m); + } } elseif (is_array($context->not->$m)) { if (!$context->not->$m) { // for exclusions we don't care if the array is empty diff --git a/lib/REST/Fever/API.php b/lib/REST/Fever/API.php index c581d88..7ad69ba 100644 --- a/lib/REST/Fever/API.php +++ b/lib/REST/Fever/API.php @@ -388,10 +388,10 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { if ($G['with_ids']) { $c->articles(explode(",", $G['with_ids']))->hidden(null); } elseif ($G['max_id']) { - $c->latestArticle($G['max_id'] - 1); + $c->articleRange(null, $G['max_id'] - 1); $reverse = true; } elseif ($G['since_id']) { - $c->oldestArticle($G['since_id'] + 1); + $c->articleRange($G['since_id'] + 1, null); } // handle the undocumented options if ($G['group_ids']) { diff --git a/lib/REST/Miniflux/V1.php b/lib/REST/Miniflux/V1.php index ca8535c..09a24f3 100644 --- a/lib/REST/Miniflux/V1.php +++ b/lib/REST/Miniflux/V1.php @@ -894,8 +894,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { ->offset($query['offset']) ->starred($query['starred']) ->modifiedRange($query['after'], $query['before']) // FIXME: This may not be the correct date field - ->oldestArticle($query['after_entry_id'] ? $query['after_entry_id'] + 1 : null) // FIXME: This might be edition - ->latestArticle($query['before_entry_id'] ? $query['before_entry_id'] - 1 : null) + ->articleRange($query['after_entry_id'] ? $query['after_entry_id'] + 1 : null, $query['before_entry_id'] ? $query['before_entry_id'] - 1 : null) // FIXME: This might be edition ->searchTerms(strlen($query['search'] ?? "") ? preg_split("/\s+/", $query['search']) : null); // NOTE: Miniflux matches only whole words; we match simple substrings if ($query['category_id']) { if ($query['category_id'] === 1) { diff --git a/lib/REST/NextcloudNews/V1_2.php b/lib/REST/NextcloudNews/V1_2.php index 21bc6fb..7ec195c 100644 --- a/lib/REST/NextcloudNews/V1_2.php +++ b/lib/REST/NextcloudNews/V1_2.php @@ -346,7 +346,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } // build the context $c = (new Context)->hidden(false); - $c->latestEdition((int) $data['newestItemId']); + $c->editionRange(null, (int) $data['newestItemId']); $c->folder((int) $url[1]); // perform the operation try { @@ -501,7 +501,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } // build the context $c = (new Context)->hidden(false); - $c->latestEdition((int) $data['newestItemId']); + $c->editionRange(null, (int) $data['newestItemId']); $c->subscription((int) $url[1]); // perform the operation try { @@ -526,9 +526,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { // set the edition mark-off; the database uses an or-equal comparison for internal consistency, but the protocol does not, so we must adjust by one if ($data['offset'] > 0) { if ($reverse) { - $c->latestEdition($data['offset'] - 1); + $c->editionRange(null, $data['offset'] - 1); } else { - $c->oldestEdition($data['offset'] + 1); + $c->editionRange($data['offset'] + 1, null); } } // set whether to only return unread @@ -597,7 +597,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } // build the context $c = (new Context)->hidden(false); - $c->latestEdition((int) $data['newestItemId']); + $c->editionRange(null, (int) $data['newestItemId']); // perform the operation Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c); return new EmptyResponse(204); diff --git a/lib/REST/TinyTinyRSS/API.php b/lib/REST/TinyTinyRSS/API.php index 757d476..d214709 100644 --- a/lib/REST/TinyTinyRSS/API.php +++ b/lib/REST/TinyTinyRSS/API.php @@ -1550,7 +1550,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { } // set the minimum article ID if ($data['since_id'] > 0) { - $c->oldestArticle($data['since_id'] + 1); + $c->articleRange($data['since_id'] + 1, null); } // return results return Arsse::$db->articleList(Arsse::$user->id, $c, $fields, $order); diff --git a/tests/cases/Database/SeriesArticle.php b/tests/cases/Database/SeriesArticle.php index 82bcef8..a1eafda 100644 --- a/tests/cases/Database/SeriesArticle.php +++ b/tests/cases/Database/SeriesArticle.php @@ -456,12 +456,12 @@ trait SeriesArticle { 'Not hidden' => [(new Context)->hidden(false), [1,2,3,4,5,7,8,19,20]], 'Labelled' => [(new Context)->labelled(true), [1,5,8,19,20]], 'Not labelled' => [(new Context)->labelled(false), [2,3,4,6,7]], - 'Not after edition 999' => [(new Context)->subscription(5)->latestEdition(999), [19]], - 'Not after edition 19' => [(new Context)->subscription(5)->latestEdition(19), [19]], - 'Not before edition 999' => [(new Context)->subscription(5)->oldestEdition(999), [20]], - 'Not before edition 1001' => [(new Context)->subscription(5)->oldestEdition(1001), [20]], - 'Not after article 3' => [(new Context)->latestArticle(3), [1,2,3]], - 'Not before article 19' => [(new Context)->oldestArticle(19), [19,20]], + 'Not after edition 999' => [(new Context)->subscription(5)->editionRange(null, 999), [19]], + 'Not after edition 19' => [(new Context)->subscription(5)->editionRange(null, 19), [19]], + 'Not before edition 999' => [(new Context)->subscription(5)->editionRange(999, null), [20]], + 'Not before edition 1001' => [(new Context)->subscription(5)->editionRange(1001, null), [20]], + 'Not after article 3' => [(new Context)->articleRange(null, 3), [1,2,3]], + 'Not before article 19' => [(new Context)->articleRange(19, null), [19,20]], 'Modified by author since 2005' => [(new Context)->modifiedRange("2005-01-01T00:00:00Z", null), [2,4,6,8,20]], 'Modified by author since 2010' => [(new Context)->modifiedRange("2010-01-01T00:00:00Z", null), [2,4,6,8,20]], 'Not modified by author since 2005' => [(new Context)->modifiedRange(null, "2005-01-01T00:00:00Z"), [1,3,5,7,19]], @@ -472,7 +472,7 @@ trait SeriesArticle { 'Not marked or labelled since 2005' => [(new Context)->markedRange(null, "2005-01-01T00:00:00Z"), [1,3,5,7]], 'Marked or labelled between 2000 and 2015' => [(new Context)->markedRange("2000-01-01T00:00:00Z", "2015-12-31T23:59:59Z"), [1,2,3,4,5,6,7,8,20]], 'Marked or labelled in 2010' => [(new Context)->markedRange("2010-01-01T00:00:00Z", "2010-12-31T23:59:59Z"), [2,4,6,20]], - 'Paged results' => [(new Context)->limit(2)->oldestEdition(4), [4,5]], + 'Paged results' => [(new Context)->limit(2)->editionRange(4, null), [4,5]], 'With label ID 1' => [(new Context)->label(1), [1,19]], 'With label ID 2' => [(new Context)->label(2), [1,5,20]], 'With label ID 1 or 2' => [(new Context)->labels([1,2]), [1,5,19,20]], @@ -929,7 +929,7 @@ trait SeriesArticle { } public function testMarkByOldestEdition(): void { - Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->oldestEdition(19)); + Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->editionRange(19, null)); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); $state['arsse_marks']['rows'][8][3] = 1; @@ -940,7 +940,7 @@ trait SeriesArticle { } public function testMarkByLatestEdition(): void { - Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->latestEdition(20)); + Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->editionRange(null, 20)); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); $state['arsse_marks']['rows'][8][3] = 1; diff --git a/tests/cases/Misc/TestContext.php b/tests/cases/Misc/TestContext.php index 7e1d6af..a05cab6 100644 --- a/tests/cases/Misc/TestContext.php +++ b/tests/cases/Misc/TestContext.php @@ -11,6 +11,8 @@ use JKingWeb\Arsse\Misc\ValueInfo; /** @covers \JKingWeb\Arsse\Context\Context */ class TestContext extends \JKingWeb\Arsse\Test\AbstractTest { + protected $ranges = ['modifiedRange', 'markedRange', 'articleRange', 'editionRange']; + public function testVerifyInitialState(): void { $c = new Context; foreach ((new \ReflectionObject($c))->getMethods(\ReflectionMethod::IS_PUBLIC) as $m) { @@ -19,7 +21,11 @@ class TestContext extends \JKingWeb\Arsse\Test\AbstractTest { } $method = $m->name; $this->assertFalse($c->$method(), "Context method $method did not initially return false"); - $this->assertEquals(null, $c->$method, "Context property $method is not initially falsy"); + if (in_array($method, $this->ranges)) { + $this->assertEquals([null, null], $c->$method, "Context property $method is not initially a two-member falsy array"); + } else { + $this->assertEquals(null, $c->$method, "Context property $method is not initially falsy"); + } } } @@ -40,10 +46,6 @@ class TestContext extends \JKingWeb\Arsse\Test\AbstractTest { 'subscriptions' => [44, 2112], 'article' => 255, 'edition' => 65535, - 'latestArticle' => 47, - 'oldestArticle' => 1337, - 'latestEdition' => 47, - 'oldestEdition' => 1337, 'unread' => true, 'starred' => true, 'hidden' => true, @@ -61,10 +63,9 @@ class TestContext extends \JKingWeb\Arsse\Test\AbstractTest { 'authorTerms' => ["foo", "bar"], 'not' => (new Context)->subscription(5), ]; - $ranges = ['modifiedRange', 'markedRange', 'articleRange', 'editionRange']; $c = new Context; foreach ((new \ReflectionObject($c))->getMethods(\ReflectionMethod::IS_PUBLIC) as $m) { - if ($m->isStatic() || strpos($m->name, "__") === 0 || in_array($m->name, $ranges)) { + if ($m->isStatic() || strpos($m->name, "__") === 0 || in_array($m->name, $this->ranges)) { continue; } $method = $m->name; diff --git a/tests/cases/REST/Fever/TestAPI.php b/tests/cases/REST/Fever/TestAPI.php index 4dfaec8..6a618b6 100644 --- a/tests/cases/REST/Fever/TestAPI.php +++ b/tests/cases/REST/Fever/TestAPI.php @@ -316,12 +316,12 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { ["items&group_ids=1,2,3,4", (clone $c)->tags([1,2,3,4])->hidden(false), false], ["items&feed_ids=1,2,3,4", (clone $c)->subscriptions([1,2,3,4])->hidden(false), false], ["items&with_ids=1,2,3,4", (clone $c)->articles([1,2,3,4]), false], - ["items&since_id=1", (clone $c)->oldestArticle(2)->hidden(false), false], - ["items&max_id=2", (clone $c)->latestArticle(1)->hidden(false), true], + ["items&since_id=1", (clone $c)->articleRange(2, null)->hidden(false), false], + ["items&max_id=2", (clone $c)->articleRange(null, 1)->hidden(false), true], ["items&with_ids=1,2,3,4&max_id=6", (clone $c)->articles([1,2,3,4]), false], ["items&with_ids=1,2,3,4&since_id=6", (clone $c)->articles([1,2,3,4]), false], - ["items&max_id=3&since_id=6", (clone $c)->latestArticle(2)->hidden(false), true], - ["items&feed_ids=1,2,3,4&since_id=6", (clone $c)->subscriptions([1,2,3,4])->oldestArticle(7)->hidden(false), false], + ["items&max_id=3&since_id=6", (clone $c)->articleRange(null, 2)->hidden(false), true], + ["items&feed_ids=1,2,3,4&since_id=6", (clone $c)->subscriptions([1,2,3,4])->articleRange(7, null)->hidden(false), false], ]; } diff --git a/tests/cases/REST/Miniflux/TestV1.php b/tests/cases/REST/Miniflux/TestV1.php index a87daf6..5a8c651 100644 --- a/tests/cases/REST/Miniflux/TestV1.php +++ b/tests/cases/REST/Miniflux/TestV1.php @@ -772,8 +772,8 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { ["/entries?before=0", $c, $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/entries?before=1", (clone $c)->modifiedRange(null, 1), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], ["/entries?before=1&after=0", (clone $c)->modifiedRange(0, 1), $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?after_entry_id=42", (clone $c)->articleRange(43, null), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])], + ["/entries?before_entry_id=47", (clone $c)->articleRange(null, 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' => []])], diff --git a/tests/cases/REST/NextcloudNews/TestV1_2.php b/tests/cases/REST/NextcloudNews/TestV1_2.php index b637b0f..f58f87d 100644 --- a/tests/cases/REST/NextcloudNews/TestV1_2.php +++ b/tests/cases/REST/NextcloudNews/TestV1_2.php @@ -686,40 +686,40 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $r200 = new Response(['items' => $this->articles['rest']]); $r422 = new EmptyResponse(422); return [ - ["/items", [], clone $c, $out, $r200], - ["/items", ['type' => 0, 'id' => 42], (clone $c)->subscription(42), new ExceptionInput("idMissing"), $r422], - ["/items", ['type' => 1, 'id' => 2112], (clone $c)->folder(2112), new ExceptionInput("idMissing"), $r422], - ["/items", ['type' => 0, 'id' => -1], (clone $c)->subscription(-1), new ExceptionInput("typeViolation"), $r422], - ["/items", ['type' => 1, 'id' => -1], (clone $c)->folder(-1), new ExceptionInput("typeViolation"), $r422], - ["/items", ['type' => 2, 'id' => 0], (clone $c)->starred(true), $out, $r200], - ["/items", ['type' => 3, 'id' => 0], clone $c, $out, $r200], - ["/items", ['getRead' => true], clone $c, $out, $r200], - ["/items", ['getRead' => false], (clone $c)->unread(true), $out, $r200], - ["/items", ['lastModified' => $t->getTimestamp()], (clone $c)->markedRange($t, null), $out, $r200], - ["/items", ['oldestFirst' => true, 'batchSize' => 10, 'offset' => 5], (clone $c)->oldestEdition(6)->limit(10), $out, $r200], - ["/items", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 5], (clone $c)->latestEdition(4)->limit(5), $out, $r200], - ["/items", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 0], (clone $c)->limit(5), $out, $r200], - ["/items/updated", [], clone $c, $out, $r200], - ["/items/updated", ['type' => 0, 'id' => 42], (clone $c)->subscription(42), new ExceptionInput("idMissing"), $r422], - ["/items/updated", ['type' => 1, 'id' => 2112], (clone $c)->folder(2112), new ExceptionInput("idMissing"), $r422], - ["/items/updated", ['type' => 0, 'id' => -1], (clone $c)->subscription(-1), new ExceptionInput("typeViolation"), $r422], - ["/items/updated", ['type' => 1, 'id' => -1], (clone $c)->folder(-1), new ExceptionInput("typeViolation"), $r422], - ["/items/updated", ['type' => 2, 'id' => 0], (clone $c)->starred(true), $out, $r200], - ["/items/updated", ['type' => 3, 'id' => 0], clone $c, $out, $r200], - ["/items/updated", ['getRead' => true], clone $c, $out, $r200], - ["/items/updated", ['getRead' => false], (clone $c)->unread(true), $out, $r200], - ["/items/updated", ['lastModified' => $t->getTimestamp()], (clone $c)->markedRange($t, null), $out, $r200], - ["/items/updated", ['oldestFirst' => true, 'batchSize' => 10, 'offset' => 5], (clone $c)->oldestEdition(6)->limit(10), $out, $r200], - ["/items/updated", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 5], (clone $c)->latestEdition(4)->limit(5), $out, $r200], - ["/items/updated", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 0], (clone $c)->limit(5), $out, $r200], + ["/items", [], clone $c, $out, $r200], + ["/items", ['type' => 0, 'id' => 42], (clone $c)->subscription(42), new ExceptionInput("idMissing"), $r422], + ["/items", ['type' => 1, 'id' => 2112], (clone $c)->folder(2112), new ExceptionInput("idMissing"), $r422], + ["/items", ['type' => 0, 'id' => -1], (clone $c)->subscription(-1), new ExceptionInput("typeViolation"), $r422], + ["/items", ['type' => 1, 'id' => -1], (clone $c)->folder(-1), new ExceptionInput("typeViolation"), $r422], + ["/items", ['type' => 2, 'id' => 0], (clone $c)->starred(true), $out, $r200], + ["/items", ['type' => 3, 'id' => 0], clone $c, $out, $r200], + ["/items", ['getRead' => true], clone $c, $out, $r200], + ["/items", ['getRead' => false], (clone $c)->unread(true), $out, $r200], + ["/items", ['lastModified' => $t->getTimestamp()], (clone $c)->markedRange($t, null), $out, $r200], + ["/items", ['oldestFirst' => true, 'batchSize' => 10, 'offset' => 5], (clone $c)->editionRange(6, null)->limit(10), $out, $r200], + ["/items", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 5], (clone $c)->editionRange(null, 4)->limit(5), $out, $r200], + ["/items", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 0], (clone $c)->limit(5), $out, $r200], + ["/items/updated", [], clone $c, $out, $r200], + ["/items/updated", ['type' => 0, 'id' => 42], (clone $c)->subscription(42), new ExceptionInput("idMissing"), $r422], + ["/items/updated", ['type' => 1, 'id' => 2112], (clone $c)->folder(2112), new ExceptionInput("idMissing"), $r422], + ["/items/updated", ['type' => 0, 'id' => -1], (clone $c)->subscription(-1), new ExceptionInput("typeViolation"), $r422], + ["/items/updated", ['type' => 1, 'id' => -1], (clone $c)->folder(-1), new ExceptionInput("typeViolation"), $r422], + ["/items/updated", ['type' => 2, 'id' => 0], (clone $c)->starred(true), $out, $r200], + ["/items/updated", ['type' => 3, 'id' => 0], clone $c, $out, $r200], + ["/items/updated", ['getRead' => true], clone $c, $out, $r200], + ["/items/updated", ['getRead' => false], (clone $c)->unread(true), $out, $r200], + ["/items/updated", ['lastModified' => $t->getTimestamp()], (clone $c)->markedRange($t, null), $out, $r200], + ["/items/updated", ['oldestFirst' => true, 'batchSize' => 10, 'offset' => 5], (clone $c)->editionRange(6, null)->limit(10), $out, $r200], + ["/items/updated", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 5], (clone $c)->editionRange(null, 4)->limit(5), $out, $r200], + ["/items/updated", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 0], (clone $c)->limit(5), $out, $r200], ]; } public function testMarkAFolderRead(): void { $read = ['read' => true]; $in = json_encode(['newestItemId' => 2112]); - $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->folder(1)->latestEdition(2112)->hidden(false)))->returns(42); - $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->folder(42)->latestEdition(2112)->hidden(false)))->throws(new ExceptionInput("idMissing")); // folder doesn't exist + $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->folder(1)->editionRange(null, 2112)->hidden(false)))->returns(42); + $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->folder(42)->editionRange(null, 2112)->hidden(false)))->throws(new ExceptionInput("idMissing")); // folder doesn't exist $exp = new EmptyResponse(204); $this->assertMessage($exp, $this->req("PUT", "/folders/1/read", $in)); $this->assertMessage($exp, $this->req("PUT", "/folders/1/read?newestItemId=2112")); @@ -733,8 +733,8 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function testMarkASubscriptionRead(): void { $read = ['read' => true]; $in = json_encode(['newestItemId' => 2112]); - $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->subscription(1)->latestEdition(2112)->hidden(false)))->returns(42); - $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->subscription(42)->latestEdition(2112)->hidden(false)))->throws(new ExceptionInput("idMissing")); // subscription doesn't exist + $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->subscription(1)->editionRange(null, 2112)->hidden(false)))->returns(42); + $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->subscription(42)->editionRange(null, 2112)->hidden(false)))->throws(new ExceptionInput("idMissing")); // subscription doesn't exist $exp = new EmptyResponse(204); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/read", $in)); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/read?newestItemId=2112")); @@ -748,7 +748,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function testMarkAllItemsRead(): void { $read = ['read' => true]; $in = json_encode(['newestItemId' => 2112]); - $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->latestEdition(2112)))->returns(42); + $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->editionRange(null, 2112)))->returns(42); $exp = new EmptyResponse(204); $this->assertMessage($exp, $this->req("PUT", "/items/read", $in)); $this->assertMessage($exp, $this->req("PUT", "/items/read?newestItemId=2112")); diff --git a/tests/cases/REST/TinyTinyRSS/TestAPI.php b/tests/cases/REST/TinyTinyRSS/TestAPI.php index e9ed0e5..fe5c07b 100644 --- a/tests/cases/REST/TinyTinyRSS/TestAPI.php +++ b/tests/cases/REST/TinyTinyRSS/TestAPI.php @@ -1539,7 +1539,7 @@ LONG_STRING; [true, ['feed_id' => -4, 'limit' => 5], $out, (clone $c)->limit(5), $fields, $sort, $expFull], [true, ['feed_id' => -4, 'skip' => 2], $out, (clone $c)->offset(2), $fields, $sort, $expFull], [true, ['feed_id' => -4, 'limit' => 5, 'skip' => 2], $out, (clone $c)->limit(5)->offset(2), $fields, $sort, $expFull], - [true, ['feed_id' => -4, 'since_id' => 47], $out, (clone $c)->oldestArticle(48), $fields, $sort, $expFull], + [true, ['feed_id' => -4, 'since_id' => 47], $out, (clone $c)->articleRange(48, null), $fields, $sort, $expFull], [true, ['feed_id' => -3, 'is_cat' => true], $out, $c, $fields, $sort, $expFull], [true, ['feed_id' => -4, 'is_cat' => true], $out, $c, $fields, $sort, $expFull], [true, ['feed_id' => -2, 'is_cat' => true], $out, (clone $c)->labelled(true), $fields, $sort, $expFull], @@ -1571,7 +1571,7 @@ LONG_STRING; [false, ['feed_id' => -4, 'limit' => 5], $comp, (clone $c)->limit(5), ["id"], $sort, $expComp], [false, ['feed_id' => -4, 'skip' => 2], $comp, (clone $c)->limit(null)->offset(2), ["id"], $sort, $expComp], [false, ['feed_id' => -4, 'limit' => 5, 'skip' => 2], $comp, (clone $c)->limit(5)->offset(2), ["id"], $sort, $expComp], - [false, ['feed_id' => -4, 'since_id' => 47], $comp, (clone $c)->limit(null)->oldestArticle(48), ["id"], $sort, $expComp], + [false, ['feed_id' => -4, 'since_id' => 47], $comp, (clone $c)->limit(null)->articleRange(48, null), ["id"], $sort, $expComp], [false, ['feed_id' => -6], $comp, (clone $c)->limit(null)->unread(false)->markedRange(Date::sub("PT24H", $t), null), ["id"], ["marked_date desc"], $expComp], [false, ['feed_id' => -6, 'view_mode' => "unread"], null, (clone $c)->limit(null), ["id"], $sort, $this->respGood([])], [false, ['feed_id' => -3], $comp, (clone $c)->limit(null)->unread(true)->modifiedRange(Date::sub("PT24H", $t), null), ["id"], $sort, $expComp],