@ -11,13 +11,14 @@ use JKingWeb\Arsse\Conf;
use JKingWeb\Arsse\User;
use JKingWeb\Arsse\Database;
use JKingWeb\Arsse\Service;
use JKingWeb\Arsse\REST\Request;
use JKingWeb\Arsse\Test\Result;
use JKingWeb\Arsse\Misc\Date;
use JKingWeb\Arsse\Misc\Context;
use JKingWeb\Arsse\Db\ExceptionInput;
use JKingWeb\Arsse\Db\Transaction;
use JKingWeb\Arsse\REST\NextCloudNews\V1_2;
use Psr\Http\Message\ResponseInterface;
use Zend\Diactoros\ServerRequest;
use Zend\Diactoros\Response\JsonResponse as Response;
use Zend\Diactoros\Response\EmptyResponse;
use Phake;
@ -300,6 +301,40 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
],
];
protected function req(string $method, string $target, string $data = "", array $headers = []): ResponseInterface {
$url = "/index.php/apps/news/api/v1-2".$target;
$server = [
'REQUEST_METHOD' => $method,
'REQUEST_URI' => $url,
'PHP_AUTH_USER' => "john.doe@example.com",
'PHP_AUTH_PW' => "secret",
'REMOTE_USER' => "john.doe@example.com",
];
if (strlen($data)) {
$server['HTTP_CONTENT_TYPE'] = "application/json";
}
$req = new ServerRequest($server, [], $url, $method, "php://memory");
foreach($headers as $key => $value) {
if (!is_null($value)) {
$req = $req->withHeader($key, $value);
} else {
$req = $req->withoutHeader($key);
}
}
if (strlen($data)) {
$body = $req->getBody();
$body->write($data);
$req = $req->withBody($body);
}
$q = $req->getUri()->getQuery();
if (strlen($q)) {
parse_str($q, $q);
$req = $req->withQueryParams($q);
}
$req = $req->withRequestTarget($target);
return $this->h->dispatch($req);
}
public function setUp() {
$this->clearData();
Arsse::$conf = new Conf();
@ -321,7 +356,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
public function testSendAuthenticationChallenge() {
Phake::when(Arsse::$user)->authHTTP->thenReturn(false);
$exp = new EmptyResponse(401, ['WWW-Authenticate' => 'Basic realm="'.V1_2::REALM.'"']);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/") ));
$this->assertResponse($exp, $this->req("GET", "/" ));
}
public function testRespondToInvalidPaths() {
@ -359,22 +394,23 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
foreach ($errs[404] as $req) {
$exp = new EmptyResponse(404);
list($method, $path) = $req;
$this->assertResponse($exp, $this->h->dispatch(new Request($method, $path) ), "$method call to $path did not return 404.");
$this->assertResponse($exp, $this->req($method, $path ), "$method call to $path did not return 404.");
}
foreach ($errs[405] as $allow => $cases) {
$exp = new EmptyResponse(405, ['Allow' => $allow]);
foreach ($cases as $req) {
list($method, $path) = $req;
$this->assertResponse($exp, $this->h->dispatch(new Request($method, $path) ), "$method call to $path did not return 405.");
$this->assertResponse($exp, $this->req($method, $path ), "$method call to $path did not return 405.");
}
}
}
public function testRespondToInvalidInputTypes() {
$exp = new EmptyResponse(415, ['Accept' => "application/json"]);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/folders/1", '< data / > ', 'application/xml') ));
$this->assertResponse($exp, $this->req ("PUT", "/folders/1", '< data / > ', ['Content-Type' => "application/xml"] ));
$exp = new EmptyResponse(400);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", '< data / > ', 'application/json')));
$this->assertResponse($exp, $this->req("PUT", "/folders/1", '< data / > '));
$this->assertResponse($exp, $this->req("PUT", "/folders/1", '< data / > ', ['Content-Type' => null]));
}
public function testRespondToOptionsRequests() {
@ -382,19 +418,19 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
'Allow' => "HEAD,GET,POST",
'Accept' => "application/json",
]);
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/feeds") ));
$this->assertResponse($exp, $this->req("OPTIONS", "/feeds" ));
$exp = new EmptyResponse(204, [
'Allow' => "DELETE",
'Accept' => "application/json",
]);
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/feeds/2112") ));
$this->assertResponse($exp, $this->req("OPTIONS", "/feeds/2112" ));
$exp = new EmptyResponse(204, [
'Allow' => "HEAD,GET",
'Accept' => "application/json",
]);
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/user") ));
$this->assertResponse($exp, $this->req("OPTIONS", "/user" ));
$exp = new EmptyResponse(404);
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/invalid/path") ));
$this->assertResponse($exp, $this->req("OPTIONS", "/invalid/path" ));
}
public function testListFolders() {
@ -408,9 +444,9 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
];
Phake::when(Arsse::$db)->folderList(Arsse::$user->id, null, false)->thenReturn(new Result([]))->thenReturn(new Result($list));
$exp = new Response(['folders' => []]);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/folders") ));
$this->assertResponse($exp, $this->req("GET", "/folders" ));
$exp = new Response(['folders' => $out]);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/folders") ));
$this->assertResponse($exp, $this->req("GET", "/folders" ));
}
public function testAddAFolder() {
@ -438,33 +474,33 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, ['name' => " "])->thenThrow(new ExceptionInput("whitespace"));
// correctly add two folders, using different means
$exp = new Response(['folders' => [$out[0]]]);
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/folders", json_encode($in[0]), 'application/json' )));
$this->assertResponse($exp, $this->req ("POST", "/folders", json_encode($in[0])));
$exp = new Response(['folders' => [$out[1]]]);
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders?name=Hardware") ));
$this->assertResponse($exp, $this->req("POST", "/folders?name=Hardware" ));
Phake::verify(Arsse::$db)->folderAdd(Arsse::$user->id, $in[0]);
Phake::verify(Arsse::$db)->folderAdd(Arsse::$user->id, $in[1]);
Phake::verify(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 1);
Phake::verify(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 2);
// test bad folder names
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders") ));
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/folders", '{"name":""}', 'application/json') ));
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/folders", '{"name":" "}', 'application/json') ));
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/folders", '{"name":{}}', 'application/json') ));
$this->assertResponse($exp, $this->req("POST", "/folders" ));
$this->assertResponse($exp, $this->req ("POST", "/folders", '{"name":""}'));
$this->assertResponse($exp, $this->req ("POST", "/folders", '{"name":" "}'));
$this->assertResponse($exp, $this->req ("POST", "/folders", '{"name":{}}'));
// try adding the same two folders again
$exp = new EmptyResponse(409);
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders?name=Software") ));
$this->assertResponse($exp, $this->req("POST", "/folders?name=Software" ));
$exp = new EmptyResponse(409);
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/folders", json_encode($in[1]), 'application/json' )));
$this->assertResponse($exp, $this->req ("POST", "/folders", json_encode($in[1])));
}
public function testRemoveAFolder() {
Phake::when(Arsse::$db)->folderRemove(Arsse::$user->id, 1)->thenReturn(true)->thenThrow(new ExceptionInput("subjectMissing"));
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/folders/1") ));
$this->assertResponse($exp, $this->req("DELETE", "/folders/1" ));
// fail on the second invocation because it no longer exists
$exp = new EmptyResponse(404);
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/folders/1") ));
$this->assertResponse($exp, $this->req("DELETE", "/folders/1" ));
Phake::verify(Arsse::$db, Phake::times(2))->folderRemove(Arsse::$user->id, 1);
}
@ -483,17 +519,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[4])->thenReturn(true); // this should be stopped by the handler before the request gets to the database
Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 3, $this->anything())->thenThrow(new ExceptionInput("subjectMissing")); // folder ID 3 does not exist
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/folders/1", json_encode($in[0]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/folders/1", json_encode($in[0])));
$exp = new EmptyResponse(409);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/folders/2", json_encode($in[1]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/folders/2", json_encode($in[1])));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/folders/1", json_encode($in[2]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/folders/1", json_encode($in[2])));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/folders/1", json_encode($in[3]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/folders/1", json_encode($in[3])));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/folders/1", json_encode($in[4]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/folders/1", json_encode($in[4])));
$exp = new EmptyResponse(404);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/folders/3", json_encode($in[0]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/folders/3", json_encode($in[0])));
}
public function testRetrieveServerVersion() {
@ -501,7 +537,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
'version' => V1_2::VERSION,
'arsse_version' => Arsse::VERSION,
]);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/version") ));
$this->assertResponse($exp, $this->req("GET", "/version" ));
}
public function testListSubscriptions() {
@ -518,9 +554,9 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->articleStarred(Arsse::$user->id)->thenReturn(['total' => 0])->thenReturn(['total' => 5]);
Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id)->thenReturn(0)->thenReturn(4758915);
$exp = new Response($exp1);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds") ));
$this->assertResponse($exp, $this->req("GET", "/feeds" ));
$exp = new Response($exp2);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds") ));
$this->assertResponse($exp, $this->req("GET", "/feeds" ));
}
public function testAddASubscription() {
@ -553,31 +589,31 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.net/news.atom")->thenThrow(new \JKingWeb\Arsse\Feed\Exception("http://example.net/news.atom", new \PicoFeed\Client\InvalidUrlException()))->thenReturn(47);
// add the subscriptions
$exp = new Response($out[0]);
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/feeds", json_encode($in[0]), 'application/json' )));
$this->assertResponse($exp, $this->req ("POST", "/feeds", json_encode($in[0])));
$exp = new Response($out[1]);
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/feeds", json_encode($in[1]), 'application/json' )));
$this->assertResponse($exp, $this->req ("POST", "/feeds", json_encode($in[1])));
// try to add them a second time
$exp = new EmptyResponse(409);
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/feeds", json_encode($in[0]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/feeds", json_encode($in[1]), 'application/json' )));
$this->assertResponse($exp, $this->req ("POST", "/feeds", json_encode($in[0])));
$this->assertResponse($exp, $this->req ("POST", "/feeds", json_encode($in[1])));
// try to add a bad feed
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/feeds", json_encode($in[2]), 'application/json' )));
$this->assertResponse($exp, $this->req ("POST", "/feeds", json_encode($in[2])));
// try again (this will succeed), with an invalid folder ID
$exp = new Response($out[2]);
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/feeds", json_encode($in[3]), 'application/json' )));
$this->assertResponse($exp, $this->req ("POST", "/feeds", json_encode($in[3])));
// try to add no feed
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("POST", "/feeds", json_encode($in[4]), 'application/json' )));
$this->assertResponse($exp, $this->req ("POST", "/feeds", json_encode($in[4])));
}
public function testRemoveASubscription() {
Phake::when(Arsse::$db)->subscriptionRemove(Arsse::$user->id, 1)->thenReturn(true)->thenThrow(new ExceptionInput("subjectMissing"));
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/feeds/1") ));
$this->assertResponse($exp, $this->req("DELETE", "/feeds/1" ));
// fail on the second invocation because it no longer exists
$exp = new EmptyResponse(404);
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/feeds/1") ));
$this->assertResponse($exp, $this->req("DELETE", "/feeds/1" ));
Phake::verify(Arsse::$db, Phake::times(2))->subscriptionRemove(Arsse::$user->id, 1);
}
@ -596,17 +632,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, ['folder' => -1])->thenThrow(new ExceptionInput("typeViolation")); // folder is invalid
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, $this->anything())->thenThrow(new ExceptionInput("subjectMissing")); // subscription does not exist
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/move", json_encode($in[0]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/move", json_encode($in[0])));
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/move", json_encode($in[1]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/move", json_encode($in[1])));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/move", json_encode($in[2]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/move", json_encode($in[2])));
$exp = new EmptyResponse(404);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/42/move", json_encode($in[3]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/42/move", json_encode($in[3])));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/move", json_encode($in[4]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/move", json_encode($in[4])));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/move", json_encode($in[5]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/move", json_encode($in[5])));
}
public function testRenameASubscription() {
@ -626,17 +662,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, $this->identicalTo(['title' => false]))->thenThrow(new ExceptionInput("missing"));
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, $this->anything())->thenThrow(new ExceptionInput("subjectMissing"));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/rename", json_encode($in[0]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/rename", json_encode($in[0])));
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/rename", json_encode($in[1]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/rename", json_encode($in[1])));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/rename", json_encode($in[2]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/rename", json_encode($in[2])));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/rename", json_encode($in[3]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/rename", json_encode($in[3])));
$exp = new EmptyResponse(404);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/42/rename", json_encode($in[4]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/42/rename", json_encode($in[4])));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/rename", json_encode($in[6]), 'application/json' )));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/rename", json_encode($in[6])));
}
public function testListStaleFeeds() {
@ -652,11 +688,11 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
];
Phake::when(Arsse::$db)->feedListStale->thenReturn(array_column($out, "id"));
$exp = new Response(['feeds' => $out]);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/all") ));
$this->assertResponse($exp, $this->req("GET", "/feeds/all" ));
// retrieving the list when not an admin fails
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
$exp = new EmptyResponse(403);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/all") ));
$this->assertResponse($exp, $this->req("GET", "/feeds/all" ));
}
public function testUpdateAFeed() {
@ -671,17 +707,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->feedUpdate(2112)->thenThrow(new ExceptionInput("subjectMissing"));
Phake::when(Arsse::$db)->feedUpdate($this->lessThan(1))->thenThrow(new ExceptionInput("typeViolation"));
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request ("GET", "/feeds/update", json_encode($in[0]), 'application/json' )));
$this->assertResponse($exp, $this->req ("GET", "/feeds/update", json_encode($in[0])));
$exp = new EmptyResponse(404);
$this->assertResponse($exp, $this->h->dispatch(new Request ("GET", "/feeds/update", json_encode($in[1]), 'application/json' )));
$this->assertResponse($exp, $this->req ("GET", "/feeds/update", json_encode($in[1])));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("GET", "/feeds/update", json_encode($in[2]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("GET", "/feeds/update", json_encode($in[3]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("GET", "/feeds/update", json_encode($in[4]), 'application/json' )));
$this->assertResponse($exp, $this->req ("GET", "/feeds/update", json_encode($in[2])));
$this->assertResponse($exp, $this->req ("GET", "/feeds/update", json_encode($in[3])));
$this->assertResponse($exp, $this->req ("GET", "/feeds/update", json_encode($in[4])));
// updating a feed when not an admin fails
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
$exp = new EmptyResponse(403);
$this->assertResponse($exp, $this->h->dispatch(new Request ("GET", "/feeds/update", json_encode($in[0]), 'application/json' )));
$this->assertResponse($exp, $this->req ("GET", "/feeds/update", json_encode($in[0])));
}
public function testListArticles() {
@ -708,23 +744,23 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->folder(-1), Database::LIST_TYPICAL)->thenThrow(new ExceptionInput("typeViolation"));
$exp = new Response(['items' => $this->articles['rest']]);
// check the contents of the response
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items") )); // first instance of base context
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items/updated") )); // second instance of base context
$this->assertResponse($exp, $this->req("GET", "/items" )); // first instance of base context
$this->assertResponse($exp, $this->req("GET", "/items/updated" )); // second instance of base context
// check error conditions
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request ("GET", "/items", json_encode($in[0]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("GET", "/items", json_encode($in[1]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("GET", "/items", json_encode($in[2]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("GET", "/items", json_encode($in[3]), 'application/json' )));
$this->assertResponse($exp, $this->req ("GET", "/items", json_encode($in[0])));
$this->assertResponse($exp, $this->req ("GET", "/items", json_encode($in[1])));
$this->assertResponse($exp, $this->req ("GET", "/items", json_encode($in[2])));
$this->assertResponse($exp, $this->req ("GET", "/items", json_encode($in[3])));
// simply run through the remainder of the input for later method verification
$this->h->dispatch(new Request ("GET", "/items", json_encode($in[4]), 'application/json' ));
$this->h->dispatch(new Request ("GET", "/items", json_encode($in[5]), 'application/json' )); // third instance of base context
$this->h->dispatch(new Request ("GET", "/items", json_encode($in[6]), 'application/json' ));
$this->h->dispatch(new Request ("GET", "/items", json_encode($in[7]), 'application/json' ));
$this->h->dispatch(new Request ("GET", "/items", json_encode($in[8]), 'application/json' )); // fourth instance of base context
$this->h->dispatch(new Request ("GET", "/items", json_encode($in[9]), 'application/json' ));
$this->h->dispatch(new Request ("GET", "/items", json_encode($in[10]), 'application/json' ));
$this->h->dispatch(new Request ("GET", "/items", json_encode($in[11]), 'application/json' ));
$this->req ("GET", "/items", json_encode($in[4]));
$this->req ("GET", "/items", json_encode($in[5])); // third instance of base context
$this->req ("GET", "/items", json_encode($in[6]));
$this->req ("GET", "/items", json_encode($in[7]));
$this->req ("GET", "/items", json_encode($in[8])); // fourth instance of base context
$this->req ("GET", "/items", json_encode($in[9]));
$this->req ("GET", "/items", json_encode($in[10]));
$this->req ("GET", "/items", json_encode($in[11]));
// perform method verifications
Phake::verify(Arsse::$db, Phake::times(4))->articleList(Arsse::$user->id, (new Context)->reverse(true), Database::LIST_TYPICAL);
Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->subscription(42), Database::LIST_TYPICAL);
@ -745,13 +781,13 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->folder(1)->latestEdition(2112))->thenReturn(42);
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->folder(42)->latestEdition(2112))->thenThrow(new ExceptionInput("idMissing")); // folder doesn't exist
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read", $in, 'application/json') ));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/folders/1/read?newestItemId=2112") ));
$this->assertResponse($exp, $this->req("PUT", "/folders/1/read", $in ));
$this->assertResponse($exp, $this->req ("PUT", "/folders/1/read?newestItemId=2112"));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read") ));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/folders/1/read?newestItemId=ook") ));
$this->assertResponse($exp, $this->req("PUT", "/folders/1/read" ));
$this->assertResponse($exp, $this->req ("PUT", "/folders/1/read?newestItemId=ook"));
$exp = new EmptyResponse(404);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/42/read", $in, 'application/json') ));
$this->assertResponse($exp, $this->req("PUT", "/folders/42/read", $in ));
}
public function testMarkASubscriptionRead() {
@ -760,13 +796,13 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->subscription(1)->latestEdition(2112))->thenReturn(42);
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->subscription(42)->latestEdition(2112))->thenThrow(new ExceptionInput("idMissing")); // subscription doesn't exist
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read", $in, 'application/json') ));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/read?newestItemId=2112") ));
$this->assertResponse($exp, $this->req("PUT", "/feeds/1/read", $in ));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/read?newestItemId=2112"));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read") ));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/feeds/1/read?newestItemId=ook") ));
$this->assertResponse($exp, $this->req("PUT", "/feeds/1/read" ));
$this->assertResponse($exp, $this->req ("PUT", "/feeds/1/read?newestItemId=ook"));
$exp = new EmptyResponse(404);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/42/read", $in, 'application/json') ));
$this->assertResponse($exp, $this->req("PUT", "/feeds/42/read", $in ));
}
public function testMarkAllItemsRead() {
@ -774,11 +810,11 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
$in = json_encode(['newestItemId' => 2112]);
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->latestEdition(2112))->thenReturn(42);
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read", $in, 'application/json') ));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/read?newestItemId=2112") ));
$this->assertResponse($exp, $this->req("PUT", "/items/read", $in ));
$this->assertResponse($exp, $this->req ("PUT", "/items/read?newestItemId=2112"));
$exp = new EmptyResponse(422);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read") ));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/read?newestItemId=ook") ));
$this->assertResponse($exp, $this->req("PUT", "/items/read" ));
$this->assertResponse($exp, $this->req ("PUT", "/items/read?newestItemId=ook"));
}
public function testChangeMarksOfASingleArticle() {
@ -795,15 +831,15 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->article(4))->thenReturn(42);
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->article(1337))->thenThrow(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/1/read") ));
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/2/unread") ));
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/1/3/star") ));
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/4400/4/unstar") ));
$this->assertResponse($exp, $this->req("PUT", "/items/1/read" ));
$this->assertResponse($exp, $this->req("PUT", "/items/2/unread" ));
$this->assertResponse($exp, $this->req("PUT", "/items/1/3/star" ));
$this->assertResponse($exp, $this->req("PUT", "/items/4400/4/unstar" ));
$exp = new EmptyResponse(404);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/42/read") ));
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/47/unread") ));
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/1/2112/star") ));
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/4400/1337/unstar") ));
$this->assertResponse($exp, $this->req("PUT", "/items/42/read" ));
$this->assertResponse($exp, $this->req("PUT", "/items/47/unread" ));
$this->assertResponse($exp, $this->req("PUT", "/items/1/2112/star" ));
$this->assertResponse($exp, $this->req("PUT", "/items/4400/1337/unstar" ));
Phake::verify(Arsse::$db, Phake::times(8))->articleMark(Arsse::$user->id, $this->anything(), $this->anything());
}
@ -826,26 +862,26 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), (new Context)->editions([]))->thenThrow(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), (new Context)->articles([]))->thenThrow(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read/multiple") ));
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/unread/multiple") ));
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/star/multiple") ));
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/unstar/multiple") ));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/read/multiple", json_encode(['items' => "ook"]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/unread/multiple", json_encode(['items' => "ook"]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/star/multiple", json_encode(['items' => "ook"]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/unstar/multiple", json_encode(['items' => "ook"]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/read/multiple", json_encode(['items' => []]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/unread/multiple", json_encode(['items' => []]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/read/multiple", json_encode(['items' => $in[0]]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/unread/multiple", json_encode(['items' => $in[0]]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/read/multiple", json_encode(['items' => $in[1]]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/unread/multiple", json_encode(['items' => $in[1]]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/star/multiple", json_encode(['items' => []]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/unstar/multiple", json_encode(['items' => []]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/star/multiple", json_encode(['items' => $inStar[0]]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/unstar/multiple", json_encode(['items' => $inStar[0]]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/star/multiple", json_encode(['items' => $inStar[1]]), 'application/json' )));
$this->assertResponse($exp, $this->h->dispatch(new Request ("PUT", "/items/unstar/multiple", json_encode(['items' => $inStar[1]]), 'application/json' )));
$this->assertResponse($exp, $this->req("PUT", "/items/read/multiple" ));
$this->assertResponse($exp, $this->req("PUT", "/items/unread/multiple" ));
$this->assertResponse($exp, $this->req("PUT", "/items/star/multiple" ));
$this->assertResponse($exp, $this->req("PUT", "/items/unstar/multiple" ));
$this->assertResponse($exp, $this->req ("PUT", "/items/read/multiple", json_encode(['items' => "ook"])));
$this->assertResponse($exp, $this->req ("PUT", "/items/unread/multiple", json_encode(['items' => "ook"])));
$this->assertResponse($exp, $this->req ("PUT", "/items/star/multiple", json_encode(['items' => "ook"])));
$this->assertResponse($exp, $this->req ("PUT", "/items/unstar/multiple", json_encode(['items' => "ook"])));
$this->assertResponse($exp, $this->req ("PUT", "/items/read/multiple", json_encode(['items' => []])));
$this->assertResponse($exp, $this->req ("PUT", "/items/unread/multiple", json_encode(['items' => []])));
$this->assertResponse($exp, $this->req ("PUT", "/items/read/multiple", json_encode(['items' => $in[0]])));
$this->assertResponse($exp, $this->req ("PUT", "/items/unread/multiple", json_encode(['items' => $in[0]])));
$this->assertResponse($exp, $this->req ("PUT", "/items/read/multiple", json_encode(['items' => $in[1]])));
$this->assertResponse($exp, $this->req ("PUT", "/items/unread/multiple", json_encode(['items' => $in[1]])));
$this->assertResponse($exp, $this->req ("PUT", "/items/star/multiple", json_encode(['items' => []])));
$this->assertResponse($exp, $this->req ("PUT", "/items/unstar/multiple", json_encode(['items' => []])));
$this->assertResponse($exp, $this->req ("PUT", "/items/star/multiple", json_encode(['items' => $inStar[0]])));
$this->assertResponse($exp, $this->req ("PUT", "/items/unstar/multiple", json_encode(['items' => $inStar[0]])));
$this->assertResponse($exp, $this->req ("PUT", "/items/star/multiple", json_encode(['items' => $inStar[1]])));
$this->assertResponse($exp, $this->req ("PUT", "/items/unstar/multiple", json_encode(['items' => $inStar[1]])));
// ensure the data model was queried appropriately for read/unread
Phake::verify(Arsse::$db, Phake::atLeast(1))->articleMark(Arsse::$user->id, $read, (new Context)->editions([]));
Phake::verify(Arsse::$db, Phake::atLeast(1))->articleMark(Arsse::$user->id, $read, (new Context)->editions($in[0]));
@ -879,28 +915,28 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
$arr2['warnings']['improperlyConfiguredCron'] = true;
$arr2['warnings']['incorrectDbCharset'] = true;
$exp = new Response($arr1);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/status") ));
$this->assertResponse($exp, $this->req("GET", "/status" ));
}
public function testCleanUpBeforeUpdate() {
Phake::when(Arsse::$db)->feedCleanup()->thenReturn(true);
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/before-update") ));
$this->assertResponse($exp, $this->req("GET", "/cleanup/before-update" ));
Phake::verify(Arsse::$db)->feedCleanup();
// performing a cleanup when not an admin fails
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
$exp = new EmptyResponse(403);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/before-update") ));
$this->assertResponse($exp, $this->req("GET", "/cleanup/before-update" ));
}
public function testCleanUpAfterUpdate() {
Phake::when(Arsse::$db)->articleCleanup()->thenReturn(true);
$exp = new EmptyResponse(204);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/after-update") ));
$this->assertResponse($exp, $this->req("GET", "/cleanup/after-update" ));
Phake::verify(Arsse::$db)->articleCleanup();
// performing a cleanup when not an admin fails
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
$exp = new EmptyResponse(403);
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/after-update") ));
$this->assertResponse($exp, $this->req("GET", "/cleanup/after-update" ));
}
}