ArrTest.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. <?php
  2. /**
  3. * Tests the Arr lib that's shipped with kohana
  4. *
  5. * @group kohana
  6. * @group kohana.core
  7. * @group kohana.core.arr
  8. *
  9. * @package Kohana
  10. * @category Tests
  11. * @author Kohana Team
  12. * @author BRMatt <matthew@sigswitch.com>
  13. * @copyright (c) Kohana Team
  14. * @license https://koseven.ga/LICENSE.md
  15. */
  16. class Kohana_ArrTest extends Unittest_TestCase
  17. {
  18. /**
  19. * Provides test data for test_callback()
  20. *
  21. * @return array
  22. */
  23. public function provider_callback()
  24. {
  25. return [
  26. // Tests....
  27. // That no parameters returns null
  28. ['function', ['function', NULL]],
  29. // That we can get an array of parameters values
  30. ['function(1,2,3)', ['function', ['1', '2', '3']]],
  31. // That it's not just using the callback "function"
  32. ['different_name(harry,jerry)', ['different_name', ['harry', 'jerry']]],
  33. // That static callbacks are parsed into arrays
  34. ['kohana::appify(this)', [['kohana', 'appify'], ['this']]],
  35. // Spaces are preserved in parameters
  36. ['deal::make(me, my mate )', [['deal', 'make'], ['me', ' my mate ']]]
  37. // TODO: add more cases
  38. ];
  39. }
  40. /**
  41. * Tests Arr::callback()
  42. *
  43. * @test
  44. * @dataProvider provider_callback
  45. * @param string $str String to parse
  46. * @param array $expected Callback and its parameters
  47. */
  48. public function test_callback($str, $expected)
  49. {
  50. $result = Arr::callback($str);
  51. $this->assertSame(2, count($result));
  52. $this->assertSame($expected, $result);
  53. }
  54. /**
  55. * Provides test data for test_extract
  56. *
  57. * @return array
  58. */
  59. public function provider_extract()
  60. {
  61. return [
  62. [
  63. ['kohana' => 'awesome', 'blueflame' => 'was'],
  64. ['kohana', 'cakephp', 'symfony'],
  65. NULL,
  66. ['kohana' => 'awesome', 'cakephp' => NULL, 'symfony' => NULL]
  67. ],
  68. // I realise noone should EVER code like this in real life,
  69. // but unit testing is very very very very boring
  70. [
  71. ['chocolate cake' => 'in stock', 'carrot cake' => 'in stock'],
  72. ['carrot cake', 'humble pie'],
  73. 'not in stock',
  74. ['carrot cake' => 'in stock', 'humble pie' => 'not in stock'],
  75. ],
  76. [
  77. // Source Array
  78. ['level1' => ['level2a' => 'value 1', 'level2b' => 'value 2']],
  79. // Paths to extract
  80. ['level1.level2a', 'level1.level2b'],
  81. // Default
  82. NULL,
  83. // Expected Result
  84. ['level1' => ['level2a' => 'value 1', 'level2b' => 'value 2']],
  85. ],
  86. [
  87. // Source Array
  88. ['level1a' => ['level2a' => 'value 1'], 'level1b' => ['level2b' => 'value 2']],
  89. // Paths to extract
  90. ['level1a', 'level1b.level2b'],
  91. // Default
  92. NULL,
  93. // Expected Result
  94. ['level1a' => ['level2a' => 'value 1'], 'level1b' => ['level2b' => 'value 2']],
  95. ],
  96. [
  97. // Source Array
  98. ['level1a' => ['level2a' => 'value 1'], 'level1b' => ['level2b' => 'value 2']],
  99. // Paths to extract
  100. ['level1a', 'level1b.level2b', 'level1c', 'level1d.notfound'],
  101. // Default
  102. 'default',
  103. // Expected Result
  104. ['level1a' => ['level2a' => 'value 1'], 'level1b' => ['level2b' => 'value 2'], 'level1c' => 'default', 'level1d' => ['notfound' => 'default']],
  105. ],
  106. ];
  107. }
  108. /**
  109. * Tests Arr::extract()
  110. *
  111. * @test
  112. * @dataProvider provider_extract
  113. * @param array $array
  114. * @param array $paths
  115. * @param mixed $default
  116. * @param array $expected
  117. */
  118. public function test_extract(array $array, array $paths, $default, $expected)
  119. {
  120. $array = Arr::extract($array, $paths, $default);
  121. $this->assertSame(count($expected), count($array));
  122. $this->assertSame($expected, $array);
  123. }
  124. /**
  125. * Provides test data for test_pluck
  126. *
  127. * @return array
  128. */
  129. public function provider_pluck()
  130. {
  131. return [
  132. [
  133. [
  134. ['id' => 20, 'name' => 'John Smith'],
  135. ['name' => 'Linda'],
  136. ['id' => 25, 'name' => 'Fred'],
  137. ],
  138. 'id',
  139. [20, 25]
  140. ],
  141. ];
  142. }
  143. /**
  144. * Tests Arr::pluck()
  145. *
  146. * @test
  147. * @dataProvider provider_pluck
  148. * @param array $array
  149. * @param string $key
  150. * @param array $expected
  151. */
  152. public function test_pluck(array $array, $key, $expected)
  153. {
  154. $array = Arr::pluck($array, $key);
  155. $this->assertSame(count($expected), count($array));
  156. $this->assertSame($expected, $array);
  157. }
  158. /**
  159. * Provides test data for test_get()
  160. *
  161. * @return array
  162. */
  163. public function provider_get()
  164. {
  165. return [
  166. [['uno', 'dos', 'tress'], 1, NULL, 'dos'],
  167. [['we' => 'can', 'make' => 'change'], 'we', NULL, 'can'],
  168. [['uno', 'dos', 'tress'], 10, NULL, NULL],
  169. [['we' => 'can', 'make' => 'change'], 'he', NULL, NULL],
  170. [['we' => 'can', 'make' => 'change'], 'he', 'who', 'who'],
  171. [['we' => 'can', 'make' => 'change'], 'he', ['arrays'], ['arrays']],
  172. ];
  173. }
  174. /**
  175. * Tests Arr::get()
  176. *
  177. * @test
  178. * @dataProvider provider_get()
  179. * @param array $array Array to look in
  180. * @param string|integer $key Key to look for
  181. * @param mixed $default What to return if $key isn't set
  182. * @param mixed $expected The expected value returned
  183. */
  184. public function test_get(array $array, $key, $default, $expected)
  185. {
  186. $this->assertSame(
  187. $expected,
  188. Arr::get($array, $key, $default)
  189. );
  190. }
  191. /**
  192. * Provides test data for test_is_assoc()
  193. *
  194. * @return array
  195. */
  196. public function provider_is_assoc()
  197. {
  198. return [
  199. [['one', 'two', 'three'], FALSE],
  200. [['one' => 'o clock', 'two' => 'o clock', 'three' => 'o clock'], TRUE],
  201. ];
  202. }
  203. /**
  204. * Tests Arr::is_assoc()
  205. *
  206. * @test
  207. * @dataProvider provider_is_assoc
  208. * @param array $array Array to check
  209. * @param boolean $expected Is $array assoc
  210. */
  211. public function test_is_assoc(array $array, $expected)
  212. {
  213. $this->assertSame(
  214. $expected,
  215. Arr::is_assoc($array)
  216. );
  217. }
  218. /**
  219. * Provides test data for test_is_array()
  220. *
  221. * @return array
  222. */
  223. public function provider_is_array()
  224. {
  225. return [
  226. [$a = ['one', 'two', 'three'], TRUE],
  227. [new ArrayObject($a), TRUE],
  228. [new ArrayIterator($a), TRUE],
  229. ['not an array', FALSE],
  230. [new stdClass, FALSE],
  231. ];
  232. }
  233. /**
  234. * Tests Arr::is_array()
  235. *
  236. * @test
  237. * @dataProvider provider_is_array
  238. * @param mixed $value Value to check
  239. * @param boolean $expected Is $value an array?
  240. */
  241. public function test_is_array($array, $expected)
  242. {
  243. $this->assertSame(
  244. $expected,
  245. Arr::is_array($array)
  246. );
  247. }
  248. public function provider_merge()
  249. {
  250. return [
  251. // Test how it merges arrays and sub arrays with assoc keys
  252. [
  253. ['name' => 'mary', 'children' => ['fred', 'paul', 'sally', 'jane']],
  254. ['name' => 'john', 'children' => ['fred', 'paul', 'sally', 'jane']],
  255. ['name' => 'mary', 'children' => ['jane']],
  256. ],
  257. // See how it merges sub-arrays with numerical indexes
  258. [
  259. [['test1'], ['test2'], ['test3']],
  260. [['test1'], ['test2']],
  261. [['test2'], ['test3']],
  262. ],
  263. [
  264. [[['test1']], [['test2']], [['test3']]],
  265. [[['test1']], [['test2']]],
  266. [[['test2']], [['test3']]],
  267. ],
  268. [
  269. ['a' => ['test1','test2'], 'b' => ['test2','test3']],
  270. ['a' => ['test1'], 'b' => ['test2']],
  271. ['a' => ['test2'], 'b' => ['test3']],
  272. ],
  273. [
  274. ['digits' => [0, 1, 2, 3]],
  275. ['digits' => [0, 1]],
  276. ['digits' => [2, 3]],
  277. ],
  278. // See how it manages merging items with numerical indexes
  279. [
  280. [0, 1, 2, 3],
  281. [0, 1],
  282. [2, 3],
  283. ],
  284. // Try and get it to merge assoc. arrays recursively
  285. [
  286. ['foo' => 'bar', ['temp' => 'life']],
  287. ['foo' => 'bin', ['temp' => 'name']],
  288. ['foo' => 'bar', ['temp' => 'life']],
  289. ],
  290. // Bug #3139
  291. [
  292. ['foo' => ['bar']],
  293. ['foo' => 'bar'],
  294. ['foo' => ['bar']],
  295. ],
  296. [
  297. ['foo' => 'bar'],
  298. ['foo' => ['bar']],
  299. ['foo' => 'bar'],
  300. ],
  301. // data set #9
  302. // Associative, Associative
  303. [
  304. ['a' => 'K', 'b' => 'K', 'c' => 'L'],
  305. ['a' => 'J', 'b' => 'K'],
  306. ['a' => 'K', 'c' => 'L'],
  307. ],
  308. // Associative, Indexed
  309. [
  310. ['a' => 'J', 'b' => 'K', 'L'],
  311. ['a' => 'J', 'b' => 'K'],
  312. ['K', 'L'],
  313. ],
  314. // Associative, Mixed
  315. [
  316. ['a' => 'J', 'b' => 'K', 'K', 'c' => 'L'],
  317. ['a' => 'J', 'b' => 'K'],
  318. ['K', 'c' => 'L'],
  319. ],
  320. // data set #12
  321. // Indexed, Associative
  322. [
  323. ['J', 'K', 'a' => 'K', 'c' => 'L'],
  324. ['J', 'K'],
  325. ['a' => 'K', 'c' => 'L'],
  326. ],
  327. // Indexed, Indexed
  328. [
  329. ['J', 'K', 'L'],
  330. ['J', 'K'],
  331. ['K', 'L'],
  332. ],
  333. // Indexed, Mixed
  334. [
  335. ['K', 'K', 'c' => 'L'],
  336. ['J', 'K'],
  337. ['K', 'c' => 'L'],
  338. ],
  339. // data set #15
  340. // Mixed, Associative
  341. [
  342. ['a' => 'K', 'K', 'c' => 'L'],
  343. ['a' => 'J', 'K'],
  344. ['a' => 'K', 'c' => 'L'],
  345. ],
  346. // Mixed, Indexed
  347. [
  348. ['a' => 'J', 'K', 'L'],
  349. ['a' => 'J', 'K'],
  350. ['J', 'L'],
  351. ],
  352. // Mixed, Mixed
  353. [
  354. ['a' => 'K', 'L'],
  355. ['a' => 'J', 'K'],
  356. ['a' => 'K', 'L'],
  357. ],
  358. // Bug #3141
  359. [
  360. ['servers' => [['1.1.1.1', 4730], ['2.2.2.2', 4730]]],
  361. ['servers' => [['1.1.1.1', 4730]]],
  362. ['servers' => [['2.2.2.2', 4730]]],
  363. ],
  364. ];
  365. }
  366. /**
  367. *
  368. * @test
  369. * @dataProvider provider_merge
  370. */
  371. public function test_merge($expected, $array1, $array2)
  372. {
  373. $this->assertSame(
  374. $expected,
  375. Arr::merge($array1,$array2)
  376. );
  377. }
  378. /**
  379. * Provides test data for test_path()
  380. *
  381. * @return array
  382. */
  383. public function provider_path()
  384. {
  385. $array = [
  386. 'foobar' => ['definition' => 'lost'],
  387. 'kohana' => 'awesome',
  388. 'users' => [
  389. 1 => ['name' => 'matt'],
  390. 2 => ['name' => 'john', 'interests' => ['hocky' => ['length' => 2], 'football' => []]],
  391. 3 => 'frank', // Issue #3194
  392. ],
  393. 'object' => new ArrayObject(['iterator' => TRUE]), // Iterable object should work exactly the same
  394. ];
  395. return [
  396. // Tests returns normal values
  397. [$array['foobar'], $array, 'foobar'],
  398. [$array['kohana'], $array, 'kohana'],
  399. [$array['foobar']['definition'], $array, 'foobar.definition'],
  400. // Custom delimiters
  401. [$array['foobar']['definition'], $array, 'foobar/definition', NULL, '/'],
  402. // We should be able to use NULL as a default, returned if the key DNX
  403. [NULL, $array, 'foobar.alternatives', NULL],
  404. [NULL, $array, 'kohana.alternatives', NULL],
  405. // Try using a string as a default
  406. ['nothing', $array, 'kohana.alternatives', 'nothing'],
  407. // Make sure you can use arrays as defaults
  408. [['far', 'wide'], $array, 'cheese.origins', ['far', 'wide']],
  409. // Ensures path() casts ints to actual integers for keys
  410. [$array['users'][1]['name'], $array, 'users.1.name'],
  411. // Test that a wildcard returns the entire array at that "level"
  412. [$array['users'], $array, 'users.*'],
  413. // Now we check that keys after a wilcard will be processed
  414. [[0 => [0 => 2]], $array, 'users.*.interests.*.length'],
  415. // See what happens when it can't dig any deeper from a wildcard
  416. [NULL, $array, 'users.*.fans'],
  417. // Starting wildcards, issue #3269
  418. [['matt', 'john'], $array['users'], '*.name'],
  419. // Path as array, issue #3260
  420. [$array['users'][2]['name'], $array, ['users', 2, 'name']],
  421. [$array['object']['iterator'], $array, 'object.iterator'],
  422. ];
  423. }
  424. /**
  425. * Tests Arr::path()
  426. *
  427. * @test
  428. * @dataProvider provider_path
  429. * @param string $path The path to follow
  430. * @param mixed $default The value to return if dnx
  431. * @param boolean $expected The expected value
  432. * @param string $delimiter The path delimiter
  433. */
  434. public function test_path($expected, $array, $path, $default = NULL, $delimiter = NULL)
  435. {
  436. $this->assertSame(
  437. $expected,
  438. Arr::path($array, $path, $default, $delimiter)
  439. );
  440. }
  441. /**
  442. * Provides test data for test_path()
  443. *
  444. * @return array
  445. */
  446. public function provider_set_path()
  447. {
  448. return [
  449. // Tests returns normal values
  450. [['foo' => 'bar'], [], 'foo', 'bar'],
  451. [['kohana' => ['is' => 'awesome']], [], 'kohana.is', 'awesome'],
  452. [['kohana' => ['is' => 'cool', 'and' => 'slow']],
  453. ['kohana' => ['is' => 'cool']], 'kohana.and', 'slow'],
  454. // Custom delimiters
  455. [['kohana' => ['is' => 'awesome']], [], 'kohana/is', 'awesome', '/'],
  456. // Ensures set_path() casts ints to actual integers for keys
  457. [['foo' => ['bar']], ['foo' => ['test']], 'foo.0', 'bar'],
  458. // Tests if it allows arrays
  459. [['kohana' => ['is' => 'awesome']], [], ['kohana', 'is'], 'awesome'],
  460. ];
  461. }
  462. /**
  463. * Tests Arr::path()
  464. *
  465. * @test
  466. * @dataProvider provider_set_path
  467. * @param string $path The path to follow
  468. * @param boolean $expected The expected value
  469. * @param string $delimiter The path delimiter
  470. */
  471. public function test_set_path($expected, $array, $path, $value, $delimiter = NULL)
  472. {
  473. Arr::set_path($array, $path, $value, $delimiter);
  474. $this->assertSame($expected, $array);
  475. }
  476. /**
  477. * Provides test data for test_range()
  478. *
  479. * @return array
  480. */
  481. public function provider_range()
  482. {
  483. return [
  484. [1, 2],
  485. [1, 100],
  486. [25, 10],
  487. ];
  488. }
  489. /**
  490. * Tests Arr::range()
  491. *
  492. * @dataProvider provider_range
  493. * @param integer $step The step between each value in the array
  494. * @param integer $max The max value of the range (inclusive)
  495. */
  496. public function test_range($step, $max)
  497. {
  498. $range = Arr::range($step, $max);
  499. $this->assertSame( (int) floor($max / $step), count($range));
  500. $current = $step;
  501. foreach ($range as $key => $value)
  502. {
  503. $this->assertSame($key, $value);
  504. $this->assertSame($current, $key);
  505. $this->assertLessThanOrEqual($max, $key);
  506. $current += $step;
  507. }
  508. }
  509. /**
  510. * Provides test data for test_unshift()
  511. *
  512. * @return array
  513. */
  514. public function provider_unshift()
  515. {
  516. return [
  517. [['one' => '1', 'two' => '2',], 'zero', '0'],
  518. [['step 1', 'step 2', 'step 3'], 'step 0', 'wow']
  519. ];
  520. }
  521. /**
  522. * Tests Arr::unshift()
  523. *
  524. * @test
  525. * @dataProvider provider_unshift
  526. * @param array $array
  527. * @param string $key
  528. * @param mixed $value
  529. */
  530. public function test_unshift(array $array, $key, $value)
  531. {
  532. $original = $array;
  533. Arr::unshift($array, $key, $value);
  534. $this->assertNotSame($original, $array);
  535. $this->assertSame(count($original) + 1, count($array));
  536. $this->assertArrayHasKey($key, $array);
  537. $this->assertSame($value, reset($array));
  538. $this->assertSame(key($array), $key);
  539. }
  540. /**
  541. * Provies test data for test_overwrite
  542. *
  543. * @return array Test Data
  544. */
  545. public function provider_overwrite()
  546. {
  547. return [
  548. [
  549. ['name' => 'Henry', 'mood' => 'tired', 'food' => 'waffles', 'sport' => 'checkers'],
  550. ['name' => 'John', 'mood' => 'bored', 'food' => 'bacon', 'sport' => 'checkers'],
  551. ['name' => 'Matt', 'mood' => 'tired', 'food' => 'waffles'],
  552. ['name' => 'Henry', 'age' => 18,],
  553. ],
  554. ];
  555. }
  556. /**
  557. *
  558. * @test
  559. * @dataProvider provider_overwrite
  560. */
  561. public function test_overwrite($expected, $arr1, $arr2, $arr3 = [], $arr4 = [])
  562. {
  563. $this->assertSame(
  564. $expected,
  565. Arr::overwrite($arr1, $arr2, $arr3, $arr4)
  566. );
  567. }
  568. /**
  569. * Provides test data for test_map
  570. *
  571. * @return array Test Data
  572. */
  573. public function provider_map()
  574. {
  575. return [
  576. ['strip_tags', ['<p>foobar</p>'], NULL, ['foobar']],
  577. ['strip_tags', [['<p>foobar</p>'], ['<p>foobar</p>']], NULL, [['foobar'], ['foobar']]],
  578. [
  579. 'strip_tags',
  580. [
  581. 'foo' => '<p>foobar</p>',
  582. 'bar' => '<p>foobar</p>',
  583. ],
  584. NULL,
  585. [
  586. 'foo' => 'foobar',
  587. 'bar' => 'foobar',
  588. ],
  589. ],
  590. [
  591. 'strip_tags',
  592. [
  593. 'foo' => '<p>foobar</p>',
  594. 'bar' => '<p>foobar</p>',
  595. ],
  596. ['foo'],
  597. [
  598. 'foo' => 'foobar',
  599. 'bar' => '<p>foobar</p>',
  600. ],
  601. ],
  602. [
  603. [
  604. 'strip_tags',
  605. 'trim',
  606. ],
  607. [
  608. 'foo' => '<p>foobar </p>',
  609. 'bar' => '<p>foobar</p>',
  610. ],
  611. NULL,
  612. [
  613. 'foo' => 'foobar',
  614. 'bar' => 'foobar',
  615. ],
  616. ],
  617. [
  618. 'strip_tags',
  619. [
  620. [
  621. 'foo' => '<p>foobar</p>',
  622. 'bar' => '<p>foobar</p>',
  623. ],
  624. ],
  625. ['foo'],
  626. [
  627. [
  628. 'foo' => 'foobar',
  629. 'bar' => '<p>foobar</p>',
  630. ],
  631. ],
  632. ],
  633. ];
  634. }
  635. /**
  636. *
  637. * @test
  638. * @dataProvider provider_map
  639. */
  640. public function test_map($method, $source, $keys, $expected)
  641. {
  642. $this->assertSame(
  643. $expected,
  644. Arr::map($method, $source, $keys)
  645. );
  646. }
  647. /**
  648. * Provides test data for test_flatten
  649. *
  650. * @return array Test Data
  651. */
  652. public function provider_flatten()
  653. {
  654. return [
  655. [['set' => ['one' => 'something'], 'two' => 'other'], ['one' => 'something', 'two' => 'other']],
  656. ];
  657. }
  658. /**
  659. *
  660. * @test
  661. * @dataProvider provider_flatten
  662. */
  663. public function test_flatten($source, $expected)
  664. {
  665. $this->assertSame(
  666. $expected,
  667. Arr::flatten($source)
  668. );
  669. }
  670. }