]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - tests/LinkUtilsTest.php
lint: apply phpcbf to tests/
[github/shaarli/Shaarli.git] / tests / LinkUtilsTest.php
1 <?php
2
3 require_once 'application/LinkUtils.php';
4
5 /**
6 * Class LinkUtilsTest.
7 */
8 class LinkUtilsTest extends PHPUnit_Framework_TestCase
9 {
10 /**
11 * Test html_extract_title() when the title is found.
12 */
13 public function testHtmlExtractExistentTitle()
14 {
15 $title = 'Read me please.';
16 $html = '<html><meta>stuff</meta><title>'. $title .'</title></html>';
17 $this->assertEquals($title, html_extract_title($html));
18 $html = '<html><title>'. $title .'</title>blabla<title>another</title></html>';
19 $this->assertEquals($title, html_extract_title($html));
20 }
21
22 /**
23 * Test html_extract_title() when the title is not found.
24 */
25 public function testHtmlExtractNonExistentTitle()
26 {
27 $html = '<html><meta>stuff</meta></html>';
28 $this->assertFalse(html_extract_title($html));
29 }
30
31 /**
32 * Test headers_extract_charset() when the charset is found.
33 */
34 public function testHeadersExtractExistentCharset()
35 {
36 $charset = 'x-MacCroatian';
37 $headers = 'text/html; charset='. $charset;
38 $this->assertEquals(strtolower($charset), header_extract_charset($headers));
39 }
40
41 /**
42 * Test headers_extract_charset() when the charset is not found.
43 */
44 public function testHeadersExtractNonExistentCharset()
45 {
46 $headers = '';
47 $this->assertFalse(header_extract_charset($headers));
48
49 $headers = 'text/html';
50 $this->assertFalse(header_extract_charset($headers));
51 }
52
53 /**
54 * Test html_extract_charset() when the charset is found.
55 */
56 public function testHtmlExtractExistentCharset()
57 {
58 $charset = 'x-MacCroatian';
59 $html = '<html><meta>stuff2</meta><meta charset="'. $charset .'"/></html>';
60 $this->assertEquals(strtolower($charset), html_extract_charset($html));
61 }
62
63 /**
64 * Test html_extract_charset() when the charset is not found.
65 */
66 public function testHtmlExtractNonExistentCharset()
67 {
68 $html = '<html><meta>stuff</meta></html>';
69 $this->assertFalse(html_extract_charset($html));
70 $html = '<html><meta>stuff</meta><meta charset=""/></html>';
71 $this->assertFalse(html_extract_charset($html));
72 }
73
74 /**
75 * Test the download callback with valid value
76 */
77 public function testCurlDownloadCallbackOk()
78 {
79 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok');
80 $data = [
81 'HTTP/1.1 200 OK',
82 'Server: GitHub.com',
83 'Date: Sat, 28 Oct 2017 12:01:33 GMT',
84 'Content-Type: text/html; charset=utf-8',
85 'Status: 200 OK',
86 'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
87 '<title>ignored</title>',
88 ];
89 foreach ($data as $key => $line) {
90 $ignore = null;
91 $expected = $key !== 'end' ? strlen($line) : false;
92 $this->assertEquals($expected, $callback($ignore, $line));
93 if ($expected === false) {
94 break;
95 }
96 }
97 $this->assertEquals('utf-8', $charset);
98 $this->assertEquals('Refactoring · GitHub', $title);
99 }
100
101 /**
102 * Test the download callback with valid values and no charset
103 */
104 public function testCurlDownloadCallbackOkNoCharset()
105 {
106 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
107 $data = [
108 'HTTP/1.1 200 OK',
109 'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
110 '<title>ignored</title>',
111 ];
112 foreach ($data as $key => $line) {
113 $ignore = null;
114 $this->assertEquals(strlen($line), $callback($ignore, $line));
115 }
116 $this->assertEmpty($charset);
117 $this->assertEquals('Refactoring · GitHub', $title);
118 }
119
120 /**
121 * Test the download callback with valid values and no charset
122 */
123 public function testCurlDownloadCallbackOkHtmlCharset()
124 {
125 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
126 $data = [
127 'HTTP/1.1 200 OK',
128 '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',
129 'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
130 '<title>ignored</title>',
131 ];
132 foreach ($data as $key => $line) {
133 $ignore = null;
134 $expected = $key !== 'end' ? strlen($line) : false;
135 $this->assertEquals($expected, $callback($ignore, $line));
136 if ($expected === false) {
137 break;
138 }
139 }
140 $this->assertEquals('utf-8', $charset);
141 $this->assertEquals('Refactoring · GitHub', $title);
142 }
143
144 /**
145 * Test the download callback with valid values and no title
146 */
147 public function testCurlDownloadCallbackOkNoTitle()
148 {
149 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok');
150 $data = [
151 'HTTP/1.1 200 OK',
152 'end' => 'th=device-width">Refactoring · GitHub<link rel="search" type="application/opensea',
153 'ignored',
154 ];
155 foreach ($data as $key => $line) {
156 $ignore = null;
157 $this->assertEquals(strlen($line), $callback($ignore, $line));
158 }
159 $this->assertEquals('utf-8', $charset);
160 $this->assertEmpty($title);
161 }
162
163 /**
164 * Test the download callback with an invalid content type.
165 */
166 public function testCurlDownloadCallbackInvalidContentType()
167 {
168 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ct_ko');
169 $ignore = null;
170 $this->assertFalse($callback($ignore, ''));
171 $this->assertEmpty($charset);
172 $this->assertEmpty($title);
173 }
174
175 /**
176 * Test the download callback with an invalid response code.
177 */
178 public function testCurlDownloadCallbackInvalidResponseCode()
179 {
180 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rc_ko');
181 $ignore = null;
182 $this->assertFalse($callback($ignore, ''));
183 $this->assertEmpty($charset);
184 $this->assertEmpty($title);
185 }
186
187 /**
188 * Test the download callback with an invalid content type and response code.
189 */
190 public function testCurlDownloadCallbackInvalidContentTypeAndResponseCode()
191 {
192 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rs_ct_ko');
193 $ignore = null;
194 $this->assertFalse($callback($ignore, ''));
195 $this->assertEmpty($charset);
196 $this->assertEmpty($title);
197 }
198
199 /**
200 * Test count_private.
201 */
202 public function testCountPrivateLinks()
203 {
204 $refDB = new ReferenceLinkDB();
205 $this->assertEquals($refDB->countPrivateLinks(), count_private($refDB->getLinks()));
206 }
207
208 /**
209 * Test text2clickable without a redirector being set.
210 */
211 public function testText2clickableWithoutRedirector()
212 {
213 $text = 'stuff http://hello.there/is=someone#here otherstuff';
214 $expectedText = 'stuff <a href="http://hello.there/is=someone#here">http://hello.there/is=someone#here</a> otherstuff';
215 $processedText = text2clickable($text, '');
216 $this->assertEquals($expectedText, $processedText);
217
218 $text = 'stuff http://hello.there/is=someone#here(please) otherstuff';
219 $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)">http://hello.there/is=someone#here(please)</a> otherstuff';
220 $processedText = text2clickable($text, '');
221 $this->assertEquals($expectedText, $processedText);
222
223 $text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff';
224 $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)&no">http://hello.there/is=someone#here(please)&no</a> otherstuff';
225 $processedText = text2clickable($text, '');
226 $this->assertEquals($expectedText, $processedText);
227 }
228
229 /**
230 * Test text2clickable a redirector set.
231 */
232 public function testText2clickableWithRedirector()
233 {
234 $text = 'stuff http://hello.there/is=someone#here otherstuff';
235 $redirector = 'http://redirector.to';
236 $expectedText = 'stuff <a href="'.
237 $redirector .
238 urlencode('http://hello.there/is=someone#here') .
239 '">http://hello.there/is=someone#here</a> otherstuff';
240 $processedText = text2clickable($text, $redirector);
241 $this->assertEquals($expectedText, $processedText);
242 }
243
244 /**
245 * Test text2clickable a redirector set and without URL encode.
246 */
247 public function testText2clickableWithRedirectorDontEncode()
248 {
249 $text = 'stuff http://hello.there/?is=someone&or=something#here otherstuff';
250 $redirector = 'http://redirector.to';
251 $expectedText = 'stuff <a href="'.
252 $redirector .
253 'http://hello.there/?is=someone&or=something#here' .
254 '">http://hello.there/?is=someone&or=something#here</a> otherstuff';
255 $processedText = text2clickable($text, $redirector, false);
256 $this->assertEquals($expectedText, $processedText);
257 }
258
259 /**
260 * Test testSpace2nbsp.
261 */
262 public function testSpace2nbsp()
263 {
264 $text = ' Are you thrilled by flags ?'. PHP_EOL .' Really?';
265 $expectedText = '&nbsp; Are you &nbsp; thrilled &nbsp;by flags &nbsp; ?'. PHP_EOL .'&nbsp;Really?';
266 $processedText = space2nbsp($text);
267 $this->assertEquals($expectedText, $processedText);
268 }
269
270 /**
271 * Test hashtags auto-link.
272 */
273 public function testHashtagAutolink()
274 {
275 $index = 'http://domain.tld/';
276 $rawDescription = '#hashtag\n
277 # nothashtag\n
278 test#nothashtag #hashtag \#nothashtag\n
279 test #hashtag #hashtag test #hashtag.test\n
280 #hashtag #hashtag-nothashtag #hashtag_hashtag\n
281 What is #ашок anyway?\n
282 カタカナ #カタカナ」カタカナ\n';
283 $autolinkedDescription = hashtag_autolink($rawDescription, $index);
284
285 $this->assertContains($this->getHashtagLink('hashtag', $index), $autolinkedDescription);
286 $this->assertNotContains(' #hashtag', $autolinkedDescription);
287 $this->assertNotContains('>#nothashtag', $autolinkedDescription);
288 $this->assertContains($this->getHashtagLink('ашок', $index), $autolinkedDescription);
289 $this->assertContains($this->getHashtagLink('カタカナ', $index), $autolinkedDescription);
290 $this->assertContains($this->getHashtagLink('hashtag_hashtag', $index), $autolinkedDescription);
291 $this->assertNotContains($this->getHashtagLink('hashtag-nothashtag', $index), $autolinkedDescription);
292 }
293
294 /**
295 * Test hashtags auto-link without index URL.
296 */
297 public function testHashtagAutolinkNoIndex()
298 {
299 $rawDescription = 'blabla #hashtag x#nothashtag';
300 $autolinkedDescription = hashtag_autolink($rawDescription);
301
302 $this->assertContains($this->getHashtagLink('hashtag'), $autolinkedDescription);
303 $this->assertNotContains(' #hashtag', $autolinkedDescription);
304 $this->assertNotContains('>#nothashtag', $autolinkedDescription);
305 }
306
307 /**
308 * Util function to build an hashtag link.
309 *
310 * @param string $hashtag Hashtag name.
311 * @param string $index Index URL.
312 *
313 * @return string HTML hashtag link.
314 */
315 private function getHashtagLink($hashtag, $index = '')
316 {
317 $hashtagLink = '<a href="'. $index .'?addtag=$1" title="Hashtag $1">#$1</a>';
318 return str_replace('$1', $hashtag, $hashtagLink);
319 }
320 }
321
322 // old style mock: PHPUnit doesn't allow function mock
323
324 /**
325 * Returns code 200 or html content type.
326 *
327 * @param resource $ch cURL resource
328 * @param int $type cURL info type
329 *
330 * @return int|string 200 or 'text/html'
331 */
332 function ut_curl_getinfo_ok($ch, $type)
333 {
334 switch ($type) {
335 case CURLINFO_RESPONSE_CODE:
336 return 200;
337 case CURLINFO_CONTENT_TYPE:
338 return 'text/html; charset=utf-8';
339 }
340 }
341
342 /**
343 * Returns code 200 or html content type without charset.
344 *
345 * @param resource $ch cURL resource
346 * @param int $type cURL info type
347 *
348 * @return int|string 200 or 'text/html'
349 */
350 function ut_curl_getinfo_no_charset($ch, $type)
351 {
352 switch ($type) {
353 case CURLINFO_RESPONSE_CODE:
354 return 200;
355 case CURLINFO_CONTENT_TYPE:
356 return 'text/html';
357 }
358 }
359
360 /**
361 * Invalid response code.
362 *
363 * @param resource $ch cURL resource
364 * @param int $type cURL info type
365 *
366 * @return int|string 404 or 'text/html'
367 */
368 function ut_curl_getinfo_rc_ko($ch, $type)
369 {
370 switch ($type) {
371 case CURLINFO_RESPONSE_CODE:
372 return 404;
373 case CURLINFO_CONTENT_TYPE:
374 return 'text/html; charset=utf-8';
375 }
376 }
377
378 /**
379 * Invalid content type.
380 *
381 * @param resource $ch cURL resource
382 * @param int $type cURL info type
383 *
384 * @return int|string 200 or 'text/plain'
385 */
386 function ut_curl_getinfo_ct_ko($ch, $type)
387 {
388 switch ($type) {
389 case CURLINFO_RESPONSE_CODE:
390 return 200;
391 case CURLINFO_CONTENT_TYPE:
392 return 'text/plain';
393 }
394 }
395
396 /**
397 * Invalid response code and content type.
398 *
399 * @param resource $ch cURL resource
400 * @param int $type cURL info type
401 *
402 * @return int|string 404 or 'text/plain'
403 */
404 function ut_curl_getinfo_rs_ct_ko($ch, $type)
405 {
406 switch ($type) {
407 case CURLINFO_RESPONSE_CODE:
408 return 404;
409 case CURLINFO_CONTENT_TYPE:
410 return 'text/plain';
411 }
412 }