TextTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. <?php defined('SYSPATH') OR die('Kohana bootstrap needs to be included before tests run');
  2. /**
  3. * Tests the kohana text class (Kohana_Text)
  4. *
  5. * @group kohana
  6. * @group kohana.core
  7. * @group kohana.core.text
  8. *
  9. * @package Kohana
  10. * @category Tests
  11. */
  12. class Kohana_TextTest extends Unittest_TestCase
  13. {
  14. /**
  15. * Sets up the test enviroment
  16. */
  17. // @codingStandardsIgnoreStart
  18. function setUp()
  19. // @codingStandardsIgnoreEnd
  20. {
  21. parent::setUp();
  22. Text::alternate();
  23. }
  24. /**
  25. * This test makes sure that auto_p returns an empty string if
  26. * an empty input was provided
  27. *
  28. * @test
  29. * @covers Text::auto_p
  30. */
  31. function test_auto_para_returns_empty_string_on_empty_input()
  32. {
  33. $this->assertSame('', Text::auto_p(''));
  34. }
  35. /**
  36. *
  37. * @return array Test Data
  38. */
  39. function provider_auto_para_does_not_enclose_html_tags_in_paragraphs()
  40. {
  41. return array(
  42. array(
  43. array('div'),
  44. '<div>Pick a plum of peppers</div>',
  45. ),
  46. array(
  47. array('div'),
  48. '<div id="awesome">Tangas</div>',
  49. ),
  50. );
  51. }
  52. /**
  53. * This test makes sure that auto_p doesn't enclose HTML tags
  54. * in paragraphs
  55. *
  56. * @test
  57. * @covers Text::auto_p
  58. * @dataProvider provider_auto_para_does_not_enclose_html_tags_in_paragraphs
  59. */
  60. function test_auto_para_does_not_enclose_html_tags_in_paragraphs(array $tags, $text)
  61. {
  62. $output = Text::auto_p($text);
  63. foreach ($tags as $tag)
  64. {
  65. $this->assertNotTag(
  66. array('tag' => $tag, 'ancestor' => array('tag' => 'p')),
  67. $output
  68. );
  69. }
  70. }
  71. /**
  72. * This test makes sure that auto_p surrounds a single line of text
  73. * with paragraph tags
  74. *
  75. * @test
  76. * @covers Text::auto_p
  77. */
  78. function test_auto_para_encloses_slot_in_paragraph()
  79. {
  80. $text = 'Pick a pinch of purple pepper';
  81. $this->assertSame('<p>'.$text.'</p>', Text::auto_p($text));
  82. }
  83. /**
  84. * Make sure that multiple new lines are replaced with paragraph tags
  85. *
  86. * @test
  87. * @covers Text::auto_p
  88. */
  89. public function test_auto_para_replaces_multiple_newlines_with_paragraph()
  90. {
  91. $this->assertSame(
  92. "<p>My name is john</p>\n\n<p>I'm a developer</p>",
  93. Text::auto_p("My name is john\n\n\n\nI'm a developer")
  94. );
  95. }
  96. /**
  97. * Data provider for test_limit_words
  98. *
  99. * @return array Array of test data
  100. */
  101. function provider_limit_words()
  102. {
  103. return array
  104. (
  105. array('', '', 100, NULL),
  106. array('…', 'The rain in spain', -10, NULL),
  107. array('The rain…', 'The rain in spain', 2, NULL),
  108. array('The rain...', 'The rain in spain', 2, '...'),
  109. );
  110. }
  111. /**
  112. *
  113. * @test
  114. * @dataProvider provider_limit_words
  115. */
  116. function test_limit_words($expected, $str, $limit, $end_char)
  117. {
  118. $this->assertSame($expected, Text::limit_words($str, $limit, $end_char));
  119. }
  120. /**
  121. * Provides test data for test_limit_chars()
  122. *
  123. * @return array Test data
  124. */
  125. function provider_limit_chars()
  126. {
  127. return array
  128. (
  129. array('', '', 100, NULL, FALSE),
  130. array('…', 'BOO!', -42, NULL, FALSE),
  131. array('making php bet…', 'making php better for the sane', 14, NULL, FALSE),
  132. array('Garçon! Un café s.v.p.', 'Garçon! Un café s.v.p.', 50, '__', FALSE),
  133. array('Garçon!__', 'Garçon! Un café s.v.p.', 8, '__', FALSE),
  134. // @issue 3238
  135. array('making php…', 'making php better for the sane', 14, NULL, TRUE),
  136. array('Garçon!__', 'Garçon! Un café s.v.p.', 9, '__', TRUE),
  137. array('Garçon!__', 'Garçon! Un café s.v.p.', 7, '__', TRUE),
  138. array('__', 'Garçon! Un café s.v.p.', 5, '__', TRUE),
  139. );
  140. }
  141. /**
  142. * Tests Text::limit_chars()
  143. *
  144. * @test
  145. * @dataProvider provider_limit_chars
  146. */
  147. function test_limit_chars($expected, $str, $limit, $end_char, $preserve_words)
  148. {
  149. $this->assertSame($expected, Text::limit_chars($str, $limit, $end_char, $preserve_words));
  150. }
  151. /**
  152. * Test Text::alternate()
  153. *
  154. * @test
  155. */
  156. function test_alternate_alternates_between_parameters()
  157. {
  158. list($val_a, $val_b, $val_c) = array('good', 'bad', 'ugly');
  159. $this->assertSame('good', Text::alternate($val_a, $val_b, $val_c));
  160. $this->assertSame('bad', Text::alternate($val_a, $val_b, $val_c));
  161. $this->assertSame('ugly', Text::alternate($val_a, $val_b, $val_c));
  162. $this->assertSame('good', Text::alternate($val_a, $val_b, $val_c));
  163. }
  164. /**
  165. * Tests Text::alternate()
  166. *
  167. * @test
  168. * @covers Text::alternate
  169. */
  170. function test_alternate_resets_when_called_with_no_params_and_returns_empty_string()
  171. {
  172. list($val_a, $val_b, $val_c) = array('yes', 'no', 'maybe');
  173. $this->assertSame('yes', Text::alternate($val_a, $val_b, $val_c));
  174. $this->assertSame('', Text::alternate());
  175. $this->assertSame('yes', Text::alternate($val_a, $val_b, $val_c));
  176. }
  177. /**
  178. * Provides test data for test_reducde_slashes()
  179. *
  180. * @returns array Array of test data
  181. */
  182. function provider_reduce_slashes()
  183. {
  184. return array
  185. (
  186. array('/', '//'),
  187. array('/google/php/kohana/', '//google/php//kohana//'),
  188. );
  189. }
  190. /**
  191. * Covers Text::reduce_slashes()
  192. *
  193. * @test
  194. * @dataProvider provider_reduce_slashes
  195. */
  196. function test_reduce_slashes($expected, $str)
  197. {
  198. $this->assertSame($expected, Text::reduce_slashes($str));
  199. }
  200. /**
  201. * Provides test data for test_censor()
  202. *
  203. * @return array Test data
  204. */
  205. function provider_censor()
  206. {
  207. return array
  208. (
  209. // If the replacement is 1 character long it should be repeated for the length of the removed word
  210. array("A donkey is also an ***", 'A donkey is also an ass', array('ass'), '*', TRUE),
  211. array("Cake### isn't nearly as good as kohana###", "CakePHP isn't nearly as good as kohanaphp", array('php'), '#', TRUE),
  212. // If it's > 1 then it's just replaced straight out
  213. array("If you're born out of wedlock you're a --expletive--", "If you're born out of wedlock you're a child", array('child'), '--expletive--', TRUE),
  214. array('class', 'class', array('ass'), '*', FALSE),
  215. );
  216. }
  217. /**
  218. * Tests Text::censor
  219. *
  220. * @test
  221. * @dataProvider provider_censor
  222. */
  223. function test_censor($expected, $str, $badwords, $replacement, $replace_partial_words)
  224. {
  225. $this->assertSame($expected, Text::censor($str, $badwords, $replacement, $replace_partial_words));
  226. }
  227. /**
  228. * Provides test data for test_random
  229. *
  230. * @return array Test Data
  231. */
  232. function provider_random()
  233. {
  234. return array(
  235. array('alnum', 8),
  236. array('alpha', 10),
  237. array('hexdec', 20),
  238. array('nozero', 5),
  239. array('numeric', 14),
  240. array('distinct', 12),
  241. array('aeiou', 4),
  242. array('‹¡›«¿»', 8), // UTF8 characters
  243. array(NULL, 8), // Issue #3256
  244. );
  245. }
  246. /**
  247. * Tests Text::random() as well as possible
  248. *
  249. * Obviously you can't compare a randomly generated string against a
  250. * pre-generated one and check that they are the same as this goes
  251. * against the whole ethos of random.
  252. *
  253. * This test just makes sure that the value returned is of the correct
  254. * values and length
  255. *
  256. * @test
  257. * @dataProvider provider_random
  258. */
  259. function test_random($type, $length)
  260. {
  261. if ($type === NULL)
  262. {
  263. $type = 'alnum';
  264. }
  265. $pool = (string) $type;
  266. switch ($pool)
  267. {
  268. case 'alnum':
  269. $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  270. break;
  271. case 'alpha':
  272. $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  273. break;
  274. case 'hexdec':
  275. $pool = '0123456789abcdef';
  276. break;
  277. case 'numeric':
  278. $pool = '0123456789';
  279. break;
  280. case 'nozero':
  281. $pool = '123456789';
  282. break;
  283. case 'distinct':
  284. $pool = '2345679ACDEFHJKLMNPRSTUVWXYZ';
  285. break;
  286. }
  287. $this->assertRegExp('/^['.$pool.']{'.$length.'}$/u', Text::random($type, $length));
  288. }
  289. /**
  290. * Provides test data for test_similar
  291. *
  292. * @return array
  293. */
  294. function provider_similar()
  295. {
  296. return array
  297. (
  298. // TODO: add some more cases
  299. array('foo', array('foobar', 'food', 'fooberry')),
  300. );
  301. }
  302. /**
  303. * Tests Text::similar()
  304. *
  305. * @test
  306. * @dataProvider provider_similar
  307. * @covers Text::similar
  308. */
  309. function test_similar($expected, $words)
  310. {
  311. $this->assertSame($expected, Text::similar($words));
  312. }
  313. /**
  314. * Provides test data for test_bytes
  315. *
  316. * @return array
  317. */
  318. public function provider_bytes()
  319. {
  320. return array
  321. (
  322. // TODO: cover the other units
  323. array('256.00 B', 256, NULL, NULL, TRUE),
  324. array('1.02 kB', 1024, NULL, NULL, TRUE),
  325. // In case you need to know the size of a floppy disk in petabytes
  326. array('0.00147 GB', 1.44 * 1000 * 1024, 'GB', '%01.5f %s', TRUE),
  327. // SI is the standard, but lets deviate slightly
  328. array('1.00 MiB', 1024 * 1024, 'MiB', NULL, FALSE),
  329. );
  330. }
  331. /**
  332. * Tests Text::bytes()
  333. *
  334. * @test
  335. * @dataProvider provider_bytes
  336. */
  337. function test_bytes($expected, $bytes, $force_unit, $format, $si)
  338. {
  339. $this->assertSame($expected, Text::bytes($bytes, $force_unit, $format, $si));
  340. }
  341. /**
  342. * Provides test data for test_widont()
  343. *
  344. * @return array Test data
  345. */
  346. function provider_widont()
  347. {
  348. return array
  349. (
  350. array('No gain, no&nbsp;pain', 'No gain, no pain'),
  351. array("spaces?what'rethey?", "spaces?what'rethey?"),
  352. array('', ''),
  353. );
  354. }
  355. /**
  356. * Tests Text::widont()
  357. *
  358. * @test
  359. * @dataProvider provider_widont
  360. */
  361. function test_widont($expected, $string)
  362. {
  363. $this->assertSame($expected, Text::widont($string));
  364. }
  365. /**
  366. * This checks that auto_link_emails() respects word boundaries and does not
  367. * just blindly replace all occurences of the email address in the text.
  368. *
  369. * In the sample below the algorithm was replacing all occurences of [email protected]
  370. * inc the copy in the second list item.
  371. *
  372. * It was updated in 6c199366efc1115545ba13108b876acc66c54b2d to respect word boundaries
  373. *
  374. * @test
  375. * @covers Text::auto_link_emails
  376. * @ticket 2772
  377. */
  378. function test_auto_link_emails_respects_word_boundaries()
  379. {
  380. $original = '<ul>
  381. <li>[email protected]</li>
  382. <li>[email protected]</li>
  383. </ul>';
  384. $this->assertFalse(strpos('vice', Text::auto_link_emails($original)));
  385. }
  386. /**
  387. * Provides some test data for test_number()
  388. *
  389. * @return array
  390. */
  391. public function provider_number()
  392. {
  393. return array(
  394. array('one', 1),
  395. array('twenty-three', 23),
  396. array('fourty-two', 42),
  397. array('five million, six hundred and thirty-two', 5000632),
  398. array('five million, six hundred and thirty', 5000630),
  399. array('nine hundred million', 900000000),
  400. array('thirty-seven thousand', 37000),
  401. array('one thousand and twenty-four', 1024),
  402. );
  403. }
  404. /**
  405. * Checks that Text::number formats a number into english text
  406. *
  407. * @test
  408. * @dataProvider provider_number
  409. */
  410. public function test_number($expected, $number)
  411. {
  412. $this->assertSame($expected, Text::number($number));
  413. }
  414. /**
  415. * Provides test data for test_auto_link_urls()
  416. *
  417. * @return array
  418. */
  419. public function provider_auto_link_urls()
  420. {
  421. return array(
  422. // First we try with the really obvious url
  423. array(
  424. 'Some random text <a href="http://www.google.com">http://www.google.com</a>',
  425. 'Some random text http://www.google.com',
  426. ),
  427. // Then we try with varying urls
  428. array(
  429. 'Some random <a href="http://www.google.com">www.google.com</a>',
  430. 'Some random www.google.com',
  431. ),
  432. array(
  433. 'Some random google.com',
  434. 'Some random google.com',
  435. ),
  436. // Check that it doesn't link urls in a href
  437. array(
  438. 'Look at me <a href="http://google.com">Awesome stuff</a>',
  439. 'Look at me <a href="http://google.com">Awesome stuff</a>',
  440. ),
  441. array(
  442. 'Look at me <a href="http://www.google.com">http://www.google.com</a>',
  443. 'Look at me <a href="http://www.google.com">http://www.google.com</a>',
  444. ),
  445. // Punctuation at the end of the URL
  446. array(
  447. 'Wow <a href="http://www.google.com">http://www.google.com</a>!',
  448. 'Wow http://www.google.com!',
  449. ),
  450. array(
  451. 'Zomg <a href="http://www.google.com">www.google.com</a>!',
  452. 'Zomg www.google.com!',
  453. ),
  454. array(
  455. 'Well this, <a href="http://www.google.com">www.google.com</a>, is cool',
  456. 'Well this, www.google.com, is cool',
  457. ),
  458. // @issue 3190
  459. array(
  460. '<a href="http://www.google.com/">www.google.com</a>',
  461. '<a href="http://www.google.com/">www.google.com</a>',
  462. ),
  463. array(
  464. '<a href="http://www.google.com/">www.google.com</a> <a href="http://www.google.com/">http://www.google.com/</a>',
  465. '<a href="http://www.google.com/">www.google.com</a> http://www.google.com/',
  466. ),
  467. // @issue 3436
  468. array(
  469. '<strong><a href="http://www.google.com/">http://www.google.com/</a></strong>',
  470. '<strong>http://www.google.com/</strong>',
  471. ),
  472. // @issue 4208, URLs with a path
  473. array(
  474. 'Foobar <a href="http://www.google.com/analytics">www.google.com/analytics</a> cake',
  475. 'Foobar www.google.com/analytics cake',
  476. ),
  477. array(
  478. 'Look at this <a href="http://www.google.com/analytics">www.google.com/analytics</a>!',
  479. 'Look at this www.google.com/analytics!',
  480. ),
  481. array(
  482. 'Path <a href="http://www.google.com/analytics">http://www.google.com/analytics</a> works?',
  483. 'Path http://www.google.com/analytics works?',
  484. ),
  485. array(
  486. 'Path <a href="http://www.google.com/analytics">http://www.google.com/analytics</a>',
  487. 'Path http://www.google.com/analytics',
  488. ),
  489. array(
  490. 'Path <a href="http://www.google.com/analytics">www.google.com/analytics</a>',
  491. 'Path www.google.com/analytics',
  492. ),
  493. );
  494. }
  495. /**
  496. * Runs tests for Test::auto_link_urls
  497. *
  498. * @test
  499. * @dataProvider provider_auto_link_urls
  500. */
  501. public function test_auto_link_urls($expected, $text)
  502. {
  503. $this->assertSame($expected, Text::auto_link_urls($text));
  504. }
  505. /**
  506. * Provides test data for test_auto_link_emails()
  507. *
  508. * @return array
  509. */
  510. public function provider_auto_link_emails()
  511. {
  512. return array(
  513. // @issue 3162
  514. array(
  515. '<span class="broken"><a href="mailto:[email protected]">[email protected]</a></span>',
  516. '<span class="broken">[email protected]</span>',
  517. ),
  518. array(
  519. '<a href="mailto:[email protected]">[email protected]</a>',
  520. '<a href="mailto:[email protected]">[email protected]</a>',
  521. ),
  522. // @issue 3189
  523. array(
  524. '<a href="mailto:[email protected]">[email protected]</a> <a href="mailto:[email protected]">[email protected]</a>',
  525. '<a href="mailto:[email protected]">[email protected]</a> [email protected]',
  526. ),
  527. );
  528. }
  529. /**
  530. * Runs tests for Test::auto_link_emails
  531. *
  532. * @test
  533. * @dataProvider provider_auto_link_emails
  534. */
  535. public function test_auto_link_emails($expected, $text)
  536. {
  537. // Use html_entity_decode because emails will be randomly encoded by HTML::mailto
  538. $this->assertSame($expected, html_entity_decode(Text::auto_link_emails($text)));
  539. }
  540. /**
  541. * Provides test data for test_auto_link
  542. *
  543. * @return array Test data
  544. */
  545. public function provider_auto_link()
  546. {
  547. return array(
  548. array(
  549. 'Hi there, my site is kohanaframework.org and you can email me at [email protected]',
  550. array('kohanaframework.org'),
  551. ),
  552. array(
  553. 'Hi [email protected] you came from',
  554. FALSE,
  555. array('[email protected]'),
  556. ),
  557. );
  558. }
  559. /**
  560. * Tests Text::auto_link()
  561. *
  562. * @test
  563. * @dataProvider provider_auto_link
  564. */
  565. public function test_auto_link($text, $urls = array(), $emails = array())
  566. {
  567. $linked_text = Text::auto_link($text);
  568. if ($urls === FALSE)
  569. {
  570. $this->assertNotContains('http://', $linked_text);
  571. }
  572. elseif (count($urls))
  573. {
  574. foreach ($urls as $url)
  575. {
  576. // Assert that all the urls have been caught by text auto_link_urls()
  577. $this->assertContains(Text::auto_link_urls($url), $linked_text);
  578. }
  579. }
  580. foreach ($emails as $email)
  581. {
  582. $this->assertContains('&#109;&#097;&#105;&#108;&#116;&#111;&#058;'.$email, $linked_text);
  583. }
  584. }
  585. }