From d3f42ca487287447efb81061609644108044a038 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 19 May 2018 15:04:04 +0200 Subject: Implements Tags endpoints for Shaarli's REST API Endpoints: * List All Tags [GET] * Get a tag [GET] * Update a tag [PUT] * Delete a tag [DELETE] Fixes #904 References shaarli/api-documentation#34 --- tests/api/controllers/DeleteLinkTest.php | 126 ------- tests/api/controllers/GetLinkIdTest.php | 132 ------- tests/api/controllers/GetLinksTest.php | 472 ------------------------- tests/api/controllers/HistoryTest.php | 216 ----------- tests/api/controllers/InfoTest.php | 115 ------ tests/api/controllers/PostLinkTest.php | 218 ------------ tests/api/controllers/PutLinkTest.php | 222 ------------ tests/api/controllers/history/HistoryTest.php | 216 +++++++++++ tests/api/controllers/info/InfoTest.php | 115 ++++++ tests/api/controllers/links/DeleteLinkTest.php | 126 +++++++ tests/api/controllers/links/GetLinkIdTest.php | 132 +++++++ tests/api/controllers/links/GetLinksTest.php | 472 +++++++++++++++++++++++++ tests/api/controllers/links/PostLinkTest.php | 218 ++++++++++++ tests/api/controllers/links/PutLinkTest.php | 222 ++++++++++++ tests/api/controllers/tags/DeleteTagTest.php | 164 +++++++++ tests/api/controllers/tags/GetTagNameTest.php | 129 +++++++ tests/api/controllers/tags/GetTagsTest.php | 209 +++++++++++ tests/api/controllers/tags/PutTagTest.php | 209 +++++++++++ 18 files changed, 2212 insertions(+), 1501 deletions(-) delete mode 100644 tests/api/controllers/DeleteLinkTest.php delete mode 100644 tests/api/controllers/GetLinkIdTest.php delete mode 100644 tests/api/controllers/GetLinksTest.php delete mode 100644 tests/api/controllers/HistoryTest.php delete mode 100644 tests/api/controllers/InfoTest.php delete mode 100644 tests/api/controllers/PostLinkTest.php delete mode 100644 tests/api/controllers/PutLinkTest.php create mode 100644 tests/api/controllers/history/HistoryTest.php create mode 100644 tests/api/controllers/info/InfoTest.php create mode 100644 tests/api/controllers/links/DeleteLinkTest.php create mode 100644 tests/api/controllers/links/GetLinkIdTest.php create mode 100644 tests/api/controllers/links/GetLinksTest.php create mode 100644 tests/api/controllers/links/PostLinkTest.php create mode 100644 tests/api/controllers/links/PutLinkTest.php create mode 100644 tests/api/controllers/tags/DeleteTagTest.php create mode 100644 tests/api/controllers/tags/GetTagNameTest.php create mode 100644 tests/api/controllers/tags/GetTagsTest.php create mode 100644 tests/api/controllers/tags/PutTagTest.php (limited to 'tests/api') diff --git a/tests/api/controllers/DeleteLinkTest.php b/tests/api/controllers/DeleteLinkTest.php deleted file mode 100644 index 7d797137..00000000 --- a/tests/api/controllers/DeleteLinkTest.php +++ /dev/null @@ -1,126 +0,0 @@ -conf = new ConfigManager('tests/utils/config/configJson'); - $this->refDB = new \ReferenceLinkDB(); - $this->refDB->write(self::$testDatastore); - $this->linkDB = new \LinkDB(self::$testDatastore, true, false); - $refHistory = new \ReferenceHistory(); - $refHistory->write(self::$testHistory); - $this->history = new \History(self::$testHistory); - $this->container = new Container(); - $this->container['conf'] = $this->conf; - $this->container['db'] = $this->linkDB; - $this->container['history'] = $this->history; - - $this->controller = new Links($this->container); - } - - /** - * After each test, remove the test datastore. - */ - public function tearDown() - { - @unlink(self::$testDatastore); - @unlink(self::$testHistory); - } - - /** - * Test DELETE link endpoint: the link should be removed. - */ - public function testDeleteLinkValid() - { - $id = '41'; - $this->assertTrue(isset($this->linkDB[$id])); - $env = Environment::mock([ - 'REQUEST_METHOD' => 'DELETE', - ]); - $request = Request::createFromEnvironment($env); - - $response = $this->controller->deleteLink($request, new Response(), ['id' => $id]); - $this->assertEquals(204, $response->getStatusCode()); - $this->assertEmpty((string) $response->getBody()); - - $this->linkDB = new \LinkDB(self::$testDatastore, true, false); - $this->assertFalse(isset($this->linkDB[$id])); - - $historyEntry = $this->history->getHistory()[0]; - $this->assertEquals(\History::DELETED, $historyEntry['event']); - $this->assertTrue( - (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime'] - ); - $this->assertEquals($id, $historyEntry['id']); - } - - /** - * Test DELETE link endpoint: reach not existing ID. - * - * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException - */ - public function testDeleteLink404() - { - $id = -1; - $this->assertFalse(isset($this->linkDB[$id])); - $env = Environment::mock([ - 'REQUEST_METHOD' => 'DELETE', - ]); - $request = Request::createFromEnvironment($env); - - $this->controller->deleteLink($request, new Response(), ['id' => $id]); - } -} diff --git a/tests/api/controllers/GetLinkIdTest.php b/tests/api/controllers/GetLinkIdTest.php deleted file mode 100644 index 57528d5a..00000000 --- a/tests/api/controllers/GetLinkIdTest.php +++ /dev/null @@ -1,132 +0,0 @@ -conf = new ConfigManager('tests/utils/config/configJson'); - $this->refDB = new \ReferenceLinkDB(); - $this->refDB->write(self::$testDatastore); - - $this->container = new Container(); - $this->container['conf'] = $this->conf; - $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); - $this->container['history'] = null; - - $this->controller = new Links($this->container); - } - - /** - * After each test, remove the test datastore. - */ - public function tearDown() - { - @unlink(self::$testDatastore); - } - - /** - * Test basic getLink service: return link ID=41. - */ - public function testGetLinkId() - { - // Used by index_url(). - $_SERVER['SERVER_NAME'] = 'domain.tld'; - $_SERVER['SERVER_PORT'] = 80; - $_SERVER['SCRIPT_NAME'] = '/'; - - $id = 41; - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - ]); - $request = Request::createFromEnvironment($env); - - $response = $this->controller->getLink($request, new Response(), ['id' => $id]); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(self::NB_FIELDS_LINK, count($data)); - $this->assertEquals($id, $data['id']); - - // Check link elements - $this->assertEquals('http://domain.tld/?WDWyig', $data['url']); - $this->assertEquals('WDWyig', $data['shorturl']); - $this->assertEquals('Link title: @website', $data['title']); - $this->assertEquals( - 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag', - $data['description'] - ); - $this->assertEquals('sTuff', $data['tags'][0]); - $this->assertEquals(false, $data['private']); - $this->assertEquals( - \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM), - $data['created'] - ); - $this->assertEmpty($data['updated']); - } - - /** - * Test basic getLink service: get non existent link => ApiLinkNotFoundException. - * - * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException - * @expectedExceptionMessage Link not found - */ - public function testGetLink404() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - ]); - $request = Request::createFromEnvironment($env); - - $this->controller->getLink($request, new Response(), ['id' => -1]); - } -} diff --git a/tests/api/controllers/GetLinksTest.php b/tests/api/controllers/GetLinksTest.php deleted file mode 100644 index d22ed3bf..00000000 --- a/tests/api/controllers/GetLinksTest.php +++ /dev/null @@ -1,472 +0,0 @@ -conf = new ConfigManager('tests/utils/config/configJson'); - $this->refDB = new \ReferenceLinkDB(); - $this->refDB->write(self::$testDatastore); - - $this->container = new Container(); - $this->container['conf'] = $this->conf; - $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); - $this->container['history'] = null; - - $this->controller = new Links($this->container); - } - - /** - * After every test, remove the test datastore. - */ - public function tearDown() - { - @unlink(self::$testDatastore); - } - - /** - * Test basic getLinks service: returns all links. - */ - public function testGetLinks() - { - // Used by index_url(). - $_SERVER['SERVER_NAME'] = 'domain.tld'; - $_SERVER['SERVER_PORT'] = 80; - $_SERVER['SCRIPT_NAME'] = '/'; - - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - ]); - $request = Request::createFromEnvironment($env); - - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals($this->refDB->countLinks(), count($data)); - - // Check order - $order = [41, 8, 6, 7, 0, 1, 9, 4, 42]; - $cpt = 0; - foreach ($data as $link) { - $this->assertEquals(self::NB_FIELDS_LINK, count($link)); - $this->assertEquals($order[$cpt++], $link['id']); - } - - // Check first element fields - $first = $data[0]; - $this->assertEquals('http://domain.tld/?WDWyig', $first['url']); - $this->assertEquals('WDWyig', $first['shorturl']); - $this->assertEquals('Link title: @website', $first['title']); - $this->assertEquals( - 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag', - $first['description'] - ); - $this->assertEquals('sTuff', $first['tags'][0]); - $this->assertEquals(false, $first['private']); - $this->assertEquals( - \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM), - $first['created'] - ); - $this->assertEmpty($first['updated']); - - // Multi tags - $link = $data[1]; - $this->assertEquals(7, count($link['tags'])); - - // Update date - $this->assertEquals( - \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20160803_093033')->format(\DateTime::ATOM), - $link['updated'] - ); - } - - /** - * Test getLinks service with offset and limit parameter: - * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC). - */ - public function testGetLinksOffsetLimit() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'offset=1&limit=1' - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(1, count($data)); - $this->assertEquals(8, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - } - - /** - * Test getLinks with limit=all (return all link). - */ - public function testGetLinksLimitAll() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'limit=all' - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals($this->refDB->countLinks(), count($data)); - // Check order - $order = [41, 8, 6, 7, 0, 1, 9, 4, 42]; - $cpt = 0; - foreach ($data as $link) { - $this->assertEquals(self::NB_FIELDS_LINK, count($link)); - $this->assertEquals($order[$cpt++], $link['id']); - } - } - - /** - * Test getLinks service with offset and limit parameter: - * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC). - */ - public function testGetLinksOffsetTooHigh() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'offset=100' - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEmpty(count($data)); - } - - /** - * Test getLinks with visibility parameter set to all - */ - public function testGetLinksVisibilityAll() - { - $env = Environment::mock( - [ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'visibility=all' - ] - ); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string)$response->getBody(), true); - $this->assertEquals($this->refDB->countLinks(), count($data)); - $this->assertEquals(41, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - } - - /** - * Test getLinks with visibility parameter set to private - */ - public function testGetLinksVisibilityPrivate() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'visibility=private' - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals($this->refDB->countPrivateLinks(), count($data)); - $this->assertEquals(6, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - } - - /** - * Test getLinks with visibility parameter set to public - */ - public function testGetLinksVisibilityPublic() - { - $env = Environment::mock( - [ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'visibility=public' - ] - ); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string)$response->getBody(), true); - $this->assertEquals($this->refDB->countPublicLinks(), count($data)); - $this->assertEquals(41, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - } - - /** - * Test getLinks service with offset and limit parameter: - * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC). - */ - public function testGetLinksSearchTerm() - { - // Only in description - 1 result - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchterm=Tropical' - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(1, count($data)); - $this->assertEquals(1, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - - // Only in tags - 1 result - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchterm=tag3' - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(1, count($data)); - $this->assertEquals(0, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - - // Multiple results (2) - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchterm=stallman' - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(2, count($data)); - $this->assertEquals(41, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - $this->assertEquals(8, $data[1]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); - - // Multiword - 2 results - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchterm=stallman+software' - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(2, count($data)); - $this->assertEquals(41, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - $this->assertEquals(8, $data[1]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); - - // URL encoding - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchterm='. urlencode('@web') - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(2, count($data)); - $this->assertEquals(41, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - $this->assertEquals(8, $data[1]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); - } - - public function testGetLinksSearchTermNoResult() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchterm=nope' - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(0, count($data)); - } - - public function testGetLinksSearchTags() - { - // Single tag - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchtags=dev', - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(2, count($data)); - $this->assertEquals(0, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - $this->assertEquals(4, $data[1]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); - - // Multitag + exclude - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchtags=stuff+-gnu', - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(1, count($data)); - $this->assertEquals(41, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - - // wildcard: placeholder at the start - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchtags=*Tuff', - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(2, count($data)); - $this->assertEquals(41, $data[0]['id']); - - // wildcard: placeholder at the end - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchtags=c*', - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(4, count($data)); - $this->assertEquals(6, $data[0]['id']); - - // wildcard: placeholder at the middle - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchtags=w*b', - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(4, count($data)); - $this->assertEquals(6, $data[0]['id']); - - // wildcard: match all - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchtags=*', - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(9, count($data)); - $this->assertEquals(41, $data[0]['id']); - - // wildcard: optional ('*' does not need to expand) - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchtags=*stuff*', - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(2, count($data)); - $this->assertEquals(41, $data[0]['id']); - - // wildcard: exclusions - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchtags=*a*+-*e*', - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(1, count($data)); - $this->assertEquals(41, $data[0]['id']); // finds '#hashtag' in descr. - - // wildcard: exclude all - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchtags=-*', - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(0, count($data)); - } - - /** - * Test getLinks service with search tags+terms. - */ - public function testGetLinksSearchTermsAndTags() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'searchterm=poke&searchtags=dev', - ]); - $request = Request::createFromEnvironment($env); - $response = $this->controller->getLinks($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(1, count($data)); - $this->assertEquals(0, $data[0]['id']); - $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); - } -} diff --git a/tests/api/controllers/HistoryTest.php b/tests/api/controllers/HistoryTest.php deleted file mode 100644 index 61046d97..00000000 --- a/tests/api/controllers/HistoryTest.php +++ /dev/null @@ -1,216 +0,0 @@ -conf = new ConfigManager('tests/utils/config/configJson.json.php'); - $this->refHistory = new \ReferenceHistory(); - $this->refHistory->write(self::$testHistory); - $this->container = new Container(); - $this->container['conf'] = $this->conf; - $this->container['db'] = true; - $this->container['history'] = new \History(self::$testHistory); - - $this->controller = new History($this->container); - } - - /** - * After every test, remove the test datastore. - */ - public function tearDown() - { - @unlink(self::$testHistory); - } - - /** - * Test /history service without parameter. - */ - public function testGetHistory() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - ]); - $request = Request::createFromEnvironment($env); - - $response = $this->controller->getHistory($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - - $this->assertEquals($this->refHistory->count(), count($data)); - - $this->assertEquals(\History::DELETED, $data[0]['event']); - $this->assertEquals( - \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM), - $data[0]['datetime'] - ); - $this->assertEquals(124, $data[0]['id']); - - $this->assertEquals(\History::SETTINGS, $data[1]['event']); - $this->assertEquals( - \DateTime::createFromFormat('Ymd_His', '20170302_121215')->format(\DateTime::ATOM), - $data[1]['datetime'] - ); - $this->assertNull($data[1]['id']); - - $this->assertEquals(\History::UPDATED, $data[2]['event']); - $this->assertEquals( - \DateTime::createFromFormat('Ymd_His', '20170301_121214')->format(\DateTime::ATOM), - $data[2]['datetime'] - ); - $this->assertEquals(123, $data[2]['id']); - - $this->assertEquals(\History::CREATED, $data[3]['event']); - $this->assertEquals( - \DateTime::createFromFormat('Ymd_His', '20170201_121214')->format(\DateTime::ATOM), - $data[3]['datetime'] - ); - $this->assertEquals(124, $data[3]['id']); - - $this->assertEquals(\History::CREATED, $data[4]['event']); - $this->assertEquals( - \DateTime::createFromFormat('Ymd_His', '20170101_121212')->format(\DateTime::ATOM), - $data[4]['datetime'] - ); - $this->assertEquals(123, $data[4]['id']); - } - - /** - * Test /history service with limit parameter. - */ - public function testGetHistoryLimit() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'limit=1' - ]); - $request = Request::createFromEnvironment($env); - - $response = $this->controller->getHistory($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - - $this->assertEquals(1, count($data)); - - $this->assertEquals(\History::DELETED, $data[0]['event']); - $this->assertEquals( - \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM), - $data[0]['datetime'] - ); - $this->assertEquals(124, $data[0]['id']); - } - - /** - * Test /history service with offset parameter. - */ - public function testGetHistoryOffset() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'offset=4' - ]); - $request = Request::createFromEnvironment($env); - - $response = $this->controller->getHistory($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - - $this->assertEquals(1, count($data)); - - $this->assertEquals(\History::CREATED, $data[0]['event']); - $this->assertEquals( - \DateTime::createFromFormat('Ymd_His', '20170101_121212')->format(\DateTime::ATOM), - $data[0]['datetime'] - ); - $this->assertEquals(123, $data[0]['id']); - } - - /** - * Test /history service with since parameter. - */ - public function testGetHistorySince() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'since=2017-03-03T00:00:00%2B00:00' - ]); - $request = Request::createFromEnvironment($env); - - $response = $this->controller->getHistory($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - - $this->assertEquals(1, count($data)); - - $this->assertEquals(\History::DELETED, $data[0]['event']); - $this->assertEquals( - \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM), - $data[0]['datetime'] - ); - $this->assertEquals(124, $data[0]['id']); - } - - /** - * Test /history service with since parameter. - */ - public function testGetHistorySinceOffsetLimit() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => 'since=2017-02-01T00:00:00%2B00:00&offset=1&limit=1' - ]); - $request = Request::createFromEnvironment($env); - - $response = $this->controller->getHistory($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - - $this->assertEquals(1, count($data)); - - $this->assertEquals(\History::SETTINGS, $data[0]['event']); - $this->assertEquals( - \DateTime::createFromFormat('Ymd_His', '20170302_121215')->format(\DateTime::ATOM), - $data[0]['datetime'] - ); - } -} diff --git a/tests/api/controllers/InfoTest.php b/tests/api/controllers/InfoTest.php deleted file mode 100644 index f7e63bfa..00000000 --- a/tests/api/controllers/InfoTest.php +++ /dev/null @@ -1,115 +0,0 @@ -conf = new ConfigManager('tests/utils/config/configJson.json.php'); - $this->refDB = new \ReferenceLinkDB(); - $this->refDB->write(self::$testDatastore); - - $this->container = new Container(); - $this->container['conf'] = $this->conf; - $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); - $this->container['history'] = null; - - $this->controller = new Info($this->container); - } - - /** - * After every test, remove the test datastore. - */ - public function tearDown() - { - @unlink(self::$testDatastore); - } - - /** - * Test /info service. - */ - public function testGetInfo() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'GET', - ]); - $request = Request::createFromEnvironment($env); - - $response = $this->controller->getInfo($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - - $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']); - $this->assertEquals(2, $data['private_counter']); - $this->assertEquals('Shaarli', $data['settings']['title']); - $this->assertEquals('?', $data['settings']['header_link']); - $this->assertEquals('UTC', $data['settings']['timezone']); - $this->assertEquals(ConfigManager::$DEFAULT_PLUGINS, $data['settings']['enabled_plugins']); - $this->assertEquals(false, $data['settings']['default_private_links']); - - $title = 'My links'; - $headerLink = 'http://shaarli.tld'; - $timezone = 'Europe/Paris'; - $enabledPlugins = array('foo', 'bar'); - $defaultPrivateLinks = true; - $this->conf->set('general.title', $title); - $this->conf->set('general.header_link', $headerLink); - $this->conf->set('general.timezone', $timezone); - $this->conf->set('general.enabled_plugins', $enabledPlugins); - $this->conf->set('privacy.default_private_links', $defaultPrivateLinks); - - $response = $this->controller->getInfo($request, new Response()); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - - $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']); - $this->assertEquals(2, $data['private_counter']); - $this->assertEquals($title, $data['settings']['title']); - $this->assertEquals($headerLink, $data['settings']['header_link']); - $this->assertEquals($timezone, $data['settings']['timezone']); - $this->assertEquals($enabledPlugins, $data['settings']['enabled_plugins']); - $this->assertEquals($defaultPrivateLinks, $data['settings']['default_private_links']); - } -} diff --git a/tests/api/controllers/PostLinkTest.php b/tests/api/controllers/PostLinkTest.php deleted file mode 100644 index 100a9170..00000000 --- a/tests/api/controllers/PostLinkTest.php +++ /dev/null @@ -1,218 +0,0 @@ -conf = new ConfigManager('tests/utils/config/configJson.json.php'); - $this->refDB = new \ReferenceLinkDB(); - $this->refDB->write(self::$testDatastore); - - $refHistory = new \ReferenceHistory(); - $refHistory->write(self::$testHistory); - $this->history = new \History(self::$testHistory); - - $this->container = new Container(); - $this->container['conf'] = $this->conf; - $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); - $this->container['history'] = new \History(self::$testHistory); - - $this->controller = new Links($this->container); - - $mock = $this->createMock(Router::class); - $mock->expects($this->any()) - ->method('relativePathFor') - ->willReturn('api/v1/links/1'); - - // affect @property-read... seems to work - $this->controller->getCi()->router = $mock; - - // Used by index_url(). - $this->controller->getCi()['environment'] = [ - 'SERVER_NAME' => 'domain.tld', - 'SERVER_PORT' => 80, - 'SCRIPT_NAME' => '/', - ]; - } - - /** - * After every test, remove the test datastore. - */ - public function tearDown() - { - @unlink(self::$testDatastore); - @unlink(self::$testHistory); - } - - /** - * Test link creation without any field: creates a blank note. - */ - public function testPostLinkMinimal() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'POST', - ]); - - $request = Request::createFromEnvironment($env); - - $response = $this->controller->postLink($request, new Response()); - $this->assertEquals(201, $response->getStatusCode()); - $this->assertEquals('api/v1/links/1', $response->getHeader('Location')[0]); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(self::NB_FIELDS_LINK, count($data)); - $this->assertEquals(43, $data['id']); - $this->assertRegExp('/[\w-_]{6}/', $data['shorturl']); - $this->assertEquals('http://domain.tld/?' . $data['shorturl'], $data['url']); - $this->assertEquals('?' . $data['shorturl'], $data['title']); - $this->assertEquals('', $data['description']); - $this->assertEquals([], $data['tags']); - $this->assertEquals(false, $data['private']); - $this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])); - $this->assertEquals('', $data['updated']); - - $historyEntry = $this->history->getHistory()[0]; - $this->assertEquals(\History::CREATED, $historyEntry['event']); - $this->assertTrue( - (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime'] - ); - $this->assertEquals(43, $historyEntry['id']); - } - - /** - * Test link creation with all available fields. - */ - public function testPostLinkFull() - { - $link = [ - 'url' => 'website.tld/test?foo=bar', - 'title' => 'new entry', - 'description' => 'shaare description', - 'tags' => ['one', 'two'], - 'private' => true, - ]; - $env = Environment::mock([ - 'REQUEST_METHOD' => 'POST', - 'CONTENT_TYPE' => 'application/json' - ]); - - $request = Request::createFromEnvironment($env); - $request = $request->withParsedBody($link); - $response = $this->controller->postLink($request, new Response()); - - $this->assertEquals(201, $response->getStatusCode()); - $this->assertEquals('api/v1/links/1', $response->getHeader('Location')[0]); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(self::NB_FIELDS_LINK, count($data)); - $this->assertEquals(43, $data['id']); - $this->assertRegExp('/[\w-_]{6}/', $data['shorturl']); - $this->assertEquals('http://' . $link['url'], $data['url']); - $this->assertEquals($link['title'], $data['title']); - $this->assertEquals($link['description'], $data['description']); - $this->assertEquals($link['tags'], $data['tags']); - $this->assertEquals(true, $data['private']); - $this->assertTrue(new \DateTime('2 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])); - $this->assertEquals('', $data['updated']); - } - - /** - * Test link creation with an existing link (duplicate URL). Should return a 409 HTTP error and the existing link. - */ - public function testPostLinkDuplicate() - { - $link = [ - 'url' => 'mediagoblin.org/', - 'title' => 'new entry', - 'description' => 'shaare description', - 'tags' => ['one', 'two'], - 'private' => true, - ]; - $env = Environment::mock([ - 'REQUEST_METHOD' => 'POST', - 'CONTENT_TYPE' => 'application/json' - ]); - - $request = Request::createFromEnvironment($env); - $request = $request->withParsedBody($link); - $response = $this->controller->postLink($request, new Response()); - - $this->assertEquals(409, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(self::NB_FIELDS_LINK, count($data)); - $this->assertEquals(7, $data['id']); - $this->assertEquals('IuWvgA', $data['shorturl']); - $this->assertEquals('http://mediagoblin.org/', $data['url']); - $this->assertEquals('MediaGoblin', $data['title']); - $this->assertEquals('A free software media publishing platform #hashtagOther', $data['description']); - $this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']); - $this->assertEquals(false, $data['private']); - $this->assertEquals( - \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130614_184135'), - \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) - ); - $this->assertEquals( - \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130615_184230'), - \DateTime::createFromFormat(\DateTime::ATOM, $data['updated']) - ); - } -} diff --git a/tests/api/controllers/PutLinkTest.php b/tests/api/controllers/PutLinkTest.php deleted file mode 100644 index 8a562571..00000000 --- a/tests/api/controllers/PutLinkTest.php +++ /dev/null @@ -1,222 +0,0 @@ -conf = new ConfigManager('tests/utils/config/configJson.json.php'); - $this->refDB = new \ReferenceLinkDB(); - $this->refDB->write(self::$testDatastore); - - $refHistory = new \ReferenceHistory(); - $refHistory->write(self::$testHistory); - $this->history = new \History(self::$testHistory); - - $this->container = new Container(); - $this->container['conf'] = $this->conf; - $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); - $this->container['history'] = new \History(self::$testHistory); - - $this->controller = new Links($this->container); - - // Used by index_url(). - $this->controller->getCi()['environment'] = [ - 'SERVER_NAME' => 'domain.tld', - 'SERVER_PORT' => 80, - 'SCRIPT_NAME' => '/', - ]; - } - - /** - * After every test, remove the test datastore. - */ - public function tearDown() - { - @unlink(self::$testDatastore); - @unlink(self::$testHistory); - } - - /** - * Test link update without value: reset the link to default values - */ - public function testPutLinkMinimal() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'PUT', - ]); - $id = '41'; - $request = Request::createFromEnvironment($env); - - $response = $this->controller->putLink($request, new Response(), ['id' => $id]); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(self::NB_FIELDS_LINK, count($data)); - $this->assertEquals($id, $data['id']); - $this->assertEquals('WDWyig', $data['shorturl']); - $this->assertEquals('http://domain.tld/?WDWyig', $data['url']); - $this->assertEquals('?WDWyig', $data['title']); - $this->assertEquals('', $data['description']); - $this->assertEquals([], $data['tags']); - $this->assertEquals(false, $data['private']); - $this->assertEquals( - \DateTime::createFromFormat('Ymd_His', '20150310_114651'), - \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) - ); - $this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])); - - $historyEntry = $this->history->getHistory()[0]; - $this->assertEquals(\History::UPDATED, $historyEntry['event']); - $this->assertTrue( - (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime'] - ); - $this->assertEquals($id, $historyEntry['id']); - } - - /** - * Test link update with new values - */ - public function testPutLinkWithValues() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'PUT', - 'CONTENT_TYPE' => 'application/json' - ]); - $id = 41; - $update = [ - 'url' => 'http://somewhere.else', - 'title' => 'Le Cid', - 'description' => 'Percé jusques au fond du cœur [...]', - 'tags' => ['corneille', 'rodrigue'], - 'private' => true, - ]; - $request = Request::createFromEnvironment($env); - $request = $request->withParsedBody($update); - - $response = $this->controller->putLink($request, new Response(), ['id' => $id]); - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(self::NB_FIELDS_LINK, count($data)); - $this->assertEquals($id, $data['id']); - $this->assertEquals('WDWyig', $data['shorturl']); - $this->assertEquals('http://somewhere.else', $data['url']); - $this->assertEquals('Le Cid', $data['title']); - $this->assertEquals('Percé jusques au fond du cœur [...]', $data['description']); - $this->assertEquals(['corneille', 'rodrigue'], $data['tags']); - $this->assertEquals(true, $data['private']); - $this->assertEquals( - \DateTime::createFromFormat('Ymd_His', '20150310_114651'), - \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) - ); - $this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])); - } - - /** - * Test link update with an existing URL: 409 Conflict with the existing link as body - */ - public function testPutLinkDuplicate() - { - $link = [ - 'url' => 'mediagoblin.org/', - 'title' => 'new entry', - 'description' => 'shaare description', - 'tags' => ['one', 'two'], - 'private' => true, - ]; - $env = Environment::mock([ - 'REQUEST_METHOD' => 'PUT', - 'CONTENT_TYPE' => 'application/json' - ]); - - $request = Request::createFromEnvironment($env); - $request = $request->withParsedBody($link); - $response = $this->controller->putLink($request, new Response(), ['id' => 41]); - - $this->assertEquals(409, $response->getStatusCode()); - $data = json_decode((string) $response->getBody(), true); - $this->assertEquals(self::NB_FIELDS_LINK, count($data)); - $this->assertEquals(7, $data['id']); - $this->assertEquals('IuWvgA', $data['shorturl']); - $this->assertEquals('http://mediagoblin.org/', $data['url']); - $this->assertEquals('MediaGoblin', $data['title']); - $this->assertEquals('A free software media publishing platform #hashtagOther', $data['description']); - $this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']); - $this->assertEquals(false, $data['private']); - $this->assertEquals( - \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130614_184135'), - \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) - ); - $this->assertEquals( - \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130615_184230'), - \DateTime::createFromFormat(\DateTime::ATOM, $data['updated']) - ); - } - - /** - * Test link update on non existent link => ApiLinkNotFoundException. - * - * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException - * @expectedExceptionMessage Link not found - */ - public function testGetLink404() - { - $env = Environment::mock([ - 'REQUEST_METHOD' => 'PUT', - ]); - $request = Request::createFromEnvironment($env); - - $this->controller->putLink($request, new Response(), ['id' => -1]); - } -} diff --git a/tests/api/controllers/history/HistoryTest.php b/tests/api/controllers/history/HistoryTest.php new file mode 100644 index 00000000..61046d97 --- /dev/null +++ b/tests/api/controllers/history/HistoryTest.php @@ -0,0 +1,216 @@ +conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->refHistory = new \ReferenceHistory(); + $this->refHistory->write(self::$testHistory); + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->container['db'] = true; + $this->container['history'] = new \History(self::$testHistory); + + $this->controller = new History($this->container); + } + + /** + * After every test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testHistory); + } + + /** + * Test /history service without parameter. + */ + public function testGetHistory() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getHistory($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals($this->refHistory->count(), count($data)); + + $this->assertEquals(\History::DELETED, $data[0]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM), + $data[0]['datetime'] + ); + $this->assertEquals(124, $data[0]['id']); + + $this->assertEquals(\History::SETTINGS, $data[1]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170302_121215')->format(\DateTime::ATOM), + $data[1]['datetime'] + ); + $this->assertNull($data[1]['id']); + + $this->assertEquals(\History::UPDATED, $data[2]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170301_121214')->format(\DateTime::ATOM), + $data[2]['datetime'] + ); + $this->assertEquals(123, $data[2]['id']); + + $this->assertEquals(\History::CREATED, $data[3]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170201_121214')->format(\DateTime::ATOM), + $data[3]['datetime'] + ); + $this->assertEquals(124, $data[3]['id']); + + $this->assertEquals(\History::CREATED, $data[4]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170101_121212')->format(\DateTime::ATOM), + $data[4]['datetime'] + ); + $this->assertEquals(123, $data[4]['id']); + } + + /** + * Test /history service with limit parameter. + */ + public function testGetHistoryLimit() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'limit=1' + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getHistory($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals(1, count($data)); + + $this->assertEquals(\History::DELETED, $data[0]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM), + $data[0]['datetime'] + ); + $this->assertEquals(124, $data[0]['id']); + } + + /** + * Test /history service with offset parameter. + */ + public function testGetHistoryOffset() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'offset=4' + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getHistory($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals(1, count($data)); + + $this->assertEquals(\History::CREATED, $data[0]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170101_121212')->format(\DateTime::ATOM), + $data[0]['datetime'] + ); + $this->assertEquals(123, $data[0]['id']); + } + + /** + * Test /history service with since parameter. + */ + public function testGetHistorySince() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'since=2017-03-03T00:00:00%2B00:00' + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getHistory($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals(1, count($data)); + + $this->assertEquals(\History::DELETED, $data[0]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM), + $data[0]['datetime'] + ); + $this->assertEquals(124, $data[0]['id']); + } + + /** + * Test /history service with since parameter. + */ + public function testGetHistorySinceOffsetLimit() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'since=2017-02-01T00:00:00%2B00:00&offset=1&limit=1' + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getHistory($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals(1, count($data)); + + $this->assertEquals(\History::SETTINGS, $data[0]['event']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20170302_121215')->format(\DateTime::ATOM), + $data[0]['datetime'] + ); + } +} diff --git a/tests/api/controllers/info/InfoTest.php b/tests/api/controllers/info/InfoTest.php new file mode 100644 index 00000000..f7e63bfa --- /dev/null +++ b/tests/api/controllers/info/InfoTest.php @@ -0,0 +1,115 @@ +conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->refDB = new \ReferenceLinkDB(); + $this->refDB->write(self::$testDatastore); + + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); + $this->container['history'] = null; + + $this->controller = new Info($this->container); + } + + /** + * After every test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testDatastore); + } + + /** + * Test /info service. + */ + public function testGetInfo() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getInfo($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']); + $this->assertEquals(2, $data['private_counter']); + $this->assertEquals('Shaarli', $data['settings']['title']); + $this->assertEquals('?', $data['settings']['header_link']); + $this->assertEquals('UTC', $data['settings']['timezone']); + $this->assertEquals(ConfigManager::$DEFAULT_PLUGINS, $data['settings']['enabled_plugins']); + $this->assertEquals(false, $data['settings']['default_private_links']); + + $title = 'My links'; + $headerLink = 'http://shaarli.tld'; + $timezone = 'Europe/Paris'; + $enabledPlugins = array('foo', 'bar'); + $defaultPrivateLinks = true; + $this->conf->set('general.title', $title); + $this->conf->set('general.header_link', $headerLink); + $this->conf->set('general.timezone', $timezone); + $this->conf->set('general.enabled_plugins', $enabledPlugins); + $this->conf->set('privacy.default_private_links', $defaultPrivateLinks); + + $response = $this->controller->getInfo($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + + $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']); + $this->assertEquals(2, $data['private_counter']); + $this->assertEquals($title, $data['settings']['title']); + $this->assertEquals($headerLink, $data['settings']['header_link']); + $this->assertEquals($timezone, $data['settings']['timezone']); + $this->assertEquals($enabledPlugins, $data['settings']['enabled_plugins']); + $this->assertEquals($defaultPrivateLinks, $data['settings']['default_private_links']); + } +} diff --git a/tests/api/controllers/links/DeleteLinkTest.php b/tests/api/controllers/links/DeleteLinkTest.php new file mode 100644 index 00000000..7d797137 --- /dev/null +++ b/tests/api/controllers/links/DeleteLinkTest.php @@ -0,0 +1,126 @@ +conf = new ConfigManager('tests/utils/config/configJson'); + $this->refDB = new \ReferenceLinkDB(); + $this->refDB->write(self::$testDatastore); + $this->linkDB = new \LinkDB(self::$testDatastore, true, false); + $refHistory = new \ReferenceHistory(); + $refHistory->write(self::$testHistory); + $this->history = new \History(self::$testHistory); + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->container['db'] = $this->linkDB; + $this->container['history'] = $this->history; + + $this->controller = new Links($this->container); + } + + /** + * After each test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testDatastore); + @unlink(self::$testHistory); + } + + /** + * Test DELETE link endpoint: the link should be removed. + */ + public function testDeleteLinkValid() + { + $id = '41'; + $this->assertTrue(isset($this->linkDB[$id])); + $env = Environment::mock([ + 'REQUEST_METHOD' => 'DELETE', + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->deleteLink($request, new Response(), ['id' => $id]); + $this->assertEquals(204, $response->getStatusCode()); + $this->assertEmpty((string) $response->getBody()); + + $this->linkDB = new \LinkDB(self::$testDatastore, true, false); + $this->assertFalse(isset($this->linkDB[$id])); + + $historyEntry = $this->history->getHistory()[0]; + $this->assertEquals(\History::DELETED, $historyEntry['event']); + $this->assertTrue( + (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime'] + ); + $this->assertEquals($id, $historyEntry['id']); + } + + /** + * Test DELETE link endpoint: reach not existing ID. + * + * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException + */ + public function testDeleteLink404() + { + $id = -1; + $this->assertFalse(isset($this->linkDB[$id])); + $env = Environment::mock([ + 'REQUEST_METHOD' => 'DELETE', + ]); + $request = Request::createFromEnvironment($env); + + $this->controller->deleteLink($request, new Response(), ['id' => $id]); + } +} diff --git a/tests/api/controllers/links/GetLinkIdTest.php b/tests/api/controllers/links/GetLinkIdTest.php new file mode 100644 index 00000000..57528d5a --- /dev/null +++ b/tests/api/controllers/links/GetLinkIdTest.php @@ -0,0 +1,132 @@ +conf = new ConfigManager('tests/utils/config/configJson'); + $this->refDB = new \ReferenceLinkDB(); + $this->refDB->write(self::$testDatastore); + + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); + $this->container['history'] = null; + + $this->controller = new Links($this->container); + } + + /** + * After each test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testDatastore); + } + + /** + * Test basic getLink service: return link ID=41. + */ + public function testGetLinkId() + { + // Used by index_url(). + $_SERVER['SERVER_NAME'] = 'domain.tld'; + $_SERVER['SERVER_PORT'] = 80; + $_SERVER['SCRIPT_NAME'] = '/'; + + $id = 41; + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getLink($request, new Response(), ['id' => $id]); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(self::NB_FIELDS_LINK, count($data)); + $this->assertEquals($id, $data['id']); + + // Check link elements + $this->assertEquals('http://domain.tld/?WDWyig', $data['url']); + $this->assertEquals('WDWyig', $data['shorturl']); + $this->assertEquals('Link title: @website', $data['title']); + $this->assertEquals( + 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag', + $data['description'] + ); + $this->assertEquals('sTuff', $data['tags'][0]); + $this->assertEquals(false, $data['private']); + $this->assertEquals( + \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM), + $data['created'] + ); + $this->assertEmpty($data['updated']); + } + + /** + * Test basic getLink service: get non existent link => ApiLinkNotFoundException. + * + * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException + * @expectedExceptionMessage Link not found + */ + public function testGetLink404() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + ]); + $request = Request::createFromEnvironment($env); + + $this->controller->getLink($request, new Response(), ['id' => -1]); + } +} diff --git a/tests/api/controllers/links/GetLinksTest.php b/tests/api/controllers/links/GetLinksTest.php new file mode 100644 index 00000000..d22ed3bf --- /dev/null +++ b/tests/api/controllers/links/GetLinksTest.php @@ -0,0 +1,472 @@ +conf = new ConfigManager('tests/utils/config/configJson'); + $this->refDB = new \ReferenceLinkDB(); + $this->refDB->write(self::$testDatastore); + + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); + $this->container['history'] = null; + + $this->controller = new Links($this->container); + } + + /** + * After every test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testDatastore); + } + + /** + * Test basic getLinks service: returns all links. + */ + public function testGetLinks() + { + // Used by index_url(). + $_SERVER['SERVER_NAME'] = 'domain.tld'; + $_SERVER['SERVER_PORT'] = 80; + $_SERVER['SCRIPT_NAME'] = '/'; + + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals($this->refDB->countLinks(), count($data)); + + // Check order + $order = [41, 8, 6, 7, 0, 1, 9, 4, 42]; + $cpt = 0; + foreach ($data as $link) { + $this->assertEquals(self::NB_FIELDS_LINK, count($link)); + $this->assertEquals($order[$cpt++], $link['id']); + } + + // Check first element fields + $first = $data[0]; + $this->assertEquals('http://domain.tld/?WDWyig', $first['url']); + $this->assertEquals('WDWyig', $first['shorturl']); + $this->assertEquals('Link title: @website', $first['title']); + $this->assertEquals( + 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag', + $first['description'] + ); + $this->assertEquals('sTuff', $first['tags'][0]); + $this->assertEquals(false, $first['private']); + $this->assertEquals( + \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM), + $first['created'] + ); + $this->assertEmpty($first['updated']); + + // Multi tags + $link = $data[1]; + $this->assertEquals(7, count($link['tags'])); + + // Update date + $this->assertEquals( + \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20160803_093033')->format(\DateTime::ATOM), + $link['updated'] + ); + } + + /** + * Test getLinks service with offset and limit parameter: + * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC). + */ + public function testGetLinksOffsetLimit() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'offset=1&limit=1' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(1, count($data)); + $this->assertEquals(8, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + } + + /** + * Test getLinks with limit=all (return all link). + */ + public function testGetLinksLimitAll() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'limit=all' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals($this->refDB->countLinks(), count($data)); + // Check order + $order = [41, 8, 6, 7, 0, 1, 9, 4, 42]; + $cpt = 0; + foreach ($data as $link) { + $this->assertEquals(self::NB_FIELDS_LINK, count($link)); + $this->assertEquals($order[$cpt++], $link['id']); + } + } + + /** + * Test getLinks service with offset and limit parameter: + * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC). + */ + public function testGetLinksOffsetTooHigh() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'offset=100' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEmpty(count($data)); + } + + /** + * Test getLinks with visibility parameter set to all + */ + public function testGetLinksVisibilityAll() + { + $env = Environment::mock( + [ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'visibility=all' + ] + ); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string)$response->getBody(), true); + $this->assertEquals($this->refDB->countLinks(), count($data)); + $this->assertEquals(41, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + } + + /** + * Test getLinks with visibility parameter set to private + */ + public function testGetLinksVisibilityPrivate() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'visibility=private' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals($this->refDB->countPrivateLinks(), count($data)); + $this->assertEquals(6, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + } + + /** + * Test getLinks with visibility parameter set to public + */ + public function testGetLinksVisibilityPublic() + { + $env = Environment::mock( + [ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'visibility=public' + ] + ); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string)$response->getBody(), true); + $this->assertEquals($this->refDB->countPublicLinks(), count($data)); + $this->assertEquals(41, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + } + + /** + * Test getLinks service with offset and limit parameter: + * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC). + */ + public function testGetLinksSearchTerm() + { + // Only in description - 1 result + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchterm=Tropical' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(1, count($data)); + $this->assertEquals(1, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + + // Only in tags - 1 result + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchterm=tag3' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(1, count($data)); + $this->assertEquals(0, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + + // Multiple results (2) + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchterm=stallman' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(2, count($data)); + $this->assertEquals(41, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + $this->assertEquals(8, $data[1]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); + + // Multiword - 2 results + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchterm=stallman+software' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(2, count($data)); + $this->assertEquals(41, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + $this->assertEquals(8, $data[1]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); + + // URL encoding + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchterm='. urlencode('@web') + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(2, count($data)); + $this->assertEquals(41, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + $this->assertEquals(8, $data[1]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); + } + + public function testGetLinksSearchTermNoResult() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchterm=nope' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(0, count($data)); + } + + public function testGetLinksSearchTags() + { + // Single tag + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchtags=dev', + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(2, count($data)); + $this->assertEquals(0, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + $this->assertEquals(4, $data[1]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); + + // Multitag + exclude + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchtags=stuff+-gnu', + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(1, count($data)); + $this->assertEquals(41, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + + // wildcard: placeholder at the start + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchtags=*Tuff', + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(2, count($data)); + $this->assertEquals(41, $data[0]['id']); + + // wildcard: placeholder at the end + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchtags=c*', + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(4, count($data)); + $this->assertEquals(6, $data[0]['id']); + + // wildcard: placeholder at the middle + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchtags=w*b', + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(4, count($data)); + $this->assertEquals(6, $data[0]['id']); + + // wildcard: match all + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchtags=*', + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(9, count($data)); + $this->assertEquals(41, $data[0]['id']); + + // wildcard: optional ('*' does not need to expand) + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchtags=*stuff*', + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(2, count($data)); + $this->assertEquals(41, $data[0]['id']); + + // wildcard: exclusions + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchtags=*a*+-*e*', + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(1, count($data)); + $this->assertEquals(41, $data[0]['id']); // finds '#hashtag' in descr. + + // wildcard: exclude all + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchtags=-*', + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(0, count($data)); + } + + /** + * Test getLinks service with search tags+terms. + */ + public function testGetLinksSearchTermsAndTags() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'searchterm=poke&searchtags=dev', + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getLinks($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(1, count($data)); + $this->assertEquals(0, $data[0]['id']); + $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); + } +} diff --git a/tests/api/controllers/links/PostLinkTest.php b/tests/api/controllers/links/PostLinkTest.php new file mode 100644 index 00000000..100a9170 --- /dev/null +++ b/tests/api/controllers/links/PostLinkTest.php @@ -0,0 +1,218 @@ +conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->refDB = new \ReferenceLinkDB(); + $this->refDB->write(self::$testDatastore); + + $refHistory = new \ReferenceHistory(); + $refHistory->write(self::$testHistory); + $this->history = new \History(self::$testHistory); + + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); + $this->container['history'] = new \History(self::$testHistory); + + $this->controller = new Links($this->container); + + $mock = $this->createMock(Router::class); + $mock->expects($this->any()) + ->method('relativePathFor') + ->willReturn('api/v1/links/1'); + + // affect @property-read... seems to work + $this->controller->getCi()->router = $mock; + + // Used by index_url(). + $this->controller->getCi()['environment'] = [ + 'SERVER_NAME' => 'domain.tld', + 'SERVER_PORT' => 80, + 'SCRIPT_NAME' => '/', + ]; + } + + /** + * After every test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testDatastore); + @unlink(self::$testHistory); + } + + /** + * Test link creation without any field: creates a blank note. + */ + public function testPostLinkMinimal() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'POST', + ]); + + $request = Request::createFromEnvironment($env); + + $response = $this->controller->postLink($request, new Response()); + $this->assertEquals(201, $response->getStatusCode()); + $this->assertEquals('api/v1/links/1', $response->getHeader('Location')[0]); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(self::NB_FIELDS_LINK, count($data)); + $this->assertEquals(43, $data['id']); + $this->assertRegExp('/[\w-_]{6}/', $data['shorturl']); + $this->assertEquals('http://domain.tld/?' . $data['shorturl'], $data['url']); + $this->assertEquals('?' . $data['shorturl'], $data['title']); + $this->assertEquals('', $data['description']); + $this->assertEquals([], $data['tags']); + $this->assertEquals(false, $data['private']); + $this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])); + $this->assertEquals('', $data['updated']); + + $historyEntry = $this->history->getHistory()[0]; + $this->assertEquals(\History::CREATED, $historyEntry['event']); + $this->assertTrue( + (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime'] + ); + $this->assertEquals(43, $historyEntry['id']); + } + + /** + * Test link creation with all available fields. + */ + public function testPostLinkFull() + { + $link = [ + 'url' => 'website.tld/test?foo=bar', + 'title' => 'new entry', + 'description' => 'shaare description', + 'tags' => ['one', 'two'], + 'private' => true, + ]; + $env = Environment::mock([ + 'REQUEST_METHOD' => 'POST', + 'CONTENT_TYPE' => 'application/json' + ]); + + $request = Request::createFromEnvironment($env); + $request = $request->withParsedBody($link); + $response = $this->controller->postLink($request, new Response()); + + $this->assertEquals(201, $response->getStatusCode()); + $this->assertEquals('api/v1/links/1', $response->getHeader('Location')[0]); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(self::NB_FIELDS_LINK, count($data)); + $this->assertEquals(43, $data['id']); + $this->assertRegExp('/[\w-_]{6}/', $data['shorturl']); + $this->assertEquals('http://' . $link['url'], $data['url']); + $this->assertEquals($link['title'], $data['title']); + $this->assertEquals($link['description'], $data['description']); + $this->assertEquals($link['tags'], $data['tags']); + $this->assertEquals(true, $data['private']); + $this->assertTrue(new \DateTime('2 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])); + $this->assertEquals('', $data['updated']); + } + + /** + * Test link creation with an existing link (duplicate URL). Should return a 409 HTTP error and the existing link. + */ + public function testPostLinkDuplicate() + { + $link = [ + 'url' => 'mediagoblin.org/', + 'title' => 'new entry', + 'description' => 'shaare description', + 'tags' => ['one', 'two'], + 'private' => true, + ]; + $env = Environment::mock([ + 'REQUEST_METHOD' => 'POST', + 'CONTENT_TYPE' => 'application/json' + ]); + + $request = Request::createFromEnvironment($env); + $request = $request->withParsedBody($link); + $response = $this->controller->postLink($request, new Response()); + + $this->assertEquals(409, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(self::NB_FIELDS_LINK, count($data)); + $this->assertEquals(7, $data['id']); + $this->assertEquals('IuWvgA', $data['shorturl']); + $this->assertEquals('http://mediagoblin.org/', $data['url']); + $this->assertEquals('MediaGoblin', $data['title']); + $this->assertEquals('A free software media publishing platform #hashtagOther', $data['description']); + $this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']); + $this->assertEquals(false, $data['private']); + $this->assertEquals( + \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130614_184135'), + \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) + ); + $this->assertEquals( + \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130615_184230'), + \DateTime::createFromFormat(\DateTime::ATOM, $data['updated']) + ); + } +} diff --git a/tests/api/controllers/links/PutLinkTest.php b/tests/api/controllers/links/PutLinkTest.php new file mode 100644 index 00000000..8a562571 --- /dev/null +++ b/tests/api/controllers/links/PutLinkTest.php @@ -0,0 +1,222 @@ +conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->refDB = new \ReferenceLinkDB(); + $this->refDB->write(self::$testDatastore); + + $refHistory = new \ReferenceHistory(); + $refHistory->write(self::$testHistory); + $this->history = new \History(self::$testHistory); + + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); + $this->container['history'] = new \History(self::$testHistory); + + $this->controller = new Links($this->container); + + // Used by index_url(). + $this->controller->getCi()['environment'] = [ + 'SERVER_NAME' => 'domain.tld', + 'SERVER_PORT' => 80, + 'SCRIPT_NAME' => '/', + ]; + } + + /** + * After every test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testDatastore); + @unlink(self::$testHistory); + } + + /** + * Test link update without value: reset the link to default values + */ + public function testPutLinkMinimal() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'PUT', + ]); + $id = '41'; + $request = Request::createFromEnvironment($env); + + $response = $this->controller->putLink($request, new Response(), ['id' => $id]); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(self::NB_FIELDS_LINK, count($data)); + $this->assertEquals($id, $data['id']); + $this->assertEquals('WDWyig', $data['shorturl']); + $this->assertEquals('http://domain.tld/?WDWyig', $data['url']); + $this->assertEquals('?WDWyig', $data['title']); + $this->assertEquals('', $data['description']); + $this->assertEquals([], $data['tags']); + $this->assertEquals(false, $data['private']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20150310_114651'), + \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) + ); + $this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])); + + $historyEntry = $this->history->getHistory()[0]; + $this->assertEquals(\History::UPDATED, $historyEntry['event']); + $this->assertTrue( + (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime'] + ); + $this->assertEquals($id, $historyEntry['id']); + } + + /** + * Test link update with new values + */ + public function testPutLinkWithValues() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'PUT', + 'CONTENT_TYPE' => 'application/json' + ]); + $id = 41; + $update = [ + 'url' => 'http://somewhere.else', + 'title' => 'Le Cid', + 'description' => 'Percé jusques au fond du cœur [...]', + 'tags' => ['corneille', 'rodrigue'], + 'private' => true, + ]; + $request = Request::createFromEnvironment($env); + $request = $request->withParsedBody($update); + + $response = $this->controller->putLink($request, new Response(), ['id' => $id]); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(self::NB_FIELDS_LINK, count($data)); + $this->assertEquals($id, $data['id']); + $this->assertEquals('WDWyig', $data['shorturl']); + $this->assertEquals('http://somewhere.else', $data['url']); + $this->assertEquals('Le Cid', $data['title']); + $this->assertEquals('Percé jusques au fond du cœur [...]', $data['description']); + $this->assertEquals(['corneille', 'rodrigue'], $data['tags']); + $this->assertEquals(true, $data['private']); + $this->assertEquals( + \DateTime::createFromFormat('Ymd_His', '20150310_114651'), + \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) + ); + $this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])); + } + + /** + * Test link update with an existing URL: 409 Conflict with the existing link as body + */ + public function testPutLinkDuplicate() + { + $link = [ + 'url' => 'mediagoblin.org/', + 'title' => 'new entry', + 'description' => 'shaare description', + 'tags' => ['one', 'two'], + 'private' => true, + ]; + $env = Environment::mock([ + 'REQUEST_METHOD' => 'PUT', + 'CONTENT_TYPE' => 'application/json' + ]); + + $request = Request::createFromEnvironment($env); + $request = $request->withParsedBody($link); + $response = $this->controller->putLink($request, new Response(), ['id' => 41]); + + $this->assertEquals(409, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(self::NB_FIELDS_LINK, count($data)); + $this->assertEquals(7, $data['id']); + $this->assertEquals('IuWvgA', $data['shorturl']); + $this->assertEquals('http://mediagoblin.org/', $data['url']); + $this->assertEquals('MediaGoblin', $data['title']); + $this->assertEquals('A free software media publishing platform #hashtagOther', $data['description']); + $this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']); + $this->assertEquals(false, $data['private']); + $this->assertEquals( + \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130614_184135'), + \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) + ); + $this->assertEquals( + \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130615_184230'), + \DateTime::createFromFormat(\DateTime::ATOM, $data['updated']) + ); + } + + /** + * Test link update on non existent link => ApiLinkNotFoundException. + * + * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException + * @expectedExceptionMessage Link not found + */ + public function testGetLink404() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'PUT', + ]); + $request = Request::createFromEnvironment($env); + + $this->controller->putLink($request, new Response(), ['id' => -1]); + } +} diff --git a/tests/api/controllers/tags/DeleteTagTest.php b/tests/api/controllers/tags/DeleteTagTest.php new file mode 100644 index 00000000..7ba5a862 --- /dev/null +++ b/tests/api/controllers/tags/DeleteTagTest.php @@ -0,0 +1,164 @@ +conf = new ConfigManager('tests/utils/config/configJson'); + $this->refDB = new \ReferenceLinkDB(); + $this->refDB->write(self::$testDatastore); + $this->linkDB = new \LinkDB(self::$testDatastore, true, false); + $refHistory = new \ReferenceHistory(); + $refHistory->write(self::$testHistory); + $this->history = new \History(self::$testHistory); + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->container['db'] = $this->linkDB; + $this->container['history'] = $this->history; + + $this->controller = new Tags($this->container); + } + + /** + * After each test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testDatastore); + @unlink(self::$testHistory); + } + + /** + * Test DELETE tag endpoint: the tag should be removed. + */ + public function testDeleteTagValid() + { + $tagName = 'gnu'; + $tags = $this->linkDB->linksCountPerTag(); + $this->assertTrue($tags[$tagName] > 0); + $env = Environment::mock([ + 'REQUEST_METHOD' => 'DELETE', + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->deleteTag($request, new Response(), ['tagName' => $tagName]); + $this->assertEquals(204, $response->getStatusCode()); + $this->assertEmpty((string) $response->getBody()); + + $this->linkDB = new \LinkDB(self::$testDatastore, true, false); + $tags = $this->linkDB->linksCountPerTag(); + $this->assertFalse(isset($tags[$tagName])); + + // 2 links affected + $historyEntry = $this->history->getHistory()[0]; + $this->assertEquals(\History::UPDATED, $historyEntry['event']); + $this->assertTrue( + (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime'] + ); + $historyEntry = $this->history->getHistory()[1]; + $this->assertEquals(\History::UPDATED, $historyEntry['event']); + $this->assertTrue( + (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime'] + ); + } + + /** + * Test DELETE tag endpoint: the tag should be removed. + */ + public function testDeleteTagCaseSensitivity() + { + $tagName = 'sTuff'; + $tags = $this->linkDB->linksCountPerTag(); + $this->assertTrue($tags[$tagName] > 0); + $env = Environment::mock([ + 'REQUEST_METHOD' => 'DELETE', + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->deleteTag($request, new Response(), ['tagName' => $tagName]); + $this->assertEquals(204, $response->getStatusCode()); + $this->assertEmpty((string) $response->getBody()); + + $this->linkDB = new \LinkDB(self::$testDatastore, true, false); + $tags = $this->linkDB->linksCountPerTag(); + $this->assertFalse(isset($tags[$tagName])); + $this->assertTrue($tags[strtolower($tagName)] > 0); + + $historyEntry = $this->history->getHistory()[0]; + $this->assertEquals(\History::UPDATED, $historyEntry['event']); + $this->assertTrue( + (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime'] + ); + } + + /** + * Test DELETE link endpoint: reach not existing ID. + * + * @expectedException Shaarli\Api\Exceptions\ApiTagNotFoundException + * @expectedExceptionMessage Tag not found + */ + public function testDeleteLink404() + { + $tagName = 'nopenope'; + $tags = $this->linkDB->linksCountPerTag(); + $this->assertFalse(isset($tags[$tagName])); + $env = Environment::mock([ + 'REQUEST_METHOD' => 'DELETE', + ]); + $request = Request::createFromEnvironment($env); + + $this->controller->deleteTag($request, new Response(), ['tagName' => $tagName]); + } +} diff --git a/tests/api/controllers/tags/GetTagNameTest.php b/tests/api/controllers/tags/GetTagNameTest.php new file mode 100644 index 00000000..d60f5b38 --- /dev/null +++ b/tests/api/controllers/tags/GetTagNameTest.php @@ -0,0 +1,129 @@ +conf = new ConfigManager('tests/utils/config/configJson'); + $this->refDB = new \ReferenceLinkDB(); + $this->refDB->write(self::$testDatastore); + + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); + $this->container['history'] = null; + + $this->controller = new Tags($this->container); + } + + /** + * After each test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testDatastore); + } + + /** + * Test basic getTag service: return gnu tag with 2 occurrences. + */ + public function testGetTag() + { + $tagName = 'gnu'; + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getTag($request, new Response(), ['tagName' => $tagName]); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(self::NB_FIELDS_TAG, count($data)); + $this->assertEquals($tagName, $data['name']); + $this->assertEquals(2, $data['occurrences']); + } + + /** + * Test getTag service which is not case sensitive: occurrences with both sTuff and stuff + */ + public function testGetTagNotCaseSensitive() + { + $tagName = 'sTuff'; + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getTag($request, new Response(), ['tagName' => $tagName]); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(self::NB_FIELDS_TAG, count($data)); + $this->assertEquals($tagName, $data['name']); + $this->assertEquals(2, $data['occurrences']); + } + + /** + * Test basic getLink service: get non existent link => ApiLinkNotFoundException. + * + * @expectedException Shaarli\Api\Exceptions\ApiTagNotFoundException + * @expectedExceptionMessage Tag not found + */ + public function testGetTag404() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + ]); + $request = Request::createFromEnvironment($env); + + $this->controller->getTag($request, new Response(), ['tagName' => 'nopenope']); + } +} diff --git a/tests/api/controllers/tags/GetTagsTest.php b/tests/api/controllers/tags/GetTagsTest.php new file mode 100644 index 00000000..cf066bc3 --- /dev/null +++ b/tests/api/controllers/tags/GetTagsTest.php @@ -0,0 +1,209 @@ +conf = new ConfigManager('tests/utils/config/configJson'); + $this->refDB = new \ReferenceLinkDB(); + $this->refDB->write(self::$testDatastore); + + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->linkDB = new \LinkDB(self::$testDatastore, true, false); + $this->container['db'] = $this->linkDB; + $this->container['history'] = null; + + $this->controller = new Tags($this->container); + } + + /** + * After every test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testDatastore); + } + + /** + * Test basic getLinks service: returns all tags. + */ + public function testGetTagsAll() + { + $tags = $this->linkDB->linksCountPerTag(); + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + ]); + $request = Request::createFromEnvironment($env); + + $response = $this->controller->getTags($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(count($tags), count($data)); + + // Check order + $this->assertEquals(self::NB_FIELDS_TAG, count($data[0])); + $this->assertEquals('web', $data[0]['name']); + $this->assertEquals(4, $data[0]['occurrences']); + $this->assertEquals(self::NB_FIELDS_TAG, count($data[1])); + $this->assertEquals('cartoon', $data[1]['name']); + $this->assertEquals(3, $data[1]['occurrences']); + // Case insensitive + $this->assertEquals(self::NB_FIELDS_TAG, count($data[2])); + $this->assertEquals('sTuff', $data[2]['name']); + $this->assertEquals(2, $data[2]['occurrences']); + // End + $this->assertEquals(self::NB_FIELDS_TAG, count($data[count($data) - 1])); + $this->assertEquals('ut', $data[count($data) - 1]['name']); + $this->assertEquals(1, $data[count($data) - 1]['occurrences']); + } + + /** + * Test getTags service with offset and limit parameter: + * limit=1 and offset=1 should return only the second tag, cartoon with 3 occurrences + */ + public function testGetTagsOffsetLimit() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'offset=1&limit=1' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getTags($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(1, count($data)); + $this->assertEquals(self::NB_FIELDS_TAG, count($data[0])); + $this->assertEquals('cartoon', $data[0]['name']); + $this->assertEquals(3, $data[0]['occurrences']); + } + + /** + * Test getTags with limit=all (return all tags). + */ + public function testGetTagsLimitAll() + { + $tags = $this->linkDB->linksCountPerTag(); + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'limit=all' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getTags($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(count($tags), count($data)); + } + + /** + * Test getTags service with offset and limit parameter: + * limit=1 and offset=1 should not return any tag + */ + public function testGetTagsOffsetTooHigh() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'offset=100' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getTags($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEmpty(count($data)); + } + + /** + * Test getTags with visibility parameter set to private + */ + public function testGetTagsVisibilityPrivate() + { + $tags = $this->linkDB->linksCountPerTag([], 'private'); + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'visibility=private' + ]); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getTags($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(count($tags), count($data)); + $this->assertEquals(self::NB_FIELDS_TAG, count($data[0])); + $this->assertEquals('css', $data[0]['name']); + $this->assertEquals(1, $data[0]['occurrences']); + } + + /** + * Test getTags with visibility parameter set to public + */ + public function testGetTagsVisibilityPublic() + { + $tags = $this->linkDB->linksCountPerTag([], 'public'); + $env = Environment::mock( + [ + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'visibility=public' + ] + ); + $request = Request::createFromEnvironment($env); + $response = $this->controller->getTags($request, new Response()); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string)$response->getBody(), true); + $this->assertEquals(count($tags), count($data)); + $this->assertEquals(self::NB_FIELDS_TAG, count($data[0])); + $this->assertEquals('web', $data[0]['name']); + $this->assertEquals(3, $data[0]['occurrences']); + } +} diff --git a/tests/api/controllers/tags/PutTagTest.php b/tests/api/controllers/tags/PutTagTest.php new file mode 100644 index 00000000..6f7dec22 --- /dev/null +++ b/tests/api/controllers/tags/PutTagTest.php @@ -0,0 +1,209 @@ +conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->refDB = new \ReferenceLinkDB(); + $this->refDB->write(self::$testDatastore); + + $refHistory = new \ReferenceHistory(); + $refHistory->write(self::$testHistory); + $this->history = new \History(self::$testHistory); + + $this->container = new Container(); + $this->container['conf'] = $this->conf; + $this->linkDB = new \LinkDB(self::$testDatastore, true, false); + $this->container['db'] = $this->linkDB; + $this->container['history'] = $this->history; + + $this->controller = new Tags($this->container); + } + + /** + * After every test, remove the test datastore. + */ + public function tearDown() + { + @unlink(self::$testDatastore); + @unlink(self::$testHistory); + } + + /** + * Test tags update + */ + public function testPutLinkValid() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'PUT', + ]); + $tagName = 'gnu'; + $update = ['name' => $newName = 'newtag']; + $request = Request::createFromEnvironment($env); + $request = $request->withParsedBody($update); + + $response = $this->controller->putTag($request, new Response(), ['tagName' => $tagName]); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(self::NB_FIELDS_TAG, count($data)); + $this->assertEquals($newName, $data['name']); + $this->assertEquals(2, $data['occurrences']); + + $tags = $this->linkDB->linksCountPerTag(); + $this->assertNotTrue(isset($tags[$tagName])); + $this->assertEquals(2, $tags[$newName]); + + $historyEntry = $this->history->getHistory()[0]; + $this->assertEquals(\History::UPDATED, $historyEntry['event']); + $this->assertTrue( + (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime'] + ); + $historyEntry = $this->history->getHistory()[1]; + $this->assertEquals(\History::UPDATED, $historyEntry['event']); + $this->assertTrue( + (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime'] + ); + } + + /** + * Test tag update with an existing tag: they should be merged + */ + public function testPutTagMerge() + { + $tagName = 'gnu'; + $newName = 'w3c'; + + $tags = $this->linkDB->linksCountPerTag(); + $this->assertEquals(1, $tags[$newName]); + $this->assertEquals(2, $tags[$tagName]); + + $env = Environment::mock([ + 'REQUEST_METHOD' => 'PUT', + ]); + $update = ['name' => $newName]; + $request = Request::createFromEnvironment($env); + $request = $request->withParsedBody($update); + + $response = $this->controller->putTag($request, new Response(), ['tagName' => $tagName]); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode((string) $response->getBody(), true); + $this->assertEquals(self::NB_FIELDS_TAG, count($data)); + $this->assertEquals($newName, $data['name']); + $this->assertEquals(3, $data['occurrences']); + + $tags = $this->linkDB->linksCountPerTag(); + $this->assertNotTrue(isset($tags[$tagName])); + $this->assertEquals(3, $tags[$newName]); + } + + /** + * Test tag update with an empty new tag name => ApiBadParametersException + * + * @expectedException Shaarli\Api\Exceptions\ApiBadParametersException + * @expectedExceptionMessage New tag name is required in the request body + */ + public function testPutTagEmpty() + { + $tagName = 'gnu'; + $newName = ''; + + $tags = $this->linkDB->linksCountPerTag(); + $this->assertEquals(2, $tags[$tagName]); + + $env = Environment::mock([ + 'REQUEST_METHOD' => 'PUT', + ]); + $request = Request::createFromEnvironment($env); + + $env = Environment::mock([ + 'REQUEST_METHOD' => 'PUT', + ]); + $update = ['name' => $newName]; + $request = Request::createFromEnvironment($env); + $request = $request->withParsedBody($update); + + try { + $this->controller->putTag($request, new Response(), ['tagName' => $tagName]); + } catch (ApiBadParametersException $e) { + $tags = $this->linkDB->linksCountPerTag(); + $this->assertEquals(2, $tags[$tagName]); + throw $e; + } + } + + /** + * Test tag update on non existent tag => ApiTagNotFoundException. + * + * @expectedException Shaarli\Api\Exceptions\ApiTagNotFoundException + * @expectedExceptionMessage Tag not found + */ + public function testPutTag404() + { + $env = Environment::mock([ + 'REQUEST_METHOD' => 'PUT', + ]); + $request = Request::createFromEnvironment($env); + + $this->controller->putTag($request, new Response(), ['tagName' => 'nopenope']); + } +} -- cgit v1.2.3