]> git.immae.eu Git - github/shaarli/Shaarli.git/blobdiff - tests/bookmark/BookmarkFileServiceTest.php
Handle pagination through BookmarkService
[github/shaarli/Shaarli.git] / tests / bookmark / BookmarkFileServiceTest.php
index 1b438a7f97304503e310093b457c11a86cba4e01..d1af3fb04f6fffa71813ab4161d02ea6a500d0eb 100644 (file)
@@ -6,13 +6,15 @@
 namespace Shaarli\Bookmark;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
+use malkusch\lock\mutex\NoMutex;
 use ReferenceLinkDB;
 use ReflectionClass;
 use Shaarli;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Config\ConfigManager;
+use Shaarli\Formatter\BookmarkMarkdownFormatter;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 /**
  * Unitary tests for LegacyLinkDBTest
@@ -51,6 +53,9 @@ class BookmarkFileServiceTest extends TestCase
      */
     protected $privateLinkDB = null;
 
+    /** @var NoMutex */
+    protected $mutex;
+
     /**
      * Instantiates public and private LinkDBs with test data
      *
@@ -65,8 +70,10 @@ class BookmarkFileServiceTest extends TestCase
      *
      * Resets test data for each test
      */
-    protected function setUp()
+    protected function setUp(): void
     {
+        $this->mutex = new NoMutex();
+
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
         }
@@ -86,8 +93,8 @@ class BookmarkFileServiceTest extends TestCase
         $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);
+        $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
     }
 
     /**
@@ -104,7 +111,7 @@ class BookmarkFileServiceTest extends TestCase
         $db = self::getMethod('migrate');
         $db->invokeArgs($this->privateLinkDB, []);
 
-        $db = new \FakeBookmarkService($this->conf, $this->history, true);
+        $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, true);
         $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
         $this->assertEquals($this->refDB->countLinks(), $db->count());
     }
@@ -133,11 +140,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);
     }
 
@@ -173,7 +180,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals($updated, $bookmark->getUpdated());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(43);
         $this->assertEquals(43, $bookmark->getId());
@@ -199,7 +206,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());
@@ -211,11 +218,11 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertNull($bookmark->getUpdated());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $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());
@@ -229,53 +236,42 @@ 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());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, 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());
-    }
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('You\'re not authorized to alter the datastore');
 
-    /**
-     * 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!']);
+        $this->publicLinkDB->add(new Bookmark());
     }
 
     /**
      * 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);
@@ -313,7 +309,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(42);
         $this->assertEquals(42, $bookmark->getId());
@@ -339,7 +335,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());
@@ -354,11 +350,11 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $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());
@@ -387,7 +383,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals($title, $bookmark->getTitle());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(42);
         $this->assertEquals(42, $bookmark->getId());
@@ -396,44 +392,33 @@ 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->publicLinkDB->set(new Bookmark());
-    }
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('You\'re not authorized to alter the datastore');
 
-    /**
-     * 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!']);
+        $this->publicLinkDB->set(new Bookmark());
     }
 
     /**
      * 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);
@@ -451,7 +436,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals(43, $bookmark->getId());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(43);
         $this->assertEquals(43, $bookmark->getId());
@@ -471,7 +456,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals($title, $bookmark->getTitle());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(42);
         $this->assertEquals(42, $bookmark->getId());
@@ -480,24 +465,13 @@ 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->publicLinkDB->addOrSet(new Bookmark());
-    }
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('You\'re not authorized to alter the datastore');
 
-    /**
-     * 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!']);
+        $this->publicLinkDB->addOrSet(new Bookmark());
     }
 
     /**
@@ -514,7 +488,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals($title, $bookmark->getTitle());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(42);
         $this->assertEquals(42, $bookmark->getId());
@@ -523,11 +497,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);
 
@@ -540,41 +514,30 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertInstanceOf(BookmarkNotFoundException::class, $exception);
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, 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()
     {
+        $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->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);
@@ -614,14 +577,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()
         );
     }
 
@@ -630,18 +597,17 @@ 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->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');
         $conf->set('resource.datastore', 'null/store.db');
-        new BookmarkFileService($conf, $this->history, true);
+        new BookmarkFileService($conf, $this->history, $this->mutex, true);
     }
 
     /**
@@ -651,7 +617,7 @@ class BookmarkFileServiceTest extends TestCase
     {
         unlink(self::$testDatastore);
         $this->assertFileNotExists(self::$testDatastore);
-        new BookmarkFileService($this->conf, $this->history, true);
+        new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
         $this->assertFileExists(self::$testDatastore);
 
         // ensure the correct data has been written
@@ -665,7 +631,7 @@ class BookmarkFileServiceTest extends TestCase
     {
         unlink(self::$testDatastore);
         $this->assertFileNotExists(self::$testDatastore);
-        $db = new \FakeBookmarkService($this->conf, $this->history, false);
+        $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, false);
         $this->assertFileNotExists(self::$testDatastore);
         $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
         $this->assertCount(0, $db->getBookmarks());
@@ -698,13 +664,13 @@ class BookmarkFileServiceTest extends TestCase
      */
     public function testSave()
     {
-        $testDB = new BookmarkFileService($this->conf, $this->history, true);
+        $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
         $dbSize = $testDB->count();
 
         $bookmark = new Bookmark();
         $testDB->add($bookmark);
 
-        $testDB = new BookmarkFileService($this->conf, $this->history, true);
+        $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
         $this->assertEquals($dbSize + 1, $testDB->count());
     }
 
