]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - tests/legacy/LegacyLinkDBTest.php
add search highlight unit tests
[github/shaarli/Shaarli.git] / tests / legacy / LegacyLinkDBTest.php
CommitLineData
ca74886f
V
1<?php
2/**
3 * Link datastore tests
4 */
5
e26e2060 6namespace Shaarli\Legacy;
f24896b2
V
7
8use DateTime;
f24896b2
V
9use ReferenceLinkDB;
10use ReflectionClass;
11use Shaarli;
e26e2060 12use Shaarli\Bookmark\Bookmark;
f24896b2 13
ca74886f
V
14require_once 'application/Utils.php';
15require_once 'tests/utils/ReferenceLinkDB.php';
16
ca74886f
V
17
18/**
e26e2060 19 * Unitary tests for LegacyLinkDBTest
ca74886f 20 */
a5a9cf23 21class LegacyLinkDBTest extends \Shaarli\TestCase
ca74886f
V
22{
23 // datastore to test write operations
4bf35ba5 24 protected static $testDatastore = 'sandbox/datastore.php';
528a6f8a
A
25
26 /**
27 * @var ReferenceLinkDB instance.
28 */
ca74886f 29 protected static $refDB = null;
528a6f8a
A
30
31 /**
e26e2060 32 * @var LegacyLinkDB public LinkDB instance.
528a6f8a 33 */
ca74886f 34 protected static $publicLinkDB = null;
528a6f8a
A
35
36 /**
e26e2060 37 * @var LegacyLinkDB private LinkDB instance.
528a6f8a 38 */
ca74886f
V
39 protected static $privateLinkDB = null;
40
41 /**
42 * Instantiates public and private LinkDBs with test data
43 *
e26e2060 44 * The reference datastore contains public and private bookmarks that
ca74886f
V
45 * will be used to test LinkDB's methods:
46 * - access filtering (public/private),
47 * - link searches:
48 * - by day,
49 * - by tag,
50 * - by text,
51 * - etc.
bd1adc8d 52 *
ca74886f
V
53 * Resets test data for each test
54 */
8f60e120 55 protected function setUp(): void
ca74886f 56 {
ca74886f
V
57 if (file_exists(self::$testDatastore)) {
58 unlink(self::$testDatastore);
59 }
bd1adc8d 60
e26e2060 61 self::$refDB = new ReferenceLinkDB(true);
bd1adc8d 62 self::$refDB->write(self::$testDatastore);
e26e2060
A
63 self::$publicLinkDB = new LegacyLinkDB(self::$testDatastore, false, false);
64 self::$privateLinkDB = new LegacyLinkDB(self::$testDatastore, true, false);
ca74886f
V
65 }
66
67 /**
68 * Allows to test LinkDB's private methods
69 *
70 * @see
71 * https://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html
72 * http://stackoverflow.com/a/2798203
73 */
74 protected static function getMethod($name)
75 {
e26e2060 76 $class = new ReflectionClass('Shaarli\Legacy\LegacyLinkDB');
ca74886f
V
77 $method = $class->getMethod($name);
78 $method->setAccessible(true);
79 return $method;
80 }
81
82 /**
83 * Instantiate LinkDB objects - logged in user
84 */
85 public function testConstructLoggedIn()
86 {
e26e2060 87 new LegacyLinkDB(self::$testDatastore, true, false);
ca74886f
V
88 $this->assertFileExists(self::$testDatastore);
89 }
90
91 /**
92 * Instantiate LinkDB objects - logged out or public instance
93 */
94 public function testConstructLoggedOut()
95 {
e26e2060 96 new LegacyLinkDB(self::$testDatastore, false, false);
ca74886f
V
97 $this->assertFileExists(self::$testDatastore);
98 }
99
100 /**
101 * Attempt to instantiate a LinkDB whereas the datastore is not writable
ca74886f
V
102 */
103 public function testConstructDatastoreNotWriteable()
104 {
f447edb7 105 $this->expectException(\Shaarli\Exceptions\IOException::class);
b1baca99
A
106 $this->expectExceptionMessageRegExp('/Error accessing "null"/');
107
e26e2060 108 new LegacyLinkDB('null/store.db', false, false);
ca74886f
V
109 }
110
111 /**
112 * The DB doesn't exist, ensure it is created with dummy content
113 */
114 public function testCheckDBNew()
115 {
e26e2060 116 $linkDB = new LegacyLinkDB(self::$testDatastore, false, false);
ca74886f
V
117 unlink(self::$testDatastore);
118 $this->assertFileNotExists(self::$testDatastore);
119
f21abf32 120 $checkDB = self::getMethod('check');
ca74886f
V
121 $checkDB->invokeArgs($linkDB, array());
122 $this->assertFileExists(self::$testDatastore);
123
124 // ensure the correct data has been written
0037fbe1 125 $this->assertGreaterThan(0, filesize(self::$testDatastore));
ca74886f
V
126 }
127
128 /**
129 * The DB exists, don't do anything
130 */
131 public function testCheckDBLoad()
132 {
e26e2060 133 $linkDB = new LegacyLinkDB(self::$testDatastore, false, false);
0037fbe1
V
134 $datastoreSize = filesize(self::$testDatastore);
135 $this->assertGreaterThan(0, $datastoreSize);
ca74886f 136
f21abf32 137 $checkDB = self::getMethod('check');
ca74886f
V
138 $checkDB->invokeArgs($linkDB, array());
139
140 // ensure the datastore is left unmodified
141 $this->assertEquals(
0037fbe1 142 $datastoreSize,
30e6f1ca 143 filesize(self::$testDatastore)
ca74886f
V
144 );
145 }
146
147 /**
148 * Load an empty DB
149 */
150 public function testReadEmptyDB()
151 {
9c8752a2 152 file_put_contents(self::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
e26e2060 153 $emptyDB = new LegacyLinkDB(self::$testDatastore, false, false);
ca74886f
V
154 $this->assertEquals(0, sizeof($emptyDB));
155 $this->assertEquals(0, count($emptyDB));
156 }
157
158 /**
e26e2060 159 * Load public bookmarks from the DB
ca74886f
V
160 */
161 public function testReadPublicDB()
162 {
163 $this->assertEquals(
164 self::$refDB->countPublicLinks(),
165 sizeof(self::$publicLinkDB)
166 );
167 }
168
169 /**
e26e2060 170 * Load public and private bookmarks from the DB
ca74886f
V
171 */
172 public function testReadPrivateDB()
173 {
174 $this->assertEquals(
175 self::$refDB->countLinks(),
176 sizeof(self::$privateLinkDB)
177 );
178 }
179
180 /**
e26e2060 181 * Save the bookmarks to the DB
ca74886f 182 */
f21abf32 183 public function testSave()
ca74886f 184 {
e26e2060 185 $testDB = new LegacyLinkDB(self::$testDatastore, true, false);
ca74886f
V
186 $dbSize = sizeof($testDB);
187
188 $link = array(
bd1adc8d 189 'id' => 43,
f24896b2
V
190 'title' => 'an additional link',
191 'url' => 'http://dum.my',
192 'description' => 'One more',
193 'private' => 0,
e26e2060 194 'created' => DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150518_190000'),
f24896b2 195 'tags' => 'unit test'
ca74886f 196 );
c3dfd899 197 $testDB[$link['id']] = $link;
f21abf32 198 $testDB->save('tests');
ca74886f 199
e26e2060 200 $testDB = new LegacyLinkDB(self::$testDatastore, true, false);
ca74886f
V
201 $this->assertEquals($dbSize + 1, sizeof($testDB));
202 }
203
204 /**
e26e2060 205 * Count existing bookmarks
ca74886f
V
206 */
207 public function testCount()
208 {
209 $this->assertEquals(
210 self::$refDB->countPublicLinks(),
211 self::$publicLinkDB->count()
212 );
213 $this->assertEquals(
214 self::$refDB->countLinks(),
215 self::$privateLinkDB->count()
216 );
217 }
218
9f15ca9e 219 /**
e26e2060 220 * Count existing bookmarks - public bookmarks hidden
9f15ca9e
V
221 */
222 public function testCountHiddenPublic()
223 {
e26e2060 224 $linkDB = new LegacyLinkDB(self::$testDatastore, false, true);
9f15ca9e
V
225
226 $this->assertEquals(
227 0,
228 $linkDB->count()
229 );
230 $this->assertEquals(
231 0,
232 $linkDB->count()
233 );
234 }
235
ca74886f 236 /**
e26e2060 237 * List the days for which bookmarks have been posted
ca74886f
V
238 */
239 public function testDays()
240 {
241 $this->assertEquals(
4154c25b 242 array('20100309', '20100310', '20121206', '20121207', '20130614', '20150310'),
ca74886f
V
243 self::$publicLinkDB->days()
244 );
245
246 $this->assertEquals(
4154c25b 247 array('20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'),
ca74886f
V
248 self::$privateLinkDB->days()
249 );
250 }
251
252 /**
253 * The URL corresponds to an existing entry in the DB
254 */
255 public function testGetKnownLinkFromURL()
256 {
257 $link = self::$publicLinkDB->getLinkFromUrl('http://mediagoblin.org/');
258
259 $this->assertNotEquals(false, $link);
a5a9cf23 260 $this->assertContainsPolyfill(
ca74886f
V
261 'A free software media publishing platform',
262 $link['description']
263 );
264 }
265
266 /**
267 * The URL is not in the DB
268 */
269 public function testGetUnknownLinkFromURL()
270 {
271 $this->assertEquals(
272 false,
273 self::$publicLinkDB->getLinkFromUrl('http://dev.null')
274 );
275 }
276
277 /**
278 * Lists all tags
279 */
280 public function testAllTags()
281 {
282 $this->assertEquals(
d1e2f8e5 283 array(
ca74886f
V
284 'web' => 3,
285 'cartoon' => 2,
286 'gnu' => 2,
287 'dev' => 1,
288 'samba' => 1,
289 'media' => 1,
290 'software' => 1,
291 'stallman' => 1,
21979ff1
A
292 'free' => 1,
293 '-exclude' => 1,
c3dfd899 294 'hashtag' => 2,
b1eb5d1d 295 // The DB contains a link with `sTuff` and another one with `stuff` tag.
c3dfd899 296 // They need to be grouped with the first case found - order by date DESC: `sTuff`.
b1eb5d1d 297 'sTuff' => 2,
c3dfd899 298 'ut' => 1,
f1a148ab
A
299 'assurance' => 1,
300 'coding-style' => 1,
301 'quality' => 1,
302 'standards' => 1,
d1e2f8e5 303 ),
6ccd0b21 304 self::$publicLinkDB->linksCountPerTag()
ca74886f
V
305 );
306
307 $this->assertEquals(
d1e2f8e5 308 array(
ca74886f
V
309 'web' => 4,
310 'cartoon' => 3,
311 'gnu' => 2,
312 'dev' => 2,
313 'samba' => 1,
314 'media' => 1,
315 'software' => 1,
316 'stallman' => 1,
317 'free' => 1,
318 'html' => 1,
319 'w3c' => 1,
320 'css' => 1,
21979ff1 321 'Mercurial' => 1,
b1eb5d1d 322 'sTuff' => 2,
21979ff1 323 '-exclude' => 1,
195acf9f 324 '.hidden' => 1,
9ccca401 325 'hashtag' => 2,
9866b408
A
326 'tag1' => 1,
327 'tag2' => 1,
328 'tag3' => 1,
329 'tag4' => 1,
c3dfd899 330 'ut' => 1,
f1a148ab
A
331 'assurance' => 1,
332 'coding-style' => 1,
333 'quality' => 1,
334 'standards' => 1,
d1e2f8e5 335 ),
6ccd0b21
LC
336 self::$privateLinkDB->linksCountPerTag()
337 );
338 $this->assertEquals(
339 array(
340 'web' => 4,
341 'cartoon' => 2,
342 'gnu' => 1,
343 'dev' => 1,
344 'samba' => 1,
345 'media' => 1,
346 'html' => 1,
347 'w3c' => 1,
348 'css' => 1,
349 'Mercurial' => 1,
350 '.hidden' => 1,
351 'hashtag' => 1,
352 ),
353 self::$privateLinkDB->linksCountPerTag(['web'])
354 );
355 $this->assertEquals(
356 array(
357 'web' => 1,
358 'html' => 1,
359 'w3c' => 1,
360 'css' => 1,
361 'Mercurial' => 1,
362 ),
363 self::$privateLinkDB->linksCountPerTag(['web'], 'private')
ca74886f
V
364 );
365 }
366
ca74886f 367 /**
822bffce 368 * Test filter with string.
ca74886f 369 */
822bffce 370 public function testFilterString()
ca74886f 371 {
822bffce 372 $tags = 'dev cartoon';
528a6f8a 373 $request = array('searchtags' => $tags);
ca74886f
V
374 $this->assertEquals(
375 2,
528a6f8a 376 count(self::$privateLinkDB->filterSearch($request, true, false))
ca74886f
V
377 );
378 }
379
380 /**
822bffce 381 * Test filter with string.
ca74886f 382 */
822bffce 383 public function testFilterArray()
ca74886f 384 {
822bffce 385 $tags = array('dev', 'cartoon');
528a6f8a 386 $request = array('searchtags' => $tags);
ca74886f
V
387 $this->assertEquals(
388 2,
528a6f8a 389 count(self::$privateLinkDB->filterSearch($request, true, false))
ca74886f
V
390 );
391 }
195acf9f
A
392
393 /**
394 * Test hidden tags feature:
395 * tags starting with a dot '.' are only visible when logged in.
396 */
397 public function testHiddenTags()
398 {
399 $tags = '.hidden';
528a6f8a 400 $request = array('searchtags' => $tags);
195acf9f
A
401 $this->assertEquals(
402 1,
528a6f8a 403 count(self::$privateLinkDB->filterSearch($request, true, false))
195acf9f
A
404 );
405
406 $this->assertEquals(
407 0,
528a6f8a 408 count(self::$publicLinkDB->filterSearch($request, true, false))
195acf9f
A
409 );
410 }
528a6f8a
A
411
412 /**
413 * Test filterHash() with a valid smallhash.
414 */
415 public function testFilterHashValid()
416 {
417 $request = smallHash('20150310_114651');
418 $this->assertEquals(
419 1,
420 count(self::$publicLinkDB->filterHash($request))
421 );
c3dfd899
A
422 $request = smallHash('20150310_114633' . 8);
423 $this->assertEquals(
424 1,
425 count(self::$publicLinkDB->filterHash($request))
426 );
528a6f8a
A
427 }
428
429 /**
430 * Test filterHash() with an invalid smallhash.
528a6f8a
A
431 */
432 public function testFilterHashInValid1()
433 {
b1baca99
A
434 $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
435
528a6f8a
A
436 $request = 'blabla';
437 self::$publicLinkDB->filterHash($request);
438 }
439
440 /**
441 * Test filterHash() with an empty smallhash.
528a6f8a
A
442 */
443 public function testFilterHashInValid()
444 {
b1baca99
A
445 $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
446
528a6f8a
A
447 self::$publicLinkDB->filterHash('');
448 }
c3dfd899
A
449
450 /**
451 * Test reorder with asc/desc parameter.
452 */
453 public function testReorderLinksDesc()
454 {
d592daea 455 self::$privateLinkDB->reorder('ASC');
4154c25b
A
456 $stickyIds = [11, 10];
457 $standardIds = [42, 4, 9, 1, 0, 7, 6, 8, 41];
458 $linkIds = array_merge($stickyIds, $standardIds);
d592daea
A
459 $cpt = 0;
460 foreach (self::$privateLinkDB as $key => $value) {
461 $this->assertEquals($linkIds[$cpt++], $key);
c3dfd899 462 }
d592daea 463 self::$privateLinkDB->reorder('DESC');
4154c25b 464 $linkIds = array_merge(array_reverse($stickyIds), array_reverse($standardIds));
d592daea
A
465 $cpt = 0;
466 foreach (self::$privateLinkDB as $key => $value) {
467 $this->assertEquals($linkIds[$cpt++], $key);
c3dfd899
A
468 }
469 }
3b67b222
A
470
471 /**
e26e2060 472 * Test rename tag with a valid value present in multiple bookmarks
3b67b222
A
473 */
474 public function testRenameTagMultiple()
475 {
476 self::$refDB->write(self::$testDatastore);
e26e2060 477 $linkDB = new LegacyLinkDB(self::$testDatastore, true, false);
3b67b222
A
478
479 $res = $linkDB->renameTag('cartoon', 'Taz');
480 $this->assertEquals(3, count($res));
a5a9cf23
A
481 $this->assertContainsPolyfill(' Taz ', $linkDB[4]['tags']);
482 $this->assertContainsPolyfill(' Taz ', $linkDB[1]['tags']);
483 $this->assertContainsPolyfill(' Taz ', $linkDB[0]['tags']);
3b67b222
A
484 }
485
486 /**
487 * Test rename tag with a valid value
488 */
489 public function testRenameTagCaseSensitive()
490 {
491 self::$refDB->write(self::$testDatastore);
e26e2060 492 $linkDB = new LegacyLinkDB(self::$testDatastore, true, false);
3b67b222
A
493
494 $res = $linkDB->renameTag('sTuff', 'Taz');
495 $this->assertEquals(1, count($res));
496 $this->assertEquals('Taz', $linkDB[41]['tags']);
497 }
498
499 /**
500 * Test rename tag with invalid values
501 */
502 public function testRenameTagInvalid()
503 {
e26e2060 504 $linkDB = new LegacyLinkDB(self::$testDatastore, false, false);
3b67b222
A
505
506 $this->assertFalse($linkDB->renameTag('', 'test'));
507 $this->assertFalse($linkDB->renameTag('', ''));
508 // tag non existent
509 $this->assertEquals([], $linkDB->renameTag('test', ''));
510 $this->assertEquals([], $linkDB->renameTag('test', 'retest'));
511 }
512
513 /**
514 * Test delete tag with a valid value
515 */
516 public function testDeleteTag()
517 {
518 self::$refDB->write(self::$testDatastore);
e26e2060 519 $linkDB = new LegacyLinkDB(self::$testDatastore, true, false);
3b67b222
A
520
521 $res = $linkDB->renameTag('cartoon', null);
522 $this->assertEquals(3, count($res));
a5a9cf23 523 $this->assertNotContainsPolyfill('cartoon', $linkDB[4]['tags']);
3b67b222 524 }
f8c5660d
A
525
526 /**
527 * Test linksCountPerTag all tags without filter.
528 * Equal occurrences should be sorted alphabetically.
529 */
530 public function testCountLinkPerTagAllNoFilter()
531 {
532 $expected = [
533 'web' => 4,
534 'cartoon' => 3,
535 'dev' => 2,
536 'gnu' => 2,
537 'hashtag' => 2,
538 'sTuff' => 2,
539 '-exclude' => 1,
540 '.hidden' => 1,
541 'Mercurial' => 1,
542 'css' => 1,
543 'free' => 1,
544 'html' => 1,
545 'media' => 1,
546 'samba' => 1,
547 'software' => 1,
548 'stallman' => 1,
549 'tag1' => 1,
550 'tag2' => 1,
551 'tag3' => 1,
552 'tag4' => 1,
553 'ut' => 1,
554 'w3c' => 1,
f1a148ab
A
555 'assurance' => 1,
556 'coding-style' => 1,
557 'quality' => 1,
558 'standards' => 1,
f8c5660d
A
559 ];
560 $tags = self::$privateLinkDB->linksCountPerTag();
561
562 $this->assertEquals($expected, $tags, var_export($tags, true));
563 }
564
565 /**
566 * Test linksCountPerTag all tags with filter.
567 * Equal occurrences should be sorted alphabetically.
568 */
569 public function testCountLinkPerTagAllWithFilter()
570 {
571 $expected = [
572 'gnu' => 2,
573 'hashtag' => 2,
574 '-exclude' => 1,
575 '.hidden' => 1,
576 'free' => 1,
577 'media' => 1,
578 'software' => 1,
579 'stallman' => 1,
580 'stuff' => 1,
581 'web' => 1,
582 ];
583 $tags = self::$privateLinkDB->linksCountPerTag(['gnu']);
584
585 $this->assertEquals($expected, $tags, var_export($tags, true));
586 }
587
588 /**
589 * Test linksCountPerTag public tags with filter.
590 * Equal occurrences should be sorted alphabetically.
591 */
592 public function testCountLinkPerTagPublicWithFilter()
593 {
594 $expected = [
595 'gnu' => 2,
596 'hashtag' => 2,
597 '-exclude' => 1,
598 '.hidden' => 1,
599 'free' => 1,
600 'media' => 1,
601 'software' => 1,
602 'stallman' => 1,
603 'stuff' => 1,
604 'web' => 1,
605 ];
606 $tags = self::$privateLinkDB->linksCountPerTag(['gnu'], 'public');
607
608 $this->assertEquals($expected, $tags, var_export($tags, true));
609 }
610
611 /**
612 * Test linksCountPerTag public tags with filter.
613 * Equal occurrences should be sorted alphabetically.
614 */
615 public function testCountLinkPerTagPrivateWithFilter()
616 {
617 $expected = [
618 'cartoon' => 1,
619 'dev' => 1,
620 'tag1' => 1,
621 'tag2' => 1,
622 'tag3' => 1,
623 'tag4' => 1,
624 ];
625 $tags = self::$privateLinkDB->linksCountPerTag(['dev'], 'private');
626
627 $this->assertEquals($expected, $tags, var_export($tags, true));
628 }
9f962705
A
629
630 /**
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.
633 */
634 public function testConsistentOrder()
635 {
bd1adc8d 636 $nextId = 43;
9f962705 637 $creation = DateTime::createFromFormat('Ymd_His', '20190807_130444');
e26e2060 638 $linkDB = new LegacyLinkDB(self::$testDatastore, true, false);
9f962705
A
639 for ($i = 0; $i < 4; ++$i) {
640 $linkDB[$nextId + $i] = [
641 'id' => $nextId + $i,
642 'url' => 'http://'. $i,
643 'created' => $creation,
644 'title' => true,
645 'description' => true,
646 'tags' => true,
647 ];
648 }
649
650 // Check 4 new links 4 times
651 for ($i = 0; $i < 4; ++$i) {
652 $linkDB->save('tests');
e26e2060 653 $linkDB = new LegacyLinkDB(self::$testDatastore, true, false);
9f962705
A
654 $count = 3;
655 foreach ($linkDB as $link) {
bd1adc8d
A
656 if ($link['sticky'] === true) {
657 continue;
658 }
9f962705
A
659 $this->assertEquals($nextId + $count, $link['id']);
660 $this->assertEquals('http://'. $count, $link['url']);
661 if (--$count < 0) {
662 break;
663 }
664 }
665 }
666 }
ca74886f 667}