]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - tests/bookmark/BookmarkFilterTest.php
Improve metadata retrieval (performances and accuracy)
[github/shaarli/Shaarli.git] / tests / bookmark / BookmarkFilterTest.php
1 <?php
2
3 namespace Shaarli\Bookmark;
4
5 use Exception;
6 use malkusch\lock\mutex\NoMutex;
7 use ReferenceLinkDB;
8 use Shaarli\Config\ConfigManager;
9 use Shaarli\History;
10 use Shaarli\TestCase;
11
12 /**
13 * Class BookmarkFilterTest.
14 */
15 class BookmarkFilterTest extends TestCase
16 {
17 /**
18 * @var string Test datastore path.
19 */
20 protected static $testDatastore = 'sandbox/datastore.php';
21 /**
22 * @var BookmarkFilter instance.
23 */
24 protected static $linkFilter;
25
26 /**
27 * @var ReferenceLinkDB instance
28 */
29 protected static $refDB;
30
31 /**
32 * @var BookmarkFileService instance
33 */
34 protected static $bookmarkService;
35
36 /**
37 * Instantiate linkFilter with ReferenceLinkDB data.
38 */
39 public static function setUpBeforeClass(): void
40 {
41 $mutex = new NoMutex();
42 $conf = new ConfigManager('tests/utils/config/configJson');
43 $conf->set('resource.datastore', self::$testDatastore);
44 self::$refDB = new \ReferenceLinkDB();
45 self::$refDB->write(self::$testDatastore);
46 $history = new History('sandbox/history.php');
47 self::$bookmarkService = new \FakeBookmarkService($conf, $history, $mutex, true);
48 self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks());
49 }
50
51 /**
52 * Blank filter.
53 */
54 public function testFilter()
55 {
56 $this->assertEquals(
57 self::$refDB->countLinks(),
58 count(self::$linkFilter->filter('', ''))
59 );
60
61 $this->assertEquals(
62 self::$refDB->countLinks(),
63 count(self::$linkFilter->filter('', '', 'all'))
64 );
65
66 $this->assertEquals(
67 self::$refDB->countLinks(),
68 count(self::$linkFilter->filter('', '', 'randomstr'))
69 );
70
71 // Private only.
72 $this->assertEquals(
73 self::$refDB->countPrivateLinks(),
74 count(self::$linkFilter->filter('', '', false, 'private'))
75 );
76
77 // Public only.
78 $this->assertEquals(
79 self::$refDB->countPublicLinks(),
80 count(self::$linkFilter->filter('', '', false, 'public'))
81 );
82
83 $this->assertEquals(
84 ReferenceLinkDB::$NB_LINKS_TOTAL,
85 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, ''))
86 );
87
88 $this->assertEquals(
89 self::$refDB->countUntaggedLinks(),
90 count(
91 self::$linkFilter->filter(
92 BookmarkFilter::$FILTER_TAG,
93 /*$request=*/
94 '',
95 /*$casesensitive=*/
96 false,
97 /*$visibility=*/
98 'all',
99 /*$untaggedonly=*/
100 true
101 )
102 )
103 );
104
105 $this->assertEquals(
106 ReferenceLinkDB::$NB_LINKS_TOTAL,
107 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, ''))
108 );
109 }
110
111 /**
112 * Filter bookmarks using a tag
113 */
114 public function testFilterOneTag()
115 {
116 $this->assertEquals(
117 4,
118 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false))
119 );
120
121 $this->assertEquals(
122 4,
123 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'all'))
124 );
125
126 $this->assertEquals(
127 4,
128 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'default-blabla'))
129 );
130
131 // Private only.
132 $this->assertEquals(
133 1,
134 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'private'))
135 );
136
137 // Public only.
138 $this->assertEquals(
139 3,
140 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'public'))
141 );
142 }
143
144 /**
145 * Filter bookmarks using a tag - case-sensitive
146 */
147 public function testFilterCaseSensitiveTag()
148 {
149 $this->assertEquals(
150 0,
151 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'mercurial', true))
152 );
153
154 $this->assertEquals(
155 1,
156 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'Mercurial', true))
157 );
158 }
159
160 /**
161 * Filter bookmarks using a tag combination
162 */
163 public function testFilterMultipleTags()
164 {
165 $this->assertEquals(
166 2,
167 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'dev cartoon', false))
168 );
169 }
170
171 /**
172 * Filter bookmarks using a non-existent tag
173 */
174 public function testFilterUnknownTag()
175 {
176 $this->assertEquals(
177 0,
178 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'null', false))
179 );
180 }
181
182 /**
183 * Return bookmarks for a given day
184 */
185 public function testFilterDay()
186 {
187 $this->assertEquals(
188 4,
189 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20121206'))
190 );
191 }
192
193 /**
194 * Return bookmarks for a given day
195 */
196 public function testFilterDayRestrictedVisibility(): void
197 {
198 $this->assertEquals(
199 3,
200 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20121206', false, BookmarkFilter::$PUBLIC))
201 );
202 }
203
204 /**
205 * 404 - day not found
206 */
207 public function testFilterUnknownDay()
208 {
209 $this->assertEquals(
210 0,
211 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '19700101'))
212 );
213 }
214
215 /**
216 * Use an invalid date format
217 */
218 public function testFilterInvalidDayWithChars()
219 {
220 $this->expectException(\Exception::class);
221 $this->expectExceptionMessageRegExp('/Invalid date format/');
222
223 self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, 'Rainy day, dream away');
224 }
225
226 /**
227 * Use an invalid date format
228 */
229 public function testFilterInvalidDayDigits()
230 {
231 $this->expectException(\Exception::class);
232 $this->expectExceptionMessageRegExp('/Invalid date format/');
233
234 self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20');
235 }
236
237 /**
238 * Retrieve a link entry with its hash
239 */
240 public function testFilterSmallHash()
241 {
242 $links = self::$linkFilter->filter(BookmarkFilter::$FILTER_HASH, 'IuWvgA');
243
244 $this->assertEquals(
245 1,
246 count($links)
247 );
248
249 $this->assertEquals(
250 'MediaGoblin',
251 $links[7]->getTitle()
252 );
253 }
254
255 /**
256 * No link for this hash
257 */
258 public function testFilterUnknownSmallHash()
259 {
260 $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
261
262 self::$linkFilter->filter(BookmarkFilter::$FILTER_HASH, 'Iblaah');
263 }
264
265 /**
266 * Full-text search - no result found.
267 */
268 public function testFilterFullTextNoResult()
269 {
270 $this->assertEquals(
271 0,
272 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'azertyuiop'))
273 );
274 }
275
276 /**
277 * Full-text search - result from a link's URL
278 */
279 public function testFilterFullTextURL()
280 {
281 $this->assertEquals(
282 2,
283 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'ars.userfriendly.org'))
284 );
285
286 $this->assertEquals(
287 2,
288 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'ars org'))
289 );
290 }
291
292 /**
293 * Full-text search - result from a link's title only
294 */
295 public function testFilterFullTextTitle()
296 {
297 // use miscellaneous cases
298 $this->assertEquals(
299 2,
300 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'userfriendly -'))
301 );
302 $this->assertEquals(
303 2,
304 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'UserFriendly -'))
305 );
306 $this->assertEquals(
307 2,
308 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'uSeRFrIendlY -'))
309 );
310
311 // use miscellaneous case and offset
312 $this->assertEquals(
313 2,
314 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'RFrIendL'))
315 );
316 }
317
318 /**
319 * Full-text search - result from the link's description only
320 */
321 public function testFilterFullTextDescription()
322 {
323 $this->assertEquals(
324 1,
325 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'publishing media'))
326 );
327
328 $this->assertEquals(
329 1,
330 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'mercurial w3c'))
331 );
332
333 $this->assertEquals(
334 3,
335 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, '"free software"'))
336 );
337 }
338
339 /**
340 * Full-text search - result from the link's tags only
341 */
342 public function testFilterFullTextTags()
343 {
344 $this->assertEquals(
345 6,
346 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web'))
347 );
348
349 $this->assertEquals(
350 6,
351 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', 'all'))
352 );
353
354 $this->assertEquals(
355 6,
356 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', 'bla'))
357 );
358
359 // Private only.
360 $this->assertEquals(
361 1,
362 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', false, 'private'))
363 );
364
365 // Public only.
366 $this->assertEquals(
367 5,
368 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', false, 'public'))
369 );
370 }
371
372 /**
373 * Full-text search - result set from mixed sources
374 */
375 public function testFilterFullTextMixed()
376 {
377 $this->assertEquals(
378 3,
379 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'free software'))
380 );
381 }
382
383 /**
384 * Full-text search - test exclusion with '-'.
385 */
386 public function testExcludeSearch()
387 {
388 $this->assertEquals(
389 1,
390 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'free -gnu'))
391 );
392
393 $this->assertEquals(
394 ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
395 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, '-revolution'))
396 );
397 }
398
399 /**
400 * Full-text search - test AND, exact terms and exclusion combined, across fields.
401 */
402 public function testMultiSearch()
403 {
404 $this->assertEquals(
405 2,
406 count(self::$linkFilter->filter(
407 BookmarkFilter::$FILTER_TEXT,
408 '"Free Software " stallman "read this" @website stuff'
409 ))
410 );
411
412 $this->assertEquals(
413 1,
414 count(self::$linkFilter->filter(
415 BookmarkFilter::$FILTER_TEXT,
416 '"free software " stallman "read this" -beard @website stuff'
417 ))
418 );
419 }
420
421 /**
422 * Full-text search - make sure that exact search won't work across fields.
423 */
424 public function testSearchExactTermMultiFieldsKo()
425 {
426 $this->assertEquals(
427 0,
428 count(self::$linkFilter->filter(
429 BookmarkFilter::$FILTER_TEXT,
430 '"designer naming"'
431 ))
432 );
433
434 $this->assertEquals(
435 0,
436 count(self::$linkFilter->filter(
437 BookmarkFilter::$FILTER_TEXT,
438 '"designernaming"'
439 ))
440 );
441 }
442
443 /**
444 * Tag search with exclusion.
445 */
446 public function testTagFilterWithExclusion()
447 {
448 $this->assertEquals(
449 1,
450 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'gnu -free'))
451 );
452
453 $this->assertEquals(
454 ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
455 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, '-free'))
456 );
457 }
458
459 /**
460 * Test crossed search (terms + tags).
461 */
462 public function testFilterCrossedSearch()
463 {
464 $terms = '"Free Software " stallman "read this" @website stuff';
465 $tags = 'free';
466 $this->assertEquals(
467 1,
468 count(self::$linkFilter->filter(
469 BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
470 array($tags, $terms)
471 ))
472 );
473 $this->assertEquals(
474 2,
475 count(self::$linkFilter->filter(
476 BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
477 array('', $terms)
478 ))
479 );
480 $this->assertEquals(
481 1,
482 count(self::$linkFilter->filter(
483 BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
484 array(false, 'PSR-2')
485 ))
486 );
487 $this->assertEquals(
488 1,
489 count(self::$linkFilter->filter(
490 BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
491 array($tags, '')
492 ))
493 );
494 $this->assertEquals(
495 ReferenceLinkDB::$NB_LINKS_TOTAL,
496 count(self::$linkFilter->filter(
497 BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
498 ''
499 ))
500 );
501 }
502
503 /**
504 * Filter bookmarks by #hashtag.
505 */
506 public function testFilterByHashtag()
507 {
508 $hashtag = 'hashtag';
509 $this->assertEquals(
510 3,
511 count(self::$linkFilter->filter(
512 BookmarkFilter::$FILTER_TAG,
513 $hashtag
514 ))
515 );
516
517 $hashtag = 'private';
518 $this->assertEquals(
519 1,
520 count(self::$linkFilter->filter(
521 BookmarkFilter::$FILTER_TAG,
522 $hashtag,
523 false,
524 'private'
525 ))
526 );
527 }
528 }