6 namespace Shaarli\Legacy
;
12 use Shaarli\Bookmark\Bookmark
;
14 require_once 'application/Utils.php';
15 require_once 'tests/utils/ReferenceLinkDB.php';
19 * Unitary tests for LegacyLinkDBTest
21 class LegacyLinkDBTest
extends \Shaarli\TestCase
23 // datastore to test write operations
24 protected static $testDatastore = 'sandbox/datastore.php';
27 * @var ReferenceLinkDB instance.
29 protected static $refDB = null;
32 * @var LegacyLinkDB public LinkDB instance.
34 protected static $publicLinkDB = null;
37 * @var LegacyLinkDB private LinkDB instance.
39 protected static $privateLinkDB = null;
42 * Instantiates public and private LinkDBs with test data
44 * The reference datastore contains public and private bookmarks that
45 * will be used to test LinkDB's methods:
46 * - access filtering (public/private),
53 * Resets test data for each test
55 protected function setUp(): void
57 if (file_exists(self
::$testDatastore)) {
58 unlink(self
::$testDatastore);
61 self
::$refDB = new ReferenceLinkDB(true);
62 self
::$refDB->write(self
::$testDatastore);
63 self
::$publicLinkDB = new LegacyLinkDB(self
::$testDatastore, false, false);
64 self
::$privateLinkDB = new LegacyLinkDB(self
::$testDatastore, true, false);
68 * Allows to test LinkDB's private methods
71 * https://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html
72 * http://stackoverflow.com/a/2798203
74 protected static function getMethod($name)
76 $class = new ReflectionClass('Shaarli\Legacy\LegacyLinkDB');
77 $method = $class->getMethod($name);
78 $method->setAccessible(true);
83 * Instantiate LinkDB objects - logged in user
85 public function testConstructLoggedIn()
87 new LegacyLinkDB(self
::$testDatastore, true, false);
88 $this->assertFileExists(self
::$testDatastore);
92 * Instantiate LinkDB objects - logged out or public instance
94 public function testConstructLoggedOut()
96 new LegacyLinkDB(self
::$testDatastore, false, false);
97 $this->assertFileExists(self
::$testDatastore);
101 * Attempt to instantiate a LinkDB whereas the datastore is not writable
103 public function testConstructDatastoreNotWriteable()
105 $this->expectException(\Shaarli\Exceptions\IOException
::class);
106 $this->expectExceptionMessageRegExp('/Error accessing "null"/');
108 new LegacyLinkDB('null/store.db', false, false);
112 * The DB doesn't exist, ensure it is created with dummy content
114 public function testCheckDBNew()
116 $linkDB = new LegacyLinkDB(self
::$testDatastore, false, false);
117 unlink(self
::$testDatastore);
118 $this->assertFileNotExists(self
::$testDatastore);
120 $checkDB = self
::getMethod('check');
121 $checkDB->invokeArgs($linkDB, array());
122 $this->assertFileExists(self
::$testDatastore);
124 // ensure the correct data has been written
125 $this->assertGreaterThan(0, filesize(self
::$testDatastore));
129 * The DB exists, don't do anything
131 public function testCheckDBLoad()
133 $linkDB = new LegacyLinkDB(self
::$testDatastore, false, false);
134 $datastoreSize = filesize(self
::$testDatastore);
135 $this->assertGreaterThan(0, $datastoreSize);
137 $checkDB = self
::getMethod('check');
138 $checkDB->invokeArgs($linkDB, array());
140 // ensure the datastore is left unmodified
143 filesize(self
::$testDatastore)
150 public function testReadEmptyDB()
152 file_put_contents(self
::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
153 $emptyDB = new LegacyLinkDB(self
::$testDatastore, false, false);
154 $this->assertEquals(0, sizeof($emptyDB));
155 $this->assertEquals(0, count($emptyDB));
159 * Load public bookmarks from the DB
161 public function testReadPublicDB()
164 self
::$refDB->countPublicLinks(),
165 sizeof(self
::$publicLinkDB)
170 * Load public and private bookmarks from the DB
172 public function testReadPrivateDB()
175 self
::$refDB->countLinks(),
176 sizeof(self
::$privateLinkDB)
181 * Save the bookmarks to the DB
183 public function testSave()
185 $testDB = new LegacyLinkDB(self
::$testDatastore, true, false);
186 $dbSize = sizeof($testDB);
190 'title' => 'an additional link',
191 'url' => 'http://dum.my',
192 'description' => 'One more',
194 'created' => DateTime
::createFromFormat(Bookmark
::LINK_DATE_FORMAT
, '20150518_190000'),
195 'tags' => 'unit test'
197 $testDB[$link['id']] = $link;
198 $testDB->save('tests');
200 $testDB = new LegacyLinkDB(self
::$testDatastore, true, false);
201 $this->assertEquals($dbSize +
1, sizeof($testDB));
205 * Count existing bookmarks
207 public function testCount()
210 self
::$refDB->countPublicLinks(),
211 self
::$publicLinkDB->count()
214 self
::$refDB->countLinks(),
215 self
::$privateLinkDB->count()
220 * Count existing bookmarks - public bookmarks hidden
222 public function testCountHiddenPublic()
224 $linkDB = new LegacyLinkDB(self
::$testDatastore, false, true);
237 * List the days for which bookmarks have been posted
239 public function testDays()
242 array('20100309', '20100310', '20121206', '20121207', '20130614', '20150310'),
243 self
::$publicLinkDB->days()
247 array('20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'),
248 self
::$privateLinkDB->days()
253 * The URL corresponds to an existing entry in the DB
255 public function testGetKnownLinkFromURL()
257 $link = self
::$publicLinkDB->getLinkFromUrl('http://mediagoblin.org/');
259 $this->assertNotEquals(false, $link);
260 $this->assertContainsPolyfill(
261 'A free software media publishing platform',
267 * The URL is not in the DB
269 public function testGetUnknownLinkFromURL()
273 self
::$publicLinkDB->getLinkFromUrl('http://dev.null')
280 public function testAllTags()
295 // The DB contains a link with `sTuff` and another one with `stuff` tag.
296 // They need to be grouped with the first case found - order by date DESC: `sTuff`.
304 self
::$publicLinkDB->linksCountPerTag()
336 self
::$privateLinkDB->linksCountPerTag()
353 self
::$privateLinkDB->linksCountPerTag(['web'])
363 self
::$privateLinkDB->linksCountPerTag(['web'], 'private')
368 * Test filter with string.
370 public function testFilterString()
372 $tags = 'dev cartoon';
373 $request = array('searchtags' => $tags);
376 count(self
::$privateLinkDB->filterSearch($request, true, false))
381 * Test filter with string.
383 public function testFilterArray()
385 $tags = array('dev', 'cartoon');
386 $request = array('searchtags' => $tags);
389 count(self
::$privateLinkDB->filterSearch($request, true, false))
394 * Test hidden tags feature:
395 * tags starting with a dot '.' are only visible when logged in.
397 public function testHiddenTags()
400 $request = array('searchtags' => $tags);
403 count(self
::$privateLinkDB->filterSearch($request, true, false))
408 count(self
::$publicLinkDB->filterSearch($request, true, false))
413 * Test filterHash() with a valid smallhash.
415 public function testFilterHashValid()
417 $request = smallHash('20150310_114651');
420 count(self
::$publicLinkDB->filterHash($request))
422 $request = smallHash('20150310_114633' . 8);
425 count(self
::$publicLinkDB->filterHash($request))
430 * Test filterHash() with an invalid smallhash.
432 public function testFilterHashInValid1()
434 $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException
::class);
437 self
::$publicLinkDB->filterHash($request);
441 * Test filterHash() with an empty smallhash.
443 public function testFilterHashInValid()
445 $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException
::class);
447 self
::$publicLinkDB->filterHash('');
451 * Test reorder with asc/desc parameter.
453 public function testReorderLinksDesc()
455 self
::$privateLinkDB->reorder('ASC');
456 $stickyIds = [11, 10];
457 $standardIds = [42, 4, 9, 1, 0, 7, 6, 8, 41];
458 $linkIds = array_merge($stickyIds, $standardIds);
460 foreach (self
::$privateLinkDB as $key => $value) {
461 $this->assertEquals($linkIds[$cpt++
], $key);
463 self
::$privateLinkDB->reorder('DESC');
464 $linkIds = array_merge(array_reverse($stickyIds), array_reverse($standardIds));
466 foreach (self
::$privateLinkDB as $key => $value) {
467 $this->assertEquals($linkIds[$cpt++
], $key);
472 * Test rename tag with a valid value present in multiple bookmarks
474 public function testRenameTagMultiple()
476 self
::$refDB->write(self
::$testDatastore);
477 $linkDB = new LegacyLinkDB(self
::$testDatastore, true, false);
479 $res = $linkDB->renameTag('cartoon', 'Taz');
480 $this->assertEquals(3, count($res));
481 $this->assertContainsPolyfill(' Taz ', $linkDB[4]['tags']);
482 $this->assertContainsPolyfill(' Taz ', $linkDB[1]['tags']);
483 $this->assertContainsPolyfill(' Taz ', $linkDB[0]['tags']);
487 * Test rename tag with a valid value
489 public function testRenameTagCaseSensitive()
491 self
::$refDB->write(self
::$testDatastore);
492 $linkDB = new LegacyLinkDB(self
::$testDatastore, true, false);
494 $res = $linkDB->renameTag('sTuff', 'Taz');
495 $this->assertEquals(1, count($res));
496 $this->assertEquals('Taz', $linkDB[41]['tags']);
500 * Test rename tag with invalid values
502 public function testRenameTagInvalid()
504 $linkDB = new LegacyLinkDB(self
::$testDatastore, false, false);
506 $this->assertFalse($linkDB->renameTag('', 'test'));
507 $this->assertFalse($linkDB->renameTag('', ''));
509 $this->assertEquals([], $linkDB->renameTag('test', ''));
510 $this->assertEquals([], $linkDB->renameTag('test', 'retest'));
514 * Test delete tag with a valid value
516 public function testDeleteTag()
518 self
::$refDB->write(self
::$testDatastore);
519 $linkDB = new LegacyLinkDB(self
::$testDatastore, true, false);
521 $res = $linkDB->renameTag('cartoon', null);
522 $this->assertEquals(3, count($res));
523 $this->assertNotContainsPolyfill('cartoon', $linkDB[4]['tags']);
527 * Test linksCountPerTag all tags without filter.
528 * Equal occurrences should be sorted alphabetically.
530 public function testCountLinkPerTagAllNoFilter()
560 $tags = self
::$privateLinkDB->linksCountPerTag();
562 $this->assertEquals($expected, $tags, var_export($tags, true));
566 * Test linksCountPerTag all tags with filter.
567 * Equal occurrences should be sorted alphabetically.
569 public function testCountLinkPerTagAllWithFilter()
583 $tags = self
::$privateLinkDB->linksCountPerTag(['gnu']);
585 $this->assertEquals($expected, $tags, var_export($tags, true));
589 * Test linksCountPerTag public tags with filter.
590 * Equal occurrences should be sorted alphabetically.
592 public function testCountLinkPerTagPublicWithFilter()
606 $tags = self
::$privateLinkDB->linksCountPerTag(['gnu'], 'public');
608 $this->assertEquals($expected, $tags, var_export($tags, true));
612 * Test linksCountPerTag public tags with filter.
613 * Equal occurrences should be sorted alphabetically.
615 public function testCountLinkPerTagPrivateWithFilter()
625 $tags = self
::$privateLinkDB->linksCountPerTag(['dev'], 'private');
627 $this->assertEquals($expected, $tags, var_export($tags, true));
631 * Make sure that bookmarks with the same timestamp have a consistent order:
632 * if their creation date is equal, bookmarks are sorted by ID DESC.
634 public function testConsistentOrder()
637 $creation = DateTime
::createFromFormat('Ymd_His', '20190807_130444');
638 $linkDB = new LegacyLinkDB(self
::$testDatastore, true, false);
639 for ($i = 0; $i < 4; ++
$i) {
640 $linkDB[$nextId +
$i] = [
641 'id' => $nextId +
$i,
642 'url' => 'http://'. $i,
643 'created' => $creation,
645 'description' => true,
650 // Check 4 new links 4 times
651 for ($i = 0; $i < 4; ++
$i) {
652 $linkDB->save('tests');
653 $linkDB = new LegacyLinkDB(self
::$testDatastore, true, false);
655 foreach ($linkDB as $link) {
656 if ($link['sticky'] === true) {
659 $this->assertEquals($nextId +
$count, $link['id']);
660 $this->assertEquals('http://'. $count, $link['url']);