@@ -714,27 +680,11 @@ class BookmarkFileServiceTest extends TestCase
     public function testCountHiddenPublic()
     {
         $this->conf->set('privacy.hide_public_links', true);
-        $linkDB = new BookmarkFileService($this->conf, $this->history, false);
+        $linkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, 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
      */
@@ -743,7 +693,7 @@ class BookmarkFileServiceTest extends TestCase
         $link = $this->publicLinkDB->findByUrl('http://mediagoblin.org/');
 
         $this->assertNotEquals(false, $link);
-        $this->assertContains(
+        $this->assertContainsPolyfill(
             'A free software media publishing platform',
             $link->getDescription()
         );
@@ -782,6 +732,10 @@ class BookmarkFileServiceTest extends TestCase
                 // They need to be grouped with the first case found - order by date DESC: `sTuff`.
                 'sTuff' => 2,
                 'ut' => 1,
+                'assurance' => 1,
+                'coding-style' => 1,
+                'quality' => 1,
+                'standards' => 1,
             ],
             $this->publicLinkDB->bookmarksCountPerTag()
         );
@@ -810,12 +764,15 @@ class BookmarkFileServiceTest extends TestCase
                 'tag3' => 1,
                 'tag4' => 1,
                 'ut' => 1,
+                'assurance' => 1,
+                'coding-style' => 1,
+                'quality' => 1,
+                'standards' => 1,
             ],
             $this->privateLinkDB->bookmarksCountPerTag()
         );
         $this->assertEquals(
             [
-                'web' => 4,
                 'cartoon' => 2,
                 'gnu' => 1,
                 'dev' => 1,
@@ -832,7 +789,6 @@ class BookmarkFileServiceTest extends TestCase
         );
         $this->assertEquals(
             [
-                'web' => 1,
                 'html' => 1,
                 'w3c' => 1,
                 'css' => 1,
@@ -851,7 +807,7 @@ class BookmarkFileServiceTest extends TestCase
         $request = ['searchtags' => $tags];
         $this->assertEquals(
             2,
-            count($this->privateLinkDB->search($request, null, true))
+            count($this->privateLinkDB->search($request, null, true)->getBookmarks())
         );
     }
 
@@ -864,7 +820,7 @@ class BookmarkFileServiceTest extends TestCase
         $request = ['searchtags' => $tags];
         $this->assertEquals(
             2,
-            count($this->privateLinkDB->search($request, null, true))
+            count($this->privateLinkDB->search($request, null, true)->getBookmarks())
         );
     }
 
@@ -878,12 +834,12 @@ class BookmarkFileServiceTest extends TestCase
         $request = ['searchtags' => $tags];
         $this->assertEquals(
             1,
-            count($this->privateLinkDB->search($request, 'all', true))
+            count($this->privateLinkDB->search($request, 'all', true)->getBookmarks())
         );
 
         $this->assertEquals(
             0,
-            count($this->publicLinkDB->search($request, 'public', true))
+            count($this->publicLinkDB->search($request, 'public', true)->getBookmarks())
         );
     }
 
@@ -893,38 +849,69 @@ 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('');
     }
 
