3 declare(strict_types
=1);
5 namespace Shaarli\Front\Controller\Visitor
;
7 use Shaarli\Bookmark\Bookmark
;
8 use Shaarli\Bookmark\Exception\BookmarkNotFoundException
;
9 use Shaarli\Config\ConfigManager
;
10 use Shaarli\Security\LoginManager
;
12 use Shaarli\Thumbnailer
;
13 use Slim\Http\Request
;
14 use Slim\Http\Response
;
16 class BookmarkListControllerTest
extends TestCase
18 use FrontControllerMockHelper
;
20 /** @var BookmarkListController */
21 protected $controller;
23 public function setUp(): void
25 $this->createContainer();
27 $this->controller
= new BookmarkListController($this->container
);
31 * Test rendering list of bookmarks with default parameters (first page).
33 public function testIndexDefaultFirstPage(): void
35 $assignedVariables = [];
36 $this->assignTemplateVars($assignedVariables);
38 $request = $this->createMock(Request
::class);
39 $response = new Response();
41 $this->container
->bookmarkService
42 ->expects(static::once())
45 ['searchtags' => '', 'searchterm' => ''],
51 (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
52 (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
53 (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
57 $this->container
->sessionManager
58 ->method('getSessionParameter')
59 ->willReturnCallback(function (string $parameter, $default = null) {
60 if ('LINKS_PER_PAGE' === $parameter) {
68 $result = $this->controller
->index($request, $response);
70 static::assertSame(200, $result->getStatusCode());
71 static::assertSame('linklist', (string) $result->getBody());
73 static::assertSame('Shaarli', $assignedVariables['pagetitle']);
74 static::assertSame('?page=2', $assignedVariables['previous_page_url']);
75 static::assertSame('', $assignedVariables['next_page_url']);
76 static::assertSame(2, $assignedVariables['page_max']);
77 static::assertSame('', $assignedVariables['search_tags']);
78 static::assertSame(3, $assignedVariables['result_count']);
79 static::assertSame(1, $assignedVariables['page_current']);
80 static::assertSame('', $assignedVariables['search_term']);
81 static::assertNull($assignedVariables['visibility']);
82 static::assertCount(2, $assignedVariables['links']);
84 $link = $assignedVariables['links'][0];
86 static::assertSame(1, $link['id']);
87 static::assertSame('http://url1.tld', $link['url']);
88 static::assertSame('Title 1', $link['title']);
90 $link = $assignedVariables['links'][1];
92 static::assertSame(2, $link['id']);
93 static::assertSame('http://url2.tld', $link['url']);
94 static::assertSame('Title 2', $link['title']);
98 * Test rendering list of bookmarks with default parameters (second page).
100 public function testIndexDefaultSecondPage(): void
102 $assignedVariables = [];
103 $this->assignTemplateVars($assignedVariables);
105 $request = $this->createMock(Request
::class);
106 $request->method('getParam')->willReturnCallback(function (string $key) {
107 if ('page' === $key) {
113 $response = new Response();
115 $this->container
->bookmarkService
116 ->expects(static::once())
119 ['searchtags' => '', 'searchterm' => ''],
125 (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
126 (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
127 (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
131 $this->container
->sessionManager
132 ->method('getSessionParameter')
133 ->willReturnCallback(function (string $parameter, $default = null) {
134 if ('LINKS_PER_PAGE' === $parameter) {
142 $result = $this->controller
->index($request, $response);
144 static::assertSame(200, $result->getStatusCode());
145 static::assertSame('linklist', (string) $result->getBody());
147 static::assertSame('Shaarli', $assignedVariables['pagetitle']);
148 static::assertSame('', $assignedVariables['previous_page_url']);
149 static::assertSame('?page=1', $assignedVariables['next_page_url']);
150 static::assertSame(2, $assignedVariables['page_max']);
151 static::assertSame('', $assignedVariables['search_tags']);
152 static::assertSame(3, $assignedVariables['result_count']);
153 static::assertSame(2, $assignedVariables['page_current']);
154 static::assertSame('', $assignedVariables['search_term']);
155 static::assertNull($assignedVariables['visibility']);
156 static::assertCount(1, $assignedVariables['links']);
158 $link = $assignedVariables['links'][2];
160 static::assertSame(3, $link['id']);
161 static::assertSame('http://url3.tld', $link['url']);
162 static::assertSame('Title 3', $link['title']);
166 * Test rendering list of bookmarks with filters.
168 public function testIndexDefaultWithFilters(): void
170 $assignedVariables = [];
171 $this->assignTemplateVars($assignedVariables);
173 $request = $this->createMock(Request
::class);
174 $request->method('getParam')->willReturnCallback(function (string $key) {
175 if ('searchtags' === $key) {
178 if ('searchterm' === $key) {
184 $response = new Response();
186 $this->container
->sessionManager
187 ->method('getSessionParameter')
188 ->willReturnCallback(function (string $key, $default) {
189 if ('LINKS_PER_PAGE' === $key) {
192 if ('visibility' === $key) {
195 if ('untaggedonly' === $key) {
203 $this->container
->bookmarkService
204 ->expects(static::once())
207 ['searchtags' => 'abc def', 'searchterm' => 'ghi jkl'],
213 (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
214 (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
215 (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
219 $result = $this->controller
->index($request, $response);
221 static::assertSame(200, $result->getStatusCode());
222 static::assertSame('linklist', (string) $result->getBody());
224 static::assertSame('Search: ghi jkl [abc] [def] - Shaarli', $assignedVariables['pagetitle']);
225 static::assertSame('?page=2&searchterm=ghi+jkl&searchtags=abc+def', $assignedVariables['previous_page_url']);
229 * Test displaying a permalink with valid parameters
231 public function testPermalinkValid(): void
235 $assignedVariables = [];
236 $this->assignTemplateVars($assignedVariables);
238 $request = $this->createMock(Request
::class);
239 $response = new Response();
241 $this->container
->bookmarkService
242 ->expects(static::once())
243 ->method('findByHash')
245 ->willReturn((new Bookmark())->setId(123)->setTitle('Title 1')->setUrl('http://url1.tld'))
248 $result = $this->controller
->permalink($request, $response, ['hash' => $hash]);
250 static::assertSame(200, $result->getStatusCode());
251 static::assertSame('linklist', (string) $result->getBody());
253 static::assertSame('Title 1 - Shaarli', $assignedVariables['pagetitle']);
254 static::assertCount(1, $assignedVariables['links']);
256 $link = $assignedVariables['links'][0];
258 static::assertSame(123, $link['id']);
259 static::assertSame('http://url1.tld', $link['url']);
260 static::assertSame('Title 1', $link['title']);
264 * Test displaying a permalink with an unknown small hash : renders a 404 template error
266 public function testPermalinkNotFound(): void
270 $assignedVariables = [];
271 $this->assignTemplateVars($assignedVariables);
273 $request = $this->createMock(Request
::class);
274 $response = new Response();
276 $this->container
->bookmarkService
277 ->expects(static::once())
278 ->method('findByHash')
280 ->willThrowException(new BookmarkNotFoundException())
283 $result = $this->controller
->permalink($request, $response, ['hash' => $hash]);
285 static::assertSame(200, $result->getStatusCode());
286 static::assertSame('404', (string) $result->getBody());
289 'The link you are trying to reach does not exist or has been deleted.',
290 $assignedVariables['error_message']
295 * Test getting link list with thumbnail updates.
296 * -> 2 thumbnails update, only 1 datastore write
298 public function testThumbnailUpdateFromLinkList(): void
300 $request = $this->createMock(Request
::class);
301 $response = new Response();
303 $this->container
->loginManager
= $this->createMock(LoginManager
::class);
304 $this->container
->loginManager
->method('isLoggedIn')->willReturn(true);
306 $this->container
->conf
= $this->createMock(ConfigManager
::class);
307 $this->container
->conf
309 ->willReturnCallback(function (string $key, $default) {
310 if ($key === 'thumbnails.mode') {
311 return Thumbnailer
::MODE_ALL
;
312 } elseif ($key === 'general.enable_async_metadata') {
320 $this->container
->thumbnailer
= $this->createMock(Thumbnailer
::class);
321 $this->container
->thumbnailer
322 ->expects(static::exactly(2))
324 ->withConsecutive(['https://url2.tld'], ['https://url4.tld'])
327 $this->container
->bookmarkService
328 ->expects(static::once())
331 (new Bookmark())->setId(1)->setUrl('https://url1.tld')->setTitle('Title 1')->setThumbnail(false),
332 $b1 = (new Bookmark())->setId(2)->setUrl('https://url2.tld')->setTitle('Title 2'),
333 (new Bookmark())->setId(3)->setUrl('https://url3.tld')->setTitle('Title 3')->setThumbnail(false),
334 $b2 = (new Bookmark())->setId(2)->setUrl('https://url4.tld')->setTitle('Title 4'),
335 (new Bookmark())->setId(2)->setUrl('ftp://url5.tld', ['ftp'])->setTitle('Title 5'),
338 $this->container
->bookmarkService
339 ->expects(static::exactly(2))
341 ->withConsecutive([$b1, false], [$b2, false])
343 $this->container
->bookmarkService
->expects(static::once())->method('save');
345 $result = $this->controller
->index($request, $response);
347 static::assertSame(200, $result->getStatusCode());
348 static::assertSame('linklist', (string) $result->getBody());
352 * Test getting a permalink with thumbnail update.
354 public function testThumbnailUpdateFromPermalink(): void
356 $request = $this->createMock(Request
::class);
357 $response = new Response();
359 $this->container
->loginManager
= $this->createMock(LoginManager
::class);
360 $this->container
->loginManager
->method('isLoggedIn')->willReturn(true);
362 $this->container
->conf
= $this->createMock(ConfigManager
::class);
363 $this->container
->conf
365 ->willReturnCallback(function (string $key, $default) {
366 if ($key === 'thumbnails.mode') {
367 return Thumbnailer
::MODE_ALL
;
368 } elseif ($key === 'general.enable_async_metadata') {
376 $this->container
->thumbnailer
= $this->createMock(Thumbnailer
::class);
377 $this->container
->thumbnailer
->expects(static::once())->method('get')->withConsecutive(['https://url.tld']);
379 $this->container
->bookmarkService
380 ->expects(static::once())
381 ->method('findByHash')
382 ->willReturn($bookmark = (new Bookmark())->setId(2)->setUrl('https://url.tld')->setTitle('Title 1'))
384 $this->container
->bookmarkService
->expects(static::once())->method('set')->with($bookmark, true);
385 $this->container
->bookmarkService
->expects(static::never())->method('save');
387 $result = $this->controller
->permalink($request, $response, ['hash' => 'abc']);
389 static::assertSame(200, $result->getStatusCode());
390 static::assertSame('linklist', (string) $result->getBody());
394 * Test getting a permalink with thumbnail update with async setting: no update should run.
396 public function testThumbnailUpdateFromPermalinkAsync(): void
398 $request = $this->createMock(Request
::class);
399 $response = new Response();
401 $this->container
->loginManager
= $this->createMock(LoginManager
::class);
402 $this->container
->loginManager
->method('isLoggedIn')->willReturn(true);
404 $this->container
->conf
= $this->createMock(ConfigManager
::class);
405 $this->container
->conf
407 ->willReturnCallback(function (string $key, $default) {
408 if ($key === 'thumbnails.mode') {
409 return Thumbnailer
::MODE_ALL
;
410 } elseif ($key === 'general.enable_async_metadata') {
418 $this->container
->thumbnailer
= $this->createMock(Thumbnailer
::class);
419 $this->container
->thumbnailer
->expects(static::never())->method('get');
421 $this->container
->bookmarkService
422 ->expects(static::once())
423 ->method('findByHash')
424 ->willReturn((new Bookmark())->setId(2)->setUrl('https://url.tld')->setTitle('Title 1'))
426 $this->container
->bookmarkService
->expects(static::never())->method('set');
427 $this->container
->bookmarkService
->expects(static::never())->method('save');
429 $result = $this->controller
->permalink($request, $response, ['hash' => 'abc']);
431 static::assertSame(200, $result->getStatusCode());
435 * Trigger legacy controller in link list controller: permalink
437 public function testLegacyControllerPermalink(): void
440 $this->container
->environment
['QUERY_STRING'] = $hash;
442 $request = $this->createMock(Request
::class);
443 $response = new Response();
445 $result = $this->controller
->index($request, $response);
447 static::assertSame(302, $result->getStatusCode());
448 static::assertSame('/subfolder/shaare/' . $hash, $result->getHeader('location')[0]);
452 * Trigger legacy controller in link list controller: ?do= query parameter
454 public function testLegacyControllerDoPage(): void
456 $request = $this->createMock(Request
::class);
457 $request->method('getQueryParam')->with('do')->willReturn('picwall');
458 $response = new Response();
460 $result = $this->controller
->index($request, $response);
462 static::assertSame(302, $result->getStatusCode());
463 static::assertSame('/subfolder/picture-wall', $result->getHeader('location')[0]);
467 * Trigger legacy controller in link list controller: ?do= query parameter with unknown legacy route
469 public function testLegacyControllerUnknownDoPage(): void
471 $request = $this->createMock(Request
::class);
472 $request->method('getQueryParam')->with('do')->willReturn('nope');
473 $response = new Response();
475 $result = $this->controller
->index($request, $response);
477 static::assertSame(200, $result->getStatusCode());
478 static::assertSame('linklist', (string) $result->getBody());
482 * Trigger legacy controller in link list controller: other GET route (e.g. ?post)
484 public function testLegacyControllerGetParameter(): void
486 $request = $this->createMock(Request
::class);
487 $request->method('getQueryParams')->willReturn(['post' => $url = 'http://url.tld']);
488 $response = new Response();
490 $this->container
->loginManager
= $this->createMock(LoginManager
::class);
491 $this->container
->loginManager
->method('isLoggedIn')->willReturn(true);
493 $result = $this->controller
->index($request, $response);
495 static::assertSame(302, $result->getStatusCode());
497 '/subfolder/admin/shaare?post=' . urlencode($url),
498 $result->getHeader('location')[0]