LinkUtilsTest.php 14 KB

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