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