+    /**
+     * Test filterHash() on a private bookmark while logged out.
+     */
+    public function testFilterHashPrivateWhileLoggedOut()
+    {
+        $this->expectException(BookmarkNotFoundException::class);
+        $this->expectExceptionMessage('The link you are trying to reach does not exist or has been deleted');
+
+        $hash = smallHash('20141125_084734' . 6);
+
+        $this->publicLinkDB->findByHash($hash);
+    }
+
+    /**
+     * Test filterHash() with private key.
+     */
+    public function testFilterHashWithPrivateKey()
+    {
+        $hash = smallHash('20141125_084734' . 6);
+        $privateKey = 'this is usually auto generated';
+
+        $bookmark = $this->privateLinkDB->findByHash($hash);
+        $bookmark->addAdditionalContentEntry('private_key', $privateKey);
+        $this->privateLinkDB->save();
+
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
+        $bookmark = $this->privateLinkDB->findByHash($hash, $privateKey);
+
+        static::assertSame(6, $bookmark->getId());
+    }
+
     /**
      * Test linksCountPerTag all tags without filter.
      * Equal occurrences should be sorted alphabetically.
@@ -954,6 +941,10 @@ class BookmarkFileServiceTest extends TestCase
             'tag4' => 1,
             'ut' => 1,
             'w3c' => 1,
+            'assurance' => 1,
+            'coding-style' => 1,
+            'quality' => 1,
+            'standards' => 1,
         ];
         $tags = $this->privateLinkDB->bookmarksCountPerTag();
 
@@ -967,7 +958,6 @@ class BookmarkFileServiceTest extends TestCase
     public function testCountLinkPerTagAllWithFilter()
     {
         $expected = [
-            'gnu' => 2,
             'hashtag' => 2,
             '-exclude' => 1,
             '.hidden' => 1,
@@ -990,7 +980,6 @@ class BookmarkFileServiceTest extends TestCase
     public function testCountLinkPerTagPublicWithFilter()
     {
         $expected = [
-            'gnu' => 2,
             'hashtag' => 2,
             '-exclude' => 1,
             '.hidden' => 1,
@@ -1014,7 +1003,6 @@ class BookmarkFileServiceTest extends TestCase
     {
         $expected = [
             'cartoon' => 1,
-            'dev' => 1,
             'tag1' => 1,
             'tag2' => 1,
             'tag3' => 1,
@@ -1025,6 +1013,152 @@ 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,
+            'assurance' => 1,
+            'coding-style' => 1,
+            'quality' => 1,
+            'standards' => 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));
+    }
+
+    /**
+     * Test find by dates in the middle of the datastore (sorted by dates) with a single bookmark as a result.
+     */
+    public function testFilterByDateMidTimePeriodSingleBookmark(): void
+    {
+        $bookmarks = $this->privateLinkDB->findByDate(
+            DateTime::createFromFormat('Ymd_His', '20121206_150000'),
+            DateTime::createFromFormat('Ymd_His', '20121206_160000'),
+            $before,
+            $after
+        );
+
+        static::assertCount(1, $bookmarks);
+
+        static::assertSame(9, $bookmarks[0]->getId());
+        static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_142300'), $before);
+        static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_172539'), $after);
+    }
+
+    /**
+     * Test find by dates in the middle of the datastore (sorted by dates) with a multiple bookmarks as a result.
+     */
+    public function testFilterByDateMidTimePeriodMultipleBookmarks(): void
+    {
+        $bookmarks = $this->privateLinkDB->findByDate(
+            DateTime::createFromFormat('Ymd_His', '20121206_150000'),
+            DateTime::createFromFormat('Ymd_His', '20121206_180000'),
+            $before,
+            $after
+        );
+
+        static::assertCount(2, $bookmarks);
+
+        static::assertSame(1, $bookmarks[0]->getId());
+        static::assertSame(9, $bookmarks[1]->getId());
+        static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_142300'), $before);
+        static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_182539'), $after);
+    }
+
+    /**
+     * Test find by dates at the end of the datastore (sorted by dates).
+     */
+    public function testFilterByDateLastTimePeriod(): void
+    {
+        $after = new DateTime();
+        $bookmarks = $this->privateLinkDB->findByDate(
+            DateTime::createFromFormat('Ymd_His', '20150310_114640'),
+            DateTime::createFromFormat('Ymd_His', '20450101_010101'),
+            $before,
+            $after
+        );
+
+        static::assertCount(1, $bookmarks);
+
+        static::assertSame(41, $bookmarks[0]->getId());
+        static::assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114633'), $before);
+        static::assertNull($after);
+    }
+
+    /**
+     * Test find by dates at the beginning of the datastore (sorted by dates).
+     */
+    public function testFilterByDateFirstTimePeriod(): void
+    {
+        $before = new DateTime();
+        $bookmarks = $this->privateLinkDB->findByDate(
+            DateTime::createFromFormat('Ymd_His', '20000101_101010'),
+            DateTime::createFromFormat('Ymd_His', '20100309_110000'),
+            $before,
+            $after
+        );
+
+        static::assertCount(1, $bookmarks);
+
+        static::assertSame(11, $bookmarks[0]->getId());
+        static::assertNull($before);
+        static::assertEquals(DateTime::createFromFormat('Ymd_His', '20100310_101010'), $after);
+    }
+
+    /**
+     * Test getLatest with a sticky bookmark: it should be ignored and return the latest by creation date instead.
+     */
+    public function testGetLatestWithSticky(): void
+    {
+        $bookmark = $this->publicLinkDB->getLatest();
+
+        static::assertSame(41, $bookmark->getId());
+    }
+
+    /**
+     * Test getLatest with a sticky bookmark: it should be ignored and return the latest by creation date instead.
+     */
+    public function testGetLatestEmptyDatastore(): void
+    {
+        unlink($this->conf->get('resource.datastore'));
+        $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
+
+        $bookmark = $this->publicLinkDB->getLatest();
+
+        static::assertNull($bookmark);
+    }
+
     /**
      * Allows to test LinkDB's private methods
      *