From 9f9627059a0b17de45a90e3c5fad9c1a49318151 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Wed, 7 Aug 2019 13:18:02 +0200 Subject: Make sure that bookmark sort is consistent, even with equal timestamps Fixes #1348 --- tests/bookmark/LinkDBTest.php | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'tests') diff --git a/tests/bookmark/LinkDBTest.php b/tests/bookmark/LinkDBTest.php index 2990a6b5..5bbdcea1 100644 --- a/tests/bookmark/LinkDBTest.php +++ b/tests/bookmark/LinkDBTest.php @@ -619,4 +619,39 @@ class LinkDBTest extends \PHPUnit\Framework\TestCase $this->assertEquals($expected, $tags, var_export($tags, true)); } + + /** + * Make sure that bookmarks with the same timestamp have a consistent order: + * if their creation date is equal, bookmarks are sorted by ID DESC. + */ + public function testConsistentOrder() + { + $nextId = 42; + $creation = DateTime::createFromFormat('Ymd_His', '20190807_130444'); + $linkDB = new LinkDB(self::$testDatastore, true, false); + for ($i = 0; $i < 4; ++$i) { + $linkDB[$nextId + $i] = [ + 'id' => $nextId + $i, + 'url' => 'http://'. $i, + 'created' => $creation, + 'title' => true, + 'description' => true, + 'tags' => true, + ]; + } + + // Check 4 new links 4 times + for ($i = 0; $i < 4; ++$i) { + $linkDB->save('tests'); + $linkDB = new LinkDB(self::$testDatastore, true, false); + $count = 3; + foreach ($linkDB as $link) { + $this->assertEquals($nextId + $count, $link['id']); + $this->assertEquals('http://'. $count, $link['url']); + if (--$count < 0) { + break; + } + } + } + } } -- cgit v1.2.3 From bd1adc8df6138f7fda9a50e92702941da85de50c Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 10 Aug 2019 12:42:53 +0200 Subject: Fix UT: LinkDBTest - make each tests independant Otherwise the datastore is empty in the last test, making it inconsistent due to dates issues. --- tests/bookmark/LinkDBTest.php | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'tests') diff --git a/tests/bookmark/LinkDBTest.php b/tests/bookmark/LinkDBTest.php index 5bbdcea1..ffe03cc5 100644 --- a/tests/bookmark/LinkDBTest.php +++ b/tests/bookmark/LinkDBTest.php @@ -49,17 +49,7 @@ class LinkDBTest extends \PHPUnit\Framework\TestCase * - by tag, * - by text, * - etc. - */ - public static function setUpBeforeClass() - { - self::$refDB = new ReferenceLinkDB(); - self::$refDB->write(self::$testDatastore); - - self::$publicLinkDB = new LinkDB(self::$testDatastore, false, false); - self::$privateLinkDB = new LinkDB(self::$testDatastore, true, false); - } - - /** + * * Resets test data for each test */ protected function setUp() @@ -67,6 +57,12 @@ class LinkDBTest extends \PHPUnit\Framework\TestCase if (file_exists(self::$testDatastore)) { unlink(self::$testDatastore); } + + self::$refDB = new ReferenceLinkDB(); + self::$refDB->write(self::$testDatastore); + + self::$publicLinkDB = new LinkDB(self::$testDatastore, false, false); + self::$privateLinkDB = new LinkDB(self::$testDatastore, true, false); } /** @@ -191,7 +187,7 @@ class LinkDBTest extends \PHPUnit\Framework\TestCase $dbSize = sizeof($testDB); $link = array( - 'id' => 42, + 'id' => 43, 'title' => 'an additional link', 'url' => 'http://dum.my', 'description' => 'One more', @@ -626,7 +622,7 @@ class LinkDBTest extends \PHPUnit\Framework\TestCase */ public function testConsistentOrder() { - $nextId = 42; + $nextId = 43; $creation = DateTime::createFromFormat('Ymd_His', '20190807_130444'); $linkDB = new LinkDB(self::$testDatastore, true, false); for ($i = 0; $i < 4; ++$i) { @@ -646,6 +642,9 @@ class LinkDBTest extends \PHPUnit\Framework\TestCase $linkDB = new LinkDB(self::$testDatastore, true, false); $count = 3; foreach ($linkDB as $link) { + if ($link['sticky'] === true) { + continue; + } $this->assertEquals($nextId + $count, $link['id']); $this->assertEquals('http://'. $count, $link['url']); if (--$count < 0) { -- cgit v1.2.3 From 354fb98cc96595870c1962d5939f0bab24951ffa Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Thu, 15 Aug 2019 12:56:32 +0200 Subject: Markdown plugin: fix RSS feed direct link reverse The plugin was only reversing permalinks and failed with setting rss_permalinks set to false --- tests/plugins/PluginMarkdownTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tests') diff --git a/tests/plugins/PluginMarkdownTest.php b/tests/plugins/PluginMarkdownTest.php index 9ddbc558..15fa9ba5 100644 --- a/tests/plugins/PluginMarkdownTest.php +++ b/tests/plugins/PluginMarkdownTest.php @@ -156,6 +156,16 @@ class PluginMarkdownTest extends \PHPUnit\Framework\TestCase $this->assertEquals($expected, $processedText); } + public function testReverseFeedDirectLink() + { + $text = 'Description... '; + $text .= '— Direct link'; + $expected = 'Description... — [Direct link](http://domain.tld/?0oc_VQ)'; + $processedText = reverse_feed_permalink($text); + + $this->assertEquals($expected, $processedText); + } + public function testReverseLastFeedPermalink() { $text = 'Description... '; -- cgit v1.2.3 From def39d0dd7a81a4af9ad68b62c9e9823fbc2b38e Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 10 Aug 2019 12:31:32 +0200 Subject: Run Unit Tests against PHP 7.4 Bump PHPUnit version and fix unit test - Globals are handled differently and are persistent through tests - Tests without assertions are marked as risky: some of them are just meant to check that no error is raised. --- tests/ApplicationUtilsTest.php | 10 +++++----- tests/PluginManagerTest.php | 3 +-- tests/api/ApiUtilsTest.php | 2 +- tests/config/ConfigPhpTest.php | 4 ++++ tests/feed/CachedPageTest.php | 1 + tests/updater/UpdaterTest.php | 6 ++++++ 6 files changed, 18 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/tests/ApplicationUtilsTest.php b/tests/ApplicationUtilsTest.php index 82f8804d..15388970 100644 --- a/tests/ApplicationUtilsTest.php +++ b/tests/ApplicationUtilsTest.php @@ -253,9 +253,9 @@ class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase public function testCheckSupportedPHPVersion() { $minVersion = '5.3'; - ApplicationUtils::checkPHPVersion($minVersion, '5.4.32'); - ApplicationUtils::checkPHPVersion($minVersion, '5.5'); - ApplicationUtils::checkPHPVersion($minVersion, '5.6.10'); + $this->assertTrue(ApplicationUtils::checkPHPVersion($minVersion, '5.4.32')); + $this->assertTrue(ApplicationUtils::checkPHPVersion($minVersion, '5.5')); + $this->assertTrue(ApplicationUtils::checkPHPVersion($minVersion, '5.6.10')); } /** @@ -265,7 +265,7 @@ class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase */ public function testCheckSupportedPHPVersion51() { - ApplicationUtils::checkPHPVersion('5.3', '5.1.0'); + $this->assertTrue(ApplicationUtils::checkPHPVersion('5.3', '5.1.0')); } /** @@ -275,7 +275,7 @@ class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase */ public function testCheckSupportedPHPVersion52() { - ApplicationUtils::checkPHPVersion('5.3', '5.2'); + $this->assertTrue(ApplicationUtils::checkPHPVersion('5.3', '5.2')); } /** diff --git a/tests/PluginManagerTest.php b/tests/PluginManagerTest.php index 71761ac1..195d959c 100644 --- a/tests/PluginManagerTest.php +++ b/tests/PluginManagerTest.php @@ -58,13 +58,12 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase /** * Test missing plugin loading. - * - * @return void */ public function testPluginNotFound() { $this->pluginManager->load(array()); $this->pluginManager->load(array('nope', 'renope')); + $this->addToAssertionCount(1); } /** diff --git a/tests/api/ApiUtilsTest.php b/tests/api/ApiUtilsTest.php index ea0ae500..7499dd71 100644 --- a/tests/api/ApiUtilsTest.php +++ b/tests/api/ApiUtilsTest.php @@ -60,7 +60,7 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase public function testValidateJwtTokenValid() { $secret = 'WarIsPeace'; - ApiUtils::validateJwtToken(self::generateValidJwtToken($secret), $secret); + $this->assertTrue(ApiUtils::validateJwtToken(self::generateValidJwtToken($secret), $secret)); } /** diff --git a/tests/config/ConfigPhpTest.php b/tests/config/ConfigPhpTest.php index 67d878ce..fb91b51b 100644 --- a/tests/config/ConfigPhpTest.php +++ b/tests/config/ConfigPhpTest.php @@ -3,6 +3,10 @@ namespace Shaarli\Config; /** * Class ConfigPhpTest + * + * We run tests in separate processes due to the usage for $GLOBALS + * which are kept between tests. + * @runTestsInSeparateProcesses */ class ConfigPhpTest extends \PHPUnit\Framework\TestCase { diff --git a/tests/feed/CachedPageTest.php b/tests/feed/CachedPageTest.php index 0bcc1442..363028a2 100644 --- a/tests/feed/CachedPageTest.php +++ b/tests/feed/CachedPageTest.php @@ -44,6 +44,7 @@ class CachedPageTest extends \PHPUnit\Framework\TestCase new CachedPage(self::$testCacheDir, '', false); new CachedPage(self::$testCacheDir, 'http://shaar.li/?do=rss', true); new CachedPage(self::$testCacheDir, 'http://shaar.li/?do=atom', false); + $this->addToAssertionCount(1); } /** diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php index 93bc86c1..ac87e33c 100644 --- a/tests/updater/UpdaterTest.php +++ b/tests/updater/UpdaterTest.php @@ -724,6 +724,9 @@ $GLOBALS[\'privateLinkByDefault\'] = true;'; */ public function testUpdateMethodWebThumbnailerDisabled() { + if (isset($_SESSION['warnings'])) { + unset($_SESSION['warnings']); + } $this->conf->remove('thumbnails'); $this->conf->set('thumbnail.enable_thumbnails', false); $updater = new Updater([], [], $this->conf, true, $_SESSION); @@ -740,6 +743,9 @@ $GLOBALS[\'privateLinkByDefault\'] = true;'; */ public function testUpdateMethodWebThumbnailerNothingToDo() { + if (isset($_SESSION['warnings'])) { + unset($_SESSION['warnings']); + } $updater = new Updater([], [], $this->conf, true, $_SESSION); $this->assertTrue($updater->updateMethodWebThumbnailer()); $this->assertFalse($this->conf->exists('thumbnail')); -- cgit v1.2.3 From e26e2060f5470ce8bf4c5973284bae07b8af170a Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Fri, 17 Jan 2020 21:34:12 +0100 Subject: Add and update unit test for the new system (Bookmark + Service) See #1307 --- tests/HistoryTest.php | 240 ++--- tests/api/ApiMiddlewareTest.php | 8 +- tests/api/ApiUtilsTest.php | 67 +- tests/api/controllers/history/HistoryTest.php | 4 +- tests/api/controllers/info/InfoTest.php | 20 +- tests/api/controllers/links/DeleteLinkTest.php | 22 +- tests/api/controllers/links/GetLinkIdTest.php | 11 +- tests/api/controllers/links/GetLinksTest.php | 15 +- tests/api/controllers/links/PostLinkTest.php | 30 +- tests/api/controllers/links/PutLinkTest.php | 24 +- tests/api/controllers/tags/DeleteTagTest.php | 29 +- tests/api/controllers/tags/GetTagNameTest.php | 8 +- tests/api/controllers/tags/GetTagsTest.php | 23 +- tests/api/controllers/tags/PutTagTest.php | 25 +- tests/bookmark/BookmarkArrayTest.php | 239 +++++ tests/bookmark/BookmarkFileServiceTest.php | 1042 +++++++++++++++++++++ tests/bookmark/BookmarkFilterTest.php | 514 ++++++++++ tests/bookmark/BookmarkInitializerTest.php | 120 +++ tests/bookmark/BookmarkTest.php | 388 ++++++++ tests/bookmark/LinkDBTest.php | 656 ------------- tests/bookmark/LinkFilterTest.php | 507 ---------- tests/bookmark/LinkUtilsTest.php | 9 - tests/bootstrap.php | 18 + tests/config/ConfigJsonTest.php | 2 +- tests/feed/FeedBuilderTest.php | 103 +- tests/formatter/BookmarkDefaultFormatterTest.php | 156 +++ tests/formatter/BookmarkMarkdownFormatterTest.php | 160 ++++ tests/formatter/BookmarkRawFormatterTest.php | 97 ++ tests/formatter/FormatterFactoryTest.php | 101 ++ tests/legacy/LegacyDummyUpdater.php | 74 ++ tests/legacy/LegacyLinkDBTest.php | 656 +++++++++++++ tests/legacy/LegacyLinkFilterTest.php | 509 ++++++++++ tests/legacy/LegacyUpdaterTest.php | 886 ++++++++++++++++++ tests/netscape/BookmarkExportTest.php | 70 +- tests/netscape/BookmarkImportTest.php | 570 +++++------ tests/plugins/PluginArchiveorgTest.php | 4 +- tests/plugins/PluginIssoTest.php | 12 +- tests/plugins/PluginMarkdownTest.php | 316 ------- tests/updater/DummyUpdater.php | 13 +- tests/updater/UpdaterTest.php | 684 +------------- tests/utils/FakeBookmarkService.php | 18 + tests/utils/ReferenceHistory.php | 2 +- tests/utils/ReferenceLinkDB.php | 111 ++- tests/utils/config/configJson.json.php | 6 +- 44 files changed, 5769 insertions(+), 2800 deletions(-) create mode 100644 tests/bookmark/BookmarkArrayTest.php create mode 100644 tests/bookmark/BookmarkFileServiceTest.php create mode 100644 tests/bookmark/BookmarkFilterTest.php create mode 100644 tests/bookmark/BookmarkInitializerTest.php create mode 100644 tests/bookmark/BookmarkTest.php delete mode 100644 tests/bookmark/LinkDBTest.php delete mode 100644 tests/bookmark/LinkFilterTest.php create mode 100644 tests/formatter/BookmarkDefaultFormatterTest.php create mode 100644 tests/formatter/BookmarkMarkdownFormatterTest.php create mode 100644 tests/formatter/BookmarkRawFormatterTest.php create mode 100644 tests/formatter/FormatterFactoryTest.php create mode 100644 tests/legacy/LegacyDummyUpdater.php create mode 100644 tests/legacy/LegacyLinkDBTest.php create mode 100644 tests/legacy/LegacyLinkFilterTest.php create mode 100644 tests/legacy/LegacyUpdaterTest.php delete mode 100644 tests/plugins/PluginMarkdownTest.php create mode 100644 tests/utils/FakeBookmarkService.php (limited to 'tests') diff --git a/tests/HistoryTest.php b/tests/HistoryTest.php index 8303e53a..7189c3a9 100644 --- a/tests/HistoryTest.php +++ b/tests/HistoryTest.php @@ -4,6 +4,7 @@ namespace Shaarli; use DateTime; use Exception; +use Shaarli\Bookmark\Bookmark; class HistoryTest extends \PHPUnit\Framework\TestCase { @@ -15,9 +16,11 @@ class HistoryTest extends \PHPUnit\Framework\TestCase /** * Delete history file. */ - public function tearDown() + public function setUp() { - @unlink(self::$historyFilePath); + if (file_exists(self::$historyFilePath)) { + unlink(self::$historyFilePath); + } } /** @@ -73,137 +76,140 @@ class HistoryTest extends \PHPUnit\Framework\TestCase public function testAddLink() { $history = new History(self::$historyFilePath); - $history->addLink(['id' => 0]); + $bookmark = (new Bookmark())->setId(0); + $history->addLink($bookmark); $actual = $history->getHistory()[0]; $this->assertEquals(History::CREATED, $actual['event']); $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); $this->assertEquals(0, $actual['id']); $history = new History(self::$historyFilePath); - $history->addLink(['id' => 1]); + $bookmark = (new Bookmark())->setId(1); + $history->addLink($bookmark); $actual = $history->getHistory()[0]; $this->assertEquals(History::CREATED, $actual['event']); $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); $this->assertEquals(1, $actual['id']); $history = new History(self::$historyFilePath); - $history->addLink(['id' => 'str']); + $bookmark = (new Bookmark())->setId('str'); + $history->addLink($bookmark); $actual = $history->getHistory()[0]; $this->assertEquals(History::CREATED, $actual['event']); $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); $this->assertEquals('str', $actual['id']); } - /** - * Test updated link event - */ - public function testUpdateLink() - { - $history = new History(self::$historyFilePath); - $history->updateLink(['id' => 1]); - $actual = $history->getHistory()[0]; - $this->assertEquals(History::UPDATED, $actual['event']); - $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); - $this->assertEquals(1, $actual['id']); - } - - /** - * Test delete link event - */ - public function testDeleteLink() - { - $history = new History(self::$historyFilePath); - $history->deleteLink(['id' => 1]); - $actual = $history->getHistory()[0]; - $this->assertEquals(History::DELETED, $actual['event']); - $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); - $this->assertEquals(1, $actual['id']); - } - - /** - * Test updated settings event - */ - public function testUpdateSettings() - { - $history = new History(self::$historyFilePath); - $history->updateSettings(); - $actual = $history->getHistory()[0]; - $this->assertEquals(History::SETTINGS, $actual['event']); - $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); - $this->assertEmpty($actual['id']); - } - - /** - * Make sure that new items are stored at the beginning - */ - public function testHistoryOrder() - { - $history = new History(self::$historyFilePath); - $history->updateLink(['id' => 1]); - $actual = $history->getHistory()[0]; - $this->assertEquals(History::UPDATED, $actual['event']); - $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); - $this->assertEquals(1, $actual['id']); - - $history->addLink(['id' => 1]); - $actual = $history->getHistory()[0]; - $this->assertEquals(History::CREATED, $actual['event']); - $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); - $this->assertEquals(1, $actual['id']); - } - - /** - * Re-read history from file after writing an event - */ - public function testHistoryRead() - { - $history = new History(self::$historyFilePath); - $history->updateLink(['id' => 1]); - $history = new History(self::$historyFilePath); - $actual = $history->getHistory()[0]; - $this->assertEquals(History::UPDATED, $actual['event']); - $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); - $this->assertEquals(1, $actual['id']); - } - - /** - * Re-read history from file after writing an event and make sure that the order is correct - */ - public function testHistoryOrderRead() - { - $history = new History(self::$historyFilePath); - $history->updateLink(['id' => 1]); - $history->addLink(['id' => 1]); - - $history = new History(self::$historyFilePath); - $actual = $history->getHistory()[0]; - $this->assertEquals(History::CREATED, $actual['event']); - $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); - $this->assertEquals(1, $actual['id']); - - $actual = $history->getHistory()[1]; - $this->assertEquals(History::UPDATED, $actual['event']); - $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); - $this->assertEquals(1, $actual['id']); - } - - /** - * Test retention time: delete old entries. - */ - public function testHistoryRententionTime() - { - $history = new History(self::$historyFilePath, 5); - $history->updateLink(['id' => 1]); - $this->assertEquals(1, count($history->getHistory())); - $arr = $history->getHistory(); - $arr[0]['datetime'] = new DateTime('-1 hour'); - FileUtils::writeFlatDB(self::$historyFilePath, $arr); - - $history = new History(self::$historyFilePath, 60); - $this->assertEquals(1, count($history->getHistory())); - $this->assertEquals(1, $history->getHistory()[0]['id']); - $history->updateLink(['id' => 2]); - $this->assertEquals(1, count($history->getHistory())); - $this->assertEquals(2, $history->getHistory()[0]['id']); - } +// /** +// * Test updated link event +// */ +// public function testUpdateLink() +// { +// $history = new History(self::$historyFilePath); +// $history->updateLink(['id' => 1]); +// $actual = $history->getHistory()[0]; +// $this->assertEquals(History::UPDATED, $actual['event']); +// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); +// $this->assertEquals(1, $actual['id']); +// } +// +// /** +// * Test delete link event +// */ +// public function testDeleteLink() +// { +// $history = new History(self::$historyFilePath); +// $history->deleteLink(['id' => 1]); +// $actual = $history->getHistory()[0]; +// $this->assertEquals(History::DELETED, $actual['event']); +// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); +// $this->assertEquals(1, $actual['id']); +// } +// +// /** +// * Test updated settings event +// */ +// public function testUpdateSettings() +// { +// $history = new History(self::$historyFilePath); +// $history->updateSettings(); +// $actual = $history->getHistory()[0]; +// $this->assertEquals(History::SETTINGS, $actual['event']); +// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); +// $this->assertEmpty($actual['id']); +// } +// +// /** +// * Make sure that new items are stored at the beginning +// */ +// public function testHistoryOrder() +// { +// $history = new History(self::$historyFilePath); +// $history->updateLink(['id' => 1]); +// $actual = $history->getHistory()[0]; +// $this->assertEquals(History::UPDATED, $actual['event']); +// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); +// $this->assertEquals(1, $actual['id']); +// +// $history->addLink(['id' => 1]); +// $actual = $history->getHistory()[0]; +// $this->assertEquals(History::CREATED, $actual['event']); +// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); +// $this->assertEquals(1, $actual['id']); +// } +// +// /** +// * Re-read history from file after writing an event +// */ +// public function testHistoryRead() +// { +// $history = new History(self::$historyFilePath); +// $history->updateLink(['id' => 1]); +// $history = new History(self::$historyFilePath); +// $actual = $history->getHistory()[0]; +// $this->assertEquals(History::UPDATED, $actual['event']); +// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); +// $this->assertEquals(1, $actual['id']); +// } +// +// /** +// * Re-read history from file after writing an event and make sure that the order is correct +// */ +// public function testHistoryOrderRead() +// { +// $history = new History(self::$historyFilePath); +// $history->updateLink(['id' => 1]); +// $history->addLink(['id' => 1]); +// +// $history = new History(self::$historyFilePath); +// $actual = $history->getHistory()[0]; +// $this->assertEquals(History::CREATED, $actual['event']); +// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); +// $this->assertEquals(1, $actual['id']); +// +// $actual = $history->getHistory()[1]; +// $this->assertEquals(History::UPDATED, $actual['event']); +// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); +// $this->assertEquals(1, $actual['id']); +// } +// +// /** +// * Test retention time: delete old entries. +// */ +// public function testHistoryRententionTime() +// { +// $history = new History(self::$historyFilePath, 5); +// $history->updateLink(['id' => 1]); +// $this->assertEquals(1, count($history->getHistory())); +// $arr = $history->getHistory(); +// $arr[0]['datetime'] = new DateTime('-1 hour'); +// FileUtils::writeFlatDB(self::$historyFilePath, $arr); +// +// $history = new History(self::$historyFilePath, 60); +// $this->assertEquals(1, count($history->getHistory())); +// $this->assertEquals(1, $history->getHistory()[0]['id']); +// $history->updateLink(['id' => 2]); +// $this->assertEquals(1, count($history->getHistory())); +// $this->assertEquals(2, $history->getHistory()[0]['id']); +// } } diff --git a/tests/api/ApiMiddlewareTest.php b/tests/api/ApiMiddlewareTest.php index 0b9b03f2..df2fb33a 100644 --- a/tests/api/ApiMiddlewareTest.php +++ b/tests/api/ApiMiddlewareTest.php @@ -2,6 +2,7 @@ namespace Shaarli\Api; use Shaarli\Config\ConfigManager; +use Shaarli\History; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -40,18 +41,21 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase protected $container; /** - * Before every test, instantiate a new Api with its config, plugins and links. + * Before every test, instantiate a new Api with its config, plugins and bookmarks. */ public function setUp() { - $this->conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->conf = new ConfigManager('tests/utils/config/configJson'); $this->conf->set('api.secret', 'NapoleonWasALizard'); $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); + $history = new History('sandbox/history.php'); + $this->container = new Container(); $this->container['conf'] = $this->conf; + $this->container['history'] = $history; } /** diff --git a/tests/api/ApiUtilsTest.php b/tests/api/ApiUtilsTest.php index 7499dd71..7efec9bb 100644 --- a/tests/api/ApiUtilsTest.php +++ b/tests/api/ApiUtilsTest.php @@ -2,6 +2,7 @@ namespace Shaarli\Api; +use Shaarli\Bookmark\Bookmark; use Shaarli\Http\Base64Url; /** @@ -212,7 +213,7 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase public function testFormatLinkComplete() { $indexUrl = 'https://domain.tld/sub/'; - $link = [ + $data = [ 'id' => 12, 'url' => 'http://lol.lol', 'shorturl' => 'abc', @@ -223,6 +224,8 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase 'created' => \DateTime::createFromFormat('Ymd_His', '20170107_160102'), 'updated' => \DateTime::createFromFormat('Ymd_His', '20170107_160612'), ]; + $bookmark = new Bookmark(); + $bookmark->fromArray($data); $expected = [ 'id' => 12, @@ -236,7 +239,7 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase 'updated' => '2017-01-07T16:06:12+00:00', ]; - $this->assertEquals($expected, ApiUtils::formatLink($link, $indexUrl)); + $this->assertEquals($expected, ApiUtils::formatLink($bookmark, $indexUrl)); } /** @@ -245,7 +248,7 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase public function testFormatLinkMinimalNote() { $indexUrl = 'https://domain.tld/sub/'; - $link = [ + $data = [ 'id' => 12, 'url' => '?abc', 'shorturl' => 'abc', @@ -255,6 +258,8 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase 'private' => '', 'created' => \DateTime::createFromFormat('Ymd_His', '20170107_160102'), ]; + $bookmark = new Bookmark(); + $bookmark->fromArray($data); $expected = [ 'id' => 12, @@ -268,7 +273,7 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase 'updated' => '', ]; - $this->assertEquals($expected, ApiUtils::formatLink($link, $indexUrl)); + $this->assertEquals($expected, ApiUtils::formatLink($bookmark, $indexUrl)); } /** @@ -277,7 +282,7 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase public function testUpdateLink() { $created = \DateTime::createFromFormat('Ymd_His', '20170107_160102'); - $old = [ + $data = [ 'id' => 12, 'url' => '?abc', 'shorturl' => 'abc', @@ -287,8 +292,10 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase 'private' => '', 'created' => $created, ]; + $old = new Bookmark(); + $old->fromArray($data); - $new = [ + $data = [ 'id' => 13, 'shorturl' => 'nope', 'url' => 'http://somewhere.else', @@ -299,17 +306,18 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase 'created' => 'creation', 'updated' => 'updation', ]; + $new = new Bookmark(); + $new->fromArray($data); $result = ApiUtils::updateLink($old, $new); - $this->assertEquals(12, $result['id']); - $this->assertEquals('http://somewhere.else', $result['url']); - $this->assertEquals('abc', $result['shorturl']); - $this->assertEquals('Le Cid', $result['title']); - $this->assertEquals('Percé jusques au fond du cœur [...]', $result['description']); - $this->assertEquals('corneille rodrigue', $result['tags']); - $this->assertEquals(true, $result['private']); - $this->assertEquals($created, $result['created']); - $this->assertTrue(new \DateTime('5 seconds ago') < $result['updated']); + $this->assertEquals(12, $result->getId()); + $this->assertEquals('http://somewhere.else', $result->getUrl()); + $this->assertEquals('abc', $result->getShortUrl()); + $this->assertEquals('Le Cid', $result->getTitle()); + $this->assertEquals('Percé jusques au fond du cœur [...]', $result->getDescription()); + $this->assertEquals('corneille rodrigue', $result->getTagsString()); + $this->assertEquals(true, $result->isPrivate()); + $this->assertEquals($created, $result->getCreated()); } /** @@ -318,7 +326,7 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase public function testUpdateLinkMinimal() { $created = \DateTime::createFromFormat('Ymd_His', '20170107_160102'); - $old = [ + $data = [ 'id' => 12, 'url' => '?abc', 'shorturl' => 'abc', @@ -328,24 +336,19 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase 'private' => true, 'created' => $created, ]; + $old = new Bookmark(); + $old->fromArray($data); - $new = [ - 'url' => '', - 'title' => '', - 'description' => '', - 'tags' => '', - 'private' => false, - ]; + $new = new Bookmark(); $result = ApiUtils::updateLink($old, $new); - $this->assertEquals(12, $result['id']); - $this->assertEquals('?abc', $result['url']); - $this->assertEquals('abc', $result['shorturl']); - $this->assertEquals('?abc', $result['title']); - $this->assertEquals('', $result['description']); - $this->assertEquals('', $result['tags']); - $this->assertEquals(false, $result['private']); - $this->assertEquals($created, $result['created']); - $this->assertTrue(new \DateTime('5 seconds ago') < $result['updated']); + $this->assertEquals(12, $result->getId()); + $this->assertEquals('', $result->getUrl()); + $this->assertEquals('abc', $result->getShortUrl()); + $this->assertEquals('', $result->getTitle()); + $this->assertEquals('', $result->getDescription()); + $this->assertEquals('', $result->getTagsString()); + $this->assertEquals(false, $result->isPrivate()); + $this->assertEquals($created, $result->getCreated()); } } diff --git a/tests/api/controllers/history/HistoryTest.php b/tests/api/controllers/history/HistoryTest.php index e287f239..f4d3b646 100644 --- a/tests/api/controllers/history/HistoryTest.php +++ b/tests/api/controllers/history/HistoryTest.php @@ -39,11 +39,11 @@ class HistoryTest extends \PHPUnit\Framework\TestCase protected $controller; /** - * Before every test, instantiate a new Api with its config, plugins and links. + * Before every test, instantiate a new Api with its config, plugins and bookmarks. */ public function setUp() { - $this->conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->conf = new ConfigManager('tests/utils/config/configJson'); $this->refHistory = new \ReferenceHistory(); $this->refHistory->write(self::$testHistory); $this->container = new Container(); diff --git a/tests/api/controllers/info/InfoTest.php b/tests/api/controllers/info/InfoTest.php index e70d371b..b5c938e1 100644 --- a/tests/api/controllers/info/InfoTest.php +++ b/tests/api/controllers/info/InfoTest.php @@ -1,7 +1,10 @@ conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->conf = new ConfigManager('tests/utils/config/configJson'); + $this->conf->set('resource.datastore', self::$testDatastore); $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); + $history = new History('sandbox/history.php'); + $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = new \Shaarli\Bookmark\LinkDB(self::$testDatastore, true, false); + $this->container['db'] = new BookmarkFileService($this->conf, $history, true); $this->container['history'] = null; $this->controller = new Info($this->container); @@ -84,11 +90,11 @@ class InfoTest extends \PHPUnit\Framework\TestCase $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('Europe/Paris', $data['settings']['timezone']); $this->assertEquals(ConfigManager::$DEFAULT_PLUGINS, $data['settings']['enabled_plugins']); - $this->assertEquals(false, $data['settings']['default_private_links']); + $this->assertEquals(true, $data['settings']['default_private_links']); - $title = 'My links'; + $title = 'My bookmarks'; $headerLink = 'http://shaarli.tld'; $timezone = 'Europe/Paris'; $enabledPlugins = array('foo', 'bar'); diff --git a/tests/api/controllers/links/DeleteLinkTest.php b/tests/api/controllers/links/DeleteLinkTest.php index 90193e28..6c2b3698 100644 --- a/tests/api/controllers/links/DeleteLinkTest.php +++ b/tests/api/controllers/links/DeleteLinkTest.php @@ -3,7 +3,7 @@ namespace Shaarli\Api\Controllers; -use Shaarli\Bookmark\LinkDB; +use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Config\ConfigManager; use Shaarli\History; use Slim\Container; @@ -34,9 +34,9 @@ class DeleteLinkTest extends \PHPUnit\Framework\TestCase protected $refDB = null; /** - * @var LinkDB instance. + * @var BookmarkFileService instance. */ - protected $linkDB; + protected $bookmarkService; /** * @var HistoryController instance. @@ -54,20 +54,22 @@ class DeleteLinkTest extends \PHPUnit\Framework\TestCase protected $controller; /** - * Before each test, instantiate a new Api with its config, plugins and links. + * Before each test, instantiate a new Api with its config, plugins and bookmarks. */ public function setUp() { $this->conf = new ConfigManager('tests/utils/config/configJson'); + $this->conf->set('resource.datastore', self::$testDatastore); $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->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); + $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = $this->linkDB; + $this->container['db'] = $this->bookmarkService; $this->container['history'] = $this->history; $this->controller = new Links($this->container); @@ -88,7 +90,7 @@ class DeleteLinkTest extends \PHPUnit\Framework\TestCase public function testDeleteLinkValid() { $id = '41'; - $this->assertTrue(isset($this->linkDB[$id])); + $this->assertTrue($this->bookmarkService->exists($id)); $env = Environment::mock([ 'REQUEST_METHOD' => 'DELETE', ]); @@ -98,8 +100,8 @@ class DeleteLinkTest extends \PHPUnit\Framework\TestCase $this->assertEquals(204, $response->getStatusCode()); $this->assertEmpty((string) $response->getBody()); - $this->linkDB = new LinkDB(self::$testDatastore, true, false); - $this->assertFalse(isset($this->linkDB[$id])); + $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); + $this->assertFalse($this->bookmarkService->exists($id)); $historyEntry = $this->history->getHistory()[0]; $this->assertEquals(History::DELETED, $historyEntry['event']); @@ -117,7 +119,7 @@ class DeleteLinkTest extends \PHPUnit\Framework\TestCase public function testDeleteLink404() { $id = -1; - $this->assertFalse(isset($this->linkDB[$id])); + $this->assertFalse($this->bookmarkService->exists($id)); $env = Environment::mock([ 'REQUEST_METHOD' => 'DELETE', ]); diff --git a/tests/api/controllers/links/GetLinkIdTest.php b/tests/api/controllers/links/GetLinkIdTest.php index cb9b7f6a..c26411ac 100644 --- a/tests/api/controllers/links/GetLinkIdTest.php +++ b/tests/api/controllers/links/GetLinkIdTest.php @@ -2,7 +2,10 @@ namespace Shaarli\Api\Controllers; +use Shaarli\Bookmark\Bookmark; +use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Config\ConfigManager; +use Shaarli\History; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -50,17 +53,19 @@ class GetLinkIdTest extends \PHPUnit\Framework\TestCase const NB_FIELDS_LINK = 9; /** - * Before each test, instantiate a new Api with its config, plugins and links. + * Before each test, instantiate a new Api with its config, plugins and bookmarks. */ public function setUp() { $this->conf = new ConfigManager('tests/utils/config/configJson'); + $this->conf->set('resource.datastore', self::$testDatastore); $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); + $history = new History('sandbox/history.php'); $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = new \Shaarli\Bookmark\LinkDB(self::$testDatastore, true, false); + $this->container['db'] = new BookmarkFileService($this->conf, $history, true); $this->container['history'] = null; $this->controller = new Links($this->container); @@ -107,7 +112,7 @@ class GetLinkIdTest extends \PHPUnit\Framework\TestCase $this->assertEquals('sTuff', $data['tags'][0]); $this->assertEquals(false, $data['private']); $this->assertEquals( - \DateTime::createFromFormat(\Shaarli\Bookmark\LinkDB::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM), + \DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM), $data['created'] ); $this->assertEmpty($data['updated']); diff --git a/tests/api/controllers/links/GetLinksTest.php b/tests/api/controllers/links/GetLinksTest.php index 711a3152..4e2d55ac 100644 --- a/tests/api/controllers/links/GetLinksTest.php +++ b/tests/api/controllers/links/GetLinksTest.php @@ -1,8 +1,11 @@ conf = new ConfigManager('tests/utils/config/configJson'); + $this->conf->set('resource.datastore', self::$testDatastore); $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); + $history = new History('sandbox/history.php'); $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = new LinkDB(self::$testDatastore, true, false); + $this->container['db'] = new BookmarkFileService($this->conf, $history, true); $this->container['history'] = null; $this->controller = new Links($this->container); @@ -75,7 +80,7 @@ class GetLinksTest extends \PHPUnit\Framework\TestCase } /** - * Test basic getLinks service: returns all links. + * Test basic getLinks service: returns all bookmarks. */ public function testGetLinks() { @@ -114,7 +119,7 @@ class GetLinksTest extends \PHPUnit\Framework\TestCase $this->assertEquals('sTuff', $first['tags'][0]); $this->assertEquals(false, $first['private']); $this->assertEquals( - \DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM), + \DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM), $first['created'] ); $this->assertEmpty($first['updated']); @@ -125,7 +130,7 @@ class GetLinksTest extends \PHPUnit\Framework\TestCase // Update date $this->assertEquals( - \DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160803_093033')->format(\DateTime::ATOM), + \DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160803_093033')->format(\DateTime::ATOM), $link['updated'] ); } diff --git a/tests/api/controllers/links/PostLinkTest.php b/tests/api/controllers/links/PostLinkTest.php index d683a984..b2dd09eb 100644 --- a/tests/api/controllers/links/PostLinkTest.php +++ b/tests/api/controllers/links/PostLinkTest.php @@ -3,6 +3,8 @@ namespace Shaarli\Api\Controllers; use PHPUnit\Framework\TestCase; +use Shaarli\Bookmark\Bookmark; +use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Config\ConfigManager; use Shaarli\History; use Slim\Container; @@ -40,6 +42,11 @@ class PostLinkTest extends TestCase */ protected $refDB = null; + /** + * @var BookmarkFileService instance. + */ + protected $bookmarkService; + /** * @var HistoryController instance. */ @@ -61,29 +68,30 @@ class PostLinkTest extends TestCase const NB_FIELDS_LINK = 9; /** - * Before every test, instantiate a new Api with its config, plugins and links. + * Before every test, instantiate a new Api with its config, plugins and bookmarks. */ public function setUp() { - $this->conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->conf = new ConfigManager('tests/utils/config/configJson'); + $this->conf->set('resource.datastore', self::$testDatastore); $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); - $refHistory = new \ReferenceHistory(); $refHistory->write(self::$testHistory); $this->history = new History(self::$testHistory); + $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = new \Shaarli\Bookmark\LinkDB(self::$testDatastore, true, false); - $this->container['history'] = new History(self::$testHistory); + $this->container['db'] = $this->bookmarkService; + $this->container['history'] = $this->history; $this->controller = new Links($this->container); $mock = $this->createMock(Router::class); $mock->expects($this->any()) ->method('relativePathFor') - ->willReturn('api/v1/links/1'); + ->willReturn('api/v1/bookmarks/1'); // affect @property-read... seems to work $this->controller->getCi()->router = $mock; @@ -118,7 +126,7 @@ class PostLinkTest extends TestCase $response = $this->controller->postLink($request, new Response()); $this->assertEquals(201, $response->getStatusCode()); - $this->assertEquals('api/v1/links/1', $response->getHeader('Location')[0]); + $this->assertEquals('api/v1/bookmarks/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']); @@ -127,7 +135,7 @@ class PostLinkTest extends TestCase $this->assertEquals('?' . $data['shorturl'], $data['title']); $this->assertEquals('', $data['description']); $this->assertEquals([], $data['tags']); - $this->assertEquals(false, $data['private']); + $this->assertEquals(true, $data['private']); $this->assertTrue( new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) ); @@ -163,7 +171,7 @@ class PostLinkTest extends TestCase $response = $this->controller->postLink($request, new Response()); $this->assertEquals(201, $response->getStatusCode()); - $this->assertEquals('api/v1/links/1', $response->getHeader('Location')[0]); + $this->assertEquals('api/v1/bookmarks/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']); @@ -211,11 +219,11 @@ class PostLinkTest extends TestCase $this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']); $this->assertEquals(false, $data['private']); $this->assertEquals( - \DateTime::createFromFormat(\Shaarli\Bookmark\LinkDB::LINK_DATE_FORMAT, '20130614_184135'), + \DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20130614_184135'), \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) ); $this->assertEquals( - \DateTime::createFromFormat(\Shaarli\Bookmark\LinkDB::LINK_DATE_FORMAT, '20130615_184230'), + \DateTime::createFromFormat(Bookmark::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 index cd815b66..cb63742e 100644 --- a/tests/api/controllers/links/PutLinkTest.php +++ b/tests/api/controllers/links/PutLinkTest.php @@ -3,6 +3,8 @@ namespace Shaarli\Api\Controllers; +use Shaarli\Bookmark\Bookmark; +use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Config\ConfigManager; use Shaarli\History; use Slim\Container; @@ -32,6 +34,11 @@ class PutLinkTest extends \PHPUnit\Framework\TestCase */ protected $refDB = null; + /** + * @var BookmarkFileService instance. + */ + protected $bookmarkService; + /** * @var HistoryController instance. */ @@ -53,22 +60,23 @@ class PutLinkTest extends \PHPUnit\Framework\TestCase const NB_FIELDS_LINK = 9; /** - * Before every test, instantiate a new Api with its config, plugins and links. + * Before every test, instantiate a new Api with its config, plugins and bookmarks. */ public function setUp() { - $this->conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->conf = new ConfigManager('tests/utils/config/configJson'); + $this->conf->set('resource.datastore', self::$testDatastore); $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); - $refHistory = new \ReferenceHistory(); $refHistory->write(self::$testHistory); $this->history = new History(self::$testHistory); + $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = new \Shaarli\Bookmark\LinkDB(self::$testDatastore, true, false); - $this->container['history'] = new History(self::$testHistory); + $this->container['db'] = $this->bookmarkService; + $this->container['history'] = $this->history; $this->controller = new Links($this->container); @@ -110,7 +118,7 @@ class PutLinkTest extends \PHPUnit\Framework\TestCase $this->assertEquals('?WDWyig', $data['title']); $this->assertEquals('', $data['description']); $this->assertEquals([], $data['tags']); - $this->assertEquals(false, $data['private']); + $this->assertEquals(true, $data['private']); $this->assertEquals( \DateTime::createFromFormat('Ymd_His', '20150310_114651'), \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) @@ -199,11 +207,11 @@ class PutLinkTest extends \PHPUnit\Framework\TestCase $this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']); $this->assertEquals(false, $data['private']); $this->assertEquals( - \DateTime::createFromFormat(\Shaarli\Bookmark\LinkDB::LINK_DATE_FORMAT, '20130614_184135'), + \DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20130614_184135'), \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) ); $this->assertEquals( - \DateTime::createFromFormat(\Shaarli\Bookmark\LinkDB::LINK_DATE_FORMAT, '20130615_184230'), + \DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20130615_184230'), \DateTime::createFromFormat(\DateTime::ATOM, $data['updated']) ); } diff --git a/tests/api/controllers/tags/DeleteTagTest.php b/tests/api/controllers/tags/DeleteTagTest.php index 84e1d56e..c6748872 100644 --- a/tests/api/controllers/tags/DeleteTagTest.php +++ b/tests/api/controllers/tags/DeleteTagTest.php @@ -3,6 +3,7 @@ namespace Shaarli\Api\Controllers; +use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Bookmark\LinkDB; use Shaarli\Config\ConfigManager; use Shaarli\History; @@ -34,9 +35,9 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase protected $refDB = null; /** - * @var LinkDB instance. + * @var BookmarkFileService instance. */ - protected $linkDB; + protected $bookmarkService; /** * @var HistoryController instance. @@ -54,20 +55,22 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase protected $controller; /** - * Before each test, instantiate a new Api with its config, plugins and links. + * Before each test, instantiate a new Api with its config, plugins and bookmarks. */ public function setUp() { $this->conf = new ConfigManager('tests/utils/config/configJson'); + $this->conf->set('resource.datastore', self::$testDatastore); $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->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); + $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = $this->linkDB; + $this->container['db'] = $this->bookmarkService; $this->container['history'] = $this->history; $this->controller = new Tags($this->container); @@ -88,7 +91,7 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase public function testDeleteTagValid() { $tagName = 'gnu'; - $tags = $this->linkDB->linksCountPerTag(); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertTrue($tags[$tagName] > 0); $env = Environment::mock([ 'REQUEST_METHOD' => 'DELETE', @@ -99,11 +102,11 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase $this->assertEquals(204, $response->getStatusCode()); $this->assertEmpty((string) $response->getBody()); - $this->linkDB = new LinkDB(self::$testDatastore, true, false); - $tags = $this->linkDB->linksCountPerTag(); + $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertFalse(isset($tags[$tagName])); - // 2 links affected + // 2 bookmarks affected $historyEntry = $this->history->getHistory()[0]; $this->assertEquals(History::UPDATED, $historyEntry['event']); $this->assertTrue( @@ -122,7 +125,7 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase public function testDeleteTagCaseSensitivity() { $tagName = 'sTuff'; - $tags = $this->linkDB->linksCountPerTag(); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertTrue($tags[$tagName] > 0); $env = Environment::mock([ 'REQUEST_METHOD' => 'DELETE', @@ -133,8 +136,8 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase $this->assertEquals(204, $response->getStatusCode()); $this->assertEmpty((string) $response->getBody()); - $this->linkDB = new LinkDB(self::$testDatastore, true, false); - $tags = $this->linkDB->linksCountPerTag(); + $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertFalse(isset($tags[$tagName])); $this->assertTrue($tags[strtolower($tagName)] > 0); @@ -154,7 +157,7 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase public function testDeleteLink404() { $tagName = 'nopenope'; - $tags = $this->linkDB->linksCountPerTag(); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertFalse(isset($tags[$tagName])); $env = Environment::mock([ 'REQUEST_METHOD' => 'DELETE', diff --git a/tests/api/controllers/tags/GetTagNameTest.php b/tests/api/controllers/tags/GetTagNameTest.php index a2525c17..b9a81f9b 100644 --- a/tests/api/controllers/tags/GetTagNameTest.php +++ b/tests/api/controllers/tags/GetTagNameTest.php @@ -2,8 +2,10 @@ namespace Shaarli\Api\Controllers; +use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Bookmark\LinkDB; use Shaarli\Config\ConfigManager; +use Shaarli\History; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -49,17 +51,19 @@ class GetTagNameTest extends \PHPUnit\Framework\TestCase const NB_FIELDS_TAG = 2; /** - * Before each test, instantiate a new Api with its config, plugins and links. + * Before each test, instantiate a new Api with its config, plugins and bookmarks. */ public function setUp() { $this->conf = new ConfigManager('tests/utils/config/configJson'); + $this->conf->set('resource.datastore', self::$testDatastore); $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); + $history = new History('sandbox/history.php'); $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = new LinkDB(self::$testDatastore, true, false); + $this->container['db'] = new BookmarkFileService($this->conf, $history, true); $this->container['history'] = null; $this->controller = new Tags($this->container); diff --git a/tests/api/controllers/tags/GetTagsTest.php b/tests/api/controllers/tags/GetTagsTest.php index 98628c98..53a3326d 100644 --- a/tests/api/controllers/tags/GetTagsTest.php +++ b/tests/api/controllers/tags/GetTagsTest.php @@ -1,8 +1,10 @@ conf = new ConfigManager('tests/utils/config/configJson'); + $this->conf->set('resource.datastore', self::$testDatastore); $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); + $history = new History('sandbox/history.php'); + + $this->bookmarkService = new BookmarkFileService($this->conf, $history, true); $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->linkDB = new LinkDB(self::$testDatastore, true, false); - $this->container['db'] = $this->linkDB; + $this->container['db'] = $this->bookmarkService; $this->container['history'] = null; $this->controller = new Tags($this->container); @@ -83,7 +88,7 @@ class GetTagsTest extends \PHPUnit\Framework\TestCase */ public function testGetTagsAll() { - $tags = $this->linkDB->linksCountPerTag(); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $env = Environment::mock([ 'REQUEST_METHOD' => 'GET', ]); @@ -136,7 +141,7 @@ class GetTagsTest extends \PHPUnit\Framework\TestCase */ public function testGetTagsLimitAll() { - $tags = $this->linkDB->linksCountPerTag(); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $env = Environment::mock([ 'REQUEST_METHOD' => 'GET', 'QUERY_STRING' => 'limit=all' @@ -170,7 +175,7 @@ class GetTagsTest extends \PHPUnit\Framework\TestCase */ public function testGetTagsVisibilityPrivate() { - $tags = $this->linkDB->linksCountPerTag([], 'private'); + $tags = $this->bookmarkService->bookmarksCountPerTag([], 'private'); $env = Environment::mock([ 'REQUEST_METHOD' => 'GET', 'QUERY_STRING' => 'visibility=private' @@ -190,7 +195,7 @@ class GetTagsTest extends \PHPUnit\Framework\TestCase */ public function testGetTagsVisibilityPublic() { - $tags = $this->linkDB->linksCountPerTag([], 'public'); + $tags = $this->bookmarkService->bookmarksCountPerTag([], 'public'); $env = Environment::mock( [ 'REQUEST_METHOD' => 'GET', diff --git a/tests/api/controllers/tags/PutTagTest.php b/tests/api/controllers/tags/PutTagTest.php index 86106fc7..2a3cc15a 100644 --- a/tests/api/controllers/tags/PutTagTest.php +++ b/tests/api/controllers/tags/PutTagTest.php @@ -3,6 +3,7 @@ namespace Shaarli\Api\Controllers; use Shaarli\Api\Exceptions\ApiBadParametersException; +use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Bookmark\LinkDB; use Shaarli\Config\ConfigManager; use Shaarli\History; @@ -44,9 +45,9 @@ class PutTagTest extends \PHPUnit\Framework\TestCase protected $container; /** - * @var LinkDB instance. + * @var BookmarkFileService instance. */ - protected $linkDB; + protected $bookmarkService; /** * @var Tags controller instance. @@ -59,22 +60,22 @@ class PutTagTest extends \PHPUnit\Framework\TestCase const NB_FIELDS_TAG = 2; /** - * Before every test, instantiate a new Api with its config, plugins and links. + * Before every test, instantiate a new Api with its config, plugins and bookmarks. */ public function setUp() { - $this->conf = new ConfigManager('tests/utils/config/configJson.json.php'); + $this->conf = new ConfigManager('tests/utils/config/configJson'); + $this->conf->set('resource.datastore', self::$testDatastore); $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); - $refHistory = new \ReferenceHistory(); $refHistory->write(self::$testHistory); $this->history = new History(self::$testHistory); + $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->linkDB = new LinkDB(self::$testDatastore, true, false); - $this->container['db'] = $this->linkDB; + $this->container['db'] = $this->bookmarkService; $this->container['history'] = $this->history; $this->controller = new Tags($this->container); @@ -109,7 +110,7 @@ class PutTagTest extends \PHPUnit\Framework\TestCase $this->assertEquals($newName, $data['name']); $this->assertEquals(2, $data['occurrences']); - $tags = $this->linkDB->linksCountPerTag(); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertNotTrue(isset($tags[$tagName])); $this->assertEquals(2, $tags[$newName]); @@ -133,7 +134,7 @@ class PutTagTest extends \PHPUnit\Framework\TestCase $tagName = 'gnu'; $newName = 'w3c'; - $tags = $this->linkDB->linksCountPerTag(); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertEquals(1, $tags[$newName]); $this->assertEquals(2, $tags[$tagName]); @@ -151,7 +152,7 @@ class PutTagTest extends \PHPUnit\Framework\TestCase $this->assertEquals($newName, $data['name']); $this->assertEquals(3, $data['occurrences']); - $tags = $this->linkDB->linksCountPerTag(); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertNotTrue(isset($tags[$tagName])); $this->assertEquals(3, $tags[$newName]); } @@ -167,7 +168,7 @@ class PutTagTest extends \PHPUnit\Framework\TestCase $tagName = 'gnu'; $newName = ''; - $tags = $this->linkDB->linksCountPerTag(); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertEquals(2, $tags[$tagName]); $env = Environment::mock([ @@ -185,7 +186,7 @@ class PutTagTest extends \PHPUnit\Framework\TestCase try { $this->controller->putTag($request, new Response(), ['tagName' => $tagName]); } catch (ApiBadParametersException $e) { - $tags = $this->linkDB->linksCountPerTag(); + $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertEquals(2, $tags[$tagName]); throw $e; } diff --git a/tests/bookmark/BookmarkArrayTest.php b/tests/bookmark/BookmarkArrayTest.php new file mode 100644 index 00000000..0f8f04c5 --- /dev/null +++ b/tests/bookmark/BookmarkArrayTest.php @@ -0,0 +1,239 @@ +assertTrue(is_iterable($array)); + $this->assertEmpty($array); + } + + /** + * Test adding entries to the array, specifying the key offset or not. + */ + public function testArrayAccessAddEntries() + { + $array = new BookmarkArray(); + $bookmark = new Bookmark(); + $bookmark->setId(11)->validate(); + $array[] = $bookmark; + $this->assertCount(1, $array); + $this->assertTrue(isset($array[11])); + $this->assertNull($array[0]); + $this->assertEquals($bookmark, $array[11]); + + $bookmark = new Bookmark(); + $bookmark->setId(14)->validate(); + $array[14] = $bookmark; + $this->assertCount(2, $array); + $this->assertTrue(isset($array[14])); + $this->assertNull($array[0]); + $this->assertEquals($bookmark, $array[14]); + } + + /** + * Test adding a bad entry: wrong type + * + * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException + */ + public function testArrayAccessAddBadEntryInstance() + { + $array = new BookmarkArray(); + $array[] = 'nope'; + } + + /** + * Test adding a bad entry: no id + * + * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException + */ + public function testArrayAccessAddBadEntryNoId() + { + $array = new BookmarkArray(); + $bookmark = new Bookmark(); + $array[] = $bookmark; + } + + /** + * Test adding a bad entry: no url + * + * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException + */ + public function testArrayAccessAddBadEntryNoUrl() + { + $array = new BookmarkArray(); + $bookmark = (new Bookmark())->setId(11); + $array[] = $bookmark; + } + + /** + * Test adding a bad entry: invalid offset + * + * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException + */ + public function testArrayAccessAddBadEntryOffset() + { + $array = new BookmarkArray(); + $bookmark = (new Bookmark())->setId(11); + $bookmark->validate(); + $array['nope'] = $bookmark; + } + + /** + * Test adding a bad entry: invalid ID type + * + * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException + */ + public function testArrayAccessAddBadEntryIdType() + { + $array = new BookmarkArray(); + $bookmark = (new Bookmark())->setId('nope'); + $bookmark->validate(); + $array[] = $bookmark; + } + + /** + * Test adding a bad entry: ID/offset not consistent + * + * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException + */ + public function testArrayAccessAddBadEntryIdOffset() + { + $array = new BookmarkArray(); + $bookmark = (new Bookmark())->setId(11); + $bookmark->validate(); + $array[14] = $bookmark; + } + + /** + * Test update entries through array access. + */ + public function testArrayAccessUpdateEntries() + { + $array = new BookmarkArray(); + $bookmark = new Bookmark(); + $bookmark->setId(11)->validate(); + $bookmark->setTitle('old'); + $array[] = $bookmark; + $bookmark = new Bookmark(); + $bookmark->setId(11)->validate(); + $bookmark->setTitle('test'); + $array[] = $bookmark; + $this->assertCount(1, $array); + $this->assertEquals('test', $array[11]->getTitle()); + + $bookmark = new Bookmark(); + $bookmark->setId(11)->validate(); + $bookmark->setTitle('test2'); + $array[11] = $bookmark; + $this->assertCount(1, $array); + $this->assertEquals('test2', $array[11]->getTitle()); + } + + /** + * Test delete entries through array access. + */ + public function testArrayAccessDeleteEntries() + { + $array = new BookmarkArray(); + $bookmark11 = new Bookmark(); + $bookmark11->setId(11)->validate(); + $array[] = $bookmark11; + $bookmark14 = new Bookmark(); + $bookmark14->setId(14)->validate(); + $array[] = $bookmark14; + $bookmark23 = new Bookmark(); + $bookmark23->setId(23)->validate(); + $array[] = $bookmark23; + $bookmark0 = new Bookmark(); + $bookmark0->setId(0)->validate(); + $array[] = $bookmark0; + $this->assertCount(4, $array); + + unset($array[14]); + $this->assertCount(3, $array); + $this->assertEquals($bookmark11, $array[11]); + $this->assertEquals($bookmark23, $array[23]); + $this->assertEquals($bookmark0, $array[0]); + + unset($array[23]); + $this->assertCount(2, $array); + $this->assertEquals($bookmark11, $array[11]); + $this->assertEquals($bookmark0, $array[0]); + + unset($array[11]); + $this->assertCount(1, $array); + $this->assertEquals($bookmark0, $array[0]); + + unset($array[0]); + $this->assertCount(0, $array); + } + + /** + * Test iterating through array access. + */ + public function testArrayAccessIterate() + { + $array = new BookmarkArray(); + $bookmark11 = new Bookmark(); + $bookmark11->setId(11)->validate(); + $array[] = $bookmark11; + $bookmark14 = new Bookmark(); + $bookmark14->setId(14)->validate(); + $array[] = $bookmark14; + $bookmark23 = new Bookmark(); + $bookmark23->setId(23)->validate(); + $array[] = $bookmark23; + $this->assertCount(3, $array); + + foreach ($array as $id => $bookmark) { + $this->assertEquals(${'bookmark'. $id}, $bookmark); + } + } + + /** + * Test reordering the array. + */ + public function testReorder() + { + $refDB = new \ReferenceLinkDB(); + $refDB->write('sandbox/datastore.php'); + + + $bookmarks = $refDB->getLinks(); + $bookmarks->reorder('ASC'); + $this->assertInstanceOf(BookmarkArray::class, $bookmarks); + + $stickyIds = [11, 10]; + $standardIds = [42, 4, 9, 1, 0, 7, 6, 8, 41]; + $linkIds = array_merge($stickyIds, $standardIds); + $cpt = 0; + foreach ($bookmarks as $key => $value) { + $this->assertEquals($linkIds[$cpt++], $key); + } + + $bookmarks = $refDB->getLinks(); + $bookmarks->reorder('DESC'); + $this->assertInstanceOf(BookmarkArray::class, $bookmarks); + + $linkIds = array_merge(array_reverse($stickyIds), array_reverse($standardIds)); + $cpt = 0; + foreach ($bookmarks as $key => $value) { + $this->assertEquals($linkIds[$cpt++], $key); + } + } +} diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php new file mode 100644 index 00000000..1b438a7f --- /dev/null +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -0,0 +1,1042 @@ +conf = new ConfigManager(self::$testConf); + $this->conf->set('resource.datastore', self::$testDatastore); + $this->conf->set('resource.updates', self::$testUpdates); + $this->refDB = new \ReferenceLinkDB(); + $this->refDB->write(self::$testDatastore); + $this->history = new History('sandbox/history.php'); + $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, false); + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + } + + /** + * Test migrate() method with a legacy datastore. + */ + public function testDatabaseMigration() + { + if (!defined('SHAARLI_VERSION')) { + define('SHAARLI_VERSION', 'dev'); + } + + $this->refDB = new \ReferenceLinkDB(true); + $this->refDB->write(self::$testDatastore); + $db = self::getMethod('migrate'); + $db->invokeArgs($this->privateLinkDB, []); + + $db = new \FakeBookmarkService($this->conf, $this->history, true); + $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); + $this->assertEquals($this->refDB->countLinks(), $db->count()); + } + + /** + * Test get() method for a defined and saved bookmark + */ + public function testGetDefinedSaved() + { + $bookmark = $this->privateLinkDB->get(42); + $this->assertEquals(42, $bookmark->getId()); + $this->assertEquals('Note: I have a big ID but an old date', $bookmark->getTitle()); + } + + /** + * Test get() method for a defined and not saved bookmark + */ + public function testGetDefinedNotSaved() + { + $bookmark = new Bookmark(); + $this->privateLinkDB->add($bookmark); + $createdBookmark = $this->privateLinkDB->get(43); + $this->assertEquals(43, $createdBookmark->getId()); + $this->assertEmpty($createdBookmark->getDescription()); + } + + /** + * Test get() method for an undefined bookmark + * + * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testGetUndefined() + { + $this->privateLinkDB->get(666); + } + + /** + * Test add() method for a bookmark fully built + */ + public function testAddFull() + { + $bookmark = new Bookmark(); + $bookmark->setUrl($url = 'https://domain.tld/index.php'); + $bookmark->setShortUrl('abc'); + $bookmark->setTitle($title = 'This a brand new bookmark'); + $bookmark->setDescription($desc = 'It should be created and written'); + $bookmark->setTags($tags = ['tag1', 'tagssss']); + $bookmark->setThumbnail($thumb = 'http://thumb.tld/dle.png'); + $bookmark->setPrivate(true); + $bookmark->setSticky(true); + $bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190518_140354')); + $bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190518_150354')); + + $this->privateLinkDB->add($bookmark); + $bookmark = $this->privateLinkDB->get(43); + $this->assertEquals(43, $bookmark->getId()); + $this->assertEquals($url, $bookmark->getUrl()); + $this->assertEquals('abc', $bookmark->getShortUrl()); + $this->assertEquals($title, $bookmark->getTitle()); + $this->assertEquals($desc, $bookmark->getDescription()); + $this->assertEquals($tags, $bookmark->getTags()); + $this->assertEquals($thumb, $bookmark->getThumbnail()); + $this->assertTrue($bookmark->isPrivate()); + $this->assertTrue($bookmark->isSticky()); + $this->assertEquals($created, $bookmark->getCreated()); + $this->assertEquals($updated, $bookmark->getUpdated()); + + // reload from file + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + + $bookmark = $this->privateLinkDB->get(43); + $this->assertEquals(43, $bookmark->getId()); + $this->assertEquals($url, $bookmark->getUrl()); + $this->assertEquals('abc', $bookmark->getShortUrl()); + $this->assertEquals($title, $bookmark->getTitle()); + $this->assertEquals($desc, $bookmark->getDescription()); + $this->assertEquals($tags, $bookmark->getTags()); + $this->assertEquals($thumb, $bookmark->getThumbnail()); + $this->assertTrue($bookmark->isPrivate()); + $this->assertTrue($bookmark->isSticky()); + $this->assertEquals($created, $bookmark->getCreated()); + $this->assertEquals($updated, $bookmark->getUpdated()); + } + + /** + * Test add() method for a bookmark without any field set + */ + public function testAddMinimal() + { + $bookmark = new Bookmark(); + $this->privateLinkDB->add($bookmark); + + $bookmark = $this->privateLinkDB->get(43); + $this->assertEquals(43, $bookmark->getId()); + $this->assertRegExp('/\?[\w\-]{6}/', $bookmark->getUrl()); + $this->assertRegExp('/[\w\-]{6}/', $bookmark->getShortUrl()); + $this->assertEquals($bookmark->getUrl(), $bookmark->getTitle()); + $this->assertEmpty($bookmark->getDescription()); + $this->assertEmpty($bookmark->getTags()); + $this->assertEmpty($bookmark->getThumbnail()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertFalse($bookmark->isSticky()); + $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getCreated()); + $this->assertNull($bookmark->getUpdated()); + + // reload from file + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + + $bookmark = $this->privateLinkDB->get(43); + $this->assertEquals(43, $bookmark->getId()); + $this->assertRegExp('/\?[\w\-]{6}/', $bookmark->getUrl()); + $this->assertRegExp('/[\w\-]{6}/', $bookmark->getShortUrl()); + $this->assertEquals($bookmark->getUrl(), $bookmark->getTitle()); + $this->assertEmpty($bookmark->getDescription()); + $this->assertEmpty($bookmark->getTags()); + $this->assertEmpty($bookmark->getThumbnail()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertFalse($bookmark->isSticky()); + $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getCreated()); + $this->assertNull($bookmark->getUpdated()); + } + + /** + * Test add() method for a bookmark without any field set and without writing the data store + * + * @expectedExceptionMessage Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testAddMinimalNoWrite() + { + $bookmark = new Bookmark(); + $this->privateLinkDB->add($bookmark); + + $bookmark = $this->privateLinkDB->get(43); + $this->assertEquals(43, $bookmark->getId()); + + // reload from file + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + + $this->privateLinkDB->get(43); + } + + /** + * Test add() method while logged out + * + * @expectedException \Exception + * @expectedExceptionMessage You're not authorized to alter the datastore + */ + public function testAddLoggedOut() + { + $this->publicLinkDB->add(new Bookmark()); + } + + /** + * Test add() method with an entry which is not a bookmark instance + * + * @expectedException \Exception + * @expectedExceptionMessage Provided data is invalid + */ + public function testAddNotABookmark() + { + $this->privateLinkDB->add(['title' => 'hi!']); + } + + /** + * Test add() method with a Bookmark already containing an ID + * + * @expectedException \Exception + * @expectedExceptionMessage This bookmarks already exists + */ + public function testAddWithId() + { + $bookmark = new Bookmark(); + $bookmark->setId(43); + $this->privateLinkDB->add($bookmark); + } + + /** + * Test set() method for a bookmark fully built + */ + public function testSetFull() + { + $bookmark = $this->privateLinkDB->get(42); + $bookmark->setUrl($url = 'https://domain.tld/index.php'); + $bookmark->setShortUrl('abc'); + $bookmark->setTitle($title = 'This a brand new bookmark'); + $bookmark->setDescription($desc = 'It should be created and written'); + $bookmark->setTags($tags = ['tag1', 'tagssss']); + $bookmark->setThumbnail($thumb = 'http://thumb.tld/dle.png'); + $bookmark->setPrivate(true); + $bookmark->setSticky(true); + $bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190518_140354')); + $bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190518_150354')); + + $this->privateLinkDB->set($bookmark); + $bookmark = $this->privateLinkDB->get(42); + $this->assertEquals(42, $bookmark->getId()); + $this->assertEquals($url, $bookmark->getUrl()); + $this->assertEquals('abc', $bookmark->getShortUrl()); + $this->assertEquals($title, $bookmark->getTitle()); + $this->assertEquals($desc, $bookmark->getDescription()); + $this->assertEquals($tags, $bookmark->getTags()); + $this->assertEquals($thumb, $bookmark->getThumbnail()); + $this->assertTrue($bookmark->isPrivate()); + $this->assertTrue($bookmark->isSticky()); + $this->assertEquals($created, $bookmark->getCreated()); + $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); + + // reload from file + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + + $bookmark = $this->privateLinkDB->get(42); + $this->assertEquals(42, $bookmark->getId()); + $this->assertEquals($url, $bookmark->getUrl()); + $this->assertEquals('abc', $bookmark->getShortUrl()); + $this->assertEquals($title, $bookmark->getTitle()); + $this->assertEquals($desc, $bookmark->getDescription()); + $this->assertEquals($tags, $bookmark->getTags()); + $this->assertEquals($thumb, $bookmark->getThumbnail()); + $this->assertTrue($bookmark->isPrivate()); + $this->assertTrue($bookmark->isSticky()); + $this->assertEquals($created, $bookmark->getCreated()); + $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); + } + + /** + * Test set() method for a bookmark without any field set + */ + public function testSetMinimal() + { + $bookmark = $this->privateLinkDB->get(42); + $this->privateLinkDB->set($bookmark); + + $bookmark = $this->privateLinkDB->get(42); + $this->assertEquals(42, $bookmark->getId()); + $this->assertEquals('?WDWyig', $bookmark->getUrl()); + $this->assertEquals('1eYJ1Q', $bookmark->getShortUrl()); + $this->assertEquals('Note: I have a big ID but an old date', $bookmark->getTitle()); + $this->assertEquals('Used to test bookmarks reordering.', $bookmark->getDescription()); + $this->assertEquals(['ut'], $bookmark->getTags()); + $this->assertFalse($bookmark->getThumbnail()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertFalse($bookmark->isSticky()); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20100310_101010'), + $bookmark->getCreated() + ); + $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); + + // reload from file + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + + $bookmark = $this->privateLinkDB->get(42); + $this->assertEquals(42, $bookmark->getId()); + $this->assertEquals('?WDWyig', $bookmark->getUrl()); + $this->assertEquals('1eYJ1Q', $bookmark->getShortUrl()); + $this->assertEquals('Note: I have a big ID but an old date', $bookmark->getTitle()); + $this->assertEquals('Used to test bookmarks reordering.', $bookmark->getDescription()); + $this->assertEquals(['ut'], $bookmark->getTags()); + $this->assertFalse($bookmark->getThumbnail()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertFalse($bookmark->isSticky()); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20100310_101010'), + $bookmark->getCreated() + ); + $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); + } + + /** + * Test set() method for a bookmark without any field set and without writing the data store + */ + public function testSetMinimalNoWrite() + { + $bookmark = $this->privateLinkDB->get(42); + $bookmark->setTitle($title = 'hi!'); + $this->privateLinkDB->set($bookmark, false); + + $bookmark = $this->privateLinkDB->get(42); + $this->assertEquals(42, $bookmark->getId()); + $this->assertEquals($title, $bookmark->getTitle()); + + // reload from file + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + + $bookmark = $this->privateLinkDB->get(42); + $this->assertEquals(42, $bookmark->getId()); + $this->assertEquals('Note: I have a big ID but an old date', $bookmark->getTitle()); + } + + /** + * Test set() method while logged out + * + * @expectedException \Exception + * @expectedExceptionMessage You're not authorized to alter the datastore + */ + public function testSetLoggedOut() + { + $this->publicLinkDB->set(new Bookmark()); + } + + /** + * Test set() method with an entry which is not a bookmark instance + * + * @expectedException \Exception + * @expectedExceptionMessage Provided data is invalid + */ + public function testSetNotABookmark() + { + $this->privateLinkDB->set(['title' => 'hi!']); + } + + /** + * Test set() method with a Bookmark without an ID defined. + * + * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testSetWithoutId() + { + $bookmark = new Bookmark(); + $this->privateLinkDB->set($bookmark); + } + + /** + * Test set() method with a Bookmark with an unknow ID + * + * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testSetWithUnknownId() + { + $bookmark = new Bookmark(); + $bookmark->setId(666); + $this->privateLinkDB->set($bookmark); + } + + /** + * Test addOrSet() method with a new ID + */ + public function testAddOrSetNew() + { + $bookmark = new Bookmark(); + $this->privateLinkDB->addOrSet($bookmark); + + $bookmark = $this->privateLinkDB->get(43); + $this->assertEquals(43, $bookmark->getId()); + + // reload from file + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + + $bookmark = $this->privateLinkDB->get(43); + $this->assertEquals(43, $bookmark->getId()); + } + + /** + * Test addOrSet() method with an existing ID + */ + public function testAddOrSetExisting() + { + $bookmark = $this->privateLinkDB->get(42); + $bookmark->setTitle($title = 'hi!'); + $this->privateLinkDB->addOrSet($bookmark); + + $bookmark = $this->privateLinkDB->get(42); + $this->assertEquals(42, $bookmark->getId()); + $this->assertEquals($title, $bookmark->getTitle()); + + // reload from file + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + + $bookmark = $this->privateLinkDB->get(42); + $this->assertEquals(42, $bookmark->getId()); + $this->assertEquals($title, $bookmark->getTitle()); + } + + /** + * Test addOrSet() method while logged out + * + * @expectedException \Exception + * @expectedExceptionMessage You're not authorized to alter the datastore + */ + public function testAddOrSetLoggedOut() + { + $this->publicLinkDB->addOrSet(new Bookmark()); + } + + /** + * Test addOrSet() method with an entry which is not a bookmark instance + * + * @expectedException \Exception + * @expectedExceptionMessage Provided data is invalid + */ + public function testAddOrSetNotABookmark() + { + $this->privateLinkDB->addOrSet(['title' => 'hi!']); + } + + /** + * Test addOrSet() method for a bookmark without any field set and without writing the data store + */ + public function testAddOrSetMinimalNoWrite() + { + $bookmark = $this->privateLinkDB->get(42); + $bookmark->setTitle($title = 'hi!'); + $this->privateLinkDB->addOrSet($bookmark, false); + + $bookmark = $this->privateLinkDB->get(42); + $this->assertEquals(42, $bookmark->getId()); + $this->assertEquals($title, $bookmark->getTitle()); + + // reload from file + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + + $bookmark = $this->privateLinkDB->get(42); + $this->assertEquals(42, $bookmark->getId()); + $this->assertEquals('Note: I have a big ID but an old date', $bookmark->getTitle()); + } + + /** + * Test remove() method with an existing Bookmark + * + * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testRemoveExisting() + { + $bookmark = $this->privateLinkDB->get(42); + $this->privateLinkDB->remove($bookmark); + + $exception = null; + try { + $this->privateLinkDB->get(42); + } catch (BookmarkNotFoundException $e) { + $exception = $e; + } + $this->assertInstanceOf(BookmarkNotFoundException::class, $exception); + + // reload from file + $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); + + $this->privateLinkDB->get(42); + } + + /** + * Test remove() method while logged out + * + * @expectedException \Exception + * @expectedExceptionMessage You're not authorized to alter the datastore + */ + public function testRemoveLoggedOut() + { + $bookmark = $this->privateLinkDB->get(42); + $this->publicLinkDB->remove($bookmark); + } + + /** + * Test remove() method with an entry which is not a bookmark instance + * + * @expectedException \Exception + * @expectedExceptionMessage Provided data is invalid + */ + public function testRemoveNotABookmark() + { + $this->privateLinkDB->remove(['title' => 'hi!']); + } + + /** + * Test remove() method with a Bookmark with an unknown ID + * + * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testRemoveWithUnknownId() + { + $bookmark = new Bookmark(); + $bookmark->setId(666); + $this->privateLinkDB->remove($bookmark); + } + + /** + * Test exists() method + */ + public function testExists() + { + $this->assertTrue($this->privateLinkDB->exists(42)); // public + $this->assertTrue($this->privateLinkDB->exists(6)); // private + + $this->assertTrue($this->privateLinkDB->exists(42, BookmarkFilter::$ALL)); + $this->assertTrue($this->privateLinkDB->exists(6, BookmarkFilter::$ALL)); + + $this->assertTrue($this->privateLinkDB->exists(42, BookmarkFilter::$PUBLIC)); + $this->assertFalse($this->privateLinkDB->exists(6, BookmarkFilter::$PUBLIC)); + + $this->assertFalse($this->privateLinkDB->exists(42, BookmarkFilter::$PRIVATE)); + $this->assertTrue($this->privateLinkDB->exists(6, BookmarkFilter::$PRIVATE)); + + $this->assertTrue($this->publicLinkDB->exists(42)); + $this->assertFalse($this->publicLinkDB->exists(6)); + + $this->assertTrue($this->publicLinkDB->exists(42, BookmarkFilter::$PUBLIC)); + $this->assertFalse($this->publicLinkDB->exists(6, BookmarkFilter::$PUBLIC)); + + $this->assertFalse($this->publicLinkDB->exists(42, BookmarkFilter::$PRIVATE)); + $this->assertTrue($this->publicLinkDB->exists(6, BookmarkFilter::$PRIVATE)); + } + + /** + * Test initialize() method + */ + public function testInitialize() + { + $dbSize = $this->privateLinkDB->count(); + $this->privateLinkDB->initialize(); + $this->assertEquals($dbSize + 2, $this->privateLinkDB->count()); + $this->assertEquals( + 'My secret stuff... - Pastebin.com', + $this->privateLinkDB->get(43)->getTitle() + ); + $this->assertEquals( + 'The personal, minimalist, super-fast, database free, bookmarking service', + $this->privateLinkDB->get(44)->getTitle() + ); + } + + /* + * The following tests have been taken from the legacy LinkDB test and adapted + * to make sure that nothing have been broken in the migration process. + * They mostly cover search/filters. Some of them might be redundant with the previous ones. + */ + + /** + * Attempt to instantiate a LinkDB whereas the datastore is not writable + * + * @expectedException Shaarli\Bookmark\Exception\NotWritableDataStoreException + * @expectedExceptionMessageRegExp #Couldn't load data from the data store file "null".*# + */ + public function testConstructDatastoreNotWriteable() + { + $conf = new ConfigManager('tests/utils/config/configJson'); + $conf->set('resource.datastore', 'null/store.db'); + new BookmarkFileService($conf, $this->history, true); + } + + /** + * The DB doesn't exist, ensure it is created with an empty datastore + */ + public function testCheckDBNewLoggedIn() + { + unlink(self::$testDatastore); + $this->assertFileNotExists(self::$testDatastore); + new BookmarkFileService($this->conf, $this->history, true); + $this->assertFileExists(self::$testDatastore); + + // ensure the correct data has been written + $this->assertGreaterThan(0, filesize(self::$testDatastore)); + } + + /** + * The DB doesn't exist, but not logged in, ensure it initialized, but the file is not written + */ + public function testCheckDBNewLoggedOut() + { + unlink(self::$testDatastore); + $this->assertFileNotExists(self::$testDatastore); + $db = new \FakeBookmarkService($this->conf, $this->history, false); + $this->assertFileNotExists(self::$testDatastore); + $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); + $this->assertCount(0, $db->getBookmarks()); + } + + /** + * Load public bookmarks from the DB + */ + public function testReadPublicDB() + { + $this->assertEquals( + $this->refDB->countPublicLinks(), + $this->publicLinkDB->count() + ); + } + + /** + * Load public and private bookmarks from the DB + */ + public function testReadPrivateDB() + { + $this->assertEquals( + $this->refDB->countLinks(), + $this->privateLinkDB->count() + ); + } + + /** + * Save the bookmarks to the DB + */ + public function testSave() + { + $testDB = new BookmarkFileService($this->conf, $this->history, true); + $dbSize = $testDB->count(); + + $bookmark = new Bookmark(); + $testDB->add($bookmark); + + $testDB = new BookmarkFileService($this->conf, $this->history, true); + $this->assertEquals($dbSize + 1, $testDB->count()); + } + + /** + * Count existing bookmarks - public bookmarks hidden + */ + public function testCountHiddenPublic() + { + $this->conf->set('privacy.hide_public_links', true); + $linkDB = new BookmarkFileService($this->conf, $this->history, false); + + $this->assertEquals(0, $linkDB->count()); + } + + /** + * List the days for which bookmarks have been posted + */ + public function testDays() + { + $this->assertEquals( + ['20100309', '20100310', '20121206', '20121207', '20130614', '20150310'], + $this->publicLinkDB->days() + ); + + $this->assertEquals( + ['20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'], + $this->privateLinkDB->days() + ); + } + + /** + * The URL corresponds to an existing entry in the DB + */ + public function testGetKnownLinkFromURL() + { + $link = $this->publicLinkDB->findByUrl('http://mediagoblin.org/'); + + $this->assertNotEquals(false, $link); + $this->assertContains( + 'A free software media publishing platform', + $link->getDescription() + ); + } + + /** + * The URL is not in the DB + */ + public function testGetUnknownLinkFromURL() + { + $this->assertEquals( + false, + $this->publicLinkDB->findByUrl('http://dev.null') + ); + } + + /** + * Lists all tags + */ + public function testAllTags() + { + $this->assertEquals( + [ + 'web' => 3, + 'cartoon' => 2, + 'gnu' => 2, + 'dev' => 1, + 'samba' => 1, + 'media' => 1, + 'software' => 1, + 'stallman' => 1, + 'free' => 1, + '-exclude' => 1, + 'hashtag' => 2, + // The DB contains a link with `sTuff` and another one with `stuff` tag. + // They need to be grouped with the first case found - order by date DESC: `sTuff`. + 'sTuff' => 2, + 'ut' => 1, + ], + $this->publicLinkDB->bookmarksCountPerTag() + ); + + $this->assertEquals( + [ + 'web' => 4, + 'cartoon' => 3, + 'gnu' => 2, + 'dev' => 2, + 'samba' => 1, + 'media' => 1, + 'software' => 1, + 'stallman' => 1, + 'free' => 1, + 'html' => 1, + 'w3c' => 1, + 'css' => 1, + 'Mercurial' => 1, + 'sTuff' => 2, + '-exclude' => 1, + '.hidden' => 1, + 'hashtag' => 2, + 'tag1' => 1, + 'tag2' => 1, + 'tag3' => 1, + 'tag4' => 1, + 'ut' => 1, + ], + $this->privateLinkDB->bookmarksCountPerTag() + ); + $this->assertEquals( + [ + 'web' => 4, + 'cartoon' => 2, + 'gnu' => 1, + 'dev' => 1, + 'samba' => 1, + 'media' => 1, + 'html' => 1, + 'w3c' => 1, + 'css' => 1, + 'Mercurial' => 1, + '.hidden' => 1, + 'hashtag' => 1, + ], + $this->privateLinkDB->bookmarksCountPerTag(['web']) + ); + $this->assertEquals( + [ + 'web' => 1, + 'html' => 1, + 'w3c' => 1, + 'css' => 1, + 'Mercurial' => 1, + ], + $this->privateLinkDB->bookmarksCountPerTag(['web'], 'private') + ); + } + + /** + * Test filter with string. + */ + public function testFilterString() + { + $tags = 'dev cartoon'; + $request = ['searchtags' => $tags]; + $this->assertEquals( + 2, + count($this->privateLinkDB->search($request, null, true)) + ); + } + + /** + * Test filter with array. + */ + public function testFilterArray() + { + $tags = ['dev', 'cartoon']; + $request = ['searchtags' => $tags]; + $this->assertEquals( + 2, + count($this->privateLinkDB->search($request, null, true)) + ); + } + + /** + * Test hidden tags feature: + * tags starting with a dot '.' are only visible when logged in. + */ + public function testHiddenTags() + { + $tags = '.hidden'; + $request = ['searchtags' => $tags]; + $this->assertEquals( + 1, + count($this->privateLinkDB->search($request, 'all', true)) + ); + + $this->assertEquals( + 0, + count($this->publicLinkDB->search($request, 'public', true)) + ); + } + + /** + * Test filterHash() with a valid smallhash. + */ + public function testFilterHashValid() + { + $request = smallHash('20150310_114651'); + $this->assertEquals( + 1, + count($this->publicLinkDB->findByHash($request)) + ); + $request = smallHash('20150310_114633' . 8); + $this->assertEquals( + 1, + count($this->publicLinkDB->findByHash($request)) + ); + } + + /** + * Test filterHash() with an invalid smallhash. + * + * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testFilterHashInValid1() + { + $request = 'blabla'; + $this->publicLinkDB->findByHash($request); + } + + /** + * Test filterHash() with an empty smallhash. + * + * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testFilterHashInValid() + { + $this->publicLinkDB->findByHash(''); + } + + /** + * Test linksCountPerTag all tags without filter. + * Equal occurrences should be sorted alphabetically. + */ + public function testCountLinkPerTagAllNoFilter() + { + $expected = [ + 'web' => 4, + 'cartoon' => 3, + 'dev' => 2, + 'gnu' => 2, + 'hashtag' => 2, + 'sTuff' => 2, + '-exclude' => 1, + '.hidden' => 1, + 'Mercurial' => 1, + 'css' => 1, + 'free' => 1, + 'html' => 1, + 'media' => 1, + 'samba' => 1, + 'software' => 1, + 'stallman' => 1, + 'tag1' => 1, + 'tag2' => 1, + 'tag3' => 1, + 'tag4' => 1, + 'ut' => 1, + 'w3c' => 1, + ]; + $tags = $this->privateLinkDB->bookmarksCountPerTag(); + + $this->assertEquals($expected, $tags, var_export($tags, true)); + } + + /** + * Test linksCountPerTag all tags with filter. + * Equal occurrences should be sorted alphabetically. + */ + public function testCountLinkPerTagAllWithFilter() + { + $expected = [ + 'gnu' => 2, + 'hashtag' => 2, + '-exclude' => 1, + '.hidden' => 1, + 'free' => 1, + 'media' => 1, + 'software' => 1, + 'stallman' => 1, + 'stuff' => 1, + 'web' => 1, + ]; + $tags = $this->privateLinkDB->bookmarksCountPerTag(['gnu']); + + $this->assertEquals($expected, $tags, var_export($tags, true)); + } + + /** + * Test linksCountPerTag public tags with filter. + * Equal occurrences should be sorted alphabetically. + */ + public function testCountLinkPerTagPublicWithFilter() + { + $expected = [ + 'gnu' => 2, + 'hashtag' => 2, + '-exclude' => 1, + '.hidden' => 1, + 'free' => 1, + 'media' => 1, + 'software' => 1, + 'stallman' => 1, + 'stuff' => 1, + 'web' => 1, + ]; + $tags = $this->privateLinkDB->bookmarksCountPerTag(['gnu'], 'public'); + + $this->assertEquals($expected, $tags, var_export($tags, true)); + } + + /** + * Test linksCountPerTag public tags with filter. + * Equal occurrences should be sorted alphabetically. + */ + public function testCountLinkPerTagPrivateWithFilter() + { + $expected = [ + 'cartoon' => 1, + 'dev' => 1, + 'tag1' => 1, + 'tag2' => 1, + 'tag3' => 1, + 'tag4' => 1, + ]; + $tags = $this->privateLinkDB->bookmarksCountPerTag(['dev'], 'private'); + + $this->assertEquals($expected, $tags, var_export($tags, true)); + } + + /** + * Allows to test LinkDB's private methods + * + * @see + * https://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html + * http://stackoverflow.com/a/2798203 + */ + protected static function getMethod($name) + { + $class = new ReflectionClass('Shaarli\Bookmark\BookmarkFileService'); + $method = $class->getMethod($name); + $method->setAccessible(true); + return $method; + } +} diff --git a/tests/bookmark/BookmarkFilterTest.php b/tests/bookmark/BookmarkFilterTest.php new file mode 100644 index 00000000..d4c71cb9 --- /dev/null +++ b/tests/bookmark/BookmarkFilterTest.php @@ -0,0 +1,514 @@ +set('resource.datastore', self::$testDatastore); + self::$refDB = new \ReferenceLinkDB(); + self::$refDB->write(self::$testDatastore); + $history = new History('sandbox/history.php'); + self::$bookmarkService = new \FakeBookmarkService($conf, $history, true); + self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks()); + } + + /** + * Blank filter. + */ + public function testFilter() + { + $this->assertEquals( + self::$refDB->countLinks(), + count(self::$linkFilter->filter('', '')) + ); + + $this->assertEquals( + self::$refDB->countLinks(), + count(self::$linkFilter->filter('', '', 'all')) + ); + + $this->assertEquals( + self::$refDB->countLinks(), + count(self::$linkFilter->filter('', '', 'randomstr')) + ); + + // Private only. + $this->assertEquals( + self::$refDB->countPrivateLinks(), + count(self::$linkFilter->filter('', '', false, 'private')) + ); + + // Public only. + $this->assertEquals( + self::$refDB->countPublicLinks(), + count(self::$linkFilter->filter('', '', false, 'public')) + ); + + $this->assertEquals( + ReferenceLinkDB::$NB_LINKS_TOTAL, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, '')) + ); + + $this->assertEquals( + self::$refDB->countUntaggedLinks(), + count( + self::$linkFilter->filter( + BookmarkFilter::$FILTER_TAG, + /*$request=*/ + '', + /*$casesensitive=*/ + false, + /*$visibility=*/ + 'all', + /*$untaggedonly=*/ + true + ) + ) + ); + + $this->assertEquals( + ReferenceLinkDB::$NB_LINKS_TOTAL, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, '')) + ); + } + + /** + * Filter bookmarks using a tag + */ + public function testFilterOneTag() + { + $this->assertEquals( + 4, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false)) + ); + + $this->assertEquals( + 4, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'all')) + ); + + $this->assertEquals( + 4, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'default-blabla')) + ); + + // Private only. + $this->assertEquals( + 1, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'private')) + ); + + // Public only. + $this->assertEquals( + 3, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'public')) + ); + } + + /** + * Filter bookmarks using a tag - case-sensitive + */ + public function testFilterCaseSensitiveTag() + { + $this->assertEquals( + 0, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'mercurial', true)) + ); + + $this->assertEquals( + 1, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'Mercurial', true)) + ); + } + + /** + * Filter bookmarks using a tag combination + */ + public function testFilterMultipleTags() + { + $this->assertEquals( + 2, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'dev cartoon', false)) + ); + } + + /** + * Filter bookmarks using a non-existent tag + */ + public function testFilterUnknownTag() + { + $this->assertEquals( + 0, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'null', false)) + ); + } + + /** + * Return bookmarks for a given day + */ + public function testFilterDay() + { + $this->assertEquals( + 4, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20121206')) + ); + } + + /** + * 404 - day not found + */ + public function testFilterUnknownDay() + { + $this->assertEquals( + 0, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '19700101')) + ); + } + + /** + * Use an invalid date format + * @expectedException Exception + * @expectedExceptionMessageRegExp /Invalid date format/ + */ + public function testFilterInvalidDayWithChars() + { + self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, 'Rainy day, dream away'); + } + + /** + * Use an invalid date format + * @expectedException Exception + * @expectedExceptionMessageRegExp /Invalid date format/ + */ + public function testFilterInvalidDayDigits() + { + self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20'); + } + + /** + * Retrieve a link entry with its hash + */ + public function testFilterSmallHash() + { + $links = self::$linkFilter->filter(BookmarkFilter::$FILTER_HASH, 'IuWvgA'); + + $this->assertEquals( + 1, + count($links) + ); + + $this->assertEquals( + 'MediaGoblin', + $links[7]->getTitle() + ); + } + + /** + * No link for this hash + * + * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testFilterUnknownSmallHash() + { + self::$linkFilter->filter(BookmarkFilter::$FILTER_HASH, 'Iblaah'); + } + + /** + * Full-text search - no result found. + */ + public function testFilterFullTextNoResult() + { + $this->assertEquals( + 0, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'azertyuiop')) + ); + } + + /** + * Full-text search - result from a link's URL + */ + public function testFilterFullTextURL() + { + $this->assertEquals( + 2, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'ars.userfriendly.org')) + ); + + $this->assertEquals( + 2, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'ars org')) + ); + } + + /** + * Full-text search - result from a link's title only + */ + public function testFilterFullTextTitle() + { + // use miscellaneous cases + $this->assertEquals( + 2, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'userfriendly -')) + ); + $this->assertEquals( + 2, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'UserFriendly -')) + ); + $this->assertEquals( + 2, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'uSeRFrIendlY -')) + ); + + // use miscellaneous case and offset + $this->assertEquals( + 2, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'RFrIendL')) + ); + } + + /** + * Full-text search - result from the link's description only + */ + public function testFilterFullTextDescription() + { + $this->assertEquals( + 1, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'publishing media')) + ); + + $this->assertEquals( + 1, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'mercurial w3c')) + ); + + $this->assertEquals( + 3, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, '"free software"')) + ); + } + + /** + * Full-text search - result from the link's tags only + */ + public function testFilterFullTextTags() + { + $this->assertEquals( + 6, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web')) + ); + + $this->assertEquals( + 6, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', 'all')) + ); + + $this->assertEquals( + 6, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', 'bla')) + ); + + // Private only. + $this->assertEquals( + 1, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', false, 'private')) + ); + + // Public only. + $this->assertEquals( + 5, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', false, 'public')) + ); + } + + /** + * Full-text search - result set from mixed sources + */ + public function testFilterFullTextMixed() + { + $this->assertEquals( + 3, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'free software')) + ); + } + + /** + * Full-text search - test exclusion with '-'. + */ + public function testExcludeSearch() + { + $this->assertEquals( + 1, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'free -gnu')) + ); + + $this->assertEquals( + ReferenceLinkDB::$NB_LINKS_TOTAL - 1, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, '-revolution')) + ); + } + + /** + * Full-text search - test AND, exact terms and exclusion combined, across fields. + */ + public function testMultiSearch() + { + $this->assertEquals( + 2, + count(self::$linkFilter->filter( + BookmarkFilter::$FILTER_TEXT, + '"Free Software " stallman "read this" @website stuff' + )) + ); + + $this->assertEquals( + 1, + count(self::$linkFilter->filter( + BookmarkFilter::$FILTER_TEXT, + '"free software " stallman "read this" -beard @website stuff' + )) + ); + } + + /** + * Full-text search - make sure that exact search won't work across fields. + */ + public function testSearchExactTermMultiFieldsKo() + { + $this->assertEquals( + 0, + count(self::$linkFilter->filter( + BookmarkFilter::$FILTER_TEXT, + '"designer naming"' + )) + ); + + $this->assertEquals( + 0, + count(self::$linkFilter->filter( + BookmarkFilter::$FILTER_TEXT, + '"designernaming"' + )) + ); + } + + /** + * Tag search with exclusion. + */ + public function testTagFilterWithExclusion() + { + $this->assertEquals( + 1, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'gnu -free')) + ); + + $this->assertEquals( + ReferenceLinkDB::$NB_LINKS_TOTAL - 1, + count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, '-free')) + ); + } + + /** + * Test crossed search (terms + tags). + */ + public function testFilterCrossedSearch() + { + $terms = '"Free Software " stallman "read this" @website stuff'; + $tags = 'free'; + $this->assertEquals( + 1, + count(self::$linkFilter->filter( + BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT, + array($tags, $terms) + )) + ); + $this->assertEquals( + 2, + count(self::$linkFilter->filter( + BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT, + array('', $terms) + )) + ); + $this->assertEquals( + 1, + count(self::$linkFilter->filter( + BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT, + array(false, 'PSR-2') + )) + ); + $this->assertEquals( + 1, + count(self::$linkFilter->filter( + BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT, + array($tags, '') + )) + ); + $this->assertEquals( + ReferenceLinkDB::$NB_LINKS_TOTAL, + count(self::$linkFilter->filter( + BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT, + '' + )) + ); + } + + /** + * Filter bookmarks by #hashtag. + */ + public function testFilterByHashtag() + { + $hashtag = 'hashtag'; + $this->assertEquals( + 3, + count(self::$linkFilter->filter( + BookmarkFilter::$FILTER_TAG, + $hashtag + )) + ); + + $hashtag = 'private'; + $this->assertEquals( + 1, + count(self::$linkFilter->filter( + BookmarkFilter::$FILTER_TAG, + $hashtag, + false, + 'private' + )) + ); + } +} diff --git a/tests/bookmark/BookmarkInitializerTest.php b/tests/bookmark/BookmarkInitializerTest.php new file mode 100644 index 00000000..d23eb069 --- /dev/null +++ b/tests/bookmark/BookmarkInitializerTest.php @@ -0,0 +1,120 @@ +conf = new ConfigManager(self::$testConf); + $this->conf->set('resource.datastore', self::$testDatastore); + $this->history = new History('sandbox/history.php'); + $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); + + $this->initializer = new BookmarkInitializer($this->bookmarkService); + } + + /** + * Test initialize() with an empty data store. + */ + public function testInitializeEmptyDataStore() + { + $refDB = new \ReferenceLinkDB(); + $refDB->write(self::$testDatastore); + $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); + $this->initializer = new BookmarkInitializer($this->bookmarkService); + + $this->initializer->initialize(); + + $this->assertEquals($refDB->countLinks() + 2, $this->bookmarkService->count()); + $bookmark = $this->bookmarkService->get(43); + $this->assertEquals(43, $bookmark->getId()); + $this->assertEquals('My secret stuff... - Pastebin.com', $bookmark->getTitle()); + $this->assertTrue($bookmark->isPrivate()); + + $bookmark = $this->bookmarkService->get(44); + $this->assertEquals(44, $bookmark->getId()); + $this->assertEquals( + 'The personal, minimalist, super-fast, database free, bookmarking service', + $bookmark->getTitle() + ); + $this->assertFalse($bookmark->isPrivate()); + + // Reload from file + $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); + $this->assertEquals($refDB->countLinks() + 2, $this->bookmarkService->count()); + $bookmark = $this->bookmarkService->get(43); + $this->assertEquals(43, $bookmark->getId()); + $this->assertEquals('My secret stuff... - Pastebin.com', $bookmark->getTitle()); + $this->assertTrue($bookmark->isPrivate()); + + $bookmark = $this->bookmarkService->get(44); + $this->assertEquals(44, $bookmark->getId()); + $this->assertEquals( + 'The personal, minimalist, super-fast, database free, bookmarking service', + $bookmark->getTitle() + ); + $this->assertFalse($bookmark->isPrivate()); + } + + /** + * Test initialize() with a data store containing bookmarks. + */ + public function testInitializeNotEmptyDataStore() + { + $this->initializer->initialize(); + + $this->assertEquals(2, $this->bookmarkService->count()); + $bookmark = $this->bookmarkService->get(0); + $this->assertEquals(0, $bookmark->getId()); + $this->assertEquals('My secret stuff... - Pastebin.com', $bookmark->getTitle()); + $this->assertTrue($bookmark->isPrivate()); + + $bookmark = $this->bookmarkService->get(1); + $this->assertEquals(1, $bookmark->getId()); + $this->assertEquals( + 'The personal, minimalist, super-fast, database free, bookmarking service', + $bookmark->getTitle() + ); + $this->assertFalse($bookmark->isPrivate()); + } +} diff --git a/tests/bookmark/BookmarkTest.php b/tests/bookmark/BookmarkTest.php new file mode 100644 index 00000000..9a3bbbfc --- /dev/null +++ b/tests/bookmark/BookmarkTest.php @@ -0,0 +1,388 @@ + 1, + 'shorturl' => 'abc', + 'url' => 'https://domain.tld/oof.html?param=value#anchor', + 'title' => 'This is an array link', + 'description' => 'HTML desc

hi!

', + 'thumbnail' => 'https://domain.tld/pic.png', + 'sticky' => true, + 'created' => new \DateTime('-1 minute'), + 'tags' => ['tag1', 'tag2', 'chair'], + 'updated' => new \DateTime(), + 'private' => true, + ]; + + $bookmark = (new Bookmark())->fromArray($data); + $this->assertEquals($data['id'], $bookmark->getId()); + $this->assertEquals($data['shorturl'], $bookmark->getShortUrl()); + $this->assertEquals($data['url'], $bookmark->getUrl()); + $this->assertEquals($data['title'], $bookmark->getTitle()); + $this->assertEquals($data['description'], $bookmark->getDescription()); + $this->assertEquals($data['thumbnail'], $bookmark->getThumbnail()); + $this->assertEquals($data['sticky'], $bookmark->isSticky()); + $this->assertEquals($data['created'], $bookmark->getCreated()); + $this->assertEquals($data['tags'], $bookmark->getTags()); + $this->assertEquals('tag1 tag2 chair', $bookmark->getTagsString()); + $this->assertEquals($data['updated'], $bookmark->getUpdated()); + $this->assertEquals($data['private'], $bookmark->isPrivate()); + $this->assertFalse($bookmark->isNote()); + } + + /** + * Test fromArray() with a link with minimal data. + * Note that I use null values everywhere but this should not happen in the real world. + */ + public function testFromArrayMinimal() + { + $data = [ + 'id' => null, + 'shorturl' => null, + 'url' => null, + 'title' => null, + 'description' => null, + 'created' => null, + 'tags' => null, + 'private' => null, + ]; + + $bookmark = (new Bookmark())->fromArray($data); + $this->assertNull($bookmark->getId()); + $this->assertNull($bookmark->getShortUrl()); + $this->assertNull($bookmark->getUrl()); + $this->assertNull($bookmark->getTitle()); + $this->assertEquals('', $bookmark->getDescription()); + $this->assertNull($bookmark->getCreated()); + $this->assertEquals([], $bookmark->getTags()); + $this->assertEquals('', $bookmark->getTagsString()); + $this->assertNull($bookmark->getUpdated()); + $this->assertFalse($bookmark->getThumbnail()); + $this->assertFalse($bookmark->isSticky()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertTrue($bookmark->isNote()); + } + + /** + * Test validate() with a valid minimal bookmark + */ + public function testValidateValidFullBookmark() + { + $bookmark = new Bookmark(); + $bookmark->setId(2); + $bookmark->setShortUrl('abc'); + $bookmark->setCreated($date = \DateTime::createFromFormat('Ymd_His', '20190514_200102')); + $bookmark->setUpdated($dateUp = \DateTime::createFromFormat('Ymd_His', '20190514_210203')); + $bookmark->setUrl($url = 'https://domain.tld/oof.html?param=value#anchor'); + $bookmark->setTitle($title = 'This is an array link'); + $bookmark->setDescription($desc = 'HTML desc

hi!

'); + $bookmark->setTags($tags = ['tag1', 'tag2', 'chair']); + $bookmark->setThumbnail($thumb = 'https://domain.tld/pic.png'); + $bookmark->setPrivate(true); + $bookmark->validate(); + + $this->assertEquals(2, $bookmark->getId()); + $this->assertEquals('abc', $bookmark->getShortUrl()); + $this->assertEquals($date, $bookmark->getCreated()); + $this->assertEquals($dateUp, $bookmark->getUpdated()); + $this->assertEquals($url, $bookmark->getUrl()); + $this->assertEquals($title, $bookmark->getTitle()); + $this->assertEquals($desc, $bookmark->getDescription()); + $this->assertEquals($tags, $bookmark->getTags()); + $this->assertEquals(implode(' ', $tags), $bookmark->getTagsString()); + $this->assertEquals($thumb, $bookmark->getThumbnail()); + $this->assertTrue($bookmark->isPrivate()); + $this->assertFalse($bookmark->isNote()); + } + + /** + * Test validate() with a valid minimal bookmark + */ + public function testValidateValidMinimalBookmark() + { + $bookmark = new Bookmark(); + $bookmark->setId(1); + $bookmark->setShortUrl('abc'); + $bookmark->setCreated($date = \DateTime::createFromFormat('Ymd_His', '20190514_200102')); + $bookmark->validate(); + + $this->assertEquals(1, $bookmark->getId()); + $this->assertEquals('abc', $bookmark->getShortUrl()); + $this->assertEquals($date, $bookmark->getCreated()); + $this->assertEquals('?abc', $bookmark->getUrl()); + $this->assertEquals('?abc', $bookmark->getTitle()); + $this->assertEquals('', $bookmark->getDescription()); + $this->assertEquals([], $bookmark->getTags()); + $this->assertEquals('', $bookmark->getTagsString()); + $this->assertFalse($bookmark->getThumbnail()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertTrue($bookmark->isNote()); + $this->assertNull($bookmark->getUpdated()); + } + + /** + * Test validate() with a a bookmark without ID. + */ + public function testValidateNotValidNoId() + { + $bookmark = new Bookmark(); + $bookmark->setShortUrl('abc'); + $bookmark->setCreated(\DateTime::createFromFormat('Ymd_His', '20190514_200102')); + $exception = null; + try { + $bookmark->validate(); + } catch (InvalidBookmarkException $e) { + $exception = $e; + } + $this->assertNotNull($exception); + $this->assertContains('- ID: '. PHP_EOL, $exception->getMessage()); + } + + /** + * Test validate() with a a bookmark with a non integer ID. + */ + public function testValidateNotValidStringId() + { + $bookmark = new Bookmark(); + $bookmark->setId('str'); + $bookmark->setShortUrl('abc'); + $bookmark->setCreated(\DateTime::createFromFormat('Ymd_His', '20190514_200102')); + $exception = null; + try { + $bookmark->validate(); + } catch (InvalidBookmarkException $e) { + $exception = $e; + } + $this->assertNotNull($exception); + $this->assertContains('- ID: str'. PHP_EOL, $exception->getMessage()); + } + + /** + * Test validate() with a a bookmark without short url. + */ + public function testValidateNotValidNoShortUrl() + { + $bookmark = new Bookmark(); + $bookmark->setId(1); + $bookmark->setCreated(\DateTime::createFromFormat('Ymd_His', '20190514_200102')); + $bookmark->setShortUrl(null); + $exception = null; + try { + $bookmark->validate(); + } catch (InvalidBookmarkException $e) { + $exception = $e; + } + $this->assertNotNull($exception); + $this->assertContains('- ShortUrl: '. PHP_EOL, $exception->getMessage()); + } + + /** + * Test validate() with a a bookmark without created datetime. + */ + public function testValidateNotValidNoCreated() + { + $bookmark = new Bookmark(); + $bookmark->setId(1); + $bookmark->setShortUrl('abc'); + $bookmark->setCreated(null); + $exception = null; + try { + $bookmark->validate(); + } catch (InvalidBookmarkException $e) { + $exception = $e; + } + $this->assertNotNull($exception); + $this->assertContains('- Created: '. PHP_EOL, $exception->getMessage()); + } + + /** + * Test validate() with a a bookmark with a bad created datetime. + */ + public function testValidateNotValidBadCreated() + { + $bookmark = new Bookmark(); + $bookmark->setId(1); + $bookmark->setShortUrl('abc'); + $bookmark->setCreated('hi!'); + $exception = null; + try { + $bookmark->validate(); + } catch (InvalidBookmarkException $e) { + $exception = $e; + } + $this->assertNotNull($exception); + $this->assertContains('- Created: Not a DateTime object'. PHP_EOL, $exception->getMessage()); + } + + /** + * Test setId() and make sure that default fields are generated. + */ + public function testSetIdEmptyGeneratedFields() + { + $bookmark = new Bookmark(); + $bookmark->setId(2); + + $this->assertEquals(2, $bookmark->getId()); + $this->assertRegExp('/[\w\-]{6}/', $bookmark->getShortUrl()); + $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getCreated()); + } + + /** + * Test setId() and with generated fields already set. + */ + public function testSetIdSetGeneratedFields() + { + $bookmark = new Bookmark(); + $bookmark->setShortUrl('abc'); + $bookmark->setCreated($date = \DateTime::createFromFormat('Ymd_His', '20190514_200102')); + $bookmark->setId(2); + + $this->assertEquals(2, $bookmark->getId()); + $this->assertEquals('abc', $bookmark->getShortUrl()); + $this->assertEquals($date, $bookmark->getCreated()); + } + + /** + * Test setUrl() and make sure it accepts custom protocols + */ + public function testGetUrlWithValidProtocols() + { + $bookmark = new Bookmark(); + $bookmark->setUrl($url = 'myprotocol://helloworld', ['myprotocol']); + $this->assertEquals($url, $bookmark->getUrl()); + + $bookmark->setUrl($url = 'https://helloworld.tld', ['myprotocol']); + $this->assertEquals($url, $bookmark->getUrl()); + } + + /** + * Test setUrl() and make sure it accepts custom protocols + */ + public function testGetUrlWithNotValidProtocols() + { + $bookmark = new Bookmark(); + $bookmark->setUrl('myprotocol://helloworld', []); + $this->assertEquals('http://helloworld', $bookmark->getUrl()); + + $bookmark->setUrl($url = 'https://helloworld.tld', []); + $this->assertEquals($url, $bookmark->getUrl()); + } + + /** + * Test setTagsString() with exotic data + */ + public function testSetTagsString() + { + $bookmark = new Bookmark(); + + $str = 'tag1 tag2 tag3.tag3-2, tag4 , -tag5 '; + $bookmark->setTagsString($str); + $this->assertEquals( + [ + 'tag1', + 'tag2', + 'tag3.tag3-2', + 'tag4', + 'tag5', + ], + $bookmark->getTags() + ); + } + + /** + * Test setTags() with exotic data + */ + public function testSetTags() + { + $bookmark = new Bookmark(); + + $array = [ + 'tag1 ', + ' tag2', + 'tag3.tag3-2,', + ', tag4', + ', ', + '-tag5 ', + ]; + $bookmark->setTags($array); + $this->assertEquals( + [ + 'tag1', + 'tag2', + 'tag3.tag3-2', + 'tag4', + 'tag5', + ], + $bookmark->getTags() + ); + } + + /** + * Test renameTag() + */ + public function testRenameTag() + { + $bookmark = new Bookmark(); + $bookmark->setTags(['tag1', 'tag2', 'chair']); + $bookmark->renameTag('chair', 'table'); + $this->assertEquals(['tag1', 'tag2', 'table'], $bookmark->getTags()); + $bookmark->renameTag('tag1', 'tag42'); + $this->assertEquals(['tag42', 'tag2', 'table'], $bookmark->getTags()); + $bookmark->renameTag('tag42', 'tag43'); + $this->assertEquals(['tag43', 'tag2', 'table'], $bookmark->getTags()); + $bookmark->renameTag('table', 'desk'); + $this->assertEquals(['tag43', 'tag2', 'desk'], $bookmark->getTags()); + } + + /** + * Test renameTag() with a tag that is not present in the bookmark + */ + public function testRenameTagNotExists() + { + $bookmark = new Bookmark(); + $bookmark->setTags(['tag1', 'tag2', 'chair']); + $bookmark->renameTag('nope', 'table'); + $this->assertEquals(['tag1', 'tag2', 'chair'], $bookmark->getTags()); + } + + /** + * Test deleteTag() + */ + public function testDeleteTag() + { + $bookmark = new Bookmark(); + $bookmark->setTags(['tag1', 'tag2', 'chair']); + $bookmark->deleteTag('chair'); + $this->assertEquals(['tag1', 'tag2'], $bookmark->getTags()); + $bookmark->deleteTag('tag1'); + $this->assertEquals(['tag2'], $bookmark->getTags()); + $bookmark->deleteTag('tag2'); + $this->assertEquals([], $bookmark->getTags()); + } + + /** + * Test deleteTag() with a tag that is not present in the bookmark + */ + public function testDeleteTagNotExists() + { + $bookmark = new Bookmark(); + $bookmark->setTags(['tag1', 'tag2', 'chair']); + $bookmark->deleteTag('nope'); + $this->assertEquals(['tag1', 'tag2', 'chair'], $bookmark->getTags()); + } +} diff --git a/tests/bookmark/LinkDBTest.php b/tests/bookmark/LinkDBTest.php deleted file mode 100644 index ffe03cc5..00000000 --- a/tests/bookmark/LinkDBTest.php +++ /dev/null @@ -1,656 +0,0 @@ -write(self::$testDatastore); - - self::$publicLinkDB = new LinkDB(self::$testDatastore, false, false); - self::$privateLinkDB = new LinkDB(self::$testDatastore, true, false); - } - - /** - * Allows to test LinkDB's private methods - * - * @see - * https://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html - * http://stackoverflow.com/a/2798203 - */ - protected static function getMethod($name) - { - $class = new ReflectionClass('Shaarli\Bookmark\LinkDB'); - $method = $class->getMethod($name); - $method->setAccessible(true); - return $method; - } - - /** - * Instantiate LinkDB objects - logged in user - */ - public function testConstructLoggedIn() - { - new LinkDB(self::$testDatastore, true, false); - $this->assertFileExists(self::$testDatastore); - } - - /** - * Instantiate LinkDB objects - logged out or public instance - */ - public function testConstructLoggedOut() - { - new LinkDB(self::$testDatastore, false, false); - $this->assertFileExists(self::$testDatastore); - } - - /** - * Attempt to instantiate a LinkDB whereas the datastore is not writable - * - * @expectedException Shaarli\Exceptions\IOException - * @expectedExceptionMessageRegExp /Error accessing "null"/ - */ - public function testConstructDatastoreNotWriteable() - { - new LinkDB('null/store.db', false, false); - } - - /** - * The DB doesn't exist, ensure it is created with dummy content - */ - public function testCheckDBNew() - { - $linkDB = new LinkDB(self::$testDatastore, false, false); - unlink(self::$testDatastore); - $this->assertFileNotExists(self::$testDatastore); - - $checkDB = self::getMethod('check'); - $checkDB->invokeArgs($linkDB, array()); - $this->assertFileExists(self::$testDatastore); - - // ensure the correct data has been written - $this->assertGreaterThan(0, filesize(self::$testDatastore)); - } - - /** - * The DB exists, don't do anything - */ - public function testCheckDBLoad() - { - $linkDB = new LinkDB(self::$testDatastore, false, false); - $datastoreSize = filesize(self::$testDatastore); - $this->assertGreaterThan(0, $datastoreSize); - - $checkDB = self::getMethod('check'); - $checkDB->invokeArgs($linkDB, array()); - - // ensure the datastore is left unmodified - $this->assertEquals( - $datastoreSize, - filesize(self::$testDatastore) - ); - } - - /** - * Load an empty DB - */ - public function testReadEmptyDB() - { - file_put_contents(self::$testDatastore, ''); - $emptyDB = new LinkDB(self::$testDatastore, false, false); - $this->assertEquals(0, sizeof($emptyDB)); - $this->assertEquals(0, count($emptyDB)); - } - - /** - * Load public links from the DB - */ - public function testReadPublicDB() - { - $this->assertEquals( - self::$refDB->countPublicLinks(), - sizeof(self::$publicLinkDB) - ); - } - - /** - * Load public and private links from the DB - */ - public function testReadPrivateDB() - { - $this->assertEquals( - self::$refDB->countLinks(), - sizeof(self::$privateLinkDB) - ); - } - - /** - * Save the links to the DB - */ - public function testSave() - { - $testDB = new LinkDB(self::$testDatastore, true, false); - $dbSize = sizeof($testDB); - - $link = array( - 'id' => 43, - 'title' => 'an additional link', - 'url' => 'http://dum.my', - 'description' => 'One more', - 'private' => 0, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150518_190000'), - 'tags' => 'unit test' - ); - $testDB[$link['id']] = $link; - $testDB->save('tests'); - - $testDB = new LinkDB(self::$testDatastore, true, false); - $this->assertEquals($dbSize + 1, sizeof($testDB)); - } - - /** - * Count existing links - */ - public function testCount() - { - $this->assertEquals( - self::$refDB->countPublicLinks(), - self::$publicLinkDB->count() - ); - $this->assertEquals( - self::$refDB->countLinks(), - self::$privateLinkDB->count() - ); - } - - /** - * Count existing links - public links hidden - */ - public function testCountHiddenPublic() - { - $linkDB = new LinkDB(self::$testDatastore, false, true); - - $this->assertEquals( - 0, - $linkDB->count() - ); - $this->assertEquals( - 0, - $linkDB->count() - ); - } - - /** - * List the days for which links have been posted - */ - public function testDays() - { - $this->assertEquals( - array('20100309', '20100310', '20121206', '20121207', '20130614', '20150310'), - self::$publicLinkDB->days() - ); - - $this->assertEquals( - array('20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'), - self::$privateLinkDB->days() - ); - } - - /** - * The URL corresponds to an existing entry in the DB - */ - public function testGetKnownLinkFromURL() - { - $link = self::$publicLinkDB->getLinkFromUrl('http://mediagoblin.org/'); - - $this->assertNotEquals(false, $link); - $this->assertContains( - 'A free software media publishing platform', - $link['description'] - ); - } - - /** - * The URL is not in the DB - */ - public function testGetUnknownLinkFromURL() - { - $this->assertEquals( - false, - self::$publicLinkDB->getLinkFromUrl('http://dev.null') - ); - } - - /** - * Lists all tags - */ - public function testAllTags() - { - $this->assertEquals( - array( - 'web' => 3, - 'cartoon' => 2, - 'gnu' => 2, - 'dev' => 1, - 'samba' => 1, - 'media' => 1, - 'software' => 1, - 'stallman' => 1, - 'free' => 1, - '-exclude' => 1, - 'hashtag' => 2, - // The DB contains a link with `sTuff` and another one with `stuff` tag. - // They need to be grouped with the first case found - order by date DESC: `sTuff`. - 'sTuff' => 2, - 'ut' => 1, - ), - self::$publicLinkDB->linksCountPerTag() - ); - - $this->assertEquals( - array( - 'web' => 4, - 'cartoon' => 3, - 'gnu' => 2, - 'dev' => 2, - 'samba' => 1, - 'media' => 1, - 'software' => 1, - 'stallman' => 1, - 'free' => 1, - 'html' => 1, - 'w3c' => 1, - 'css' => 1, - 'Mercurial' => 1, - 'sTuff' => 2, - '-exclude' => 1, - '.hidden' => 1, - 'hashtag' => 2, - 'tag1' => 1, - 'tag2' => 1, - 'tag3' => 1, - 'tag4' => 1, - 'ut' => 1, - ), - self::$privateLinkDB->linksCountPerTag() - ); - $this->assertEquals( - array( - 'web' => 4, - 'cartoon' => 2, - 'gnu' => 1, - 'dev' => 1, - 'samba' => 1, - 'media' => 1, - 'html' => 1, - 'w3c' => 1, - 'css' => 1, - 'Mercurial' => 1, - '.hidden' => 1, - 'hashtag' => 1, - ), - self::$privateLinkDB->linksCountPerTag(['web']) - ); - $this->assertEquals( - array( - 'web' => 1, - 'html' => 1, - 'w3c' => 1, - 'css' => 1, - 'Mercurial' => 1, - ), - self::$privateLinkDB->linksCountPerTag(['web'], 'private') - ); - } - - /** - * Test filter with string. - */ - public function testFilterString() - { - $tags = 'dev cartoon'; - $request = array('searchtags' => $tags); - $this->assertEquals( - 2, - count(self::$privateLinkDB->filterSearch($request, true, false)) - ); - } - - /** - * Test filter with string. - */ - public function testFilterArray() - { - $tags = array('dev', 'cartoon'); - $request = array('searchtags' => $tags); - $this->assertEquals( - 2, - count(self::$privateLinkDB->filterSearch($request, true, false)) - ); - } - - /** - * Test hidden tags feature: - * tags starting with a dot '.' are only visible when logged in. - */ - public function testHiddenTags() - { - $tags = '.hidden'; - $request = array('searchtags' => $tags); - $this->assertEquals( - 1, - count(self::$privateLinkDB->filterSearch($request, true, false)) - ); - - $this->assertEquals( - 0, - count(self::$publicLinkDB->filterSearch($request, true, false)) - ); - } - - /** - * Test filterHash() with a valid smallhash. - */ - public function testFilterHashValid() - { - $request = smallHash('20150310_114651'); - $this->assertEquals( - 1, - count(self::$publicLinkDB->filterHash($request)) - ); - $request = smallHash('20150310_114633' . 8); - $this->assertEquals( - 1, - count(self::$publicLinkDB->filterHash($request)) - ); - } - - /** - * Test filterHash() with an invalid smallhash. - * - * @expectedException \Shaarli\Bookmark\Exception\LinkNotFoundException - */ - public function testFilterHashInValid1() - { - $request = 'blabla'; - self::$publicLinkDB->filterHash($request); - } - - /** - * Test filterHash() with an empty smallhash. - * - * @expectedException \Shaarli\Bookmark\Exception\LinkNotFoundException - */ - public function testFilterHashInValid() - { - self::$publicLinkDB->filterHash(''); - } - - /** - * Test reorder with asc/desc parameter. - */ - public function testReorderLinksDesc() - { - self::$privateLinkDB->reorder('ASC'); - $stickyIds = [11, 10]; - $standardIds = [42, 4, 9, 1, 0, 7, 6, 8, 41]; - $linkIds = array_merge($stickyIds, $standardIds); - $cpt = 0; - foreach (self::$privateLinkDB as $key => $value) { - $this->assertEquals($linkIds[$cpt++], $key); - } - self::$privateLinkDB->reorder('DESC'); - $linkIds = array_merge(array_reverse($stickyIds), array_reverse($standardIds)); - $cpt = 0; - foreach (self::$privateLinkDB as $key => $value) { - $this->assertEquals($linkIds[$cpt++], $key); - } - } - - /** - * Test rename tag with a valid value present in multiple links - */ - public function testRenameTagMultiple() - { - self::$refDB->write(self::$testDatastore); - $linkDB = new LinkDB(self::$testDatastore, true, false); - - $res = $linkDB->renameTag('cartoon', 'Taz'); - $this->assertEquals(3, count($res)); - $this->assertContains(' Taz ', $linkDB[4]['tags']); - $this->assertContains(' Taz ', $linkDB[1]['tags']); - $this->assertContains(' Taz ', $linkDB[0]['tags']); - } - - /** - * Test rename tag with a valid value - */ - public function testRenameTagCaseSensitive() - { - self::$refDB->write(self::$testDatastore); - $linkDB = new LinkDB(self::$testDatastore, true, false); - - $res = $linkDB->renameTag('sTuff', 'Taz'); - $this->assertEquals(1, count($res)); - $this->assertEquals('Taz', $linkDB[41]['tags']); - } - - /** - * Test rename tag with invalid values - */ - public function testRenameTagInvalid() - { - $linkDB = new LinkDB(self::$testDatastore, false, false); - - $this->assertFalse($linkDB->renameTag('', 'test')); - $this->assertFalse($linkDB->renameTag('', '')); - // tag non existent - $this->assertEquals([], $linkDB->renameTag('test', '')); - $this->assertEquals([], $linkDB->renameTag('test', 'retest')); - } - - /** - * Test delete tag with a valid value - */ - public function testDeleteTag() - { - self::$refDB->write(self::$testDatastore); - $linkDB = new LinkDB(self::$testDatastore, true, false); - - $res = $linkDB->renameTag('cartoon', null); - $this->assertEquals(3, count($res)); - $this->assertNotContains('cartoon', $linkDB[4]['tags']); - } - - /** - * Test linksCountPerTag all tags without filter. - * Equal occurrences should be sorted alphabetically. - */ - public function testCountLinkPerTagAllNoFilter() - { - $expected = [ - 'web' => 4, - 'cartoon' => 3, - 'dev' => 2, - 'gnu' => 2, - 'hashtag' => 2, - 'sTuff' => 2, - '-exclude' => 1, - '.hidden' => 1, - 'Mercurial' => 1, - 'css' => 1, - 'free' => 1, - 'html' => 1, - 'media' => 1, - 'samba' => 1, - 'software' => 1, - 'stallman' => 1, - 'tag1' => 1, - 'tag2' => 1, - 'tag3' => 1, - 'tag4' => 1, - 'ut' => 1, - 'w3c' => 1, - ]; - $tags = self::$privateLinkDB->linksCountPerTag(); - - $this->assertEquals($expected, $tags, var_export($tags, true)); - } - - /** - * Test linksCountPerTag all tags with filter. - * Equal occurrences should be sorted alphabetically. - */ - public function testCountLinkPerTagAllWithFilter() - { - $expected = [ - 'gnu' => 2, - 'hashtag' => 2, - '-exclude' => 1, - '.hidden' => 1, - 'free' => 1, - 'media' => 1, - 'software' => 1, - 'stallman' => 1, - 'stuff' => 1, - 'web' => 1, - ]; - $tags = self::$privateLinkDB->linksCountPerTag(['gnu']); - - $this->assertEquals($expected, $tags, var_export($tags, true)); - } - - /** - * Test linksCountPerTag public tags with filter. - * Equal occurrences should be sorted alphabetically. - */ - public function testCountLinkPerTagPublicWithFilter() - { - $expected = [ - 'gnu' => 2, - 'hashtag' => 2, - '-exclude' => 1, - '.hidden' => 1, - 'free' => 1, - 'media' => 1, - 'software' => 1, - 'stallman' => 1, - 'stuff' => 1, - 'web' => 1, - ]; - $tags = self::$privateLinkDB->linksCountPerTag(['gnu'], 'public'); - - $this->assertEquals($expected, $tags, var_export($tags, true)); - } - - /** - * Test linksCountPerTag public tags with filter. - * Equal occurrences should be sorted alphabetically. - */ - public function testCountLinkPerTagPrivateWithFilter() - { - $expected = [ - 'cartoon' => 1, - 'dev' => 1, - 'tag1' => 1, - 'tag2' => 1, - 'tag3' => 1, - 'tag4' => 1, - ]; - $tags = self::$privateLinkDB->linksCountPerTag(['dev'], 'private'); - - $this->assertEquals($expected, $tags, var_export($tags, true)); - } - - /** - * Make sure that bookmarks with the same timestamp have a consistent order: - * if their creation date is equal, bookmarks are sorted by ID DESC. - */ - public function testConsistentOrder() - { - $nextId = 43; - $creation = DateTime::createFromFormat('Ymd_His', '20190807_130444'); - $linkDB = new LinkDB(self::$testDatastore, true, false); - for ($i = 0; $i < 4; ++$i) { - $linkDB[$nextId + $i] = [ - 'id' => $nextId + $i, - 'url' => 'http://'. $i, - 'created' => $creation, - 'title' => true, - 'description' => true, - 'tags' => true, - ]; - } - - // Check 4 new links 4 times - for ($i = 0; $i < 4; ++$i) { - $linkDB->save('tests'); - $linkDB = new LinkDB(self::$testDatastore, true, false); - $count = 3; - foreach ($linkDB as $link) { - if ($link['sticky'] === true) { - continue; - } - $this->assertEquals($nextId + $count, $link['id']); - $this->assertEquals('http://'. $count, $link['url']); - if (--$count < 0) { - break; - } - } - } - } -} diff --git a/tests/bookmark/LinkFilterTest.php b/tests/bookmark/LinkFilterTest.php deleted file mode 100644 index 808f8122..00000000 --- a/tests/bookmark/LinkFilterTest.php +++ /dev/null @@ -1,507 +0,0 @@ -write(self::$testDatastore); - self::$linkDB = new LinkDB(self::$testDatastore, true, false); - self::$linkFilter = new LinkFilter(self::$linkDB); - } - - /** - * Blank filter. - */ - public function testFilter() - { - $this->assertEquals( - self::$refDB->countLinks(), - count(self::$linkFilter->filter('', '')) - ); - - $this->assertEquals( - self::$refDB->countLinks(), - count(self::$linkFilter->filter('', '', 'all')) - ); - - $this->assertEquals( - self::$refDB->countLinks(), - count(self::$linkFilter->filter('', '', 'randomstr')) - ); - - // Private only. - $this->assertEquals( - self::$refDB->countPrivateLinks(), - count(self::$linkFilter->filter('', '', false, 'private')) - ); - - // Public only. - $this->assertEquals( - self::$refDB->countPublicLinks(), - count(self::$linkFilter->filter('', '', false, 'public')) - ); - - $this->assertEquals( - ReferenceLinkDB::$NB_LINKS_TOTAL, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '')) - ); - - $this->assertEquals( - self::$refDB->countUntaggedLinks(), - count( - self::$linkFilter->filter( - LinkFilter::$FILTER_TAG, - /*$request=*/ - '', - /*$casesensitive=*/ - false, - /*$visibility=*/ - 'all', - /*$untaggedonly=*/ - true - ) - ) - ); - - $this->assertEquals( - ReferenceLinkDB::$NB_LINKS_TOTAL, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '')) - ); - } - - /** - * Filter links using a tag - */ - public function testFilterOneTag() - { - $this->assertEquals( - 4, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false)) - ); - - $this->assertEquals( - 4, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false, 'all')) - ); - - $this->assertEquals( - 4, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false, 'default-blabla')) - ); - - // Private only. - $this->assertEquals( - 1, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false, 'private')) - ); - - // Public only. - $this->assertEquals( - 3, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false, 'public')) - ); - } - - /** - * Filter links using a tag - case-sensitive - */ - public function testFilterCaseSensitiveTag() - { - $this->assertEquals( - 0, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'mercurial', true)) - ); - - $this->assertEquals( - 1, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'Mercurial', true)) - ); - } - - /** - * Filter links using a tag combination - */ - public function testFilterMultipleTags() - { - $this->assertEquals( - 2, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'dev cartoon', false)) - ); - } - - /** - * Filter links using a non-existent tag - */ - public function testFilterUnknownTag() - { - $this->assertEquals( - 0, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'null', false)) - ); - } - - /** - * Return links for a given day - */ - public function testFilterDay() - { - $this->assertEquals( - 4, - count(self::$linkFilter->filter(LinkFilter::$FILTER_DAY, '20121206')) - ); - } - - /** - * 404 - day not found - */ - public function testFilterUnknownDay() - { - $this->assertEquals( - 0, - count(self::$linkFilter->filter(LinkFilter::$FILTER_DAY, '19700101')) - ); - } - - /** - * Use an invalid date format - * @expectedException Exception - * @expectedExceptionMessageRegExp /Invalid date format/ - */ - public function testFilterInvalidDayWithChars() - { - self::$linkFilter->filter(LinkFilter::$FILTER_DAY, 'Rainy day, dream away'); - } - - /** - * Use an invalid date format - * @expectedException Exception - * @expectedExceptionMessageRegExp /Invalid date format/ - */ - public function testFilterInvalidDayDigits() - { - self::$linkFilter->filter(LinkFilter::$FILTER_DAY, '20'); - } - - /** - * Retrieve a link entry with its hash - */ - public function testFilterSmallHash() - { - $links = self::$linkFilter->filter(LinkFilter::$FILTER_HASH, 'IuWvgA'); - - $this->assertEquals( - 1, - count($links) - ); - - $this->assertEquals( - 'MediaGoblin', - $links[7]['title'] - ); - } - - /** - * No link for this hash - * - * @expectedException \Shaarli\Bookmark\Exception\LinkNotFoundException - */ - public function testFilterUnknownSmallHash() - { - self::$linkFilter->filter(LinkFilter::$FILTER_HASH, 'Iblaah'); - } - - /** - * Full-text search - no result found. - */ - public function testFilterFullTextNoResult() - { - $this->assertEquals( - 0, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'azertyuiop')) - ); - } - - /** - * Full-text search - result from a link's URL - */ - public function testFilterFullTextURL() - { - $this->assertEquals( - 2, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'ars.userfriendly.org')) - ); - - $this->assertEquals( - 2, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'ars org')) - ); - } - - /** - * Full-text search - result from a link's title only - */ - public function testFilterFullTextTitle() - { - // use miscellaneous cases - $this->assertEquals( - 2, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'userfriendly -')) - ); - $this->assertEquals( - 2, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'UserFriendly -')) - ); - $this->assertEquals( - 2, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'uSeRFrIendlY -')) - ); - - // use miscellaneous case and offset - $this->assertEquals( - 2, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'RFrIendL')) - ); - } - - /** - * Full-text search - result from the link's description only - */ - public function testFilterFullTextDescription() - { - $this->assertEquals( - 1, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'publishing media')) - ); - - $this->assertEquals( - 1, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'mercurial w3c')) - ); - - $this->assertEquals( - 3, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '"free software"')) - ); - } - - /** - * Full-text search - result from the link's tags only - */ - public function testFilterFullTextTags() - { - $this->assertEquals( - 6, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'web')) - ); - - $this->assertEquals( - 6, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'web', 'all')) - ); - - $this->assertEquals( - 6, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'web', 'bla')) - ); - - // Private only. - $this->assertEquals( - 1, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'web', false, 'private')) - ); - - // Public only. - $this->assertEquals( - 5, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'web', false, 'public')) - ); - } - - /** - * Full-text search - result set from mixed sources - */ - public function testFilterFullTextMixed() - { - $this->assertEquals( - 3, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'free software')) - ); - } - - /** - * Full-text search - test exclusion with '-'. - */ - public function testExcludeSearch() - { - $this->assertEquals( - 1, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'free -gnu')) - ); - - $this->assertEquals( - ReferenceLinkDB::$NB_LINKS_TOTAL - 1, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution')) - ); - } - - /** - * Full-text search - test AND, exact terms and exclusion combined, across fields. - */ - public function testMultiSearch() - { - $this->assertEquals( - 2, - count(self::$linkFilter->filter( - LinkFilter::$FILTER_TEXT, - '"Free Software " stallman "read this" @website stuff' - )) - ); - - $this->assertEquals( - 1, - count(self::$linkFilter->filter( - LinkFilter::$FILTER_TEXT, - '"free software " stallman "read this" -beard @website stuff' - )) - ); - } - - /** - * Full-text search - make sure that exact search won't work across fields. - */ - public function testSearchExactTermMultiFieldsKo() - { - $this->assertEquals( - 0, - count(self::$linkFilter->filter( - LinkFilter::$FILTER_TEXT, - '"designer naming"' - )) - ); - - $this->assertEquals( - 0, - count(self::$linkFilter->filter( - LinkFilter::$FILTER_TEXT, - '"designernaming"' - )) - ); - } - - /** - * Tag search with exclusion. - */ - public function testTagFilterWithExclusion() - { - $this->assertEquals( - 1, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'gnu -free')) - ); - - $this->assertEquals( - ReferenceLinkDB::$NB_LINKS_TOTAL - 1, - count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free')) - ); - } - - /** - * Test crossed search (terms + tags). - */ - public function testFilterCrossedSearch() - { - $terms = '"Free Software " stallman "read this" @website stuff'; - $tags = 'free'; - $this->assertEquals( - 1, - count(self::$linkFilter->filter( - LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT, - array($tags, $terms) - )) - ); - $this->assertEquals( - 2, - count(self::$linkFilter->filter( - LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT, - array('', $terms) - )) - ); - $this->assertEquals( - 1, - count(self::$linkFilter->filter( - LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT, - array(false, 'PSR-2') - )) - ); - $this->assertEquals( - 1, - count(self::$linkFilter->filter( - LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT, - array($tags, '') - )) - ); - $this->assertEquals( - ReferenceLinkDB::$NB_LINKS_TOTAL, - count(self::$linkFilter->filter( - LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT, - '' - )) - ); - } - - /** - * Filter links by #hashtag. - */ - public function testFilterByHashtag() - { - $hashtag = 'hashtag'; - $this->assertEquals( - 3, - count(self::$linkFilter->filter( - LinkFilter::$FILTER_TAG, - $hashtag - )) - ); - - $hashtag = 'private'; - $this->assertEquals( - 1, - count(self::$linkFilter->filter( - LinkFilter::$FILTER_TAG, - $hashtag, - false, - 'private' - )) - ); - } -} diff --git a/tests/bookmark/LinkUtilsTest.php b/tests/bookmark/LinkUtilsTest.php index 78cb8f2a..591976f2 100644 --- a/tests/bookmark/LinkUtilsTest.php +++ b/tests/bookmark/LinkUtilsTest.php @@ -388,15 +388,6 @@ class LinkUtilsTest extends TestCase $this->assertEmpty($keywords); } - /** - * Test count_private. - */ - public function testCountPrivateLinks() - { - $refDB = new ReferenceLinkDB(); - $this->assertEquals($refDB->countPrivateLinks(), count_private($refDB->getLinks())); - } - /** * Test text2clickable. */ diff --git a/tests/bootstrap.php b/tests/bootstrap.php index d36d73cd..0afbcba6 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -4,3 +4,21 @@ require_once 'vendor/autoload.php'; $conf = new \Shaarli\Config\ConfigManager('tests/utils/config/configJson'); new \Shaarli\Languages('en', $conf); + +// is_iterable is only compatible with PHP 7.1+ +if (!function_exists('is_iterable')) { + function is_iterable($var) + { + return is_array($var) || $var instanceof \Traversable; + } +} + +// TODO: remove this after fixing UT +require_once 'application/bookmark/LinkUtils.php'; +require_once 'application/Utils.php'; +require_once 'application/http/UrlUtils.php'; +require_once 'application/http/HttpUtils.php'; +require_once 'application/feed/Cache.php'; +require_once 'tests/utils/ReferenceLinkDB.php'; +require_once 'tests/utils/ReferenceHistory.php'; +require_once 'tests/utils/FakeBookmarkService.php'; diff --git a/tests/config/ConfigJsonTest.php b/tests/config/ConfigJsonTest.php index 95ad060b..33160eb0 100644 --- a/tests/config/ConfigJsonTest.php +++ b/tests/config/ConfigJsonTest.php @@ -24,7 +24,7 @@ class ConfigJsonTest extends \PHPUnit\Framework\TestCase $conf = $this->configIO->read('tests/utils/config/configJson.json.php'); $this->assertEquals('root', $conf['credentials']['login']); $this->assertEquals('lala', $conf['redirector']['url']); - $this->assertEquals('tests/utils/config/datastore.php', $conf['resource']['datastore']); + $this->assertEquals('sandbox/datastore.php', $conf['resource']['datastore']); $this->assertEquals('1', $conf['plugins']['WALLABAG_VERSION']); } diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php index b496cb4c..a43ff672 100644 --- a/tests/feed/FeedBuilderTest.php +++ b/tests/feed/FeedBuilderTest.php @@ -4,7 +4,12 @@ namespace Shaarli\Feed; use DateTime; use ReferenceLinkDB; +use Shaarli\Bookmark\Bookmark; +use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Bookmark\LinkDB; +use Shaarli\Config\ConfigManager; +use Shaarli\Formatter\FormatterFactory; +use Shaarli\History; /** * FeedBuilderTest class. @@ -30,7 +35,9 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase protected static $testDatastore = 'sandbox/datastore.php'; - public static $linkDB; + public static $bookmarkService; + + public static $formatter; public static $serverInfo; @@ -39,9 +46,15 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase */ public static function setUpBeforeClass() { - $refLinkDB = new ReferenceLinkDB(); + $conf = new ConfigManager('tests/utils/config/configJson'); + $conf->set('resource.datastore', self::$testDatastore); + $refLinkDB = new \ReferenceLinkDB(); $refLinkDB->write(self::$testDatastore); - self::$linkDB = new LinkDB(self::$testDatastore, true, false); + $history = new History('sandbox/history.php'); + $factory = new FormatterFactory($conf); + self::$formatter = $factory->getFormatter(); + self::$bookmarkService = new BookmarkFileService($conf, $history, true); + self::$serverInfo = array( 'HTTPS' => 'Off', 'SERVER_NAME' => 'host.tld', @@ -56,15 +69,15 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase */ public function testGetTypeLanguage() { - $feedBuilder = new FeedBuilder(null, FeedBuilder::$FEED_ATOM, null, null, false); + $feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_ATOM, null, null, false); $feedBuilder->setLocale(self::$LOCALE); $this->assertEquals(self::$ATOM_LANGUAGUE, $feedBuilder->getTypeLanguage()); - $feedBuilder = new FeedBuilder(null, FeedBuilder::$FEED_RSS, null, null, false); + $feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_RSS, null, null, false); $feedBuilder->setLocale(self::$LOCALE); $this->assertEquals(self::$RSS_LANGUAGE, $feedBuilder->getTypeLanguage()); - $feedBuilder = new FeedBuilder(null, FeedBuilder::$FEED_ATOM, null, null, false); + $feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_ATOM, null, null, false); $this->assertEquals('en', $feedBuilder->getTypeLanguage()); - $feedBuilder = new FeedBuilder(null, FeedBuilder::$FEED_RSS, null, null, false); + $feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_RSS, null, null, false); $this->assertEquals('en-en', $feedBuilder->getTypeLanguage()); } @@ -73,7 +86,14 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase */ public function testRSSBuildData() { - $feedBuilder = new FeedBuilder(self::$linkDB, FeedBuilder::$FEED_RSS, self::$serverInfo, null, false); + $feedBuilder = new FeedBuilder( + self::$bookmarkService, + self::$formatter, + FeedBuilder::$FEED_RSS, + self::$serverInfo, + null, + false + ); $feedBuilder->setLocale(self::$LOCALE); $data = $feedBuilder->buildData(); // Test headers (RSS) @@ -88,7 +108,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase // Test first not pinned link (note link) $link = $data['links'][array_keys($data['links'])[2]]; $this->assertEquals(41, $link['id']); - $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); + $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); $this->assertEquals('http://host.tld/?WDWyig', $link['url']); $this->assertRegExp('/Tue, 10 Mar 2015 11:46:51 \+\d{4}/', $link['pub_iso_date']); @@ -117,7 +137,14 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase */ public function testAtomBuildData() { - $feedBuilder = new FeedBuilder(self::$linkDB, FeedBuilder::$FEED_ATOM, self::$serverInfo, null, false); + $feedBuilder = new FeedBuilder( + self::$bookmarkService, + self::$formatter, + FeedBuilder::$FEED_ATOM, + self::$serverInfo, + null, + false + ); $feedBuilder->setLocale(self::$LOCALE); $data = $feedBuilder->buildData(); $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); @@ -136,13 +163,20 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase 'searchtags' => 'stuff', 'searchterm' => 'beard', ); - $feedBuilder = new FeedBuilder(self::$linkDB, FeedBuilder::$FEED_ATOM, self::$serverInfo, $criteria, false); + $feedBuilder = new FeedBuilder( + self::$bookmarkService, + self::$formatter, + FeedBuilder::$FEED_ATOM, + self::$serverInfo, + $criteria, + false + ); $feedBuilder->setLocale(self::$LOCALE); $data = $feedBuilder->buildData(); $this->assertEquals(1, count($data['links'])); $link = array_shift($data['links']); $this->assertEquals(41, $link['id']); - $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); + $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); } /** @@ -153,13 +187,20 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $criteria = array( 'nb' => '3', ); - $feedBuilder = new FeedBuilder(self::$linkDB, FeedBuilder::$FEED_ATOM, self::$serverInfo, $criteria, false); + $feedBuilder = new FeedBuilder( + self::$bookmarkService, + self::$formatter, + FeedBuilder::$FEED_ATOM, + self::$serverInfo, + $criteria, + false + ); $feedBuilder->setLocale(self::$LOCALE); $data = $feedBuilder->buildData(); $this->assertEquals(3, count($data['links'])); $link = $data['links'][array_keys($data['links'])[2]]; $this->assertEquals(41, $link['id']); - $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); + $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); } /** @@ -167,7 +208,14 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase */ public function testBuildDataPermalinks() { - $feedBuilder = new FeedBuilder(self::$linkDB, FeedBuilder::$FEED_ATOM, self::$serverInfo, null, false); + $feedBuilder = new FeedBuilder( + self::$bookmarkService, + self::$formatter, + FeedBuilder::$FEED_ATOM, + self::$serverInfo, + null, + false + ); $feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setUsePermalinks(true); $data = $feedBuilder->buildData(); @@ -176,7 +224,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase // First link is a permalink $link = $data['links'][array_keys($data['links'])[2]]; $this->assertEquals(41, $link['id']); - $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); + $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); $this->assertEquals('http://host.tld/?WDWyig', $link['url']); $this->assertContains('Direct link', $link['description']); @@ -184,7 +232,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase // Second link is a direct link $link = $data['links'][array_keys($data['links'])[3]]; $this->assertEquals(8, $link['id']); - $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114633'), $link['created']); + $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114633'), $link['created']); $this->assertEquals('http://host.tld/?RttfEw', $link['guid']); $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['url']); $this->assertContains('Direct link', $link['description']); @@ -196,7 +244,14 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase */ public function testBuildDataHideDates() { - $feedBuilder = new FeedBuilder(self::$linkDB, FeedBuilder::$FEED_ATOM, self::$serverInfo, null, false); + $feedBuilder = new FeedBuilder( + self::$bookmarkService, + self::$formatter, + FeedBuilder::$FEED_ATOM, + self::$serverInfo, + null, + false + ); $feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setHideDates(true); $data = $feedBuilder->buildData(); @@ -204,7 +259,14 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $this->assertFalse($data['show_dates']); // Show dates while logged in - $feedBuilder = new FeedBuilder(self::$linkDB, FeedBuilder::$FEED_ATOM, self::$serverInfo, null, true); + $feedBuilder = new FeedBuilder( + self::$bookmarkService, + self::$formatter, + FeedBuilder::$FEED_ATOM, + self::$serverInfo, + null, + true + ); $feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setHideDates(true); $data = $feedBuilder->buildData(); @@ -225,7 +287,8 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase 'REQUEST_URI' => '/~user/shaarli/index.php?do=feed', ); $feedBuilder = new FeedBuilder( - self::$linkDB, + self::$bookmarkService, + self::$formatter, FeedBuilder::$FEED_ATOM, $serverInfo, null, diff --git a/tests/formatter/BookmarkDefaultFormatterTest.php b/tests/formatter/BookmarkDefaultFormatterTest.php new file mode 100644 index 00000000..fe42a208 --- /dev/null +++ b/tests/formatter/BookmarkDefaultFormatterTest.php @@ -0,0 +1,156 @@ +conf = new ConfigManager(self::$testConf); + $this->formatter = new BookmarkDefaultFormatter($this->conf); + } + + /** + * Test formatting a bookmark with all its attribute filled. + */ + public function testFormatFull() + { + $bookmark = new Bookmark(); + $bookmark->setId($id = 11); + $bookmark->setShortUrl($short = 'abcdef'); + $bookmark->setUrl('https://sub.domain.tld?query=here&for=real#hash'); + $bookmark->setTitle($title = 'This is a bookmark'); + $bookmark->setDescription($desc = '

Content

`Here is some content

'); + $bookmark->setTags($tags = ['tag1', 'bookmark', 'other', '']); + $bookmark->setThumbnail('http://domain2.tdl2/?type=img&name=file.png'); + $bookmark->setSticky(true); + $bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190521_190412')); + $bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190521_191213')); + $bookmark->setPrivate(true); + + $link = $this->formatter->format($bookmark); + $this->assertEquals($id, $link['id']); + $this->assertEquals($short, $link['shorturl']); + $this->assertEquals('https://sub.domain.tld?query=here&for=real#hash', $link['url']); + $this->assertEquals( + 'https://sub.domain.tld?query=here&for=real#hash', + $link['real_url'] + ); + $this->assertEquals('This is a <strong>bookmark</strong>', $link['title']); + $this->assertEquals( + '<h2>Content</h2><p>`Here is some content</p>', + $link['description'] + ); + $tags[3] = '<script>alert("xss");</script>'; + $this->assertEquals($tags, $link['taglist']); + $this->assertEquals(implode(' ', $tags), $link['tags']); + $this->assertEquals( + 'http://domain2.tdl2/?type=img&name=file.png', + $link['thumbnail'] + ); + $this->assertEquals($created, $link['created']); + $this->assertEquals($created->getTimestamp(), $link['timestamp']); + $this->assertEquals($updated, $link['updated']); + $this->assertEquals($updated->getTimestamp(), $link['updated_timestamp']); + $this->assertTrue($link['private']); + $this->assertTrue($link['sticky']); + $this->assertEquals('private', $link['class']); + } + + /** + * Test formatting a bookmark with all its attribute filled. + */ + public function testFormatMinimal() + { + $bookmark = new Bookmark(); + + $link = $this->formatter->format($bookmark); + $this->assertEmpty($link['id']); + $this->assertEmpty($link['shorturl']); + $this->assertEmpty($link['url']); + $this->assertEmpty($link['real_url']); + $this->assertEmpty($link['title']); + $this->assertEmpty($link['description']); + $this->assertEmpty($link['taglist']); + $this->assertEmpty($link['tags']); + $this->assertEmpty($link['thumbnail']); + $this->assertEmpty($link['created']); + $this->assertEmpty($link['timestamp']); + $this->assertEmpty($link['updated']); + $this->assertEmpty($link['updated_timestamp']); + $this->assertFalse($link['private']); + $this->assertFalse($link['sticky']); + $this->assertEmpty($link['class']); + } + + /** + * Make sure that the description is properly formatted by the default formatter. + */ + public function testFormatDescription() + { + $description = []; + $description[] = 'This a description' . PHP_EOL; + $description[] = 'text https://sub.domain.tld?query=here&for=real#hash more text'. PHP_EOL; + $description[] = 'Also, there is an #hashtag added'. PHP_EOL; + $description[] = ' A N D KEEP SPACES ! '. PHP_EOL; + + $bookmark = new Bookmark(); + $bookmark->setDescription(implode('', $description)); + $link = $this->formatter->format($bookmark); + + $description[0] = 'This a <strong>description</strong>
'; + $url = 'https://sub.domain.tld?query=here&for=real#hash'; + $description[1] = 'text '. $url .' more text
'; + $description[2] = 'Also, there is an #hashtag added
'; + $description[3] = '    A  N  D KEEP     '. + 'SPACES    !  
'; + + $this->assertEquals(implode(PHP_EOL, $description) . PHP_EOL, $link['description']); + } + + /** + * Test formatting URL with an index_url set + * It should prepend relative links. + */ + public function testFormatNoteWithIndexUrl() + { + $bookmark = new Bookmark(); + $bookmark->setUrl($short = '?abcdef'); + $description = 'Text #hashtag more text'; + $bookmark->setDescription($description); + + $this->formatter->addContextData('index_url', $root = 'https://domain.tld/hithere/'); + + $link = $this->formatter->format($bookmark); + $this->assertEquals($root . $short, $link['url']); + $this->assertEquals($root . $short, $link['real_url']); + $this->assertEquals( + 'Text '. + '#hashtag more text', + $link['description'] + ); + } +} diff --git a/tests/formatter/BookmarkMarkdownFormatterTest.php b/tests/formatter/BookmarkMarkdownFormatterTest.php new file mode 100644 index 00000000..0ca7f802 --- /dev/null +++ b/tests/formatter/BookmarkMarkdownFormatterTest.php @@ -0,0 +1,160 @@ +conf = new ConfigManager(self::$testConf); + $this->formatter = new BookmarkMarkdownFormatter($this->conf); + } + + /** + * Test formatting a bookmark with all its attribute filled. + */ + public function testFormatFull() + { + $bookmark = new Bookmark(); + $bookmark->setId($id = 11); + $bookmark->setShortUrl($short = 'abcdef'); + $bookmark->setUrl('https://sub.domain.tld?query=here&for=real#hash'); + $bookmark->setTitle($title = 'This is a bookmark'); + $bookmark->setDescription('

Content

`Here is some content

'); + $bookmark->setTags($tags = ['tag1', 'bookmark', 'other', '']); + $bookmark->setThumbnail('http://domain2.tdl2/?type=img&name=file.png'); + $bookmark->setSticky(true); + $bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190521_190412')); + $bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190521_191213')); + $bookmark->setPrivate(true); + + $link = $this->formatter->format($bookmark); + $this->assertEquals($id, $link['id']); + $this->assertEquals($short, $link['shorturl']); + $this->assertEquals('https://sub.domain.tld?query=here&for=real#hash', $link['url']); + $this->assertEquals( + 'https://sub.domain.tld?query=here&for=real#hash', + $link['real_url'] + ); + $this->assertEquals('This is a <strong>bookmark</strong>', $link['title']); + $this->assertEquals( + '

'. + '<h2>Content</h2><p>`Here is some content</p>'. + '

', + $link['description'] + ); + $tags[3] = '<script>alert("xss");</script>'; + $this->assertEquals($tags, $link['taglist']); + $this->assertEquals(implode(' ', $tags), $link['tags']); + $this->assertEquals( + 'http://domain2.tdl2/?type=img&name=file.png', + $link['thumbnail'] + ); + $this->assertEquals($created, $link['created']); + $this->assertEquals($created->getTimestamp(), $link['timestamp']); + $this->assertEquals($updated, $link['updated']); + $this->assertEquals($updated->getTimestamp(), $link['updated_timestamp']); + $this->assertTrue($link['private']); + $this->assertTrue($link['sticky']); + $this->assertEquals('private', $link['class']); + } + + /** + * Test formatting a bookmark with all its attribute filled. + */ + public function testFormatMinimal() + { + $bookmark = new Bookmark(); + + $link = $this->formatter->format($bookmark); + $this->assertEmpty($link['id']); + $this->assertEmpty($link['shorturl']); + $this->assertEmpty($link['url']); + $this->assertEmpty($link['real_url']); + $this->assertEmpty($link['title']); + $this->assertEmpty($link['description']); + $this->assertEmpty($link['taglist']); + $this->assertEmpty($link['tags']); + $this->assertEmpty($link['thumbnail']); + $this->assertEmpty($link['created']); + $this->assertEmpty($link['timestamp']); + $this->assertEmpty($link['updated']); + $this->assertEmpty($link['updated_timestamp']); + $this->assertFalse($link['private']); + $this->assertFalse($link['sticky']); + $this->assertEmpty($link['class']); + } + + /** + * Make sure that the description is properly formatted by the default formatter. + */ + public function testFormatDescription() + { + $description = 'This a description'. PHP_EOL; + $description .= 'text https://sub.domain.tld?query=here&for=real#hash more text'. PHP_EOL; + $description .= 'Also, there is an #hashtag added'. PHP_EOL; + $description .= ' A N D KEEP SPACES ! '. PHP_EOL; + + $bookmark = new Bookmark(); + $bookmark->setDescription($description); + $link = $this->formatter->format($bookmark); + + $description = '

'; + $description .= 'This a <strong>description</strong>
'. PHP_EOL; + $url = 'https://sub.domain.tld?query=here&for=real#hash'; + $description .= 'text '. $url .' more text
'. PHP_EOL; + $description .= 'Also, there is an #hashtag added
'. PHP_EOL; + $description .= 'A N D KEEP SPACES ! '; + $description .= '

'; + + $this->assertEquals($description, $link['description']); + } + + /** + * Test formatting URL with an index_url set + * It should prepend relative links. + */ + public function testFormatNoteWithIndexUrl() + { + $bookmark = new Bookmark(); + $bookmark->setUrl($short = '?abcdef'); + $description = 'Text #hashtag more text'; + $bookmark->setDescription($description); + + $this->formatter->addContextData('index_url', $root = 'https://domain.tld/hithere/'); + + $description = '

'; + $description .= 'Text #hashtag more text'; + $description .= '

'; + + $link = $this->formatter->format($bookmark); + $this->assertEquals($root . $short, $link['url']); + $this->assertEquals($root . $short, $link['real_url']); + $this->assertEquals( + $description, + $link['description'] + ); + } +} diff --git a/tests/formatter/BookmarkRawFormatterTest.php b/tests/formatter/BookmarkRawFormatterTest.php new file mode 100644 index 00000000..ceb6fb73 --- /dev/null +++ b/tests/formatter/BookmarkRawFormatterTest.php @@ -0,0 +1,97 @@ +conf = new ConfigManager(self::$testConf); + $this->formatter = new BookmarkRawFormatter($this->conf); + } + + /** + * Test formatting a bookmark with all its attribute filled. + */ + public function testFormatFull() + { + $bookmark = new Bookmark(); + $bookmark->setId($id = 11); + $bookmark->setShortUrl($short = 'abcdef'); + $bookmark->setUrl($url = 'https://sub.domain.tld?query=here&for=real#hash'); + $bookmark->setTitle($title = 'This is a bookmark'); + $bookmark->setDescription($desc = '

Content

`Here is some content

'); + $bookmark->setTags($tags = ['tag1', 'bookmark', 'other', '']); + $bookmark->setThumbnail($thumb = 'http://domain2.tdl2/file.png'); + $bookmark->setSticky(true); + $bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190521_190412')); + $bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190521_191213')); + $bookmark->setPrivate(true); + + $link = $this->formatter->format($bookmark); + $this->assertEquals($id, $link['id']); + $this->assertEquals($short, $link['shorturl']); + $this->assertEquals($url, $link['url']); + $this->assertEquals($url, $link['real_url']); + $this->assertEquals($title, $link['title']); + $this->assertEquals($desc, $link['description']); + $this->assertEquals($tags, $link['taglist']); + $this->assertEquals(implode(' ', $tags), $link['tags']); + $this->assertEquals($thumb, $link['thumbnail']); + $this->assertEquals($created, $link['created']); + $this->assertEquals($created->getTimestamp(), $link['timestamp']); + $this->assertEquals($updated, $link['updated']); + $this->assertEquals($updated->getTimestamp(), $link['updated_timestamp']); + $this->assertTrue($link['private']); + $this->assertTrue($link['sticky']); + $this->assertEquals('private', $link['class']); + } + + /** + * Test formatting a bookmark with all its attribute filled. + */ + public function testFormatMinimal() + { + $bookmark = new Bookmark(); + + $link = $this->formatter->format($bookmark); + $this->assertEmpty($link['id']); + $this->assertEmpty($link['shorturl']); + $this->assertEmpty($link['url']); + $this->assertEmpty($link['real_url']); + $this->assertEmpty($link['title']); + $this->assertEmpty($link['description']); + $this->assertEmpty($link['taglist']); + $this->assertEmpty($link['tags']); + $this->assertEmpty($link['thumbnail']); + $this->assertEmpty($link['created']); + $this->assertEmpty($link['timestamp']); + $this->assertEmpty($link['updated']); + $this->assertEmpty($link['updated_timestamp']); + $this->assertFalse($link['private']); + $this->assertFalse($link['sticky']); + $this->assertEmpty($link['class']); + } +} diff --git a/tests/formatter/FormatterFactoryTest.php b/tests/formatter/FormatterFactoryTest.php new file mode 100644 index 00000000..317c0b2d --- /dev/null +++ b/tests/formatter/FormatterFactoryTest.php @@ -0,0 +1,101 @@ +conf = new ConfigManager(self::$testConf); + $this->factory = new FormatterFactory($this->conf); + } + + /** + * Test creating an instance of BookmarkFormatter without any setting -> default formatter + */ + public function testCreateInstanceDefault() + { + $this->assertInstanceOf(BookmarkDefaultFormatter::class, $this->factory->getFormatter()); + } + + /** + * Test creating an instance of BookmarkDefaultFormatter from settings + */ + public function testCreateInstanceDefaultSetting() + { + $this->conf->set('formatter', 'default'); + $this->assertInstanceOf(BookmarkDefaultFormatter::class, $this->factory->getFormatter()); + } + + /** + * Test creating an instance of BookmarkDefaultFormatter from parameter + */ + public function testCreateInstanceDefaultParameter() + { + $this->assertInstanceOf( + BookmarkDefaultFormatter::class, + $this->factory->getFormatter('default') + ); + } + + /** + * Test creating an instance of BookmarkRawFormatter from settings + */ + public function testCreateInstanceRawSetting() + { + $this->conf->set('formatter', 'raw'); + $this->assertInstanceOf(BookmarkRawFormatter::class, $this->factory->getFormatter()); + } + + /** + * Test creating an instance of BookmarkRawFormatter from parameter + */ + public function testCreateInstanceRawParameter() + { + $this->assertInstanceOf( + BookmarkRawFormatter::class, + $this->factory->getFormatter('raw') + ); + } + + /** + * Test creating an instance of BookmarkMarkdownFormatter from settings + */ + public function testCreateInstanceMarkdownSetting() + { + $this->conf->set('formatter', 'markdown'); + $this->assertInstanceOf(BookmarkMarkdownFormatter::class, $this->factory->getFormatter()); + } + + /** + * Test creating an instance of BookmarkMarkdownFormatter from parameter + */ + public function testCreateInstanceMarkdownParameter() + { + $this->assertInstanceOf( + BookmarkMarkdownFormatter::class, + $this->factory->getFormatter('markdown') + ); + } +} diff --git a/tests/legacy/LegacyDummyUpdater.php b/tests/legacy/LegacyDummyUpdater.php new file mode 100644 index 00000000..10e0a5b7 --- /dev/null +++ b/tests/legacy/LegacyDummyUpdater.php @@ -0,0 +1,74 @@ +methods = $class->getMethods(ReflectionMethod::IS_FINAL); + } + + /** + * Update method 1. + * + * @return bool true. + */ + final private function updateMethodDummy1() + { + return true; + } + + /** + * Update method 2. + * + * @return bool true. + */ + final private function updateMethodDummy2() + { + return true; + } + + /** + * Update method 3. + * + * @return bool true. + */ + final private function updateMethodDummy3() + { + return true; + } + + /** + * Update method 4, raise an exception. + * + * @throws Exception error. + */ + final private function updateMethodException() + { + throw new Exception('whatever'); + } +} diff --git a/tests/legacy/LegacyLinkDBTest.php b/tests/legacy/LegacyLinkDBTest.php new file mode 100644 index 00000000..17b2b0e6 --- /dev/null +++ b/tests/legacy/LegacyLinkDBTest.php @@ -0,0 +1,656 @@ +write(self::$testDatastore); + self::$publicLinkDB = new LegacyLinkDB(self::$testDatastore, false, false); + self::$privateLinkDB = new LegacyLinkDB(self::$testDatastore, true, false); + } + + /** + * Allows to test LinkDB's private methods + * + * @see + * https://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html + * http://stackoverflow.com/a/2798203 + */ + protected static function getMethod($name) + { + $class = new ReflectionClass('Shaarli\Legacy\LegacyLinkDB'); + $method = $class->getMethod($name); + $method->setAccessible(true); + return $method; + } + + /** + * Instantiate LinkDB objects - logged in user + */ + public function testConstructLoggedIn() + { + new LegacyLinkDB(self::$testDatastore, true, false); + $this->assertFileExists(self::$testDatastore); + } + + /** + * Instantiate LinkDB objects - logged out or public instance + */ + public function testConstructLoggedOut() + { + new LegacyLinkDB(self::$testDatastore, false, false); + $this->assertFileExists(self::$testDatastore); + } + + /** + * Attempt to instantiate a LinkDB whereas the datastore is not writable + * + * @expectedException Shaarli\Exceptions\IOException + * @expectedExceptionMessageRegExp /Error accessing "null"/ + */ + public function testConstructDatastoreNotWriteable() + { + new LegacyLinkDB('null/store.db', false, false); + } + + /** + * The DB doesn't exist, ensure it is created with dummy content + */ + public function testCheckDBNew() + { + $linkDB = new LegacyLinkDB(self::$testDatastore, false, false); + unlink(self::$testDatastore); + $this->assertFileNotExists(self::$testDatastore); + + $checkDB = self::getMethod('check'); + $checkDB->invokeArgs($linkDB, array()); + $this->assertFileExists(self::$testDatastore); + + // ensure the correct data has been written + $this->assertGreaterThan(0, filesize(self::$testDatastore)); + } + + /** + * The DB exists, don't do anything + */ + public function testCheckDBLoad() + { + $linkDB = new LegacyLinkDB(self::$testDatastore, false, false); + $datastoreSize = filesize(self::$testDatastore); + $this->assertGreaterThan(0, $datastoreSize); + + $checkDB = self::getMethod('check'); + $checkDB->invokeArgs($linkDB, array()); + + // ensure the datastore is left unmodified + $this->assertEquals( + $datastoreSize, + filesize(self::$testDatastore) + ); + } + + /** + * Load an empty DB + */ + public function testReadEmptyDB() + { + file_put_contents(self::$testDatastore, ''); + $emptyDB = new LegacyLinkDB(self::$testDatastore, false, false); + $this->assertEquals(0, sizeof($emptyDB)); + $this->assertEquals(0, count($emptyDB)); + } + + /** + * Load public bookmarks from the DB + */ + public function testReadPublicDB() + { + $this->assertEquals( + self::$refDB->countPublicLinks(), + sizeof(self::$publicLinkDB) + ); + } + + /** + * Load public and private bookmarks from the DB + */ + public function testReadPrivateDB() + { + $this->assertEquals( + self::$refDB->countLinks(), + sizeof(self::$privateLinkDB) + ); + } + + /** + * Save the bookmarks to the DB + */ + public function testSave() + { + $testDB = new LegacyLinkDB(self::$testDatastore, true, false); + $dbSize = sizeof($testDB); + + $link = array( + 'id' => 43, + 'title' => 'an additional link', + 'url' => 'http://dum.my', + 'description' => 'One more', + 'private' => 0, + 'created' => DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150518_190000'), + 'tags' => 'unit test' + ); + $testDB[$link['id']] = $link; + $testDB->save('tests'); + + $testDB = new LegacyLinkDB(self::$testDatastore, true, false); + $this->assertEquals($dbSize + 1, sizeof($testDB)); + } + + /** + * Count existing bookmarks + */ + public function testCount() + { + $this->assertEquals( + self::$refDB->countPublicLinks(), + self::$publicLinkDB->count() + ); + $this->assertEquals( + self::$refDB->countLinks(), + self::$privateLinkDB->count() + ); + } + + /** + * Count existing bookmarks - public bookmarks hidden + */ + public function testCountHiddenPublic() + { + $linkDB = new LegacyLinkDB(self::$testDatastore, false, true); + + $this->assertEquals( + 0, + $linkDB->count() + ); + $this->assertEquals( + 0, + $linkDB->count() + ); + } + + /** + * List the days for which bookmarks have been posted + */ + public function testDays() + { + $this->assertEquals( + array('20100309', '20100310', '20121206', '20121207', '20130614', '20150310'), + self::$publicLinkDB->days() + ); + + $this->assertEquals( + array('20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'), + self::$privateLinkDB->days() + ); + } + + /** + * The URL corresponds to an existing entry in the DB + */ + public function testGetKnownLinkFromURL() + { + $link = self::$publicLinkDB->getLinkFromUrl('http://mediagoblin.org/'); + + $this->assertNotEquals(false, $link); + $this->assertContains( + 'A free software media publishing platform', + $link['description'] + ); + } + + /** + * The URL is not in the DB + */ + public function testGetUnknownLinkFromURL() + { + $this->assertEquals( + false, + self::$publicLinkDB->getLinkFromUrl('http://dev.null') + ); + } + + /** + * Lists all tags + */ + public function testAllTags() + { + $this->assertEquals( + array( + 'web' => 3, + 'cartoon' => 2, + 'gnu' => 2, + 'dev' => 1, + 'samba' => 1, + 'media' => 1, + 'software' => 1, + 'stallman' => 1, + 'free' => 1, + '-exclude' => 1, + 'hashtag' => 2, + // The DB contains a link with `sTuff` and another one with `stuff` tag. + // They need to be grouped with the first case found - order by date DESC: `sTuff`. + 'sTuff' => 2, + 'ut' => 1, + ), + self::$publicLinkDB->linksCountPerTag() + ); + + $this->assertEquals( + array( + 'web' => 4, + 'cartoon' => 3, + 'gnu' => 2, + 'dev' => 2, + 'samba' => 1, + 'media' => 1, + 'software' => 1, + 'stallman' => 1, + 'free' => 1, + 'html' => 1, + 'w3c' => 1, + 'css' => 1, + 'Mercurial' => 1, + 'sTuff' => 2, + '-exclude' => 1, + '.hidden' => 1, + 'hashtag' => 2, + 'tag1' => 1, + 'tag2' => 1, + 'tag3' => 1, + 'tag4' => 1, + 'ut' => 1, + ), + self::$privateLinkDB->linksCountPerTag() + ); + $this->assertEquals( + array( + 'web' => 4, + 'cartoon' => 2, + 'gnu' => 1, + 'dev' => 1, + 'samba' => 1, + 'media' => 1, + 'html' => 1, + 'w3c' => 1, + 'css' => 1, + 'Mercurial' => 1, + '.hidden' => 1, + 'hashtag' => 1, + ), + self::$privateLinkDB->linksCountPerTag(['web']) + ); + $this->assertEquals( + array( + 'web' => 1, + 'html' => 1, + 'w3c' => 1, + 'css' => 1, + 'Mercurial' => 1, + ), + self::$privateLinkDB->linksCountPerTag(['web'], 'private') + ); + } + + /** + * Test filter with string. + */ + public function testFilterString() + { + $tags = 'dev cartoon'; + $request = array('searchtags' => $tags); + $this->assertEquals( + 2, + count(self::$privateLinkDB->filterSearch($request, true, false)) + ); + } + + /** + * Test filter with string. + */ + public function testFilterArray() + { + $tags = array('dev', 'cartoon'); + $request = array('searchtags' => $tags); + $this->assertEquals( + 2, + count(self::$privateLinkDB->filterSearch($request, true, false)) + ); + } + + /** + * Test hidden tags feature: + * tags starting with a dot '.' are only visible when logged in. + */ + public function testHiddenTags() + { + $tags = '.hidden'; + $request = array('searchtags' => $tags); + $this->assertEquals( + 1, + count(self::$privateLinkDB->filterSearch($request, true, false)) + ); + + $this->assertEquals( + 0, + count(self::$publicLinkDB->filterSearch($request, true, false)) + ); + } + + /** + * Test filterHash() with a valid smallhash. + */ + public function testFilterHashValid() + { + $request = smallHash('20150310_114651'); + $this->assertEquals( + 1, + count(self::$publicLinkDB->filterHash($request)) + ); + $request = smallHash('20150310_114633' . 8); + $this->assertEquals( + 1, + count(self::$publicLinkDB->filterHash($request)) + ); + } + + /** + * Test filterHash() with an invalid smallhash. + * + * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testFilterHashInValid1() + { + $request = 'blabla'; + self::$publicLinkDB->filterHash($request); + } + + /** + * Test filterHash() with an empty smallhash. + * + * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testFilterHashInValid() + { + self::$publicLinkDB->filterHash(''); + } + + /** + * Test reorder with asc/desc parameter. + */ + public function testReorderLinksDesc() + { + self::$privateLinkDB->reorder('ASC'); + $stickyIds = [11, 10]; + $standardIds = [42, 4, 9, 1, 0, 7, 6, 8, 41]; + $linkIds = array_merge($stickyIds, $standardIds); + $cpt = 0; + foreach (self::$privateLinkDB as $key => $value) { + $this->assertEquals($linkIds[$cpt++], $key); + } + self::$privateLinkDB->reorder('DESC'); + $linkIds = array_merge(array_reverse($stickyIds), array_reverse($standardIds)); + $cpt = 0; + foreach (self::$privateLinkDB as $key => $value) { + $this->assertEquals($linkIds[$cpt++], $key); + } + } + + /** + * Test rename tag with a valid value present in multiple bookmarks + */ + public function testRenameTagMultiple() + { + self::$refDB->write(self::$testDatastore); + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + + $res = $linkDB->renameTag('cartoon', 'Taz'); + $this->assertEquals(3, count($res)); + $this->assertContains(' Taz ', $linkDB[4]['tags']); + $this->assertContains(' Taz ', $linkDB[1]['tags']); + $this->assertContains(' Taz ', $linkDB[0]['tags']); + } + + /** + * Test rename tag with a valid value + */ + public function testRenameTagCaseSensitive() + { + self::$refDB->write(self::$testDatastore); + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + + $res = $linkDB->renameTag('sTuff', 'Taz'); + $this->assertEquals(1, count($res)); + $this->assertEquals('Taz', $linkDB[41]['tags']); + } + + /** + * Test rename tag with invalid values + */ + public function testRenameTagInvalid() + { + $linkDB = new LegacyLinkDB(self::$testDatastore, false, false); + + $this->assertFalse($linkDB->renameTag('', 'test')); + $this->assertFalse($linkDB->renameTag('', '')); + // tag non existent + $this->assertEquals([], $linkDB->renameTag('test', '')); + $this->assertEquals([], $linkDB->renameTag('test', 'retest')); + } + + /** + * Test delete tag with a valid value + */ + public function testDeleteTag() + { + self::$refDB->write(self::$testDatastore); + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + + $res = $linkDB->renameTag('cartoon', null); + $this->assertEquals(3, count($res)); + $this->assertNotContains('cartoon', $linkDB[4]['tags']); + } + + /** + * Test linksCountPerTag all tags without filter. + * Equal occurrences should be sorted alphabetically. + */ + public function testCountLinkPerTagAllNoFilter() + { + $expected = [ + 'web' => 4, + 'cartoon' => 3, + 'dev' => 2, + 'gnu' => 2, + 'hashtag' => 2, + 'sTuff' => 2, + '-exclude' => 1, + '.hidden' => 1, + 'Mercurial' => 1, + 'css' => 1, + 'free' => 1, + 'html' => 1, + 'media' => 1, + 'samba' => 1, + 'software' => 1, + 'stallman' => 1, + 'tag1' => 1, + 'tag2' => 1, + 'tag3' => 1, + 'tag4' => 1, + 'ut' => 1, + 'w3c' => 1, + ]; + $tags = self::$privateLinkDB->linksCountPerTag(); + + $this->assertEquals($expected, $tags, var_export($tags, true)); + } + + /** + * Test linksCountPerTag all tags with filter. + * Equal occurrences should be sorted alphabetically. + */ + public function testCountLinkPerTagAllWithFilter() + { + $expected = [ + 'gnu' => 2, + 'hashtag' => 2, + '-exclude' => 1, + '.hidden' => 1, + 'free' => 1, + 'media' => 1, + 'software' => 1, + 'stallman' => 1, + 'stuff' => 1, + 'web' => 1, + ]; + $tags = self::$privateLinkDB->linksCountPerTag(['gnu']); + + $this->assertEquals($expected, $tags, var_export($tags, true)); + } + + /** + * Test linksCountPerTag public tags with filter. + * Equal occurrences should be sorted alphabetically. + */ + public function testCountLinkPerTagPublicWithFilter() + { + $expected = [ + 'gnu' => 2, + 'hashtag' => 2, + '-exclude' => 1, + '.hidden' => 1, + 'free' => 1, + 'media' => 1, + 'software' => 1, + 'stallman' => 1, + 'stuff' => 1, + 'web' => 1, + ]; + $tags = self::$privateLinkDB->linksCountPerTag(['gnu'], 'public'); + + $this->assertEquals($expected, $tags, var_export($tags, true)); + } + + /** + * Test linksCountPerTag public tags with filter. + * Equal occurrences should be sorted alphabetically. + */ + public function testCountLinkPerTagPrivateWithFilter() + { + $expected = [ + 'cartoon' => 1, + 'dev' => 1, + 'tag1' => 1, + 'tag2' => 1, + 'tag3' => 1, + 'tag4' => 1, + ]; + $tags = self::$privateLinkDB->linksCountPerTag(['dev'], 'private'); + + $this->assertEquals($expected, $tags, var_export($tags, true)); + } + + /** + * Make sure that bookmarks with the same timestamp have a consistent order: + * if their creation date is equal, bookmarks are sorted by ID DESC. + */ + public function testConsistentOrder() + { + $nextId = 43; + $creation = DateTime::createFromFormat('Ymd_His', '20190807_130444'); + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + for ($i = 0; $i < 4; ++$i) { + $linkDB[$nextId + $i] = [ + 'id' => $nextId + $i, + 'url' => 'http://'. $i, + 'created' => $creation, + 'title' => true, + 'description' => true, + 'tags' => true, + ]; + } + + // Check 4 new links 4 times + for ($i = 0; $i < 4; ++$i) { + $linkDB->save('tests'); + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + $count = 3; + foreach ($linkDB as $link) { + if ($link['sticky'] === true) { + continue; + } + $this->assertEquals($nextId + $count, $link['id']); + $this->assertEquals('http://'. $count, $link['url']); + if (--$count < 0) { + break; + } + } + } + } +} diff --git a/tests/legacy/LegacyLinkFilterTest.php b/tests/legacy/LegacyLinkFilterTest.php new file mode 100644 index 00000000..ba9ec529 --- /dev/null +++ b/tests/legacy/LegacyLinkFilterTest.php @@ -0,0 +1,509 @@ +write(self::$testDatastore); + self::$linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + self::$linkFilter = new LegacyLinkFilter(self::$linkDB); + } + + /** + * Blank filter. + */ + public function testFilter() + { + $this->assertEquals( + self::$refDB->countLinks(), + count(self::$linkFilter->filter('', '')) + ); + + $this->assertEquals( + self::$refDB->countLinks(), + count(self::$linkFilter->filter('', '', 'all')) + ); + + $this->assertEquals( + self::$refDB->countLinks(), + count(self::$linkFilter->filter('', '', 'randomstr')) + ); + + // Private only. + $this->assertEquals( + self::$refDB->countPrivateLinks(), + count(self::$linkFilter->filter('', '', false, 'private')) + ); + + // Public only. + $this->assertEquals( + self::$refDB->countPublicLinks(), + count(self::$linkFilter->filter('', '', false, 'public')) + ); + + $this->assertEquals( + ReferenceLinkDB::$NB_LINKS_TOTAL, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, '')) + ); + + $this->assertEquals( + self::$refDB->countUntaggedLinks(), + count( + self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TAG, + /*$request=*/ + '', + /*$casesensitive=*/ + false, + /*$visibility=*/ + 'all', + /*$untaggedonly=*/ + true + ) + ) + ); + + $this->assertEquals( + ReferenceLinkDB::$NB_LINKS_TOTAL, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, '')) + ); + } + + /** + * Filter bookmarks using a tag + */ + public function testFilterOneTag() + { + $this->assertEquals( + 4, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, 'web', false)) + ); + + $this->assertEquals( + 4, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, 'web', false, 'all')) + ); + + $this->assertEquals( + 4, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, 'web', false, 'default-blabla')) + ); + + // Private only. + $this->assertEquals( + 1, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, 'web', false, 'private')) + ); + + // Public only. + $this->assertEquals( + 3, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, 'web', false, 'public')) + ); + } + + /** + * Filter bookmarks using a tag - case-sensitive + */ + public function testFilterCaseSensitiveTag() + { + $this->assertEquals( + 0, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, 'mercurial', true)) + ); + + $this->assertEquals( + 1, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, 'Mercurial', true)) + ); + } + + /** + * Filter bookmarks using a tag combination + */ + public function testFilterMultipleTags() + { + $this->assertEquals( + 2, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, 'dev cartoon', false)) + ); + } + + /** + * Filter bookmarks using a non-existent tag + */ + public function testFilterUnknownTag() + { + $this->assertEquals( + 0, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, 'null', false)) + ); + } + + /** + * Return bookmarks for a given day + */ + public function testFilterDay() + { + $this->assertEquals( + 4, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_DAY, '20121206')) + ); + } + + /** + * 404 - day not found + */ + public function testFilterUnknownDay() + { + $this->assertEquals( + 0, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_DAY, '19700101')) + ); + } + + /** + * Use an invalid date format + * @expectedException Exception + * @expectedExceptionMessageRegExp /Invalid date format/ + */ + public function testFilterInvalidDayWithChars() + { + self::$linkFilter->filter(LegacyLinkFilter::$FILTER_DAY, 'Rainy day, dream away'); + } + + /** + * Use an invalid date format + * @expectedException Exception + * @expectedExceptionMessageRegExp /Invalid date format/ + */ + public function testFilterInvalidDayDigits() + { + self::$linkFilter->filter(LegacyLinkFilter::$FILTER_DAY, '20'); + } + + /** + * Retrieve a link entry with its hash + */ + public function testFilterSmallHash() + { + $links = self::$linkFilter->filter(LegacyLinkFilter::$FILTER_HASH, 'IuWvgA'); + + $this->assertEquals( + 1, + count($links) + ); + + $this->assertEquals( + 'MediaGoblin', + $links[7]['title'] + ); + } + + /** + * No link for this hash + * + * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException + */ + public function testFilterUnknownSmallHash() + { + self::$linkFilter->filter(LegacyLinkFilter::$FILTER_HASH, 'Iblaah'); + } + + /** + * Full-text search - no result found. + */ + public function testFilterFullTextNoResult() + { + $this->assertEquals( + 0, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'azertyuiop')) + ); + } + + /** + * Full-text search - result from a link's URL + */ + public function testFilterFullTextURL() + { + $this->assertEquals( + 2, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'ars.userfriendly.org')) + ); + + $this->assertEquals( + 2, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'ars org')) + ); + } + + /** + * Full-text search - result from a link's title only + */ + public function testFilterFullTextTitle() + { + // use miscellaneous cases + $this->assertEquals( + 2, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'userfriendly -')) + ); + $this->assertEquals( + 2, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'UserFriendly -')) + ); + $this->assertEquals( + 2, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'uSeRFrIendlY -')) + ); + + // use miscellaneous case and offset + $this->assertEquals( + 2, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'RFrIendL')) + ); + } + + /** + * Full-text search - result from the link's description only + */ + public function testFilterFullTextDescription() + { + $this->assertEquals( + 1, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'publishing media')) + ); + + $this->assertEquals( + 1, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'mercurial w3c')) + ); + + $this->assertEquals( + 3, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, '"free software"')) + ); + } + + /** + * Full-text search - result from the link's tags only + */ + public function testFilterFullTextTags() + { + $this->assertEquals( + 6, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'web')) + ); + + $this->assertEquals( + 6, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'web', 'all')) + ); + + $this->assertEquals( + 6, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'web', 'bla')) + ); + + // Private only. + $this->assertEquals( + 1, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'web', false, 'private')) + ); + + // Public only. + $this->assertEquals( + 5, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'web', false, 'public')) + ); + } + + /** + * Full-text search - result set from mixed sources + */ + public function testFilterFullTextMixed() + { + $this->assertEquals( + 3, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'free software')) + ); + } + + /** + * Full-text search - test exclusion with '-'. + */ + public function testExcludeSearch() + { + $this->assertEquals( + 1, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, 'free -gnu')) + ); + + $this->assertEquals( + ReferenceLinkDB::$NB_LINKS_TOTAL - 1, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TEXT, '-revolution')) + ); + } + + /** + * Full-text search - test AND, exact terms and exclusion combined, across fields. + */ + public function testMultiSearch() + { + $this->assertEquals( + 2, + count(self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TEXT, + '"Free Software " stallman "read this" @website stuff' + )) + ); + + $this->assertEquals( + 1, + count(self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TEXT, + '"free software " stallman "read this" -beard @website stuff' + )) + ); + } + + /** + * Full-text search - make sure that exact search won't work across fields. + */ + public function testSearchExactTermMultiFieldsKo() + { + $this->assertEquals( + 0, + count(self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TEXT, + '"designer naming"' + )) + ); + + $this->assertEquals( + 0, + count(self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TEXT, + '"designernaming"' + )) + ); + } + + /** + * Tag search with exclusion. + */ + public function testTagFilterWithExclusion() + { + $this->assertEquals( + 1, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, 'gnu -free')) + ); + + $this->assertEquals( + ReferenceLinkDB::$NB_LINKS_TOTAL - 1, + count(self::$linkFilter->filter(LegacyLinkFilter::$FILTER_TAG, '-free')) + ); + } + + /** + * Test crossed search (terms + tags). + */ + public function testFilterCrossedSearch() + { + $terms = '"Free Software " stallman "read this" @website stuff'; + $tags = 'free'; + $this->assertEquals( + 1, + count(self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TAG | LegacyLinkFilter::$FILTER_TEXT, + array($tags, $terms) + )) + ); + $this->assertEquals( + 2, + count(self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TAG | LegacyLinkFilter::$FILTER_TEXT, + array('', $terms) + )) + ); + $this->assertEquals( + 1, + count(self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TAG | LegacyLinkFilter::$FILTER_TEXT, + array(false, 'PSR-2') + )) + ); + $this->assertEquals( + 1, + count(self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TAG | LegacyLinkFilter::$FILTER_TEXT, + array($tags, '') + )) + ); + $this->assertEquals( + ReferenceLinkDB::$NB_LINKS_TOTAL, + count(self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TAG | LegacyLinkFilter::$FILTER_TEXT, + '' + )) + ); + } + + /** + * Filter bookmarks by #hashtag. + */ + public function testFilterByHashtag() + { + $hashtag = 'hashtag'; + $this->assertEquals( + 3, + count(self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TAG, + $hashtag + )) + ); + + $hashtag = 'private'; + $this->assertEquals( + 1, + count(self::$linkFilter->filter( + LegacyLinkFilter::$FILTER_TAG, + $hashtag, + false, + 'private' + )) + ); + } +} diff --git a/tests/legacy/LegacyUpdaterTest.php b/tests/legacy/LegacyUpdaterTest.php new file mode 100644 index 00000000..7c429811 --- /dev/null +++ b/tests/legacy/LegacyUpdaterTest.php @@ -0,0 +1,886 @@ +conf = new ConfigManager(self::$configFile); + } + + /** + * Test UpdaterUtils::read_updates_file with an empty/missing file. + */ + public function testReadEmptyUpdatesFile() + { + $this->assertEquals(array(), UpdaterUtils::read_updates_file('')); + $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; + touch($updatesFile); + $this->assertEquals(array(), UpdaterUtils::read_updates_file($updatesFile)); + unlink($updatesFile); + } + + /** + * Test read/write updates file. + */ + public function testReadWriteUpdatesFile() + { + $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; + $updatesMethods = array('m1', 'm2', 'm3'); + + UpdaterUtils::write_updates_file($updatesFile, $updatesMethods); + $readMethods = UpdaterUtils::read_updates_file($updatesFile); + $this->assertEquals($readMethods, $updatesMethods); + + // Update + $updatesMethods[] = 'm4'; + UpdaterUtils::write_updates_file($updatesFile, $updatesMethods); + $readMethods = UpdaterUtils::read_updates_file($updatesFile); + $this->assertEquals($readMethods, $updatesMethods); + unlink($updatesFile); + } + + /** + * Test errors in UpdaterUtils::write_updates_file(): empty updates file. + * + * @expectedException Exception + * @expectedExceptionMessageRegExp /Updates file path is not set(.*)/ + */ + public function testWriteEmptyUpdatesFile() + { + UpdaterUtils::write_updates_file('', array('test')); + } + + /** + * Test errors in UpdaterUtils::write_updates_file(): not writable updates file. + * + * @expectedException Exception + * @expectedExceptionMessageRegExp /Unable to write(.*)/ + */ + public function testWriteUpdatesFileNotWritable() + { + $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; + touch($updatesFile); + chmod($updatesFile, 0444); + try { + @UpdaterUtils::write_updates_file($updatesFile, array('test')); + } catch (Exception $e) { + unlink($updatesFile); + throw $e; + } + } + + /** + * Test the update() method, with no update to run. + * 1. Everything already run. + * 2. User is logged out. + */ + public function testNoUpdates() + { + $updates = array( + 'updateMethodDummy1', + 'updateMethodDummy2', + 'updateMethodDummy3', + 'updateMethodException', + ); + $updater = new DummyUpdater($updates, array(), $this->conf, true); + $this->assertEquals(array(), $updater->update()); + + $updater = new DummyUpdater(array(), array(), $this->conf, false); + $this->assertEquals(array(), $updater->update()); + } + + /** + * Test the update() method, with all updates to run (except the failing one). + */ + public function testUpdatesFirstTime() + { + $updates = array('updateMethodException',); + $expectedUpdates = array( + 'updateMethodDummy1', + 'updateMethodDummy2', + 'updateMethodDummy3', + ); + $updater = new DummyUpdater($updates, array(), $this->conf, true); + $this->assertEquals($expectedUpdates, $updater->update()); + } + + /** + * Test the update() method, only one update to run. + */ + public function testOneUpdate() + { + $updates = array( + 'updateMethodDummy1', + 'updateMethodDummy3', + 'updateMethodException', + ); + $expectedUpdate = array('updateMethodDummy2'); + + $updater = new DummyUpdater($updates, array(), $this->conf, true); + $this->assertEquals($expectedUpdate, $updater->update()); + } + + /** + * Test Update failed. + * + * @expectedException \Exception + */ + public function testUpdateFailed() + { + $updates = array( + 'updateMethodDummy1', + 'updateMethodDummy2', + 'updateMethodDummy3', + ); + + $updater = new DummyUpdater($updates, array(), $this->conf, true); + $updater->update(); + } + + /** + * Test update mergeDeprecatedConfig: + * 1. init a config file. + * 2. init a options.php file with update value. + * 3. merge. + * 4. check updated value in config file. + */ + public function testUpdateMergeDeprecatedConfig() + { + $this->conf->setConfigFile('tests/utils/config/configPhp'); + $this->conf->reset(); + + $optionsFile = 'tests/updater/options.php'; + $options = 'conf->setConfigFile('tests/updater/config'); + + // merge configs + $updater = new LegacyUpdater(array(), array(), $this->conf, true); + // This writes a new config file in tests/updater/config.php + $updater->updateMethodMergeDeprecatedConfigFile(); + + // make sure updated field is changed + $this->conf->reload(); + $this->assertTrue($this->conf->get('privacy.default_private_links')); + $this->assertFalse(is_file($optionsFile)); + // Delete the generated file. + unlink($this->conf->getConfigFileExt()); + } + + /** + * Test mergeDeprecatedConfig in without options file. + */ + public function testMergeDeprecatedConfigNoFile() + { + $updater = new LegacyUpdater(array(), array(), $this->conf, true); + $updater->updateMethodMergeDeprecatedConfigFile(); + + $this->assertEquals('root', $this->conf->get('credentials.login')); + } + + /** + * Test renameDashTags update method. + */ + public function testRenameDashTags() + { + $refDB = new \ReferenceLinkDB(true); + $refDB->write(self::$testDatastore); + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + + $this->assertEmpty($linkDB->filterSearch(array('searchtags' => 'exclude'))); + $updater = new LegacyUpdater(array(), $linkDB, $this->conf, true); + $updater->updateMethodRenameDashTags(); + $this->assertNotEmpty($linkDB->filterSearch(array('searchtags' => 'exclude'))); + } + + /** + * Convert old PHP config file to JSON config. + */ + public function testConfigToJson() + { + $configFile = 'tests/utils/config/configPhp'; + $this->conf->setConfigFile($configFile); + $this->conf->reset(); + + // The ConfigIO is initialized with ConfigPhp. + $this->assertTrue($this->conf->getConfigIO() instanceof ConfigPhp); + + $updater = new LegacyUpdater(array(), array(), $this->conf, false); + $done = $updater->updateMethodConfigToJson(); + $this->assertTrue($done); + + // The ConfigIO has been updated to ConfigJson. + $this->assertTrue($this->conf->getConfigIO() instanceof ConfigJson); + $this->assertTrue(file_exists($this->conf->getConfigFileExt())); + + // Check JSON config data. + $this->conf->reload(); + $this->assertEquals('root', $this->conf->get('credentials.login')); + $this->assertEquals('lala', $this->conf->get('redirector.url')); + $this->assertEquals('data/datastore.php', $this->conf->get('resource.datastore')); + $this->assertEquals('1', $this->conf->get('plugins.WALLABAG_VERSION')); + + rename($configFile . '.save.php', $configFile . '.php'); + unlink($this->conf->getConfigFileExt()); + } + + /** + * Launch config conversion update with an existing JSON file => nothing to do. + */ + public function testConfigToJsonNothingToDo() + { + $filetime = filemtime($this->conf->getConfigFileExt()); + $updater = new LegacyUpdater(array(), array(), $this->conf, false); + $done = $updater->updateMethodConfigToJson(); + $this->assertTrue($done); + $expected = filemtime($this->conf->getConfigFileExt()); + $this->assertEquals($expected, $filetime); + } + + /** + * Test escapeUnescapedConfig with valid data. + */ + public function testEscapeConfig() + { + $sandbox = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandbox . '.json.php'); + $this->conf = new ConfigManager($sandbox); + $title = ''; + $headerLink = ''; + $this->conf->set('general.title', $title); + $this->conf->set('general.header_link', $headerLink); + $updater = new LegacyUpdater(array(), array(), $this->conf, true); + $done = $updater->updateMethodEscapeUnescapedConfig(); + $this->assertTrue($done); + $this->conf->reload(); + $this->assertEquals(escape($title), $this->conf->get('general.title')); + $this->assertEquals(escape($headerLink), $this->conf->get('general.header_link')); + unlink($sandbox . '.json.php'); + } + + /** + * Test updateMethodApiSettings(): create default settings for the API (enabled + secret). + */ + public function testUpdateApiSettings() + { + $confFile = 'sandbox/config'; + copy(self::$configFile .'.json.php', $confFile .'.json.php'); + $conf = new ConfigManager($confFile); + $updater = new LegacyUpdater(array(), array(), $conf, true); + + $this->assertFalse($conf->exists('api.enabled')); + $this->assertFalse($conf->exists('api.secret')); + $updater->updateMethodApiSettings(); + $conf->reload(); + $this->assertTrue($conf->get('api.enabled')); + $this->assertTrue($conf->exists('api.secret')); + unlink($confFile .'.json.php'); + } + + /** + * Test updateMethodApiSettings(): already set, do nothing. + */ + public function testUpdateApiSettingsNothingToDo() + { + $confFile = 'sandbox/config'; + copy(self::$configFile .'.json.php', $confFile .'.json.php'); + $conf = new ConfigManager($confFile); + $conf->set('api.enabled', false); + $conf->set('api.secret', ''); + $updater = new LegacyUpdater(array(), array(), $conf, true); + $updater->updateMethodApiSettings(); + $this->assertFalse($conf->get('api.enabled')); + $this->assertEmpty($conf->get('api.secret')); + unlink($confFile .'.json.php'); + } + + /** + * Test updateMethodDatastoreIds(). + */ + public function testDatastoreIds() + { + $links = array( + '20121206_182539' => array( + 'linkdate' => '20121206_182539', + 'title' => 'Geek and Poke', + 'url' => 'http://geek-and-poke.com/', + 'description' => 'desc', + 'tags' => 'dev cartoon tag1 tag2 tag3 tag4 ', + 'updated' => '20121206_190301', + 'private' => false, + ), + '20121206_172539' => array( + 'linkdate' => '20121206_172539', + 'title' => 'UserFriendly - Samba', + 'url' => 'http://ars.userfriendly.org/cartoons/?id=20010306', + 'description' => '', + 'tags' => 'samba cartoon web', + 'private' => false, + ), + '20121206_142300' => array( + 'linkdate' => '20121206_142300', + 'title' => 'UserFriendly - Web Designer', + 'url' => 'http://ars.userfriendly.org/cartoons/?id=20121206', + 'description' => 'Naming conventions... #private', + 'tags' => 'samba cartoon web', + 'private' => true, + ), + ); + $refDB = new \ReferenceLinkDB(true); + $refDB->setLinks($links); + $refDB->write(self::$testDatastore); + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + + $checksum = hash_file('sha1', self::$testDatastore); + + $this->conf->set('resource.data_dir', 'sandbox'); + $this->conf->set('resource.datastore', self::$testDatastore); + + $updater = new LegacyUpdater(array(), $linkDB, $this->conf, true); + $this->assertTrue($updater->updateMethodDatastoreIds()); + + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + + $backupFiles = glob($this->conf->get('resource.data_dir') . '/datastore.'. date('YmdH') .'*.php'); + $backup = null; + foreach ($backupFiles as $backupFile) { + if (strpos($backupFile, '_1') === false) { + $backup = $backupFile; + } + } + $this->assertNotNull($backup); + $this->assertFileExists($backup); + $this->assertEquals($checksum, hash_file('sha1', $backup)); + unlink($backup); + + $this->assertEquals(3, count($linkDB)); + $this->assertTrue(isset($linkDB[0])); + $this->assertFalse(isset($linkDB[0]['linkdate'])); + $this->assertEquals(0, $linkDB[0]['id']); + $this->assertEquals('UserFriendly - Web Designer', $linkDB[0]['title']); + $this->assertEquals('http://ars.userfriendly.org/cartoons/?id=20121206', $linkDB[0]['url']); + $this->assertEquals('Naming conventions... #private', $linkDB[0]['description']); + $this->assertEquals('samba cartoon web', $linkDB[0]['tags']); + $this->assertTrue($linkDB[0]['private']); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121206_142300'), + $linkDB[0]['created'] + ); + + $this->assertTrue(isset($linkDB[1])); + $this->assertFalse(isset($linkDB[1]['linkdate'])); + $this->assertEquals(1, $linkDB[1]['id']); + $this->assertEquals('UserFriendly - Samba', $linkDB[1]['title']); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121206_172539'), + $linkDB[1]['created'] + ); + + $this->assertTrue(isset($linkDB[2])); + $this->assertFalse(isset($linkDB[2]['linkdate'])); + $this->assertEquals(2, $linkDB[2]['id']); + $this->assertEquals('Geek and Poke', $linkDB[2]['title']); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121206_182539'), + $linkDB[2]['created'] + ); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121206_190301'), + $linkDB[2]['updated'] + ); + } + + /** + * Test updateMethodDatastoreIds() with the update already applied: nothing to do. + */ + public function testDatastoreIdsNothingToDo() + { + $refDB = new \ReferenceLinkDB(true); + $refDB->write(self::$testDatastore); + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + + $this->conf->set('resource.data_dir', 'sandbox'); + $this->conf->set('resource.datastore', self::$testDatastore); + + $checksum = hash_file('sha1', self::$testDatastore); + $updater = new LegacyUpdater(array(), $linkDB, $this->conf, true); + $this->assertTrue($updater->updateMethodDatastoreIds()); + $this->assertEquals($checksum, hash_file('sha1', self::$testDatastore)); + } + + /** + * Test defaultTheme update with default settings: nothing to do. + */ + public function testDefaultThemeWithDefaultSettings() + { + $sandbox = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandbox . '.json.php'); + $this->conf = new ConfigManager($sandbox); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodDefaultTheme()); + + $this->assertEquals('tpl/', $this->conf->get('resource.raintpl_tpl')); + $this->assertEquals('default', $this->conf->get('resource.theme')); + $this->conf = new ConfigManager($sandbox); + $this->assertEquals('tpl/', $this->conf->get('resource.raintpl_tpl')); + $this->assertEquals('default', $this->conf->get('resource.theme')); + unlink($sandbox . '.json.php'); + } + + /** + * Test defaultTheme update with a custom theme in a subfolder + */ + public function testDefaultThemeWithCustomTheme() + { + $theme = 'iamanartist'; + $sandbox = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandbox . '.json.php'); + $this->conf = new ConfigManager($sandbox); + mkdir('sandbox/'. $theme); + touch('sandbox/'. $theme .'/linklist.html'); + $this->conf->set('resource.raintpl_tpl', 'sandbox/'. $theme .'/'); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodDefaultTheme()); + + $this->assertEquals('sandbox', $this->conf->get('resource.raintpl_tpl')); + $this->assertEquals($theme, $this->conf->get('resource.theme')); + $this->conf = new ConfigManager($sandbox); + $this->assertEquals('sandbox', $this->conf->get('resource.raintpl_tpl')); + $this->assertEquals($theme, $this->conf->get('resource.theme')); + unlink($sandbox . '.json.php'); + unlink('sandbox/'. $theme .'/linklist.html'); + rmdir('sandbox/'. $theme); + } + + /** + * Test updateMethodEscapeMarkdown with markdown plugin enabled + * => setting markdown_escape set to false. + */ + public function testEscapeMarkdownSettingToFalse() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + + $this->conf->set('general.enabled_plugins', ['markdown']); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodEscapeMarkdown()); + $this->assertFalse($this->conf->get('security.markdown_escape')); + + // reload from file + $this->conf = new ConfigManager($sandboxConf); + $this->assertFalse($this->conf->get('security.markdown_escape')); + } + + + /** + * Test updateMethodEscapeMarkdown with markdown plugin disabled + * => setting markdown_escape set to true. + */ + public function testEscapeMarkdownSettingToTrue() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + + $this->conf->set('general.enabled_plugins', []); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodEscapeMarkdown()); + $this->assertTrue($this->conf->get('security.markdown_escape')); + + // reload from file + $this->conf = new ConfigManager($sandboxConf); + $this->assertTrue($this->conf->get('security.markdown_escape')); + } + + /** + * Test updateMethodEscapeMarkdown with nothing to do (setting already enabled) + */ + public function testEscapeMarkdownSettingNothingToDoEnabled() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $this->conf->set('security.markdown_escape', true); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodEscapeMarkdown()); + $this->assertTrue($this->conf->get('security.markdown_escape')); + } + + /** + * Test updateMethodEscapeMarkdown with nothing to do (setting already disabled) + */ + public function testEscapeMarkdownSettingNothingToDoDisabled() + { + $this->conf->set('security.markdown_escape', false); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodEscapeMarkdown()); + $this->assertFalse($this->conf->get('security.markdown_escape')); + } + + /** + * Test updateMethodPiwikUrl with valid data + */ + public function testUpdatePiwikUrlValid() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $url = 'mypiwik.tld'; + $this->conf->set('plugins.PIWIK_URL', $url); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodPiwikUrl()); + $this->assertEquals('http://'. $url, $this->conf->get('plugins.PIWIK_URL')); + + // reload from file + $this->conf = new ConfigManager($sandboxConf); + $this->assertEquals('http://'. $url, $this->conf->get('plugins.PIWIK_URL')); + } + + /** + * Test updateMethodPiwikUrl without setting + */ + public function testUpdatePiwikUrlEmpty() + { + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodPiwikUrl()); + $this->assertEmpty($this->conf->get('plugins.PIWIK_URL')); + } + + /** + * Test updateMethodPiwikUrl: valid URL, nothing to do + */ + public function testUpdatePiwikUrlNothingToDo() + { + $url = 'https://mypiwik.tld'; + $this->conf->set('plugins.PIWIK_URL', $url); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodPiwikUrl()); + $this->assertEquals($url, $this->conf->get('plugins.PIWIK_URL')); + } + + /** + * Test updateMethodAtomDefault with show_atom set to false + * => update to true. + */ + public function testUpdateMethodAtomDefault() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $this->conf->set('feed.show_atom', false); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodAtomDefault()); + $this->assertTrue($this->conf->get('feed.show_atom')); + // reload from file + $this->conf = new ConfigManager($sandboxConf); + $this->assertTrue($this->conf->get('feed.show_atom')); + } + /** + * Test updateMethodAtomDefault with show_atom not set. + * => nothing to do + */ + public function testUpdateMethodAtomDefaultNoExist() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodAtomDefault()); + $this->assertTrue($this->conf->get('feed.show_atom')); + } + /** + * Test updateMethodAtomDefault with show_atom set to true. + * => nothing to do + */ + public function testUpdateMethodAtomDefaultAlreadyTrue() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $this->conf->set('feed.show_atom', true); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodAtomDefault()); + $this->assertTrue($this->conf->get('feed.show_atom')); + } + + /** + * Test updateMethodDownloadSizeAndTimeoutConf, it should be set if none is already defined. + */ + public function testUpdateMethodDownloadSizeAndTimeoutConf() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf()); + $this->assertEquals(4194304, $this->conf->get('general.download_max_size')); + $this->assertEquals(30, $this->conf->get('general.download_timeout')); + + $this->conf = new ConfigManager($sandboxConf); + $this->assertEquals(4194304, $this->conf->get('general.download_max_size')); + $this->assertEquals(30, $this->conf->get('general.download_timeout')); + } + + /** + * Test updateMethodDownloadSizeAndTimeoutConf, it shouldn't be set if it is already defined. + */ + public function testUpdateMethodDownloadSizeAndTimeoutConfIgnore() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $this->conf->set('general.download_max_size', 38); + $this->conf->set('general.download_timeout', 70); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf()); + $this->assertEquals(38, $this->conf->get('general.download_max_size')); + $this->assertEquals(70, $this->conf->get('general.download_timeout')); + } + + /** + * Test updateMethodDownloadSizeAndTimeoutConf, only the maz size should be set here. + */ + public function testUpdateMethodDownloadSizeAndTimeoutConfOnlySize() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $this->conf->set('general.download_max_size', 38); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf()); + $this->assertEquals(38, $this->conf->get('general.download_max_size')); + $this->assertEquals(30, $this->conf->get('general.download_timeout')); + } + + /** + * Test updateMethodDownloadSizeAndTimeoutConf, only the time out should be set here. + */ + public function testUpdateMethodDownloadSizeAndTimeoutConfOnlyTimeout() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $this->conf->set('general.download_timeout', 3); + $updater = new LegacyUpdater([], [], $this->conf, true); + $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf()); + $this->assertEquals(4194304, $this->conf->get('general.download_max_size')); + $this->assertEquals(3, $this->conf->get('general.download_timeout')); + } + + /** + * Test updateMethodWebThumbnailer with thumbnails enabled. + */ + public function testUpdateMethodWebThumbnailerEnabled() + { + $this->conf->remove('thumbnails'); + $this->conf->set('thumbnail.enable_thumbnails', true); + $updater = new LegacyUpdater([], [], $this->conf, true, $_SESSION); + $this->assertTrue($updater->updateMethodWebThumbnailer()); + $this->assertFalse($this->conf->exists('thumbnail')); + $this->assertEquals(\Shaarli\Thumbnailer::MODE_ALL, $this->conf->get('thumbnails.mode')); + $this->assertEquals(125, $this->conf->get('thumbnails.width')); + $this->assertEquals(90, $this->conf->get('thumbnails.height')); + $this->assertContains('You have enabled or changed thumbnails', $_SESSION['warnings'][0]); + } + + /** + * Test updateMethodWebThumbnailer with thumbnails disabled. + */ + public function testUpdateMethodWebThumbnailerDisabled() + { + if (isset($_SESSION['warnings'])) { + unset($_SESSION['warnings']); + } + + $this->conf->remove('thumbnails'); + $this->conf->set('thumbnail.enable_thumbnails', false); + $updater = new LegacyUpdater([], [], $this->conf, true, $_SESSION); + $this->assertTrue($updater->updateMethodWebThumbnailer()); + $this->assertFalse($this->conf->exists('thumbnail')); + $this->assertEquals(Thumbnailer::MODE_NONE, $this->conf->get('thumbnails.mode')); + $this->assertEquals(125, $this->conf->get('thumbnails.width')); + $this->assertEquals(90, $this->conf->get('thumbnails.height')); + $this->assertTrue(empty($_SESSION['warnings'])); + } + + /** + * Test updateMethodWebThumbnailer with thumbnails disabled. + */ + public function testUpdateMethodWebThumbnailerNothingToDo() + { + if (isset($_SESSION['warnings'])) { + unset($_SESSION['warnings']); + } + + $updater = new LegacyUpdater([], [], $this->conf, true, $_SESSION); + $this->assertTrue($updater->updateMethodWebThumbnailer()); + $this->assertFalse($this->conf->exists('thumbnail')); + $this->assertEquals(Thumbnailer::MODE_COMMON, $this->conf->get('thumbnails.mode')); + $this->assertEquals(90, $this->conf->get('thumbnails.width')); + $this->assertEquals(53, $this->conf->get('thumbnails.height')); + $this->assertTrue(empty($_SESSION['warnings'])); + } + + /** + * Test updateMethodSetSticky(). + */ + public function testUpdateStickyValid() + { + $blank = [ + 'id' => 1, + 'url' => 'z', + 'title' => '', + 'description' => '', + 'tags' => '', + 'created' => new DateTime(), + ]; + $links = [ + 1 => ['id' => 1] + $blank, + 2 => ['id' => 2] + $blank, + ]; + $refDB = new \ReferenceLinkDB(true); + $refDB->setLinks($links); + $refDB->write(self::$testDatastore); + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + + $updater = new LegacyUpdater(array(), $linkDB, $this->conf, true); + $this->assertTrue($updater->updateMethodSetSticky()); + + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + foreach ($linkDB as $link) { + $this->assertFalse($link['sticky']); + } + } + + /** + * Test updateMethodSetSticky(). + */ + public function testUpdateStickyNothingToDo() + { + $blank = [ + 'id' => 1, + 'url' => 'z', + 'title' => '', + 'description' => '', + 'tags' => '', + 'created' => new DateTime(), + ]; + $links = [ + 1 => ['id' => 1, 'sticky' => true] + $blank, + 2 => ['id' => 2] + $blank, + ]; + $refDB = new \ReferenceLinkDB(true); + $refDB->setLinks($links); + $refDB->write(self::$testDatastore); + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + + $updater = new LegacyUpdater(array(), $linkDB, $this->conf, true); + $this->assertTrue($updater->updateMethodSetSticky()); + + $linkDB = new LegacyLinkDB(self::$testDatastore, true, false); + $this->assertTrue($linkDB[1]['sticky']); + } + + /** + * Test updateMethodRemoveRedirector(). + */ + public function testUpdateRemoveRedirector() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $updater = new LegacyUpdater([], null, $this->conf, true); + $this->assertTrue($updater->updateMethodRemoveRedirector()); + $this->assertFalse($this->conf->exists('redirector')); + $this->conf = new ConfigManager($sandboxConf); + $this->assertFalse($this->conf->exists('redirector')); + } + + /** + * Test updateMethodFormatterSetting() + */ + public function testUpdateMethodFormatterSettingDefault() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $this->conf->set('formatter', 'default'); + $updater = new LegacyUpdater([], null, $this->conf, true); + $enabledPlugins = $this->conf->get('general.enabled_plugins'); + $this->assertFalse(in_array('markdown', $enabledPlugins)); + $this->assertTrue($updater->updateMethodFormatterSetting()); + $this->assertEquals('default', $this->conf->get('formatter')); + $this->assertEquals($enabledPlugins, $this->conf->get('general.enabled_plugins')); + + $this->conf = new ConfigManager($sandboxConf); + $this->assertEquals('default', $this->conf->get('formatter')); + $this->assertEquals($enabledPlugins, $this->conf->get('general.enabled_plugins')); + } + + /** + * Test updateMethodFormatterSetting() + */ + public function testUpdateMethodFormatterSettingMarkdown() + { + $sandboxConf = 'sandbox/config'; + copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); + $this->conf = new ConfigManager($sandboxConf); + $this->conf->set('formatter', 'default'); + $updater = new LegacyUpdater([], null, $this->conf, true); + $enabledPlugins = $this->conf->get('general.enabled_plugins'); + $enabledPlugins[] = 'markdown'; + $this->conf->set('general.enabled_plugins', $enabledPlugins); + + $this->assertTrue(in_array('markdown', $this->conf->get('general.enabled_plugins'))); + $this->assertTrue($updater->updateMethodFormatterSetting()); + $this->assertEquals('markdown', $this->conf->get('formatter')); + $this->assertFalse(in_array('markdown', $this->conf->get('general.enabled_plugins'))); + + $this->conf = new ConfigManager($sandboxConf); + $this->assertEquals('markdown', $this->conf->get('formatter')); + $this->assertFalse(in_array('markdown', $this->conf->get('general.enabled_plugins'))); + } +} diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php index 6de9876d..011d19ac 100644 --- a/tests/netscape/BookmarkExportTest.php +++ b/tests/netscape/BookmarkExportTest.php @@ -1,7 +1,12 @@ set('resource.datastore', self::$testDatastore); self::$refDb = new \ReferenceLinkDB(); self::$refDb->write(self::$testDatastore); - self::$linkDb = new LinkDB(self::$testDatastore, true, false); + $history = new History('sandbox/history.php'); + self::$bookmarkService = new BookmarkFileService($conf, $history, true); + $factory = new FormatterFactory($conf); + self::$formatter = $factory->getFormatter('raw'); } /** @@ -42,15 +57,27 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase */ public function testFilterAndFormatInvalid() { - NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'derp', false, ''); + NetscapeBookmarkUtils::filterAndFormat( + self::$bookmarkService, + self::$formatter, + 'derp', + false, + '' + ); } /** - * Prepare all links for export + * Prepare all bookmarks for export */ public function testFilterAndFormatAll() { - $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'all', false, ''); + $links = NetscapeBookmarkUtils::filterAndFormat( + self::$bookmarkService, + self::$formatter, + 'all', + false, + '' + ); $this->assertEquals(self::$refDb->countLinks(), sizeof($links)); foreach ($links as $link) { $date = $link['created']; @@ -66,11 +93,17 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase } /** - * Prepare private links for export + * Prepare private bookmarks for export */ public function testFilterAndFormatPrivate() { - $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'private', false, ''); + $links = NetscapeBookmarkUtils::filterAndFormat( + self::$bookmarkService, + self::$formatter, + 'private', + false, + '' + ); $this->assertEquals(self::$refDb->countPrivateLinks(), sizeof($links)); foreach ($links as $link) { $date = $link['created']; @@ -86,11 +119,17 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase } /** - * Prepare public links for export + * Prepare public bookmarks for export */ public function testFilterAndFormatPublic() { - $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'public', false, ''); + $links = NetscapeBookmarkUtils::filterAndFormat( + self::$bookmarkService, + self::$formatter, + 'public', + false, + '' + ); $this->assertEquals(self::$refDb->countPublicLinks(), sizeof($links)); foreach ($links as $link) { $date = $link['created']; @@ -110,7 +149,13 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase */ public function testFilterAndFormatDoNotPrependNoteUrl() { - $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'public', false, ''); + $links = NetscapeBookmarkUtils::filterAndFormat( + self::$bookmarkService, + self::$formatter, + 'public', + false, + '' + ); $this->assertEquals( '?WDWyig', $links[2]['url'] @@ -124,7 +169,8 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase { $indexUrl = 'http://localhost:7469/shaarli/'; $links = NetscapeBookmarkUtils::filterAndFormat( - self::$linkDb, + self::$bookmarkService, + self::$formatter, 'public', true, $indexUrl diff --git a/tests/netscape/BookmarkImportTest.php b/tests/netscape/BookmarkImportTest.php index ccafc161..fef7f6d1 100644 --- a/tests/netscape/BookmarkImportTest.php +++ b/tests/netscape/BookmarkImportTest.php @@ -2,6 +2,9 @@ namespace Shaarli\Netscape; use DateTime; +use Shaarli\Bookmark\Bookmark; +use Shaarli\Bookmark\BookmarkFilter; +use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Bookmark\LinkDB; use Shaarli\Config\ConfigManager; use Shaarli\History; @@ -41,9 +44,9 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase protected static $historyFilePath = 'sandbox/history.php'; /** - * @var LinkDB private LinkDB instance + * @var BookmarkFileService private LinkDB instance */ - protected $linkDb = null; + protected $bookmarkService = null; /** * @var string Dummy page cache @@ -82,10 +85,12 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase } // start with an empty datastore file_put_contents(self::$testDatastore, ''); - $this->linkDb = new LinkDB(self::$testDatastore, true, false); + $this->conf = new ConfigManager('tests/utils/config/configJson'); $this->conf->set('resource.page_cache', $this->pagecache); + $this->conf->set('resource.datastore', self::$testDatastore); $this->history = new History(self::$historyFilePath); + $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); } /** @@ -112,7 +117,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase .' Nothing was imported.', NetscapeBookmarkUtils::import(null, $files, null, $this->conf, $this->history) ); - $this->assertEquals(0, count($this->linkDb)); + $this->assertEquals(0, $this->bookmarkService->count()); } /** @@ -125,7 +130,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase 'File no_doctype.htm (350 bytes) has an unknown file format. Nothing was imported.', NetscapeBookmarkUtils::import(null, $files, null, $this->conf, $this->history) ); - $this->assertEquals(0, count($this->linkDb)); + $this->assertEquals(0, $this->bookmarkService->count()); } /** @@ -136,10 +141,10 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('lowercase_doctype.htm'); $this->assertStringMatchesFormat( 'File lowercase_doctype.htm (386 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import(null, $files, $this->linkDb, $this->conf, $this->history) + .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import(null, $files, $this->bookmarkService, $this->conf, $this->history) ); - $this->assertEquals(2, count($this->linkDb)); + $this->assertEquals(2, $this->bookmarkService->count()); } @@ -151,25 +156,24 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('internet_explorer_encoding.htm'); $this->assertStringMatchesFormat( 'File internet_explorer_encoding.htm (356 bytes) was successfully processed in %d seconds:' - .' 1 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history) + .' 1 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import([], $files, $this->bookmarkService, $this->conf, $this->history) ); - $this->assertEquals(1, count($this->linkDb)); - $this->assertEquals(0, count_private($this->linkDb)); + $this->assertEquals(1, $this->bookmarkService->count()); + $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + $bookmark = $this->bookmarkService->findByUrl('http://hginit.com/'); + $this->assertEquals(0, $bookmark->getId()); $this->assertEquals( - array( - 'id' => 0, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160618_203944'), - 'title' => 'Hg Init a Mercurial tutorial by Joel Spolsky', - 'url' => 'http://hginit.com/', - 'description' => '', - 'private' => 0, - 'tags' => '', - 'shorturl' => 'La37cg', - ), - $this->linkDb->getLinkFromUrl('http://hginit.com/') + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160618_203944'), + $bookmark->getCreated() ); + $this->assertEquals('Hg Init a Mercurial tutorial by Joel Spolsky', $bookmark->getTitle()); + $this->assertEquals('http://hginit.com/', $bookmark->getUrl()); + $this->assertEquals('', $bookmark->getDescription()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertEquals('', $bookmark->getTagsString()); + $this->assertEquals('La37cg', $bookmark->getShortUrl()); } /** @@ -180,116 +184,115 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('netscape_nested.htm'); $this->assertStringMatchesFormat( 'File netscape_nested.htm (1337 bytes) was successfully processed in %d seconds:' - .' 8 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history) - ); - $this->assertEquals(8, count($this->linkDb)); - $this->assertEquals(2, count_private($this->linkDb)); - - $this->assertEquals( - array( - 'id' => 0, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235541'), - 'title' => 'Nested 1', - 'url' => 'http://nest.ed/1', - 'description' => '', - 'private' => 0, - 'tags' => 'tag1 tag2', - 'shorturl' => 'KyDNKA', - ), - $this->linkDb->getLinkFromUrl('http://nest.ed/1') - ); - $this->assertEquals( - array( - 'id' => 1, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235542'), - 'title' => 'Nested 1-1', - 'url' => 'http://nest.ed/1-1', - 'description' => '', - 'private' => 0, - 'tags' => 'folder1 tag1 tag2', - 'shorturl' => 'T2LnXg', - ), - $this->linkDb->getLinkFromUrl('http://nest.ed/1-1') - ); - $this->assertEquals( - array( - 'id' => 2, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235547'), - 'title' => 'Nested 1-2', - 'url' => 'http://nest.ed/1-2', - 'description' => '', - 'private' => 0, - 'tags' => 'folder1 tag3 tag4', - 'shorturl' => '46SZxA', - ), - $this->linkDb->getLinkFromUrl('http://nest.ed/1-2') - ); - $this->assertEquals( - array( - 'id' => 3, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160202_202222'), - 'title' => 'Nested 2-1', - 'url' => 'http://nest.ed/2-1', - 'description' => 'First link of the second section', - 'private' => 1, - 'tags' => 'folder2', - 'shorturl' => '4UHOSw', - ), - $this->linkDb->getLinkFromUrl('http://nest.ed/2-1') - ); - $this->assertEquals( - array( - 'id' => 4, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160119_230227'), - 'title' => 'Nested 2-2', - 'url' => 'http://nest.ed/2-2', - 'description' => 'Second link of the second section', - 'private' => 1, - 'tags' => 'folder2', - 'shorturl' => 'yfzwbw', - ), - $this->linkDb->getLinkFromUrl('http://nest.ed/2-2') - ); - $this->assertEquals( - array( - 'id' => 5, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160202_202222'), - 'title' => 'Nested 3-1', - 'url' => 'http://nest.ed/3-1', - 'description' => '', - 'private' => 0, - 'tags' => 'folder3 folder3-1 tag3', - 'shorturl' => 'UwxIUQ', - ), - $this->linkDb->getLinkFromUrl('http://nest.ed/3-1') - ); - $this->assertEquals( - array( - 'id' => 6, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160119_230227'), - 'title' => 'Nested 3-2', - 'url' => 'http://nest.ed/3-2', - 'description' => '', - 'private' => 0, - 'tags' => 'folder3 folder3-1', - 'shorturl' => 'p8dyZg', - ), - $this->linkDb->getLinkFromUrl('http://nest.ed/3-2') - ); - $this->assertEquals( - array( - 'id' => 7, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160229_111541'), - 'title' => 'Nested 2', - 'url' => 'http://nest.ed/2', - 'description' => '', - 'private' => 0, - 'tags' => 'tag4', - 'shorturl' => 'Gt3Uug', - ), - $this->linkDb->getLinkFromUrl('http://nest.ed/2') + .' 8 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import([], $files, $this->bookmarkService, $this->conf, $this->history) ); + $this->assertEquals(8, $this->bookmarkService->count()); + $this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + + $bookmark = $this->bookmarkService->findByUrl('http://nest.ed/1'); + $this->assertEquals(0, $bookmark->getId()); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160225_235541'), + $bookmark->getCreated() + ); + $this->assertEquals('Nested 1', $bookmark->getTitle()); + $this->assertEquals('http://nest.ed/1', $bookmark->getUrl()); + $this->assertEquals('', $bookmark->getDescription()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertEquals('tag1 tag2', $bookmark->getTagsString()); + $this->assertEquals('KyDNKA', $bookmark->getShortUrl()); + + $bookmark = $this->bookmarkService->findByUrl('http://nest.ed/1-1'); + $this->assertEquals(1, $bookmark->getId()); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160225_235542'), + $bookmark->getCreated() + ); + $this->assertEquals('Nested 1-1', $bookmark->getTitle()); + $this->assertEquals('http://nest.ed/1-1', $bookmark->getUrl()); + $this->assertEquals('', $bookmark->getDescription()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertEquals('folder1 tag1 tag2', $bookmark->getTagsString()); + $this->assertEquals('T2LnXg', $bookmark->getShortUrl()); + + $bookmark = $this->bookmarkService->findByUrl('http://nest.ed/1-2'); + $this->assertEquals(2, $bookmark->getId()); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160225_235547'), + $bookmark->getCreated() + ); + $this->assertEquals('Nested 1-2', $bookmark->getTitle()); + $this->assertEquals('http://nest.ed/1-2', $bookmark->getUrl()); + $this->assertEquals('', $bookmark->getDescription()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertEquals('folder1 tag3 tag4', $bookmark->getTagsString()); + $this->assertEquals('46SZxA', $bookmark->getShortUrl()); + + $bookmark = $this->bookmarkService->findByUrl('http://nest.ed/2-1'); + $this->assertEquals(3, $bookmark->getId()); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160202_202222'), + $bookmark->getCreated() + ); + $this->assertEquals('Nested 2-1', $bookmark->getTitle()); + $this->assertEquals('http://nest.ed/2-1', $bookmark->getUrl()); + $this->assertEquals('First link of the second section', $bookmark->getDescription()); + $this->assertTrue($bookmark->isPrivate()); + $this->assertEquals('folder2', $bookmark->getTagsString()); + $this->assertEquals('4UHOSw', $bookmark->getShortUrl()); + + $bookmark = $this->bookmarkService->findByUrl('http://nest.ed/2-2'); + $this->assertEquals(4, $bookmark->getId()); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160119_230227'), + $bookmark->getCreated() + ); + $this->assertEquals('Nested 2-2', $bookmark->getTitle()); + $this->assertEquals('http://nest.ed/2-2', $bookmark->getUrl()); + $this->assertEquals('Second link of the second section', $bookmark->getDescription()); + $this->assertTrue($bookmark->isPrivate()); + $this->assertEquals('folder2', $bookmark->getTagsString()); + $this->assertEquals('yfzwbw', $bookmark->getShortUrl()); + + $bookmark = $this->bookmarkService->findByUrl('http://nest.ed/3-1'); + $this->assertEquals(5, $bookmark->getId()); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160202_202222'), + $bookmark->getCreated() + ); + $this->assertEquals('Nested 3-1', $bookmark->getTitle()); + $this->assertEquals('http://nest.ed/3-1', $bookmark->getUrl()); + $this->assertEquals('', $bookmark->getDescription()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertEquals('folder3 folder3-1 tag3', $bookmark->getTagsString()); + $this->assertEquals('UwxIUQ', $bookmark->getShortUrl()); + + $bookmark = $this->bookmarkService->findByUrl('http://nest.ed/3-2'); + $this->assertEquals(6, $bookmark->getId()); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160119_230227'), + $bookmark->getCreated() + ); + $this->assertEquals('Nested 3-2', $bookmark->getTitle()); + $this->assertEquals('http://nest.ed/3-2', $bookmark->getUrl()); + $this->assertEquals('', $bookmark->getDescription()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertEquals('folder3 folder3-1', $bookmark->getTagsString()); + $this->assertEquals('p8dyZg', $bookmark->getShortUrl()); + + $bookmark = $this->bookmarkService->findByUrl('http://nest.ed/2'); + $this->assertEquals(7, $bookmark->getId()); + $this->assertEquals( + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160229_111541'), + $bookmark->getCreated() + ); + $this->assertEquals('Nested 2', $bookmark->getTitle()); + $this->assertEquals('http://nest.ed/2', $bookmark->getUrl()); + $this->assertEquals('', $bookmark->getDescription()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertEquals('tag4', $bookmark->getTagsString()); + $this->assertEquals('Gt3Uug', $bookmark->getShortUrl()); } /** @@ -302,40 +305,38 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('netscape_basic.htm'); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history) + .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import([], $files, $this->bookmarkService, $this->conf, $this->history) ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(1, count_private($this->linkDb)); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(1, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + $bookmark = $this->bookmarkService->findByUrl('https://private.tld'); + $this->assertEquals(0, $bookmark->getId()); $this->assertEquals( - array( - 'id' => 0, - // Old link - UTC+4 (note that TZ in the import file is ignored). - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20001010_135536'), - 'title' => 'Secret stuff', - 'url' => 'https://private.tld', - 'description' => "Super-secret stuff you're not supposed to know about", - 'private' => 1, - 'tags' => 'private secret', - 'shorturl' => 'EokDtA', - ), - $this->linkDb->getLinkFromUrl('https://private.tld') + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20001010_135536'), + $bookmark->getCreated() ); + $this->assertEquals('Secret stuff', $bookmark->getTitle()); + $this->assertEquals('https://private.tld', $bookmark->getUrl()); + $this->assertEquals('Super-secret stuff you\'re not supposed to know about', $bookmark->getDescription()); + $this->assertTrue($bookmark->isPrivate()); + $this->assertEquals('private secret', $bookmark->getTagsString()); + $this->assertEquals('EokDtA', $bookmark->getShortUrl()); + + $bookmark = $this->bookmarkService->findByUrl('http://public.tld'); + $this->assertEquals(1, $bookmark->getId()); $this->assertEquals( - array( - 'id' => 1, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235548'), - 'title' => 'Public stuff', - 'url' => 'http://public.tld', - 'description' => '', - 'private' => 0, - 'tags' => 'public hello world', - 'shorturl' => 'Er9ddA', - ), - $this->linkDb->getLinkFromUrl('http://public.tld') + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160225_235548'), + $bookmark->getCreated() ); + $this->assertEquals('Public stuff', $bookmark->getTitle()); + $this->assertEquals('http://public.tld', $bookmark->getUrl()); + $this->assertEquals('', $bookmark->getDescription()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertEquals('public hello world', $bookmark->getTagsString()); + $this->assertEquals('Er9ddA', $bookmark->getShortUrl()); } /** @@ -347,43 +348,42 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('netscape_basic.htm'); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) + .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(1, count_private($this->linkDb)); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(1, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + + $bookmark = $this->bookmarkService->findByUrl('https://private.tld'); + $this->assertEquals(0, $bookmark->getId()); $this->assertEquals( - array( - 'id' => 0, - // Note that TZ in the import file is ignored. - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20001010_135536'), - 'title' => 'Secret stuff', - 'url' => 'https://private.tld', - 'description' => "Super-secret stuff you're not supposed to know about", - 'private' => 1, - 'tags' => 'private secret', - 'shorturl' => 'EokDtA', - ), - $this->linkDb->getLinkFromUrl('https://private.tld') + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20001010_135536'), + $bookmark->getCreated() ); + $this->assertEquals('Secret stuff', $bookmark->getTitle()); + $this->assertEquals('https://private.tld', $bookmark->getUrl()); + $this->assertEquals('Super-secret stuff you\'re not supposed to know about', $bookmark->getDescription()); + $this->assertTrue($bookmark->isPrivate()); + $this->assertEquals('private secret', $bookmark->getTagsString()); + $this->assertEquals('EokDtA', $bookmark->getShortUrl()); + + $bookmark = $this->bookmarkService->findByUrl('http://public.tld'); + $this->assertEquals(1, $bookmark->getId()); $this->assertEquals( - array( - 'id' => 1, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235548'), - 'title' => 'Public stuff', - 'url' => 'http://public.tld', - 'description' => '', - 'private' => 0, - 'tags' => 'public hello world', - 'shorturl' => 'Er9ddA', - ), - $this->linkDb->getLinkFromUrl('http://public.tld') + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160225_235548'), + $bookmark->getCreated() ); + $this->assertEquals('Public stuff', $bookmark->getTitle()); + $this->assertEquals('http://public.tld', $bookmark->getUrl()); + $this->assertEquals('', $bookmark->getDescription()); + $this->assertFalse($bookmark->isPrivate()); + $this->assertEquals('public hello world', $bookmark->getTagsString()); + $this->assertEquals('Er9ddA', $bookmark->getShortUrl()); } /** - * Import links as public + * Import bookmarks as public */ public function testImportAsPublic() { @@ -391,23 +391,17 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('netscape_basic.htm'); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) - ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(0, count_private($this->linkDb)); - $this->assertEquals( - 0, - $this->linkDb[0]['private'] - ); - $this->assertEquals( - 0, - $this->linkDb[1]['private'] + .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) ); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + $this->assertFalse($this->bookmarkService->get(0)->isPrivate()); + $this->assertFalse($this->bookmarkService->get(1)->isPrivate()); } /** - * Import links as private + * Import bookmarks as private */ public function testImportAsPrivate() { @@ -415,45 +409,34 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('netscape_basic.htm'); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) - ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(2, count_private($this->linkDb)); - $this->assertEquals( - 1, - $this->linkDb['0']['private'] - ); - $this->assertEquals( - 1, - $this->linkDb['1']['private'] + .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) ); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + $this->assertTrue($this->bookmarkService->get(0)->isPrivate()); + $this->assertTrue($this->bookmarkService->get(1)->isPrivate()); } /** - * Overwrite private links so they become public + * Overwrite private bookmarks so they become public */ public function testOverwriteAsPublic() { $files = file2array('netscape_basic.htm'); - // import links as private + // import bookmarks as private $post = array('privacy' => 'private'); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) - ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(2, count_private($this->linkDb)); - $this->assertEquals( - 1, - $this->linkDb[0]['private'] - ); - $this->assertEquals( - 1, - $this->linkDb[1]['private'] + .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) ); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + $this->assertTrue($this->bookmarkService->get(0)->isPrivate()); + $this->assertTrue($this->bookmarkService->get(1)->isPrivate()); + // re-import as public, enable overwriting $post = array( 'privacy' => 'public', @@ -461,45 +444,33 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase ); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 2 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) - ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(0, count_private($this->linkDb)); - $this->assertEquals( - 0, - $this->linkDb[0]['private'] - ); - $this->assertEquals( - 0, - $this->linkDb[1]['private'] + .' 2 bookmarks imported, 2 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) ); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + $this->assertFalse($this->bookmarkService->get(0)->isPrivate()); + $this->assertFalse($this->bookmarkService->get(1)->isPrivate()); } /** - * Overwrite public links so they become private + * Overwrite public bookmarks so they become private */ public function testOverwriteAsPrivate() { $files = file2array('netscape_basic.htm'); - // import links as public + // import bookmarks as public $post = array('privacy' => 'public'); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) - ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(0, count_private($this->linkDb)); - $this->assertEquals( - 0, - $this->linkDb['0']['private'] - ); - $this->assertEquals( - 0, - $this->linkDb['1']['private'] + .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) ); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + $this->assertFalse($this->bookmarkService->get(0)->isPrivate()); + $this->assertFalse($this->bookmarkService->get(1)->isPrivate()); // re-import as private, enable overwriting $post = array( @@ -508,23 +479,17 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase ); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 2 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) - ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(2, count_private($this->linkDb)); - $this->assertEquals( - 1, - $this->linkDb['0']['private'] - ); - $this->assertEquals( - 1, - $this->linkDb['1']['private'] + .' 2 bookmarks imported, 2 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) ); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + $this->assertTrue($this->bookmarkService->get(0)->isPrivate()); + $this->assertTrue($this->bookmarkService->get(1)->isPrivate()); } /** - * Attept to import the same links twice without enabling overwriting + * Attept to import the same bookmarks twice without enabling overwriting */ public function testSkipOverwrite() { @@ -532,21 +497,21 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('netscape_basic.htm'); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) + .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(0, count_private($this->linkDb)); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); // re-import as private, DO NOT enable overwriting $post = array('privacy' => 'private'); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 0 links imported, 0 links overwritten, 2 links skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) + .' 0 bookmarks imported, 0 bookmarks overwritten, 2 bookmarks skipped.', + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(0, count_private($this->linkDb)); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); } /** @@ -561,19 +526,13 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('netscape_basic.htm'); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) - ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(0, count_private($this->linkDb)); - $this->assertEquals( - 'tag1 tag2 tag3 private secret', - $this->linkDb['0']['tags'] - ); - $this->assertEquals( - 'tag1 tag2 tag3 public hello world', - $this->linkDb['1']['tags'] + .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) ); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + $this->assertEquals('tag1 tag2 tag3 private secret', $this->bookmarkService->get(0)->getTagsString()); + $this->assertEquals('tag1 tag2 tag3 public hello world', $this->bookmarkService->get(1)->getTagsString()); } /** @@ -588,18 +547,18 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('netscape_basic.htm'); $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' - .' 2 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) + .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) ); - $this->assertEquals(2, count($this->linkDb)); - $this->assertEquals(0, count_private($this->linkDb)); + $this->assertEquals(2, $this->bookmarkService->count()); + $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); $this->assertEquals( 'tag1& tag2 "tag3" private secret', - $this->linkDb['0']['tags'] + $this->bookmarkService->get(0)->getTagsString() ); $this->assertEquals( 'tag1& tag2 "tag3" public hello world', - $this->linkDb['1']['tags'] + $this->bookmarkService->get(1)->getTagsString() ); } @@ -613,23 +572,14 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('same_date.htm'); $this->assertStringMatchesFormat( 'File same_date.htm (453 bytes) was successfully processed in %d seconds:' - .' 3 links imported, 0 links overwritten, 0 links skipped.', - NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->conf, $this->history) - ); - $this->assertEquals(3, count($this->linkDb)); - $this->assertEquals(0, count_private($this->linkDb)); - $this->assertEquals( - 0, - $this->linkDb[0]['id'] - ); - $this->assertEquals( - 1, - $this->linkDb[1]['id'] - ); - $this->assertEquals( - 2, - $this->linkDb[2]['id'] - ); + .' 3 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', + NetscapeBookmarkUtils::import(array(), $files, $this->bookmarkService, $this->conf, $this->history) + ); + $this->assertEquals(3, $this->bookmarkService->count()); + $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); + $this->assertEquals(0, $this->bookmarkService->get(0)->getId()); + $this->assertEquals(1, $this->bookmarkService->get(1)->getId()); + $this->assertEquals(2, $this->bookmarkService->get(2)->getId()); } public function testImportCreateUpdateHistory() @@ -639,14 +589,14 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase 'overwrite' => 'true', ]; $files = file2array('netscape_basic.htm'); - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history); + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history); $history = $this->history->getHistory(); $this->assertEquals(1, count($history)); $this->assertEquals(History::IMPORT, $history[0]['event']); $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']); // re-import as private, enable overwriting - NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history); + NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history); $history = $this->history->getHistory(); $this->assertEquals(2, count($history)); $this->assertEquals(History::IMPORT, $history[0]['event']); diff --git a/tests/plugins/PluginArchiveorgTest.php b/tests/plugins/PluginArchiveorgTest.php index 510288bb..b9a67adb 100644 --- a/tests/plugins/PluginArchiveorgTest.php +++ b/tests/plugins/PluginArchiveorgTest.php @@ -24,7 +24,7 @@ class PluginArchiveorgTest extends \PHPUnit\Framework\TestCase } /** - * Test render_linklist hook on external links. + * Test render_linklist hook on external bookmarks. */ public function testArchiveorgLinklistOnExternalLinks() { @@ -54,7 +54,7 @@ class PluginArchiveorgTest extends \PHPUnit\Framework\TestCase } /** - * Test render_linklist hook on internal links. + * Test render_linklist hook on internal bookmarks. */ public function testArchiveorgLinklistOnInternalLinks() { diff --git a/tests/plugins/PluginIssoTest.php b/tests/plugins/PluginIssoTest.php index bdfab439..99477205 100644 --- a/tests/plugins/PluginIssoTest.php +++ b/tests/plugins/PluginIssoTest.php @@ -2,7 +2,7 @@ namespace Shaarli\Plugin\Isso; use DateTime; -use Shaarli\Bookmark\LinkDB; +use Shaarli\Bookmark\Bookmark; use Shaarli\Config\ConfigManager; use Shaarli\Plugin\PluginManager; @@ -60,7 +60,7 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase array( 'id' => 12, 'url' => $str, - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date), + 'created' => DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, $date), ) ) ); @@ -85,7 +85,7 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase } /** - * Test isso plugin when multiple links are displayed (shouldn't be displayed). + * Test isso plugin when multiple bookmarks are displayed (shouldn't be displayed). */ public function testIssoMultipleLinks() { @@ -102,13 +102,13 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase 'id' => 12, 'url' => $str, 'shorturl' => $short1 = 'abcd', - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date1), + 'created' => DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, $date1), ), array( 'id' => 13, 'url' => $str . '2', 'shorturl' => $short2 = 'efgh', - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date2), + 'created' => DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, $date2), ), ) ); @@ -136,7 +136,7 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase 'id' => 12, 'url' => $str, 'shorturl' => $short1 = 'abcd', - 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date), + 'created' => DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, $date), ) ), 'search_term' => $str diff --git a/tests/plugins/PluginMarkdownTest.php b/tests/plugins/PluginMarkdownTest.php deleted file mode 100644 index 15fa9ba5..00000000 --- a/tests/plugins/PluginMarkdownTest.php +++ /dev/null @@ -1,316 +0,0 @@ -conf = new ConfigManager('tests/utils/config/configJson'); - $this->conf->set('security.allowed_protocols', ['ftp', 'magnet']); - } - - /** - * Test render_linklist hook. - * Only check that there is basic markdown rendering. - */ - public function testMarkdownLinklist() - { - $markdown = '# My title' . PHP_EOL . 'Very interesting content.'; - $data = array( - 'links' => array( - 0 => array( - 'description' => $markdown, - ), - ), - ); - - $data = hook_markdown_render_linklist($data, $this->conf); - $this->assertNotFalse(strpos($data['links'][0]['description'], '

')); - $this->assertNotFalse(strpos($data['links'][0]['description'], '

')); - - $this->assertEquals($markdown, $data['links'][0]['description_src']); - } - - /** - * Test render_feed hook. - */ - public function testMarkdownFeed() - { - $markdown = '# My title' . PHP_EOL . 'Very interesting content.'; - $markdown .= '— Permalien'; - $data = array( - 'links' => array( - 0 => array( - 'description' => $markdown, - ), - ), - ); - - $data = hook_markdown_render_feed($data, $this->conf); - $this->assertNotFalse(strpos($data['links'][0]['description'], '

')); - $this->assertNotFalse(strpos($data['links'][0]['description'], '

')); - $this->assertStringEndsWith( - '— Permalien

', - $data['links'][0]['description'] - ); - } - - /** - * Test render_daily hook. - * Only check that there is basic markdown rendering. - */ - public function testMarkdownDaily() - { - $markdown = '# My title' . PHP_EOL . 'Very interesting content.'; - $data = array( - // Columns data - 'linksToDisplay' => array( - // nth link - 0 => array( - 'formatedDescription' => $markdown, - ), - ), - ); - - $data = hook_markdown_render_daily($data, $this->conf); - $this->assertNotFalse(strpos($data['linksToDisplay'][0]['formatedDescription'], '

')); - $this->assertNotFalse(strpos($data['linksToDisplay'][0]['formatedDescription'], '

')); - } - - /** - * Test reverse_text2clickable(). - */ - public function testReverseText2clickable() - { - $text = 'stuff http://hello.there/is=someone#here otherstuff'; - $clickableText = text2clickable($text); - $reversedText = reverse_text2clickable($clickableText); - $this->assertEquals($text, $reversedText); - } - - /** - * Test reverse_text2clickable(). - */ - public function testReverseText2clickableHashtags() - { - $text = file_get_contents('tests/plugins/resources/hashtags.raw'); - $md = file_get_contents('tests/plugins/resources/hashtags.md'); - $clickableText = hashtag_autolink($text); - $reversedText = reverse_text2clickable($clickableText); - $this->assertEquals($md, $reversedText); - } - - /** - * Test reverse_nl2br(). - */ - public function testReverseNl2br() - { - $text = 'stuff' . PHP_EOL . 'otherstuff'; - $processedText = nl2br($text); - $reversedText = reverse_nl2br($processedText); - $this->assertEquals($text, $reversedText); - } - - /** - * Test reverse_space2nbsp(). - */ - public function testReverseSpace2nbsp() - { - $text = ' stuff' . PHP_EOL . ' otherstuff and another'; - $processedText = space2nbsp($text); - $reversedText = reverse_space2nbsp($processedText); - $this->assertEquals($text, $reversedText); - } - - public function testReverseFeedPermalink() - { - $text = 'Description... '; - $text .= '— Permalien'; - $expected = 'Description... — [Permalien](http://domain.tld/?0oc_VQ)'; - $processedText = reverse_feed_permalink($text); - - $this->assertEquals($expected, $processedText); - } - - public function testReverseFeedDirectLink() - { - $text = 'Description... '; - $text .= '— Direct link'; - $expected = 'Description... — [Direct link](http://domain.tld/?0oc_VQ)'; - $processedText = reverse_feed_permalink($text); - - $this->assertEquals($expected, $processedText); - } - - public function testReverseLastFeedPermalink() - { - $text = 'Description... '; - $text .= '
Permalien'; - $expected = $text; - $text .= '
Permalien'; - $expected .= '
— [Permalien](http://domain.tld/?0oc_VQ)'; - $processedText = reverse_feed_permalink($text); - - $this->assertEquals($expected, $processedText); - } - - public function testReverseNoFeedPermalink() - { - $text = 'Hello! Where are you from?'; - $expected = $text; - $processedText = reverse_feed_permalink($text); - - $this->assertEquals($expected, $processedText); - } - - /** - * Test sanitize_html(). - */ - public function testSanitizeHtml() - { - $input = '< script src="js.js"/>'; - $input .= '< script attr>alert(\'xss\');'; - $input .= ''; - $output = escape($input); - $input .= 'link'; - $output .= 'link'; - $input .= 'link'; - $output .= 'link'; - $this->assertEquals($output, sanitize_html($input)); - // Do not touch escaped HTML. - $input = escape($input); - $this->assertEquals($input, sanitize_html($input)); - } - - /** - * Test the no markdown tag. - */ - public function testNoMarkdownTag() - { - $str = 'All _work_ and `no play` makes Jack a *dull* boy.'; - $data = array( - 'links' => array(array( - 'description' => $str, - 'tags' => NO_MD_TAG, - 'taglist' => array(NO_MD_TAG), - )) - ); - - $processed = hook_markdown_render_linklist($data, $this->conf); - $this->assertEquals($str, $processed['links'][0]['description']); - - $processed = hook_markdown_render_feed($data, $this->conf); - $this->assertEquals($str, $processed['links'][0]['description']); - - $data = array( - // Columns data - 'linksToDisplay' => array( - // nth link - 0 => array( - 'formatedDescription' => $str, - 'tags' => NO_MD_TAG, - 'taglist' => array(), - ), - ), - ); - - $data = hook_markdown_render_daily($data, $this->conf); - $this->assertEquals($str, $data['linksToDisplay'][0]['formatedDescription']); - } - - /** - * Test that a close value to nomarkdown is not understand as nomarkdown (previous value `.nomarkdown`). - */ - public function testNoMarkdownNotExcactlyMatching() - { - $str = 'All _work_ and `no play` makes Jack a *dull* boy.'; - $data = array( - 'links' => array(array( - 'description' => $str, - 'tags' => '.' . NO_MD_TAG, - 'taglist' => array('.'. NO_MD_TAG), - )) - ); - - $data = hook_markdown_render_feed($data, $this->conf); - $this->assertContains('', $data['links'][0]['description']); - } - - /** - * Make sure that the generated HTML match the reference HTML file. - */ - public function testMarkdownGlobalProcessDescription() - { - $md = file_get_contents('tests/plugins/resources/markdown.md'); - $md = format_description($md); - $html = file_get_contents('tests/plugins/resources/markdown.html'); - - $data = process_markdown( - $md, - $this->conf->get('security.markdown_escape', true), - $this->conf->get('security.allowed_protocols') - ); - $this->assertEquals($html, $data . PHP_EOL); - } - - /** - * Make sure that the HTML tags are escaped. - */ - public function testMarkdownWithHtmlEscape() - { - $md = '**strong** strong'; - $html = '

strong <strong>strong</strong>

'; - $data = array( - 'links' => array( - 0 => array( - 'description' => $md, - ), - ), - ); - $data = hook_markdown_render_linklist($data, $this->conf); - $this->assertEquals($html, $data['links'][0]['description']); - } - - /** - * Make sure that the HTML tags aren't escaped with the setting set to false. - */ - public function testMarkdownWithHtmlNoEscape() - { - $this->conf->set('security.markdown_escape', false); - $md = '**strong** strong'; - $html = '

strong strong

'; - $data = array( - 'links' => array( - 0 => array( - 'description' => $md, - ), - ), - ); - $data = hook_markdown_render_linklist($data, $this->conf); - $this->assertEquals($html, $data['links'][0]['description']); - } -} diff --git a/tests/updater/DummyUpdater.php b/tests/updater/DummyUpdater.php index 9e866f1f..07c7f5c4 100644 --- a/tests/updater/DummyUpdater.php +++ b/tests/updater/DummyUpdater.php @@ -4,6 +4,7 @@ namespace Shaarli\Updater; use Exception; use ReflectionClass; use ReflectionMethod; +use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Bookmark\LinkDB; use Shaarli\Config\ConfigManager; @@ -16,14 +17,14 @@ class DummyUpdater extends Updater /** * Object constructor. * - * @param array $doneUpdates Updates which are already done. - * @param LinkDB $linkDB LinkDB instance. - * @param ConfigManager $conf Configuration Manager instance. - * @param boolean $isLoggedIn True if the user is logged in. + * @param array $doneUpdates Updates which are already done. + * @param BookmarkFileService $bookmarkService LinkDB instance. + * @param ConfigManager $conf Configuration Manager instance. + * @param boolean $isLoggedIn True if the user is logged in. */ - public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn) + public function __construct($doneUpdates, $bookmarkService, $conf, $isLoggedIn) { - parent::__construct($doneUpdates, $linkDB, $conf, $isLoggedIn); + parent::__construct($doneUpdates, $bookmarkService, $conf, $isLoggedIn); // Retrieve all update methods. // For unit test, only retrieve final methods, diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php index ac87e33c..c689982b 100644 --- a/tests/updater/UpdaterTest.php +++ b/tests/updater/UpdaterTest.php @@ -1,15 +1,9 @@ assertEquals(array(), read_updates_file('')); + $this->assertEquals(array(), UpdaterUtils::read_updates_file('')); $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; touch($updatesFile); - $this->assertEquals(array(), read_updates_file($updatesFile)); + $this->assertEquals(array(), UpdaterUtils::read_updates_file($updatesFile)); unlink($updatesFile); } @@ -64,31 +58,31 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; $updatesMethods = array('m1', 'm2', 'm3'); - write_updates_file($updatesFile, $updatesMethods); - $readMethods = read_updates_file($updatesFile); + UpdaterUtils::write_updates_file($updatesFile, $updatesMethods); + $readMethods = UpdaterUtils::read_updates_file($updatesFile); $this->assertEquals($readMethods, $updatesMethods); // Update $updatesMethods[] = 'm4'; - write_updates_file($updatesFile, $updatesMethods); - $readMethods = read_updates_file($updatesFile); + UpdaterUtils::write_updates_file($updatesFile, $updatesMethods); + $readMethods = UpdaterUtils::read_updates_file($updatesFile); $this->assertEquals($readMethods, $updatesMethods); unlink($updatesFile); } /** - * Test errors in write_updates_file(): empty updates file. + * Test errors in UpdaterUtils::write_updates_file(): empty updates file. * * @expectedException Exception * @expectedExceptionMessageRegExp /Updates file path is not set(.*)/ */ public function testWriteEmptyUpdatesFile() { - write_updates_file('', array('test')); + UpdaterUtils::write_updates_file('', array('test')); } /** - * Test errors in write_updates_file(): not writable updates file. + * Test errors in UpdaterUtils::write_updates_file(): not writable updates file. * * @expectedException Exception * @expectedExceptionMessageRegExp /Unable to write(.*)/ @@ -99,7 +93,7 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase touch($updatesFile); chmod($updatesFile, 0444); try { - @write_updates_file($updatesFile, array('test')); + @UpdaterUtils::write_updates_file($updatesFile, array('test')); } catch (Exception $e) { unlink($updatesFile); throw $e; @@ -173,660 +167,4 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase $updater = new DummyUpdater($updates, array(), $this->conf, true); $updater->update(); } - - /** - * Test update mergeDeprecatedConfig: - * 1. init a config file. - * 2. init a options.php file with update value. - * 3. merge. - * 4. check updated value in config file. - */ - public function testUpdateMergeDeprecatedConfig() - { - $this->conf->setConfigFile('tests/utils/config/configPhp'); - $this->conf->reset(); - - $optionsFile = 'tests/updater/options.php'; - $options = 'conf->setConfigFile('tests/updater/config'); - - // merge configs - $updater = new Updater(array(), array(), $this->conf, true); - // This writes a new config file in tests/updater/config.php - $updater->updateMethodMergeDeprecatedConfigFile(); - - // make sure updated field is changed - $this->conf->reload(); - $this->assertTrue($this->conf->get('privacy.default_private_links')); - $this->assertFalse(is_file($optionsFile)); - // Delete the generated file. - unlink($this->conf->getConfigFileExt()); - } - - /** - * Test mergeDeprecatedConfig in without options file. - */ - public function testMergeDeprecatedConfigNoFile() - { - $updater = new Updater(array(), array(), $this->conf, true); - $updater->updateMethodMergeDeprecatedConfigFile(); - - $this->assertEquals('root', $this->conf->get('credentials.login')); - } - - /** - * Test renameDashTags update method. - */ - public function testRenameDashTags() - { - $refDB = new \ReferenceLinkDB(); - $refDB->write(self::$testDatastore); - $linkDB = new LinkDB(self::$testDatastore, true, false); - - $this->assertEmpty($linkDB->filterSearch(array('searchtags' => 'exclude'))); - $updater = new Updater(array(), $linkDB, $this->conf, true); - $updater->updateMethodRenameDashTags(); - $this->assertNotEmpty($linkDB->filterSearch(array('searchtags' => 'exclude'))); - } - - /** - * Convert old PHP config file to JSON config. - */ - public function testConfigToJson() - { - $configFile = 'tests/utils/config/configPhp'; - $this->conf->setConfigFile($configFile); - $this->conf->reset(); - - // The ConfigIO is initialized with ConfigPhp. - $this->assertTrue($this->conf->getConfigIO() instanceof ConfigPhp); - - $updater = new Updater(array(), array(), $this->conf, false); - $done = $updater->updateMethodConfigToJson(); - $this->assertTrue($done); - - // The ConfigIO has been updated to ConfigJson. - $this->assertTrue($this->conf->getConfigIO() instanceof ConfigJson); - $this->assertTrue(file_exists($this->conf->getConfigFileExt())); - - // Check JSON config data. - $this->conf->reload(); - $this->assertEquals('root', $this->conf->get('credentials.login')); - $this->assertEquals('lala', $this->conf->get('redirector.url')); - $this->assertEquals('data/datastore.php', $this->conf->get('resource.datastore')); - $this->assertEquals('1', $this->conf->get('plugins.WALLABAG_VERSION')); - - rename($configFile . '.save.php', $configFile . '.php'); - unlink($this->conf->getConfigFileExt()); - } - - /** - * Launch config conversion update with an existing JSON file => nothing to do. - */ - public function testConfigToJsonNothingToDo() - { - $filetime = filemtime($this->conf->getConfigFileExt()); - $updater = new Updater(array(), array(), $this->conf, false); - $done = $updater->updateMethodConfigToJson(); - $this->assertTrue($done); - $expected = filemtime($this->conf->getConfigFileExt()); - $this->assertEquals($expected, $filetime); - } - - /** - * Test escapeUnescapedConfig with valid data. - */ - public function testEscapeConfig() - { - $sandbox = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandbox . '.json.php'); - $this->conf = new ConfigManager($sandbox); - $title = ''; - $headerLink = ''; - $this->conf->set('general.title', $title); - $this->conf->set('general.header_link', $headerLink); - $updater = new Updater(array(), array(), $this->conf, true); - $done = $updater->updateMethodEscapeUnescapedConfig(); - $this->assertTrue($done); - $this->conf->reload(); - $this->assertEquals(escape($title), $this->conf->get('general.title')); - $this->assertEquals(escape($headerLink), $this->conf->get('general.header_link')); - unlink($sandbox . '.json.php'); - } - - /** - * Test updateMethodApiSettings(): create default settings for the API (enabled + secret). - */ - public function testUpdateApiSettings() - { - $confFile = 'sandbox/config'; - copy(self::$configFile .'.json.php', $confFile .'.json.php'); - $conf = new ConfigManager($confFile); - $updater = new Updater(array(), array(), $conf, true); - - $this->assertFalse($conf->exists('api.enabled')); - $this->assertFalse($conf->exists('api.secret')); - $updater->updateMethodApiSettings(); - $conf->reload(); - $this->assertTrue($conf->get('api.enabled')); - $this->assertTrue($conf->exists('api.secret')); - unlink($confFile .'.json.php'); - } - - /** - * Test updateMethodApiSettings(): already set, do nothing. - */ - public function testUpdateApiSettingsNothingToDo() - { - $confFile = 'sandbox/config'; - copy(self::$configFile .'.json.php', $confFile .'.json.php'); - $conf = new ConfigManager($confFile); - $conf->set('api.enabled', false); - $conf->set('api.secret', ''); - $updater = new Updater(array(), array(), $conf, true); - $updater->updateMethodApiSettings(); - $this->assertFalse($conf->get('api.enabled')); - $this->assertEmpty($conf->get('api.secret')); - unlink($confFile .'.json.php'); - } - - /** - * Test updateMethodDatastoreIds(). - */ - public function testDatastoreIds() - { - $links = array( - '20121206_182539' => array( - 'linkdate' => '20121206_182539', - 'title' => 'Geek and Poke', - 'url' => 'http://geek-and-poke.com/', - 'description' => 'desc', - 'tags' => 'dev cartoon tag1 tag2 tag3 tag4 ', - 'updated' => '20121206_190301', - 'private' => false, - ), - '20121206_172539' => array( - 'linkdate' => '20121206_172539', - 'title' => 'UserFriendly - Samba', - 'url' => 'http://ars.userfriendly.org/cartoons/?id=20010306', - 'description' => '', - 'tags' => 'samba cartoon web', - 'private' => false, - ), - '20121206_142300' => array( - 'linkdate' => '20121206_142300', - 'title' => 'UserFriendly - Web Designer', - 'url' => 'http://ars.userfriendly.org/cartoons/?id=20121206', - 'description' => 'Naming conventions... #private', - 'tags' => 'samba cartoon web', - 'private' => true, - ), - ); - $refDB = new \ReferenceLinkDB(); - $refDB->setLinks($links); - $refDB->write(self::$testDatastore); - $linkDB = new LinkDB(self::$testDatastore, true, false); - - $checksum = hash_file('sha1', self::$testDatastore); - - $this->conf->set('resource.data_dir', 'sandbox'); - $this->conf->set('resource.datastore', self::$testDatastore); - - $updater = new Updater(array(), $linkDB, $this->conf, true); - $this->assertTrue($updater->updateMethodDatastoreIds()); - - $linkDB = new LinkDB(self::$testDatastore, true, false); - - $backup = glob($this->conf->get('resource.data_dir') . '/datastore.'. date('YmdH') .'*.php'); - $backup = $backup[0]; - - $this->assertFileExists($backup); - $this->assertEquals($checksum, hash_file('sha1', $backup)); - unlink($backup); - - $this->assertEquals(3, count($linkDB)); - $this->assertTrue(isset($linkDB[0])); - $this->assertFalse(isset($linkDB[0]['linkdate'])); - $this->assertEquals(0, $linkDB[0]['id']); - $this->assertEquals('UserFriendly - Web Designer', $linkDB[0]['title']); - $this->assertEquals('http://ars.userfriendly.org/cartoons/?id=20121206', $linkDB[0]['url']); - $this->assertEquals('Naming conventions... #private', $linkDB[0]['description']); - $this->assertEquals('samba cartoon web', $linkDB[0]['tags']); - $this->assertTrue($linkDB[0]['private']); - $this->assertEquals( - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_142300'), - $linkDB[0]['created'] - ); - - $this->assertTrue(isset($linkDB[1])); - $this->assertFalse(isset($linkDB[1]['linkdate'])); - $this->assertEquals(1, $linkDB[1]['id']); - $this->assertEquals('UserFriendly - Samba', $linkDB[1]['title']); - $this->assertEquals( - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_172539'), - $linkDB[1]['created'] - ); - - $this->assertTrue(isset($linkDB[2])); - $this->assertFalse(isset($linkDB[2]['linkdate'])); - $this->assertEquals(2, $linkDB[2]['id']); - $this->assertEquals('Geek and Poke', $linkDB[2]['title']); - $this->assertEquals( - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_182539'), - $linkDB[2]['created'] - ); - $this->assertEquals( - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_190301'), - $linkDB[2]['updated'] - ); - } - - /** - * Test updateMethodDatastoreIds() with the update already applied: nothing to do. - */ - public function testDatastoreIdsNothingToDo() - { - $refDB = new \ReferenceLinkDB(); - $refDB->write(self::$testDatastore); - $linkDB = new LinkDB(self::$testDatastore, true, false); - - $this->conf->set('resource.data_dir', 'sandbox'); - $this->conf->set('resource.datastore', self::$testDatastore); - - $checksum = hash_file('sha1', self::$testDatastore); - $updater = new Updater(array(), $linkDB, $this->conf, true); - $this->assertTrue($updater->updateMethodDatastoreIds()); - $this->assertEquals($checksum, hash_file('sha1', self::$testDatastore)); - } - - /** - * Test defaultTheme update with default settings: nothing to do. - */ - public function testDefaultThemeWithDefaultSettings() - { - $sandbox = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandbox . '.json.php'); - $this->conf = new ConfigManager($sandbox); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodDefaultTheme()); - - $this->assertEquals('tpl/', $this->conf->get('resource.raintpl_tpl')); - $this->assertEquals('default', $this->conf->get('resource.theme')); - $this->conf = new ConfigManager($sandbox); - $this->assertEquals('tpl/', $this->conf->get('resource.raintpl_tpl')); - $this->assertEquals('default', $this->conf->get('resource.theme')); - unlink($sandbox . '.json.php'); - } - - /** - * Test defaultTheme update with a custom theme in a subfolder - */ - public function testDefaultThemeWithCustomTheme() - { - $theme = 'iamanartist'; - $sandbox = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandbox . '.json.php'); - $this->conf = new ConfigManager($sandbox); - mkdir('sandbox/'. $theme); - touch('sandbox/'. $theme .'/linklist.html'); - $this->conf->set('resource.raintpl_tpl', 'sandbox/'. $theme .'/'); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodDefaultTheme()); - - $this->assertEquals('sandbox', $this->conf->get('resource.raintpl_tpl')); - $this->assertEquals($theme, $this->conf->get('resource.theme')); - $this->conf = new ConfigManager($sandbox); - $this->assertEquals('sandbox', $this->conf->get('resource.raintpl_tpl')); - $this->assertEquals($theme, $this->conf->get('resource.theme')); - unlink($sandbox . '.json.php'); - unlink('sandbox/'. $theme .'/linklist.html'); - rmdir('sandbox/'. $theme); - } - - /** - * Test updateMethodEscapeMarkdown with markdown plugin enabled - * => setting markdown_escape set to false. - */ - public function testEscapeMarkdownSettingToFalse() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - - $this->conf->set('general.enabled_plugins', ['markdown']); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodEscapeMarkdown()); - $this->assertFalse($this->conf->get('security.markdown_escape')); - - // reload from file - $this->conf = new ConfigManager($sandboxConf); - $this->assertFalse($this->conf->get('security.markdown_escape')); - } - - - /** - * Test updateMethodEscapeMarkdown with markdown plugin disabled - * => setting markdown_escape set to true. - */ - public function testEscapeMarkdownSettingToTrue() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - - $this->conf->set('general.enabled_plugins', []); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodEscapeMarkdown()); - $this->assertTrue($this->conf->get('security.markdown_escape')); - - // reload from file - $this->conf = new ConfigManager($sandboxConf); - $this->assertTrue($this->conf->get('security.markdown_escape')); - } - - /** - * Test updateMethodEscapeMarkdown with nothing to do (setting already enabled) - */ - public function testEscapeMarkdownSettingNothingToDoEnabled() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - $this->conf->set('security.markdown_escape', true); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodEscapeMarkdown()); - $this->assertTrue($this->conf->get('security.markdown_escape')); - } - - /** - * Test updateMethodEscapeMarkdown with nothing to do (setting already disabled) - */ - public function testEscapeMarkdownSettingNothingToDoDisabled() - { - $this->conf->set('security.markdown_escape', false); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodEscapeMarkdown()); - $this->assertFalse($this->conf->get('security.markdown_escape')); - } - - /** - * Test updateMethodPiwikUrl with valid data - */ - public function testUpdatePiwikUrlValid() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - $url = 'mypiwik.tld'; - $this->conf->set('plugins.PIWIK_URL', $url); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodPiwikUrl()); - $this->assertEquals('http://'. $url, $this->conf->get('plugins.PIWIK_URL')); - - // reload from file - $this->conf = new ConfigManager($sandboxConf); - $this->assertEquals('http://'. $url, $this->conf->get('plugins.PIWIK_URL')); - } - - /** - * Test updateMethodPiwikUrl without setting - */ - public function testUpdatePiwikUrlEmpty() - { - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodPiwikUrl()); - $this->assertEmpty($this->conf->get('plugins.PIWIK_URL')); - } - - /** - * Test updateMethodPiwikUrl: valid URL, nothing to do - */ - public function testUpdatePiwikUrlNothingToDo() - { - $url = 'https://mypiwik.tld'; - $this->conf->set('plugins.PIWIK_URL', $url); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodPiwikUrl()); - $this->assertEquals($url, $this->conf->get('plugins.PIWIK_URL')); - } - - /** - * Test updateMethodAtomDefault with show_atom set to false - * => update to true. - */ - public function testUpdateMethodAtomDefault() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - $this->conf->set('feed.show_atom', false); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodAtomDefault()); - $this->assertTrue($this->conf->get('feed.show_atom')); - // reload from file - $this->conf = new ConfigManager($sandboxConf); - $this->assertTrue($this->conf->get('feed.show_atom')); - } - /** - * Test updateMethodAtomDefault with show_atom not set. - * => nothing to do - */ - public function testUpdateMethodAtomDefaultNoExist() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodAtomDefault()); - $this->assertTrue($this->conf->get('feed.show_atom')); - } - /** - * Test updateMethodAtomDefault with show_atom set to true. - * => nothing to do - */ - public function testUpdateMethodAtomDefaultAlreadyTrue() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - $this->conf->set('feed.show_atom', true); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodAtomDefault()); - $this->assertTrue($this->conf->get('feed.show_atom')); - } - - /** - * Test updateMethodDownloadSizeAndTimeoutConf, it should be set if none is already defined. - */ - public function testUpdateMethodDownloadSizeAndTimeoutConf() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf()); - $this->assertEquals(4194304, $this->conf->get('general.download_max_size')); - $this->assertEquals(30, $this->conf->get('general.download_timeout')); - - $this->conf = new ConfigManager($sandboxConf); - $this->assertEquals(4194304, $this->conf->get('general.download_max_size')); - $this->assertEquals(30, $this->conf->get('general.download_timeout')); - } - - /** - * Test updateMethodDownloadSizeAndTimeoutConf, it shouldn't be set if it is already defined. - */ - public function testUpdateMethodDownloadSizeAndTimeoutConfIgnore() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - $this->conf->set('general.download_max_size', 38); - $this->conf->set('general.download_timeout', 70); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf()); - $this->assertEquals(38, $this->conf->get('general.download_max_size')); - $this->assertEquals(70, $this->conf->get('general.download_timeout')); - } - - /** - * Test updateMethodDownloadSizeAndTimeoutConf, only the maz size should be set here. - */ - public function testUpdateMethodDownloadSizeAndTimeoutConfOnlySize() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - $this->conf->set('general.download_max_size', 38); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf()); - $this->assertEquals(38, $this->conf->get('general.download_max_size')); - $this->assertEquals(30, $this->conf->get('general.download_timeout')); - } - - /** - * Test updateMethodDownloadSizeAndTimeoutConf, only the time out should be set here. - */ - public function testUpdateMethodDownloadSizeAndTimeoutConfOnlyTimeout() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - $this->conf->set('general.download_timeout', 3); - $updater = new Updater([], [], $this->conf, true); - $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf()); - $this->assertEquals(4194304, $this->conf->get('general.download_max_size')); - $this->assertEquals(3, $this->conf->get('general.download_timeout')); - } - - /** - * Test updateMethodWebThumbnailer with thumbnails enabled. - */ - public function testUpdateMethodWebThumbnailerEnabled() - { - $this->conf->remove('thumbnails'); - $this->conf->set('thumbnail.enable_thumbnails', true); - $updater = new Updater([], [], $this->conf, true, $_SESSION); - $this->assertTrue($updater->updateMethodWebThumbnailer()); - $this->assertFalse($this->conf->exists('thumbnail')); - $this->assertEquals(\Shaarli\Thumbnailer::MODE_ALL, $this->conf->get('thumbnails.mode')); - $this->assertEquals(125, $this->conf->get('thumbnails.width')); - $this->assertEquals(90, $this->conf->get('thumbnails.height')); - $this->assertContains('You have enabled or changed thumbnails', $_SESSION['warnings'][0]); - } - - /** - * Test updateMethodWebThumbnailer with thumbnails disabled. - */ - public function testUpdateMethodWebThumbnailerDisabled() - { - if (isset($_SESSION['warnings'])) { - unset($_SESSION['warnings']); - } - $this->conf->remove('thumbnails'); - $this->conf->set('thumbnail.enable_thumbnails', false); - $updater = new Updater([], [], $this->conf, true, $_SESSION); - $this->assertTrue($updater->updateMethodWebThumbnailer()); - $this->assertFalse($this->conf->exists('thumbnail')); - $this->assertEquals(Thumbnailer::MODE_NONE, $this->conf->get('thumbnails.mode')); - $this->assertEquals(125, $this->conf->get('thumbnails.width')); - $this->assertEquals(90, $this->conf->get('thumbnails.height')); - $this->assertTrue(empty($_SESSION['warnings'])); - } - - /** - * Test updateMethodWebThumbnailer with thumbnails disabled. - */ - public function testUpdateMethodWebThumbnailerNothingToDo() - { - if (isset($_SESSION['warnings'])) { - unset($_SESSION['warnings']); - } - $updater = new Updater([], [], $this->conf, true, $_SESSION); - $this->assertTrue($updater->updateMethodWebThumbnailer()); - $this->assertFalse($this->conf->exists('thumbnail')); - $this->assertEquals(Thumbnailer::MODE_COMMON, $this->conf->get('thumbnails.mode')); - $this->assertEquals(90, $this->conf->get('thumbnails.width')); - $this->assertEquals(53, $this->conf->get('thumbnails.height')); - $this->assertTrue(empty($_SESSION['warnings'])); - } - - /** - * Test updateMethodSetSticky(). - */ - public function testUpdateStickyValid() - { - $blank = [ - 'id' => 1, - 'url' => 'z', - 'title' => '', - 'description' => '', - 'tags' => '', - 'created' => new DateTime(), - ]; - $links = [ - 1 => ['id' => 1] + $blank, - 2 => ['id' => 2] + $blank, - ]; - $refDB = new \ReferenceLinkDB(); - $refDB->setLinks($links); - $refDB->write(self::$testDatastore); - $linkDB = new LinkDB(self::$testDatastore, true, false); - - $updater = new Updater(array(), $linkDB, $this->conf, true); - $this->assertTrue($updater->updateMethodSetSticky()); - - $linkDB = new LinkDB(self::$testDatastore, true, false); - foreach ($linkDB as $link) { - $this->assertFalse($link['sticky']); - } - } - - /** - * Test updateMethodSetSticky(). - */ - public function testUpdateStickyNothingToDo() - { - $blank = [ - 'id' => 1, - 'url' => 'z', - 'title' => '', - 'description' => '', - 'tags' => '', - 'created' => new DateTime(), - ]; - $links = [ - 1 => ['id' => 1, 'sticky' => true] + $blank, - 2 => ['id' => 2] + $blank, - ]; - $refDB = new \ReferenceLinkDB(); - $refDB->setLinks($links); - $refDB->write(self::$testDatastore); - $linkDB = new LinkDB(self::$testDatastore, true, false); - - $updater = new Updater(array(), $linkDB, $this->conf, true); - $this->assertTrue($updater->updateMethodSetSticky()); - - $linkDB = new LinkDB(self::$testDatastore, true, false); - $this->assertTrue($linkDB[1]['sticky']); - } - - /** - * Test updateMethodRemoveRedirector(). - */ - public function testUpdateRemoveRedirector() - { - $sandboxConf = 'sandbox/config'; - copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); - $this->conf = new ConfigManager($sandboxConf); - $updater = new Updater([], null, $this->conf, true); - $this->assertTrue($updater->updateMethodRemoveRedirector()); - $this->assertFalse($this->conf->exists('redirector')); - $this->conf = new ConfigManager($sandboxConf); - $this->assertFalse($this->conf->exists('redirector')); - } } diff --git a/tests/utils/FakeBookmarkService.php b/tests/utils/FakeBookmarkService.php new file mode 100644 index 00000000..1ec5bc3d --- /dev/null +++ b/tests/utils/FakeBookmarkService.php @@ -0,0 +1,18 @@ +bookmarks; + } +} diff --git a/tests/utils/ReferenceHistory.php b/tests/utils/ReferenceHistory.php index e411c417..516c9f51 100644 --- a/tests/utils/ReferenceHistory.php +++ b/tests/utils/ReferenceHistory.php @@ -76,7 +76,7 @@ class ReferenceHistory } /** - * Returns the number of links in the reference data + * Returns the number of bookmarks in the reference data */ public function count() { diff --git a/tests/utils/ReferenceLinkDB.php b/tests/utils/ReferenceLinkDB.php index c12bcb67..0095f5a1 100644 --- a/tests/utils/ReferenceLinkDB.php +++ b/tests/utils/ReferenceLinkDB.php @@ -1,30 +1,39 @@ isLegacy = $isLegacy; + if (! $this->isLegacy) { + $this->bookmarks = new BookmarkArray(); + } $this->addLink( 11, 'Pined older', '?PCRizQ', 'This is an older pinned link', 0, - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20100309_101010'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20100309_101010'), '', null, 'PCRizQ', @@ -37,7 +46,7 @@ class ReferenceLinkDB '?0gCTjQ', 'This is a pinned link', 0, - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121207_152312'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121207_152312'), '', null, '0gCTjQ', @@ -50,7 +59,7 @@ class ReferenceLinkDB '?WDWyig', 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag', 0, - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), 'sTuff', null, 'WDWyig' @@ -60,9 +69,9 @@ class ReferenceLinkDB 42, 'Note: I have a big ID but an old date', '?WDWyig', - 'Used to test links reordering.', + 'Used to test bookmarks reordering.', 0, - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20100310_101010'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20100310_101010'), 'ut' ); @@ -72,7 +81,7 @@ class ReferenceLinkDB 'http://www.php-fig.org/psr/psr-2/', 'This guide extends and expands on PSR-1, the basic coding standard.', 0, - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_152312'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121206_152312'), '' ); @@ -82,9 +91,9 @@ class ReferenceLinkDB 'https://static.fsf.org/nosvn/faif-2.0.pdf', 'Richard Stallman and the Free Software Revolution. Read this. #hashtag', 0, - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114633'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114633'), 'free gnu software stallman -exclude stuff hashtag', - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160803_093033') + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160803_093033') ); $this->addLink( @@ -93,9 +102,9 @@ class ReferenceLinkDB 'http://mediagoblin.org/', 'A free software media publishing platform #hashtagOther', 0, - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20130614_184135'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20130614_184135'), 'gnu media web .hidden hashtag', - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20130615_184230'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20130615_184230'), 'IuWvgA' ); @@ -105,7 +114,7 @@ class ReferenceLinkDB 'https://dvcs.w3.org/hg/markup-validator/summary', 'Mercurial repository for the W3C Validator #private', 1, - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20141125_084734'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20141125_084734'), 'css html w3c web Mercurial' ); @@ -115,7 +124,7 @@ class ReferenceLinkDB 'http://ars.userfriendly.org/cartoons/?id=20121206', 'Naming conventions... #private', 0, - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_142300'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121206_142300'), 'dev cartoon web' ); @@ -125,7 +134,7 @@ class ReferenceLinkDB 'http://ars.userfriendly.org/cartoons/?id=20010306', 'Tropical printing', 0, - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_172539'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121206_172539'), 'samba cartoon web' ); @@ -135,7 +144,7 @@ class ReferenceLinkDB 'http://geek-and-poke.com/', '', 1, - DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_182539'), + DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121206_182539'), 'dev cartoon tag1 tag2 tag3 tag4 ' ); } @@ -164,10 +173,15 @@ class ReferenceLinkDB 'tags' => $tags, 'created' => $date, 'updated' => $updated, - 'shorturl' => $shorturl ? $shorturl : smallHash($date->format(LinkDB::LINK_DATE_FORMAT) . $id), + 'shorturl' => $shorturl ? $shorturl : smallHash($date->format(Bookmark::LINK_DATE_FORMAT) . $id), 'sticky' => $pinned ); - $this->_links[$id] = $link; + if (! $this->isLegacy) { + $bookmark = new Bookmark(); + $this->bookmarks[$id] = $bookmark->fromArray($link); + } else { + $this->bookmarks[$id] = $link; + } if ($private) { $this->_privateCount++; @@ -184,37 +198,38 @@ class ReferenceLinkDB $this->reorder(); file_put_contents( $filename, - '_links))).' */ ?>' + 'bookmarks))).' */ ?>' ); } /** * Reorder links by creation date (newest first). * - * Also update the urls and ids mapping arrays. - * * @param string $order ASC|DESC */ public function reorder($order = 'DESC') { - // backward compatibility: ignore reorder if the the `created` field doesn't exist - if (! isset(array_values($this->_links)[0]['created'])) { - return; - } - - $order = $order === 'ASC' ? -1 : 1; - // Reorder array by dates. - usort($this->_links, function ($a, $b) use ($order) { - if (isset($a['sticky']) && isset($b['sticky']) && $a['sticky'] !== $b['sticky']) { - return $a['sticky'] ? -1 : 1; + if (! $this->isLegacy) { + $this->bookmarks->reorder($order); + } else { + $order = $order === 'ASC' ? -1 : 1; + // backward compatibility: ignore reorder if the the `created` field doesn't exist + if (! isset(array_values($this->bookmarks)[0]['created'])) { + return; } - return $a['created'] < $b['created'] ? 1 * $order : -1 * $order; - }); + usort($this->bookmarks, function ($a, $b) use ($order) { + if (isset($a['sticky']) && isset($b['sticky']) && $a['sticky'] !== $b['sticky']) { + return $a['sticky'] ? -1 : 1; + } + + return $a['created'] < $b['created'] ? 1 * $order : -1 * $order; + }); + } } /** - * Returns the number of links in the reference data + * Returns the number of bookmarks in the reference data */ public function countLinks() { @@ -222,7 +237,7 @@ class ReferenceLinkDB } /** - * Returns the number of public links in the reference data + * Returns the number of public bookmarks in the reference data */ public function countPublicLinks() { @@ -230,7 +245,7 @@ class ReferenceLinkDB } /** - * Returns the number of private links in the reference data + * Returns the number of private bookmarks in the reference data */ public function countPrivateLinks() { @@ -238,14 +253,20 @@ class ReferenceLinkDB } /** - * Returns the number of links without tag + * Returns the number of bookmarks without tag */ public function countUntaggedLinks() { $cpt = 0; - foreach ($this->_links as $link) { - if (empty($link['tags'])) { - ++$cpt; + foreach ($this->bookmarks as $link) { + if (! $this->isLegacy) { + if (empty($link->getTags())) { + ++$cpt; + } + } else { + if (empty($link['tags'])) { + ++$cpt; + } } } return $cpt; @@ -254,16 +275,16 @@ class ReferenceLinkDB public function getLinks() { $this->reorder(); - return $this->_links; + return $this->bookmarks; } /** * Setter to override link creation. * - * @param array $links List of links. + * @param array $links List of bookmarks. */ public function setLinks($links) { - $this->_links = $links; + $this->bookmarks = $links; } } diff --git a/tests/utils/config/configJson.json.php b/tests/utils/config/configJson.json.php index 1549ddfc..b04dc303 100644 --- a/tests/utils/config/configJson.json.php +++ b/tests/utils/config/configJson.json.php @@ -41,12 +41,12 @@ "foo": "bar" }, "resource": { - "datastore": "tests\/utils\/config\/datastore.php", + "datastore": "sandbox/datastore.php", "data_dir": "sandbox\/", "raintpl_tpl": "tpl\/", "config": "data\/config.php", "ban_file": "data\/ipbans.php", - "updates": "data\/updates.txt", + "updates": "sandbox/updates.txt", "log": "data\/log.txt", "update_check": "data\/lastupdatecheck.txt", "history": "data\/history.php", @@ -59,7 +59,7 @@ "WALLABAG_VERSION": 1 }, "dev": { - "debug": true + "debug": false }, "updates": { "check_updates": false, -- cgit v1.2.3 From a39acb2518f272df8a601af72c13eabe2719dcb8 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 18 Jan 2020 11:33:23 +0100 Subject: Fix an issue with private tags and fix nomarkdown tag The new bookmark service wasn't handling private tags properly. nomarkdown tag is now shown only for logged in user in bookmarks, and hidden for everyone in tag clouds/lists. Fixes #726 --- tests/bookmark/BookmarkFileServiceTest.php | 41 +++++++++++++++++++++++ tests/feed/FeedBuilderTest.php | 2 +- tests/formatter/BookmarkDefaultFormatterTest.php | 23 ++++++++++++- tests/formatter/BookmarkMarkdownFormatterTest.php | 2 +- tests/formatter/BookmarkRawFormatterTest.php | 2 +- tests/formatter/FormatterFactoryTest.php | 2 +- tests/netscape/BookmarkExportTest.php | 2 +- 7 files changed, 68 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php index 1b438a7f..4900d41d 100644 --- a/tests/bookmark/BookmarkFileServiceTest.php +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -12,6 +12,7 @@ use ReflectionClass; use Shaarli; use Shaarli\Bookmark\Exception\BookmarkNotFoundException; use Shaarli\Config\ConfigManager; +use Shaarli\Formatter\BookmarkMarkdownFormatter; use Shaarli\History; /** @@ -1025,6 +1026,46 @@ class BookmarkFileServiceTest extends TestCase $this->assertEquals($expected, $tags, var_export($tags, true)); } + /** + * Test linksCountPerTag public tags with filter. + * Equal occurrences should be sorted alphabetically. + */ + public function testCountTagsNoMarkdown() + { + $expected = [ + 'cartoon' => 3, + 'dev' => 2, + 'tag1' => 1, + 'tag2' => 1, + 'tag3' => 1, + 'tag4' => 1, + 'web' => 4, + 'gnu' => 2, + 'hashtag' => 2, + 'sTuff' => 2, + '-exclude' => 1, + '.hidden' => 1, + 'Mercurial' => 1, + 'css' => 1, + 'free' => 1, + 'html' => 1, + 'media' => 1, + 'newTagToCount' => 1, + 'samba' => 1, + 'software' => 1, + 'stallman' => 1, + 'ut' => 1, + 'w3c' => 1, + ]; + $bookmark = new Bookmark(); + $bookmark->setTags(['newTagToCount', BookmarkMarkdownFormatter::NO_MD_TAG]); + $this->privateLinkDB->add($bookmark); + + $tags = $this->privateLinkDB->bookmarksCountPerTag(); + + $this->assertEquals($expected, $tags, var_export($tags, true)); + } + /** * Allows to test LinkDB's private methods * diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php index a43ff672..54671891 100644 --- a/tests/feed/FeedBuilderTest.php +++ b/tests/feed/FeedBuilderTest.php @@ -51,7 +51,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $refLinkDB = new \ReferenceLinkDB(); $refLinkDB->write(self::$testDatastore); $history = new History('sandbox/history.php'); - $factory = new FormatterFactory($conf); + $factory = new FormatterFactory($conf, true); self::$formatter = $factory->getFormatter(); self::$bookmarkService = new BookmarkFileService($conf, $history, true); diff --git a/tests/formatter/BookmarkDefaultFormatterTest.php b/tests/formatter/BookmarkDefaultFormatterTest.php index fe42a208..382a560e 100644 --- a/tests/formatter/BookmarkDefaultFormatterTest.php +++ b/tests/formatter/BookmarkDefaultFormatterTest.php @@ -29,7 +29,7 @@ class BookmarkDefaultFormatterTest extends TestCase { copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php'); $this->conf = new ConfigManager(self::$testConf); - $this->formatter = new BookmarkDefaultFormatter($this->conf); + $this->formatter = new BookmarkDefaultFormatter($this->conf, true); } /** @@ -153,4 +153,25 @@ class BookmarkDefaultFormatterTest extends TestCase $link['description'] ); } + + /** + * Make sure that private tags are properly filtered out when the user is logged out. + */ + public function testFormatTagListRemovePrivate(): void + { + $this->formatter = new BookmarkDefaultFormatter($this->conf, false); + + $bookmark = new Bookmark(); + $bookmark->setId($id = 11); + $bookmark->setTags($tags = ['bookmark', '.private', 'othertag']); + + $link = $this->formatter->format($bookmark); + + unset($tags[1]); + $tags = array_values($tags); + + $this->assertSame(11, $link['id']); + $this->assertSame($tags, $link['taglist']); + $this->assertSame(implode(' ', $tags), $link['tags']); + } } diff --git a/tests/formatter/BookmarkMarkdownFormatterTest.php b/tests/formatter/BookmarkMarkdownFormatterTest.php index 0ca7f802..f1f12c04 100644 --- a/tests/formatter/BookmarkMarkdownFormatterTest.php +++ b/tests/formatter/BookmarkMarkdownFormatterTest.php @@ -29,7 +29,7 @@ class BookmarkMarkdownFormatterTest extends TestCase { copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php'); $this->conf = new ConfigManager(self::$testConf); - $this->formatter = new BookmarkMarkdownFormatter($this->conf); + $this->formatter = new BookmarkMarkdownFormatter($this->conf, true); } /** diff --git a/tests/formatter/BookmarkRawFormatterTest.php b/tests/formatter/BookmarkRawFormatterTest.php index ceb6fb73..4491b035 100644 --- a/tests/formatter/BookmarkRawFormatterTest.php +++ b/tests/formatter/BookmarkRawFormatterTest.php @@ -29,7 +29,7 @@ class BookmarkRawFormatterTest extends TestCase { copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php'); $this->conf = new ConfigManager(self::$testConf); - $this->formatter = new BookmarkRawFormatter($this->conf); + $this->formatter = new BookmarkRawFormatter($this->conf, true); } /** diff --git a/tests/formatter/FormatterFactoryTest.php b/tests/formatter/FormatterFactoryTest.php index 317c0b2d..5adf3ffd 100644 --- a/tests/formatter/FormatterFactoryTest.php +++ b/tests/formatter/FormatterFactoryTest.php @@ -28,7 +28,7 @@ class FormatterFactoryTest extends TestCase { copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php'); $this->conf = new ConfigManager(self::$testConf); - $this->factory = new FormatterFactory($this->conf); + $this->factory = new FormatterFactory($this->conf, true); } /** diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php index 011d19ac..6c948bba 100644 --- a/tests/netscape/BookmarkExportTest.php +++ b/tests/netscape/BookmarkExportTest.php @@ -46,7 +46,7 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase self::$refDb->write(self::$testDatastore); $history = new History('sandbox/history.php'); self::$bookmarkService = new BookmarkFileService($conf, $history, true); - $factory = new FormatterFactory($conf); + $factory = new FormatterFactory($conf, true); self::$formatter = $factory->getFormatter('raw'); } -- cgit v1.2.3 From 6c50a6ccceecf54850e62c312ab2397b84d89ab4 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 18 Jan 2020 17:50:11 +0100 Subject: Render login page through Slim controller --- tests/container/ContainerBuilderTest.php | 49 +++++++ tests/front/ShaarliMiddlewareTest.php | 70 ++++++++++ tests/front/controller/LoginControllerTest.php | 173 +++++++++++++++++++++++++ 3 files changed, 292 insertions(+) create mode 100644 tests/container/ContainerBuilderTest.php create mode 100644 tests/front/ShaarliMiddlewareTest.php create mode 100644 tests/front/controller/LoginControllerTest.php (limited to 'tests') diff --git a/tests/container/ContainerBuilderTest.php b/tests/container/ContainerBuilderTest.php new file mode 100644 index 00000000..9b97ed6d --- /dev/null +++ b/tests/container/ContainerBuilderTest.php @@ -0,0 +1,49 @@ +conf = new ConfigManager('tests/utils/config/configJson'); + $this->sessionManager = $this->createMock(SessionManager::class); + $this->loginManager = $this->createMock(LoginManager::class); + + $this->containerBuilder = new ContainerBuilder($this->conf, $this->sessionManager, $this->loginManager); + } + + public function testBuildContainer(): void + { + $container = $this->containerBuilder->build(); + + static::assertInstanceOf(ConfigManager::class, $container->conf); + static::assertInstanceOf(SessionManager::class, $container->sessionManager); + static::assertInstanceOf(LoginManager::class, $container->loginManager); + static::assertInstanceOf(History::class, $container->history); + static::assertInstanceOf(BookmarkServiceInterface::class, $container->bookmarkService); + static::assertInstanceOf(PageBuilder::class, $container->pageBuilder); + } +} diff --git a/tests/front/ShaarliMiddlewareTest.php b/tests/front/ShaarliMiddlewareTest.php new file mode 100644 index 00000000..80974f37 --- /dev/null +++ b/tests/front/ShaarliMiddlewareTest.php @@ -0,0 +1,70 @@ +container = $this->createMock(ShaarliContainer::class); + $this->middleware = new ShaarliMiddleware($this->container); + } + + public function testMiddlewareExecution(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + $controller = function (Request $request, Response $response): Response { + return $response->withStatus(418); // I'm a tea pot + }; + + /** @var Response $result */ + $result = $this->middleware->__invoke($request, $response, $controller); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(418, $result->getStatusCode()); + } + + public function testMiddlewareExecutionWithException(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + $controller = function (): void { + $exception = new LoginBannedException(); + + throw new $exception; + }; + + $pageBuilder = $this->createMock(PageBuilder::class); + $pageBuilder->method('render')->willReturnCallback(function (string $message): string { + return $message; + }); + $this->container->pageBuilder = $pageBuilder; + + $conf = $this->createMock(ConfigManager::class); + $this->container->conf = $conf; + + /** @var Response $result */ + $result = $this->middleware->__invoke($request, $response, $controller); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(401, $result->getStatusCode()); + static::assertContains('error', (string) $result->getBody()); + } +} diff --git a/tests/front/controller/LoginControllerTest.php b/tests/front/controller/LoginControllerTest.php new file mode 100644 index 00000000..ddcfe154 --- /dev/null +++ b/tests/front/controller/LoginControllerTest.php @@ -0,0 +1,173 @@ +container = $this->createMock(ShaarliContainer::class); + $this->controller = new LoginController($this->container); + } + + public function testValidControllerInvoke(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); + $response = new Response(); + + $assignedVariables = []; + $this->container->pageBuilder + ->expects(static::exactly(3)) + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { + $assignedVariables[$key] = $value; + + return $this; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(200, $result->getStatusCode()); + static::assertSame('loginform', (string) $result->getBody()); + + static::assertSame('> referer', $assignedVariables['returnurl']); + static::assertSame(true, $assignedVariables['remember_user_default']); + static::assertSame('Login - Shaarli', $assignedVariables['pagetitle']); + } + + public function testValidControllerInvokeWithUserName(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); + $request->expects(static::exactly(2))->method('getParam')->willReturn('myUser>'); + $response = new Response(); + + $assignedVariables = []; + $this->container->pageBuilder + ->expects(static::exactly(4)) + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { + $assignedVariables[$key] = $value; + + return $this; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(200, $result->getStatusCode()); + static::assertSame('loginform', (string) $result->getBody()); + + static::assertSame('myUser>', $assignedVariables['username']); + static::assertSame('> referer', $assignedVariables['returnurl']); + static::assertSame(true, $assignedVariables['remember_user_default']); + static::assertSame('Login - Shaarli', $assignedVariables['pagetitle']); + } + + public function testLoginControllerWhileLoggedIn(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $loginManager = $this->createMock(LoginManager::class); + $loginManager->expects(static::once())->method('isLoggedIn')->willReturn(true); + $this->container->loginManager = $loginManager; + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('Location')); + } + + public function testLoginControllerOpenShaarli(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $conf = $this->createMock(ConfigManager::class); + $conf->method('get')->willReturnCallback(function (string $parameter, $default) { + if ($parameter === 'security.open_shaarli') { + return true; + } + return $default; + }); + $this->container->conf = $conf; + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('Location')); + } + + public function testLoginControllerWhileBanned(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $loginManager = $this->createMock(LoginManager::class); + $loginManager->method('isLoggedIn')->willReturn(false); + $loginManager->method('canLogin')->willReturn(false); + $this->container->loginManager = $loginManager; + + $this->expectException(LoginBannedException::class); + + $this->controller->index($request, $response); + } + + protected function createValidContainerMockSet(): void + { + // User logged out + $loginManager = $this->createMock(LoginManager::class); + $loginManager->method('isLoggedIn')->willReturn(false); + $loginManager->method('canLogin')->willReturn(true); + $this->container->loginManager = $loginManager; + + // Config + $conf = $this->createMock(ConfigManager::class); + $conf->method('get')->willReturnCallback(function (string $parameter, $default) { + return $default; + }); + $this->container->conf = $conf; + + // PageBuilder + $pageBuilder = $this->createMock(PageBuilder::class); + $pageBuilder + ->method('render') + ->willReturnCallback(function (string $template): string { + return $template; + }) + ; + $this->container->pageBuilder = $pageBuilder; + } +} -- cgit v1.2.3 From 9e4cc28e2957e1f7df713d52a03e350d728dc58e Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Thu, 23 Jan 2020 20:05:41 +0100 Subject: Fix all existing links and redirection to ?do=login --- tests/UtilsTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php index 8225d95a..26d2a6b8 100644 --- a/tests/UtilsTest.php +++ b/tests/UtilsTest.php @@ -203,7 +203,7 @@ class UtilsTest extends PHPUnit\Framework\TestCase public function testGenerateLocationLoop() { $ref = 'http://localhost/?test'; - $this->assertEquals('?', generateLocation($ref, 'localhost', array('test'))); + $this->assertEquals('./?', generateLocation($ref, 'localhost', array('test'))); } /** @@ -212,7 +212,7 @@ class UtilsTest extends PHPUnit\Framework\TestCase public function testGenerateLocationOut() { $ref = 'http://somewebsite.com/?test'; - $this->assertEquals('?', generateLocation($ref, 'localhost')); + $this->assertEquals('./?', generateLocation($ref, 'localhost')); } -- cgit v1.2.3 From 0498b209b551cad5595312583e5d6fb1bc3303a5 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Thu, 23 Jan 2020 20:06:32 +0100 Subject: Execute common plugin hooks before rendering login page --- tests/front/controller/LoginControllerTest.php | 9 +- tests/front/controller/ShaarliControllerTest.php | 116 +++++++++++++++++++++++ 2 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 tests/front/controller/ShaarliControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/LoginControllerTest.php b/tests/front/controller/LoginControllerTest.php index ddcfe154..8cf8ece7 100644 --- a/tests/front/controller/LoginControllerTest.php +++ b/tests/front/controller/LoginControllerTest.php @@ -5,9 +5,11 @@ declare(strict_types=1); namespace Shaarli\Front\Controller; use PHPUnit\Framework\TestCase; +use Shaarli\Bookmark\BookmarkServiceInterface; use Shaarli\Config\ConfigManager; use Shaarli\Container\ShaarliContainer; use Shaarli\Front\Exception\LoginBannedException; +use Shaarli\Plugin\PluginManager; use Shaarli\Render\PageBuilder; use Shaarli\Security\LoginManager; use Slim\Http\Request; @@ -37,7 +39,6 @@ class LoginControllerTest extends TestCase $assignedVariables = []; $this->container->pageBuilder - ->expects(static::exactly(3)) ->method('assign') ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { $assignedVariables[$key] = $value; @@ -68,7 +69,6 @@ class LoginControllerTest extends TestCase $assignedVariables = []; $this->container->pageBuilder - ->expects(static::exactly(4)) ->method('assign') ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { $assignedVariables[$key] = $value; @@ -169,5 +169,10 @@ class LoginControllerTest extends TestCase }) ; $this->container->pageBuilder = $pageBuilder; + + $pluginManager = $this->createMock(PluginManager::class); + $this->container->pluginManager = $pluginManager; + $bookmarkService = $this->createMock(BookmarkServiceInterface::class); + $this->container->bookmarkService = $bookmarkService; } } diff --git a/tests/front/controller/ShaarliControllerTest.php b/tests/front/controller/ShaarliControllerTest.php new file mode 100644 index 00000000..6fa3feb9 --- /dev/null +++ b/tests/front/controller/ShaarliControllerTest.php @@ -0,0 +1,116 @@ +container = $this->createMock(ShaarliContainer::class); + $this->controller = new class($this->container) extends ShaarliController + { + public function assignView(string $key, $value): ShaarliController + { + return parent::assignView($key, $value); + } + + public function render(string $template): string + { + return parent::render($template); + } + }; + $this->assignedValues = []; + } + + public function testAssignView(): void + { + $this->createValidContainerMockSet(); + + $self = $this->controller->assignView('variableName', 'variableValue'); + + static::assertInstanceOf(ShaarliController::class, $self); + static::assertSame('variableValue', $this->assignedValues['variableName']); + } + + public function testRender(): void + { + $this->createValidContainerMockSet(); + + $render = $this->controller->render('templateName'); + + static::assertSame('templateName', $render); + + static::assertSame(10, $this->assignedValues['linkcount']); + static::assertSame(5, $this->assignedValues['privateLinkcount']); + static::assertSame(['error'], $this->assignedValues['plugin_errors']); + + static::assertSame('templateName', $this->assignedValues['plugins_includes']['render_includes']['target']); + static::assertTrue($this->assignedValues['plugins_includes']['render_includes']['loggedin']); + static::assertSame('templateName', $this->assignedValues['plugins_header']['render_header']['target']); + static::assertTrue($this->assignedValues['plugins_header']['render_header']['loggedin']); + static::assertSame('templateName', $this->assignedValues['plugins_footer']['render_footer']['target']); + static::assertTrue($this->assignedValues['plugins_footer']['render_footer']['loggedin']); + } + + protected function createValidContainerMockSet(): void + { + $pageBuilder = $this->createMock(PageBuilder::class); + $pageBuilder + ->method('assign') + ->willReturnCallback(function (string $key, $value): void { + $this->assignedValues[$key] = $value; + }); + $pageBuilder + ->method('render') + ->willReturnCallback(function (string $template): string { + return $template; + }); + $this->container->pageBuilder = $pageBuilder; + + $bookmarkService = $this->createMock(BookmarkServiceInterface::class); + $bookmarkService + ->method('count') + ->willReturnCallback(function (string $visibility): int { + return $visibility === BookmarkFilter::$PRIVATE ? 5 : 10; + }); + $this->container->bookmarkService = $bookmarkService; + + $pluginManager = $this->createMock(PluginManager::class); + $pluginManager + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array &$data, array $params): array { + return $data[$hook] = $params; + }); + $pluginManager->method('getErrors')->willReturn(['error']); + $this->container->pluginManager = $pluginManager; + + $loginManager = $this->createMock(LoginManager::class); + $loginManager->method('isLoggedIn')->willReturn(true); + $this->container->loginManager = $loginManager; + } +} -- cgit v1.2.3 From cc2ded54e12e3f3140b895067af086cd71cc5dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20NOBILI?= Date: Mon, 2 Mar 2020 17:08:19 +0100 Subject: ldap authentication, fixes shaarli/Shaarli#1343 --- tests/security/LoginManagerTest.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'tests') diff --git a/tests/security/LoginManagerTest.php b/tests/security/LoginManagerTest.php index eef0f22a..f2d78802 100644 --- a/tests/security/LoginManagerTest.php +++ b/tests/security/LoginManagerTest.php @@ -78,6 +78,7 @@ class LoginManagerTest extends TestCase 'security.ban_after' => 2, 'security.ban_duration' => 3600, 'security.trusted_proxies' => [$this->trustedProxy], + 'ldap.host' => '', ]); $this->cookie = []; @@ -296,4 +297,37 @@ class LoginManagerTest extends TestCase $this->loginManager->checkCredentials('', '', $this->login, $this->password) ); } + + /** + * Check user credentials through LDAP - server unreachable + */ + public function testCheckCredentialsFromUnreachableLdap() + { + $this->configManager->set('ldap.host', 'dummy'); + $this->assertFalse( + $this->loginManager->checkCredentials('', '', $this->login, $this->password) + ); + } + + /** + * Check user credentials through LDAP - wrong login and password supplied + */ + public function testCheckCredentialsFromLdapWrongLoginAndPassword() + { + $this->coddnfigManager->set('ldap.host', 'dummy'); + $this->assertFalse( + $this->loginManager->checkCredentialsFromLdap($this->login, $this->password, function() { return null; }, function() { return false; }) + ); + } + + /** + * Check user credentials through LDAP - correct login and password supplied + */ + public function testCheckCredentialsFromLdapGoodLoginAndPassword() + { + $this->configManager->set('ldap.host', 'dummy'); + $this->assertTrue( + $this->loginManager->checkCredentialsFromLdap($this->login, $this->password, function() { return null; }, function() { return true; }) + ); + } } -- cgit v1.2.3 From 46846fd4fcc391f46f17037d69d0699567ae769e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20NOBILI?= Date: Mon, 2 Mar 2020 18:23:55 +0100 Subject: fixed typo --- tests/security/LoginManagerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/security/LoginManagerTest.php b/tests/security/LoginManagerTest.php index f2d78802..8fd1698c 100644 --- a/tests/security/LoginManagerTest.php +++ b/tests/security/LoginManagerTest.php @@ -314,7 +314,7 @@ class LoginManagerTest extends TestCase */ public function testCheckCredentialsFromLdapWrongLoginAndPassword() { - $this->coddnfigManager->set('ldap.host', 'dummy'); + $this->configManager->set('ldap.host', 'dummy'); $this->assertFalse( $this->loginManager->checkCredentialsFromLdap($this->login, $this->password, function() { return null; }, function() { return false; }) ); -- cgit v1.2.3 From 485b168a9677d160b0c0426e4f282b9bd0c632c1 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sun, 26 Jan 2020 11:15:15 +0100 Subject: Process picwall rendering through Slim controller + UT --- tests/container/ContainerBuilderTest.php | 4 + .../front/controller/PictureWallControllerTest.php | 180 +++++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 tests/front/controller/PictureWallControllerTest.php (limited to 'tests') diff --git a/tests/container/ContainerBuilderTest.php b/tests/container/ContainerBuilderTest.php index 9b97ed6d..cc2eb37f 100644 --- a/tests/container/ContainerBuilderTest.php +++ b/tests/container/ContainerBuilderTest.php @@ -7,6 +7,7 @@ namespace Shaarli\Container; use PHPUnit\Framework\TestCase; use Shaarli\Bookmark\BookmarkServiceInterface; use Shaarli\Config\ConfigManager; +use Shaarli\Formatter\FormatterFactory; use Shaarli\History; use Shaarli\Render\PageBuilder; use Shaarli\Security\LoginManager; @@ -30,7 +31,9 @@ class ContainerBuilderTest extends TestCase { $this->conf = new ConfigManager('tests/utils/config/configJson'); $this->sessionManager = $this->createMock(SessionManager::class); + $this->loginManager = $this->createMock(LoginManager::class); + $this->loginManager->method('isLoggedIn')->willReturn(true); $this->containerBuilder = new ContainerBuilder($this->conf, $this->sessionManager, $this->loginManager); } @@ -45,5 +48,6 @@ class ContainerBuilderTest extends TestCase static::assertInstanceOf(History::class, $container->history); static::assertInstanceOf(BookmarkServiceInterface::class, $container->bookmarkService); static::assertInstanceOf(PageBuilder::class, $container->pageBuilder); + static::assertInstanceOf(FormatterFactory::class, $container->formatterFactory); } } diff --git a/tests/front/controller/PictureWallControllerTest.php b/tests/front/controller/PictureWallControllerTest.php new file mode 100644 index 00000000..63802abd --- /dev/null +++ b/tests/front/controller/PictureWallControllerTest.php @@ -0,0 +1,180 @@ +container = $this->createMock(ShaarliContainer::class); + $this->controller = new PictureWallController($this->container); + } + + public function testValidControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->expects(static::once())->method('getQueryParams')->willReturn([]); + $response = new Response(); + + // ConfigManager: thumbnails are enabled + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + if ($parameter === 'thumbnails.mode') { + return Thumbnailer::MODE_COMMON; + } + + return $default; + }); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->container->pageBuilder + ->expects(static::atLeastOnce()) + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { + $assignedVariables[$key] = $value; + + return $this; + }) + ; + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('search') + ->willReturnCallback(function (array $parameters, ?string $visibility): array { + // Visibility is set through the container, not the call + static::assertNull($visibility); + + // No query parameters + if (count($parameters) === 0) { + return [ + (new Bookmark())->setId(1)->setUrl('http://url.tld')->setThumbnail('thumb1'), + (new Bookmark())->setId(2)->setUrl('http://url2.tld'), + (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setThumbnail('thumb2'), + ]; + } + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_picwall', $hook); + static::assertArrayHasKey('linksToDisplay', $data); + static::assertCount(2, $data['linksToDisplay']); + static::assertSame(1, $data['linksToDisplay'][0]['id']); + static::assertSame(3, $data['linksToDisplay'][1]['id']); + static::assertArrayHasKey('loggedin', $param); + + return $data; + }); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('picwall', (string) $result->getBody()); + static::assertSame('Picture wall - Shaarli', $assignedVariables['pagetitle']); + static::assertCount(2, $assignedVariables['linksToDisplay']); + + $link = $assignedVariables['linksToDisplay'][0]; + + static::assertSame(1, $link['id']); + static::assertSame('http://url.tld', $link['url']); + static::assertSame('thumb1', $link['thumbnail']); + + $link = $assignedVariables['linksToDisplay'][1]; + + static::assertSame(3, $link['id']); + static::assertSame('http://url3.tld', $link['url']); + static::assertSame('thumb2', $link['thumbnail']); + } + + public function testControllerWithThumbnailsDisabled(): void + { + $this->expectException(ThumbnailsDisabledException::class); + + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // ConfigManager: thumbnails are disabled + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + if ($parameter === 'thumbnails.mode') { + return Thumbnailer::MODE_NONE; + } + + return $default; + }); + + $this->controller->index($request, $response); + } + + protected function createValidContainerMockSet(): void + { + $loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager = $loginManager; + + // Config + $conf = $this->createMock(ConfigManager::class); + $this->container->conf = $conf; + + // PageBuilder + $pageBuilder = $this->createMock(PageBuilder::class); + $pageBuilder + ->method('render') + ->willReturnCallback(function (string $template): string { + return $template; + }) + ; + $this->container->pageBuilder = $pageBuilder; + + // Plugin Manager + $pluginManager = $this->createMock(PluginManager::class); + $this->container->pluginManager = $pluginManager; + + // BookmarkService + $bookmarkService = $this->createMock(BookmarkServiceInterface::class); + $this->container->bookmarkService = $bookmarkService; + + // Formatter + $formatterFactory = $this->createMock(FormatterFactory::class); + $formatterFactory + ->method('getFormatter') + ->willReturnCallback(function (string $type): BookmarkFormatter { + if ($type === 'raw') { + return new BookmarkRawFormatter($this->container->conf, true); + } + }) + ; + $this->container->formatterFactory = $formatterFactory; + } +} -- cgit v1.2.3 From b0428aa9b02b058b72c40b6e8dc2298d55bf692f Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Thu, 23 Jan 2020 21:13:41 +0100 Subject: Migrate cache purge function to a proper class And update dependencies and tests. Note that SESSION['tags'] has been removed a log ago --- tests/bootstrap.php | 1 - tests/feed/CacheTest.php | 92 ----------------------------------- tests/legacy/LegacyLinkDBTest.php | 1 - tests/render/PageCacheManagerTest.php | 86 ++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 94 deletions(-) delete mode 100644 tests/feed/CacheTest.php create mode 100644 tests/render/PageCacheManagerTest.php (limited to 'tests') diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 0afbcba6..c80bcb33 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -18,7 +18,6 @@ require_once 'application/bookmark/LinkUtils.php'; require_once 'application/Utils.php'; require_once 'application/http/UrlUtils.php'; require_once 'application/http/HttpUtils.php'; -require_once 'application/feed/Cache.php'; require_once 'tests/utils/ReferenceLinkDB.php'; require_once 'tests/utils/ReferenceHistory.php'; require_once 'tests/utils/FakeBookmarkService.php'; diff --git a/tests/feed/CacheTest.php b/tests/feed/CacheTest.php deleted file mode 100644 index c0a9f26f..00000000 --- a/tests/feed/CacheTest.php +++ /dev/null @@ -1,92 +0,0 @@ -assertFileNotExists(self::$testCacheDir . '/' . $page . '.cache'); - } - - $this->assertFileExists(self::$testCacheDir . '/intru.der'); - } - - /** - * Purge cached pages - missing directory - */ - public function testPurgeCachedPagesMissingDir() - { - $oldlog = ini_get('error_log'); - ini_set('error_log', '/dev/null'); - $this->assertEquals( - 'Cannot purge sandbox/dummycache_missing: no directory', - purgeCachedPages(self::$testCacheDir . '_missing') - ); - ini_set('error_log', $oldlog); - } - - /** - * Purge cached pages and session cache - */ - public function testInvalidateCaches() - { - $this->assertArrayNotHasKey('tags', $_SESSION); - $_SESSION['tags'] = array('goodbye', 'cruel', 'world'); - - invalidateCaches(self::$testCacheDir); - foreach (self::$pages as $page) { - $this->assertFileNotExists(self::$testCacheDir . '/' . $page . '.cache'); - } - - $this->assertArrayNotHasKey('tags', $_SESSION); - } -} diff --git a/tests/legacy/LegacyLinkDBTest.php b/tests/legacy/LegacyLinkDBTest.php index 17b2b0e6..0884ad03 100644 --- a/tests/legacy/LegacyLinkDBTest.php +++ b/tests/legacy/LegacyLinkDBTest.php @@ -11,7 +11,6 @@ use ReflectionClass; use Shaarli; use Shaarli\Bookmark\Bookmark; -require_once 'application/feed/Cache.php'; require_once 'application/Utils.php'; require_once 'tests/utils/ReferenceLinkDB.php'; diff --git a/tests/render/PageCacheManagerTest.php b/tests/render/PageCacheManagerTest.php new file mode 100644 index 00000000..991515d0 --- /dev/null +++ b/tests/render/PageCacheManagerTest.php @@ -0,0 +1,86 @@ +cacheManager = new PageCacheManager(static::$testCacheDir); + + if (!is_dir(self::$testCacheDir)) { + mkdir(self::$testCacheDir); + } else { + array_map('unlink', glob(self::$testCacheDir . '/*')); + } + + foreach (self::$pages as $page) { + file_put_contents(self::$testCacheDir . '/' . $page . '.cache', $page); + } + file_put_contents(self::$testCacheDir . '/intru.der', 'ShouldNotBeThere'); + } + + /** + * Remove dummycache folder after each tests. + */ + public function tearDown() + { + array_map('unlink', glob(self::$testCacheDir . '/*')); + rmdir(self::$testCacheDir); + } + + /** + * Purge cached pages + */ + public function testPurgeCachedPages() + { + $this->cacheManager->purgeCachedPages(); + foreach (self::$pages as $page) { + $this->assertFileNotExists(self::$testCacheDir . '/' . $page . '.cache'); + } + + $this->assertFileExists(self::$testCacheDir . '/intru.der'); + } + + /** + * Purge cached pages - missing directory + */ + public function testPurgeCachedPagesMissingDir() + { + $this->cacheManager = new PageCacheManager(self::$testCacheDir . '_missing'); + + $oldlog = ini_get('error_log'); + ini_set('error_log', '/dev/null'); + $this->assertEquals( + 'Cannot purge sandbox/dummycache_missing: no directory', + $this->cacheManager->purgeCachedPages() + ); + ini_set('error_log', $oldlog); + } +} -- cgit v1.2.3 From 8e47af2b3620c920116ec056173277c039163ec1 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Thu, 23 Jan 2020 21:52:03 +0100 Subject: Process logout through Slim controller --- tests/container/ContainerBuilderTest.php | 10 ++++- tests/front/controller/LogoutControllerTest.php | 60 +++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tests/front/controller/LogoutControllerTest.php (limited to 'tests') diff --git a/tests/container/ContainerBuilderTest.php b/tests/container/ContainerBuilderTest.php index cc2eb37f..65647249 100644 --- a/tests/container/ContainerBuilderTest.php +++ b/tests/container/ContainerBuilderTest.php @@ -10,6 +10,7 @@ use Shaarli\Config\ConfigManager; use Shaarli\Formatter\FormatterFactory; use Shaarli\History; use Shaarli\Render\PageBuilder; +use Shaarli\Render\PageCacheManager; use Shaarli\Security\LoginManager; use Shaarli\Security\SessionManager; @@ -35,7 +36,12 @@ class ContainerBuilderTest extends TestCase $this->loginManager = $this->createMock(LoginManager::class); $this->loginManager->method('isLoggedIn')->willReturn(true); - $this->containerBuilder = new ContainerBuilder($this->conf, $this->sessionManager, $this->loginManager); + $this->containerBuilder = new ContainerBuilder( + $this->conf, + $this->sessionManager, + $this->loginManager, + 'UT web path' + ); } public function testBuildContainer(): void @@ -45,9 +51,11 @@ class ContainerBuilderTest extends TestCase static::assertInstanceOf(ConfigManager::class, $container->conf); static::assertInstanceOf(SessionManager::class, $container->sessionManager); static::assertInstanceOf(LoginManager::class, $container->loginManager); + static::assertSame('UT web path', $container->webPath); static::assertInstanceOf(History::class, $container->history); static::assertInstanceOf(BookmarkServiceInterface::class, $container->bookmarkService); static::assertInstanceOf(PageBuilder::class, $container->pageBuilder); static::assertInstanceOf(FormatterFactory::class, $container->formatterFactory); + static::assertInstanceOf(PageCacheManager::class, $container->pageCacheManager); } } diff --git a/tests/front/controller/LogoutControllerTest.php b/tests/front/controller/LogoutControllerTest.php new file mode 100644 index 00000000..d9ca1c25 --- /dev/null +++ b/tests/front/controller/LogoutControllerTest.php @@ -0,0 +1,60 @@ +container = $this->createMock(ShaarliContainer::class); + $this->controller = new LogoutController($this->container); + + setcookie(LoginManager::$STAY_SIGNED_IN_COOKIE, $cookie = 'hi there'); + } + + public function testValidControllerInvoke(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $pageCacheManager = $this->createMock(PageCacheManager::class); + $pageCacheManager->expects(static::once())->method('invalidateCaches'); + $this->container->pageCacheManager = $pageCacheManager; + + $sessionManager = $this->createMock(SessionManager::class); + $sessionManager->expects(static::once())->method('logout'); + $this->container->sessionManager = $sessionManager; + + static::assertSame('hi there', $_COOKIE[LoginManager::$STAY_SIGNED_IN_COOKIE]); + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertContains('./', $result->getHeader('Location')); + static::assertSame('false', $_COOKIE[LoginManager::$STAY_SIGNED_IN_COOKIE]); + } +} -- cgit v1.2.3 From 03340c18ead651ef9e11f883745695f2edafbae3 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Tue, 12 May 2020 12:44:48 +0200 Subject: Slim router: handle add tag route --- tests/bookmark/LinkUtilsTest.php | 4 +- tests/feed/FeedBuilderTest.php | 2 +- tests/formatter/BookmarkDefaultFormatterTest.php | 4 +- tests/formatter/BookmarkMarkdownFormatterTest.php | 4 +- tests/front/controller/TagControllerTest.php | 191 ++++++++++++++++++++++ tests/plugins/resources/hashtags.md | 10 -- tests/plugins/resources/hashtags.raw | 10 -- tests/plugins/resources/markdown.html | 33 ---- tests/plugins/resources/markdown.md | 34 ---- 9 files changed, 197 insertions(+), 95 deletions(-) create mode 100644 tests/front/controller/TagControllerTest.php delete mode 100644 tests/plugins/resources/hashtags.md delete mode 100644 tests/plugins/resources/hashtags.raw delete mode 100644 tests/plugins/resources/markdown.html delete mode 100644 tests/plugins/resources/markdown.md (limited to 'tests') diff --git a/tests/bookmark/LinkUtilsTest.php b/tests/bookmark/LinkUtilsTest.php index 591976f2..7d4a7b89 100644 --- a/tests/bookmark/LinkUtilsTest.php +++ b/tests/bookmark/LinkUtilsTest.php @@ -3,8 +3,6 @@ namespace Shaarli\Bookmark; use PHPUnit\Framework\TestCase; -use ReferenceLinkDB; -use Shaarli\Config\ConfigManager; require_once 'tests/utils/CurlUtils.php'; @@ -491,7 +489,7 @@ class LinkUtilsTest extends TestCase */ private function getHashtagLink($hashtag, $index = '') { - $hashtagLink = '#$1'; + $hashtagLink = '#$1'; return str_replace('$1', $hashtag, $hashtagLink); } } diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php index 54671891..535207aa 100644 --- a/tests/feed/FeedBuilderTest.php +++ b/tests/feed/FeedBuilderTest.php @@ -306,6 +306,6 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $link = $data['links'][array_keys($data['links'])[2]]; $this->assertEquals('http://host.tld:8080/~user/shaarli/?WDWyig', $link['guid']); $this->assertEquals('http://host.tld:8080/~user/shaarli/?WDWyig', $link['url']); - $this->assertContains('http://host.tld:8080/~user/shaarli/?addtag=hashtag', $link['description']); + $this->assertContains('http://host.tld:8080/~user/shaarli/./add-tag/hashtag', $link['description']); } } diff --git a/tests/formatter/BookmarkDefaultFormatterTest.php b/tests/formatter/BookmarkDefaultFormatterTest.php index 382a560e..cf48b00b 100644 --- a/tests/formatter/BookmarkDefaultFormatterTest.php +++ b/tests/formatter/BookmarkDefaultFormatterTest.php @@ -123,7 +123,7 @@ class BookmarkDefaultFormatterTest extends TestCase $description[0] = 'This a <strong>description</strong>
'; $url = 'https://sub.domain.tld?query=here&for=real#hash'; $description[1] = 'text '. $url .' more text
'; - $description[2] = 'Also, there is an #hashtag added
'; $description[3] = '    A  N  D KEEP     '. 'SPACES    !  
'; @@ -148,7 +148,7 @@ class BookmarkDefaultFormatterTest extends TestCase $this->assertEquals($root . $short, $link['url']); $this->assertEquals($root . $short, $link['real_url']); $this->assertEquals( - 'Text '. + 'Text '. '#hashtag more text', $link['description'] ); diff --git a/tests/formatter/BookmarkMarkdownFormatterTest.php b/tests/formatter/BookmarkMarkdownFormatterTest.php index f1f12c04..3e72d1ee 100644 --- a/tests/formatter/BookmarkMarkdownFormatterTest.php +++ b/tests/formatter/BookmarkMarkdownFormatterTest.php @@ -125,7 +125,7 @@ class BookmarkMarkdownFormatterTest extends TestCase $description .= 'This a <strong>description</strong>
'. PHP_EOL; $url = 'https://sub.domain.tld?query=here&for=real#hash'; $description .= 'text '. $url .' more text
'. PHP_EOL; - $description .= 'Also, there is an #hashtag added
'. PHP_EOL; + $description .= 'Also, there is an #hashtag added
'. PHP_EOL; $description .= 'A N D KEEP SPACES ! '; $description .= '

'; @@ -146,7 +146,7 @@ class BookmarkMarkdownFormatterTest extends TestCase $this->formatter->addContextData('index_url', $root = 'https://domain.tld/hithere/'); $description = '

'; - $description .= 'Text #hashtag more text'; + $description .= 'Text #hashtag more text'; $description .= '

'; $link = $this->formatter->format($bookmark); diff --git a/tests/front/controller/TagControllerTest.php b/tests/front/controller/TagControllerTest.php new file mode 100644 index 00000000..bbac5652 --- /dev/null +++ b/tests/front/controller/TagControllerTest.php @@ -0,0 +1,191 @@ +container = $this->createMock(ShaarliContainer::class); + $this->controller = new TagController($this->container); + } + + public function testAddTagWithReferer(): void + { + $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=abc'], $result->getHeader('location')); + } + + public function testAddTagWithRefererAndExistingSearch(): void + { + $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); + } + + public function testAddTagWithoutRefererAndExistingSearch(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./?searchtags=abc'], $result->getHeader('location')); + } + + public function testAddTagRemoveLegacyQueryParam(): void + { + $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&addtag=abc']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); + } + + public function testAddTagResetPagination(): void + { + $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&page=12']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); + } + + public function testAddTagWithRefererAndEmptySearch(): void + { + $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=abc'], $result->getHeader('location')); + } + + public function testAddTagWithoutNewTagWithReferer(): void + { + $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->addTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def'], $result->getHeader('location')); + } + + public function testAddTagWithoutNewTagWithoutReferer(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->addTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } + + protected function createValidContainerMockSet(): void + { + // User logged out + $loginManager = $this->createMock(LoginManager::class); + $loginManager->method('isLoggedIn')->willReturn(false); + $loginManager->method('canLogin')->willReturn(true); + $this->container->loginManager = $loginManager; + + // Config + $conf = $this->createMock(ConfigManager::class); + $conf->method('get')->willReturnCallback(function (string $parameter, $default) { + return $default; + }); + $this->container->conf = $conf; + + // PageBuilder + $pageBuilder = $this->createMock(PageBuilder::class); + $pageBuilder + ->method('render') + ->willReturnCallback(function (string $template): string { + return $template; + }) + ; + $this->container->pageBuilder = $pageBuilder; + + $pluginManager = $this->createMock(PluginManager::class); + $this->container->pluginManager = $pluginManager; + $bookmarkService = $this->createMock(BookmarkServiceInterface::class); + $this->container->bookmarkService = $bookmarkService; + } +} diff --git a/tests/plugins/resources/hashtags.md b/tests/plugins/resources/hashtags.md deleted file mode 100644 index 46326de3..00000000 --- a/tests/plugins/resources/hashtags.md +++ /dev/null @@ -1,10 +0,0 @@ -[#lol](?addtag=lol) - - #test - -`#test2` - -``` -bla #bli blo -#bla -``` diff --git a/tests/plugins/resources/hashtags.raw b/tests/plugins/resources/hashtags.raw deleted file mode 100644 index 9d2dc98a..00000000 --- a/tests/plugins/resources/hashtags.raw +++ /dev/null @@ -1,10 +0,0 @@ -#lol - - #test - -`#test2` - -``` -bla #bli blo -#bla -``` diff --git a/tests/plugins/resources/markdown.html b/tests/plugins/resources/markdown.html deleted file mode 100644 index c3460bf7..00000000 --- a/tests/plugins/resources/markdown.html +++ /dev/null @@ -1,33 +0,0 @@ -
-
    -
  1. zero -
      -
    1. two
    2. -
    3. three
    4. -
    5. four
    6. -
    7. foo #foobar
    8. -
  2. -
-

#foobar foo lol #foo #bar

-

fsdfs http://link.tld #foobar http://link.tld

-
http://link.tld #foobar
-next #foo
-

Block:

-
lorem ipsum #foobar http://link.tld
-#foobar http://link.tld
-

link
-link
-link
-link
-link
-link
-link
-link
-link

diff --git a/tests/plugins/resources/markdown.md b/tests/plugins/resources/markdown.md deleted file mode 100644 index 9350a8c7..00000000 --- a/tests/plugins/resources/markdown.md +++ /dev/null @@ -1,34 +0,0 @@ -* test: - * [zero](http://link.tld) - + [two](http://link.tld) - - [three](http://link.tld) - -1. [zero](http://link.tld) - 2. [two](http://link.tld) - 3. [three](http://link.tld) - 4. [four](http://link.tld) - 5. foo #foobar - -#foobar foo `lol #foo` #bar - -fsdfs http://link.tld #foobar `http://link.tld` - - http://link.tld #foobar - next #foo - -Block: - -``` -lorem ipsum #foobar http://link.tld -#foobar http://link.tld -``` - -[link](?123456) -![link](/img/train.png) -[link](test.tld/path/?query=value#hash) -[link](http://test.tld/path/?query=value#hash) -[link](https://test.tld/path/?query=value#hash) -[link](ftp://test.tld/path/?query=value#hash) -[link](magnet:test.tld/path/?query=value#hash) -[link](javascript:alert('xss')) -[link](other://test.tld/path/?query=value#hash) -- cgit v1.2.3 From 72caf4e84c412ab6a4181b83a96dbef8ebb3c65a Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 16 May 2020 12:55:29 +0200 Subject: Working version before optimization --- tests/front/controller/TagCloudControllerTest.php | 258 ++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 tests/front/controller/TagCloudControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/TagCloudControllerTest.php b/tests/front/controller/TagCloudControllerTest.php new file mode 100644 index 00000000..a76d5835 --- /dev/null +++ b/tests/front/controller/TagCloudControllerTest.php @@ -0,0 +1,258 @@ +container = $this->createMock(ShaarliContainer::class); + $this->controller = new TagCloudController($this->container); + } + + public function testValidCloudControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $allTags = [ + 'ghi' => 1, + 'abc' => 3, + 'def' => 12, + ]; + $expectedOrder = ['abc', 'def', 'ghi']; + + $request = $this->createMock(Request::class); + $request->expects(static::once())->method('getQueryParam')->with('searchtags')->willReturn(null); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function () use ($allTags): array { + return $allTags; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_tagcloud', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(3, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.cloud', (string) $result->getBody()); + static::assertSame('Tag cloud - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(3, $assignedVariables['tags']); + static::assertSame($expectedOrder, array_keys($assignedVariables['tags'])); + + foreach ($allTags as $tag => $count) { + static::assertArrayHasKey($tag, $assignedVariables['tags']); + static::assertSame($count, $assignedVariables['tags'][$tag]['count']); + static::assertGreaterThan(0, $assignedVariables['tags'][$tag]['size']); + static::assertLessThan(5, $assignedVariables['tags'][$tag]['size']); + } + } + + /** + * Additional parameters: + * - logged in + * - visibility private + * - search tags: `ghi` and `def` (note that filtered tags are not displayed anymore) + */ + public function testValidCloudControllerInvokeWithParameters(): void + { + $this->createValidContainerMockSet(); + + $allTags = [ + 'ghi' => 1, + 'abc' => 3, + 'def' => 12, + ]; + + $request = $this->createMock(Request::class); + $request + ->expects(static::once()) + ->method('getQueryParam') + ->with('searchtags') + ->willReturn('ghi def') + ; + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->loginManager->method('isLoggedin')->willReturn(true); + $this->container->sessionManager->expects(static::once())->method('getSessionParameter')->willReturn('private'); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with(['ghi', 'def'], BookmarkFilter::$PRIVATE) + ->willReturnCallback(function () use ($allTags): array { + return $allTags; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_tagcloud', $hook); + static::assertSame('ghi def', $data['search_tags']); + static::assertCount(1, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.cloud', (string) $result->getBody()); + static::assertSame('ghi def - Tag cloud - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('ghi def', $assignedVariables['search_tags']); + static::assertCount(1, $assignedVariables['tags']); + + static::assertArrayHasKey('abc', $assignedVariables['tags']); + static::assertSame(3, $assignedVariables['tags']['abc']['count']); + static::assertGreaterThan(0, $assignedVariables['tags']['abc']['size']); + static::assertLessThan(5, $assignedVariables['tags']['abc']['size']); + } + + public function testEmptyCloud(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->expects(static::once())->method('getQueryParam')->with('searchtags')->willReturn(null); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function (array $parameters, ?string $visibility): array { + return []; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_tagcloud', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(0, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.cloud', (string) $result->getBody()); + static::assertSame('Tag cloud - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(0, $assignedVariables['tags']); + } + + protected function createValidContainerMockSet(): void + { + $loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager = $loginManager; + + $sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager = $sessionManager; + + // Config + $conf = $this->createMock(ConfigManager::class); + $this->container->conf = $conf; + + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + return $default; + }); + + // PageBuilder + $pageBuilder = $this->createMock(PageBuilder::class); + $pageBuilder + ->method('render') + ->willReturnCallback(function (string $template): string { + return $template; + }) + ; + $this->container->pageBuilder = $pageBuilder; + + // Plugin Manager + $pluginManager = $this->createMock(PluginManager::class); + $this->container->pluginManager = $pluginManager; + + // BookmarkService + $bookmarkService = $this->createMock(BookmarkServiceInterface::class); + $this->container->bookmarkService = $bookmarkService; + } + + protected function assignTemplateVars(array &$variables): void + { + $this->container->pageBuilder + ->expects(static::atLeastOnce()) + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$variables) { + $variables[$key] = $value; + + return $this; + }) + ; + } +} -- cgit v1.2.3 From c79473bd84ab5aba7836d2caaf61847cabaf1e53 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 16 May 2020 13:13:00 +0200 Subject: Handle tag filtering in the Bookmark service --- tests/bookmark/BookmarkFileServiceTest.php | 5 ----- tests/front/controller/TagCloudControllerTest.php | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php index 4900d41d..5adc26aa 100644 --- a/tests/bookmark/BookmarkFileServiceTest.php +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -816,7 +816,6 @@ class BookmarkFileServiceTest extends TestCase ); $this->assertEquals( [ - 'web' => 4, 'cartoon' => 2, 'gnu' => 1, 'dev' => 1, @@ -833,7 +832,6 @@ class BookmarkFileServiceTest extends TestCase ); $this->assertEquals( [ - 'web' => 1, 'html' => 1, 'w3c' => 1, 'css' => 1, @@ -968,7 +966,6 @@ class BookmarkFileServiceTest extends TestCase public function testCountLinkPerTagAllWithFilter() { $expected = [ - 'gnu' => 2, 'hashtag' => 2, '-exclude' => 1, '.hidden' => 1, @@ -991,7 +988,6 @@ class BookmarkFileServiceTest extends TestCase public function testCountLinkPerTagPublicWithFilter() { $expected = [ - 'gnu' => 2, 'hashtag' => 2, '-exclude' => 1, '.hidden' => 1, @@ -1015,7 +1011,6 @@ class BookmarkFileServiceTest extends TestCase { $expected = [ 'cartoon' => 1, - 'dev' => 1, 'tag1' => 1, 'tag2' => 1, 'tag3' => 1, diff --git a/tests/front/controller/TagCloudControllerTest.php b/tests/front/controller/TagCloudControllerTest.php index a76d5835..5cbf06a9 100644 --- a/tests/front/controller/TagCloudControllerTest.php +++ b/tests/front/controller/TagCloudControllerTest.php @@ -127,8 +127,8 @@ class TagCloudControllerTest extends TestCase ->expects(static::once()) ->method('bookmarksCountPerTag') ->with(['ghi', 'def'], BookmarkFilter::$PRIVATE) - ->willReturnCallback(function () use ($allTags): array { - return $allTags; + ->willReturnCallback(function (): array { + return ['abc' => 3]; }) ; -- cgit v1.2.3 From 3772298ee7d8d0708f4e72798600accafa17740b Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 16 May 2020 13:33:39 +0200 Subject: Few optimizations and code readability for tag cloud controller --- tests/front/controller/TagCloudControllerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/front/controller/TagCloudControllerTest.php b/tests/front/controller/TagCloudControllerTest.php index 5cbf06a9..352bdee2 100644 --- a/tests/front/controller/TagCloudControllerTest.php +++ b/tests/front/controller/TagCloudControllerTest.php @@ -73,7 +73,7 @@ class TagCloudControllerTest extends TestCase }) ; - $result = $this->controller->index($request, $response); + $result = $this->controller->cloud($request, $response); static::assertSame(200, $result->getStatusCode()); static::assertSame('tag.cloud', (string) $result->getBody()); @@ -147,7 +147,7 @@ class TagCloudControllerTest extends TestCase }) ; - $result = $this->controller->index($request, $response); + $result = $this->controller->cloud($request, $response); static::assertSame(200, $result->getStatusCode()); static::assertSame('tag.cloud', (string) $result->getBody()); @@ -198,7 +198,7 @@ class TagCloudControllerTest extends TestCase }) ; - $result = $this->controller->index($request, $response); + $result = $this->controller->cloud($request, $response); static::assertSame(200, $result->getStatusCode()); static::assertSame('tag.cloud', (string) $result->getBody()); -- cgit v1.2.3 From 60ae241251b753fc052e50ebd95277dfcb074cb0 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 16 May 2020 14:56:22 +0200 Subject: Process tag list page through Slim controller --- tests/front/controller/TagCloudControllerTest.php | 203 ++++++++++++++++++++-- 1 file changed, 191 insertions(+), 12 deletions(-) (limited to 'tests') diff --git a/tests/front/controller/TagCloudControllerTest.php b/tests/front/controller/TagCloudControllerTest.php index 352bdee2..719610d7 100644 --- a/tests/front/controller/TagCloudControllerTest.php +++ b/tests/front/controller/TagCloudControllerTest.php @@ -30,6 +30,9 @@ class TagCloudControllerTest extends TestCase $this->controller = new TagCloudController($this->container); } + /** + * Tag Cloud - default parameters + */ public function testValidCloudControllerInvokeDefault(): void { $this->createValidContainerMockSet(); @@ -42,7 +45,6 @@ class TagCloudControllerTest extends TestCase $expectedOrder = ['abc', 'def', 'ghi']; $request = $this->createMock(Request::class); - $request->expects(static::once())->method('getQueryParam')->with('searchtags')->willReturn(null); $response = new Response(); // Save RainTPL assigned variables @@ -92,7 +94,7 @@ class TagCloudControllerTest extends TestCase } /** - * Additional parameters: + * Tag Cloud - Additional parameters: * - logged in * - visibility private * - search tags: `ghi` and `def` (note that filtered tags are not displayed anymore) @@ -101,18 +103,17 @@ class TagCloudControllerTest extends TestCase { $this->createValidContainerMockSet(); - $allTags = [ - 'ghi' => 1, - 'abc' => 3, - 'def' => 12, - ]; - $request = $this->createMock(Request::class); $request - ->expects(static::once()) ->method('getQueryParam') - ->with('searchtags') - ->willReturn('ghi def') + ->with() + ->willReturnCallback(function (string $key): ?string { + if ('searchtags' === $key) { + return 'ghi def'; + } + + return null; + }) ; $response = new Response(); @@ -162,12 +163,14 @@ class TagCloudControllerTest extends TestCase static::assertLessThan(5, $assignedVariables['tags']['abc']['size']); } + /** + * Tag Cloud - empty + */ public function testEmptyCloud(): void { $this->createValidContainerMockSet(); $request = $this->createMock(Request::class); - $request->expects(static::once())->method('getQueryParam')->with('searchtags')->willReturn(null); $response = new Response(); // Save RainTPL assigned variables @@ -208,6 +211,182 @@ class TagCloudControllerTest extends TestCase static::assertCount(0, $assignedVariables['tags']); } + /** + * Tag List - Default sort is by usage DESC + */ + public function testValidListControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $allTags = [ + 'def' => 12, + 'abc' => 3, + 'ghi' => 1, + ]; + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function () use ($allTags): array { + return $allTags; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_taglist', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(3, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->list($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.list', (string) $result->getBody()); + static::assertSame('Tag list - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(3, $assignedVariables['tags']); + + foreach ($allTags as $tag => $count) { + static::assertSame($count, $assignedVariables['tags'][$tag]); + } + } + + /** + * Tag List - Additional parameters: + * - logged in + * - visibility private + * - search tags: `ghi` and `def` (note that filtered tags are not displayed anymore) + * - sort alphabetically + */ + public function testValidListControllerInvokeWithParameters(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request + ->method('getQueryParam') + ->with() + ->willReturnCallback(function (string $key): ?string { + if ('searchtags' === $key) { + return 'ghi def'; + } elseif ('sort' === $key) { + return 'alpha'; + } + + return null; + }) + ; + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->loginManager->method('isLoggedin')->willReturn(true); + $this->container->sessionManager->expects(static::once())->method('getSessionParameter')->willReturn('private'); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with(['ghi', 'def'], BookmarkFilter::$PRIVATE) + ->willReturnCallback(function (): array { + return ['abc' => 3]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_taglist', $hook); + static::assertSame('ghi def', $data['search_tags']); + static::assertCount(1, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->list($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.list', (string) $result->getBody()); + static::assertSame('ghi def - Tag list - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('ghi def', $assignedVariables['search_tags']); + static::assertCount(1, $assignedVariables['tags']); + static::assertSame(3, $assignedVariables['tags']['abc']); + } + + /** + * Tag List - empty + */ + public function testEmptyList(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function (array $parameters, ?string $visibility): array { + return []; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_taglist', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(0, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->list($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.list', (string) $result->getBody()); + static::assertSame('Tag list - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(0, $assignedVariables['tags']); + } + + protected function createValidContainerMockSet(): void { $loginManager = $this->createMock(LoginManager::class); -- cgit v1.2.3 From 69e29ff65ef56b886748c58ba5b037cf217c4a1d Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sun, 17 May 2020 11:06:39 +0200 Subject: Process daily page through Slim controller --- tests/front/controller/DailyControllerTest.php | 423 +++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 tests/front/controller/DailyControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/DailyControllerTest.php b/tests/front/controller/DailyControllerTest.php new file mode 100644 index 00000000..bb453d5b --- /dev/null +++ b/tests/front/controller/DailyControllerTest.php @@ -0,0 +1,423 @@ +container = $this->createMock(ShaarliContainer::class); + $this->controller = new DailyController($this->container); + } + + public function testValidControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $currentDay = new \DateTimeImmutable('2020-05-13'); + + $request = $this->createMock(Request::class); + $request->method('getQueryParam')->willReturn($currentDay->format('Ymd')); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function () use ($currentDay): array { + return [ + '20200510', + $currentDay->format('Ymd'), + '20200516', + ]; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return [ + (new Bookmark()) + ->setId(1) + ->setUrl('http://url.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + (new Bookmark()) + ->setId(2) + ->setUrl('http://url2.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + (new Bookmark()) + ->setId(3) + ->setUrl('http://url3.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + ]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array { + static::assertSame('render_daily', $hook); + + static::assertArrayHasKey('linksToDisplay', $data); + static::assertCount(3, $data['linksToDisplay']); + static::assertSame(1, $data['linksToDisplay'][0]['id']); + static::assertSame($currentDay->getTimestamp(), $data['day']); + static::assertSame('20200510', $data['previousday']); + static::assertSame('20200516', $data['nextday']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertSame( + 'Daily - '. format_date($currentDay, false, true) .' - Shaarli', + $assignedVariables['pagetitle'] + ); + static::assertCount(3, $assignedVariables['linksToDisplay']); + + $link = $assignedVariables['linksToDisplay'][0]; + + static::assertSame(1, $link['id']); + static::assertSame('http://url.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['linksToDisplay'][1]; + + static::assertSame(2, $link['id']); + static::assertSame('http://url2.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['linksToDisplay'][2]; + + static::assertSame(3, $link['id']); + static::assertSame('http://url3.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + static::assertCount(3, $assignedVariables['cols']); + static::assertCount(1, $assignedVariables['cols'][0]); + static::assertCount(1, $assignedVariables['cols'][1]); + static::assertCount(1, $assignedVariables['cols'][2]); + + $link = $assignedVariables['cols'][0][0]; + + static::assertSame(1, $link['id']); + static::assertSame('http://url.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['cols'][1][0]; + + static::assertSame(2, $link['id']); + static::assertSame('http://url2.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['cols'][2][0]; + + static::assertSame(3, $link['id']); + static::assertSame('http://url3.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + } + + /** + * Daily page - test that everything goes fine with no future or past bookmarks + */ + public function testValidControllerInvokeNoFutureOrPast(): void + { + $this->createValidContainerMockSet(); + + $currentDay = new \DateTimeImmutable('2020-05-13'); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function () use ($currentDay): array { + return [ + $currentDay->format($currentDay->format('Ymd')), + ]; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return [ + (new Bookmark()) + ->setId(1) + ->setUrl('http://url.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + ]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array { + static::assertSame('render_daily', $hook); + + static::assertArrayHasKey('linksToDisplay', $data); + static::assertCount(1, $data['linksToDisplay']); + static::assertSame(1, $data['linksToDisplay'][0]['id']); + static::assertSame($currentDay->getTimestamp(), $data['day']); + static::assertEmpty($data['previousday']); + static::assertEmpty($data['nextday']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertSame( + 'Daily - '. format_date($currentDay, false, true) .' - Shaarli', + $assignedVariables['pagetitle'] + ); + static::assertCount(1, $assignedVariables['linksToDisplay']); + + $link = $assignedVariables['linksToDisplay'][0]; + static::assertSame(1, $link['id']); + } + + /** + * Daily page - test that height adjustment in columns is working + */ + public function testValidControllerInvokeHeightAdjustment(): void + { + $this->createValidContainerMockSet(); + + $currentDay = new \DateTimeImmutable('2020-05-13'); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function () use ($currentDay): array { + return [ + $currentDay->format($currentDay->format('Ymd')), + ]; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return [ + (new Bookmark())->setId(1)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark()) + ->setId(2) + ->setUrl('http://url.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(5000)) + , + (new Bookmark())->setId(3)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(4)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(5)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(6)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(7)->setUrl('http://url.tld')->setTitle('title'), + ]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + return $data; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertCount(7, $assignedVariables['linksToDisplay']); + + $columnIds = function (array $column): array { + return array_map(function (array $item): int { return $item['id']; }, $column); + }; + + static::assertSame([1, 4, 6], $columnIds($assignedVariables['cols'][0])); + static::assertSame([2], $columnIds($assignedVariables['cols'][1])); + static::assertSame([3, 5, 7], $columnIds($assignedVariables['cols'][2])); + } + + /** + * Daily page - no bookmark + */ + public function testValidControllerInvokeNoBookmark(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function (): array { + return []; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return []; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + return $data; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertCount(0, $assignedVariables['linksToDisplay']); + static::assertSame('Today', $assignedVariables['dayDesc']); + } + + protected function createValidContainerMockSet(): void + { + $loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager = $loginManager; + + // Config + $conf = $this->createMock(ConfigManager::class); + $this->container->conf = $conf; + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + return $default; + }); + + // PageBuilder + $pageBuilder = $this->createMock(PageBuilder::class); + $pageBuilder + ->method('render') + ->willReturnCallback(function (string $template): string { + return $template; + }) + ; + $this->container->pageBuilder = $pageBuilder; + + // Plugin Manager + $pluginManager = $this->createMock(PluginManager::class); + $this->container->pluginManager = $pluginManager; + + // BookmarkService + $bookmarkService = $this->createMock(BookmarkServiceInterface::class); + $this->container->bookmarkService = $bookmarkService; + + // Formatter + $formatterFactory = $this->createMock(FormatterFactory::class); + $formatterFactory + ->method('getFormatter') + ->willReturnCallback(function (): BookmarkFormatter { + return new BookmarkRawFormatter($this->container->conf, true); + }) + ; + $this->container->formatterFactory = $formatterFactory; + } + + protected function assignTemplateVars(array &$variables): void + { + $this->container->pageBuilder + ->expects(static::atLeastOnce()) + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$variables) { + $variables[$key] = $value; + + return $this; + }) + ; + } + + protected static function generateContent(int $length): string + { + // bin2hex(random_bytes) generates string twice as long as given parameter + $length = (int) ceil($length / 2); + return bin2hex(random_bytes($length)); + } +} -- cgit v1.2.3 From e3d28be9673a9f8404ff907b8191209729ad690c Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sun, 17 May 2020 11:29:17 +0200 Subject: Slim daily: minor bugfix with empty data --- tests/front/controller/DailyControllerTest.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tests') diff --git a/tests/front/controller/DailyControllerTest.php b/tests/front/controller/DailyControllerTest.php index bb453d5b..2714bfd9 100644 --- a/tests/front/controller/DailyControllerTest.php +++ b/tests/front/controller/DailyControllerTest.php @@ -112,6 +112,8 @@ class DailyControllerTest extends TestCase 'Daily - '. format_date($currentDay, false, true) .' - Shaarli', $assignedVariables['pagetitle'] ); + static::assertEquals($currentDay, $assignedVariables['dayDate']); + static::assertEquals($currentDay->getTimestamp(), $assignedVariables['day']); static::assertCount(3, $assignedVariables['linksToDisplay']); $link = $assignedVariables['linksToDisplay'][0]; @@ -358,6 +360,8 @@ class DailyControllerTest extends TestCase static::assertSame('daily', (string) $result->getBody()); static::assertCount(0, $assignedVariables['linksToDisplay']); static::assertSame('Today', $assignedVariables['dayDesc']); + static::assertEquals((new \DateTime())->setTime(0, 0)->getTimestamp(), $assignedVariables['day']); + static::assertEquals((new \DateTime())->setTime(0, 0), $assignedVariables['dayDate']); } protected function createValidContainerMockSet(): void -- cgit v1.2.3 From c4d5be53c2ae503c00da3cfe6b28d0ce9d2ca7f5 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sun, 17 May 2020 14:16:32 +0200 Subject: Process Daily RSS feed through Slim controller The daily RSS template has been entirely rewritten to handle the whole feed through the template engine. --- tests/front/controller/DailyControllerTest.php | 152 ++++++++++++++++++++++++- tests/http/HttpUtils/IndexUrlTest.php | 32 ++++++ tests/render/PageCacheManagerTest.php | 4 +- 3 files changed, 182 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/front/controller/DailyControllerTest.php b/tests/front/controller/DailyControllerTest.php index 2714bfd9..72a0339f 100644 --- a/tests/front/controller/DailyControllerTest.php +++ b/tests/front/controller/DailyControllerTest.php @@ -9,11 +9,13 @@ use Shaarli\Bookmark\Bookmark; use Shaarli\Bookmark\BookmarkServiceInterface; use Shaarli\Config\ConfigManager; use Shaarli\Container\ShaarliContainer; +use Shaarli\Feed\CachedPage; use Shaarli\Formatter\BookmarkFormatter; use Shaarli\Formatter\BookmarkRawFormatter; use Shaarli\Formatter\FormatterFactory; use Shaarli\Plugin\PluginManager; use Shaarli\Render\PageBuilder; +use Shaarli\Render\PageCacheManager; use Shaarli\Security\LoginManager; use Slim\Http\Request; use Slim\Http\Response; @@ -30,9 +32,10 @@ class DailyControllerTest extends TestCase { $this->container = $this->createMock(ShaarliContainer::class); $this->controller = new DailyController($this->container); + DailyController::$DAILY_RSS_NB_DAYS = 2; } - public function testValidControllerInvokeDefault(): void + public function testValidIndexControllerInvokeDefault(): void { $this->createValidContainerMockSet(); @@ -173,7 +176,7 @@ class DailyControllerTest extends TestCase /** * Daily page - test that everything goes fine with no future or past bookmarks */ - public function testValidControllerInvokeNoFutureOrPast(): void + public function testValidIndexControllerInvokeNoFutureOrPast(): void { $this->createValidContainerMockSet(); @@ -247,7 +250,7 @@ class DailyControllerTest extends TestCase /** * Daily page - test that height adjustment in columns is working */ - public function testValidControllerInvokeHeightAdjustment(): void + public function testValidIndexControllerInvokeHeightAdjustment(): void { $this->createValidContainerMockSet(); @@ -318,7 +321,7 @@ class DailyControllerTest extends TestCase /** * Daily page - no bookmark */ - public function testValidControllerInvokeNoBookmark(): void + public function testValidIndexControllerInvokeNoBookmark(): void { $this->createValidContainerMockSet(); @@ -364,6 +367,136 @@ class DailyControllerTest extends TestCase static::assertEquals((new \DateTime())->setTime(0, 0), $assignedVariables['dayDate']); } + /** + * Daily RSS - default behaviour + */ + public function testValidRssControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $dates = [ + new \DateTimeImmutable('2020-05-17'), + new \DateTimeImmutable('2020-05-15'), + new \DateTimeImmutable('2020-05-13'), + ]; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([ + (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'), + (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'), + (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'), + (new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'), + ]); + + $this->container->pageCacheManager + ->expects(static::once()) + ->method('getCachePage') + ->willReturnCallback(function (): CachedPage { + $cachedPage = $this->createMock(CachedPage::class); + $cachedPage->expects(static::once())->method('cache')->with('dailyrss'); + + return $cachedPage; + } + ); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('dailyrss', (string) $result->getBody()); + static::assertSame('Shaarli', $assignedVariables['title']); + static::assertSame('http://shaarli', $assignedVariables['index_url']); + static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']); + static::assertFalse($assignedVariables['hide_timestamps']); + static::assertCount(2, $assignedVariables['days']); + + $day = $assignedVariables['days'][$dates[0]->format('Ymd')]; + + static::assertEquals($dates[0], $day['date']); + static::assertSame($dates[0]->format(\DateTimeInterface::RSS), $day['date_rss']); + static::assertSame(format_date($dates[0], false), $day['date_human']); + static::assertSame('http://shaarli/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']); + static::assertCount(1, $day['links']); + static::assertSame(1, $day['links'][0]['id']); + static::assertSame('http://domain.tld/1', $day['links'][0]['url']); + static::assertEquals($dates[0], $day['links'][0]['created']); + + $day = $assignedVariables['days'][$dates[1]->format('Ymd')]; + + static::assertEquals($dates[1], $day['date']); + static::assertSame($dates[1]->format(\DateTimeInterface::RSS), $day['date_rss']); + static::assertSame(format_date($dates[1], false), $day['date_human']); + static::assertSame('http://shaarli/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']); + static::assertCount(2, $day['links']); + + static::assertSame(2, $day['links'][0]['id']); + static::assertSame('http://domain.tld/2', $day['links'][0]['url']); + static::assertEquals($dates[1], $day['links'][0]['created']); + static::assertSame(3, $day['links'][1]['id']); + static::assertSame('http://domain.tld/3', $day['links'][1]['url']); + static::assertEquals($dates[1], $day['links'][1]['created']); + } + + /** + * Daily RSS - trigger cache rendering + */ + public function testValidRssControllerInvokeTriggerCache(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->pageCacheManager->method('getCachePage')->willReturnCallback(function (): CachedPage { + $cachedPage = $this->createMock(CachedPage::class); + $cachedPage->method('cachedVersion')->willReturn('this is cache!'); + + return $cachedPage; + }); + + $this->container->bookmarkService->expects(static::never())->method('search'); + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('this is cache!', (string) $result->getBody()); + } + + /** + * Daily RSS - No bookmark + */ + public function testValidRssControllerInvokeNoBookmark(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([]); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('dailyrss', (string) $result->getBody()); + static::assertSame('Shaarli', $assignedVariables['title']); + static::assertSame('http://shaarli', $assignedVariables['index_url']); + static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']); + static::assertFalse($assignedVariables['hide_timestamps']); + static::assertCount(0, $assignedVariables['days']); + } + protected function createValidContainerMockSet(): void { $loginManager = $this->createMock(LoginManager::class); @@ -403,6 +536,17 @@ class DailyControllerTest extends TestCase }) ; $this->container->formatterFactory = $formatterFactory; + + // CacheManager + $pageCacheManager = $this->createMock(PageCacheManager::class); + $this->container->pageCacheManager = $pageCacheManager; + + // $_SERVER + $this->container->environment = [ + 'SERVER_NAME' => 'shaarli', + 'SERVER_PORT' => '80', + 'REQUEST_URI' => '/daily-rss', + ]; } protected function assignTemplateVars(array &$variables): void diff --git a/tests/http/HttpUtils/IndexUrlTest.php b/tests/http/HttpUtils/IndexUrlTest.php index bcbe59cb..73d33cd4 100644 --- a/tests/http/HttpUtils/IndexUrlTest.php +++ b/tests/http/HttpUtils/IndexUrlTest.php @@ -71,4 +71,36 @@ class IndexUrlTest extends \PHPUnit\Framework\TestCase ) ); } + + /** + * The route is stored in REQUEST_URI + */ + public function testPageUrlWithRoute() + { + $this->assertEquals( + 'http://host.tld/picture-wall', + page_url( + array( + 'HTTPS' => 'Off', + 'SERVER_NAME' => 'host.tld', + 'SERVER_PORT' => '80', + 'SCRIPT_NAME' => '/index.php', + 'REQUEST_URI' => '/picture-wall', + ) + ) + ); + + $this->assertEquals( + 'http://host.tld/admin/picture-wall', + page_url( + array( + 'HTTPS' => 'Off', + 'SERVER_NAME' => 'host.tld', + 'SERVER_PORT' => '80', + 'SCRIPT_NAME' => '/admin/index.php', + 'REQUEST_URI' => '/admin/picture-wall', + ) + ) + ); + } } diff --git a/tests/render/PageCacheManagerTest.php b/tests/render/PageCacheManagerTest.php index 991515d0..b870e6eb 100644 --- a/tests/render/PageCacheManagerTest.php +++ b/tests/render/PageCacheManagerTest.php @@ -32,7 +32,7 @@ class PageCacheManagerTest extends TestCase */ public function setUp() { - $this->cacheManager = new PageCacheManager(static::$testCacheDir); + $this->cacheManager = new PageCacheManager(static::$testCacheDir, true); if (!is_dir(self::$testCacheDir)) { mkdir(self::$testCacheDir); @@ -73,7 +73,7 @@ class PageCacheManagerTest extends TestCase */ public function testPurgeCachedPagesMissingDir() { - $this->cacheManager = new PageCacheManager(self::$testCacheDir . '_missing'); + $this->cacheManager = new PageCacheManager(self::$testCacheDir . '_missing', true); $oldlog = ini_get('error_log'); ini_set('error_log', '/dev/null'); -- cgit v1.2.3 From 029ada5a071240fd10f3557fd3c0fc865c54c5a8 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sun, 17 May 2020 15:45:26 +0200 Subject: PHP 7.1 compatibility --- tests/front/controller/DailyControllerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/front/controller/DailyControllerTest.php b/tests/front/controller/DailyControllerTest.php index 72a0339f..88ec116b 100644 --- a/tests/front/controller/DailyControllerTest.php +++ b/tests/front/controller/DailyControllerTest.php @@ -419,7 +419,7 @@ class DailyControllerTest extends TestCase $day = $assignedVariables['days'][$dates[0]->format('Ymd')]; static::assertEquals($dates[0], $day['date']); - static::assertSame($dates[0]->format(\DateTimeInterface::RSS), $day['date_rss']); + static::assertSame($dates[0]->format(\DateTime::RSS), $day['date_rss']); static::assertSame(format_date($dates[0], false), $day['date_human']); static::assertSame('http://shaarli/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']); static::assertCount(1, $day['links']); @@ -430,7 +430,7 @@ class DailyControllerTest extends TestCase $day = $assignedVariables['days'][$dates[1]->format('Ymd')]; static::assertEquals($dates[1], $day['date']); - static::assertSame($dates[1]->format(\DateTimeInterface::RSS), $day['date_rss']); + static::assertSame($dates[1]->format(\DateTime::RSS), $day['date_rss']); static::assertSame(format_date($dates[1], false), $day['date_human']); static::assertSame('http://shaarli/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']); static::assertCount(2, $day['links']); -- cgit v1.2.3 From f4929b1188b4bc5e92b925ebc44f5ad40bb1a4ed Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Mon, 18 May 2020 13:03:13 +0200 Subject: Make FeedBuilder instance creation independant of the request stack --- tests/feed/FeedBuilderTest.php | 63 ++++++++++-------------------------------- 1 file changed, 15 insertions(+), 48 deletions(-) (limited to 'tests') diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php index 535207aa..b2b70b70 100644 --- a/tests/feed/FeedBuilderTest.php +++ b/tests/feed/FeedBuilderTest.php @@ -64,23 +64,6 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase ); } - /** - * Test GetTypeLanguage(). - */ - public function testGetTypeLanguage() - { - $feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_ATOM, null, null, false); - $feedBuilder->setLocale(self::$LOCALE); - $this->assertEquals(self::$ATOM_LANGUAGUE, $feedBuilder->getTypeLanguage()); - $feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_RSS, null, null, false); - $feedBuilder->setLocale(self::$LOCALE); - $this->assertEquals(self::$RSS_LANGUAGE, $feedBuilder->getTypeLanguage()); - $feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_ATOM, null, null, false); - $this->assertEquals('en', $feedBuilder->getTypeLanguage()); - $feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_RSS, null, null, false); - $this->assertEquals('en-en', $feedBuilder->getTypeLanguage()); - } - /** * Test buildData with RSS feed. */ @@ -89,13 +72,11 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $feedBuilder = new FeedBuilder( self::$bookmarkService, self::$formatter, - FeedBuilder::$FEED_RSS, - self::$serverInfo, - null, + static::$serverInfo, false ); $feedBuilder->setLocale(self::$LOCALE); - $data = $feedBuilder->buildData(); + $data = $feedBuilder->buildData(FeedBuilder::$FEED_RSS, null); // Test headers (RSS) $this->assertEquals(self::$RSS_LANGUAGE, $data['language']); $this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']); @@ -140,13 +121,11 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $feedBuilder = new FeedBuilder( self::$bookmarkService, self::$formatter, - FeedBuilder::$FEED_ATOM, - self::$serverInfo, - null, + static::$serverInfo, false ); $feedBuilder->setLocale(self::$LOCALE); - $data = $feedBuilder->buildData(); + $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null); $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['last_update']); $link = $data['links'][array_keys($data['links'])[2]]; @@ -166,13 +145,11 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $feedBuilder = new FeedBuilder( self::$bookmarkService, self::$formatter, - FeedBuilder::$FEED_ATOM, - self::$serverInfo, - $criteria, + static::$serverInfo, false ); $feedBuilder->setLocale(self::$LOCALE); - $data = $feedBuilder->buildData(); + $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, $criteria); $this->assertEquals(1, count($data['links'])); $link = array_shift($data['links']); $this->assertEquals(41, $link['id']); @@ -190,13 +167,11 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $feedBuilder = new FeedBuilder( self::$bookmarkService, self::$formatter, - FeedBuilder::$FEED_ATOM, - self::$serverInfo, - $criteria, + static::$serverInfo, false ); $feedBuilder->setLocale(self::$LOCALE); - $data = $feedBuilder->buildData(); + $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, $criteria); $this->assertEquals(3, count($data['links'])); $link = $data['links'][array_keys($data['links'])[2]]; $this->assertEquals(41, $link['id']); @@ -211,14 +186,12 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $feedBuilder = new FeedBuilder( self::$bookmarkService, self::$formatter, - FeedBuilder::$FEED_ATOM, - self::$serverInfo, - null, + static::$serverInfo, false ); $feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setUsePermalinks(true); - $data = $feedBuilder->buildData(); + $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null); $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); $this->assertTrue($data['usepermalinks']); // First link is a permalink @@ -247,14 +220,12 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $feedBuilder = new FeedBuilder( self::$bookmarkService, self::$formatter, - FeedBuilder::$FEED_ATOM, - self::$serverInfo, - null, + static::$serverInfo, false ); $feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setHideDates(true); - $data = $feedBuilder->buildData(); + $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null); $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); $this->assertFalse($data['show_dates']); @@ -262,14 +233,12 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $feedBuilder = new FeedBuilder( self::$bookmarkService, self::$formatter, - FeedBuilder::$FEED_ATOM, - self::$serverInfo, - null, + static::$serverInfo, true ); $feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setHideDates(true); - $data = $feedBuilder->buildData(); + $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null); $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); $this->assertTrue($data['show_dates']); } @@ -289,13 +258,11 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase $feedBuilder = new FeedBuilder( self::$bookmarkService, self::$formatter, - FeedBuilder::$FEED_ATOM, $serverInfo, - null, false ); $feedBuilder->setLocale(self::$LOCALE); - $data = $feedBuilder->buildData(); + $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null); $this->assertEquals( 'http://host.tld:8080/~user/shaarli/index.php?do=feed', -- cgit v1.2.3 From 7b2ba6ef820335df682fbe3dcfaceef3a62cf4a5 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Mon, 18 May 2020 17:17:36 +0200 Subject: RSS/ATOM feeds: process through Slim controller --- tests/feed/CachedPageTest.php | 6 +- tests/front/controller/FeedControllerTest.php | 219 ++++++++++++++++++++++++++ 2 files changed, 222 insertions(+), 3 deletions(-) create mode 100644 tests/front/controller/FeedControllerTest.php (limited to 'tests') diff --git a/tests/feed/CachedPageTest.php b/tests/feed/CachedPageTest.php index 363028a2..57f3b09b 100644 --- a/tests/feed/CachedPageTest.php +++ b/tests/feed/CachedPageTest.php @@ -11,7 +11,7 @@ class CachedPageTest extends \PHPUnit\Framework\TestCase { // test cache directory protected static $testCacheDir = 'sandbox/pagecache'; - protected static $url = 'http://shaar.li/?do=atom'; + protected static $url = 'http://shaar.li/feed-atom'; protected static $filename; /** @@ -42,8 +42,8 @@ class CachedPageTest extends \PHPUnit\Framework\TestCase { new CachedPage(self::$testCacheDir, '', true); new CachedPage(self::$testCacheDir, '', false); - new CachedPage(self::$testCacheDir, 'http://shaar.li/?do=rss', true); - new CachedPage(self::$testCacheDir, 'http://shaar.li/?do=atom', false); + new CachedPage(self::$testCacheDir, 'http://shaar.li/feed-rss', true); + new CachedPage(self::$testCacheDir, 'http://shaar.li/feed-atom', false); $this->addToAssertionCount(1); } diff --git a/tests/front/controller/FeedControllerTest.php b/tests/front/controller/FeedControllerTest.php new file mode 100644 index 00000000..d4cc5536 --- /dev/null +++ b/tests/front/controller/FeedControllerTest.php @@ -0,0 +1,219 @@ +container = $this->createMock(ShaarliContainer::class); + $this->controller = new FeedController($this->container); + } + + /** + * Feed Controller - RSS default behaviour + */ + public function testDefaultRssController(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->feedBuilder->expects(static::once())->method('setLocale'); + $this->container->feedBuilder->expects(static::once())->method('setHideDates')->with(false); + $this->container->feedBuilder->expects(static::once())->method('setUsePermalinks')->with(true); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->feedBuilder->method('buildData')->willReturn(['content' => 'data']); + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): void { + static::assertSame('render_feed', $hook); + static::assertSame('data', $data['content']); + + static::assertArrayHasKey('loggedin', $param); + static::assertSame('rss', $param['target']); + }) + ; + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('feed.rss', (string) $result->getBody()); + static::assertSame('data', $assignedVariables['content']); + } + + /** + * Feed Controller - ATOM default behaviour + */ + public function testDefaultAtomController(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->feedBuilder->expects(static::once())->method('setLocale'); + $this->container->feedBuilder->expects(static::once())->method('setHideDates')->with(false); + $this->container->feedBuilder->expects(static::once())->method('setUsePermalinks')->with(true); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->feedBuilder->method('buildData')->willReturn(['content' => 'data']); + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): void { + static::assertSame('render_feed', $hook); + static::assertSame('data', $data['content']); + + static::assertArrayHasKey('loggedin', $param); + static::assertSame('atom', $param['target']); + }) + ; + + $result = $this->controller->atom($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/atom', $result->getHeader('Content-Type')[0]); + static::assertSame('feed.atom', (string) $result->getBody()); + static::assertSame('data', $assignedVariables['content']); + } + + /** + * Feed Controller - ATOM with parameters + */ + public function testAtomControllerWithParameters(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->method('getParams')->willReturn(['parameter' => 'value']); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->feedBuilder + ->method('buildData') + ->with('atom', ['parameter' => 'value']) + ->willReturn(['content' => 'data']) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): void { + static::assertSame('render_feed', $hook); + static::assertSame('data', $data['content']); + + static::assertArrayHasKey('loggedin', $param); + static::assertSame('atom', $param['target']); + }) + ; + + $result = $this->controller->atom($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/atom', $result->getHeader('Content-Type')[0]); + static::assertSame('feed.atom', (string) $result->getBody()); + static::assertSame('data', $assignedVariables['content']); + } + + protected function createValidContainerMockSet(): void + { + $loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager = $loginManager; + + // Config + $conf = $this->createMock(ConfigManager::class); + $this->container->conf = $conf; + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + return $default; + }); + + // PageBuilder + $pageBuilder = $this->createMock(PageBuilder::class); + $pageBuilder + ->method('render') + ->willReturnCallback(function (string $template): string { + return $template; + }) + ; + $this->container->pageBuilder = $pageBuilder; + + $bookmarkService = $this->createMock(BookmarkServiceInterface::class); + $this->container->bookmarkService = $bookmarkService; + + // Plugin Manager + $pluginManager = $this->createMock(PluginManager::class); + $this->container->pluginManager = $pluginManager; + + // Formatter + $formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory = $formatterFactory; + + // CacheManager + $pageCacheManager = $this->createMock(PageCacheManager::class); + $this->container->pageCacheManager = $pageCacheManager; + + // FeedBuilder + $feedBuilder = $this->createMock(FeedBuilder::class); + $this->container->feedBuilder = $feedBuilder; + + // $_SERVER + $this->container->environment = [ + 'SERVER_NAME' => 'shaarli', + 'SERVER_PORT' => '80', + 'REQUEST_URI' => '/daily-rss', + ]; + } + + protected function assignTemplateVars(array &$variables): void + { + $this->container->pageBuilder + ->expects(static::atLeastOnce()) + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$variables) { + $variables[$key] = $value; + + return $this; + }) + ; + } +} -- cgit v1.2.3 From 5ec4708ced1cdca01eddd7e52377ab5e5f8b3290 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Wed, 20 May 2020 10:47:20 +0200 Subject: Process OpenSearch controller through Slim Also it was missing on the default template feeds --- .../front/controller/OpenSearchControllerTest.php | 92 ++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 tests/front/controller/OpenSearchControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/OpenSearchControllerTest.php b/tests/front/controller/OpenSearchControllerTest.php new file mode 100644 index 00000000..7ba0f7df --- /dev/null +++ b/tests/front/controller/OpenSearchControllerTest.php @@ -0,0 +1,92 @@ +container = $this->createMock(ShaarliContainer::class); + $this->controller = new OpenSearchController($this->container); + } + + public function testOpenSearchController(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/xml', $result->getHeader('Content-Type')[0]); + static::assertSame('opensearch', (string) $result->getBody()); + static::assertSame('http://shaarli', $assignedVariables['serverurl']); + } + + protected function createValidContainerMockSet(): void + { + $loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager = $loginManager; + + // PageBuilder + $pageBuilder = $this->createMock(PageBuilder::class); + $pageBuilder + ->method('render') + ->willReturnCallback(function (string $template): string { + return $template; + }) + ; + $this->container->pageBuilder = $pageBuilder; + + $bookmarkService = $this->createMock(BookmarkServiceInterface::class); + $this->container->bookmarkService = $bookmarkService; + + // Plugin Manager + $pluginManager = $this->createMock(PluginManager::class); + $this->container->pluginManager = $pluginManager; + + // $_SERVER + $this->container->environment = [ + 'SERVER_NAME' => 'shaarli', + 'SERVER_PORT' => '80', + 'REQUEST_URI' => '/open-search', + ]; + } + + protected function assignTemplateVars(array &$variables): void + { + $this->container->pageBuilder + ->expects(static::atLeastOnce()) + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$variables) { + $variables[$key] = $value; + + return $this; + }) + ; + } +} -- cgit v1.2.3 From dd09ec52b20b4a548ecf5c847627575e506e3a50 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Wed, 20 May 2020 12:43:40 +0200 Subject: Refactor front controller tests to create container mock using a trait --- tests/bootstrap.php | 2 + tests/container/ShaarliTestContainer.php | 38 +++++++ tests/front/controller/DailyControllerTest.php | 84 +-------------- tests/front/controller/FeedControllerTest.php | 78 +------------- .../front/controller/FrontControllerMockHelper.php | 114 +++++++++++++++++++++ tests/front/controller/LoginControllerTest.php | 58 +++-------- tests/front/controller/LogoutControllerTest.php | 19 ++-- .../front/controller/OpenSearchControllerTest.php | 60 ++--------- .../front/controller/PictureWallControllerTest.php | 65 +----------- tests/front/controller/ShaarliControllerTest.php | 68 +++++------- tests/front/controller/TagCloudControllerTest.php | 62 +---------- tests/front/controller/TagControllerTest.php | 49 ++------- 12 files changed, 232 insertions(+), 465 deletions(-) create mode 100644 tests/container/ShaarliTestContainer.php create mode 100644 tests/front/controller/FrontControllerMockHelper.php (limited to 'tests') diff --git a/tests/bootstrap.php b/tests/bootstrap.php index c80bcb33..6bb345c2 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -21,3 +21,5 @@ require_once 'application/http/HttpUtils.php'; require_once 'tests/utils/ReferenceLinkDB.php'; require_once 'tests/utils/ReferenceHistory.php'; require_once 'tests/utils/FakeBookmarkService.php'; +require_once 'tests/container/ShaarliTestContainer.php'; +require_once 'tests/front/controller/FrontControllerMockHelper.php'; diff --git a/tests/container/ShaarliTestContainer.php b/tests/container/ShaarliTestContainer.php new file mode 100644 index 00000000..53197ae6 --- /dev/null +++ b/tests/container/ShaarliTestContainer.php @@ -0,0 +1,38 @@ +container = $this->createMock(ShaarliContainer::class); + $this->createContainer(); + $this->controller = new DailyController($this->container); DailyController::$DAILY_RSS_NB_DAYS = 2; } @@ -105,7 +95,8 @@ class DailyControllerTest extends TestCase static::assertArrayHasKey('loggedin', $param); return $data; - }); + }) + ; $result = $this->controller->index($request, $response); @@ -497,71 +488,6 @@ class DailyControllerTest extends TestCase static::assertCount(0, $assignedVariables['days']); } - protected function createValidContainerMockSet(): void - { - $loginManager = $this->createMock(LoginManager::class); - $this->container->loginManager = $loginManager; - - // Config - $conf = $this->createMock(ConfigManager::class); - $this->container->conf = $conf; - $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { - return $default; - }); - - // PageBuilder - $pageBuilder = $this->createMock(PageBuilder::class); - $pageBuilder - ->method('render') - ->willReturnCallback(function (string $template): string { - return $template; - }) - ; - $this->container->pageBuilder = $pageBuilder; - - // Plugin Manager - $pluginManager = $this->createMock(PluginManager::class); - $this->container->pluginManager = $pluginManager; - - // BookmarkService - $bookmarkService = $this->createMock(BookmarkServiceInterface::class); - $this->container->bookmarkService = $bookmarkService; - - // Formatter - $formatterFactory = $this->createMock(FormatterFactory::class); - $formatterFactory - ->method('getFormatter') - ->willReturnCallback(function (): BookmarkFormatter { - return new BookmarkRawFormatter($this->container->conf, true); - }) - ; - $this->container->formatterFactory = $formatterFactory; - - // CacheManager - $pageCacheManager = $this->createMock(PageCacheManager::class); - $this->container->pageCacheManager = $pageCacheManager; - - // $_SERVER - $this->container->environment = [ - 'SERVER_NAME' => 'shaarli', - 'SERVER_PORT' => '80', - 'REQUEST_URI' => '/daily-rss', - ]; - } - - protected function assignTemplateVars(array &$variables): void - { - $this->container->pageBuilder - ->expects(static::atLeastOnce()) - ->method('assign') - ->willReturnCallback(function ($key, $value) use (&$variables) { - $variables[$key] = $value; - - return $this; - }) - ; - } - protected static function generateContent(int $length): string { // bin2hex(random_bytes) generates string twice as long as given parameter diff --git a/tests/front/controller/FeedControllerTest.php b/tests/front/controller/FeedControllerTest.php index d4cc5536..7e8657e2 100644 --- a/tests/front/controller/FeedControllerTest.php +++ b/tests/front/controller/FeedControllerTest.php @@ -5,29 +5,23 @@ declare(strict_types=1); namespace Shaarli\Front\Controller; use PHPUnit\Framework\TestCase; -use Shaarli\Bookmark\BookmarkServiceInterface; -use Shaarli\Config\ConfigManager; -use Shaarli\Container\ShaarliContainer; use Shaarli\Feed\FeedBuilder; -use Shaarli\Formatter\FormatterFactory; -use Shaarli\Plugin\PluginManager; -use Shaarli\Render\PageBuilder; -use Shaarli\Render\PageCacheManager; -use Shaarli\Security\LoginManager; use Slim\Http\Request; use Slim\Http\Response; class FeedControllerTest extends TestCase { - /** @var ShaarliContainer */ - protected $container; + use FrontControllerMockHelper; /** @var FeedController */ protected $controller; public function setUp(): void { - $this->container = $this->createMock(ShaarliContainer::class); + $this->createContainer(); + + $this->container->feedBuilder = $this->createMock(FeedBuilder::class); + $this->controller = new FeedController($this->container); } @@ -154,66 +148,4 @@ class FeedControllerTest extends TestCase static::assertSame('feed.atom', (string) $result->getBody()); static::assertSame('data', $assignedVariables['content']); } - - protected function createValidContainerMockSet(): void - { - $loginManager = $this->createMock(LoginManager::class); - $this->container->loginManager = $loginManager; - - // Config - $conf = $this->createMock(ConfigManager::class); - $this->container->conf = $conf; - $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { - return $default; - }); - - // PageBuilder - $pageBuilder = $this->createMock(PageBuilder::class); - $pageBuilder - ->method('render') - ->willReturnCallback(function (string $template): string { - return $template; - }) - ; - $this->container->pageBuilder = $pageBuilder; - - $bookmarkService = $this->createMock(BookmarkServiceInterface::class); - $this->container->bookmarkService = $bookmarkService; - - // Plugin Manager - $pluginManager = $this->createMock(PluginManager::class); - $this->container->pluginManager = $pluginManager; - - // Formatter - $formatterFactory = $this->createMock(FormatterFactory::class); - $this->container->formatterFactory = $formatterFactory; - - // CacheManager - $pageCacheManager = $this->createMock(PageCacheManager::class); - $this->container->pageCacheManager = $pageCacheManager; - - // FeedBuilder - $feedBuilder = $this->createMock(FeedBuilder::class); - $this->container->feedBuilder = $feedBuilder; - - // $_SERVER - $this->container->environment = [ - 'SERVER_NAME' => 'shaarli', - 'SERVER_PORT' => '80', - 'REQUEST_URI' => '/daily-rss', - ]; - } - - protected function assignTemplateVars(array &$variables): void - { - $this->container->pageBuilder - ->expects(static::atLeastOnce()) - ->method('assign') - ->willReturnCallback(function ($key, $value) use (&$variables) { - $variables[$key] = $value; - - return $this; - }) - ; - } } diff --git a/tests/front/controller/FrontControllerMockHelper.php b/tests/front/controller/FrontControllerMockHelper.php new file mode 100644 index 00000000..b65607e7 --- /dev/null +++ b/tests/front/controller/FrontControllerMockHelper.php @@ -0,0 +1,114 @@ +container = $this->createMock(ShaarliTestContainer::class); + } + + /** + * Initialize container's services used by tests + */ + protected function createValidContainerMockSet(): void + { + $this->container->loginManager = $this->createMock(LoginManager::class); + + // Config + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + return $default; + }); + + // PageBuilder + $this->container->pageBuilder = $this->createMock(PageBuilder::class); + $this->container->pageBuilder + ->method('render') + ->willReturnCallback(function (string $template): string { + return $template; + }) + ; + + // Plugin Manager + $this->container->pluginManager = $this->createMock(PluginManager::class); + + // BookmarkService + $this->container->bookmarkService = $this->createMock(BookmarkServiceInterface::class); + + // Formatter + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->method('getFormatter') + ->willReturnCallback(function (): BookmarkFormatter { + return new BookmarkRawFormatter($this->container->conf, true); + }) + ; + + // CacheManager + $this->container->pageCacheManager = $this->createMock(PageCacheManager::class); + + // SessionManager + $this->container->sessionManager = $this->createMock(SessionManager::class); + + // $_SERVER + $this->container->environment = [ + 'SERVER_NAME' => 'shaarli', + 'SERVER_PORT' => '80', + 'REQUEST_URI' => '/daily-rss', + ]; + } + + /** + * Pass a reference of an array which will be populated by `pageBuilder->assign` calls during execution. + * + * @param mixed $variables Array reference to populate. + */ + protected function assignTemplateVars(array &$variables): void + { + $this->container->pageBuilder + ->expects(static::atLeastOnce()) + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$variables) { + $variables[$key] = $value; + + return $this; + }) + ; + } + + /** + * Force to be used in PHPUnit context. + */ + protected abstract function createMock($originalClassName): MockObject; +} diff --git a/tests/front/controller/LoginControllerTest.php b/tests/front/controller/LoginControllerTest.php index 8cf8ece7..21937f3c 100644 --- a/tests/front/controller/LoginControllerTest.php +++ b/tests/front/controller/LoginControllerTest.php @@ -5,27 +5,22 @@ declare(strict_types=1); namespace Shaarli\Front\Controller; use PHPUnit\Framework\TestCase; -use Shaarli\Bookmark\BookmarkServiceInterface; use Shaarli\Config\ConfigManager; -use Shaarli\Container\ShaarliContainer; use Shaarli\Front\Exception\LoginBannedException; -use Shaarli\Plugin\PluginManager; -use Shaarli\Render\PageBuilder; -use Shaarli\Security\LoginManager; use Slim\Http\Request; use Slim\Http\Response; class LoginControllerTest extends TestCase { - /** @var ShaarliContainer */ - protected $container; + use FrontControllerMockHelper; /** @var LoginController */ protected $controller; public function setUp(): void { - $this->container = $this->createMock(ShaarliContainer::class); + $this->createContainer(); + $this->controller = new LoginController($this->container); } @@ -47,6 +42,8 @@ class LoginControllerTest extends TestCase }) ; + $this->container->loginManager->method('canLogin')->willReturn(true); + $result = $this->controller->index($request, $response); static::assertInstanceOf(Response::class, $result); @@ -77,6 +74,8 @@ class LoginControllerTest extends TestCase }) ; + $this->container->loginManager->expects(static::once())->method('canLogin')->willReturn(true); + $result = $this->controller->index($request, $response); static::assertInstanceOf(Response::class, $result); @@ -91,12 +90,12 @@ class LoginControllerTest extends TestCase public function testLoginControllerWhileLoggedIn(): void { + $this->createValidContainerMockSet(); + $request = $this->createMock(Request::class); $response = new Response(); - $loginManager = $this->createMock(LoginManager::class); - $loginManager->expects(static::once())->method('isLoggedIn')->willReturn(true); - $this->container->loginManager = $loginManager; + $this->container->loginManager->expects(static::once())->method('isLoggedIn')->willReturn(true); $result = $this->controller->index($request, $response); @@ -135,44 +134,11 @@ class LoginControllerTest extends TestCase $request = $this->createMock(Request::class); $response = new Response(); - $loginManager = $this->createMock(LoginManager::class); - $loginManager->method('isLoggedIn')->willReturn(false); - $loginManager->method('canLogin')->willReturn(false); - $this->container->loginManager = $loginManager; + $this->container->loginManager->method('isLoggedIn')->willReturn(false); + $this->container->loginManager->method('canLogin')->willReturn(false); $this->expectException(LoginBannedException::class); $this->controller->index($request, $response); } - - protected function createValidContainerMockSet(): void - { - // User logged out - $loginManager = $this->createMock(LoginManager::class); - $loginManager->method('isLoggedIn')->willReturn(false); - $loginManager->method('canLogin')->willReturn(true); - $this->container->loginManager = $loginManager; - - // Config - $conf = $this->createMock(ConfigManager::class); - $conf->method('get')->willReturnCallback(function (string $parameter, $default) { - return $default; - }); - $this->container->conf = $conf; - - // PageBuilder - $pageBuilder = $this->createMock(PageBuilder::class); - $pageBuilder - ->method('render') - ->willReturnCallback(function (string $template): string { - return $template; - }) - ; - $this->container->pageBuilder = $pageBuilder; - - $pluginManager = $this->createMock(PluginManager::class); - $this->container->pluginManager = $pluginManager; - $bookmarkService = $this->createMock(BookmarkServiceInterface::class); - $this->container->bookmarkService = $bookmarkService; - } } diff --git a/tests/front/controller/LogoutControllerTest.php b/tests/front/controller/LogoutControllerTest.php index d9ca1c25..8e01c367 100644 --- a/tests/front/controller/LogoutControllerTest.php +++ b/tests/front/controller/LogoutControllerTest.php @@ -12,8 +12,6 @@ if (!function_exists('Shaarli\Front\Controller\setcookie')) { } use PHPUnit\Framework\TestCase; -use Shaarli\Container\ShaarliContainer; -use Shaarli\Render\PageCacheManager; use Shaarli\Security\LoginManager; use Shaarli\Security\SessionManager; use Slim\Http\Request; @@ -21,15 +19,15 @@ use Slim\Http\Response; class LogoutControllerTest extends TestCase { - /** @var ShaarliContainer */ - protected $container; + use FrontControllerMockHelper; /** @var LogoutController */ protected $controller; public function setUp(): void { - $this->container = $this->createMock(ShaarliContainer::class); + $this->createContainer(); + $this->controller = new LogoutController($this->container); setcookie(LoginManager::$STAY_SIGNED_IN_COOKIE, $cookie = 'hi there'); @@ -37,16 +35,15 @@ class LogoutControllerTest extends TestCase public function testValidControllerInvoke(): void { + $this->createValidContainerMockSet(); + $request = $this->createMock(Request::class); $response = new Response(); - $pageCacheManager = $this->createMock(PageCacheManager::class); - $pageCacheManager->expects(static::once())->method('invalidateCaches'); - $this->container->pageCacheManager = $pageCacheManager; + $this->container->pageCacheManager->expects(static::once())->method('invalidateCaches'); - $sessionManager = $this->createMock(SessionManager::class); - $sessionManager->expects(static::once())->method('logout'); - $this->container->sessionManager = $sessionManager; + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager->expects(static::once())->method('logout'); static::assertSame('hi there', $_COOKIE[LoginManager::$STAY_SIGNED_IN_COOKIE]); diff --git a/tests/front/controller/OpenSearchControllerTest.php b/tests/front/controller/OpenSearchControllerTest.php index 7ba0f7df..f3b6f439 100644 --- a/tests/front/controller/OpenSearchControllerTest.php +++ b/tests/front/controller/OpenSearchControllerTest.php @@ -5,26 +5,22 @@ declare(strict_types=1); namespace front\controller; use PHPUnit\Framework\TestCase; -use Shaarli\Bookmark\BookmarkServiceInterface; -use Shaarli\Container\ShaarliContainer; +use Shaarli\Front\Controller\FrontControllerMockHelper; use Shaarli\Front\Controller\OpenSearchController; -use Shaarli\Plugin\PluginManager; -use Shaarli\Render\PageBuilder; -use Shaarli\Security\LoginManager; use Slim\Http\Request; use Slim\Http\Response; class OpenSearchControllerTest extends TestCase { - /** @var ShaarliContainer */ - protected $container; + use FrontControllerMockHelper; /** @var OpenSearchController */ protected $controller; public function setUp(): void { - $this->container = $this->createMock(ShaarliContainer::class); + $this->createContainer(); + $this->controller = new OpenSearchController($this->container); } @@ -42,51 +38,11 @@ class OpenSearchControllerTest extends TestCase $result = $this->controller->index($request, $response); static::assertSame(200, $result->getStatusCode()); - static::assertStringContainsString('application/xml', $result->getHeader('Content-Type')[0]); + static::assertStringContainsString( + 'application/opensearchdescription+xml', + $result->getHeader('Content-Type')[0] + ); static::assertSame('opensearch', (string) $result->getBody()); static::assertSame('http://shaarli', $assignedVariables['serverurl']); } - - protected function createValidContainerMockSet(): void - { - $loginManager = $this->createMock(LoginManager::class); - $this->container->loginManager = $loginManager; - - // PageBuilder - $pageBuilder = $this->createMock(PageBuilder::class); - $pageBuilder - ->method('render') - ->willReturnCallback(function (string $template): string { - return $template; - }) - ; - $this->container->pageBuilder = $pageBuilder; - - $bookmarkService = $this->createMock(BookmarkServiceInterface::class); - $this->container->bookmarkService = $bookmarkService; - - // Plugin Manager - $pluginManager = $this->createMock(PluginManager::class); - $this->container->pluginManager = $pluginManager; - - // $_SERVER - $this->container->environment = [ - 'SERVER_NAME' => 'shaarli', - 'SERVER_PORT' => '80', - 'REQUEST_URI' => '/open-search', - ]; - } - - protected function assignTemplateVars(array &$variables): void - { - $this->container->pageBuilder - ->expects(static::atLeastOnce()) - ->method('assign') - ->willReturnCallback(function ($key, $value) use (&$variables) { - $variables[$key] = $value; - - return $this; - }) - ; - } } diff --git a/tests/front/controller/PictureWallControllerTest.php b/tests/front/controller/PictureWallControllerTest.php index 63802abd..8160bb38 100644 --- a/tests/front/controller/PictureWallControllerTest.php +++ b/tests/front/controller/PictureWallControllerTest.php @@ -6,31 +6,23 @@ namespace Shaarli\Front\Controller; use PHPUnit\Framework\TestCase; use Shaarli\Bookmark\Bookmark; -use Shaarli\Bookmark\BookmarkServiceInterface; use Shaarli\Config\ConfigManager; -use Shaarli\Container\ShaarliContainer; -use Shaarli\Formatter\BookmarkFormatter; -use Shaarli\Formatter\BookmarkRawFormatter; -use Shaarli\Formatter\FormatterFactory; use Shaarli\Front\Exception\ThumbnailsDisabledException; -use Shaarli\Plugin\PluginManager; -use Shaarli\Render\PageBuilder; -use Shaarli\Security\LoginManager; use Shaarli\Thumbnailer; use Slim\Http\Request; use Slim\Http\Response; class PictureWallControllerTest extends TestCase { - /** @var ShaarliContainer */ - protected $container; + use FrontControllerMockHelper; /** @var PictureWallController */ protected $controller; public function setUp(): void { - $this->container = $this->createMock(ShaarliContainer::class); + $this->createContainer(); + $this->controller = new PictureWallController($this->container); } @@ -43,6 +35,7 @@ class PictureWallControllerTest extends TestCase $response = new Response(); // ConfigManager: thumbnails are enabled + $this->container->conf = $this->createMock(ConfigManager::class); $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { if ($parameter === 'thumbnails.mode') { return Thumbnailer::MODE_COMMON; @@ -53,15 +46,7 @@ class PictureWallControllerTest extends TestCase // Save RainTPL assigned variables $assignedVariables = []; - $this->container->pageBuilder - ->expects(static::atLeastOnce()) - ->method('assign') - ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { - $assignedVariables[$key] = $value; - - return $this; - }) - ; + $this->assignTemplateVars($assignedVariables); // Links dataset: 2 links with thumbnails $this->container->bookmarkService @@ -137,44 +122,4 @@ class PictureWallControllerTest extends TestCase $this->controller->index($request, $response); } - - protected function createValidContainerMockSet(): void - { - $loginManager = $this->createMock(LoginManager::class); - $this->container->loginManager = $loginManager; - - // Config - $conf = $this->createMock(ConfigManager::class); - $this->container->conf = $conf; - - // PageBuilder - $pageBuilder = $this->createMock(PageBuilder::class); - $pageBuilder - ->method('render') - ->willReturnCallback(function (string $template): string { - return $template; - }) - ; - $this->container->pageBuilder = $pageBuilder; - - // Plugin Manager - $pluginManager = $this->createMock(PluginManager::class); - $this->container->pluginManager = $pluginManager; - - // BookmarkService - $bookmarkService = $this->createMock(BookmarkServiceInterface::class); - $this->container->bookmarkService = $bookmarkService; - - // Formatter - $formatterFactory = $this->createMock(FormatterFactory::class); - $formatterFactory - ->method('getFormatter') - ->willReturnCallback(function (string $type): BookmarkFormatter { - if ($type === 'raw') { - return new BookmarkRawFormatter($this->container->conf, true); - } - }) - ; - $this->container->formatterFactory = $formatterFactory; - } } diff --git a/tests/front/controller/ShaarliControllerTest.php b/tests/front/controller/ShaarliControllerTest.php index 6fa3feb9..3efe4d95 100644 --- a/tests/front/controller/ShaarliControllerTest.php +++ b/tests/front/controller/ShaarliControllerTest.php @@ -6,11 +6,6 @@ namespace Shaarli\Front\Controller; use PHPUnit\Framework\TestCase; use Shaarli\Bookmark\BookmarkFilter; -use Shaarli\Bookmark\BookmarkServiceInterface; -use Shaarli\Container\ShaarliContainer; -use Shaarli\Plugin\PluginManager; -use Shaarli\Render\PageBuilder; -use Shaarli\Security\LoginManager; /** * Class ShaarliControllerTest @@ -20,8 +15,7 @@ use Shaarli\Security\LoginManager; */ class ShaarliControllerTest extends TestCase { - /** @var ShaarliContainer */ - protected $container; + use FrontControllerMockHelper; /** @var LoginController */ protected $controller; @@ -31,7 +25,8 @@ class ShaarliControllerTest extends TestCase public function setUp(): void { - $this->container = $this->createMock(ShaarliContainer::class); + $this->createContainer(); + $this->controller = new class($this->container) extends ShaarliController { public function assignView(string $key, $value): ShaarliController @@ -51,6 +46,8 @@ class ShaarliControllerTest extends TestCase { $this->createValidContainerMockSet(); + $this->assignTemplateVars($this->assignedValues); + $self = $this->controller->assignView('variableName', 'variableValue'); static::assertInstanceOf(ShaarliController::class, $self); @@ -61,6 +58,24 @@ class ShaarliControllerTest extends TestCase { $this->createValidContainerMockSet(); + $this->assignTemplateVars($this->assignedValues); + + $this->container->bookmarkService + ->method('count') + ->willReturnCallback(function (string $visibility): int { + return $visibility === BookmarkFilter::$PRIVATE ? 5 : 10; + }) + ; + + $this->container->pluginManager + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array &$data, array $params): array { + return $data[$hook] = $params; + }); + $this->container->pluginManager->method('getErrors')->willReturn(['error']); + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + $render = $this->controller->render('templateName'); static::assertSame('templateName', $render); @@ -76,41 +91,4 @@ class ShaarliControllerTest extends TestCase static::assertSame('templateName', $this->assignedValues['plugins_footer']['render_footer']['target']); static::assertTrue($this->assignedValues['plugins_footer']['render_footer']['loggedin']); } - - protected function createValidContainerMockSet(): void - { - $pageBuilder = $this->createMock(PageBuilder::class); - $pageBuilder - ->method('assign') - ->willReturnCallback(function (string $key, $value): void { - $this->assignedValues[$key] = $value; - }); - $pageBuilder - ->method('render') - ->willReturnCallback(function (string $template): string { - return $template; - }); - $this->container->pageBuilder = $pageBuilder; - - $bookmarkService = $this->createMock(BookmarkServiceInterface::class); - $bookmarkService - ->method('count') - ->willReturnCallback(function (string $visibility): int { - return $visibility === BookmarkFilter::$PRIVATE ? 5 : 10; - }); - $this->container->bookmarkService = $bookmarkService; - - $pluginManager = $this->createMock(PluginManager::class); - $pluginManager - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array &$data, array $params): array { - return $data[$hook] = $params; - }); - $pluginManager->method('getErrors')->willReturn(['error']); - $this->container->pluginManager = $pluginManager; - - $loginManager = $this->createMock(LoginManager::class); - $loginManager->method('isLoggedIn')->willReturn(true); - $this->container->loginManager = $loginManager; - } } diff --git a/tests/front/controller/TagCloudControllerTest.php b/tests/front/controller/TagCloudControllerTest.php index 719610d7..8c27900d 100644 --- a/tests/front/controller/TagCloudControllerTest.php +++ b/tests/front/controller/TagCloudControllerTest.php @@ -6,27 +6,20 @@ namespace Shaarli\Front\Controller; use PHPUnit\Framework\TestCase; use Shaarli\Bookmark\BookmarkFilter; -use Shaarli\Bookmark\BookmarkServiceInterface; -use Shaarli\Config\ConfigManager; -use Shaarli\Container\ShaarliContainer; -use Shaarli\Plugin\PluginManager; -use Shaarli\Render\PageBuilder; -use Shaarli\Security\LoginManager; -use Shaarli\Security\SessionManager; use Slim\Http\Request; use Slim\Http\Response; class TagCloudControllerTest extends TestCase { - /** @var ShaarliContainer */ - protected $container; + use FrontControllerMockHelper; /** @var TagCloudController */ protected $controller; public function setUp(): void { - $this->container = $this->createMock(ShaarliContainer::class); + $this->createContainer(); + $this->controller = new TagCloudController($this->container); } @@ -385,53 +378,4 @@ class TagCloudControllerTest extends TestCase static::assertSame('', $assignedVariables['search_tags']); static::assertCount(0, $assignedVariables['tags']); } - - - protected function createValidContainerMockSet(): void - { - $loginManager = $this->createMock(LoginManager::class); - $this->container->loginManager = $loginManager; - - $sessionManager = $this->createMock(SessionManager::class); - $this->container->sessionManager = $sessionManager; - - // Config - $conf = $this->createMock(ConfigManager::class); - $this->container->conf = $conf; - - $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { - return $default; - }); - - // PageBuilder - $pageBuilder = $this->createMock(PageBuilder::class); - $pageBuilder - ->method('render') - ->willReturnCallback(function (string $template): string { - return $template; - }) - ; - $this->container->pageBuilder = $pageBuilder; - - // Plugin Manager - $pluginManager = $this->createMock(PluginManager::class); - $this->container->pluginManager = $pluginManager; - - // BookmarkService - $bookmarkService = $this->createMock(BookmarkServiceInterface::class); - $this->container->bookmarkService = $bookmarkService; - } - - protected function assignTemplateVars(array &$variables): void - { - $this->container->pageBuilder - ->expects(static::atLeastOnce()) - ->method('assign') - ->willReturnCallback(function ($key, $value) use (&$variables) { - $variables[$key] = $value; - - return $this; - }) - ; - } } diff --git a/tests/front/controller/TagControllerTest.php b/tests/front/controller/TagControllerTest.php index bbac5652..5eea537b 100644 --- a/tests/front/controller/TagControllerTest.php +++ b/tests/front/controller/TagControllerTest.php @@ -5,32 +5,27 @@ declare(strict_types=1); namespace Shaarli\Front\Controller; use PHPUnit\Framework\TestCase; -use Shaarli\Bookmark\BookmarkServiceInterface; -use Shaarli\Config\ConfigManager; -use Shaarli\Container\ShaarliContainer; -use Shaarli\Plugin\PluginManager; -use Shaarli\Render\PageBuilder; -use Shaarli\Security\LoginManager; use Slim\Http\Request; use Slim\Http\Response; class TagControllerTest extends TestCase { - /** @var ShaarliContainer */ - protected $container; + use FrontControllerMockHelper; /** @var TagController */ protected $controller; public function setUp(): void { - $this->container = $this->createMock(ShaarliContainer::class); + $this->createContainer(); + $this->controller = new TagController($this->container); } public function testAddTagWithReferer(): void { $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; $request = $this->createMock(Request::class); @@ -48,6 +43,7 @@ class TagControllerTest extends TestCase public function testAddTagWithRefererAndExistingSearch(): void { $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; $request = $this->createMock(Request::class); @@ -81,6 +77,7 @@ class TagControllerTest extends TestCase public function testAddTagRemoveLegacyQueryParam(): void { $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&addtag=abc']; $request = $this->createMock(Request::class); @@ -98,6 +95,7 @@ class TagControllerTest extends TestCase public function testAddTagResetPagination(): void { $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&page=12']; $request = $this->createMock(Request::class); @@ -115,6 +113,7 @@ class TagControllerTest extends TestCase public function testAddTagWithRefererAndEmptySearch(): void { $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=']; $request = $this->createMock(Request::class); @@ -132,6 +131,7 @@ class TagControllerTest extends TestCase public function testAddTagWithoutNewTagWithReferer(): void { $this->createValidContainerMockSet(); + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; $request = $this->createMock(Request::class); @@ -157,35 +157,4 @@ class TagControllerTest extends TestCase static::assertSame(302, $result->getStatusCode()); static::assertSame(['./'], $result->getHeader('location')); } - - protected function createValidContainerMockSet(): void - { - // User logged out - $loginManager = $this->createMock(LoginManager::class); - $loginManager->method('isLoggedIn')->willReturn(false); - $loginManager->method('canLogin')->willReturn(true); - $this->container->loginManager = $loginManager; - - // Config - $conf = $this->createMock(ConfigManager::class); - $conf->method('get')->willReturnCallback(function (string $parameter, $default) { - return $default; - }); - $this->container->conf = $conf; - - // PageBuilder - $pageBuilder = $this->createMock(PageBuilder::class); - $pageBuilder - ->method('render') - ->willReturnCallback(function (string $template): string { - return $template; - }) - ; - $this->container->pageBuilder = $pageBuilder; - - $pluginManager = $this->createMock(PluginManager::class); - $this->container->pluginManager = $pluginManager; - $bookmarkService = $this->createMock(BookmarkServiceInterface::class); - $this->container->bookmarkService = $bookmarkService; - } } -- cgit v1.2.3 From 893f5159c64e5bcff505c8367e6dc22cc2a7b14d Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Wed, 20 May 2020 14:38:31 +0200 Subject: Process remove tag endpoint through Slim controller --- tests/front/controller/TagControllerTest.php | 82 ++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) (limited to 'tests') diff --git a/tests/front/controller/TagControllerTest.php b/tests/front/controller/TagControllerTest.php index 5eea537b..2184cb11 100644 --- a/tests/front/controller/TagControllerTest.php +++ b/tests/front/controller/TagControllerTest.php @@ -157,4 +157,86 @@ class TagControllerTest extends TestCase static::assertSame(302, $result->getStatusCode()); static::assertSame(['./'], $result->getHeader('location')); } + + public function testRemoveTagWithoutMatchingTag(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['tag' => 'abc']; + + $result = $this->controller->removeTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutTagsearch(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['tag' => 'abc']; + + $result = $this->controller->removeTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutReferer(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['tag' => 'abc']; + + $result = $this->controller->removeTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutTag(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtag=abc']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->removeTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtag=abc'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutTagWithoutReferer(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->removeTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } } -- cgit v1.2.3 From af290059d10319e76d1e7d78b592cab99c26d91a Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Fri, 22 May 2020 11:02:56 +0200 Subject: Process session filters through Slim controllers Including: - visibility - links per page - untagged only --- .../controller/SessionFilterControllerTest.php | 290 +++++++++++++++++++++ tests/front/controller/ShaarliControllerTest.php | 131 ++++++++++ tests/security/SessionManagerTest.php | 57 ++++ 3 files changed, 478 insertions(+) create mode 100644 tests/front/controller/SessionFilterControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/SessionFilterControllerTest.php b/tests/front/controller/SessionFilterControllerTest.php new file mode 100644 index 00000000..f541de03 --- /dev/null +++ b/tests/front/controller/SessionFilterControllerTest.php @@ -0,0 +1,290 @@ +createContainer(); + + $this->controller = new SessionFilterController($this->container); + } + + /** + * Link per page - Default call with valid parameter and a referer. + */ + public function testLinksPerPage(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $request = $this->createMock(Request::class); + $request->method('getParam')->with('nb')->willReturn('8'); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_LINKS_PER_PAGE, 8) + ; + + $result = $this->controller->linksPerPage($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Link per page - Invalid value, should use default value (20) + */ + public function testLinksPerPageNotValid(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->method('getParam')->with('nb')->willReturn('test'); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_LINKS_PER_PAGE, 20) + ; + + $result = $this->controller->linksPerPage($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } + + /** + * Visibility - Default call for private filter while logged in without current value + */ + public function testVisibility(): void + { + $this->createValidContainerMockSet(); + + $arg = ['visibility' => 'private']; + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_VISIBILITY, 'private') + ; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->visibility($request, $response, $arg); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Visibility - Toggle off private visibility + */ + public function testVisibilityToggleOff(): void + { + $this->createValidContainerMockSet(); + + $arg = ['visibility' => 'private']; + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + $this->container->sessionManager + ->method('getSessionParameter') + ->with(SessionManager::KEY_VISIBILITY) + ->willReturn('private') + ; + $this->container->sessionManager + ->expects(static::never()) + ->method('setSessionParameter') + ; + $this->container->sessionManager + ->expects(static::once()) + ->method('deleteSessionParameter') + ->with(SessionManager::KEY_VISIBILITY) + ; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->visibility($request, $response, $arg); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Visibility - Change private to public + */ + public function testVisibilitySwitch(): void + { + $this->createValidContainerMockSet(); + + $arg = ['visibility' => 'private']; + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + $this->container->sessionManager + ->method('getSessionParameter') + ->with(SessionManager::KEY_VISIBILITY) + ->willReturn('public') + ; + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_VISIBILITY, 'private') + ; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->visibility($request, $response, $arg); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } + + /** + * Visibility - With invalid value - should remove any visibility setting + */ + public function testVisibilityInvalidValue(): void + { + $this->createValidContainerMockSet(); + + $arg = ['visibility' => 'test']; + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + $this->container->sessionManager + ->expects(static::never()) + ->method('setSessionParameter') + ; + $this->container->sessionManager + ->expects(static::once()) + ->method('deleteSessionParameter') + ->with(SessionManager::KEY_VISIBILITY) + ; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->visibility($request, $response, $arg); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Visibility - Try to change visibility while logged out + */ + public function testVisibilityLoggedOut(): void + { + $this->createValidContainerMockSet(); + + $arg = ['visibility' => 'test']; + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $this->container->loginManager->method('isLoggedIn')->willReturn(false); + $this->container->sessionManager + ->expects(static::never()) + ->method('setSessionParameter') + ; + $this->container->sessionManager + ->expects(static::never()) + ->method('deleteSessionParameter') + ->with(SessionManager::KEY_VISIBILITY) + ; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->visibility($request, $response, $arg); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Untagged only - valid call + */ + public function testUntaggedOnly(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_UNTAGGED_ONLY, true) + ; + + $result = $this->controller->untaggedOnly($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Untagged only - toggle off + */ + public function testUntaggedOnlyToggleOff(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager + ->method('getSessionParameter') + ->with(SessionManager::KEY_UNTAGGED_ONLY) + ->willReturn(true) + ; + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_UNTAGGED_ONLY, false) + ; + + $result = $this->controller->untaggedOnly($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } +} diff --git a/tests/front/controller/ShaarliControllerTest.php b/tests/front/controller/ShaarliControllerTest.php index 3efe4d95..a6011b49 100644 --- a/tests/front/controller/ShaarliControllerTest.php +++ b/tests/front/controller/ShaarliControllerTest.php @@ -6,6 +6,7 @@ namespace Shaarli\Front\Controller; use PHPUnit\Framework\TestCase; use Shaarli\Bookmark\BookmarkFilter; +use Slim\Http\Response; /** * Class ShaarliControllerTest @@ -38,6 +39,14 @@ class ShaarliControllerTest extends TestCase { return parent::render($template); } + + public function redirectFromReferer( + Response $response, + array $loopTerms = [], + array $clearParams = [] + ): Response { + return parent::redirectFromReferer($response, $loopTerms, $clearParams); + } }; $this->assignedValues = []; } @@ -91,4 +100,126 @@ class ShaarliControllerTest extends TestCase static::assertSame('templateName', $this->assignedValues['plugins_footer']['render_footer']['target']); static::assertTrue($this->assignedValues['plugins_footer']['render_footer']['loggedin']); } + + /** + * Test redirectFromReferer() - Default behaviour + */ + public function testRedirectFromRefererDefault(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term not matched in the referer + */ + public function testRedirectFromRefererWithUnmatchedLoopTerm(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($response, ['nope']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its path -> redirect to default + */ + public function testRedirectFromRefererWithMatchingLoopTermInPath(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($response, ['nope', 'controller']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its query parameters -> redirect to default + */ + public function testRedirectFromRefererWithMatchingLoopTermInQueryParam(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($response, ['nope', 'other']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its query value + * -> we do not block redirection for query parameter values. + */ + public function testRedirectFromRefererWithMatchingLoopTermInQueryValue(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($response, ['nope', 'param']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its domain name + * -> we do not block redirection for shaarli's hosts + */ + public function testRedirectFromRefererWithLoopTermInDomain(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($response, ['shaarli']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching a query parameter AND clear this query param + * -> the param should be cleared before checking if it matches the redir loop terms + */ + public function testRedirectFromRefererWithMatchingClearedParam(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($response, ['query'], ['query']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?other=2'], $result->getHeader('location')); + } } diff --git a/tests/security/SessionManagerTest.php b/tests/security/SessionManagerTest.php index f264505e..d9db775e 100644 --- a/tests/security/SessionManagerTest.php +++ b/tests/security/SessionManagerTest.php @@ -269,4 +269,61 @@ class SessionManagerTest extends TestCase $this->session['ip'] = 'ip_id_one'; $this->assertTrue($this->sessionManager->hasClientIpChanged('ip_id_two')); } + + /** + * Test creating an entry in the session array + */ + public function testSetSessionParameterCreate(): void + { + $this->sessionManager->setSessionParameter('abc', 'def'); + + static::assertSame('def', $this->session['abc']); + } + + /** + * Test updating an entry in the session array + */ + public function testSetSessionParameterUpdate(): void + { + $this->session['abc'] = 'ghi'; + + $this->sessionManager->setSessionParameter('abc', 'def'); + + static::assertSame('def', $this->session['abc']); + } + + /** + * Test updating an entry in the session array with null value + */ + public function testSetSessionParameterUpdateNull(): void + { + $this->session['abc'] = 'ghi'; + + $this->sessionManager->setSessionParameter('abc', null); + + static::assertArrayHasKey('abc', $this->session); + static::assertNull($this->session['abc']); + } + + /** + * Test deleting an existing entry in the session array + */ + public function testDeleteSessionParameter(): void + { + $this->session['abc'] = 'def'; + + $this->sessionManager->deleteSessionParameter('abc'); + + static::assertArrayNotHasKey('abc', $this->session); + } + + /** + * Test deleting a non existent entry in the session array + */ + public function testDeleteSessionParameterNotExisting(): void + { + $this->sessionManager->deleteSessionParameter('abc'); + + static::assertArrayNotHasKey('abc', $this->session); + } } -- cgit v1.2.3 From 2899ebb5b5e82890c877151f5c02045266ac9973 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Fri, 22 May 2020 13:20:31 +0200 Subject: Initialize admin Slim controllers - Reorganize visitor controllers - Fix redirection with Slim's requests base path - Fix daily links --- tests/bootstrap.php | 3 +- tests/front/controller/DailyControllerTest.php | 497 --------------------- tests/front/controller/FeedControllerTest.php | 151 ------- .../front/controller/FrontControllerMockHelper.php | 114 ----- tests/front/controller/LoginControllerTest.php | 144 ------ tests/front/controller/LogoutControllerTest.php | 57 --- .../front/controller/OpenSearchControllerTest.php | 48 -- .../front/controller/PictureWallControllerTest.php | 125 ------ .../controller/SessionFilterControllerTest.php | 290 ------------ tests/front/controller/ShaarliControllerTest.php | 225 ---------- tests/front/controller/TagCloudControllerTest.php | 381 ---------------- tests/front/controller/TagControllerTest.php | 242 ---------- .../admin/FrontAdminControllerMockHelper.php | 34 ++ .../controller/admin/LogoutControllerTest.php | 57 +++ .../admin/SessionFilterControllerTest.php | 348 +++++++++++++++ .../controller/visitor/DailyControllerTest.php | 497 +++++++++++++++++++++ .../controller/visitor/FeedControllerTest.php | 151 +++++++ .../visitor/FrontControllerMockHelper.php | 114 +++++ .../controller/visitor/LoginControllerTest.php | 144 ++++++ .../visitor/OpenSearchControllerTest.php | 46 ++ .../visitor/PictureWallControllerTest.php | 125 ++++++ .../visitor/ShaarliPublicControllerTest.php | 239 ++++++++++ .../controller/visitor/TagCloudControllerTest.php | 381 ++++++++++++++++ .../front/controller/visitor/TagControllerTest.php | 241 ++++++++++ 24 files changed, 2379 insertions(+), 2275 deletions(-) delete mode 100644 tests/front/controller/DailyControllerTest.php delete mode 100644 tests/front/controller/FeedControllerTest.php delete mode 100644 tests/front/controller/FrontControllerMockHelper.php delete mode 100644 tests/front/controller/LoginControllerTest.php delete mode 100644 tests/front/controller/LogoutControllerTest.php delete mode 100644 tests/front/controller/OpenSearchControllerTest.php delete mode 100644 tests/front/controller/PictureWallControllerTest.php delete mode 100644 tests/front/controller/SessionFilterControllerTest.php delete mode 100644 tests/front/controller/ShaarliControllerTest.php delete mode 100644 tests/front/controller/TagCloudControllerTest.php delete mode 100644 tests/front/controller/TagControllerTest.php create mode 100644 tests/front/controller/admin/FrontAdminControllerMockHelper.php create mode 100644 tests/front/controller/admin/LogoutControllerTest.php create mode 100644 tests/front/controller/admin/SessionFilterControllerTest.php create mode 100644 tests/front/controller/visitor/DailyControllerTest.php create mode 100644 tests/front/controller/visitor/FeedControllerTest.php create mode 100644 tests/front/controller/visitor/FrontControllerMockHelper.php create mode 100644 tests/front/controller/visitor/LoginControllerTest.php create mode 100644 tests/front/controller/visitor/OpenSearchControllerTest.php create mode 100644 tests/front/controller/visitor/PictureWallControllerTest.php create mode 100644 tests/front/controller/visitor/ShaarliPublicControllerTest.php create mode 100644 tests/front/controller/visitor/TagCloudControllerTest.php create mode 100644 tests/front/controller/visitor/TagControllerTest.php (limited to 'tests') diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 6bb345c2..511698ff 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -22,4 +22,5 @@ require_once 'tests/utils/ReferenceLinkDB.php'; require_once 'tests/utils/ReferenceHistory.php'; require_once 'tests/utils/FakeBookmarkService.php'; require_once 'tests/container/ShaarliTestContainer.php'; -require_once 'tests/front/controller/FrontControllerMockHelper.php'; +require_once 'tests/front/controller/visitor/FrontControllerMockHelper.php'; +require_once 'tests/front/controller/admin/FrontAdminControllerMockHelper.php'; diff --git a/tests/front/controller/DailyControllerTest.php b/tests/front/controller/DailyControllerTest.php deleted file mode 100644 index 7ec99030..00000000 --- a/tests/front/controller/DailyControllerTest.php +++ /dev/null @@ -1,497 +0,0 @@ -createContainer(); - - $this->controller = new DailyController($this->container); - DailyController::$DAILY_RSS_NB_DAYS = 2; - } - - public function testValidIndexControllerInvokeDefault(): void - { - $this->createValidContainerMockSet(); - - $currentDay = new \DateTimeImmutable('2020-05-13'); - - $request = $this->createMock(Request::class); - $request->method('getQueryParam')->willReturn($currentDay->format('Ymd')); - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - // Links dataset: 2 links with thumbnails - $this->container->bookmarkService - ->expects(static::once()) - ->method('days') - ->willReturnCallback(function () use ($currentDay): array { - return [ - '20200510', - $currentDay->format('Ymd'), - '20200516', - ]; - }) - ; - $this->container->bookmarkService - ->expects(static::once()) - ->method('filterDay') - ->willReturnCallback(function (): array { - return [ - (new Bookmark()) - ->setId(1) - ->setUrl('http://url.tld') - ->setTitle(static::generateContent(50)) - ->setDescription(static::generateContent(500)) - , - (new Bookmark()) - ->setId(2) - ->setUrl('http://url2.tld') - ->setTitle(static::generateContent(50)) - ->setDescription(static::generateContent(500)) - , - (new Bookmark()) - ->setId(3) - ->setUrl('http://url3.tld') - ->setTitle(static::generateContent(50)) - ->setDescription(static::generateContent(500)) - , - ]; - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array { - static::assertSame('render_daily', $hook); - - static::assertArrayHasKey('linksToDisplay', $data); - static::assertCount(3, $data['linksToDisplay']); - static::assertSame(1, $data['linksToDisplay'][0]['id']); - static::assertSame($currentDay->getTimestamp(), $data['day']); - static::assertSame('20200510', $data['previousday']); - static::assertSame('20200516', $data['nextday']); - - static::assertArrayHasKey('loggedin', $param); - - return $data; - }) - ; - - $result = $this->controller->index($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('daily', (string) $result->getBody()); - static::assertSame( - 'Daily - '. format_date($currentDay, false, true) .' - Shaarli', - $assignedVariables['pagetitle'] - ); - static::assertEquals($currentDay, $assignedVariables['dayDate']); - static::assertEquals($currentDay->getTimestamp(), $assignedVariables['day']); - static::assertCount(3, $assignedVariables['linksToDisplay']); - - $link = $assignedVariables['linksToDisplay'][0]; - - static::assertSame(1, $link['id']); - static::assertSame('http://url.tld', $link['url']); - static::assertNotEmpty($link['title']); - static::assertNotEmpty($link['description']); - static::assertNotEmpty($link['formatedDescription']); - - $link = $assignedVariables['linksToDisplay'][1]; - - static::assertSame(2, $link['id']); - static::assertSame('http://url2.tld', $link['url']); - static::assertNotEmpty($link['title']); - static::assertNotEmpty($link['description']); - static::assertNotEmpty($link['formatedDescription']); - - $link = $assignedVariables['linksToDisplay'][2]; - - static::assertSame(3, $link['id']); - static::assertSame('http://url3.tld', $link['url']); - static::assertNotEmpty($link['title']); - static::assertNotEmpty($link['description']); - static::assertNotEmpty($link['formatedDescription']); - - static::assertCount(3, $assignedVariables['cols']); - static::assertCount(1, $assignedVariables['cols'][0]); - static::assertCount(1, $assignedVariables['cols'][1]); - static::assertCount(1, $assignedVariables['cols'][2]); - - $link = $assignedVariables['cols'][0][0]; - - static::assertSame(1, $link['id']); - static::assertSame('http://url.tld', $link['url']); - static::assertNotEmpty($link['title']); - static::assertNotEmpty($link['description']); - static::assertNotEmpty($link['formatedDescription']); - - $link = $assignedVariables['cols'][1][0]; - - static::assertSame(2, $link['id']); - static::assertSame('http://url2.tld', $link['url']); - static::assertNotEmpty($link['title']); - static::assertNotEmpty($link['description']); - static::assertNotEmpty($link['formatedDescription']); - - $link = $assignedVariables['cols'][2][0]; - - static::assertSame(3, $link['id']); - static::assertSame('http://url3.tld', $link['url']); - static::assertNotEmpty($link['title']); - static::assertNotEmpty($link['description']); - static::assertNotEmpty($link['formatedDescription']); - } - - /** - * Daily page - test that everything goes fine with no future or past bookmarks - */ - public function testValidIndexControllerInvokeNoFutureOrPast(): void - { - $this->createValidContainerMockSet(); - - $currentDay = new \DateTimeImmutable('2020-05-13'); - - $request = $this->createMock(Request::class); - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - // Links dataset: 2 links with thumbnails - $this->container->bookmarkService - ->expects(static::once()) - ->method('days') - ->willReturnCallback(function () use ($currentDay): array { - return [ - $currentDay->format($currentDay->format('Ymd')), - ]; - }) - ; - $this->container->bookmarkService - ->expects(static::once()) - ->method('filterDay') - ->willReturnCallback(function (): array { - return [ - (new Bookmark()) - ->setId(1) - ->setUrl('http://url.tld') - ->setTitle(static::generateContent(50)) - ->setDescription(static::generateContent(500)) - , - ]; - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array { - static::assertSame('render_daily', $hook); - - static::assertArrayHasKey('linksToDisplay', $data); - static::assertCount(1, $data['linksToDisplay']); - static::assertSame(1, $data['linksToDisplay'][0]['id']); - static::assertSame($currentDay->getTimestamp(), $data['day']); - static::assertEmpty($data['previousday']); - static::assertEmpty($data['nextday']); - - static::assertArrayHasKey('loggedin', $param); - - return $data; - }); - - $result = $this->controller->index($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('daily', (string) $result->getBody()); - static::assertSame( - 'Daily - '. format_date($currentDay, false, true) .' - Shaarli', - $assignedVariables['pagetitle'] - ); - static::assertCount(1, $assignedVariables['linksToDisplay']); - - $link = $assignedVariables['linksToDisplay'][0]; - static::assertSame(1, $link['id']); - } - - /** - * Daily page - test that height adjustment in columns is working - */ - public function testValidIndexControllerInvokeHeightAdjustment(): void - { - $this->createValidContainerMockSet(); - - $currentDay = new \DateTimeImmutable('2020-05-13'); - - $request = $this->createMock(Request::class); - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - // Links dataset: 2 links with thumbnails - $this->container->bookmarkService - ->expects(static::once()) - ->method('days') - ->willReturnCallback(function () use ($currentDay): array { - return [ - $currentDay->format($currentDay->format('Ymd')), - ]; - }) - ; - $this->container->bookmarkService - ->expects(static::once()) - ->method('filterDay') - ->willReturnCallback(function (): array { - return [ - (new Bookmark())->setId(1)->setUrl('http://url.tld')->setTitle('title'), - (new Bookmark()) - ->setId(2) - ->setUrl('http://url.tld') - ->setTitle(static::generateContent(50)) - ->setDescription(static::generateContent(5000)) - , - (new Bookmark())->setId(3)->setUrl('http://url.tld')->setTitle('title'), - (new Bookmark())->setId(4)->setUrl('http://url.tld')->setTitle('title'), - (new Bookmark())->setId(5)->setUrl('http://url.tld')->setTitle('title'), - (new Bookmark())->setId(6)->setUrl('http://url.tld')->setTitle('title'), - (new Bookmark())->setId(7)->setUrl('http://url.tld')->setTitle('title'), - ]; - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): array { - return $data; - }) - ; - - $result = $this->controller->index($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('daily', (string) $result->getBody()); - static::assertCount(7, $assignedVariables['linksToDisplay']); - - $columnIds = function (array $column): array { - return array_map(function (array $item): int { return $item['id']; }, $column); - }; - - static::assertSame([1, 4, 6], $columnIds($assignedVariables['cols'][0])); - static::assertSame([2], $columnIds($assignedVariables['cols'][1])); - static::assertSame([3, 5, 7], $columnIds($assignedVariables['cols'][2])); - } - - /** - * Daily page - no bookmark - */ - public function testValidIndexControllerInvokeNoBookmark(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - // Links dataset: 2 links with thumbnails - $this->container->bookmarkService - ->expects(static::once()) - ->method('days') - ->willReturnCallback(function (): array { - return []; - }) - ; - $this->container->bookmarkService - ->expects(static::once()) - ->method('filterDay') - ->willReturnCallback(function (): array { - return []; - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): array { - return $data; - }) - ; - - $result = $this->controller->index($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('daily', (string) $result->getBody()); - static::assertCount(0, $assignedVariables['linksToDisplay']); - static::assertSame('Today', $assignedVariables['dayDesc']); - static::assertEquals((new \DateTime())->setTime(0, 0)->getTimestamp(), $assignedVariables['day']); - static::assertEquals((new \DateTime())->setTime(0, 0), $assignedVariables['dayDate']); - } - - /** - * Daily RSS - default behaviour - */ - public function testValidRssControllerInvokeDefault(): void - { - $this->createValidContainerMockSet(); - - $dates = [ - new \DateTimeImmutable('2020-05-17'), - new \DateTimeImmutable('2020-05-15'), - new \DateTimeImmutable('2020-05-13'), - ]; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([ - (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'), - (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'), - (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'), - (new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'), - ]); - - $this->container->pageCacheManager - ->expects(static::once()) - ->method('getCachePage') - ->willReturnCallback(function (): CachedPage { - $cachedPage = $this->createMock(CachedPage::class); - $cachedPage->expects(static::once())->method('cache')->with('dailyrss'); - - return $cachedPage; - } - ); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $result = $this->controller->rss($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); - static::assertSame('dailyrss', (string) $result->getBody()); - static::assertSame('Shaarli', $assignedVariables['title']); - static::assertSame('http://shaarli', $assignedVariables['index_url']); - static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']); - static::assertFalse($assignedVariables['hide_timestamps']); - static::assertCount(2, $assignedVariables['days']); - - $day = $assignedVariables['days'][$dates[0]->format('Ymd')]; - - static::assertEquals($dates[0], $day['date']); - static::assertSame($dates[0]->format(\DateTime::RSS), $day['date_rss']); - static::assertSame(format_date($dates[0], false), $day['date_human']); - static::assertSame('http://shaarli/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']); - static::assertCount(1, $day['links']); - static::assertSame(1, $day['links'][0]['id']); - static::assertSame('http://domain.tld/1', $day['links'][0]['url']); - static::assertEquals($dates[0], $day['links'][0]['created']); - - $day = $assignedVariables['days'][$dates[1]->format('Ymd')]; - - static::assertEquals($dates[1], $day['date']); - static::assertSame($dates[1]->format(\DateTime::RSS), $day['date_rss']); - static::assertSame(format_date($dates[1], false), $day['date_human']); - static::assertSame('http://shaarli/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']); - static::assertCount(2, $day['links']); - - static::assertSame(2, $day['links'][0]['id']); - static::assertSame('http://domain.tld/2', $day['links'][0]['url']); - static::assertEquals($dates[1], $day['links'][0]['created']); - static::assertSame(3, $day['links'][1]['id']); - static::assertSame('http://domain.tld/3', $day['links'][1]['url']); - static::assertEquals($dates[1], $day['links'][1]['created']); - } - - /** - * Daily RSS - trigger cache rendering - */ - public function testValidRssControllerInvokeTriggerCache(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->pageCacheManager->method('getCachePage')->willReturnCallback(function (): CachedPage { - $cachedPage = $this->createMock(CachedPage::class); - $cachedPage->method('cachedVersion')->willReturn('this is cache!'); - - return $cachedPage; - }); - - $this->container->bookmarkService->expects(static::never())->method('search'); - - $result = $this->controller->rss($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); - static::assertSame('this is cache!', (string) $result->getBody()); - } - - /** - * Daily RSS - No bookmark - */ - public function testValidRssControllerInvokeNoBookmark(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([]); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $result = $this->controller->rss($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); - static::assertSame('dailyrss', (string) $result->getBody()); - static::assertSame('Shaarli', $assignedVariables['title']); - static::assertSame('http://shaarli', $assignedVariables['index_url']); - static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']); - static::assertFalse($assignedVariables['hide_timestamps']); - static::assertCount(0, $assignedVariables['days']); - } - - protected static function generateContent(int $length): string - { - // bin2hex(random_bytes) generates string twice as long as given parameter - $length = (int) ceil($length / 2); - return bin2hex(random_bytes($length)); - } -} diff --git a/tests/front/controller/FeedControllerTest.php b/tests/front/controller/FeedControllerTest.php deleted file mode 100644 index 7e8657e2..00000000 --- a/tests/front/controller/FeedControllerTest.php +++ /dev/null @@ -1,151 +0,0 @@ -createContainer(); - - $this->container->feedBuilder = $this->createMock(FeedBuilder::class); - - $this->controller = new FeedController($this->container); - } - - /** - * Feed Controller - RSS default behaviour - */ - public function testDefaultRssController(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->feedBuilder->expects(static::once())->method('setLocale'); - $this->container->feedBuilder->expects(static::once())->method('setHideDates')->with(false); - $this->container->feedBuilder->expects(static::once())->method('setUsePermalinks')->with(true); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $this->container->feedBuilder->method('buildData')->willReturn(['content' => 'data']); - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): void { - static::assertSame('render_feed', $hook); - static::assertSame('data', $data['content']); - - static::assertArrayHasKey('loggedin', $param); - static::assertSame('rss', $param['target']); - }) - ; - - $result = $this->controller->rss($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); - static::assertSame('feed.rss', (string) $result->getBody()); - static::assertSame('data', $assignedVariables['content']); - } - - /** - * Feed Controller - ATOM default behaviour - */ - public function testDefaultAtomController(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->feedBuilder->expects(static::once())->method('setLocale'); - $this->container->feedBuilder->expects(static::once())->method('setHideDates')->with(false); - $this->container->feedBuilder->expects(static::once())->method('setUsePermalinks')->with(true); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $this->container->feedBuilder->method('buildData')->willReturn(['content' => 'data']); - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): void { - static::assertSame('render_feed', $hook); - static::assertSame('data', $data['content']); - - static::assertArrayHasKey('loggedin', $param); - static::assertSame('atom', $param['target']); - }) - ; - - $result = $this->controller->atom($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertStringContainsString('application/atom', $result->getHeader('Content-Type')[0]); - static::assertSame('feed.atom', (string) $result->getBody()); - static::assertSame('data', $assignedVariables['content']); - } - - /** - * Feed Controller - ATOM with parameters - */ - public function testAtomControllerWithParameters(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $request->method('getParams')->willReturn(['parameter' => 'value']); - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $this->container->feedBuilder - ->method('buildData') - ->with('atom', ['parameter' => 'value']) - ->willReturn(['content' => 'data']) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): void { - static::assertSame('render_feed', $hook); - static::assertSame('data', $data['content']); - - static::assertArrayHasKey('loggedin', $param); - static::assertSame('atom', $param['target']); - }) - ; - - $result = $this->controller->atom($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertStringContainsString('application/atom', $result->getHeader('Content-Type')[0]); - static::assertSame('feed.atom', (string) $result->getBody()); - static::assertSame('data', $assignedVariables['content']); - } -} diff --git a/tests/front/controller/FrontControllerMockHelper.php b/tests/front/controller/FrontControllerMockHelper.php deleted file mode 100644 index b65607e7..00000000 --- a/tests/front/controller/FrontControllerMockHelper.php +++ /dev/null @@ -1,114 +0,0 @@ -container = $this->createMock(ShaarliTestContainer::class); - } - - /** - * Initialize container's services used by tests - */ - protected function createValidContainerMockSet(): void - { - $this->container->loginManager = $this->createMock(LoginManager::class); - - // Config - $this->container->conf = $this->createMock(ConfigManager::class); - $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { - return $default; - }); - - // PageBuilder - $this->container->pageBuilder = $this->createMock(PageBuilder::class); - $this->container->pageBuilder - ->method('render') - ->willReturnCallback(function (string $template): string { - return $template; - }) - ; - - // Plugin Manager - $this->container->pluginManager = $this->createMock(PluginManager::class); - - // BookmarkService - $this->container->bookmarkService = $this->createMock(BookmarkServiceInterface::class); - - // Formatter - $this->container->formatterFactory = $this->createMock(FormatterFactory::class); - $this->container->formatterFactory - ->method('getFormatter') - ->willReturnCallback(function (): BookmarkFormatter { - return new BookmarkRawFormatter($this->container->conf, true); - }) - ; - - // CacheManager - $this->container->pageCacheManager = $this->createMock(PageCacheManager::class); - - // SessionManager - $this->container->sessionManager = $this->createMock(SessionManager::class); - - // $_SERVER - $this->container->environment = [ - 'SERVER_NAME' => 'shaarli', - 'SERVER_PORT' => '80', - 'REQUEST_URI' => '/daily-rss', - ]; - } - - /** - * Pass a reference of an array which will be populated by `pageBuilder->assign` calls during execution. - * - * @param mixed $variables Array reference to populate. - */ - protected function assignTemplateVars(array &$variables): void - { - $this->container->pageBuilder - ->expects(static::atLeastOnce()) - ->method('assign') - ->willReturnCallback(function ($key, $value) use (&$variables) { - $variables[$key] = $value; - - return $this; - }) - ; - } - - /** - * Force to be used in PHPUnit context. - */ - protected abstract function createMock($originalClassName): MockObject; -} diff --git a/tests/front/controller/LoginControllerTest.php b/tests/front/controller/LoginControllerTest.php deleted file mode 100644 index 21937f3c..00000000 --- a/tests/front/controller/LoginControllerTest.php +++ /dev/null @@ -1,144 +0,0 @@ -createContainer(); - - $this->controller = new LoginController($this->container); - } - - public function testValidControllerInvoke(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); - $response = new Response(); - - $assignedVariables = []; - $this->container->pageBuilder - ->method('assign') - ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { - $assignedVariables[$key] = $value; - - return $this; - }) - ; - - $this->container->loginManager->method('canLogin')->willReturn(true); - - $result = $this->controller->index($request, $response); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(200, $result->getStatusCode()); - static::assertSame('loginform', (string) $result->getBody()); - - static::assertSame('> referer', $assignedVariables['returnurl']); - static::assertSame(true, $assignedVariables['remember_user_default']); - static::assertSame('Login - Shaarli', $assignedVariables['pagetitle']); - } - - public function testValidControllerInvokeWithUserName(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); - $request->expects(static::exactly(2))->method('getParam')->willReturn('myUser>'); - $response = new Response(); - - $assignedVariables = []; - $this->container->pageBuilder - ->method('assign') - ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { - $assignedVariables[$key] = $value; - - return $this; - }) - ; - - $this->container->loginManager->expects(static::once())->method('canLogin')->willReturn(true); - - $result = $this->controller->index($request, $response); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(200, $result->getStatusCode()); - static::assertSame('loginform', (string) $result->getBody()); - - static::assertSame('myUser>', $assignedVariables['username']); - static::assertSame('> referer', $assignedVariables['returnurl']); - static::assertSame(true, $assignedVariables['remember_user_default']); - static::assertSame('Login - Shaarli', $assignedVariables['pagetitle']); - } - - public function testLoginControllerWhileLoggedIn(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->loginManager->expects(static::once())->method('isLoggedIn')->willReturn(true); - - $result = $this->controller->index($request, $response); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('Location')); - } - - public function testLoginControllerOpenShaarli(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $conf = $this->createMock(ConfigManager::class); - $conf->method('get')->willReturnCallback(function (string $parameter, $default) { - if ($parameter === 'security.open_shaarli') { - return true; - } - return $default; - }); - $this->container->conf = $conf; - - $result = $this->controller->index($request, $response); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('Location')); - } - - public function testLoginControllerWhileBanned(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->loginManager->method('isLoggedIn')->willReturn(false); - $this->container->loginManager->method('canLogin')->willReturn(false); - - $this->expectException(LoginBannedException::class); - - $this->controller->index($request, $response); - } -} diff --git a/tests/front/controller/LogoutControllerTest.php b/tests/front/controller/LogoutControllerTest.php deleted file mode 100644 index 8e01c367..00000000 --- a/tests/front/controller/LogoutControllerTest.php +++ /dev/null @@ -1,57 +0,0 @@ -createContainer(); - - $this->controller = new LogoutController($this->container); - - setcookie(LoginManager::$STAY_SIGNED_IN_COOKIE, $cookie = 'hi there'); - } - - public function testValidControllerInvoke(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->pageCacheManager->expects(static::once())->method('invalidateCaches'); - - $this->container->sessionManager = $this->createMock(SessionManager::class); - $this->container->sessionManager->expects(static::once())->method('logout'); - - static::assertSame('hi there', $_COOKIE[LoginManager::$STAY_SIGNED_IN_COOKIE]); - - $result = $this->controller->index($request, $response); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertContains('./', $result->getHeader('Location')); - static::assertSame('false', $_COOKIE[LoginManager::$STAY_SIGNED_IN_COOKIE]); - } -} diff --git a/tests/front/controller/OpenSearchControllerTest.php b/tests/front/controller/OpenSearchControllerTest.php deleted file mode 100644 index f3b6f439..00000000 --- a/tests/front/controller/OpenSearchControllerTest.php +++ /dev/null @@ -1,48 +0,0 @@ -createContainer(); - - $this->controller = new OpenSearchController($this->container); - } - - public function testOpenSearchController(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $result = $this->controller->index($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertStringContainsString( - 'application/opensearchdescription+xml', - $result->getHeader('Content-Type')[0] - ); - static::assertSame('opensearch', (string) $result->getBody()); - static::assertSame('http://shaarli', $assignedVariables['serverurl']); - } -} diff --git a/tests/front/controller/PictureWallControllerTest.php b/tests/front/controller/PictureWallControllerTest.php deleted file mode 100644 index 8160bb38..00000000 --- a/tests/front/controller/PictureWallControllerTest.php +++ /dev/null @@ -1,125 +0,0 @@ -createContainer(); - - $this->controller = new PictureWallController($this->container); - } - - public function testValidControllerInvokeDefault(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $request->expects(static::once())->method('getQueryParams')->willReturn([]); - $response = new Response(); - - // ConfigManager: thumbnails are enabled - $this->container->conf = $this->createMock(ConfigManager::class); - $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { - if ($parameter === 'thumbnails.mode') { - return Thumbnailer::MODE_COMMON; - } - - return $default; - }); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - // Links dataset: 2 links with thumbnails - $this->container->bookmarkService - ->expects(static::once()) - ->method('search') - ->willReturnCallback(function (array $parameters, ?string $visibility): array { - // Visibility is set through the container, not the call - static::assertNull($visibility); - - // No query parameters - if (count($parameters) === 0) { - return [ - (new Bookmark())->setId(1)->setUrl('http://url.tld')->setThumbnail('thumb1'), - (new Bookmark())->setId(2)->setUrl('http://url2.tld'), - (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setThumbnail('thumb2'), - ]; - } - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): array { - static::assertSame('render_picwall', $hook); - static::assertArrayHasKey('linksToDisplay', $data); - static::assertCount(2, $data['linksToDisplay']); - static::assertSame(1, $data['linksToDisplay'][0]['id']); - static::assertSame(3, $data['linksToDisplay'][1]['id']); - static::assertArrayHasKey('loggedin', $param); - - return $data; - }); - - $result = $this->controller->index($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('picwall', (string) $result->getBody()); - static::assertSame('Picture wall - Shaarli', $assignedVariables['pagetitle']); - static::assertCount(2, $assignedVariables['linksToDisplay']); - - $link = $assignedVariables['linksToDisplay'][0]; - - static::assertSame(1, $link['id']); - static::assertSame('http://url.tld', $link['url']); - static::assertSame('thumb1', $link['thumbnail']); - - $link = $assignedVariables['linksToDisplay'][1]; - - static::assertSame(3, $link['id']); - static::assertSame('http://url3.tld', $link['url']); - static::assertSame('thumb2', $link['thumbnail']); - } - - public function testControllerWithThumbnailsDisabled(): void - { - $this->expectException(ThumbnailsDisabledException::class); - - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - // ConfigManager: thumbnails are disabled - $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { - if ($parameter === 'thumbnails.mode') { - return Thumbnailer::MODE_NONE; - } - - return $default; - }); - - $this->controller->index($request, $response); - } -} diff --git a/tests/front/controller/SessionFilterControllerTest.php b/tests/front/controller/SessionFilterControllerTest.php deleted file mode 100644 index f541de03..00000000 --- a/tests/front/controller/SessionFilterControllerTest.php +++ /dev/null @@ -1,290 +0,0 @@ -createContainer(); - - $this->controller = new SessionFilterController($this->container); - } - - /** - * Link per page - Default call with valid parameter and a referer. - */ - public function testLinksPerPage(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; - - $request = $this->createMock(Request::class); - $request->method('getParam')->with('nb')->willReturn('8'); - $response = new Response(); - - $this->container->sessionManager - ->expects(static::once()) - ->method('setSessionParameter') - ->with(SessionManager::KEY_LINKS_PER_PAGE, 8) - ; - - $result = $this->controller->linksPerPage($request, $response); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); - } - - /** - * Link per page - Invalid value, should use default value (20) - */ - public function testLinksPerPageNotValid(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $request->method('getParam')->with('nb')->willReturn('test'); - $response = new Response(); - - $this->container->sessionManager - ->expects(static::once()) - ->method('setSessionParameter') - ->with(SessionManager::KEY_LINKS_PER_PAGE, 20) - ; - - $result = $this->controller->linksPerPage($request, $response); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('location')); - } - - /** - * Visibility - Default call for private filter while logged in without current value - */ - public function testVisibility(): void - { - $this->createValidContainerMockSet(); - - $arg = ['visibility' => 'private']; - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; - - $this->container->loginManager->method('isLoggedIn')->willReturn(true); - $this->container->sessionManager - ->expects(static::once()) - ->method('setSessionParameter') - ->with(SessionManager::KEY_VISIBILITY, 'private') - ; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $result = $this->controller->visibility($request, $response, $arg); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); - } - - /** - * Visibility - Toggle off private visibility - */ - public function testVisibilityToggleOff(): void - { - $this->createValidContainerMockSet(); - - $arg = ['visibility' => 'private']; - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; - - $this->container->loginManager->method('isLoggedIn')->willReturn(true); - $this->container->sessionManager - ->method('getSessionParameter') - ->with(SessionManager::KEY_VISIBILITY) - ->willReturn('private') - ; - $this->container->sessionManager - ->expects(static::never()) - ->method('setSessionParameter') - ; - $this->container->sessionManager - ->expects(static::once()) - ->method('deleteSessionParameter') - ->with(SessionManager::KEY_VISIBILITY) - ; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $result = $this->controller->visibility($request, $response, $arg); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); - } - - /** - * Visibility - Change private to public - */ - public function testVisibilitySwitch(): void - { - $this->createValidContainerMockSet(); - - $arg = ['visibility' => 'private']; - - $this->container->loginManager->method('isLoggedIn')->willReturn(true); - $this->container->sessionManager - ->method('getSessionParameter') - ->with(SessionManager::KEY_VISIBILITY) - ->willReturn('public') - ; - $this->container->sessionManager - ->expects(static::once()) - ->method('setSessionParameter') - ->with(SessionManager::KEY_VISIBILITY, 'private') - ; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $result = $this->controller->visibility($request, $response, $arg); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('location')); - } - - /** - * Visibility - With invalid value - should remove any visibility setting - */ - public function testVisibilityInvalidValue(): void - { - $this->createValidContainerMockSet(); - - $arg = ['visibility' => 'test']; - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; - - $this->container->loginManager->method('isLoggedIn')->willReturn(true); - $this->container->sessionManager - ->expects(static::never()) - ->method('setSessionParameter') - ; - $this->container->sessionManager - ->expects(static::once()) - ->method('deleteSessionParameter') - ->with(SessionManager::KEY_VISIBILITY) - ; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $result = $this->controller->visibility($request, $response, $arg); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); - } - - /** - * Visibility - Try to change visibility while logged out - */ - public function testVisibilityLoggedOut(): void - { - $this->createValidContainerMockSet(); - - $arg = ['visibility' => 'test']; - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; - - $this->container->loginManager->method('isLoggedIn')->willReturn(false); - $this->container->sessionManager - ->expects(static::never()) - ->method('setSessionParameter') - ; - $this->container->sessionManager - ->expects(static::never()) - ->method('deleteSessionParameter') - ->with(SessionManager::KEY_VISIBILITY) - ; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $result = $this->controller->visibility($request, $response, $arg); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); - } - - /** - * Untagged only - valid call - */ - public function testUntaggedOnly(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->sessionManager - ->expects(static::once()) - ->method('setSessionParameter') - ->with(SessionManager::KEY_UNTAGGED_ONLY, true) - ; - - $result = $this->controller->untaggedOnly($request, $response); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); - } - - /** - * Untagged only - toggle off - */ - public function testUntaggedOnlyToggleOff(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->sessionManager - ->method('getSessionParameter') - ->with(SessionManager::KEY_UNTAGGED_ONLY) - ->willReturn(true) - ; - $this->container->sessionManager - ->expects(static::once()) - ->method('setSessionParameter') - ->with(SessionManager::KEY_UNTAGGED_ONLY, false) - ; - - $result = $this->controller->untaggedOnly($request, $response); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); - } -} diff --git a/tests/front/controller/ShaarliControllerTest.php b/tests/front/controller/ShaarliControllerTest.php deleted file mode 100644 index a6011b49..00000000 --- a/tests/front/controller/ShaarliControllerTest.php +++ /dev/null @@ -1,225 +0,0 @@ -createContainer(); - - $this->controller = new class($this->container) extends ShaarliController - { - public function assignView(string $key, $value): ShaarliController - { - return parent::assignView($key, $value); - } - - public function render(string $template): string - { - return parent::render($template); - } - - public function redirectFromReferer( - Response $response, - array $loopTerms = [], - array $clearParams = [] - ): Response { - return parent::redirectFromReferer($response, $loopTerms, $clearParams); - } - }; - $this->assignedValues = []; - } - - public function testAssignView(): void - { - $this->createValidContainerMockSet(); - - $this->assignTemplateVars($this->assignedValues); - - $self = $this->controller->assignView('variableName', 'variableValue'); - - static::assertInstanceOf(ShaarliController::class, $self); - static::assertSame('variableValue', $this->assignedValues['variableName']); - } - - public function testRender(): void - { - $this->createValidContainerMockSet(); - - $this->assignTemplateVars($this->assignedValues); - - $this->container->bookmarkService - ->method('count') - ->willReturnCallback(function (string $visibility): int { - return $visibility === BookmarkFilter::$PRIVATE ? 5 : 10; - }) - ; - - $this->container->pluginManager - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array &$data, array $params): array { - return $data[$hook] = $params; - }); - $this->container->pluginManager->method('getErrors')->willReturn(['error']); - - $this->container->loginManager->method('isLoggedIn')->willReturn(true); - - $render = $this->controller->render('templateName'); - - static::assertSame('templateName', $render); - - static::assertSame(10, $this->assignedValues['linkcount']); - static::assertSame(5, $this->assignedValues['privateLinkcount']); - static::assertSame(['error'], $this->assignedValues['plugin_errors']); - - static::assertSame('templateName', $this->assignedValues['plugins_includes']['render_includes']['target']); - static::assertTrue($this->assignedValues['plugins_includes']['render_includes']['loggedin']); - static::assertSame('templateName', $this->assignedValues['plugins_header']['render_header']['target']); - static::assertTrue($this->assignedValues['plugins_header']['render_header']['loggedin']); - static::assertSame('templateName', $this->assignedValues['plugins_footer']['render_footer']['target']); - static::assertTrue($this->assignedValues['plugins_footer']['render_footer']['loggedin']); - } - - /** - * Test redirectFromReferer() - Default behaviour - */ - public function testRedirectFromRefererDefault(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($response); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term not matched in the referer - */ - public function testRedirectFromRefererWithUnmatchedLoopTerm(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($response, ['nope']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term matching the referer in its path -> redirect to default - */ - public function testRedirectFromRefererWithMatchingLoopTermInPath(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($response, ['nope', 'controller']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term matching the referer in its query parameters -> redirect to default - */ - public function testRedirectFromRefererWithMatchingLoopTermInQueryParam(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($response, ['nope', 'other']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term matching the referer in its query value - * -> we do not block redirection for query parameter values. - */ - public function testRedirectFromRefererWithMatchingLoopTermInQueryValue(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($response, ['nope', 'param']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term matching the referer in its domain name - * -> we do not block redirection for shaarli's hosts - */ - public function testRedirectFromRefererWithLoopTermInDomain(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($response, ['shaarli']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term matching a query parameter AND clear this query param - * -> the param should be cleared before checking if it matches the redir loop terms - */ - public function testRedirectFromRefererWithMatchingClearedParam(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($response, ['query'], ['query']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller?other=2'], $result->getHeader('location')); - } -} diff --git a/tests/front/controller/TagCloudControllerTest.php b/tests/front/controller/TagCloudControllerTest.php deleted file mode 100644 index 8c27900d..00000000 --- a/tests/front/controller/TagCloudControllerTest.php +++ /dev/null @@ -1,381 +0,0 @@ -createContainer(); - - $this->controller = new TagCloudController($this->container); - } - - /** - * Tag Cloud - default parameters - */ - public function testValidCloudControllerInvokeDefault(): void - { - $this->createValidContainerMockSet(); - - $allTags = [ - 'ghi' => 1, - 'abc' => 3, - 'def' => 12, - ]; - $expectedOrder = ['abc', 'def', 'ghi']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $this->container->bookmarkService - ->expects(static::once()) - ->method('bookmarksCountPerTag') - ->with([], null) - ->willReturnCallback(function () use ($allTags): array { - return $allTags; - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): array { - static::assertSame('render_tagcloud', $hook); - static::assertSame('', $data['search_tags']); - static::assertCount(3, $data['tags']); - - static::assertArrayHasKey('loggedin', $param); - - return $data; - }) - ; - - $result = $this->controller->cloud($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('tag.cloud', (string) $result->getBody()); - static::assertSame('Tag cloud - Shaarli', $assignedVariables['pagetitle']); - - static::assertSame('', $assignedVariables['search_tags']); - static::assertCount(3, $assignedVariables['tags']); - static::assertSame($expectedOrder, array_keys($assignedVariables['tags'])); - - foreach ($allTags as $tag => $count) { - static::assertArrayHasKey($tag, $assignedVariables['tags']); - static::assertSame($count, $assignedVariables['tags'][$tag]['count']); - static::assertGreaterThan(0, $assignedVariables['tags'][$tag]['size']); - static::assertLessThan(5, $assignedVariables['tags'][$tag]['size']); - } - } - - /** - * Tag Cloud - Additional parameters: - * - logged in - * - visibility private - * - search tags: `ghi` and `def` (note that filtered tags are not displayed anymore) - */ - public function testValidCloudControllerInvokeWithParameters(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $request - ->method('getQueryParam') - ->with() - ->willReturnCallback(function (string $key): ?string { - if ('searchtags' === $key) { - return 'ghi def'; - } - - return null; - }) - ; - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $this->container->loginManager->method('isLoggedin')->willReturn(true); - $this->container->sessionManager->expects(static::once())->method('getSessionParameter')->willReturn('private'); - - $this->container->bookmarkService - ->expects(static::once()) - ->method('bookmarksCountPerTag') - ->with(['ghi', 'def'], BookmarkFilter::$PRIVATE) - ->willReturnCallback(function (): array { - return ['abc' => 3]; - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): array { - static::assertSame('render_tagcloud', $hook); - static::assertSame('ghi def', $data['search_tags']); - static::assertCount(1, $data['tags']); - - static::assertArrayHasKey('loggedin', $param); - - return $data; - }) - ; - - $result = $this->controller->cloud($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('tag.cloud', (string) $result->getBody()); - static::assertSame('ghi def - Tag cloud - Shaarli', $assignedVariables['pagetitle']); - - static::assertSame('ghi def', $assignedVariables['search_tags']); - static::assertCount(1, $assignedVariables['tags']); - - static::assertArrayHasKey('abc', $assignedVariables['tags']); - static::assertSame(3, $assignedVariables['tags']['abc']['count']); - static::assertGreaterThan(0, $assignedVariables['tags']['abc']['size']); - static::assertLessThan(5, $assignedVariables['tags']['abc']['size']); - } - - /** - * Tag Cloud - empty - */ - public function testEmptyCloud(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $this->container->bookmarkService - ->expects(static::once()) - ->method('bookmarksCountPerTag') - ->with([], null) - ->willReturnCallback(function (array $parameters, ?string $visibility): array { - return []; - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): array { - static::assertSame('render_tagcloud', $hook); - static::assertSame('', $data['search_tags']); - static::assertCount(0, $data['tags']); - - static::assertArrayHasKey('loggedin', $param); - - return $data; - }) - ; - - $result = $this->controller->cloud($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('tag.cloud', (string) $result->getBody()); - static::assertSame('Tag cloud - Shaarli', $assignedVariables['pagetitle']); - - static::assertSame('', $assignedVariables['search_tags']); - static::assertCount(0, $assignedVariables['tags']); - } - - /** - * Tag List - Default sort is by usage DESC - */ - public function testValidListControllerInvokeDefault(): void - { - $this->createValidContainerMockSet(); - - $allTags = [ - 'def' => 12, - 'abc' => 3, - 'ghi' => 1, - ]; - - $request = $this->createMock(Request::class); - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $this->container->bookmarkService - ->expects(static::once()) - ->method('bookmarksCountPerTag') - ->with([], null) - ->willReturnCallback(function () use ($allTags): array { - return $allTags; - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): array { - static::assertSame('render_taglist', $hook); - static::assertSame('', $data['search_tags']); - static::assertCount(3, $data['tags']); - - static::assertArrayHasKey('loggedin', $param); - - return $data; - }) - ; - - $result = $this->controller->list($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('tag.list', (string) $result->getBody()); - static::assertSame('Tag list - Shaarli', $assignedVariables['pagetitle']); - - static::assertSame('', $assignedVariables['search_tags']); - static::assertCount(3, $assignedVariables['tags']); - - foreach ($allTags as $tag => $count) { - static::assertSame($count, $assignedVariables['tags'][$tag]); - } - } - - /** - * Tag List - Additional parameters: - * - logged in - * - visibility private - * - search tags: `ghi` and `def` (note that filtered tags are not displayed anymore) - * - sort alphabetically - */ - public function testValidListControllerInvokeWithParameters(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $request - ->method('getQueryParam') - ->with() - ->willReturnCallback(function (string $key): ?string { - if ('searchtags' === $key) { - return 'ghi def'; - } elseif ('sort' === $key) { - return 'alpha'; - } - - return null; - }) - ; - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $this->container->loginManager->method('isLoggedin')->willReturn(true); - $this->container->sessionManager->expects(static::once())->method('getSessionParameter')->willReturn('private'); - - $this->container->bookmarkService - ->expects(static::once()) - ->method('bookmarksCountPerTag') - ->with(['ghi', 'def'], BookmarkFilter::$PRIVATE) - ->willReturnCallback(function (): array { - return ['abc' => 3]; - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): array { - static::assertSame('render_taglist', $hook); - static::assertSame('ghi def', $data['search_tags']); - static::assertCount(1, $data['tags']); - - static::assertArrayHasKey('loggedin', $param); - - return $data; - }) - ; - - $result = $this->controller->list($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('tag.list', (string) $result->getBody()); - static::assertSame('ghi def - Tag list - Shaarli', $assignedVariables['pagetitle']); - - static::assertSame('ghi def', $assignedVariables['search_tags']); - static::assertCount(1, $assignedVariables['tags']); - static::assertSame(3, $assignedVariables['tags']['abc']); - } - - /** - * Tag List - empty - */ - public function testEmptyList(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - // Save RainTPL assigned variables - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $this->container->bookmarkService - ->expects(static::once()) - ->method('bookmarksCountPerTag') - ->with([], null) - ->willReturnCallback(function (array $parameters, ?string $visibility): array { - return []; - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data, array $param): array { - static::assertSame('render_taglist', $hook); - static::assertSame('', $data['search_tags']); - static::assertCount(0, $data['tags']); - - static::assertArrayHasKey('loggedin', $param); - - return $data; - }) - ; - - $result = $this->controller->list($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('tag.list', (string) $result->getBody()); - static::assertSame('Tag list - Shaarli', $assignedVariables['pagetitle']); - - static::assertSame('', $assignedVariables['search_tags']); - static::assertCount(0, $assignedVariables['tags']); - } -} diff --git a/tests/front/controller/TagControllerTest.php b/tests/front/controller/TagControllerTest.php deleted file mode 100644 index 2184cb11..00000000 --- a/tests/front/controller/TagControllerTest.php +++ /dev/null @@ -1,242 +0,0 @@ -createContainer(); - - $this->controller = new TagController($this->container); - } - - public function testAddTagWithReferer(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $tags = ['newTag' => 'abc']; - - $result = $this->controller->addTag($request, $response, $tags); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/controller/?searchtags=abc'], $result->getHeader('location')); - } - - public function testAddTagWithRefererAndExistingSearch(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $tags = ['newTag' => 'abc']; - - $result = $this->controller->addTag($request, $response, $tags); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); - } - - public function testAddTagWithoutRefererAndExistingSearch(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $tags = ['newTag' => 'abc']; - - $result = $this->controller->addTag($request, $response, $tags); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./?searchtags=abc'], $result->getHeader('location')); - } - - public function testAddTagRemoveLegacyQueryParam(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&addtag=abc']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $tags = ['newTag' => 'abc']; - - $result = $this->controller->addTag($request, $response, $tags); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); - } - - public function testAddTagResetPagination(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&page=12']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $tags = ['newTag' => 'abc']; - - $result = $this->controller->addTag($request, $response, $tags); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); - } - - public function testAddTagWithRefererAndEmptySearch(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $tags = ['newTag' => 'abc']; - - $result = $this->controller->addTag($request, $response, $tags); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/controller/?searchtags=abc'], $result->getHeader('location')); - } - - public function testAddTagWithoutNewTagWithReferer(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $result = $this->controller->addTag($request, $response, []); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/controller/?searchtags=def'], $result->getHeader('location')); - } - - public function testAddTagWithoutNewTagWithoutReferer(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $result = $this->controller->addTag($request, $response, []); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('location')); - } - - public function testRemoveTagWithoutMatchingTag(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $tags = ['tag' => 'abc']; - - $result = $this->controller->removeTag($request, $response, $tags); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/controller/?searchtags=def'], $result->getHeader('location')); - } - - public function testRemoveTagWithoutTagsearch(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $tags = ['tag' => 'abc']; - - $result = $this->controller->removeTag($request, $response, $tags); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/controller/'], $result->getHeader('location')); - } - - public function testRemoveTagWithoutReferer(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $tags = ['tag' => 'abc']; - - $result = $this->controller->removeTag($request, $response, $tags); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('location')); - } - - public function testRemoveTagWithoutTag(): void - { - $this->createValidContainerMockSet(); - - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtag=abc']; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $result = $this->controller->removeTag($request, $response, []); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/controller/?searchtag=abc'], $result->getHeader('location')); - } - - public function testRemoveTagWithoutTagWithoutReferer(): void - { - $this->createValidContainerMockSet(); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $result = $this->controller->removeTag($request, $response, []); - - static::assertInstanceOf(Response::class, $result); - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('location')); - } -} diff --git a/tests/front/controller/admin/FrontAdminControllerMockHelper.php b/tests/front/controller/admin/FrontAdminControllerMockHelper.php new file mode 100644 index 00000000..94581c09 --- /dev/null +++ b/tests/front/controller/admin/FrontAdminControllerMockHelper.php @@ -0,0 +1,34 @@ +parentCreateContainer(); + + $this->container->loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + } +} diff --git a/tests/front/controller/admin/LogoutControllerTest.php b/tests/front/controller/admin/LogoutControllerTest.php new file mode 100644 index 00000000..239e39b2 --- /dev/null +++ b/tests/front/controller/admin/LogoutControllerTest.php @@ -0,0 +1,57 @@ +createContainer(); + + $this->controller = new LogoutController($this->container); + + setcookie(LoginManager::$STAY_SIGNED_IN_COOKIE, $cookie = 'hi there'); + } + + public function testValidControllerInvoke(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->pageCacheManager->expects(static::once())->method('invalidateCaches'); + + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager->expects(static::once())->method('logout'); + + static::assertSame('hi there', $_COOKIE[LoginManager::$STAY_SIGNED_IN_COOKIE]); + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertContains('./', $result->getHeader('Location')); + static::assertSame('false', $_COOKIE[LoginManager::$STAY_SIGNED_IN_COOKIE]); + } +} diff --git a/tests/front/controller/admin/SessionFilterControllerTest.php b/tests/front/controller/admin/SessionFilterControllerTest.php new file mode 100644 index 00000000..f50f2fc2 --- /dev/null +++ b/tests/front/controller/admin/SessionFilterControllerTest.php @@ -0,0 +1,348 @@ +createContainer(); + + $this->controller = new SessionFilterController($this->container); + } + + /** + * Link per page - Default call with valid parameter and a referer. + */ + public function testLinksPerPage(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $request->method('getParam')->with('nb')->willReturn('8'); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_LINKS_PER_PAGE, 8) + ; + + $result = $this->controller->linksPerPage($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Link per page - Invalid value, should use default value (20) + */ + public function testLinksPerPageNotValid(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $request->method('getParam')->with('nb')->willReturn('test'); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_LINKS_PER_PAGE, 20) + ; + + $result = $this->controller->linksPerPage($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder'], $result->getHeader('location')); + } + + /** + * Visibility - Default call for private filter while logged in without current value + */ + public function testVisibility(): void + { + $this->createValidContainerMockSet(); + + $arg = ['visibility' => 'private']; + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_VISIBILITY, 'private') + ; + + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $response = new Response(); + + $result = $this->controller->visibility($request, $response, $arg); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Visibility - Toggle off private visibility + */ + public function testVisibilityToggleOff(): void + { + $this->createValidContainerMockSet(); + + $arg = ['visibility' => 'private']; + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + $this->container->sessionManager + ->method('getSessionParameter') + ->with(SessionManager::KEY_VISIBILITY) + ->willReturn('private') + ; + $this->container->sessionManager + ->expects(static::never()) + ->method('setSessionParameter') + ; + $this->container->sessionManager + ->expects(static::once()) + ->method('deleteSessionParameter') + ->with(SessionManager::KEY_VISIBILITY) + ; + + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $response = new Response(); + + $result = $this->controller->visibility($request, $response, $arg); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Visibility - Change private to public + */ + public function testVisibilitySwitch(): void + { + $this->createValidContainerMockSet(); + + $arg = ['visibility' => 'private']; + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + $this->container->sessionManager + ->method('getSessionParameter') + ->with(SessionManager::KEY_VISIBILITY) + ->willReturn('public') + ; + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_VISIBILITY, 'private') + ; + + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $response = new Response(); + + $result = $this->controller->visibility($request, $response, $arg); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder'], $result->getHeader('location')); + } + + /** + * Visibility - With invalid value - should remove any visibility setting + */ + public function testVisibilityInvalidValue(): void + { + $this->createValidContainerMockSet(); + + $arg = ['visibility' => 'test']; + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + $this->container->sessionManager + ->expects(static::never()) + ->method('setSessionParameter') + ; + $this->container->sessionManager + ->expects(static::once()) + ->method('deleteSessionParameter') + ->with(SessionManager::KEY_VISIBILITY) + ; + + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $response = new Response(); + + $result = $this->controller->visibility($request, $response, $arg); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Visibility - Try to change visibility while logged out + */ + public function testVisibilityLoggedOut(): void + { + $this->createValidContainerMockSet(); + + $arg = ['visibility' => 'test']; + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $this->container->loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager->method('isLoggedIn')->willReturn(false); + $this->container->sessionManager + ->expects(static::never()) + ->method('setSessionParameter') + ; + $this->container->sessionManager + ->expects(static::never()) + ->method('deleteSessionParameter') + ->with(SessionManager::KEY_VISIBILITY) + ; + + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $response = new Response(); + + $result = $this->controller->visibility($request, $response, $arg); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Untagged only - valid call + */ + public function testUntaggedOnly(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_UNTAGGED_ONLY, true) + ; + + $result = $this->controller->untaggedOnly($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } + + /** + * Untagged only - toggle off + */ + public function testUntaggedOnlyToggleOff(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; + + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + + $response = new Response(); + + $this->container->sessionManager + ->method('getSessionParameter') + ->with(SessionManager::KEY_UNTAGGED_ONLY) + ->willReturn(true) + ; + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_UNTAGGED_ONLY, false) + ; + + $result = $this->controller->untaggedOnly($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location')); + } +} diff --git a/tests/front/controller/visitor/DailyControllerTest.php b/tests/front/controller/visitor/DailyControllerTest.php new file mode 100644 index 00000000..6ff769fc --- /dev/null +++ b/tests/front/controller/visitor/DailyControllerTest.php @@ -0,0 +1,497 @@ +createContainer(); + + $this->controller = new DailyController($this->container); + DailyController::$DAILY_RSS_NB_DAYS = 2; + } + + public function testValidIndexControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $currentDay = new \DateTimeImmutable('2020-05-13'); + + $request = $this->createMock(Request::class); + $request->method('getQueryParam')->willReturn($currentDay->format('Ymd')); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function () use ($currentDay): array { + return [ + '20200510', + $currentDay->format('Ymd'), + '20200516', + ]; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return [ + (new Bookmark()) + ->setId(1) + ->setUrl('http://url.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + (new Bookmark()) + ->setId(2) + ->setUrl('http://url2.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + (new Bookmark()) + ->setId(3) + ->setUrl('http://url3.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + ]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array { + static::assertSame('render_daily', $hook); + + static::assertArrayHasKey('linksToDisplay', $data); + static::assertCount(3, $data['linksToDisplay']); + static::assertSame(1, $data['linksToDisplay'][0]['id']); + static::assertSame($currentDay->getTimestamp(), $data['day']); + static::assertSame('20200510', $data['previousday']); + static::assertSame('20200516', $data['nextday']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertSame( + 'Daily - '. format_date($currentDay, false, true) .' - Shaarli', + $assignedVariables['pagetitle'] + ); + static::assertEquals($currentDay, $assignedVariables['dayDate']); + static::assertEquals($currentDay->getTimestamp(), $assignedVariables['day']); + static::assertCount(3, $assignedVariables['linksToDisplay']); + + $link = $assignedVariables['linksToDisplay'][0]; + + static::assertSame(1, $link['id']); + static::assertSame('http://url.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['linksToDisplay'][1]; + + static::assertSame(2, $link['id']); + static::assertSame('http://url2.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['linksToDisplay'][2]; + + static::assertSame(3, $link['id']); + static::assertSame('http://url3.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + static::assertCount(3, $assignedVariables['cols']); + static::assertCount(1, $assignedVariables['cols'][0]); + static::assertCount(1, $assignedVariables['cols'][1]); + static::assertCount(1, $assignedVariables['cols'][2]); + + $link = $assignedVariables['cols'][0][0]; + + static::assertSame(1, $link['id']); + static::assertSame('http://url.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['cols'][1][0]; + + static::assertSame(2, $link['id']); + static::assertSame('http://url2.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['cols'][2][0]; + + static::assertSame(3, $link['id']); + static::assertSame('http://url3.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + } + + /** + * Daily page - test that everything goes fine with no future or past bookmarks + */ + public function testValidIndexControllerInvokeNoFutureOrPast(): void + { + $this->createValidContainerMockSet(); + + $currentDay = new \DateTimeImmutable('2020-05-13'); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function () use ($currentDay): array { + return [ + $currentDay->format($currentDay->format('Ymd')), + ]; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return [ + (new Bookmark()) + ->setId(1) + ->setUrl('http://url.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + ]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array { + static::assertSame('render_daily', $hook); + + static::assertArrayHasKey('linksToDisplay', $data); + static::assertCount(1, $data['linksToDisplay']); + static::assertSame(1, $data['linksToDisplay'][0]['id']); + static::assertSame($currentDay->getTimestamp(), $data['day']); + static::assertEmpty($data['previousday']); + static::assertEmpty($data['nextday']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertSame( + 'Daily - '. format_date($currentDay, false, true) .' - Shaarli', + $assignedVariables['pagetitle'] + ); + static::assertCount(1, $assignedVariables['linksToDisplay']); + + $link = $assignedVariables['linksToDisplay'][0]; + static::assertSame(1, $link['id']); + } + + /** + * Daily page - test that height adjustment in columns is working + */ + public function testValidIndexControllerInvokeHeightAdjustment(): void + { + $this->createValidContainerMockSet(); + + $currentDay = new \DateTimeImmutable('2020-05-13'); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function () use ($currentDay): array { + return [ + $currentDay->format($currentDay->format('Ymd')), + ]; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return [ + (new Bookmark())->setId(1)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark()) + ->setId(2) + ->setUrl('http://url.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(5000)) + , + (new Bookmark())->setId(3)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(4)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(5)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(6)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(7)->setUrl('http://url.tld')->setTitle('title'), + ]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + return $data; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertCount(7, $assignedVariables['linksToDisplay']); + + $columnIds = function (array $column): array { + return array_map(function (array $item): int { return $item['id']; }, $column); + }; + + static::assertSame([1, 4, 6], $columnIds($assignedVariables['cols'][0])); + static::assertSame([2], $columnIds($assignedVariables['cols'][1])); + static::assertSame([3, 5, 7], $columnIds($assignedVariables['cols'][2])); + } + + /** + * Daily page - no bookmark + */ + public function testValidIndexControllerInvokeNoBookmark(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function (): array { + return []; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return []; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + return $data; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertCount(0, $assignedVariables['linksToDisplay']); + static::assertSame('Today', $assignedVariables['dayDesc']); + static::assertEquals((new \DateTime())->setTime(0, 0)->getTimestamp(), $assignedVariables['day']); + static::assertEquals((new \DateTime())->setTime(0, 0), $assignedVariables['dayDate']); + } + + /** + * Daily RSS - default behaviour + */ + public function testValidRssControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $dates = [ + new \DateTimeImmutable('2020-05-17'), + new \DateTimeImmutable('2020-05-15'), + new \DateTimeImmutable('2020-05-13'), + ]; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([ + (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'), + (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'), + (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'), + (new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'), + ]); + + $this->container->pageCacheManager + ->expects(static::once()) + ->method('getCachePage') + ->willReturnCallback(function (): CachedPage { + $cachedPage = $this->createMock(CachedPage::class); + $cachedPage->expects(static::once())->method('cache')->with('dailyrss'); + + return $cachedPage; + } + ); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('dailyrss', (string) $result->getBody()); + static::assertSame('Shaarli', $assignedVariables['title']); + static::assertSame('http://shaarli', $assignedVariables['index_url']); + static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']); + static::assertFalse($assignedVariables['hide_timestamps']); + static::assertCount(2, $assignedVariables['days']); + + $day = $assignedVariables['days'][$dates[0]->format('Ymd')]; + + static::assertEquals($dates[0], $day['date']); + static::assertSame($dates[0]->format(\DateTime::RSS), $day['date_rss']); + static::assertSame(format_date($dates[0], false), $day['date_human']); + static::assertSame('http://shaarli/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']); + static::assertCount(1, $day['links']); + static::assertSame(1, $day['links'][0]['id']); + static::assertSame('http://domain.tld/1', $day['links'][0]['url']); + static::assertEquals($dates[0], $day['links'][0]['created']); + + $day = $assignedVariables['days'][$dates[1]->format('Ymd')]; + + static::assertEquals($dates[1], $day['date']); + static::assertSame($dates[1]->format(\DateTime::RSS), $day['date_rss']); + static::assertSame(format_date($dates[1], false), $day['date_human']); + static::assertSame('http://shaarli/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']); + static::assertCount(2, $day['links']); + + static::assertSame(2, $day['links'][0]['id']); + static::assertSame('http://domain.tld/2', $day['links'][0]['url']); + static::assertEquals($dates[1], $day['links'][0]['created']); + static::assertSame(3, $day['links'][1]['id']); + static::assertSame('http://domain.tld/3', $day['links'][1]['url']); + static::assertEquals($dates[1], $day['links'][1]['created']); + } + + /** + * Daily RSS - trigger cache rendering + */ + public function testValidRssControllerInvokeTriggerCache(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->pageCacheManager->method('getCachePage')->willReturnCallback(function (): CachedPage { + $cachedPage = $this->createMock(CachedPage::class); + $cachedPage->method('cachedVersion')->willReturn('this is cache!'); + + return $cachedPage; + }); + + $this->container->bookmarkService->expects(static::never())->method('search'); + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('this is cache!', (string) $result->getBody()); + } + + /** + * Daily RSS - No bookmark + */ + public function testValidRssControllerInvokeNoBookmark(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([]); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('dailyrss', (string) $result->getBody()); + static::assertSame('Shaarli', $assignedVariables['title']); + static::assertSame('http://shaarli', $assignedVariables['index_url']); + static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']); + static::assertFalse($assignedVariables['hide_timestamps']); + static::assertCount(0, $assignedVariables['days']); + } + + protected static function generateContent(int $length): string + { + // bin2hex(random_bytes) generates string twice as long as given parameter + $length = (int) ceil($length / 2); + return bin2hex(random_bytes($length)); + } +} diff --git a/tests/front/controller/visitor/FeedControllerTest.php b/tests/front/controller/visitor/FeedControllerTest.php new file mode 100644 index 00000000..fd4679ea --- /dev/null +++ b/tests/front/controller/visitor/FeedControllerTest.php @@ -0,0 +1,151 @@ +createContainer(); + + $this->container->feedBuilder = $this->createMock(FeedBuilder::class); + + $this->controller = new FeedController($this->container); + } + + /** + * Feed Controller - RSS default behaviour + */ + public function testDefaultRssController(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->feedBuilder->expects(static::once())->method('setLocale'); + $this->container->feedBuilder->expects(static::once())->method('setHideDates')->with(false); + $this->container->feedBuilder->expects(static::once())->method('setUsePermalinks')->with(true); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->feedBuilder->method('buildData')->willReturn(['content' => 'data']); + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): void { + static::assertSame('render_feed', $hook); + static::assertSame('data', $data['content']); + + static::assertArrayHasKey('loggedin', $param); + static::assertSame('rss', $param['target']); + }) + ; + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('feed.rss', (string) $result->getBody()); + static::assertSame('data', $assignedVariables['content']); + } + + /** + * Feed Controller - ATOM default behaviour + */ + public function testDefaultAtomController(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->feedBuilder->expects(static::once())->method('setLocale'); + $this->container->feedBuilder->expects(static::once())->method('setHideDates')->with(false); + $this->container->feedBuilder->expects(static::once())->method('setUsePermalinks')->with(true); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->feedBuilder->method('buildData')->willReturn(['content' => 'data']); + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): void { + static::assertSame('render_feed', $hook); + static::assertSame('data', $data['content']); + + static::assertArrayHasKey('loggedin', $param); + static::assertSame('atom', $param['target']); + }) + ; + + $result = $this->controller->atom($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/atom', $result->getHeader('Content-Type')[0]); + static::assertSame('feed.atom', (string) $result->getBody()); + static::assertSame('data', $assignedVariables['content']); + } + + /** + * Feed Controller - ATOM with parameters + */ + public function testAtomControllerWithParameters(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->method('getParams')->willReturn(['parameter' => 'value']); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->feedBuilder + ->method('buildData') + ->with('atom', ['parameter' => 'value']) + ->willReturn(['content' => 'data']) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): void { + static::assertSame('render_feed', $hook); + static::assertSame('data', $data['content']); + + static::assertArrayHasKey('loggedin', $param); + static::assertSame('atom', $param['target']); + }) + ; + + $result = $this->controller->atom($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/atom', $result->getHeader('Content-Type')[0]); + static::assertSame('feed.atom', (string) $result->getBody()); + static::assertSame('data', $assignedVariables['content']); + } +} diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php new file mode 100644 index 00000000..bc3266b5 --- /dev/null +++ b/tests/front/controller/visitor/FrontControllerMockHelper.php @@ -0,0 +1,114 @@ +container = $this->createMock(ShaarliTestContainer::class); + } + + /** + * Initialize container's services used by tests + */ + protected function createValidContainerMockSet(): void + { + $this->container->loginManager = $this->createMock(LoginManager::class); + + // Config + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + return $default; + }); + + // PageBuilder + $this->container->pageBuilder = $this->createMock(PageBuilder::class); + $this->container->pageBuilder + ->method('render') + ->willReturnCallback(function (string $template): string { + return $template; + }) + ; + + // Plugin Manager + $this->container->pluginManager = $this->createMock(PluginManager::class); + + // BookmarkService + $this->container->bookmarkService = $this->createMock(BookmarkServiceInterface::class); + + // Formatter + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->method('getFormatter') + ->willReturnCallback(function (): BookmarkFormatter { + return new BookmarkRawFormatter($this->container->conf, true); + }) + ; + + // CacheManager + $this->container->pageCacheManager = $this->createMock(PageCacheManager::class); + + // SessionManager + $this->container->sessionManager = $this->createMock(SessionManager::class); + + // $_SERVER + $this->container->environment = [ + 'SERVER_NAME' => 'shaarli', + 'SERVER_PORT' => '80', + 'REQUEST_URI' => '/daily-rss', + ]; + } + + /** + * Pass a reference of an array which will be populated by `pageBuilder->assign` calls during execution. + * + * @param mixed $variables Array reference to populate. + */ + protected function assignTemplateVars(array &$variables): void + { + $this->container->pageBuilder + ->expects(static::atLeastOnce()) + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$variables) { + $variables[$key] = $value; + + return $this; + }) + ; + } + + /** + * Force to be used in PHPUnit context. + */ + protected abstract function createMock($originalClassName): MockObject; +} diff --git a/tests/front/controller/visitor/LoginControllerTest.php b/tests/front/controller/visitor/LoginControllerTest.php new file mode 100644 index 00000000..9d223316 --- /dev/null +++ b/tests/front/controller/visitor/LoginControllerTest.php @@ -0,0 +1,144 @@ +createContainer(); + + $this->controller = new LoginController($this->container); + } + + public function testValidControllerInvoke(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); + $response = new Response(); + + $assignedVariables = []; + $this->container->pageBuilder + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { + $assignedVariables[$key] = $value; + + return $this; + }) + ; + + $this->container->loginManager->method('canLogin')->willReturn(true); + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(200, $result->getStatusCode()); + static::assertSame('loginform', (string) $result->getBody()); + + static::assertSame('> referer', $assignedVariables['returnurl']); + static::assertSame(true, $assignedVariables['remember_user_default']); + static::assertSame('Login - Shaarli', $assignedVariables['pagetitle']); + } + + public function testValidControllerInvokeWithUserName(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); + $request->expects(static::exactly(2))->method('getParam')->willReturn('myUser>'); + $response = new Response(); + + $assignedVariables = []; + $this->container->pageBuilder + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { + $assignedVariables[$key] = $value; + + return $this; + }) + ; + + $this->container->loginManager->expects(static::once())->method('canLogin')->willReturn(true); + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(200, $result->getStatusCode()); + static::assertSame('loginform', (string) $result->getBody()); + + static::assertSame('myUser>', $assignedVariables['username']); + static::assertSame('> referer', $assignedVariables['returnurl']); + static::assertSame(true, $assignedVariables['remember_user_default']); + static::assertSame('Login - Shaarli', $assignedVariables['pagetitle']); + } + + public function testLoginControllerWhileLoggedIn(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->loginManager->expects(static::once())->method('isLoggedIn')->willReturn(true); + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('Location')); + } + + public function testLoginControllerOpenShaarli(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $conf = $this->createMock(ConfigManager::class); + $conf->method('get')->willReturnCallback(function (string $parameter, $default) { + if ($parameter === 'security.open_shaarli') { + return true; + } + return $default; + }); + $this->container->conf = $conf; + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('Location')); + } + + public function testLoginControllerWhileBanned(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->loginManager->method('isLoggedIn')->willReturn(false); + $this->container->loginManager->method('canLogin')->willReturn(false); + + $this->expectException(LoginBannedException::class); + + $this->controller->index($request, $response); + } +} diff --git a/tests/front/controller/visitor/OpenSearchControllerTest.php b/tests/front/controller/visitor/OpenSearchControllerTest.php new file mode 100644 index 00000000..52475318 --- /dev/null +++ b/tests/front/controller/visitor/OpenSearchControllerTest.php @@ -0,0 +1,46 @@ +createContainer(); + + $this->controller = new OpenSearchController($this->container); + } + + public function testOpenSearchController(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString( + 'application/opensearchdescription+xml', + $result->getHeader('Content-Type')[0] + ); + static::assertSame('opensearch', (string) $result->getBody()); + static::assertSame('http://shaarli', $assignedVariables['serverurl']); + } +} diff --git a/tests/front/controller/visitor/PictureWallControllerTest.php b/tests/front/controller/visitor/PictureWallControllerTest.php new file mode 100644 index 00000000..7ac842cb --- /dev/null +++ b/tests/front/controller/visitor/PictureWallControllerTest.php @@ -0,0 +1,125 @@ +createContainer(); + + $this->controller = new PictureWallController($this->container); + } + + public function testValidControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->expects(static::once())->method('getQueryParams')->willReturn([]); + $response = new Response(); + + // ConfigManager: thumbnails are enabled + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + if ($parameter === 'thumbnails.mode') { + return Thumbnailer::MODE_COMMON; + } + + return $default; + }); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('search') + ->willReturnCallback(function (array $parameters, ?string $visibility): array { + // Visibility is set through the container, not the call + static::assertNull($visibility); + + // No query parameters + if (count($parameters) === 0) { + return [ + (new Bookmark())->setId(1)->setUrl('http://url.tld')->setThumbnail('thumb1'), + (new Bookmark())->setId(2)->setUrl('http://url2.tld'), + (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setThumbnail('thumb2'), + ]; + } + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_picwall', $hook); + static::assertArrayHasKey('linksToDisplay', $data); + static::assertCount(2, $data['linksToDisplay']); + static::assertSame(1, $data['linksToDisplay'][0]['id']); + static::assertSame(3, $data['linksToDisplay'][1]['id']); + static::assertArrayHasKey('loggedin', $param); + + return $data; + }); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('picwall', (string) $result->getBody()); + static::assertSame('Picture wall - Shaarli', $assignedVariables['pagetitle']); + static::assertCount(2, $assignedVariables['linksToDisplay']); + + $link = $assignedVariables['linksToDisplay'][0]; + + static::assertSame(1, $link['id']); + static::assertSame('http://url.tld', $link['url']); + static::assertSame('thumb1', $link['thumbnail']); + + $link = $assignedVariables['linksToDisplay'][1]; + + static::assertSame(3, $link['id']); + static::assertSame('http://url3.tld', $link['url']); + static::assertSame('thumb2', $link['thumbnail']); + } + + public function testControllerWithThumbnailsDisabled(): void + { + $this->expectException(ThumbnailsDisabledException::class); + + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // ConfigManager: thumbnails are disabled + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + if ($parameter === 'thumbnails.mode') { + return Thumbnailer::MODE_NONE; + } + + return $default; + }); + + $this->controller->index($request, $response); + } +} diff --git a/tests/front/controller/visitor/ShaarliPublicControllerTest.php b/tests/front/controller/visitor/ShaarliPublicControllerTest.php new file mode 100644 index 00000000..e2e88da3 --- /dev/null +++ b/tests/front/controller/visitor/ShaarliPublicControllerTest.php @@ -0,0 +1,239 @@ +createContainer(); + + $this->controller = new class($this->container) extends ShaarliVisitorController + { + public function assignView(string $key, $value): ShaarliVisitorController + { + return parent::assignView($key, $value); + } + + public function render(string $template): string + { + return parent::render($template); + } + + public function redirectFromReferer( + Request $request, + Response $response, + array $loopTerms = [], + array $clearParams = [] + ): Response { + return parent::redirectFromReferer($request, $response, $loopTerms, $clearParams); + } + }; + $this->assignedValues = []; + + $this->request = $this->createMock(Request::class); + $this->request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + } + + public function testAssignView(): void + { + $this->createValidContainerMockSet(); + + $this->assignTemplateVars($this->assignedValues); + + $self = $this->controller->assignView('variableName', 'variableValue'); + + static::assertInstanceOf(ShaarliVisitorController::class, $self); + static::assertSame('variableValue', $this->assignedValues['variableName']); + } + + public function testRender(): void + { + $this->createValidContainerMockSet(); + + $this->assignTemplateVars($this->assignedValues); + + $this->container->bookmarkService + ->method('count') + ->willReturnCallback(function (string $visibility): int { + return $visibility === BookmarkFilter::$PRIVATE ? 5 : 10; + }) + ; + + $this->container->pluginManager + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array &$data, array $params): array { + return $data[$hook] = $params; + }); + $this->container->pluginManager->method('getErrors')->willReturn(['error']); + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + + $render = $this->controller->render('templateName'); + + static::assertSame('templateName', $render); + + static::assertSame(10, $this->assignedValues['linkcount']); + static::assertSame(5, $this->assignedValues['privateLinkcount']); + static::assertSame(['error'], $this->assignedValues['plugin_errors']); + + static::assertSame('templateName', $this->assignedValues['plugins_includes']['render_includes']['target']); + static::assertTrue($this->assignedValues['plugins_includes']['render_includes']['loggedin']); + static::assertSame('templateName', $this->assignedValues['plugins_header']['render_header']['target']); + static::assertTrue($this->assignedValues['plugins_header']['render_header']['loggedin']); + static::assertSame('templateName', $this->assignedValues['plugins_footer']['render_footer']['target']); + static::assertTrue($this->assignedValues['plugins_footer']['render_footer']['loggedin']); + } + + /** + * Test redirectFromReferer() - Default behaviour + */ + public function testRedirectFromRefererDefault(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term not matched in the referer + */ + public function testRedirectFromRefererWithUnmatchedLoopTerm(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its path -> redirect to default + */ + public function testRedirectFromRefererWithMatchingLoopTermInPath(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'controller']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its query parameters -> redirect to default + */ + public function testRedirectFromRefererWithMatchingLoopTermInQueryParam(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'other']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its query value + * -> we do not block redirection for query parameter values. + */ + public function testRedirectFromRefererWithMatchingLoopTermInQueryValue(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'param']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its domain name + * -> we do not block redirection for shaarli's hosts + */ + public function testRedirectFromRefererWithLoopTermInDomain(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['shaarli']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching a query parameter AND clear this query param + * -> the param should be cleared before checking if it matches the redir loop terms + */ + public function testRedirectFromRefererWithMatchingClearedParam(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['query'], ['query']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?other=2'], $result->getHeader('location')); + } +} diff --git a/tests/front/controller/visitor/TagCloudControllerTest.php b/tests/front/controller/visitor/TagCloudControllerTest.php new file mode 100644 index 00000000..e636d496 --- /dev/null +++ b/tests/front/controller/visitor/TagCloudControllerTest.php @@ -0,0 +1,381 @@ +createContainer(); + + $this->controller = new TagCloudController($this->container); + } + + /** + * Tag Cloud - default parameters + */ + public function testValidCloudControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $allTags = [ + 'ghi' => 1, + 'abc' => 3, + 'def' => 12, + ]; + $expectedOrder = ['abc', 'def', 'ghi']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function () use ($allTags): array { + return $allTags; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_tagcloud', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(3, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->cloud($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.cloud', (string) $result->getBody()); + static::assertSame('Tag cloud - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(3, $assignedVariables['tags']); + static::assertSame($expectedOrder, array_keys($assignedVariables['tags'])); + + foreach ($allTags as $tag => $count) { + static::assertArrayHasKey($tag, $assignedVariables['tags']); + static::assertSame($count, $assignedVariables['tags'][$tag]['count']); + static::assertGreaterThan(0, $assignedVariables['tags'][$tag]['size']); + static::assertLessThan(5, $assignedVariables['tags'][$tag]['size']); + } + } + + /** + * Tag Cloud - Additional parameters: + * - logged in + * - visibility private + * - search tags: `ghi` and `def` (note that filtered tags are not displayed anymore) + */ + public function testValidCloudControllerInvokeWithParameters(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request + ->method('getQueryParam') + ->with() + ->willReturnCallback(function (string $key): ?string { + if ('searchtags' === $key) { + return 'ghi def'; + } + + return null; + }) + ; + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->loginManager->method('isLoggedin')->willReturn(true); + $this->container->sessionManager->expects(static::once())->method('getSessionParameter')->willReturn('private'); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with(['ghi', 'def'], BookmarkFilter::$PRIVATE) + ->willReturnCallback(function (): array { + return ['abc' => 3]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_tagcloud', $hook); + static::assertSame('ghi def', $data['search_tags']); + static::assertCount(1, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->cloud($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.cloud', (string) $result->getBody()); + static::assertSame('ghi def - Tag cloud - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('ghi def', $assignedVariables['search_tags']); + static::assertCount(1, $assignedVariables['tags']); + + static::assertArrayHasKey('abc', $assignedVariables['tags']); + static::assertSame(3, $assignedVariables['tags']['abc']['count']); + static::assertGreaterThan(0, $assignedVariables['tags']['abc']['size']); + static::assertLessThan(5, $assignedVariables['tags']['abc']['size']); + } + + /** + * Tag Cloud - empty + */ + public function testEmptyCloud(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function (array $parameters, ?string $visibility): array { + return []; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_tagcloud', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(0, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->cloud($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.cloud', (string) $result->getBody()); + static::assertSame('Tag cloud - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(0, $assignedVariables['tags']); + } + + /** + * Tag List - Default sort is by usage DESC + */ + public function testValidListControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $allTags = [ + 'def' => 12, + 'abc' => 3, + 'ghi' => 1, + ]; + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function () use ($allTags): array { + return $allTags; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_taglist', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(3, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->list($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.list', (string) $result->getBody()); + static::assertSame('Tag list - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(3, $assignedVariables['tags']); + + foreach ($allTags as $tag => $count) { + static::assertSame($count, $assignedVariables['tags'][$tag]); + } + } + + /** + * Tag List - Additional parameters: + * - logged in + * - visibility private + * - search tags: `ghi` and `def` (note that filtered tags are not displayed anymore) + * - sort alphabetically + */ + public function testValidListControllerInvokeWithParameters(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request + ->method('getQueryParam') + ->with() + ->willReturnCallback(function (string $key): ?string { + if ('searchtags' === $key) { + return 'ghi def'; + } elseif ('sort' === $key) { + return 'alpha'; + } + + return null; + }) + ; + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->loginManager->method('isLoggedin')->willReturn(true); + $this->container->sessionManager->expects(static::once())->method('getSessionParameter')->willReturn('private'); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with(['ghi', 'def'], BookmarkFilter::$PRIVATE) + ->willReturnCallback(function (): array { + return ['abc' => 3]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_taglist', $hook); + static::assertSame('ghi def', $data['search_tags']); + static::assertCount(1, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->list($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.list', (string) $result->getBody()); + static::assertSame('ghi def - Tag list - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('ghi def', $assignedVariables['search_tags']); + static::assertCount(1, $assignedVariables['tags']); + static::assertSame(3, $assignedVariables['tags']['abc']); + } + + /** + * Tag List - empty + */ + public function testEmptyList(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function (array $parameters, ?string $visibility): array { + return []; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_taglist', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(0, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->list($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.list', (string) $result->getBody()); + static::assertSame('Tag list - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(0, $assignedVariables['tags']); + } +} diff --git a/tests/front/controller/visitor/TagControllerTest.php b/tests/front/controller/visitor/TagControllerTest.php new file mode 100644 index 00000000..9a2b1f71 --- /dev/null +++ b/tests/front/controller/visitor/TagControllerTest.php @@ -0,0 +1,241 @@ +createContainer(); + + $this->controller = new TagController($this->container); + } + + public function testAddTagWithReferer(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=abc'], $result->getHeader('location')); + } + + public function testAddTagWithRefererAndExistingSearch(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); + } + + public function testAddTagWithoutRefererAndExistingSearch(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./?searchtags=abc'], $result->getHeader('location')); + } + + public function testAddTagRemoveLegacyQueryParam(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&addtag=abc']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); + } + + public function testAddTagResetPagination(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&page=12']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); + } + + public function testAddTagWithRefererAndEmptySearch(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=abc'], $result->getHeader('location')); + } + + public function testAddTagWithoutNewTagWithReferer(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->addTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def'], $result->getHeader('location')); + } + + public function testAddTagWithoutNewTagWithoutReferer(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->addTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutMatchingTag(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['tag' => 'abc']; + + $result = $this->controller->removeTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutTagsearch(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['tag' => 'abc']; + + $result = $this->controller->removeTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutReferer(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['tag' => 'abc']; + + $result = $this->controller->removeTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutTag(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtag=abc']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->removeTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtag=abc'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutTagWithoutReferer(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->removeTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } +} -- cgit v1.2.3 From ba43064ddb7771fc97df135a32f9b0d5e373dd36 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Fri, 22 May 2020 13:47:02 +0200 Subject: Process tools page through Slim controller --- .../controller/admin/LogoutControllerTest.php | 2 +- .../front/controller/admin/ToolsControllerTest.php | 73 ++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 tests/front/controller/admin/ToolsControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/LogoutControllerTest.php b/tests/front/controller/admin/LogoutControllerTest.php index 239e39b2..ba681b16 100644 --- a/tests/front/controller/admin/LogoutControllerTest.php +++ b/tests/front/controller/admin/LogoutControllerTest.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace Shaarli\Front\Controller\Admin; /** Override PHP builtin setcookie function in the local namespace to mock it... more or less */ -if (!function_exists('Shaarli\Front\Controller\setcookie')) { +if (!function_exists('Shaarli\Front\Controller\Admin\setcookie')) { function setcookie(string $name, string $value): void { $_COOKIE[$name] = $value; } diff --git a/tests/front/controller/admin/ToolsControllerTest.php b/tests/front/controller/admin/ToolsControllerTest.php new file mode 100644 index 00000000..47c5746e --- /dev/null +++ b/tests/front/controller/admin/ToolsControllerTest.php @@ -0,0 +1,73 @@ +createContainer(); + + $this->controller = new ToolsController($this->container); + } + + public function testDefaultInvokeWithHttps(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->environment = [ + 'SERVER_NAME' => 'shaarli', + 'SERVER_PORT' => 443, + 'HTTPS' => 'on', + ]; + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tools', (string) $result->getBody()); + static::assertSame('https://shaarli', $assignedVariables['pageabsaddr']); + static::assertTrue($assignedVariables['sslenabled']); + } + + public function testDefaultInvokeWithoutHttps(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->environment = [ + 'SERVER_NAME' => 'shaarli', + 'SERVER_PORT' => 80, + ]; + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tools', (string) $result->getBody()); + static::assertSame('http://shaarli', $assignedVariables['pageabsaddr']); + static::assertFalse($assignedVariables['sslenabled']); + } +} -- cgit v1.2.3 From ef00f9d2033f6de11e71bf3a909399cae6f73a9f Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Wed, 27 May 2020 13:35:48 +0200 Subject: Process password change controller through Slim --- .../admin/FrontAdminControllerMockHelper.php | 3 +- .../controller/admin/LogoutControllerTest.php | 2 - .../controller/admin/PasswordControllerTest.php | 186 +++++++++++++++++++++ .../admin/SessionFilterControllerTest.php | 18 -- .../front/controller/admin/ToolsControllerTest.php | 4 - .../controller/visitor/DailyControllerTest.php | 14 -- .../controller/visitor/FeedControllerTest.php | 6 - .../visitor/FrontControllerMockHelper.php | 8 +- .../controller/visitor/LoginControllerTest.php | 10 -- .../visitor/OpenSearchControllerTest.php | 2 - .../visitor/PictureWallControllerTest.php | 4 - .../visitor/ShaarliPublicControllerTest.php | 18 -- .../controller/visitor/TagCloudControllerTest.php | 12 -- .../front/controller/visitor/TagControllerTest.php | 26 --- 14 files changed, 188 insertions(+), 125 deletions(-) create mode 100644 tests/front/controller/admin/PasswordControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/FrontAdminControllerMockHelper.php b/tests/front/controller/admin/FrontAdminControllerMockHelper.php index 94581c09..bd40c0c7 100644 --- a/tests/front/controller/admin/FrontAdminControllerMockHelper.php +++ b/tests/front/controller/admin/FrontAdminControllerMockHelper.php @@ -6,7 +6,6 @@ namespace Shaarli\Front\Controller\Admin; use Shaarli\Container\ShaarliTestContainer; use Shaarli\Front\Controller\Visitor\FrontControllerMockHelper; -use Shaarli\Security\LoginManager; /** * Trait FrontControllerMockHelper @@ -28,7 +27,7 @@ trait FrontAdminControllerMockHelper { $this->parentCreateContainer(); - $this->container->loginManager = $this->createMock(LoginManager::class); $this->container->loginManager->method('isLoggedIn')->willReturn(true); + $this->container->sessionManager->method('checkToken')->willReturn(true); } } diff --git a/tests/front/controller/admin/LogoutControllerTest.php b/tests/front/controller/admin/LogoutControllerTest.php index ba681b16..78a0fe73 100644 --- a/tests/front/controller/admin/LogoutControllerTest.php +++ b/tests/front/controller/admin/LogoutControllerTest.php @@ -35,8 +35,6 @@ class LogoutControllerTest extends TestCase public function testValidControllerInvoke(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); diff --git a/tests/front/controller/admin/PasswordControllerTest.php b/tests/front/controller/admin/PasswordControllerTest.php new file mode 100644 index 00000000..7262243e --- /dev/null +++ b/tests/front/controller/admin/PasswordControllerTest.php @@ -0,0 +1,186 @@ +createContainer(); + $this->assignTemplateVars($this->assignedVariables); + + $this->controller = new PasswordController($this->container); + } + + /** + * Test displaying the change password page. + */ + public function testGetPage(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('changepassword', (string) $result->getBody()); + static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']); + } + + /** + * Change the password with valid parameters + */ + public function testPostNewPasswordDefault(): void + { + $request = $this->createMock(Request::class); + $request->method('getParam')->willReturnCallback(function (string $key): string { + if ('oldpassword' === $key) { + return 'old'; + } + if ('setpassword' === $key) { + return 'new'; + } + + return $key; + }); + $response = new Response(); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) { + if ('credentials.hash' === $key) { + return sha1('old' . 'credentials.login' . 'credentials.salt'); + } + + return strpos($key, 'credentials') !== false ? $key : $default; + }); + $this->container->conf->expects(static::once())->method('write')->with(true); + + $this->container->conf + ->method('set') + ->willReturnCallback(function (string $key, string $value) { + if ('credentials.hash' === $key) { + static::assertSame(sha1('new' . 'credentials.login' . 'credentials.salt'), $value); + } + }) + ; + + $result = $this->controller->change($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('changepassword', (string) $result->getBody()); + static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']); + } + + /** + * Change the password with a wrong existing password + */ + public function testPostNewPasswordWrongOldPassword(): void + { + $request = $this->createMock(Request::class); + $request->method('getParam')->willReturnCallback(function (string $key): string { + if ('oldpassword' === $key) { + return 'wrong'; + } + if ('setpassword' === $key) { + return 'new'; + } + + return $key; + }); + $response = new Response(); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) { + if ('credentials.hash' === $key) { + return sha1('old' . 'credentials.login' . 'credentials.salt'); + } + + return strpos($key, 'credentials') !== false ? $key : $default; + }); + + $this->container->conf->expects(static::never())->method('set'); + $this->container->conf->expects(static::never())->method('write'); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['The old password is not correct.']) + ; + + $result = $this->controller->change($request, $response); + + static::assertSame(400, $result->getStatusCode()); + static::assertSame('changepassword', (string) $result->getBody()); + static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']); + } + + /** + * Change the password with a wrong existing password + */ + public function testPostNewPasswordWrongToken(): void + { + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager->method('checkToken')->willReturn(false); + + $this->container->conf->expects(static::never())->method('set'); + $this->container->conf->expects(static::never())->method('write'); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->expectException(WrongTokenException::class); + + $this->controller->change($request, $response); + } + + /** + * Change the password with an empty new password + */ + public function testPostNewEmptyPassword(): void + { + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['You must provide the current and new password to change it.']) + ; + + $this->container->conf->expects(static::never())->method('set'); + $this->container->conf->expects(static::never())->method('write'); + + $request = $this->createMock(Request::class); + $request->method('getParam')->willReturnCallback(function (string $key): string { + if ('oldpassword' === $key) { + return 'old'; + } + if ('setpassword' === $key) { + return ''; + } + + return $key; + }); + $response = new Response(); + + $result = $this->controller->change($request, $response); + + static::assertSame(400, $result->getStatusCode()); + static::assertSame('changepassword', (string) $result->getBody()); + static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']); + } +} diff --git a/tests/front/controller/admin/SessionFilterControllerTest.php b/tests/front/controller/admin/SessionFilterControllerTest.php index f50f2fc2..096963cf 100644 --- a/tests/front/controller/admin/SessionFilterControllerTest.php +++ b/tests/front/controller/admin/SessionFilterControllerTest.php @@ -30,8 +30,6 @@ class SessionFilterControllerTest extends TestCase */ public function testLinksPerPage(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; $request = $this->createMock(Request::class); @@ -62,8 +60,6 @@ class SessionFilterControllerTest extends TestCase */ public function testLinksPerPageNotValid(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $request->method('getUri')->willReturnCallback(function (): Uri { $uri = $this->createMock(Uri::class); @@ -92,8 +88,6 @@ class SessionFilterControllerTest extends TestCase */ public function testVisibility(): void { - $this->createValidContainerMockSet(); - $arg = ['visibility' => 'private']; $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; @@ -126,8 +120,6 @@ class SessionFilterControllerTest extends TestCase */ public function testVisibilityToggleOff(): void { - $this->createValidContainerMockSet(); - $arg = ['visibility' => 'private']; $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; @@ -169,8 +161,6 @@ class SessionFilterControllerTest extends TestCase */ public function testVisibilitySwitch(): void { - $this->createValidContainerMockSet(); - $arg = ['visibility' => 'private']; $this->container->loginManager->method('isLoggedIn')->willReturn(true); @@ -206,8 +196,6 @@ class SessionFilterControllerTest extends TestCase */ public function testVisibilityInvalidValue(): void { - $this->createValidContainerMockSet(); - $arg = ['visibility' => 'test']; $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; @@ -244,8 +232,6 @@ class SessionFilterControllerTest extends TestCase */ public function testVisibilityLoggedOut(): void { - $this->createValidContainerMockSet(); - $arg = ['visibility' => 'test']; $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; @@ -283,8 +269,6 @@ class SessionFilterControllerTest extends TestCase */ public function testUntaggedOnly(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; $request = $this->createMock(Request::class); @@ -314,8 +298,6 @@ class SessionFilterControllerTest extends TestCase */ public function testUntaggedOnlyToggleOff(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; $request = $this->createMock(Request::class); diff --git a/tests/front/controller/admin/ToolsControllerTest.php b/tests/front/controller/admin/ToolsControllerTest.php index 47c5746e..fc756f0f 100644 --- a/tests/front/controller/admin/ToolsControllerTest.php +++ b/tests/front/controller/admin/ToolsControllerTest.php @@ -24,8 +24,6 @@ class ToolsControllerTestControllerTest extends TestCase public function testDefaultInvokeWithHttps(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); @@ -49,8 +47,6 @@ class ToolsControllerTestControllerTest extends TestCase public function testDefaultInvokeWithoutHttps(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); diff --git a/tests/front/controller/visitor/DailyControllerTest.php b/tests/front/controller/visitor/DailyControllerTest.php index 6ff769fc..872420fd 100644 --- a/tests/front/controller/visitor/DailyControllerTest.php +++ b/tests/front/controller/visitor/DailyControllerTest.php @@ -27,8 +27,6 @@ class DailyControllerTest extends TestCase public function testValidIndexControllerInvokeDefault(): void { - $this->createValidContainerMockSet(); - $currentDay = new \DateTimeImmutable('2020-05-13'); $request = $this->createMock(Request::class); @@ -169,8 +167,6 @@ class DailyControllerTest extends TestCase */ public function testValidIndexControllerInvokeNoFutureOrPast(): void { - $this->createValidContainerMockSet(); - $currentDay = new \DateTimeImmutable('2020-05-13'); $request = $this->createMock(Request::class); @@ -243,8 +239,6 @@ class DailyControllerTest extends TestCase */ public function testValidIndexControllerInvokeHeightAdjustment(): void { - $this->createValidContainerMockSet(); - $currentDay = new \DateTimeImmutable('2020-05-13'); $request = $this->createMock(Request::class); @@ -314,8 +308,6 @@ class DailyControllerTest extends TestCase */ public function testValidIndexControllerInvokeNoBookmark(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); @@ -363,8 +355,6 @@ class DailyControllerTest extends TestCase */ public function testValidRssControllerInvokeDefault(): void { - $this->createValidContainerMockSet(); - $dates = [ new \DateTimeImmutable('2020-05-17'), new \DateTimeImmutable('2020-05-15'), @@ -439,8 +429,6 @@ class DailyControllerTest extends TestCase */ public function testValidRssControllerInvokeTriggerCache(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); @@ -465,8 +453,6 @@ class DailyControllerTest extends TestCase */ public function testValidRssControllerInvokeNoBookmark(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); diff --git a/tests/front/controller/visitor/FeedControllerTest.php b/tests/front/controller/visitor/FeedControllerTest.php index fd4679ea..fb417e2a 100644 --- a/tests/front/controller/visitor/FeedControllerTest.php +++ b/tests/front/controller/visitor/FeedControllerTest.php @@ -30,8 +30,6 @@ class FeedControllerTest extends TestCase */ public function testDefaultRssController(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); @@ -71,8 +69,6 @@ class FeedControllerTest extends TestCase */ public function testDefaultAtomController(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); @@ -112,8 +108,6 @@ class FeedControllerTest extends TestCase */ public function testAtomControllerWithParameters(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $request->method('getParams')->willReturn(['parameter' => 'value']); $response = new Response(); diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php index bc3266b5..d16b6949 100644 --- a/tests/front/controller/visitor/FrontControllerMockHelper.php +++ b/tests/front/controller/visitor/FrontControllerMockHelper.php @@ -31,18 +31,12 @@ trait FrontControllerMockHelper protected $container; /** - * Mock the container instance + * Mock the container instance and initialize container's services used by tests */ protected function createContainer(): void { $this->container = $this->createMock(ShaarliTestContainer::class); - } - /** - * Initialize container's services used by tests - */ - protected function createValidContainerMockSet(): void - { $this->container->loginManager = $this->createMock(LoginManager::class); // Config diff --git a/tests/front/controller/visitor/LoginControllerTest.php b/tests/front/controller/visitor/LoginControllerTest.php index 9d223316..faa8ac71 100644 --- a/tests/front/controller/visitor/LoginControllerTest.php +++ b/tests/front/controller/visitor/LoginControllerTest.php @@ -26,8 +26,6 @@ class LoginControllerTest extends TestCase public function testValidControllerInvoke(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); $response = new Response(); @@ -57,8 +55,6 @@ class LoginControllerTest extends TestCase public function testValidControllerInvokeWithUserName(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); $request->expects(static::exactly(2))->method('getParam')->willReturn('myUser>'); @@ -90,8 +86,6 @@ class LoginControllerTest extends TestCase public function testLoginControllerWhileLoggedIn(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); @@ -106,8 +100,6 @@ class LoginControllerTest extends TestCase public function testLoginControllerOpenShaarli(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); @@ -129,8 +121,6 @@ class LoginControllerTest extends TestCase public function testLoginControllerWhileBanned(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); diff --git a/tests/front/controller/visitor/OpenSearchControllerTest.php b/tests/front/controller/visitor/OpenSearchControllerTest.php index 52475318..5f9f5b12 100644 --- a/tests/front/controller/visitor/OpenSearchControllerTest.php +++ b/tests/front/controller/visitor/OpenSearchControllerTest.php @@ -24,8 +24,6 @@ class OpenSearchControllerTest extends TestCase public function testOpenSearchController(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); diff --git a/tests/front/controller/visitor/PictureWallControllerTest.php b/tests/front/controller/visitor/PictureWallControllerTest.php index 7ac842cb..3dc3f292 100644 --- a/tests/front/controller/visitor/PictureWallControllerTest.php +++ b/tests/front/controller/visitor/PictureWallControllerTest.php @@ -28,8 +28,6 @@ class PictureWallControllerTest extends TestCase public function testValidControllerInvokeDefault(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $request->expects(static::once())->method('getQueryParams')->willReturn([]); $response = new Response(); @@ -106,8 +104,6 @@ class PictureWallControllerTest extends TestCase { $this->expectException(ThumbnailsDisabledException::class); - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); diff --git a/tests/front/controller/visitor/ShaarliPublicControllerTest.php b/tests/front/controller/visitor/ShaarliPublicControllerTest.php index e2e88da3..1f7d57ad 100644 --- a/tests/front/controller/visitor/ShaarliPublicControllerTest.php +++ b/tests/front/controller/visitor/ShaarliPublicControllerTest.php @@ -67,8 +67,6 @@ class ShaarliControllerTest extends TestCase public function testAssignView(): void { - $this->createValidContainerMockSet(); - $this->assignTemplateVars($this->assignedValues); $self = $this->controller->assignView('variableName', 'variableValue'); @@ -79,8 +77,6 @@ class ShaarliControllerTest extends TestCase public function testRender(): void { - $this->createValidContainerMockSet(); - $this->assignTemplateVars($this->assignedValues); $this->container->bookmarkService @@ -120,8 +116,6 @@ class ShaarliControllerTest extends TestCase */ public function testRedirectFromRefererDefault(): void { - $this->createValidContainerMockSet(); - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; $response = new Response(); @@ -137,8 +131,6 @@ class ShaarliControllerTest extends TestCase */ public function testRedirectFromRefererWithUnmatchedLoopTerm(): void { - $this->createValidContainerMockSet(); - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; $response = new Response(); @@ -154,8 +146,6 @@ class ShaarliControllerTest extends TestCase */ public function testRedirectFromRefererWithMatchingLoopTermInPath(): void { - $this->createValidContainerMockSet(); - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; $response = new Response(); @@ -171,8 +161,6 @@ class ShaarliControllerTest extends TestCase */ public function testRedirectFromRefererWithMatchingLoopTermInQueryParam(): void { - $this->createValidContainerMockSet(); - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; $response = new Response(); @@ -189,8 +177,6 @@ class ShaarliControllerTest extends TestCase */ public function testRedirectFromRefererWithMatchingLoopTermInQueryValue(): void { - $this->createValidContainerMockSet(); - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; $response = new Response(); @@ -207,8 +193,6 @@ class ShaarliControllerTest extends TestCase */ public function testRedirectFromRefererWithLoopTermInDomain(): void { - $this->createValidContainerMockSet(); - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; $response = new Response(); @@ -225,8 +209,6 @@ class ShaarliControllerTest extends TestCase */ public function testRedirectFromRefererWithMatchingClearedParam(): void { - $this->createValidContainerMockSet(); - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; $response = new Response(); diff --git a/tests/front/controller/visitor/TagCloudControllerTest.php b/tests/front/controller/visitor/TagCloudControllerTest.php index e636d496..9a6a4bc0 100644 --- a/tests/front/controller/visitor/TagCloudControllerTest.php +++ b/tests/front/controller/visitor/TagCloudControllerTest.php @@ -28,8 +28,6 @@ class TagCloudControllerTest extends TestCase */ public function testValidCloudControllerInvokeDefault(): void { - $this->createValidContainerMockSet(); - $allTags = [ 'ghi' => 1, 'abc' => 3, @@ -94,8 +92,6 @@ class TagCloudControllerTest extends TestCase */ public function testValidCloudControllerInvokeWithParameters(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $request ->method('getQueryParam') @@ -161,8 +157,6 @@ class TagCloudControllerTest extends TestCase */ public function testEmptyCloud(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); @@ -209,8 +203,6 @@ class TagCloudControllerTest extends TestCase */ public function testValidListControllerInvokeDefault(): void { - $this->createValidContainerMockSet(); - $allTags = [ 'def' => 12, 'abc' => 3, @@ -271,8 +263,6 @@ class TagCloudControllerTest extends TestCase */ public function testValidListControllerInvokeWithParameters(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $request ->method('getQueryParam') @@ -336,8 +326,6 @@ class TagCloudControllerTest extends TestCase */ public function testEmptyList(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); diff --git a/tests/front/controller/visitor/TagControllerTest.php b/tests/front/controller/visitor/TagControllerTest.php index 9a2b1f71..1242a2e9 100644 --- a/tests/front/controller/visitor/TagControllerTest.php +++ b/tests/front/controller/visitor/TagControllerTest.php @@ -23,8 +23,6 @@ class TagControllerTest extends TestCase public function testAddTagWithReferer(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; $request = $this->createMock(Request::class); @@ -41,8 +39,6 @@ class TagControllerTest extends TestCase public function testAddTagWithRefererAndExistingSearch(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; $request = $this->createMock(Request::class); @@ -59,8 +55,6 @@ class TagControllerTest extends TestCase public function testAddTagWithoutRefererAndExistingSearch(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); @@ -75,8 +69,6 @@ class TagControllerTest extends TestCase public function testAddTagRemoveLegacyQueryParam(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&addtag=abc']; $request = $this->createMock(Request::class); @@ -93,8 +85,6 @@ class TagControllerTest extends TestCase public function testAddTagResetPagination(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&page=12']; $request = $this->createMock(Request::class); @@ -111,8 +101,6 @@ class TagControllerTest extends TestCase public function testAddTagWithRefererAndEmptySearch(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=']; $request = $this->createMock(Request::class); @@ -129,8 +117,6 @@ class TagControllerTest extends TestCase public function testAddTagWithoutNewTagWithReferer(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; $request = $this->createMock(Request::class); @@ -145,8 +131,6 @@ class TagControllerTest extends TestCase public function testAddTagWithoutNewTagWithoutReferer(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); @@ -159,8 +143,6 @@ class TagControllerTest extends TestCase public function testRemoveTagWithoutMatchingTag(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; $request = $this->createMock(Request::class); @@ -177,8 +159,6 @@ class TagControllerTest extends TestCase public function testRemoveTagWithoutTagsearch(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; $request = $this->createMock(Request::class); @@ -195,8 +175,6 @@ class TagControllerTest extends TestCase public function testRemoveTagWithoutReferer(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); @@ -211,8 +189,6 @@ class TagControllerTest extends TestCase public function testRemoveTagWithoutTag(): void { - $this->createValidContainerMockSet(); - $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtag=abc']; $request = $this->createMock(Request::class); @@ -227,8 +203,6 @@ class TagControllerTest extends TestCase public function testRemoveTagWithoutTagWithoutReferer(): void { - $this->createValidContainerMockSet(); - $request = $this->createMock(Request::class); $response = new Response(); -- cgit v1.2.3 From fdedbfd4a7fb547da0e0ce65c6180f74aad90691 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Wed, 27 May 2020 14:13:49 +0200 Subject: Test ShaarliAdminController --- .../admin/ShaarliAdminControllerTest.php | 199 +++++++++++++++++++++ .../visitor/ShaarliPublicControllerTest.php | 2 +- 2 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 tests/front/controller/admin/ShaarliAdminControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/ShaarliAdminControllerTest.php b/tests/front/controller/admin/ShaarliAdminControllerTest.php new file mode 100644 index 00000000..7c5f50a6 --- /dev/null +++ b/tests/front/controller/admin/ShaarliAdminControllerTest.php @@ -0,0 +1,199 @@ +createContainer(); + + $this->controller = new class($this->container) extends ShaarliAdminController + { + public function checkToken(Request $request): bool + { + return parent::checkToken($request); + } + + public function saveSuccessMessage(string $message): void + { + parent::saveSuccessMessage($message); + } + + public function saveWarningMessage(string $message): void + { + parent::saveWarningMessage($message); + } + + public function saveErrorMessage(string $message): void + { + parent::saveErrorMessage($message); + } + }; + } + + /** + * Creating an instance of an admin controller while logged out should raise an exception. + */ + public function testInstantiateWhileLoggedOut(): void + { + $this->expectException(UnauthorizedException::class); + + $this->container->loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager->method('isLoggedIn')->willReturn(false); + + $this->controller = new class($this->container) extends ShaarliAdminController {}; + } + + /** + * Trigger controller's checkToken with a valid token. + */ + public function testCheckTokenWithValidToken(): void + { + $request = $this->createMock(Request::class); + $request->method('getParam')->with('token')->willReturn($token = '12345'); + + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager->method('checkToken')->with($token)->willReturn(true); + + static::assertTrue($this->controller->checkToken($request)); + } + + /** + * Trigger controller's checkToken with na valid token should raise an exception. + */ + public function testCheckTokenWithNotValidToken(): void + { + $request = $this->createMock(Request::class); + $request->method('getParam')->with('token')->willReturn($token = '12345'); + + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager->method('checkToken')->with($token)->willReturn(false); + + $this->expectException(WrongTokenException::class); + + $this->controller->checkToken($request); + } + + /** + * Test saveSuccessMessage() with a first message. + */ + public function testSaveSuccessMessage(): void + { + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_SUCCESS_MESSAGES, [$message = 'bravo!']) + ; + + $this->controller->saveSuccessMessage($message); + } + + /** + * Test saveSuccessMessage() with existing messages. + */ + public function testSaveSuccessMessageWithExistingMessages(): void + { + $this->container->sessionManager + ->expects(static::once()) + ->method('getSessionParameter') + ->with(SessionManager::KEY_SUCCESS_MESSAGES) + ->willReturn(['success1', 'success2']) + ; + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_SUCCESS_MESSAGES, ['success1', 'success2', $message = 'bravo!']) + ; + + $this->controller->saveSuccessMessage($message); + } + + /** + * Test saveWarningMessage() with a first message. + */ + public function testSaveWarningMessage(): void + { + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_WARNING_MESSAGES, [$message = 'warning!']) + ; + + $this->controller->saveWarningMessage($message); + } + + /** + * Test saveWarningMessage() with existing messages. + */ + public function testSaveWarningMessageWithExistingMessages(): void + { + $this->container->sessionManager + ->expects(static::once()) + ->method('getSessionParameter') + ->with(SessionManager::KEY_WARNING_MESSAGES) + ->willReturn(['warning1', 'warning2']) + ; + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_WARNING_MESSAGES, ['warning1', 'warning2', $message = 'warning!']) + ; + + $this->controller->saveWarningMessage($message); + } + + /** + * Test saveErrorMessage() with a first message. + */ + public function testSaveErrorMessage(): void + { + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, [$message = 'error!']) + ; + + $this->controller->saveErrorMessage($message); + } + + /** + * Test saveErrorMessage() with existing messages. + */ + public function testSaveErrorMessageWithExistingMessages(): void + { + $this->container->sessionManager + ->expects(static::once()) + ->method('getSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES) + ->willReturn(['error1', 'error2']) + ; + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['error1', 'error2', $message = 'error!']) + ; + + $this->controller->saveErrorMessage($message); + } +} diff --git a/tests/front/controller/visitor/ShaarliPublicControllerTest.php b/tests/front/controller/visitor/ShaarliPublicControllerTest.php index 1f7d57ad..899b280b 100644 --- a/tests/front/controller/visitor/ShaarliPublicControllerTest.php +++ b/tests/front/controller/visitor/ShaarliPublicControllerTest.php @@ -16,7 +16,7 @@ use Slim\Http\Uri; * This class is used to test default behavior of ShaarliController abstract class. * It uses a dummy non abstract controller. */ -class ShaarliControllerTest extends TestCase +class ShaarliPublicControllerTest extends TestCase { use FrontControllerMockHelper; -- cgit v1.2.3 From 465033230da0398426010aa7bd3694735b71c899 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Wed, 27 May 2020 14:18:07 +0200 Subject: Password change: UT use case with open shaarli --- tests/front/controller/admin/PasswordControllerTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'tests') diff --git a/tests/front/controller/admin/PasswordControllerTest.php b/tests/front/controller/admin/PasswordControllerTest.php index 7262243e..9a01089e 100644 --- a/tests/front/controller/admin/PasswordControllerTest.php +++ b/tests/front/controller/admin/PasswordControllerTest.php @@ -6,6 +6,7 @@ namespace Shaarli\Front\Controller\Admin; use PHPUnit\Framework\TestCase; use Shaarli\Config\ConfigManager; +use Shaarli\Front\Exception\OpenShaarliPasswordException; use Shaarli\Front\Exception\WrongTokenException; use Shaarli\Security\SessionManager; use Slim\Http\Request; @@ -183,4 +184,20 @@ class PasswordControllerTest extends TestCase static::assertSame('changepassword', (string) $result->getBody()); static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']); } + + /** + * Change the password on an open shaarli + */ + public function testPostNewPasswordOnOpenShaarli(): void + { + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->with('security.open_shaarli')->willReturn(true); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->expectException(OpenShaarliPasswordException::class); + + $this->controller->change($request, $response); + } } -- cgit v1.2.3 From 66063ed1a18d739b1a60bfb163d8656417a4c529 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 30 May 2020 14:00:06 +0200 Subject: Process configure page through Slim controller --- .../controller/admin/ConfigureControllerTest.php | 252 +++++++++++++++++++++ .../admin/FrontAdminControllerMockHelper.php | 23 ++ .../controller/visitor/DailyControllerTest.php | 27 +-- .../visitor/FrontControllerMockHelper.php | 10 +- 4 files changed, 294 insertions(+), 18 deletions(-) create mode 100644 tests/front/controller/admin/ConfigureControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/ConfigureControllerTest.php b/tests/front/controller/admin/ConfigureControllerTest.php new file mode 100644 index 00000000..40304a18 --- /dev/null +++ b/tests/front/controller/admin/ConfigureControllerTest.php @@ -0,0 +1,252 @@ +createContainer(); + + $this->controller = new ConfigureController($this->container); + } + + /** + * Test displaying configure page - it should display all config variables + */ + public function testIndex(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->willReturnCallback(function (string $key) { + return $key; + }); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('configure', (string) $result->getBody()); + + static::assertSame('Configure - general.title', $assignedVariables['pagetitle']); + static::assertSame('general.title', $assignedVariables['title']); + static::assertSame('resource.theme', $assignedVariables['theme']); + static::assertEmpty($assignedVariables['theme_available']); + static::assertSame(['default', 'markdown'], $assignedVariables['formatter_available']); + static::assertNotEmpty($assignedVariables['continents']); + static::assertNotEmpty($assignedVariables['cities']); + static::assertSame('general.retrieve_description', $assignedVariables['retrieve_description']); + static::assertSame('privacy.default_private_links', $assignedVariables['private_links_default']); + static::assertSame('security.session_protection_disabled', $assignedVariables['session_protection_disabled']); + static::assertSame('feed.rss_permalinks', $assignedVariables['enable_rss_permalinks']); + static::assertSame('updates.check_updates', $assignedVariables['enable_update_check']); + static::assertSame('privacy.hide_public_links', $assignedVariables['hide_public_links']); + static::assertSame('api.enabled', $assignedVariables['api_enabled']); + static::assertSame('api.secret', $assignedVariables['api_secret']); + static::assertCount(4, $assignedVariables['languages']); + static::assertArrayHasKey('gd_enabled', $assignedVariables); + static::assertSame('thumbnails.mode', $assignedVariables['thumbnails_mode']); + } + + /** + * Test posting a new config - make sure that everything is saved properly, without errors. + */ + public function testSaveNewConfig(): void + { + $session = []; + $this->assignSessionVars($session); + + $parameters = [ + 'token' => 'token', + 'continent' => 'Europe', + 'city' => 'Moscow', + 'title' => 'Shaarli', + 'titleLink' => './', + 'retrieveDescription' => 'on', + 'theme' => 'vintage', + 'disablesessionprotection' => null, + 'privateLinkByDefault' => true, + 'enableRssPermalinks' => true, + 'updateCheck' => false, + 'hidePublicLinks' => 'on', + 'enableApi' => 'on', + 'apiSecret' => 'abcdef', + 'formatter' => 'markdown', + 'language' => 'fr', + 'enableThumbnails' => Thumbnailer::MODE_NONE, + ]; + + $parametersConfigMapping = [ + 'general.timezone' => $parameters['continent'] . '/' . $parameters['city'], + 'general.title' => $parameters['title'], + 'general.header_link' => $parameters['titleLink'], + 'general.retrieve_description' => !!$parameters['retrieveDescription'], + 'resource.theme' => $parameters['theme'], + 'security.session_protection_disabled' => !!$parameters['disablesessionprotection'], + 'privacy.default_private_links' => !!$parameters['privateLinkByDefault'], + 'feed.rss_permalinks' => !!$parameters['enableRssPermalinks'], + 'updates.check_updates' => !!$parameters['updateCheck'], + 'privacy.hide_public_links' => !!$parameters['hidePublicLinks'], + 'api.enabled' => !!$parameters['enableApi'], + 'api.secret' => $parameters['apiSecret'], + 'formatter' => $parameters['formatter'], + 'translation.language' => $parameters['language'], + 'thumbnails.mode' => $parameters['enableThumbnails'], + ]; + + $request = $this->createMock(Request::class); + $request + ->expects(static::atLeastOnce()) + ->method('getParam')->willReturnCallback(function (string $key) use ($parameters) { + if (false === array_key_exists($key, $parameters)) { + static::fail('unknown key: ' . $key); + } + + return $parameters[$key]; + } + ); + + $response = new Response(); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf + ->expects(static::atLeastOnce()) + ->method('set') + ->willReturnCallback(function (string $key, $value) use ($parametersConfigMapping): void { + if (false === array_key_exists($key, $parametersConfigMapping)) { + static::fail('unknown key: ' . $key); + } + + static::assertSame($parametersConfigMapping[$key], $value); + } + ); + + $result = $this->controller->save($request, $response); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./configure'], $result->getHeader('Location')); + + static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); + static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); + static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); + static::assertSame(['Configuration was saved.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]); + } + + /** + * Test posting a new config - wrong token. + */ + public function testSaveNewConfigWrongToken(): void + { + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager->method('checkToken')->willReturn(false); + + $this->container->conf->expects(static::never())->method('set'); + $this->container->conf->expects(static::never())->method('write'); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->expectException(WrongTokenException::class); + + $this->controller->save($request, $response); + } + + /** + * Test posting a new config - thumbnail activation. + */ + public function testSaveNewConfigThumbnailsActivation(): void + { + $session = []; + $this->assignSessionVars($session); + + $request = $this->createMock(Request::class); + $request + ->expects(static::atLeastOnce()) + ->method('getParam')->willReturnCallback(function (string $key) { + if ('enableThumbnails' === $key) { + return Thumbnailer::MODE_ALL; + } + + return $key; + }) + ; + $response = new Response(); + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./configure'], $result->getHeader('Location')); + + static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); + static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); + static::assertStringContainsString( + 'You have enabled or changed thumbnails mode', + $session[SessionManager::KEY_WARNING_MESSAGES][0] + ); + static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); + static::assertSame(['Configuration was saved.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]); + } + + /** + * Test posting a new config - thumbnail activation. + */ + public function testSaveNewConfigThumbnailsAlreadyActive(): void + { + $session = []; + $this->assignSessionVars($session); + + $request = $this->createMock(Request::class); + $request + ->expects(static::atLeastOnce()) + ->method('getParam')->willReturnCallback(function (string $key) { + if ('enableThumbnails' === $key) { + return Thumbnailer::MODE_ALL; + } + + return $key; + }) + ; + $response = new Response(); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf + ->expects(static::atLeastOnce()) + ->method('get') + ->willReturnCallback(function (string $key): string { + if ('thumbnails.mode' === $key) { + return Thumbnailer::MODE_ALL; + } + + return $key; + }) + ; + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./configure'], $result->getHeader('Location')); + + static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); + static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); + static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); + static::assertSame(['Configuration was saved.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]); + } +} diff --git a/tests/front/controller/admin/FrontAdminControllerMockHelper.php b/tests/front/controller/admin/FrontAdminControllerMockHelper.php index bd40c0c7..2b9f2ef1 100644 --- a/tests/front/controller/admin/FrontAdminControllerMockHelper.php +++ b/tests/front/controller/admin/FrontAdminControllerMockHelper.php @@ -6,6 +6,7 @@ namespace Shaarli\Front\Controller\Admin; use Shaarli\Container\ShaarliTestContainer; use Shaarli\Front\Controller\Visitor\FrontControllerMockHelper; +use Shaarli\History; /** * Trait FrontControllerMockHelper @@ -27,7 +28,29 @@ trait FrontAdminControllerMockHelper { $this->parentCreateContainer(); + $this->container->history = $this->createMock(History::class); + $this->container->loginManager->method('isLoggedIn')->willReturn(true); $this->container->sessionManager->method('checkToken')->willReturn(true); } + + + /** + * Pass a reference of an array which will be populated by `sessionManager->setSessionParameter` + * calls during execution. + * + * @param mixed $variables Array reference to populate. + */ + protected function assignSessionVars(array &$variables): void + { + $this->container->sessionManager + ->expects(static::atLeastOnce()) + ->method('setSessionParameter') + ->willReturnCallback(function ($key, $value) use (&$variables) { + $variables[$key] = $value; + + return $this->container->sessionManager; + }) + ; + } } diff --git a/tests/front/controller/visitor/DailyControllerTest.php b/tests/front/controller/visitor/DailyControllerTest.php index 872420fd..b802c62c 100644 --- a/tests/front/controller/visitor/DailyControllerTest.php +++ b/tests/front/controller/visitor/DailyControllerTest.php @@ -57,20 +57,20 @@ class DailyControllerTest extends TestCase (new Bookmark()) ->setId(1) ->setUrl('http://url.tld') - ->setTitle(static::generateContent(50)) - ->setDescription(static::generateContent(500)) + ->setTitle(static::generateString(50)) + ->setDescription(static::generateString(500)) , (new Bookmark()) ->setId(2) ->setUrl('http://url2.tld') - ->setTitle(static::generateContent(50)) - ->setDescription(static::generateContent(500)) + ->setTitle(static::generateString(50)) + ->setDescription(static::generateString(500)) , (new Bookmark()) ->setId(3) ->setUrl('http://url3.tld') - ->setTitle(static::generateContent(50)) - ->setDescription(static::generateContent(500)) + ->setTitle(static::generateString(50)) + ->setDescription(static::generateString(500)) , ]; }) @@ -194,8 +194,8 @@ class DailyControllerTest extends TestCase (new Bookmark()) ->setId(1) ->setUrl('http://url.tld') - ->setTitle(static::generateContent(50)) - ->setDescription(static::generateContent(500)) + ->setTitle(static::generateString(50)) + ->setDescription(static::generateString(500)) , ]; }) @@ -267,8 +267,8 @@ class DailyControllerTest extends TestCase (new Bookmark()) ->setId(2) ->setUrl('http://url.tld') - ->setTitle(static::generateContent(50)) - ->setDescription(static::generateContent(5000)) + ->setTitle(static::generateString(50)) + ->setDescription(static::generateString(5000)) , (new Bookmark())->setId(3)->setUrl('http://url.tld')->setTitle('title'), (new Bookmark())->setId(4)->setUrl('http://url.tld')->setTitle('title'), @@ -473,11 +473,4 @@ class DailyControllerTest extends TestCase static::assertFalse($assignedVariables['hide_timestamps']); static::assertCount(0, $assignedVariables['days']); } - - protected static function generateContent(int $length): string - { - // bin2hex(random_bytes) generates string twice as long as given parameter - $length = (int) ceil($length / 2); - return bin2hex(random_bytes($length)); - } } diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php index d16b6949..fecd0c82 100644 --- a/tests/front/controller/visitor/FrontControllerMockHelper.php +++ b/tests/front/controller/visitor/FrontControllerMockHelper.php @@ -42,7 +42,7 @@ trait FrontControllerMockHelper // Config $this->container->conf = $this->createMock(ConfigManager::class); $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { - return $default; + return $default === null ? $parameter : $default; }); // PageBuilder @@ -101,6 +101,14 @@ trait FrontControllerMockHelper ; } + protected static function generateString(int $length): string + { + // bin2hex(random_bytes) generates string twice as long as given parameter + $length = (int) ceil($length / 2); + + return bin2hex(random_bytes($length)); + } + /** * Force to be used in PHPUnit context. */ -- cgit v1.2.3 From 8eac2e54882d8adae8cbb45386dca1b465242632 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 30 May 2020 15:51:14 +0200 Subject: Process manage tags page through Slim controller --- .../controller/admin/ManageTagControllerTest.php | 272 +++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 tests/front/controller/admin/ManageTagControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/ManageTagControllerTest.php b/tests/front/controller/admin/ManageTagControllerTest.php new file mode 100644 index 00000000..eed99231 --- /dev/null +++ b/tests/front/controller/admin/ManageTagControllerTest.php @@ -0,0 +1,272 @@ +createContainer(); + + $this->controller = new ManageTagController($this->container); + } + + /** + * Test displaying manage tag page + */ + public function testIndex(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $request->method('getParam')->with('fromtag')->willReturn('fromtag'); + $response = new Response(); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('changetag', (string) $result->getBody()); + + static::assertSame('fromtag', $assignedVariables['fromtag']); + static::assertSame('Manage tags - Shaarli', $assignedVariables['pagetitle']); + } + + /** + * Test posting a tag update - rename tag - valid info provided. + */ + public function testSaveRenameTagValid(): void + { + $session = []; + $this->assignSessionVars($session); + + $requestParameters = [ + 'renametag' => 'rename', + 'fromtag' => 'old-tag', + 'totag' => 'new-tag', + ]; + $request = $this->createMock(Request::class); + $request + ->expects(static::atLeastOnce()) + ->method('getParam') + ->willReturnCallback(function (string $key) use ($requestParameters): ?string { + return $requestParameters[$key] ?? null; + }) + ; + $response = new Response(); + + $bookmark1 = $this->createMock(Bookmark::class); + $bookmark2 = $this->createMock(Bookmark::class); + $this->container->bookmarkService + ->expects(static::once()) + ->method('search') + ->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true) + ->willReturnCallback(function () use ($bookmark1, $bookmark2): array { + $bookmark1->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag'); + $bookmark2->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag'); + + return [$bookmark1, $bookmark2]; + }) + ; + $this->container->bookmarkService + ->expects(static::exactly(2)) + ->method('set') + ->withConsecutive([$bookmark1, false], [$bookmark2, false]) + ; + $this->container->bookmarkService->expects(static::once())->method('save'); + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./?searchtags=new-tag'], $result->getHeader('location')); + + static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); + static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); + static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); + static::assertSame(['The tag was renamed in 2 bookmarks.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]); + } + + /** + * Test posting a tag update - delete tag - valid info provided. + */ + public function testSaveDeleteTagValid(): void + { + $session = []; + $this->assignSessionVars($session); + + $requestParameters = [ + 'deletetag' => 'delete', + 'fromtag' => 'old-tag', + ]; + $request = $this->createMock(Request::class); + $request + ->expects(static::atLeastOnce()) + ->method('getParam') + ->willReturnCallback(function (string $key) use ($requestParameters): ?string { + return $requestParameters[$key] ?? null; + }) + ; + $response = new Response(); + + $bookmark1 = $this->createMock(Bookmark::class); + $bookmark2 = $this->createMock(Bookmark::class); + $this->container->bookmarkService + ->expects(static::once()) + ->method('search') + ->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true) + ->willReturnCallback(function () use ($bookmark1, $bookmark2): array { + $bookmark1->expects(static::once())->method('deleteTag')->with('old-tag'); + $bookmark2->expects(static::once())->method('deleteTag')->with('old-tag'); + + return [$bookmark1, $bookmark2]; + }) + ; + $this->container->bookmarkService + ->expects(static::exactly(2)) + ->method('set') + ->withConsecutive([$bookmark1, false], [$bookmark2, false]) + ; + $this->container->bookmarkService->expects(static::once())->method('save'); + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./manage-tags'], $result->getHeader('location')); + + static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); + static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); + static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); + static::assertSame(['The tag was removed from 2 bookmarks.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]); + } + + /** + * Test posting a tag update - wrong token. + */ + public function testSaveWrongToken(): void + { + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager->method('checkToken')->willReturn(false); + + $this->container->conf->expects(static::never())->method('set'); + $this->container->conf->expects(static::never())->method('write'); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->expectException(WrongTokenException::class); + + $this->controller->save($request, $response); + } + + /** + * Test posting a tag update - rename tag - missing "FROM" tag. + */ + public function testSaveRenameTagMissingFrom(): void + { + $session = []; + $this->assignSessionVars($session); + + $requestParameters = [ + 'renametag' => 'rename', + ]; + $request = $this->createMock(Request::class); + $request + ->expects(static::atLeastOnce()) + ->method('getParam') + ->willReturnCallback(function (string $key) use ($requestParameters): ?string { + return $requestParameters[$key] ?? null; + }) + ; + $response = new Response(); + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./manage-tags'], $result->getHeader('location')); + + static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); + static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); + static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); + static::assertSame(['Invalid tags provided.'], $session[SessionManager::KEY_WARNING_MESSAGES]); + } + + /** + * Test posting a tag update - delete tag - missing "FROM" tag. + */ + public function testSaveDeleteTagMissingFrom(): void + { + $session = []; + $this->assignSessionVars($session); + + $requestParameters = [ + 'deletetag' => 'delete', + ]; + $request = $this->createMock(Request::class); + $request + ->expects(static::atLeastOnce()) + ->method('getParam') + ->willReturnCallback(function (string $key) use ($requestParameters): ?string { + return $requestParameters[$key] ?? null; + }) + ; + $response = new Response(); + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./manage-tags'], $result->getHeader('location')); + + static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); + static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); + static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); + static::assertSame(['Invalid tags provided.'], $session[SessionManager::KEY_WARNING_MESSAGES]); + } + + /** + * Test posting a tag update - rename tag - missing "TO" tag. + */ + public function testSaveRenameTagMissingTo(): void + { + $session = []; + $this->assignSessionVars($session); + + $requestParameters = [ + 'renametag' => 'rename', + 'fromtag' => 'old-tag' + ]; + $request = $this->createMock(Request::class); + $request + ->expects(static::atLeastOnce()) + ->method('getParam') + ->willReturnCallback(function (string $key) use ($requestParameters): ?string { + return $requestParameters[$key] ?? null; + }) + ; + $response = new Response(); + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./manage-tags'], $result->getHeader('location')); + + static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); + static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); + static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); + static::assertSame(['Invalid tags provided.'], $session[SessionManager::KEY_WARNING_MESSAGES]); + } +} -- cgit v1.2.3 From c22fa57a5505fe95fd01860e3d3dfbb089f869cd Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 6 Jun 2020 14:01:03 +0200 Subject: Handle shaare creation/edition/deletion through Slim controllers --- tests/container/ShaarliTestContainer.php | 4 + .../admin/PostBookmarkControllerTest.php | 652 +++++++++++++++++++++ 2 files changed, 656 insertions(+) create mode 100644 tests/front/controller/admin/PostBookmarkControllerTest.php (limited to 'tests') diff --git a/tests/container/ShaarliTestContainer.php b/tests/container/ShaarliTestContainer.php index 53197ae6..7dbe914c 100644 --- a/tests/container/ShaarliTestContainer.php +++ b/tests/container/ShaarliTestContainer.php @@ -10,11 +10,13 @@ use Shaarli\Config\ConfigManager; use Shaarli\Feed\FeedBuilder; use Shaarli\Formatter\FormatterFactory; use Shaarli\History; +use Shaarli\Http\HttpAccess; use Shaarli\Plugin\PluginManager; use Shaarli\Render\PageBuilder; use Shaarli\Render\PageCacheManager; use Shaarli\Security\LoginManager; use Shaarli\Security\SessionManager; +use Shaarli\Thumbnailer; /** * Test helper allowing auto-completion for MockObjects. @@ -31,6 +33,8 @@ use Shaarli\Security\SessionManager; * @property MockObject|FormatterFactory $formatterFactory * @property MockObject|PageCacheManager $pageCacheManager * @property MockObject|FeedBuilder $feedBuilder + * @property MockObject|Thumbnailer $thumbnailer + * @property MockObject|HttpAccess $httpAccess */ class ShaarliTestContainer extends ShaarliContainer { diff --git a/tests/front/controller/admin/PostBookmarkControllerTest.php b/tests/front/controller/admin/PostBookmarkControllerTest.php new file mode 100644 index 00000000..f00a15c9 --- /dev/null +++ b/tests/front/controller/admin/PostBookmarkControllerTest.php @@ -0,0 +1,652 @@ +createContainer(); + + $this->container->httpAccess = $this->createMock(HttpAccess::class); + $this->controller = new PostBookmarkController($this->container); + } + + /** + * Test displaying add link page + */ + public function testAddShaare(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->addShaare($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('addlink', (string) $result->getBody()); + + static::assertSame('Shaare a new link - Shaarli', $assignedVariables['pagetitle']); + } + + /** + * Test displaying bookmark create form + * Ensure that every step of the standard workflow works properly. + */ + public function testDisplayCreateFormWithUrl(): void + { + $this->container->environment = [ + 'HTTP_REFERER' => $referer = 'http://shaarli/subfolder/controller/?searchtag=abc' + ]; + + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $url = 'http://url.tld/other?part=3&utm_ad=pay#hash'; + $expectedUrl = str_replace('&utm_ad=pay', '', $url); + $remoteTitle = 'Remote Title'; + $remoteDesc = 'Sometimes the meta description is relevant.'; + $remoteTags = 'abc def'; + + $request = $this->createMock(Request::class); + $request->method('getParam')->willReturnCallback(function (string $key) use ($url): ?string { + return $key === 'post' ? $url : null; + }); + $response = new Response(); + + $this->container->httpAccess + ->expects(static::once()) + ->method('getCurlDownloadCallback') + ->willReturnCallback( + function (&$charset, &$title, &$description, &$tags) use ( + $remoteTitle, + $remoteDesc, + $remoteTags + ): callable { + return function () use ( + &$charset, + &$title, + &$description, + &$tags, + $remoteTitle, + $remoteDesc, + $remoteTags + ): void { + $charset = 'ISO-8859-1'; + $title = $remoteTitle; + $description = $remoteDesc; + $tags = $remoteTags; + }; + } + ) + ; + $this->container->httpAccess + ->expects(static::once()) + ->method('getHttpResponse') + ->with($expectedUrl, 30, 4194304) + ->willReturnCallback(function($url, $timeout, $maxBytes, $callback): void { + $callback(); + }) + ; + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->willReturn($tags = ['tag1' => 2, 'tag2' => 1]) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data) use ($remoteTitle, $remoteDesc): array { + static::assertSame('render_editlink', $hook); + static::assertSame($remoteTitle, $data['link']['title']); + static::assertSame($remoteDesc, $data['link']['description']); + + return $data; + }) + ; + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + + static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame($expectedUrl, $assignedVariables['link']['url']); + static::assertSame($remoteTitle, $assignedVariables['link']['title']); + static::assertSame($remoteDesc, $assignedVariables['link']['description']); + static::assertSame($remoteTags, $assignedVariables['link']['tags']); + static::assertFalse($assignedVariables['link']['private']); + + static::assertTrue($assignedVariables['link_is_new']); + static::assertSame($referer, $assignedVariables['http_referer']); + static::assertSame($tags, $assignedVariables['tags']); + static::assertArrayHasKey('source', $assignedVariables); + static::assertArrayHasKey('default_private_links', $assignedVariables); + } + + /** + * Test displaying bookmark create form + * Ensure all available query parameters are handled properly. + */ + public function testDisplayCreateFormWithFullParameters(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $parameters = [ + 'post' => 'http://url.tld/other?part=3&utm_ad=pay#hash', + 'title' => 'Provided Title', + 'description' => 'Provided description.', + 'tags' => 'abc def', + 'private' => '1', + 'source' => 'apps', + ]; + $expectedUrl = str_replace('&utm_ad=pay', '', $parameters['post']); + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }); + $response = new Response(); + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + + static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame($expectedUrl, $assignedVariables['link']['url']); + static::assertSame($parameters['title'], $assignedVariables['link']['title']); + static::assertSame($parameters['description'], $assignedVariables['link']['description']); + static::assertSame($parameters['tags'], $assignedVariables['link']['tags']); + static::assertTrue($assignedVariables['link']['private']); + static::assertTrue($assignedVariables['link_is_new']); + static::assertSame($parameters['source'], $assignedVariables['source']); + } + + /** + * Test displaying bookmark create form + * Without any parameter. + */ + public function testDisplayCreateFormEmpty(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); + $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + static::assertSame('', $assignedVariables['link']['url']); + static::assertSame('Note: ', $assignedVariables['link']['title']); + static::assertSame('', $assignedVariables['link']['description']); + static::assertSame('', $assignedVariables['link']['tags']); + static::assertFalse($assignedVariables['link']['private']); + static::assertTrue($assignedVariables['link_is_new']); + } + + /** + * Test displaying bookmark create form + * URL not using HTTP protocol: do not try to retrieve the title + */ + public function testDisplayCreateFormNotHttp(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $url = 'magnet://kubuntu.torrent'; + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($url): ?string { + return $key === 'post' ? $url : null; + }); + $response = new Response(); + + $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); + $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + static::assertSame($url, $assignedVariables['link']['url']); + static::assertTrue($assignedVariables['link_is_new']); + } + + /** + * Test displaying bookmark create form + * When markdown formatter is enabled, the no markdown tag should be added to existing tags. + */ + public function testDisplayCreateFormWithMarkdownEnabled(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf + ->expects(static::atLeastOnce()) + ->method('get')->willReturnCallback(function (string $key): ?string { + if ($key === 'formatter') { + return 'markdown'; + } + + return $key; + }) + ; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + static::assertSame(['nomarkdown' => 1], $assignedVariables['tags']); + } + + /** + * Test displaying bookmark create form + * When an existing URL is submitted, we want to edit the existing link. + */ + public function testDisplayCreateFormWithExistingUrl(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $url = 'http://url.tld/other?part=3&utm_ad=pay#hash'; + $expectedUrl = str_replace('&utm_ad=pay', '', $url); + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($url): ?string { + return $key === 'post' ? $url : null; + }); + $response = new Response(); + + $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); + $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('findByUrl') + ->with($expectedUrl) + ->willReturn( + (new Bookmark()) + ->setId($id = 23) + ->setUrl($expectedUrl) + ->setTitle($title = 'Bookmark Title') + ->setDescription($description = 'Bookmark description.') + ->setTags($tags = ['abc', 'def']) + ->setPrivate(true) + ->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44')) + ) + ; + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + + static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']); + static::assertFalse($assignedVariables['link_is_new']); + + static::assertSame($id, $assignedVariables['link']['id']); + static::assertSame($expectedUrl, $assignedVariables['link']['url']); + static::assertSame($title, $assignedVariables['link']['title']); + static::assertSame($description, $assignedVariables['link']['description']); + static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']); + static::assertTrue($assignedVariables['link']['private']); + static::assertSame($createdAt, $assignedVariables['link']['created']); + } + + /** + * Test displaying bookmark edit form + * When an existing ID is provided, ensure that default workflow works properly. + */ + public function testDisplayEditFormDefault(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $id = 11; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); + $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->with($id) + ->willReturn( + (new Bookmark()) + ->setId($id) + ->setUrl($url = 'http://domain.tld') + ->setTitle($title = 'Bookmark Title') + ->setDescription($description = 'Bookmark description.') + ->setTags($tags = ['abc', 'def']) + ->setPrivate(true) + ->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44')) + ) + ; + + $result = $this->controller->displayEditForm($request, $response, ['id' => (string) $id]); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + + static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']); + static::assertFalse($assignedVariables['link_is_new']); + + static::assertSame($id, $assignedVariables['link']['id']); + static::assertSame($url, $assignedVariables['link']['url']); + static::assertSame($title, $assignedVariables['link']['title']); + static::assertSame($description, $assignedVariables['link']['description']); + static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']); + static::assertTrue($assignedVariables['link']['private']); + static::assertSame($createdAt, $assignedVariables['link']['created']); + } + + /** + * Test save a new bookmark + */ + public function testSaveBookmark(): void + { + $id = 21; + $parameters = [ + 'lf_url' => 'http://url.tld/other?part=3#hash', + 'lf_title' => 'Provided Title', + 'lf_description' => 'Provided description.', + 'lf_tags' => 'abc def', + 'lf_private' => '1', + 'returnurl' => 'http://shaarli.tld/subfolder/add-shaare' + ]; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $response = new Response(); + + $checkBookmark = function (Bookmark $bookmark) use ($parameters) { + static::assertSame($parameters['lf_url'], $bookmark->getUrl()); + static::assertSame($parameters['lf_title'], $bookmark->getTitle()); + static::assertSame($parameters['lf_description'], $bookmark->getDescription()); + static::assertSame($parameters['lf_tags'], $bookmark->getTagsString()); + static::assertTrue($bookmark->isPrivate()); + }; + + $this->container->bookmarkService + ->expects(static::once()) + ->method('addOrSet') + ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { + static::assertFalse($save); + + $checkBookmark($bookmark); + + $bookmark->setId($id); + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('set') + ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { + static::assertTrue($save); + + $checkBookmark($bookmark); + + static::assertSame($id, $bookmark->getId()); + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array { + static::assertSame('save_link', $hook); + + static::assertSame($id, $data['id']); + static::assertSame($parameters['lf_url'], $data['url']); + static::assertSame($parameters['lf_title'], $data['title']); + static::assertSame($parameters['lf_description'], $data['description']); + static::assertSame($parameters['lf_tags'], $data['tags']); + static::assertTrue($data['private']); + + return $data; + }) + ; + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertRegExp('@/subfolder/#\w{6}@', $result->getHeader('location')[0]); + } + + + /** + * Test save an existing bookmark + */ + public function testSaveExistingBookmark(): void + { + $id = 21; + $parameters = [ + 'lf_id' => (string) $id, + 'lf_url' => 'http://url.tld/other?part=3#hash', + 'lf_title' => 'Provided Title', + 'lf_description' => 'Provided description.', + 'lf_tags' => 'abc def', + 'lf_private' => '1', + 'returnurl' => 'http://shaarli.tld/subfolder/?page=2' + ]; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $response = new Response(); + + $checkBookmark = function (Bookmark $bookmark) use ($parameters, $id) { + static::assertSame($id, $bookmark->getId()); + static::assertSame($parameters['lf_url'], $bookmark->getUrl()); + static::assertSame($parameters['lf_title'], $bookmark->getTitle()); + static::assertSame($parameters['lf_description'], $bookmark->getDescription()); + static::assertSame($parameters['lf_tags'], $bookmark->getTagsString()); + static::assertTrue($bookmark->isPrivate()); + }; + + $this->container->bookmarkService->expects(static::atLeastOnce())->method('exists')->willReturn(true); + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->willReturn((new Bookmark())->setId($id)->setUrl('http://other.url')) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('addOrSet') + ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { + static::assertFalse($save); + + $checkBookmark($bookmark); + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('set') + ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { + static::assertTrue($save); + + $checkBookmark($bookmark); + + static::assertSame($id, $bookmark->getId()); + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array { + static::assertSame('save_link', $hook); + + static::assertSame($id, $data['id']); + static::assertSame($parameters['lf_url'], $data['url']); + static::assertSame($parameters['lf_title'], $data['title']); + static::assertSame($parameters['lf_description'], $data['description']); + static::assertSame($parameters['lf_tags'], $data['tags']); + static::assertTrue($data['private']); + + return $data; + }) + ; + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertRegExp('@/subfolder/\?page=2#\w{6}@', $result->getHeader('location')[0]); + } + + /** + * Test save a bookmark - try to retrieve the thumbnail + */ + public function testSaveBookmarkWithThumbnail(): void + { + $parameters = ['lf_url' => 'http://url.tld/other?part=3#hash']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $response = new Response(); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) { + return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default; + }); + + $this->container->thumbnailer = $this->createMock(Thumbnailer::class); + $this->container->thumbnailer + ->expects(static::once()) + ->method('get') + ->with($parameters['lf_url']) + ->willReturn($thumb = 'http://thumb.url') + ; + + $this->container->bookmarkService + ->expects(static::once()) + ->method('addOrSet') + ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($thumb): void { + static::assertSame($thumb, $bookmark->getThumbnail()); + }) + ; + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + } + + /** + * Change the password with a wrong existing password + */ + public function testSaveBookmarkFromBookmarklet(): void + { + $parameters = ['source' => 'bookmarklet']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $result = $this->controller->save($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('', (string) $result->getBody()); + } + + /** + * Change the password with a wrong existing password + */ + public function testSaveBookmarkWrongToken(): void + { + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager->method('checkToken')->willReturn(false); + + $this->container->bookmarkService->expects(static::never())->method('addOrSet'); + $this->container->bookmarkService->expects(static::never())->method('set'); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->expectException(WrongTokenException::class); + + $this->controller->save($request, $response); + } +} -- cgit v1.2.3 From 818b3193ffabec57501e3bdfa997206e3c0671ef Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 13 Jun 2020 11:22:14 +0200 Subject: Explicitly define base and asset path in templates With the new routes, all pages are not all at the same folder level anymore (e.g. /shaare and /shaare/123), so we can't just use './' everywhere. The most consistent way to handle this is to prefix all path with the proper variable, and handle the actual path in controllers. --- tests/front/ShaarliMiddlewareTest.php | 15 ++ .../admin/PostBookmarkControllerTest.php | 19 -- .../admin/SessionFilterControllerTest.php | 60 +----- .../visitor/FrontControllerMockHelper.php | 2 + .../visitor/ShaarliPublicControllerTest.php | 221 --------------------- .../visitor/ShaarliVisitorControllerTest.php | 217 ++++++++++++++++++++ 6 files changed, 236 insertions(+), 298 deletions(-) delete mode 100644 tests/front/controller/visitor/ShaarliPublicControllerTest.php create mode 100644 tests/front/controller/visitor/ShaarliVisitorControllerTest.php (limited to 'tests') diff --git a/tests/front/ShaarliMiddlewareTest.php b/tests/front/ShaarliMiddlewareTest.php index 80974f37..57be1002 100644 --- a/tests/front/ShaarliMiddlewareTest.php +++ b/tests/front/ShaarliMiddlewareTest.php @@ -11,6 +11,7 @@ use Shaarli\Front\Exception\LoginBannedException; use Shaarli\Render\PageBuilder; use Slim\Http\Request; use Slim\Http\Response; +use Slim\Http\Uri; class ShaarliMiddlewareTest extends TestCase { @@ -29,6 +30,13 @@ class ShaarliMiddlewareTest extends TestCase public function testMiddlewareExecution(): void { $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $response = new Response(); $controller = function (Request $request, Response $response): Response { return $response->withStatus(418); // I'm a tea pot @@ -44,6 +52,13 @@ class ShaarliMiddlewareTest extends TestCase public function testMiddlewareExecutionWithException(): void { $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + $response = new Response(); $controller = function (): void { $exception = new LoginBannedException(); diff --git a/tests/front/controller/admin/PostBookmarkControllerTest.php b/tests/front/controller/admin/PostBookmarkControllerTest.php index f00a15c9..69673bd2 100644 --- a/tests/front/controller/admin/PostBookmarkControllerTest.php +++ b/tests/front/controller/admin/PostBookmarkControllerTest.php @@ -13,7 +13,6 @@ use Shaarli\Security\SessionManager; use Shaarli\Thumbnailer; use Slim\Http\Request; use Slim\Http\Response; -use Slim\Http\Uri; class PostBookmarkControllerTest extends TestCase { @@ -406,12 +405,6 @@ class PostBookmarkControllerTest extends TestCase return $parameters[$key] ?? null; }) ; - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); $response = new Response(); $checkBookmark = function (Bookmark $bookmark) use ($parameters) { @@ -493,12 +486,6 @@ class PostBookmarkControllerTest extends TestCase return $parameters[$key] ?? null; }) ; - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); $response = new Response(); $checkBookmark = function (Bookmark $bookmark) use ($parameters, $id) { @@ -575,12 +562,6 @@ class PostBookmarkControllerTest extends TestCase return $parameters[$key] ?? null; }) ; - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); $response = new Response(); $this->container->conf = $this->createMock(ConfigManager::class); diff --git a/tests/front/controller/admin/SessionFilterControllerTest.php b/tests/front/controller/admin/SessionFilterControllerTest.php index 096963cf..ea07edee 100644 --- a/tests/front/controller/admin/SessionFilterControllerTest.php +++ b/tests/front/controller/admin/SessionFilterControllerTest.php @@ -9,7 +9,6 @@ use Shaarli\Security\LoginManager; use Shaarli\Security\SessionManager; use Slim\Http\Request; use Slim\Http\Response; -use Slim\Http\Uri; class SessionFilterControllerTest extends TestCase { @@ -33,12 +32,6 @@ class SessionFilterControllerTest extends TestCase $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; $request = $this->createMock(Request::class); - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); $request->method('getParam')->with('nb')->willReturn('8'); $response = new Response(); @@ -61,12 +54,6 @@ class SessionFilterControllerTest extends TestCase public function testLinksPerPageNotValid(): void { $request = $this->createMock(Request::class); - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); $request->method('getParam')->with('nb')->willReturn('test'); $response = new Response(); @@ -80,7 +67,7 @@ class SessionFilterControllerTest extends TestCase static::assertInstanceOf(Response::class, $result); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder'], $result->getHeader('location')); + static::assertSame(['/subfolder/'], $result->getHeader('location')); } /** @@ -100,12 +87,6 @@ class SessionFilterControllerTest extends TestCase ; $request = $this->createMock(Request::class); - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); $response = new Response(); $result = $this->controller->visibility($request, $response, $arg); @@ -141,12 +122,6 @@ class SessionFilterControllerTest extends TestCase ; $request = $this->createMock(Request::class); - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); $response = new Response(); $result = $this->controller->visibility($request, $response, $arg); @@ -176,19 +151,13 @@ class SessionFilterControllerTest extends TestCase ; $request = $this->createMock(Request::class); - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); $response = new Response(); $result = $this->controller->visibility($request, $response, $arg); static::assertInstanceOf(Response::class, $result); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder'], $result->getHeader('location')); + static::assertSame(['/subfolder/'], $result->getHeader('location')); } /** @@ -212,12 +181,6 @@ class SessionFilterControllerTest extends TestCase ; $request = $this->createMock(Request::class); - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); $response = new Response(); $result = $this->controller->visibility($request, $response, $arg); @@ -249,12 +212,6 @@ class SessionFilterControllerTest extends TestCase ; $request = $this->createMock(Request::class); - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); $response = new Response(); $result = $this->controller->visibility($request, $response, $arg); @@ -272,12 +229,6 @@ class SessionFilterControllerTest extends TestCase $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; $request = $this->createMock(Request::class); - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); $response = new Response(); $this->container->sessionManager @@ -301,13 +252,6 @@ class SessionFilterControllerTest extends TestCase $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; $request = $this->createMock(Request::class); - $request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); - $response = new Response(); $this->container->sessionManager diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php index fecd0c82..7f560662 100644 --- a/tests/front/controller/visitor/FrontControllerMockHelper.php +++ b/tests/front/controller/visitor/FrontControllerMockHelper.php @@ -81,6 +81,8 @@ trait FrontControllerMockHelper 'SERVER_PORT' => '80', 'REQUEST_URI' => '/daily-rss', ]; + + $this->container->basePath = '/subfolder'; } /** diff --git a/tests/front/controller/visitor/ShaarliPublicControllerTest.php b/tests/front/controller/visitor/ShaarliPublicControllerTest.php deleted file mode 100644 index 899b280b..00000000 --- a/tests/front/controller/visitor/ShaarliPublicControllerTest.php +++ /dev/null @@ -1,221 +0,0 @@ -createContainer(); - - $this->controller = new class($this->container) extends ShaarliVisitorController - { - public function assignView(string $key, $value): ShaarliVisitorController - { - return parent::assignView($key, $value); - } - - public function render(string $template): string - { - return parent::render($template); - } - - public function redirectFromReferer( - Request $request, - Response $response, - array $loopTerms = [], - array $clearParams = [] - ): Response { - return parent::redirectFromReferer($request, $response, $loopTerms, $clearParams); - } - }; - $this->assignedValues = []; - - $this->request = $this->createMock(Request::class); - $this->request->method('getUri')->willReturnCallback(function (): Uri { - $uri = $this->createMock(Uri::class); - $uri->method('getBasePath')->willReturn('/subfolder'); - - return $uri; - }); - } - - public function testAssignView(): void - { - $this->assignTemplateVars($this->assignedValues); - - $self = $this->controller->assignView('variableName', 'variableValue'); - - static::assertInstanceOf(ShaarliVisitorController::class, $self); - static::assertSame('variableValue', $this->assignedValues['variableName']); - } - - public function testRender(): void - { - $this->assignTemplateVars($this->assignedValues); - - $this->container->bookmarkService - ->method('count') - ->willReturnCallback(function (string $visibility): int { - return $visibility === BookmarkFilter::$PRIVATE ? 5 : 10; - }) - ; - - $this->container->pluginManager - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array &$data, array $params): array { - return $data[$hook] = $params; - }); - $this->container->pluginManager->method('getErrors')->willReturn(['error']); - - $this->container->loginManager->method('isLoggedIn')->willReturn(true); - - $render = $this->controller->render('templateName'); - - static::assertSame('templateName', $render); - - static::assertSame(10, $this->assignedValues['linkcount']); - static::assertSame(5, $this->assignedValues['privateLinkcount']); - static::assertSame(['error'], $this->assignedValues['plugin_errors']); - - static::assertSame('templateName', $this->assignedValues['plugins_includes']['render_includes']['target']); - static::assertTrue($this->assignedValues['plugins_includes']['render_includes']['loggedin']); - static::assertSame('templateName', $this->assignedValues['plugins_header']['render_header']['target']); - static::assertTrue($this->assignedValues['plugins_header']['render_header']['loggedin']); - static::assertSame('templateName', $this->assignedValues['plugins_footer']['render_footer']['target']); - static::assertTrue($this->assignedValues['plugins_footer']['render_footer']['loggedin']); - } - - /** - * Test redirectFromReferer() - Default behaviour - */ - public function testRedirectFromRefererDefault(): void - { - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($this->request, $response); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term not matched in the referer - */ - public function testRedirectFromRefererWithUnmatchedLoopTerm(): void - { - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($this->request, $response, ['nope']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term matching the referer in its path -> redirect to default - */ - public function testRedirectFromRefererWithMatchingLoopTermInPath(): void - { - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'controller']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term matching the referer in its query parameters -> redirect to default - */ - public function testRedirectFromRefererWithMatchingLoopTermInQueryParam(): void - { - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'other']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term matching the referer in its query value - * -> we do not block redirection for query parameter values. - */ - public function testRedirectFromRefererWithMatchingLoopTermInQueryValue(): void - { - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'param']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term matching the referer in its domain name - * -> we do not block redirection for shaarli's hosts - */ - public function testRedirectFromRefererWithLoopTermInDomain(): void - { - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($this->request, $response, ['shaarli']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); - } - - /** - * Test redirectFromReferer() - With a loop term matching a query parameter AND clear this query param - * -> the param should be cleared before checking if it matches the redir loop terms - */ - public function testRedirectFromRefererWithMatchingClearedParam(): void - { - $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; - - $response = new Response(); - - $result = $this->controller->redirectFromReferer($this->request, $response, ['query'], ['query']); - - static::assertSame(302, $result->getStatusCode()); - static::assertSame(['/subfolder/controller?other=2'], $result->getHeader('location')); - } -} diff --git a/tests/front/controller/visitor/ShaarliVisitorControllerTest.php b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php new file mode 100644 index 00000000..83d08358 --- /dev/null +++ b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php @@ -0,0 +1,217 @@ +createContainer(); + + $this->controller = new class($this->container) extends ShaarliVisitorController + { + public function assignView(string $key, $value): ShaarliVisitorController + { + return parent::assignView($key, $value); + } + + public function render(string $template): string + { + return parent::render($template); + } + + public function redirectFromReferer( + Request $request, + Response $response, + array $loopTerms = [], + array $clearParams = [], + string $anchor = null + ): Response { + return parent::redirectFromReferer($request, $response, $loopTerms, $clearParams, $anchor); + } + }; + $this->assignedValues = []; + + $this->request = $this->createMock(Request::class); + } + + public function testAssignView(): void + { + $this->assignTemplateVars($this->assignedValues); + + $self = $this->controller->assignView('variableName', 'variableValue'); + + static::assertInstanceOf(ShaarliVisitorController::class, $self); + static::assertSame('variableValue', $this->assignedValues['variableName']); + } + + public function testRender(): void + { + $this->assignTemplateVars($this->assignedValues); + + $this->container->bookmarkService + ->method('count') + ->willReturnCallback(function (string $visibility): int { + return $visibility === BookmarkFilter::$PRIVATE ? 5 : 10; + }) + ; + + $this->container->pluginManager + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array &$data, array $params): array { + return $data[$hook] = $params; + }); + $this->container->pluginManager->method('getErrors')->willReturn(['error']); + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + + $render = $this->controller->render('templateName'); + + static::assertSame('templateName', $render); + + static::assertSame(10, $this->assignedValues['linkcount']); + static::assertSame(5, $this->assignedValues['privateLinkcount']); + static::assertSame(['error'], $this->assignedValues['plugin_errors']); + static::assertSame('/subfolder', $this->assignedValues['base_path']); + static::assertSame('/subfolder/tpl/default', $this->assignedValues['asset_path']); + + static::assertSame('templateName', $this->assignedValues['plugins_includes']['render_includes']['target']); + static::assertTrue($this->assignedValues['plugins_includes']['render_includes']['loggedin']); + static::assertSame('templateName', $this->assignedValues['plugins_header']['render_header']['target']); + static::assertTrue($this->assignedValues['plugins_header']['render_header']['loggedin']); + static::assertSame('templateName', $this->assignedValues['plugins_footer']['render_footer']['target']); + static::assertTrue($this->assignedValues['plugins_footer']['render_footer']['loggedin']); + } + + /** + * Test redirectFromReferer() - Default behaviour + */ + public function testRedirectFromRefererDefault(): void + { + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term not matched in the referer + */ + public function testRedirectFromRefererWithUnmatchedLoopTerm(): void + { + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its path -> redirect to default + */ + public function testRedirectFromRefererWithMatchingLoopTermInPath(): void + { + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'controller']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its query parameters -> redirect to default + */ + public function testRedirectFromRefererWithMatchingLoopTermInQueryParam(): void + { + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'other']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its query value + * -> we do not block redirection for query parameter values. + */ + public function testRedirectFromRefererWithMatchingLoopTermInQueryValue(): void + { + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'param']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its domain name + * -> we do not block redirection for shaarli's hosts + */ + public function testRedirectFromRefererWithLoopTermInDomain(): void + { + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['shaarli']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching a query parameter AND clear this query param + * -> the param should be cleared before checking if it matches the redir loop terms + */ + public function testRedirectFromRefererWithMatchingClearedParam(): void + { + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['query'], ['query']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?other=2'], $result->getHeader('location')); + } +} -- cgit v1.2.3 From 9c75f877935fa6adec951a4d8d32b328aaab314f Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 13 Jun 2020 13:08:01 +0200 Subject: Use multi-level routes for existing controllers instead of 1 level everywhere Also prefix most admin routes with /admin/ --- tests/container/ContainerBuilderTest.php | 15 ++++++++++++--- tests/feed/CachedPageTest.php | 6 +++--- tests/front/controller/admin/ConfigureControllerTest.php | 6 +++--- tests/front/controller/admin/LogoutControllerTest.php | 2 +- tests/front/controller/admin/ManageTagControllerTest.php | 10 +++++----- .../front/controller/admin/PostBookmarkControllerTest.php | 6 +++--- tests/front/controller/visitor/LoginControllerTest.php | 4 ++-- tests/front/controller/visitor/TagControllerTest.php | 8 ++++---- 8 files changed, 33 insertions(+), 24 deletions(-) (limited to 'tests') diff --git a/tests/container/ContainerBuilderTest.php b/tests/container/ContainerBuilderTest.php index 65647249..db533f37 100644 --- a/tests/container/ContainerBuilderTest.php +++ b/tests/container/ContainerBuilderTest.php @@ -7,12 +7,16 @@ namespace Shaarli\Container; use PHPUnit\Framework\TestCase; use Shaarli\Bookmark\BookmarkServiceInterface; use Shaarli\Config\ConfigManager; +use Shaarli\Feed\FeedBuilder; use Shaarli\Formatter\FormatterFactory; use Shaarli\History; +use Shaarli\Http\HttpAccess; +use Shaarli\Plugin\PluginManager; use Shaarli\Render\PageBuilder; use Shaarli\Render\PageCacheManager; use Shaarli\Security\LoginManager; use Shaarli\Security\SessionManager; +use Shaarli\Thumbnailer; class ContainerBuilderTest extends TestCase { @@ -39,8 +43,7 @@ class ContainerBuilderTest extends TestCase $this->containerBuilder = new ContainerBuilder( $this->conf, $this->sessionManager, - $this->loginManager, - 'UT web path' + $this->loginManager ); } @@ -51,11 +54,17 @@ class ContainerBuilderTest extends TestCase static::assertInstanceOf(ConfigManager::class, $container->conf); static::assertInstanceOf(SessionManager::class, $container->sessionManager); static::assertInstanceOf(LoginManager::class, $container->loginManager); - static::assertSame('UT web path', $container->webPath); static::assertInstanceOf(History::class, $container->history); static::assertInstanceOf(BookmarkServiceInterface::class, $container->bookmarkService); static::assertInstanceOf(PageBuilder::class, $container->pageBuilder); + static::assertInstanceOf(PluginManager::class, $container->pluginManager); static::assertInstanceOf(FormatterFactory::class, $container->formatterFactory); static::assertInstanceOf(PageCacheManager::class, $container->pageCacheManager); + static::assertInstanceOf(FeedBuilder::class, $container->feedBuilder); + static::assertInstanceOf(Thumbnailer::class, $container->thumbnailer); + static::assertInstanceOf(HttpAccess::class, $container->httpAccess); + + // Set by the middleware + static::assertNull($container->basePath); } } diff --git a/tests/feed/CachedPageTest.php b/tests/feed/CachedPageTest.php index 57f3b09b..2e716432 100644 --- a/tests/feed/CachedPageTest.php +++ b/tests/feed/CachedPageTest.php @@ -11,7 +11,7 @@ class CachedPageTest extends \PHPUnit\Framework\TestCase { // test cache directory protected static $testCacheDir = 'sandbox/pagecache'; - protected static $url = 'http://shaar.li/feed-atom'; + protected static $url = 'http://shaar.li/feed/atom'; protected static $filename; /** @@ -42,8 +42,8 @@ class CachedPageTest extends \PHPUnit\Framework\TestCase { new CachedPage(self::$testCacheDir, '', true); new CachedPage(self::$testCacheDir, '', false); - new CachedPage(self::$testCacheDir, 'http://shaar.li/feed-rss', true); - new CachedPage(self::$testCacheDir, 'http://shaar.li/feed-atom', false); + new CachedPage(self::$testCacheDir, 'http://shaar.li/feed/rss', true); + new CachedPage(self::$testCacheDir, 'http://shaar.li/feed/atom', false); $this->addToAssertionCount(1); } diff --git a/tests/front/controller/admin/ConfigureControllerTest.php b/tests/front/controller/admin/ConfigureControllerTest.php index 40304a18..f2f84bac 100644 --- a/tests/front/controller/admin/ConfigureControllerTest.php +++ b/tests/front/controller/admin/ConfigureControllerTest.php @@ -142,7 +142,7 @@ class ConfigureControllerTest extends TestCase $result = $this->controller->save($request, $response); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./configure'], $result->getHeader('Location')); + static::assertSame(['/subfolder/admin/configure'], $result->getHeader('Location')); static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); @@ -193,7 +193,7 @@ class ConfigureControllerTest extends TestCase $result = $this->controller->save($request, $response); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./configure'], $result->getHeader('Location')); + static::assertSame(['/subfolder/admin/configure'], $result->getHeader('Location')); static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); @@ -242,7 +242,7 @@ class ConfigureControllerTest extends TestCase $result = $this->controller->save($request, $response); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./configure'], $result->getHeader('Location')); + static::assertSame(['/subfolder/admin/configure'], $result->getHeader('Location')); static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); diff --git a/tests/front/controller/admin/LogoutControllerTest.php b/tests/front/controller/admin/LogoutControllerTest.php index 78a0fe73..ca177085 100644 --- a/tests/front/controller/admin/LogoutControllerTest.php +++ b/tests/front/controller/admin/LogoutControllerTest.php @@ -49,7 +49,7 @@ class LogoutControllerTest extends TestCase static::assertInstanceOf(Response::class, $result); static::assertSame(302, $result->getStatusCode()); - static::assertContains('./', $result->getHeader('Location')); + static::assertSame(['/subfolder/'], $result->getHeader('location')); static::assertSame('false', $_COOKIE[LoginManager::$STAY_SIGNED_IN_COOKIE]); } } diff --git a/tests/front/controller/admin/ManageTagControllerTest.php b/tests/front/controller/admin/ManageTagControllerTest.php index eed99231..09ba0b4b 100644 --- a/tests/front/controller/admin/ManageTagControllerTest.php +++ b/tests/front/controller/admin/ManageTagControllerTest.php @@ -93,7 +93,7 @@ class ManageTagControllerTest extends TestCase $result = $this->controller->save($request, $response); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./?searchtags=new-tag'], $result->getHeader('location')); + static::assertSame(['/subfolder/?searchtags=new-tag'], $result->getHeader('location')); static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); @@ -146,7 +146,7 @@ class ManageTagControllerTest extends TestCase $result = $this->controller->save($request, $response); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./manage-tags'], $result->getHeader('location')); + static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location')); static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); @@ -197,7 +197,7 @@ class ManageTagControllerTest extends TestCase $result = $this->controller->save($request, $response); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./manage-tags'], $result->getHeader('location')); + static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location')); static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); @@ -229,7 +229,7 @@ class ManageTagControllerTest extends TestCase $result = $this->controller->save($request, $response); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./manage-tags'], $result->getHeader('location')); + static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location')); static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); @@ -262,7 +262,7 @@ class ManageTagControllerTest extends TestCase $result = $this->controller->save($request, $response); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./manage-tags'], $result->getHeader('location')); + static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location')); static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session); static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session); diff --git a/tests/front/controller/admin/PostBookmarkControllerTest.php b/tests/front/controller/admin/PostBookmarkControllerTest.php index 69673bd2..8dcd1b50 100644 --- a/tests/front/controller/admin/PostBookmarkControllerTest.php +++ b/tests/front/controller/admin/PostBookmarkControllerTest.php @@ -395,7 +395,7 @@ class PostBookmarkControllerTest extends TestCase 'lf_description' => 'Provided description.', 'lf_tags' => 'abc def', 'lf_private' => '1', - 'returnurl' => 'http://shaarli.tld/subfolder/add-shaare' + 'returnurl' => 'http://shaarli.tld/subfolder/admin/add-shaare' ]; $request = $this->createMock(Request::class); @@ -459,7 +459,7 @@ class PostBookmarkControllerTest extends TestCase $result = $this->controller->save($request, $response); static::assertSame(302, $result->getStatusCode()); - static::assertRegExp('@/subfolder/#\w{6}@', $result->getHeader('location')[0]); + static::assertRegExp('@/subfolder/#[\w\-]{6}@', $result->getHeader('location')[0]); } @@ -545,7 +545,7 @@ class PostBookmarkControllerTest extends TestCase $result = $this->controller->save($request, $response); static::assertSame(302, $result->getStatusCode()); - static::assertRegExp('@/subfolder/\?page=2#\w{6}@', $result->getHeader('location')[0]); + static::assertRegExp('@/subfolder/\?page=2#[\w\-]{6}@', $result->getHeader('location')[0]); } /** diff --git a/tests/front/controller/visitor/LoginControllerTest.php b/tests/front/controller/visitor/LoginControllerTest.php index faa8ac71..e57f44b9 100644 --- a/tests/front/controller/visitor/LoginControllerTest.php +++ b/tests/front/controller/visitor/LoginControllerTest.php @@ -95,7 +95,7 @@ class LoginControllerTest extends TestCase static::assertInstanceOf(Response::class, $result); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('Location')); + static::assertSame(['/subfolder/'], $result->getHeader('Location')); } public function testLoginControllerOpenShaarli(): void @@ -116,7 +116,7 @@ class LoginControllerTest extends TestCase static::assertInstanceOf(Response::class, $result); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('Location')); + static::assertSame(['/subfolder/'], $result->getHeader('Location')); } public function testLoginControllerWhileBanned(): void diff --git a/tests/front/controller/visitor/TagControllerTest.php b/tests/front/controller/visitor/TagControllerTest.php index 1242a2e9..43076086 100644 --- a/tests/front/controller/visitor/TagControllerTest.php +++ b/tests/front/controller/visitor/TagControllerTest.php @@ -64,7 +64,7 @@ class TagControllerTest extends TestCase static::assertInstanceOf(Response::class, $result); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./?searchtags=abc'], $result->getHeader('location')); + static::assertSame(['/subfolder/?searchtags=abc'], $result->getHeader('location')); } public function testAddTagRemoveLegacyQueryParam(): void @@ -138,7 +138,7 @@ class TagControllerTest extends TestCase static::assertInstanceOf(Response::class, $result); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('location')); + static::assertSame(['/subfolder/'], $result->getHeader('location')); } public function testRemoveTagWithoutMatchingTag(): void @@ -184,7 +184,7 @@ class TagControllerTest extends TestCase static::assertInstanceOf(Response::class, $result); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('location')); + static::assertSame(['/subfolder/'], $result->getHeader('location')); } public function testRemoveTagWithoutTag(): void @@ -210,6 +210,6 @@ class TagControllerTest extends TestCase static::assertInstanceOf(Response::class, $result); static::assertSame(302, $result->getStatusCode()); - static::assertSame(['./'], $result->getHeader('location')); + static::assertSame(['/subfolder/'], $result->getHeader('location')); } } -- cgit v1.2.3 From baa6979194573855b260593094983c33ec338dc7 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 13 Jun 2020 15:37:02 +0200 Subject: Improve ManageTagController coverage and error handling --- .../ManageShaareControllerTest/AddShaareTest.php | 47 ++ .../DeleteBookmarkTest.php | 361 ++++++++++++ .../DisplayCreateFormTest.php | 315 ++++++++++ .../DisplayEditFormTest.php | 155 +++++ .../SaveBookmarkTest.php | 282 +++++++++ .../admin/PostBookmarkControllerTest.php | 633 --------------------- 6 files changed, 1160 insertions(+), 633 deletions(-) create mode 100644 tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php create mode 100644 tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php create mode 100644 tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php create mode 100644 tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php create mode 100644 tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php delete mode 100644 tests/front/controller/admin/PostBookmarkControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php b/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php new file mode 100644 index 00000000..7d5b752a --- /dev/null +++ b/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php @@ -0,0 +1,47 @@ +createContainer(); + + $this->container->httpAccess = $this->createMock(HttpAccess::class); + $this->controller = new ManageShaareController($this->container); + } + + /** + * Test displaying add link page + */ + public function testAddShaare(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->addShaare($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('addlink', (string) $result->getBody()); + + static::assertSame('Shaare a new link - Shaarli', $assignedVariables['pagetitle']); + } +} diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php new file mode 100644 index 00000000..caaf549d --- /dev/null +++ b/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php @@ -0,0 +1,361 @@ +createContainer(); + + $this->container->httpAccess = $this->createMock(HttpAccess::class); + $this->controller = new ManageShaareController($this->container); + } + + /** + * Delete bookmark - Single bookmark with valid parameters + */ + public function testDeleteSingleBookmark(): void + { + $parameters = ['id' => '123']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $bookmark = (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123'); + + $this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark); + $this->container->bookmarkService->expects(static::once())->method('remove')->with($bookmark, false); + $this->container->bookmarkService->expects(static::once())->method('save'); + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->expects(static::once()) + ->method('getFormatter') + ->with('raw') + ->willReturnCallback(function () use ($bookmark): BookmarkFormatter { + $formatter = $this->createMock(BookmarkFormatter::class); + + $formatter->expects(static::once())->method('format')->with($bookmark); + + return $formatter; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::once()) + ->method('executeHooks') + ->with('delete_link') + ; + + $result = $this->controller->deleteBookmark($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Delete bookmark - Multiple bookmarks with valid parameters + */ + public function testDeleteMultipleBookmarks(): void + { + $parameters = ['id' => '123 456 789']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $bookmarks = [ + (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123'), + (new Bookmark())->setId(456)->setUrl('http://domain.tld')->setTitle('Title 456'), + (new Bookmark())->setId(789)->setUrl('http://domain.tld')->setTitle('Title 789'), + ]; + + $this->container->bookmarkService + ->expects(static::exactly(3)) + ->method('get') + ->withConsecutive([123], [456], [789]) + ->willReturnOnConsecutiveCalls(...$bookmarks) + ; + $this->container->bookmarkService + ->expects(static::exactly(3)) + ->method('remove') + ->withConsecutive(...array_map(function (Bookmark $bookmark): array { + return [$bookmark, false]; + }, $bookmarks)) + ; + $this->container->bookmarkService->expects(static::once())->method('save'); + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->expects(static::once()) + ->method('getFormatter') + ->with('raw') + ->willReturnCallback(function () use ($bookmarks): BookmarkFormatter { + $formatter = $this->createMock(BookmarkFormatter::class); + + $formatter + ->expects(static::exactly(3)) + ->method('format') + ->withConsecutive(...array_map(function (Bookmark $bookmark): array { + return [$bookmark]; + }, $bookmarks)) + ; + + return $formatter; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::exactly(3)) + ->method('executeHooks') + ->with('delete_link') + ; + + $result = $this->controller->deleteBookmark($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Delete bookmark - Single bookmark not found in the data store + */ + public function testDeleteSingleBookmarkNotFound(): void + { + $parameters = ['id' => '123']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->willThrowException(new BookmarkNotFoundException()) + ; + $this->container->bookmarkService->expects(static::never())->method('remove'); + $this->container->bookmarkService->expects(static::never())->method('save'); + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->expects(static::once()) + ->method('getFormatter') + ->with('raw') + ->willReturnCallback(function (): BookmarkFormatter { + $formatter = $this->createMock(BookmarkFormatter::class); + + $formatter->expects(static::never())->method('format'); + + return $formatter; + }) + ; + // Make sure that PluginManager hook is not triggered + $this->container->pluginManager + ->expects(static::never()) + ->method('executeHooks') + ->with('delete_link') + ; + + $result = $this->controller->deleteBookmark($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Delete bookmark - Multiple bookmarks with one not found in the data store + */ + public function testDeleteMultipleBookmarksOneNotFound(): void + { + $parameters = ['id' => '123 456 789']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $bookmarks = [ + (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123'), + (new Bookmark())->setId(789)->setUrl('http://domain.tld')->setTitle('Title 789'), + ]; + + $this->container->bookmarkService + ->expects(static::exactly(3)) + ->method('get') + ->withConsecutive([123], [456], [789]) + ->willReturnCallback(function (int $id) use ($bookmarks): Bookmark { + if ($id === 123) { + return $bookmarks[0]; + } + if ($id === 789) { + return $bookmarks[1]; + } + throw new BookmarkNotFoundException(); + }) + ; + $this->container->bookmarkService + ->expects(static::exactly(2)) + ->method('remove') + ->withConsecutive(...array_map(function (Bookmark $bookmark): array { + return [$bookmark, false]; + }, $bookmarks)) + ; + $this->container->bookmarkService->expects(static::once())->method('save'); + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->expects(static::once()) + ->method('getFormatter') + ->with('raw') + ->willReturnCallback(function () use ($bookmarks): BookmarkFormatter { + $formatter = $this->createMock(BookmarkFormatter::class); + + $formatter + ->expects(static::exactly(2)) + ->method('format') + ->withConsecutive(...array_map(function (Bookmark $bookmark): array { + return [$bookmark]; + }, $bookmarks)) + ; + + return $formatter; + }) + ; + + // Make sure that PluginManager hook is not triggered + $this->container->pluginManager + ->expects(static::exactly(2)) + ->method('executeHooks') + ->with('delete_link') + ; + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier 456 could not be found.']) + ; + + $result = $this->controller->deleteBookmark($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Delete bookmark - Invalid ID + */ + public function testDeleteInvalidId(): void + { + $parameters = ['id' => 'nope not an ID']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.']) + ; + + $result = $this->controller->deleteBookmark($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Delete bookmark - Empty ID + */ + public function testDeleteEmptyId(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.']) + ; + + $result = $this->controller->deleteBookmark($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Delete bookmark - from bookmarklet + */ + public function testDeleteBookmarkFromBookmarklet(): void + { + $parameters = [ + 'id' => '123', + 'source' => 'bookmarklet', + ]; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->expects(static::once()) + ->method('getFormatter') + ->willReturn($this->createMock(BookmarkFormatter::class)) + ; + + $result = $this->controller->deleteBookmark($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('', (string) $result->getBody('location')); + } +} diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php b/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php new file mode 100644 index 00000000..777583d5 --- /dev/null +++ b/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php @@ -0,0 +1,315 @@ +createContainer(); + + $this->container->httpAccess = $this->createMock(HttpAccess::class); + $this->controller = new ManageShaareController($this->container); + } + + /** + * Test displaying bookmark create form + * Ensure that every step of the standard workflow works properly. + */ + public function testDisplayCreateFormWithUrl(): void + { + $this->container->environment = [ + 'HTTP_REFERER' => $referer = 'http://shaarli/subfolder/controller/?searchtag=abc' + ]; + + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $url = 'http://url.tld/other?part=3&utm_ad=pay#hash'; + $expectedUrl = str_replace('&utm_ad=pay', '', $url); + $remoteTitle = 'Remote Title'; + $remoteDesc = 'Sometimes the meta description is relevant.'; + $remoteTags = 'abc def'; + + $request = $this->createMock(Request::class); + $request->method('getParam')->willReturnCallback(function (string $key) use ($url): ?string { + return $key === 'post' ? $url : null; + }); + $response = new Response(); + + $this->container->httpAccess + ->expects(static::once()) + ->method('getCurlDownloadCallback') + ->willReturnCallback( + function (&$charset, &$title, &$description, &$tags) use ( + $remoteTitle, + $remoteDesc, + $remoteTags + ): callable { + return function () use ( + &$charset, + &$title, + &$description, + &$tags, + $remoteTitle, + $remoteDesc, + $remoteTags + ): void { + $charset = 'ISO-8859-1'; + $title = $remoteTitle; + $description = $remoteDesc; + $tags = $remoteTags; + }; + } + ) + ; + $this->container->httpAccess + ->expects(static::once()) + ->method('getHttpResponse') + ->with($expectedUrl, 30, 4194304) + ->willReturnCallback(function($url, $timeout, $maxBytes, $callback): void { + $callback(); + }) + ; + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->willReturn($tags = ['tag1' => 2, 'tag2' => 1]) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data) use ($remoteTitle, $remoteDesc): array { + static::assertSame('render_editlink', $hook); + static::assertSame($remoteTitle, $data['link']['title']); + static::assertSame($remoteDesc, $data['link']['description']); + + return $data; + }) + ; + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + + static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame($expectedUrl, $assignedVariables['link']['url']); + static::assertSame($remoteTitle, $assignedVariables['link']['title']); + static::assertSame($remoteDesc, $assignedVariables['link']['description']); + static::assertSame($remoteTags, $assignedVariables['link']['tags']); + static::assertFalse($assignedVariables['link']['private']); + + static::assertTrue($assignedVariables['link_is_new']); + static::assertSame($referer, $assignedVariables['http_referer']); + static::assertSame($tags, $assignedVariables['tags']); + static::assertArrayHasKey('source', $assignedVariables); + static::assertArrayHasKey('default_private_links', $assignedVariables); + } + + /** + * Test displaying bookmark create form + * Ensure all available query parameters are handled properly. + */ + public function testDisplayCreateFormWithFullParameters(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $parameters = [ + 'post' => 'http://url.tld/other?part=3&utm_ad=pay#hash', + 'title' => 'Provided Title', + 'description' => 'Provided description.', + 'tags' => 'abc def', + 'private' => '1', + 'source' => 'apps', + ]; + $expectedUrl = str_replace('&utm_ad=pay', '', $parameters['post']); + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }); + $response = new Response(); + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + + static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame($expectedUrl, $assignedVariables['link']['url']); + static::assertSame($parameters['title'], $assignedVariables['link']['title']); + static::assertSame($parameters['description'], $assignedVariables['link']['description']); + static::assertSame($parameters['tags'], $assignedVariables['link']['tags']); + static::assertTrue($assignedVariables['link']['private']); + static::assertTrue($assignedVariables['link_is_new']); + static::assertSame($parameters['source'], $assignedVariables['source']); + } + + /** + * Test displaying bookmark create form + * Without any parameter. + */ + public function testDisplayCreateFormEmpty(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); + $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + static::assertSame('', $assignedVariables['link']['url']); + static::assertSame('Note: ', $assignedVariables['link']['title']); + static::assertSame('', $assignedVariables['link']['description']); + static::assertSame('', $assignedVariables['link']['tags']); + static::assertFalse($assignedVariables['link']['private']); + static::assertTrue($assignedVariables['link_is_new']); + } + + /** + * Test displaying bookmark create form + * URL not using HTTP protocol: do not try to retrieve the title + */ + public function testDisplayCreateFormNotHttp(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $url = 'magnet://kubuntu.torrent'; + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($url): ?string { + return $key === 'post' ? $url : null; + }); + $response = new Response(); + + $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); + $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + static::assertSame($url, $assignedVariables['link']['url']); + static::assertTrue($assignedVariables['link_is_new']); + } + + /** + * Test displaying bookmark create form + * When markdown formatter is enabled, the no markdown tag should be added to existing tags. + */ + public function testDisplayCreateFormWithMarkdownEnabled(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf + ->expects(static::atLeastOnce()) + ->method('get')->willReturnCallback(function (string $key): ?string { + if ($key === 'formatter') { + return 'markdown'; + } + + return $key; + }) + ; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + static::assertSame(['nomarkdown' => 1], $assignedVariables['tags']); + } + + /** + * Test displaying bookmark create form + * When an existing URL is submitted, we want to edit the existing link. + */ + public function testDisplayCreateFormWithExistingUrl(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $url = 'http://url.tld/other?part=3&utm_ad=pay#hash'; + $expectedUrl = str_replace('&utm_ad=pay', '', $url); + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($url): ?string { + return $key === 'post' ? $url : null; + }); + $response = new Response(); + + $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); + $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('findByUrl') + ->with($expectedUrl) + ->willReturn( + (new Bookmark()) + ->setId($id = 23) + ->setUrl($expectedUrl) + ->setTitle($title = 'Bookmark Title') + ->setDescription($description = 'Bookmark description.') + ->setTags($tags = ['abc', 'def']) + ->setPrivate(true) + ->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44')) + ) + ; + + $result = $this->controller->displayCreateForm($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + + static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']); + static::assertFalse($assignedVariables['link_is_new']); + + static::assertSame($id, $assignedVariables['link']['id']); + static::assertSame($expectedUrl, $assignedVariables['link']['url']); + static::assertSame($title, $assignedVariables['link']['title']); + static::assertSame($description, $assignedVariables['link']['description']); + static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']); + static::assertTrue($assignedVariables['link']['private']); + static::assertSame($createdAt, $assignedVariables['link']['created']); + } +} diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php b/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php new file mode 100644 index 00000000..1a1cdcf3 --- /dev/null +++ b/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php @@ -0,0 +1,155 @@ +createContainer(); + + $this->container->httpAccess = $this->createMock(HttpAccess::class); + $this->controller = new ManageShaareController($this->container); + } + + /** + * Test displaying bookmark edit form + * When an existing ID is provided, ensure that default workflow works properly. + */ + public function testDisplayEditFormDefault(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $id = 11; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); + $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->with($id) + ->willReturn( + (new Bookmark()) + ->setId($id) + ->setUrl($url = 'http://domain.tld') + ->setTitle($title = 'Bookmark Title') + ->setDescription($description = 'Bookmark description.') + ->setTags($tags = ['abc', 'def']) + ->setPrivate(true) + ->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44')) + ) + ; + + $result = $this->controller->displayEditForm($request, $response, ['id' => (string) $id]); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('editlink', (string) $result->getBody()); + + static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']); + static::assertFalse($assignedVariables['link_is_new']); + + static::assertSame($id, $assignedVariables['link']['id']); + static::assertSame($url, $assignedVariables['link']['url']); + static::assertSame($title, $assignedVariables['link']['title']); + static::assertSame($description, $assignedVariables['link']['description']); + static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']); + static::assertTrue($assignedVariables['link']['private']); + static::assertSame($createdAt, $assignedVariables['link']['created']); + } + + /** + * Test displaying bookmark edit form + * Invalid ID provided. + */ + public function testDisplayEditFormInvalidId(): void + { + $id = 'invalid'; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier invalid could not be found.']) + ; + + $result = $this->controller->displayEditForm($request, $response, ['id' => $id]); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Test displaying bookmark edit form + * ID not provided. + */ + public function testDisplayEditFormIdNotProvided(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier could not be found.']) + ; + + $result = $this->controller->displayEditForm($request, $response, []); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Test displaying bookmark edit form + * Bookmark not found. + */ + public function testDisplayEditFormBookmarkNotFound(): void + { + $id = 123; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->with($id) + ->willThrowException(new BookmarkNotFoundException()) + ; + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier 123 could not be found.']) + ; + + $result = $this->controller->displayEditForm($request, $response, ['id' => (string) $id]); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } +} diff --git a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php new file mode 100644 index 00000000..dabcd60d --- /dev/null +++ b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php @@ -0,0 +1,282 @@ +createContainer(); + + $this->container->httpAccess = $this->createMock(HttpAccess::class); + $this->controller = new ManageShaareController($this->container); + } + + /** + * Test save a new bookmark + */ + public function testSaveBookmark(): void + { + $id = 21; + $parameters = [ + 'lf_url' => 'http://url.tld/other?part=3#hash', + 'lf_title' => 'Provided Title', + 'lf_description' => 'Provided description.', + 'lf_tags' => 'abc def', + 'lf_private' => '1', + 'returnurl' => 'http://shaarli.tld/subfolder/admin/add-shaare' + ]; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $checkBookmark = function (Bookmark $bookmark) use ($parameters) { + static::assertSame($parameters['lf_url'], $bookmark->getUrl()); + static::assertSame($parameters['lf_title'], $bookmark->getTitle()); + static::assertSame($parameters['lf_description'], $bookmark->getDescription()); + static::assertSame($parameters['lf_tags'], $bookmark->getTagsString()); + static::assertTrue($bookmark->isPrivate()); + }; + + $this->container->bookmarkService + ->expects(static::once()) + ->method('addOrSet') + ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { + static::assertFalse($save); + + $checkBookmark($bookmark); + + $bookmark->setId($id); + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('set') + ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { + static::assertTrue($save); + + $checkBookmark($bookmark); + + static::assertSame($id, $bookmark->getId()); + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array { + static::assertSame('save_link', $hook); + + static::assertSame($id, $data['id']); + static::assertSame($parameters['lf_url'], $data['url']); + static::assertSame($parameters['lf_title'], $data['title']); + static::assertSame($parameters['lf_description'], $data['description']); + static::assertSame($parameters['lf_tags'], $data['tags']); + static::assertTrue($data['private']); + + return $data; + }) + ; + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertRegExp('@/subfolder/#[\w\-]{6}@', $result->getHeader('location')[0]); + } + + + /** + * Test save an existing bookmark + */ + public function testSaveExistingBookmark(): void + { + $id = 21; + $parameters = [ + 'lf_id' => (string) $id, + 'lf_url' => 'http://url.tld/other?part=3#hash', + 'lf_title' => 'Provided Title', + 'lf_description' => 'Provided description.', + 'lf_tags' => 'abc def', + 'lf_private' => '1', + 'returnurl' => 'http://shaarli.tld/subfolder/?page=2' + ]; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $checkBookmark = function (Bookmark $bookmark) use ($parameters, $id) { + static::assertSame($id, $bookmark->getId()); + static::assertSame($parameters['lf_url'], $bookmark->getUrl()); + static::assertSame($parameters['lf_title'], $bookmark->getTitle()); + static::assertSame($parameters['lf_description'], $bookmark->getDescription()); + static::assertSame($parameters['lf_tags'], $bookmark->getTagsString()); + static::assertTrue($bookmark->isPrivate()); + }; + + $this->container->bookmarkService->expects(static::atLeastOnce())->method('exists')->willReturn(true); + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->willReturn((new Bookmark())->setId($id)->setUrl('http://other.url')) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('addOrSet') + ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { + static::assertFalse($save); + + $checkBookmark($bookmark); + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('set') + ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { + static::assertTrue($save); + + $checkBookmark($bookmark); + + static::assertSame($id, $bookmark->getId()); + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array { + static::assertSame('save_link', $hook); + + static::assertSame($id, $data['id']); + static::assertSame($parameters['lf_url'], $data['url']); + static::assertSame($parameters['lf_title'], $data['title']); + static::assertSame($parameters['lf_description'], $data['description']); + static::assertSame($parameters['lf_tags'], $data['tags']); + static::assertTrue($data['private']); + + return $data; + }) + ; + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertRegExp('@/subfolder/\?page=2#[\w\-]{6}@', $result->getHeader('location')[0]); + } + + /** + * Test save a bookmark - try to retrieve the thumbnail + */ + public function testSaveBookmarkWithThumbnail(): void + { + $parameters = ['lf_url' => 'http://url.tld/other?part=3#hash']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) { + return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default; + }); + + $this->container->thumbnailer = $this->createMock(Thumbnailer::class); + $this->container->thumbnailer + ->expects(static::once()) + ->method('get') + ->with($parameters['lf_url']) + ->willReturn($thumb = 'http://thumb.url') + ; + + $this->container->bookmarkService + ->expects(static::once()) + ->method('addOrSet') + ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($thumb): void { + static::assertSame($thumb, $bookmark->getThumbnail()); + }) + ; + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + } + + /** + * Change the password with a wrong existing password + */ + public function testSaveBookmarkFromBookmarklet(): void + { + $parameters = ['source' => 'bookmarklet']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $result = $this->controller->save($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('', (string) $result->getBody()); + } + + /** + * Change the password with a wrong existing password + */ + public function testSaveBookmarkWrongToken(): void + { + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager->method('checkToken')->willReturn(false); + + $this->container->bookmarkService->expects(static::never())->method('addOrSet'); + $this->container->bookmarkService->expects(static::never())->method('set'); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->expectException(WrongTokenException::class); + + $this->controller->save($request, $response); + } + +} diff --git a/tests/front/controller/admin/PostBookmarkControllerTest.php b/tests/front/controller/admin/PostBookmarkControllerTest.php deleted file mode 100644 index 8dcd1b50..00000000 --- a/tests/front/controller/admin/PostBookmarkControllerTest.php +++ /dev/null @@ -1,633 +0,0 @@ -createContainer(); - - $this->container->httpAccess = $this->createMock(HttpAccess::class); - $this->controller = new PostBookmarkController($this->container); - } - - /** - * Test displaying add link page - */ - public function testAddShaare(): void - { - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $result = $this->controller->addShaare($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('addlink', (string) $result->getBody()); - - static::assertSame('Shaare a new link - Shaarli', $assignedVariables['pagetitle']); - } - - /** - * Test displaying bookmark create form - * Ensure that every step of the standard workflow works properly. - */ - public function testDisplayCreateFormWithUrl(): void - { - $this->container->environment = [ - 'HTTP_REFERER' => $referer = 'http://shaarli/subfolder/controller/?searchtag=abc' - ]; - - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $url = 'http://url.tld/other?part=3&utm_ad=pay#hash'; - $expectedUrl = str_replace('&utm_ad=pay', '', $url); - $remoteTitle = 'Remote Title'; - $remoteDesc = 'Sometimes the meta description is relevant.'; - $remoteTags = 'abc def'; - - $request = $this->createMock(Request::class); - $request->method('getParam')->willReturnCallback(function (string $key) use ($url): ?string { - return $key === 'post' ? $url : null; - }); - $response = new Response(); - - $this->container->httpAccess - ->expects(static::once()) - ->method('getCurlDownloadCallback') - ->willReturnCallback( - function (&$charset, &$title, &$description, &$tags) use ( - $remoteTitle, - $remoteDesc, - $remoteTags - ): callable { - return function () use ( - &$charset, - &$title, - &$description, - &$tags, - $remoteTitle, - $remoteDesc, - $remoteTags - ): void { - $charset = 'ISO-8859-1'; - $title = $remoteTitle; - $description = $remoteDesc; - $tags = $remoteTags; - }; - } - ) - ; - $this->container->httpAccess - ->expects(static::once()) - ->method('getHttpResponse') - ->with($expectedUrl, 30, 4194304) - ->willReturnCallback(function($url, $timeout, $maxBytes, $callback): void { - $callback(); - }) - ; - - $this->container->bookmarkService - ->expects(static::once()) - ->method('bookmarksCountPerTag') - ->willReturn($tags = ['tag1' => 2, 'tag2' => 1]) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data) use ($remoteTitle, $remoteDesc): array { - static::assertSame('render_editlink', $hook); - static::assertSame($remoteTitle, $data['link']['title']); - static::assertSame($remoteDesc, $data['link']['description']); - - return $data; - }) - ; - - $result = $this->controller->displayCreateForm($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('editlink', (string) $result->getBody()); - - static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']); - - static::assertSame($expectedUrl, $assignedVariables['link']['url']); - static::assertSame($remoteTitle, $assignedVariables['link']['title']); - static::assertSame($remoteDesc, $assignedVariables['link']['description']); - static::assertSame($remoteTags, $assignedVariables['link']['tags']); - static::assertFalse($assignedVariables['link']['private']); - - static::assertTrue($assignedVariables['link_is_new']); - static::assertSame($referer, $assignedVariables['http_referer']); - static::assertSame($tags, $assignedVariables['tags']); - static::assertArrayHasKey('source', $assignedVariables); - static::assertArrayHasKey('default_private_links', $assignedVariables); - } - - /** - * Test displaying bookmark create form - * Ensure all available query parameters are handled properly. - */ - public function testDisplayCreateFormWithFullParameters(): void - { - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $parameters = [ - 'post' => 'http://url.tld/other?part=3&utm_ad=pay#hash', - 'title' => 'Provided Title', - 'description' => 'Provided description.', - 'tags' => 'abc def', - 'private' => '1', - 'source' => 'apps', - ]; - $expectedUrl = str_replace('&utm_ad=pay', '', $parameters['post']); - - $request = $this->createMock(Request::class); - $request - ->method('getParam') - ->willReturnCallback(function (string $key) use ($parameters): ?string { - return $parameters[$key] ?? null; - }); - $response = new Response(); - - $result = $this->controller->displayCreateForm($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('editlink', (string) $result->getBody()); - - static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']); - - static::assertSame($expectedUrl, $assignedVariables['link']['url']); - static::assertSame($parameters['title'], $assignedVariables['link']['title']); - static::assertSame($parameters['description'], $assignedVariables['link']['description']); - static::assertSame($parameters['tags'], $assignedVariables['link']['tags']); - static::assertTrue($assignedVariables['link']['private']); - static::assertTrue($assignedVariables['link_is_new']); - static::assertSame($parameters['source'], $assignedVariables['source']); - } - - /** - * Test displaying bookmark create form - * Without any parameter. - */ - public function testDisplayCreateFormEmpty(): void - { - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); - $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); - - $result = $this->controller->displayCreateForm($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('editlink', (string) $result->getBody()); - static::assertSame('', $assignedVariables['link']['url']); - static::assertSame('Note: ', $assignedVariables['link']['title']); - static::assertSame('', $assignedVariables['link']['description']); - static::assertSame('', $assignedVariables['link']['tags']); - static::assertFalse($assignedVariables['link']['private']); - static::assertTrue($assignedVariables['link_is_new']); - } - - /** - * Test displaying bookmark create form - * URL not using HTTP protocol: do not try to retrieve the title - */ - public function testDisplayCreateFormNotHttp(): void - { - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $url = 'magnet://kubuntu.torrent'; - $request = $this->createMock(Request::class); - $request - ->method('getParam') - ->willReturnCallback(function (string $key) use ($url): ?string { - return $key === 'post' ? $url : null; - }); - $response = new Response(); - - $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); - $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); - - $result = $this->controller->displayCreateForm($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('editlink', (string) $result->getBody()); - static::assertSame($url, $assignedVariables['link']['url']); - static::assertTrue($assignedVariables['link_is_new']); - } - - /** - * Test displaying bookmark create form - * When markdown formatter is enabled, the no markdown tag should be added to existing tags. - */ - public function testDisplayCreateFormWithMarkdownEnabled(): void - { - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $this->container->conf = $this->createMock(ConfigManager::class); - $this->container->conf - ->expects(static::atLeastOnce()) - ->method('get')->willReturnCallback(function (string $key): ?string { - if ($key === 'formatter') { - return 'markdown'; - } - - return $key; - }) - ; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $result = $this->controller->displayCreateForm($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('editlink', (string) $result->getBody()); - static::assertSame(['nomarkdown' => 1], $assignedVariables['tags']); - } - - /** - * Test displaying bookmark create form - * When an existing URL is submitted, we want to edit the existing link. - */ - public function testDisplayCreateFormWithExistingUrl(): void - { - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $url = 'http://url.tld/other?part=3&utm_ad=pay#hash'; - $expectedUrl = str_replace('&utm_ad=pay', '', $url); - - $request = $this->createMock(Request::class); - $request - ->method('getParam') - ->willReturnCallback(function (string $key) use ($url): ?string { - return $key === 'post' ? $url : null; - }); - $response = new Response(); - - $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); - $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); - - $this->container->bookmarkService - ->expects(static::once()) - ->method('findByUrl') - ->with($expectedUrl) - ->willReturn( - (new Bookmark()) - ->setId($id = 23) - ->setUrl($expectedUrl) - ->setTitle($title = 'Bookmark Title') - ->setDescription($description = 'Bookmark description.') - ->setTags($tags = ['abc', 'def']) - ->setPrivate(true) - ->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44')) - ) - ; - - $result = $this->controller->displayCreateForm($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('editlink', (string) $result->getBody()); - - static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']); - static::assertFalse($assignedVariables['link_is_new']); - - static::assertSame($id, $assignedVariables['link']['id']); - static::assertSame($expectedUrl, $assignedVariables['link']['url']); - static::assertSame($title, $assignedVariables['link']['title']); - static::assertSame($description, $assignedVariables['link']['description']); - static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']); - static::assertTrue($assignedVariables['link']['private']); - static::assertSame($createdAt, $assignedVariables['link']['created']); - } - - /** - * Test displaying bookmark edit form - * When an existing ID is provided, ensure that default workflow works properly. - */ - public function testDisplayEditFormDefault(): void - { - $assignedVariables = []; - $this->assignTemplateVars($assignedVariables); - - $id = 11; - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->container->httpAccess->expects(static::never())->method('getHttpResponse'); - $this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback'); - - $this->container->bookmarkService - ->expects(static::once()) - ->method('get') - ->with($id) - ->willReturn( - (new Bookmark()) - ->setId($id) - ->setUrl($url = 'http://domain.tld') - ->setTitle($title = 'Bookmark Title') - ->setDescription($description = 'Bookmark description.') - ->setTags($tags = ['abc', 'def']) - ->setPrivate(true) - ->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44')) - ) - ; - - $result = $this->controller->displayEditForm($request, $response, ['id' => (string) $id]); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('editlink', (string) $result->getBody()); - - static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']); - static::assertFalse($assignedVariables['link_is_new']); - - static::assertSame($id, $assignedVariables['link']['id']); - static::assertSame($url, $assignedVariables['link']['url']); - static::assertSame($title, $assignedVariables['link']['title']); - static::assertSame($description, $assignedVariables['link']['description']); - static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']); - static::assertTrue($assignedVariables['link']['private']); - static::assertSame($createdAt, $assignedVariables['link']['created']); - } - - /** - * Test save a new bookmark - */ - public function testSaveBookmark(): void - { - $id = 21; - $parameters = [ - 'lf_url' => 'http://url.tld/other?part=3#hash', - 'lf_title' => 'Provided Title', - 'lf_description' => 'Provided description.', - 'lf_tags' => 'abc def', - 'lf_private' => '1', - 'returnurl' => 'http://shaarli.tld/subfolder/admin/add-shaare' - ]; - - $request = $this->createMock(Request::class); - $request - ->method('getParam') - ->willReturnCallback(function (string $key) use ($parameters): ?string { - return $parameters[$key] ?? null; - }) - ; - $response = new Response(); - - $checkBookmark = function (Bookmark $bookmark) use ($parameters) { - static::assertSame($parameters['lf_url'], $bookmark->getUrl()); - static::assertSame($parameters['lf_title'], $bookmark->getTitle()); - static::assertSame($parameters['lf_description'], $bookmark->getDescription()); - static::assertSame($parameters['lf_tags'], $bookmark->getTagsString()); - static::assertTrue($bookmark->isPrivate()); - }; - - $this->container->bookmarkService - ->expects(static::once()) - ->method('addOrSet') - ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { - static::assertFalse($save); - - $checkBookmark($bookmark); - - $bookmark->setId($id); - }) - ; - $this->container->bookmarkService - ->expects(static::once()) - ->method('set') - ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { - static::assertTrue($save); - - $checkBookmark($bookmark); - - static::assertSame($id, $bookmark->getId()); - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array { - static::assertSame('save_link', $hook); - - static::assertSame($id, $data['id']); - static::assertSame($parameters['lf_url'], $data['url']); - static::assertSame($parameters['lf_title'], $data['title']); - static::assertSame($parameters['lf_description'], $data['description']); - static::assertSame($parameters['lf_tags'], $data['tags']); - static::assertTrue($data['private']); - - return $data; - }) - ; - - $result = $this->controller->save($request, $response); - - static::assertSame(302, $result->getStatusCode()); - static::assertRegExp('@/subfolder/#[\w\-]{6}@', $result->getHeader('location')[0]); - } - - - /** - * Test save an existing bookmark - */ - public function testSaveExistingBookmark(): void - { - $id = 21; - $parameters = [ - 'lf_id' => (string) $id, - 'lf_url' => 'http://url.tld/other?part=3#hash', - 'lf_title' => 'Provided Title', - 'lf_description' => 'Provided description.', - 'lf_tags' => 'abc def', - 'lf_private' => '1', - 'returnurl' => 'http://shaarli.tld/subfolder/?page=2' - ]; - - $request = $this->createMock(Request::class); - $request - ->method('getParam') - ->willReturnCallback(function (string $key) use ($parameters): ?string { - return $parameters[$key] ?? null; - }) - ; - $response = new Response(); - - $checkBookmark = function (Bookmark $bookmark) use ($parameters, $id) { - static::assertSame($id, $bookmark->getId()); - static::assertSame($parameters['lf_url'], $bookmark->getUrl()); - static::assertSame($parameters['lf_title'], $bookmark->getTitle()); - static::assertSame($parameters['lf_description'], $bookmark->getDescription()); - static::assertSame($parameters['lf_tags'], $bookmark->getTagsString()); - static::assertTrue($bookmark->isPrivate()); - }; - - $this->container->bookmarkService->expects(static::atLeastOnce())->method('exists')->willReturn(true); - $this->container->bookmarkService - ->expects(static::once()) - ->method('get') - ->willReturn((new Bookmark())->setId($id)->setUrl('http://other.url')) - ; - $this->container->bookmarkService - ->expects(static::once()) - ->method('addOrSet') - ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { - static::assertFalse($save); - - $checkBookmark($bookmark); - }) - ; - $this->container->bookmarkService - ->expects(static::once()) - ->method('set') - ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { - static::assertTrue($save); - - $checkBookmark($bookmark); - - static::assertSame($id, $bookmark->getId()); - }) - ; - - // Make sure that PluginManager hook is triggered - $this->container->pluginManager - ->expects(static::at(0)) - ->method('executeHooks') - ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array { - static::assertSame('save_link', $hook); - - static::assertSame($id, $data['id']); - static::assertSame($parameters['lf_url'], $data['url']); - static::assertSame($parameters['lf_title'], $data['title']); - static::assertSame($parameters['lf_description'], $data['description']); - static::assertSame($parameters['lf_tags'], $data['tags']); - static::assertTrue($data['private']); - - return $data; - }) - ; - - $result = $this->controller->save($request, $response); - - static::assertSame(302, $result->getStatusCode()); - static::assertRegExp('@/subfolder/\?page=2#[\w\-]{6}@', $result->getHeader('location')[0]); - } - - /** - * Test save a bookmark - try to retrieve the thumbnail - */ - public function testSaveBookmarkWithThumbnail(): void - { - $parameters = ['lf_url' => 'http://url.tld/other?part=3#hash']; - - $request = $this->createMock(Request::class); - $request - ->method('getParam') - ->willReturnCallback(function (string $key) use ($parameters): ?string { - return $parameters[$key] ?? null; - }) - ; - $response = new Response(); - - $this->container->conf = $this->createMock(ConfigManager::class); - $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) { - return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default; - }); - - $this->container->thumbnailer = $this->createMock(Thumbnailer::class); - $this->container->thumbnailer - ->expects(static::once()) - ->method('get') - ->with($parameters['lf_url']) - ->willReturn($thumb = 'http://thumb.url') - ; - - $this->container->bookmarkService - ->expects(static::once()) - ->method('addOrSet') - ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($thumb): void { - static::assertSame($thumb, $bookmark->getThumbnail()); - }) - ; - - $result = $this->controller->save($request, $response); - - static::assertSame(302, $result->getStatusCode()); - } - - /** - * Change the password with a wrong existing password - */ - public function testSaveBookmarkFromBookmarklet(): void - { - $parameters = ['source' => 'bookmarklet']; - - $request = $this->createMock(Request::class); - $request - ->method('getParam') - ->willReturnCallback(function (string $key) use ($parameters): ?string { - return $parameters[$key] ?? null; - }) - ; - $response = new Response(); - - $result = $this->controller->save($request, $response); - - static::assertSame(200, $result->getStatusCode()); - static::assertSame('', (string) $result->getBody()); - } - - /** - * Change the password with a wrong existing password - */ - public function testSaveBookmarkWrongToken(): void - { - $this->container->sessionManager = $this->createMock(SessionManager::class); - $this->container->sessionManager->method('checkToken')->willReturn(false); - - $this->container->bookmarkService->expects(static::never())->method('addOrSet'); - $this->container->bookmarkService->expects(static::never())->method('set'); - - $request = $this->createMock(Request::class); - $response = new Response(); - - $this->expectException(WrongTokenException::class); - - $this->controller->save($request, $response); - } -} -- cgit v1.2.3 From 7b8a6f2858248601d43c1b8247deb91b74392d2e Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 13 Jun 2020 19:40:32 +0200 Subject: Process change visibility action through Slim controller --- .../ChangeVisibilityBookmarkTest.php | 418 +++++++++++++++++++++ 1 file changed, 418 insertions(+) create mode 100644 tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php new file mode 100644 index 00000000..5a615791 --- /dev/null +++ b/tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php @@ -0,0 +1,418 @@ +createContainer(); + + $this->container->httpAccess = $this->createMock(HttpAccess::class); + $this->controller = new ManageShaareController($this->container); + } + + /** + * Change bookmark visibility - Set private - Single public bookmark with valid parameters + */ + public function testSetSingleBookmarkPrivate(): void + { + $parameters = ['id' => '123', 'newVisibility' => 'private']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $bookmark = (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')->setPrivate(false); + + static::assertFalse($bookmark->isPrivate()); + + $this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark); + $this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, false); + $this->container->bookmarkService->expects(static::once())->method('save'); + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->expects(static::once()) + ->method('getFormatter') + ->with('raw') + ->willReturnCallback(function () use ($bookmark): BookmarkFormatter { + return new BookmarkRawFormatter($this->container->conf, true); + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::once()) + ->method('executeHooks') + ->with('save_link') + ; + + $result = $this->controller->changeVisibility($request, $response); + + static::assertTrue($bookmark->isPrivate()); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Change bookmark visibility - Set public - Single private bookmark with valid parameters + */ + public function testSetSingleBookmarkPublic(): void + { + $parameters = ['id' => '123', 'newVisibility' => 'public']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $bookmark = (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')->setPrivate(true); + + static::assertTrue($bookmark->isPrivate()); + + $this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark); + $this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, false); + $this->container->bookmarkService->expects(static::once())->method('save'); + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->expects(static::once()) + ->method('getFormatter') + ->with('raw') + ->willReturn(new BookmarkRawFormatter($this->container->conf, true)) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::once()) + ->method('executeHooks') + ->with('save_link') + ; + + $result = $this->controller->changeVisibility($request, $response); + + static::assertFalse($bookmark->isPrivate()); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Change bookmark visibility - Set private on single already private bookmark + */ + public function testSetSinglePrivateBookmarkPrivate(): void + { + $parameters = ['id' => '123', 'newVisibility' => 'private']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $bookmark = (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')->setPrivate(true); + + static::assertTrue($bookmark->isPrivate()); + + $this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark); + $this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, false); + $this->container->bookmarkService->expects(static::once())->method('save'); + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->expects(static::once()) + ->method('getFormatter') + ->with('raw') + ->willReturn(new BookmarkRawFormatter($this->container->conf, true)) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::once()) + ->method('executeHooks') + ->with('save_link') + ; + + $result = $this->controller->changeVisibility($request, $response); + + static::assertTrue($bookmark->isPrivate()); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Change bookmark visibility - Set multiple bookmarks private + */ + public function testSetMultipleBookmarksPrivate(): void + { + $parameters = ['id' => '123 456 789', 'newVisibility' => 'private']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $bookmarks = [ + (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')->setPrivate(false), + (new Bookmark())->setId(456)->setUrl('http://domain.tld')->setTitle('Title 456')->setPrivate(true), + (new Bookmark())->setId(789)->setUrl('http://domain.tld')->setTitle('Title 789')->setPrivate(false), + ]; + + $this->container->bookmarkService + ->expects(static::exactly(3)) + ->method('get') + ->withConsecutive([123], [456], [789]) + ->willReturnOnConsecutiveCalls(...$bookmarks) + ; + $this->container->bookmarkService + ->expects(static::exactly(3)) + ->method('set') + ->withConsecutive(...array_map(function (Bookmark $bookmark): array { + return [$bookmark, false]; + }, $bookmarks)) + ; + $this->container->bookmarkService->expects(static::once())->method('save'); + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->expects(static::once()) + ->method('getFormatter') + ->with('raw') + ->willReturn(new BookmarkRawFormatter($this->container->conf, true)) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::exactly(3)) + ->method('executeHooks') + ->with('save_link') + ; + + $result = $this->controller->changeVisibility($request, $response); + + static::assertTrue($bookmarks[0]->isPrivate()); + static::assertTrue($bookmarks[1]->isPrivate()); + static::assertTrue($bookmarks[2]->isPrivate()); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Change bookmark visibility - Single bookmark not found. + */ + public function testChangeVisibilitySingleBookmarkNotFound(): void + { + $parameters = ['id' => '123', 'newVisibility' => 'private']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->willThrowException(new BookmarkNotFoundException()) + ; + $this->container->bookmarkService->expects(static::never())->method('set'); + $this->container->bookmarkService->expects(static::never())->method('save'); + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->expects(static::once()) + ->method('getFormatter') + ->with('raw') + ->willReturn(new BookmarkRawFormatter($this->container->conf, true)) + ; + + // Make sure that PluginManager hook is not triggered + $this->container->pluginManager + ->expects(static::never()) + ->method('executeHooks') + ->with('save_link') + ; + + $result = $this->controller->changeVisibility($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Change bookmark visibility - Multiple bookmarks with one not found. + */ + public function testChangeVisibilityMultipleBookmarksOneNotFound(): void + { + $parameters = ['id' => '123 456 789', 'newVisibility' => 'public']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $bookmarks = [ + (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')->setPrivate(true), + (new Bookmark())->setId(789)->setUrl('http://domain.tld')->setTitle('Title 789')->setPrivate(false), + ]; + + $this->container->bookmarkService + ->expects(static::exactly(3)) + ->method('get') + ->withConsecutive([123], [456], [789]) + ->willReturnCallback(function (int $id) use ($bookmarks): Bookmark { + if ($id === 123) { + return $bookmarks[0]; + } + if ($id === 789) { + return $bookmarks[1]; + } + throw new BookmarkNotFoundException(); + }) + ; + $this->container->bookmarkService + ->expects(static::exactly(2)) + ->method('set') + ->withConsecutive(...array_map(function (Bookmark $bookmark): array { + return [$bookmark, false]; + }, $bookmarks)) + ; + $this->container->bookmarkService->expects(static::once())->method('save'); + + // Make sure that PluginManager hook is not triggered + $this->container->pluginManager + ->expects(static::exactly(2)) + ->method('executeHooks') + ->with('save_link') + ; + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier 456 could not be found.']) + ; + + $result = $this->controller->changeVisibility($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Change bookmark visibility - Invalid ID + */ + public function testChangeVisibilityInvalidId(): void + { + $parameters = ['id' => 'nope not an ID', 'newVisibility' => 'private']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.']) + ; + + $result = $this->controller->changeVisibility($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Change bookmark visibility - Empty ID + */ + public function testChangeVisibilityEmptyId(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.']) + ; + + $result = $this->controller->changeVisibility($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Change bookmark visibility - with invalid visibility + */ + public function testChangeVisibilityWithInvalidVisibility(): void + { + $parameters = ['id' => '123', 'newVisibility' => 'invalid']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid visibility provided.']) + ; + + $result = $this->controller->changeVisibility($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } +} -- cgit v1.2.3 From 3447d888d7881eed437117a6de2450abb96f6a76 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Mon, 15 Jun 2020 08:15:40 +0200 Subject: Pin bookmarks through Slim controller --- .../ManageShaareControllerTest/PinBookmarkTest.php | 145 +++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php new file mode 100644 index 00000000..1607b475 --- /dev/null +++ b/tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php @@ -0,0 +1,145 @@ +createContainer(); + + $this->container->httpAccess = $this->createMock(HttpAccess::class); + $this->controller = new ManageShaareController($this->container); + } + + /** + * Test pin bookmark - with valid input + * + * @dataProvider initialStickyValuesProvider() + */ + public function testPinBookmarkIsStickyNull(?bool $sticky, bool $expectedValue): void + { + $id = 123; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $bookmark = (new Bookmark()) + ->setId(123) + ->setUrl('http://domain.tld') + ->setTitle('Title 123') + ->setSticky($sticky) + ; + + $this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark); + $this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, true); + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::once()) + ->method('executeHooks') + ->with('save_link') + ; + + $result = $this->controller->pinBookmark($request, $response, ['id' => (string) $id]); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + + static::assertSame($expectedValue, $bookmark->isSticky()); + } + + public function initialStickyValuesProvider(): array + { + // [initialStickyState, isStickyAfterPin] + return [[null, true], [false, true], [true, false]]; + } + + /** + * Test pin bookmark - invalid bookmark ID + */ + public function testDisplayEditFormInvalidId(): void + { + $id = 'invalid'; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier invalid could not be found.']) + ; + + $result = $this->controller->pinBookmark($request, $response, ['id' => $id]); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Test pin bookmark - Bookmark ID not provided + */ + public function testDisplayEditFormIdNotProvided(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier could not be found.']) + ; + + $result = $this->controller->pinBookmark($request, $response, []); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } + + /** + * Test pin bookmark - bookmark not found + */ + public function testDisplayEditFormBookmarkNotFound(): void + { + $id = 123; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->with($id) + ->willThrowException(new BookmarkNotFoundException()) + ; + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier 123 could not be found.']) + ; + + $result = $this->controller->pinBookmark($request, $response, ['id' => (string) $id]); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/'], $result->getHeader('location')); + } +} -- cgit v1.2.3 From e8a10f312a5c44314292402bb44e6ee2e71f3d5d Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Wed, 17 Jun 2020 15:55:31 +0200 Subject: Use NetscapeBookmarkUtils object instance instead of static calls --- tests/netscape/BookmarkExportTest.php | 65 ++++++++++++++++++++++------------- tests/netscape/BookmarkImportTest.php | 53 +++++++++++++++------------- 2 files changed, 72 insertions(+), 46 deletions(-) (limited to 'tests') diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php index 6c948bba..344c1dc0 100644 --- a/tests/netscape/BookmarkExportTest.php +++ b/tests/netscape/BookmarkExportTest.php @@ -1,11 +1,12 @@ set('resource.datastore', self::$testDatastore); - self::$refDb = new \ReferenceLinkDB(); - self::$refDb->write(self::$testDatastore); - $history = new History('sandbox/history.php'); - self::$bookmarkService = new BookmarkFileService($conf, $history, true); - $factory = new FormatterFactory($conf, true); - self::$formatter = $factory->getFormatter('raw'); + static::$conf = new ConfigManager('tests/utils/config/configJson'); + static::$conf->set('resource.datastore', static::$testDatastore); + static::$refDb = new \ReferenceLinkDB(); + static::$refDb->write(static::$testDatastore); + static::$history = new History('sandbox/history.php'); + static::$bookmarkService = new BookmarkFileService(static::$conf, static::$history, true); + $factory = new FormatterFactory(static::$conf, true); + static::$formatter = $factory->getFormatter('raw'); + } + + public function setUp(): void + { + $this->netscapeBookmarkUtils = new NetscapeBookmarkUtils( + static::$bookmarkService, + static::$conf, + static::$history + ); } /** @@ -57,8 +82,7 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase */ public function testFilterAndFormatInvalid() { - NetscapeBookmarkUtils::filterAndFormat( - self::$bookmarkService, + $this->netscapeBookmarkUtils->filterAndFormat( self::$formatter, 'derp', false, @@ -71,8 +95,7 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase */ public function testFilterAndFormatAll() { - $links = NetscapeBookmarkUtils::filterAndFormat( - self::$bookmarkService, + $links = $this->netscapeBookmarkUtils->filterAndFormat( self::$formatter, 'all', false, @@ -97,8 +120,7 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase */ public function testFilterAndFormatPrivate() { - $links = NetscapeBookmarkUtils::filterAndFormat( - self::$bookmarkService, + $links = $this->netscapeBookmarkUtils->filterAndFormat( self::$formatter, 'private', false, @@ -123,8 +145,7 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase */ public function testFilterAndFormatPublic() { - $links = NetscapeBookmarkUtils::filterAndFormat( - self::$bookmarkService, + $links = $this->netscapeBookmarkUtils->filterAndFormat( self::$formatter, 'public', false, @@ -149,8 +170,7 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase */ public function testFilterAndFormatDoNotPrependNoteUrl() { - $links = NetscapeBookmarkUtils::filterAndFormat( - self::$bookmarkService, + $links = $this->netscapeBookmarkUtils->filterAndFormat( self::$formatter, 'public', false, @@ -168,8 +188,7 @@ class BookmarkExportTest extends \PHPUnit\Framework\TestCase public function testFilterAndFormatPrependNoteUrl() { $indexUrl = 'http://localhost:7469/shaarli/'; - $links = NetscapeBookmarkUtils::filterAndFormat( - self::$bookmarkService, + $links = $this->netscapeBookmarkUtils->filterAndFormat( self::$formatter, 'public', true, diff --git a/tests/netscape/BookmarkImportTest.php b/tests/netscape/BookmarkImportTest.php index fef7f6d1..20b1c6f4 100644 --- a/tests/netscape/BookmarkImportTest.php +++ b/tests/netscape/BookmarkImportTest.php @@ -1,11 +1,12 @@ conf->set('resource.datastore', self::$testDatastore); $this->history = new History(self::$historyFilePath); $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); + $this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history); } /** @@ -115,7 +122,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertEquals( 'File empty.htm (0 bytes) has an unknown file format.' .' Nothing was imported.', - NetscapeBookmarkUtils::import(null, $files, null, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import(null, $files) ); $this->assertEquals(0, $this->bookmarkService->count()); } @@ -128,7 +135,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $files = file2array('no_doctype.htm'); $this->assertEquals( 'File no_doctype.htm (350 bytes) has an unknown file format. Nothing was imported.', - NetscapeBookmarkUtils::import(null, $files, null, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import(null, $files) ); $this->assertEquals(0, $this->bookmarkService->count()); } @@ -142,7 +149,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File lowercase_doctype.htm (386 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import(null, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import(null, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); } @@ -157,7 +164,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File internet_explorer_encoding.htm (356 bytes) was successfully processed in %d seconds:' .' 1 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import([], $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import([], $files) ); $this->assertEquals(1, $this->bookmarkService->count()); $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -185,7 +192,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_nested.htm (1337 bytes) was successfully processed in %d seconds:' .' 8 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import([], $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import([], $files) ); $this->assertEquals(8, $this->bookmarkService->count()); $this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -306,7 +313,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import([], $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import([], $files) ); $this->assertEquals(2, $this->bookmarkService->count()); @@ -349,7 +356,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import($post, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); @@ -392,7 +399,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import($post, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -410,7 +417,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import($post, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); $this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -430,7 +437,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import($post, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); $this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -445,7 +452,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 2 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import($post, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -465,7 +472,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import($post, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -480,7 +487,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 2 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import($post, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); $this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -498,7 +505,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import($post, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -508,7 +515,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 0 bookmarks imported, 0 bookmarks overwritten, 2 bookmarks skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import($post, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -527,7 +534,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import($post, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -548,7 +555,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import($post, $files) ); $this->assertEquals(2, $this->bookmarkService->count()); $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -573,7 +580,7 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase $this->assertStringMatchesFormat( 'File same_date.htm (453 bytes) was successfully processed in %d seconds:' .' 3 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.', - NetscapeBookmarkUtils::import(array(), $files, $this->bookmarkService, $this->conf, $this->history) + $this->netscapeBookmarkUtils->import(array(), $files) ); $this->assertEquals(3, $this->bookmarkService->count()); $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE)); @@ -589,14 +596,14 @@ class BookmarkImportTest extends \PHPUnit\Framework\TestCase 'overwrite' => 'true', ]; $files = file2array('netscape_basic.htm'); - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history); + $this->netscapeBookmarkUtils->import($post, $files); $history = $this->history->getHistory(); $this->assertEquals(1, count($history)); $this->assertEquals(History::IMPORT, $history[0]['event']); $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']); // re-import as private, enable overwriting - NetscapeBookmarkUtils::import($post, $files, $this->bookmarkService, $this->conf, $this->history); + $this->netscapeBookmarkUtils->import($post, $files); $history = $this->history->getHistory(); $this->assertEquals(2, count($history)); $this->assertEquals(History::IMPORT, $history[0]['event']); -- cgit v1.2.3 From c70ff64a61d62cc8d35a62f30596ecc2a3c578a3 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Wed, 17 Jun 2020 16:04:18 +0200 Subject: Process bookmark exports through Slim controllers --- .../controller/admin/ExportControllerTest.php | 167 +++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 tests/front/controller/admin/ExportControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/ExportControllerTest.php b/tests/front/controller/admin/ExportControllerTest.php new file mode 100644 index 00000000..e43a9626 --- /dev/null +++ b/tests/front/controller/admin/ExportControllerTest.php @@ -0,0 +1,167 @@ +createContainer(); + + $this->controller = new ExportController($this->container); + } + + /** + * Test displaying export page + */ + public function testIndex(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('export', (string) $result->getBody()); + + static::assertSame('Export - Shaarli', $assignedVariables['pagetitle']); + } + + /** + * Test posting an export request + */ + public function testExportDefault(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $parameters = [ + 'selection' => 'all', + 'prepend_note_url' => 'on', + ]; + + $request = $this->createMock(Request::class); + $request->method('getParam')->willReturnCallback(function (string $key) use ($parameters) { + return $parameters[$key] ?? null; + }); + $response = new Response(); + + $bookmarks = [ + (new Bookmark())->setUrl('http://link1.tld')->setTitle('Title 1'), + (new Bookmark())->setUrl('http://link2.tld')->setTitle('Title 2'), + ]; + + $this->container->netscapeBookmarkUtils = $this->createMock(NetscapeBookmarkUtils::class); + $this->container->netscapeBookmarkUtils + ->expects(static::once()) + ->method('filterAndFormat') + ->willReturnCallback( + function ( + BookmarkFormatter $formatter, + string $selection, + bool $prependNoteUrl, + string $indexUrl + ) use ($parameters, $bookmarks): array { + static::assertInstanceOf(BookmarkRawFormatter::class, $formatter); + static::assertSame($parameters['selection'], $selection); + static::assertTrue($prependNoteUrl); + static::assertSame('http://shaarli', $indexUrl); + + return $bookmarks; + } + ) + ; + + $result = $this->controller->export($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('export.bookmarks', (string) $result->getBody()); + static::assertSame(['text/html; charset=utf-8'], $result->getHeader('content-type')); + static::assertRegExp( + '/attachment; filename=bookmarks_all_[\d]{8}_[\d]{6}\.html/', + $result->getHeader('content-disposition')[0] + ); + + static::assertNotEmpty($assignedVariables['date']); + static::assertSame(PHP_EOL, $assignedVariables['eol']); + static::assertSame('all', $assignedVariables['selection']); + static::assertSame($bookmarks, $assignedVariables['links']); + } + + /** + * Test posting an export request - without selection parameter + */ + public function testExportSelectionMissing(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['Please select an export mode.']) + ; + + $result = $this->controller->export($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/admin/export'], $result->getHeader('location')); + } + + /** + * Test posting an export request - without selection parameter + */ + public function testExportErrorEncountered(): void + { + $parameters = [ + 'selection' => 'all', + ]; + + $request = $this->createMock(Request::class); + $request->method('getParam')->willReturnCallback(function (string $key) use ($parameters) { + return $parameters[$key] ?? null; + }); + $response = new Response(); + + $this->container->netscapeBookmarkUtils = $this->createMock(NetscapeBookmarkUtils::class); + $this->container->netscapeBookmarkUtils + ->expects(static::once()) + ->method('filterAndFormat') + ->willThrowException(new \Exception($message = 'error message')); + ; + + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, [$message]) + ; + + $result = $this->controller->export($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/admin/export'], $result->getHeader('location')); + } +} -- cgit v1.2.3 From 78657347c5b463d7c22bfc8c87b7db39fe058833 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Wed, 17 Jun 2020 19:08:02 +0200 Subject: Process bookmarks import through Slim controller --- .../controller/admin/ExportControllerTest.php | 6 +- .../controller/admin/ImportControllerTest.php | 148 +++++++++++++++++++++ tests/netscape/BookmarkImportTest.php | 15 ++- 3 files changed, 157 insertions(+), 12 deletions(-) create mode 100644 tests/front/controller/admin/ImportControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/ExportControllerTest.php b/tests/front/controller/admin/ExportControllerTest.php index e43a9626..50d9e378 100644 --- a/tests/front/controller/admin/ExportControllerTest.php +++ b/tests/front/controller/admin/ExportControllerTest.php @@ -2,14 +2,12 @@ declare(strict_types=1); -namespace front\controller\admin; +namespace Shaarli\Front\Controller\Admin; use PHPUnit\Framework\TestCase; use Shaarli\Bookmark\Bookmark; use Shaarli\Formatter\BookmarkFormatter; use Shaarli\Formatter\BookmarkRawFormatter; -use Shaarli\Front\Controller\Admin\ExportController; -use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper; use Shaarli\Netscape\NetscapeBookmarkUtils; use Shaarli\Security\SessionManager; use Slim\Http\Request; @@ -117,7 +115,6 @@ class ExportControllerTest extends TestCase $request = $this->createMock(Request::class); $response = new Response(); - $this->container->sessionManager = $this->createMock(SessionManager::class); $this->container->sessionManager ->expects(static::once()) ->method('setSessionParameter') @@ -152,7 +149,6 @@ class ExportControllerTest extends TestCase ->willThrowException(new \Exception($message = 'error message')); ; - $this->container->sessionManager = $this->createMock(SessionManager::class); $this->container->sessionManager ->expects(static::once()) ->method('setSessionParameter') diff --git a/tests/front/controller/admin/ImportControllerTest.php b/tests/front/controller/admin/ImportControllerTest.php new file mode 100644 index 00000000..eb31fad0 --- /dev/null +++ b/tests/front/controller/admin/ImportControllerTest.php @@ -0,0 +1,148 @@ +createContainer(); + + $this->controller = new ImportController($this->container); + } + + /** + * Test displaying import page + */ + public function testIndex(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('import', (string) $result->getBody()); + + static::assertSame('Import - Shaarli', $assignedVariables['pagetitle']); + static::assertIsInt($assignedVariables['maxfilesize']); + static::assertRegExp('/\d+[KM]iB/', $assignedVariables['maxfilesizeHuman']); + } + + /** + * Test importing a file with default and valid parameters + */ + public function testImportDefault(): void + { + $parameters = [ + 'abc' => 'def', + 'other' => 'param', + ]; + + $requestFile = new UploadedFile('file', 'name', 'type', 123); + + $request = $this->createMock(Request::class); + $request->method('getParams')->willReturnCallback(function () use ($parameters) { + return $parameters; + }); + $request->method('getUploadedFiles')->willReturn(['filetoupload' => $requestFile]); + $response = new Response(); + + $this->container->netscapeBookmarkUtils = $this->createMock(NetscapeBookmarkUtils::class); + $this->container->netscapeBookmarkUtils + ->expects(static::once()) + ->method('import') + ->willReturnCallback( + function ( + array $post, + UploadedFileInterface $file + ) use ($parameters, $requestFile): string { + static::assertSame($parameters, $post); + static::assertSame($requestFile, $file); + + return 'status'; + } + ) + ; + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_SUCCESS_MESSAGES, ['status']) + ; + + $result = $this->controller->import($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/admin/import'], $result->getHeader('location')); + } + + /** + * Test posting an import request - without import file + */ + public function testImportFileMissing(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(SessionManager::KEY_ERROR_MESSAGES, ['No import file provided.']) + ; + + $result = $this->controller->import($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/admin/import'], $result->getHeader('location')); + } + + /** + * Test posting an import request - with an empty file + */ + public function testImportEmptyFile(): void + { + $requestFile = new UploadedFile('file', 'name', 'type', 0); + + $request = $this->createMock(Request::class); + $request->method('getUploadedFiles')->willReturn(['filetoupload' => $requestFile]); + $response = new Response(); + + $this->container->netscapeBookmarkUtils = $this->createMock(NetscapeBookmarkUtils::class); + $this->container->netscapeBookmarkUtils->expects(static::never())->method('filterAndFormat'); + + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->willReturnCallback(function (string $key, array $value): SessionManager { + static::assertSame(SessionManager::KEY_ERROR_MESSAGES, $key); + static::assertStringStartsWith('The file you are trying to upload is probably bigger', $value[0]); + + return $this->container->sessionManager; + }) + ; + + $result = $this->controller->import($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/admin/import'], $result->getHeader('location')); + } +} diff --git a/tests/netscape/BookmarkImportTest.php b/tests/netscape/BookmarkImportTest.php index 20b1c6f4..f678e26b 100644 --- a/tests/netscape/BookmarkImportTest.php +++ b/tests/netscape/BookmarkImportTest.php @@ -4,27 +4,28 @@ namespace Shaarli\Netscape; use DateTime; use PHPUnit\Framework\TestCase; +use Psr\Http\Message\UploadedFileInterface; use Shaarli\Bookmark\Bookmark; use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Bookmark\BookmarkFilter; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Slim\Http\UploadedFile; /** * Utility function to load a file's metadata in a $_FILES-like array * * @param string $filename Basename of the file * - * @return array A $_FILES-like array + * @return UploadedFileInterface Upload file in PSR-7 compatible object */ function file2array($filename) { - return array( - 'filetoupload' => array( - 'name' => $filename, - 'tmp_name' => __DIR__ . '/input/' . $filename, - 'size' => filesize(__DIR__ . '/input/' . $filename) - ) + return new UploadedFile( + __DIR__ . '/input/' . $filename, + $filename, + null, + filesize(__DIR__ . '/input/' . $filename) ); } -- cgit v1.2.3 From 1b8620b1ad4e2c647ff2d032c8e7c6687b6647a1 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 20 Jun 2020 15:14:24 +0200 Subject: Process plugins administration page through Slim controllers --- .../controller/admin/PluginsControllerTest.php | 190 +++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 tests/front/controller/admin/PluginsControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/PluginsControllerTest.php b/tests/front/controller/admin/PluginsControllerTest.php new file mode 100644 index 00000000..700a0df2 --- /dev/null +++ b/tests/front/controller/admin/PluginsControllerTest.php @@ -0,0 +1,190 @@ +createContainer(); + + $this->controller = new PluginsController($this->container); + } + + /** + * Test displaying plugins admin page + */ + public function testIndex(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $data = [ + 'plugin1' => ['order' => 2, 'other' => 'field'], + 'plugin2' => ['order' => 1], + 'plugin3' => ['order' => false, 'abc' => 'def'], + 'plugin4' => [], + ]; + + $this->container->pluginManager + ->expects(static::once()) + ->method('getPluginsMeta') + ->willReturn($data); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('pluginsadmin', (string) $result->getBody()); + + static::assertSame('Plugin Administration - Shaarli', $assignedVariables['pagetitle']); + static::assertSame( + ['plugin2' => $data['plugin2'], 'plugin1' => $data['plugin1']], + $assignedVariables['enabledPlugins'] + ); + static::assertSame( + ['plugin3' => $data['plugin3'], 'plugin4' => $data['plugin4']], + $assignedVariables['disabledPlugins'] + ); + } + + /** + * Test save plugins admin page + */ + public function testSaveEnabledPlugins(): void + { + $parameters = [ + 'plugin1' => 'on', + 'order_plugin1' => '2', + 'plugin2' => 'on', + ]; + + $request = $this->createMock(Request::class); + $request + ->expects(static::atLeastOnce()) + ->method('getParams') + ->willReturnCallback(function () use ($parameters): array { + return $parameters; + }) + ; + $response = new Response(); + + $this->container->pluginManager + ->expects(static::once()) + ->method('executeHooks') + ->with('save_plugin_parameters', $parameters) + ; + $this->container->conf + ->expects(static::atLeastOnce()) + ->method('set') + ->with('general.enabled_plugins', ['plugin1', 'plugin2']) + ; + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/admin/plugins'], $result->getHeader('location')); + } + + /** + * Test save plugin parameters + */ + public function testSavePluginParameters(): void + { + $parameters = [ + 'parameters_form' => true, + 'parameter1' => 'blip', + 'parameter2' => 'blop', + ]; + + $request = $this->createMock(Request::class); + $request + ->expects(static::atLeastOnce()) + ->method('getParams') + ->willReturnCallback(function () use ($parameters): array { + return $parameters; + }) + ; + $response = new Response(); + + $this->container->pluginManager + ->expects(static::once()) + ->method('executeHooks') + ->with('save_plugin_parameters', $parameters) + ; + $this->container->conf + ->expects(static::atLeastOnce()) + ->method('set') + ->withConsecutive(['plugins.parameter1', 'blip'], ['plugins.parameter2', 'blop']) + ; + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/admin/plugins'], $result->getHeader('location')); + } + + /** + * Test save plugin parameters - error encountered + */ + public function testSaveWithError(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf + ->expects(static::atLeastOnce()) + ->method('write') + ->willThrowException(new \Exception($message = 'error message')) + ; + + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager->method('checkToken')->willReturn(true); + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with( + SessionManager::KEY_ERROR_MESSAGES, + ['ERROR while saving plugin configuration: ' . PHP_EOL . $message] + ) + ; + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/admin/plugins'], $result->getHeader('location')); + } + + /** + * Test save plugin parameters - wrong token + */ + public function testSaveWrongToken(): void + { + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager->method('checkToken')->willReturn(false); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->expectException(WrongTokenException::class); + + $this->controller->save($request, $response); + } +} -- cgit v1.2.3 From 764d34a7d347d653414e5f5c632e02499edaef04 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sun, 21 Jun 2020 12:21:31 +0200 Subject: Process token retrieve through Slim controller --- .../front/controller/admin/TokenControllerTest.php | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/front/controller/admin/TokenControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/TokenControllerTest.php b/tests/front/controller/admin/TokenControllerTest.php new file mode 100644 index 00000000..04b0c0fa --- /dev/null +++ b/tests/front/controller/admin/TokenControllerTest.php @@ -0,0 +1,41 @@ +createContainer(); + + $this->controller = new TokenController($this->container); + } + + public function testGetToken(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager + ->expects(static::once()) + ->method('generateToken') + ->willReturn($token = 'token1234') + ; + + $result = $this->controller->getToken($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame($token, (string) $result->getBody()); + } +} -- cgit v1.2.3 From 6132d64748dfc6806ed25f71d2e078a5ed29d071 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 27 Jun 2020 12:08:26 +0200 Subject: Process thumbnail synchronize page through Slim controllers --- .../controller/admin/ThumbnailsControllerTest.php | 154 +++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 tests/front/controller/admin/ThumbnailsControllerTest.php (limited to 'tests') diff --git a/tests/front/controller/admin/ThumbnailsControllerTest.php b/tests/front/controller/admin/ThumbnailsControllerTest.php new file mode 100644 index 00000000..0c0c8a83 --- /dev/null +++ b/tests/front/controller/admin/ThumbnailsControllerTest.php @@ -0,0 +1,154 @@ +createContainer(); + + $this->controller = new ThumbnailsController($this->container); + } + + /** + * Test displaying the thumbnails update page + * Note that only non-note and HTTP bookmarks should be returned. + */ + public function testIndex(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('search') + ->willReturn([ + (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'), + (new Bookmark())->setId(2)->setUrl('?abcdef')->setTitle('Note 1'), + (new Bookmark())->setId(3)->setUrl('http://url2.tld')->setTitle('Title 2'), + (new Bookmark())->setId(4)->setUrl('ftp://domain.tld', ['ftp'])->setTitle('FTP'), + ]) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('thumbnails', (string) $result->getBody()); + + static::assertSame('Thumbnails update - Shaarli', $assignedVariables['pagetitle']); + static::assertSame([1, 3], $assignedVariables['ids']); + } + + /** + * Test updating a bookmark thumbnail with valid parameters + */ + public function testAjaxUpdateValid(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $bookmark = (new Bookmark()) + ->setId($id = 123) + ->setUrl($url = 'http://url1.tld') + ->setTitle('Title 1') + ->setThumbnail(false) + ; + + $this->container->thumbnailer = $this->createMock(Thumbnailer::class); + $this->container->thumbnailer + ->expects(static::once()) + ->method('get') + ->with($url) + ->willReturn($thumb = 'http://img.tld/pic.png') + ; + + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->with($id) + ->willReturn($bookmark) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('set') + ->willReturnCallback(function (Bookmark $bookmark) use ($thumb) { + static::assertSame($thumb, $bookmark->getThumbnail()); + }) + ; + + $result = $this->controller->ajaxUpdate($request, $response, ['id' => (string) $id]); + + static::assertSame(200, $result->getStatusCode()); + + $payload = json_decode((string) $result->getBody(), true); + + static::assertSame($id, $payload['id']); + static::assertSame($url, $payload['url']); + static::assertSame($thumb, $payload['thumbnail']); + } + + /** + * Test updating a bookmark thumbnail - Invalid ID + */ + public function testAjaxUpdateInvalidId(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->ajaxUpdate($request, $response, ['id' => 'nope']); + + static::assertSame(400, $result->getStatusCode()); + } + + /** + * Test updating a bookmark thumbnail - No ID + */ + public function testAjaxUpdateNoId(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->ajaxUpdate($request, $response, []); + + static::assertSame(400, $result->getStatusCode()); + } + + /** + * Test updating a bookmark thumbnail with valid parameters + */ + public function testAjaxUpdateBookmarkNotFound(): void + { + $id = 123; + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('get') + ->with($id) + ->willThrowException(new BookmarkNotFoundException()) + ; + + $result = $this->controller->ajaxUpdate($request, $response, ['id' => (string) $id]); + + static::assertSame(404, $result->getStatusCode()); + } +} -- cgit v1.2.3 From 1a8ac737e52cb25a5c346232ee398f5908cee7d7 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Mon, 6 Jul 2020 08:04:35 +0200 Subject: Process main page (linklist) through Slim controller Including a bunch of improvements on the container, and helper used across new controllers. --- tests/RouterTest.php | 509 -------------------- tests/bookmark/BookmarkFileServiceTest.php | 20 +- tests/front/ShaarliMiddlewareTest.php | 130 +++++- .../visitor/BookmarkListControllerTest.php | 448 ++++++++++++++++++ tests/legacy/LegacyControllerTest.php | 99 ++++ tests/legacy/LegacyRouterTest.php | 512 +++++++++++++++++++++ tests/plugins/PluginAddlinkTest.php | 6 +- tests/plugins/PluginPlayvideosTest.php | 6 +- tests/plugins/PluginPubsubhubbubTest.php | 6 +- tests/plugins/PluginQrcodeTest.php | 4 +- tests/updater/UpdaterTest.php | 19 + 11 files changed, 1224 insertions(+), 535 deletions(-) delete mode 100644 tests/RouterTest.php create mode 100644 tests/front/controller/visitor/BookmarkListControllerTest.php create mode 100644 tests/legacy/LegacyControllerTest.php create mode 100644 tests/legacy/LegacyRouterTest.php (limited to 'tests') diff --git a/tests/RouterTest.php b/tests/RouterTest.php deleted file mode 100644 index 0cd49bb8..00000000 --- a/tests/RouterTest.php +++ /dev/null @@ -1,509 +0,0 @@ -assertEquals( - Router::$PAGE_LOGIN, - Router::findPage('do=login', array(), false) - ); - - $this->assertEquals( - Router::$PAGE_LOGIN, - Router::findPage('do=login', array(), 1) - ); - - $this->assertEquals( - Router::$PAGE_LOGIN, - Router::findPage('do=login&stuff', array(), false) - ); - } - - /** - * Test findPage: login page output. - * Invalid: page shouldn't be return. - * - * @return void - */ - public function testFindPageLoginInvalid() - { - $this->assertNotEquals( - Router::$PAGE_LOGIN, - Router::findPage('do=login', array(), true) - ); - - $this->assertNotEquals( - Router::$PAGE_LOGIN, - Router::findPage('do=other', array(), false) - ); - } - - /** - * Test findPage: picwall page output. - * Valid: page should be return. - * - * @return void - */ - public function testFindPagePicwallValid() - { - $this->assertEquals( - Router::$PAGE_PICWALL, - Router::findPage('do=picwall', array(), false) - ); - - $this->assertEquals( - Router::$PAGE_PICWALL, - Router::findPage('do=picwall', array(), true) - ); - } - - /** - * Test findPage: picwall page output. - * Invalid: page shouldn't be return. - * - * @return void - */ - public function testFindPagePicwallInvalid() - { - $this->assertEquals( - Router::$PAGE_PICWALL, - Router::findPage('do=picwall&stuff', array(), false) - ); - - $this->assertNotEquals( - Router::$PAGE_PICWALL, - Router::findPage('do=other', array(), false) - ); - } - - /** - * Test findPage: tagcloud page output. - * Valid: page should be return. - * - * @return void - */ - public function testFindPageTagcloudValid() - { - $this->assertEquals( - Router::$PAGE_TAGCLOUD, - Router::findPage('do=tagcloud', array(), false) - ); - - $this->assertEquals( - Router::$PAGE_TAGCLOUD, - Router::findPage('do=tagcloud', array(), true) - ); - - $this->assertEquals( - Router::$PAGE_TAGCLOUD, - Router::findPage('do=tagcloud&stuff', array(), false) - ); - } - - /** - * Test findPage: tagcloud page output. - * Invalid: page shouldn't be return. - * - * @return void - */ - public function testFindPageTagcloudInvalid() - { - $this->assertNotEquals( - Router::$PAGE_TAGCLOUD, - Router::findPage('do=other', array(), false) - ); - } - - /** - * Test findPage: linklist page output. - * Valid: page should be return. - * - * @return void - */ - public function testFindPageLinklistValid() - { - $this->assertEquals( - Router::$PAGE_LINKLIST, - Router::findPage('', array(), true) - ); - - $this->assertEquals( - Router::$PAGE_LINKLIST, - Router::findPage('whatever', array(), true) - ); - - $this->assertEquals( - Router::$PAGE_LINKLIST, - Router::findPage('whatever', array(), false) - ); - - $this->assertEquals( - Router::$PAGE_LINKLIST, - Router::findPage('do=tools', array(), false) - ); - } - - /** - * Test findPage: tools page output. - * Valid: page should be return. - * - * @return void - */ - public function testFindPageToolsValid() - { - $this->assertEquals( - Router::$PAGE_TOOLS, - Router::findPage('do=tools', array(), true) - ); - - $this->assertEquals( - Router::$PAGE_TOOLS, - Router::findPage('do=tools&stuff', array(), true) - ); - } - - /** - * Test findPage: tools page output. - * Invalid: page shouldn't be return. - * - * @return void - */ - public function testFindPageToolsInvalid() - { - $this->assertNotEquals( - Router::$PAGE_TOOLS, - Router::findPage('do=tools', array(), 1) - ); - - $this->assertNotEquals( - Router::$PAGE_TOOLS, - Router::findPage('do=tools', array(), false) - ); - - $this->assertNotEquals( - Router::$PAGE_TOOLS, - Router::findPage('do=other', array(), true) - ); - } - - /** - * Test findPage: changepasswd page output. - * Valid: page should be return. - * - * @return void - */ - public function testFindPageChangepasswdValid() - { - $this->assertEquals( - Router::$PAGE_CHANGEPASSWORD, - Router::findPage('do=changepasswd', array(), true) - ); - $this->assertEquals( - Router::$PAGE_CHANGEPASSWORD, - Router::findPage('do=changepasswd&stuff', array(), true) - ); - } - - /** - * Test findPage: changepasswd page output. - * Invalid: page shouldn't be return. - * - * @return void - */ - public function testFindPageChangepasswdInvalid() - { - $this->assertNotEquals( - Router::$PAGE_CHANGEPASSWORD, - Router::findPage('do=changepasswd', array(), 1) - ); - - $this->assertNotEquals( - Router::$PAGE_CHANGEPASSWORD, - Router::findPage('do=changepasswd', array(), false) - ); - - $this->assertNotEquals( - Router::$PAGE_CHANGEPASSWORD, - Router::findPage('do=other', array(), true) - ); - } - /** - * Test findPage: configure page output. - * Valid: page should be return. - * - * @return void - */ - public function testFindPageConfigureValid() - { - $this->assertEquals( - Router::$PAGE_CONFIGURE, - Router::findPage('do=configure', array(), true) - ); - - $this->assertEquals( - Router::$PAGE_CONFIGURE, - Router::findPage('do=configure&stuff', array(), true) - ); - } - - /** - * Test findPage: configure page output. - * Invalid: page shouldn't be return. - * - * @return void - */ - public function testFindPageConfigureInvalid() - { - $this->assertNotEquals( - Router::$PAGE_CONFIGURE, - Router::findPage('do=configure', array(), 1) - ); - - $this->assertNotEquals( - Router::$PAGE_CONFIGURE, - Router::findPage('do=configure', array(), false) - ); - - $this->assertNotEquals( - Router::$PAGE_CONFIGURE, - Router::findPage('do=other', array(), true) - ); - } - - /** - * Test findPage: changetag page output. - * Valid: page should be return. - * - * @return void - */ - public function testFindPageChangetagValid() - { - $this->assertEquals( - Router::$PAGE_CHANGETAG, - Router::findPage('do=changetag', array(), true) - ); - - $this->assertEquals( - Router::$PAGE_CHANGETAG, - Router::findPage('do=changetag&stuff', array(), true) - ); - } - - /** - * Test findPage: changetag page output. - * Invalid: page shouldn't be return. - * - * @return void - */ - public function testFindPageChangetagInvalid() - { - $this->assertNotEquals( - Router::$PAGE_CHANGETAG, - Router::findPage('do=changetag', array(), 1) - ); - - $this->assertNotEquals( - Router::$PAGE_CHANGETAG, - Router::findPage('do=changetag', array(), false) - ); - - $this->assertNotEquals( - Router::$PAGE_CHANGETAG, - Router::findPage('do=other', array(), true) - ); - } - - /** - * Test findPage: addlink page output. - * Valid: page should be return. - * - * @return void - */ - public function testFindPageAddlinkValid() - { - $this->assertEquals( - Router::$PAGE_ADDLINK, - Router::findPage('do=addlink', array(), true) - ); - - $this->assertEquals( - Router::$PAGE_ADDLINK, - Router::findPage('do=addlink&stuff', array(), true) - ); - } - - /** - * Test findPage: addlink page output. - * Invalid: page shouldn't be return. - * - * @return void - */ - public function testFindPageAddlinkInvalid() - { - $this->assertNotEquals( - Router::$PAGE_ADDLINK, - Router::findPage('do=addlink', array(), 1) - ); - - $this->assertNotEquals( - Router::$PAGE_ADDLINK, - Router::findPage('do=addlink', array(), false) - ); - - $this->assertNotEquals( - Router::$PAGE_ADDLINK, - Router::findPage('do=other', array(), true) - ); - } - - /** - * Test findPage: export page output. - * Valid: page should be return. - * - * @return void - */ - public function testFindPageExportValid() - { - $this->assertEquals( - Router::$PAGE_EXPORT, - Router::findPage('do=export', array(), true) - ); - - $this->assertEquals( - Router::$PAGE_EXPORT, - Router::findPage('do=export&stuff', array(), true) - ); - } - - /** - * Test findPage: export page output. - * Invalid: page shouldn't be return. - * - * @return void - */ - public function testFindPageExportInvalid() - { - $this->assertNotEquals( - Router::$PAGE_EXPORT, - Router::findPage('do=export', array(), 1) - ); - - $this->assertNotEquals( - Router::$PAGE_EXPORT, - Router::findPage('do=export', array(), false) - ); - - $this->assertNotEquals( - Router::$PAGE_EXPORT, - Router::findPage('do=other', array(), true) - ); - } - - /** - * Test findPage: import page output. - * Valid: page should be return. - * - * @return void - */ - public function testFindPageImportValid() - { - $this->assertEquals( - Router::$PAGE_IMPORT, - Router::findPage('do=import', array(), true) - ); - - $this->assertEquals( - Router::$PAGE_IMPORT, - Router::findPage('do=import&stuff', array(), true) - ); - } - - /** - * Test findPage: import page output. - * Invalid: page shouldn't be return. - * - * @return void - */ - public function testFindPageImportInvalid() - { - $this->assertNotEquals( - Router::$PAGE_IMPORT, - Router::findPage('do=import', array(), 1) - ); - - $this->assertNotEquals( - Router::$PAGE_IMPORT, - Router::findPage('do=import', array(), false) - ); - - $this->assertNotEquals( - Router::$PAGE_IMPORT, - Router::findPage('do=other', array(), true) - ); - } - - /** - * Test findPage: editlink page output. - * Valid: page should be return. - * - * @return void - */ - public function testFindPageEditlinkValid() - { - $this->assertEquals( - Router::$PAGE_EDITLINK, - Router::findPage('whatever', array('edit_link' => 1), true) - ); - - $this->assertEquals( - Router::$PAGE_EDITLINK, - Router::findPage('', array('edit_link' => 1), true) - ); - - - $this->assertEquals( - Router::$PAGE_EDITLINK, - Router::findPage('whatever', array('post' => 1), true) - ); - - $this->assertEquals( - Router::$PAGE_EDITLINK, - Router::findPage('whatever', array('post' => 1, 'edit_link' => 1), true) - ); - } - - /** - * Test findPage: editlink page output. - * Invalid: page shouldn't be return. - * - * @return void - */ - public function testFindPageEditlinkInvalid() - { - $this->assertNotEquals( - Router::$PAGE_EDITLINK, - Router::findPage('whatever', array('edit_link' => 1), false) - ); - - $this->assertNotEquals( - Router::$PAGE_EDITLINK, - Router::findPage('whatever', array('edit_link' => 1), 1) - ); - - $this->assertNotEquals( - Router::$PAGE_EDITLINK, - Router::findPage('whatever', array(), true) - ); - } -} diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php index 5adc26aa..b19c8250 100644 --- a/tests/bookmark/BookmarkFileServiceTest.php +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -892,35 +892,35 @@ class BookmarkFileServiceTest extends TestCase public function testFilterHashValid() { $request = smallHash('20150310_114651'); - $this->assertEquals( - 1, - count($this->publicLinkDB->findByHash($request)) + $this->assertSame( + $request, + $this->publicLinkDB->findByHash($request)->getShortUrl() ); $request = smallHash('20150310_114633' . 8); - $this->assertEquals( - 1, - count($this->publicLinkDB->findByHash($request)) + $this->assertSame( + $request, + $this->publicLinkDB->findByHash($request)->getShortUrl() ); } /** * Test filterHash() with an invalid smallhash. - * - * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException */ public function testFilterHashInValid1() { + $this->expectException(BookmarkNotFoundException::class); + $request = 'blabla'; $this->publicLinkDB->findByHash($request); } /** * Test filterHash() with an empty smallhash. - * - * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException */ public function testFilterHashInValid() { + $this->expectException(BookmarkNotFoundException::class); + $this->publicLinkDB->findByHash(''); } diff --git a/tests/front/ShaarliMiddlewareTest.php b/tests/front/ShaarliMiddlewareTest.php index 57be1002..81ea1344 100644 --- a/tests/front/ShaarliMiddlewareTest.php +++ b/tests/front/ShaarliMiddlewareTest.php @@ -8,7 +8,11 @@ use PHPUnit\Framework\TestCase; use Shaarli\Config\ConfigManager; use Shaarli\Container\ShaarliContainer; use Shaarli\Front\Exception\LoginBannedException; +use Shaarli\Front\Exception\UnauthorizedException; use Shaarli\Render\PageBuilder; +use Shaarli\Render\PageCacheManager; +use Shaarli\Security\LoginManager; +use Shaarli\Updater\Updater; use Slim\Http\Request; use Slim\Http\Response; use Slim\Http\Uri; @@ -24,9 +28,16 @@ class ShaarliMiddlewareTest extends TestCase public function setUp(): void { $this->container = $this->createMock(ShaarliContainer::class); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->loginManager = $this->createMock(LoginManager::class); + $this->middleware = new ShaarliMiddleware($this->container); } + /** + * Test middleware execution with valid controller call + */ public function testMiddlewareExecution(): void { $request = $this->createMock(Request::class); @@ -49,7 +60,10 @@ class ShaarliMiddlewareTest extends TestCase static::assertSame(418, $result->getStatusCode()); } - public function testMiddlewareExecutionWithException(): void + /** + * Test middleware execution with controller throwing a known front exception + */ + public function testMiddlewareExecutionWithFrontException(): void { $request = $this->createMock(Request::class); $request->method('getUri')->willReturnCallback(function (): Uri { @@ -58,7 +72,7 @@ class ShaarliMiddlewareTest extends TestCase return $uri; }); - + $response = new Response(); $controller = function (): void { $exception = new LoginBannedException(); @@ -72,9 +86,6 @@ class ShaarliMiddlewareTest extends TestCase }); $this->container->pageBuilder = $pageBuilder; - $conf = $this->createMock(ConfigManager::class); - $this->container->conf = $conf; - /** @var Response $result */ $result = $this->middleware->__invoke($request, $response, $controller); @@ -82,4 +93,113 @@ class ShaarliMiddlewareTest extends TestCase static::assertSame(401, $result->getStatusCode()); static::assertContains('error', (string) $result->getBody()); } + + /** + * Test middleware execution with controller throwing a not authorized exception + */ + public function testMiddlewareExecutionWithUnauthorizedException(): void + { + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + + $response = new Response(); + $controller = function (): void { + throw new UnauthorizedException(); + }; + + /** @var Response $result */ + $result = $this->middleware->__invoke($request, $response, $controller); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame('/subfolder/login', $result->getHeader('location')[0]); + } + + /** + * Test middleware execution with controller throwing a not authorized exception + */ + public function testMiddlewareExecutionWithServerExceptionWith(): void + { + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + + $response = new Response(); + $controller = function (): void { + throw new \Exception(); + }; + + $parameters = []; + $this->container->pageBuilder = $this->createMock(PageBuilder::class); + $this->container->pageBuilder->method('render')->willReturnCallback(function (string $message): string { + return $message; + }); + $this->container->pageBuilder + ->method('assign') + ->willReturnCallback(function (string $key, string $value) use (&$parameters): void { + $parameters[$key] = $value; + }) + ; + + /** @var Response $result */ + $result = $this->middleware->__invoke($request, $response, $controller); + + static::assertSame(500, $result->getStatusCode()); + static::assertContains('error', (string) $result->getBody()); + static::assertSame('An unexpected error occurred.', $parameters['message']); + } + + public function testMiddlewareExecutionWithUpdates(): void + { + $request = $this->createMock(Request::class); + $request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + + $response = new Response(); + $controller = function (Request $request, Response $response): Response { + return $response->withStatus(418); // I'm a tea pot + }; + + $this->container->loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->willReturnCallback(function (string $key): string { + return $key; + }); + + $this->container->pageCacheManager = $this->createMock(PageCacheManager::class); + $this->container->pageCacheManager->expects(static::once())->method('invalidateCaches'); + + $this->container->updater = $this->createMock(Updater::class); + $this->container->updater + ->expects(static::once()) + ->method('update') + ->willReturn(['update123']) + ; + $this->container->updater->method('getDoneUpdates')->willReturn($updates = ['update123', 'other']); + $this->container->updater + ->expects(static::once()) + ->method('writeUpdates') + ->with('resource.updates', $updates) + ; + + /** @var Response $result */ + $result = $this->middleware->__invoke($request, $response, $controller); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(418, $result->getStatusCode()); + } } diff --git a/tests/front/controller/visitor/BookmarkListControllerTest.php b/tests/front/controller/visitor/BookmarkListControllerTest.php new file mode 100644 index 00000000..5daaa2c4 --- /dev/null +++ b/tests/front/controller/visitor/BookmarkListControllerTest.php @@ -0,0 +1,448 @@ +createContainer(); + + $this->controller = new BookmarkListController($this->container); + } + + /** + * Test rendering list of bookmarks with default parameters (first page). + */ + public function testIndexDefaultFirstPage(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('search') + ->with( + ['searchtags' => '', 'searchterm' => ''], + null, + false, + false + ) + ->willReturn([ + (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'), + (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'), + (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'), + ] + ); + + $this->container->sessionManager + ->method('getSessionParameter') + ->willReturnCallback(function (string $parameter, $default = null) { + if ('LINKS_PER_PAGE' === $parameter) { + return 2; + } + + return $default; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('linklist', (string) $result->getBody()); + + static::assertSame('Shaarli', $assignedVariables['pagetitle']); + static::assertSame('?page=2', $assignedVariables['previous_page_url']); + static::assertSame('', $assignedVariables['next_page_url']); + static::assertSame(2, $assignedVariables['page_max']); + static::assertSame('', $assignedVariables['search_tags']); + static::assertSame(3, $assignedVariables['result_count']); + static::assertSame(1, $assignedVariables['page_current']); + static::assertSame('', $assignedVariables['search_term']); + static::assertNull($assignedVariables['visibility']); + static::assertCount(2, $assignedVariables['links']); + + $link = $assignedVariables['links'][0]; + + static::assertSame(1, $link['id']); + static::assertSame('http://url1.tld', $link['url']); + static::assertSame('Title 1', $link['title']); + + $link = $assignedVariables['links'][1]; + + static::assertSame(2, $link['id']); + static::assertSame('http://url2.tld', $link['url']); + static::assertSame('Title 2', $link['title']); + } + + /** + * Test rendering list of bookmarks with default parameters (second page). + */ + public function testIndexDefaultSecondPage(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $request->method('getParam')->willReturnCallback(function (string $key) { + if ('page' === $key) { + return '2'; + } + + return null; + }); + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('search') + ->with( + ['searchtags' => '', 'searchterm' => ''], + null, + false, + false + ) + ->willReturn([ + (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'), + (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'), + (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'), + ]) + ; + + $this->container->sessionManager + ->method('getSessionParameter') + ->willReturnCallback(function (string $parameter, $default = null) { + if ('LINKS_PER_PAGE' === $parameter) { + return 2; + } + + return $default; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('linklist', (string) $result->getBody()); + + static::assertSame('Shaarli', $assignedVariables['pagetitle']); + static::assertSame('', $assignedVariables['previous_page_url']); + static::assertSame('?page=1', $assignedVariables['next_page_url']); + static::assertSame(2, $assignedVariables['page_max']); + static::assertSame('', $assignedVariables['search_tags']); + static::assertSame(3, $assignedVariables['result_count']); + static::assertSame(2, $assignedVariables['page_current']); + static::assertSame('', $assignedVariables['search_term']); + static::assertNull($assignedVariables['visibility']); + static::assertCount(1, $assignedVariables['links']); + + $link = $assignedVariables['links'][2]; + + static::assertSame(3, $link['id']); + static::assertSame('http://url3.tld', $link['url']); + static::assertSame('Title 3', $link['title']); + } + + /** + * Test rendering list of bookmarks with filters. + */ + public function testIndexDefaultWithFilters(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $request->method('getParam')->willReturnCallback(function (string $key) { + if ('searchtags' === $key) { + return 'abc def'; + } + if ('searchterm' === $key) { + return 'ghi jkl'; + } + + return null; + }); + $response = new Response(); + + $this->container->sessionManager + ->method('getSessionParameter') + ->willReturnCallback(function (string $key, $default) { + if ('LINKS_PER_PAGE' === $key) { + return 2; + } + if ('visibility' === $key) { + return 'private'; + } + if ('untaggedonly' === $key) { + return true; + } + + return $default; + }) + ; + + $this->container->bookmarkService + ->expects(static::once()) + ->method('search') + ->with( + ['searchtags' => 'abc def', 'searchterm' => 'ghi jkl'], + 'private', + false, + true + ) + ->willReturn([ + (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'), + (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'), + (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'), + ]) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('linklist', (string) $result->getBody()); + + static::assertSame('Search: ghi jkl [abc] [def] - Shaarli', $assignedVariables['pagetitle']); + static::assertSame('?page=2&searchterm=ghi+jkl&searchtags=abc+def', $assignedVariables['previous_page_url']); + } + + /** + * Test displaying a permalink with valid parameters + */ + public function testPermalinkValid(): void + { + $hash = 'abcdef'; + + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('findByHash') + ->with($hash) + ->willReturn((new Bookmark())->setId(123)->setTitle('Title 1')->setUrl('http://url1.tld')) + ; + + $result = $this->controller->permalink($request, $response, ['hash' => $hash]); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('linklist', (string) $result->getBody()); + + static::assertSame('Title 1 - Shaarli', $assignedVariables['pagetitle']); + static::assertCount(1, $assignedVariables['links']); + + $link = $assignedVariables['links'][0]; + + static::assertSame(123, $link['id']); + static::assertSame('http://url1.tld', $link['url']); + static::assertSame('Title 1', $link['title']); + } + + /** + * Test displaying a permalink with an unknown small hash : renders a 404 template error + */ + public function testPermalinkNotFound(): void + { + $hash = 'abcdef'; + + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('findByHash') + ->with($hash) + ->willThrowException(new BookmarkNotFoundException()) + ; + + $result = $this->controller->permalink($request, $response, ['hash' => $hash]); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('404', (string) $result->getBody()); + + static::assertSame( + 'The link you are trying to reach does not exist or has been deleted.', + $assignedVariables['error_message'] + ); + } + + /** + * Test getting link list with thumbnail updates. + * -> 2 thumbnails update, only 1 datastore write + */ + public function testThumbnailUpdateFromLinkList(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf + ->method('get') + ->willReturnCallback(function (string $key, $default) { + return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default; + }) + ; + + $this->container->thumbnailer = $this->createMock(Thumbnailer::class); + $this->container->thumbnailer + ->expects(static::exactly(2)) + ->method('get') + ->withConsecutive(['https://url2.tld'], ['https://url4.tld']) + ; + + $this->container->bookmarkService + ->expects(static::once()) + ->method('search') + ->willReturn([ + (new Bookmark())->setId(1)->setUrl('https://url1.tld')->setTitle('Title 1')->setThumbnail(false), + $b1 = (new Bookmark())->setId(2)->setUrl('https://url2.tld')->setTitle('Title 2'), + (new Bookmark())->setId(3)->setUrl('https://url3.tld')->setTitle('Title 3')->setThumbnail(false), + $b2 = (new Bookmark())->setId(2)->setUrl('https://url4.tld')->setTitle('Title 4'), + (new Bookmark())->setId(2)->setUrl('ftp://url5.tld', ['ftp'])->setTitle('Title 5'), + ]) + ; + $this->container->bookmarkService + ->expects(static::exactly(2)) + ->method('set') + ->withConsecutive([$b1, false], [$b2, false]) + ; + $this->container->bookmarkService->expects(static::once())->method('save'); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('linklist', (string) $result->getBody()); + } + + /** + * Test getting a permalink with thumbnail update. + */ + public function testThumbnailUpdateFromPermalink(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf + ->method('get') + ->willReturnCallback(function (string $key, $default) { + return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default; + }) + ; + + $this->container->thumbnailer = $this->createMock(Thumbnailer::class); + $this->container->thumbnailer->expects(static::once())->method('get')->withConsecutive(['https://url.tld']); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('findByHash') + ->willReturn($bookmark = (new Bookmark())->setId(2)->setUrl('https://url.tld')->setTitle('Title 1')) + ; + $this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, true); + $this->container->bookmarkService->expects(static::never())->method('save'); + + $result = $this->controller->permalink($request, $response, ['hash' => 'abc']); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('linklist', (string) $result->getBody()); + } + + /** + * Trigger legacy controller in link list controller: permalink + */ + public function testLegacyControllerPermalink(): void + { + $hash = 'abcdef'; + $this->container->environment['QUERY_STRING'] = $hash; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->index($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame('/subfolder/shaare/' . $hash, $result->getHeader('location')[0]); + } + + /** + * Trigger legacy controller in link list controller: ?do= query parameter + */ + public function testLegacyControllerDoPage(): void + { + $request = $this->createMock(Request::class); + $request->method('getQueryParam')->with('do')->willReturn('picwall'); + $response = new Response(); + + $result = $this->controller->index($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame('/subfolder/picture-wall', $result->getHeader('location')[0]); + } + + /** + * Trigger legacy controller in link list controller: ?do= query parameter with unknown legacy route + */ + public function testLegacyControllerUnknownDoPage(): void + { + $request = $this->createMock(Request::class); + $request->method('getQueryParam')->with('do')->willReturn('nope'); + $response = new Response(); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('linklist', (string) $result->getBody()); + } + + /** + * Trigger legacy controller in link list controller: other GET route (e.g. ?post) + */ + public function testLegacyControllerGetParameter(): void + { + $request = $this->createMock(Request::class); + $request->method('getQueryParams')->willReturn(['post' => $url = 'http://url.tld']); + $response = new Response(); + + $this->container->loginManager = $this->createMock(LoginManager::class); + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + + $result = $this->controller->index($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame( + '/subfolder/admin/shaare?post=' . urlencode($url), + $result->getHeader('location')[0] + ); + } +} diff --git a/tests/legacy/LegacyControllerTest.php b/tests/legacy/LegacyControllerTest.php new file mode 100644 index 00000000..ff4520a3 --- /dev/null +++ b/tests/legacy/LegacyControllerTest.php @@ -0,0 +1,99 @@ +createContainer(); + + $this->controller = new LegacyController($this->container); + } + + /** + * @dataProvider getProcessProvider + */ + public function testProcess(string $legacyRoute, array $queryParameters, string $slimRoute, bool $isLoggedIn): void + { + $request = $this->createMock(Request::class); + $request->method('getQueryParams')->willReturn($queryParameters); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($queryParameters): ?string { + return $queryParameters[$key] ?? null; + }) + ; + $response = new Response(); + + $this->container->loginManager->method('isLoggedIn')->willReturn($isLoggedIn); + + $result = $this->controller->process($request, $response, $legacyRoute); + + static::assertSame('/subfolder' . $slimRoute, $result->getHeader('location')[0]); + } + + public function testProcessNotFound(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->expectException(UnknowLegacyRouteException::class); + + $this->controller->process($request, $response, 'nope'); + } + + /** + * @return array[] Parameters: + * - string legacyRoute + * - array queryParameters + * - string slimRoute + * - bool isLoggedIn + */ + public function getProcessProvider(): array + { + return [ + ['post', [], '/admin/shaare', true], + ['post', [], '/login', false], + ['post', ['title' => 'test'], '/admin/shaare?title=test', true], + ['post', ['title' => 'test'], '/login?title=test', false], + ['addlink', [], '/admin/add-shaare', true], + ['addlink', [], '/login', false], + ['login', [], '/login', true], + ['login', [], '/login', false], + ['logout', [], '/logout', true], + ['logout', [], '/logout', false], + ['picwall', [], '/picture-wall', false], + ['picwall', [], '/picture-wall', true], + ['tagcloud', [], '/tags/cloud', false], + ['tagcloud', [], '/tags/cloud', true], + ['taglist', [], '/tags/list', false], + ['taglist', [], '/tags/list', true], + ['daily', [], '/daily', false], + ['daily', [], '/daily', true], + ['daily', ['day' => '123456789', 'discard' => '1'], '/daily?day=123456789', false], + ['rss', [], '/feed/rss', false], + ['rss', [], '/feed/rss', true], + ['rss', ['search' => 'filter123', 'other' => 'param'], '/feed/rss?search=filter123&other=param', false], + ['atom', [], '/feed/atom', false], + ['atom', [], '/feed/atom', true], + ['atom', ['search' => 'filter123', 'other' => 'param'], '/feed/atom?search=filter123&other=param', false], + ['opensearch', [], '/open-search', false], + ['opensearch', [], '/open-search', true], + ['dailyrss', [], '/daily-rss', false], + ['dailyrss', [], '/daily-rss', true], + ]; + } +} diff --git a/tests/legacy/LegacyRouterTest.php b/tests/legacy/LegacyRouterTest.php new file mode 100644 index 00000000..c2019ca7 --- /dev/null +++ b/tests/legacy/LegacyRouterTest.php @@ -0,0 +1,512 @@ +assertEquals( + LegacyRouter::$PAGE_LOGIN, + LegacyRouter::findPage('do=login', array(), false) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_LOGIN, + LegacyRouter::findPage('do=login', array(), 1) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_LOGIN, + LegacyRouter::findPage('do=login&stuff', array(), false) + ); + } + + /** + * Test findPage: login page output. + * Invalid: page shouldn't be return. + * + * @return void + */ + public function testFindPageLoginInvalid() + { + $this->assertNotEquals( + LegacyRouter::$PAGE_LOGIN, + LegacyRouter::findPage('do=login', array(), true) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_LOGIN, + LegacyRouter::findPage('do=other', array(), false) + ); + } + + /** + * Test findPage: picwall page output. + * Valid: page should be return. + * + * @return void + */ + public function testFindPagePicwallValid() + { + $this->assertEquals( + LegacyRouter::$PAGE_PICWALL, + LegacyRouter::findPage('do=picwall', array(), false) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_PICWALL, + LegacyRouter::findPage('do=picwall', array(), true) + ); + } + + /** + * Test findPage: picwall page output. + * Invalid: page shouldn't be return. + * + * @return void + */ + public function testFindPagePicwallInvalid() + { + $this->assertEquals( + LegacyRouter::$PAGE_PICWALL, + LegacyRouter::findPage('do=picwall&stuff', array(), false) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_PICWALL, + LegacyRouter::findPage('do=other', array(), false) + ); + } + + /** + * Test findPage: tagcloud page output. + * Valid: page should be return. + * + * @return void + */ + public function testFindPageTagcloudValid() + { + $this->assertEquals( + LegacyRouter::$PAGE_TAGCLOUD, + LegacyRouter::findPage('do=tagcloud', array(), false) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_TAGCLOUD, + LegacyRouter::findPage('do=tagcloud', array(), true) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_TAGCLOUD, + LegacyRouter::findPage('do=tagcloud&stuff', array(), false) + ); + } + + /** + * Test findPage: tagcloud page output. + * Invalid: page shouldn't be return. + * + * @return void + */ + public function testFindPageTagcloudInvalid() + { + $this->assertNotEquals( + LegacyRouter::$PAGE_TAGCLOUD, + LegacyRouter::findPage('do=other', array(), false) + ); + } + + /** + * Test findPage: linklist page output. + * Valid: page should be return. + * + * @return void + */ + public function testFindPageLinklistValid() + { + $this->assertEquals( + LegacyRouter::$PAGE_LINKLIST, + LegacyRouter::findPage('', array(), true) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_LINKLIST, + LegacyRouter::findPage('whatever', array(), true) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_LINKLIST, + LegacyRouter::findPage('whatever', array(), false) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_LINKLIST, + LegacyRouter::findPage('do=tools', array(), false) + ); + } + + /** + * Test findPage: tools page output. + * Valid: page should be return. + * + * @return void + */ + public function testFindPageToolsValid() + { + $this->assertEquals( + LegacyRouter::$PAGE_TOOLS, + LegacyRouter::findPage('do=tools', array(), true) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_TOOLS, + LegacyRouter::findPage('do=tools&stuff', array(), true) + ); + } + + /** + * Test findPage: tools page output. + * Invalid: page shouldn't be return. + * + * @return void + */ + public function testFindPageToolsInvalid() + { + $this->assertNotEquals( + LegacyRouter::$PAGE_TOOLS, + LegacyRouter::findPage('do=tools', array(), 1) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_TOOLS, + LegacyRouter::findPage('do=tools', array(), false) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_TOOLS, + LegacyRouter::findPage('do=other', array(), true) + ); + } + + /** + * Test findPage: changepasswd page output. + * Valid: page should be return. + * + * @return void + */ + public function testFindPageChangepasswdValid() + { + $this->assertEquals( + LegacyRouter::$PAGE_CHANGEPASSWORD, + LegacyRouter::findPage('do=changepasswd', array(), true) + ); + $this->assertEquals( + LegacyRouter::$PAGE_CHANGEPASSWORD, + LegacyRouter::findPage('do=changepasswd&stuff', array(), true) + ); + } + + /** + * Test findPage: changepasswd page output. + * Invalid: page shouldn't be return. + * + * @return void + */ + public function testFindPageChangepasswdInvalid() + { + $this->assertNotEquals( + LegacyRouter::$PAGE_CHANGEPASSWORD, + LegacyRouter::findPage('do=changepasswd', array(), 1) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_CHANGEPASSWORD, + LegacyRouter::findPage('do=changepasswd', array(), false) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_CHANGEPASSWORD, + LegacyRouter::findPage('do=other', array(), true) + ); + } + /** + * Test findPage: configure page output. + * Valid: page should be return. + * + * @return void + */ + public function testFindPageConfigureValid() + { + $this->assertEquals( + LegacyRouter::$PAGE_CONFIGURE, + LegacyRouter::findPage('do=configure', array(), true) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_CONFIGURE, + LegacyRouter::findPage('do=configure&stuff', array(), true) + ); + } + + /** + * Test findPage: configure page output. + * Invalid: page shouldn't be return. + * + * @return void + */ + public function testFindPageConfigureInvalid() + { + $this->assertNotEquals( + LegacyRouter::$PAGE_CONFIGURE, + LegacyRouter::findPage('do=configure', array(), 1) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_CONFIGURE, + LegacyRouter::findPage('do=configure', array(), false) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_CONFIGURE, + LegacyRouter::findPage('do=other', array(), true) + ); + } + + /** + * Test findPage: changetag page output. + * Valid: page should be return. + * + * @return void + */ + public function testFindPageChangetagValid() + { + $this->assertEquals( + LegacyRouter::$PAGE_CHANGETAG, + LegacyRouter::findPage('do=changetag', array(), true) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_CHANGETAG, + LegacyRouter::findPage('do=changetag&stuff', array(), true) + ); + } + + /** + * Test findPage: changetag page output. + * Invalid: page shouldn't be return. + * + * @return void + */ + public function testFindPageChangetagInvalid() + { + $this->assertNotEquals( + LegacyRouter::$PAGE_CHANGETAG, + LegacyRouter::findPage('do=changetag', array(), 1) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_CHANGETAG, + LegacyRouter::findPage('do=changetag', array(), false) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_CHANGETAG, + LegacyRouter::findPage('do=other', array(), true) + ); + } + + /** + * Test findPage: addlink page output. + * Valid: page should be return. + * + * @return void + */ + public function testFindPageAddlinkValid() + { + $this->assertEquals( + LegacyRouter::$PAGE_ADDLINK, + LegacyRouter::findPage('do=addlink', array(), true) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_ADDLINK, + LegacyRouter::findPage('do=addlink&stuff', array(), true) + ); + } + + /** + * Test findPage: addlink page output. + * Invalid: page shouldn't be return. + * + * @return void + */ + public function testFindPageAddlinkInvalid() + { + $this->assertNotEquals( + LegacyRouter::$PAGE_ADDLINK, + LegacyRouter::findPage('do=addlink', array(), 1) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_ADDLINK, + LegacyRouter::findPage('do=addlink', array(), false) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_ADDLINK, + LegacyRouter::findPage('do=other', array(), true) + ); + } + + /** + * Test findPage: export page output. + * Valid: page should be return. + * + * @return void + */ + public function testFindPageExportValid() + { + $this->assertEquals( + LegacyRouter::$PAGE_EXPORT, + LegacyRouter::findPage('do=export', array(), true) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_EXPORT, + LegacyRouter::findPage('do=export&stuff', array(), true) + ); + } + + /** + * Test findPage: export page output. + * Invalid: page shouldn't be return. + * + * @return void + */ + public function testFindPageExportInvalid() + { + $this->assertNotEquals( + LegacyRouter::$PAGE_EXPORT, + LegacyRouter::findPage('do=export', array(), 1) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_EXPORT, + LegacyRouter::findPage('do=export', array(), false) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_EXPORT, + LegacyRouter::findPage('do=other', array(), true) + ); + } + + /** + * Test findPage: import page output. + * Valid: page should be return. + * + * @return void + */ + public function testFindPageImportValid() + { + $this->assertEquals( + LegacyRouter::$PAGE_IMPORT, + LegacyRouter::findPage('do=import', array(), true) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_IMPORT, + LegacyRouter::findPage('do=import&stuff', array(), true) + ); + } + + /** + * Test findPage: import page output. + * Invalid: page shouldn't be return. + * + * @return void + */ + public function testFindPageImportInvalid() + { + $this->assertNotEquals( + LegacyRouter::$PAGE_IMPORT, + LegacyRouter::findPage('do=import', array(), 1) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_IMPORT, + LegacyRouter::findPage('do=import', array(), false) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_IMPORT, + LegacyRouter::findPage('do=other', array(), true) + ); + } + + /** + * Test findPage: editlink page output. + * Valid: page should be return. + * + * @return void + */ + public function testFindPageEditlinkValid() + { + $this->assertEquals( + LegacyRouter::$PAGE_EDITLINK, + LegacyRouter::findPage('whatever', array('edit_link' => 1), true) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_EDITLINK, + LegacyRouter::findPage('', array('edit_link' => 1), true) + ); + + + $this->assertEquals( + LegacyRouter::$PAGE_EDITLINK, + LegacyRouter::findPage('whatever', array('post' => 1), true) + ); + + $this->assertEquals( + LegacyRouter::$PAGE_EDITLINK, + LegacyRouter::findPage('whatever', array('post' => 1, 'edit_link' => 1), true) + ); + } + + /** + * Test findPage: editlink page output. + * Invalid: page shouldn't be return. + * + * @return void + */ + public function testFindPageEditlinkInvalid() + { + $this->assertNotEquals( + LegacyRouter::$PAGE_EDITLINK, + LegacyRouter::findPage('whatever', array('edit_link' => 1), false) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_EDITLINK, + LegacyRouter::findPage('whatever', array('edit_link' => 1), 1) + ); + + $this->assertNotEquals( + LegacyRouter::$PAGE_EDITLINK, + LegacyRouter::findPage('whatever', array(), true) + ); + } +} diff --git a/tests/plugins/PluginAddlinkTest.php b/tests/plugins/PluginAddlinkTest.php index d052f8b9..4018c1a8 100644 --- a/tests/plugins/PluginAddlinkTest.php +++ b/tests/plugins/PluginAddlinkTest.php @@ -2,7 +2,7 @@ namespace Shaarli\Plugin\Addlink; use Shaarli\Plugin\PluginManager; -use Shaarli\Router; +use Shaarli\Render\TemplatePage; require_once 'plugins/addlink_toolbar/addlink_toolbar.php'; @@ -26,7 +26,7 @@ class PluginAddlinkTest extends \PHPUnit\Framework\TestCase { $str = 'stuff'; $data = array($str => $str); - $data['_PAGE_'] = Router::$PAGE_LINKLIST; + $data['_PAGE_'] = TemplatePage::LINKLIST; $data['_LOGGEDIN_'] = true; $data = hook_addlink_toolbar_render_header($data); @@ -48,7 +48,7 @@ class PluginAddlinkTest extends \PHPUnit\Framework\TestCase { $str = 'stuff'; $data = array($str => $str); - $data['_PAGE_'] = Router::$PAGE_LINKLIST; + $data['_PAGE_'] = TemplatePage::LINKLIST; $data['_LOGGEDIN_'] = false; $data = hook_addlink_toolbar_render_header($data); diff --git a/tests/plugins/PluginPlayvideosTest.php b/tests/plugins/PluginPlayvideosTest.php index 51472617..b7b6ce53 100644 --- a/tests/plugins/PluginPlayvideosTest.php +++ b/tests/plugins/PluginPlayvideosTest.php @@ -6,7 +6,7 @@ namespace Shaarli\Plugin\Playvideos; */ use Shaarli\Plugin\PluginManager; -use Shaarli\Router; +use Shaarli\Render\TemplatePage; require_once 'plugins/playvideos/playvideos.php'; @@ -31,7 +31,7 @@ class PluginPlayvideosTest extends \PHPUnit\Framework\TestCase { $str = 'stuff'; $data = array($str => $str); - $data['_PAGE_'] = Router::$PAGE_LINKLIST; + $data['_PAGE_'] = TemplatePage::LINKLIST; $data = hook_playvideos_render_header($data); $this->assertEquals($str, $data[$str]); @@ -50,7 +50,7 @@ class PluginPlayvideosTest extends \PHPUnit\Framework\TestCase { $str = 'stuff'; $data = array($str => $str); - $data['_PAGE_'] = Router::$PAGE_LINKLIST; + $data['_PAGE_'] = TemplatePage::LINKLIST; $data = hook_playvideos_render_footer($data); $this->assertEquals($str, $data[$str]); diff --git a/tests/plugins/PluginPubsubhubbubTest.php b/tests/plugins/PluginPubsubhubbubTest.php index a7bd8fc9..e66f484e 100644 --- a/tests/plugins/PluginPubsubhubbubTest.php +++ b/tests/plugins/PluginPubsubhubbubTest.php @@ -3,7 +3,7 @@ namespace Shaarli\Plugin\Pubsubhubbub; use Shaarli\Config\ConfigManager; use Shaarli\Plugin\PluginManager; -use Shaarli\Router; +use Shaarli\Render\TemplatePage; require_once 'plugins/pubsubhubbub/pubsubhubbub.php'; @@ -34,7 +34,7 @@ class PluginPubsubhubbubTest extends \PHPUnit\Framework\TestCase $hub = 'http://domain.hub'; $conf = new ConfigManager(self::$configFile); $conf->set('plugins.PUBSUBHUB_URL', $hub); - $data['_PAGE_'] = Router::$PAGE_FEED_RSS; + $data['_PAGE_'] = TemplatePage::FEED_RSS; $data = hook_pubsubhubbub_render_feed($data, $conf); $expected = ''; @@ -49,7 +49,7 @@ class PluginPubsubhubbubTest extends \PHPUnit\Framework\TestCase $hub = 'http://domain.hub'; $conf = new ConfigManager(self::$configFile); $conf->set('plugins.PUBSUBHUB_URL', $hub); - $data['_PAGE_'] = Router::$PAGE_FEED_ATOM; + $data['_PAGE_'] = TemplatePage::FEED_ATOM; $data = hook_pubsubhubbub_render_feed($data, $conf); $expected = ''; diff --git a/tests/plugins/PluginQrcodeTest.php b/tests/plugins/PluginQrcodeTest.php index 0c61e14a..c9f8c733 100644 --- a/tests/plugins/PluginQrcodeTest.php +++ b/tests/plugins/PluginQrcodeTest.php @@ -6,7 +6,7 @@ namespace Shaarli\Plugin\Qrcode; */ use Shaarli\Plugin\PluginManager; -use Shaarli\Router; +use Shaarli\Render\TemplatePage; require_once 'plugins/qrcode/qrcode.php'; @@ -57,7 +57,7 @@ class PluginQrcodeTest extends \PHPUnit\Framework\TestCase { $str = 'stuff'; $data = array($str => $str); - $data['_PAGE_'] = Router::$PAGE_LINKLIST; + $data['_PAGE_'] = TemplatePage::LINKLIST; $data = hook_qrcode_render_footer($data); $this->assertEquals($str, $data[$str]); diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php index c689982b..afc35aec 100644 --- a/tests/updater/UpdaterTest.php +++ b/tests/updater/UpdaterTest.php @@ -2,7 +2,10 @@ namespace Shaarli\Updater; use Exception; +use Shaarli\Bookmark\BookmarkFileService; +use Shaarli\Bookmark\BookmarkServiceInterface; use Shaarli\Config\ConfigManager; +use Shaarli\History; require_once 'tests/updater/DummyUpdater.php'; require_once 'tests/utils/ReferenceLinkDB.php'; @@ -29,6 +32,12 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase */ protected $conf; + /** @var BookmarkServiceInterface */ + protected $bookmarkService; + + /** @var Updater */ + protected $updater; + /** * Executed before each test. */ @@ -36,6 +45,8 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase { copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php'); $this->conf = new ConfigManager(self::$configFile); + $this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), true); + $this->updater = new Updater([], $this->bookmarkService, $this->conf, true); } /** @@ -167,4 +178,12 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase $updater = new DummyUpdater($updates, array(), $this->conf, true); $updater->update(); } + + public function testUpdateMethodRelativeHomeLinkRename(): void + { + $this->conf->set('general.header_link', '?'); + $this->updater->updateMethodRelativeHomeLink(); + + static::assertSame(); + } } -- cgit v1.2.3 From c4ad3d4f061d05a01db25aa54dda830ba776792d Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Tue, 7 Jul 2020 10:15:56 +0200 Subject: Process Shaarli install through Slim controller --- tests/bootstrap.php | 11 +- tests/container/ContainerBuilderTest.php | 11 + tests/front/ShaarliMiddlewareTest.php | 12 + .../controller/admin/LogoutControllerTest.php | 18 +- .../controller/visitor/InstallControllerTest.php | 264 +++++++++++++++++++++ tests/render/PageCacheManagerTest.php | 5 +- tests/security/LoginManagerTest.php | 30 ++- tests/security/SessionManagerTest.php | 14 +- tests/updater/UpdaterTest.php | 42 +++- 9 files changed, 365 insertions(+), 42 deletions(-) create mode 100644 tests/front/controller/visitor/InstallControllerTest.php (limited to 'tests') diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 511698ff..d4ddedd5 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -18,9 +18,14 @@ require_once 'application/bookmark/LinkUtils.php'; require_once 'application/Utils.php'; require_once 'application/http/UrlUtils.php'; require_once 'application/http/HttpUtils.php'; -require_once 'tests/utils/ReferenceLinkDB.php'; -require_once 'tests/utils/ReferenceHistory.php'; -require_once 'tests/utils/FakeBookmarkService.php'; require_once 'tests/container/ShaarliTestContainer.php'; require_once 'tests/front/controller/visitor/FrontControllerMockHelper.php'; require_once 'tests/front/controller/admin/FrontAdminControllerMockHelper.php'; +require_once 'tests/updater/DummyUpdater.php'; +require_once 'tests/utils/FakeBookmarkService.php'; +require_once 'tests/utils/FakeConfigManager.php'; +require_once 'tests/utils/ReferenceHistory.php'; +require_once 'tests/utils/ReferenceLinkDB.php'; +require_once 'tests/utils/ReferenceSessionIdHashes.php'; + +\ReferenceSessionIdHashes::genAllHashes(); diff --git a/tests/container/ContainerBuilderTest.php b/tests/container/ContainerBuilderTest.php index db533f37..fa77bf31 100644 --- a/tests/container/ContainerBuilderTest.php +++ b/tests/container/ContainerBuilderTest.php @@ -11,12 +11,15 @@ use Shaarli\Feed\FeedBuilder; use Shaarli\Formatter\FormatterFactory; use Shaarli\History; use Shaarli\Http\HttpAccess; +use Shaarli\Netscape\NetscapeBookmarkUtils; use Shaarli\Plugin\PluginManager; use Shaarli\Render\PageBuilder; use Shaarli\Render\PageCacheManager; +use Shaarli\Security\CookieManager; use Shaarli\Security\LoginManager; use Shaarli\Security\SessionManager; use Shaarli\Thumbnailer; +use Shaarli\Updater\Updater; class ContainerBuilderTest extends TestCase { @@ -32,10 +35,14 @@ class ContainerBuilderTest extends TestCase /** @var ContainerBuilder */ protected $containerBuilder; + /** @var CookieManager */ + protected $cookieManager; + public function setUp(): void { $this->conf = new ConfigManager('tests/utils/config/configJson'); $this->sessionManager = $this->createMock(SessionManager::class); + $this->cookieManager = $this->createMock(CookieManager::class); $this->loginManager = $this->createMock(LoginManager::class); $this->loginManager->method('isLoggedIn')->willReturn(true); @@ -43,6 +50,7 @@ class ContainerBuilderTest extends TestCase $this->containerBuilder = new ContainerBuilder( $this->conf, $this->sessionManager, + $this->cookieManager, $this->loginManager ); } @@ -53,6 +61,7 @@ class ContainerBuilderTest extends TestCase static::assertInstanceOf(ConfigManager::class, $container->conf); static::assertInstanceOf(SessionManager::class, $container->sessionManager); + static::assertInstanceOf(CookieManager::class, $container->cookieManager); static::assertInstanceOf(LoginManager::class, $container->loginManager); static::assertInstanceOf(History::class, $container->history); static::assertInstanceOf(BookmarkServiceInterface::class, $container->bookmarkService); @@ -63,6 +72,8 @@ class ContainerBuilderTest extends TestCase static::assertInstanceOf(FeedBuilder::class, $container->feedBuilder); static::assertInstanceOf(Thumbnailer::class, $container->thumbnailer); static::assertInstanceOf(HttpAccess::class, $container->httpAccess); + static::assertInstanceOf(NetscapeBookmarkUtils::class, $container->netscapeBookmarkUtils); + static::assertInstanceOf(Updater::class, $container->updater); // Set by the middleware static::assertNull($container->basePath); diff --git a/tests/front/ShaarliMiddlewareTest.php b/tests/front/ShaarliMiddlewareTest.php index 81ea1344..20090d8b 100644 --- a/tests/front/ShaarliMiddlewareTest.php +++ b/tests/front/ShaarliMiddlewareTest.php @@ -19,6 +19,8 @@ use Slim\Http\Uri; class ShaarliMiddlewareTest extends TestCase { + protected const TMP_MOCK_FILE = '.tmp'; + /** @var ShaarliContainer */ protected $container; @@ -29,12 +31,21 @@ class ShaarliMiddlewareTest extends TestCase { $this->container = $this->createMock(ShaarliContainer::class); + touch(static::TMP_MOCK_FILE); + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('getConfigFileExt')->willReturn(static::TMP_MOCK_FILE); + $this->container->loginManager = $this->createMock(LoginManager::class); $this->middleware = new ShaarliMiddleware($this->container); } + public function tearDown() + { + unlink(static::TMP_MOCK_FILE); + } + /** * Test middleware execution with valid controller call */ @@ -179,6 +190,7 @@ class ShaarliMiddlewareTest extends TestCase $this->container->conf->method('get')->willReturnCallback(function (string $key): string { return $key; }); + $this->container->conf->method('getConfigFileExt')->willReturn(static::TMP_MOCK_FILE); $this->container->pageCacheManager = $this->createMock(PageCacheManager::class); $this->container->pageCacheManager->expects(static::once())->method('invalidateCaches'); diff --git a/tests/front/controller/admin/LogoutControllerTest.php b/tests/front/controller/admin/LogoutControllerTest.php index ca177085..45e84dc0 100644 --- a/tests/front/controller/admin/LogoutControllerTest.php +++ b/tests/front/controller/admin/LogoutControllerTest.php @@ -4,14 +4,8 @@ declare(strict_types=1); namespace Shaarli\Front\Controller\Admin; -/** Override PHP builtin setcookie function in the local namespace to mock it... more or less */ -if (!function_exists('Shaarli\Front\Controller\Admin\setcookie')) { - function setcookie(string $name, string $value): void { - $_COOKIE[$name] = $value; - } -} - use PHPUnit\Framework\TestCase; +use Shaarli\Security\CookieManager; use Shaarli\Security\LoginManager; use Shaarli\Security\SessionManager; use Slim\Http\Request; @@ -29,8 +23,6 @@ class LogoutControllerTest extends TestCase $this->createContainer(); $this->controller = new LogoutController($this->container); - - setcookie(LoginManager::$STAY_SIGNED_IN_COOKIE, $cookie = 'hi there'); } public function testValidControllerInvoke(): void @@ -43,13 +35,17 @@ class LogoutControllerTest extends TestCase $this->container->sessionManager = $this->createMock(SessionManager::class); $this->container->sessionManager->expects(static::once())->method('logout'); - static::assertSame('hi there', $_COOKIE[LoginManager::$STAY_SIGNED_IN_COOKIE]); + $this->container->cookieManager = $this->createMock(CookieManager::class); + $this->container->cookieManager + ->expects(static::once()) + ->method('setCookieParameter') + ->with(CookieManager::STAY_SIGNED_IN, 'false', 0, '/subfolder/') + ; $result = $this->controller->index($request, $response); static::assertInstanceOf(Response::class, $result); static::assertSame(302, $result->getStatusCode()); static::assertSame(['/subfolder/'], $result->getHeader('location')); - static::assertSame('false', $_COOKIE[LoginManager::$STAY_SIGNED_IN_COOKIE]); } } diff --git a/tests/front/controller/visitor/InstallControllerTest.php b/tests/front/controller/visitor/InstallControllerTest.php new file mode 100644 index 00000000..6871fdd9 --- /dev/null +++ b/tests/front/controller/visitor/InstallControllerTest.php @@ -0,0 +1,264 @@ +createContainer(); + + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('getConfigFileExt')->willReturn(static::MOCK_FILE); + $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) { + if ($key === 'resource.raintpl_tpl') { + return '.'; + } + + return $default ?? $key; + }); + + $this->controller = new InstallController($this->container); + } + + protected function tearDown(): void + { + if (file_exists(static::MOCK_FILE)) { + unlink(static::MOCK_FILE); + } + } + + /** + * Test displaying install page with valid session. + */ + public function testInstallIndexWithValidSession(): void + { + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager + ->method('getSessionParameter') + ->willReturnCallback(function (string $key, $default) { + return $key === 'session_tested' ? 'Working' : $default; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('install', (string) $result->getBody()); + + static::assertIsArray($assignedVariables['continents']); + static::assertSame('Africa', $assignedVariables['continents'][0]); + static::assertSame('UTC', $assignedVariables['continents']['selected']); + + static::assertIsArray($assignedVariables['cities']); + static::assertSame(['continent' => 'Africa', 'city' => 'Abidjan'], $assignedVariables['cities'][0]); + static::assertSame('UTC', $assignedVariables['continents']['selected']); + + static::assertIsArray($assignedVariables['languages']); + static::assertSame('Automatic', $assignedVariables['languages']['auto']); + static::assertSame('French', $assignedVariables['languages']['fr']); + } + + /** + * Instantiate the install controller with an existing config file: exception. + */ + public function testInstallWithExistingConfigFile(): void + { + $this->expectException(AlreadyInstalledException::class); + + touch(static::MOCK_FILE); + + $this->controller = new InstallController($this->container); + } + + /** + * Call controller without session yet defined, redirect to test session install page. + */ + public function testInstallRedirectToSessionTest(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager + ->expects(static::once()) + ->method('setSessionParameter') + ->with(InstallController::SESSION_TEST_KEY, InstallController::SESSION_TEST_VALUE) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame('/subfolder/install/session-test', $result->getHeader('location')[0]); + } + + /** + * Call controller in session test mode: valid session then redirect to install page. + */ + public function testInstallSessionTestValid(): void + { + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager + ->method('getSessionParameter') + ->with(InstallController::SESSION_TEST_KEY) + ->willReturn(InstallController::SESSION_TEST_VALUE) + ; + + $result = $this->controller->sessionTest($request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame('/subfolder/install', $result->getHeader('location')[0]); + } + + /** + * Call controller in session test mode: invalid session then redirect to error page. + */ + public function testInstallSessionTestError(): void + { + $assignedVars = []; + $this->assignTemplateVars($assignedVars); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->sessionManager = $this->createMock(SessionManager::class); + $this->container->sessionManager + ->method('getSessionParameter') + ->with(InstallController::SESSION_TEST_KEY) + ->willReturn('KO') + ; + + $result = $this->controller->sessionTest($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('error', (string) $result->getBody()); + static::assertStringStartsWith( + '
Sessions do not seem to work correctly on your server',
+            $assignedVars['message']
+        );
+    }
+
+    /**
+     * Test saving valid data from install form. Also initialize datastore.
+     */
+    public function testSaveInstallValid(): void
+    {
+        $providedParameters = [
+            'continent' => 'Europe',
+            'city' => 'Berlin',
+            'setlogin' => 'bob',
+            'setpassword' => 'password',
+            'title' => 'Shaarli',
+            'language' => 'fr',
+            'updateCheck' => true,
+            'enableApi' => true,
+        ];
+
+        $expectedSettings = [
+            'general.timezone' => 'Europe/Berlin',
+            'credentials.login' => 'bob',
+            'credentials.salt' => '_NOT_EMPTY',
+            'credentials.hash' => '_NOT_EMPTY',
+            'general.title' => 'Shaarli',
+            'translation.language' => 'en',
+            'updates.check_updates' => true,
+            'api.enabled' => true,
+            'api.secret' => '_NOT_EMPTY',
+        ];
+
+        $request = $this->createMock(Request::class);
+        $request->method('getParam')->willReturnCallback(function (string $key) use ($providedParameters) {
+            return $providedParameters[$key] ?? null;
+        });
+        $response = new Response();
+
+        $this->container->conf = $this->createMock(ConfigManager::class);
+        $this->container->conf
+            ->method('get')
+            ->willReturnCallback(function (string $key, $value) {
+                if ($key === 'credentials.login') {
+                    return 'bob';
+                } elseif ($key === 'credentials.salt') {
+                    return 'salt';
+                }
+
+                return $value;
+            })
+        ;
+        $this->container->conf
+            ->expects(static::exactly(count($expectedSettings)))
+            ->method('set')
+            ->willReturnCallback(function (string $key, $value) use ($expectedSettings) {
+                if ($expectedSettings[$key] ?? null === '_NOT_EMPTY') {
+                    static::assertNotEmpty($value);
+                } else {
+                    static::assertSame($expectedSettings[$key], $value);
+                }
+            })
+        ;
+        $this->container->conf->expects(static::once())->method('write');
+
+        $this->container->bookmarkService->expects(static::once())->method('count')->willReturn(0);
+        $this->container->bookmarkService->expects(static::once())->method('initialize');
+
+        $this->container->sessionManager
+            ->expects(static::once())
+            ->method('setSessionParameter')
+            ->with(SessionManager::KEY_SUCCESS_MESSAGES)
+        ;
+
+        $result = $this->controller->save($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/subfolder/', $result->getHeader('location')[0]);
+    }
+
+    /**
+     * Test default settings (timezone and title).
+     * Also check that bookmarks are not initialized if
+     */
+    public function testSaveInstallDefaultValues(): void
+    {
+        $confSettings = [];
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->conf->method('set')->willReturnCallback(function (string $key, $value) use (&$confSettings) {
+            $confSettings[$key] = $value;
+        });
+
+        $result = $this->controller->save($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/subfolder/', $result->getHeader('location')[0]);
+
+        static::assertSame('UTC', $confSettings['general.timezone']);
+        static::assertSame('Shared bookmarks on http://shaarli', $confSettings['general.title']);
+    }
+}
diff --git a/tests/render/PageCacheManagerTest.php b/tests/render/PageCacheManagerTest.php
index b870e6eb..c258f45f 100644
--- a/tests/render/PageCacheManagerTest.php
+++ b/tests/render/PageCacheManagerTest.php
@@ -1,15 +1,14 @@
 cookie = [];
         $this->session = [];
 
-        $this->sessionManager = new SessionManager($this->session, $this->configManager);
-        $this->loginManager = new LoginManager($this->configManager, $this->sessionManager);
+        $this->cookieManager = $this->createMock(CookieManager::class);
+        $this->cookieManager->method('getCookieParameter')->willReturnCallback(function (string $key) {
+            return $this->cookie[$key] ?? null;
+        });
+        $this->sessionManager = new SessionManager($this->session, $this->configManager, 'session_path');
+        $this->loginManager = new LoginManager($this->configManager, $this->sessionManager, $this->cookieManager);
         $this->server['REMOTE_ADDR'] = $this->ipAddr;
     }
 
@@ -193,8 +199,8 @@ class LoginManagerTest extends TestCase
         $configManager = new \FakeConfigManager([
             'resource.ban_file' => $this->banFile,
         ]);
-        $loginManager = new LoginManager($configManager, null);
-        $loginManager->checkLoginState([], '');
+        $loginManager = new LoginManager($configManager, null, $this->cookieManager);
+        $loginManager->checkLoginState('');
 
         $this->assertFalse($loginManager->isLoggedIn());
     }
@@ -210,9 +216,9 @@ class LoginManagerTest extends TestCase
             'expires_on' => time() + 100,
         ];
         $this->loginManager->generateStaySignedInToken($this->clientIpAddress);
-        $this->cookie[LoginManager::$STAY_SIGNED_IN_COOKIE] = 'nope';
+        $this->cookie[CookieManager::STAY_SIGNED_IN] = 'nope';
 
-        $this->loginManager->checkLoginState($this->cookie, $this->clientIpAddress);
+        $this->loginManager->checkLoginState($this->clientIpAddress);
 
         $this->assertTrue($this->loginManager->isLoggedIn());
         $this->assertTrue(empty($this->session['username']));
@@ -224,9 +230,9 @@ class LoginManagerTest extends TestCase
     public function testCheckLoginStateStaySignedInWithValidToken()
     {
         $this->loginManager->generateStaySignedInToken($this->clientIpAddress);
-        $this->cookie[LoginManager::$STAY_SIGNED_IN_COOKIE] = $this->loginManager->getStaySignedInToken();
+        $this->cookie[CookieManager::STAY_SIGNED_IN] = $this->loginManager->getStaySignedInToken();
 
-        $this->loginManager->checkLoginState($this->cookie, $this->clientIpAddress);
+        $this->loginManager->checkLoginState($this->clientIpAddress);
 
         $this->assertTrue($this->loginManager->isLoggedIn());
         $this->assertEquals($this->login, $this->session['username']);
@@ -241,7 +247,7 @@ class LoginManagerTest extends TestCase
         $this->loginManager->generateStaySignedInToken($this->clientIpAddress);
         $this->session['expires_on'] = time() - 100;
 
-        $this->loginManager->checkLoginState($this->cookie, $this->clientIpAddress);
+        $this->loginManager->checkLoginState($this->clientIpAddress);
 
         $this->assertFalse($this->loginManager->isLoggedIn());
     }
@@ -253,7 +259,7 @@ class LoginManagerTest extends TestCase
     {
         $this->loginManager->generateStaySignedInToken($this->clientIpAddress);
 
-        $this->loginManager->checkLoginState($this->cookie, '10.7.157.98');
+        $this->loginManager->checkLoginState('10.7.157.98');
 
         $this->assertFalse($this->loginManager->isLoggedIn());
     }
diff --git a/tests/security/SessionManagerTest.php b/tests/security/SessionManagerTest.php
index d9db775e..60695dcf 100644
--- a/tests/security/SessionManagerTest.php
+++ b/tests/security/SessionManagerTest.php
@@ -1,12 +1,8 @@
 conf = new FakeConfigManager([
+        $this->conf = new \FakeConfigManager([
             'credentials.login' => 'johndoe',
             'credentials.salt' => 'salt',
             'security.session_protection_disabled' => false,
         ]);
         $this->session = [];
-        $this->sessionManager = new SessionManager($this->session, $this->conf);
+        $this->sessionManager = new SessionManager($this->session, $this->conf, 'session_path');
     }
 
     /**
@@ -69,7 +65,7 @@ class SessionManagerTest extends TestCase
                 $token => 1,
             ],
         ];
-        $sessionManager = new SessionManager($session, $this->conf);
+        $sessionManager = new SessionManager($session, $this->conf, 'session_path');
 
         // check and destroy the token
         $this->assertTrue($sessionManager->checkToken($token));
diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php
index afc35aec..c801d451 100644
--- a/tests/updater/UpdaterTest.php
+++ b/tests/updater/UpdaterTest.php
@@ -7,9 +7,6 @@ use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
 
-require_once 'tests/updater/DummyUpdater.php';
-require_once 'tests/utils/ReferenceLinkDB.php';
-require_once 'inc/rain.tpl.class.php';
 
 /**
  * Class UpdaterTest.
@@ -35,6 +32,9 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase
     /** @var BookmarkServiceInterface */
     protected $bookmarkService;
 
+    /** @var \ReferenceLinkDB */
+    protected $refDB;
+
     /** @var Updater */
     protected $updater;
 
@@ -43,6 +43,9 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase
      */
     public function setUp()
     {
+        $this->refDB = new \ReferenceLinkDB();
+        $this->refDB->write(self::$testDatastore);
+
         copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php');
         $this->conf = new ConfigManager(self::$configFile);
         $this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), true);
@@ -181,9 +184,40 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase
 
     public function testUpdateMethodRelativeHomeLinkRename(): void
     {
+        $this->updater->setBasePath('/subfolder');
         $this->conf->set('general.header_link', '?');
+
+        $this->updater->updateMethodRelativeHomeLink();
+
+        static::assertSame('/subfolder/', $this->conf->get('general.header_link'));
+    }
+
+    public function testUpdateMethodRelativeHomeLinkDoNotRename(): void
+    {
+        $this->updater->setBasePath('/subfolder');
+        $this->conf->set('general.header_link', '~/my-blog');
+
         $this->updater->updateMethodRelativeHomeLink();
 
-        static::assertSame();
+        static::assertSame('~/my-blog', $this->conf->get('general.header_link'));
+    }
+
+    public function testUpdateMethodMigrateExistingNotesUrl(): void
+    {
+        $this->updater->setBasePath('/subfolder');
+
+        $this->updater->updateMethodMigrateExistingNotesUrl();
+
+        static::assertSame($this->refDB->getLinks()[0]->getUrl(), $this->bookmarkService->get(0)->getUrl());
+        static::assertSame($this->refDB->getLinks()[1]->getUrl(), $this->bookmarkService->get(1)->getUrl());
+        static::assertSame($this->refDB->getLinks()[4]->getUrl(), $this->bookmarkService->get(4)->getUrl());
+        static::assertSame($this->refDB->getLinks()[6]->getUrl(), $this->bookmarkService->get(6)->getUrl());
+        static::assertSame($this->refDB->getLinks()[7]->getUrl(), $this->bookmarkService->get(7)->getUrl());
+        static::assertSame($this->refDB->getLinks()[8]->getUrl(), $this->bookmarkService->get(8)->getUrl());
+        static::assertSame($this->refDB->getLinks()[9]->getUrl(), $this->bookmarkService->get(9)->getUrl());
+        static::assertSame('/subfolder/shaare/WDWyig', $this->bookmarkService->get(42)->getUrl());
+        static::assertSame('/subfolder/shaare/WDWyig', $this->bookmarkService->get(41)->getUrl());
+        static::assertSame('/subfolder/shaare/0gCTjQ', $this->bookmarkService->get(10)->getUrl());
+        static::assertSame('/subfolder/shaare/PCRizQ', $this->bookmarkService->get(11)->getUrl());
     }
 }
-- 
cgit v1.2.3


From a8c11451e8d885a243c1ad52012093ba8d121e2c Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 21 Jul 2020 20:33:33 +0200
Subject: Process login through Slim controller

---
 tests/front/ShaarliMiddlewareTest.php              |   7 +-
 .../visitor/FrontControllerMockHelper.php          |   1 +
 .../controller/visitor/LoginControllerTest.php     | 278 ++++++++++++++++++++-
 3 files changed, 281 insertions(+), 5 deletions(-)

(limited to 'tests')

diff --git a/tests/front/ShaarliMiddlewareTest.php b/tests/front/ShaarliMiddlewareTest.php
index 20090d8b..09bebd04 100644
--- a/tests/front/ShaarliMiddlewareTest.php
+++ b/tests/front/ShaarliMiddlewareTest.php
@@ -38,6 +38,8 @@ class ShaarliMiddlewareTest extends TestCase
 
         $this->container->loginManager = $this->createMock(LoginManager::class);
 
+        $this->container->environment = ['REQUEST_URI' => 'http://shaarli/subfolder/path'];
+
         $this->middleware = new ShaarliMiddleware($this->container);
     }
 
@@ -127,7 +129,10 @@ class ShaarliMiddlewareTest extends TestCase
         $result = $this->middleware->__invoke($request, $response, $controller);
 
         static::assertSame(302, $result->getStatusCode());
-        static::assertSame('/subfolder/login', $result->getHeader('location')[0]);
+        static::assertSame(
+            '/subfolder/login?returnurl=' . urlencode('http://shaarli/subfolder/path'),
+            $result->getHeader('location')[0]
+        );
     }
 
     /**
diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php
index 7f560662..e0bd4ecf 100644
--- a/tests/front/controller/visitor/FrontControllerMockHelper.php
+++ b/tests/front/controller/visitor/FrontControllerMockHelper.php
@@ -80,6 +80,7 @@ trait FrontControllerMockHelper
             'SERVER_NAME' => 'shaarli',
             'SERVER_PORT' => '80',
             'REQUEST_URI' => '/daily-rss',
+            'REMOTE_ADDR' => '1.2.3.4',
         ];
 
         $this->container->basePath = '/subfolder';
diff --git a/tests/front/controller/visitor/LoginControllerTest.php b/tests/front/controller/visitor/LoginControllerTest.php
index e57f44b9..0a21f938 100644
--- a/tests/front/controller/visitor/LoginControllerTest.php
+++ b/tests/front/controller/visitor/LoginControllerTest.php
@@ -7,6 +7,10 @@ namespace Shaarli\Front\Controller\Visitor;
 use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\LoginBannedException;
+use Shaarli\Front\Exception\WrongTokenException;
+use Shaarli\Render\TemplatePage;
+use Shaarli\Security\CookieManager;
+use Shaarli\Security\SessionManager;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -21,13 +25,25 @@ class LoginControllerTest extends TestCase
     {
         $this->createContainer();
 
+        $this->container->cookieManager = $this->createMock(CookieManager::class);
+        $this->container->sessionManager->method('checkToken')->willReturn(true);
+
         $this->controller = new LoginController($this->container);
     }
 
+    /**
+     * Test displaying login form with valid parameters.
+     */
     public function testValidControllerInvoke(): void
     {
         $request = $this->createMock(Request::class);
-        $request->expects(static::once())->method('getServerParam')->willReturn('> referer');
+        $request
+            ->expects(static::atLeastOnce())
+            ->method('getParam')
+            ->willReturnCallback(function (string $key) {
+                return 'returnurl' === $key ? '> referer' : null;
+            })
+        ;
         $response = new Response();
 
         $assignedVariables = [];
@@ -46,18 +62,32 @@ class LoginControllerTest extends TestCase
 
         static::assertInstanceOf(Response::class, $result);
         static::assertSame(200, $result->getStatusCode());
-        static::assertSame('loginform', (string) $result->getBody());
+        static::assertSame(TemplatePage::LOGIN, (string) $result->getBody());
 
         static::assertSame('> referer', $assignedVariables['returnurl']);
         static::assertSame(true, $assignedVariables['remember_user_default']);
         static::assertSame('Login - Shaarli', $assignedVariables['pagetitle']);
     }
 
+    /**
+     * Test displaying login form with username defined in the request.
+     */
     public function testValidControllerInvokeWithUserName(): void
     {
+        $this->container->environment = ['HTTP_REFERER' => '> referer'];
+
         $request = $this->createMock(Request::class);
-        $request->expects(static::once())->method('getServerParam')->willReturn('> referer');
-        $request->expects(static::exactly(2))->method('getParam')->willReturn('myUser>');
+        $request
+            ->expects(static::atLeastOnce())
+            ->method('getParam')
+            ->willReturnCallback(function (string $key, $default) {
+                if ('login' === $key) {
+                    return 'myUser>';
+                }
+
+                return $default;
+            })
+        ;
         $response = new Response();
 
         $assignedVariables = [];
@@ -84,6 +114,9 @@ class LoginControllerTest extends TestCase
         static::assertSame('Login - Shaarli', $assignedVariables['pagetitle']);
     }
 
+    /**
+     * Test displaying login page while being logged in.
+     */
     public function testLoginControllerWhileLoggedIn(): void
     {
         $request = $this->createMock(Request::class);
@@ -98,6 +131,9 @@ class LoginControllerTest extends TestCase
         static::assertSame(['/subfolder/'], $result->getHeader('Location'));
     }
 
+    /**
+     * Test displaying login page with open shaarli configured: redirect to homepage.
+     */
     public function testLoginControllerOpenShaarli(): void
     {
         $request = $this->createMock(Request::class);
@@ -119,6 +155,9 @@ class LoginControllerTest extends TestCase
         static::assertSame(['/subfolder/'], $result->getHeader('Location'));
     }
 
+    /**
+     * Test displaying login page while being banned.
+     */
     public function testLoginControllerWhileBanned(): void
     {
         $request = $this->createMock(Request::class);
@@ -131,4 +170,235 @@ class LoginControllerTest extends TestCase
 
         $this->controller->index($request, $response);
     }
+
+    /**
+     * Test processing login with valid parameters.
+     */
+    public function testProcessLoginWithValidParameters(): void
+    {
+        $parameters = [
+            'login' => 'bob',
+            'password' => 'pass',
+        ];
+        $request = $this->createMock(Request::class);
+        $request
+            ->expects(static::atLeastOnce())
+            ->method('getParam')
+            ->willReturnCallback(function (string $key) use ($parameters) {
+                return $parameters[$key] ?? null;
+            })
+        ;
+        $response = new Response();
+
+        $this->container->loginManager->method('canLogin')->willReturn(true);
+        $this->container->loginManager->expects(static::once())->method('handleSuccessfulLogin');
+        $this->container->loginManager
+            ->expects(static::once())
+            ->method('checkCredentials')
+            ->with('1.2.3.4', '1.2.3.4', 'bob', 'pass')
+            ->willReturn(true)
+        ;
+        $this->container->loginManager->method('getStaySignedInToken')->willReturn(bin2hex(random_bytes(8)));
+
+        $this->container->sessionManager->expects(static::never())->method('extendSession');
+        $this->container->sessionManager->expects(static::once())->method('destroy');
+        $this->container->sessionManager
+            ->expects(static::once())
+            ->method('cookieParameters')
+            ->with(0, '/subfolder/', 'shaarli')
+        ;
+        $this->container->sessionManager->expects(static::once())->method('start');
+        $this->container->sessionManager->expects(static::once())->method('regenerateId')->with(true);
+
+        $result = $this->controller->login($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/subfolder/', $result->getHeader('location')[0]);
+    }
+
+    /**
+     * Test processing login with return URL.
+     */
+    public function testProcessLoginWithReturnUrl(): void
+    {
+        $parameters = [
+            'returnurl' => 'http://shaarli/subfolder/admin/shaare',
+        ];
+        $request = $this->createMock(Request::class);
+        $request
+            ->expects(static::atLeastOnce())
+            ->method('getParam')
+            ->willReturnCallback(function (string $key) use ($parameters) {
+                return $parameters[$key] ?? null;
+            })
+        ;
+        $response = new Response();
+
+        $this->container->loginManager->method('canLogin')->willReturn(true);
+        $this->container->loginManager->expects(static::once())->method('handleSuccessfulLogin');
+        $this->container->loginManager->expects(static::once())->method('checkCredentials')->willReturn(true);
+        $this->container->loginManager->method('getStaySignedInToken')->willReturn(bin2hex(random_bytes(8)));
+
+        $result = $this->controller->login($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/subfolder/admin/shaare', $result->getHeader('location')[0]);
+    }
+
+    /**
+     * Test processing login with remember me session enabled.
+     */
+    public function testProcessLoginLongLastingSession(): void
+    {
+        $parameters = [
+            'longlastingsession' => true,
+        ];
+        $request = $this->createMock(Request::class);
+        $request
+            ->expects(static::atLeastOnce())
+            ->method('getParam')
+            ->willReturnCallback(function (string $key) use ($parameters) {
+                return $parameters[$key] ?? null;
+            })
+        ;
+        $response = new Response();
+
+        $this->container->loginManager->method('canLogin')->willReturn(true);
+        $this->container->loginManager->expects(static::once())->method('handleSuccessfulLogin');
+        $this->container->loginManager->expects(static::once())->method('checkCredentials')->willReturn(true);
+        $this->container->loginManager->method('getStaySignedInToken')->willReturn(bin2hex(random_bytes(8)));
+
+        $this->container->sessionManager->expects(static::once())->method('destroy');
+        $this->container->sessionManager
+            ->expects(static::once())
+            ->method('cookieParameters')
+            ->with(42, '/subfolder/', 'shaarli')
+        ;
+        $this->container->sessionManager->expects(static::once())->method('start');
+        $this->container->sessionManager->expects(static::once())->method('regenerateId')->with(true);
+        $this->container->sessionManager->expects(static::once())->method('extendSession')->willReturn(42);
+
+        $this->container->cookieManager = $this->createMock(CookieManager::class);
+        $this->container->cookieManager
+            ->expects(static::once())
+            ->method('setCookieParameter')
+            ->willReturnCallback(function (string $name): CookieManager {
+                static::assertSame(CookieManager::STAY_SIGNED_IN, $name);
+
+                return $this->container->cookieManager;
+            })
+        ;
+
+        $result = $this->controller->login($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/subfolder/', $result->getHeader('location')[0]);
+    }
+
+    /**
+     * Test processing login with invalid credentials
+     */
+    public function testProcessLoginWrongCredentials(): void
+    {
+        $parameters = [
+            'returnurl' => 'http://shaarli/subfolder/admin/shaare',
+        ];
+        $request = $this->createMock(Request::class);
+        $request
+            ->expects(static::atLeastOnce())
+            ->method('getParam')
+            ->willReturnCallback(function (string $key) use ($parameters) {
+                return $parameters[$key] ?? null;
+            })
+        ;
+        $response = new Response();
+
+        $this->container->loginManager->method('canLogin')->willReturn(true);
+        $this->container->loginManager->expects(static::once())->method('handleFailedLogin');
+        $this->container->loginManager->expects(static::once())->method('checkCredentials')->willReturn(false);
+
+        $this->container->sessionManager
+            ->expects(static::once())
+            ->method('setSessionParameter')
+            ->with(SessionManager::KEY_ERROR_MESSAGES, ['Wrong login/password.'])
+        ;
+
+        $result = $this->controller->login($request, $response);
+
+        static::assertSame(200, $result->getStatusCode());
+        static::assertSame(TemplatePage::LOGIN, (string) $result->getBody());
+    }
+
+    /**
+     * Test processing login with wrong token
+     */
+    public function testProcessLoginWrongToken(): void
+    {
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->sessionManager = $this->createMock(SessionManager::class);
+        $this->container->sessionManager->method('checkToken')->willReturn(false);
+
+        $this->expectException(WrongTokenException::class);
+
+        $this->controller->login($request, $response);
+    }
+
+    /**
+     * Test processing login with wrong token
+     */
+    public function testProcessLoginAlreadyLoggedIn(): void
+    {
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->loginManager->method('isLoggedIn')->willReturn(true);
+        $this->container->loginManager->expects(static::never())->method('handleSuccessfulLogin');
+        $this->container->loginManager->expects(static::never())->method('handleFailedLogin');
+
+        $result = $this->controller->login($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/subfolder/', $result->getHeader('location')[0]);
+    }
+
+    /**
+     * Test processing login with wrong token
+     */
+    public function testProcessLoginInOpenShaarli(): void
+    {
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->conf = $this->createMock(ConfigManager::class);
+        $this->container->conf->method('get')->willReturnCallback(function (string $key, $value) {
+            return 'security.open_shaarli' === $key ? true : $value;
+        });
+
+        $this->container->loginManager->expects(static::never())->method('handleSuccessfulLogin');
+        $this->container->loginManager->expects(static::never())->method('handleFailedLogin');
+
+        $result = $this->controller->login($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/subfolder/', $result->getHeader('location')[0]);
+    }
+
+    /**
+     * Test processing login while being banned
+     */
+    public function testProcessLoginWhileBanned(): void
+    {
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->loginManager->method('canLogin')->willReturn(false);
+        $this->container->loginManager->expects(static::never())->method('handleSuccessfulLogin');
+        $this->container->loginManager->expects(static::never())->method('handleFailedLogin');
+
+        $this->expectException(LoginBannedException::class);
+
+        $this->controller->login($request, $response);
+    }
 }
-- 
cgit v1.2.3


From 3ee8351e438f13ccf36062ce956e0b4a4d5f4a29 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Thu, 23 Jul 2020 16:41:32 +0200
Subject: Multiple small fixes

---
 tests/front/controller/admin/PluginsControllerTest.php   | 2 +-
 tests/front/controller/visitor/InstallControllerTest.php | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

(limited to 'tests')

diff --git a/tests/front/controller/admin/PluginsControllerTest.php b/tests/front/controller/admin/PluginsControllerTest.php
index 700a0df2..ad0cda70 100644
--- a/tests/front/controller/admin/PluginsControllerTest.php
+++ b/tests/front/controller/admin/PluginsControllerTest.php
@@ -162,7 +162,7 @@ class PluginsControllerTest extends TestCase
             ->method('setSessionParameter')
             ->with(
                 SessionManager::KEY_ERROR_MESSAGES,
-                ['ERROR while saving plugin configuration: ' . PHP_EOL . $message]
+                ['Error while saving plugin configuration: ' . PHP_EOL . $message]
             )
         ;
 
diff --git a/tests/front/controller/visitor/InstallControllerTest.php b/tests/front/controller/visitor/InstallControllerTest.php
index 6871fdd9..29c4d7a0 100644
--- a/tests/front/controller/visitor/InstallControllerTest.php
+++ b/tests/front/controller/visitor/InstallControllerTest.php
@@ -189,6 +189,7 @@ class InstallControllerTest extends TestCase
             'updates.check_updates' => true,
             'api.enabled' => true,
             'api.secret' => '_NOT_EMPTY',
+            'general.header_link' => '/subfolder',
         ];
 
         $request = $this->createMock(Request::class);
-- 
cgit v1.2.3


From 87ae3c4f08431e02869376cb57add257747910d1 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Fri, 24 Jul 2020 10:30:47 +0200
Subject: Fix default link and redirection in install controller

---
 tests/front/controller/visitor/InstallControllerTest.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'tests')

diff --git a/tests/front/controller/visitor/InstallControllerTest.php b/tests/front/controller/visitor/InstallControllerTest.php
index 29c4d7a0..089c64ac 100644
--- a/tests/front/controller/visitor/InstallControllerTest.php
+++ b/tests/front/controller/visitor/InstallControllerTest.php
@@ -236,7 +236,7 @@ class InstallControllerTest extends TestCase
         $result = $this->controller->save($request, $response);
 
         static::assertSame(302, $result->getStatusCode());
-        static::assertSame('/subfolder/', $result->getHeader('location')[0]);
+        static::assertSame('/subfolder/login', $result->getHeader('location')[0]);
     }
 
     /**
@@ -257,7 +257,7 @@ class InstallControllerTest extends TestCase
         $result = $this->controller->save($request, $response);
 
         static::assertSame(302, $result->getStatusCode());
-        static::assertSame('/subfolder/', $result->getHeader('location')[0]);
+        static::assertSame('/subfolder/login', $result->getHeader('location')[0]);
 
         static::assertSame('UTC', $confSettings['general.timezone']);
         static::assertSame('Shared bookmarks on http://shaarli', $confSettings['general.title']);
-- 
cgit v1.2.3


From 204035bd3c91b9a5c39fcb6fc470e108b032dbd9 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Fri, 24 Jul 2020 12:48:53 +0200
Subject: Fix: visitor are allowed to chose nb of links per page

---
 .../admin/SessionFilterControllerTest.php          | 48 +--------------
 .../visitor/PublicSessionFilterControllerTest.php  | 71 ++++++++++++++++++++++
 2 files changed, 72 insertions(+), 47 deletions(-)
 create mode 100644 tests/front/controller/visitor/PublicSessionFilterControllerTest.php

(limited to 'tests')

diff --git a/tests/front/controller/admin/SessionFilterControllerTest.php b/tests/front/controller/admin/SessionFilterControllerTest.php
index ea07edee..124b0bf2 100644
--- a/tests/front/controller/admin/SessionFilterControllerTest.php
+++ b/tests/front/controller/admin/SessionFilterControllerTest.php
@@ -23,53 +23,7 @@ class SessionFilterControllerTest extends TestCase
 
         $this->controller = new SessionFilterController($this->container);
     }
-
-    /**
-     * Link per page - Default call with valid parameter and a referer.
-     */
-    public function testLinksPerPage(): void
-    {
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
-
-        $request = $this->createMock(Request::class);
-        $request->method('getParam')->with('nb')->willReturn('8');
-        $response = new Response();
-
-        $this->container->sessionManager
-            ->expects(static::once())
-            ->method('setSessionParameter')
-            ->with(SessionManager::KEY_LINKS_PER_PAGE, 8)
-        ;
-
-        $result = $this->controller->linksPerPage($request, $response);
-
-        static::assertInstanceOf(Response::class, $result);
-        static::assertSame(302, $result->getStatusCode());
-        static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
-    }
-
-    /**
-     * Link per page - Invalid value, should use default value (20)
-     */
-    public function testLinksPerPageNotValid(): void
-    {
-        $request = $this->createMock(Request::class);
-        $request->method('getParam')->with('nb')->willReturn('test');
-        $response = new Response();
-
-        $this->container->sessionManager
-            ->expects(static::once())
-            ->method('setSessionParameter')
-            ->with(SessionManager::KEY_LINKS_PER_PAGE, 20)
-        ;
-
-        $result = $this->controller->linksPerPage($request, $response);
-
-        static::assertInstanceOf(Response::class, $result);
-        static::assertSame(302, $result->getStatusCode());
-        static::assertSame(['/subfolder/'], $result->getHeader('location'));
-    }
-
+    
     /**
      * Visibility - Default call for private filter while logged in without current value
      */
diff --git a/tests/front/controller/visitor/PublicSessionFilterControllerTest.php b/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
new file mode 100644
index 00000000..3aa1cb99
--- /dev/null
+++ b/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
@@ -0,0 +1,71 @@
+createContainer();
+
+        $this->controller = new PublicSessionFilterController($this->container);
+    }
+
+    /**
+     * Link per page - Default call with valid parameter and a referer.
+     */
+    public function testLinksPerPage(): void
+    {
+        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+
+        $request = $this->createMock(Request::class);
+        $request->method('getParam')->with('nb')->willReturn('8');
+        $response = new Response();
+
+        $this->container->sessionManager
+            ->expects(static::once())
+            ->method('setSessionParameter')
+            ->with(SessionManager::KEY_LINKS_PER_PAGE, 8)
+        ;
+
+        $result = $this->controller->linksPerPage($request, $response);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
+    }
+
+    /**
+     * Link per page - Invalid value, should use default value (20)
+     */
+    public function testLinksPerPageNotValid(): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->method('getParam')->with('nb')->willReturn('test');
+        $response = new Response();
+
+        $this->container->sessionManager
+            ->expects(static::once())
+            ->method('setSessionParameter')
+            ->with(SessionManager::KEY_LINKS_PER_PAGE, 20)
+        ;
+
+        $result = $this->controller->linksPerPage($request, $response);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/subfolder/'], $result->getHeader('location'));
+    }
+}
-- 
cgit v1.2.3


From 9fbc42294e7667c5ef19cafa0d1fcfbc1c0f36a9 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Sun, 26 Jul 2020 14:43:10 +0200
Subject: New basePath: fix officiel plugin paths and vintage template

---
 tests/config/ConfigPluginTest.php                  | 16 +++++++++++----
 .../DeleteBookmarkTest.php                         | 23 ++++++++++++++++++----
 .../controller/admin/PluginsControllerTest.php     | 14 +++++++++++++
 .../admin/SessionFilterControllerTest.php          |  2 +-
 .../visitor/ShaarliVisitorControllerTest.php       |  2 --
 tests/plugins/PluginAddlinkTest.php                |  4 ++++
 6 files changed, 50 insertions(+), 11 deletions(-)

(limited to 'tests')

diff --git a/tests/config/ConfigPluginTest.php b/tests/config/ConfigPluginTest.php
index d7a70e68..b2cc0045 100644
--- a/tests/config/ConfigPluginTest.php
+++ b/tests/config/ConfigPluginTest.php
@@ -2,6 +2,7 @@
 namespace Shaarli\Config;
 
 use Shaarli\Config\Exception\PluginConfigOrderException;
+use Shaarli\Plugin\PluginManager;
 
 require_once 'application/config/ConfigPlugin.php';
 
@@ -17,23 +18,30 @@ class ConfigPluginTest extends \PHPUnit\Framework\TestCase
      */
     public function testSavePluginConfigValid()
     {
-        $data = array(
+        $data = [
             'order_plugin1' => 2,   // no plugin related
             'plugin2' => 0,         // new - at the end
             'plugin3' => 0,         // 2nd
             'order_plugin3' => 8,
             'plugin4' => 0,         // 1st
             'order_plugin4' => 5,
-        );
+        ];
 
-        $expected = array(
+        $expected = [
             'plugin3',
             'plugin4',
             'plugin2',
-        );
+        ];
+
+        mkdir($path = __DIR__ . '/folder');
+        PluginManager::$PLUGINS_PATH = $path;
+        array_map(function (string $plugin) use ($path) { touch($path . '/' . $plugin); }, $expected);
 
         $out = save_plugin_config($data);
         $this->assertEquals($expected, $out);
+
+        array_map(function (string $plugin) use ($path) { unlink($path . '/' . $plugin); }, $expected);
+        rmdir($path);
     }
 
     /**
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
index caaf549d..dee622bb 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
@@ -59,8 +59,12 @@ class DeleteBookmarkTest extends TestCase
             ->with('raw')
             ->willReturnCallback(function () use ($bookmark): BookmarkFormatter {
                 $formatter = $this->createMock(BookmarkFormatter::class);
-
-                $formatter->expects(static::once())->method('format')->with($bookmark);
+                $formatter
+                    ->expects(static::once())
+                    ->method('format')
+                    ->with($bookmark)
+                    ->willReturn(['formatted' => $bookmark])
+                ;
 
                 return $formatter;
             })
@@ -70,7 +74,7 @@ class DeleteBookmarkTest extends TestCase
         $this->container->pluginManager
             ->expects(static::once())
             ->method('executeHooks')
-            ->with('delete_link')
+            ->with('delete_link', ['formatted' => $bookmark])
         ;
 
         $result = $this->controller->deleteBookmark($request, $response);
@@ -129,6 +133,9 @@ class DeleteBookmarkTest extends TestCase
                     ->withConsecutive(...array_map(function (Bookmark $bookmark): array {
                         return [$bookmark];
                     }, $bookmarks))
+                    ->willReturnOnConsecutiveCalls(...array_map(function (Bookmark $bookmark): array {
+                        return ['formatted' => $bookmark];
+                    }, $bookmarks))
                 ;
 
                 return $formatter;
@@ -254,6 +261,9 @@ class DeleteBookmarkTest extends TestCase
                     ->withConsecutive(...array_map(function (Bookmark $bookmark): array {
                         return [$bookmark];
                     }, $bookmarks))
+                    ->willReturnOnConsecutiveCalls(...array_map(function (Bookmark $bookmark): array {
+                        return ['formatted' => $bookmark];
+                    }, $bookmarks))
                 ;
 
                 return $formatter;
@@ -350,7 +360,12 @@ class DeleteBookmarkTest extends TestCase
         $this->container->formatterFactory
             ->expects(static::once())
             ->method('getFormatter')
-            ->willReturn($this->createMock(BookmarkFormatter::class))
+            ->willReturnCallback(function (): BookmarkFormatter {
+                $formatter = $this->createMock(BookmarkFormatter::class);
+                $formatter->method('format')->willReturn(['formatted']);
+
+                return $formatter;
+            })
         ;
 
         $result = $this->controller->deleteBookmark($request, $response);
diff --git a/tests/front/controller/admin/PluginsControllerTest.php b/tests/front/controller/admin/PluginsControllerTest.php
index ad0cda70..5b59285c 100644
--- a/tests/front/controller/admin/PluginsControllerTest.php
+++ b/tests/front/controller/admin/PluginsControllerTest.php
@@ -7,6 +7,7 @@ namespace Shaarli\Front\Controller\Admin;
 use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\WrongTokenException;
+use Shaarli\Plugin\PluginManager;
 use Shaarli\Security\SessionManager;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -15,6 +16,8 @@ class PluginsControllerTest extends TestCase
 {
     use FrontAdminControllerMockHelper;
 
+    const PLUGIN_NAMES = ['plugin1', 'plugin2', 'plugin3', 'plugin4'];
+
     /** @var PluginsController */
     protected $controller;
 
@@ -23,6 +26,17 @@ class PluginsControllerTest extends TestCase
         $this->createContainer();
 
         $this->controller = new PluginsController($this->container);
+
+        mkdir($path = __DIR__ . '/folder');
+        PluginManager::$PLUGINS_PATH = $path;
+        array_map(function (string $plugin) use ($path) { touch($path . '/' . $plugin); }, static::PLUGIN_NAMES);
+    }
+
+    public function tearDown()
+    {
+        $path = __DIR__ . '/folder';
+        array_map(function (string $plugin) use ($path) { unlink($path . '/' . $plugin); }, static::PLUGIN_NAMES);
+        rmdir($path);
     }
 
     /**
diff --git a/tests/front/controller/admin/SessionFilterControllerTest.php b/tests/front/controller/admin/SessionFilterControllerTest.php
index 124b0bf2..7d5511ed 100644
--- a/tests/front/controller/admin/SessionFilterControllerTest.php
+++ b/tests/front/controller/admin/SessionFilterControllerTest.php
@@ -23,7 +23,7 @@ class SessionFilterControllerTest extends TestCase
 
         $this->controller = new SessionFilterController($this->container);
     }
-    
+
     /**
      * Visibility - Default call for private filter while logged in without current value
      */
diff --git a/tests/front/controller/visitor/ShaarliVisitorControllerTest.php b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
index 83d08358..316ce49c 100644
--- a/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
+++ b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
@@ -96,8 +96,6 @@ class ShaarliVisitorControllerTest extends TestCase
         static::assertSame(10, $this->assignedValues['linkcount']);
         static::assertSame(5, $this->assignedValues['privateLinkcount']);
         static::assertSame(['error'], $this->assignedValues['plugin_errors']);
-        static::assertSame('/subfolder', $this->assignedValues['base_path']);
-        static::assertSame('/subfolder/tpl/default', $this->assignedValues['asset_path']);
 
         static::assertSame('templateName', $this->assignedValues['plugins_includes']['render_includes']['target']);
         static::assertTrue($this->assignedValues['plugins_includes']['render_includes']['loggedin']);
diff --git a/tests/plugins/PluginAddlinkTest.php b/tests/plugins/PluginAddlinkTest.php
index 4018c1a8..aa5c6988 100644
--- a/tests/plugins/PluginAddlinkTest.php
+++ b/tests/plugins/PluginAddlinkTest.php
@@ -28,6 +28,7 @@ class PluginAddlinkTest extends \PHPUnit\Framework\TestCase
         $data = array($str => $str);
         $data['_PAGE_'] = TemplatePage::LINKLIST;
         $data['_LOGGEDIN_'] = true;
+        $data['_BASE_PATH_'] = '/subfolder';
 
         $data = hook_addlink_toolbar_render_header($data);
         $this->assertEquals($str, $data[$str]);
@@ -36,6 +37,8 @@ class PluginAddlinkTest extends \PHPUnit\Framework\TestCase
         $data = array($str => $str);
         $data['_PAGE_'] = $str;
         $data['_LOGGEDIN_'] = true;
+        $data['_BASE_PATH_'] = '/subfolder';
+
         $data = hook_addlink_toolbar_render_header($data);
         $this->assertEquals($str, $data[$str]);
         $this->assertArrayNotHasKey('fields_toolbar', $data);
@@ -50,6 +53,7 @@ class PluginAddlinkTest extends \PHPUnit\Framework\TestCase
         $data = array($str => $str);
         $data['_PAGE_'] = TemplatePage::LINKLIST;
         $data['_LOGGEDIN_'] = false;
+        $data['_BASE_PATH_'] = '/subfolder';
 
         $data = hook_addlink_toolbar_render_header($data);
         $this->assertEquals($str, $data[$str]);
-- 
cgit v1.2.3


From 301c7ab1a079d937ab41c6f52b8804e5731008e6 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 28 Jul 2020 20:46:11 +0200
Subject: Better support for notes permalink

---
 tests/api/controllers/links/PostLinkTest.php | 4 ++--
 tests/api/controllers/links/PutLinkTest.php  | 4 ++--
 tests/bookmark/BookmarkFileServiceTest.php   | 4 ++--
 tests/bookmark/BookmarkTest.php              | 4 ++--
 4 files changed, 8 insertions(+), 8 deletions(-)

(limited to 'tests')

diff --git a/tests/api/controllers/links/PostLinkTest.php b/tests/api/controllers/links/PostLinkTest.php
index b2dd09eb..4e791a04 100644
--- a/tests/api/controllers/links/PostLinkTest.php
+++ b/tests/api/controllers/links/PostLinkTest.php
@@ -131,8 +131,8 @@ class PostLinkTest extends TestCase
         $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('http://domain.tld/shaare/' . $data['shorturl'], $data['url']);
+        $this->assertEquals('/shaare/' . $data['shorturl'], $data['title']);
         $this->assertEquals('', $data['description']);
         $this->assertEquals([], $data['tags']);
         $this->assertEquals(true, $data['private']);
diff --git a/tests/api/controllers/links/PutLinkTest.php b/tests/api/controllers/links/PutLinkTest.php
index cb63742e..302cac0f 100644
--- a/tests/api/controllers/links/PutLinkTest.php
+++ b/tests/api/controllers/links/PutLinkTest.php
@@ -114,8 +114,8 @@ class PutLinkTest extends \PHPUnit\Framework\TestCase
         $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('http://domain.tld/shaare/WDWyig', $data['url']);
+        $this->assertEquals('/shaare/WDWyig', $data['title']);
         $this->assertEquals('', $data['description']);
         $this->assertEquals([], $data['tags']);
         $this->assertEquals(true, $data['private']);
diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php
index b19c8250..a8bf47cb 100644
--- a/tests/bookmark/BookmarkFileServiceTest.php
+++ b/tests/bookmark/BookmarkFileServiceTest.php
@@ -200,7 +200,7 @@ class BookmarkFileServiceTest extends TestCase
 
         $bookmark = $this->privateLinkDB->get(43);
         $this->assertEquals(43, $bookmark->getId());
-        $this->assertRegExp('/\?[\w\-]{6}/', $bookmark->getUrl());
+        $this->assertRegExp('#/shaare/[\w\-]{6}#', $bookmark->getUrl());
         $this->assertRegExp('/[\w\-]{6}/', $bookmark->getShortUrl());
         $this->assertEquals($bookmark->getUrl(), $bookmark->getTitle());
         $this->assertEmpty($bookmark->getDescription());
@@ -216,7 +216,7 @@ class BookmarkFileServiceTest extends TestCase
 
         $bookmark = $this->privateLinkDB->get(43);
         $this->assertEquals(43, $bookmark->getId());
-        $this->assertRegExp('/\?[\w\-]{6}/', $bookmark->getUrl());
+        $this->assertRegExp('#/shaare/[\w\-]{6}#', $bookmark->getUrl());
         $this->assertRegExp('/[\w\-]{6}/', $bookmark->getShortUrl());
         $this->assertEquals($bookmark->getUrl(), $bookmark->getTitle());
         $this->assertEmpty($bookmark->getDescription());
diff --git a/tests/bookmark/BookmarkTest.php b/tests/bookmark/BookmarkTest.php
index 9a3bbbfc..4b6a3c07 100644
--- a/tests/bookmark/BookmarkTest.php
+++ b/tests/bookmark/BookmarkTest.php
@@ -124,8 +124,8 @@ class BookmarkTest extends TestCase
         $this->assertEquals(1, $bookmark->getId());
         $this->assertEquals('abc', $bookmark->getShortUrl());
         $this->assertEquals($date, $bookmark->getCreated());
-        $this->assertEquals('?abc', $bookmark->getUrl());
-        $this->assertEquals('?abc', $bookmark->getTitle());
+        $this->assertEquals('/shaare/abc', $bookmark->getUrl());
+        $this->assertEquals('/shaare/abc', $bookmark->getTitle());
         $this->assertEquals('', $bookmark->getDescription());
         $this->assertEquals([], $bookmark->getTags());
         $this->assertEquals('', $bookmark->getTagsString());
-- 
cgit v1.2.3


From f7f08ceec1b218e1525153e8bd3d0199f2fb1c9d Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 28 Jul 2020 22:24:41 +0200
Subject: Fix basePath in unit tests reference DB

---
 tests/api/controllers/links/GetLinkIdTest.php |  2 +-
 tests/api/controllers/links/GetLinksTest.php  |  2 +-
 tests/bookmark/BookmarkFileServiceTest.php    |  4 ++--
 tests/feed/FeedBuilderTest.php                | 18 +++++++++---------
 tests/netscape/BookmarkExportTest.php         |  4 ++--
 tests/updater/UpdaterTest.php                 | 14 ++++++--------
 tests/utils/ReferenceLinkDB.php               |  8 ++++----
 7 files changed, 25 insertions(+), 27 deletions(-)

(limited to 'tests')

diff --git a/tests/api/controllers/links/GetLinkIdTest.php b/tests/api/controllers/links/GetLinkIdTest.php
index c26411ac..8bb81dc8 100644
--- a/tests/api/controllers/links/GetLinkIdTest.php
+++ b/tests/api/controllers/links/GetLinkIdTest.php
@@ -102,7 +102,7 @@ class GetLinkIdTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals($id, $data['id']);
 
         // Check link elements
-        $this->assertEquals('http://domain.tld/?WDWyig', $data['url']);
+        $this->assertEquals('http://domain.tld/shaare/WDWyig', $data['url']);
         $this->assertEquals('WDWyig', $data['shorturl']);
         $this->assertEquals('Link title: @website', $data['title']);
         $this->assertEquals(
diff --git a/tests/api/controllers/links/GetLinksTest.php b/tests/api/controllers/links/GetLinksTest.php
index 4e2d55ac..d02e6fad 100644
--- a/tests/api/controllers/links/GetLinksTest.php
+++ b/tests/api/controllers/links/GetLinksTest.php
@@ -109,7 +109,7 @@ class GetLinksTest extends \PHPUnit\Framework\TestCase
 
         // Check first element fields
         $first = $data[2];
-        $this->assertEquals('http://domain.tld/?WDWyig', $first['url']);
+        $this->assertEquals('http://domain.tld/shaare/WDWyig', $first['url']);
         $this->assertEquals('WDWyig', $first['shorturl']);
         $this->assertEquals('Link title: @website', $first['title']);
         $this->assertEquals(
diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php
index a8bf47cb..7b1906d3 100644
--- a/tests/bookmark/BookmarkFileServiceTest.php
+++ b/tests/bookmark/BookmarkFileServiceTest.php
@@ -340,7 +340,7 @@ class BookmarkFileServiceTest extends TestCase
 
         $bookmark = $this->privateLinkDB->get(42);
         $this->assertEquals(42, $bookmark->getId());
-        $this->assertEquals('?WDWyig', $bookmark->getUrl());
+        $this->assertEquals('/shaare/WDWyig', $bookmark->getUrl());
         $this->assertEquals('1eYJ1Q', $bookmark->getShortUrl());
         $this->assertEquals('Note: I have a big ID but an old date', $bookmark->getTitle());
         $this->assertEquals('Used to test bookmarks reordering.', $bookmark->getDescription());
@@ -359,7 +359,7 @@ class BookmarkFileServiceTest extends TestCase
 
         $bookmark = $this->privateLinkDB->get(42);
         $this->assertEquals(42, $bookmark->getId());
-        $this->assertEquals('?WDWyig', $bookmark->getUrl());
+        $this->assertEquals('/shaare/WDWyig', $bookmark->getUrl());
         $this->assertEquals('1eYJ1Q', $bookmark->getShortUrl());
         $this->assertEquals('Note: I have a big ID but an old date', $bookmark->getTitle());
         $this->assertEquals('Used to test bookmarks reordering.', $bookmark->getDescription());
diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php
index b2b70b70..5c2aaedb 100644
--- a/tests/feed/FeedBuilderTest.php
+++ b/tests/feed/FeedBuilderTest.php
@@ -90,15 +90,15 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $link = $data['links'][array_keys($data['links'])[2]];
         $this->assertEquals(41, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
-        $this->assertEquals('http://host.tld/?WDWyig', $link['guid']);
-        $this->assertEquals('http://host.tld/?WDWyig', $link['url']);
+        $this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']);
+        $this->assertEquals('http://host.tld/shaare/WDWyig', $link['url']);
         $this->assertRegExp('/Tue, 10 Mar 2015 11:46:51 \+\d{4}/', $link['pub_iso_date']);
         $pub = DateTime::createFromFormat(DateTime::RSS, $link['pub_iso_date']);
         $up = DateTime::createFromFormat(DateTime::ATOM, $link['up_iso_date']);
         $this->assertEquals($pub, $up);
         $this->assertContains('Stallman has a beard', $link['description']);
         $this->assertContains('Permalink', $link['description']);
-        $this->assertContains('http://host.tld/?WDWyig', $link['description']);
+        $this->assertContains('http://host.tld/shaare/WDWyig', $link['description']);
         $this->assertEquals(1, count($link['taglist']));
         $this->assertEquals('sTuff', $link['taglist'][0]);
 
@@ -198,15 +198,15 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $link = $data['links'][array_keys($data['links'])[2]];
         $this->assertEquals(41, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
-        $this->assertEquals('http://host.tld/?WDWyig', $link['guid']);
-        $this->assertEquals('http://host.tld/?WDWyig', $link['url']);
+        $this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']);
+        $this->assertEquals('http://host.tld/shaare/WDWyig', $link['url']);
         $this->assertContains('Direct link', $link['description']);
-        $this->assertContains('http://host.tld/?WDWyig', $link['description']);
+        $this->assertContains('http://host.tld/shaare/WDWyig', $link['description']);
         // Second link is a direct link
         $link = $data['links'][array_keys($data['links'])[3]];
         $this->assertEquals(8, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114633'), $link['created']);
-        $this->assertEquals('http://host.tld/?RttfEw', $link['guid']);
+        $this->assertEquals('http://host.tld/shaare/RttfEw', $link['guid']);
         $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['url']);
         $this->assertContains('Direct link', $link['description']);
         $this->assertContains('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['description']);
@@ -271,8 +271,8 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
 
         // Test first link (note link)
         $link = $data['links'][array_keys($data['links'])[2]];
-        $this->assertEquals('http://host.tld:8080/~user/shaarli/?WDWyig', $link['guid']);
-        $this->assertEquals('http://host.tld:8080/~user/shaarli/?WDWyig', $link['url']);
+        $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['guid']);
+        $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['url']);
         $this->assertContains('http://host.tld:8080/~user/shaarli/./add-tag/hashtag', $link['description']);
     }
 }
diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php
index 344c1dc0..509da51d 100644
--- a/tests/netscape/BookmarkExportTest.php
+++ b/tests/netscape/BookmarkExportTest.php
@@ -177,7 +177,7 @@ class BookmarkExportTest extends TestCase
             ''
         );
         $this->assertEquals(
-            '?WDWyig',
+            '/shaare/WDWyig',
             $links[2]['url']
         );
     }
@@ -195,7 +195,7 @@ class BookmarkExportTest extends TestCase
             $indexUrl
         );
         $this->assertEquals(
-            $indexUrl . '?WDWyig',
+            $indexUrl . 'shaare/WDWyig',
             $links[2]['url']
         );
     }
diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php
index c801d451..a7dd70bf 100644
--- a/tests/updater/UpdaterTest.php
+++ b/tests/updater/UpdaterTest.php
@@ -2,6 +2,7 @@
 namespace Shaarli\Updater;
 
 use Exception;
+use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
@@ -12,7 +13,7 @@ use Shaarli\History;
  * Class UpdaterTest.
  * Runs unit tests against the updater class.
  */
-class UpdaterTest extends \PHPUnit\Framework\TestCase
+class UpdaterTest extends TestCase
 {
     /**
      * @var string Path to test datastore.
@@ -194,7 +195,6 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase
 
     public function testUpdateMethodRelativeHomeLinkDoNotRename(): void
     {
-        $this->updater->setBasePath('/subfolder');
         $this->conf->set('general.header_link', '~/my-blog');
 
         $this->updater->updateMethodRelativeHomeLink();
@@ -204,8 +204,6 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase
 
     public function testUpdateMethodMigrateExistingNotesUrl(): void
     {
-        $this->updater->setBasePath('/subfolder');
-
         $this->updater->updateMethodMigrateExistingNotesUrl();
 
         static::assertSame($this->refDB->getLinks()[0]->getUrl(), $this->bookmarkService->get(0)->getUrl());
@@ -215,9 +213,9 @@ class UpdaterTest extends \PHPUnit\Framework\TestCase
         static::assertSame($this->refDB->getLinks()[7]->getUrl(), $this->bookmarkService->get(7)->getUrl());
         static::assertSame($this->refDB->getLinks()[8]->getUrl(), $this->bookmarkService->get(8)->getUrl());
         static::assertSame($this->refDB->getLinks()[9]->getUrl(), $this->bookmarkService->get(9)->getUrl());
-        static::assertSame('/subfolder/shaare/WDWyig', $this->bookmarkService->get(42)->getUrl());
-        static::assertSame('/subfolder/shaare/WDWyig', $this->bookmarkService->get(41)->getUrl());
-        static::assertSame('/subfolder/shaare/0gCTjQ', $this->bookmarkService->get(10)->getUrl());
-        static::assertSame('/subfolder/shaare/PCRizQ', $this->bookmarkService->get(11)->getUrl());
+        static::assertSame('/shaare/WDWyig', $this->bookmarkService->get(42)->getUrl());
+        static::assertSame('/shaare/WDWyig', $this->bookmarkService->get(41)->getUrl());
+        static::assertSame('/shaare/0gCTjQ', $this->bookmarkService->get(10)->getUrl());
+        static::assertSame('/shaare/PCRizQ', $this->bookmarkService->get(11)->getUrl());
     }
 }
diff --git a/tests/utils/ReferenceLinkDB.php b/tests/utils/ReferenceLinkDB.php
index 0095f5a1..fc3cb109 100644
--- a/tests/utils/ReferenceLinkDB.php
+++ b/tests/utils/ReferenceLinkDB.php
@@ -30,7 +30,7 @@ class ReferenceLinkDB
         $this->addLink(
             11,
             'Pined older',
-            '?PCRizQ',
+            '/shaare/PCRizQ',
             'This is an older pinned link',
             0,
             DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20100309_101010'),
@@ -43,7 +43,7 @@ class ReferenceLinkDB
         $this->addLink(
             10,
             'Pined',
-            '?0gCTjQ',
+            '/shaare/0gCTjQ',
             'This is a pinned link',
             0,
             DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121207_152312'),
@@ -56,7 +56,7 @@ class ReferenceLinkDB
         $this->addLink(
             41,
             'Link title: @website',
-            '?WDWyig',
+            '/shaare/WDWyig',
             'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag',
             0,
             DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'),
@@ -68,7 +68,7 @@ class ReferenceLinkDB
         $this->addLink(
             42,
             'Note: I have a big ID but an old date',
-            '?WDWyig',
+            '/shaare/WDWyig',
             'Used to test bookmarks reordering.',
             0,
             DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20100310_101010'),
-- 
cgit v1.2.3


From d6e5f04d3987e498c5cb859eed6bff33d67949df Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Sat, 1 Aug 2020 11:10:57 +0200
Subject: Remove anonymous permission and initialize bookmarks on login

---
 tests/bookmark/BookmarkInitializerTest.php               | 14 +++++++++-----
 tests/front/controller/visitor/InstallControllerTest.php |  3 ---
 2 files changed, 9 insertions(+), 8 deletions(-)

(limited to 'tests')

diff --git a/tests/bookmark/BookmarkInitializerTest.php b/tests/bookmark/BookmarkInitializerTest.php
index d23eb069..3906cc7f 100644
--- a/tests/bookmark/BookmarkInitializerTest.php
+++ b/tests/bookmark/BookmarkInitializerTest.php
@@ -3,7 +3,6 @@
 namespace Shaarli\Bookmark;
 
 use PHPUnit\Framework\TestCase;
-use ReferenceLinkDB;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
 
@@ -54,9 +53,9 @@ class BookmarkInitializerTest extends TestCase
     }
 
     /**
-     * Test initialize() with an empty data store.
+     * Test initialize() with a data store containing bookmarks.
      */
-    public function testInitializeEmptyDataStore()
+    public function testInitializeNotEmptyDataStore(): void
     {
         $refDB = new \ReferenceLinkDB();
         $refDB->write(self::$testDatastore);
@@ -79,6 +78,8 @@ class BookmarkInitializerTest extends TestCase
         );
         $this->assertFalse($bookmark->isPrivate());
 
+        $this->bookmarkService->save();
+
         // Reload from file
         $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
         $this->assertEquals($refDB->countLinks() + 2, $this->bookmarkService->count());
@@ -97,10 +98,13 @@ class BookmarkInitializerTest extends TestCase
     }
 
     /**
-     * Test initialize() with a data store containing bookmarks.
+     * Test initialize() with an a non existent datastore file .
      */
-    public function testInitializeNotEmptyDataStore()
+    public function testInitializeNonExistentDataStore(): void
     {
+        $this->conf->set('resource.datastore', static::$testDatastore . '_empty');
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+
         $this->initializer->initialize();
 
         $this->assertEquals(2, $this->bookmarkService->count());
diff --git a/tests/front/controller/visitor/InstallControllerTest.php b/tests/front/controller/visitor/InstallControllerTest.php
index 089c64ac..3b855365 100644
--- a/tests/front/controller/visitor/InstallControllerTest.php
+++ b/tests/front/controller/visitor/InstallControllerTest.php
@@ -224,9 +224,6 @@ class InstallControllerTest extends TestCase
         ;
         $this->container->conf->expects(static::once())->method('write');
 
-        $this->container->bookmarkService->expects(static::once())->method('count')->willReturn(0);
-        $this->container->bookmarkService->expects(static::once())->method('initialize');
-
         $this->container->sessionManager
             ->expects(static::once())
             ->method('setSessionParameter')
-- 
cgit v1.2.3


From bedbb845eec20363b928b424143787dbe988eefe Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Thu, 13 Aug 2020 11:08:13 +0200
Subject: Move all admin controller into a dedicated group

Also handle authentication check in a new middleware for the admin group.
---
 tests/front/ShaarliAdminMiddlewareTest.php         | 100 +++++++++++++++++++++
 tests/front/ShaarliMiddlewareTest.php              |   2 +-
 .../admin/SessionFilterControllerTest.php          |  51 -----------
 .../admin/ShaarliAdminControllerTest.php           |  15 ----
 .../visitor/PublicSessionFilterControllerTest.php  |  51 +++++++++++
 tests/legacy/LegacyControllerTest.php              |   4 +-
 6 files changed, 154 insertions(+), 69 deletions(-)
 create mode 100644 tests/front/ShaarliAdminMiddlewareTest.php

(limited to 'tests')

diff --git a/tests/front/ShaarliAdminMiddlewareTest.php b/tests/front/ShaarliAdminMiddlewareTest.php
new file mode 100644
index 00000000..7451330b
--- /dev/null
+++ b/tests/front/ShaarliAdminMiddlewareTest.php
@@ -0,0 +1,100 @@
+container = $this->createMock(ShaarliContainer::class);
+
+        touch(static::TMP_MOCK_FILE);
+
+        $this->container->conf = $this->createMock(ConfigManager::class);
+        $this->container->conf->method('getConfigFileExt')->willReturn(static::TMP_MOCK_FILE);
+
+        $this->container->loginManager = $this->createMock(LoginManager::class);
+        $this->container->updater = $this->createMock(Updater::class);
+
+        $this->container->environment = ['REQUEST_URI' => 'http://shaarli/subfolder/path'];
+
+        $this->middleware = new ShaarliAdminMiddleware($this->container);
+    }
+
+    public function tearDown(): void
+    {
+        unlink(static::TMP_MOCK_FILE);
+    }
+
+    /**
+     * Try to access an admin controller while logged out -> redirected to login page.
+     */
+    public function testMiddlewareWhileLoggedOut(): void
+    {
+        $this->container->loginManager->expects(static::once())->method('isLoggedIn')->willReturn(false);
+
+        $request = $this->createMock(Request::class);
+        $request->method('getUri')->willReturnCallback(function (): Uri {
+            $uri = $this->createMock(Uri::class);
+            $uri->method('getBasePath')->willReturn('/subfolder');
+
+            return $uri;
+        });
+
+        $response = new Response();
+
+        /** @var Response $result */
+        $result = $this->middleware->__invoke($request, $response, function () {});
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(
+            '/subfolder/login?returnurl=' . urlencode('http://shaarli/subfolder/path'),
+            $result->getHeader('location')[0]
+        );
+    }
+
+    /**
+     * Process controller while logged in.
+     */
+    public function testMiddlewareWhileLoggedIn(): void
+    {
+        $this->container->loginManager->method('isLoggedIn')->willReturn(true);
+
+        $request = $this->createMock(Request::class);
+        $request->method('getUri')->willReturnCallback(function (): Uri {
+            $uri = $this->createMock(Uri::class);
+            $uri->method('getBasePath')->willReturn('/subfolder');
+
+            return $uri;
+        });
+
+        $response = new Response();
+        $controller = function (Request $request, Response $response): Response {
+            return $response->withStatus(418); // I'm a tea pot
+        };
+
+        /** @var Response $result */
+        $result = $this->middleware->__invoke($request, $response, $controller);
+
+        static::assertSame(418, $result->getStatusCode());
+    }
+}
diff --git a/tests/front/ShaarliMiddlewareTest.php b/tests/front/ShaarliMiddlewareTest.php
index 09bebd04..d435f506 100644
--- a/tests/front/ShaarliMiddlewareTest.php
+++ b/tests/front/ShaarliMiddlewareTest.php
@@ -43,7 +43,7 @@ class ShaarliMiddlewareTest extends TestCase
         $this->middleware = new ShaarliMiddleware($this->container);
     }
 
-    public function tearDown()
+    public function tearDown(): void
     {
         unlink(static::TMP_MOCK_FILE);
     }
diff --git a/tests/front/controller/admin/SessionFilterControllerTest.php b/tests/front/controller/admin/SessionFilterControllerTest.php
index 7d5511ed..d306c6e9 100644
--- a/tests/front/controller/admin/SessionFilterControllerTest.php
+++ b/tests/front/controller/admin/SessionFilterControllerTest.php
@@ -174,55 +174,4 @@ class SessionFilterControllerTest extends TestCase
         static::assertSame(302, $result->getStatusCode());
         static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
     }
-
-    /**
-     * Untagged only - valid call
-     */
-    public function testUntaggedOnly(): void
-    {
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
-
-        $request = $this->createMock(Request::class);
-        $response = new Response();
-
-        $this->container->sessionManager
-            ->expects(static::once())
-            ->method('setSessionParameter')
-            ->with(SessionManager::KEY_UNTAGGED_ONLY, true)
-        ;
-
-        $result = $this->controller->untaggedOnly($request, $response);
-
-        static::assertInstanceOf(Response::class, $result);
-        static::assertSame(302, $result->getStatusCode());
-        static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
-    }
-
-    /**
-     * Untagged only - toggle off
-     */
-    public function testUntaggedOnlyToggleOff(): void
-    {
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
-
-        $request = $this->createMock(Request::class);
-        $response = new Response();
-
-        $this->container->sessionManager
-            ->method('getSessionParameter')
-            ->with(SessionManager::KEY_UNTAGGED_ONLY)
-            ->willReturn(true)
-        ;
-        $this->container->sessionManager
-            ->expects(static::once())
-            ->method('setSessionParameter')
-            ->with(SessionManager::KEY_UNTAGGED_ONLY, false)
-        ;
-
-        $result = $this->controller->untaggedOnly($request, $response);
-
-        static::assertInstanceOf(Response::class, $result);
-        static::assertSame(302, $result->getStatusCode());
-        static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
-    }
 }
diff --git a/tests/front/controller/admin/ShaarliAdminControllerTest.php b/tests/front/controller/admin/ShaarliAdminControllerTest.php
index 7c5f50a6..fff427cb 100644
--- a/tests/front/controller/admin/ShaarliAdminControllerTest.php
+++ b/tests/front/controller/admin/ShaarliAdminControllerTest.php
@@ -5,9 +5,7 @@ declare(strict_types=1);
 namespace Shaarli\Front\Controller\Admin;
 
 use PHPUnit\Framework\TestCase;
-use Shaarli\Front\Exception\UnauthorizedException;
 use Shaarli\Front\Exception\WrongTokenException;
-use Shaarli\Security\LoginManager;
 use Shaarli\Security\SessionManager;
 use Slim\Http\Request;
 
@@ -52,19 +50,6 @@ class ShaarliAdminControllerTest extends TestCase
         };
     }
 
-    /**
-     * Creating an instance of an admin controller while logged out should raise an exception.
-     */
-    public function testInstantiateWhileLoggedOut(): void
-    {
-        $this->expectException(UnauthorizedException::class);
-
-        $this->container->loginManager = $this->createMock(LoginManager::class);
-        $this->container->loginManager->method('isLoggedIn')->willReturn(false);
-
-        $this->controller = new class($this->container) extends ShaarliAdminController {};
-    }
-
     /**
      * Trigger controller's checkToken with a valid token.
      */
diff --git a/tests/front/controller/visitor/PublicSessionFilterControllerTest.php b/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
index 3aa1cb99..06352750 100644
--- a/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
+++ b/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
@@ -68,4 +68,55 @@ class PublicSessionFilterControllerTest extends TestCase
         static::assertSame(302, $result->getStatusCode());
         static::assertSame(['/subfolder/'], $result->getHeader('location'));
     }
+
+    /**
+     * Untagged only - valid call
+     */
+    public function testUntaggedOnly(): void
+    {
+        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->sessionManager
+            ->expects(static::once())
+            ->method('setSessionParameter')
+            ->with(SessionManager::KEY_UNTAGGED_ONLY, true)
+        ;
+
+        $result = $this->controller->untaggedOnly($request, $response);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
+    }
+
+    /**
+     * Untagged only - toggle off
+     */
+    public function testUntaggedOnlyToggleOff(): void
+    {
+        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->sessionManager
+            ->method('getSessionParameter')
+            ->with(SessionManager::KEY_UNTAGGED_ONLY)
+            ->willReturn(true)
+        ;
+        $this->container->sessionManager
+            ->expects(static::once())
+            ->method('setSessionParameter')
+            ->with(SessionManager::KEY_UNTAGGED_ONLY, false)
+        ;
+
+        $result = $this->controller->untaggedOnly($request, $response);
+
+        static::assertInstanceOf(Response::class, $result);
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
+    }
 }
diff --git a/tests/legacy/LegacyControllerTest.php b/tests/legacy/LegacyControllerTest.php
index ff4520a3..759a5b2a 100644
--- a/tests/legacy/LegacyControllerTest.php
+++ b/tests/legacy/LegacyControllerTest.php
@@ -73,8 +73,8 @@ class LegacyControllerTest extends TestCase
             ['addlink', [], '/login', false],
             ['login', [], '/login', true],
             ['login', [], '/login', false],
-            ['logout', [], '/logout', true],
-            ['logout', [], '/logout', false],
+            ['logout', [], '/admin/logout', true],
+            ['logout', [], '/admin/logout', false],
             ['picwall', [], '/picture-wall', false],
             ['picwall', [], '/picture-wall', true],
             ['tagcloud', [], '/tags/cloud', false],
-- 
cgit v1.2.3


From 0c6fdbe12bbbb336348666b14b82096f24d5858b Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Fri, 21 Aug 2020 10:50:44 +0200
Subject: Move error handling to dedicated controller instead of middleware

---
 tests/front/ShaarliMiddlewareTest.php              | 29 +++++----
 .../controller/visitor/ErrorControllerTest.php     | 70 ++++++++++++++++++++++
 2 files changed, 84 insertions(+), 15 deletions(-)
 create mode 100644 tests/front/controller/visitor/ErrorControllerTest.php

(limited to 'tests')

diff --git a/tests/front/ShaarliMiddlewareTest.php b/tests/front/ShaarliMiddlewareTest.php
index d435f506..05aa34a9 100644
--- a/tests/front/ShaarliMiddlewareTest.php
+++ b/tests/front/ShaarliMiddlewareTest.php
@@ -74,7 +74,8 @@ class ShaarliMiddlewareTest extends TestCase
     }
 
     /**
-     * Test middleware execution with controller throwing a known front exception
+     * Test middleware execution with controller throwing a known front exception.
+     * The exception should be thrown to be later handled by the error handler.
      */
     public function testMiddlewareExecutionWithFrontException(): void
     {
@@ -99,16 +100,14 @@ class ShaarliMiddlewareTest extends TestCase
         });
         $this->container->pageBuilder = $pageBuilder;
 
-        /** @var Response $result */
-        $result = $this->middleware->__invoke($request, $response, $controller);
+        $this->expectException(LoginBannedException::class);
 
-        static::assertInstanceOf(Response::class, $result);
-        static::assertSame(401, $result->getStatusCode());
-        static::assertContains('error', (string) $result->getBody());
+        $this->middleware->__invoke($request, $response, $controller);
     }
 
     /**
      * Test middleware execution with controller throwing a not authorized exception
+     * The middle should send a redirection response to the login page.
      */
     public function testMiddlewareExecutionWithUnauthorizedException(): void
     {
@@ -136,9 +135,10 @@ class ShaarliMiddlewareTest extends TestCase
     }
 
     /**
-     * Test middleware execution with controller throwing a not authorized exception
+     * Test middleware execution with controller throwing a not authorized exception.
+     * The exception should be thrown to be later handled by the error handler.
      */
-    public function testMiddlewareExecutionWithServerExceptionWith(): void
+    public function testMiddlewareExecutionWithServerException(): void
     {
         $request = $this->createMock(Request::class);
         $request->method('getUri')->willReturnCallback(function (): Uri {
@@ -148,9 +148,11 @@ class ShaarliMiddlewareTest extends TestCase
             return $uri;
         });
 
+        $dummyException = new class() extends \Exception {};
+
         $response = new Response();
-        $controller = function (): void {
-            throw new \Exception();
+        $controller = function () use ($dummyException): void {
+            throw $dummyException;
         };
 
         $parameters = [];
@@ -165,12 +167,9 @@ class ShaarliMiddlewareTest extends TestCase
             })
         ;
 
-        /** @var Response $result */
-        $result = $this->middleware->__invoke($request, $response, $controller);
+        $this->expectException(get_class($dummyException));
 
-        static::assertSame(500, $result->getStatusCode());
-        static::assertContains('error', (string) $result->getBody());
-        static::assertSame('An unexpected error occurred.', $parameters['message']);
+        $this->middleware->__invoke($request, $response, $controller);
     }
 
     public function testMiddlewareExecutionWithUpdates(): void
diff --git a/tests/front/controller/visitor/ErrorControllerTest.php b/tests/front/controller/visitor/ErrorControllerTest.php
new file mode 100644
index 00000000..e497bfef
--- /dev/null
+++ b/tests/front/controller/visitor/ErrorControllerTest.php
@@ -0,0 +1,70 @@
+createContainer();
+
+        $this->controller = new ErrorController($this->container);
+    }
+
+    /**
+     * Test displaying error with a ShaarliFrontException: display exception message and use its code for HTTTP code
+     */
+    public function testDisplayFrontExceptionError(): void
+    {
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $message = 'error message';
+        $errorCode = 418;
+
+        // Save RainTPL assigned variables
+        $assignedVariables = [];
+        $this->assignTemplateVars($assignedVariables);
+
+        $result = ($this->controller)(
+            $request,
+            $response,
+            new class($message, $errorCode) extends ShaarliFrontException {}
+        );
+
+        static::assertSame($errorCode, $result->getStatusCode());
+        static::assertSame($message, $assignedVariables['message']);
+        static::assertArrayNotHasKey('stacktrace', $assignedVariables);
+    }
+
+    /**
+     * Test displaying error with any exception (no debug): only display an error occurred with HTTP 500.
+     */
+    public function testDisplayAnyExceptionErrorNoDebug(): void
+    {
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        // Save RainTPL assigned variables
+        $assignedVariables = [];
+        $this->assignTemplateVars($assignedVariables);
+
+        $result = ($this->controller)($request, $response, new \Exception('abc'));
+
+        static::assertSame(500, $result->getStatusCode());
+        static::assertSame('An unexpected error occurred.', $assignedVariables['message']);
+        static::assertArrayNotHasKey('stacktrace', $assignedVariables);
+    }
+}
-- 
cgit v1.2.3


From 7e3dc0ba98bf019c2804e5c74fb6061b16fb712f Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Thu, 27 Aug 2020 12:04:36 +0200
Subject: Better handling of plugin incompatibility

If a PHP is raised while executing plugin hook, Shaarli will display an error instead of rendering the error page (or just ending in fatal error for default hooks).
Also added phpErrorHandler which is handled differently that regular errorHandler by Slim.:
---
 tests/PluginManagerTest.php              | 29 +++++++++++++++++++++++------
 tests/container/ContainerBuilderTest.php | 23 ++++++++++++++---------
 tests/plugins/test/test.php              |  5 +++++
 3 files changed, 42 insertions(+), 15 deletions(-)

(limited to 'tests')

diff --git a/tests/PluginManagerTest.php b/tests/PluginManagerTest.php
index 195d959c..a5d5dbe9 100644
--- a/tests/PluginManagerTest.php
+++ b/tests/PluginManagerTest.php
@@ -25,7 +25,7 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase
      */
     protected $pluginManager;
 
-    public function setUp()
+    public function setUp(): void
     {
         $conf = new ConfigManager('');
         $this->pluginManager = new PluginManager($conf);
@@ -33,10 +33,8 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test plugin loading and hook execution.
-     *
-     * @return void
      */
-    public function testPlugin()
+    public function testPlugin(): void
     {
         PluginManager::$PLUGINS_PATH = self::$pluginPath;
         $this->pluginManager->load(array(self::$pluginName));
@@ -56,10 +54,29 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals('loggedin', $data[1]);
     }
 
+    /**
+     * Test plugin loading and hook execution with an error: raise an incompatibility error.
+     */
+    public function testPluginWithPhpError(): void
+    {
+        PluginManager::$PLUGINS_PATH = self::$pluginPath;
+        $this->pluginManager->load(array(self::$pluginName));
+
+        $this->assertTrue(function_exists('hook_test_error'));
+
+        $data = [];
+        $this->pluginManager->executeHooks('error', $data);
+
+        $this->assertSame(
+            'test [plugin incompatibility]: Class \'Unknown\' not found',
+            $this->pluginManager->getErrors()[0]
+        );
+    }
+
     /**
      * Test missing plugin loading.
      */
-    public function testPluginNotFound()
+    public function testPluginNotFound(): void
     {
         $this->pluginManager->load(array());
         $this->pluginManager->load(array('nope', 'renope'));
@@ -69,7 +86,7 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase
     /**
      * Test plugin metadata loading.
      */
-    public function testGetPluginsMeta()
+    public function testGetPluginsMeta(): void
     {
         PluginManager::$PLUGINS_PATH = self::$pluginPath;
         $this->pluginManager->load(array(self::$pluginName));
diff --git a/tests/container/ContainerBuilderTest.php b/tests/container/ContainerBuilderTest.php
index fa77bf31..c08010ae 100644
--- a/tests/container/ContainerBuilderTest.php
+++ b/tests/container/ContainerBuilderTest.php
@@ -9,6 +9,7 @@ use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Feed\FeedBuilder;
 use Shaarli\Formatter\FormatterFactory;
+use Shaarli\Front\Controller\Visitor\ErrorController;
 use Shaarli\History;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Netscape\NetscapeBookmarkUtils;
@@ -20,6 +21,7 @@ use Shaarli\Security\LoginManager;
 use Shaarli\Security\SessionManager;
 use Shaarli\Thumbnailer;
 use Shaarli\Updater\Updater;
+use Slim\Http\Environment;
 
 class ContainerBuilderTest extends TestCase
 {
@@ -59,20 +61,23 @@ class ContainerBuilderTest extends TestCase
     {
         $container = $this->containerBuilder->build();
 
-        static::assertInstanceOf(ConfigManager::class, $container->conf);
-        static::assertInstanceOf(SessionManager::class, $container->sessionManager);
+        static::assertInstanceOf(BookmarkServiceInterface::class, $container->bookmarkService);
         static::assertInstanceOf(CookieManager::class, $container->cookieManager);
-        static::assertInstanceOf(LoginManager::class, $container->loginManager);
+        static::assertInstanceOf(ConfigManager::class, $container->conf);
+        static::assertInstanceOf(ErrorController::class, $container->errorHandler);
+        static::assertInstanceOf(Environment::class, $container->environment);
+        static::assertInstanceOf(FeedBuilder::class, $container->feedBuilder);
+        static::assertInstanceOf(FormatterFactory::class, $container->formatterFactory);
         static::assertInstanceOf(History::class, $container->history);
-        static::assertInstanceOf(BookmarkServiceInterface::class, $container->bookmarkService);
+        static::assertInstanceOf(HttpAccess::class, $container->httpAccess);
+        static::assertInstanceOf(LoginManager::class, $container->loginManager);
+        static::assertInstanceOf(NetscapeBookmarkUtils::class, $container->netscapeBookmarkUtils);
         static::assertInstanceOf(PageBuilder::class, $container->pageBuilder);
-        static::assertInstanceOf(PluginManager::class, $container->pluginManager);
-        static::assertInstanceOf(FormatterFactory::class, $container->formatterFactory);
         static::assertInstanceOf(PageCacheManager::class, $container->pageCacheManager);
-        static::assertInstanceOf(FeedBuilder::class, $container->feedBuilder);
+        static::assertInstanceOf(ErrorController::class, $container->phpErrorHandler);
+        static::assertInstanceOf(PluginManager::class, $container->pluginManager);
+        static::assertInstanceOf(SessionManager::class, $container->sessionManager);
         static::assertInstanceOf(Thumbnailer::class, $container->thumbnailer);
-        static::assertInstanceOf(HttpAccess::class, $container->httpAccess);
-        static::assertInstanceOf(NetscapeBookmarkUtils::class, $container->netscapeBookmarkUtils);
         static::assertInstanceOf(Updater::class, $container->updater);
 
         // Set by the middleware
diff --git a/tests/plugins/test/test.php b/tests/plugins/test/test.php
index 2aaf5122..ae5032dd 100644
--- a/tests/plugins/test/test.php
+++ b/tests/plugins/test/test.php
@@ -19,3 +19,8 @@ function hook_test_random($data)
 
     return $data;
 }
+
+function hook_test_error()
+{
+    new Unknown();
+}
-- 
cgit v1.2.3


From 8af1d2da60a80f87cdc90ef308353dced34a43e9 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Thu, 27 Aug 2020 15:26:52 +0200
Subject: Fix UT

---
 tests/front/controller/admin/ConfigureControllerTest.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'tests')

diff --git a/tests/front/controller/admin/ConfigureControllerTest.php b/tests/front/controller/admin/ConfigureControllerTest.php
index f2f84bac..612f20f1 100644
--- a/tests/front/controller/admin/ConfigureControllerTest.php
+++ b/tests/front/controller/admin/ConfigureControllerTest.php
@@ -62,7 +62,7 @@ class ConfigureControllerTest extends TestCase
         static::assertSame('privacy.hide_public_links', $assignedVariables['hide_public_links']);
         static::assertSame('api.enabled', $assignedVariables['api_enabled']);
         static::assertSame('api.secret', $assignedVariables['api_secret']);
-        static::assertCount(4, $assignedVariables['languages']);
+        static::assertCount(5, $assignedVariables['languages']);
         static::assertArrayHasKey('gd_enabled', $assignedVariables);
         static::assertSame('thumbnails.mode', $assignedVariables['thumbnails_mode']);
     }
-- 
cgit v1.2.3


From 972daa4513420d3293d46a808ca2d5be0313e78b Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Sat, 29 Aug 2020 09:38:30 +0200
Subject: Default colors plugin: generate CSS file during initialization

Current behaviour only generate the custom CSS file when the plugin settings are saved, which can be annoying if the file is deleted but the settings are set.
Most common use case is Docker deployment, because the plugin directory is not mounted as a volume.
---
 tests/plugins/PluginDefaultColorsTest.php | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

(limited to 'tests')

diff --git a/tests/plugins/PluginDefaultColorsTest.php b/tests/plugins/PluginDefaultColorsTest.php
index b9951cca..9835dfa3 100644
--- a/tests/plugins/PluginDefaultColorsTest.php
+++ b/tests/plugins/PluginDefaultColorsTest.php
@@ -2,7 +2,6 @@
 
 namespace Shaarli\Plugin\DefaultColors;
 
-use DateTime;
 use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\LinkDB;
 use Shaarli\Config\ConfigManager;
@@ -57,6 +56,8 @@ class PluginDefaultColorsTest extends TestCase
         $conf->set('plugins.DEFAULT_COLORS_BACKGROUND', 'value');
         $errors = default_colors_init($conf);
         $this->assertEmpty($errors);
+
+        $this->assertFileExists($file = 'sandbox/default_colors/default_colors.css');
     }
 
     /**
@@ -72,9 +73,9 @@ class PluginDefaultColorsTest extends TestCase
     /**
      * Test the save plugin parameters hook with all colors specified.
      */
-    public function testSavePluginParametersAll()
+    public function testGenerateCssFile()
     {
-        $post = [
+        $params = [
             'other1' => true,
             'DEFAULT_COLORS_MAIN' => 'blue',
             'DEFAULT_COLORS_BACKGROUND' => 'pink',
@@ -82,7 +83,7 @@ class PluginDefaultColorsTest extends TestCase
             'DEFAULT_COLORS_DARK_MAIN' => 'green',
         ];
 
-        hook_default_colors_save_plugin_parameters($post);
+        default_colors_generate_css_file($params);
         $this->assertFileExists($file = 'sandbox/default_colors/default_colors.css');
         $content = file_get_contents($file);
         $expected = ':root {
@@ -98,16 +99,16 @@ class PluginDefaultColorsTest extends TestCase
     /**
      * Test the save plugin parameters hook with only one color specified.
      */
-    public function testSavePluginParametersSingle()
+    public function testGenerateCssFileSingle()
     {
-        $post = [
+        $params = [
             'other1' => true,
             'DEFAULT_COLORS_BACKGROUND' => 'pink',
             'other2' => ['yep'],
             'DEFAULT_COLORS_DARK_MAIN' => '',
         ];
 
-        hook_default_colors_save_plugin_parameters($post);
+        default_colors_generate_css_file($params);
         $this->assertFileExists($file = 'sandbox/default_colors/default_colors.css');
         $content = file_get_contents($file);
         $expected = ':root {
@@ -121,9 +122,9 @@ class PluginDefaultColorsTest extends TestCase
     /**
      * Test the save plugin parameters hook with no color specified.
      */
-    public function testSavePluginParametersNone()
+    public function testGenerateCssFileNone()
     {
-        hook_default_colors_save_plugin_parameters([]);
+        default_colors_generate_css_file([]);
         $this->assertFileNotExists($file = 'sandbox/default_colors/default_colors.css');
     }
 
-- 
cgit v1.2.3


From a8e210faa624517ee8b8978b7e659a0b3c689297 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Sat, 29 Aug 2020 10:06:40 +0200
Subject: Fixed: Pinned bookmarks are displayed first in ATOM/RSS feeds

Fixes #1485
---
 tests/feed/FeedBuilderTest.php | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

(limited to 'tests')

diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php
index 5c2aaedb..fe37d5f2 100644
--- a/tests/feed/FeedBuilderTest.php
+++ b/tests/feed/FeedBuilderTest.php
@@ -87,7 +87,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
 
         // Test first not pinned link (note link)
-        $link = $data['links'][array_keys($data['links'])[2]];
+        $link = $data['links'][array_keys($data['links'])[0]];
         $this->assertEquals(41, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
         $this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']);
@@ -128,7 +128,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
         $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
         $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['last_update']);
-        $link = $data['links'][array_keys($data['links'])[2]];
+        $link = $data['links'][array_keys($data['links'])[0]];
         $this->assertRegExp('/2015-03-10T11:46:51\+\d{2}:\d{2}/', $link['pub_iso_date']);
         $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links'][8]['up_iso_date']);
     }
@@ -173,7 +173,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $feedBuilder->setLocale(self::$LOCALE);
         $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, $criteria);
         $this->assertEquals(3, count($data['links']));
-        $link = $data['links'][array_keys($data['links'])[2]];
+        $link = $data['links'][array_keys($data['links'])[0]];
         $this->assertEquals(41, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
     }
@@ -195,7 +195,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
         $this->assertTrue($data['usepermalinks']);
         // First link is a permalink
-        $link = $data['links'][array_keys($data['links'])[2]];
+        $link = $data['links'][array_keys($data['links'])[0]];
         $this->assertEquals(41, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
         $this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']);
@@ -203,7 +203,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $this->assertContains('Direct link', $link['description']);
         $this->assertContains('http://host.tld/shaare/WDWyig', $link['description']);
         // Second link is a direct link
-        $link = $data['links'][array_keys($data['links'])[3]];
+        $link = $data['links'][array_keys($data['links'])[1]];
         $this->assertEquals(8, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114633'), $link['created']);
         $this->assertEquals('http://host.tld/shaare/RttfEw', $link['guid']);
@@ -270,7 +270,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         );
 
         // Test first link (note link)
-        $link = $data['links'][array_keys($data['links'])[2]];
+        $link = $data['links'][array_keys($data['links'])[0]];
         $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['guid']);
         $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['url']);
         $this->assertContains('http://host.tld:8080/~user/shaarli/./add-tag/hashtag', $link['description']);
-- 
cgit v1.2.3


From 63b0059ed55dceaa58396b7baeb2b490b57ce9cc Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Mon, 31 Aug 2020 13:58:09 +0200
Subject: Fix broken route to filter not tagged bookmarks

Also display the filter for visitors.

Fixes #1529
---
 tests/security/SessionManagerTest.php | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

(limited to 'tests')

diff --git a/tests/security/SessionManagerTest.php b/tests/security/SessionManagerTest.php
index 60695dcf..11a59f9c 100644
--- a/tests/security/SessionManagerTest.php
+++ b/tests/security/SessionManagerTest.php
@@ -207,15 +207,16 @@ class SessionManagerTest extends TestCase
             'expires_on' => time() + 1000,
             'username' => 'johndoe',
             'visibility' => 'public',
-            'untaggedonly' => false,
+            'untaggedonly' => true,
         ];
         $this->sessionManager->logout();
 
-        $this->assertFalse(isset($this->session['ip']));
-        $this->assertFalse(isset($this->session['expires_on']));
-        $this->assertFalse(isset($this->session['username']));
-        $this->assertFalse(isset($this->session['visibility']));
-        $this->assertFalse(isset($this->session['untaggedonly']));
+        $this->assertArrayNotHasKey('ip', $this->session);
+        $this->assertArrayNotHasKey('expires_on', $this->session);
+        $this->assertArrayNotHasKey('username', $this->session);
+        $this->assertArrayNotHasKey('visibility', $this->session);
+        $this->assertArrayHasKey('untaggedonly', $this->session);
+        $this->assertTrue($this->session['untaggedonly']);
     }
 
     /**
-- 
cgit v1.2.3


From aca995e09cf9c210ffe45584fbe50dcedb8bdebb Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 1 Sep 2020 10:12:54 +0200
Subject: Fix support for legacy route login redirection

Makes sure that the user is properly redirected to the bookmark form after login, even with legacy routes
---
 tests/legacy/LegacyControllerTest.php | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'tests')

diff --git a/tests/legacy/LegacyControllerTest.php b/tests/legacy/LegacyControllerTest.php
index 759a5b2a..460fbb3b 100644
--- a/tests/legacy/LegacyControllerTest.php
+++ b/tests/legacy/LegacyControllerTest.php
@@ -66,11 +66,11 @@ class LegacyControllerTest extends TestCase
     {
         return [
             ['post', [], '/admin/shaare', true],
-            ['post', [], '/login', false],
+            ['post', [], '/login?returnurl=/admin/shaare', false],
             ['post', ['title' => 'test'], '/admin/shaare?title=test', true],
-            ['post', ['title' => 'test'], '/login?title=test', false],
+            ['post', ['title' => 'test'], '/login?returnurl=/admin/shaare?title=test', false],
             ['addlink', [], '/admin/add-shaare', true],
-            ['addlink', [], '/login', false],
+            ['addlink', [], '/login?returnurl=/admin/add-shaare', false],
             ['login', [], '/login', true],
             ['login', [], '/login', false],
             ['logout', [], '/admin/logout', true],
-- 
cgit v1.2.3


From 9e2d47e519783a991962e1fe2c9f28d77756ae49 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 1 Sep 2020 10:40:18 +0200
Subject: Fix legacy redirection when Shaarli instance is under a subfolder

---
 tests/legacy/LegacyControllerTest.php | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'tests')

diff --git a/tests/legacy/LegacyControllerTest.php b/tests/legacy/LegacyControllerTest.php
index 460fbb3b..2bbbb1d7 100644
--- a/tests/legacy/LegacyControllerTest.php
+++ b/tests/legacy/LegacyControllerTest.php
@@ -66,11 +66,11 @@ class LegacyControllerTest extends TestCase
     {
         return [
             ['post', [], '/admin/shaare', true],
-            ['post', [], '/login?returnurl=/admin/shaare', false],
+            ['post', [], '/login?returnurl=/subfolder/admin/shaare', false],
             ['post', ['title' => 'test'], '/admin/shaare?title=test', true],
-            ['post', ['title' => 'test'], '/login?returnurl=/admin/shaare?title=test', false],
+            ['post', ['title' => 'test'], '/login?returnurl=/subfolder/admin/shaare?title=test', false],
             ['addlink', [], '/admin/add-shaare', true],
-            ['addlink', [], '/login?returnurl=/admin/add-shaare', false],
+            ['addlink', [], '/login?returnurl=/subfolder/admin/add-shaare', false],
             ['login', [], '/login', true],
             ['login', [], '/login', false],
             ['logout', [], '/admin/logout', true],
-- 
cgit v1.2.3


From 11aa4a7a29c5a6358584ce0f63c061fdb0704b18 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 1 Sep 2020 10:40:35 +0200
Subject: Support redirection of legacy route 'do=configure'

---
 tests/legacy/LegacyControllerTest.php | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'tests')

diff --git a/tests/legacy/LegacyControllerTest.php b/tests/legacy/LegacyControllerTest.php
index 2bbbb1d7..4e52f3e1 100644
--- a/tests/legacy/LegacyControllerTest.php
+++ b/tests/legacy/LegacyControllerTest.php
@@ -94,6 +94,8 @@ class LegacyControllerTest extends TestCase
             ['opensearch', [], '/open-search', true],
             ['dailyrss', [], '/daily-rss', false],
             ['dailyrss', [], '/daily-rss', true],
+            ['configure', [], '/login?returnurl=/subfolder/admin/configure', false],
+            ['configure', [], '/admin/configure', true],
         ];
     }
 }
-- 
cgit v1.2.3


From ce7918386a00c4a10ad8c9942c8ac28ea1fae0c2 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Thu, 3 Sep 2020 10:09:32 +0200
Subject: Improve backward compatibility for LegacyRouter

LegacyRouter is no longer used for routing, only in existing plugins to match the _PAGE_ parameter.
So we change a few of its values there, to match the new ones defined in TemplatePage.

@see discussion in shaarli/Shaarli#1537
---
 tests/legacy/LegacyRouterTest.php | 512 --------------------------------------
 1 file changed, 512 deletions(-)
 delete mode 100644 tests/legacy/LegacyRouterTest.php

(limited to 'tests')

diff --git a/tests/legacy/LegacyRouterTest.php b/tests/legacy/LegacyRouterTest.php
deleted file mode 100644
index c2019ca7..00000000
--- a/tests/legacy/LegacyRouterTest.php
+++ /dev/null
@@ -1,512 +0,0 @@
-assertEquals(
-            LegacyRouter::$PAGE_LOGIN,
-            LegacyRouter::findPage('do=login', array(), false)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LOGIN,
-            LegacyRouter::findPage('do=login', array(), 1)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LOGIN,
-            LegacyRouter::findPage('do=login&stuff', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: login page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageLoginInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_LOGIN,
-            LegacyRouter::findPage('do=login', array(), true)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_LOGIN,
-            LegacyRouter::findPage('do=other', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: picwall page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPagePicwallValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_PICWALL,
-            LegacyRouter::findPage('do=picwall', array(), false)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_PICWALL,
-            LegacyRouter::findPage('do=picwall', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: picwall page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPagePicwallInvalid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_PICWALL,
-            LegacyRouter::findPage('do=picwall&stuff', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_PICWALL,
-            LegacyRouter::findPage('do=other', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: tagcloud page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageTagcloudValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_TAGCLOUD,
-            LegacyRouter::findPage('do=tagcloud', array(), false)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_TAGCLOUD,
-            LegacyRouter::findPage('do=tagcloud', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_TAGCLOUD,
-            LegacyRouter::findPage('do=tagcloud&stuff', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: tagcloud page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageTagcloudInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_TAGCLOUD,
-            LegacyRouter::findPage('do=other', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: linklist page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageLinklistValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LINKLIST,
-            LegacyRouter::findPage('', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LINKLIST,
-            LegacyRouter::findPage('whatever', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LINKLIST,
-            LegacyRouter::findPage('whatever', array(), false)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LINKLIST,
-            LegacyRouter::findPage('do=tools', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: tools page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageToolsValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_TOOLS,
-            LegacyRouter::findPage('do=tools', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_TOOLS,
-            LegacyRouter::findPage('do=tools&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: tools page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageToolsInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_TOOLS,
-            LegacyRouter::findPage('do=tools', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_TOOLS,
-            LegacyRouter::findPage('do=tools', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_TOOLS,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: changepasswd page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageChangepasswdValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CHANGEPASSWORD,
-            LegacyRouter::findPage('do=changepasswd', array(), true)
-        );
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CHANGEPASSWORD,
-            LegacyRouter::findPage('do=changepasswd&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: changepasswd page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageChangepasswdInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGEPASSWORD,
-            LegacyRouter::findPage('do=changepasswd', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGEPASSWORD,
-            LegacyRouter::findPage('do=changepasswd', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGEPASSWORD,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-    /**
-     * Test findPage: configure page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageConfigureValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CONFIGURE,
-            LegacyRouter::findPage('do=configure', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CONFIGURE,
-            LegacyRouter::findPage('do=configure&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: configure page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageConfigureInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CONFIGURE,
-            LegacyRouter::findPage('do=configure', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CONFIGURE,
-            LegacyRouter::findPage('do=configure', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CONFIGURE,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: changetag page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageChangetagValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CHANGETAG,
-            LegacyRouter::findPage('do=changetag', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CHANGETAG,
-            LegacyRouter::findPage('do=changetag&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: changetag page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageChangetagInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGETAG,
-            LegacyRouter::findPage('do=changetag', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGETAG,
-            LegacyRouter::findPage('do=changetag', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGETAG,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: addlink page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageAddlinkValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_ADDLINK,
-            LegacyRouter::findPage('do=addlink', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_ADDLINK,
-            LegacyRouter::findPage('do=addlink&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: addlink page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageAddlinkInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_ADDLINK,
-            LegacyRouter::findPage('do=addlink', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_ADDLINK,
-            LegacyRouter::findPage('do=addlink', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_ADDLINK,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: export page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageExportValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EXPORT,
-            LegacyRouter::findPage('do=export', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EXPORT,
-            LegacyRouter::findPage('do=export&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: export page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageExportInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EXPORT,
-            LegacyRouter::findPage('do=export', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EXPORT,
-            LegacyRouter::findPage('do=export', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EXPORT,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: import page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageImportValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_IMPORT,
-            LegacyRouter::findPage('do=import', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_IMPORT,
-            LegacyRouter::findPage('do=import&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: import page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageImportInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_IMPORT,
-            LegacyRouter::findPage('do=import', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_IMPORT,
-            LegacyRouter::findPage('do=import', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_IMPORT,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: editlink page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageEditlinkValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array('edit_link' => 1), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('', array('edit_link' => 1), true)
-        );
-
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array('post' => 1), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array('post' => 1, 'edit_link' => 1), true)
-        );
-    }
-
-    /**
-     * Test findPage: editlink page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageEditlinkInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array('edit_link' => 1), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array('edit_link' => 1), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array(), true)
-        );
-    }
-}
-- 
cgit v1.2.3


From 0386a84d824f95b991280e8c93645fa013eef7c4 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Thu, 3 Sep 2020 10:18:04 +0200
Subject: Fix feed target in UT

---
 tests/front/controller/visitor/FeedControllerTest.php | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'tests')

diff --git a/tests/front/controller/visitor/FeedControllerTest.php b/tests/front/controller/visitor/FeedControllerTest.php
index fb417e2a..0a6b577f 100644
--- a/tests/front/controller/visitor/FeedControllerTest.php
+++ b/tests/front/controller/visitor/FeedControllerTest.php
@@ -52,7 +52,7 @@ class FeedControllerTest extends TestCase
                 static::assertSame('data', $data['content']);
 
                 static::assertArrayHasKey('loggedin', $param);
-                static::assertSame('rss', $param['target']);
+                static::assertSame('feed.rss', $param['target']);
             })
         ;
 
@@ -91,7 +91,7 @@ class FeedControllerTest extends TestCase
                 static::assertSame('data', $data['content']);
 
                 static::assertArrayHasKey('loggedin', $param);
-                static::assertSame('atom', $param['target']);
+                static::assertSame('feed.atom', $param['target']);
             })
         ;
 
@@ -131,7 +131,7 @@ class FeedControllerTest extends TestCase
                 static::assertSame('data', $data['content']);
 
                 static::assertArrayHasKey('loggedin', $param);
-                static::assertSame('atom', $param['target']);
+                static::assertSame('feed.atom', $param['target']);
             })
         ;
 
-- 
cgit v1.2.3


From 27ddfec3c3847f10ab0de246f4a174b751c5f19e Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Sun, 6 Sep 2020 14:11:02 +0200
Subject: Fix visibility issue on daily page

This filter (links by day) didn't apply any visibility parameter.

Fixes #1543
---
 tests/bookmark/BookmarkFileServiceTest.php | 30 ++++++++++++++++++++++++++++++
 tests/bookmark/BookmarkFilterTest.php      | 14 ++++++++++++--
 2 files changed, 42 insertions(+), 2 deletions(-)

(limited to 'tests')

diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php
index 7b1906d3..c59fd443 100644
--- a/tests/bookmark/BookmarkFileServiceTest.php
+++ b/tests/bookmark/BookmarkFileServiceTest.php
@@ -1061,6 +1061,36 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals($expected, $tags, var_export($tags, true));
     }
 
+    /**
+     * Test filterDay while logged in
+     */
+    public function testFilterDayLoggedIn(): void
+    {
+        $bookmarks = $this->privateLinkDB->filterDay('20121206');
+        $expectedIds = [4, 9, 1, 0];
+
+        static::assertCount(4, $bookmarks);
+        foreach ($bookmarks as $bookmark) {
+            $i = ($i ?? -1) + 1;
+            static::assertSame($expectedIds[$i], $bookmark->getId());
+        }
+    }
+
+    /**
+     * Test filterDay while logged out
+     */
+    public function testFilterDayLoggedOut(): void
+    {
+        $bookmarks = $this->publicLinkDB->filterDay('20121206');
+        $expectedIds = [4, 9, 1];
+
+        static::assertCount(3, $bookmarks);
+        foreach ($bookmarks as $bookmark) {
+            $i = ($i ?? -1) + 1;
+            static::assertSame($expectedIds[$i], $bookmark->getId());
+        }
+    }
+
     /**
      * Allows to test LinkDB's private methods
      *
diff --git a/tests/bookmark/BookmarkFilterTest.php b/tests/bookmark/BookmarkFilterTest.php
index d4c71cb9..91e139c2 100644
--- a/tests/bookmark/BookmarkFilterTest.php
+++ b/tests/bookmark/BookmarkFilterTest.php
@@ -6,7 +6,6 @@ use Exception;
 use PHPUnit\Framework\TestCase;
 use ReferenceLinkDB;
 use Shaarli\Config\ConfigManager;
-use Shaarli\Formatter\FormatterFactory;
 use Shaarli\History;
 
 /**
@@ -36,7 +35,7 @@ class BookmarkFilterTest extends TestCase
     /**
      * Instantiate linkFilter with ReferenceLinkDB data.
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         $conf = new ConfigManager('tests/utils/config/configJson');
         $conf->set('resource.datastore', self::$testDatastore);
@@ -189,6 +188,17 @@ class BookmarkFilterTest extends TestCase
         );
     }
 
+    /**
+     * Return bookmarks for a given day
+     */
+    public function testFilterDayRestrictedVisibility(): void
+    {
+        $this->assertEquals(
+            3,
+            count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20121206', false, BookmarkFilter::$PUBLIC))
+        );
+    }
+
     /**
      * 404 - day not found
      */
-- 
cgit v1.2.3


From da7acb98302b99ec729bcde3e3c9f4bb164a1b34 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Sun, 6 Sep 2020 13:42:45 +0200
Subject: Improve default bookmarks after install

Used @nodiscc suggestion in #1148 (slightly edited).
It provides a description of what Shaarli does, Markdown rendering demo, and a thumbnail link.

Fixes #1148
---
 tests/bookmark/BookmarkFileServiceTest.php | 18 +++++---
 tests/bookmark/BookmarkInitializerTest.php | 70 ++++++++++++++++++++----------
 2 files changed, 59 insertions(+), 29 deletions(-)

(limited to 'tests')

diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php
index 7b1906d3..a91f374f 100644
--- a/tests/bookmark/BookmarkFileServiceTest.php
+++ b/tests/bookmark/BookmarkFileServiceTest.php
@@ -615,14 +615,18 @@ class BookmarkFileServiceTest extends TestCase
     {
         $dbSize = $this->privateLinkDB->count();
         $this->privateLinkDB->initialize();
-        $this->assertEquals($dbSize + 2, $this->privateLinkDB->count());
-        $this->assertEquals(
-            'My secret stuff... - Pastebin.com',
-            $this->privateLinkDB->get(43)->getTitle()
+        $this->assertEquals($dbSize + 3, $this->privateLinkDB->count());
+        $this->assertStringStartsWith(
+            'Shaarli will automatically pick up the thumbnail for links to a variety of websites.',
+            $this->privateLinkDB->get(43)->getDescription()
         );
-        $this->assertEquals(
-            'The personal, minimalist, super-fast, database free, bookmarking service',
-            $this->privateLinkDB->get(44)->getTitle()
+        $this->assertStringStartsWith(
+            'Adding a shaare without entering a URL creates a text-only "note" post such as this one.',
+            $this->privateLinkDB->get(44)->getDescription()
+        );
+        $this->assertStringStartsWith(
+            'Welcome to Shaarli!',
+            $this->privateLinkDB->get(45)->getDescription()
         );
     }
 
diff --git a/tests/bookmark/BookmarkInitializerTest.php b/tests/bookmark/BookmarkInitializerTest.php
index 3906cc7f..454269bb 100644
--- a/tests/bookmark/BookmarkInitializerTest.php
+++ b/tests/bookmark/BookmarkInitializerTest.php
@@ -37,7 +37,7 @@ class BookmarkInitializerTest extends TestCase
     /**
      * Initialize an empty BookmarkFileService
      */
-    public function setUp()
+    public function setUp(): void
     {
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
@@ -64,17 +64,26 @@ class BookmarkInitializerTest extends TestCase
 
         $this->initializer->initialize();
 
-        $this->assertEquals($refDB->countLinks() + 2, $this->bookmarkService->count());
+        $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
+
         $bookmark = $this->bookmarkService->get(43);
-        $this->assertEquals(43, $bookmark->getId());
-        $this->assertEquals('My secret stuff... - Pastebin.com', $bookmark->getTitle());
+        $this->assertStringStartsWith(
+            'Shaarli will automatically pick up the thumbnail for links to a variety of websites.',
+            $bookmark->getDescription()
+        );
         $this->assertTrue($bookmark->isPrivate());
 
         $bookmark = $this->bookmarkService->get(44);
-        $this->assertEquals(44, $bookmark->getId());
-        $this->assertEquals(
-            'The personal, minimalist, super-fast, database free, bookmarking service',
-            $bookmark->getTitle()
+        $this->assertStringStartsWith(
+            'Adding a shaare without entering a URL creates a text-only "note" post such as this one.',
+            $bookmark->getDescription()
+        );
+        $this->assertTrue($bookmark->isPrivate());
+
+        $bookmark = $this->bookmarkService->get(45);
+        $this->assertStringStartsWith(
+            'Welcome to Shaarli!',
+            $bookmark->getDescription()
         );
         $this->assertFalse($bookmark->isPrivate());
 
@@ -82,17 +91,26 @@ class BookmarkInitializerTest extends TestCase
 
         // Reload from file
         $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
-        $this->assertEquals($refDB->countLinks() + 2, $this->bookmarkService->count());
+        $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
+
         $bookmark = $this->bookmarkService->get(43);
-        $this->assertEquals(43, $bookmark->getId());
-        $this->assertEquals('My secret stuff... - Pastebin.com', $bookmark->getTitle());
+        $this->assertStringStartsWith(
+            'Shaarli will automatically pick up the thumbnail for links to a variety of websites.',
+            $bookmark->getDescription()
+        );
         $this->assertTrue($bookmark->isPrivate());
 
         $bookmark = $this->bookmarkService->get(44);
-        $this->assertEquals(44, $bookmark->getId());
-        $this->assertEquals(
-            'The personal, minimalist, super-fast, database free, bookmarking service',
-            $bookmark->getTitle()
+        $this->assertStringStartsWith(
+            'Adding a shaare without entering a URL creates a text-only "note" post such as this one.',
+            $bookmark->getDescription()
+        );
+        $this->assertTrue($bookmark->isPrivate());
+
+        $bookmark = $this->bookmarkService->get(45);
+        $this->assertStringStartsWith(
+            'Welcome to Shaarli!',
+            $bookmark->getDescription()
         );
         $this->assertFalse($bookmark->isPrivate());
     }
@@ -107,17 +125,25 @@ class BookmarkInitializerTest extends TestCase
 
         $this->initializer->initialize();
 
-        $this->assertEquals(2, $this->bookmarkService->count());
+        $this->assertEquals(3, $this->bookmarkService->count());
         $bookmark = $this->bookmarkService->get(0);
-        $this->assertEquals(0, $bookmark->getId());
-        $this->assertEquals('My secret stuff... - Pastebin.com', $bookmark->getTitle());
+        $this->assertStringStartsWith(
+            'Shaarli will automatically pick up the thumbnail for links to a variety of websites.',
+            $bookmark->getDescription()
+        );
         $this->assertTrue($bookmark->isPrivate());
 
         $bookmark = $this->bookmarkService->get(1);
-        $this->assertEquals(1, $bookmark->getId());
-        $this->assertEquals(
-            'The personal, minimalist, super-fast, database free, bookmarking service',
-            $bookmark->getTitle()
+        $this->assertStringStartsWith(
+            'Adding a shaare without entering a URL creates a text-only "note" post such as this one.',
+            $bookmark->getDescription()
+        );
+        $this->assertTrue($bookmark->isPrivate());
+
+        $bookmark = $this->bookmarkService->get(2);
+        $this->assertStringStartsWith(
+            'Welcome to Shaarli!',
+            $bookmark->getDescription()
         );
         $this->assertFalse($bookmark->isPrivate());
     }
-- 
cgit v1.2.3


From d52ab0b1e99aa0c494f389092dce1e926296032d Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Sat, 12 Sep 2020 12:42:19 +0200
Subject: Properly handle 404 errors

Use 404 template instead of default Slim error page if the route is not found.

Fixes #827
---
 tests/container/ContainerBuilderTest.php           |  2 +
 .../visitor/ErrorNotFoundControllerTest.php        | 81 ++++++++++++++++++++++
 .../visitor/FrontControllerMockHelper.php          |  1 -
 3 files changed, 83 insertions(+), 1 deletion(-)
 create mode 100644 tests/front/controller/visitor/ErrorNotFoundControllerTest.php

(limited to 'tests')

diff --git a/tests/container/ContainerBuilderTest.php b/tests/container/ContainerBuilderTest.php
index c08010ae..2047a63a 100644
--- a/tests/container/ContainerBuilderTest.php
+++ b/tests/container/ContainerBuilderTest.php
@@ -10,6 +10,7 @@ use Shaarli\Config\ConfigManager;
 use Shaarli\Feed\FeedBuilder;
 use Shaarli\Formatter\FormatterFactory;
 use Shaarli\Front\Controller\Visitor\ErrorController;
+use Shaarli\Front\Controller\Visitor\ErrorNotFoundController;
 use Shaarli\History;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Netscape\NetscapeBookmarkUtils;
@@ -75,6 +76,7 @@ class ContainerBuilderTest extends TestCase
         static::assertInstanceOf(PageBuilder::class, $container->pageBuilder);
         static::assertInstanceOf(PageCacheManager::class, $container->pageCacheManager);
         static::assertInstanceOf(ErrorController::class, $container->phpErrorHandler);
+        static::assertInstanceOf(ErrorNotFoundController::class, $container->notFoundHandler);
         static::assertInstanceOf(PluginManager::class, $container->pluginManager);
         static::assertInstanceOf(SessionManager::class, $container->sessionManager);
         static::assertInstanceOf(Thumbnailer::class, $container->thumbnailer);
diff --git a/tests/front/controller/visitor/ErrorNotFoundControllerTest.php b/tests/front/controller/visitor/ErrorNotFoundControllerTest.php
new file mode 100644
index 00000000..625467b1
--- /dev/null
+++ b/tests/front/controller/visitor/ErrorNotFoundControllerTest.php
@@ -0,0 +1,81 @@
+createContainer();
+
+        $this->controller = new ErrorNotFoundController($this->container);
+    }
+
+    /**
+     * Test displaying 404 error
+     */
+    public function testDisplayNotFoundError(): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->expects(static::once())->method('getRequestTarget')->willReturn('/');
+        $request->method('getUri')->willReturnCallback(function (): Uri {
+            $uri = $this->createMock(Uri::class);
+            $uri->method('getBasePath')->willReturn('/subfolder');
+
+            return $uri;
+        });
+
+        $response = new Response();
+
+        // Save RainTPL assigned variables
+        $assignedVariables = [];
+        $this->assignTemplateVars($assignedVariables);
+
+        $result = ($this->controller)(
+            $request,
+            $response
+        );
+
+        static::assertSame(404, $result->getStatusCode());
+        static::assertSame('404', (string) $result->getBody());
+        static::assertSame('Requested page could not be found.', $assignedVariables['error_message']);
+    }
+
+    /**
+     * Test displaying 404 error from REST API
+     */
+    public function testDisplayNotFoundErrorFromAPI(): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->expects(static::once())->method('getRequestTarget')->willReturn('/sufolder/api/v1/links');
+        $request->method('getUri')->willReturnCallback(function (): Uri {
+            $uri = $this->createMock(Uri::class);
+            $uri->method('getBasePath')->willReturn('/subfolder');
+
+            return $uri;
+        });
+
+        $response = new Response();
+
+        // Save RainTPL assigned variables
+        $assignedVariables = [];
+        $this->assignTemplateVars($assignedVariables);
+
+        $result = ($this->controller)($request, $response);
+
+        static::assertSame(404, $result->getStatusCode());
+        static::assertSame([], $assignedVariables);
+    }
+}
diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php
index e0bd4ecf..927e7f0a 100644
--- a/tests/front/controller/visitor/FrontControllerMockHelper.php
+++ b/tests/front/controller/visitor/FrontControllerMockHelper.php
@@ -94,7 +94,6 @@ trait FrontControllerMockHelper
     protected function assignTemplateVars(array &$variables): void
     {
         $this->container->pageBuilder
-            ->expects(static::atLeastOnce())
             ->method('assign')
             ->willReturnCallback(function ($key, $value) use (&$variables) {
                 $variables[$key] = $value;
-- 
cgit v1.2.3


From 4ff703e3691e6cb398e8d208c1f54ed61315e0e8 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Thu, 10 Sep 2020 14:08:19 +0200
Subject: Plugins: do not save metadata along plugin parameters

Also prevent the token to be saved.

Fixes #1550
---
 tests/PluginManagerTest.php                        | 44 ++++++++++++++--------
 .../controller/admin/PluginsControllerTest.php     |  5 ++-
 tests/plugins/test/test.php                        |  3 ++
 3 files changed, 35 insertions(+), 17 deletions(-)

(limited to 'tests')

diff --git a/tests/PluginManagerTest.php b/tests/PluginManagerTest.php
index a5d5dbe9..3018999c 100644
--- a/tests/PluginManagerTest.php
+++ b/tests/PluginManagerTest.php
@@ -41,17 +41,31 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase
 
         $this->assertTrue(function_exists('hook_test_random'));
 
-        $data = array(0 => 'woot');
+        $data = [0 => 'woot'];
         $this->pluginManager->executeHooks('random', $data);
-        $this->assertEquals('woot', $data[1]);
 
-        $data = array(0 => 'woot');
+        static::assertCount(2, $data);
+        static::assertSame('woot', $data[1]);
+
+        $data = [0 => 'woot'];
         $this->pluginManager->executeHooks('random', $data, array('target' => 'test'));
-        $this->assertEquals('page test', $data[1]);
 
-        $data = array(0 => 'woot');
+        static::assertCount(2, $data);
+        static::assertSame('page test', $data[1]);
+
+        $data = [0 => 'woot'];
         $this->pluginManager->executeHooks('random', $data, array('loggedin' => true));
-        $this->assertEquals('loggedin', $data[1]);
+
+        static::assertCount(2, $data);
+        static::assertEquals('loggedin', $data[1]);
+
+        $data = [0 => 'woot'];
+        $this->pluginManager->executeHooks('random', $data, array('loggedin' => null));
+
+        static::assertCount(3, $data);
+        static::assertEquals('loggedin', $data[1]);
+        static::assertArrayHasKey(2, $data);
+        static::assertNull($data[2]);
     }
 
     /**
@@ -78,8 +92,8 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase
      */
     public function testPluginNotFound(): void
     {
-        $this->pluginManager->load(array());
-        $this->pluginManager->load(array('nope', 'renope'));
+        $this->pluginManager->load([]);
+        $this->pluginManager->load(['nope', 'renope']);
         $this->addToAssertionCount(1);
     }
 
@@ -89,18 +103,18 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase
     public function testGetPluginsMeta(): void
     {
         PluginManager::$PLUGINS_PATH = self::$pluginPath;
-        $this->pluginManager->load(array(self::$pluginName));
+        $this->pluginManager->load([self::$pluginName]);
 
-        $expectedParameters = array(
-            'pop' => array(
+        $expectedParameters = [
+            'pop' => [
                 'value' => '',
                 'desc'  => 'pop description',
-            ),
-            'hip' => array(
+            ],
+            'hip' => [
                 'value' => '',
                 'desc' => '',
-            ),
-        );
+            ],
+        ];
         $meta = $this->pluginManager->getPluginsMeta();
         $this->assertEquals('test plugin', $meta[self::$pluginName]['description']);
         $this->assertEquals($expectedParameters, $meta[self::$pluginName]['parameters']);
diff --git a/tests/front/controller/admin/PluginsControllerTest.php b/tests/front/controller/admin/PluginsControllerTest.php
index 5b59285c..9526474c 100644
--- a/tests/front/controller/admin/PluginsControllerTest.php
+++ b/tests/front/controller/admin/PluginsControllerTest.php
@@ -32,7 +32,7 @@ class PluginsControllerTest extends TestCase
         array_map(function (string $plugin) use ($path) { touch($path . '/' . $plugin); }, static::PLUGIN_NAMES);
     }
 
-    public function tearDown()
+    public function tearDown(): void
     {
         $path = __DIR__ . '/folder';
         array_map(function (string $plugin) use ($path) { unlink($path . '/' . $plugin); }, static::PLUGIN_NAMES);
@@ -125,6 +125,7 @@ class PluginsControllerTest extends TestCase
             'parameters_form' => true,
             'parameter1' => 'blip',
             'parameter2' => 'blop',
+            'token' => 'this parameter should not be saved'
         ];
 
         $request = $this->createMock(Request::class);
@@ -143,7 +144,7 @@ class PluginsControllerTest extends TestCase
             ->with('save_plugin_parameters', $parameters)
         ;
         $this->container->conf
-            ->expects(static::atLeastOnce())
+            ->expects(static::exactly(2))
             ->method('set')
             ->withConsecutive(['plugins.parameter1', 'blip'], ['plugins.parameter2', 'blop'])
         ;
diff --git a/tests/plugins/test/test.php b/tests/plugins/test/test.php
index ae5032dd..03be4f4e 100644
--- a/tests/plugins/test/test.php
+++ b/tests/plugins/test/test.php
@@ -13,6 +13,9 @@ function hook_test_random($data)
         $data[1] = 'page test';
     } elseif (isset($data['_LOGGEDIN_']) && $data['_LOGGEDIN_'] === true) {
         $data[1] = 'loggedin';
+    } elseif (array_key_exists('_LOGGEDIN_', $data)) {
+        $data[1] = 'loggedin';
+        $data[2] = $data['_LOGGEDIN_'];
     } else {
         $data[1] = $data[0];
     }
-- 
cgit v1.2.3


From 650a5f09cbeb1c1bef19810c6cc504c06d5b7e87 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Thu, 3 Sep 2020 14:51:41 +0200
Subject: Add manual configuration for root URL

This new setting under 'general.root_url' allows to override automatic discovery of Shaarli instance's URL.

Fixes #1339
---
 tests/http/HttpUtils/IndexUrlTest.php             | 36 +++++++++++++++-
 tests/http/HttpUtils/IndexUrlTestWithConstant.php | 51 +++++++++++++++++++++++
 2 files changed, 86 insertions(+), 1 deletion(-)
 create mode 100644 tests/http/HttpUtils/IndexUrlTestWithConstant.php

(limited to 'tests')

diff --git a/tests/http/HttpUtils/IndexUrlTest.php b/tests/http/HttpUtils/IndexUrlTest.php
index 73d33cd4..cce45c51 100644
--- a/tests/http/HttpUtils/IndexUrlTest.php
+++ b/tests/http/HttpUtils/IndexUrlTest.php
@@ -5,12 +5,14 @@
 
 namespace Shaarli\Http;
 
+use PHPUnit\Framework\TestCase;
+
 require_once 'application/http/HttpUtils.php';
 
 /**
  * Unitary tests for index_url()
  */
-class IndexUrlTest extends \PHPUnit\Framework\TestCase
+class IndexUrlTest extends TestCase
 {
     /**
      * If on the main page, remove "index.php" from the URL resource
@@ -103,4 +105,36 @@ class IndexUrlTest extends \PHPUnit\Framework\TestCase
             )
         );
     }
+
+    /**
+     * The route is stored in REQUEST_URI and subfolder
+     */
+    public function testPageUrlWithRouteUnderSubfolder()
+    {
+        $this->assertEquals(
+            'http://host.tld/subfolder/picture-wall',
+            page_url(
+                array(
+                    'HTTPS' => 'Off',
+                    'SERVER_NAME' => 'host.tld',
+                    'SERVER_PORT' => '80',
+                    'SCRIPT_NAME' => '/subfolder/index.php',
+                    'REQUEST_URI' => '/subfolder/picture-wall',
+                )
+            )
+        );
+
+        $this->assertEquals(
+            'http://host.tld/subfolder/admin/picture-wall',
+            page_url(
+                array(
+                    'HTTPS' => 'Off',
+                    'SERVER_NAME' => 'host.tld',
+                    'SERVER_PORT' => '80',
+                    'SCRIPT_NAME' => '/subfolder/admin/index.php',
+                    'REQUEST_URI' => '/subfolder/admin/picture-wall',
+                )
+            )
+        );
+    }
 }
diff --git a/tests/http/HttpUtils/IndexUrlTestWithConstant.php b/tests/http/HttpUtils/IndexUrlTestWithConstant.php
new file mode 100644
index 00000000..15ca3d72
--- /dev/null
+++ b/tests/http/HttpUtils/IndexUrlTestWithConstant.php
@@ -0,0 +1,51 @@
+assertEquals(
+            'http://other-host.tld/subfolder/',
+            index_url(
+                array(
+                    'HTTPS' => 'Off',
+                    'SERVER_NAME' => 'host.tld',
+                    'SERVER_PORT' => '80',
+                    'SCRIPT_NAME' => '/index.php',
+                    'REQUEST_URI' => '/picture-wall',
+                )
+            )
+        );
+
+        $this->assertEquals(
+            'http://other-host.tld/subfolder/',
+            index_url(
+                array(
+                    'HTTPS' => 'Off',
+                    'SERVER_NAME' => 'host.tld',
+                    'SERVER_PORT' => '80',
+                    'SCRIPT_NAME' => '/admin/index.php',
+                    'REQUEST_URI' => '/admin/picture-wall',
+                )
+            )
+        );
+    }
+}
-- 
cgit v1.2.3


From b93cfeba7b5ddb8b20d805017404e73eafd68c95 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Thu, 3 Sep 2020 14:52:34 +0200
Subject: Fix subfolder configuration in unit tests

---
 tests/feed/FeedBuilderTest.php                     | 13 ++++----
 .../controller/admin/ExportControllerTest.php      |  2 +-
 .../front/controller/admin/ToolsControllerTest.php |  6 ++--
 .../controller/visitor/DailyControllerTest.php     | 12 ++++----
 .../visitor/FrontControllerMockHelper.php          |  3 +-
 .../controller/visitor/InstallControllerTest.php   | 35 +++++++++++++++++++++-
 .../visitor/OpenSearchControllerTest.php           |  2 +-
 7 files changed, 54 insertions(+), 19 deletions(-)

(limited to 'tests')

diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php
index fe37d5f2..5dfe73aa 100644
--- a/tests/feed/FeedBuilderTest.php
+++ b/tests/feed/FeedBuilderTest.php
@@ -3,6 +3,7 @@
 namespace Shaarli\Feed;
 
 use DateTime;
+use PHPUnit\Framework\TestCase;
 use ReferenceLinkDB;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
@@ -16,7 +17,7 @@ use Shaarli\History;
  *
  * Unit tests for FeedBuilder.
  */
-class FeedBuilderTest extends \PHPUnit\Framework\TestCase
+class FeedBuilderTest extends TestCase
 {
     /**
      * @var string locale Basque (Spain).
@@ -44,7 +45,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
     /**
      * Called before every test method.
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         $conf = new ConfigManager('tests/utils/config/configJson');
         $conf->set('resource.datastore', self::$testDatastore);
@@ -60,7 +61,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
             'SERVER_NAME' => 'host.tld',
             'SERVER_PORT' => '80',
             'SCRIPT_NAME' => '/index.php',
-            'REQUEST_URI' => '/index.php?do=feed',
+            'REQUEST_URI' => '/feed/atom',
         );
     }
 
@@ -81,7 +82,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(self::$RSS_LANGUAGE, $data['language']);
         $this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']);
         $this->assertEquals(true, $data['show_dates']);
-        $this->assertEquals('http://host.tld/index.php?do=feed', $data['self_link']);
+        $this->assertEquals('http://host.tld/feed/atom', $data['self_link']);
         $this->assertEquals('http://host.tld/', $data['index_url']);
         $this->assertFalse($data['usepermalinks']);
         $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
@@ -253,7 +254,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
             'SERVER_NAME' => 'host.tld',
             'SERVER_PORT' => '8080',
             'SCRIPT_NAME' => '/~user/shaarli/index.php',
-            'REQUEST_URI' => '/~user/shaarli/index.php?do=feed',
+            'REQUEST_URI' => '/~user/shaarli/feed/atom',
         );
         $feedBuilder = new FeedBuilder(
             self::$bookmarkService,
@@ -265,7 +266,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
 
         $this->assertEquals(
-            'http://host.tld:8080/~user/shaarli/index.php?do=feed',
+            'http://host.tld:8080/~user/shaarli/feed/atom',
             $data['self_link']
         );
 
diff --git a/tests/front/controller/admin/ExportControllerTest.php b/tests/front/controller/admin/ExportControllerTest.php
index 50d9e378..12d26f4a 100644
--- a/tests/front/controller/admin/ExportControllerTest.php
+++ b/tests/front/controller/admin/ExportControllerTest.php
@@ -84,7 +84,7 @@ class ExportControllerTest extends TestCase
                     static::assertInstanceOf(BookmarkRawFormatter::class, $formatter);
                     static::assertSame($parameters['selection'], $selection);
                     static::assertTrue($prependNoteUrl);
-                    static::assertSame('http://shaarli', $indexUrl);
+                    static::assertSame('http://shaarli/subfolder/', $indexUrl);
 
                     return $bookmarks;
                 }
diff --git a/tests/front/controller/admin/ToolsControllerTest.php b/tests/front/controller/admin/ToolsControllerTest.php
index fc756f0f..39144d2f 100644
--- a/tests/front/controller/admin/ToolsControllerTest.php
+++ b/tests/front/controller/admin/ToolsControllerTest.php
@@ -8,7 +8,7 @@ use PHPUnit\Framework\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
-class ToolsControllerTestControllerTest extends TestCase
+class ToolsControllerTest extends TestCase
 {
     use FrontAdminControllerMockHelper;
 
@@ -41,7 +41,7 @@ class ToolsControllerTestControllerTest extends TestCase
 
         static::assertSame(200, $result->getStatusCode());
         static::assertSame('tools', (string) $result->getBody());
-        static::assertSame('https://shaarli', $assignedVariables['pageabsaddr']);
+        static::assertSame('https://shaarli/', $assignedVariables['pageabsaddr']);
         static::assertTrue($assignedVariables['sslenabled']);
     }
 
@@ -63,7 +63,7 @@ class ToolsControllerTestControllerTest extends TestCase
 
         static::assertSame(200, $result->getStatusCode());
         static::assertSame('tools', (string) $result->getBody());
-        static::assertSame('http://shaarli', $assignedVariables['pageabsaddr']);
+        static::assertSame('http://shaarli/', $assignedVariables['pageabsaddr']);
         static::assertFalse($assignedVariables['sslenabled']);
     }
 }
diff --git a/tests/front/controller/visitor/DailyControllerTest.php b/tests/front/controller/visitor/DailyControllerTest.php
index b802c62c..cb5b96f3 100644
--- a/tests/front/controller/visitor/DailyControllerTest.php
+++ b/tests/front/controller/visitor/DailyControllerTest.php
@@ -392,8 +392,8 @@ class DailyControllerTest extends TestCase
         static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
         static::assertSame('dailyrss', (string) $result->getBody());
         static::assertSame('Shaarli', $assignedVariables['title']);
-        static::assertSame('http://shaarli', $assignedVariables['index_url']);
-        static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']);
+        static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
+        static::assertSame('http://shaarli/subfolder/daily-rss', $assignedVariables['page_url']);
         static::assertFalse($assignedVariables['hide_timestamps']);
         static::assertCount(2, $assignedVariables['days']);
 
@@ -402,7 +402,7 @@ class DailyControllerTest extends TestCase
         static::assertEquals($dates[0], $day['date']);
         static::assertSame($dates[0]->format(\DateTime::RSS), $day['date_rss']);
         static::assertSame(format_date($dates[0], false), $day['date_human']);
-        static::assertSame('http://shaarli/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']);
+        static::assertSame('http://shaarli/subfolder/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']);
         static::assertCount(1, $day['links']);
         static::assertSame(1, $day['links'][0]['id']);
         static::assertSame('http://domain.tld/1', $day['links'][0]['url']);
@@ -413,7 +413,7 @@ class DailyControllerTest extends TestCase
         static::assertEquals($dates[1], $day['date']);
         static::assertSame($dates[1]->format(\DateTime::RSS), $day['date_rss']);
         static::assertSame(format_date($dates[1], false), $day['date_human']);
-        static::assertSame('http://shaarli/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']);
+        static::assertSame('http://shaarli/subfolder/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']);
         static::assertCount(2, $day['links']);
 
         static::assertSame(2, $day['links'][0]['id']);
@@ -468,8 +468,8 @@ class DailyControllerTest extends TestCase
         static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
         static::assertSame('dailyrss', (string) $result->getBody());
         static::assertSame('Shaarli', $assignedVariables['title']);
-        static::assertSame('http://shaarli', $assignedVariables['index_url']);
-        static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']);
+        static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
+        static::assertSame('http://shaarli/subfolder/daily-rss', $assignedVariables['page_url']);
         static::assertFalse($assignedVariables['hide_timestamps']);
         static::assertCount(0, $assignedVariables['days']);
     }
diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php
index e0bd4ecf..fe6ac9b0 100644
--- a/tests/front/controller/visitor/FrontControllerMockHelper.php
+++ b/tests/front/controller/visitor/FrontControllerMockHelper.php
@@ -79,8 +79,9 @@ trait FrontControllerMockHelper
         $this->container->environment = [
             'SERVER_NAME' => 'shaarli',
             'SERVER_PORT' => '80',
-            'REQUEST_URI' => '/daily-rss',
+            'REQUEST_URI' => '/subfolder/daily-rss',
             'REMOTE_ADDR' => '1.2.3.4',
+            'SCRIPT_NAME' => '/subfolder/index.php',
         ];
 
         $this->container->basePath = '/subfolder';
diff --git a/tests/front/controller/visitor/InstallControllerTest.php b/tests/front/controller/visitor/InstallControllerTest.php
index 3b855365..994d3f33 100644
--- a/tests/front/controller/visitor/InstallControllerTest.php
+++ b/tests/front/controller/visitor/InstallControllerTest.php
@@ -257,6 +257,39 @@ class InstallControllerTest extends TestCase
         static::assertSame('/subfolder/login', $result->getHeader('location')[0]);
 
         static::assertSame('UTC', $confSettings['general.timezone']);
-        static::assertSame('Shared bookmarks on http://shaarli', $confSettings['general.title']);
+        static::assertSame('Shared bookmarks on http://shaarli/subfolder/', $confSettings['general.title']);
+    }
+
+    /**
+     * Same test  as testSaveInstallDefaultValues() but for an instance install in root directory.
+     */
+    public function testSaveInstallDefaultValuesWithoutSubfolder(): void
+    {
+        $confSettings = [];
+
+        $this->container->environment = [
+            'SERVER_NAME' => 'shaarli',
+            'SERVER_PORT' => '80',
+            'REQUEST_URI' => '/install',
+            'REMOTE_ADDR' => '1.2.3.4',
+            'SCRIPT_NAME' => '/index.php',
+        ];
+
+        $this->container->basePath = '';
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->conf->method('set')->willReturnCallback(function (string $key, $value) use (&$confSettings) {
+            $confSettings[$key] = $value;
+        });
+
+        $result = $this->controller->save($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/login', $result->getHeader('location')[0]);
+
+        static::assertSame('UTC', $confSettings['general.timezone']);
+        static::assertSame('Shared bookmarks on http://shaarli/', $confSettings['general.title']);
     }
 }
diff --git a/tests/front/controller/visitor/OpenSearchControllerTest.php b/tests/front/controller/visitor/OpenSearchControllerTest.php
index 5f9f5b12..9609a377 100644
--- a/tests/front/controller/visitor/OpenSearchControllerTest.php
+++ b/tests/front/controller/visitor/OpenSearchControllerTest.php
@@ -39,6 +39,6 @@ class OpenSearchControllerTest extends TestCase
             $result->getHeader('Content-Type')[0]
         );
         static::assertSame('opensearch', (string) $result->getBody());
-        static::assertSame('http://shaarli', $assignedVariables['serverurl']);
+        static::assertSame('http://shaarli/subfolder/', $assignedVariables['serverurl']);
     }
 }
-- 
cgit v1.2.3


From 76fe68d924d424283d0a1784c5f5e7582dda3a00 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 22 Sep 2020 12:44:08 +0200
Subject: Fix plugin base path in core plugins

Also fix note check in archiveorg plugin, and regression on vintage template.
Documentation regarding relative path has been added.

Fixes #1548
---
 tests/plugins/PluginArchiveorgTest.php | 37 +++++++++++++++++++++++++---------
 tests/plugins/PluginIssoTest.php       | 23 +++++++++++----------
 2 files changed, 39 insertions(+), 21 deletions(-)

(limited to 'tests')

diff --git a/tests/plugins/PluginArchiveorgTest.php b/tests/plugins/PluginArchiveorgTest.php
index b9a67adb..9c19752c 100644
--- a/tests/plugins/PluginArchiveorgTest.php
+++ b/tests/plugins/PluginArchiveorgTest.php
@@ -1,10 +1,12 @@
 savedScriptName = $_SERVER['SCRIPT_NAME'] ?? null;
+        $_SERVER['SCRIPT_NAME'] = '/index.php';
+    }
+
+    public function tearDown(): void
+    {
+        unset($_SERVER['SERVER_PORT']);
+        unset($_SERVER['SERVER_NAME']);
+        $_SERVER['SCRIPT_NAME'] = $this->savedScriptName;
     }
 
     /**
      * Test render_linklist hook on external bookmarks.
      */
-    public function testArchiveorgLinklistOnExternalLinks()
+    public function testArchiveorgLinklistOnExternalLinks(): void
     {
         $str = 'http://randomstr.com/test';
 
@@ -56,16 +73,16 @@ class PluginArchiveorgTest extends \PHPUnit\Framework\TestCase
     /**
      * Test render_linklist hook on internal bookmarks.
      */
-    public function testArchiveorgLinklistOnInternalLinks()
+    public function testArchiveorgLinklistOnInternalLinks(): void
     {
-        $internalLink1 = 'http://shaarli.shaarli/?qvMAqg';
-        $internalLinkRealURL1 = '?qvMAqg';
+        $internalLink1 = 'http://shaarli.shaarli/shaare/qvMAqg';
+        $internalLinkRealURL1 = '/shaare/qvMAqg';
 
-        $internalLink2 = 'http://shaarli.shaarli/?2_7zww';
-        $internalLinkRealURL2 = '?2_7zww';
+        $internalLink2 = 'http://shaarli.shaarli/shaare/2_7zww';
+        $internalLinkRealURL2 = '/shaare/2_7zww';
 
-        $internalLink3 = 'http://shaarli.shaarli/?z7u-_Q';
-        $internalLinkRealURL3 = '?z7u-_Q';
+        $internalLink3 = 'http://shaarli.shaarli/shaare/z7u-_Q';
+        $internalLinkRealURL3 = '/shaare/z7u-_Q';
 
         $data = array(
             'title' => $internalLink1,
diff --git a/tests/plugins/PluginIssoTest.php b/tests/plugins/PluginIssoTest.php
index 99477205..2bbb93d2 100644
--- a/tests/plugins/PluginIssoTest.php
+++ b/tests/plugins/PluginIssoTest.php
@@ -2,6 +2,7 @@
 namespace Shaarli\Plugin\Isso;
 
 use DateTime;
+use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Plugin\PluginManager;
@@ -13,12 +14,12 @@ require_once 'plugins/isso/isso.php';
  *
  * Test the Isso plugin (comment system).
  */
-class PluginIssoTest extends \PHPUnit\Framework\TestCase
+class PluginIssoTest extends TestCase
 {
     /**
      * Reset plugin path
      */
-    public function setUp()
+    public function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
@@ -26,7 +27,7 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
     /**
      * Test Isso init without errors.
      */
-    public function testIssoInitNoError()
+    public function testIssoInitNoError(): void
     {
         $conf = new ConfigManager('');
         $conf->set('plugins.ISSO_SERVER', 'value');
@@ -37,7 +38,7 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
     /**
      * Test Isso init with errors.
      */
-    public function testIssoInitError()
+    public function testIssoInitError(): void
     {
         $conf = new ConfigManager('');
         $errors = isso_init($conf);
@@ -47,7 +48,7 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
     /**
      * Test render_linklist hook with valid settings to display the comment form.
      */
-    public function testIssoDisplayed()
+    public function testIssoDisplayed(): void
     {
         $conf = new ConfigManager('');
         $conf->set('plugins.ISSO_SERVER', 'value');
@@ -87,7 +88,7 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
     /**
      * Test isso plugin when multiple bookmarks are displayed (shouldn't be displayed).
      */
-    public function testIssoMultipleLinks()
+    public function testIssoMultipleLinks(): void
     {
         $conf = new ConfigManager('');
         $conf->set('plugins.ISSO_SERVER', 'value');
@@ -115,14 +116,14 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
 
         $processed = hook_isso_render_linklist($data, $conf);
         // link_plugin should be added for the icon
-        $this->assertContains('', $processed['links'][0]['link_plugin'][0]);
-        $this->assertContains('', $processed['links'][1]['link_plugin'][0]);
+        $this->assertContains('', $processed['links'][0]['link_plugin'][0]);
+        $this->assertContains('', $processed['links'][1]['link_plugin'][0]);
     }
 
     /**
      * Test isso plugin when using search (shouldn't be displayed).
      */
-    public function testIssoNotDisplayedWhenSearch()
+    public function testIssoNotDisplayedWhenSearch(): void
     {
         $conf = new ConfigManager('');
         $conf->set('plugins.ISSO_SERVER', 'value');
@@ -145,13 +146,13 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
         $processed = hook_isso_render_linklist($data, $conf);
 
         // link_plugin should be added for the icon
-        $this->assertContains('', $processed['links'][0]['link_plugin'][0]);
+        $this->assertContains('', $processed['links'][0]['link_plugin'][0]);
     }
 
     /**
      * Test isso plugin without server configuration (shouldn't be displayed).
      */
-    public function testIssoWithoutConf()
+    public function testIssoWithoutConf(): void
     {
         $data = 'abc';
         $conf = new ConfigManager('');
-- 
cgit v1.2.3


From abe033be855f76fde9e8576ce36460fbb23b1e57 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 22 Sep 2020 15:17:13 +0200
Subject: Fix invalid redirection using the path of an external domain

Fixes #1554
---
 .../SaveBookmarkTest.php                           |  4 +-
 .../admin/SessionFilterControllerTest.php          |  8 ++--
 .../visitor/PublicSessionFilterControllerTest.php  |  6 +--
 .../visitor/ShaarliVisitorControllerTest.php       | 45 ++++++++++++++++++----
 4 files changed, 47 insertions(+), 16 deletions(-)

(limited to 'tests')

diff --git a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
index dabcd60d..58eaaa9b 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
@@ -43,7 +43,7 @@ class SaveBookmarkTest extends TestCase
             'lf_description' => 'Provided description.',
             'lf_tags' => 'abc def',
             'lf_private' => '1',
-            'returnurl' => 'http://shaarli.tld/subfolder/admin/add-shaare'
+            'returnurl' => 'http://shaarli/subfolder/admin/add-shaare'
         ];
 
         $request = $this->createMock(Request::class);
@@ -124,7 +124,7 @@ class SaveBookmarkTest extends TestCase
             'lf_description' => 'Provided description.',
             'lf_tags' => 'abc def',
             'lf_private' => '1',
-            'returnurl' => 'http://shaarli.tld/subfolder/?page=2'
+            'returnurl' => 'http://shaarli/subfolder/?page=2'
         ];
 
         $request = $this->createMock(Request::class);
diff --git a/tests/front/controller/admin/SessionFilterControllerTest.php b/tests/front/controller/admin/SessionFilterControllerTest.php
index d306c6e9..c4253167 100644
--- a/tests/front/controller/admin/SessionFilterControllerTest.php
+++ b/tests/front/controller/admin/SessionFilterControllerTest.php
@@ -31,7 +31,7 @@ class SessionFilterControllerTest extends TestCase
     {
         $arg = ['visibility' => 'private'];
 
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $this->container->loginManager->method('isLoggedIn')->willReturn(true);
         $this->container->sessionManager
@@ -57,7 +57,7 @@ class SessionFilterControllerTest extends TestCase
     {
         $arg = ['visibility' => 'private'];
 
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $this->container->loginManager->method('isLoggedIn')->willReturn(true);
         $this->container->sessionManager
@@ -121,7 +121,7 @@ class SessionFilterControllerTest extends TestCase
     {
         $arg = ['visibility' => 'test'];
 
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $this->container->loginManager->method('isLoggedIn')->willReturn(true);
         $this->container->sessionManager
@@ -151,7 +151,7 @@ class SessionFilterControllerTest extends TestCase
     {
         $arg = ['visibility' => 'test'];
 
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $this->container->loginManager = $this->createMock(LoginManager::class);
         $this->container->loginManager->method('isLoggedIn')->willReturn(false);
diff --git a/tests/front/controller/visitor/PublicSessionFilterControllerTest.php b/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
index 06352750..b45fbe53 100644
--- a/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
+++ b/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
@@ -28,7 +28,7 @@ class PublicSessionFilterControllerTest extends TestCase
      */
     public function testLinksPerPage(): void
     {
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $request = $this->createMock(Request::class);
         $request->method('getParam')->with('nb')->willReturn('8');
@@ -74,7 +74,7 @@ class PublicSessionFilterControllerTest extends TestCase
      */
     public function testUntaggedOnly(): void
     {
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $request = $this->createMock(Request::class);
         $response = new Response();
@@ -97,7 +97,7 @@ class PublicSessionFilterControllerTest extends TestCase
      */
     public function testUntaggedOnlyToggleOff(): void
     {
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $request = $this->createMock(Request::class);
         $response = new Response();
diff --git a/tests/front/controller/visitor/ShaarliVisitorControllerTest.php b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
index 316ce49c..00188c02 100644
--- a/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
+++ b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
@@ -110,7 +110,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererDefault(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -125,7 +125,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithUnmatchedLoopTerm(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -140,7 +140,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithMatchingLoopTermInPath(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -155,7 +155,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithMatchingLoopTermInQueryParam(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -171,7 +171,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithMatchingLoopTermInQueryValue(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -187,7 +187,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithLoopTermInDomain(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -203,7 +203,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithMatchingClearedParam(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -212,4 +212,35 @@ class ShaarliVisitorControllerTest extends TestCase
         static::assertSame(302, $result->getStatusCode());
         static::assertSame(['/subfolder/controller?other=2'], $result->getHeader('location'));
     }
+
+    /**
+     * Test redirectFromReferer() - From another domain -> we ignore the given referrer.
+     */
+    public function testRedirectExternalReferer(): void
+    {
+        $this->container->environment['HTTP_REFERER'] = 'http://other.domain.tld/controller?query=param&other=2';
+
+        $response = new Response();
+
+        $result = $this->controller->redirectFromReferer($this->request, $response, ['query'], ['query']);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/subfolder/'], $result->getHeader('location'));
+    }
+
+    /**
+     * Test redirectFromReferer() - From another domain -> we ignore the given referrer.
+     */
+    public function testRedirectExternalRefererExplicitDomainName(): void
+    {
+        $this->container->environment['SERVER_NAME'] = 'my.shaarli.tld';
+        $this->container->environment['HTTP_REFERER'] = 'http://your.shaarli.tld/controller?query=param&other=2';
+
+        $response = new Response();
+
+        $result = $this->controller->redirectFromReferer($this->request, $response, ['query'], ['query']);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/subfolder/'], $result->getHeader('location'));
+    }
 }
-- 
cgit v1.2.3


From 8f60e1206e45e67c96a7630d4ff94e72fe875f09 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Sat, 26 Sep 2020 15:08:39 +0200
Subject: Comply with PHPUnit V8: setup/teardown functions must return void

---
 tests/ApplicationUtilsTest.php                    | 4 ++--
 tests/FileUtilsTest.php                           | 2 +-
 tests/HistoryTest.php                             | 2 +-
 tests/LanguagesTest.php                           | 2 +-
 tests/ThumbnailerTest.php                         | 4 ++--
 tests/TimeZoneTest.php                            | 2 +-
 tests/UtilsTest.php                               | 6 +++---
 tests/api/ApiMiddlewareTest.php                   | 4 ++--
 tests/api/ApiUtilsTest.php                        | 2 +-
 tests/api/controllers/history/HistoryTest.php     | 4 ++--
 tests/api/controllers/info/InfoTest.php           | 4 ++--
 tests/api/controllers/links/DeleteLinkTest.php    | 4 ++--
 tests/api/controllers/links/GetLinkIdTest.php     | 4 ++--
 tests/api/controllers/links/GetLinksTest.php      | 4 ++--
 tests/api/controllers/links/PostLinkTest.php      | 4 ++--
 tests/api/controllers/links/PutLinkTest.php       | 4 ++--
 tests/api/controllers/tags/DeleteTagTest.php      | 4 ++--
 tests/api/controllers/tags/GetTagNameTest.php     | 4 ++--
 tests/api/controllers/tags/GetTagsTest.php        | 4 ++--
 tests/api/controllers/tags/PutTagTest.php         | 4 ++--
 tests/bookmark/BookmarkFileServiceTest.php        | 2 +-
 tests/config/ConfigJsonTest.php                   | 2 +-
 tests/config/ConfigManagerTest.php                | 2 +-
 tests/config/ConfigPhpTest.php                    | 2 +-
 tests/feed/CachedPageTest.php                     | 4 ++--
 tests/formatter/BookmarkDefaultFormatterTest.php  | 2 +-
 tests/formatter/BookmarkMarkdownFormatterTest.php | 2 +-
 tests/formatter/BookmarkRawFormatterTest.php      | 2 +-
 tests/formatter/FormatterFactoryTest.php          | 2 +-
 tests/languages/fr/LanguagesFrTest.php            | 4 ++--
 tests/legacy/LegacyLinkDBTest.php                 | 2 +-
 tests/legacy/LegacyLinkFilterTest.php             | 2 +-
 tests/legacy/LegacyUpdaterTest.php                | 4 ++--
 tests/netscape/BookmarkExportTest.php             | 2 +-
 tests/netscape/BookmarkImportTest.php             | 8 ++++----
 tests/plugins/PluginAddlinkTest.php               | 2 +-
 tests/plugins/PluginDefaultColorsTest.php         | 4 ++--
 tests/plugins/PluginPlayvideosTest.php            | 2 +-
 tests/plugins/PluginPubsubhubbubTest.php          | 2 +-
 tests/plugins/PluginQrcodeTest.php                | 2 +-
 tests/plugins/PluginWallabagTest.php              | 2 +-
 tests/plugins/WallabagInstanceTest.php            | 2 +-
 tests/render/PageCacheManagerTest.php             | 4 ++--
 tests/security/BanManagerTest.php                 | 2 +-
 tests/security/LoginManagerTest.php               | 2 +-
 tests/security/SessionManagerTest.php             | 4 ++--
 tests/updater/UpdaterTest.php                     | 2 +-
 47 files changed, 72 insertions(+), 72 deletions(-)

(limited to 'tests')

diff --git a/tests/ApplicationUtilsTest.php b/tests/ApplicationUtilsTest.php
index 15388970..57359196 100644
--- a/tests/ApplicationUtilsTest.php
+++ b/tests/ApplicationUtilsTest.php
@@ -17,7 +17,7 @@ class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset test data for each test
      */
-    public function setUp()
+    protected function setUp(): void
     {
         FakeApplicationUtils::$VERSION_CODE = '';
         if (file_exists(self::$testUpdateFile)) {
@@ -28,7 +28,7 @@ class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase
     /**
      * Remove test version file if it exists
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         if (is_file('sandbox/version.php')) {
             unlink('sandbox/version.php');
diff --git a/tests/FileUtilsTest.php b/tests/FileUtilsTest.php
index 57719175..eb9cb89a 100644
--- a/tests/FileUtilsTest.php
+++ b/tests/FileUtilsTest.php
@@ -19,7 +19,7 @@ class FileUtilsTest extends \PHPUnit\Framework\TestCase
     /**
      * Delete test file after every test.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$file);
     }
diff --git a/tests/HistoryTest.php b/tests/HistoryTest.php
index 7189c3a9..e9e61032 100644
--- a/tests/HistoryTest.php
+++ b/tests/HistoryTest.php
@@ -16,7 +16,7 @@ class HistoryTest extends \PHPUnit\Framework\TestCase
     /**
      * Delete history file.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$historyFilePath)) {
             unlink(self::$historyFilePath);
diff --git a/tests/LanguagesTest.php b/tests/LanguagesTest.php
index de83f291..914179c8 100644
--- a/tests/LanguagesTest.php
+++ b/tests/LanguagesTest.php
@@ -22,7 +22,7 @@ class LanguagesTest extends \PHPUnit\Framework\TestCase
     /**
      *
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager(self::$configFile);
     }
diff --git a/tests/ThumbnailerTest.php b/tests/ThumbnailerTest.php
index c01849f7..5b6d6a4d 100644
--- a/tests/ThumbnailerTest.php
+++ b/tests/ThumbnailerTest.php
@@ -30,7 +30,7 @@ class ThumbnailerTest extends TestCase
      */
     protected $conf;
 
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('thumbnails.mode', Thumbnailer::MODE_ALL);
@@ -43,7 +43,7 @@ class ThumbnailerTest extends TestCase
         WTConfigManager::addFile('tests/utils/config/wt.json');
     }
 
-    public function tearDown()
+    protected function tearDown(): void
     {
         $this->rrmdirContent('sandbox/');
     }
diff --git a/tests/TimeZoneTest.php b/tests/TimeZoneTest.php
index 02bf060f..d3d9aeeb 100644
--- a/tests/TimeZoneTest.php
+++ b/tests/TimeZoneTest.php
@@ -15,7 +15,7 @@ class TimeZoneTest extends PHPUnit\Framework\TestCase
      */
     protected $installedTimezones;
 
-    public function setUp()
+    protected function setUp(): void
     {
         $this->installedTimezones = [
             'Antarctica/Syowa',
diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php
index 26d2a6b8..93b77539 100644
--- a/tests/UtilsTest.php
+++ b/tests/UtilsTest.php
@@ -26,7 +26,7 @@ class UtilsTest extends PHPUnit\Framework\TestCase
     /**
      * Assign reference data
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         self::$defaultTimeZone = date_default_timezone_get();
         // Timezone without DST for test consistency
@@ -36,7 +36,7 @@ class UtilsTest extends PHPUnit\Framework\TestCase
     /**
      * Reset the timezone
      */
-    public static function tearDownAfterClass()
+    public static function tearDownAfterClass(): void
     {
         date_default_timezone_set(self::$defaultTimeZone);
     }
@@ -44,7 +44,7 @@ class UtilsTest extends PHPUnit\Framework\TestCase
     /**
      * Resets test data before each test
      */
-    protected function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$testLogFile)) {
             unlink(self::$testLogFile);
diff --git a/tests/api/ApiMiddlewareTest.php b/tests/api/ApiMiddlewareTest.php
index df2fb33a..b157e4a7 100644
--- a/tests/api/ApiMiddlewareTest.php
+++ b/tests/api/ApiMiddlewareTest.php
@@ -43,7 +43,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('api.secret', 'NapoleonWasALizard');
@@ -61,7 +61,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
diff --git a/tests/api/ApiUtilsTest.php b/tests/api/ApiUtilsTest.php
index 7efec9bb..e8075a5d 100644
--- a/tests/api/ApiUtilsTest.php
+++ b/tests/api/ApiUtilsTest.php
@@ -13,7 +13,7 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase
     /**
      * Force the timezone for ISO datetimes.
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         date_default_timezone_set('UTC');
     }
diff --git a/tests/api/controllers/history/HistoryTest.php b/tests/api/controllers/history/HistoryTest.php
index f4d3b646..40f26b12 100644
--- a/tests/api/controllers/history/HistoryTest.php
+++ b/tests/api/controllers/history/HistoryTest.php
@@ -41,7 +41,7 @@ class HistoryTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->refHistory = new \ReferenceHistory();
@@ -57,7 +57,7 @@ class HistoryTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testHistory);
     }
diff --git a/tests/api/controllers/info/InfoTest.php b/tests/api/controllers/info/InfoTest.php
index b5c938e1..cc50d2e3 100644
--- a/tests/api/controllers/info/InfoTest.php
+++ b/tests/api/controllers/info/InfoTest.php
@@ -47,7 +47,7 @@ class InfoTest extends TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -67,7 +67,7 @@ class InfoTest extends TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
diff --git a/tests/api/controllers/links/DeleteLinkTest.php b/tests/api/controllers/links/DeleteLinkTest.php
index 6c2b3698..10dfe8bc 100644
--- a/tests/api/controllers/links/DeleteLinkTest.php
+++ b/tests/api/controllers/links/DeleteLinkTest.php
@@ -56,7 +56,7 @@ class DeleteLinkTest extends \PHPUnit\Framework\TestCase
     /**
      * Before each test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -78,7 +78,7 @@ class DeleteLinkTest extends \PHPUnit\Framework\TestCase
     /**
      * After each test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
         @unlink(self::$testHistory);
diff --git a/tests/api/controllers/links/GetLinkIdTest.php b/tests/api/controllers/links/GetLinkIdTest.php
index 8bb81dc8..ee42e259 100644
--- a/tests/api/controllers/links/GetLinkIdTest.php
+++ b/tests/api/controllers/links/GetLinkIdTest.php
@@ -55,7 +55,7 @@ class GetLinkIdTest extends \PHPUnit\Framework\TestCase
     /**
      * Before each test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -74,7 +74,7 @@ class GetLinkIdTest extends \PHPUnit\Framework\TestCase
     /**
      * After each test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
diff --git a/tests/api/controllers/links/GetLinksTest.php b/tests/api/controllers/links/GetLinksTest.php
index d02e6fad..01c40c2f 100644
--- a/tests/api/controllers/links/GetLinksTest.php
+++ b/tests/api/controllers/links/GetLinksTest.php
@@ -55,7 +55,7 @@ class GetLinksTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -74,7 +74,7 @@ class GetLinksTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
diff --git a/tests/api/controllers/links/PostLinkTest.php b/tests/api/controllers/links/PostLinkTest.php
index 4e791a04..b1c9008b 100644
--- a/tests/api/controllers/links/PostLinkTest.php
+++ b/tests/api/controllers/links/PostLinkTest.php
@@ -70,7 +70,7 @@ class PostLinkTest extends TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -107,7 +107,7 @@ class PostLinkTest extends TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
         @unlink(self::$testHistory);
diff --git a/tests/api/controllers/links/PutLinkTest.php b/tests/api/controllers/links/PutLinkTest.php
index 302cac0f..f582a2b5 100644
--- a/tests/api/controllers/links/PutLinkTest.php
+++ b/tests/api/controllers/links/PutLinkTest.php
@@ -62,7 +62,7 @@ class PutLinkTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -91,7 +91,7 @@ class PutLinkTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
         @unlink(self::$testHistory);
diff --git a/tests/api/controllers/tags/DeleteTagTest.php b/tests/api/controllers/tags/DeleteTagTest.php
index c6748872..b0980572 100644
--- a/tests/api/controllers/tags/DeleteTagTest.php
+++ b/tests/api/controllers/tags/DeleteTagTest.php
@@ -57,7 +57,7 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase
     /**
      * Before each test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -79,7 +79,7 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase
     /**
      * After each test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
         @unlink(self::$testHistory);
diff --git a/tests/api/controllers/tags/GetTagNameTest.php b/tests/api/controllers/tags/GetTagNameTest.php
index b9a81f9b..f8ee10d9 100644
--- a/tests/api/controllers/tags/GetTagNameTest.php
+++ b/tests/api/controllers/tags/GetTagNameTest.php
@@ -53,7 +53,7 @@ class GetTagNameTest extends \PHPUnit\Framework\TestCase
     /**
      * Before each test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -72,7 +72,7 @@ class GetTagNameTest extends \PHPUnit\Framework\TestCase
     /**
      * After each test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
diff --git a/tests/api/controllers/tags/GetTagsTest.php b/tests/api/controllers/tags/GetTagsTest.php
index 53a3326d..ab666f20 100644
--- a/tests/api/controllers/tags/GetTagsTest.php
+++ b/tests/api/controllers/tags/GetTagsTest.php
@@ -57,7 +57,7 @@ class GetTagsTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -78,7 +78,7 @@ class GetTagsTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
diff --git a/tests/api/controllers/tags/PutTagTest.php b/tests/api/controllers/tags/PutTagTest.php
index 2a3cc15a..e0bc8663 100644
--- a/tests/api/controllers/tags/PutTagTest.php
+++ b/tests/api/controllers/tags/PutTagTest.php
@@ -62,7 +62,7 @@ class PutTagTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -84,7 +84,7 @@ class PutTagTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
         @unlink(self::$testHistory);
diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php
index a4ec1013..aed4dc76 100644
--- a/tests/bookmark/BookmarkFileServiceTest.php
+++ b/tests/bookmark/BookmarkFileServiceTest.php
@@ -66,7 +66,7 @@ class BookmarkFileServiceTest extends TestCase
      *
      * Resets test data for each test
      */
-    protected function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
diff --git a/tests/config/ConfigJsonTest.php b/tests/config/ConfigJsonTest.php
index 33160eb0..f1612e9b 100644
--- a/tests/config/ConfigJsonTest.php
+++ b/tests/config/ConfigJsonTest.php
@@ -11,7 +11,7 @@ class ConfigJsonTest extends \PHPUnit\Framework\TestCase
      */
     protected $configIO;
 
-    public function setUp()
+    protected function setUp(): void
     {
         $this->configIO = new ConfigJson();
     }
diff --git a/tests/config/ConfigManagerTest.php b/tests/config/ConfigManagerTest.php
index 33830bc9..69456bce 100644
--- a/tests/config/ConfigManagerTest.php
+++ b/tests/config/ConfigManagerTest.php
@@ -14,7 +14,7 @@ class ConfigManagerTest extends \PHPUnit\Framework\TestCase
      */
     protected $conf;
 
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
     }
diff --git a/tests/config/ConfigPhpTest.php b/tests/config/ConfigPhpTest.php
index fb91b51b..a9aa80f5 100644
--- a/tests/config/ConfigPhpTest.php
+++ b/tests/config/ConfigPhpTest.php
@@ -15,7 +15,7 @@ class ConfigPhpTest extends \PHPUnit\Framework\TestCase
      */
     protected $configIO;
 
-    public function setUp()
+    protected function setUp(): void
     {
         $this->configIO = new ConfigPhp();
     }
diff --git a/tests/feed/CachedPageTest.php b/tests/feed/CachedPageTest.php
index 2e716432..25d640d3 100644
--- a/tests/feed/CachedPageTest.php
+++ b/tests/feed/CachedPageTest.php
@@ -17,7 +17,7 @@ class CachedPageTest extends \PHPUnit\Framework\TestCase
     /**
      * Create the cache directory if needed
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         if (!is_dir(self::$testCacheDir)) {
             mkdir(self::$testCacheDir);
@@ -28,7 +28,7 @@ class CachedPageTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset the page cache
      */
-    public function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$filename)) {
             unlink(self::$filename);
diff --git a/tests/formatter/BookmarkDefaultFormatterTest.php b/tests/formatter/BookmarkDefaultFormatterTest.php
index cf48b00b..9ea86c14 100644
--- a/tests/formatter/BookmarkDefaultFormatterTest.php
+++ b/tests/formatter/BookmarkDefaultFormatterTest.php
@@ -25,7 +25,7 @@ class BookmarkDefaultFormatterTest extends TestCase
     /**
      * Initialize formatter instance.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
diff --git a/tests/formatter/BookmarkMarkdownFormatterTest.php b/tests/formatter/BookmarkMarkdownFormatterTest.php
index 3e72d1ee..a7729416 100644
--- a/tests/formatter/BookmarkMarkdownFormatterTest.php
+++ b/tests/formatter/BookmarkMarkdownFormatterTest.php
@@ -25,7 +25,7 @@ class BookmarkMarkdownFormatterTest extends TestCase
     /**
      * Initialize formatter instance.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
diff --git a/tests/formatter/BookmarkRawFormatterTest.php b/tests/formatter/BookmarkRawFormatterTest.php
index 4491b035..76cf1172 100644
--- a/tests/formatter/BookmarkRawFormatterTest.php
+++ b/tests/formatter/BookmarkRawFormatterTest.php
@@ -25,7 +25,7 @@ class BookmarkRawFormatterTest extends TestCase
     /**
      * Initialize formatter instance.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
diff --git a/tests/formatter/FormatterFactoryTest.php b/tests/formatter/FormatterFactoryTest.php
index 5adf3ffd..6aab6a61 100644
--- a/tests/formatter/FormatterFactoryTest.php
+++ b/tests/formatter/FormatterFactoryTest.php
@@ -24,7 +24,7 @@ class FormatterFactoryTest extends TestCase
     /**
      * Initialize FormatterFactory instance
      */
-    public function setUp()
+    protected function setUp(): void
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
diff --git a/tests/languages/fr/LanguagesFrTest.php b/tests/languages/fr/LanguagesFrTest.php
index b8b7ca3a..e412b5bc 100644
--- a/tests/languages/fr/LanguagesFrTest.php
+++ b/tests/languages/fr/LanguagesFrTest.php
@@ -27,7 +27,7 @@ class LanguagesFrTest extends \PHPUnit\Framework\TestCase
     /**
      * Init: force French
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager(self::$configFile);
         $this->conf->set('translation.language', 'fr');
@@ -36,7 +36,7 @@ class LanguagesFrTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset the locale since gettext seems to mess with it, making it too long
      */
-    public static function tearDownAfterClass()
+    public static function tearDownAfterClass(): void
     {
         if (! empty(getenv('UT_LOCALE'))) {
             setlocale(LC_ALL, getenv('UT_LOCALE'));
diff --git a/tests/legacy/LegacyLinkDBTest.php b/tests/legacy/LegacyLinkDBTest.php
index 0884ad03..92cf607c 100644
--- a/tests/legacy/LegacyLinkDBTest.php
+++ b/tests/legacy/LegacyLinkDBTest.php
@@ -52,7 +52,7 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
      *
      * Resets test data for each test
      */
-    protected function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
diff --git a/tests/legacy/LegacyLinkFilterTest.php b/tests/legacy/LegacyLinkFilterTest.php
index ba9ec529..8223cc15 100644
--- a/tests/legacy/LegacyLinkFilterTest.php
+++ b/tests/legacy/LegacyLinkFilterTest.php
@@ -34,7 +34,7 @@ class LegacyLinkFilterTest extends \PHPUnit\Framework\TestCase
     /**
      * Instantiate linkFilter with ReferenceLinkDB data.
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         self::$refDB = new ReferenceLinkDB(true);
         self::$refDB->write(self::$testDatastore);
diff --git a/tests/legacy/LegacyUpdaterTest.php b/tests/legacy/LegacyUpdaterTest.php
index 7c429811..9b693dcb 100644
--- a/tests/legacy/LegacyUpdaterTest.php
+++ b/tests/legacy/LegacyUpdaterTest.php
@@ -40,7 +40,7 @@ class LegacyUpdaterTest extends \PHPUnit\Framework\TestCase
     /**
      * Executed before each test.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php');
         $this->conf = new ConfigManager(self::$configFile);
@@ -754,7 +754,7 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
         if (isset($_SESSION['warnings'])) {
             unset($_SESSION['warnings']);
         }
-        
+
         $updater = new LegacyUpdater([], [], $this->conf, true, $_SESSION);
         $this->assertTrue($updater->updateMethodWebThumbnailer());
         $this->assertFalse($this->conf->exists('thumbnail'));
diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php
index 509da51d..13b85f3d 100644
--- a/tests/netscape/BookmarkExportTest.php
+++ b/tests/netscape/BookmarkExportTest.php
@@ -54,7 +54,7 @@ class BookmarkExportTest extends TestCase
     /**
      * Instantiate reference data
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         static::$conf = new ConfigManager('tests/utils/config/configJson');
         static::$conf->set('resource.datastore', static::$testDatastore);
diff --git a/tests/netscape/BookmarkImportTest.php b/tests/netscape/BookmarkImportTest.php
index f678e26b..89ae4aa7 100644
--- a/tests/netscape/BookmarkImportTest.php
+++ b/tests/netscape/BookmarkImportTest.php
@@ -75,7 +75,7 @@ class BookmarkImportTest extends TestCase
      */
     protected static $defaultTimeZone;
 
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         self::$defaultTimeZone = date_default_timezone_get();
         // Timezone without DST for test consistency
@@ -85,7 +85,7 @@ class BookmarkImportTest extends TestCase
     /**
      * Resets test data before each test
      */
-    protected function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
@@ -104,12 +104,12 @@ class BookmarkImportTest extends TestCase
     /**
      * Delete history file.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$historyFilePath);
     }
 
-    public static function tearDownAfterClass()
+    public static function tearDownAfterClass(): void
     {
         date_default_timezone_set(self::$defaultTimeZone);
     }
diff --git a/tests/plugins/PluginAddlinkTest.php b/tests/plugins/PluginAddlinkTest.php
index aa5c6988..1f60d289 100644
--- a/tests/plugins/PluginAddlinkTest.php
+++ b/tests/plugins/PluginAddlinkTest.php
@@ -14,7 +14,7 @@ class PluginAddlinkTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset plugin path.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
diff --git a/tests/plugins/PluginDefaultColorsTest.php b/tests/plugins/PluginDefaultColorsTest.php
index 9835dfa3..240bb4b2 100644
--- a/tests/plugins/PluginDefaultColorsTest.php
+++ b/tests/plugins/PluginDefaultColorsTest.php
@@ -19,7 +19,7 @@ class PluginDefaultColorsTest extends TestCase
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'sandbox';
         mkdir(PluginManager::$PLUGINS_PATH . '/default_colors/');
@@ -32,7 +32,7 @@ class PluginDefaultColorsTest extends TestCase
     /**
      * Remove sandbox files and folder
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         if (file_exists('sandbox/default_colors/default_colors.css.template')) {
             unlink('sandbox/default_colors/default_colors.css.template');
diff --git a/tests/plugins/PluginPlayvideosTest.php b/tests/plugins/PluginPlayvideosTest.php
index b7b6ce53..de1a1aec 100644
--- a/tests/plugins/PluginPlayvideosTest.php
+++ b/tests/plugins/PluginPlayvideosTest.php
@@ -19,7 +19,7 @@ class PluginPlayvideosTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
diff --git a/tests/plugins/PluginPubsubhubbubTest.php b/tests/plugins/PluginPubsubhubbubTest.php
index e66f484e..d30c3703 100644
--- a/tests/plugins/PluginPubsubhubbubTest.php
+++ b/tests/plugins/PluginPubsubhubbubTest.php
@@ -21,7 +21,7 @@ class PluginPubsubhubbubTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
diff --git a/tests/plugins/PluginQrcodeTest.php b/tests/plugins/PluginQrcodeTest.php
index c9f8c733..bc6be0eb 100644
--- a/tests/plugins/PluginQrcodeTest.php
+++ b/tests/plugins/PluginQrcodeTest.php
@@ -19,7 +19,7 @@ class PluginQrcodeTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
diff --git a/tests/plugins/PluginWallabagTest.php b/tests/plugins/PluginWallabagTest.php
index 79751921..372929ea 100644
--- a/tests/plugins/PluginWallabagTest.php
+++ b/tests/plugins/PluginWallabagTest.php
@@ -15,7 +15,7 @@ class PluginWallabagTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
diff --git a/tests/plugins/WallabagInstanceTest.php b/tests/plugins/WallabagInstanceTest.php
index a3cd9076..4cb0d4cc 100644
--- a/tests/plugins/WallabagInstanceTest.php
+++ b/tests/plugins/WallabagInstanceTest.php
@@ -14,7 +14,7 @@ class WallabagInstanceTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->instance = 'http://some.url';
     }
diff --git a/tests/render/PageCacheManagerTest.php b/tests/render/PageCacheManagerTest.php
index c258f45f..4aa7e179 100644
--- a/tests/render/PageCacheManagerTest.php
+++ b/tests/render/PageCacheManagerTest.php
@@ -29,7 +29,7 @@ class PageCacheManagerTest extends TestCase
     /**
      * Populate the cache with dummy files
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->cacheManager = new PageCacheManager(static::$testCacheDir, true);
 
@@ -48,7 +48,7 @@ class PageCacheManagerTest extends TestCase
     /**
      * Remove dummycache folder after each tests.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         array_map('unlink', glob(self::$testCacheDir . '/*'));
         rmdir(self::$testCacheDir);
diff --git a/tests/security/BanManagerTest.php b/tests/security/BanManagerTest.php
index bba7c8ad..2fef82f5 100644
--- a/tests/security/BanManagerTest.php
+++ b/tests/security/BanManagerTest.php
@@ -32,7 +32,7 @@ class BanManagerTest extends TestCase
     /**
      * Prepare or reset test resources
      */
-    public function setUp()
+    protected function setUp(): void
     {
         if (file_exists($this->banFile)) {
             unlink($this->banFile);
diff --git a/tests/security/LoginManagerTest.php b/tests/security/LoginManagerTest.php
index f242be09..cc9aa647 100644
--- a/tests/security/LoginManagerTest.php
+++ b/tests/security/LoginManagerTest.php
@@ -63,7 +63,7 @@ class LoginManagerTest extends TestCase
     /**
      * Prepare or reset test resources
      */
-    public function setUp()
+    protected function setUp(): void
     {
         if (file_exists($this->banFile)) {
             unlink($this->banFile);
diff --git a/tests/security/SessionManagerTest.php b/tests/security/SessionManagerTest.php
index 11a59f9c..27e3b1a9 100644
--- a/tests/security/SessionManagerTest.php
+++ b/tests/security/SessionManagerTest.php
@@ -24,7 +24,7 @@ class SessionManagerTest extends TestCase
     /**
      * Assign reference data
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         self::$sidHashes = \ReferenceSessionIdHashes::getHashes();
     }
@@ -32,7 +32,7 @@ class SessionManagerTest extends TestCase
     /**
      * Initialize or reset test resources
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new \FakeConfigManager([
             'credentials.login' => 'johndoe',
diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php
index a7dd70bf..277f2fb0 100644
--- a/tests/updater/UpdaterTest.php
+++ b/tests/updater/UpdaterTest.php
@@ -42,7 +42,7 @@ class UpdaterTest extends TestCase
     /**
      * Executed before each test.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->refDB = new \ReferenceLinkDB();
         $this->refDB->write(self::$testDatastore);
-- 
cgit v1.2.3


From b1baca99f280570d0336b4d71ad1f9dca213a35b Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Sun, 27 Sep 2020 14:07:08 +0200
Subject: Convert legacy PHPUnit @expected* to new ->expect*

Converted automatically using https://github.com/ArthurHoaro/convert-legacy-phpunit-expect
---
 tests/ApplicationUtilsTest.php                 |  9 ++-
 tests/FileUtilsTest.php                        | 18 +++---
 tests/HistoryTest.php                          | 12 ++--
 tests/api/ApiUtilsTest.php                     | 72 +++++++++++-----------
 tests/api/controllers/links/DeleteLinkTest.php |  4 +-
 tests/api/controllers/links/GetLinkIdTest.php  |  6 +-
 tests/api/controllers/links/PutLinkTest.php    |  6 +-
 tests/api/controllers/tags/DeleteTagTest.php   |  6 +-
 tests/api/controllers/tags/GetTagNameTest.php  |  6 +-
 tests/api/controllers/tags/PutTagTest.php      | 12 ++--
 tests/bookmark/BookmarkArrayTest.php           | 24 ++++----
 tests/bookmark/BookmarkFileServiceTest.php     | 84 +++++++++++++-------------
 tests/bookmark/BookmarkFilterTest.php          | 10 +--
 tests/config/ConfigJsonTest.php                | 14 ++---
 tests/config/ConfigManagerTest.php             | 22 +++----
 tests/config/ConfigPluginTest.php              |  4 +-
 tests/legacy/LegacyLinkDBTest.php              | 11 ++--
 tests/legacy/LegacyLinkFilterTest.php          | 10 +--
 tests/legacy/LegacyUpdaterTest.php             | 10 +--
 tests/netscape/BookmarkExportTest.php          |  3 +-
 tests/updater/UpdaterTest.php                  | 10 +--
 21 files changed, 183 insertions(+), 170 deletions(-)

(limited to 'tests')

diff --git a/tests/ApplicationUtilsTest.php b/tests/ApplicationUtilsTest.php
index 57359196..421d2dd9 100644
--- a/tests/ApplicationUtilsTest.php
+++ b/tests/ApplicationUtilsTest.php
@@ -145,10 +145,11 @@ class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase
     /**
      * Test update checks - invalid Git branch
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid branch selected for updates/
      */
     public function testCheckUpdateInvalidGitBranch()
     {
+        $this->expectExceptionMessageRegExp('/Invalid branch selected for updates/');
+
         ApplicationUtils::checkUpdate('', 'null', 0, true, true, 'unstable');
     }
 
@@ -261,20 +262,22 @@ class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase
     /**
      * Check a unsupported PHP version
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Your PHP version is obsolete/
      */
     public function testCheckSupportedPHPVersion51()
     {
+        $this->expectExceptionMessageRegExp('/Your PHP version is obsolete/');
+
         $this->assertTrue(ApplicationUtils::checkPHPVersion('5.3', '5.1.0'));
     }
 
     /**
      * Check another unsupported PHP version
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Your PHP version is obsolete/
      */
     public function testCheckSupportedPHPVersion52()
     {
+        $this->expectExceptionMessageRegExp('/Your PHP version is obsolete/');
+
         $this->assertTrue(ApplicationUtils::checkPHPVersion('5.3', '5.2'));
     }
 
diff --git a/tests/FileUtilsTest.php b/tests/FileUtilsTest.php
index eb9cb89a..6e8f44f2 100644
--- a/tests/FileUtilsTest.php
+++ b/tests/FileUtilsTest.php
@@ -49,12 +49,12 @@ class FileUtilsTest extends \PHPUnit\Framework\TestCase
 
     /**
      * File not writable: raise an exception.
-     *
-     * @expectedException Shaarli\Exceptions\IOException
-     * @expectedExceptionMessage Error accessing "sandbox/flat.db"
      */
     public function testWriteWithoutPermission()
     {
+        $this->expectException(\Shaarli\Exceptions\IOException::class);
+        $this->expectExceptionMessage('Error accessing "sandbox/flat.db"');
+
         touch(self::$file);
         chmod(self::$file, 0440);
         FileUtils::writeFlatDB(self::$file, null);
@@ -62,23 +62,23 @@ class FileUtilsTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Folder non existent: raise an exception.
-     *
-     * @expectedException Shaarli\Exceptions\IOException
-     * @expectedExceptionMessage Error accessing "nopefolder"
      */
     public function testWriteFolderDoesNotExist()
     {
+        $this->expectException(\Shaarli\Exceptions\IOException::class);
+        $this->expectExceptionMessage('Error accessing "nopefolder"');
+
         FileUtils::writeFlatDB('nopefolder/file', null);
     }
 
     /**
      * Folder non writable: raise an exception.
-     *
-     * @expectedException Shaarli\Exceptions\IOException
-     * @expectedExceptionMessage Error accessing "sandbox"
      */
     public function testWriteFolderPermission()
     {
+        $this->expectException(\Shaarli\Exceptions\IOException::class);
+        $this->expectExceptionMessage('Error accessing "sandbox"');
+
         chmod(dirname(self::$file), 0555);
         try {
             FileUtils::writeFlatDB(self::$file, null);
diff --git a/tests/HistoryTest.php b/tests/HistoryTest.php
index e9e61032..fb633e79 100644
--- a/tests/HistoryTest.php
+++ b/tests/HistoryTest.php
@@ -44,12 +44,12 @@ class HistoryTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Not writable history file: raise an exception.
-     *
-     * @expectedException Exception
-     * @expectedExceptionMessage History file isn't readable or writable
      */
     public function testConstructNotWritable()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('History file isn\'t readable or writable');
+
         touch(self::$historyFilePath);
         chmod(self::$historyFilePath, 0440);
         $history = new History(self::$historyFilePath);
@@ -58,12 +58,12 @@ class HistoryTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Not parsable history file: raise an exception.
-     *
-     * @expectedException Exception
-     * @expectedExceptionMessageRegExp /Could not parse history file/
      */
     public function testConstructNotParsable()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Could not parse history file/');
+
         file_put_contents(self::$historyFilePath, 'not parsable');
         $history = new History(self::$historyFilePath);
         // gzinflate generates a warning
diff --git a/tests/api/ApiUtilsTest.php b/tests/api/ApiUtilsTest.php
index e8075a5d..96787014 100644
--- a/tests/api/ApiUtilsTest.php
+++ b/tests/api/ApiUtilsTest.php
@@ -66,143 +66,143 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test validateJwtToken() with a malformed JWT token.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Malformed JWT token
      */
     public function testValidateJwtTokenMalformed()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Malformed JWT token');
+
         $token = 'ABC.DEF';
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with an empty JWT token.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Malformed JWT token
      */
     public function testValidateJwtTokenMalformedEmpty()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Malformed JWT token');
+
         $token = false;
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with a JWT token without header.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Malformed JWT token
      */
     public function testValidateJwtTokenMalformedEmptyHeader()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Malformed JWT token');
+
         $token = '.payload.signature';
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with a JWT token without payload
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Malformed JWT token
      */
     public function testValidateJwtTokenMalformedEmptyPayload()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Malformed JWT token');
+
         $token = 'header..signature';
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with a JWT token with an empty signature.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT signature
      */
     public function testValidateJwtTokenInvalidSignatureEmpty()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT signature');
+
         $token = 'header.payload.';
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with a JWT token with an invalid signature.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT signature
      */
     public function testValidateJwtTokenInvalidSignature()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT signature');
+
         $token = 'header.payload.nope';
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with a JWT token with a signature generated with the wrong API secret.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT signature
      */
     public function testValidateJwtTokenInvalidSignatureSecret()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT signature');
+
         ApiUtils::validateJwtToken(self::generateValidJwtToken('foo'), 'bar');
     }
 
     /**
      * Test validateJwtToken() with a JWT token with a an invalid header (not JSON).
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT header
      */
     public function testValidateJwtTokenInvalidHeader()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT header');
+
         $token = $this->generateCustomJwtToken('notJSON', '{"JSON":1}', 'secret');
         ApiUtils::validateJwtToken($token, 'secret');
     }
 
     /**
      * Test validateJwtToken() with a JWT token with a an invalid payload (not JSON).
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT payload
      */
     public function testValidateJwtTokenInvalidPayload()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT payload');
+
         $token = $this->generateCustomJwtToken('{"JSON":1}', 'notJSON', 'secret');
         ApiUtils::validateJwtToken($token, 'secret');
     }
 
     /**
      * Test validateJwtToken() with a JWT token without issued time.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT issued time
      */
     public function testValidateJwtTokenInvalidTimeEmpty()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT issued time');
+
         $token = $this->generateCustomJwtToken('{"JSON":1}', '{"JSON":1}', 'secret');
         ApiUtils::validateJwtToken($token, 'secret');
     }
 
     /**
      * Test validateJwtToken() with an expired JWT token.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT issued time
      */
     public function testValidateJwtTokenInvalidTimeExpired()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT issued time');
+
         $token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() - 600) . '}', 'secret');
         ApiUtils::validateJwtToken($token, 'secret');
     }
 
     /**
      * Test validateJwtToken() with a JWT token issued in the future.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT issued time
      */
     public function testValidateJwtTokenInvalidTimeFuture()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT issued time');
+
         $token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() + 60) . '}', 'secret');
         ApiUtils::validateJwtToken($token, 'secret');
     }
diff --git a/tests/api/controllers/links/DeleteLinkTest.php b/tests/api/controllers/links/DeleteLinkTest.php
index 10dfe8bc..bd8403cf 100644
--- a/tests/api/controllers/links/DeleteLinkTest.php
+++ b/tests/api/controllers/links/DeleteLinkTest.php
@@ -113,11 +113,11 @@ class DeleteLinkTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test DELETE link endpoint: reach not existing ID.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiLinkNotFoundException
      */
     public function testDeleteLink404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiLinkNotFoundException::class);
+
         $id = -1;
         $this->assertFalse($this->bookmarkService->exists($id));
         $env = Environment::mock([
diff --git a/tests/api/controllers/links/GetLinkIdTest.php b/tests/api/controllers/links/GetLinkIdTest.php
index ee42e259..3a3aaa7b 100644
--- a/tests/api/controllers/links/GetLinkIdTest.php
+++ b/tests/api/controllers/links/GetLinkIdTest.php
@@ -120,12 +120,12 @@ class GetLinkIdTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test basic getLink service: get non existent link => ApiLinkNotFoundException.
-     *
-     * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException
-     * @expectedExceptionMessage Link not found
      */
     public function testGetLink404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiLinkNotFoundException::class);
+        $this->expectExceptionMessage('Link not found');
+
         $env = Environment::mock([
             'REQUEST_METHOD' => 'GET',
         ]);
diff --git a/tests/api/controllers/links/PutLinkTest.php b/tests/api/controllers/links/PutLinkTest.php
index f582a2b5..3d62a1b1 100644
--- a/tests/api/controllers/links/PutLinkTest.php
+++ b/tests/api/controllers/links/PutLinkTest.php
@@ -218,12 +218,12 @@ class PutLinkTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test link update on non existent link => ApiLinkNotFoundException.
-     *
-     * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException
-     * @expectedExceptionMessage Link not found
      */
     public function testGetLink404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiLinkNotFoundException::class);
+        $this->expectExceptionMessage('Link not found');
+
         $env = Environment::mock([
             'REQUEST_METHOD' => 'PUT',
         ]);
diff --git a/tests/api/controllers/tags/DeleteTagTest.php b/tests/api/controllers/tags/DeleteTagTest.php
index b0980572..0d991b85 100644
--- a/tests/api/controllers/tags/DeleteTagTest.php
+++ b/tests/api/controllers/tags/DeleteTagTest.php
@@ -150,12 +150,12 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test DELETE tag endpoint: reach not existing tag.
-     *
-     * @expectedException Shaarli\Api\Exceptions\ApiTagNotFoundException
-     * @expectedExceptionMessage Tag not found
      */
     public function testDeleteLink404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiTagNotFoundException::class);
+        $this->expectExceptionMessage('Tag not found');
+
         $tagName = 'nopenope';
         $tags = $this->bookmarkService->bookmarksCountPerTag();
         $this->assertFalse(isset($tags[$tagName]));
diff --git a/tests/api/controllers/tags/GetTagNameTest.php b/tests/api/controllers/tags/GetTagNameTest.php
index f8ee10d9..a2fb89ab 100644
--- a/tests/api/controllers/tags/GetTagNameTest.php
+++ b/tests/api/controllers/tags/GetTagNameTest.php
@@ -117,12 +117,12 @@ class GetTagNameTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test basic getTag service: get non existent tag => ApiTagNotFoundException.
-     *
-     * @expectedException Shaarli\Api\Exceptions\ApiTagNotFoundException
-     * @expectedExceptionMessage Tag not found
      */
     public function testGetTag404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiTagNotFoundException::class);
+        $this->expectExceptionMessage('Tag not found');
+
         $env = Environment::mock([
             'REQUEST_METHOD' => 'GET',
         ]);
diff --git a/tests/api/controllers/tags/PutTagTest.php b/tests/api/controllers/tags/PutTagTest.php
index e0bc8663..0845dce1 100644
--- a/tests/api/controllers/tags/PutTagTest.php
+++ b/tests/api/controllers/tags/PutTagTest.php
@@ -159,12 +159,12 @@ class PutTagTest extends \PHPUnit\Framework\TestCase
 
     /**
      * 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()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiBadParametersException::class);
+        $this->expectExceptionMessage('New tag name is required in the request body');
+
         $tagName = 'gnu';
         $newName = '';
 
@@ -194,12 +194,12 @@ class PutTagTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test tag update on non existent tag => ApiTagNotFoundException.
-     *
-     * @expectedException Shaarli\Api\Exceptions\ApiTagNotFoundException
-     * @expectedExceptionMessage Tag not found
      */
     public function testPutTag404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiTagNotFoundException::class);
+        $this->expectExceptionMessage('Tag not found');
+
         $env = Environment::mock([
             'REQUEST_METHOD' => 'PUT',
         ]);
diff --git a/tests/bookmark/BookmarkArrayTest.php b/tests/bookmark/BookmarkArrayTest.php
index 0f8f04c5..bad3af8d 100644
--- a/tests/bookmark/BookmarkArrayTest.php
+++ b/tests/bookmark/BookmarkArrayTest.php
@@ -47,22 +47,22 @@ class BookmarkArrayTest extends TestCase
 
     /**
      * Test adding a bad entry: wrong type
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryInstance()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $array[] = 'nope';
     }
 
     /**
      * Test adding a bad entry: no id
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryNoId()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $bookmark = new Bookmark();
         $array[] = $bookmark;
@@ -70,11 +70,11 @@ class BookmarkArrayTest extends TestCase
 
     /**
      * Test adding a bad entry: no url
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryNoUrl()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $bookmark = (new Bookmark())->setId(11);
         $array[] = $bookmark;
@@ -82,11 +82,11 @@ class BookmarkArrayTest extends TestCase
 
     /**
      * Test adding a bad entry: invalid offset
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryOffset()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $bookmark = (new Bookmark())->setId(11);
         $bookmark->validate();
@@ -95,11 +95,11 @@ class BookmarkArrayTest extends TestCase
 
     /**
      * Test adding a bad entry: invalid ID type
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryIdType()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $bookmark = (new Bookmark())->setId('nope');
         $bookmark->validate();
@@ -108,11 +108,11 @@ class BookmarkArrayTest extends TestCase
 
     /**
      * Test adding a bad entry: ID/offset not consistent
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryIdOffset()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $bookmark = (new Bookmark())->setId(11);
         $bookmark->validate();
diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php
index aed4dc76..9cff0fb3 100644
--- a/tests/bookmark/BookmarkFileServiceTest.php
+++ b/tests/bookmark/BookmarkFileServiceTest.php
@@ -134,11 +134,11 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test get() method for an undefined bookmark
-     *
-     * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testGetUndefined()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $this->privateLinkDB->get(666);
     }
 
@@ -230,13 +230,13 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test add() method for a bookmark without any field set and without writing the data store
-     *
-     * @expectedExceptionMessage Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testAddMinimalNoWrite()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $bookmark = new Bookmark();
-        $this->privateLinkDB->add($bookmark);
+        $this->privateLinkDB->add($bookmark, false);
 
         $bookmark = $this->privateLinkDB->get(43);
         $this->assertEquals(43, $bookmark->getId());
@@ -249,34 +249,34 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test add() method while logged out
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage You're not authorized to alter the datastore
      */
     public function testAddLoggedOut()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('You\'re not authorized to alter the datastore');
+
         $this->publicLinkDB->add(new Bookmark());
     }
 
     /**
      * Test add() method with an entry which is not a bookmark instance
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage Provided data is invalid
      */
     public function testAddNotABookmark()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('Provided data is invalid');
+
         $this->privateLinkDB->add(['title' => 'hi!']);
     }
 
     /**
      * Test add() method with a Bookmark already containing an ID
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage This bookmarks already exists
      */
     public function testAddWithId()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('This bookmarks already exists');
+
         $bookmark = new Bookmark();
         $bookmark->setId(43);
         $this->privateLinkDB->add($bookmark);
@@ -397,44 +397,44 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test set() method while logged out
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage You're not authorized to alter the datastore
      */
     public function testSetLoggedOut()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('You\'re not authorized to alter the datastore');
+
         $this->publicLinkDB->set(new Bookmark());
     }
 
     /**
      * Test set() method with an entry which is not a bookmark instance
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage Provided data is invalid
      */
     public function testSetNotABookmark()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('Provided data is invalid');
+
         $this->privateLinkDB->set(['title' => 'hi!']);
     }
 
     /**
      * Test set() method with a Bookmark without an ID defined.
-     *
-     * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testSetWithoutId()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $bookmark = new Bookmark();
         $this->privateLinkDB->set($bookmark);
     }
 
     /**
      * Test set() method with a Bookmark with an unknow ID
-     *
-     * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testSetWithUnknownId()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $bookmark = new Bookmark();
         $bookmark->setId(666);
         $this->privateLinkDB->set($bookmark);
@@ -481,23 +481,23 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test addOrSet() method while logged out
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage You're not authorized to alter the datastore
      */
     public function testAddOrSetLoggedOut()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('You\'re not authorized to alter the datastore');
+
         $this->publicLinkDB->addOrSet(new Bookmark());
     }
 
     /**
      * Test addOrSet() method with an entry which is not a bookmark instance
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage Provided data is invalid
      */
     public function testAddOrSetNotABookmark()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('Provided data is invalid');
+
         $this->privateLinkDB->addOrSet(['title' => 'hi!']);
     }
 
@@ -524,11 +524,11 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test remove() method with an existing Bookmark
-     *
-     * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testRemoveExisting()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $bookmark = $this->privateLinkDB->get(42);
         $this->privateLinkDB->remove($bookmark);
 
@@ -548,34 +548,34 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test remove() method while logged out
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage You're not authorized to alter the datastore
      */
     public function testRemoveLoggedOut()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('You\'re not authorized to alter the datastore');
+
         $bookmark = $this->privateLinkDB->get(42);
         $this->publicLinkDB->remove($bookmark);
     }
 
     /**
      * Test remove() method with an entry which is not a bookmark instance
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage Provided data is invalid
      */
     public function testRemoveNotABookmark()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('Provided data is invalid');
+
         $this->privateLinkDB->remove(['title' => 'hi!']);
     }
 
     /**
      * Test remove() method with a Bookmark with an unknown ID
-     *
-     * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testRemoveWithUnknownId()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $bookmark = new Bookmark();
         $bookmark->setId(666);
         $this->privateLinkDB->remove($bookmark);
@@ -635,15 +635,15 @@ class BookmarkFileServiceTest extends TestCase
      * to make sure that nothing have been broken in the migration process.
      * They mostly cover search/filters. Some of them might be redundant with the previous ones.
      */
-
     /**
      * Attempt to instantiate a LinkDB whereas the datastore is not writable
      *
      * @expectedException              Shaarli\Bookmark\Exception\NotWritableDataStoreException
-     * @expectedExceptionMessageRegExp #Couldn't load data from the data store file "null".*#
      */
     public function testConstructDatastoreNotWriteable()
     {
+        $this->expectExceptionMessageRegExp('#Couldn\'t load data from the data store file "null".*#');
+
         $conf = new ConfigManager('tests/utils/config/configJson');
         $conf->set('resource.datastore', 'null/store.db');
         new BookmarkFileService($conf, $this->history, true);
diff --git a/tests/bookmark/BookmarkFilterTest.php b/tests/bookmark/BookmarkFilterTest.php
index 91e139c2..752631a5 100644
--- a/tests/bookmark/BookmarkFilterTest.php
+++ b/tests/bookmark/BookmarkFilterTest.php
@@ -213,20 +213,22 @@ class BookmarkFilterTest extends TestCase
     /**
      * Use an invalid date format
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid date format/
      */
     public function testFilterInvalidDayWithChars()
     {
+        $this->expectExceptionMessageRegExp('/Invalid date format/');
+
         self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, 'Rainy day, dream away');
     }
 
     /**
      * Use an invalid date format
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid date format/
      */
     public function testFilterInvalidDayDigits()
     {
+        $this->expectExceptionMessageRegExp('/Invalid date format/');
+
         self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20');
     }
 
@@ -250,11 +252,11 @@ class BookmarkFilterTest extends TestCase
 
     /**
      * No link for this hash
-     *
-     * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testFilterUnknownSmallHash()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         self::$linkFilter->filter(BookmarkFilter::$FILTER_HASH, 'Iblaah');
     }
 
diff --git a/tests/config/ConfigJsonTest.php b/tests/config/ConfigJsonTest.php
index f1612e9b..f884b0c6 100644
--- a/tests/config/ConfigJsonTest.php
+++ b/tests/config/ConfigJsonTest.php
@@ -38,12 +38,12 @@ class ConfigJsonTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Read a non existent config file -> empty array.
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessageRegExp  /An error occurred while parsing JSON configuration file \([\w\/\.]+\): error code #4/
      */
     public function testReadInvalidJson()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp(' /An error occurred while parsing JSON configuration file \\([\\w\\/\\.]+\\): error code #4/');
+
         $this->configIO->read('tests/utils/config/configInvalid.json.php');
     }
 
@@ -110,22 +110,22 @@ class ConfigJsonTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Write to invalid path.
-     *
-     * @expectedException \Shaarli\Exceptions\IOException
      */
     public function testWriteInvalidArray()
     {
+        $this->expectException(\Shaarli\Exceptions\IOException::class);
+
         $conf = array('conf' => 'value');
         @$this->configIO->write(array(), $conf);
     }
 
     /**
      * Write to invalid path.
-     *
-     * @expectedException \Shaarli\Exceptions\IOException
      */
     public function testWriteInvalidBlank()
     {
+        $this->expectException(\Shaarli\Exceptions\IOException::class);
+
         $conf = array('conf' => 'value');
         @$this->configIO->write('', $conf);
     }
diff --git a/tests/config/ConfigManagerTest.php b/tests/config/ConfigManagerTest.php
index 69456bce..802e6524 100644
--- a/tests/config/ConfigManagerTest.php
+++ b/tests/config/ConfigManagerTest.php
@@ -95,44 +95,44 @@ class ConfigManagerTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Set with an empty key.
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*#
      */
     public function testSetEmptyKey()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('#^Invalid setting key parameter. String expected, got.*#');
+
         $this->conf->set('', 'stuff');
     }
 
     /**
      * Set with an array key.
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*#
      */
     public function testSetArrayKey()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('#^Invalid setting key parameter. String expected, got.*#');
+
         $this->conf->set(array('foo' => 'bar'), 'stuff');
     }
 
     /**
      * Remove with an empty key.
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*#
      */
     public function testRmoveEmptyKey()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('#^Invalid setting key parameter. String expected, got.*#');
+
         $this->conf->remove('');
     }
 
     /**
      * Try to write the config without mandatory parameter (e.g. 'login').
-     *
-     * @expectedException Shaarli\Config\Exception\MissingFieldConfigException
      */
     public function testWriteMissingParameter()
     {
+        $this->expectException(\Shaarli\Config\Exception\MissingFieldConfigException::class);
+
         $this->conf->setConfigFile('tests/utils/config/configTmp');
         $this->assertFalse(file_exists($this->conf->getConfigFileExt()));
         $this->conf->reload();
diff --git a/tests/config/ConfigPluginTest.php b/tests/config/ConfigPluginTest.php
index b2cc0045..3a45f623 100644
--- a/tests/config/ConfigPluginTest.php
+++ b/tests/config/ConfigPluginTest.php
@@ -46,11 +46,11 @@ class ConfigPluginTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test save_plugin_config with invalid data.
-     *
-     * @expectedException Shaarli\Config\Exception\PluginConfigOrderException
      */
     public function testSavePluginConfigInvalid()
     {
+        $this->expectException(\Shaarli\Config\Exception\PluginConfigOrderException::class);
+
         $data = array(
             'plugin2' => 0,
             'plugin3' => 0,
diff --git a/tests/legacy/LegacyLinkDBTest.php b/tests/legacy/LegacyLinkDBTest.php
index 92cf607c..819bc272 100644
--- a/tests/legacy/LegacyLinkDBTest.php
+++ b/tests/legacy/LegacyLinkDBTest.php
@@ -101,10 +101,11 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
      * Attempt to instantiate a LinkDB whereas the datastore is not writable
      *
      * @expectedException              Shaarli\Exceptions\IOException
-     * @expectedExceptionMessageRegExp /Error accessing "null"/
      */
     public function testConstructDatastoreNotWriteable()
     {
+        $this->expectExceptionMessageRegExp('/Error accessing "null"/');
+
         new LegacyLinkDB('null/store.db', false, false);
     }
 
@@ -420,22 +421,22 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test filterHash() with an invalid smallhash.
-     *
-     * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testFilterHashInValid1()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $request = 'blabla';
         self::$publicLinkDB->filterHash($request);
     }
 
     /**
      * Test filterHash() with an empty smallhash.
-     *
-     * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testFilterHashInValid()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         self::$publicLinkDB->filterHash('');
     }
 
diff --git a/tests/legacy/LegacyLinkFilterTest.php b/tests/legacy/LegacyLinkFilterTest.php
index 8223cc15..9db921a9 100644
--- a/tests/legacy/LegacyLinkFilterTest.php
+++ b/tests/legacy/LegacyLinkFilterTest.php
@@ -198,20 +198,22 @@ class LegacyLinkFilterTest extends \PHPUnit\Framework\TestCase
     /**
      * Use an invalid date format
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid date format/
      */
     public function testFilterInvalidDayWithChars()
     {
+        $this->expectExceptionMessageRegExp('/Invalid date format/');
+
         self::$linkFilter->filter(LegacyLinkFilter::$FILTER_DAY, 'Rainy day, dream away');
     }
 
     /**
      * Use an invalid date format
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid date format/
      */
     public function testFilterInvalidDayDigits()
     {
+        $this->expectExceptionMessageRegExp('/Invalid date format/');
+
         self::$linkFilter->filter(LegacyLinkFilter::$FILTER_DAY, '20');
     }
 
@@ -235,11 +237,11 @@ class LegacyLinkFilterTest extends \PHPUnit\Framework\TestCase
 
     /**
      * No link for this hash
-     *
-     * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testFilterUnknownSmallHash()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         self::$linkFilter->filter(LegacyLinkFilter::$FILTER_HASH, 'Iblaah');
     }
 
diff --git a/tests/legacy/LegacyUpdaterTest.php b/tests/legacy/LegacyUpdaterTest.php
index 9b693dcb..acfac530 100644
--- a/tests/legacy/LegacyUpdaterTest.php
+++ b/tests/legacy/LegacyUpdaterTest.php
@@ -82,10 +82,11 @@ class LegacyUpdaterTest extends \PHPUnit\Framework\TestCase
      * Test errors in UpdaterUtils::write_updates_file(): empty updates file.
      *
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Updates file path is not set(.*)/
      */
     public function testWriteEmptyUpdatesFile()
     {
+        $this->expectExceptionMessageRegExp('/Updates file path is not set(.*)/');
+
         UpdaterUtils::write_updates_file('', array('test'));
     }
 
@@ -93,10 +94,11 @@ class LegacyUpdaterTest extends \PHPUnit\Framework\TestCase
      * Test errors in UpdaterUtils::write_updates_file(): not writable updates file.
      *
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Unable to write(.*)/
      */
     public function testWriteUpdatesFileNotWritable()
     {
+        $this->expectExceptionMessageRegExp('/Unable to write(.*)/');
+
         $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
         touch($updatesFile);
         chmod($updatesFile, 0444);
@@ -161,11 +163,11 @@ class LegacyUpdaterTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test Update failed.
-     *
-     * @expectedException \Exception
      */
     public function testUpdateFailed()
     {
+        $this->expectException(\Exception::class);
+
         $updates = array(
             'updateMethodDummy1',
             'updateMethodDummy2',
diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php
index 13b85f3d..a6eacae4 100644
--- a/tests/netscape/BookmarkExportTest.php
+++ b/tests/netscape/BookmarkExportTest.php
@@ -78,10 +78,11 @@ class BookmarkExportTest extends TestCase
     /**
      * Attempt to export an invalid link selection
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid export selection/
      */
     public function testFilterAndFormatInvalid()
     {
+        $this->expectExceptionMessageRegExp('/Invalid export selection/');
+
         $this->netscapeBookmarkUtils->filterAndFormat(
             self::$formatter,
             'derp',
diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php
index 277f2fb0..5cfcd5db 100644
--- a/tests/updater/UpdaterTest.php
+++ b/tests/updater/UpdaterTest.php
@@ -89,10 +89,11 @@ class UpdaterTest extends TestCase
      * Test errors in UpdaterUtils::write_updates_file(): empty updates file.
      *
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Updates file path is not set(.*)/
      */
     public function testWriteEmptyUpdatesFile()
     {
+        $this->expectExceptionMessageRegExp('/Updates file path is not set(.*)/');
+
         UpdaterUtils::write_updates_file('', array('test'));
     }
 
@@ -100,10 +101,11 @@ class UpdaterTest extends TestCase
      * Test errors in UpdaterUtils::write_updates_file(): not writable updates file.
      *
      * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Unable to write(.*)/
      */
     public function testWriteUpdatesFileNotWritable()
     {
+        $this->expectExceptionMessageRegExp('/Unable to write(.*)/');
+
         $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
         touch($updatesFile);
         chmod($updatesFile, 0444);
@@ -168,11 +170,11 @@ class UpdaterTest extends TestCase
 
     /**
      * Test Update failed.
-     *
-     * @expectedException \Exception
      */
     public function testUpdateFailed()
     {
+        $this->expectException(\Exception::class);
+
         $updates = array(
             'updateMethodDummy1',
             'updateMethodDummy2',
-- 
cgit v1.2.3


From a5a9cf23acd1248585173aa32757d9720b5f2d62 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 29 Sep 2020 14:41:40 +0200
Subject: Compatibility with PHPUnit 9

---
 tests/ApplicationUtilsTest.php                     |  2 +-
 tests/FileUtilsTest.php                            |  2 +-
 tests/HistoryTest.php                              |  3 +-
 tests/LanguagesTest.php                            |  2 +-
 tests/PluginManagerTest.php                        |  2 +-
 tests/TestCase.php                                 | 77 ++++++++++++++++++++++
 tests/ThumbnailerTest.php                          |  1 -
 tests/TimeZoneTest.php                             |  2 +-
 tests/UtilsTest.php                                |  2 +-
 tests/api/ApiMiddlewareTest.php                    | 14 ++--
 tests/api/ApiUtilsTest.php                         |  2 +-
 tests/api/controllers/history/HistoryTest.php      |  2 +-
 tests/api/controllers/info/InfoTest.php            |  2 +-
 tests/api/controllers/links/DeleteLinkTest.php     |  2 +-
 tests/api/controllers/links/GetLinkIdTest.php      |  2 +-
 tests/api/controllers/links/GetLinksTest.php       |  2 +-
 tests/api/controllers/links/PostLinkTest.php       |  2 +-
 tests/api/controllers/links/PutLinkTest.php        |  2 +-
 tests/api/controllers/tags/DeleteTagTest.php       |  2 +-
 tests/api/controllers/tags/GetTagNameTest.php      |  2 +-
 tests/api/controllers/tags/GetTagsTest.php         |  2 +-
 tests/api/controllers/tags/PutTagTest.php          |  2 +-
 tests/bookmark/BookmarkArrayTest.php               |  5 +-
 tests/bookmark/BookmarkFileServiceTest.php         |  4 +-
 tests/bookmark/BookmarkFilterTest.php              |  2 +-
 tests/bookmark/BookmarkInitializerTest.php         |  2 +-
 tests/bookmark/BookmarkTest.php                    | 12 ++--
 tests/bookmark/LinkUtilsTest.php                   | 22 +++----
 tests/bootstrap.php                                |  1 +
 tests/config/ConfigJsonTest.php                    |  2 +-
 tests/config/ConfigManagerTest.php                 |  2 +-
 tests/config/ConfigPhpTest.php                     |  2 +-
 tests/config/ConfigPluginTest.php                  |  2 +-
 tests/container/ContainerBuilderTest.php           |  2 +-
 tests/feed/CachedPageTest.php                      |  2 +-
 tests/feed/FeedBuilderTest.php                     | 18 ++---
 tests/formatter/BookmarkDefaultFormatterTest.php   |  2 +-
 tests/formatter/BookmarkMarkdownFormatterTest.php  |  2 +-
 tests/formatter/BookmarkRawFormatterTest.php       |  2 +-
 tests/formatter/FormatterFactoryTest.php           |  2 +-
 tests/front/ShaarliAdminMiddlewareTest.php         |  2 +-
 tests/front/ShaarliMiddlewareTest.php              |  2 +-
 .../controller/admin/ConfigureControllerTest.php   |  2 +-
 .../controller/admin/ExportControllerTest.php      |  2 +-
 .../controller/admin/ImportControllerTest.php      |  2 +-
 .../controller/admin/LogoutControllerTest.php      |  3 +-
 .../ManageShaareControllerTest/AddShaareTest.php   |  2 +-
 .../ChangeVisibilityBookmarkTest.php               |  2 +-
 .../DeleteBookmarkTest.php                         |  2 +-
 .../DisplayCreateFormTest.php                      | 12 ++--
 .../DisplayEditFormTest.php                        |  2 +-
 .../ManageShaareControllerTest/PinBookmarkTest.php |  2 +-
 .../SaveBookmarkTest.php                           | 40 +++++------
 .../controller/admin/ManageTagControllerTest.php   |  2 +-
 .../controller/admin/PasswordControllerTest.php    |  2 +-
 .../controller/admin/PluginsControllerTest.php     |  2 +-
 .../admin/SessionFilterControllerTest.php          |  2 +-
 .../admin/ShaarliAdminControllerTest.php           |  2 +-
 .../controller/admin/ThumbnailsControllerTest.php  |  2 +-
 .../front/controller/admin/TokenControllerTest.php |  2 +-
 .../front/controller/admin/ToolsControllerTest.php |  2 +-
 .../visitor/BookmarkListControllerTest.php         |  2 +-
 .../controller/visitor/DailyControllerTest.php     | 48 +++++++-------
 .../controller/visitor/ErrorControllerTest.php     |  2 +-
 .../visitor/ErrorNotFoundControllerTest.php        |  2 +-
 .../controller/visitor/FeedControllerTest.php      | 38 ++++++-----
 .../visitor/FrontControllerMockHelper.php          |  3 +-
 .../controller/visitor/InstallControllerTest.php   |  2 +-
 .../controller/visitor/LoginControllerTest.php     |  2 +-
 .../visitor/OpenSearchControllerTest.php           |  2 +-
 .../visitor/PictureWallControllerTest.php          | 18 ++---
 .../visitor/PublicSessionFilterControllerTest.php  |  2 +-
 .../visitor/ShaarliVisitorControllerTest.php       |  2 +-
 .../controller/visitor/TagCloudControllerTest.php  | 74 ++++++++++++---------
 .../front/controller/visitor/TagControllerTest.php |  2 +-
 tests/http/HttpUtils/ClientIpIdTest.php            |  2 +-
 tests/http/HttpUtils/GetHttpUrlTest.php            |  2 +-
 tests/http/HttpUtils/GetIpAdressFromProxyTest.php  |  2 +-
 tests/http/HttpUtils/IndexUrlTest.php              |  2 +-
 tests/http/HttpUtils/IndexUrlTestWithConstant.php  |  2 +-
 tests/http/HttpUtils/IsHttpsTest.php               |  2 +-
 tests/http/HttpUtils/PageUrlTest.php               |  2 +-
 tests/http/HttpUtils/ServerUrlTest.php             |  2 +-
 tests/http/UrlTest.php                             |  2 +-
 tests/http/UrlUtils/CleanupUrlTest.php             |  2 +-
 tests/http/UrlUtils/GetUrlSchemeTest.php           |  2 +-
 tests/http/UrlUtils/UnparseUrlTest.php             |  2 +-
 tests/http/UrlUtils/WhitelistProtocolsTest.php     |  2 +-
 tests/languages/fr/LanguagesFrTest.php             |  2 +-
 tests/legacy/LegacyControllerTest.php              |  2 +-
 tests/legacy/LegacyLinkDBTest.php                  | 12 ++--
 tests/legacy/LegacyLinkFilterTest.php              |  2 +-
 tests/legacy/LegacyUpdaterTest.php                 |  4 +-
 tests/netscape/BookmarkExportTest.php              |  2 +-
 tests/netscape/BookmarkImportTest.php              |  2 +-
 tests/plugins/PluginAddlinkTest.php                |  2 +-
 tests/plugins/PluginArchiveorgTest.php             |  2 +-
 tests/plugins/PluginDefaultColorsTest.php          |  2 +-
 tests/plugins/PluginIssoTest.php                   |  8 +--
 tests/plugins/PluginPlayvideosTest.php             |  2 +-
 tests/plugins/PluginPubsubhubbubTest.php           |  2 +-
 tests/plugins/PluginQrcodeTest.php                 |  2 +-
 tests/plugins/PluginWallabagTest.php               |  2 +-
 tests/plugins/WallabagInstanceTest.php             |  2 +-
 tests/render/PageCacheManagerTest.php              |  2 +-
 tests/render/ThemeUtilsTest.php                    |  2 +-
 tests/security/BanManagerTest.php                  |  2 +-
 tests/security/LoginManagerTest.php                |  2 +-
 tests/security/SessionManagerTest.php              |  2 +-
 tests/updater/UpdaterTest.php                      |  2 +-
 110 files changed, 346 insertions(+), 249 deletions(-)
 create mode 100644 tests/TestCase.php

(limited to 'tests')

diff --git a/tests/ApplicationUtilsTest.php b/tests/ApplicationUtilsTest.php
index 421d2dd9..7ad1d34c 100644
--- a/tests/ApplicationUtilsTest.php
+++ b/tests/ApplicationUtilsTest.php
@@ -8,7 +8,7 @@ require_once 'tests/utils/FakeApplicationUtils.php';
 /**
  * Unitary tests for Shaarli utilities
  */
-class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase
+class ApplicationUtilsTest extends \Shaarli\TestCase
 {
     protected static $testUpdateFile = 'sandbox/update.txt';
     protected static $testVersion = '0.5.0';
diff --git a/tests/FileUtilsTest.php b/tests/FileUtilsTest.php
index 6e8f44f2..9163bdf1 100644
--- a/tests/FileUtilsTest.php
+++ b/tests/FileUtilsTest.php
@@ -9,7 +9,7 @@ use Exception;
  *
  * Test file utility class.
  */
-class FileUtilsTest extends \PHPUnit\Framework\TestCase
+class FileUtilsTest extends \Shaarli\TestCase
 {
     /**
      * @var string Test file path.
diff --git a/tests/HistoryTest.php b/tests/HistoryTest.php
index fb633e79..6dc0e5b7 100644
--- a/tests/HistoryTest.php
+++ b/tests/HistoryTest.php
@@ -3,10 +3,9 @@
 namespace Shaarli;
 
 use DateTime;
-use Exception;
 use Shaarli\Bookmark\Bookmark;
 
-class HistoryTest extends \PHPUnit\Framework\TestCase
+class HistoryTest extends \Shaarli\TestCase
 {
     /**
      * @var string History file path
diff --git a/tests/LanguagesTest.php b/tests/LanguagesTest.php
index 914179c8..ce24c160 100644
--- a/tests/LanguagesTest.php
+++ b/tests/LanguagesTest.php
@@ -7,7 +7,7 @@ use Shaarli\Config\ConfigManager;
 /**
  * Class LanguagesTest.
  */
-class LanguagesTest extends \PHPUnit\Framework\TestCase
+class LanguagesTest extends \Shaarli\TestCase
 {
     /**
      * @var string Config file path (without extension).
diff --git a/tests/PluginManagerTest.php b/tests/PluginManagerTest.php
index 3018999c..38cd5eba 100644
--- a/tests/PluginManagerTest.php
+++ b/tests/PluginManagerTest.php
@@ -6,7 +6,7 @@ use Shaarli\Config\ConfigManager;
 /**
  * Unit tests for Plugins
  */
-class PluginManagerTest extends \PHPUnit\Framework\TestCase
+class PluginManagerTest extends \Shaarli\TestCase
 {
     /**
      * Path to tests plugin.
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 00000000..781e7aa3
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,77 @@
+expectExceptionMessageMatches($regularExpression);
+        } else {
+            parent::expectExceptionMessageRegExp($regularExpression);
+        }
+    }
+
+    /**
+     * assertContains is now used for iterable, strings should use assertStringContainsString
+     */
+    public function assertContainsPolyfill($expected, $actual, string $message = ''): void
+    {
+        if (is_string($actual) && method_exists($this, 'assertStringContainsString')) {
+            static::assertStringContainsString($expected, $actual, $message);
+        } else {
+            static::assertContains($expected, $actual, $message);
+        }
+    }
+
+    /**
+     * assertNotContains is now used for iterable, strings should use assertStringNotContainsString
+     */
+    public function assertNotContainsPolyfill($expected, $actual, string $message = ''): void
+    {
+        if (is_string($actual) && method_exists($this, 'assertStringNotContainsString')) {
+            static::assertStringNotContainsString($expected, $actual, $message);
+        } else {
+            static::assertNotContains($expected, $actual, $message);
+        }
+    }
+
+    /**
+     * assertFileNotExists has been renamed in assertFileDoesNotExist
+     */
+    public static function assertFileNotExists(string $filename, string $message = ''): void
+    {
+        if (method_exists(TestCase::class, 'assertFileDoesNotExist')) {
+            static::assertFileDoesNotExist($filename, $message);
+        } else {
+            parent::assertFileNotExists($filename, $message);
+        }
+    }
+
+    /**
+     * assertRegExp has been renamed in assertMatchesRegularExpression
+     */
+    public static function assertRegExp(string $pattern, string $string, string $message = ''): void
+    {
+        if (method_exists(TestCase::class, 'assertMatchesRegularExpression')) {
+            static::assertMatchesRegularExpression($pattern, $string, $message);
+        } else {
+            parent::assertRegExp($pattern, $string, $message);
+        }
+    }
+
+    public function isInTestsContext(): bool
+    {
+        return true;
+    }
+}
diff --git a/tests/ThumbnailerTest.php b/tests/ThumbnailerTest.php
index 5b6d6a4d..70519aca 100644
--- a/tests/ThumbnailerTest.php
+++ b/tests/ThumbnailerTest.php
@@ -2,7 +2,6 @@
 
 namespace Shaarli;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use WebThumbnailer\Application\ConfigManager as WTConfigManager;
 
diff --git a/tests/TimeZoneTest.php b/tests/TimeZoneTest.php
index d3d9aeeb..77862855 100644
--- a/tests/TimeZoneTest.php
+++ b/tests/TimeZoneTest.php
@@ -8,7 +8,7 @@ require_once 'application/TimeZone.php';
 /**
  * Unitary tests for timezone utilities
  */
-class TimeZoneTest extends PHPUnit\Framework\TestCase
+class TimeZoneTest extends \Shaarli\TestCase
 {
     /**
      * @var array of timezones
diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php
index 93b77539..6e787d7f 100644
--- a/tests/UtilsTest.php
+++ b/tests/UtilsTest.php
@@ -10,7 +10,7 @@ require_once 'application/Languages.php';
 /**
  * Unitary tests for Shaarli utilities
  */
-class UtilsTest extends PHPUnit\Framework\TestCase
+class UtilsTest extends \Shaarli\TestCase
 {
     // Log file
     protected static $testLogFile = 'tests.log';
diff --git a/tests/api/ApiMiddlewareTest.php b/tests/api/ApiMiddlewareTest.php
index b157e4a7..7386e435 100644
--- a/tests/api/ApiMiddlewareTest.php
+++ b/tests/api/ApiMiddlewareTest.php
@@ -18,7 +18,7 @@ use Slim\Http\Response;
  *
  * @package Api
  */
-class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
+class ApiMiddlewareTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -26,7 +26,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
     protected static $testDatastore = 'sandbox/datastore.php';
 
     /**
-     * @var \ConfigManager instance
+     * @var ConfigManager instance
      */
     protected $conf;
 
@@ -109,7 +109,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(401, $response->getStatusCode());
         $body = json_decode((string) $response->getBody());
         $this->assertEquals('Not authorized: API is disabled', $body->message);
-        $this->assertContains('ApiAuthorizationException', $body->stacktrace);
+        $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
     }
 
     /**
@@ -132,7 +132,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(401, $response->getStatusCode());
         $body = json_decode((string) $response->getBody());
         $this->assertEquals('Not authorized: JWT token not provided', $body->message);
-        $this->assertContains('ApiAuthorizationException', $body->stacktrace);
+        $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
     }
 
     /**
@@ -157,7 +157,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(401, $response->getStatusCode());
         $body = json_decode((string) $response->getBody());
         $this->assertEquals('Not authorized: Token secret must be set in Shaarli\'s administration', $body->message);
-        $this->assertContains('ApiAuthorizationException', $body->stacktrace);
+        $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
     }
 
     /**
@@ -180,7 +180,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(401, $response->getStatusCode());
         $body = json_decode((string) $response->getBody());
         $this->assertEquals('Not authorized: Invalid JWT header', $body->message);
-        $this->assertContains('ApiAuthorizationException', $body->stacktrace);
+        $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
     }
 
     /**
@@ -206,6 +206,6 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(401, $response->getStatusCode());
         $body = json_decode((string) $response->getBody());
         $this->assertEquals('Not authorized: Malformed JWT token', $body->message);
-        $this->assertContains('ApiAuthorizationException', $body->stacktrace);
+        $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
     }
 }
diff --git a/tests/api/ApiUtilsTest.php b/tests/api/ApiUtilsTest.php
index 96787014..7a143859 100644
--- a/tests/api/ApiUtilsTest.php
+++ b/tests/api/ApiUtilsTest.php
@@ -8,7 +8,7 @@ use Shaarli\Http\Base64Url;
 /**
  * Class ApiUtilsTest
  */
-class ApiUtilsTest extends \PHPUnit\Framework\TestCase
+class ApiUtilsTest extends \Shaarli\TestCase
 {
     /**
      * Force the timezone for ISO datetimes.
diff --git a/tests/api/controllers/history/HistoryTest.php b/tests/api/controllers/history/HistoryTest.php
index 40f26b12..84f8716e 100644
--- a/tests/api/controllers/history/HistoryTest.php
+++ b/tests/api/controllers/history/HistoryTest.php
@@ -11,7 +11,7 @@ use Slim\Http\Response;
 
 require_once 'tests/utils/ReferenceHistory.php';
 
-class HistoryTest extends \PHPUnit\Framework\TestCase
+class HistoryTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
diff --git a/tests/api/controllers/info/InfoTest.php b/tests/api/controllers/info/InfoTest.php
index cc50d2e3..1598e1e8 100644
--- a/tests/api/controllers/info/InfoTest.php
+++ b/tests/api/controllers/info/InfoTest.php
@@ -1,10 +1,10 @@
 publicLinkDB->findByUrl('http://mediagoblin.org/');
 
         $this->assertNotEquals(false, $link);
-        $this->assertContains(
+        $this->assertContainsPolyfill(
             'A free software media publishing platform',
             $link->getDescription()
         );
diff --git a/tests/bookmark/BookmarkFilterTest.php b/tests/bookmark/BookmarkFilterTest.php
index 752631a5..2f15cb3c 100644
--- a/tests/bookmark/BookmarkFilterTest.php
+++ b/tests/bookmark/BookmarkFilterTest.php
@@ -3,10 +3,10 @@
 namespace Shaarli\Bookmark;
 
 use Exception;
-use PHPUnit\Framework\TestCase;
 use ReferenceLinkDB;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkFilterTest.
diff --git a/tests/bookmark/BookmarkInitializerTest.php b/tests/bookmark/BookmarkInitializerTest.php
index 454269bb..25704004 100644
--- a/tests/bookmark/BookmarkInitializerTest.php
+++ b/tests/bookmark/BookmarkInitializerTest.php
@@ -2,9 +2,9 @@
 
 namespace Shaarli\Bookmark;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkInitializerTest
diff --git a/tests/bookmark/BookmarkTest.php b/tests/bookmark/BookmarkTest.php
index 4b6a3c07..afec2440 100644
--- a/tests/bookmark/BookmarkTest.php
+++ b/tests/bookmark/BookmarkTest.php
@@ -2,8 +2,8 @@
 
 namespace Shaarli\Bookmark;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Exception\InvalidBookmarkException;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkTest
@@ -150,7 +150,7 @@ class BookmarkTest extends TestCase
             $exception = $e;
         }
         $this->assertNotNull($exception);
-        $this->assertContains('- ID: '. PHP_EOL, $exception->getMessage());
+        $this->assertContainsPolyfill('- ID: '. PHP_EOL, $exception->getMessage());
     }
 
     /**
@@ -169,7 +169,7 @@ class BookmarkTest extends TestCase
             $exception = $e;
         }
         $this->assertNotNull($exception);
-        $this->assertContains('- ID: str'. PHP_EOL, $exception->getMessage());
+        $this->assertContainsPolyfill('- ID: str'. PHP_EOL, $exception->getMessage());
     }
 
     /**
@@ -188,7 +188,7 @@ class BookmarkTest extends TestCase
             $exception = $e;
         }
         $this->assertNotNull($exception);
-        $this->assertContains('- ShortUrl: '. PHP_EOL, $exception->getMessage());
+        $this->assertContainsPolyfill('- ShortUrl: '. PHP_EOL, $exception->getMessage());
     }
 
     /**
@@ -207,7 +207,7 @@ class BookmarkTest extends TestCase
             $exception = $e;
         }
         $this->assertNotNull($exception);
-        $this->assertContains('- Created: '. PHP_EOL, $exception->getMessage());
+        $this->assertContainsPolyfill('- Created: '. PHP_EOL, $exception->getMessage());
     }
 
     /**
@@ -226,7 +226,7 @@ class BookmarkTest extends TestCase
             $exception = $e;
         }
         $this->assertNotNull($exception);
-        $this->assertContains('- Created: Not a DateTime object'. PHP_EOL, $exception->getMessage());
+        $this->assertContainsPolyfill('- Created: Not a DateTime object'. PHP_EOL, $exception->getMessage());
     }
 
     /**
diff --git a/tests/bookmark/LinkUtilsTest.php b/tests/bookmark/LinkUtilsTest.php
index 7d4a7b89..a7087953 100644
--- a/tests/bookmark/LinkUtilsTest.php
+++ b/tests/bookmark/LinkUtilsTest.php
@@ -2,7 +2,7 @@
 
 namespace Shaarli\Bookmark;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 
 require_once 'tests/utils/CurlUtils.php';
 
@@ -437,13 +437,13 @@ class LinkUtilsTest extends TestCase
             カタカナ #カタカナ」カタカナ\n';
         $autolinkedDescription = hashtag_autolink($rawDescription, $index);
 
-        $this->assertContains($this->getHashtagLink('hashtag', $index), $autolinkedDescription);
-        $this->assertNotContains(' #hashtag', $autolinkedDescription);
-        $this->assertNotContains('>#nothashtag', $autolinkedDescription);
-        $this->assertContains($this->getHashtagLink('ашок', $index), $autolinkedDescription);
-        $this->assertContains($this->getHashtagLink('カタカナ', $index), $autolinkedDescription);
-        $this->assertContains($this->getHashtagLink('hashtag_hashtag', $index), $autolinkedDescription);
-        $this->assertNotContains($this->getHashtagLink('hashtag-nothashtag', $index), $autolinkedDescription);
+        $this->assertContainsPolyfill($this->getHashtagLink('hashtag', $index), $autolinkedDescription);
+        $this->assertNotContainsPolyfill(' #hashtag', $autolinkedDescription);
+        $this->assertNotContainsPolyfill('>#nothashtag', $autolinkedDescription);
+        $this->assertContainsPolyfill($this->getHashtagLink('ашок', $index), $autolinkedDescription);
+        $this->assertContainsPolyfill($this->getHashtagLink('カタカナ', $index), $autolinkedDescription);
+        $this->assertContainsPolyfill($this->getHashtagLink('hashtag_hashtag', $index), $autolinkedDescription);
+        $this->assertNotContainsPolyfill($this->getHashtagLink('hashtag-nothashtag', $index), $autolinkedDescription);
     }
 
     /**
@@ -454,9 +454,9 @@ class LinkUtilsTest extends TestCase
         $rawDescription = 'blabla #hashtag x#nothashtag';
         $autolinkedDescription = hashtag_autolink($rawDescription);
 
-        $this->assertContains($this->getHashtagLink('hashtag'), $autolinkedDescription);
-        $this->assertNotContains(' #hashtag', $autolinkedDescription);
-        $this->assertNotContains('>#nothashtag', $autolinkedDescription);
+        $this->assertContainsPolyfill($this->getHashtagLink('hashtag'), $autolinkedDescription);
+        $this->assertNotContainsPolyfill(' #hashtag', $autolinkedDescription);
+        $this->assertNotContainsPolyfill('>#nothashtag', $autolinkedDescription);
     }
 
     /**
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index d4ddedd5..2d675c9a 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -18,6 +18,7 @@ require_once 'application/bookmark/LinkUtils.php';
 require_once 'application/Utils.php';
 require_once 'application/http/UrlUtils.php';
 require_once 'application/http/HttpUtils.php';
+require_once 'tests/TestCase.php';
 require_once 'tests/container/ShaarliTestContainer.php';
 require_once 'tests/front/controller/visitor/FrontControllerMockHelper.php';
 require_once 'tests/front/controller/admin/FrontAdminControllerMockHelper.php';
diff --git a/tests/config/ConfigJsonTest.php b/tests/config/ConfigJsonTest.php
index f884b0c6..4f508925 100644
--- a/tests/config/ConfigJsonTest.php
+++ b/tests/config/ConfigJsonTest.php
@@ -4,7 +4,7 @@ namespace Shaarli\Config;
 /**
  * Class ConfigJsonTest
  */
-class ConfigJsonTest extends \PHPUnit\Framework\TestCase
+class ConfigJsonTest extends \Shaarli\TestCase
 {
     /**
      * @var ConfigJson
diff --git a/tests/config/ConfigManagerTest.php b/tests/config/ConfigManagerTest.php
index 802e6524..65d8ba2c 100644
--- a/tests/config/ConfigManagerTest.php
+++ b/tests/config/ConfigManagerTest.php
@@ -7,7 +7,7 @@ namespace Shaarli\Config;
  * Note: it only test the manager with ConfigJson,
  *  ConfigPhp is only a workaround to handle the transition to JSON type.
  */
-class ConfigManagerTest extends \PHPUnit\Framework\TestCase
+class ConfigManagerTest extends \Shaarli\TestCase
 {
     /**
      * @var ConfigManager
diff --git a/tests/config/ConfigPhpTest.php b/tests/config/ConfigPhpTest.php
index a9aa80f5..7bf9fe64 100644
--- a/tests/config/ConfigPhpTest.php
+++ b/tests/config/ConfigPhpTest.php
@@ -8,7 +8,7 @@ namespace Shaarli\Config;
  * which are kept between tests.
  * @runTestsInSeparateProcesses
  */
-class ConfigPhpTest extends \PHPUnit\Framework\TestCase
+class ConfigPhpTest extends \Shaarli\TestCase
 {
     /**
      * @var ConfigPhp
diff --git a/tests/config/ConfigPluginTest.php b/tests/config/ConfigPluginTest.php
index 3a45f623..fa72d8c4 100644
--- a/tests/config/ConfigPluginTest.php
+++ b/tests/config/ConfigPluginTest.php
@@ -9,7 +9,7 @@ require_once 'application/config/ConfigPlugin.php';
 /**
  * Unitary tests for Shaarli config related functions
  */
-class ConfigPluginTest extends \PHPUnit\Framework\TestCase
+class ConfigPluginTest extends \Shaarli\TestCase
 {
     /**
      * Test save_plugin_config with valid data.
diff --git a/tests/container/ContainerBuilderTest.php b/tests/container/ContainerBuilderTest.php
index 2047a63a..5d52daef 100644
--- a/tests/container/ContainerBuilderTest.php
+++ b/tests/container/ContainerBuilderTest.php
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Shaarli\Container;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Feed\FeedBuilder;
@@ -20,6 +19,7 @@ use Shaarli\Render\PageCacheManager;
 use Shaarli\Security\CookieManager;
 use Shaarli\Security\LoginManager;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Shaarli\Updater\Updater;
 use Slim\Http\Environment;
diff --git a/tests/feed/CachedPageTest.php b/tests/feed/CachedPageTest.php
index 25d640d3..904db9dc 100644
--- a/tests/feed/CachedPageTest.php
+++ b/tests/feed/CachedPageTest.php
@@ -7,7 +7,7 @@ namespace Shaarli\Feed;
 /**
  * Unitary tests for cached pages
  */
-class CachedPageTest extends \PHPUnit\Framework\TestCase
+class CachedPageTest extends \Shaarli\TestCase
 {
     // test cache directory
     protected static $testCacheDir = 'sandbox/pagecache';
diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php
index 5dfe73aa..c29e8ef3 100644
--- a/tests/feed/FeedBuilderTest.php
+++ b/tests/feed/FeedBuilderTest.php
@@ -3,7 +3,6 @@
 namespace Shaarli\Feed;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
 use ReferenceLinkDB;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
@@ -11,6 +10,7 @@ use Shaarli\Bookmark\LinkDB;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Formatter\FormatterFactory;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 /**
  * FeedBuilderTest class.
@@ -97,9 +97,9 @@ class FeedBuilderTest extends TestCase
         $pub = DateTime::createFromFormat(DateTime::RSS, $link['pub_iso_date']);
         $up = DateTime::createFromFormat(DateTime::ATOM, $link['up_iso_date']);
         $this->assertEquals($pub, $up);
-        $this->assertContains('Stallman has a beard', $link['description']);
-        $this->assertContains('Permalink', $link['description']);
-        $this->assertContains('http://host.tld/shaare/WDWyig', $link['description']);
+        $this->assertContainsPolyfill('Stallman has a beard', $link['description']);
+        $this->assertContainsPolyfill('Permalink', $link['description']);
+        $this->assertContainsPolyfill('http://host.tld/shaare/WDWyig', $link['description']);
         $this->assertEquals(1, count($link['taglist']));
         $this->assertEquals('sTuff', $link['taglist'][0]);
 
@@ -201,16 +201,16 @@ class FeedBuilderTest extends TestCase
         $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
         $this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']);
         $this->assertEquals('http://host.tld/shaare/WDWyig', $link['url']);
-        $this->assertContains('Direct link', $link['description']);
-        $this->assertContains('http://host.tld/shaare/WDWyig', $link['description']);
+        $this->assertContainsPolyfill('Direct link', $link['description']);
+        $this->assertContainsPolyfill('http://host.tld/shaare/WDWyig', $link['description']);
         // Second link is a direct link
         $link = $data['links'][array_keys($data['links'])[1]];
         $this->assertEquals(8, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114633'), $link['created']);
         $this->assertEquals('http://host.tld/shaare/RttfEw', $link['guid']);
         $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['url']);
-        $this->assertContains('Direct link', $link['description']);
-        $this->assertContains('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['description']);
+        $this->assertContainsPolyfill('Direct link', $link['description']);
+        $this->assertContainsPolyfill('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['description']);
     }
 
     /**
@@ -274,6 +274,6 @@ class FeedBuilderTest extends TestCase
         $link = $data['links'][array_keys($data['links'])[0]];
         $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['guid']);
         $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['url']);
-        $this->assertContains('http://host.tld:8080/~user/shaarli/./add-tag/hashtag', $link['description']);
+        $this->assertContainsPolyfill('http://host.tld:8080/~user/shaarli/./add-tag/hashtag', $link['description']);
     }
 }
diff --git a/tests/formatter/BookmarkDefaultFormatterTest.php b/tests/formatter/BookmarkDefaultFormatterTest.php
index 9ea86c14..9534436e 100644
--- a/tests/formatter/BookmarkDefaultFormatterTest.php
+++ b/tests/formatter/BookmarkDefaultFormatterTest.php
@@ -3,9 +3,9 @@
 namespace Shaarli\Formatter;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkDefaultFormatterTest
diff --git a/tests/formatter/BookmarkMarkdownFormatterTest.php b/tests/formatter/BookmarkMarkdownFormatterTest.php
index a7729416..ab6b4080 100644
--- a/tests/formatter/BookmarkMarkdownFormatterTest.php
+++ b/tests/formatter/BookmarkMarkdownFormatterTest.php
@@ -3,9 +3,9 @@
 namespace Shaarli\Formatter;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkMarkdownFormatterTest
diff --git a/tests/formatter/BookmarkRawFormatterTest.php b/tests/formatter/BookmarkRawFormatterTest.php
index 76cf1172..c76bb7b9 100644
--- a/tests/formatter/BookmarkRawFormatterTest.php
+++ b/tests/formatter/BookmarkRawFormatterTest.php
@@ -3,9 +3,9 @@
 namespace Shaarli\Formatter;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkRawFormatterTest
diff --git a/tests/formatter/FormatterFactoryTest.php b/tests/formatter/FormatterFactoryTest.php
index 6aab6a61..ae476cb5 100644
--- a/tests/formatter/FormatterFactoryTest.php
+++ b/tests/formatter/FormatterFactoryTest.php
@@ -2,8 +2,8 @@
 
 namespace Shaarli\Formatter;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
+use Shaarli\TestCase;
 
 /**
  * Class FormatterFactoryTest
diff --git a/tests/front/ShaarliAdminMiddlewareTest.php b/tests/front/ShaarliAdminMiddlewareTest.php
index 7451330b..44025f11 100644
--- a/tests/front/ShaarliAdminMiddlewareTest.php
+++ b/tests/front/ShaarliAdminMiddlewareTest.php
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Container\ShaarliContainer;
 use Shaarli\Security\LoginManager;
+use Shaarli\TestCase;
 use Shaarli\Updater\Updater;
 use Slim\Http\Request;
 use Slim\Http\Response;
diff --git a/tests/front/ShaarliMiddlewareTest.php b/tests/front/ShaarliMiddlewareTest.php
index 05aa34a9..655c5bba 100644
--- a/tests/front/ShaarliMiddlewareTest.php
+++ b/tests/front/ShaarliMiddlewareTest.php
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Shaarli\Front;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Container\ShaarliContainer;
 use Shaarli\Front\Exception\LoginBannedException;
@@ -12,6 +11,7 @@ use Shaarli\Front\Exception\UnauthorizedException;
 use Shaarli\Render\PageBuilder;
 use Shaarli\Render\PageCacheManager;
 use Shaarli\Security\LoginManager;
+use Shaarli\TestCase;
 use Shaarli\Updater\Updater;
 use Slim\Http\Request;
 use Slim\Http\Response;
diff --git a/tests/front/controller/admin/ConfigureControllerTest.php b/tests/front/controller/admin/ConfigureControllerTest.php
index 612f20f1..aca6cff3 100644
--- a/tests/front/controller/admin/ConfigureControllerTest.php
+++ b/tests/front/controller/admin/ConfigureControllerTest.php
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
diff --git a/tests/front/controller/admin/ExportControllerTest.php b/tests/front/controller/admin/ExportControllerTest.php
index 12d26f4a..0e6f2762 100644
--- a/tests/front/controller/admin/ExportControllerTest.php
+++ b/tests/front/controller/admin/ExportControllerTest.php
@@ -4,12 +4,12 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Formatter\BookmarkFormatter;
 use Shaarli\Formatter\BookmarkRawFormatter;
 use Shaarli\Netscape\NetscapeBookmarkUtils;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/ImportControllerTest.php b/tests/front/controller/admin/ImportControllerTest.php
index eb31fad0..c266caa5 100644
--- a/tests/front/controller/admin/ImportControllerTest.php
+++ b/tests/front/controller/admin/ImportControllerTest.php
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UploadedFileInterface;
 use Shaarli\Netscape\NetscapeBookmarkUtils;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 use Slim\Http\UploadedFile;
diff --git a/tests/front/controller/admin/LogoutControllerTest.php b/tests/front/controller/admin/LogoutControllerTest.php
index 45e84dc0..94e53019 100644
--- a/tests/front/controller/admin/LogoutControllerTest.php
+++ b/tests/front/controller/admin/LogoutControllerTest.php
@@ -4,10 +4,9 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Security\CookieManager;
-use Shaarli\Security\LoginManager;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php b/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php
index 7d5b752a..0f27ec2f 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php
index 5a615791..096d0774 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Formatter\BookmarkFormatter;
@@ -14,6 +13,7 @@ use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
index dee622bb..ba774e21 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Formatter\BookmarkFormatter;
@@ -13,6 +12,7 @@ use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php b/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php
index 777583d5..2eb95251 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php
@@ -4,12 +4,12 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -96,12 +96,14 @@ class DisplayCreateFormTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_editlink'], ['render_includes'])
             ->willReturnCallback(function (string $hook, array $data) use ($remoteTitle, $remoteDesc): array {
-                static::assertSame('render_editlink', $hook);
-                static::assertSame($remoteTitle, $data['link']['title']);
-                static::assertSame($remoteDesc, $data['link']['description']);
+                if ('render_editlink' === $hook) {
+                    static::assertSame($remoteTitle, $data['link']['title']);
+                    static::assertSame($remoteDesc, $data['link']['description']);
+                }
 
                 return $data;
             })
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php b/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php
index 1a1cdcf3..2dc3f41c 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php
@@ -4,13 +4,13 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php
index 1607b475..50ce7df1 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php
@@ -4,13 +4,13 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
index 58eaaa9b..3999b44e 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
@@ -12,6 +11,7 @@ use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -88,17 +88,18 @@ class SaveBookmarkTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['save_link'])
             ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array {
-                static::assertSame('save_link', $hook);
-
-                static::assertSame($id, $data['id']);
-                static::assertSame($parameters['lf_url'], $data['url']);
-                static::assertSame($parameters['lf_title'], $data['title']);
-                static::assertSame($parameters['lf_description'], $data['description']);
-                static::assertSame($parameters['lf_tags'], $data['tags']);
-                static::assertTrue($data['private']);
+                if ('save_link' === $hook) {
+                    static::assertSame($id, $data['id']);
+                    static::assertSame($parameters['lf_url'], $data['url']);
+                    static::assertSame($parameters['lf_title'], $data['title']);
+                    static::assertSame($parameters['lf_description'], $data['description']);
+                    static::assertSame($parameters['lf_tags'], $data['tags']);
+                    static::assertTrue($data['private']);
+                }
 
                 return $data;
             })
@@ -174,17 +175,18 @@ class SaveBookmarkTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['save_link'])
             ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array {
-                static::assertSame('save_link', $hook);
-
-                static::assertSame($id, $data['id']);
-                static::assertSame($parameters['lf_url'], $data['url']);
-                static::assertSame($parameters['lf_title'], $data['title']);
-                static::assertSame($parameters['lf_description'], $data['description']);
-                static::assertSame($parameters['lf_tags'], $data['tags']);
-                static::assertTrue($data['private']);
+                if ('save_link' === $hook) {
+                    static::assertSame($id, $data['id']);
+                    static::assertSame($parameters['lf_url'], $data['url']);
+                    static::assertSame($parameters['lf_title'], $data['title']);
+                    static::assertSame($parameters['lf_description'], $data['description']);
+                    static::assertSame($parameters['lf_tags'], $data['tags']);
+                    static::assertTrue($data['private']);
+                }
 
                 return $data;
             })
diff --git a/tests/front/controller/admin/ManageTagControllerTest.php b/tests/front/controller/admin/ManageTagControllerTest.php
index 09ba0b4b..8a0ff7a9 100644
--- a/tests/front/controller/admin/ManageTagControllerTest.php
+++ b/tests/front/controller/admin/ManageTagControllerTest.php
@@ -4,11 +4,11 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFilter;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/PasswordControllerTest.php b/tests/front/controller/admin/PasswordControllerTest.php
index 9a01089e..58f47b49 100644
--- a/tests/front/controller/admin/PasswordControllerTest.php
+++ b/tests/front/controller/admin/PasswordControllerTest.php
@@ -4,11 +4,11 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\OpenShaarliPasswordException;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/PluginsControllerTest.php b/tests/front/controller/admin/PluginsControllerTest.php
index 9526474c..974d614d 100644
--- a/tests/front/controller/admin/PluginsControllerTest.php
+++ b/tests/front/controller/admin/PluginsControllerTest.php
@@ -4,11 +4,11 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Plugin\PluginManager;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/SessionFilterControllerTest.php b/tests/front/controller/admin/SessionFilterControllerTest.php
index c4253167..712a625b 100644
--- a/tests/front/controller/admin/SessionFilterControllerTest.php
+++ b/tests/front/controller/admin/SessionFilterControllerTest.php
@@ -4,9 +4,9 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Security\LoginManager;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/ShaarliAdminControllerTest.php b/tests/front/controller/admin/ShaarliAdminControllerTest.php
index fff427cb..486d5d2d 100644
--- a/tests/front/controller/admin/ShaarliAdminControllerTest.php
+++ b/tests/front/controller/admin/ShaarliAdminControllerTest.php
@@ -4,9 +4,9 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 
 /**
diff --git a/tests/front/controller/admin/ThumbnailsControllerTest.php b/tests/front/controller/admin/ThumbnailsControllerTest.php
index 0c0c8a83..f4a8acff 100644
--- a/tests/front/controller/admin/ThumbnailsControllerTest.php
+++ b/tests/front/controller/admin/ThumbnailsControllerTest.php
@@ -4,9 +4,9 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
diff --git a/tests/front/controller/admin/TokenControllerTest.php b/tests/front/controller/admin/TokenControllerTest.php
index 04b0c0fa..d2f0907f 100644
--- a/tests/front/controller/admin/TokenControllerTest.php
+++ b/tests/front/controller/admin/TokenControllerTest.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/admin/ToolsControllerTest.php b/tests/front/controller/admin/ToolsControllerTest.php
index 39144d2f..e82f8b14 100644
--- a/tests/front/controller/admin/ToolsControllerTest.php
+++ b/tests/front/controller/admin/ToolsControllerTest.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/visitor/BookmarkListControllerTest.php b/tests/front/controller/visitor/BookmarkListControllerTest.php
index 5daaa2c4..0c95df97 100644
--- a/tests/front/controller/visitor/BookmarkListControllerTest.php
+++ b/tests/front/controller/visitor/BookmarkListControllerTest.php
@@ -4,11 +4,11 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Security\LoginManager;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
diff --git a/tests/front/controller/visitor/DailyControllerTest.php b/tests/front/controller/visitor/DailyControllerTest.php
index cb5b96f3..fc78bc13 100644
--- a/tests/front/controller/visitor/DailyControllerTest.php
+++ b/tests/front/controller/visitor/DailyControllerTest.php
@@ -4,9 +4,9 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Feed\CachedPage;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -78,19 +78,20 @@ class DailyControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_daily'])
             ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array {
-                static::assertSame('render_daily', $hook);
+                if ('render_daily' === $hook) {
+                    static::assertArrayHasKey('linksToDisplay', $data);
+                    static::assertCount(3, $data['linksToDisplay']);
+                    static::assertSame(1, $data['linksToDisplay'][0]['id']);
+                    static::assertSame($currentDay->getTimestamp(), $data['day']);
+                    static::assertSame('20200510', $data['previousday']);
+                    static::assertSame('20200516', $data['nextday']);
 
-                static::assertArrayHasKey('linksToDisplay', $data);
-                static::assertCount(3, $data['linksToDisplay']);
-                static::assertSame(1, $data['linksToDisplay'][0]['id']);
-                static::assertSame($currentDay->getTimestamp(), $data['day']);
-                static::assertSame('20200510', $data['previousday']);
-                static::assertSame('20200516', $data['nextday']);
-
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
@@ -203,19 +204,20 @@ class DailyControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_daily'])
             ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array {
-                static::assertSame('render_daily', $hook);
-
-                static::assertArrayHasKey('linksToDisplay', $data);
-                static::assertCount(1, $data['linksToDisplay']);
-                static::assertSame(1, $data['linksToDisplay'][0]['id']);
-                static::assertSame($currentDay->getTimestamp(), $data['day']);
-                static::assertEmpty($data['previousday']);
-                static::assertEmpty($data['nextday']);
+                if ('render_daily' === $hook) {
+                    static::assertArrayHasKey('linksToDisplay', $data);
+                    static::assertCount(1, $data['linksToDisplay']);
+                    static::assertSame(1, $data['linksToDisplay'][0]['id']);
+                    static::assertSame($currentDay->getTimestamp(), $data['day']);
+                    static::assertEmpty($data['previousday']);
+                    static::assertEmpty($data['nextday']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             });
@@ -281,7 +283,7 @@ class DailyControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
                 return $data;
@@ -333,7 +335,7 @@ class DailyControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
                 return $data;
diff --git a/tests/front/controller/visitor/ErrorControllerTest.php b/tests/front/controller/visitor/ErrorControllerTest.php
index e497bfef..75408cf4 100644
--- a/tests/front/controller/visitor/ErrorControllerTest.php
+++ b/tests/front/controller/visitor/ErrorControllerTest.php
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Front\Exception\ShaarliFrontException;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/visitor/ErrorNotFoundControllerTest.php b/tests/front/controller/visitor/ErrorNotFoundControllerTest.php
index 625467b1..a1cbbecf 100644
--- a/tests/front/controller/visitor/ErrorNotFoundControllerTest.php
+++ b/tests/front/controller/visitor/ErrorNotFoundControllerTest.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 use Slim\Http\Uri;
diff --git a/tests/front/controller/visitor/FeedControllerTest.php b/tests/front/controller/visitor/FeedControllerTest.php
index 0a6b577f..4ae7c925 100644
--- a/tests/front/controller/visitor/FeedControllerTest.php
+++ b/tests/front/controller/visitor/FeedControllerTest.php
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Feed\FeedBuilder;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -45,14 +45,16 @@ class FeedControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_feed'])
             ->willReturnCallback(function (string $hook, array $data, array $param): void {
-                static::assertSame('render_feed', $hook);
-                static::assertSame('data', $data['content']);
+                if ('render_feed' === $hook) {
+                    static::assertSame('data', $data['content']);
 
-                static::assertArrayHasKey('loggedin', $param);
-                static::assertSame('feed.rss', $param['target']);
+                    static::assertArrayHasKey('loggedin', $param);
+                    static::assertSame('feed.rss', $param['target']);
+                }
             })
         ;
 
@@ -84,14 +86,16 @@ class FeedControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_feed'])
             ->willReturnCallback(function (string $hook, array $data, array $param): void {
-                static::assertSame('render_feed', $hook);
-                static::assertSame('data', $data['content']);
+                if ('render_feed' === $hook) {
+                    static::assertSame('data', $data['content']);
 
-                static::assertArrayHasKey('loggedin', $param);
-                static::assertSame('feed.atom', $param['target']);
+                    static::assertArrayHasKey('loggedin', $param);
+                    static::assertSame('feed.atom', $param['target']);
+                }
             })
         ;
 
@@ -124,14 +128,16 @@ class FeedControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_feed'])
             ->willReturnCallback(function (string $hook, array $data, array $param): void {
-                static::assertSame('render_feed', $hook);
-                static::assertSame('data', $data['content']);
+                if ('render_feed' === $hook) {
+                    static::assertSame('data', $data['content']);
 
-                static::assertArrayHasKey('loggedin', $param);
-                static::assertSame('feed.atom', $param['target']);
+                    static::assertArrayHasKey('loggedin', $param);
+                    static::assertSame('feed.atom', $param['target']);
+                }
             })
         ;
 
diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php
index 6c53289b..fc0bb7d1 100644
--- a/tests/front/controller/visitor/FrontControllerMockHelper.php
+++ b/tests/front/controller/visitor/FrontControllerMockHelper.php
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\MockObject\MockObject;
 use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Container\ShaarliTestContainer;
@@ -115,5 +114,5 @@ trait FrontControllerMockHelper
     /**
      * Force to be used in PHPUnit context.
      */
-    protected abstract function createMock($originalClassName): MockObject;
+    protected abstract function isInTestsContext(): bool;
 }
diff --git a/tests/front/controller/visitor/InstallControllerTest.php b/tests/front/controller/visitor/InstallControllerTest.php
index 994d3f33..345ad544 100644
--- a/tests/front/controller/visitor/InstallControllerTest.php
+++ b/tests/front/controller/visitor/InstallControllerTest.php
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\AlreadyInstalledException;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/visitor/LoginControllerTest.php b/tests/front/controller/visitor/LoginControllerTest.php
index 0a21f938..1312ccb7 100644
--- a/tests/front/controller/visitor/LoginControllerTest.php
+++ b/tests/front/controller/visitor/LoginControllerTest.php
@@ -4,13 +4,13 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\LoginBannedException;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Render\TemplatePage;
 use Shaarli\Security\CookieManager;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/visitor/OpenSearchControllerTest.php b/tests/front/controller/visitor/OpenSearchControllerTest.php
index 9609a377..42d876c3 100644
--- a/tests/front/controller/visitor/OpenSearchControllerTest.php
+++ b/tests/front/controller/visitor/OpenSearchControllerTest.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/visitor/PictureWallControllerTest.php b/tests/front/controller/visitor/PictureWallControllerTest.php
index 3dc3f292..b868231d 100644
--- a/tests/front/controller/visitor/PictureWallControllerTest.php
+++ b/tests/front/controller/visitor/PictureWallControllerTest.php
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\ThumbnailsDisabledException;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -67,15 +67,17 @@ class PictureWallControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_picwall'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_picwall', $hook);
-                static::assertArrayHasKey('linksToDisplay', $data);
-                static::assertCount(2, $data['linksToDisplay']);
-                static::assertSame(1, $data['linksToDisplay'][0]['id']);
-                static::assertSame(3, $data['linksToDisplay'][1]['id']);
-                static::assertArrayHasKey('loggedin', $param);
+                if ('render_picwall' === $hook) {
+                    static::assertArrayHasKey('linksToDisplay', $data);
+                    static::assertCount(2, $data['linksToDisplay']);
+                    static::assertSame(1, $data['linksToDisplay'][0]['id']);
+                    static::assertSame(3, $data['linksToDisplay'][1]['id']);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             });
diff --git a/tests/front/controller/visitor/PublicSessionFilterControllerTest.php b/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
index b45fbe53..7e3b00af 100644
--- a/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
+++ b/tests/front/controller/visitor/PublicSessionFilterControllerTest.php
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/visitor/ShaarliVisitorControllerTest.php b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
index 00188c02..935ec24e 100644
--- a/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
+++ b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkFilter;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/visitor/TagCloudControllerTest.php b/tests/front/controller/visitor/TagCloudControllerTest.php
index 9a6a4bc0..9305612e 100644
--- a/tests/front/controller/visitor/TagCloudControllerTest.php
+++ b/tests/front/controller/visitor/TagCloudControllerTest.php
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkFilter;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -53,14 +53,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_tagcloud'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_tagcloud', $hook);
-                static::assertSame('', $data['search_tags']);
-                static::assertCount(3, $data['tags']);
+                if ('render_tagcloud' === $hook) {
+                    static::assertSame('', $data['search_tags']);
+                    static::assertCount(3, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
@@ -124,14 +126,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_tagcloud'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_tagcloud', $hook);
-                static::assertSame('ghi def', $data['search_tags']);
-                static::assertCount(1, $data['tags']);
+               if ('render_tagcloud' === $hook) {
+                   static::assertSame('ghi def', $data['search_tags']);
+                   static::assertCount(1, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                   static::assertArrayHasKey('loggedin', $param);
+               }
 
                 return $data;
             })
@@ -175,14 +179,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_tagcloud'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_tagcloud', $hook);
-                static::assertSame('', $data['search_tags']);
-                static::assertCount(0, $data['tags']);
+                if ('render_tagcloud' === $hook) {
+                    static::assertSame('', $data['search_tags']);
+                    static::assertCount(0, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
@@ -227,14 +233,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_taglist'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_taglist', $hook);
-                static::assertSame('', $data['search_tags']);
-                static::assertCount(3, $data['tags']);
+                if ('render_taglist' === $hook) {
+                    static::assertSame('', $data['search_tags']);
+                    static::assertCount(3, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
@@ -297,14 +305,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_taglist'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_taglist', $hook);
-                static::assertSame('ghi def', $data['search_tags']);
-                static::assertCount(1, $data['tags']);
+                if ('render_taglist' === $hook) {
+                    static::assertSame('ghi def', $data['search_tags']);
+                    static::assertCount(1, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
@@ -344,14 +354,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_taglist'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_taglist', $hook);
-                static::assertSame('', $data['search_tags']);
-                static::assertCount(0, $data['tags']);
+                if ('render_taglist' === $hook) {
+                    static::assertSame('', $data['search_tags']);
+                    static::assertCount(0, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
diff --git a/tests/front/controller/visitor/TagControllerTest.php b/tests/front/controller/visitor/TagControllerTest.php
index 43076086..750ea02d 100644
--- a/tests/front/controller/visitor/TagControllerTest.php
+++ b/tests/front/controller/visitor/TagControllerTest.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/http/HttpUtils/ClientIpIdTest.php b/tests/http/HttpUtils/ClientIpIdTest.php
index 982e57e0..3a0fcf30 100644
--- a/tests/http/HttpUtils/ClientIpIdTest.php
+++ b/tests/http/HttpUtils/ClientIpIdTest.php
@@ -10,7 +10,7 @@ require_once 'application/http/HttpUtils.php';
 /**
  * Unitary tests for client_ip_id()
  */
-class ClientIpIdTest extends \PHPUnit\Framework\TestCase
+class ClientIpIdTest extends \Shaarli\TestCase
 {
     /**
      * Get a remote client ID based on its IP
diff --git a/tests/http/HttpUtils/GetHttpUrlTest.php b/tests/http/HttpUtils/GetHttpUrlTest.php
index 3dc5bc9b..a868ac02 100644
--- a/tests/http/HttpUtils/GetHttpUrlTest.php
+++ b/tests/http/HttpUtils/GetHttpUrlTest.php
@@ -10,7 +10,7 @@ require_once 'application/http/HttpUtils.php';
 /**
  * Unitary tests for get_http_response()
  */
-class GetHttpUrlTest extends \PHPUnit\Framework\TestCase
+class GetHttpUrlTest extends \Shaarli\TestCase
 {
     /**
      * Get an invalid local URL
diff --git a/tests/http/HttpUtils/GetIpAdressFromProxyTest.php b/tests/http/HttpUtils/GetIpAdressFromProxyTest.php
index fe3a639e..60cdb992 100644
--- a/tests/http/HttpUtils/GetIpAdressFromProxyTest.php
+++ b/tests/http/HttpUtils/GetIpAdressFromProxyTest.php
@@ -7,7 +7,7 @@ require_once 'application/http/HttpUtils.php';
 /**
  * Unitary tests for getIpAddressFromProxy()
  */
-class GetIpAdressFromProxyTest extends \PHPUnit\Framework\TestCase
+class GetIpAdressFromProxyTest extends \Shaarli\TestCase
 {
 
     /**
diff --git a/tests/http/HttpUtils/IndexUrlTest.php b/tests/http/HttpUtils/IndexUrlTest.php
index cce45c51..f283d119 100644
--- a/tests/http/HttpUtils/IndexUrlTest.php
+++ b/tests/http/HttpUtils/IndexUrlTest.php
@@ -5,7 +5,7 @@
 
 namespace Shaarli\Http;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 
 require_once 'application/http/HttpUtils.php';
 
diff --git a/tests/http/HttpUtils/IndexUrlTestWithConstant.php b/tests/http/HttpUtils/IndexUrlTestWithConstant.php
index 15ca3d72..ecaea724 100644
--- a/tests/http/HttpUtils/IndexUrlTestWithConstant.php
+++ b/tests/http/HttpUtils/IndexUrlTestWithConstant.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Http;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 
 /**
  * Test index_url with SHAARLI_ROOT_URL defined to override automatic retrieval.
diff --git a/tests/http/HttpUtils/IsHttpsTest.php b/tests/http/HttpUtils/IsHttpsTest.php
index 348956c6..8b3fd93d 100644
--- a/tests/http/HttpUtils/IsHttpsTest.php
+++ b/tests/http/HttpUtils/IsHttpsTest.php
@@ -9,7 +9,7 @@ require_once 'application/http/HttpUtils.php';
  *
  * Test class for is_https() function.
  */
-class IsHttpsTest extends \PHPUnit\Framework\TestCase
+class IsHttpsTest extends \Shaarli\TestCase
 {
 
     /**
diff --git a/tests/http/HttpUtils/PageUrlTest.php b/tests/http/HttpUtils/PageUrlTest.php
index f1991716..ebb3e617 100644
--- a/tests/http/HttpUtils/PageUrlTest.php
+++ b/tests/http/HttpUtils/PageUrlTest.php
@@ -10,7 +10,7 @@ require_once 'application/http/HttpUtils.php';
 /**
  * Unitary tests for page_url()
  */
-class PageUrlTest extends \PHPUnit\Framework\TestCase
+class PageUrlTest extends \Shaarli\TestCase
 {
     /**
      * If on the main page, remove "index.php" from the URL resource
diff --git a/tests/http/HttpUtils/ServerUrlTest.php b/tests/http/HttpUtils/ServerUrlTest.php
index 9caf1049..339664e1 100644
--- a/tests/http/HttpUtils/ServerUrlTest.php
+++ b/tests/http/HttpUtils/ServerUrlTest.php
@@ -10,7 +10,7 @@ require_once 'application/http/HttpUtils.php';
 /**
  * Unitary tests for server_url()
  */
-class ServerUrlTest extends \PHPUnit\Framework\TestCase
+class ServerUrlTest extends \Shaarli\TestCase
 {
     /**
      * Detect if the server uses SSL
diff --git a/tests/http/UrlTest.php b/tests/http/UrlTest.php
index ae92f73a..c6b39c29 100644
--- a/tests/http/UrlTest.php
+++ b/tests/http/UrlTest.php
@@ -8,7 +8,7 @@ namespace Shaarli\Http;
 /**
  * Unitary tests for URL utilities
  */
-class UrlTest extends \PHPUnit\Framework\TestCase
+class UrlTest extends \Shaarli\TestCase
 {
     // base URL for tests
     protected static $baseUrl = 'http://domain.tld:3000';
diff --git a/tests/http/UrlUtils/CleanupUrlTest.php b/tests/http/UrlUtils/CleanupUrlTest.php
index 6c4d124b..45690ecf 100644
--- a/tests/http/UrlUtils/CleanupUrlTest.php
+++ b/tests/http/UrlUtils/CleanupUrlTest.php
@@ -7,7 +7,7 @@ namespace Shaarli\Http;
 
 require_once 'application/http/UrlUtils.php';
 
-class CleanupUrlTest extends \PHPUnit\Framework\TestCase
+class CleanupUrlTest extends \Shaarli\TestCase
 {
     /**
      * @var string reference URL
diff --git a/tests/http/UrlUtils/GetUrlSchemeTest.php b/tests/http/UrlUtils/GetUrlSchemeTest.php
index 2b97f7be..18a9a5e5 100644
--- a/tests/http/UrlUtils/GetUrlSchemeTest.php
+++ b/tests/http/UrlUtils/GetUrlSchemeTest.php
@@ -7,7 +7,7 @@ namespace Shaarli\Http;
 
 require_once 'application/http/UrlUtils.php';
 
-class GetUrlSchemeTest extends \PHPUnit\Framework\TestCase
+class GetUrlSchemeTest extends \Shaarli\TestCase
 {
     /**
      * Get empty scheme string for empty UrlUtils
diff --git a/tests/http/UrlUtils/UnparseUrlTest.php b/tests/http/UrlUtils/UnparseUrlTest.php
index 040d8c54..5e6246cc 100644
--- a/tests/http/UrlUtils/UnparseUrlTest.php
+++ b/tests/http/UrlUtils/UnparseUrlTest.php
@@ -10,7 +10,7 @@ require_once 'application/http/UrlUtils.php';
 /**
  * Unitary tests for unparse_url()
  */
-class UnparseUrlTest extends \PHPUnit\Framework\TestCase
+class UnparseUrlTest extends \Shaarli\TestCase
 {
     /**
      * Thanks for building nothing
diff --git a/tests/http/UrlUtils/WhitelistProtocolsTest.php b/tests/http/UrlUtils/WhitelistProtocolsTest.php
index 69512dbd..b8a6baaa 100644
--- a/tests/http/UrlUtils/WhitelistProtocolsTest.php
+++ b/tests/http/UrlUtils/WhitelistProtocolsTest.php
@@ -9,7 +9,7 @@ require_once 'application/http/UrlUtils.php';
  *
  * Test whitelist_protocols() function of UrlUtils.
  */
-class WhitelistProtocolsTest extends \PHPUnit\Framework\TestCase
+class WhitelistProtocolsTest extends \Shaarli\TestCase
 {
     /**
      * Test whitelist_protocols() on a note (relative URL).
diff --git a/tests/languages/fr/LanguagesFrTest.php b/tests/languages/fr/LanguagesFrTest.php
index e412b5bc..d84feed1 100644
--- a/tests/languages/fr/LanguagesFrTest.php
+++ b/tests/languages/fr/LanguagesFrTest.php
@@ -12,7 +12,7 @@ use Shaarli\Config\ConfigManager;
  *
  * @package Shaarli
  */
-class LanguagesFrTest extends \PHPUnit\Framework\TestCase
+class LanguagesFrTest extends \Shaarli\TestCase
 {
     /**
      * @var string Config file path (without extension).
diff --git a/tests/legacy/LegacyControllerTest.php b/tests/legacy/LegacyControllerTest.php
index 4e52f3e1..1a2549a3 100644
--- a/tests/legacy/LegacyControllerTest.php
+++ b/tests/legacy/LegacyControllerTest.php
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Legacy;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Front\Controller\Visitor\FrontControllerMockHelper;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/legacy/LegacyLinkDBTest.php b/tests/legacy/LegacyLinkDBTest.php
index 819bc272..66746dfc 100644
--- a/tests/legacy/LegacyLinkDBTest.php
+++ b/tests/legacy/LegacyLinkDBTest.php
@@ -18,7 +18,7 @@ require_once 'tests/utils/ReferenceLinkDB.php';
 /**
  * Unitary tests for LegacyLinkDBTest
  */
-class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
+class LegacyLinkDBTest extends \Shaarli\TestCase
 {
     // datastore to test write operations
     protected static $testDatastore = 'sandbox/datastore.php';
@@ -258,7 +258,7 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
         $link = self::$publicLinkDB->getLinkFromUrl('http://mediagoblin.org/');
 
         $this->assertNotEquals(false, $link);
-        $this->assertContains(
+        $this->assertContainsPolyfill(
             'A free software media publishing platform',
             $link['description']
         );
@@ -471,9 +471,9 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
 
         $res = $linkDB->renameTag('cartoon', 'Taz');
         $this->assertEquals(3, count($res));
-        $this->assertContains(' Taz ', $linkDB[4]['tags']);
-        $this->assertContains(' Taz ', $linkDB[1]['tags']);
-        $this->assertContains(' Taz ', $linkDB[0]['tags']);
+        $this->assertContainsPolyfill(' Taz ', $linkDB[4]['tags']);
+        $this->assertContainsPolyfill(' Taz ', $linkDB[1]['tags']);
+        $this->assertContainsPolyfill(' Taz ', $linkDB[0]['tags']);
     }
 
     /**
@@ -513,7 +513,7 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
 
         $res = $linkDB->renameTag('cartoon', null);
         $this->assertEquals(3, count($res));
-        $this->assertNotContains('cartoon', $linkDB[4]['tags']);
+        $this->assertNotContainsPolyfill('cartoon', $linkDB[4]['tags']);
     }
 
     /**
diff --git a/tests/legacy/LegacyLinkFilterTest.php b/tests/legacy/LegacyLinkFilterTest.php
index 9db921a9..82bc93d8 100644
--- a/tests/legacy/LegacyLinkFilterTest.php
+++ b/tests/legacy/LegacyLinkFilterTest.php
@@ -10,7 +10,7 @@ use Shaarli\Legacy\LegacyLinkFilter;
 /**
  * Class LegacyLinkFilterTest.
  */
-class LegacyLinkFilterTest extends \PHPUnit\Framework\TestCase
+class LegacyLinkFilterTest extends \Shaarli\TestCase
 {
     /**
      * @var string Test datastore path.
diff --git a/tests/legacy/LegacyUpdaterTest.php b/tests/legacy/LegacyUpdaterTest.php
index acfac530..0ddcb4a6 100644
--- a/tests/legacy/LegacyUpdaterTest.php
+++ b/tests/legacy/LegacyUpdaterTest.php
@@ -20,7 +20,7 @@ require_once 'inc/rain.tpl.class.php';
  * Class UpdaterTest.
  * Runs unit tests against the updater class.
  */
-class LegacyUpdaterTest extends \PHPUnit\Framework\TestCase
+class LegacyUpdaterTest extends \Shaarli\TestCase
 {
     /**
      * @var string Path to test datastore.
@@ -725,7 +725,7 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
         $this->assertEquals(\Shaarli\Thumbnailer::MODE_ALL, $this->conf->get('thumbnails.mode'));
         $this->assertEquals(125, $this->conf->get('thumbnails.width'));
         $this->assertEquals(90, $this->conf->get('thumbnails.height'));
-        $this->assertContains('You have enabled or changed thumbnails', $_SESSION['warnings'][0]);
+        $this->assertContainsPolyfill('You have enabled or changed thumbnails', $_SESSION['warnings'][0]);
     }
 
     /**
diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php
index a6eacae4..adf62f4f 100644
--- a/tests/netscape/BookmarkExportTest.php
+++ b/tests/netscape/BookmarkExportTest.php
@@ -2,12 +2,12 @@
 
 namespace Shaarli\Netscape;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Formatter\BookmarkFormatter;
 use Shaarli\Formatter\FormatterFactory;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 require_once 'tests/utils/ReferenceLinkDB.php';
 
diff --git a/tests/netscape/BookmarkImportTest.php b/tests/netscape/BookmarkImportTest.php
index 89ae4aa7..c1e49b5f 100644
--- a/tests/netscape/BookmarkImportTest.php
+++ b/tests/netscape/BookmarkImportTest.php
@@ -3,13 +3,13 @@
 namespace Shaarli\Netscape;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UploadedFileInterface;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\BookmarkFilter;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
+use Shaarli\TestCase;
 use Slim\Http\UploadedFile;
 
 /**
diff --git a/tests/plugins/PluginAddlinkTest.php b/tests/plugins/PluginAddlinkTest.php
index 1f60d289..a3ec9fc9 100644
--- a/tests/plugins/PluginAddlinkTest.php
+++ b/tests/plugins/PluginAddlinkTest.php
@@ -9,7 +9,7 @@ require_once 'plugins/addlink_toolbar/addlink_toolbar.php';
 /**
  * Unit test for the Addlink toolbar plugin
  */
-class PluginAddlinkTest extends \PHPUnit\Framework\TestCase
+class PluginAddlinkTest extends \Shaarli\TestCase
 {
     /**
      * Reset plugin path.
diff --git a/tests/plugins/PluginArchiveorgTest.php b/tests/plugins/PluginArchiveorgTest.php
index 9c19752c..467dc3d0 100644
--- a/tests/plugins/PluginArchiveorgTest.php
+++ b/tests/plugins/PluginArchiveorgTest.php
@@ -6,8 +6,8 @@ namespace Shaarli\Plugin\Archiveorg;
  * PluginArchiveorgTest.php
  */
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Plugin\PluginManager;
+use Shaarli\TestCase;
 
 require_once 'plugins/archiveorg/archiveorg.php';
 
diff --git a/tests/plugins/PluginDefaultColorsTest.php b/tests/plugins/PluginDefaultColorsTest.php
index 240bb4b2..cc844c60 100644
--- a/tests/plugins/PluginDefaultColorsTest.php
+++ b/tests/plugins/PluginDefaultColorsTest.php
@@ -2,10 +2,10 @@
 
 namespace Shaarli\Plugin\DefaultColors;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\LinkDB;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Plugin\PluginManager;
+use Shaarli\TestCase;
 
 require_once 'plugins/default_colors/default_colors.php';
 
diff --git a/tests/plugins/PluginIssoTest.php b/tests/plugins/PluginIssoTest.php
index 2bbb93d2..16ecf357 100644
--- a/tests/plugins/PluginIssoTest.php
+++ b/tests/plugins/PluginIssoTest.php
@@ -2,10 +2,10 @@
 namespace Shaarli\Plugin\Isso;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Plugin\PluginManager;
+use Shaarli\TestCase;
 
 require_once 'plugins/isso/isso.php';
 
@@ -116,8 +116,8 @@ class PluginIssoTest extends TestCase
 
         $processed = hook_isso_render_linklist($data, $conf);
         // link_plugin should be added for the icon
-        $this->assertContains('', $processed['links'][0]['link_plugin'][0]);
-        $this->assertContains('', $processed['links'][1]['link_plugin'][0]);
+        $this->assertContainsPolyfill('', $processed['links'][0]['link_plugin'][0]);
+        $this->assertContainsPolyfill('', $processed['links'][1]['link_plugin'][0]);
     }
 
     /**
@@ -146,7 +146,7 @@ class PluginIssoTest extends TestCase
         $processed = hook_isso_render_linklist($data, $conf);
 
         // link_plugin should be added for the icon
-        $this->assertContains('', $processed['links'][0]['link_plugin'][0]);
+        $this->assertContainsPolyfill('', $processed['links'][0]['link_plugin'][0]);
     }
 
     /**
diff --git a/tests/plugins/PluginPlayvideosTest.php b/tests/plugins/PluginPlayvideosTest.php
index de1a1aec..338d2e35 100644
--- a/tests/plugins/PluginPlayvideosTest.php
+++ b/tests/plugins/PluginPlayvideosTest.php
@@ -14,7 +14,7 @@ require_once 'plugins/playvideos/playvideos.php';
  * Class PluginPlayvideosTest
  * Unit test for the PlayVideos plugin
  */
-class PluginPlayvideosTest extends \PHPUnit\Framework\TestCase
+class PluginPlayvideosTest extends \Shaarli\TestCase
 {
     /**
      * Reset plugin path
diff --git a/tests/plugins/PluginPubsubhubbubTest.php b/tests/plugins/PluginPubsubhubbubTest.php
index d30c3703..d3f7b439 100644
--- a/tests/plugins/PluginPubsubhubbubTest.php
+++ b/tests/plugins/PluginPubsubhubbubTest.php
@@ -11,7 +11,7 @@ require_once 'plugins/pubsubhubbub/pubsubhubbub.php';
  * Class PluginPubsubhubbubTest
  * Unit test for the pubsubhubbub plugin
  */
-class PluginPubsubhubbubTest extends \PHPUnit\Framework\TestCase
+class PluginPubsubhubbubTest extends \Shaarli\TestCase
 {
     /**
      * @var string Config file path (without extension).
diff --git a/tests/plugins/PluginQrcodeTest.php b/tests/plugins/PluginQrcodeTest.php
index bc6be0eb..1d85fba6 100644
--- a/tests/plugins/PluginQrcodeTest.php
+++ b/tests/plugins/PluginQrcodeTest.php
@@ -14,7 +14,7 @@ require_once 'plugins/qrcode/qrcode.php';
  * Class PluginQrcodeTest
  * Unit test for the QR-Code plugin
  */
-class PluginQrcodeTest extends \PHPUnit\Framework\TestCase
+class PluginQrcodeTest extends \Shaarli\TestCase
 {
     /**
      * Reset plugin path
diff --git a/tests/plugins/PluginWallabagTest.php b/tests/plugins/PluginWallabagTest.php
index 372929ea..36317215 100644
--- a/tests/plugins/PluginWallabagTest.php
+++ b/tests/plugins/PluginWallabagTest.php
@@ -10,7 +10,7 @@ require_once 'plugins/wallabag/wallabag.php';
  * Class PluginWallabagTest
  * Unit test for the Wallabag plugin
  */
-class PluginWallabagTest extends \PHPUnit\Framework\TestCase
+class PluginWallabagTest extends \Shaarli\TestCase
 {
     /**
      * Reset plugin path
diff --git a/tests/plugins/WallabagInstanceTest.php b/tests/plugins/WallabagInstanceTest.php
index 4cb0d4cc..5ef3de1a 100644
--- a/tests/plugins/WallabagInstanceTest.php
+++ b/tests/plugins/WallabagInstanceTest.php
@@ -4,7 +4,7 @@ namespace Shaarli\Plugin\Wallabag;
 /**
  * Class WallabagInstanceTest
  */
-class WallabagInstanceTest extends \PHPUnit\Framework\TestCase
+class WallabagInstanceTest extends \Shaarli\TestCase
 {
     /**
      * @var string wallabag url.
diff --git a/tests/render/PageCacheManagerTest.php b/tests/render/PageCacheManagerTest.php
index 4aa7e179..08d4e5ea 100644
--- a/tests/render/PageCacheManagerTest.php
+++ b/tests/render/PageCacheManagerTest.php
@@ -6,8 +6,8 @@
 
 namespace Shaarli\Render;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 
 /**
  * Unitary tests for cached pages
diff --git a/tests/render/ThemeUtilsTest.php b/tests/render/ThemeUtilsTest.php
index 58e3426b..7d841e4d 100644
--- a/tests/render/ThemeUtilsTest.php
+++ b/tests/render/ThemeUtilsTest.php
@@ -7,7 +7,7 @@ namespace Shaarli\Render;
  *
  * @package Shaarli
  */
-class ThemeUtilsTest extends \PHPUnit\Framework\TestCase
+class ThemeUtilsTest extends \Shaarli\TestCase
 {
     /**
      * Test getThemes() with existing theme directories.
diff --git a/tests/security/BanManagerTest.php b/tests/security/BanManagerTest.php
index 2fef82f5..698d3d10 100644
--- a/tests/security/BanManagerTest.php
+++ b/tests/security/BanManagerTest.php
@@ -3,8 +3,8 @@
 
 namespace Shaarli\Security;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\FileUtils;
+use Shaarli\TestCase;
 
 /**
  * Test coverage for BanManager
diff --git a/tests/security/LoginManagerTest.php b/tests/security/LoginManagerTest.php
index cc9aa647..d302983d 100644
--- a/tests/security/LoginManagerTest.php
+++ b/tests/security/LoginManagerTest.php
@@ -2,7 +2,7 @@
 
 namespace Shaarli\Security;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 
 /**
  * Test coverage for LoginManager
diff --git a/tests/security/SessionManagerTest.php b/tests/security/SessionManagerTest.php
index 27e3b1a9..3f9c3ef5 100644
--- a/tests/security/SessionManagerTest.php
+++ b/tests/security/SessionManagerTest.php
@@ -2,7 +2,7 @@
 
 namespace Shaarli\Security;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 
 /**
  * Test coverage for SessionManager
diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php
index 5cfcd5db..73029e07 100644
--- a/tests/updater/UpdaterTest.php
+++ b/tests/updater/UpdaterTest.php
@@ -2,11 +2,11 @@
 namespace Shaarli\Updater;
 
 use Exception;
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 
 /**
-- 
cgit v1.2.3


From ab58f2542072e6bf34acd862f6cfed84b33feb29 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 29 Sep 2020 15:00:11 +0200
Subject: Compatibility with PHP 8

---
 tests/PluginManagerTest.php     |  4 ++--
 tests/config/ConfigJsonTest.php | 13 +------------
 tests/updater/DummyUpdater.php  |  8 ++++----
 3 files changed, 7 insertions(+), 18 deletions(-)

(limited to 'tests')

diff --git a/tests/PluginManagerTest.php b/tests/PluginManagerTest.php
index 38cd5eba..bbd2e142 100644
--- a/tests/PluginManagerTest.php
+++ b/tests/PluginManagerTest.php
@@ -81,8 +81,8 @@ class PluginManagerTest extends \Shaarli\TestCase
         $data = [];
         $this->pluginManager->executeHooks('error', $data);
 
-        $this->assertSame(
-            'test [plugin incompatibility]: Class \'Unknown\' not found',
+        $this->assertMatchesRegularExpression(
+            '/test \[plugin incompatibility\]: Class [\'"]Unknown[\'"] not found/',
             $this->pluginManager->getErrors()[0]
         );
     }
diff --git a/tests/config/ConfigJsonTest.php b/tests/config/ConfigJsonTest.php
index 4f508925..c0ba5b8f 100644
--- a/tests/config/ConfigJsonTest.php
+++ b/tests/config/ConfigJsonTest.php
@@ -42,7 +42,7 @@ class ConfigJsonTest extends \Shaarli\TestCase
     public function testReadInvalidJson()
     {
         $this->expectException(\Exception::class);
-        $this->expectExceptionMessageRegExp(' /An error occurred while parsing JSON configuration file \\([\\w\\/\\.]+\\): error code #4/');
+        $this->expectExceptionMessageRegExp('/An error occurred while parsing JSON configuration file \\([\\w\\/\\.]+\\): error code #4/');
 
         $this->configIO->read('tests/utils/config/configInvalid.json.php');
     }
@@ -108,17 +108,6 @@ class ConfigJsonTest extends \Shaarli\TestCase
         unlink($dest);
     }
 
-    /**
-     * Write to invalid path.
-     */
-    public function testWriteInvalidArray()
-    {
-        $this->expectException(\Shaarli\Exceptions\IOException::class);
-
-        $conf = array('conf' => 'value');
-        @$this->configIO->write(array(), $conf);
-    }
-
     /**
      * Write to invalid path.
      */
diff --git a/tests/updater/DummyUpdater.php b/tests/updater/DummyUpdater.php
index 07c7f5c4..3403233f 100644
--- a/tests/updater/DummyUpdater.php
+++ b/tests/updater/DummyUpdater.php
@@ -37,7 +37,7 @@ class DummyUpdater extends Updater
      *
      * @return bool true.
      */
-    final private function updateMethodDummy1()
+    final protected function updateMethodDummy1()
     {
         return true;
     }
@@ -47,7 +47,7 @@ class DummyUpdater extends Updater
      *
      * @return bool true.
      */
-    final private function updateMethodDummy2()
+    final protected function updateMethodDummy2()
     {
         return true;
     }
@@ -57,7 +57,7 @@ class DummyUpdater extends Updater
      *
      * @return bool true.
      */
-    final private function updateMethodDummy3()
+    final protected function updateMethodDummy3()
     {
         return true;
     }
@@ -67,7 +67,7 @@ class DummyUpdater extends Updater
      *
      * @throws Exception error.
      */
-    final private function updateMethodException()
+    final protected function updateMethodException()
     {
         throw new Exception('whatever');
     }
-- 
cgit v1.2.3


From f447edb73b1bcb52e86286467d3ec7b7bdc29948 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 29 Sep 2020 18:41:21 +0200
Subject: Fix missing @expectedException convertion

---
 tests/ApplicationUtilsTest.php             | 6 +++---
 tests/bookmark/BookmarkFileServiceTest.php | 3 +--
 tests/bookmark/BookmarkFilterTest.php      | 4 ++--
 tests/legacy/LegacyLinkDBTest.php          | 3 +--
 tests/legacy/LegacyLinkFilterTest.php      | 4 ++--
 tests/legacy/LegacyUpdaterTest.php         | 6 ++----
 tests/netscape/BookmarkExportTest.php      | 2 +-
 tests/updater/UpdaterTest.php              | 6 ++----
 8 files changed, 14 insertions(+), 20 deletions(-)

(limited to 'tests')

diff --git a/tests/ApplicationUtilsTest.php b/tests/ApplicationUtilsTest.php
index 7ad1d34c..a232b351 100644
--- a/tests/ApplicationUtilsTest.php
+++ b/tests/ApplicationUtilsTest.php
@@ -144,10 +144,10 @@ class ApplicationUtilsTest extends \Shaarli\TestCase
 
     /**
      * Test update checks - invalid Git branch
-     * @expectedException              Exception
      */
     public function testCheckUpdateInvalidGitBranch()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Invalid branch selected for updates/');
 
         ApplicationUtils::checkUpdate('', 'null', 0, true, true, 'unstable');
@@ -261,10 +261,10 @@ class ApplicationUtilsTest extends \Shaarli\TestCase
 
     /**
      * Check a unsupported PHP version
-     * @expectedException              Exception
      */
     public function testCheckSupportedPHPVersion51()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Your PHP version is obsolete/');
 
         $this->assertTrue(ApplicationUtils::checkPHPVersion('5.3', '5.1.0'));
@@ -272,10 +272,10 @@ class ApplicationUtilsTest extends \Shaarli\TestCase
 
     /**
      * Check another unsupported PHP version
-     * @expectedException              Exception
      */
     public function testCheckSupportedPHPVersion52()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Your PHP version is obsolete/');
 
         $this->assertTrue(ApplicationUtils::checkPHPVersion('5.3', '5.2'));
diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php
index 51e71a85..c399822b 100644
--- a/tests/bookmark/BookmarkFileServiceTest.php
+++ b/tests/bookmark/BookmarkFileServiceTest.php
@@ -637,11 +637,10 @@ class BookmarkFileServiceTest extends TestCase
      */
     /**
      * Attempt to instantiate a LinkDB whereas the datastore is not writable
-     *
-     * @expectedException              Shaarli\Bookmark\Exception\NotWritableDataStoreException
      */
     public function testConstructDatastoreNotWriteable()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\NotWritableDataStoreException::class);
         $this->expectExceptionMessageRegExp('#Couldn\'t load data from the data store file "null".*#');
 
         $conf = new ConfigManager('tests/utils/config/configJson');
diff --git a/tests/bookmark/BookmarkFilterTest.php b/tests/bookmark/BookmarkFilterTest.php
index 2f15cb3c..48c7f824 100644
--- a/tests/bookmark/BookmarkFilterTest.php
+++ b/tests/bookmark/BookmarkFilterTest.php
@@ -212,10 +212,10 @@ class BookmarkFilterTest extends TestCase
 
     /**
      * Use an invalid date format
-     * @expectedException              Exception
      */
     public function testFilterInvalidDayWithChars()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Invalid date format/');
 
         self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, 'Rainy day, dream away');
@@ -223,10 +223,10 @@ class BookmarkFilterTest extends TestCase
 
     /**
      * Use an invalid date format
-     * @expectedException              Exception
      */
     public function testFilterInvalidDayDigits()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Invalid date format/');
 
         self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20');
diff --git a/tests/legacy/LegacyLinkDBTest.php b/tests/legacy/LegacyLinkDBTest.php
index 66746dfc..df2cad62 100644
--- a/tests/legacy/LegacyLinkDBTest.php
+++ b/tests/legacy/LegacyLinkDBTest.php
@@ -99,11 +99,10 @@ class LegacyLinkDBTest extends \Shaarli\TestCase
 
     /**
      * Attempt to instantiate a LinkDB whereas the datastore is not writable
-     *
-     * @expectedException              Shaarli\Exceptions\IOException
      */
     public function testConstructDatastoreNotWriteable()
     {
+        $this->expectException(\Shaarli\Exceptions\IOException::class);
         $this->expectExceptionMessageRegExp('/Error accessing "null"/');
 
         new LegacyLinkDB('null/store.db', false, false);
diff --git a/tests/legacy/LegacyLinkFilterTest.php b/tests/legacy/LegacyLinkFilterTest.php
index 82bc93d8..45d7754d 100644
--- a/tests/legacy/LegacyLinkFilterTest.php
+++ b/tests/legacy/LegacyLinkFilterTest.php
@@ -197,10 +197,10 @@ class LegacyLinkFilterTest extends \Shaarli\TestCase
 
     /**
      * Use an invalid date format
-     * @expectedException              Exception
      */
     public function testFilterInvalidDayWithChars()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Invalid date format/');
 
         self::$linkFilter->filter(LegacyLinkFilter::$FILTER_DAY, 'Rainy day, dream away');
@@ -208,10 +208,10 @@ class LegacyLinkFilterTest extends \Shaarli\TestCase
 
     /**
      * Use an invalid date format
-     * @expectedException              Exception
      */
     public function testFilterInvalidDayDigits()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Invalid date format/');
 
         self::$linkFilter->filter(LegacyLinkFilter::$FILTER_DAY, '20');
diff --git a/tests/legacy/LegacyUpdaterTest.php b/tests/legacy/LegacyUpdaterTest.php
index 0ddcb4a6..f7391b86 100644
--- a/tests/legacy/LegacyUpdaterTest.php
+++ b/tests/legacy/LegacyUpdaterTest.php
@@ -80,11 +80,10 @@ class LegacyUpdaterTest extends \Shaarli\TestCase
 
     /**
      * Test errors in UpdaterUtils::write_updates_file(): empty updates file.
-     *
-     * @expectedException              Exception
      */
     public function testWriteEmptyUpdatesFile()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Updates file path is not set(.*)/');
 
         UpdaterUtils::write_updates_file('', array('test'));
@@ -92,11 +91,10 @@ class LegacyUpdaterTest extends \Shaarli\TestCase
 
     /**
      * Test errors in UpdaterUtils::write_updates_file(): not writable updates file.
-     *
-     * @expectedException              Exception
      */
     public function testWriteUpdatesFileNotWritable()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Unable to write(.*)/');
 
         $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php
index adf62f4f..9b95ccc9 100644
--- a/tests/netscape/BookmarkExportTest.php
+++ b/tests/netscape/BookmarkExportTest.php
@@ -77,10 +77,10 @@ class BookmarkExportTest extends TestCase
 
     /**
      * Attempt to export an invalid link selection
-     * @expectedException              Exception
      */
     public function testFilterAndFormatInvalid()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Invalid export selection/');
 
         $this->netscapeBookmarkUtils->filterAndFormat(
diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php
index 73029e07..a6280b8c 100644
--- a/tests/updater/UpdaterTest.php
+++ b/tests/updater/UpdaterTest.php
@@ -87,11 +87,10 @@ class UpdaterTest extends TestCase
 
     /**
      * Test errors in UpdaterUtils::write_updates_file(): empty updates file.
-     *
-     * @expectedException              Exception
      */
     public function testWriteEmptyUpdatesFile()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Updates file path is not set(.*)/');
 
         UpdaterUtils::write_updates_file('', array('test'));
@@ -99,11 +98,10 @@ class UpdaterTest extends TestCase
 
     /**
      * Test errors in UpdaterUtils::write_updates_file(): not writable updates file.
-     *
-     * @expectedException              Exception
      */
     public function testWriteUpdatesFileNotWritable()
     {
+        $this->expectException(\Exception::class);
         $this->expectExceptionMessageRegExp('/Unable to write(.*)/');
 
         $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
-- 
cgit v1.2.3


From d246e2c5129fe8d3f8e1429b4e8ff8e3e486c779 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Tue, 29 Sep 2020 18:49:02 +0200
Subject: Use assertRegExp polyfill instead of regexMatches

---
 tests/PluginManagerTest.php | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'tests')

diff --git a/tests/PluginManagerTest.php b/tests/PluginManagerTest.php
index bbd2e142..efef5e87 100644
--- a/tests/PluginManagerTest.php
+++ b/tests/PluginManagerTest.php
@@ -1,4 +1,5 @@
 pluginManager->executeHooks('error', $data);
 
-        $this->assertMatchesRegularExpression(
+        $this->assertRegExp(
             '/test \[plugin incompatibility\]: Class [\'"]Unknown[\'"] not found/',
             $this->pluginManager->getErrors()[0]
         );
-- 
cgit v1.2.3


From 1ea09a1b8b8b7f68ec8c7ef069393ee58a0e623a Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Sat, 26 Sep 2020 13:28:38 +0200
Subject: Fix warning if the encoding retrieved from external headers is
 invalid

Also fixed the regex to support this failing header: charset="utf-8"\r\n"
---
 tests/bookmark/LinkUtilsTest.php | 13 +++++++++++++
 1 file changed, 13 insertions(+)

(limited to 'tests')

diff --git a/tests/bookmark/LinkUtilsTest.php b/tests/bookmark/LinkUtilsTest.php
index 7d4a7b89..0d07897b 100644
--- a/tests/bookmark/LinkUtilsTest.php
+++ b/tests/bookmark/LinkUtilsTest.php
@@ -42,6 +42,19 @@ class LinkUtilsTest extends TestCase
         $this->assertEquals(strtolower($charset), header_extract_charset($headers));
     }
 
+    /**
+     * Test headers_extract_charset() when the charset is found with odd quotes.
+     */
+    public function testHeadersExtractExistentCharsetWithQuotes()
+    {
+        $charset = 'x-MacCroatian';
+        $headers = 'text/html; charset="' . $charset . '"otherstuff="test"';
+        $this->assertEquals(strtolower($charset), header_extract_charset($headers));
+
+        $headers = 'text/html; charset=\'' . $charset . '\'otherstuff="test"';
+        $this->assertEquals(strtolower($charset), header_extract_charset($headers));
+    }
+
     /**
      * Test headers_extract_charset() when the charset is not found.
      */
-- 
cgit v1.2.3


From 80a3efe11677b1420a7bc45d9b623c2df24cdd79 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Wed, 30 Sep 2020 15:31:34 +0200
Subject: Fix a bug preventing to edit bookmark with ID #0

---
 .../SaveBookmarkTest.php                           | 24 ++++++++++++++++++++++
 1 file changed, 24 insertions(+)

(limited to 'tests')

diff --git a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
index 58eaaa9b..a5e2dbc5 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
@@ -238,6 +238,30 @@ class SaveBookmarkTest extends TestCase
         static::assertSame(302, $result->getStatusCode());
     }
 
+    /**
+     * Test save a bookmark - with ID #0
+     */
+    public function testSaveBookmarkWithIdZero(): void
+    {
+        $parameters = ['lf_id' => '0'];
+
+        $request = $this->createMock(Request::class);
+        $request
+            ->method('getParam')
+            ->willReturnCallback(function (string $key) use ($parameters): ?string {
+                return $parameters[$key] ?? null;
+            })
+        ;
+        $response = new Response();
+
+        $this->container->bookmarkService->expects(static::once())->method('exists')->with(0)->willReturn(true);
+        $this->container->bookmarkService->expects(static::once())->method('get')->with(0)->willReturn(new Bookmark());
+
+        $result = $this->controller->save($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+    }
+
     /**
      * Change the password with a wrong existing password
      */
-- 
cgit v1.2.3


From 255b2264a119f4b8cc9fe211c7740906701e15b4 Mon Sep 17 00:00:00 2001
From: ArthurHoaro 
Date: Wed, 30 Sep 2020 15:57:57 +0200
Subject: Revert unrelated changes and add unit tests

---
 tests/api/ApiMiddlewareTest.php | 47 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

(limited to 'tests')

diff --git a/tests/api/ApiMiddlewareTest.php b/tests/api/ApiMiddlewareTest.php
index b157e4a7..32031750 100644
--- a/tests/api/ApiMiddlewareTest.php
+++ b/tests/api/ApiMiddlewareTest.php
@@ -66,6 +66,53 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
         @unlink(self::$testDatastore);
     }
 
+    /**
+     * Invoke the middleware with a valid token
+     */
+    public function testInvokeMiddlewareWithValidToken(): void
+    {
+        $next = function (Request $request, Response $response): Response {
+            return $response;
+        };
+        $mw = new ApiMiddleware($this->container);
+        $env = Environment::mock([
+            'REQUEST_METHOD' => 'GET',
+            'REQUEST_URI' => '/echo',
+            'HTTP_AUTHORIZATION'=> 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard'),
+        ]);
+        $request = Request::createFromEnvironment($env);
+        $response = new Response();
+        /** @var Response $response */
+        $response = $mw($request, $response, $next);
+
+        $this->assertEquals(200, $response->getStatusCode());
+    }
+
+    /**
+     * Invoke the middleware with a valid token
+     * Using specific Apache CGI redirected authorization.
+     */
+    public function testInvokeMiddlewareWithValidTokenFromRedirectedHeader(): void
+    {
+        $next = function (Request $request, Response $response): Response {
+            return $response;
+        };
+
+        $token = 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard');
+        $this->container->environment['REDIRECT_HTTP_AUTHORIZATION'] = $token;
+        $mw = new ApiMiddleware($this->container);
+        $env = Environment::mock([
+            'REQUEST_METHOD' => 'GET',
+            'REQUEST_URI' => '/echo',
+        ]);
+        $request = Request::createFromEnvironment($env);
+        $response = new Response();
+        /** @var Response $response */
+        $response = $mw($request, $response, $next);
+
+        $this->assertEquals(200, $response->getStatusCode());
+    }
+
     /**
      * Invoke the middleware with the API disabled:
      * should return a 401 error Unauthorized.
-- 
cgit v1.2.3