]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - tests/api/controllers/links/GetLinksTest.php
b1c46ee2816853b45a5a8abfcac28f8c71f4b973
[github/shaarli/Shaarli.git] / tests / api / controllers / links / GetLinksTest.php
1 <?php
2 namespace Shaarli\Api\Controllers;
3
4 use malkusch\lock\mutex\NoMutex;
5 use Shaarli\Bookmark\Bookmark;
6 use Shaarli\Bookmark\BookmarkFileService;
7 use Shaarli\Bookmark\LinkDB;
8 use Shaarli\Config\ConfigManager;
9 use Shaarli\History;
10 use Slim\Container;
11 use Slim\Http\Environment;
12 use Slim\Http\Request;
13 use Slim\Http\Response;
14
15 /**
16 * Class GetLinksTest
17 *
18 * Test get Link list REST API service.
19 *
20 * @see http://shaarli.github.io/api-documentation/#links-links-collection-get
21 *
22 * @package Shaarli\Api\Controllers
23 */
24 class GetLinksTest extends \Shaarli\TestCase
25 {
26 /**
27 * @var string datastore to test write operations
28 */
29 protected static $testDatastore = 'sandbox/datastore.php';
30
31 /**
32 * @var ConfigManager instance
33 */
34 protected $conf;
35
36 /**
37 * @var \ReferenceLinkDB instance.
38 */
39 protected $refDB = null;
40
41 /**
42 * @var Container instance.
43 */
44 protected $container;
45
46 /**
47 * @var Links controller instance.
48 */
49 protected $controller;
50
51 /**
52 * Number of JSON field per link.
53 */
54 const NB_FIELDS_LINK = 9;
55
56 /**
57 * Before every test, instantiate a new Api with its config, plugins and bookmarks.
58 */
59 protected function setUp(): void
60 {
61 $mutex = new NoMutex();
62 $this->conf = new ConfigManager('tests/utils/config/configJson');
63 $this->conf->set('resource.datastore', self::$testDatastore);
64 $this->refDB = new \ReferenceLinkDB();
65 $this->refDB->write(self::$testDatastore);
66 $history = new History('sandbox/history.php');
67
68 $this->container = new Container();
69 $this->container['conf'] = $this->conf;
70 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
71 $this->container['history'] = null;
72
73 $this->controller = new Links($this->container);
74 }
75
76 /**
77 * After every test, remove the test datastore.
78 */
79 protected function tearDown(): void
80 {
81 @unlink(self::$testDatastore);
82 }
83
84 /**
85 * Test basic getLinks service: returns all bookmarks.
86 */
87 public function testGetLinks()
88 {
89 // Used by index_url().
90 $_SERVER['SERVER_NAME'] = 'domain.tld';
91 $_SERVER['SERVER_PORT'] = 80;
92 $_SERVER['SCRIPT_NAME'] = '/';
93
94 $env = Environment::mock([
95 'REQUEST_METHOD' => 'GET',
96 ]);
97 $request = Request::createFromEnvironment($env);
98
99 $response = $this->controller->getLinks($request, new Response());
100 $this->assertEquals(200, $response->getStatusCode());
101 $data = json_decode((string) $response->getBody(), true);
102 $this->assertEquals($this->refDB->countLinks(), count($data));
103
104 // Check order
105 $order = [10, 11, 41, 8, 6, 7, 0, 1, 9, 4, 42];
106 $cpt = 0;
107 foreach ($data as $link) {
108 $this->assertEquals(self::NB_FIELDS_LINK, count($link));
109 $this->assertEquals($order[$cpt++], $link['id']);
110 }
111
112 // Check first element fields
113 $first = $data[2];
114 $this->assertEquals('http://domain.tld/shaare/WDWyig', $first['url']);
115 $this->assertEquals('WDWyig', $first['shorturl']);
116 $this->assertEquals('Link title: @website', $first['title']);
117 $this->assertEquals(
118 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag',
119 $first['description']
120 );
121 $this->assertEquals('sTuff', $first['tags'][0]);
122 $this->assertEquals(false, $first['private']);
123 $this->assertEquals(
124 \DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM),
125 $first['created']
126 );
127 $this->assertEmpty($first['updated']);
128
129 // Multi tags
130 $link = $data[3];
131 $this->assertEquals(7, count($link['tags']));
132
133 // Update date
134 $this->assertEquals(
135 \DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160803_093033')->format(\DateTime::ATOM),
136 $link['updated']
137 );
138 }
139
140 /**
141 * Test getLinks service with offset and limit parameter:
142 * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
143 */
144 public function testGetLinksOffsetLimit()
145 {
146 $env = Environment::mock([
147 'REQUEST_METHOD' => 'GET',
148 'QUERY_STRING' => 'offset=3&limit=1'
149 ]);
150 $request = Request::createFromEnvironment($env);
151 $response = $this->controller->getLinks($request, new Response());
152 $this->assertEquals(200, $response->getStatusCode());
153 $data = json_decode((string) $response->getBody(), true);
154 $this->assertEquals(1, count($data));
155 $this->assertEquals(8, $data[0]['id']);
156 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
157 }
158
159 /**
160 * Test getLinks with limit=all (return all link).
161 */
162 public function testGetLinksLimitAll()
163 {
164 $env = Environment::mock([
165 'REQUEST_METHOD' => 'GET',
166 'QUERY_STRING' => 'limit=all'
167 ]);
168 $request = Request::createFromEnvironment($env);
169 $response = $this->controller->getLinks($request, new Response());
170 $this->assertEquals(200, $response->getStatusCode());
171 $data = json_decode((string) $response->getBody(), true);
172 $this->assertEquals($this->refDB->countLinks(), count($data));
173 // Check order
174 $order = [10, 11, 41, 8, 6, 7, 0, 1, 9, 4, 42];
175 $cpt = 0;
176 foreach ($data as $link) {
177 $this->assertEquals(self::NB_FIELDS_LINK, count($link));
178 $this->assertEquals($order[$cpt++], $link['id']);
179 }
180 }
181
182 /**
183 * Test getLinks service with offset and limit parameter:
184 * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
185 */
186 public function testGetLinksOffsetTooHigh()
187 {
188 $env = Environment::mock([
189 'REQUEST_METHOD' => 'GET',
190 'QUERY_STRING' => 'offset=100'
191 ]);
192 $request = Request::createFromEnvironment($env);
193 $response = $this->controller->getLinks($request, new Response());
194 $this->assertEquals(200, $response->getStatusCode());
195 $data = json_decode((string) $response->getBody(), true);
196 $this->assertEmpty(count($data));
197 }
198
199 /**
200 * Test getLinks with visibility parameter set to all
201 */
202 public function testGetLinksVisibilityAll()
203 {
204 $env = Environment::mock(
205 [
206 'REQUEST_METHOD' => 'GET',
207 'QUERY_STRING' => 'visibility=all'
208 ]
209 );
210 $request = Request::createFromEnvironment($env);
211 $response = $this->controller->getLinks($request, new Response());
212 $this->assertEquals(200, $response->getStatusCode());
213 $data = json_decode((string)$response->getBody(), true);
214 $this->assertEquals($this->refDB->countLinks(), count($data));
215 $this->assertEquals(10, $data[0]['id']);
216 $this->assertEquals(41, $data[2]['id']);
217 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
218 }
219
220 /**
221 * Test getLinks with visibility parameter set to private
222 */
223 public function testGetLinksVisibilityPrivate()
224 {
225 $env = Environment::mock([
226 'REQUEST_METHOD' => 'GET',
227 'QUERY_STRING' => 'visibility=private'
228 ]);
229 $request = Request::createFromEnvironment($env);
230 $response = $this->controller->getLinks($request, new Response());
231 $this->assertEquals(200, $response->getStatusCode());
232 $data = json_decode((string) $response->getBody(), true);
233 $this->assertEquals($this->refDB->countPrivateLinks(), count($data));
234 $this->assertEquals(6, $data[0]['id']);
235 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
236 }
237
238 /**
239 * Test getLinks with visibility parameter set to public
240 */
241 public function testGetLinksVisibilityPublic()
242 {
243 $env = Environment::mock(
244 [
245 'REQUEST_METHOD' => 'GET',
246 'QUERY_STRING' => 'visibility=public'
247 ]
248 );
249 $request = Request::createFromEnvironment($env);
250 $response = $this->controller->getLinks($request, new Response());
251 $this->assertEquals(200, $response->getStatusCode());
252 $data = json_decode((string)$response->getBody(), true);
253 $this->assertEquals($this->refDB->countPublicLinks(), count($data));
254 $this->assertEquals(10, $data[0]['id']);
255 $this->assertEquals(41, $data[2]['id']);
256 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
257 }
258
259 /**
260 * Test getLinks service with offset and limit parameter:
261 * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
262 */
263 public function testGetLinksSearchTerm()
264 {
265 // Only in description - 1 result
266 $env = Environment::mock([
267 'REQUEST_METHOD' => 'GET',
268 'QUERY_STRING' => 'searchterm=Tropical'
269 ]);
270 $request = Request::createFromEnvironment($env);
271 $response = $this->controller->getLinks($request, new Response());
272 $this->assertEquals(200, $response->getStatusCode());
273 $data = json_decode((string) $response->getBody(), true);
274 $this->assertEquals(1, count($data));
275 $this->assertEquals(1, $data[0]['id']);
276 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
277
278 // Only in tags - 1 result
279 $env = Environment::mock([
280 'REQUEST_METHOD' => 'GET',
281 'QUERY_STRING' => 'searchterm=tag3'
282 ]);
283 $request = Request::createFromEnvironment($env);
284 $response = $this->controller->getLinks($request, new Response());
285 $this->assertEquals(200, $response->getStatusCode());
286 $data = json_decode((string) $response->getBody(), true);
287 $this->assertEquals(1, count($data));
288 $this->assertEquals(0, $data[0]['id']);
289 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
290
291 // Multiple results (2)
292 $env = Environment::mock([
293 'REQUEST_METHOD' => 'GET',
294 'QUERY_STRING' => 'searchterm=stallman'
295 ]);
296 $request = Request::createFromEnvironment($env);
297 $response = $this->controller->getLinks($request, new Response());
298 $this->assertEquals(200, $response->getStatusCode());
299 $data = json_decode((string) $response->getBody(), true);
300 $this->assertEquals(2, count($data));
301 $this->assertEquals(41, $data[0]['id']);
302 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
303 $this->assertEquals(8, $data[1]['id']);
304 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
305
306 // Multiword - 2 results
307 $env = Environment::mock([
308 'REQUEST_METHOD' => 'GET',
309 'QUERY_STRING' => 'searchterm=stallman+software'
310 ]);
311 $request = Request::createFromEnvironment($env);
312 $response = $this->controller->getLinks($request, new Response());
313 $this->assertEquals(200, $response->getStatusCode());
314 $data = json_decode((string) $response->getBody(), true);
315 $this->assertEquals(2, count($data));
316 $this->assertEquals(41, $data[0]['id']);
317 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
318 $this->assertEquals(8, $data[1]['id']);
319 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
320
321 // URL encoding
322 $env = Environment::mock([
323 'REQUEST_METHOD' => 'GET',
324 'QUERY_STRING' => 'searchterm='. urlencode('@web')
325 ]);
326 $request = Request::createFromEnvironment($env);
327 $response = $this->controller->getLinks($request, new Response());
328 $this->assertEquals(200, $response->getStatusCode());
329 $data = json_decode((string) $response->getBody(), true);
330 $this->assertEquals(2, count($data));
331 $this->assertEquals(41, $data[0]['id']);
332 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
333 $this->assertEquals(8, $data[1]['id']);
334 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
335 }
336
337 public function testGetLinksSearchTermNoResult()
338 {
339 $env = Environment::mock([
340 'REQUEST_METHOD' => 'GET',
341 'QUERY_STRING' => 'searchterm=nope'
342 ]);
343 $request = Request::createFromEnvironment($env);
344 $response = $this->controller->getLinks($request, new Response());
345 $this->assertEquals(200, $response->getStatusCode());
346 $data = json_decode((string) $response->getBody(), true);
347 $this->assertEquals(0, count($data));
348 }
349
350 public function testGetLinksSearchTags()
351 {
352 // Single tag
353 $env = Environment::mock([
354 'REQUEST_METHOD' => 'GET',
355 'QUERY_STRING' => 'searchtags=dev',
356 ]);
357 $request = Request::createFromEnvironment($env);
358 $response = $this->controller->getLinks($request, new Response());
359 $this->assertEquals(200, $response->getStatusCode());
360 $data = json_decode((string) $response->getBody(), true);
361 $this->assertEquals(2, count($data));
362 $this->assertEquals(0, $data[0]['id']);
363 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
364 $this->assertEquals(4, $data[1]['id']);
365 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
366
367 // Multitag + exclude
368 $env = Environment::mock([
369 'REQUEST_METHOD' => 'GET',
370 'QUERY_STRING' => 'searchtags=stuff+-gnu',
371 ]);
372 $request = Request::createFromEnvironment($env);
373 $response = $this->controller->getLinks($request, new Response());
374 $this->assertEquals(200, $response->getStatusCode());
375 $data = json_decode((string) $response->getBody(), true);
376 $this->assertEquals(1, count($data));
377 $this->assertEquals(41, $data[0]['id']);
378 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
379
380 // wildcard: placeholder at the start
381 $env = Environment::mock([
382 'REQUEST_METHOD' => 'GET',
383 'QUERY_STRING' => 'searchtags=*Tuff',
384 ]);
385 $request = Request::createFromEnvironment($env);
386 $response = $this->controller->getLinks($request, new Response());
387 $this->assertEquals(200, $response->getStatusCode());
388 $data = json_decode((string) $response->getBody(), true);
389 $this->assertEquals(2, count($data));
390 $this->assertEquals(41, $data[0]['id']);
391
392 // wildcard: placeholder at the end
393 $env = Environment::mock([
394 'REQUEST_METHOD' => 'GET',
395 'QUERY_STRING' => 'searchtags=c*',
396 ]);
397 $request = Request::createFromEnvironment($env);
398 $response = $this->controller->getLinks($request, new Response());
399 $this->assertEquals(200, $response->getStatusCode());
400 $data = json_decode((string) $response->getBody(), true);
401 $this->assertEquals(5, count($data));
402 $this->assertEquals(6, $data[0]['id']);
403
404 // wildcard: placeholder at the middle
405 $env = Environment::mock([
406 'REQUEST_METHOD' => 'GET',
407 'QUERY_STRING' => 'searchtags=w*b',
408 ]);
409 $request = Request::createFromEnvironment($env);
410 $response = $this->controller->getLinks($request, new Response());
411 $this->assertEquals(200, $response->getStatusCode());
412 $data = json_decode((string) $response->getBody(), true);
413 $this->assertEquals(4, count($data));
414 $this->assertEquals(6, $data[0]['id']);
415
416 // wildcard: match all
417 $env = Environment::mock([
418 'REQUEST_METHOD' => 'GET',
419 'QUERY_STRING' => 'searchtags=*',
420 ]);
421 $request = Request::createFromEnvironment($env);
422 $response = $this->controller->getLinks($request, new Response());
423 $this->assertEquals(200, $response->getStatusCode());
424 $data = json_decode((string) $response->getBody(), true);
425 $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, count($data));
426 $this->assertEquals(10, $data[0]['id']);
427 $this->assertEquals(41, $data[2]['id']);
428
429 // wildcard: optional ('*' does not need to expand)
430 $env = Environment::mock([
431 'REQUEST_METHOD' => 'GET',
432 'QUERY_STRING' => 'searchtags=*stuff*',
433 ]);
434 $request = Request::createFromEnvironment($env);
435 $response = $this->controller->getLinks($request, new Response());
436 $this->assertEquals(200, $response->getStatusCode());
437 $data = json_decode((string) $response->getBody(), true);
438 $this->assertEquals(2, count($data));
439 $this->assertEquals(41, $data[0]['id']);
440
441 // wildcard: exclusions
442 $env = Environment::mock([
443 'REQUEST_METHOD' => 'GET',
444 'QUERY_STRING' => 'searchtags=*a*+-*e*',
445 ]);
446 $request = Request::createFromEnvironment($env);
447 $response = $this->controller->getLinks($request, new Response());
448 $this->assertEquals(200, $response->getStatusCode());
449 $data = json_decode((string) $response->getBody(), true);
450 $this->assertEquals(1, count($data));
451 $this->assertEquals(41, $data[0]['id']); // finds '#hashtag' in descr.
452
453 // wildcard: exclude all
454 $env = Environment::mock([
455 'REQUEST_METHOD' => 'GET',
456 'QUERY_STRING' => 'searchtags=-*',
457 ]);
458 $request = Request::createFromEnvironment($env);
459 $response = $this->controller->getLinks($request, new Response());
460 $this->assertEquals(200, $response->getStatusCode());
461 $data = json_decode((string) $response->getBody(), true);
462 $this->assertEquals(0, count($data));
463 }
464
465 /**
466 * Test getLinks service with search tags+terms.
467 */
468 public function testGetLinksSearchTermsAndTags()
469 {
470 $env = Environment::mock([
471 'REQUEST_METHOD' => 'GET',
472 'QUERY_STRING' => 'searchterm=poke&searchtags=dev',
473 ]);
474 $request = Request::createFromEnvironment($env);
475 $response = $this->controller->getLinks($request, new Response());
476 $this->assertEquals(200, $response->getStatusCode());
477 $data = json_decode((string) $response->getBody(), true);
478 $this->assertEquals(1, count($data));
479 $this->assertEquals(0, $data[0]['id']);
480 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
481 }
482 }