]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - tests/front/controller/visitor/BookmarkListControllerTest.php
Merge pull request #1697 from ArthurHoaro/feature/pagination
[github/shaarli/Shaarli.git] / tests / front / controller / visitor / BookmarkListControllerTest.php
CommitLineData
1a8ac737
A
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Visitor;
6
1a8ac737
A
7use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
9b8c0a45 9use Shaarli\Bookmark\SearchResult;
1a8ac737
A
10use Shaarli\Config\ConfigManager;
11use Shaarli\Security\LoginManager;
a5a9cf23 12use Shaarli\TestCase;
1a8ac737
A
13use Shaarli\Thumbnailer;
14use Slim\Http\Request;
15use Slim\Http\Response;
16
17class BookmarkListControllerTest extends TestCase
18{
19 use FrontControllerMockHelper;
20
21 /** @var BookmarkListController */
22 protected $controller;
23
24 public function setUp(): void
25 {
26 $this->createContainer();
27
28 $this->controller = new BookmarkListController($this->container);
29 }
30
31 /**
32 * Test rendering list of bookmarks with default parameters (first page).
33 */
34 public function testIndexDefaultFirstPage(): void
35 {
36 $assignedVariables = [];
37 $this->assignTemplateVars($assignedVariables);
38
39 $request = $this->createMock(Request::class);
40 $response = new Response();
41
42 $this->container->bookmarkService
43 ->expects(static::once())
44 ->method('search')
45 ->with(
46 ['searchtags' => '', 'searchterm' => ''],
47 null,
48 false,
9b8c0a45
A
49 false,
50 false,
51 ['offset' => 0, 'limit' => 2]
1a8ac737 52 )
9b8c0a45 53 ->willReturn(SearchResult::getSearchResult([
1a8ac737
A
54 (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
55 (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
56 (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
9b8c0a45 57 ], 0, 2)
1a8ac737
A
58 );
59
60 $this->container->sessionManager
61 ->method('getSessionParameter')
62 ->willReturnCallback(function (string $parameter, $default = null) {
63 if ('LINKS_PER_PAGE' === $parameter) {
64 return 2;
65 }
66
67 return $default;
68 })
69 ;
70
71 $result = $this->controller->index($request, $response);
72
73 static::assertSame(200, $result->getStatusCode());
74 static::assertSame('linklist', (string) $result->getBody());
75
76 static::assertSame('Shaarli', $assignedVariables['pagetitle']);
77 static::assertSame('?page=2', $assignedVariables['previous_page_url']);
78 static::assertSame('', $assignedVariables['next_page_url']);
79 static::assertSame(2, $assignedVariables['page_max']);
80 static::assertSame('', $assignedVariables['search_tags']);
81 static::assertSame(3, $assignedVariables['result_count']);
82 static::assertSame(1, $assignedVariables['page_current']);
83 static::assertSame('', $assignedVariables['search_term']);
84 static::assertNull($assignedVariables['visibility']);
85 static::assertCount(2, $assignedVariables['links']);
86
87 $link = $assignedVariables['links'][0];
88
89 static::assertSame(1, $link['id']);
90 static::assertSame('http://url1.tld', $link['url']);
91 static::assertSame('Title 1', $link['title']);
92
93 $link = $assignedVariables['links'][1];
94
95 static::assertSame(2, $link['id']);
96 static::assertSame('http://url2.tld', $link['url']);
97 static::assertSame('Title 2', $link['title']);
98 }
99
100 /**
101 * Test rendering list of bookmarks with default parameters (second page).
102 */
103 public function testIndexDefaultSecondPage(): void
104 {
105 $assignedVariables = [];
106 $this->assignTemplateVars($assignedVariables);
107
108 $request = $this->createMock(Request::class);
109 $request->method('getParam')->willReturnCallback(function (string $key) {
110 if ('page' === $key) {
111 return '2';
112 }
113
114 return null;
115 });
116 $response = new Response();
117
118 $this->container->bookmarkService
119 ->expects(static::once())
120 ->method('search')
121 ->with(
122 ['searchtags' => '', 'searchterm' => ''],
123 null,
124 false,
9b8c0a45
A
125 false,
126 false,
127 ['offset' => 2, 'limit' => 2]
1a8ac737 128 )
9b8c0a45 129 ->willReturn(SearchResult::getSearchResult([
1a8ac737
A
130 (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
131 (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
132 (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
9b8c0a45 133 ], 2, 2))
1a8ac737
A
134 ;
135
136 $this->container->sessionManager
137 ->method('getSessionParameter')
138 ->willReturnCallback(function (string $parameter, $default = null) {
139 if ('LINKS_PER_PAGE' === $parameter) {
140 return 2;
141 }
142
143 return $default;
144 })
145 ;
146
147 $result = $this->controller->index($request, $response);
148
149 static::assertSame(200, $result->getStatusCode());
150 static::assertSame('linklist', (string) $result->getBody());
151
152 static::assertSame('Shaarli', $assignedVariables['pagetitle']);
153 static::assertSame('', $assignedVariables['previous_page_url']);
154 static::assertSame('?page=1', $assignedVariables['next_page_url']);
155 static::assertSame(2, $assignedVariables['page_max']);
156 static::assertSame('', $assignedVariables['search_tags']);
157 static::assertSame(3, $assignedVariables['result_count']);
158 static::assertSame(2, $assignedVariables['page_current']);
159 static::assertSame('', $assignedVariables['search_term']);
160 static::assertNull($assignedVariables['visibility']);
161 static::assertCount(1, $assignedVariables['links']);
162
163 $link = $assignedVariables['links'][2];
164
165 static::assertSame(3, $link['id']);
166 static::assertSame('http://url3.tld', $link['url']);
167 static::assertSame('Title 3', $link['title']);
168 }
169
170 /**
171 * Test rendering list of bookmarks with filters.
172 */
173 public function testIndexDefaultWithFilters(): void
174 {
175 $assignedVariables = [];
176 $this->assignTemplateVars($assignedVariables);
177
178 $request = $this->createMock(Request::class);
179 $request->method('getParam')->willReturnCallback(function (string $key) {
180 if ('searchtags' === $key) {
b3bd8c3e 181 return 'abc@def';
1a8ac737
A
182 }
183 if ('searchterm' === $key) {
184 return 'ghi jkl';
185 }
186
187 return null;
188 });
189 $response = new Response();
190
191 $this->container->sessionManager
192 ->method('getSessionParameter')
193 ->willReturnCallback(function (string $key, $default) {
194 if ('LINKS_PER_PAGE' === $key) {
195 return 2;
196 }
197 if ('visibility' === $key) {
198 return 'private';
199 }
200 if ('untaggedonly' === $key) {
201 return true;
202 }
203
204 return $default;
205 })
206 ;
207
208 $this->container->bookmarkService
209 ->expects(static::once())
210 ->method('search')
211 ->with(
b3bd8c3e 212 ['searchtags' => 'abc@def', 'searchterm' => 'ghi jkl'],
1a8ac737
A
213 'private',
214 false,
9b8c0a45
A
215 true,
216 false,
217 ['offset' => 0, 'limit' => 2]
1a8ac737 218 )
9b8c0a45 219 ->willReturn(SearchResult::getSearchResult([
1a8ac737
A
220 (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
221 (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
222 (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
9b8c0a45 223 ], 0, 2))
1a8ac737
A
224 ;
225
226 $result = $this->controller->index($request, $response);
227
228 static::assertSame(200, $result->getStatusCode());
229 static::assertSame('linklist', (string) $result->getBody());
230
231 static::assertSame('Search: ghi jkl [abc] [def] - Shaarli', $assignedVariables['pagetitle']);
b3bd8c3e 232 static::assertSame('?page=2&searchterm=ghi+jkl&searchtags=abc%40def', $assignedVariables['previous_page_url']);
1a8ac737
A
233 }
234
235 /**
236 * Test displaying a permalink with valid parameters
237 */
238 public function testPermalinkValid(): void
239 {
240 $hash = 'abcdef';
241
242 $assignedVariables = [];
243 $this->assignTemplateVars($assignedVariables);
244
245 $request = $this->createMock(Request::class);
246 $response = new Response();
247
248 $this->container->bookmarkService
249 ->expects(static::once())
250 ->method('findByHash')
251 ->with($hash)
252 ->willReturn((new Bookmark())->setId(123)->setTitle('Title 1')->setUrl('http://url1.tld'))
253 ;
254
255 $result = $this->controller->permalink($request, $response, ['hash' => $hash]);
256
257 static::assertSame(200, $result->getStatusCode());
258 static::assertSame('linklist', (string) $result->getBody());
259
260 static::assertSame('Title 1 - Shaarli', $assignedVariables['pagetitle']);
261 static::assertCount(1, $assignedVariables['links']);
262
263 $link = $assignedVariables['links'][0];
264
265 static::assertSame(123, $link['id']);
266 static::assertSame('http://url1.tld', $link['url']);
267 static::assertSame('Title 1', $link['title']);
268 }
269
270 /**
271 * Test displaying a permalink with an unknown small hash : renders a 404 template error
272 */
273 public function testPermalinkNotFound(): void
274 {
275 $hash = 'abcdef';
276
277 $assignedVariables = [];
278 $this->assignTemplateVars($assignedVariables);
279
280 $request = $this->createMock(Request::class);
281 $response = new Response();
282
283 $this->container->bookmarkService
284 ->expects(static::once())
285 ->method('findByHash')
286 ->with($hash)
287 ->willThrowException(new BookmarkNotFoundException())
288 ;
289
290 $result = $this->controller->permalink($request, $response, ['hash' => $hash]);
291
292 static::assertSame(200, $result->getStatusCode());
293 static::assertSame('404', (string) $result->getBody());
294
295 static::assertSame(
296 'The link you are trying to reach does not exist or has been deleted.',
297 $assignedVariables['error_message']
298 );
299 }
300
9c04921a
A
301 /**
302 * Test GET /shaare/{hash}?key={key} - Find a link by hash using a private link.
303 */
304 public function testPermalinkWithPrivateKey(): void
305 {
306 $hash = 'abcdef';
307 $privateKey = 'this is a private key';
308
309 $assignedVariables = [];
310 $this->assignTemplateVars($assignedVariables);
311
312 $request = $this->createMock(Request::class);
313 $request->method('getParam')->willReturnCallback(function (string $key, $default = null) use ($privateKey) {
314 return $key === 'key' ? $privateKey : $default;
315 });
316 $response = new Response();
317
318 $this->container->bookmarkService
319 ->expects(static::once())
320 ->method('findByHash')
321 ->with($hash, $privateKey)
322 ->willReturn((new Bookmark())->setId(123)->setTitle('Title 1')->setUrl('http://url1.tld'))
323 ;
324
325 $result = $this->controller->permalink($request, $response, ['hash' => $hash]);
326
327 static::assertSame(200, $result->getStatusCode());
328 static::assertSame('linklist', (string) $result->getBody());
329 static::assertCount(1, $assignedVariables['links']);
330 }
331
1a8ac737
A
332 /**
333 * Test getting link list with thumbnail updates.
334 * -> 2 thumbnails update, only 1 datastore write
335 */
336 public function testThumbnailUpdateFromLinkList(): void
337 {
338 $request = $this->createMock(Request::class);
339 $response = new Response();
340
341 $this->container->loginManager = $this->createMock(LoginManager::class);
342 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
343
344 $this->container->conf = $this->createMock(ConfigManager::class);
345 $this->container->conf
346 ->method('get')
347 ->willReturnCallback(function (string $key, $default) {
21e72da9
A
348 if ($key === 'thumbnails.mode') {
349 return Thumbnailer::MODE_ALL;
350 } elseif ($key === 'general.enable_async_metadata') {
351 return false;
352 }
353
354 return $default;
1a8ac737
A
355 })
356 ;
357
358 $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
359 $this->container->thumbnailer
360 ->expects(static::exactly(2))
361 ->method('get')
362 ->withConsecutive(['https://url2.tld'], ['https://url4.tld'])
363 ;
364
365 $this->container->bookmarkService
366 ->expects(static::once())
367 ->method('search')
9b8c0a45 368 ->willReturn(SearchResult::getSearchResult([
1a8ac737
A
369 (new Bookmark())->setId(1)->setUrl('https://url1.tld')->setTitle('Title 1')->setThumbnail(false),
370 $b1 = (new Bookmark())->setId(2)->setUrl('https://url2.tld')->setTitle('Title 2'),
371 (new Bookmark())->setId(3)->setUrl('https://url3.tld')->setTitle('Title 3')->setThumbnail(false),
372 $b2 = (new Bookmark())->setId(2)->setUrl('https://url4.tld')->setTitle('Title 4'),
373 (new Bookmark())->setId(2)->setUrl('ftp://url5.tld', ['ftp'])->setTitle('Title 5'),
9b8c0a45 374 ]))
1a8ac737
A
375 ;
376 $this->container->bookmarkService
377 ->expects(static::exactly(2))
378 ->method('set')
379 ->withConsecutive([$b1, false], [$b2, false])
380 ;
381 $this->container->bookmarkService->expects(static::once())->method('save');
382
383 $result = $this->controller->index($request, $response);
384
385 static::assertSame(200, $result->getStatusCode());
386 static::assertSame('linklist', (string) $result->getBody());
387 }
388
389 /**
390 * Test getting a permalink with thumbnail update.
391 */
392 public function testThumbnailUpdateFromPermalink(): void
393 {
394 $request = $this->createMock(Request::class);
395 $response = new Response();
396
397 $this->container->loginManager = $this->createMock(LoginManager::class);
398 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
399
400 $this->container->conf = $this->createMock(ConfigManager::class);
401 $this->container->conf
402 ->method('get')
403 ->willReturnCallback(function (string $key, $default) {
21e72da9
A
404 if ($key === 'thumbnails.mode') {
405 return Thumbnailer::MODE_ALL;
406 } elseif ($key === 'general.enable_async_metadata') {
407 return false;
408 }
409
410 return $default;
1a8ac737
A
411 })
412 ;
413
414 $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
415 $this->container->thumbnailer->expects(static::once())->method('get')->withConsecutive(['https://url.tld']);
416
417 $this->container->bookmarkService
418 ->expects(static::once())
419 ->method('findByHash')
420 ->willReturn($bookmark = (new Bookmark())->setId(2)->setUrl('https://url.tld')->setTitle('Title 1'))
421 ;
422 $this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, true);
423 $this->container->bookmarkService->expects(static::never())->method('save');
424
425 $result = $this->controller->permalink($request, $response, ['hash' => 'abc']);
426
427 static::assertSame(200, $result->getStatusCode());
428 static::assertSame('linklist', (string) $result->getBody());
429 }
430
21e72da9
A
431 /**
432 * Test getting a permalink with thumbnail update with async setting: no update should run.
433 */
434 public function testThumbnailUpdateFromPermalinkAsync(): void
435 {
436 $request = $this->createMock(Request::class);
437 $response = new Response();
438
439 $this->container->loginManager = $this->createMock(LoginManager::class);
440 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
441
442 $this->container->conf = $this->createMock(ConfigManager::class);
443 $this->container->conf
444 ->method('get')
445 ->willReturnCallback(function (string $key, $default) {
446 if ($key === 'thumbnails.mode') {
447 return Thumbnailer::MODE_ALL;
448 } elseif ($key === 'general.enable_async_metadata') {
449 return true;
450 }
451
452 return $default;
453 })
454 ;
455
456 $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
457 $this->container->thumbnailer->expects(static::never())->method('get');
458
459 $this->container->bookmarkService
460 ->expects(static::once())
461 ->method('findByHash')
462 ->willReturn((new Bookmark())->setId(2)->setUrl('https://url.tld')->setTitle('Title 1'))
463 ;
464 $this->container->bookmarkService->expects(static::never())->method('set');
465 $this->container->bookmarkService->expects(static::never())->method('save');
466
467 $result = $this->controller->permalink($request, $response, ['hash' => 'abc']);
468
469 static::assertSame(200, $result->getStatusCode());
470 }
471
1a8ac737
A
472 /**
473 * Trigger legacy controller in link list controller: permalink
474 */
475 public function testLegacyControllerPermalink(): void
476 {
477 $hash = 'abcdef';
478 $this->container->environment['QUERY_STRING'] = $hash;
479
480 $request = $this->createMock(Request::class);
481 $response = new Response();
482
483 $result = $this->controller->index($request, $response);
484
485 static::assertSame(302, $result->getStatusCode());
486 static::assertSame('/subfolder/shaare/' . $hash, $result->getHeader('location')[0]);
487 }
488
489 /**
490 * Trigger legacy controller in link list controller: ?do= query parameter
491 */
492 public function testLegacyControllerDoPage(): void
493 {
494 $request = $this->createMock(Request::class);
495 $request->method('getQueryParam')->with('do')->willReturn('picwall');
496 $response = new Response();
497
498 $result = $this->controller->index($request, $response);
499
500 static::assertSame(302, $result->getStatusCode());
501 static::assertSame('/subfolder/picture-wall', $result->getHeader('location')[0]);
502 }
503
504 /**
505 * Trigger legacy controller in link list controller: ?do= query parameter with unknown legacy route
506 */
507 public function testLegacyControllerUnknownDoPage(): void
508 {
509 $request = $this->createMock(Request::class);
510 $request->method('getQueryParam')->with('do')->willReturn('nope');
511 $response = new Response();
512
513 $result = $this->controller->index($request, $response);
514
515 static::assertSame(200, $result->getStatusCode());
516 static::assertSame('linklist', (string) $result->getBody());
517 }
518
519 /**
520 * Trigger legacy controller in link list controller: other GET route (e.g. ?post)
521 */
522 public function testLegacyControllerGetParameter(): void
523 {
524 $request = $this->createMock(Request::class);
525 $request->method('getQueryParams')->willReturn(['post' => $url = 'http://url.tld']);
526 $response = new Response();
527
528 $this->container->loginManager = $this->createMock(LoginManager::class);
529 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
530
531 $result = $this->controller->index($request, $response);
532
533 static::assertSame(302, $result->getStatusCode());
534 static::assertSame(
535 '/subfolder/admin/shaare?post=' . urlencode($url),
536 $result->getHeader('location')[0]
537 );
538 }
539}