6 use Shaarli\Exceptions\IOException
;
8 require_once 'application/Cache.php';
9 require_once 'application/FileUtils.php';
10 require_once 'application/LinkDB.php';
11 require_once 'application/Utils.php';
12 require_once 'tests/utils/ReferenceLinkDB.php';
16 * Unitary tests for LinkDB
18 class LinkDBTest
extends PHPUnit_Framework_TestCase
20 // datastore to test write operations
21 protected static $testDatastore = 'sandbox/datastore.php';
24 * @var ReferenceLinkDB instance.
26 protected static $refDB = null;
29 * @var LinkDB public LinkDB instance.
31 protected static $publicLinkDB = null;
34 * @var LinkDB private LinkDB instance.
36 protected static $privateLinkDB = null;
39 * Instantiates public and private LinkDBs with test data
41 * The reference datastore contains public and private links that
42 * will be used to test LinkDB's methods:
43 * - access filtering (public/private),
50 public static function setUpBeforeClass()
52 self
::$refDB = new ReferenceLinkDB();
53 self
::$refDB->write(self
::$testDatastore);
55 self
::$publicLinkDB = new LinkDB(self
::$testDatastore, false, false);
56 self
::$privateLinkDB = new LinkDB(self
::$testDatastore, true, false);
60 * Resets test data for each test
62 protected function setUp()
64 if (file_exists(self
::$testDatastore)) {
65 unlink(self
::$testDatastore);
70 * Allows to test LinkDB's private methods
73 * https://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html
74 * http://stackoverflow.com/a/2798203
76 protected static function getMethod($name)
78 $class = new ReflectionClass('LinkDB');
79 $method = $class->getMethod($name);
80 $method->setAccessible(true);
85 * Instantiate LinkDB objects - logged in user
87 public function testConstructLoggedIn()
89 new LinkDB(self
::$testDatastore, true, false);
90 $this->assertFileExists(self
::$testDatastore);
94 * Instantiate LinkDB objects - logged out or public instance
96 public function testConstructLoggedOut()
98 new LinkDB(self
::$testDatastore, false, false);
99 $this->assertFileExists(self
::$testDatastore);
103 * Attempt to instantiate a LinkDB whereas the datastore is not writable
105 * @expectedException Shaarli\Exceptions\IOException
106 * @expectedExceptionMessageRegExp /Error accessing "null"/
108 public function testConstructDatastoreNotWriteable()
110 new LinkDB('null/store.db', false, false);
114 * The DB doesn't exist, ensure it is created with dummy content
116 public function testCheckDBNew()
118 $linkDB = new LinkDB(self
::$testDatastore, false, false);
119 unlink(self
::$testDatastore);
120 $this->assertFileNotExists(self
::$testDatastore);
122 $checkDB = self
::getMethod('check');
123 $checkDB->invokeArgs($linkDB, array());
124 $this->assertFileExists(self
::$testDatastore);
126 // ensure the correct data has been written
127 $this->assertGreaterThan(0, filesize(self
::$testDatastore));
131 * The DB exists, don't do anything
133 public function testCheckDBLoad()
135 $linkDB = new LinkDB(self
::$testDatastore, false, false);
136 $datastoreSize = filesize(self
::$testDatastore);
137 $this->assertGreaterThan(0, $datastoreSize);
139 $checkDB = self
::getMethod('check');
140 $checkDB->invokeArgs($linkDB, array());
142 // ensure the datastore is left unmodified
145 filesize(self
::$testDatastore)
152 public function testReadEmptyDB()
154 file_put_contents(self
::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
155 $emptyDB = new LinkDB(self
::$testDatastore, false, false);
156 $this->assertEquals(0, sizeof($emptyDB));
157 $this->assertEquals(0, count($emptyDB));
161 * Load public links from the DB
163 public function testReadPublicDB()
166 self
::$refDB->countPublicLinks(),
167 sizeof(self
::$publicLinkDB)
172 * Load public and private links from the DB
174 public function testReadPrivateDB()
177 self
::$refDB->countLinks(),
178 sizeof(self
::$privateLinkDB)
183 * Save the links to the DB
185 public function testSave()
187 $testDB = new LinkDB(self
::$testDatastore, true, false);
188 $dbSize = sizeof($testDB);
192 'title'=>'an additional link',
193 'url'=>'http://dum.my',
194 'description'=>'One more',
196 'created'=> DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20150518_190000'),
199 $testDB[$link['id']] = $link;
200 $testDB->save('tests');
202 $testDB = new LinkDB(self
::$testDatastore, true, false);
203 $this->assertEquals($dbSize +
1, sizeof($testDB));
207 * Count existing links
209 public function testCount()
212 self
::$refDB->countPublicLinks(),
213 self
::$publicLinkDB->count()
216 self
::$refDB->countLinks(),
217 self
::$privateLinkDB->count()
222 * Count existing links - public links hidden
224 public function testCountHiddenPublic()
226 $linkDB = new LinkDB(self
::$testDatastore, false, true);
239 * List the days for which links have been posted
241 public function testDays()
244 array('20100309', '20100310', '20121206', '20121207', '20130614', '20150310'),
245 self
::$publicLinkDB->days()
249 array('20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'),
250 self
::$privateLinkDB->days()
255 * The URL corresponds to an existing entry in the DB
257 public function testGetKnownLinkFromURL()
259 $link = self
::$publicLinkDB->getLinkFromUrl('http://mediagoblin.org/');
261 $this->assertNotEquals(false, $link);
262 $this->assertContains(
263 'A free software media publishing platform',
269 * The URL is not in the DB
271 public function testGetUnknownLinkFromURL()
275 self
::$publicLinkDB->getLinkFromUrl('http://dev.null')
282 public function testAllTags()
297 // The DB contains a link with `sTuff` and another one with `stuff` tag.
298 // They need to be grouped with the first case found - order by date DESC: `sTuff`.
302 self
::$publicLinkDB->linksCountPerTag()
330 self
::$privateLinkDB->linksCountPerTag()
347 self
::$privateLinkDB->linksCountPerTag(['web'])
357 self
::$privateLinkDB->linksCountPerTag(['web'], 'private')
362 * Test real_url without redirector.
364 public function testLinkRealUrlWithoutRedirector()
366 $db = new LinkDB(self
::$testDatastore, false, false);
367 foreach ($db as $link) {
368 $this->assertEquals($link['url'], $link['real_url']);
373 * Test real_url with redirector.
375 public function testLinkRealUrlWithRedirector()
377 $redirector = 'http://redirector.to?';
378 $db = new LinkDB(self
::$testDatastore, false, false, $redirector);
379 foreach ($db as $link) {
380 $this->assertStringStartsWith($redirector, $link['real_url']);
381 $this->assertNotFalse(strpos($link['real_url'], urlencode('://')));
384 $db = new LinkDB(self
::$testDatastore, false, false, $redirector, false);
385 foreach ($db as $link) {
386 $this->assertStringStartsWith($redirector, $link['real_url']);
387 $this->assertFalse(strpos($link['real_url'], urlencode('://')));
392 * Test filter with string.
394 public function testFilterString()
396 $tags = 'dev cartoon';
397 $request = array('searchtags' => $tags);
400 count(self
::$privateLinkDB->filterSearch($request, true, false))
405 * Test filter with string.
407 public function testFilterArray()
409 $tags = array('dev', 'cartoon');
410 $request = array('searchtags' => $tags);
413 count(self
::$privateLinkDB->filterSearch($request, true, false))
418 * Test hidden tags feature:
419 * tags starting with a dot '.' are only visible when logged in.
421 public function testHiddenTags()
424 $request = array('searchtags' => $tags);
427 count(self
::$privateLinkDB->filterSearch($request, true, false))
432 count(self
::$publicLinkDB->filterSearch($request, true, false))
437 * Test filterHash() with a valid smallhash.
439 public function testFilterHashValid()
441 $request = smallHash('20150310_114651');
444 count(self
::$publicLinkDB->filterHash($request))
446 $request = smallHash('20150310_114633' . 8);
449 count(self
::$publicLinkDB->filterHash($request))
454 * Test filterHash() with an invalid smallhash.
456 * @expectedException LinkNotFoundException
458 public function testFilterHashInValid1()
461 self
::$publicLinkDB->filterHash($request);
465 * Test filterHash() with an empty smallhash.
467 * @expectedException LinkNotFoundException
469 public function testFilterHashInValid()
471 self
::$publicLinkDB->filterHash('');
475 * Test reorder with asc/desc parameter.
477 public function testReorderLinksDesc()
479 self
::$privateLinkDB->reorder('ASC');
480 $stickyIds = [11, 10];
481 $standardIds = [42, 4, 9, 1, 0, 7, 6, 8, 41];
482 $linkIds = array_merge($stickyIds, $standardIds);
484 foreach (self
::$privateLinkDB as $key => $value) {
485 $this->assertEquals($linkIds[$cpt++
], $key);
487 self
::$privateLinkDB->reorder('DESC');
488 $linkIds = array_merge(array_reverse($stickyIds), array_reverse($standardIds));
490 foreach (self
::$privateLinkDB as $key => $value) {
491 $this->assertEquals($linkIds[$cpt++
], $key);
496 * Test rename tag with a valid value present in multiple links
498 public function testRenameTagMultiple()
500 self
::$refDB->write(self
::$testDatastore);
501 $linkDB = new LinkDB(self
::$testDatastore, true, false);
503 $res = $linkDB->renameTag('cartoon', 'Taz');
504 $this->assertEquals(3, count($res));
505 $this->assertContains(' Taz ', $linkDB[4]['tags']);
506 $this->assertContains(' Taz ', $linkDB[1]['tags']);
507 $this->assertContains(' Taz ', $linkDB[0]['tags']);
511 * Test rename tag with a valid value
513 public function testRenameTagCaseSensitive()
515 self
::$refDB->write(self
::$testDatastore);
516 $linkDB = new LinkDB(self
::$testDatastore, true, false, '');
518 $res = $linkDB->renameTag('sTuff', 'Taz');
519 $this->assertEquals(1, count($res));
520 $this->assertEquals('Taz', $linkDB[41]['tags']);
524 * Test rename tag with invalid values
526 public function testRenameTagInvalid()
528 $linkDB = new LinkDB(self
::$testDatastore, false, false);
530 $this->assertFalse($linkDB->renameTag('', 'test'));
531 $this->assertFalse($linkDB->renameTag('', ''));
533 $this->assertEquals([], $linkDB->renameTag('test', ''));
534 $this->assertEquals([], $linkDB->renameTag('test', 'retest'));
538 * Test delete tag with a valid value
540 public function testDeleteTag()
542 self
::$refDB->write(self
::$testDatastore);
543 $linkDB = new LinkDB(self
::$testDatastore, true, false);
545 $res = $linkDB->renameTag('cartoon', null);
546 $this->assertEquals(3, count($res));
547 $this->assertNotContains('cartoon', $linkDB[4]['tags']);
551 * Test linksCountPerTag all tags without filter.
552 * Equal occurrences should be sorted alphabetically.
554 public function testCountLinkPerTagAllNoFilter()
580 $tags = self
::$privateLinkDB->linksCountPerTag();
582 $this->assertEquals($expected, $tags, var_export($tags, true));
586 * Test linksCountPerTag all tags with filter.
587 * Equal occurrences should be sorted alphabetically.
589 public function testCountLinkPerTagAllWithFilter()
603 $tags = self
::$privateLinkDB->linksCountPerTag(['gnu']);
605 $this->assertEquals($expected, $tags, var_export($tags, true));
609 * Test linksCountPerTag public tags with filter.
610 * Equal occurrences should be sorted alphabetically.
612 public function testCountLinkPerTagPublicWithFilter()
626 $tags = self
::$privateLinkDB->linksCountPerTag(['gnu'], 'public');
628 $this->assertEquals($expected, $tags, var_export($tags, true));
632 * Test linksCountPerTag public tags with filter.
633 * Equal occurrences should be sorted alphabetically.
635 public function testCountLinkPerTagPrivateWithFilter()
645 $tags = self
::$privateLinkDB->linksCountPerTag(['dev'], 'private');
647 $this->assertEquals($expected, $tags, var_export($tags, true));