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