b5bdfae674f9722384ee4c3f9080e2fff17b8134
[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 * Copyright notice
6 *
7 * (c) 2011-2013 Susanne Moog <typo3@susanne-moog.de>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 /**
28 * Testcase for class \TYPO3\CMS\Core\Utility\ArrayUtility
29 *
30 * @author Susanne Moog <typo3@susanne-moog.de>
31 * @author Christian Kuhn <lolli@schwarzbu.ch>
32 */
33 class ArrayUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
34
35 ///////////////////////
36 // Tests concerning filterByValueRecursive
37 ///////////////////////
38 /**
39 * Data provider for filterByValueRecursiveCorrectlyFiltersArray
40 *
41 * Every array splits into:
42 * - String value to search for
43 * - Input array
44 * - Expected result array
45 */
46 public function filterByValueRecursive() {
47 return array(
48 'empty search array' => array(
49 'banana',
50 array(),
51 array()
52 ),
53 'empty string as needle' => array(
54 '',
55 array(
56 '',
57 'apple'
58 ),
59 array(
60 ''
61 )
62 ),
63 'flat array searching for string' => array(
64 'banana',
65 array(
66 'apple',
67 'banana'
68 ),
69 array(
70 1 => 'banana'
71 )
72 ),
73 'flat array searching for string with two matches' => array(
74 'banana',
75 array(
76 'foo' => 'apple',
77 'firstbanana' => 'banana',
78 'secondbanana' => 'banana'
79 ),
80 array(
81 'firstbanana' => 'banana',
82 'secondbanana' => 'banana'
83 )
84 ),
85 'multi dimensional array searching for string with multiple matches' => array(
86 'banana',
87 array(
88 'foo' => 'apple',
89 'firstbanana' => 'banana',
90 'grape' => array(
91 'foo2' => 'apple2',
92 'secondbanana' => 'banana',
93 'foo3' => array()
94 ),
95 'bar' => 'orange'
96 ),
97 array(
98 'firstbanana' => 'banana',
99 'grape' => array(
100 'secondbanana' => 'banana'
101 )
102 )
103 ),
104 'multi dimensional array searching for integer with multiple matches' => array(
105 42,
106 array(
107 'foo' => 23,
108 'bar' => 42,
109 array(
110 'foo' => 23,
111 'bar' => 42
112 )
113 ),
114 array(
115 'bar' => 42,
116 array(
117 'bar' => 42
118 )
119 )
120 ),
121 'flat array searching for boolean TRUE' => array(
122 TRUE,
123 array(
124 23 => FALSE,
125 42 => TRUE
126 ),
127 array(
128 42 => TRUE
129 )
130 ),
131 'multi dimensional array searching for boolean FALSE' => array(
132 FALSE,
133 array(
134 23 => FALSE,
135 42 => TRUE,
136 'foo' => array(
137 23 => FALSE,
138 42 => TRUE
139 )
140 ),
141 array(
142 23 => FALSE,
143 'foo' => array(
144 23 => FALSE
145 )
146 )
147 ),
148 'flat array searching for array' => array(
149 array(
150 'foo' => 'bar'
151 ),
152 array(
153 'foo' => 'bar',
154 'foobar' => array(
155 'foo' => 'bar'
156 )
157 ),
158 array(
159 'foobar' => array(
160 'foo' => 'bar'
161 )
162 )
163 )
164 );
165 }
166
167 /**
168 * @test
169 * @dataProvider filterByValueRecursive
170 */
171 public function filterByValueRecursiveCorrectlyFiltersArray($needle, $haystack, $expectedResult) {
172 $this->assertEquals(
173 $expectedResult,
174 \TYPO3\CMS\Core\Utility\ArrayUtility::filterByValueRecursive($needle, $haystack)
175 );
176 }
177
178 /**
179 * @test
180 */
181 public function filterByValueRecursiveMatchesReferencesToSameObject() {
182 $instance = new \stdClass();
183 $this->assertEquals(
184 array($instance),
185 \TYPO3\CMS\Core\Utility\ArrayUtility::filterByValueRecursive($instance, array($instance))
186 );
187 }
188
189 /**
190 * @test
191 */
192 public function filterByValueRecursiveDoesNotMatchDifferentInstancesOfSameClass() {
193 $this->assertEquals(
194 array(),
195 \TYPO3\CMS\Core\Utility\ArrayUtility::filterByValueRecursive(new \stdClass(), array(new \stdClass()))
196 );
197 }
198
199 ///////////////////////
200 // Tests concerning isValidPath
201 ///////////////////////
202 /**
203 * Mock the class under test, isValidPath() (method under test), calls
204 * static getValuePath() internally, which is mocked here to return a specific
205 * result. This works because of 'static' keyword' instead of 'self'
206 * for getValueByPath() call, using late static binding in PHP 5.3
207 *
208 * @test
209 */
210 public function isValidPathReturnsTrueIfPathExists() {
211 $namespace = 'TYPO3\\CMS\\Core\\Utility';
212 $className = uniqid('ArrayUtility');
213 eval(
214 'namespace ' . $namespace . ';' .
215 'class ' . $className . ' extends \\TYPO3\\CMS\\Core\\Utility\\ArrayUtility {' .
216 ' public static function getValueByPath() {' .
217 ' return 42;' .
218 ' }' .
219 '}'
220 );
221 $className = $namespace . '\\' . $className;
222 $this->assertTrue($className::isValidPath(array('foo'), 'foo'));
223 }
224
225 /**
226 * @test
227 */
228 public function isValidPathReturnsFalseIfPathDoesNotExist() {
229 $namespace = 'TYPO3\\CMS\\Core\\Utility';
230 $className = uniqid('ArrayUtility');
231 eval(
232 'namespace ' . $namespace . ';' .
233 'class ' . $className . ' extends \\TYPO3\\CMS\\Core\\Utility\\ArrayUtility {' .
234 ' public static function getValueByPath() {' .
235 ' throw new \RuntimeException(\'foo\', 123);' .
236 ' }' .
237 '}'
238 );
239 $className = $namespace . '\\' . $className;
240 $this->assertFalse($className::isValidPath(array('foo'), 'foo'));
241 }
242
243 ///////////////////////
244 // Tests concerning getValueByPath
245 ///////////////////////
246 /**
247 * @test
248 * @expectedException \RuntimeException
249 */
250 public function getValueByPathThrowsExceptionIfPathIsEmpty() {
251 \TYPO3\CMS\Core\Utility\ArrayUtility::getValueByPath(array(), '');
252 }
253
254 /**
255 * Data provider for getValueByPathThrowsExceptionIfPathNotExists
256 * Every array splits into:
257 * - Array to get value from
258 * - String path
259 * - Expected result
260 */
261 public function getValueByPathInvalidPathDataProvider() {
262 return array(
263 'not existing path 1' => array(
264 array(
265 'foo' => array()
266 ),
267 'foo/bar/baz',
268 FALSE
269 ),
270 'not existing path 2' => array(
271 array(
272 'foo' => array(
273 'baz' => 42
274 ),
275 'bar' => array()
276 ),
277 'foo/bar/baz',
278 FALSE
279 ),
280 // Negative test: This could be improved and the test moved to
281 // the valid data provider if the method supports this
282 'doubletick encapsulated quoted doubletick does not work' => array(
283 array(
284 '"foo"bar"' => array(
285 'baz' => 42
286 ),
287 'bar' => array()
288 ),
289 '"foo\\"bar"/baz',
290 42
291 ),
292 // Negative test: Method could be improved here
293 'path with doubletick does not work' => array(
294 array(
295 'fo"o' => array(
296 'bar' => 42
297 )
298 ),
299 'fo"o/foobar',
300 42
301 )
302 );
303 }
304
305 /**
306 * @test
307 * @dataProvider getValueByPathInvalidPathDataProvider
308 * @expectedException \RuntimeException
309 */
310 public function getValueByPathThrowsExceptionIfPathNotExists(array $array, $path) {
311 \TYPO3\CMS\Core\Utility\ArrayUtility::getValueByPath($array, $path);
312 }
313
314 /**
315 * Data provider for getValueByPathReturnsCorrectValue
316 * Every array splits into:
317 * - Array to get value from
318 * - String path
319 * - Expected result
320 */
321 public function getValueByPathValidDataProvider() {
322 $testObject = new \StdClass();
323 $testObject->foo = 'foo';
324 $testObject->bar = 'bar';
325 return array(
326 'integer in multi level array' => array(
327 array(
328 'foo' => array(
329 'bar' => array(
330 'baz' => 42
331 ),
332 'bar2' => array()
333 )
334 ),
335 'foo/bar/baz',
336 42
337 ),
338 'zero integer in multi level array' => array(
339 array(
340 'foo' => array(
341 'bar' => array(
342 'baz' => 0
343 )
344 )
345 ),
346 'foo/bar/baz',
347 0
348 ),
349 'NULL value in multi level array' => array(
350 array(
351 'foo' => array(
352 'baz' => NULL
353 )
354 ),
355 'foo/baz',
356 NULL
357 ),
358 'get string value' => array(
359 array(
360 'foo' => array(
361 'baz' => 'this is a test string'
362 )
363 ),
364 'foo/baz',
365 'this is a test string'
366 ),
367 'get boolean value: FALSE' => array(
368 array(
369 'foo' => array(
370 'baz' => FALSE
371 )
372 ),
373 'foo/baz',
374 FALSE
375 ),
376 'get boolean value: TRUE' => array(
377 array(
378 'foo' => array(
379 'baz' => TRUE
380 )
381 ),
382 'foo/baz',
383 TRUE
384 ),
385 'get object value' => array(
386 array(
387 'foo' => array(
388 'baz' => $testObject
389 )
390 ),
391 'foo/baz',
392 $testObject
393 ),
394 'enclosed path' => array(
395 array(
396 'foo/bar' => array(
397 'foobar' => 42
398 )
399 ),
400 '"foo/bar"/foobar',
401 42
402 )
403 );
404 }
405
406 /**
407 * @test
408 * @dataProvider getValueByPathValidDataProvider
409 */
410 public function getValueByPathGetsCorrectValue(array $array, $path, $expectedResult) {
411 $this->assertEquals($expectedResult, \TYPO3\CMS\Core\Utility\ArrayUtility::getValueByPath($array, $path));
412 }
413
414 /**
415 * @test
416 */
417 public function getValueByPathAccpetsDifferentDelimeter() {
418 $input = array(
419 'foo' => array(
420 'bar' => array(
421 'baz' => 42
422 ),
423 'bar2' => array()
424 )
425 );
426 $searchPath = 'foo%bar%baz';
427 $expected = 42;
428 $delimeter = '%';
429 $this->assertEquals(
430 $expected,
431 \TYPO3\CMS\Core\Utility\ArrayUtility::getValueByPath($input, $searchPath, $delimeter)
432 );
433 }
434
435 ///////////////////////
436 // Tests concerning setValueByPath
437 ///////////////////////
438 /**
439 * @test
440 * @expectedException \RuntimeException
441 */
442 public function setValueByPathThrowsExceptionIfPathIsEmpty() {
443 \TYPO3\CMS\Core\Utility\ArrayUtility::setValueByPath(array(), '', NULL);
444 }
445
446 /**
447 * @test
448 * @expectedException \RuntimeException
449 */
450 public function setValueByPathThrowsExceptionIfPathIsNotAString() {
451 \TYPO3\CMS\Core\Utility\ArrayUtility::setValueByPath(array(), array('foo'), NULL);
452 }
453
454 /**
455 * Data provider for setValueByPathSetsCorrectValueDataProvider
456 *
457 * Every array splits into:
458 * - Array to set value in
459 * - String path
460 * - Value to set
461 * - Expected result
462 */
463 public function setValueByPathSetsCorrectValueDataProvider() {
464 $testObject = new \StdClass();
465 $testObject->foo = 'foo';
466 $testObject->bar = 'bar';
467 return array(
468 'set integer value: 42' => array(
469 array(
470 'foo' => array(
471 'bar' => array(
472 'baz' => 0
473 )
474 )
475 ),
476 'foo/bar/baz',
477 42,
478 array(
479 'foo' => array(
480 'bar' => array(
481 'baz' => 42
482 )
483 )
484 )
485 ),
486 'set integer value: 0' => array(
487 array(
488 'foo' => array(
489 'bar' => array(
490 'baz' => 42
491 )
492 )
493 ),
494 'foo/bar/baz',
495 0,
496 array(
497 'foo' => array(
498 'bar' => array(
499 'baz' => 0
500 )
501 )
502 )
503 ),
504 'set null value' => array(
505 array(
506 'foo' => array(
507 'bar' => array(
508 'baz' => 42
509 )
510 )
511 ),
512 'foo/bar/baz',
513 NULL,
514 array(
515 'foo' => array(
516 'bar' => array(
517 'baz' => NULL
518 )
519 )
520 )
521 ),
522 'set array value' => array(
523 array(
524 'foo' => array(
525 'bar' => array(
526 'baz' => 42
527 )
528 )
529 ),
530 'foo/bar/baz',
531 array(
532 'foo' => 123
533 ),
534 array(
535 'foo' => array(
536 'bar' => array(
537 'baz' => array(
538 'foo' => 123
539 )
540 )
541 )
542 )
543 ),
544 'set boolean value: FALSE' => array(
545 array(
546 'foo' => array(
547 'bar' => array(
548 'baz' => TRUE
549 )
550 )
551 ),
552 'foo/bar/baz',
553 FALSE,
554 array(
555 'foo' => array(
556 'bar' => array(
557 'baz' => FALSE
558 )
559 )
560 )
561 ),
562 'set boolean value: TRUE' => array(
563 array(
564 'foo' => array(
565 'bar' => array(
566 'baz' => NULL
567 )
568 )
569 ),
570 'foo/bar/baz',
571 TRUE,
572 array(
573 'foo' => array(
574 'bar' => array(
575 'baz' => TRUE
576 )
577 )
578 )
579 ),
580 'set object value' => array(
581 array(
582 'foo' => array(
583 'bar' => array(
584 'baz' => NULL
585 )
586 )
587 ),
588 'foo/bar/baz',
589 $testObject,
590 array(
591 'foo' => array(
592 'bar' => array(
593 'baz' => $testObject
594 )
595 )
596 )
597 ),
598 'multi keys in array' => array(
599 array(
600 'foo' => array(
601 'bar' => array(
602 'baz' => 'value'
603 ),
604 'bar2' => array(
605 'baz' => 'value'
606 )
607 )
608 ),
609 'foo/bar2/baz',
610 'newValue',
611 array(
612 'foo' => array(
613 'bar' => array(
614 'baz' => 'value'
615 ),
616 'bar2' => array(
617 'baz' => 'newValue'
618 )
619 )
620 )
621 )
622 );
623 }
624
625 /**
626 * @test
627 * @dataProvider setValueByPathSetsCorrectValueDataProvider
628 */
629 public function setValueByPathSetsCorrectValue(array $array, $path, $value, $expectedResult) {
630 $this->assertEquals(
631 $expectedResult,
632 \TYPO3\CMS\Core\Utility\ArrayUtility::setValueByPath($array, $path, $value)
633 );
634 }
635
636 ///////////////////////
637 // Tests concerning sortByKeyRecursive
638 ///////////////////////
639 /**
640 * @test
641 */
642 public function sortByKeyRecursiveCheckIfSortingIsCorrect() {
643 $unsortedArray = array(
644 'z' => NULL,
645 'a' => NULL,
646 'd' => array(
647 'c' => NULL,
648 'b' => NULL,
649 'd' => NULL,
650 'a' => NULL
651 )
652 );
653 $expectedResult = array(
654 'a' => NULL,
655 'd' => array(
656 'a' => NULL,
657 'b' => NULL,
658 'c' => NULL,
659 'd' => NULL
660 ),
661 'z' => NULL
662 );
663 $this->assertSame($expectedResult, \TYPO3\CMS\Core\Utility\ArrayUtility::sortByKeyRecursive($unsortedArray));
664 }
665
666 ///////////////////////
667 // Tests concerning arrayExport
668 ///////////////////////
669 /**
670 * @test
671 */
672 public function arrayExportReturnsFormattedMultidimensionalArray() {
673 $array = array(
674 'foo' => array(
675 'bar' => 42,
676 'bar2' => array(
677 'baz' => 'val\'ue',
678 'baz2' => TRUE,
679 'baz3' => FALSE,
680 'baz4' => array()
681 )
682 ),
683 'baz' => 23,
684 'foobar' => NULL,
685 'qux' => 0.1,
686 'qux2' => 0.000000001,
687 );
688 $expected =
689 'array(' . LF .
690 TAB . '\'foo\' => array(' . LF .
691 TAB . TAB . '\'bar\' => 42,' . LF .
692 TAB . TAB . '\'bar2\' => array(' . LF .
693 TAB . TAB . TAB . '\'baz\' => \'val\\\'ue\',' . LF .
694 TAB . TAB . TAB . '\'baz2\' => TRUE,' . LF .
695 TAB . TAB . TAB . '\'baz3\' => FALSE,' . LF .
696 TAB . TAB . TAB . '\'baz4\' => array(),' . LF .
697 TAB . TAB . '),' . LF .
698 TAB . '),' . LF .
699 TAB . '\'baz\' => 23,' . LF .
700 TAB . '\'foobar\' => NULL,' . LF .
701 TAB . '\'qux\' => 0.1,' . LF .
702 TAB . '\'qux2\' => 1.0E-9,' . LF .
703 ')';
704 $this->assertSame($expected, \TYPO3\CMS\Core\Utility\ArrayUtility::arrayExport($array));
705 }
706
707 /**
708 * @test
709 * @expectedException \RuntimeException
710 */
711 public function arrayExportThrowsExceptionIfObjectShouldBeExported() {
712 $array = array(
713 'foo' => array(
714 'bar' => new \stdClass()
715 )
716 );
717 \TYPO3\CMS\Core\Utility\ArrayUtility::arrayExport($array);
718 }
719
720 /**
721 * @test
722 */
723 public function arrayExportReturnsNumericArrayKeys() {
724 $array = array(
725 'foo' => 'string key',
726 23 => 'integer key',
727 '42' => 'string key representing integer'
728 );
729 $expected =
730 'array(' . LF .
731 TAB . '\'foo\' => \'string key\',' . LF .
732 TAB . '23 => \'integer key\',' . LF .
733 TAB . '42 => \'string key representing integer\',' . LF .
734 ')';
735 $this->assertSame($expected, \TYPO3\CMS\Core\Utility\ArrayUtility::arrayExport($array));
736 }
737
738 /**
739 * @test
740 */
741 public function arrayExportReturnsNoKeyIndexForConsecutiveCountedArrays() {
742 $array = array(
743 0 => 'zero',
744 1 => 'one',
745 2 => 'two'
746 );
747 $expected =
748 'array(' . LF .
749 TAB . '\'zero\',' . LF .
750 TAB . '\'one\',' . LF .
751 TAB . '\'two\',' . LF .
752 ')';
753 $this->assertSame($expected, \TYPO3\CMS\Core\Utility\ArrayUtility::arrayExport($array));
754 }
755
756 /**
757 * @test
758 */
759 public function arrayExportReturnsKeyIndexForNonConsecutiveCountedArrays() {
760 $array = array(
761 0 => 'zero',
762 1 => 'one',
763 3 => 'three',
764 4 => 'four'
765 );
766 $expected =
767 'array(' . LF .
768 TAB . '0 => \'zero\',' . LF .
769 TAB . '1 => \'one\',' . LF .
770 TAB . '3 => \'three\',' . LF .
771 TAB . '4 => \'four\',' . LF .
772 ')';
773 $this->assertSame($expected, \TYPO3\CMS\Core\Utility\ArrayUtility::arrayExport($array));
774 }
775
776
777 ///////////////////////
778 // Tests concerning flatten
779 ///////////////////////
780
781 /**
782 * @return array
783 */
784 public function flattenCalculatesExpectedResultDataProvider() {
785 return array(
786 'plain array' => array(
787 array(
788 'first' => 1,
789 'second' => 2
790 ),
791 array(
792 'first' => 1,
793 'second' => 2
794 )
795 ),
796 'plain array with faulty dots' => array(
797 array(
798 'first.' => 1,
799 'second.' => 2
800 ),
801 array(
802 'first' => 1,
803 'second' => 2
804 )
805 ),
806 'nested array of 2 levels' => array(
807 array(
808 'first.' => array(
809 'firstSub' => 1
810 ),
811 'second.' => array(
812 'secondSub' => 2
813 )
814 ),
815 array(
816 'first.firstSub' => 1,
817 'second.secondSub' => 2
818 )
819 ),
820 'nested array of 2 levels with faulty dots' => array(
821 array(
822 'first.' => array(
823 'firstSub.' => 1
824 ),
825 'second.' => array(
826 'secondSub.' => 2
827 )
828 ),
829 array(
830 'first.firstSub' => 1,
831 'second.secondSub' => 2
832 )
833 ),
834 'nested array of 3 levels' => array(
835 array(
836 'first.' => array(
837 'firstSub.' => array(
838 'firstSubSub' => 1
839 )
840 ),
841 'second.' => array(
842 'secondSub.' => array(
843 'secondSubSub' => 2
844 )
845 )
846 ),
847 array(
848 'first.firstSub.firstSubSub' => 1,
849 'second.secondSub.secondSubSub' => 2
850 )
851 ),
852 'nested array of 3 levels with faulty dots' => array(
853 array(
854 'first.' => array(
855 'firstSub.' => array(
856 'firstSubSub.' => 1
857 )
858 ),
859 'second.' => array(
860 'secondSub.' => array(
861 'secondSubSub.' => 2
862 )
863 )
864 ),
865 array(
866 'first.firstSub.firstSubSub' => 1,
867 'second.secondSub.secondSubSub' => 2
868 )
869 )
870 );
871 }
872
873 /**
874 * @test
875 * @param array $array
876 * @param array $expected
877 * @dataProvider flattenCalculatesExpectedResultDataProvider
878 */
879 public function flattenCalculatesExpectedResult(array $array, array $expected) {
880 $this->assertEquals($expected, \TYPO3\CMS\Core\Utility\ArrayUtility::flatten($array));
881 }
882
883
884 ///////////////////////
885 // Tests concerning intersectRecursive
886 ///////////////////////
887
888 /**
889 * @return array
890 */
891 public function intersectRecursiveCalculatesExpectedResultDataProvider() {
892 $sameObject = new \stdClass();
893 return array(
894 // array($source, $mask, $expected)
895 'empty array is returned if source is empty array' => array(
896 array(),
897 array(
898 'foo' => 'bar',
899 ),
900 array(),
901 ),
902 'empty array is returned if mask is empty' => array(
903 array(
904 'foo' => 'bar',
905 ),
906 array(),
907 array(),
908 ),
909 'key is kept on first level if exists in mask' => array(
910 array(
911 'foo' => 42,
912 ),
913 array(
914 'foo' => 42,
915 ),
916 array(
917 'foo' => 42,
918 ),
919 ),
920 'value of key in source is kept if mask has different value' => array(
921 array(
922 'foo' => 42,
923 ),
924 array(
925 'foo' => new \stdClass(),
926 ),
927 array(
928 'foo' => 42,
929 ),
930 ),
931 'key is kept on first level if according mask value is NULL' => array(
932 array(
933 'foo' => 42,
934 ),
935 array(
936 'foo' => NULL,
937 ),
938 array(
939 'foo' => 42,
940 ),
941 ),
942 'null in source value is kept' => array(
943 array(
944 'foo' => NULL,
945 ),
946 array(
947 'foo' => 'bar',
948 ),
949 array(
950 'foo' => NULL,
951 )
952 ),
953 'mask does not add new keys' => array(
954 array(
955 'foo' => 42,
956 ),
957 array(
958 'foo' => 23,
959 'bar' => array(
960 4711
961 ),
962 ),
963 array(
964 'foo' => 42,
965 ),
966 ),
967 'mask does not overwrite simple values with arrays' => array(
968 array(
969 'foo' => 42,
970 ),
971 array(
972 'foo' => array(
973 'bar' => 23,
974 ),
975 ),
976 array(
977 'foo' => 42,
978 ),
979 ),
980 'key is kept on first level if according mask value is array' => array(
981 array(
982 'foo' => 42,
983 ),
984 array(
985 'foo' => array(
986 'bar' => 23
987 ),
988 ),
989 array(
990 'foo' => 42,
991 ),
992 ),
993 'full array is kept if value is array and mask value is simple type' => array(
994 array(
995 'foo' => array(
996 'bar' => 23
997 ),
998 ),
999 array(
1000 'foo' => 42,
1001 ),
1002 array(
1003 'foo' => array(
1004 'bar' => 23
1005 ),
1006 ),
1007 ),
1008 'key handling is type agnostic' => array(
1009 array(
1010 42 => 'foo',
1011 ),
1012 array(
1013 '42' => 'bar',
1014 ),
1015 array(
1016 42 => 'foo',
1017 ),
1018 ),
1019 'value is same if value is object' => array(
1020 array(
1021 'foo' => $sameObject,
1022 ),
1023 array(
1024 'foo' => 'something',
1025 ),
1026 array(
1027 'foo' => $sameObject,
1028 ),
1029 ),
1030 'mask does not add simple value to result if key does not exist in source' => array(
1031 array(
1032 'foo' => '42',
1033 ),
1034 array(
1035 'foo' => '42',
1036 'bar' => 23
1037 ),
1038 array(
1039 'foo' => '42',
1040 ),
1041 ),
1042 'array of source is kept if value of mask key exists but is no array' => array(
1043 array(
1044 'foo' => '42',
1045 'bar' => array(
1046 'baz' => 23
1047 ),
1048 ),
1049 array(
1050 'foo' => 'value is not significant',
1051 'bar' => NULL,
1052 ),
1053 array(
1054 'foo' => '42',
1055 'bar' => array(
1056 'baz' => 23
1057 ),
1058 ),
1059 ),
1060 'sub arrays are kept if mask has according sub array key and is similar array' => array(
1061 array(
1062 'first1' => 42,
1063 'first2' => array(
1064 'second1' => 23,
1065 'second2' => 4711,
1066 ),
1067 ),
1068 array(
1069 'first1' => 42,
1070 'first2' => array(
1071 'second1' => 'exists but different',
1072 ),
1073 ),
1074 array(
1075 'first1' => 42,
1076 'first2' => array(
1077 'second1' => 23,
1078 ),
1079 ),
1080 ),
1081 );
1082 }
1083
1084 /**
1085 * @test
1086 * @param array $source
1087 * @param array $mask
1088 * @param array $expected
1089 * @dataProvider intersectRecursiveCalculatesExpectedResultDataProvider
1090 */
1091 public function intersectRecursiveCalculatesExpectedResult(array $source, array $mask, array $expected) {
1092 $this->assertSame($expected, \TYPO3\CMS\Core\Utility\ArrayUtility::intersectRecursive($source, $mask));
1093 }
1094
1095
1096 ///////////////////////
1097 // Tests concerning renumberKeysToAvoidLeapsIfKeysAreAllNumeric
1098 ///////////////////////
1099 /**
1100 * @return array
1101 */
1102 public function renumberKeysToAvoidLeapsIfKeysAreAllNumericDataProvider() {
1103 return array(
1104 'empty array is returned if source is empty array' => array(
1105 array(),
1106 array()
1107 ),
1108 'returns self if array is already numerically keyed' => array(
1109 array(1,2,3),
1110 array(1,2,3)
1111 ),
1112 'returns correctly if keys are numeric, but contains a leap' => array(
1113 array(0 => 'One', 1 => 'Two', 3 => 'Three'),
1114 array(0 => 'One', 1 => 'Two', 2 => 'Three'),
1115 ),
1116 'returns correctly even though keys are strings but still numeric' => array(
1117 array('0' => 'One', '1' => 'Two', '3' => 'Three'),
1118 array(0 => 'One', 1 => 'Two', 2 => 'Three'),
1119 ),
1120 'returns correctly if just a single keys is not numeric' => array(
1121 array(0 => 'Zero', '1' => 'One', 'Two' => 'Two'),
1122 array(0 => 'Zero', '1' => 'One', 'Two' => 'Two'),
1123 ),
1124 'return self with nested numerically keyed array' => array(
1125 array(
1126 'One',
1127 'Two',
1128 'Three',
1129 array(
1130 'sub.One',
1131 'sub.Two',
1132 )
1133 ),
1134 array(
1135 'One',
1136 'Two',
1137 'Three',
1138 array(
1139 'sub.One',
1140 'sub.Two',
1141 )
1142 )
1143 ),
1144 'returns correctly with nested numerically keyed array with leaps' => array(
1145 array(
1146 'One',
1147 'Two',
1148 'Three',
1149 array(
1150 0 => 'sub.One',
1151 2 => 'sub.Two',
1152 )
1153 ),
1154 array(
1155 'One',
1156 'Two',
1157 'Three',
1158 array(
1159 'sub.One',
1160 'sub.Two',
1161 )
1162 )
1163 ),
1164 'returns correctly with nested string-keyed array' => array(
1165 array(
1166 'One',
1167 'Two',
1168 'Three',
1169 array(
1170 'one' => 'sub.One',
1171 'two' => 'sub.Two',
1172 )
1173 ),
1174 array(
1175 'One',
1176 'Two',
1177 'Three',
1178 array(
1179 'one' => 'sub.One',
1180 'two' => 'sub.Two',
1181 )
1182 )
1183 ),
1184 'returns correctly with deeply nested arrays' => array(
1185 array(
1186 'One',
1187 'Two',
1188 array(
1189 'one' => 1,
1190 'two' => 2,
1191 'three' => array(
1192 2 => 'SubSubOne',
1193 5 => 'SubSubTwo',
1194 9 => array(0,1,2),
1195 array()
1196 )
1197 )
1198 ),
1199 array(
1200 'One',
1201 'Two',
1202 array(
1203 'one' => 1,
1204 'two' => 2,
1205 'three' => array(
1206 'SubSubOne',
1207 'SubSubTwo',
1208 array(0,1,2),
1209 array()
1210 )
1211 )
1212 )
1213 )
1214 );
1215 }
1216
1217 /**
1218 * @test
1219 * @param array $inputArray
1220 * @param array $expected
1221 * @dataProvider renumberKeysToAvoidLeapsIfKeysAreAllNumericDataProvider
1222 */
1223 public function renumberKeysToAvoidLeapsIfKeysAreAllNumeric(array $inputArray, array $expected) {
1224 $this->assertEquals($expected, \TYPO3\CMS\Core\Utility\ArrayUtility::renumberKeysToAvoidLeapsIfKeysAreAllNumeric($inputArray));
1225 }
1226
1227 }
1228
1229 ?>