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