]> git.immae.eu Git - github/wallabag/wallabag.git/blob - tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php
Added internal setting to enable/disable headers storage
[github/wallabag/wallabag.git] / tests / Wallabag / CoreBundle / Helper / ContentProxyTest.php
1 <?php
2
3 namespace Tests\Wallabag\CoreBundle\Helper;
4
5 use Graby\Graby;
6 use Monolog\Handler\TestHandler;
7 use Monolog\Logger;
8 use Psr\Log\NullLogger;
9 use Symfony\Component\Validator\ConstraintViolation;
10 use Symfony\Component\Validator\ConstraintViolationList;
11 use Symfony\Component\Validator\Validator\RecursiveValidator;
12 use Wallabag\CoreBundle\Entity\Entry;
13 use Wallabag\CoreBundle\Entity\Tag;
14 use Wallabag\CoreBundle\Helper\ContentProxy;
15 use Wallabag\CoreBundle\Helper\RuleBasedTagger;
16 use Wallabag\UserBundle\Entity\User;
17
18 class ContentProxyTest extends \PHPUnit_Framework_TestCase
19 {
20 private $fetchingErrorMessage = 'wallabag can\'t retrieve contents for this article. Please <a href="http://doc.wallabag.org/en/user/errors_during_fetching.html#how-can-i-help-to-fix-that">troubleshoot this issue</a>.';
21
22 public function testWithBadUrl()
23 {
24 $tagger = $this->getTaggerMock();
25 $tagger->expects($this->once())
26 ->method('tag');
27
28 $graby = $this->getMockBuilder('Graby\Graby')
29 ->setMethods(['fetchContent'])
30 ->disableOriginalConstructor()
31 ->getMock();
32
33 $graby->expects($this->any())
34 ->method('fetchContent')
35 ->willReturn([
36 'html' => false,
37 'title' => '',
38 'url' => '',
39 'content_type' => '',
40 'language' => '',
41 ]);
42
43 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage, false);
44 $entry = new Entry(new User());
45 $proxy->updateEntry($entry, 'http://user@:80');
46
47 $this->assertSame('http://user@:80', $entry->getUrl());
48 $this->assertEmpty($entry->getTitle());
49 $this->assertSame($this->fetchingErrorMessage, $entry->getContent());
50 $this->assertEmpty($entry->getPreviewPicture());
51 $this->assertEmpty($entry->getMimetype());
52 $this->assertEmpty($entry->getLanguage());
53 $this->assertSame(0.0, $entry->getReadingTime());
54 $this->assertSame(null, $entry->getDomainName());
55 }
56
57 public function testWithEmptyContent()
58 {
59 $tagger = $this->getTaggerMock();
60 $tagger->expects($this->once())
61 ->method('tag');
62
63 $graby = $this->getMockBuilder('Graby\Graby')
64 ->setMethods(['fetchContent'])
65 ->disableOriginalConstructor()
66 ->getMock();
67
68 $graby->expects($this->any())
69 ->method('fetchContent')
70 ->willReturn([
71 'html' => false,
72 'title' => '',
73 'url' => '',
74 'content_type' => '',
75 'language' => '',
76 ]);
77
78 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage, false);
79 $entry = new Entry(new User());
80 $proxy->updateEntry($entry, 'http://0.0.0.0');
81
82 $this->assertSame('http://0.0.0.0', $entry->getUrl());
83 $this->assertEmpty($entry->getTitle());
84 $this->assertSame($this->fetchingErrorMessage, $entry->getContent());
85 $this->assertEmpty($entry->getPreviewPicture());
86 $this->assertEmpty($entry->getMimetype());
87 $this->assertEmpty($entry->getLanguage());
88 $this->assertSame(0.0, $entry->getReadingTime());
89 $this->assertSame('0.0.0.0', $entry->getDomainName());
90 }
91
92 public function testWithEmptyContentButOG()
93 {
94 $tagger = $this->getTaggerMock();
95 $tagger->expects($this->once())
96 ->method('tag');
97
98 $graby = $this->getMockBuilder('Graby\Graby')
99 ->setMethods(['fetchContent'])
100 ->disableOriginalConstructor()
101 ->getMock();
102
103 $graby->expects($this->any())
104 ->method('fetchContent')
105 ->willReturn([
106 'html' => false,
107 'title' => '',
108 'url' => '',
109 'content_type' => '',
110 'language' => '',
111 'status' => '',
112 'open_graph' => [
113 'og_title' => 'my title',
114 'og_description' => 'desc',
115 ],
116 ]);
117
118 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage, false);
119 $entry = new Entry(new User());
120 $proxy->updateEntry($entry, 'http://domain.io');
121
122 $this->assertSame('http://domain.io', $entry->getUrl());
123 $this->assertSame('my title', $entry->getTitle());
124 $this->assertSame($this->fetchingErrorMessage . '<p><i>But we found a short description: </i></p>desc', $entry->getContent());
125 $this->assertEmpty($entry->getPreviewPicture());
126 $this->assertEmpty($entry->getLanguage());
127 $this->assertEmpty($entry->getHttpStatus());
128 $this->assertEmpty($entry->getMimetype());
129 $this->assertSame(0.0, $entry->getReadingTime());
130 $this->assertSame('domain.io', $entry->getDomainName());
131 }
132
133 public function testWithContent()
134 {
135 $tagger = $this->getTaggerMock();
136 $tagger->expects($this->once())
137 ->method('tag');
138
139 $graby = $this->getMockBuilder('Graby\Graby')
140 ->setMethods(['fetchContent'])
141 ->disableOriginalConstructor()
142 ->getMock();
143
144 $graby->expects($this->any())
145 ->method('fetchContent')
146 ->willReturn([
147 'html' => str_repeat('this is my content', 325),
148 'title' => 'this is my title',
149 'url' => 'http://1.1.1.1',
150 'content_type' => 'text/html',
151 'language' => 'fr',
152 'status' => '200',
153 'open_graph' => [
154 'og_title' => 'my OG title',
155 'og_description' => 'OG desc',
156 'og_image' => 'http://3.3.3.3/cover.jpg',
157 ],
158 ]);
159
160 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage, false);
161 $entry = new Entry(new User());
162 $proxy->updateEntry($entry, 'http://0.0.0.0');
163
164 $this->assertSame('http://1.1.1.1', $entry->getUrl());
165 $this->assertSame('this is my title', $entry->getTitle());
166 $this->assertContains('this is my content', $entry->getContent());
167 $this->assertSame('http://3.3.3.3/cover.jpg', $entry->getPreviewPicture());
168 $this->assertSame('text/html', $entry->getMimetype());
169 $this->assertSame('fr', $entry->getLanguage());
170 $this->assertSame('200', $entry->getHttpStatus());
171 $this->assertSame(4.0, $entry->getReadingTime());
172 $this->assertSame('1.1.1.1', $entry->getDomainName());
173 }
174
175 public function testWithContentAndNoOgImage()
176 {
177 $tagger = $this->getTaggerMock();
178 $tagger->expects($this->once())
179 ->method('tag');
180
181 $graby = $this->getMockBuilder('Graby\Graby')
182 ->setMethods(['fetchContent'])
183 ->disableOriginalConstructor()
184 ->getMock();
185
186 $graby->expects($this->any())
187 ->method('fetchContent')
188 ->willReturn([
189 'html' => str_repeat('this is my content', 325),
190 'title' => 'this is my title',
191 'url' => 'http://1.1.1.1',
192 'content_type' => 'text/html',
193 'language' => 'fr',
194 'status' => '200',
195 'open_graph' => [
196 'og_title' => 'my OG title',
197 'og_description' => 'OG desc',
198 'og_image' => null,
199 ],
200 ]);
201
202 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage, false);
203 $entry = new Entry(new User());
204 $proxy->updateEntry($entry, 'http://0.0.0.0');
205
206 $this->assertSame('http://1.1.1.1', $entry->getUrl());
207 $this->assertSame('this is my title', $entry->getTitle());
208 $this->assertContains('this is my content', $entry->getContent());
209 $this->assertNull($entry->getPreviewPicture());
210 $this->assertSame('text/html', $entry->getMimetype());
211 $this->assertSame('fr', $entry->getLanguage());
212 $this->assertSame('200', $entry->getHttpStatus());
213 $this->assertSame(4.0, $entry->getReadingTime());
214 $this->assertSame('1.1.1.1', $entry->getDomainName());
215 }
216
217 public function testWithContentAndBadLanguage()
218 {
219 $tagger = $this->getTaggerMock();
220 $tagger->expects($this->once())
221 ->method('tag');
222
223 $validator = $this->getValidator();
224 $validator->expects($this->once())
225 ->method('validate')
226 ->willReturn(new ConstraintViolationList([new ConstraintViolation('oops', 'oops', [], 'oops', 'language', 'dontexist')]));
227
228 $graby = $this->getMockBuilder('Graby\Graby')
229 ->setMethods(['fetchContent'])
230 ->disableOriginalConstructor()
231 ->getMock();
232
233 $graby->expects($this->any())
234 ->method('fetchContent')
235 ->willReturn([
236 'html' => str_repeat('this is my content', 325),
237 'title' => 'this is my title',
238 'url' => 'http://1.1.1.1',
239 'content_type' => 'text/html',
240 'language' => 'dontexist',
241 'status' => '200',
242 ]);
243
244 $proxy = new ContentProxy($graby, $tagger, $validator, $this->getLogger(), $this->fetchingErrorMessage, false);
245 $entry = new Entry(new User());
246 $proxy->updateEntry($entry, 'http://0.0.0.0');
247
248 $this->assertSame('http://1.1.1.1', $entry->getUrl());
249 $this->assertSame('this is my title', $entry->getTitle());
250 $this->assertContains('this is my content', $entry->getContent());
251 $this->assertSame('text/html', $entry->getMimetype());
252 $this->assertNull($entry->getLanguage());
253 $this->assertSame('200', $entry->getHttpStatus());
254 $this->assertSame(4.0, $entry->getReadingTime());
255 $this->assertSame('1.1.1.1', $entry->getDomainName());
256 }
257
258 public function testWithContentAndBadOgImage()
259 {
260 $tagger = $this->getTaggerMock();
261 $tagger->expects($this->once())
262 ->method('tag');
263
264 $validator = $this->getValidator();
265 $validator->expects($this->exactly(2))
266 ->method('validate')
267 ->will($this->onConsecutiveCalls(
268 new ConstraintViolationList(),
269 new ConstraintViolationList([new ConstraintViolation('oops', 'oops', [], 'oops', 'url', 'https://')])
270 ));
271
272 $graby = $this->getMockBuilder('Graby\Graby')
273 ->setMethods(['fetchContent'])
274 ->disableOriginalConstructor()
275 ->getMock();
276
277 $graby->expects($this->any())
278 ->method('fetchContent')
279 ->willReturn([
280 'html' => str_repeat('this is my content', 325),
281 'title' => 'this is my title',
282 'url' => 'http://1.1.1.1',
283 'content_type' => 'text/html',
284 'language' => 'fr',
285 'status' => '200',
286 'open_graph' => [
287 'og_title' => 'my OG title',
288 'og_description' => 'OG desc',
289 'og_image' => 'https://',
290 ],
291 ]);
292
293 $proxy = new ContentProxy($graby, $tagger, $validator, $this->getLogger(), $this->fetchingErrorMessage, false);
294 $entry = new Entry(new User());
295 $proxy->updateEntry($entry, 'http://0.0.0.0');
296
297 $this->assertSame('http://1.1.1.1', $entry->getUrl());
298 $this->assertSame('this is my title', $entry->getTitle());
299 $this->assertContains('this is my content', $entry->getContent());
300 $this->assertNull($entry->getPreviewPicture());
301 $this->assertSame('text/html', $entry->getMimetype());
302 $this->assertSame('fr', $entry->getLanguage());
303 $this->assertSame('200', $entry->getHttpStatus());
304 $this->assertSame(4.0, $entry->getReadingTime());
305 $this->assertSame('1.1.1.1', $entry->getDomainName());
306 }
307
308 public function testWithForcedContent()
309 {
310 $tagger = $this->getTaggerMock();
311 $tagger->expects($this->once())
312 ->method('tag');
313
314 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage, false);
315 $entry = new Entry(new User());
316 $proxy->updateEntry(
317 $entry,
318 'http://0.0.0.0',
319 [
320 'html' => str_repeat('this is my content', 325),
321 'title' => 'this is my title',
322 'url' => 'http://1.1.1.1',
323 'content_type' => 'text/html',
324 'language' => 'fr',
325 'date' => '1395635872',
326 'authors' => ['Jeremy', 'Nico', 'Thomas'],
327 'all_headers' => [
328 'Cache-Control' => 'no-cache',
329 ],
330 ]
331 );
332
333 $this->assertSame('http://1.1.1.1', $entry->getUrl());
334 $this->assertSame('this is my title', $entry->getTitle());
335 $this->assertContains('this is my content', $entry->getContent());
336 $this->assertSame('text/html', $entry->getMimetype());
337 $this->assertSame('fr', $entry->getLanguage());
338 $this->assertSame(4.0, $entry->getReadingTime());
339 $this->assertSame('1.1.1.1', $entry->getDomainName());
340 $this->assertSame('24/03/2014', $entry->getPublishedAt()->format('d/m/Y'));
341 $this->assertContains('Jeremy', $entry->getPublishedBy());
342 $this->assertContains('Nico', $entry->getPublishedBy());
343 $this->assertContains('Thomas', $entry->getPublishedBy());
344 $this->assertContains('no-cache', $entry->getHeaders());
345 }
346
347 public function testWithForcedContentAndDatetime()
348 {
349 $tagger = $this->getTaggerMock();
350 $tagger->expects($this->once())
351 ->method('tag');
352
353 $logHandler = new TestHandler();
354 $logger = new Logger('test', [$logHandler]);
355
356 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $logger, $this->fetchingErrorMessage, false);
357 $entry = new Entry(new User());
358 $proxy->updateEntry(
359 $entry,
360 'http://1.1.1.1',
361 [
362 'html' => str_repeat('this is my content', 325),
363 'title' => 'this is my title',
364 'url' => 'http://1.1.1.1',
365 'content_type' => 'text/html',
366 'language' => 'fr',
367 'date' => '2016-09-08T11:55:58+0200',
368 ]
369 );
370
371 $this->assertSame('http://1.1.1.1', $entry->getUrl());
372 $this->assertSame('this is my title', $entry->getTitle());
373 $this->assertContains('this is my content', $entry->getContent());
374 $this->assertSame('text/html', $entry->getMimetype());
375 $this->assertSame('fr', $entry->getLanguage());
376 $this->assertSame(4.0, $entry->getReadingTime());
377 $this->assertSame('1.1.1.1', $entry->getDomainName());
378 $this->assertSame('08/09/2016', $entry->getPublishedAt()->format('d/m/Y'));
379 }
380
381 public function testWithForcedContentAndBadDate()
382 {
383 $tagger = $this->getTaggerMock();
384 $tagger->expects($this->once())
385 ->method('tag');
386
387 $logger = new Logger('foo');
388 $handler = new TestHandler();
389 $logger->pushHandler($handler);
390
391 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $logger, $this->fetchingErrorMessage, false);
392 $entry = new Entry(new User());
393 $proxy->updateEntry(
394 $entry,
395 'http://1.1.1.1',
396 [
397 'html' => str_repeat('this is my content', 325),
398 'title' => 'this is my title',
399 'url' => 'http://1.1.1.1',
400 'content_type' => 'text/html',
401 'language' => 'fr',
402 'date' => '01 02 2012',
403 ]
404 );
405
406 $this->assertSame('http://1.1.1.1', $entry->getUrl());
407 $this->assertSame('this is my title', $entry->getTitle());
408 $this->assertContains('this is my content', $entry->getContent());
409 $this->assertSame('text/html', $entry->getMimetype());
410 $this->assertSame('fr', $entry->getLanguage());
411 $this->assertSame(4.0, $entry->getReadingTime());
412 $this->assertSame('1.1.1.1', $entry->getDomainName());
413 $this->assertNull($entry->getPublishedAt());
414
415 $records = $handler->getRecords();
416
417 $this->assertCount(1, $records);
418 $this->assertContains('Error while defining date', $records[0]['message']);
419 }
420
421 public function testTaggerThrowException()
422 {
423 $tagger = $this->getTaggerMock();
424 $tagger->expects($this->once())
425 ->method('tag')
426 ->will($this->throwException(new \Exception()));
427
428 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage, false);
429 $entry = new Entry(new User());
430 $proxy->updateEntry(
431 $entry,
432 'http://1.1.1.1',
433 [
434 'html' => str_repeat('this is my content', 325),
435 'title' => 'this is my title',
436 'url' => 'http://1.1.1.1',
437 'content_type' => 'text/html',
438 'language' => 'fr',
439 ]
440 );
441
442 $this->assertCount(0, $entry->getTags());
443 }
444
445 public function dataForCrazyHtml()
446 {
447 return [
448 'script and comment' => [
449 '<strong>Script inside:</strong> <!--[if gte IE 4]><script>alert(\'lol\');</script><![endif]--><br />',
450 'lol',
451 ],
452 'script' => [
453 '<strong>Script inside:</strong><script>alert(\'lol\');</script>',
454 'script',
455 ],
456 ];
457 }
458
459 /**
460 * @dataProvider dataForCrazyHtml
461 */
462 public function testWithCrazyHtmlContent($html, $escapedString)
463 {
464 $tagger = $this->getTaggerMock();
465 $tagger->expects($this->once())
466 ->method('tag');
467
468 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage, false);
469 $entry = new Entry(new User());
470 $proxy->updateEntry(
471 $entry,
472 'http://1.1.1.1',
473 [
474 'html' => $html,
475 'title' => 'this is my title',
476 'url' => 'http://1.1.1.1',
477 'content_type' => 'text/html',
478 'language' => 'fr',
479 'status' => '200',
480 'open_graph' => [
481 'og_title' => 'my OG title',
482 'og_description' => 'OG desc',
483 'og_image' => 'http://3.3.3.3/cover.jpg',
484 ],
485 ]
486 );
487
488 $this->assertSame('http://1.1.1.1', $entry->getUrl());
489 $this->assertSame('this is my title', $entry->getTitle());
490 $this->assertNotContains($escapedString, $entry->getContent());
491 $this->assertSame('http://3.3.3.3/cover.jpg', $entry->getPreviewPicture());
492 $this->assertSame('text/html', $entry->getMimetype());
493 $this->assertSame('fr', $entry->getLanguage());
494 $this->assertSame('200', $entry->getHttpStatus());
495 $this->assertSame('1.1.1.1', $entry->getDomainName());
496 }
497
498 public function testWithImageAsContent()
499 {
500 $tagger = $this->getTaggerMock();
501 $tagger->expects($this->once())
502 ->method('tag');
503
504 $graby = $this->getMockBuilder('Graby\Graby')
505 ->setMethods(['fetchContent'])
506 ->disableOriginalConstructor()
507 ->getMock();
508
509 $graby->expects($this->any())
510 ->method('fetchContent')
511 ->willReturn([
512 'html' => '<p><img src="http://1.1.1.1/image.jpg" /></p>',
513 'title' => 'this is my title',
514 'url' => 'http://1.1.1.1/image.jpg',
515 'content_type' => 'image/jpeg',
516 'status' => '200',
517 'open_graph' => [],
518 ]);
519
520 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage, false);
521 $entry = new Entry(new User());
522 $proxy->updateEntry($entry, 'http://0.0.0.0');
523
524 $this->assertSame('http://1.1.1.1/image.jpg', $entry->getUrl());
525 $this->assertSame('this is my title', $entry->getTitle());
526 $this->assertContains('http://1.1.1.1/image.jpg', $entry->getContent());
527 $this->assertSame('http://1.1.1.1/image.jpg', $entry->getPreviewPicture());
528 $this->assertSame('image/jpeg', $entry->getMimetype());
529 $this->assertSame('200', $entry->getHttpStatus());
530 $this->assertSame('1.1.1.1', $entry->getDomainName());
531 }
532
533 private function getTaggerMock()
534 {
535 return $this->getMockBuilder(RuleBasedTagger::class)
536 ->setMethods(['tag'])
537 ->disableOriginalConstructor()
538 ->getMock();
539 }
540
541 private function getLogger()
542 {
543 return new NullLogger();
544 }
545
546 private function getValidator()
547 {
548 return $this->getMockBuilder(RecursiveValidator::class)
549 ->setMethods(['validate'])
550 ->disableOriginalConstructor()
551 ->getMock();
552 }
553 }