StringTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2013, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\tests\cases\util;
  9. use lithium\util\String;
  10. use lithium\tests\mocks\util\MockStringObject;
  11. class StringTest extends \lithium\test\Unit {
  12. /**
  13. * testUuidGeneration method
  14. *
  15. * @return void
  16. */
  17. public function testUuidGeneration() {
  18. $result = String::uuid();
  19. $pattern = "/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[8-9a-b][a-f0-9]{3}-[a-f0-9]{12}$/";
  20. $this->assertPattern($pattern, $result);
  21. $result = String::uuid();
  22. $this->assertPattern($pattern, $result);
  23. }
  24. /**
  25. * testMultipleUuidGeneration method
  26. *
  27. * @return void
  28. */
  29. public function testMultipleUuidGeneration() {
  30. $check = array();
  31. $count = 50;
  32. $pattern = "/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[8-9a-b][a-f0-9]{3}-[a-f0-9]{12}$/";
  33. for ($i = 0; $i < $count; $i++) {
  34. $result = String::uuid();
  35. $match = preg_match($pattern, $result);
  36. $this->assertTrue($match);
  37. $this->assertFalse(in_array($result, $check));
  38. $check[] = $result;
  39. }
  40. }
  41. /**
  42. * testInsert method
  43. *
  44. * @return void
  45. */
  46. public function testInsert() {
  47. $string = '2 + 2 = {:sum}. Lithium is {:adjective}.';
  48. $expected = '2 + 2 = 4. Lithium is yummy.';
  49. $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'));
  50. $this->assertEqual($expected, $result);
  51. $string = '2 + 2 = %sum. Lithium is %adjective.';
  52. $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'), array(
  53. 'before' => '%', 'after' => ''
  54. ));
  55. $this->assertEqual($expected, $result);
  56. $string = '2 + 2 = 2sum2. Lithium is 9adjective9.';
  57. $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'), array(
  58. 'format' => '/([\d])%s\\1/'
  59. ));
  60. $this->assertEqual($expected, $result);
  61. $string = '2 + 2 = 12sum21. Lithium is 23adjective45.';
  62. $expected = '2 + 2 = 4. Lithium is 23adjective45.';
  63. $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'), array(
  64. 'format' => '/([\d])([\d])%s\\2\\1/'
  65. ));
  66. $this->assertEqual($expected, $result);
  67. $string = '{:web} {:web_site}';
  68. $expected = 'www http';
  69. $result = String::insert($string, array('web' => 'www', 'web_site' => 'http'));
  70. $this->assertEqual($expected, $result);
  71. $string = '2 + 2 = <sum. Lithium is <adjective>.';
  72. $expected = '2 + 2 = <sum. Lithium is yummy.';
  73. $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'), array(
  74. 'before' => '<', 'after' => '>'
  75. ));
  76. $this->assertEqual($expected, $result);
  77. $string = '2 + 2 = \:sum. Lithium is :adjective.';
  78. $expected = '2 + 2 = :sum. Lithium is yummy.';
  79. $result = String::insert(
  80. $string,
  81. array('sum' => '4', 'adjective' => 'yummy'),
  82. array('before' => ':', 'after' => null, 'escape' => '\\')
  83. );
  84. $this->assertEqual($expected, $result);
  85. $string = '2 + 2 = !:sum. Lithium is :adjective.';
  86. $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'), array(
  87. 'escape' => '!', 'before' => ':', 'after' => ''
  88. ));
  89. $this->assertEqual($expected, $result);
  90. $string = '2 + 2 = \%sum. Lithium is %adjective.';
  91. $expected = '2 + 2 = %sum. Lithium is yummy.';
  92. $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'), array(
  93. 'before' => '%', 'after' => '', 'escape' => '\\'
  94. ));
  95. $this->assertEqual($expected, $result);
  96. $string = ':a :b \:a :a';
  97. $expected = '1 2 :a 1';
  98. $result = String::insert($string, array('a' => 1, 'b' => 2), array(
  99. 'before' => ':', 'after' => '', 'escape' => '\\'
  100. ));
  101. $this->assertEqual($expected, $result);
  102. $string = '{:a} {:b} {:c}';
  103. $expected = '2 3';
  104. $result = String::insert($string, array('b' => 2, 'c' => 3), array('clean' => true));
  105. $this->assertEqual($expected, $result);
  106. $string = '{:a} {:b} {:c}';
  107. $expected = '1 3';
  108. $result = String::insert($string, array('a' => 1, 'c' => 3), array('clean' => true));
  109. $this->assertEqual($expected, $result);
  110. $string = '{:a} {:b} {:c}';
  111. $expected = '2 3';
  112. $result = String::insert($string, array('b' => 2, 'c' => 3), array('clean' => true));
  113. $this->assertEqual($expected, $result);
  114. $string = ':a, :b and :c';
  115. $expected = '2 and 3';
  116. $result = String::insert($string, array('b' => 2, 'c' => 3), array(
  117. 'clean' => true, 'before' => ':', 'after' => ''
  118. ));
  119. $this->assertEqual($expected, $result);
  120. $string = '{:a}, {:b} and {:c}';
  121. $expected = '2 and 3';
  122. $result = String::insert($string, array('b' => 2, 'c' => 3), array('clean' => true));
  123. $this->assertEqual($expected, $result);
  124. $string = '"{:a}, {:b} and {:c}"';
  125. $expected = '"1, 2"';
  126. $result = String::insert($string, array('a' => 1, 'b' => 2), array('clean' => true));
  127. $this->assertEqual($expected, $result);
  128. $string = '"${a}, ${b} and ${c}"';
  129. $expected = '"1, 2"';
  130. $result = String::insert($string, array('a' => 1, 'b' => 2), array(
  131. 'before' => '${', 'after' => '}', 'clean' => true
  132. ));
  133. $this->assertEqual($expected, $result);
  134. $string = '<img src="{:src}" alt="{:alt}" class="foo {:extra} bar"/>';
  135. $expected = '<img src="foo" class="foo bar"/>';
  136. $result = String::insert($string, array('src' => 'foo'), array('clean' => 'html'));
  137. $this->assertEqual($expected, $result);
  138. $string = '<img src=":src" class=":no :extra"/>';
  139. $expected = '<img src="foo"/>';
  140. $result = String::insert($string, array('src' => 'foo'), array(
  141. 'clean' => 'html', 'before' => ':', 'after' => ''
  142. ));
  143. $this->assertEqual($expected, $result);
  144. $string = '<img src="{:src}" class="{:no} {:extra}"/>';
  145. $expected = '<img src="foo" class="bar"/>';
  146. $result = String::insert($string, array('src' => 'foo', 'extra' => 'bar'), array(
  147. 'clean' => 'html'
  148. ));
  149. $this->assertEqual($expected, $result);
  150. $result = String::insert("this is a ? string", array("test"));
  151. $expected = "this is a test string";
  152. $this->assertEqual($expected, $result);
  153. $result = String::insert("this is a ? string with a ? ? ?", array(
  154. 'long', 'few?', 'params', 'you know'
  155. ));
  156. $expected = "this is a long string with a few? params you know";
  157. $this->assertEqual($expected, $result);
  158. $result = String::insert(
  159. 'update saved_urls set url = :url where id = :id',
  160. array('url' => 'http://testurl.com/param1:url/param2:id', 'id' => 1),
  161. array('before' => ':', 'after' => '')
  162. );
  163. $expected = "update saved_urls set url = http://testurl.com/param1:url/param2:id ";
  164. $expected .= "where id = 1";
  165. $this->assertEqual($expected, $result);
  166. $result = String::insert(
  167. 'update saved_urls set url = :url where id = :id',
  168. array('id' => 1, 'url' => 'http://www.testurl.com/param1:url/param2:id'),
  169. array('before' => ':', 'after' => '')
  170. );
  171. $expected = "update saved_urls set url = http://www.testurl.com/param1:url/param2:id ";
  172. $expected .= "where id = 1";
  173. $this->assertEqual($expected, $result);
  174. $result = String::insert('{:me} lithium. {:subject} {:verb} fantastic.', array(
  175. 'me' => 'I :verb', 'subject' => 'lithium', 'verb' => 'is'
  176. ));
  177. $expected = "I :verb lithium. lithium is fantastic.";
  178. $this->assertEqual($expected, $result);
  179. $result = String::insert(':I.am: :not.yet: passing.', array('I.am' => 'We are'), array(
  180. 'before' => ':', 'after' => ':', 'clean' => array(
  181. 'replacement' => ' of course', 'method' => 'text'
  182. )
  183. ));
  184. $expected = "We are of course passing.";
  185. $this->assertEqual($expected, $result);
  186. $result = String::insert(
  187. ':I.am: :not.yet: passing.',
  188. array('I.am' => 'We are'),
  189. array('before' => ':', 'after' => ':', 'clean' => true)
  190. );
  191. $expected = "We are passing.";
  192. $this->assertEqual($expected, $result);
  193. $result = String::insert('?-pended result', array('Pre'));
  194. $expected = "Pre-pended result";
  195. $this->assertEqual($expected, $result);
  196. }
  197. /**
  198. * Tests that text replacements with `String::insert()` using key/value pairs are not
  199. * mis-handled if numeric keys are present in the array (only if they appear first).
  200. *
  201. * @return void
  202. */
  203. public function testInsertWithUnusedNumericKey() {
  204. $result = String::insert("Hey, what are you tryin' to {:action} on us?", array(
  205. 'action' => 'push', '!'
  206. ));
  207. $expected = "Hey, what are you tryin' to push on us?";
  208. $this->assertEqual($expected, $result);
  209. }
  210. /**
  211. * Tests casting/inserting of custom objects with `String::insert()`.
  212. *
  213. * @return void
  214. */
  215. public function testInsertWithObject() {
  216. $foo = new MockStringObject();
  217. $result = String::insert('This is a {:foo}', compact('foo'));
  218. $expected = 'This is a custom object';
  219. $this->assertEqual($expected, $result);
  220. }
  221. /**
  222. * Test that an empty array is not added to the string
  223. *
  224. * @return void
  225. */
  226. public function testInsertWithEmptyArray() {
  227. $result = String::insert("Hey, what are you tryin' to {:action} on us?",
  228. array('action' => array())
  229. );
  230. $expected = "Hey, what are you tryin' to on us?";
  231. $this->assertEqual($expected, $result);
  232. }
  233. /**
  234. * test Clean Insert
  235. *
  236. * @return void
  237. */
  238. public function testCleanInsert() {
  239. $result = String::clean(':incomplete', array(
  240. 'clean' => true, 'before' => ':', 'after' => ''
  241. ));
  242. $this->assertEqual('', $result);
  243. $result = String::clean(':incomplete', array(
  244. 'clean' => array('method' => 'text', 'replacement' => 'complete'),
  245. 'before' => ':', 'after' => '')
  246. );
  247. $this->assertEqual('complete', $result);
  248. $result = String::clean(':in.complete', array(
  249. 'clean' => true, 'before' => ':', 'after' => ''
  250. ));
  251. $this->assertEqual('', $result);
  252. $result = String::clean(':in.complete and', array(
  253. 'clean' => true, 'before' => ':', 'after' => ''
  254. ));
  255. $this->assertEqual('', $result);
  256. $result = String::clean(':in.complete or stuff', array(
  257. 'clean' => true, 'before' => ':', 'after' => ''
  258. ));
  259. $this->assertEqual('stuff', $result);
  260. $result = String::clean(
  261. '<p class=":missing" id=":missing">Text here</p>',
  262. array('clean' => 'html', 'before' => ':', 'after' => '')
  263. );
  264. $this->assertEqual('<p>Text here</p>', $result);
  265. $string = ':a 2 3';
  266. $result = String::clean($string, array('clean' => true, 'before' => ':', 'after' => ''));
  267. $this->assertEqual('2 3', $result);
  268. $result = String::clean($string, array('clean' => false, 'before' => ':', 'after' => ''));
  269. $this->assertEqual($string, $result);
  270. }
  271. /**
  272. * testTokenize method
  273. *
  274. * @return void
  275. */
  276. public function testTokenize() {
  277. $result = String::tokenize('A,(short,boring test)');
  278. $expected = array('A', '(short,boring test)');
  279. $this->assertEqual($expected, $result);
  280. $result = String::tokenize('A,(short,more interesting( test)');
  281. $expected = array('A', '(short,more interesting( test)');
  282. $this->assertEqual($expected, $result);
  283. $result = String::tokenize('A,(short,very interesting( test))');
  284. $expected = array('A', '(short,very interesting( test))');
  285. $this->assertEqual($expected, $result);
  286. $result = String::tokenize('"single tag"', array(
  287. 'separator' => ' ', 'leftBound' => '"', 'rightBound' => '"'
  288. ));
  289. $expected = array('"single tag"');
  290. $this->assertEqual($expected, $result);
  291. $result = String::tokenize('tagA "single tag" tagB', array(
  292. 'separator' => ' ', 'leftBound' => '"', 'rightBound' => '"'
  293. ));
  294. $expected = array('tagA', '"single tag"', 'tagB');
  295. $this->assertEqual($expected, $result);
  296. $result = String::tokenize(array());
  297. $expected = array();
  298. $this->assertEqual($expected, $result);
  299. $result = String::tokenize(null);
  300. $this->assertNull($result);
  301. }
  302. /**
  303. * Tests the `String::extract()` regex helper method.
  304. */
  305. public function testStringExtraction() {
  306. $result = String::extract('/string/', 'whole string');
  307. $this->assertEqual('string', $result);
  308. $this->assertFalse(String::extract('/not/', 'whole string'));
  309. $this->assertEqual('part', String::extract('/\w+\s*(\w+)/', 'second part', 1));
  310. $this->assertNull(String::extract('/\w+\s*(\w+)/', 'second part', 2));
  311. }
  312. public function testStringInsertWithQuestionMark() {
  313. $result = String::insert('some string with a ?', array());
  314. $this->assertEqual('some string with a ?', $result);
  315. $result = String::insert('some {:param}string with a ?', array('param' => null));
  316. $this->assertEqual('some string with a ?', $result);
  317. }
  318. /**
  319. * Tests the random number generator.
  320. */
  321. public function testRandomGenerator() {
  322. $check = array();
  323. $count = 25;
  324. for ($i = 0; $i < $count; $i++) {
  325. $result = String::random(8);
  326. $this->assertFalse(in_array($result, $check));
  327. $check[] = $result;
  328. }
  329. }
  330. /**
  331. * Tests the random number generator with base64 encoding.
  332. */
  333. public function testRandom64Generator() {
  334. $check = array();
  335. $count = 25;
  336. $pattern = "/^[0-9A-Za-z\.\/]{11}$/";
  337. for ($i = 0; $i < $count; $i++) {
  338. $result = String::random(8, array('encode' => String::ENCODE_BASE_64));
  339. $this->assertPattern($pattern, $result);
  340. $this->assertFalse(in_array($result, $check));
  341. $check[] = $result;
  342. }
  343. }
  344. /**
  345. * Tests hash generation using `String::hash()`.
  346. * @return string
  347. */
  348. public function testHash() {
  349. $salt = 'Salt and pepper';
  350. $value = 'Lithium rocks!';
  351. $expected = sha1($value);
  352. $result = String::hash($value, array('type' => 'sha1'));
  353. $this->assertEqual($expected, $result);
  354. $result = String::hash($value, array('type' => 'sha1') + compact('salt'));
  355. $this->assertEqual(sha1($salt . $value), $result);
  356. $this->assertEqual(md5($value), String::hash($value, array('type' => 'md5')));
  357. $result = String::hash($value, array('type' => 'md5') + compact('salt'));
  358. $this->assertEqual(md5($salt . $value), $result);
  359. $sha256 = function($value) {
  360. if (function_exists('mhash')) {
  361. return bin2hex(mhash(MHASH_SHA256, $value));
  362. } elseif (function_exists('hash')) {
  363. return hash('sha256', $value);
  364. }
  365. throw new Exception();
  366. };
  367. try {
  368. $result = String::hash($value, array('type' => 'sha256'));
  369. $this->assertEqual($sha256($value), $result);
  370. $result = String::hash($value, array('type' => 'sha256') + compact('salt'));
  371. $this->assertEqual($sha256($salt . $value), $result);
  372. } catch (Exception $e) {
  373. }
  374. $string = 'Hash Me';
  375. $key = 'a very valid key';
  376. $salt = 'not too much';
  377. $type = 'sha256';
  378. $expected = '24f8664f7a7e56f85bd5c983634aaa0b0d3b0e470d7f63494475729cb8b3c6a4ef28398d7cf3';
  379. $expected .= '780c0caec26c85b56a409920e4af7eef38597861d49fbe31b9a0';
  380. $result = String::hash($string, compact('key'));
  381. $this->assertEqual($expected, $result);
  382. $expected = '35bc1d9a3332e524962909b7ccff6b34ae143f64c48ffa32b5be9312719a96369fbd7ebf6f49';
  383. $expected .= '09b375135b34e28b063a07b5bd62af165483c6b80dd48a252ddd';
  384. $result = String::hash($string, compact('salt'));
  385. $this->assertEqual($expected, $result);
  386. $expected = 'fa4cfa5c16d7f94e221e1d3a0cb01eadfd6823d68497a5fdcae023d24f557e4a';
  387. $result = String::hash($string, compact('type', 'key'));
  388. $this->assertEqual($expected, $result);
  389. $expected = 'a9050b4f44797bf60262de984ca12967711389cd6c4c4aeee2a739c159f1f667';
  390. $result = String::hash($string, compact('type'));
  391. $this->assertEqual($expected, $result);
  392. }
  393. public function testCompare() {
  394. $this->assertTrue(String::compare('Foo', 'Foo'));
  395. $this->assertFalse(String::compare('Foo', 'foo'));
  396. $this->assertFalse(String::compare('1', 1));
  397. }
  398. /**
  399. * Verifies that `String::insert()` doesn't completely ignore empty values.
  400. */
  401. public function testInsertingEmptyValues() {
  402. $this->assertEqual('value="0"', String::insert('value="{:value}"', array('value' => 0)));
  403. }
  404. }
  405. ?>