1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-23 08:24:54 +00:00

Refactor some tests to use data providers

This commit is contained in:
J. King 2020-01-08 12:02:43 -05:00
parent fb2602fe04
commit c4ee7254cd
2 changed files with 145 additions and 178 deletions

View file

@ -14,6 +14,7 @@ use JKingWeb\Arsse\AbstractException;
use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Db\ExceptionInput;
use JKingWeb\Arsse\Feed\Exception as FeedException; use JKingWeb\Arsse\Feed\Exception as FeedException;
use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Misc\HTTP;
use JKingWeb\Arsse\REST\Exception;
use JKingWeb\Arsse\REST\Exception404; use JKingWeb\Arsse\REST\Exception404;
use JKingWeb\Arsse\REST\Exception405; use JKingWeb\Arsse\REST\Exception405;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;

View file

@ -16,13 +16,13 @@ use JKingWeb\Arsse\Db\ExceptionInput;
use JKingWeb\Arsse\Db\Transaction; use JKingWeb\Arsse\Db\Transaction;
use JKingWeb\Arsse\REST\NextcloudNews\V1_2; use JKingWeb\Arsse\REST\NextcloudNews\V1_2;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Zend\Diactoros\ServerRequest;
use Zend\Diactoros\Response\JsonResponse as Response; use Zend\Diactoros\Response\JsonResponse as Response;
use Zend\Diactoros\Response\EmptyResponse; use Zend\Diactoros\Response\EmptyResponse;
/** @covers \JKingWeb\Arsse\REST\NextcloudNews\V1_2<extended> */ /** @covers \JKingWeb\Arsse\REST\NextcloudNews\V1_2<extended> */
class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
protected $h; protected $h;
protected $transaction;
protected $feeds = [ // expected sample output of a feed list from the database, and the resultant expected transformation by the REST handler protected $feeds = [ // expected sample output of a feed list from the database, and the resultant expected transformation by the REST handler
'db' => [ 'db' => [
[ [
@ -298,10 +298,16 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
], ],
]; ];
protected function req(string $method, string $target, string $data = "", array $headers = [], bool $authenticated = true): ResponseInterface { protected function req(string $method, string $target, $data = "", array $headers = [], bool $authenticated = true, bool $body = true): ResponseInterface {
$prefix = "/index.php/apps/news/api/v1-2"; $prefix = "/index.php/apps/news/api/v1-2";
$url = $prefix.$target; $url = $prefix.$target;
$req = $this->serverRequest($method, $url, $prefix, $headers, [], $data, "application/json", [], $authenticated ? "john.doe@example.com" : ""); if ($body) {
$params = [];
} else {
$params = $data;
$data = [];
}
$req = $this->serverRequest($method, $url, $prefix, $headers, [], $data, "application/json", $params, $authenticated ? "john.doe@example.com" : "");
return $this->h->dispatch($req); return $this->h->dispatch($req);
} }
@ -313,7 +319,9 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Arsse::$user->id = "john.doe@example.com"; Arsse::$user->id = "john.doe@example.com";
// create a mock database interface // create a mock database interface
Arsse::$db = \Phake::mock(Database::class); Arsse::$db = \Phake::mock(Database::class);
\Phake::when(Arsse::$db)->begin->thenReturn(\Phake::mock(Transaction::class)); $this->transaction = \Phake::mock(Transaction::class);
\Phake::when(Arsse::$db)->begin->thenReturn($this->transaction);
//initialize a handler
$this->h = new V1_2(); $this->h = new V1_2();
} }
@ -330,50 +338,37 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
$this->assertMessage($exp, $this->req("GET", "/", "", [], false)); $this->assertMessage($exp, $this->req("GET", "/", "", [], false));
} }
public function testRespondToInvalidPaths() { /** @dataProvider provideInvalidPaths */
$errs = [ public function testRespondToInvalidPaths($path, $method, $code, $allow = null) {
404 => [ $exp = new EmptyResponse($code, $allow ? ['Allow' => $allow] : []);
['GET', "/"], $this->assertMessage($exp, $this->req($method, $path));
['PUT', "/"], }
['POST', "/"],
['DELETE', "/"], public function provideInvalidPaths() {
['GET', "/folders/1/invalid"], return [
['PUT', "/folders/1/invalid"], ["/", "GET", 404],
['POST', "/folders/1/invalid"], ["/", "POST", 404],
['DELETE', "/folders/1/invalid"], ["/", "PUT", 404],
['GET', "/version/invalid"], ["/", "DELETE", 404],
['PUT', "/version/invalid"], ["/", "OPTIONS", 404],
['POST', "/version/invalid"], ["/version/invalid", "GET", 404],
['DELETE', "/version/invalid"], ["/version/invalid", "POST", 404],
], ["/version/invalid", "PUT", 404],
405 => [ ["/version/invalid", "DELETE", 404],
'GET' => [ ["/version/invalid", "OPTIONS", 404],
['PUT', "/version"], ["/folders/1/invalid", "GET", 404],
['POST', "/version"], ["/folders/1/invalid", "POST", 404],
['DELETE', "/version"], ["/folders/1/invalid", "PUT", 404],
], ["/folders/1/invalid", "DELETE", 404],
'GET, POST' => [ ["/folders/1/invalid", "OPTIONS", 404],
['PUT', "/folders"], ["/version", "POST", 405, "GET"],
['DELETE', "/folders"], ["/version", "PUT", 405, "GET"],
], ["/version", "DELETE", 405, "GET"],
'PUT, DELETE' => [ ["/folders", "PUT", 405, "GET, POST"],
['GET', "/folders/1"], ["/folders", "DELETE", 405, "GET, POST"],
['POST', "/folders/1"], ["/folders/1", "GET", 405, "PUT, DELETE"],
], ["/folders/1", "POST", 405, "PUT, DELETE"],
],
]; ];
foreach ($errs[404] as $req) {
$exp = new EmptyResponse(404);
list($method, $path) = $req;
$this->assertMessage($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->assertMessage($exp, $this->req($method, $path), "$method call to $path did not return 405.");
}
}
} }
public function testRespondToInvalidInputTypes() { public function testRespondToInvalidInputTypes() {
@ -384,24 +379,21 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
$this->assertMessage($exp, $this->req("PUT", "/folders/1", '<data/>', ['Content-Type' => null])); $this->assertMessage($exp, $this->req("PUT", "/folders/1", '<data/>', ['Content-Type' => null]));
} }
public function testRespondToOptionsRequests() { /** @dataProvider provideOptionsRequests */
public function testRespondToOptionsRequests(string $url, string $allow, string $accept) {
$exp = new EmptyResponse(204, [ $exp = new EmptyResponse(204, [
'Allow' => "HEAD,GET,POST", 'Allow' => $allow,
'Accept' => "application/json", 'Accept' => $accept,
]); ]);
$this->assertMessage($exp, $this->req("OPTIONS", "/feeds")); $this->assertMessage($exp, $this->req("OPTIONS", $url));
$exp = new EmptyResponse(204, [ }
'Allow' => "DELETE",
'Accept' => "application/json", public function provideOptionsRequests() {
]); return [
$this->assertMessage($exp, $this->req("OPTIONS", "/feeds/2112")); ["/feeds", "HEAD,GET,POST", "application/json"],
$exp = new EmptyResponse(204, [ ["/feeds/2112", "DELETE", "application/json"],
'Allow' => "HEAD,GET", ["/user", "HEAD,GET", "application/json"],
'Accept' => "application/json", ];
]);
$this->assertMessage($exp, $this->req("OPTIONS", "/user"));
$exp = new EmptyResponse(404);
$this->assertMessage($exp, $this->req("OPTIONS", "/invalid/path"));
} }
public function testListFolders() { public function testListFolders() {
@ -413,56 +405,40 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
['id' => 1, 'name' => "Software"], ['id' => 1, 'name' => "Software"],
['id' => 12, 'name' => "Hardware"], ['id' => 12, 'name' => "Hardware"],
]; ];
\Phake::when(Arsse::$db)->folderList(Arsse::$user->id, null, false)->thenReturn(new Result([]))->thenReturn(new Result($this->v($list))); \Phake::when(Arsse::$db)->folderList(Arsse::$user->id, null, false)->thenReturn(new Result($this->v($list)));
$exp = new Response(['folders' => []]);
$this->assertMessage($exp, $this->req("GET", "/folders"));
$exp = new Response(['folders' => $out]); $exp = new Response(['folders' => $out]);
$this->assertMessage($exp, $this->req("GET", "/folders")); $this->assertMessage($exp, $this->req("GET", "/folders"));
} }
public function testAddAFolder() { /** @dataProvider provideFolderCreations */
$in = [ public function testAddAFolder(array $input, bool $body, $output, ResponseInterface $exp) {
["name" => "Software"], if ($output instanceof ExceptionInput) {
["name" => "Hardware"], \Phake::when(Arsse::$db)->folderAdd->thenThrow($output);
} else {
\Phake::when(Arsse::$db)->folderAdd->thenReturn($output);
\Phake::when(Arsse::$db)->folderPropertiesGet->thenReturn($this->v(['id' => $output, 'name' => $input['name'], 'parent' => null]));
}
$act = $this->req("POST", "/folders", $input, [], true, $body);
$this->assertMessage($exp, $act);
\Phake::verify(Arsse::$db)->folderAdd(Arsse::$user->id, $input);
if ($output instanceof ExceptionInput) {
\Phake::verify(Arsse::$db, \Phake::times(0))->folderPropertiesGet;
} else {
\Phake::verify(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, $output);
}
}
public function provideFolderCreations() {
return [
[['name' => "Software"], true, 1, new Response(['folders' => [['id'=> 1, 'name' => "Software"]]])],
[['name' => "Software"], false, 1, new Response(['folders' => [['id'=> 1, 'name' => "Software"]]])],
[['name' => "Hardware"], true, "2", new Response(['folders' => [['id'=> 2, 'name' => "Hardware"]]])],
[['name' => "Hardware"], false, "2", new Response(['folders' => [['id'=> 2, 'name' => "Hardware"]]])],
[['name' => "Software"], true, new ExceptionInput("constraintViolation"), new EmptyResponse(409)],
[['name' => ""], true, new ExceptionInput("whitespace"), new EmptyResponse(422)],
[['name' => " "], true, new ExceptionInput("whitespace"), new EmptyResponse(422)],
[['name' => null], true, new ExceptionInput("missing"), new EmptyResponse(422)],
]; ];
$db = [
['id' => 1, 'name' => "Software", 'parent' => null],
['id' => "2", 'name' => "Hardware", 'parent' => null],
];
$out = [
['id' => 1, 'name' => "Software"],
['id' => 2, 'name' => "Hardware"],
];
// set of various mocks for testing
\Phake::when(Arsse::$db)->folderAdd($this->anything(), $this->anything())->thenThrow(new \Exception);
\Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, $in[0])->thenReturn(1)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call
\Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, $in[1])->thenReturn(2)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call
\Phake::when(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 1)->thenReturn($this->v($db[0]));
\Phake::when(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 2)->thenReturn($this->v($db[1]));
// set up mocks that produce errors
\Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, [])->thenThrow(new ExceptionInput("missing"));
\Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, ['name' => ""])->thenThrow(new ExceptionInput("missing"));
\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->assertMessage($exp, $this->req("POST", "/folders", json_encode($in[0])));
$exp = new Response(['folders' => [$out[1]]]);
$this->assertMessage($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->assertMessage($exp, $this->req("POST", "/folders"));
$this->assertMessage($exp, $this->req("POST", "/folders", '{"name":""}'));
$this->assertMessage($exp, $this->req("POST", "/folders", '{"name":" "}'));
$this->assertMessage($exp, $this->req("POST", "/folders", '{"name":{}}'));
// try adding the same two folders again
$exp = new EmptyResponse(409);
$this->assertMessage($exp, $this->req("POST", "/folders?name=Software"));
$exp = new EmptyResponse(409);
$this->assertMessage($exp, $this->req("POST", "/folders", json_encode($in[1])));
} }
public function testRemoveAFolder() { public function testRemoveAFolder() {
@ -475,32 +451,26 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
\Phake::verify(Arsse::$db, \Phake::times(2))->folderRemove(Arsse::$user->id, 1); \Phake::verify(Arsse::$db, \Phake::times(2))->folderRemove(Arsse::$user->id, 1);
} }
public function testRenameAFolder() { /** @dataProvider provideFolderRenamings */
$in = [ public function testRenameAFolder(array $input, int $id, $output, ResponseInterface $exp) {
["name" => "Software"], if ($output instanceof ExceptionInput) {
["name" => "Software"], \Phake::when(Arsse::$db)->folderPropertiesSet->thenThrow($output);
["name" => ""], } else {
["name" => " "], \Phake::when(Arsse::$db)->folderPropertiesSet->thenReturn($output);
[], }
$act = $this->req("PUT", "/folders/$id", $input);
$this->assertMessage($exp, $act);
\Phake::verify(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, $id, $input);
}
public function provideFolderRenamings() {
return [
[['name' => "Software"], 1, true, new EmptyResponse(204)],
[['name' => "Software"], 2, new ExceptionInput("constraintViolation"), new EmptyResponse(409)],
[['name' => "Software"], 3, new ExceptionInput("subjectMissing"), new EmptyResponse(404)],
[['name' => ""], 2, new ExceptionInput("whitespace"), new EmptyResponse(422)],
[['name' => " "], 2, new ExceptionInput("whitespace"), new EmptyResponse(422)],
[['name' => null], 2, new ExceptionInput("missing"), new EmptyResponse(422)],
]; ];
\Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[0])->thenReturn(true);
\Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 2, $in[1])->thenThrow(new ExceptionInput("constraintViolation"));
\Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[2])->thenThrow(new ExceptionInput("missing"));
\Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[3])->thenThrow(new ExceptionInput("whitespace"));
\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->assertMessage($exp, $this->req("PUT", "/folders/1", json_encode($in[0])));
$exp = new EmptyResponse(409);
$this->assertMessage($exp, $this->req("PUT", "/folders/2", json_encode($in[1])));
$exp = new EmptyResponse(422);
$this->assertMessage($exp, $this->req("PUT", "/folders/1", json_encode($in[2])));
$exp = new EmptyResponse(422);
$this->assertMessage($exp, $this->req("PUT", "/folders/1", json_encode($in[3])));
$exp = new EmptyResponse(422);
$this->assertMessage($exp, $this->req("PUT", "/folders/1", json_encode($in[4])));
$exp = new EmptyResponse(404);
$this->assertMessage($exp, $this->req("PUT", "/folders/3", json_encode($in[0])));
} }
public function testRetrieveServerVersion() { public function testRetrieveServerVersion() {
@ -530,52 +500,48 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
$this->assertMessage($exp, $this->req("GET", "/feeds")); $this->assertMessage($exp, $this->req("GET", "/feeds"));
} }
public function testAddASubscription() { /** @dataProvider provideNewSubscriptions */
$in = [ public function testAddASubscription(array $input, $id, int $latestEdition, array $output, $moveOutcome, ResponseInterface $exp) {
['url' => "http://example.com/news.atom", 'folderId' => 3], if ($id instanceof \Exception) {
['url' => "http://example.org/news.atom", 'folderId' => 8], \Phake::when(Arsse::$db)->subscriptionAdd->thenThrow($id);
['url' => "http://example.net/news.atom", 'folderId' => 8], } else {
['url' => "http://example.net/news.atom", 'folderId' => -1], \Phake::when(Arsse::$db)->subscriptionAdd->thenReturn($id);
[], }
if ($moveOutcome instanceof \Exception) {
\Phake::when(Arsse::$db)->subscriptionPropertiesSet->thenThrow($moveOutcome);
} else {
\Phake::when(Arsse::$db)->subscriptionPropertiesSet->thenReturn($moveOutcome);
}
\Phake::when(Arsse::$db)->subscriptionPropertiesGet->thenReturn($this->v($output));
\Phake::when(Arsse::$db)->editionLatest->thenReturn($latestEdition);
$act = $this->req("POST", "/feeds", $input);
$this->assertMessage($exp, $act);
\Phake::verify(Arsse::$db)->subscriptionAdd(Arsse::$user->id, $input['url'] ?? "");
if ($id instanceof \Exception) {
\Phake::verify(Arsse::$db, \Phake::times(0))->subscriptionPropertiesSet;
\Phake::verify(Arsse::$db, \Phake::times(0))->subscriptionPropertiesGet;
\Phake::verify(Arsse::$db, \Phake::times(0))->editionLatest;
} else {
\Phake::verify(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, $id);
\Phake::verify(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription($id));
if ($input['folderId'] ?? 0) {
\Phake::verify(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, $id, ['folder' => (int) $input['folderId']]);
} else {
\Phake::verify(Arsse::$db, \Phake::times(0))->subscriptionPropertiesSet;
}
}
}
public function provideNewSubscriptions() {
$feedException = new \JKingWeb\Arsse\Feed\Exception("", new \PicoFeed\Reader\SubscriptionNotFoundException);
return [
[['url' => "http://example.com/news.atom", 'folderId' => 3], 2112, 0, $this->feeds['db'][0], new ExceptionInput("idMissing"), new Response(['feeds' => [$this->feeds['rest'][0]]])],
[['url' => "http://example.org/news.atom", 'folderId' => 8], 42, 4758915, $this->feeds['db'][1], true, new Response(['feeds' => [$this->feeds['rest'][1]], 'newestItemId' => 4758915])],
[['url' => "http://example.com/news.atom", 'folderId' => 3], new ExceptionInput("constraintViolation"), 0, $this->feeds['db'][0], new ExceptionInput("idMissing"), new EmptyResponse(409)],
[['url' => "http://example.org/news.atom", 'folderId' => 8], new ExceptionInput("constraintViolation"), 4758915, $this->feeds['db'][1], true, new EmptyResponse(409)],
[[], $feedException, 0, [], false, new EmptyResponse(422)],
[['url' => "http://example.net/news.atom", 'folderId' => -1], 47, 2112, $this->feeds['db'][2], new ExceptionInput("typeViolation"), new Response(['feeds' => [$this->feeds['rest'][2]], 'newestItemId' => 2112])],
]; ];
$out = [
['feeds' => [$this->feeds['rest'][0]]],
['feeds' => [$this->feeds['rest'][1]], 'newestItemId' => 4758915],
['feeds' => [$this->feeds['rest'][2]], 'newestItemId' => 2112],
];
// set up the necessary mocks
\Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.com/news.atom")->thenReturn(2112)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call
\Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.org/news.atom")->thenReturn(42)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call
\Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "")->thenThrow(new \JKingWeb\Arsse\Feed\Exception("", new \PicoFeed\Reader\SubscriptionNotFoundException));
\Phake::when(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 2112)->thenReturn($this->v($this->feeds['db'][0]));
\Phake::when(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 42)->thenReturn($this->v($this->feeds['db'][1]));
\Phake::when(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 47)->thenReturn($this->v($this->feeds['db'][2]));
\Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription(2112))->thenReturn(0);
\Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription(42))->thenReturn(4758915);
\Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription(47))->thenReturn(2112);
\Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 2112, ['folder' => 3])->thenThrow(new ExceptionInput("idMissing")); // folder ID 3 does not exist
\Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, ['folder' => 8])->thenReturn(true);
\Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 47, ['folder' => -1])->thenThrow(new ExceptionInput("typeViolation")); // folder ID -1 is invalid
// set up a mock for a bad feed which succeeds the second time
\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->assertMessage($exp, $this->req("POST", "/feeds", json_encode($in[0])));
$exp = new Response($out[1]);
$this->assertMessage($exp, $this->req("POST", "/feeds", json_encode($in[1])));
// try to add them a second time
$exp = new EmptyResponse(409);
$this->assertMessage($exp, $this->req("POST", "/feeds", json_encode($in[0])));
$this->assertMessage($exp, $this->req("POST", "/feeds", json_encode($in[1])));
// try to add a bad feed
$exp = new EmptyResponse(422);
$this->assertMessage($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->assertMessage($exp, $this->req("POST", "/feeds", json_encode($in[3])));
// try to add no feed
$exp = new EmptyResponse(422);
$this->assertMessage($exp, $this->req("POST", "/feeds", json_encode($in[4])));
} }
public function testRemoveASubscription() { public function testRemoveASubscription() {