6 namespace Shaarli\Bookmark
;
13 require_once 'application/feed/Cache.php';
14 require_once 'application/Utils.php';
15 require_once 'tests/utils/ReferenceLinkDB.php';
19 * Unitary tests for LinkDB
21 class LinkDBTest
extends \PHPUnit\Framework\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 LinkDB public LinkDB instance.
34 protected static $publicLinkDB = null;
37 * @var LinkDB 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 links that
45 * will be used to test LinkDB's methods:
46 * - access filtering (public/private),
53 public static function setUpBeforeClass()
55 self
::$refDB = new ReferenceLinkDB();
56 self
::$refDB->write(self
::$testDatastore);
58 self
::$publicLinkDB = new LinkDB(self
::$testDatastore, false, false);
59 self
::$privateLinkDB = new LinkDB(self
::$testDatastore, true, false);
63 * Resets test data for each test
65 protected function setUp()
67 if (file_exists(self
::$testDatastore)) {
68 unlink(self
::$testDatastore);
73 * Allows to test LinkDB's private methods
76 * https://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html
77 * http://stackoverflow.com/a/2798203
79 protected static function getMethod($name)
81 $class = new ReflectionClass('Shaarli\Bookmark\LinkDB');
82 $method = $class->getMethod($name);
83 $method->setAccessible(true);
88 * Instantiate LinkDB objects - logged in user
90 public function testConstructLoggedIn()
92 new LinkDB(self
::$testDatastore, true, false);
93 $this->assertFileExists(self
::$testDatastore);
97 * Instantiate LinkDB objects - logged out or public instance
99 public function testConstructLoggedOut()
101 new LinkDB(self
::$testDatastore, false, false);
102 $this->assertFileExists(self
::$testDatastore);
106 * Attempt to instantiate a LinkDB whereas the datastore is not writable
108 * @expectedException Shaarli\Exceptions\IOException
109 * @expectedExceptionMessageRegExp /Error accessing "null"/
111 public function testConstructDatastoreNotWriteable()
113 new LinkDB('null/store.db', false, false);
117 * The DB doesn't exist, ensure it is created with dummy content
119 public function testCheckDBNew()
121 $linkDB = new LinkDB(self
::$testDatastore, false, false);
122 unlink(self
::$testDatastore);
123 $this->assertFileNotExists(self
::$testDatastore);
125 $checkDB = self
::getMethod('check');
126 $checkDB->invokeArgs($linkDB, array());
127 $this->assertFileExists(self
::$testDatastore);
129 // ensure the correct data has been written
130 $this->assertGreaterThan(0, filesize(self
::$testDatastore));
134 * The DB exists, don't do anything
136 public function testCheckDBLoad()
138 $linkDB = new LinkDB(self
::$testDatastore, false, false);
139 $datastoreSize = filesize(self
::$testDatastore);
140 $this->assertGreaterThan(0, $datastoreSize);
142 $checkDB = self
::getMethod('check');
143 $checkDB->invokeArgs($linkDB, array());
145 // ensure the datastore is left unmodified
148 filesize(self
::$testDatastore)
155 public function testReadEmptyDB()
157 file_put_contents(self
::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
158 $emptyDB = new LinkDB(self
::$testDatastore, false, false);
159 $this->assertEquals(0, sizeof($emptyDB));
160 $this->assertEquals(0, count($emptyDB));
164 * Load public links from the DB
166 public function testReadPublicDB()
169 self
::$refDB->countPublicLinks(),
170 sizeof(self
::$publicLinkDB)
175 * Load public and private links from the DB
177 public function testReadPrivateDB()
180 self
::$refDB->countLinks(),
181 sizeof(self
::$privateLinkDB)
186 * Save the links to the DB
188 public function testSave()
190 $testDB = new LinkDB(self
::$testDatastore, true, false);
191 $dbSize = sizeof($testDB);
195 'title' => 'an additional link',
196 'url' => 'http://dum.my',
197 'description' => 'One more',
199 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20150518_190000'),
200 'tags' => 'unit test'
202 $testDB[$link['id']] = $link;
203 $testDB->save('tests');
205 $testDB = new LinkDB(self
::$testDatastore, true, false);
206 $this->assertEquals($dbSize +
1, sizeof($testDB));
210 * Count existing links
212 public function testCount()
215 self
::$refDB->countPublicLinks(),
216 self
::$publicLinkDB->count()
219 self
::$refDB->countLinks(),
220 self
::$privateLinkDB->count()
225 * Count existing links - public links hidden
227 public function testCountHiddenPublic()
229 $linkDB = new LinkDB(self
::$testDatastore, false, true);
242 * List the days for which links have been posted
244 public function testDays()
247 array('20100309', '20100310', '20121206', '20121207', '20130614', '20150310'),
248 self
::$publicLinkDB->days()
252 array('20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'),
253 self
::$privateLinkDB->days()
258 * The URL corresponds to an existing entry in the DB
260 public function testGetKnownLinkFromURL()
262 $link = self
::$publicLinkDB->getLinkFromUrl('http://mediagoblin.org/');
264 $this->assertNotEquals(false, $link);
265 $this->assertContains(
266 'A free software media publishing platform',
272 * The URL is not in the DB
274 public function testGetUnknownLinkFromURL()
278 self
::$publicLinkDB->getLinkFromUrl('http://dev.null')
285 public function testAllTags()
300 // The DB contains a link with `sTuff` and another one with `stuff` tag.
301 // They need to be grouped with the first case found - order by date DESC: `sTuff`.
305 self
::$publicLinkDB->linksCountPerTag()
333 self
::$privateLinkDB->linksCountPerTag()
350 self
::$privateLinkDB->linksCountPerTag(['web'])
360 self
::$privateLinkDB->linksCountPerTag(['web'], 'private')
365 * Test real_url without redirector.
367 public function testLinkRealUrlWithoutRedirector()
369 $db = new LinkDB(self
::$testDatastore, false, false);
370 foreach ($db as $link) {
371 $this->assertEquals($link['url'], $link['real_url']);
376 * Test real_url with redirector.
378 public function testLinkRealUrlWithRedirector()
380 $redirector = 'http://redirector.to?';
381 $db = new LinkDB(self
::$testDatastore, false, false, $redirector);
382 foreach ($db as $link) {
383 $this->assertStringStartsWith($redirector, $link['real_url']);
384 $this->assertNotFalse(strpos($link['real_url'], urlencode('://')));
387 $db = new LinkDB(self
::$testDatastore, false, false, $redirector, false);
388 foreach ($db as $link) {
389 $this->assertStringStartsWith($redirector, $link['real_url']);
390 $this->assertFalse(strpos($link['real_url'], urlencode('://')));
395 * Test filter with string.
397 public function testFilterString()
399 $tags = 'dev cartoon';
400 $request = array('searchtags' => $tags);
403 count(self
::$privateLinkDB->filterSearch($request, true, false))
408 * Test filter with string.
410 public function testFilterArray()
412 $tags = array('dev', 'cartoon');
413 $request = array('searchtags' => $tags);
416 count(self
::$privateLinkDB->filterSearch($request, true, false))
421 * Test hidden tags feature:
422 * tags starting with a dot '.' are only visible when logged in.
424 public function testHiddenTags()
427 $request = array('searchtags' => $tags);
430 count(self
::$privateLinkDB->filterSearch($request, true, false))
435 count(self
::$publicLinkDB->filterSearch($request, true, false))
440 * Test filterHash() with a valid smallhash.
442 public function testFilterHashValid()
444 $request = smallHash('20150310_114651');
447 count(self
::$publicLinkDB->filterHash($request))
449 $request = smallHash('20150310_114633' . 8);
452 count(self
::$publicLinkDB->filterHash($request))
457 * Test filterHash() with an invalid smallhash.
459 * @expectedException \Shaarli\Bookmark\Exception\LinkNotFoundException
461 public function testFilterHashInValid1()
464 self
::$publicLinkDB->filterHash($request);
468 * Test filterHash() with an empty smallhash.
470 * @expectedException \Shaarli\Bookmark\Exception\LinkNotFoundException
472 public function testFilterHashInValid()
474 self
::$publicLinkDB->filterHash('');
478 * Test reorder with asc/desc parameter.
480 public function testReorderLinksDesc()
482 self
::$privateLinkDB->reorder('ASC');
483 $stickyIds = [11, 10];
484 $standardIds = [42, 4, 9, 1, 0, 7, 6, 8, 41];
485 $linkIds = array_merge($stickyIds, $standardIds);
487 foreach (self
::$privateLinkDB as $key => $value) {
488 $this->assertEquals($linkIds[$cpt++
], $key);
490 self
::$privateLinkDB->reorder('DESC');
491 $linkIds = array_merge(array_reverse($stickyIds), array_reverse($standardIds));
493 foreach (self
::$privateLinkDB as $key => $value) {
494 $this->assertEquals($linkIds[$cpt++
], $key);
499 * Test rename tag with a valid value present in multiple links
501 public function testRenameTagMultiple()
503 self
::$refDB->write(self
::$testDatastore);
504 $linkDB = new LinkDB(self
::$testDatastore, true, false);
506 $res = $linkDB->renameTag('cartoon', 'Taz');
507 $this->assertEquals(3, count($res));
508 $this->assertContains(' Taz ', $linkDB[4]['tags']);
509 $this->assertContains(' Taz ', $linkDB[1]['tags']);
510 $this->assertContains(' Taz ', $linkDB[0]['tags']);
514 * Test rename tag with a valid value
516 public function testRenameTagCaseSensitive()
518 self
::$refDB->write(self
::$testDatastore);
519 $linkDB = new LinkDB(self
::$testDatastore, true, false, '');
521 $res = $linkDB->renameTag('sTuff', 'Taz');
522 $this->assertEquals(1, count($res));
523 $this->assertEquals('Taz', $linkDB[41]['tags']);
527 * Test rename tag with invalid values
529 public function testRenameTagInvalid()
531 $linkDB = new LinkDB(self
::$testDatastore, false, false);
533 $this->assertFalse($linkDB->renameTag('', 'test'));
534 $this->assertFalse($linkDB->renameTag('', ''));
536 $this->assertEquals([], $linkDB->renameTag('test', ''));
537 $this->assertEquals([], $linkDB->renameTag('test', 'retest'));
541 * Test delete tag with a valid value
543 public function testDeleteTag()
545 self
::$refDB->write(self
::$testDatastore);
546 $linkDB = new LinkDB(self
::$testDatastore, true, false);
548 $res = $linkDB->renameTag('cartoon', null);
549 $this->assertEquals(3, count($res));
550 $this->assertNotContains('cartoon', $linkDB[4]['tags']);
554 * Test linksCountPerTag all tags without filter.
555 * Equal occurrences should be sorted alphabetically.
557 public function testCountLinkPerTagAllNoFilter()
583 $tags = self
::$privateLinkDB->linksCountPerTag();
585 $this->assertEquals($expected, $tags, var_export($tags, true));
589 * Test linksCountPerTag all tags with filter.
590 * Equal occurrences should be sorted alphabetically.
592 public function testCountLinkPerTagAllWithFilter()
606 $tags = self
::$privateLinkDB->linksCountPerTag(['gnu']);
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 testCountLinkPerTagPublicWithFilter()
629 $tags = self
::$privateLinkDB->linksCountPerTag(['gnu'], 'public');
631 $this->assertEquals($expected, $tags, var_export($tags, true));
635 * Test linksCountPerTag public tags with filter.
636 * Equal occurrences should be sorted alphabetically.
638 public function testCountLinkPerTagPrivateWithFilter()
648 $tags = self
::$privateLinkDB->linksCountPerTag(['dev'], 'private');
650 $this->assertEquals($expected, $tags, var_export($tags, true));