]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - tests/LinkUtilsTest.php
namespacing: \Shaarli\Bookmark\LinkFilter
[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">'
87 .'<title>Refactoring · GitHub</title>'
88 .'<link rel="search" type="application/opensea',
89 '<title>ignored</title>',
90 ];
91 foreach ($data as $key => $line) {
92 $ignore = null;
93 $expected = $key !== 'end' ? strlen($line) : false;
94 $this->assertEquals($expected, $callback($ignore, $line));
95 if ($expected === false) {
96 break;
97 }
98 }
99 $this->assertEquals('utf-8', $charset);
100 $this->assertEquals('Refactoring · GitHub', $title);
101 }
102
103 /**
104 * Test the download callback with valid values and no charset
105 */
106 public function testCurlDownloadCallbackOkNoCharset()
107 {
108 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
109 $data = [
110 'HTTP/1.1 200 OK',
111 'end' => 'th=device-width">'
112 .'<title>Refactoring · GitHub</title>'
113 .'<link rel="search" type="application/opensea',
114 '<title>ignored</title>',
115 ];
116 foreach ($data as $key => $line) {
117 $ignore = null;
118 $this->assertEquals(strlen($line), $callback($ignore, $line));
119 }
120 $this->assertEmpty($charset);
121 $this->assertEquals('Refactoring · GitHub', $title);
122 }
123
124 /**
125 * Test the download callback with valid values and no charset
126 */
127 public function testCurlDownloadCallbackOkHtmlCharset()
128 {
129 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
130 $data = [
131 'HTTP/1.1 200 OK',
132 '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',
133 'end' => 'th=device-width">'
134 .'<title>Refactoring · GitHub</title>'
135 .'<link rel="search" type="application/opensea',
136 '<title>ignored</title>',
137 ];
138 foreach ($data as $key => $line) {
139 $ignore = null;
140 $expected = $key !== 'end' ? strlen($line) : false;
141 $this->assertEquals($expected, $callback($ignore, $line));
142 if ($expected === false) {
143 break;
144 }
145 }
146 $this->assertEquals('utf-8', $charset);
147 $this->assertEquals('Refactoring · GitHub', $title);
148 }
149
150 /**
151 * Test the download callback with valid values and no title
152 */
153 public function testCurlDownloadCallbackOkNoTitle()
154 {
155 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok');
156 $data = [
157 'HTTP/1.1 200 OK',
158 'end' => 'th=device-width">Refactoring · GitHub<link rel="search" type="application/opensea',
159 'ignored',
160 ];
161 foreach ($data as $key => $line) {
162 $ignore = null;
163 $this->assertEquals(strlen($line), $callback($ignore, $line));
164 }
165 $this->assertEquals('utf-8', $charset);
166 $this->assertEmpty($title);
167 }
168
169 /**
170 * Test the download callback with an invalid content type.
171 */
172 public function testCurlDownloadCallbackInvalidContentType()
173 {
174 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ct_ko');
175 $ignore = null;
176 $this->assertFalse($callback($ignore, ''));
177 $this->assertEmpty($charset);
178 $this->assertEmpty($title);
179 }
180
181 /**
182 * Test the download callback with an invalid response code.
183 */
184 public function testCurlDownloadCallbackInvalidResponseCode()
185 {
186 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rc_ko');
187 $ignore = null;
188 $this->assertFalse($callback($ignore, ''));
189 $this->assertEmpty($charset);
190 $this->assertEmpty($title);
191 }
192
193 /**
194 * Test the download callback with an invalid content type and response code.
195 */
196 public function testCurlDownloadCallbackInvalidContentTypeAndResponseCode()
197 {
198 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rs_ct_ko');
199 $ignore = null;
200 $this->assertFalse($callback($ignore, ''));
201 $this->assertEmpty($charset);
202 $this->assertEmpty($title);
203 }
204
205 /**
206 * Test count_private.
207 */
208 public function testCountPrivateLinks()
209 {
210 $refDB = new ReferenceLinkDB();
211 $this->assertEquals($refDB->countPrivateLinks(), count_private($refDB->getLinks()));
212 }
213
214 /**
215 * Test text2clickable without a redirector being set.
216 */
217 public function testText2clickableWithoutRedirector()
218 {
219 $text = 'stuff http://hello.there/is=someone#here otherstuff';
220 $expectedText = 'stuff <a href="http://hello.there/is=someone#here">'
221 .'http://hello.there/is=someone#here</a> otherstuff';
222 $processedText = text2clickable($text, '');
223 $this->assertEquals($expectedText, $processedText);
224
225 $text = 'stuff http://hello.there/is=someone#here(please) otherstuff';
226 $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)">'
227 .'http://hello.there/is=someone#here(please)</a> otherstuff';
228 $processedText = text2clickable($text, '');
229 $this->assertEquals($expectedText, $processedText);
230
231 $text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff';
232 $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)&no">'
233 .'http://hello.there/is=someone#here(please)&no</a> otherstuff';
234 $processedText = text2clickable($text, '');
235 $this->assertEquals($expectedText, $processedText);
236 }
237
238 /**
239 * Test text2clickable with a redirector set.
240 */
241 public function testText2clickableWithRedirector()
242 {
243 $text = 'stuff http://hello.there/is=someone#here otherstuff';
244 $redirector = 'http://redirector.to';
245 $expectedText = 'stuff <a href="'.
246 $redirector .
247 urlencode('http://hello.there/is=someone#here') .
248 '">http://hello.there/is=someone#here</a> otherstuff';
249 $processedText = text2clickable($text, $redirector);
250 $this->assertEquals($expectedText, $processedText);
251 }
252
253 /**
254 * Test text2clickable a redirector set and without URL encode.
255 */
256 public function testText2clickableWithRedirectorDontEncode()
257 {
258 $text = 'stuff http://hello.there/?is=someone&or=something#here otherstuff';
259 $redirector = 'http://redirector.to';
260 $expectedText = 'stuff <a href="'.
261 $redirector .
262 'http://hello.there/?is=someone&or=something#here' .
263 '">http://hello.there/?is=someone&or=something#here</a> otherstuff';
264 $processedText = text2clickable($text, $redirector, false);
265 $this->assertEquals($expectedText, $processedText);
266 }
267
268 /**
269 * Test testSpace2nbsp.
270 */
271 public function testSpace2nbsp()
272 {
273 $text = ' Are you thrilled by flags ?'. PHP_EOL .' Really?';
274 $expectedText = '&nbsp; Are you &nbsp; thrilled &nbsp;by flags &nbsp; ?'. PHP_EOL .'&nbsp;Really?';
275 $processedText = space2nbsp($text);
276 $this->assertEquals($expectedText, $processedText);
277 }
278
279 /**
280 * Test hashtags auto-link.
281 */
282 public function testHashtagAutolink()
283 {
284 $index = 'http://domain.tld/';
285 $rawDescription = '#hashtag\n
286 # nothashtag\n
287 test#nothashtag #hashtag \#nothashtag\n
288 test #hashtag #hashtag test #hashtag.test\n
289 #hashtag #hashtag-nothashtag #hashtag_hashtag\n
290 What is #ашок anyway?\n
291 カタカナ #カタカナ」カタカナ\n';
292 $autolinkedDescription = hashtag_autolink($rawDescription, $index);
293
294 $this->assertContains($this->getHashtagLink('hashtag', $index), $autolinkedDescription);
295 $this->assertNotContains(' #hashtag', $autolinkedDescription);
296 $this->assertNotContains('>#nothashtag', $autolinkedDescription);
297 $this->assertContains($this->getHashtagLink('ашок', $index), $autolinkedDescription);
298 $this->assertContains($this->getHashtagLink('カタカナ', $index), $autolinkedDescription);
299 $this->assertContains($this->getHashtagLink('hashtag_hashtag', $index), $autolinkedDescription);
300 $this->assertNotContains($this->getHashtagLink('hashtag-nothashtag', $index), $autolinkedDescription);
301 }
302
303 /**
304 * Test hashtags auto-link without index URL.
305 */
306 public function testHashtagAutolinkNoIndex()
307 {
308 $rawDescription = 'blabla #hashtag x#nothashtag';
309 $autolinkedDescription = hashtag_autolink($rawDescription);
310
311 $this->assertContains($this->getHashtagLink('hashtag'), $autolinkedDescription);
312 $this->assertNotContains(' #hashtag', $autolinkedDescription);
313 $this->assertNotContains('>#nothashtag', $autolinkedDescription);
314 }
315
316 /**
317 * Util function to build an hashtag link.
318 *
319 * @param string $hashtag Hashtag name.
320 * @param string $index Index URL.
321 *
322 * @return string HTML hashtag link.
323 */
324 private function getHashtagLink($hashtag, $index = '')
325 {
326 $hashtagLink = '<a href="'. $index .'?addtag=$1" title="Hashtag $1">#$1</a>';
327 return str_replace('$1', $hashtag, $hashtagLink);
328 }
329 }
330
331 // old style mock: PHPUnit doesn't allow function mock
332
333 /**
334 * Returns code 200 or html content type.
335 *
336 * @param resource $ch cURL resource
337 * @param int $type cURL info type
338 *
339 * @return int|string 200 or 'text/html'
340 */
341 function ut_curl_getinfo_ok($ch, $type)
342 {
343 switch ($type) {
344 case CURLINFO_RESPONSE_CODE:
345 return 200;
346 case CURLINFO_CONTENT_TYPE:
347 return 'text/html; charset=utf-8';
348 }
349 }
350
351 /**
352 * Returns code 200 or html content type without charset.
353 *
354 * @param resource $ch cURL resource
355 * @param int $type cURL info type
356 *
357 * @return int|string 200 or 'text/html'
358 */
359 function ut_curl_getinfo_no_charset($ch, $type)
360 {
361 switch ($type) {
362 case CURLINFO_RESPONSE_CODE:
363 return 200;
364 case CURLINFO_CONTENT_TYPE:
365 return 'text/html';
366 }
367 }
368
369 /**
370 * Invalid response code.
371 *
372 * @param resource $ch cURL resource
373 * @param int $type cURL info type
374 *
375 * @return int|string 404 or 'text/html'
376 */
377 function ut_curl_getinfo_rc_ko($ch, $type)
378 {
379 switch ($type) {
380 case CURLINFO_RESPONSE_CODE:
381 return 404;
382 case CURLINFO_CONTENT_TYPE:
383 return 'text/html; charset=utf-8';
384 }
385 }
386
387 /**
388 * Invalid content type.
389 *
390 * @param resource $ch cURL resource
391 * @param int $type cURL info type
392 *
393 * @return int|string 200 or 'text/plain'
394 */
395 function ut_curl_getinfo_ct_ko($ch, $type)
396 {
397 switch ($type) {
398 case CURLINFO_RESPONSE_CODE:
399 return 200;
400 case CURLINFO_CONTENT_TYPE:
401 return 'text/plain';
402 }
403 }
404
405 /**
406 * Invalid response code and content type.
407 *
408 * @param resource $ch cURL resource
409 * @param int $type cURL info type
410 *
411 * @return int|string 404 or 'text/plain'
412 */
413 function ut_curl_getinfo_rs_ct_ko($ch, $type)
414 {
415 switch ($type) {
416 case CURLINFO_RESPONSE_CODE:
417 return 404;
418 case CURLINFO_CONTENT_TYPE:
419 return 'text/plain';
420 }
421 }