6 namespace Shaarli\Bookmark
;
9 use Shaarli\Bookmark\Exception\LinkNotFoundException
;
14 require_once 'application/feed/Cache.php';
15 require_once 'application/Utils.php';
16 require_once 'tests/utils/ReferenceLinkDB.php';
20 * Unitary tests for LinkDB
22 class LinkDBTest
extends \PHPUnit\Framework\TestCase
24 // datastore to test write operations
25 protected static $testDatastore = 'sandbox/datastore.php';
28 * @var ReferenceLinkDB instance.
30 protected static $refDB = null;
33 * @var LinkDB public LinkDB instance.
35 protected static $publicLinkDB = null;
38 * @var LinkDB private LinkDB instance.
40 protected static $privateLinkDB = null;
43 * Instantiates public and private LinkDBs with test data
45 * The reference datastore contains public and private links that
46 * will be used to test LinkDB's methods:
47 * - access filtering (public/private),
54 public static function setUpBeforeClass()
56 self
::$refDB = new ReferenceLinkDB();
57 self
::$refDB->write(self
::$testDatastore);
59 self
::$publicLinkDB = new LinkDB(self
::$testDatastore, false, false);
60 self
::$privateLinkDB = new LinkDB(self
::$testDatastore, true, false);
64 * Resets test data for each test
66 protected function setUp()
68 if (file_exists(self
::$testDatastore)) {
69 unlink(self
::$testDatastore);
74 * Allows to test LinkDB's private methods
77 * https://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html
78 * http://stackoverflow.com/a/2798203
80 protected static function getMethod($name)
82 $class = new ReflectionClass('Shaarli\Bookmark\LinkDB');
83 $method = $class->getMethod($name);
84 $method->setAccessible(true);
89 * Instantiate LinkDB objects - logged in user
91 public function testConstructLoggedIn()
93 new LinkDB(self
::$testDatastore, true, false);
94 $this->assertFileExists(self
::$testDatastore);
98 * Instantiate LinkDB objects - logged out or public instance
100 public function testConstructLoggedOut()
102 new LinkDB(self
::$testDatastore, false, false);
103 $this->assertFileExists(self
::$testDatastore);
107 * Attempt to instantiate a LinkDB whereas the datastore is not writable
109 * @expectedException Shaarli\Exceptions\IOException
110 * @expectedExceptionMessageRegExp /Error accessing "null"/
112 public function testConstructDatastoreNotWriteable()
114 new LinkDB('null/store.db', false, false);
118 * The DB doesn't exist, ensure it is created with dummy content
120 public function testCheckDBNew()
122 $linkDB = new LinkDB(self
::$testDatastore, false, false);
123 unlink(self
::$testDatastore);
124 $this->assertFileNotExists(self
::$testDatastore);
126 $checkDB = self
::getMethod('check');
127 $checkDB->invokeArgs($linkDB, array());
128 $this->assertFileExists(self
::$testDatastore);
130 // ensure the correct data has been written
131 $this->assertGreaterThan(0, filesize(self
::$testDatastore));
135 * The DB exists, don't do anything
137 public function testCheckDBLoad()
139 $linkDB = new LinkDB(self
::$testDatastore, false, false);
140 $datastoreSize = filesize(self
::$testDatastore);
141 $this->assertGreaterThan(0, $datastoreSize);
143 $checkDB = self
::getMethod('check');
144 $checkDB->invokeArgs($linkDB, array());
146 // ensure the datastore is left unmodified
149 filesize(self
::$testDatastore)
156 public function testReadEmptyDB()
158 file_put_contents(self
::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
159 $emptyDB = new LinkDB(self
::$testDatastore, false, false);
160 $this->assertEquals(0, sizeof($emptyDB));
161 $this->assertEquals(0, count($emptyDB));
165 * Load public links from the DB
167 public function testReadPublicDB()
170 self
::$refDB->countPublicLinks(),
171 sizeof(self
::$publicLinkDB)
176 * Load public and private links from the DB
178 public function testReadPrivateDB()
181 self
::$refDB->countLinks(),
182 sizeof(self
::$privateLinkDB)
187 * Save the links to the DB
189 public function testSave()
191 $testDB = new LinkDB(self
::$testDatastore, true, false);
192 $dbSize = sizeof($testDB);
196 'title' => 'an additional link',
197 'url' => 'http://dum.my',
198 'description' => 'One more',
200 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20150518_190000'),
201 'tags' => 'unit test'
203 $testDB[$link['id']] = $link;
204 $testDB->save('tests');
206 $testDB = new LinkDB(self
::$testDatastore, true, false);
207 $this->assertEquals($dbSize +
1, sizeof($testDB));
211 * Count existing links
213 public function testCount()
216 self
::$refDB->countPublicLinks(),
217 self
::$publicLinkDB->count()
220 self
::$refDB->countLinks(),
221 self
::$privateLinkDB->count()
226 * Count existing links - public links hidden
228 public function testCountHiddenPublic()
230 $linkDB = new LinkDB(self
::$testDatastore, false, true);
243 * List the days for which links have been posted
245 public function testDays()
248 array('20100309', '20100310', '20121206', '20121207', '20130614', '20150310'),
249 self
::$publicLinkDB->days()
253 array('20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'),
254 self
::$privateLinkDB->days()
259 * The URL corresponds to an existing entry in the DB
261 public function testGetKnownLinkFromURL()
263 $link = self
::$publicLinkDB->getLinkFromUrl('http://mediagoblin.org/');
265 $this->assertNotEquals(false, $link);
266 $this->assertContains(
267 'A free software media publishing platform',
273 * The URL is not in the DB
275 public function testGetUnknownLinkFromURL()
279 self
::$publicLinkDB->getLinkFromUrl('http://dev.null')
286 public function testAllTags()
301 // The DB contains a link with `sTuff` and another one with `stuff` tag.
302 // They need to be grouped with the first case found - order by date DESC: `sTuff`.
306 self
::$publicLinkDB->linksCountPerTag()
334 self
::$privateLinkDB->linksCountPerTag()
351 self
::$privateLinkDB->linksCountPerTag(['web'])
361 self
::$privateLinkDB->linksCountPerTag(['web'], 'private')
366 * Test real_url without redirector.
368 public function testLinkRealUrlWithoutRedirector()
370 $db = new LinkDB(self
::$testDatastore, false, false);
371 foreach ($db as $link) {
372 $this->assertEquals($link['url'], $link['real_url']);
377 * Test real_url with redirector.
379 public function testLinkRealUrlWithRedirector()
381 $redirector = 'http://redirector.to?';
382 $db = new LinkDB(self
::$testDatastore, false, false, $redirector);
383 foreach ($db as $link) {
384 $this->assertStringStartsWith($redirector, $link['real_url']);
385 $this->assertNotFalse(strpos($link['real_url'], urlencode('://')));
388 $db = new LinkDB(self
::$testDatastore, false, false, $redirector, false);
389 foreach ($db as $link) {
390 $this->assertStringStartsWith($redirector, $link['real_url']);
391 $this->assertFalse(strpos($link['real_url'], urlencode('://')));
396 * Test filter with string.
398 public function testFilterString()
400 $tags = 'dev cartoon';
401 $request = array('searchtags' => $tags);
404 count(self
::$privateLinkDB->filterSearch($request, true, false))
409 * Test filter with string.
411 public function testFilterArray()
413 $tags = array('dev', 'cartoon');
414 $request = array('searchtags' => $tags);
417 count(self
::$privateLinkDB->filterSearch($request, true, false))
422 * Test hidden tags feature:
423 * tags starting with a dot '.' are only visible when logged in.
425 public function testHiddenTags()
428 $request = array('searchtags' => $tags);
431 count(self
::$privateLinkDB->filterSearch($request, true, false))
436 count(self
::$publicLinkDB->filterSearch($request, true, false))
441 * Test filterHash() with a valid smallhash.
443 public function testFilterHashValid()
445 $request = smallHash('20150310_114651');
448 count(self
::$publicLinkDB->filterHash($request))
450 $request = smallHash('20150310_114633' . 8);
453 count(self
::$publicLinkDB->filterHash($request))
458 * Test filterHash() with an invalid smallhash.
460 * @expectedException \Shaarli\Bookmark\Exception\LinkNotFoundException
462 public function testFilterHashInValid1()
465 self
::$publicLinkDB->filterHash($request);
469 * Test filterHash() with an empty smallhash.
471 * @expectedException \Shaarli\Bookmark\Exception\LinkNotFoundException
473 public function testFilterHashInValid()
475 self
::$publicLinkDB->filterHash('');
479 * Test reorder with asc/desc parameter.
481 public function testReorderLinksDesc()
483 self
::$privateLinkDB->reorder('ASC');
484 $stickyIds = [11, 10];
485 $standardIds = [42, 4, 9, 1, 0, 7, 6, 8, 41];
486 $linkIds = array_merge($stickyIds, $standardIds);
488 foreach (self
::$privateLinkDB as $key => $value) {
489 $this->assertEquals($linkIds[$cpt++
], $key);
491 self
::$privateLinkDB->reorder('DESC');
492 $linkIds = array_merge(array_reverse($stickyIds), array_reverse($standardIds));
494 foreach (self
::$privateLinkDB as $key => $value) {
495 $this->assertEquals($linkIds[$cpt++
], $key);
500 * Test rename tag with a valid value present in multiple links
502 public function testRenameTagMultiple()
504 self
::$refDB->write(self
::$testDatastore);
505 $linkDB = new LinkDB(self
::$testDatastore, true, false);
507 $res = $linkDB->renameTag('cartoon', 'Taz');
508 $this->assertEquals(3, count($res));
509 $this->assertContains(' Taz ', $linkDB[4]['tags']);
510 $this->assertContains(' Taz ', $linkDB[1]['tags']);
511 $this->assertContains(' Taz ', $linkDB[0]['tags']);
515 * Test rename tag with a valid value
517 public function testRenameTagCaseSensitive()
519 self
::$refDB->write(self
::$testDatastore);
520 $linkDB = new LinkDB(self
::$testDatastore, true, false, '');
522 $res = $linkDB->renameTag('sTuff', 'Taz');
523 $this->assertEquals(1, count($res));
524 $this->assertEquals('Taz', $linkDB[41]['tags']);
528 * Test rename tag with invalid values
530 public function testRenameTagInvalid()
532 $linkDB = new LinkDB(self
::$testDatastore, false, false);
534 $this->assertFalse($linkDB->renameTag('', 'test'));
535 $this->assertFalse($linkDB->renameTag('', ''));
537 $this->assertEquals([], $linkDB->renameTag('test', ''));
538 $this->assertEquals([], $linkDB->renameTag('test', 'retest'));
542 * Test delete tag with a valid value
544 public function testDeleteTag()
546 self
::$refDB->write(self
::$testDatastore);
547 $linkDB = new LinkDB(self
::$testDatastore, true, false);
549 $res = $linkDB->renameTag('cartoon', null);
550 $this->assertEquals(3, count($res));
551 $this->assertNotContains('cartoon', $linkDB[4]['tags']);
555 * Test linksCountPerTag all tags without filter.
556 * Equal occurrences should be sorted alphabetically.
558 public function testCountLinkPerTagAllNoFilter()
584 $tags = self
::$privateLinkDB->linksCountPerTag();
586 $this->assertEquals($expected, $tags, var_export($tags, true));
590 * Test linksCountPerTag all tags with filter.
591 * Equal occurrences should be sorted alphabetically.
593 public function testCountLinkPerTagAllWithFilter()
607 $tags = self
::$privateLinkDB->linksCountPerTag(['gnu']);
609 $this->assertEquals($expected, $tags, var_export($tags, true));
613 * Test linksCountPerTag public tags with filter.
614 * Equal occurrences should be sorted alphabetically.
616 public function testCountLinkPerTagPublicWithFilter()
630 $tags = self
::$privateLinkDB->linksCountPerTag(['gnu'], 'public');
632 $this->assertEquals($expected, $tags, var_export($tags, true));
636 * Test linksCountPerTag public tags with filter.
637 * Equal occurrences should be sorted alphabetically.
639 public function testCountLinkPerTagPrivateWithFilter()
649 $tags = self
::$privateLinkDB->linksCountPerTag(['dev'], 'private');
651 $this->assertEquals($expected, $tags, var_export($tags, true));