]> git.immae.eu Git - github/wallabag/wallabag.git/blob - tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php
Validate language & preview picture fields
[github/wallabag/wallabag.git] / tests / Wallabag / CoreBundle / Helper / ContentProxyTest.php
1 <?php
2
3 namespace Tests\Wallabag\CoreBundle\Helper;
4
5 use Psr\Log\NullLogger;
6 use Monolog\Logger;
7 use Monolog\Handler\TestHandler;
8 use Wallabag\CoreBundle\Helper\ContentProxy;
9 use Wallabag\CoreBundle\Entity\Entry;
10 use Wallabag\CoreBundle\Entity\Tag;
11 use Wallabag\UserBundle\Entity\User;
12 use Wallabag\CoreBundle\Helper\RuleBasedTagger;
13 use Graby\Graby;
14 use Symfony\Component\Validator\Validator\RecursiveValidator;
15 use Symfony\Component\Validator\ConstraintViolationList;
16 use Symfony\Component\Validator\ConstraintViolation;
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);
44 $entry = new Entry(new User());
45 $proxy->updateEntry($entry, 'http://user@:80');
46
47 $this->assertEquals('http://user@:80', $entry->getUrl());
48 $this->assertEmpty($entry->getTitle());
49 $this->assertEquals($this->fetchingErrorMessage, $entry->getContent());
50 $this->assertEmpty($entry->getPreviewPicture());
51 $this->assertEmpty($entry->getMimetype());
52 $this->assertEmpty($entry->getLanguage());
53 $this->assertEquals(0.0, $entry->getReadingTime());
54 $this->assertEquals(false, $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);
79 $entry = new Entry(new User());
80 $proxy->updateEntry($entry, 'http://0.0.0.0');
81
82 $this->assertEquals('http://0.0.0.0', $entry->getUrl());
83 $this->assertEmpty($entry->getTitle());
84 $this->assertEquals($this->fetchingErrorMessage, $entry->getContent());
85 $this->assertEmpty($entry->getPreviewPicture());
86 $this->assertEmpty($entry->getMimetype());
87 $this->assertEmpty($entry->getLanguage());
88 $this->assertEquals(0.0, $entry->getReadingTime());
89 $this->assertEquals('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);
119 $entry = new Entry(new User());
120 $proxy->updateEntry($entry, 'http://domain.io');
121
122 $this->assertEquals('http://domain.io', $entry->getUrl());
123 $this->assertEquals('my title', $entry->getTitle());
124 $this->assertEquals($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->assertEquals(0.0, $entry->getReadingTime());
130 $this->assertEquals('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);
161 $entry = new Entry(new User());
162 $proxy->updateEntry($entry, 'http://0.0.0.0');
163
164 $this->assertEquals('http://1.1.1.1', $entry->getUrl());
165 $this->assertEquals('this is my title', $entry->getTitle());
166 $this->assertContains('this is my content', $entry->getContent());
167 $this->assertEquals('http://3.3.3.3/cover.jpg', $entry->getPreviewPicture());
168 $this->assertEquals('text/html', $entry->getMimetype());
169 $this->assertEquals('fr', $entry->getLanguage());
170 $this->assertEquals('200', $entry->getHttpStatus());
171 $this->assertEquals(4.0, $entry->getReadingTime());
172 $this->assertEquals('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);
203 $entry = new Entry(new User());
204 $proxy->updateEntry($entry, 'http://0.0.0.0');
205
206 $this->assertEquals('http://1.1.1.1', $entry->getUrl());
207 $this->assertEquals('this is my title', $entry->getTitle());
208 $this->assertContains('this is my content', $entry->getContent());
209 $this->assertEmpty($entry->getPreviewPicture());
210 $this->assertEquals('text/html', $entry->getMimetype());
211 $this->assertEquals('fr', $entry->getLanguage());
212 $this->assertEquals('200', $entry->getHttpStatus());
213 $this->assertEquals(4.0, $entry->getReadingTime());
214 $this->assertEquals('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->exactly(2))
225 ->method('validate')
226 ->will($this->onConsecutiveCalls(
227 new ConstraintViolationList([new ConstraintViolation('oops', 'oops', [], 'oops', 'language', 'dontexist')]),
228 new ConstraintViolationList()
229 ));
230
231 $graby = $this->getMockBuilder('Graby\Graby')
232 ->setMethods(['fetchContent'])
233 ->disableOriginalConstructor()
234 ->getMock();
235
236 $graby->expects($this->any())
237 ->method('fetchContent')
238 ->willReturn([
239 'html' => str_repeat('this is my content', 325),
240 'title' => 'this is my title',
241 'url' => 'http://1.1.1.1',
242 'content_type' => 'text/html',
243 'language' => 'dontexist',
244 'status' => '200',
245 ]);
246
247 $proxy = new ContentProxy($graby, $tagger, $validator, $this->getLogger(), $this->fetchingErrorMessage);
248 $entry = new Entry(new User());
249 $proxy->updateEntry($entry, 'http://0.0.0.0');
250
251 $this->assertEquals('http://1.1.1.1', $entry->getUrl());
252 $this->assertEquals('this is my title', $entry->getTitle());
253 $this->assertContains('this is my content', $entry->getContent());
254 $this->assertEquals('text/html', $entry->getMimetype());
255 $this->assertEmpty($entry->getLanguage());
256 $this->assertEquals('200', $entry->getHttpStatus());
257 $this->assertEquals(4.0, $entry->getReadingTime());
258 $this->assertEquals('1.1.1.1', $entry->getDomainName());
259 }
260
261 public function testWithContentAndBadOgImage()
262 {
263 $tagger = $this->getTaggerMock();
264 $tagger->expects($this->once())
265 ->method('tag');
266
267 $validator = $this->getValidator();
268 $validator->expects($this->exactly(2))
269 ->method('validate')
270 ->will($this->onConsecutiveCalls(
271 new ConstraintViolationList(),
272 new ConstraintViolationList([new ConstraintViolation('oops', 'oops', [], 'oops', 'url', 'https://')])
273 ));
274
275 $graby = $this->getMockBuilder('Graby\Graby')
276 ->setMethods(['fetchContent'])
277 ->disableOriginalConstructor()
278 ->getMock();
279
280 $graby->expects($this->any())
281 ->method('fetchContent')
282 ->willReturn([
283 'html' => str_repeat('this is my content', 325),
284 'title' => 'this is my title',
285 'url' => 'http://1.1.1.1',
286 'content_type' => 'text/html',
287 'language' => 'fr',
288 'status' => '200',
289 'open_graph' => [
290 'og_title' => 'my OG title',
291 'og_description' => 'OG desc',
292 'og_image' => 'https://',
293 ],
294 ]);
295
296 $proxy = new ContentProxy($graby, $tagger, $validator, $this->getLogger(), $this->fetchingErrorMessage);
297 $entry = new Entry(new User());
298 $proxy->updateEntry($entry, 'http://0.0.0.0');
299
300 $this->assertEquals('http://1.1.1.1', $entry->getUrl());
301 $this->assertEquals('this is my title', $entry->getTitle());
302 $this->assertContains('this is my content', $entry->getContent());
303 $this->assertEmpty($entry->getPreviewPicture());
304 $this->assertEquals('text/html', $entry->getMimetype());
305 $this->assertEquals('fr', $entry->getLanguage());
306 $this->assertEquals('200', $entry->getHttpStatus());
307 $this->assertEquals(4.0, $entry->getReadingTime());
308 $this->assertEquals('1.1.1.1', $entry->getDomainName());
309 }
310
311 public function testWithForcedContent()
312 {
313 $tagger = $this->getTaggerMock();
314 $tagger->expects($this->once())
315 ->method('tag');
316
317 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
318 $entry = new Entry(new User());
319 $proxy->updateEntry(
320 $entry,
321 'http://0.0.0.0',
322 [
323 'html' => str_repeat('this is my content', 325),
324 'title' => 'this is my title',
325 'url' => 'http://1.1.1.1',
326 'content_type' => 'text/html',
327 'language' => 'fr',
328 'date' => '1395635872',
329 'authors' => ['Jeremy', 'Nico', 'Thomas'],
330 'all_headers' => [
331 'Cache-Control' => 'no-cache',
332 ],
333 ]
334 );
335
336 $this->assertEquals('http://1.1.1.1', $entry->getUrl());
337 $this->assertEquals('this is my title', $entry->getTitle());
338 $this->assertContains('this is my content', $entry->getContent());
339 $this->assertEquals('text/html', $entry->getMimetype());
340 $this->assertEquals('fr', $entry->getLanguage());
341 $this->assertEquals(4.0, $entry->getReadingTime());
342 $this->assertEquals('1.1.1.1', $entry->getDomainName());
343 $this->assertEquals('24/03/2014', $entry->getPublishedAt()->format('d/m/Y'));
344 $this->assertContains('Jeremy', $entry->getPublishedBy());
345 $this->assertContains('Nico', $entry->getPublishedBy());
346 $this->assertContains('Thomas', $entry->getPublishedBy());
347 $this->assertContains('no-cache', $entry->getHeaders());
348 }
349
350 public function testWithForcedContentAndDatetime()
351 {
352 $tagger = $this->getTaggerMock();
353 $tagger->expects($this->once())
354 ->method('tag');
355
356 $logHandler = new TestHandler();
357 $logger = new Logger('test', [$logHandler]);
358
359 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $logger, $this->fetchingErrorMessage);
360 $entry = new Entry(new User());
361 $proxy->updateEntry(
362 $entry,
363 'http://1.1.1.1',
364 [
365 'html' => str_repeat('this is my content', 325),
366 'title' => 'this is my title',
367 'url' => 'http://1.1.1.1',
368 'content_type' => 'text/html',
369 'language' => 'fr',
370 'date' => '2016-09-08T11:55:58+0200',
371 ]
372 );
373
374 $this->assertEquals('http://1.1.1.1', $entry->getUrl());
375 $this->assertEquals('this is my title', $entry->getTitle());
376 $this->assertContains('this is my content', $entry->getContent());
377 $this->assertEquals('text/html', $entry->getMimetype());
378 $this->assertEquals('fr', $entry->getLanguage());
379 $this->assertEquals(4.0, $entry->getReadingTime());
380 $this->assertEquals('1.1.1.1', $entry->getDomainName());
381 $this->assertEquals('08/09/2016', $entry->getPublishedAt()->format('d/m/Y'));
382 }
383
384 public function testWithForcedContentAndBadDate()
385 {
386 $tagger = $this->getTaggerMock();
387 $tagger->expects($this->once())
388 ->method('tag');
389
390 $logger = new Logger('foo');
391 $handler = new TestHandler();
392 $logger->pushHandler($handler);
393
394 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $logger, $this->fetchingErrorMessage);
395 $entry = new Entry(new User());
396 $proxy->updateEntry(
397 $entry,
398 'http://1.1.1.1',
399 [
400 'html' => str_repeat('this is my content', 325),
401 'title' => 'this is my title',
402 'url' => 'http://1.1.1.1',
403 'content_type' => 'text/html',
404 'language' => 'fr',
405 'date' => '01 02 2012',
406 ]
407 );
408
409 $this->assertEquals('http://1.1.1.1', $entry->getUrl());
410 $this->assertEquals('this is my title', $entry->getTitle());
411 $this->assertContains('this is my content', $entry->getContent());
412 $this->assertEquals('text/html', $entry->getMimetype());
413 $this->assertEquals('fr', $entry->getLanguage());
414 $this->assertEquals(4.0, $entry->getReadingTime());
415 $this->assertEquals('1.1.1.1', $entry->getDomainName());
416 $this->assertNull($entry->getPublishedAt());
417
418 $records = $handler->getRecords();
419
420 $this->assertCount(1, $records);
421 $this->assertContains('Error while defining date', $records[0]['message']);
422 }
423
424 public function testTaggerThrowException()
425 {
426 $tagger = $this->getTaggerMock();
427 $tagger->expects($this->once())
428 ->method('tag')
429 ->will($this->throwException(new \Exception()));
430
431 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
432 $entry = new Entry(new User());
433 $proxy->updateEntry(
434 $entry,
435 'http://1.1.1.1',
436 [
437 'html' => str_repeat('this is my content', 325),
438 'title' => 'this is my title',
439 'url' => 'http://1.1.1.1',
440 'content_type' => 'text/html',
441 'language' => 'fr',
442 ]
443 );
444
445 $this->assertCount(0, $entry->getTags());
446 }
447
448 public function dataForCrazyHtml()
449 {
450 return [
451 'script and comment' => [
452 '<strong>Script inside:</strong> <!--[if gte IE 4]><script>alert(\'lol\');</script><![endif]--><br />',
453 'lol',
454 ],
455 'script' => [
456 '<strong>Script inside:</strong><script>alert(\'lol\');</script>',
457 'script',
458 ],
459 ];
460 }
461
462 /**
463 * @dataProvider dataForCrazyHtml
464 */
465 public function testWithCrazyHtmlContent($html, $escapedString)
466 {
467 $tagger = $this->getTaggerMock();
468 $tagger->expects($this->once())
469 ->method('tag');
470
471 $proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
472 $entry = new Entry(new User());
473 $proxy->updateEntry(
474 $entry,
475 'http://1.1.1.1',
476 [
477 'html' => $html,
478 'title' => 'this is my title',
479 'url' => 'http://1.1.1.1',
480 'content_type' => 'text/html',
481 'language' => 'fr',
482 'status' => '200',
483 'open_graph' => [
484 'og_title' => 'my OG title',
485 'og_description' => 'OG desc',
486 'og_image' => 'http://3.3.3.3/cover.jpg',
487 ],
488 ]
489 );
490
491 $this->assertEquals('http://1.1.1.1', $entry->getUrl());
492 $this->assertEquals('this is my title', $entry->getTitle());
493 $this->assertNotContains($escapedString, $entry->getContent());
494 $this->assertEquals('http://3.3.3.3/cover.jpg', $entry->getPreviewPicture());
495 $this->assertEquals('text/html', $entry->getMimetype());
496 $this->assertEquals('fr', $entry->getLanguage());
497 $this->assertEquals('200', $entry->getHttpStatus());
498 $this->assertEquals('1.1.1.1', $entry->getDomainName());
499 }
500
501 private function getTaggerMock()
502 {
503 return $this->getMockBuilder(RuleBasedTagger::class)
504 ->setMethods(['tag'])
505 ->disableOriginalConstructor()
506 ->getMock();
507 }
508
509 private function getLogger()
510 {
511 return new NullLogger();
512 }
513
514 private function getValidator()
515 {
516 return $this->getMockBuilder(RecursiveValidator::class)
517 ->setMethods(['validate'])
518 ->disableOriginalConstructor()
519 ->getMock();
520 }
521 }