LinkUtilsTest.php 14 KB

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