[TASK] Remove leading slash from use statements
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Utility / ArrayUtilityTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Utility;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\ArrayUtility;
18
19 /**
20 * Test case
21 *
22 * @author Susanne Moog <typo3@susanne-moog.de>
23 * @author Christian Kuhn <lolli@schwarzbu.ch>
24 */
25 class ArrayUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
26
27 ///////////////////////
28 // Tests concerning filterByValueRecursive
29 ///////////////////////
30 /**
31 * Data provider for filterByValueRecursiveCorrectlyFiltersArray
32 *
33 * Every array splits into:
34 * - String value to search for
35 * - Input array
36 * - Expected result array
37 */
38 public function filterByValueRecursive() {
39 return array(
40 'empty search array' => array(
41 'banana',
42 array(),
43 array()
44 ),
45 'empty string as needle' => array(
46 '',
47 array(
48 '',
49 'apple'
50 ),
51 array(
52 ''
53 )
54 ),
55 'flat array searching for string' => array(
56 'banana',
57 array(
58 'apple',
59 'banana'
60 ),
61 array(
62 1 => 'banana'
63 )
64 ),
65 'flat array searching for string with two matches' => array(
66 'banana',
67 array(
68 'foo' => 'apple',
69 'firstbanana' => 'banana',
70 'secondbanana' => 'banana'
71 ),
72 array(
73 'firstbanana' => 'banana',
74 'secondbanana' => 'banana'
75 )
76 ),
77 'multi dimensional array searching for string with multiple matches' => array(
78 'banana',
79 array(
80 'foo' => 'apple',
81 'firstbanana' => 'banana',
82 'grape' => array(
83 'foo2' => 'apple2',
84 'secondbanana' => 'banana',
85 'foo3' => array()
86 ),
87 'bar' => 'orange'
88 ),
89 array(
90 'firstbanana' => 'banana',
91 'grape' => array(
92 'secondbanana' => 'banana'
93 )
94 )
95 ),
96 'multi dimensional array searching for integer with multiple matches' => array(
97 42,
98 array(
99 'foo' => 23,
100 'bar' => 42,
101 array(
102 'foo' => 23,
103 'bar' => 42
104 )
105 ),
106 array(
107 'bar' => 42,
108 array(
109 'bar' => 42
110 )
111 )
112 ),
113 'flat array searching for boolean TRUE' => array(
114 TRUE,
115 array(
116 23 => FALSE,
117 42 => TRUE
118 ),
119 array(
120 42 => TRUE
121 )
122 ),
123 'multi dimensional array searching for boolean FALSE' => array(
124 FALSE,
125 array(
126 23 => FALSE,
127 42 => TRUE,
128 'foo' => array(
129 23 => FALSE,
130 42 => TRUE
131 )
132 ),
133 array(
134 23 => FALSE,
135 'foo' => array(
136 23 => FALSE
137 )
138 )
139 ),
140 'flat array searching for array' => array(
141 array(
142 'foo' => 'bar'
143 ),
144 array(
145 'foo' => 'bar',
146 'foobar' => array(
147 'foo' => 'bar'
148 )
149 ),
150 array(
151 'foobar' => array(
152 'foo' => 'bar'
153 )
154 )
155 )
156 );
157 }
158
159 /**
160 * @test
161 * @dataProvider filterByValueRecursive
162 * @param array $needle
163 * @param array $haystack
164 * @param array $expectedResult
165 */
166 public function filterByValueRecursiveCorrectlyFiltersArray($needle, $haystack, $expectedResult) {
167 $this->assertEquals(
168 $expectedResult,
169 ArrayUtility::filterByValueRecursive($needle, $haystack)
170 );
171 }
172
173 /**
174 * @test
175 */
176 public function filterByValueRecursiveMatchesReferencesToSameObject() {
177 $instance = new \stdClass();
178 $this->assertEquals(
179 array($instance),
180 ArrayUtility::filterByValueRecursive($instance, array($instance))
181 );
182 }
183
184 /**
185 * @test
186 */
187 public function filterByValueRecursiveDoesNotMatchDifferentInstancesOfSameClass() {
188 $this->assertEquals(
189 array(),
190 ArrayUtility::filterByValueRecursive(new \stdClass(), array(new \stdClass()))
191 );
192 }
193
194 ///////////////////////
195 // Tests concerning isValidPath
196 ///////////////////////
197 /**
198 * Mock the class under test, isValidPath() (method under test), calls
199 * static getValuePath() internally, which is mocked here to return a specific
200 * result. This works because of 'static' keyword' instead of 'self'
201 * for getValueByPath() call, using late static binding in PHP 5.3
202 *
203 * @test
204 */
205 public function isValidPathReturnsTrueIfPathExists() {
206 $className = $this->getUniqueId('ArrayUtility');
207 eval(
208 'namespace ' . __NAMESPACE__ . ';' .
209 'class ' . $className . ' extends \\TYPO3\\CMS\\Core\\Utility\\ArrayUtility {' .
210 ' public static function getValueByPath() {' .
211 ' return 42;' .
212 ' }' .
213 '}'
214 );
215 $className = __NAMESPACE__ . '\\' . $className;
216 $this->assertTrue($className::isValidPath(array('foo'), 'foo'));
217 }
218
219 /**
220 * @test
221 */
222 public function isValidPathReturnsFalseIfPathDoesNotExist() {
223 $className = $this->getUniqueId('ArrayUtility');
224 eval(
225 'namespace ' . __NAMESPACE__ . ';' .
226 'class ' . $className . ' extends \\TYPO3\\CMS\\Core\\Utility\\ArrayUtility {' .
227 ' public static function getValueByPath() {' .
228 ' throw new \RuntimeException(\'foo\', 123);' .
229 ' }' .
230 '}'
231 );
232 $className = __NAMESPACE__ . '\\' . $className;
233 $this->assertFalse($className::isValidPath(array('foo'), 'foo'));
234 }
235
236 ///////////////////////
237 // Tests concerning getValueByPath
238 ///////////////////////
239 /**
240 * @test
241 * @expectedException \RuntimeException
242 */
243 public function getValueByPathThrowsExceptionIfPathIsEmpty() {
244 ArrayUtility::getValueByPath(array(), '');
245 }
246
247 /**
248 * Data provider for getValueByPathThrowsExceptionIfPathNotExists
249 * Every array splits into:
250 * - Array to get value from
251 * - String path
252 * - Expected result
253 * @return array
254 */
255 public function getValueByPathInvalidPathDataProvider() {
256 return array(
257 'not existing path 1' => array(
258 array(
259 'foo' => array()
260 ),
261 'foo/bar/baz',
262 FALSE
263 ),
264 'not existing path 2' => array(
265 array(
266 'foo' => array(
267 'baz' => 42
268 ),
269 'bar' => array()
270 ),
271 'foo/bar/baz',
272 FALSE
273 ),
274 // Negative test: This could be improved and the test moved to
275 // the valid data provider if the method supports this
276 'doubletick encapsulated quoted doubletick does not work' => array(
277 array(
278 '"foo"bar"' => array(
279 'baz' => 42
280 ),
281 'bar' => array()
282 ),
283 '"foo\\"bar"/baz',
284 42
285 ),
286 // Negative test: Method could be improved here
287 'path with doubletick does not work' => array(
288 array(
289 'fo"o' => array(
290 'bar' => 42
291 )
292 ),
293 'fo"o/foobar',
294 42
295 )
296 );
297 }
298
299 /**
300 * @test
301 * @dataProvider getValueByPathInvalidPathDataProvider
302 * @expectedException \RuntimeException
303 * @param array $array
304 * @param string $path
305 */
306 public function getValueByPathThrowsExceptionIfPathNotExists(array $array, $path) {
307 ArrayUtility::getValueByPath($array, $path);
308 }
309
310 /**
311 * Data provider for getValueByPathReturnsCorrectValue
312 * Every array splits into:
313 * - Array to get value from
314 * - String path
315 * - Expected result
316 */
317 public function getValueByPathValidDataProvider() {
318 $testObject = new \StdClass();
319 $testObject->foo = 'foo';
320 $testObject->bar = 'bar';
321 return array(
322 'integer in multi level array' => array(
323 array(
324 'foo' => array(
325 'bar' => array(
326 'baz' => 42
327 ),
328 'bar2' => array()
329 )
330 ),
331 'foo/bar/baz',
332 42
333 ),
334 'zero integer in multi level array' => array(
335 array(
336 'foo' => array(
337 'bar' => array(
338 'baz' => 0
339 )
340 )
341 ),
342 'foo/bar/baz',
343 0
344 ),
345 'NULL value in multi level array' => array(
346 array(
347 'foo' => array(
348 'baz' => NULL
349 )
350 ),
351 'foo/baz',
352 NULL
353 ),
354 'get string value' => array(
355 array(
356 'foo' => array(
357 'baz' => 'this is a test string'
358 )
359 ),
360 'foo/baz',
361 'this is a test string'
362 ),
363 'get boolean value: FALSE' => array(
364 array(
365 'foo' => array(
366 'baz' => FALSE
367 )
368 ),
369 'foo/baz',
370 FALSE
371 ),
372 'get boolean value: TRUE' => array(
373 array(
374 'foo' => array(
375 'baz' => TRUE
376 )
377 ),
378 'foo/baz',
379 TRUE
380 ),
381 'get object value' => array(
382 array(
383 'foo' => array(
384 'baz' => $testObject
385 )
386 ),
387 'foo/baz',
388 $testObject
389 ),
390 'enclosed path' => array(
391 array(
392 'foo/bar' => array(
393 'foobar' => 42
394 )
395 ),
396 '"foo/bar"/foobar',
397 42
398 )
399 );
400 }
401
402 /**
403 * @test
404 * @dataProvider getValueByPathValidDataProvider
405 * @param array $array
406 * @param string $path
407 * @param mixed $expectedResult
408 */
409 public function getValueByPathGetsCorrectValue(array $array, $path, $expectedResult) {
410 $this->assertEquals($expectedResult, ArrayUtility::getValueByPath($array, $path));
411 }
412
413 /**
414 * @test
415 */
416 public function getValueByPathAcceptsDifferentDelimiter() {
417 $input = array(
418 'foo' => array(
419 'bar' => array(
420 'baz' => 42
421 ),
422 'bar2' => array()
423 )
424 );
425 $searchPath = 'foo%bar%baz';
426 $expected = 42;
427 $delimiter = '%';
428 $this->assertEquals(
429 $expected,
430 ArrayUtility::getValueByPath($input, $searchPath, $delimiter)
431 );
432 }
433
434 ///////////////////////
435 // Tests concerning setValueByPath
436 ///////////////////////
437 /**
438 * @test
439 * @expectedException \RuntimeException
440 */
441 public function setValueByPathThrowsExceptionIfPathIsEmpty() {
442 ArrayUtility::setValueByPath(array(), '', NULL);
443 }
444
445 /**
446 * @test
447 * @expectedException \RuntimeException
448 */
449 public function setValueByPathThrowsExceptionIfPathIsNotAString() {
450 ArrayUtility::setValueByPath(array(), array('foo'), NULL);
451 }
452
453 /**
454 * Data provider for setValueByPathSetsCorrectValueDataProvider
455 *
456 * Every array splits into:
457 * - Array to set value in
458 * - String path
459 * - Value to set
460 * - Expected result
461 */
462 public function setValueByPathSetsCorrectValueDataProvider() {
463 $testObject = new \StdClass();
464 $testObject->foo = 'foo';
465 $testObject->bar = 'bar';
466 return array(
467 'set integer value: 42' => array(
468 array(
469 'foo' => array(
470 'bar' => array(
471 'baz' => 0
472 )
473 )
474 ),
475 'foo/bar/baz',
476 42,
477 array(
478 'foo' => array(
479 'bar' => array(
480 'baz' => 42
481 )
482 )
483 )
484 ),
485 'set integer value: 0' => array(
486 array(
487 'foo' => array(
488 'bar' => array(
489 'baz' => 42
490 )
491 )
492 ),
493 'foo/bar/baz',
494 0,
495 array(
496 'foo' => array(
497 'bar' => array(
498 'baz' => 0
499 )
500 )
501 )
502 ),
503 'set null value' => array(
504 array(
505 'foo' => array(
506 'bar' => array(
507 'baz' => 42
508 )
509 )
510 ),
511 'foo/bar/baz',
512 NULL,
513 array(
514 'foo' => array(
515 'bar' => array(
516 'baz' => NULL
517 )
518 )
519 )
520 ),
521 'set array value' => array(
522 array(
523 'foo' => array(
524 'bar' => array(
525 'baz' => 42
526 )
527 )
528 ),
529 'foo/bar/baz',
530 array(
531 'foo' => 123
532 ),
533 array(
534 'foo' => array(
535 'bar' => array(
536 'baz' => array(
537 'foo' => 123
538 )
539 )
540 )
541 )
542 ),
543 'set boolean value: FALSE' => array(
544 array(
545 'foo' => array(
546 'bar' => array(
547 'baz' => TRUE
548 )
549 )
550 ),
551 'foo/bar/baz',
552 FALSE,
553 array(
554 'foo' => array(
555 'bar' => array(
556 'baz' => FALSE
557 )
558 )
559 )
560 ),
561 'set boolean value: TRUE' => array(
562 array(
563 'foo' => array(
564 'bar' => array(
565 'baz' => NULL
566 )
567 )
568 ),
569 'foo/bar/baz',
570 TRUE,
571 array(
572 'foo' => array(
573 'bar' => array(
574 'baz' => TRUE
575 )
576 )
577 )
578 ),
579 'set object value' => array(
580 array(
581 'foo' => array(
582 'bar' => array(
583 'baz' => NULL
584 )
585 )
586 ),
587 'foo/bar/baz',
588 $testObject,
589 array(
590 'foo' => array(
591 'bar' => array(
592 'baz' => $testObject
593 )
594 )
595 )
596 ),
597 'multi keys in array' => array(
598 array(
599 'foo' => array(
600 'bar' => array(
601 'baz' => 'value'
602 ),
603 'bar2' => array(
604 'baz' => 'value'
605 )
606 )
607 ),
608 'foo/bar2/baz',
609 'newValue',
610 array(
611 'foo' => array(
612 'bar' => array(
613 'baz' => 'value'
614 ),
615 'bar2' => array(
616 'baz' => 'newValue'
617 )
618 )
619 )
620 )
621 );
622 }
623
624 /**
625 * @test
626 * @dataProvider setValueByPathSetsCorrectValueDataProvider
627 * @param array $array
628 * @param string $path
629 * @param string $value
630 * @param array $expectedResult
631 */
632 public function setValueByPathSetsCorrectValue(array $array, $path, $value, $expectedResult) {
633 $this->assertEquals(
634 $expectedResult,
635 ArrayUtility::setValueByPath($array, $path, $value)
636 );
637 }
638
639 /**********************
640 /* Tests concerning removeByPath
641 ***********************/
642
643 /**
644 * @test
645 * @expectedException \RuntimeException
646 */
647 public function removeByPathThrowsExceptionIfPathIsEmpty() {
648 ArrayUtility::removeByPath(array(), '');
649 }
650
651 /**
652 * @test
653 * @expectedException \RuntimeException
654 */
655 public function removeByPathThrowsExceptionIfPathIsNotAString() {
656 ArrayUtility::removeByPath(array(), array('foo'));
657 }
658
659 /**
660 * @test
661 * @expectedException \RuntimeException
662 */
663 public function removeByPathThrowsExceptionWithEmptyPathSegment() {
664 $inputArray = array(
665 'foo' => array(
666 'bar' => 42,
667 ),
668 );
669 ArrayUtility::removeByPath($inputArray, 'foo//bar');
670 }
671
672 /**
673 * @test
674 * @expectedException \RuntimeException
675 */
676 public function removeByPathThrowsExceptionIfPathDoesNotExistInArray() {
677 $inputArray = array(
678 'foo' => array(
679 'bar' => 42,
680 ),
681 );
682 ArrayUtility::removeByPath($inputArray, 'foo/baz');
683 }
684
685 /**
686 * @test
687 */
688 public function removeByPathAcceptsGivenDelimiter() {
689 $inputArray = array(
690 'foo' => array(
691 'toRemove' => 42,
692 'keep' => 23
693 ),
694 );
695 $path = 'foo.toRemove';
696 $expected = array(
697 'foo' => array(
698 'keep' => 23,
699 ),
700 );
701 $this->assertEquals(
702 $expected,
703 ArrayUtility::removeByPath($inputArray, $path, '.')
704 );
705 }
706
707 /**
708 * Data provider for removeByPathRemovesCorrectPath
709 */
710 public function removeByPathRemovesCorrectPathDataProvider() {
711 return array(
712 'single value' => array(
713 array(
714 'foo' => array(
715 'toRemove' => 42,
716 'keep' => 23
717 ),
718 ),
719 'foo/toRemove',
720 array(
721 'foo' => array(
722 'keep' => 23,
723 ),
724 ),
725 ),
726 'whole array' => array(
727 array(
728 'foo' => array(
729 'bar' => 42
730 ),
731 ),
732 'foo',
733 array(),
734 ),
735 'sub array' => array(
736 array(
737 'foo' => array(
738 'keep' => 23,
739 'toRemove' => array(
740 'foo' => 'bar',
741 ),
742 ),
743 ),
744 'foo/toRemove',
745 array(
746 'foo' => array(
747 'keep' => 23,
748 ),
749 ),
750 ),
751 );
752 }
753
754 /**
755 * @test
756 * @dataProvider removeByPathRemovesCorrectPathDataProvider
757 * @param array $array
758 * @param string $path
759 * @param array $expectedResult
760 */
761 public function removeByPathRemovesCorrectPath(array $array, $path, $expectedResult) {
762 $this->assertEquals(
763 $expectedResult,
764 ArrayUtility::removeByPath($array, $path)
765 );
766 }
767
768 ///////////////////////
769 // Tests concerning sortByKeyRecursive
770 ///////////////////////
771 /**
772 * @test
773 */
774 public function sortByKeyRecursiveCheckIfSortingIsCorrect() {
775 $unsortedArray = array(
776 'z' => NULL,
777 'a' => NULL,
778 'd' => array(
779 'c' => NULL,
780 'b' => NULL,
781 'd' => NULL,
782 'a' => NULL
783 )
784 );
785 $expectedResult = array(
786 'a' => NULL,
787 'd' => array(
788 'a' => NULL,
789 'b' => NULL,
790 'c' => NULL,
791 'd' => NULL
792 ),
793 'z' => NULL
794 );
795 $this->assertSame($expectedResult, ArrayUtility::sortByKeyRecursive($unsortedArray));
796 }
797
798 ///////////////////////
799 // Tests concerning sortArraysByKey
800 ///////////////////////
801 /**
802 * Data provider for sortArraysByKeyCheckIfSortingIsCorrect
803 */
804 public function sortArraysByKeyCheckIfSortingIsCorrectDataProvider() {
805 return array(
806 'assoc array index' => array(
807 array(
808 '22' => array(
809 'uid' => '22',
810 'title' => 'c',
811 'dummy' => 2
812 ),
813 '24' => array(
814 'uid' => '24',
815 'title' => 'a',
816 'dummy' => 3
817 ),
818 '23' => array(
819 'uid' => '23',
820 'title' => 'b',
821 'dummy' => 4
822 ),
823 ),
824 'title',
825 TRUE,
826 array(
827 '24' => array(
828 'uid' => '24',
829 'title' => 'a',
830 'dummy' => 3
831 ),
832 '23' => array(
833 'uid' => '23',
834 'title' => 'b',
835 'dummy' => 4
836 ),
837 '22' => array(
838 'uid' => '22',
839 'title' => 'c',
840 'dummy' => 2
841 ),
842 ),
843 ),
844 'numeric array index' => array(
845 array(
846 22 => array(
847 'uid' => '22',
848 'title' => 'c',
849 'dummy' => 2
850 ),
851 24 => array(
852 'uid' => '24',
853 'title' => 'a',
854 'dummy' => 3
855 ),
856 23 => array(
857 'uid' => '23',
858 'title' => 'b',
859 'dummy' => 4
860 ),
861 ),
862 'title',
863 TRUE,
864 array(
865 24 => array(
866 'uid' => '24',
867 'title' => 'a',
868 'dummy' => 3
869 ),
870 23 => array(
871 'uid' => '23',
872 'title' => 'b',
873 'dummy' => 4
874 ),
875 22 => array(
876 'uid' => '22',
877 'title' => 'c',
878 'dummy' => 2
879 ),
880 ),
881 ),
882 'numeric array index DESC' => array(
883 array(
884 23 => array(
885 'uid' => '23',
886 'title' => 'b',
887 'dummy' => 4
888 ),
889 22 => array(
890 'uid' => '22',
891 'title' => 'c',
892 'dummy' => 2
893 ),
894 24 => array(
895 'uid' => '24',
896 'title' => 'a',
897 'dummy' => 3
898 ),
899 ),
900 'title',
901 FALSE,
902 array(
903 22 => array(
904 'uid' => '22',
905 'title' => 'c',
906 'dummy' => 2
907 ),
908 23 => array(
909 'uid' => '23',
910 'title' => 'b',
911 'dummy' => 4
912 ),
913 24 => array(
914 'uid' => '24',
915 'title' => 'a',
916 'dummy' => 3
917 ),
918 ),
919 ),
920 );
921 }
922
923 /**
924 * @test
925 * @dataProvider sortArraysByKeyCheckIfSortingIsCorrectDataProvider
926 * @param array $array
927 * @param string $key
928 * @param bool $ascending
929 * @param array $expectedResult
930 */
931 public function sortArraysByKeyCheckIfSortingIsCorrect(array $array, $key, $ascending, $expectedResult) {
932 $sortedArray = ArrayUtility::sortArraysByKey($array, $key, $ascending);
933 $this->assertSame($expectedResult, $sortedArray);
934 }
935
936 /**
937 * @test
938 * @expectedException \RuntimeException
939 */
940 public function sortArraysByKeyThrowsExceptionForNonExistingKey() {
941 ArrayUtility::sortArraysByKey(array(array('a'), array('a')), 'dummy');
942 }
943
944 ///////////////////////
945 // Tests concerning arrayExport
946 ///////////////////////
947 /**
948 * @test
949 */
950 public function arrayExportReturnsFormattedMultidimensionalArray() {
951 $array = array(
952 'foo' => array(
953 'bar' => 42,
954 'bar2' => array(
955 'baz' => 'val\'ue',
956 'baz2' => TRUE,
957 'baz3' => FALSE,
958 'baz4' => array()
959 )
960 ),
961 'baz' => 23,
962 'foobar' => NULL,
963 'qux' => 0.1,
964 'qux2' => 0.000000001,
965 );
966 $expected =
967 'array(' . LF .
968 TAB . '\'foo\' => array(' . LF .
969 TAB . TAB . '\'bar\' => 42,' . LF .
970 TAB . TAB . '\'bar2\' => array(' . LF .
971 TAB . TAB . TAB . '\'baz\' => \'val\\\'ue\',' . LF .
972 TAB . TAB . TAB . '\'baz2\' => TRUE,' . LF .
973 TAB . TAB . TAB . '\'baz3\' => FALSE,' . LF .
974 TAB . TAB . TAB . '\'baz4\' => array(),' . LF .
975 TAB . TAB . '),' . LF .
976 TAB . '),' . LF .
977 TAB . '\'baz\' => 23,' . LF .
978 TAB . '\'foobar\' => NULL,' . LF .
979 TAB . '\'qux\' => 0.1,' . LF .
980 TAB . '\'qux2\' => 1.0E-9,' . LF .
981 ')';
982 $this->assertSame($expected, ArrayUtility::arrayExport($array));
983 }
984
985 /**
986 * @test
987 * @expectedException \RuntimeException
988 */
989 public function arrayExportThrowsExceptionIfObjectShouldBeExported() {
990 $array = array(
991 'foo' => array(
992 'bar' => new \stdClass()
993 )
994 );
995 ArrayUtility::arrayExport($array);
996 }
997
998 /**
999 * @test
1000 */
1001 public function arrayExportReturnsNumericArrayKeys() {
1002 $array = array(
1003 'foo' => 'string key',
1004 23 => 'integer key',
1005 '42' => 'string key representing integer'
1006 );
1007 $expected =
1008 'array(' . LF .
1009 TAB . '\'foo\' => \'string key\',' . LF .
1010 TAB . '23 => \'integer key\',' . LF .
1011 TAB . '42 => \'string key representing integer\',' . LF .
1012 ')';
1013 $this->assertSame($expected, ArrayUtility::arrayExport($array));
1014 }
1015
1016 /**
1017 * @test
1018 */
1019 public function arrayExportReturnsNoKeyIndexForConsecutiveCountedArrays() {
1020 $array = array(
1021 0 => 'zero',
1022 1 => 'one',
1023 2 => 'two'
1024 );
1025 $expected =
1026 'array(' . LF .
1027 TAB . '\'zero\',' . LF .
1028 TAB . '\'one\',' . LF .
1029 TAB . '\'two\',' . LF .
1030 ')';
1031 $this->assertSame($expected, ArrayUtility::arrayExport($array));
1032 }
1033
1034 /**
1035 * @test
1036 */
1037 public function arrayExportReturnsKeyIndexForNonConsecutiveCountedArrays() {
1038 $array = array(
1039 0 => 'zero',
1040 1 => 'one',
1041 3 => 'three',
1042 4 => 'four'
1043 );
1044 $expected =
1045 'array(' . LF .
1046 TAB . '0 => \'zero\',' . LF .
1047 TAB . '1 => \'one\',' . LF .
1048 TAB . '3 => \'three\',' . LF .
1049 TAB . '4 => \'four\',' . LF .
1050 ')';
1051 $this->assertSame($expected, ArrayUtility::arrayExport($array));
1052 }
1053
1054
1055 ///////////////////////
1056 // Tests concerning flatten
1057 ///////////////////////
1058
1059 /**
1060 * @return array
1061 */
1062 public function flattenCalculatesExpectedResultDataProvider() {
1063 return array(
1064 'plain array' => array(
1065 array(
1066 'first' => 1,
1067 'second' => 2
1068 ),
1069 array(
1070 'first' => 1,
1071 'second' => 2
1072 )
1073 ),
1074 'plain array with faulty dots' => array(
1075 array(
1076 'first.' => 1,
1077 'second.' => 2
1078 ),
1079 array(
1080 'first' => 1,
1081 'second' => 2
1082 )
1083 ),
1084 'nested array of 2 levels' => array(
1085 array(
1086 'first.' => array(
1087 'firstSub' => 1
1088 ),
1089 'second.' => array(
1090 'secondSub' => 2
1091 )
1092 ),
1093 array(
1094 'first.firstSub' => 1,
1095 'second.secondSub' => 2
1096 )
1097 ),
1098 'nested array of 2 levels with faulty dots' => array(
1099 array(
1100 'first.' => array(
1101 'firstSub.' => 1
1102 ),
1103 'second.' => array(
1104 'secondSub.' => 2
1105 )
1106 ),
1107 array(
1108 'first.firstSub' => 1,
1109 'second.secondSub' => 2
1110 )
1111 ),
1112 'nested array of 3 levels' => array(
1113 array(
1114 'first.' => array(
1115 'firstSub.' => array(
1116 'firstSubSub' => 1
1117 )
1118 ),
1119 'second.' => array(
1120 'secondSub.' => array(
1121 'secondSubSub' => 2
1122 )
1123 )
1124 ),
1125 array(
1126 'first.firstSub.firstSubSub' => 1,
1127 'second.secondSub.secondSubSub' => 2
1128 )
1129 ),
1130 'nested array of 3 levels with faulty dots' => array(
1131 array(
1132 'first.' => array(
1133 'firstSub.' => array(
1134 'firstSubSub.' => 1
1135 )
1136 ),
1137 'second.' => array(
1138 'secondSub.' => array(
1139 'secondSubSub.' => 2
1140 )
1141 )
1142 ),
1143 array(
1144 'first.firstSub.firstSubSub' => 1,
1145 'second.secondSub.secondSubSub' => 2
1146 )
1147 )
1148 );
1149 }
1150
1151 /**
1152 * @test
1153 * @param array $array
1154 * @param array $expected
1155 * @dataProvider flattenCalculatesExpectedResultDataProvider
1156 */
1157 public function flattenCalculatesExpectedResult(array $array, array $expected) {
1158 $this->assertEquals($expected, ArrayUtility::flatten($array));
1159 }
1160
1161
1162 ///////////////////////
1163 // Tests concerning intersectRecursive
1164 ///////////////////////
1165
1166 /**
1167 * @return array
1168 */
1169 public function intersectRecursiveCalculatesExpectedResultDataProvider() {
1170 $sameObject = new \stdClass();
1171 return array(
1172 // array($source, $mask, $expected)
1173 'empty array is returned if source is empty array' => array(
1174 array(),
1175 array(
1176 'foo' => 'bar',
1177 ),
1178 array(),
1179 ),
1180 'empty array is returned if mask is empty' => array(
1181 array(
1182 'foo' => 'bar',
1183 ),
1184 array(),
1185 array(),
1186 ),
1187 'key is kept on first level if exists in mask' => array(
1188 array(
1189 'foo' => 42,
1190 ),
1191 array(
1192 'foo' => 42,
1193 ),
1194 array(
1195 'foo' => 42,
1196 ),
1197 ),
1198 'value of key in source is kept if mask has different value' => array(
1199 array(
1200 'foo' => 42,
1201 ),
1202 array(
1203 'foo' => new \stdClass(),
1204 ),
1205 array(
1206 'foo' => 42,
1207 ),
1208 ),
1209 'key is kept on first level if according mask value is NULL' => array(
1210 array(
1211 'foo' => 42,
1212 ),
1213 array(
1214 'foo' => NULL,
1215 ),
1216 array(
1217 'foo' => 42,
1218 ),
1219 ),
1220 'null in source value is kept' => array(
1221 array(
1222 'foo' => NULL,
1223 ),
1224 array(
1225 'foo' => 'bar',
1226 ),
1227 array(
1228 'foo' => NULL,
1229 )
1230 ),
1231 'mask does not add new keys' => array(
1232 array(
1233 'foo' => 42,
1234 ),
1235 array(
1236 'foo' => 23,
1237 'bar' => array(
1238 4711
1239 ),
1240 ),
1241 array(
1242 'foo' => 42,
1243 ),
1244 ),
1245 'mask does not overwrite simple values with arrays' => array(
1246 array(
1247 'foo' => 42,
1248 ),
1249 array(
1250 'foo' => array(
1251 'bar' => 23,
1252 ),
1253 ),
1254 array(
1255 'foo' => 42,
1256 ),
1257 ),
1258 'key is kept on first level if according mask value is array' => array(
1259 array(
1260 'foo' => 42,
1261 ),
1262 array(
1263 'foo' => array(
1264 'bar' => 23
1265 ),
1266 ),
1267 array(
1268 'foo' => 42,
1269 ),
1270 ),
1271 'full array is kept if value is array and mask value is simple type' => array(
1272 array(
1273 'foo' => array(
1274 'bar' => 23
1275 ),
1276 ),
1277 array(
1278 'foo' => 42,
1279 ),
1280 array(
1281 'foo' => array(
1282 'bar' => 23
1283 ),
1284 ),
1285 ),
1286 'key handling is type agnostic' => array(
1287 array(
1288 42 => 'foo',
1289 ),
1290 array(
1291 '42' => 'bar',
1292 ),
1293 array(
1294 42 => 'foo',
1295 ),
1296 ),
1297 'value is same if value is object' => array(
1298 array(
1299 'foo' => $sameObject,
1300 ),
1301 array(
1302 'foo' => 'something',
1303 ),
1304 array(
1305 'foo' => $sameObject,
1306 ),
1307 ),
1308 'mask does not add simple value to result if key does not exist in source' => array(
1309 array(
1310 'foo' => '42',
1311 ),
1312 array(
1313 'foo' => '42',
1314 'bar' => 23
1315 ),
1316 array(
1317 'foo' => '42',
1318 ),
1319 ),
1320 'array of source is kept if value of mask key exists but is no array' => array(
1321 array(
1322 'foo' => '42',
1323 'bar' => array(
1324 'baz' => 23
1325 ),
1326 ),
1327 array(
1328 'foo' => 'value is not significant',
1329 'bar' => NULL,
1330 ),
1331 array(
1332 'foo' => '42',
1333 'bar' => array(
1334 'baz' => 23
1335 ),
1336 ),
1337 ),
1338 'sub arrays are kept if mask has according sub array key and is similar array' => array(
1339 array(
1340 'first1' => 42,
1341 'first2' => array(
1342 'second1' => 23,
1343 'second2' => 4711,
1344 ),
1345 ),
1346 array(
1347 'first1' => 42,
1348 'first2' => array(
1349 'second1' => 'exists but different',
1350 ),
1351 ),
1352 array(
1353 'first1' => 42,
1354 'first2' => array(
1355 'second1' => 23,
1356 ),
1357 ),
1358 ),
1359 );
1360 }
1361
1362 /**
1363 * @test
1364 * @param array $source
1365 * @param array $mask
1366 * @param array $expected
1367 * @dataProvider intersectRecursiveCalculatesExpectedResultDataProvider
1368 */
1369 public function intersectRecursiveCalculatesExpectedResult(array $source, array $mask, array $expected) {
1370 $this->assertSame($expected, ArrayUtility::intersectRecursive($source, $mask));
1371 }
1372
1373
1374 ///////////////////////
1375 // Tests concerning renumberKeysToAvoidLeapsIfKeysAreAllNumeric
1376 ///////////////////////
1377 /**
1378 * @return array
1379 */
1380 public function renumberKeysToAvoidLeapsIfKeysAreAllNumericDataProvider() {
1381 return array(
1382 'empty array is returned if source is empty array' => array(
1383 array(),
1384 array()
1385 ),
1386 'returns self if array is already numerically keyed' => array(
1387 array(1,2,3),
1388 array(1,2,3)
1389 ),
1390 'returns correctly if keys are numeric, but contains a leap' => array(
1391 array(0 => 'One', 1 => 'Two', 3 => 'Three'),
1392 array(0 => 'One', 1 => 'Two', 2 => 'Three'),
1393 ),
1394 'returns correctly even though keys are strings but still numeric' => array(
1395 array('0' => 'One', '1' => 'Two', '3' => 'Three'),
1396 array(0 => 'One', 1 => 'Two', 2 => 'Three'),
1397 ),
1398 'returns correctly if just a single keys is not numeric' => array(
1399 array(0 => 'Zero', '1' => 'One', 'Two' => 'Two'),
1400 array(0 => 'Zero', '1' => 'One', 'Two' => 'Two'),
1401 ),
1402 'return self with nested numerically keyed array' => array(
1403 array(
1404 'One',
1405 'Two',
1406 'Three',
1407 array(
1408 'sub.One',
1409 'sub.Two',
1410 )
1411 ),
1412 array(
1413 'One',
1414 'Two',
1415 'Three',
1416 array(
1417 'sub.One',
1418 'sub.Two',
1419 )
1420 )
1421 ),
1422 'returns correctly with nested numerically keyed array with leaps' => array(
1423 array(
1424 'One',
1425 'Two',
1426 'Three',
1427 array(
1428 0 => 'sub.One',
1429 2 => 'sub.Two',
1430 )
1431 ),
1432 array(
1433 'One',
1434 'Two',
1435 'Three',
1436 array(
1437 'sub.One',
1438 'sub.Two',
1439 )
1440 )
1441 ),
1442 'returns correctly with nested string-keyed array' => array(
1443 array(
1444 'One',
1445 'Two',
1446 'Three',
1447 array(
1448 'one' => 'sub.One',
1449 'two' => 'sub.Two',
1450 )
1451 ),
1452 array(
1453 'One',
1454 'Two',
1455 'Three',
1456 array(
1457 'one' => 'sub.One',
1458 'two' => 'sub.Two',
1459 )
1460 )
1461 ),
1462 'returns correctly with deeply nested arrays' => array(
1463 array(
1464 'One',
1465 'Two',
1466 array(
1467 'one' => 1,
1468 'two' => 2,
1469 'three' => array(
1470 2 => 'SubSubOne',
1471 5 => 'SubSubTwo',
1472 9 => array(0,1,2),
1473 array()
1474 )
1475 )
1476 ),
1477 array(
1478 'One',
1479 'Two',
1480 array(
1481 'one' => 1,
1482 'two' => 2,
1483 'three' => array(
1484 'SubSubOne',
1485 'SubSubTwo',
1486 array(0,1,2),
1487 array()
1488 )
1489 )
1490 )
1491 )
1492 );
1493 }
1494
1495 /**
1496 * @test
1497 * @param array $inputArray
1498 * @param array $expected
1499 * @dataProvider renumberKeysToAvoidLeapsIfKeysAreAllNumericDataProvider
1500 */
1501 public function renumberKeysToAvoidLeapsIfKeysAreAllNumericReturnsExpectedOrder(array $inputArray, array $expected) {
1502 $this->assertEquals($expected, ArrayUtility::renumberKeysToAvoidLeapsIfKeysAreAllNumeric($inputArray));
1503 }
1504
1505 /**
1506 * @return array
1507 */
1508 public function mergeRecursiveWithOverruleCalculatesExpectedResultDataProvider() {
1509 return array(
1510 'Override array can reset string to array' => array(
1511 array(
1512 'first' => array(
1513 'second' => 'foo',
1514 ),
1515 ),
1516 array(
1517 'first' => array(
1518 'second' => array('third' => 'bar'),
1519 ),
1520 ),
1521 TRUE,
1522 TRUE,
1523 TRUE,
1524 array(
1525 'first' => array(
1526 'second' => array('third' => 'bar'),
1527 ),
1528 ),
1529 ),
1530 'Override array does not reset array to string (weird!)' => array(
1531 array(
1532 'first' => array(),
1533 ),
1534 array(
1535 'first' => 'foo',
1536 ),
1537 TRUE,
1538 TRUE,
1539 TRUE,
1540 array(
1541 'first' => array(), // This is rather unexpected, naive expectation: first => 'foo'
1542 ),
1543 ),
1544 'Override array does override string with null' => array(
1545 array(
1546 'first' => 'foo',
1547 ),
1548 array(
1549 'first' => NULL,
1550 ),
1551 TRUE,
1552 TRUE,
1553 TRUE,
1554 array(
1555 'first' => NULL,
1556 ),
1557 ),
1558 'Override array does override null with string' => array(
1559 array(
1560 'first' => NULL,
1561 ),
1562 array(
1563 'first' => 'foo',
1564 ),
1565 TRUE,
1566 TRUE,
1567 TRUE,
1568 array(
1569 'first' => 'foo',
1570 ),
1571 ),
1572 'Override array does override null with empty string' => array(
1573 array(
1574 'first' => NULL,
1575 ),
1576 array(
1577 'first' => '',
1578 ),
1579 TRUE,
1580 TRUE,
1581 TRUE,
1582 array(
1583 'first' => '',
1584 ),
1585 ),
1586 'Override array does not override string with NULL if requested' => array(
1587 array(
1588 'first' => 'foo',
1589 ),
1590 array(
1591 'first' => NULL,
1592 ),
1593 TRUE,
1594 FALSE, // no include empty values
1595 TRUE,
1596 array(
1597 'first' => 'foo',
1598 ),
1599 ),
1600 'Override array does override null with null' => array(
1601 array(
1602 'first' => NULL,
1603 ),
1604 array(
1605 'first' => NULL,
1606 ),
1607 TRUE,
1608 TRUE,
1609 TRUE,
1610 array(
1611 'first' => '',
1612 ),
1613 ),
1614 'Override array can __UNSET values' => array(
1615 array(
1616 'first' => array(
1617 'second' => 'second',
1618 'third' => 'third',
1619 ),
1620 'fifth' => array(),
1621 ),
1622 array(
1623 'first' => array(
1624 'second' => 'overrule',
1625 'third' => '__UNSET',
1626 'fourth' => 'overrile',
1627 ),
1628 'fifth' => '__UNSET',
1629 ),
1630 TRUE,
1631 TRUE,
1632 TRUE,
1633 array(
1634 'first' => array(
1635 'second' => 'overrule',
1636 'fourth' => 'overrile',
1637 ),
1638 ),
1639 ),
1640 'Override can add keys' => array(
1641 array(
1642 'first' => 'foo',
1643 ),
1644 array(
1645 'second' => 'bar',
1646 ),
1647 TRUE,
1648 TRUE,
1649 TRUE,
1650 array(
1651 'first' => 'foo',
1652 'second' => 'bar',
1653 ),
1654 ),
1655 'Override does not add key if __UNSET' => array(
1656 array(
1657 'first' => 'foo',
1658 ),
1659 array(
1660 'second' => '__UNSET',
1661 ),
1662 TRUE,
1663 TRUE,
1664 TRUE,
1665 array(
1666 'first' => 'foo',
1667 ),
1668 ),
1669 'Override does not add key if not requested' => array(
1670 array(
1671 'first' => 'foo',
1672 ),
1673 array(
1674 'second' => 'bar',
1675 ),
1676 FALSE, // no add keys
1677 TRUE,
1678 TRUE,
1679 array(
1680 'first' => 'foo',
1681 ),
1682 ),
1683 'Override does not add key if not requested with add include empty values' => array(
1684 array(
1685 'first' => 'foo',
1686 ),
1687 array(
1688 'second' => 'bar',
1689 ),
1690 FALSE, // no add keys
1691 FALSE, // no include empty values
1692 TRUE,
1693 array(
1694 'first' => 'foo',
1695 ),
1696 ),
1697 'Override does not override string with empty string if requested' => array(
1698 array(
1699 'first' => 'foo',
1700 ),
1701 array(
1702 'first' => '',
1703 ),
1704 TRUE,
1705 FALSE, // no include empty values
1706 TRUE,
1707 array(
1708 'first' => 'foo',
1709 ),
1710 ),
1711 'Override array does merge instead of __UNSET if requested (weird!)' => array(
1712 array(
1713 'first' => array(
1714 'second' => 'second',
1715 'third' => 'third',
1716 ),
1717 'fifth' => array(),
1718 ),
1719 array(
1720 'first' => array(
1721 'second' => 'overrule',
1722 'third' => '__UNSET',
1723 'fourth' => 'overrile',
1724 ),
1725 'fifth' => '__UNSET',
1726 ),
1727 TRUE,
1728 TRUE,
1729 FALSE,
1730 array(
1731 'first' => array(
1732 'second' => 'overrule',
1733 'third' => '__UNSET', // overruled
1734 'fourth' => 'overrile',
1735 ),
1736 'fifth' => array(), // not overruled with string here, naive expectation: 'fifth' => '__UNSET'
1737 ),
1738 ),
1739 );
1740 }
1741
1742 /**
1743 * @test
1744 * @dataProvider mergeRecursiveWithOverruleCalculatesExpectedResultDataProvider
1745 */
1746 public function mergeRecursiveWithOverruleCalculatesExpectedResult($input1, $input2, $addKeys, $includeEmptyValues, $enableUnsetFeature, $expected) {
1747 ArrayUtility::mergeRecursiveWithOverrule($input1, $input2, $addKeys, $includeEmptyValues, $enableUnsetFeature);
1748 $this->assertEquals($expected, $input1);
1749 }
1750
1751 //////////////////////////////////
1752 // Tests concerning inArray
1753 //////////////////////////////////
1754 /**
1755 * @test
1756 * @dataProvider inArrayDataProvider
1757 */
1758 public function inArrayChecksStringExistenceWithinArray($array, $item, $expected) {
1759 $this->assertEquals($expected, ArrayUtility::inArray($array, $item));
1760 }
1761
1762 /**
1763 * Data provider for inArrayChecksStringExistenceWithinArray
1764 *
1765 * @return array
1766 */
1767 public function inArrayDataProvider() {
1768 return array(
1769 'Empty array' => array(array(), 'search', FALSE),
1770 'One item array no match' => array(array('one'), 'two', FALSE),
1771 'One item array match' => array(array('one'), 'one', TRUE),
1772 'Multiple items array no match' => array(array('one', 2, 'three', 4), 'four', FALSE),
1773 'Multiple items array match' => array(array('one', 2, 'three', 4), 'three', TRUE),
1774 'Integer search items can match string values' => array(array('0', '1', '2'), 1, TRUE),
1775 'Search item is not casted to integer for a match' => array(array(4), '4a', FALSE),
1776 'Empty item won\'t match - in contrast to the php-builtin ' => array(array(0, 1, 2), '', FALSE)
1777 );
1778 }
1779
1780 //////////////////////////////////
1781 // Tests concerning removeArrayEntryByValue
1782 //////////////////////////////////
1783 /**
1784 * @test
1785 */
1786 public function checkRemoveArrayEntryByValueRemovesEntriesFromOneDimensionalArray() {
1787 $inputArray = array(
1788 '0' => 'test1',
1789 '1' => 'test2',
1790 '2' => 'test3',
1791 '3' => 'test2'
1792 );
1793 $compareValue = 'test2';
1794 $expectedResult = array(
1795 '0' => 'test1',
1796 '2' => 'test3'
1797 );
1798 $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
1799 $this->assertEquals($expectedResult, $actualResult);
1800 }
1801
1802 /**
1803 * @test
1804 */
1805 public function checkRemoveArrayEntryByValueRemovesEntriesFromMultiDimensionalArray() {
1806 $inputArray = array(
1807 '0' => 'foo',
1808 '1' => array(
1809 '10' => 'bar'
1810 ),
1811 '2' => 'bar'
1812 );
1813 $compareValue = 'bar';
1814 $expectedResult = array(
1815 '0' => 'foo',
1816 '1' => array()
1817 );
1818 $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
1819 $this->assertEquals($expectedResult, $actualResult);
1820 }
1821
1822 /**
1823 * @test
1824 */
1825 public function checkRemoveArrayEntryByValueRemovesEntryWithEmptyString() {
1826 $inputArray = array(
1827 '0' => 'foo',
1828 '1' => '',
1829 '2' => 'bar'
1830 );
1831 $compareValue = '';
1832 $expectedResult = array(
1833 '0' => 'foo',
1834 '2' => 'bar'
1835 );
1836 $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
1837 $this->assertEquals($expectedResult, $actualResult);
1838 }
1839
1840 //////////////////////////////////
1841 // Tests concerning keepItemsInArray
1842 //////////////////////////////////
1843 /**
1844 * @test
1845 * @dataProvider keepItemsInArrayWorksWithOneArgumentDataProvider
1846 */
1847 public function keepItemsInArrayWorksWithOneArgument($search, $array, $expected) {
1848 $this->assertEquals($expected, ArrayUtility::keepItemsInArray($array, $search));
1849 }
1850
1851 /**
1852 * Data provider for keepItemsInArrayWorksWithOneArgument
1853 *
1854 * @return array
1855 */
1856 public function keepItemsInArrayWorksWithOneArgumentDataProvider() {
1857 $array = array(
1858 'one' => 'one',
1859 'two' => 'two',
1860 'three' => 'three'
1861 );
1862 return array(
1863 'Empty argument will match "all" elements' => array(NULL, $array, $array),
1864 'No match' => array('four', $array, array()),
1865 'One match' => array('two', $array, array('two' => 'two')),
1866 'Multiple matches' => array('two,one', $array, array('one' => 'one', 'two' => 'two')),
1867 'Argument can be an array' => array(array('three'), $array, array('three' => 'three'))
1868 );
1869 }
1870
1871 /**
1872 * Shows the exmaple from the doc comment where
1873 * a function is used to reduce the sub arrays to one item which
1874 * is then used for the matching.
1875 *
1876 * @test
1877 */
1878 public function keepItemsInArrayCanUseCallbackOnSearchArray() {
1879 $array = array(
1880 'aa' => array('first', 'second'),
1881 'bb' => array('third', 'fourth'),
1882 'cc' => array('fifth', 'sixth')
1883 );
1884 $expected = array('bb' => array('third', 'fourth'));
1885 $keepItems = 'third';
1886 $getValueFunc = create_function('$value', 'return $value[0];');
1887 $match = ArrayUtility::keepItemsInArray($array, $keepItems, $getValueFunc);
1888 $this->assertEquals($expected, $match);
1889 }
1890
1891 /**
1892 * Similar to keepItemsInArrayCanUseCallbackOnSearchArray(),
1893 * but uses a closure instead of create_function()
1894 *
1895 * @test
1896 */
1897 public function keepItemsInArrayCanUseClosure() {
1898 $array = array(
1899 'aa' => array('first', 'second'),
1900 'bb' => array('third', 'fourth'),
1901 'cc' => array('fifth', 'sixth')
1902 );
1903 $expected = array('bb' => array('third', 'fourth'));
1904 $keepItems = 'third';
1905 $match = ArrayUtility::keepItemsInArray(
1906 $array,
1907 $keepItems,
1908 function ($value) {
1909 return $value[0];
1910 }
1911 );
1912 $this->assertEquals($expected, $match);
1913 }
1914
1915 //////////////////////////////////
1916 // Tests concerning remapArrayKeys
1917 //////////////////////////////////
1918 /**
1919 * @test
1920 */
1921 public function remapArrayKeysExchangesKeysWithGivenMapping() {
1922 $array = array(
1923 'one' => 'one',
1924 'two' => 'two',
1925 'three' => 'three'
1926 );
1927 $keyMapping = array(
1928 'one' => '1',
1929 'two' => '2'
1930 );
1931 $expected = array(
1932 '1' => 'one',
1933 '2' => 'two',
1934 'three' => 'three'
1935 );
1936 ArrayUtility::remapArrayKeys($array, $keyMapping);
1937 $this->assertEquals($expected, $array);
1938 }
1939
1940 //////////////////////////////////////
1941 // Tests concerning arrayDiffAssocRecursive
1942 //////////////////////////////////////
1943 /**
1944 * @test
1945 */
1946 public function arrayDiffAssocRecursiveHandlesOneDimensionalArrays() {
1947 $array1 = array(
1948 'key1' => 'value1',
1949 'key2' => 'value2',
1950 'key3' => 'value3'
1951 );
1952 $array2 = array(
1953 'key1' => 'value1',
1954 'key3' => 'value3'
1955 );
1956 $expectedResult = array(
1957 'key2' => 'value2'
1958 );
1959 $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
1960 $this->assertEquals($expectedResult, $actualResult);
1961 }
1962
1963 /**
1964 * @test
1965 */
1966 public function arrayDiffAssocRecursiveHandlesMultiDimensionalArrays() {
1967 $array1 = array(
1968 'key1' => 'value1',
1969 'key2' => array(
1970 'key21' => 'value21',
1971 'key22' => 'value22',
1972 'key23' => array(
1973 'key231' => 'value231',
1974 'key232' => 'value232'
1975 )
1976 )
1977 );
1978 $array2 = array(
1979 'key1' => 'value1',
1980 'key2' => array(
1981 'key21' => 'value21',
1982 'key23' => array(
1983 'key231' => 'value231'
1984 )
1985 )
1986 );
1987 $expectedResult = array(
1988 'key2' => array(
1989 'key22' => 'value22',
1990 'key23' => array(
1991 'key232' => 'value232'
1992 )
1993 )
1994 );
1995 $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
1996 $this->assertEquals($expectedResult, $actualResult);
1997 }
1998
1999 /**
2000 * @test
2001 */
2002 public function arrayDiffAssocRecursiveHandlesMixedArrays() {
2003 $array1 = array(
2004 'key1' => array(
2005 'key11' => 'value11',
2006 'key12' => 'value12'
2007 ),
2008 'key2' => 'value2',
2009 'key3' => 'value3'
2010 );
2011 $array2 = array(
2012 'key1' => 'value1',
2013 'key2' => array(
2014 'key21' => 'value21'
2015 )
2016 );
2017 $expectedResult = array(
2018 'key3' => 'value3'
2019 );
2020 $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2021 $this->assertEquals($expectedResult, $actualResult);
2022 }
2023
2024 //////////////////////////////////////
2025 // Tests concerning naturalKeySortRecursive
2026 //////////////////////////////////////
2027
2028 /**
2029 * @test
2030 */
2031 public function naturalKeySortRecursiveSortsOneDimensionalArrayByNaturalOrder() {
2032 $testArray = array(
2033 'bb' => 'bb',
2034 'ab' => 'ab',
2035 '123' => '123',
2036 'aaa' => 'aaa',
2037 'abc' => 'abc',
2038 '23' => '23',
2039 'ba' => 'ba',
2040 'bad' => 'bad',
2041 '2' => '2',
2042 'zap' => 'zap',
2043 '210' => '210'
2044 );
2045 $expectedResult = array(
2046 '2',
2047 '23',
2048 '123',
2049 '210',
2050 'aaa',
2051 'ab',
2052 'abc',
2053 'ba',
2054 'bad',
2055 'bb',
2056 'zap'
2057 );
2058 ArrayUtility::naturalKeySortRecursive($testArray);
2059 $this->assertEquals($expectedResult, array_values($testArray));
2060 }
2061
2062 /**
2063 * @test
2064 */
2065 public function naturalKeySortRecursiveSortsMultiDimensionalArrayByNaturalOrder() {
2066 $testArray = array(
2067 '2' => '2',
2068 'bb' => 'bb',
2069 'ab' => 'ab',
2070 '23' => '23',
2071 'aaa' => array(
2072 'bb' => 'bb',
2073 'ab' => 'ab',
2074 '123' => '123',
2075 'aaa' => 'aaa',
2076 '2' => '2',
2077 'abc' => 'abc',
2078 'ba' => 'ba',
2079 '23' => '23',
2080 'bad' => array(
2081 'bb' => 'bb',
2082 'ab' => 'ab',
2083 '123' => '123',
2084 'aaa' => 'aaa',
2085 'abc' => 'abc',
2086 '23' => '23',
2087 'ba' => 'ba',
2088 'bad' => 'bad',
2089 '2' => '2',
2090 'zap' => 'zap',
2091 '210' => '210'
2092 ),
2093 '210' => '210',
2094 'zap' => 'zap'
2095 ),
2096 'abc' => 'abc',
2097 'ba' => 'ba',
2098 '210' => '210',
2099 'bad' => 'bad',
2100 '123' => '123',
2101 'zap' => 'zap'
2102 );
2103 $expectedResult = array(
2104 '2',
2105 '23',
2106 '123',
2107 '210',
2108 'aaa',
2109 'ab',
2110 'abc',
2111 'ba',
2112 'bad',
2113 'bb',
2114 'zap'
2115 );
2116 ArrayUtility::naturalKeySortRecursive($testArray);
2117 $this->assertEquals($expectedResult, array_values(array_keys($testArray['aaa']['bad'])));
2118 $this->assertEquals($expectedResult, array_values(array_keys($testArray['aaa'])));
2119 $this->assertEquals($expectedResult, array_values(array_keys($testArray)));
2120 }
2121 }