]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - tests/LinkDBTest.php
lint: apply phpcbf to tests/
[github/shaarli/Shaarli.git] / tests / LinkDBTest.php
CommitLineData
ca74886f
V
1<?php
2/**
3 * Link datastore tests
4 */
5
01e48f26 6require_once 'application/Cache.php';
2e28269b 7require_once 'application/FileUtils.php';
ca74886f
V
8require_once 'application/LinkDB.php';
9require_once 'application/Utils.php';
10require_once 'tests/utils/ReferenceLinkDB.php';
11
ca74886f
V
12
13/**
14 * Unitary tests for LinkDB
15 */
16class LinkDBTest extends PHPUnit_Framework_TestCase
17{
18 // datastore to test write operations
4bf35ba5 19 protected static $testDatastore = 'sandbox/datastore.php';
528a6f8a
A
20
21 /**
22 * @var ReferenceLinkDB instance.
23 */
ca74886f 24 protected static $refDB = null;
528a6f8a
A
25
26 /**
27 * @var LinkDB public LinkDB instance.
28 */
ca74886f 29 protected static $publicLinkDB = null;
528a6f8a
A
30
31 /**
32 * @var LinkDB private LinkDB instance.
33 */
ca74886f
V
34 protected static $privateLinkDB = null;
35
36 /**
37 * Instantiates public and private LinkDBs with test data
38 *
39 * The reference datastore contains public and private links that
40 * will be used to test LinkDB's methods:
41 * - access filtering (public/private),
42 * - link searches:
43 * - by day,
44 * - by tag,
45 * - by text,
46 * - etc.
47 */
48 public static function setUpBeforeClass()
49 {
50 self::$refDB = new ReferenceLinkDB();
9c8752a2 51 self::$refDB->write(self::$testDatastore);
ca74886f 52
9c8752a2
V
53 self::$publicLinkDB = new LinkDB(self::$testDatastore, false, false);
54 self::$privateLinkDB = new LinkDB(self::$testDatastore, true, false);
ca74886f
V
55 }
56
57 /**
58 * Resets test data for each test
59 */
60 protected function setUp()
61 {
ca74886f
V
62 if (file_exists(self::$testDatastore)) {
63 unlink(self::$testDatastore);
64 }
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('LinkDB');
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 {
9c8752a2 87 new LinkDB(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 {
9c8752a2 96 new LinkDB(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 *
2e28269b 103 * @expectedException IOException
b2306b0c 104 * @expectedExceptionMessageRegExp /Error accessing "null"/
ca74886f
V
105 */
106 public function testConstructDatastoreNotWriteable()
107 {
9c8752a2 108 new LinkDB('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 {
9c8752a2 116 $linkDB = new LinkDB(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 {
9c8752a2 133 $linkDB = new LinkDB(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
V
152 file_put_contents(self::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
153 $emptyDB = new LinkDB(self::$testDatastore, false, false);
ca74886f
V
154 $this->assertEquals(0, sizeof($emptyDB));
155 $this->assertEquals(0, count($emptyDB));
156 }
157
158 /**
159 * Load public links 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 links 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 links to the DB
182 */
f21abf32 183 public function testSave()
ca74886f 184 {
9c8752a2 185 $testDB = new LinkDB(self::$testDatastore, true, false);
ca74886f
V
186 $dbSize = sizeof($testDB);
187
188 $link = array(
c3dfd899 189 'id' => 42,
ca74886f
V
190 'title'=>'an additional link',
191 'url'=>'http://dum.my',
192 'description'=>'One more',
193 'private'=>0,
d592daea 194 'created'=> DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150518_190000'),
ca74886f
V
195 'tags'=>'unit test'
196 );
c3dfd899 197 $testDB[$link['id']] = $link;
f21abf32 198 $testDB->save('tests');
ca74886f 199
9c8752a2 200 $testDB = new LinkDB(self::$testDatastore, true, false);
ca74886f
V
201 $this->assertEquals($dbSize + 1, sizeof($testDB));
202 }
203
204 /**
205 * Count existing links
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
V
219 /**
220 * Count existing links - public links hidden
221 */
222 public function testCountHiddenPublic()
223 {
9c8752a2 224 $linkDB = new LinkDB(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
V
236 /**
237 * List the days for which links have been posted
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);
9ccca401 260 $this->assertContains(
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,
d1e2f8e5 299 ),
6ccd0b21 300 self::$publicLinkDB->linksCountPerTag()
ca74886f
V
301 );
302
303 $this->assertEquals(
d1e2f8e5 304 array(
ca74886f
V
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,
21979ff1 317 'Mercurial' => 1,
b1eb5d1d 318 'sTuff' => 2,
21979ff1 319 '-exclude' => 1,
195acf9f 320 '.hidden' => 1,
9ccca401 321 'hashtag' => 2,
9866b408
A
322 'tag1' => 1,
323 'tag2' => 1,
324 'tag3' => 1,
325 'tag4' => 1,
c3dfd899 326 'ut' => 1,
d1e2f8e5 327 ),
6ccd0b21
LC
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')
ca74886f
V
356 );
357 }
358
359 /**
822bffce 360 * Test real_url without redirector.
ca74886f 361 */
822bffce 362 public function testLinkRealUrlWithoutRedirector()
ca74886f 363 {
822bffce 364 $db = new LinkDB(self::$testDatastore, false, false);
067c2dd8 365 foreach ($db as $link) {
822bffce
A
366 $this->assertEquals($link['url'], $link['real_url']);
367 }
ca74886f
V
368 }
369
370 /**
822bffce 371 * Test real_url with redirector.
ca74886f 372 */
822bffce 373 public function testLinkRealUrlWithRedirector()
ca74886f 374 {
822bffce
A
375 $redirector = 'http://redirector.to?';
376 $db = new LinkDB(self::$testDatastore, false, false, $redirector);
067c2dd8 377 foreach ($db as $link) {
822bffce 378 $this->assertStringStartsWith($redirector, $link['real_url']);
043eae70
A
379 $this->assertNotFalse(strpos($link['real_url'], urlencode('://')));
380 }
381
382 $db = new LinkDB(self::$testDatastore, false, false, $redirector, false);
067c2dd8 383 foreach ($db as $link) {
043eae70
A
384 $this->assertStringStartsWith($redirector, $link['real_url']);
385 $this->assertFalse(strpos($link['real_url'], urlencode('://')));
822bffce 386 }
ca74886f
V
387 }
388
389 /**
822bffce 390 * Test filter with string.
ca74886f 391 */
822bffce 392 public function testFilterString()
ca74886f 393 {
822bffce 394 $tags = 'dev cartoon';
528a6f8a 395 $request = array('searchtags' => $tags);
ca74886f
V
396 $this->assertEquals(
397 2,
528a6f8a 398 count(self::$privateLinkDB->filterSearch($request, true, false))
ca74886f
V
399 );
400 }
401
402 /**
822bffce 403 * Test filter with string.
ca74886f 404 */
822bffce 405 public function testFilterArray()
ca74886f 406 {
822bffce 407 $tags = array('dev', 'cartoon');
528a6f8a 408 $request = array('searchtags' => $tags);
ca74886f
V
409 $this->assertEquals(
410 2,
528a6f8a 411 count(self::$privateLinkDB->filterSearch($request, true, false))
ca74886f
V
412 );
413 }
195acf9f
A
414
415 /**
416 * Test hidden tags feature:
417 * tags starting with a dot '.' are only visible when logged in.
418 */
419 public function testHiddenTags()
420 {
421 $tags = '.hidden';
528a6f8a 422 $request = array('searchtags' => $tags);
195acf9f
A
423 $this->assertEquals(
424 1,
528a6f8a 425 count(self::$privateLinkDB->filterSearch($request, true, false))
195acf9f
A
426 );
427
428 $this->assertEquals(
429 0,
528a6f8a 430 count(self::$publicLinkDB->filterSearch($request, true, false))
195acf9f
A
431 );
432 }
528a6f8a
A
433
434 /**
435 * Test filterHash() with a valid smallhash.
436 */
437 public function testFilterHashValid()
438 {
439 $request = smallHash('20150310_114651');
440 $this->assertEquals(
441 1,
442 count(self::$publicLinkDB->filterHash($request))
443 );
c3dfd899
A
444 $request = smallHash('20150310_114633' . 8);
445 $this->assertEquals(
446 1,
447 count(self::$publicLinkDB->filterHash($request))
448 );
528a6f8a
A
449 }
450
451 /**
452 * Test filterHash() with an invalid smallhash.
453 *
454 * @expectedException LinkNotFoundException
455 */
456 public function testFilterHashInValid1()
457 {
458 $request = 'blabla';
459 self::$publicLinkDB->filterHash($request);
460 }
461
462 /**
463 * Test filterHash() with an empty smallhash.
464 *
465 * @expectedException LinkNotFoundException
466 */
467 public function testFilterHashInValid()
468 {
469 self::$publicLinkDB->filterHash('');
470 }
c3dfd899
A
471
472 /**
473 * Test reorder with asc/desc parameter.
474 */
475 public function testReorderLinksDesc()
476 {
d592daea 477 self::$privateLinkDB->reorder('ASC');
4154c25b
A
478 $stickyIds = [11, 10];
479 $standardIds = [42, 4, 9, 1, 0, 7, 6, 8, 41];
480 $linkIds = array_merge($stickyIds, $standardIds);
d592daea
A
481 $cpt = 0;
482 foreach (self::$privateLinkDB as $key => $value) {
483 $this->assertEquals($linkIds[$cpt++], $key);
c3dfd899 484 }
d592daea 485 self::$privateLinkDB->reorder('DESC');
4154c25b 486 $linkIds = array_merge(array_reverse($stickyIds), array_reverse($standardIds));
d592daea
A
487 $cpt = 0;
488 foreach (self::$privateLinkDB as $key => $value) {
489 $this->assertEquals($linkIds[$cpt++], $key);
c3dfd899
A
490 }
491 }
3b67b222
A
492
493 /**
494 * Test rename tag with a valid value present in multiple links
495 */
496 public function testRenameTagMultiple()
497 {
498 self::$refDB->write(self::$testDatastore);
499 $linkDB = new LinkDB(self::$testDatastore, true, false);
500
501 $res = $linkDB->renameTag('cartoon', 'Taz');
502 $this->assertEquals(3, count($res));
503 $this->assertContains(' Taz ', $linkDB[4]['tags']);
504 $this->assertContains(' Taz ', $linkDB[1]['tags']);
505 $this->assertContains(' Taz ', $linkDB[0]['tags']);
506 }
507
508 /**
509 * Test rename tag with a valid value
510 */
511 public function testRenameTagCaseSensitive()
512 {
513 self::$refDB->write(self::$testDatastore);
514 $linkDB = new LinkDB(self::$testDatastore, true, false, '');
515
516 $res = $linkDB->renameTag('sTuff', 'Taz');
517 $this->assertEquals(1, count($res));
518 $this->assertEquals('Taz', $linkDB[41]['tags']);
519 }
520
521 /**
522 * Test rename tag with invalid values
523 */
524 public function testRenameTagInvalid()
525 {
526 $linkDB = new LinkDB(self::$testDatastore, false, false);
527
528 $this->assertFalse($linkDB->renameTag('', 'test'));
529 $this->assertFalse($linkDB->renameTag('', ''));
530 // tag non existent
531 $this->assertEquals([], $linkDB->renameTag('test', ''));
532 $this->assertEquals([], $linkDB->renameTag('test', 'retest'));
533 }
534
535 /**
536 * Test delete tag with a valid value
537 */
538 public function testDeleteTag()
539 {
540 self::$refDB->write(self::$testDatastore);
541 $linkDB = new LinkDB(self::$testDatastore, true, false);
542
543 $res = $linkDB->renameTag('cartoon', null);
544 $this->assertEquals(3, count($res));
545 $this->assertNotContains('cartoon', $linkDB[4]['tags']);
546 }
f8c5660d
A
547
548 /**
549 * Test linksCountPerTag all tags without filter.
550 * Equal occurrences should be sorted alphabetically.
551 */
552 public function testCountLinkPerTagAllNoFilter()
553 {
554 $expected = [
555 'web' => 4,
556 'cartoon' => 3,
557 'dev' => 2,
558 'gnu' => 2,
559 'hashtag' => 2,
560 'sTuff' => 2,
561 '-exclude' => 1,
562 '.hidden' => 1,
563 'Mercurial' => 1,
564 'css' => 1,
565 'free' => 1,
566 'html' => 1,
567 'media' => 1,
568 'samba' => 1,
569 'software' => 1,
570 'stallman' => 1,
571 'tag1' => 1,
572 'tag2' => 1,
573 'tag3' => 1,
574 'tag4' => 1,
575 'ut' => 1,
576 'w3c' => 1,
577 ];
578 $tags = self::$privateLinkDB->linksCountPerTag();
579
580 $this->assertEquals($expected, $tags, var_export($tags, true));
581 }
582
583 /**
584 * Test linksCountPerTag all tags with filter.
585 * Equal occurrences should be sorted alphabetically.
586 */
587 public function testCountLinkPerTagAllWithFilter()
588 {
589 $expected = [
590 'gnu' => 2,
591 'hashtag' => 2,
592 '-exclude' => 1,
593 '.hidden' => 1,
594 'free' => 1,
595 'media' => 1,
596 'software' => 1,
597 'stallman' => 1,
598 'stuff' => 1,
599 'web' => 1,
600 ];
601 $tags = self::$privateLinkDB->linksCountPerTag(['gnu']);
602
603 $this->assertEquals($expected, $tags, var_export($tags, true));
604 }
605
606 /**
607 * Test linksCountPerTag public tags with filter.
608 * Equal occurrences should be sorted alphabetically.
609 */
610 public function testCountLinkPerTagPublicWithFilter()
611 {
612 $expected = [
613 'gnu' => 2,
614 'hashtag' => 2,
615 '-exclude' => 1,
616 '.hidden' => 1,
617 'free' => 1,
618 'media' => 1,
619 'software' => 1,
620 'stallman' => 1,
621 'stuff' => 1,
622 'web' => 1,
623 ];
624 $tags = self::$privateLinkDB->linksCountPerTag(['gnu'], 'public');
625
626 $this->assertEquals($expected, $tags, var_export($tags, true));
627 }
628
629 /**
630 * Test linksCountPerTag public tags with filter.
631 * Equal occurrences should be sorted alphabetically.
632 */
633 public function testCountLinkPerTagPrivateWithFilter()
634 {
635 $expected = [
636 'cartoon' => 1,
637 'dev' => 1,
638 'tag1' => 1,
639 'tag2' => 1,
640 'tag3' => 1,
641 'tag4' => 1,
642 ];
643 $tags = self::$privateLinkDB->linksCountPerTag(['dev'], 'private');
644
645 $this->assertEquals($expected, $tags, var_export($tags, true));
646 }
ca74886f 647}