ArrTest.php 16 KB

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