3 namespace Tests\Wallabag\CoreBundle\Helper
;
6 use Monolog\Handler\TestHandler
;
8 use PHPUnit\Framework\TestCase
;
9 use Psr\Log\NullLogger
;
10 use Symfony\Component\Validator\ConstraintViolation
;
11 use Symfony\Component\Validator\ConstraintViolationList
;
12 use Symfony\Component\Validator\Validator\RecursiveValidator
;
13 use Wallabag\CoreBundle\Entity\Entry
;
14 use Wallabag\CoreBundle\Entity\Tag
;
15 use Wallabag\CoreBundle\Helper\ContentProxy
;
16 use Wallabag\CoreBundle\Helper\RuleBasedTagger
;
17 use Wallabag\UserBundle\Entity\User
;
19 class ContentProxyTest
extends TestCase
21 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>.';
23 public function testWithBadUrl()
25 $tagger = $this->getTaggerMock();
26 $tagger->expects($this->once())
29 $graby = $this->getMockBuilder('Graby\Graby')
30 ->setMethods(['fetchContent'])
31 ->disableOriginalConstructor()
34 $graby->expects($this->any())
35 ->method('fetchContent')
44 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage
);
45 $entry = new Entry(new User());
46 $proxy->updateEntry($entry, 'http://user@:80');
48 $this->assertSame('http://user@:80', $entry->getUrl());
49 $this->assertEmpty($entry->getTitle());
50 $this->assertSame($this->fetchingErrorMessage
, $entry->getContent());
51 $this->assertEmpty($entry->getPreviewPicture());
52 $this->assertEmpty($entry->getMimetype());
53 $this->assertEmpty($entry->getLanguage());
54 $this->assertSame(0.0, $entry->getReadingTime());
55 $this->assertNull($entry->getDomainName());
58 public function testWithEmptyContent()
60 $tagger = $this->getTaggerMock();
61 $tagger->expects($this->once())
64 $graby = $this->getMockBuilder('Graby\Graby')
65 ->setMethods(['fetchContent'])
66 ->disableOriginalConstructor()
69 $graby->expects($this->any())
70 ->method('fetchContent')
79 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage
);
80 $entry = new Entry(new User());
81 $proxy->updateEntry($entry, 'http://0.0.0.0');
83 $this->assertSame('http://0.0.0.0', $entry->getUrl());
84 $this->assertEmpty($entry->getTitle());
85 $this->assertSame($this->fetchingErrorMessage
, $entry->getContent());
86 $this->assertEmpty($entry->getPreviewPicture());
87 $this->assertEmpty($entry->getMimetype());
88 $this->assertEmpty($entry->getLanguage());
89 $this->assertSame(0.0, $entry->getReadingTime());
90 $this->assertSame('0.0.0.0', $entry->getDomainName());
93 public function testWithEmptyContentButOG()
95 $tagger = $this->getTaggerMock();
96 $tagger->expects($this->once())
99 $graby = $this->getMockBuilder('Graby\Graby')
100 ->setMethods(['fetchContent'])
101 ->disableOriginalConstructor()
104 $graby->expects($this->any())
105 ->method('fetchContent')
110 'content_type' => '',
114 'og_title' => 'my title',
115 'og_description' => 'desc',
119 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage
);
120 $entry = new Entry(new User());
121 $proxy->updateEntry($entry, 'http://domain.io');
123 $this->assertSame('http://domain.io', $entry->getUrl());
124 $this->assertSame('my title', $entry->getTitle());
125 $this->assertSame($this->fetchingErrorMessage
. '<p><i>But we found a short description: </i></p>desc', $entry->getContent());
126 $this->assertEmpty($entry->getPreviewPicture());
127 $this->assertEmpty($entry->getLanguage());
128 $this->assertEmpty($entry->getHttpStatus());
129 $this->assertEmpty($entry->getMimetype());
130 $this->assertSame(0.0, $entry->getReadingTime());
131 $this->assertSame('domain.io', $entry->getDomainName());
134 public function testWithContent()
136 $tagger = $this->getTaggerMock();
137 $tagger->expects($this->once())
140 $graby = $this->getMockBuilder('Graby\Graby')
141 ->setMethods(['fetchContent'])
142 ->disableOriginalConstructor()
145 $graby->expects($this->any())
146 ->method('fetchContent')
148 'html' => str_repeat('this is my content', 325),
149 'title' => 'this is my title',
150 'url' => 'http://1.1.1.1',
151 'content_type' => 'text/html',
155 'og_title' => 'my OG title',
156 'og_description' => 'OG desc',
157 'og_image' => 'http://3.3.3.3/cover.jpg',
161 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage
);
162 $entry = new Entry(new User());
163 $proxy->updateEntry($entry, 'http://0.0.0.0');
165 $this->assertSame('http://1.1.1.1', $entry->getUrl());
166 $this->assertSame('this is my title', $entry->getTitle());
167 $this->assertContains('this is my content', $entry->getContent());
168 $this->assertSame('http://3.3.3.3/cover.jpg', $entry->getPreviewPicture());
169 $this->assertSame('text/html', $entry->getMimetype());
170 $this->assertSame('fr', $entry->getLanguage());
171 $this->assertSame('200', $entry->getHttpStatus());
172 $this->assertSame(4.0, $entry->getReadingTime());
173 $this->assertSame('1.1.1.1', $entry->getDomainName());
176 public function testWithContentAndNoOgImage()
178 $tagger = $this->getTaggerMock();
179 $tagger->expects($this->once())
182 $graby = $this->getMockBuilder('Graby\Graby')
183 ->setMethods(['fetchContent'])
184 ->disableOriginalConstructor()
187 $graby->expects($this->any())
188 ->method('fetchContent')
190 'html' => str_repeat('this is my content', 325),
191 'title' => 'this is my title',
192 'url' => 'http://1.1.1.1',
193 'content_type' => 'text/html',
197 'og_title' => 'my OG title',
198 'og_description' => 'OG desc',
203 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage
);
204 $entry = new Entry(new User());
205 $proxy->updateEntry($entry, 'http://0.0.0.0');
207 $this->assertSame('http://1.1.1.1', $entry->getUrl());
208 $this->assertSame('this is my title', $entry->getTitle());
209 $this->assertContains('this is my content', $entry->getContent());
210 $this->assertNull($entry->getPreviewPicture());
211 $this->assertSame('text/html', $entry->getMimetype());
212 $this->assertSame('fr', $entry->getLanguage());
213 $this->assertSame('200', $entry->getHttpStatus());
214 $this->assertSame(4.0, $entry->getReadingTime());
215 $this->assertSame('1.1.1.1', $entry->getDomainName());
218 public function testWithContentAndBadLanguage()
220 $tagger = $this->getTaggerMock();
221 $tagger->expects($this->once())
224 $validator = $this->getValidator(false);
225 $validator->expects($this->once())
227 ->willReturn(new ConstraintViolationList([new ConstraintViolation('oops', 'oops', [], 'oops', 'language', 'dontexist')]));
229 $graby = $this->getMockBuilder('Graby\Graby')
230 ->setMethods(['fetchContent'])
231 ->disableOriginalConstructor()
234 $graby->expects($this->any())
235 ->method('fetchContent')
237 'html' => str_repeat('this is my content', 325),
238 'title' => 'this is my title',
239 'url' => 'http://1.1.1.1',
240 'content_type' => 'text/html',
241 'language' => 'dontexist',
245 $proxy = new ContentProxy($graby, $tagger, $validator, $this->getLogger(), $this->fetchingErrorMessage
);
246 $entry = new Entry(new User());
247 $proxy->updateEntry($entry, 'http://0.0.0.0');
249 $this->assertSame('http://1.1.1.1', $entry->getUrl());
250 $this->assertSame('this is my title', $entry->getTitle());
251 $this->assertContains('this is my content', $entry->getContent());
252 $this->assertSame('text/html', $entry->getMimetype());
253 $this->assertNull($entry->getLanguage());
254 $this->assertSame('200', $entry->getHttpStatus());
255 $this->assertSame(4.0, $entry->getReadingTime());
256 $this->assertSame('1.1.1.1', $entry->getDomainName());
259 public function testWithContentAndBadOgImage()
261 $tagger = $this->getTaggerMock();
262 $tagger->expects($this->once())
265 $validator = $this->getValidator(false);
266 $validator->expects($this->exactly(2))
268 ->will($this->onConsecutiveCalls(
269 new ConstraintViolationList(),
270 new ConstraintViolationList([new ConstraintViolation('oops', 'oops', [], 'oops', 'url', 'https://')])
273 $graby = $this->getMockBuilder('Graby\Graby')
274 ->setMethods(['fetchContent'])
275 ->disableOriginalConstructor()
278 $graby->expects($this->any())
279 ->method('fetchContent')
281 'html' => str_repeat('this is my content', 325),
282 'title' => 'this is my title',
283 'url' => 'http://1.1.1.1',
284 'content_type' => 'text/html',
288 'og_title' => 'my OG title',
289 'og_description' => 'OG desc',
290 'og_image' => 'https://',
294 $proxy = new ContentProxy($graby, $tagger, $validator, $this->getLogger(), $this->fetchingErrorMessage
);
295 $entry = new Entry(new User());
296 $proxy->updateEntry($entry, 'http://0.0.0.0');
298 $this->assertSame('http://1.1.1.1', $entry->getUrl());
299 $this->assertSame('this is my title', $entry->getTitle());
300 $this->assertContains('this is my content', $entry->getContent());
301 $this->assertNull($entry->getPreviewPicture());
302 $this->assertSame('text/html', $entry->getMimetype());
303 $this->assertSame('fr', $entry->getLanguage());
304 $this->assertSame('200', $entry->getHttpStatus());
305 $this->assertSame(4.0, $entry->getReadingTime());
306 $this->assertSame('1.1.1.1', $entry->getDomainName());
309 public function testWithForcedContent()
311 $tagger = $this->getTaggerMock();
312 $tagger->expects($this->once())
315 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage
, true);
316 $entry = new Entry(new User());
321 'html' => str_repeat('this is my content', 325),
322 'title' => 'this is my title',
323 'url' => 'http://1.1.1.1',
324 'content_type' => 'text/html',
326 'date' => '1395635872',
327 'authors' => ['Jeremy', 'Nico', 'Thomas'],
329 'Cache-Control' => 'no-cache',
334 $this->assertSame('http://1.1.1.1', $entry->getUrl());
335 $this->assertSame('this is my title', $entry->getTitle());
336 $this->assertContains('this is my content', $entry->getContent());
337 $this->assertSame('text/html', $entry->getMimetype());
338 $this->assertSame('fr', $entry->getLanguage());
339 $this->assertSame(4.0, $entry->getReadingTime());
340 $this->assertSame('1.1.1.1', $entry->getDomainName());
341 $this->assertSame('24/03/2014', $entry->getPublishedAt()->format('d/m/Y'));
342 $this->assertContains('Jeremy', $entry->getPublishedBy());
343 $this->assertContains('Nico', $entry->getPublishedBy());
344 $this->assertContains('Thomas', $entry->getPublishedBy());
345 $this->assertNotNull($entry->getHeaders(), 'Headers are stored, so value is not null');
346 $this->assertContains('no-cache', $entry->getHeaders());
349 public function testWithForcedContentAndDatetime()
351 $tagger = $this->getTaggerMock();
352 $tagger->expects($this->once())
355 $logHandler = new TestHandler();
356 $logger = new Logger('test', [$logHandler]);
358 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $logger, $this->fetchingErrorMessage
);
359 $entry = new Entry(new User());
364 'html' => str_repeat('this is my content', 325),
365 'title' => 'this is my title',
366 'url' => 'http://1.1.1.1',
367 'content_type' => 'text/html',
369 'date' => '2016-09-08T11:55:58+0200',
373 $this->assertSame('http://1.1.1.1', $entry->getUrl());
374 $this->assertSame('this is my title', $entry->getTitle());
375 $this->assertContains('this is my content', $entry->getContent());
376 $this->assertSame('text/html', $entry->getMimetype());
377 $this->assertSame('fr', $entry->getLanguage());
378 $this->assertSame(4.0, $entry->getReadingTime());
379 $this->assertSame('1.1.1.1', $entry->getDomainName());
380 $this->assertSame('08/09/2016', $entry->getPublishedAt()->format('d/m/Y'));
383 public function testWithForcedContentAndBadDate()
385 $tagger = $this->getTaggerMock();
386 $tagger->expects($this->once())
389 $logger = new Logger('foo');
390 $handler = new TestHandler();
391 $logger->pushHandler($handler);
393 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $logger, $this->fetchingErrorMessage
);
394 $entry = new Entry(new User());
399 'html' => str_repeat('this is my content', 325),
400 'title' => 'this is my title',
401 'url' => 'http://1.1.1.1',
402 'content_type' => 'text/html',
404 'date' => '01 02 2012',
408 $this->assertSame('http://1.1.1.1', $entry->getUrl());
409 $this->assertSame('this is my title', $entry->getTitle());
410 $this->assertContains('this is my content', $entry->getContent());
411 $this->assertSame('text/html', $entry->getMimetype());
412 $this->assertSame('fr', $entry->getLanguage());
413 $this->assertSame(4.0, $entry->getReadingTime());
414 $this->assertSame('1.1.1.1', $entry->getDomainName());
415 $this->assertNull($entry->getPublishedAt());
417 $records = $handler->getRecords();
419 $this->assertCount(1, $records);
420 $this->assertContains('Error while defining date', $records[0]['message']);
423 public function testTaggerThrowException()
425 $tagger = $this->getTaggerMock();
426 $tagger->expects($this->once())
428 ->will($this->throwException(new \
Exception()));
430 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage
);
431 $entry = new Entry(new User());
436 'html' => str_repeat('this is my content', 325),
437 'title' => 'this is my title',
438 'url' => 'http://1.1.1.1',
439 'content_type' => 'text/html',
444 $this->assertCount(0, $entry->getTags());
447 public function dataForCrazyHtml()
450 'script and comment' => [
451 '<strong>Script inside:</strong> <!--[if gte IE 4]><script>alert(\'lol\');</script><![endif]--><br />',
455 '<strong>Script inside:</strong><script>alert(\'lol\');</script>',
462 * @dataProvider dataForCrazyHtml
464 public function testWithCrazyHtmlContent($html, $escapedString)
466 $tagger = $this->getTaggerMock();
467 $tagger->expects($this->once())
470 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage
);
471 $entry = new Entry(new User());
477 'title' => 'this is my title',
478 'url' => 'http://1.1.1.1',
479 'content_type' => 'text/html',
483 'og_title' => 'my OG title',
484 'og_description' => 'OG desc',
485 'og_image' => 'http://3.3.3.3/cover.jpg',
490 $this->assertSame('http://1.1.1.1', $entry->getUrl());
491 $this->assertSame('this is my title', $entry->getTitle());
492 $this->assertNotContains($escapedString, $entry->getContent());
493 $this->assertSame('http://3.3.3.3/cover.jpg', $entry->getPreviewPicture());
494 $this->assertSame('text/html', $entry->getMimetype());
495 $this->assertSame('fr', $entry->getLanguage());
496 $this->assertSame('200', $entry->getHttpStatus());
497 $this->assertSame('1.1.1.1', $entry->getDomainName());
500 public function testWithImageAsContent()
502 $tagger = $this->getTaggerMock();
503 $tagger->expects($this->once())
506 $graby = $this->getMockBuilder('Graby\Graby')
507 ->setMethods(['fetchContent'])
508 ->disableOriginalConstructor()
511 $graby->expects($this->any())
512 ->method('fetchContent')
514 'html' => '<p><img src="http://1.1.1.1/image.jpg" /></p>',
515 'title' => 'this is my title',
516 'url' => 'http://1.1.1.1/image.jpg',
517 'content_type' => 'image/jpeg',
522 $proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage
);
523 $entry = new Entry(new User());
524 $proxy->updateEntry($entry, 'http://0.0.0.0');
526 $this->assertSame('http://1.1.1.1/image.jpg', $entry->getUrl());
527 $this->assertSame('this is my title', $entry->getTitle());
528 $this->assertContains('http://1.1.1.1/image.jpg', $entry->getContent());
529 $this->assertSame('http://1.1.1.1/image.jpg', $entry->getPreviewPicture());
530 $this->assertSame('image/jpeg', $entry->getMimetype());
531 $this->assertSame('200', $entry->getHttpStatus());
532 $this->assertSame('1.1.1.1', $entry->getDomainName());
535 private function getTaggerMock()
537 return $this->getMockBuilder(RuleBasedTagger
::class)
538 ->setMethods(['tag'])
539 ->disableOriginalConstructor()
543 private function getLogger()
545 return new NullLogger();
548 private function getValidator($withDefaultMock = true)
550 $mock = $this->getMockBuilder(RecursiveValidator
::class)
551 ->setMethods(['validate'])
552 ->disableOriginalConstructor()
555 if ($withDefaultMock) {
556 $mock->expects($this->any())
558 ->willReturn(new ConstraintViolationList());