TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
core/Tests/Unit/Utility/ArrayUtilityTest.php
Go to the documentation of this file.
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 
19 
24 {
26  // Tests concerning filterByValueRecursive
28 
36  public function filterByValueRecursive()
37  {
38  return [
39  'empty search array' => [
40  'banana',
41  [],
42  []
43  ],
44  'empty string as needle' => [
45  '',
46  [
47  '',
48  'apple'
49  ],
50  [
51  ''
52  ]
53  ],
54  'flat array searching for string' => [
55  'banana',
56  [
57  'apple',
58  'banana'
59  ],
60  [
61  1 => 'banana'
62  ]
63  ],
64  'flat array searching for string with two matches' => [
65  'banana',
66  [
67  'foo' => 'apple',
68  'firstbanana' => 'banana',
69  'secondbanana' => 'banana'
70  ],
71  [
72  'firstbanana' => 'banana',
73  'secondbanana' => 'banana'
74  ]
75  ],
76  'multi dimensional array searching for string with multiple matches' => [
77  'banana',
78  [
79  'foo' => 'apple',
80  'firstbanana' => 'banana',
81  'grape' => [
82  'foo2' => 'apple2',
83  'secondbanana' => 'banana',
84  'foo3' => []
85  ],
86  'bar' => 'orange'
87  ],
88  [
89  'firstbanana' => 'banana',
90  'grape' => [
91  'secondbanana' => 'banana'
92  ]
93  ]
94  ],
95  'multi dimensional array searching for integer with multiple matches' => [
96  42,
97  [
98  'foo' => 23,
99  'bar' => 42,
100  [
101  'foo' => 23,
102  'bar' => 42
103  ]
104  ],
105  [
106  'bar' => 42,
107  [
108  'bar' => 42
109  ]
110  ]
111  ],
112  'flat array searching for boolean TRUE' => [
113  true,
114  [
115  23 => false,
116  42 => true
117  ],
118  [
119  42 => true
120  ]
121  ],
122  'multi dimensional array searching for boolean FALSE' => [
123  false,
124  [
125  23 => false,
126  42 => true,
127  'foo' => [
128  23 => false,
129  42 => true
130  ]
131  ],
132  [
133  23 => false,
134  'foo' => [
135  23 => false
136  ]
137  ]
138  ],
139  'flat array searching for array' => [
140  [
141  'foo' => 'bar'
142  ],
143  [
144  'foo' => 'bar',
145  'foobar' => [
146  'foo' => 'bar'
147  ]
148  ],
149  [
150  'foobar' => [
151  'foo' => 'bar'
152  ]
153  ]
154  ]
155  ];
156  }
157 
165  public function filterByValueRecursiveCorrectlyFiltersArray($needle, $haystack, $expectedResult)
166  {
167  $this->assertEquals(
168  $expectedResult,
169  ArrayUtility::filterByValueRecursive($needle, $haystack)
170  );
171  }
172 
177  {
178  $instance = new \stdClass();
179  $this->assertEquals(
180  [$instance],
181  ArrayUtility::filterByValueRecursive($instance, [$instance])
182  );
183  }
184 
189  {
190  $this->assertEquals(
191  [],
192  ArrayUtility::filterByValueRecursive(new \stdClass(), [new \stdClass()])
193  );
194  }
195 
197  // Tests concerning isValidPath
199 
208  {
209  $this->assertTrue(ArrayUtility::isValidPath(['foo' => 'bar'], 'foo'));
210  }
211 
216  {
217  $this->assertFalse(ArrayUtility::isValidPath(['foo' => 'bar'], 'bar'));
218  }
219 
221  // Tests concerning getValueByPath
223 
227  {
228  $this->expectException(\InvalidArgumentException::class);
229  $this->expectExceptionCode(1476557628);
230 
232  }
233 
238  {
239  $this->expectException(\RuntimeException::class);
240  $this->expectExceptionCode(1341397767);
241 
243  }
244 
249  {
250  $this->assertSame('foo', ArrayUtility::getValueByPath(['foo'], '0'));
251  }
252 
257  {
258  $this->assertSame('bar', ArrayUtility::getValueByPath(['foo' => ['bar']], 'foo/0'));
259  }
260 
270  {
271  return [
272  'not existing index' => [
273  [
274  'foo' => ['foo']
275  ],
276  'foo/1',
277  false
278  ],
279  'not existing path 1' => [
280  [
281  'foo' => []
282  ],
283  'foo/bar/baz',
284  false
285  ],
286  'not existing path 2' => [
287  [
288  'foo' => [
289  'baz' => 42
290  ],
291  'bar' => []
292  ],
293  'foo/bar/baz',
294  false
295  ],
296  // Negative test: This could be improved and the test moved to
297  // the valid data provider if the method supports this
298  'doubletick encapsulated quoted doubletick does not work' => [
299  [
300  '"foo"bar"' => [
301  'baz' => 42
302  ],
303  'bar' => []
304  ],
305  '"foo\\"bar"/baz',
306  42
307  ],
308  // Negative test: Method could be improved here
309  'path with doubletick does not work' => [
310  [
311  'fo"o' => [
312  'bar' => 42
313  ]
314  ],
315  'fo"o/foobar',
316  42
317  ]
318  ];
319  }
320 
327  public function getValueByPathThrowsExceptionIfPathNotExists(array $array, $path)
328  {
329  $this->expectException(\RuntimeException::class);
330  $this->expectExceptionCode(1341397869);
331 
332  ArrayUtility::getValueByPath($array, $path);
333  }
334 
343  {
344  $testObject = new \stdClass();
345  $testObject->foo = 'foo';
346  $testObject->bar = 'bar';
347  return [
348  'integer in multi level array' => [
349  [
350  'foo' => [
351  'bar' => [
352  'baz' => 42
353  ],
354  'bar2' => []
355  ]
356  ],
357  'foo/bar/baz',
358  42
359  ],
360  'zero integer in multi level array' => [
361  [
362  'foo' => [
363  'bar' => [
364  'baz' => 0
365  ]
366  ]
367  ],
368  'foo/bar/baz',
369  0
370  ],
371  'NULL value in multi level array' => [
372  [
373  'foo' => [
374  'baz' => null
375  ]
376  ],
377  'foo/baz',
378  null
379  ],
380  'get string value' => [
381  [
382  'foo' => [
383  'baz' => 'this is a test string'
384  ]
385  ],
386  'foo/baz',
387  'this is a test string'
388  ],
389  'get boolean value: FALSE' => [
390  [
391  'foo' => [
392  'baz' => false
393  ]
394  ],
395  'foo/baz',
396  false
397  ],
398  'get boolean value: TRUE' => [
399  [
400  'foo' => [
401  'baz' => true
402  ]
403  ],
404  'foo/baz',
405  true
406  ],
407  'get object value' => [
408  [
409  'foo' => [
410  'baz' => $testObject
411  ]
412  ],
413  'foo/baz',
414  $testObject
415  ],
416  'enclosed path' => [
417  [
418  'foo/bar' => [
419  'foobar' => 42
420  ]
421  ],
422  '"foo/bar"/foobar',
423  42
424  ]
425  ];
426  }
427 
435  public function getValueByPathGetsCorrectValue(array $array, $path, $expectedResult)
436  {
437  $this->assertEquals($expectedResult, ArrayUtility::getValueByPath($array, $path));
438  }
439 
444  {
445  $input = [
446  'foo' => [
447  'bar' => [
448  'baz' => 42
449  ],
450  'bar2' => []
451  ]
452  ];
453  $searchPath = 'foo%bar%baz';
454  $expected = 42;
455  $delimiter = '%';
456  $this->assertEquals(
457  $expected,
458  ArrayUtility::getValueByPath($input, $searchPath, $delimiter)
459  );
460  }
461 
463  // Tests concerning setValueByPath
465 
469  {
470  $this->expectException(\RuntimeException::class);
471  $this->expectExceptionCode(1341406194);
472 
473  ArrayUtility::setValueByPath([], '', null);
474  }
475 
480  {
481  $this->expectException(\InvalidArgumentException::class);
482  $this->expectExceptionCode(1478781081);
483 
484  ArrayUtility::setValueByPath([], 123, null);
485  }
486 
491  {
492  $this->expectException(\RuntimeException::class);
493  $this->expectExceptionCode(1341406846);
494 
495  ArrayUtility::setValueByPath(['foo' => 'bar'], '/foo', 'value');
496  }
497 
502  {
503  $this->assertSame(['foo' => ['value']], ArrayUtility::setValueByPath(['foo' => []], 'foo/0', 'value'));
504  }
505 
510  {
511  $this->assertSame(['value', 'bar'], ArrayUtility::setValueByPath(['foo', 'bar'], '0', 'value'));
512  }
513 
524  {
525  $testObject = new \stdClass();
526  $testObject->foo = 'foo';
527  $testObject->bar = 'bar';
528  return [
529  'set integer value: 42' => [
530  [
531  'foo' => [
532  'bar' => [
533  'baz' => 0
534  ]
535  ]
536  ],
537  'foo/bar/baz',
538  42,
539  [
540  'foo' => [
541  'bar' => [
542  'baz' => 42
543  ]
544  ]
545  ]
546  ],
547  'set integer value: 0' => [
548  [
549  'foo' => [
550  'bar' => [
551  'baz' => 42
552  ]
553  ]
554  ],
555  'foo/bar/baz',
556  0,
557  [
558  'foo' => [
559  'bar' => [
560  'baz' => 0
561  ]
562  ]
563  ]
564  ],
565  'set null value' => [
566  [
567  'foo' => [
568  'bar' => [
569  'baz' => 42
570  ]
571  ]
572  ],
573  'foo/bar/baz',
574  null,
575  [
576  'foo' => [
577  'bar' => [
578  'baz' => null
579  ]
580  ]
581  ]
582  ],
583  'set array value' => [
584  [
585  'foo' => [
586  'bar' => [
587  'baz' => 42
588  ]
589  ]
590  ],
591  'foo/bar/baz',
592  [
593  'foo' => 123
594  ],
595  [
596  'foo' => [
597  'bar' => [
598  'baz' => [
599  'foo' => 123
600  ]
601  ]
602  ]
603  ]
604  ],
605  'set boolean value: FALSE' => [
606  [
607  'foo' => [
608  'bar' => [
609  'baz' => true
610  ]
611  ]
612  ],
613  'foo/bar/baz',
614  false,
615  [
616  'foo' => [
617  'bar' => [
618  'baz' => false
619  ]
620  ]
621  ]
622  ],
623  'set boolean value: TRUE' => [
624  [
625  'foo' => [
626  'bar' => [
627  'baz' => null
628  ]
629  ]
630  ],
631  'foo/bar/baz',
632  true,
633  [
634  'foo' => [
635  'bar' => [
636  'baz' => true
637  ]
638  ]
639  ]
640  ],
641  'set object value' => [
642  [
643  'foo' => [
644  'bar' => [
645  'baz' => null
646  ]
647  ]
648  ],
649  'foo/bar/baz',
650  $testObject,
651  [
652  'foo' => [
653  'bar' => [
654  'baz' => $testObject
655  ]
656  ]
657  ]
658  ],
659  'multi keys in array' => [
660  [
661  'foo' => [
662  'bar' => [
663  'baz' => 'value'
664  ],
665  'bar2' => [
666  'baz' => 'value'
667  ]
668  ]
669  ],
670  'foo/bar2/baz',
671  'newValue',
672  [
673  'foo' => [
674  'bar' => [
675  'baz' => 'value'
676  ],
677  'bar2' => [
678  'baz' => 'newValue'
679  ]
680  ]
681  ]
682  ]
683  ];
684  }
685 
694  public function setValueByPathSetsCorrectValue(array $array, $path, $value, $expectedResult)
695  {
696  $this->assertEquals(
697  $expectedResult,
698  ArrayUtility::setValueByPath($array, $path, $value)
699  );
700  }
701 
702  /**********************
703  /* Tests concerning removeByPath
704  ***********************/
705 
710  {
711  $this->expectException(\RuntimeException::class);
712  $this->expectExceptionCode(1371757718);
713 
715  }
716 
721  {
722  $this->expectException(\RuntimeException::class);
723  $this->expectExceptionCode(1371757719);
724 
725  ArrayUtility::removeByPath([], ['foo']);
726  }
727 
732  {
733  $inputArray = [
734  'foo' => [
735  'bar' => 42,
736  ]
737  ];
738 
739  $this->expectException(\RuntimeException::class);
740  $this->expectExceptionCode(1371757720);
741 
742  ArrayUtility::removeByPath($inputArray, 'foo//bar');
743  }
744 
749  {
750  $inputArray = [
751  'foo' => ['bar']
752  ];
753 
754  $this->assertSame(['foo' => []], ArrayUtility::removeByPath($inputArray, 'foo/0'));
755  }
756 
761  {
762  $inputArray = ['bar'];
763 
764  $this->assertSame([], ArrayUtility::removeByPath($inputArray, '0'));
765  }
766 
771  {
772  $inputArray = [
773  'foo' => [
774  'bar' => 42,
775  ]
776  ];
777 
778  $this->expectException(\RuntimeException::class);
779  $this->expectExceptionCode(1371758436);
780 
781  ArrayUtility::removeByPath($inputArray, 'foo/baz');
782  }
783 
788  {
789  $inputArray = [
790  'foo' => [
791  'toRemove' => 42,
792  'keep' => 23
793  ],
794  ];
795  $path = 'foo.toRemove';
796  $expected = [
797  'foo' => [
798  'keep' => 23,
799  ],
800  ];
801  $this->assertEquals(
802  $expected,
803  ArrayUtility::removeByPath($inputArray, $path, '.')
804  );
805  }
806 
811  {
812  return [
813  'single value' => [
814  [
815  'foo' => [
816  'toRemove' => 42,
817  'keep' => 23
818  ],
819  ],
820  'foo/toRemove',
821  [
822  'foo' => [
823  'keep' => 23,
824  ],
825  ],
826  ],
827  'whole array' => [
828  [
829  'foo' => [
830  'bar' => 42
831  ],
832  ],
833  'foo',
834  [],
835  ],
836  'sub array' => [
837  [
838  'foo' => [
839  'keep' => 23,
840  'toRemove' => [
841  'foo' => 'bar',
842  ],
843  ],
844  ],
845  'foo/toRemove',
846  [
847  'foo' => [
848  'keep' => 23,
849  ],
850  ],
851  ],
852  ];
853  }
854 
862  public function removeByPathRemovesCorrectPath(array $array, $path, $expectedResult)
863  {
864  $this->assertEquals(
865  $expectedResult,
866  ArrayUtility::removeByPath($array, $path)
867  );
868  }
869 
871  // Tests concerning sortByKeyRecursive
873 
877  {
878  $unsortedArray = [
879  'z' => null,
880  'a' => null,
881  'd' => [
882  'c' => null,
883  'b' => null,
884  'd' => null,
885  'a' => null
886  ]
887  ];
888  $expectedResult = [
889  'a' => null,
890  'd' => [
891  'a' => null,
892  'b' => null,
893  'c' => null,
894  'd' => null
895  ],
896  'z' => null
897  ];
898  $this->assertSame($expectedResult, ArrayUtility::sortByKeyRecursive($unsortedArray));
899  }
900 
902  // Tests concerning sortArraysByKey
904 
908  {
909  return [
910  'assoc array index' => [
911  [
912  '22' => [
913  'uid' => '22',
914  'title' => 'c',
915  'dummy' => 2
916  ],
917  '24' => [
918  'uid' => '24',
919  'title' => 'a',
920  'dummy' => 3
921  ],
922  '23' => [
923  'uid' => '23',
924  'title' => 'b',
925  'dummy' => 4
926  ],
927  ],
928  'title',
929  true,
930  [
931  '24' => [
932  'uid' => '24',
933  'title' => 'a',
934  'dummy' => 3
935  ],
936  '23' => [
937  'uid' => '23',
938  'title' => 'b',
939  'dummy' => 4
940  ],
941  '22' => [
942  'uid' => '22',
943  'title' => 'c',
944  'dummy' => 2
945  ],
946  ],
947  ],
948  'numeric array index' => [
949  [
950  22 => [
951  'uid' => '22',
952  'title' => 'c',
953  'dummy' => 2
954  ],
955  24 => [
956  'uid' => '24',
957  'title' => 'a',
958  'dummy' => 3
959  ],
960  23 => [
961  'uid' => '23',
962  'title' => 'b',
963  'dummy' => 4
964  ],
965  ],
966  'title',
967  true,
968  [
969  24 => [
970  'uid' => '24',
971  'title' => 'a',
972  'dummy' => 3
973  ],
974  23 => [
975  'uid' => '23',
976  'title' => 'b',
977  'dummy' => 4
978  ],
979  22 => [
980  'uid' => '22',
981  'title' => 'c',
982  'dummy' => 2
983  ],
984  ],
985  ],
986  'numeric array index DESC' => [
987  [
988  23 => [
989  'uid' => '23',
990  'title' => 'b',
991  'dummy' => 4
992  ],
993  22 => [
994  'uid' => '22',
995  'title' => 'c',
996  'dummy' => 2
997  ],
998  24 => [
999  'uid' => '24',
1000  'title' => 'a',
1001  'dummy' => 3
1002  ],
1003  ],
1004  'title',
1005  false,
1006  [
1007  22 => [
1008  'uid' => '22',
1009  'title' => 'c',
1010  'dummy' => 2
1011  ],
1012  23 => [
1013  'uid' => '23',
1014  'title' => 'b',
1015  'dummy' => 4
1016  ],
1017  24 => [
1018  'uid' => '24',
1019  'title' => 'a',
1020  'dummy' => 3
1021  ],
1022  ],
1023  ],
1024  ];
1025  }
1026 
1035  public function sortArraysByKeyCheckIfSortingIsCorrect(array $array, $key, $ascending, $expectedResult)
1036  {
1037  $sortedArray = ArrayUtility::sortArraysByKey($array, $key, $ascending);
1038  $this->assertSame($expectedResult, $sortedArray);
1039  }
1040 
1045  {
1046  $this->expectException(\RuntimeException::class);
1047  $this->expectExceptionCode(1373727309);
1048 
1049  ArrayUtility::sortArraysByKey([['a'], ['a']], 'dummy');
1050  }
1051 
1053  // Tests concerning arrayExport
1055 
1059  {
1060  $array = [
1061  'foo' => [
1062  'bar' => 42,
1063  'bar2' => [
1064  'baz' => 'val\'ue',
1065  'baz2' => true,
1066  'baz3' => false,
1067  'baz4' => []
1068  ]
1069  ],
1070  'baz' => 23,
1071  'foobar' => null,
1072  'qux' => 0.1,
1073  'qux2' => 0.000000001,
1074  ];
1075  $expected =
1076  '[' . LF .
1077  ' \'foo\' => [' . LF .
1078  ' \'bar\' => 42,' . LF .
1079  ' \'bar2\' => [' . LF .
1080  ' \'baz\' => \'val\\\'ue\',' . LF .
1081  ' \'baz2\' => true,' . LF .
1082  ' \'baz3\' => false,' . LF .
1083  ' \'baz4\' => [],' . LF .
1084  ' ],' . LF .
1085  ' ],' . LF .
1086  ' \'baz\' => 23,' . LF .
1087  ' \'foobar\' => null,' . LF .
1088  ' \'qux\' => 0.1,' . LF .
1089  ' \'qux2\' => 1.0E-9,' . LF .
1090  ']';
1091  $this->assertSame($expected, ArrayUtility::arrayExport($array));
1092  }
1093 
1098  {
1099  $array = [
1100  'foo' => [
1101  'bar' => new \stdClass()
1102  ]
1103  ];
1104 
1105  $this->expectException(\RuntimeException::class);
1106  $this->expectExceptionCode(1342294987);
1107 
1108  ArrayUtility::arrayExport($array);
1109  }
1110 
1115  {
1116  $array = [
1117  'foo' => 'string key',
1118  23 => 'integer key',
1119  '42' => 'string key representing integer'
1120  ];
1121  $expected =
1122  '[' . LF .
1123  ' \'foo\' => \'string key\',' . LF .
1124  ' 23 => \'integer key\',' . LF .
1125  ' 42 => \'string key representing integer\',' . LF .
1126  ']';
1127  $this->assertSame($expected, ArrayUtility::arrayExport($array));
1128  }
1129 
1134  {
1135  $array = [
1136  0 => 'zero',
1137  1 => 'one',
1138  2 => 'two'
1139  ];
1140  $expected =
1141  '[' . LF .
1142  ' \'zero\',' . LF .
1143  ' \'one\',' . LF .
1144  ' \'two\',' . LF .
1145  ']';
1146  $this->assertSame($expected, ArrayUtility::arrayExport($array));
1147  }
1148 
1153  {
1154  $array = [
1155  0 => 'zero',
1156  1 => 'one',
1157  3 => 'three',
1158  4 => 'four'
1159  ];
1160  $expected =
1161  '[' . LF .
1162  ' 0 => \'zero\',' . LF .
1163  ' 1 => \'one\',' . LF .
1164  ' 3 => \'three\',' . LF .
1165  ' 4 => \'four\',' . LF .
1166  ']';
1167  $this->assertSame($expected, ArrayUtility::arrayExport($array));
1168  }
1169 
1171  // Tests concerning flatten
1173 
1178  {
1179  return [
1180  'plain array' => [
1181  [
1182  'first' => 1,
1183  'second' => 2
1184  ],
1185  [
1186  'first' => 1,
1187  'second' => 2
1188  ]
1189  ],
1190  'plain array with faulty dots' => [
1191  [
1192  'first.' => 1,
1193  'second.' => 2
1194  ],
1195  [
1196  'first' => 1,
1197  'second' => 2
1198  ]
1199  ],
1200  'nested array of 2 levels' => [
1201  [
1202  'first.' => [
1203  'firstSub' => 1
1204  ],
1205  'second.' => [
1206  'secondSub' => 2
1207  ]
1208  ],
1209  [
1210  'first.firstSub' => 1,
1211  'second.secondSub' => 2
1212  ]
1213  ],
1214  'nested array of 2 levels with faulty dots' => [
1215  [
1216  'first.' => [
1217  'firstSub.' => 1
1218  ],
1219  'second.' => [
1220  'secondSub.' => 2
1221  ]
1222  ],
1223  [
1224  'first.firstSub' => 1,
1225  'second.secondSub' => 2
1226  ]
1227  ],
1228  'nested array of 3 levels' => [
1229  [
1230  'first.' => [
1231  'firstSub.' => [
1232  'firstSubSub' => 1
1233  ]
1234  ],
1235  'second.' => [
1236  'secondSub.' => [
1237  'secondSubSub' => 2
1238  ]
1239  ]
1240  ],
1241  [
1242  'first.firstSub.firstSubSub' => 1,
1243  'second.secondSub.secondSubSub' => 2
1244  ]
1245  ],
1246  'nested array of 3 levels with faulty dots' => [
1247  [
1248  'first.' => [
1249  'firstSub.' => [
1250  'firstSubSub.' => 1
1251  ]
1252  ],
1253  'second.' => [
1254  'secondSub.' => [
1255  'secondSubSub.' => 2
1256  ]
1257  ]
1258  ],
1259  [
1260  'first.firstSub.firstSubSub' => 1,
1261  'second.secondSub.secondSubSub' => 2
1262  ]
1263  ]
1264  ];
1265  }
1266 
1273  public function flattenCalculatesExpectedResult(array $array, array $expected)
1274  {
1275  $this->assertEquals($expected, ArrayUtility::flatten($array));
1276  }
1277 
1279  // Tests concerning intersectRecursive
1281 
1286  {
1287  $sameObject = new \stdClass();
1288  return [
1289  // array($source, $mask, $expected)
1290  'empty array is returned if source is empty array' => [
1291  [],
1292  [
1293  'foo' => 'bar',
1294  ],
1295  [],
1296  ],
1297  'empty array is returned if mask is empty' => [
1298  [
1299  'foo' => 'bar',
1300  ],
1301  [],
1302  [],
1303  ],
1304  'key is kept on first level if exists in mask' => [
1305  [
1306  'foo' => 42,
1307  ],
1308  [
1309  'foo' => 42,
1310  ],
1311  [
1312  'foo' => 42,
1313  ],
1314  ],
1315  'value of key in source is kept if mask has different value' => [
1316  [
1317  'foo' => 42,
1318  ],
1319  [
1320  'foo' => new \stdClass(),
1321  ],
1322  [
1323  'foo' => 42,
1324  ],
1325  ],
1326  'key is kept on first level if according mask value is NULL' => [
1327  [
1328  'foo' => 42,
1329  ],
1330  [
1331  'foo' => null,
1332  ],
1333  [
1334  'foo' => 42,
1335  ],
1336  ],
1337  'null in source value is kept' => [
1338  [
1339  'foo' => null,
1340  ],
1341  [
1342  'foo' => 'bar',
1343  ],
1344  [
1345  'foo' => null,
1346  ]
1347  ],
1348  'mask does not add new keys' => [
1349  [
1350  'foo' => 42,
1351  ],
1352  [
1353  'foo' => 23,
1354  'bar' => [
1355  4711
1356  ],
1357  ],
1358  [
1359  'foo' => 42,
1360  ],
1361  ],
1362  'mask does not overwrite simple values with arrays' => [
1363  [
1364  'foo' => 42,
1365  ],
1366  [
1367  'foo' => [
1368  'bar' => 23,
1369  ],
1370  ],
1371  [
1372  'foo' => 42,
1373  ],
1374  ],
1375  'key is kept on first level if according mask value is array' => [
1376  [
1377  'foo' => 42,
1378  ],
1379  [
1380  'foo' => [
1381  'bar' => 23
1382  ],
1383  ],
1384  [
1385  'foo' => 42,
1386  ],
1387  ],
1388  'full array is kept if value is array and mask value is simple type' => [
1389  [
1390  'foo' => [
1391  'bar' => 23
1392  ],
1393  ],
1394  [
1395  'foo' => 42,
1396  ],
1397  [
1398  'foo' => [
1399  'bar' => 23
1400  ],
1401  ],
1402  ],
1403  'key handling is type agnostic' => [
1404  [
1405  42 => 'foo',
1406  ],
1407  [
1408  '42' => 'bar',
1409  ],
1410  [
1411  42 => 'foo',
1412  ],
1413  ],
1414  'value is same if value is object' => [
1415  [
1416  'foo' => $sameObject,
1417  ],
1418  [
1419  'foo' => 'something',
1420  ],
1421  [
1422  'foo' => $sameObject,
1423  ],
1424  ],
1425  'mask does not add simple value to result if key does not exist in source' => [
1426  [
1427  'foo' => '42',
1428  ],
1429  [
1430  'foo' => '42',
1431  'bar' => 23
1432  ],
1433  [
1434  'foo' => '42',
1435  ],
1436  ],
1437  'array of source is kept if value of mask key exists but is no array' => [
1438  [
1439  'foo' => '42',
1440  'bar' => [
1441  'baz' => 23
1442  ],
1443  ],
1444  [
1445  'foo' => 'value is not significant',
1446  'bar' => null,
1447  ],
1448  [
1449  'foo' => '42',
1450  'bar' => [
1451  'baz' => 23
1452  ],
1453  ],
1454  ],
1455  'sub arrays are kept if mask has according sub array key and is similar array' => [
1456  [
1457  'first1' => 42,
1458  'first2' => [
1459  'second1' => 23,
1460  'second2' => 4711,
1461  ],
1462  ],
1463  [
1464  'first1' => 42,
1465  'first2' => [
1466  'second1' => 'exists but different',
1467  ],
1468  ],
1469  [
1470  'first1' => 42,
1471  'first2' => [
1472  'second1' => 23,
1473  ],
1474  ],
1475  ],
1476  ];
1477  }
1478 
1486  public function intersectRecursiveCalculatesExpectedResult(array $source, array $mask, array $expected)
1487  {
1488  $this->assertSame($expected, ArrayUtility::intersectRecursive($source, $mask));
1489  }
1490 
1492  // Tests concerning renumberKeysToAvoidLeapsIfKeysAreAllNumeric
1494 
1498  {
1499  return [
1500  'empty array is returned if source is empty array' => [
1501  [],
1502  []
1503  ],
1504  'returns self if array is already numerically keyed' => [
1505  [1, 2, 3],
1506  [1, 2, 3]
1507  ],
1508  'returns correctly if keys are numeric, but contains a leap' => [
1509  [0 => 'One', 1 => 'Two', 3 => 'Three'],
1510  [0 => 'One', 1 => 'Two', 2 => 'Three'],
1511  ],
1512  'returns correctly even though keys are strings but still numeric' => [
1513  ['0' => 'One', '1' => 'Two', '3' => 'Three'],
1514  [0 => 'One', 1 => 'Two', 2 => 'Three'],
1515  ],
1516  'returns correctly if just a single keys is not numeric' => [
1517  [0 => 'Zero', '1' => 'One', 'Two' => 'Two'],
1518  [0 => 'Zero', '1' => 'One', 'Two' => 'Two'],
1519  ],
1520  'return self with nested numerically keyed array' => [
1521  [
1522  'One',
1523  'Two',
1524  'Three',
1525  [
1526  'sub.One',
1527  'sub.Two',
1528  ]
1529  ],
1530  [
1531  'One',
1532  'Two',
1533  'Three',
1534  [
1535  'sub.One',
1536  'sub.Two',
1537  ]
1538  ]
1539  ],
1540  'returns correctly with nested numerically keyed array with leaps' => [
1541  [
1542  'One',
1543  'Two',
1544  'Three',
1545  [
1546  0 => 'sub.One',
1547  2 => 'sub.Two',
1548  ]
1549  ],
1550  [
1551  'One',
1552  'Two',
1553  'Three',
1554  [
1555  'sub.One',
1556  'sub.Two',
1557  ]
1558  ]
1559  ],
1560  'returns correctly with nested string-keyed array' => [
1561  [
1562  'One',
1563  'Two',
1564  'Three',
1565  [
1566  'one' => 'sub.One',
1567  'two' => 'sub.Two',
1568  ]
1569  ],
1570  [
1571  'One',
1572  'Two',
1573  'Three',
1574  [
1575  'one' => 'sub.One',
1576  'two' => 'sub.Two',
1577  ]
1578  ]
1579  ],
1580  'returns correctly with deeply nested arrays' => [
1581  [
1582  'One',
1583  'Two',
1584  [
1585  'one' => 1,
1586  'two' => 2,
1587  'three' => [
1588  2 => 'SubSubOne',
1589  5 => 'SubSubTwo',
1590  9 => [0, 1, 2],
1591  []
1592  ]
1593  ]
1594  ],
1595  [
1596  'One',
1597  'Two',
1598  [
1599  'one' => 1,
1600  'two' => 2,
1601  'three' => [
1602  'SubSubOne',
1603  'SubSubTwo',
1604  [0, 1, 2],
1605  []
1606  ]
1607  ]
1608  ]
1609  ]
1610  ];
1611  }
1612 
1619  public function renumberKeysToAvoidLeapsIfKeysAreAllNumericReturnsExpectedOrder(array $inputArray, array $expected)
1620  {
1621  $this->assertEquals($expected, ArrayUtility::renumberKeysToAvoidLeapsIfKeysAreAllNumeric($inputArray));
1622  }
1623 
1628  {
1629  return [
1630  'Override array can reset string to array' => [
1631  [
1632  'first' => [
1633  'second' => 'foo',
1634  ],
1635  ],
1636  [
1637  'first' => [
1638  'second' => ['third' => 'bar'],
1639  ],
1640  ],
1641  true,
1642  true,
1643  true,
1644  [
1645  'first' => [
1646  'second' => ['third' => 'bar'],
1647  ],
1648  ],
1649  ],
1650  'Override array does not reset array to string (weird!)' => [
1651  [
1652  'first' => [],
1653  ],
1654  [
1655  'first' => 'foo',
1656  ],
1657  true,
1658  true,
1659  true,
1660  [
1661  'first' => [], // This is rather unexpected, naive expectation: first => 'foo'
1662  ],
1663  ],
1664  'Override array does override string with null' => [
1665  [
1666  'first' => 'foo',
1667  ],
1668  [
1669  'first' => null,
1670  ],
1671  true,
1672  true,
1673  true,
1674  [
1675  'first' => null,
1676  ],
1677  ],
1678  'Override array does override null with string' => [
1679  [
1680  'first' => null,
1681  ],
1682  [
1683  'first' => 'foo',
1684  ],
1685  true,
1686  true,
1687  true,
1688  [
1689  'first' => 'foo',
1690  ],
1691  ],
1692  'Override array does override null with empty string' => [
1693  [
1694  'first' => null,
1695  ],
1696  [
1697  'first' => '',
1698  ],
1699  true,
1700  true,
1701  true,
1702  [
1703  'first' => '',
1704  ],
1705  ],
1706  'Override array does not override string with NULL if requested' => [
1707  [
1708  'first' => 'foo',
1709  ],
1710  [
1711  'first' => null,
1712  ],
1713  true,
1714  false, // no include empty values
1715  true,
1716  [
1717  'first' => 'foo',
1718  ],
1719  ],
1720  'Override array does override null with null' => [
1721  [
1722  'first' => null,
1723  ],
1724  [
1725  'first' => null,
1726  ],
1727  true,
1728  true,
1729  true,
1730  [
1731  'first' => '',
1732  ],
1733  ],
1734  'Override array can __UNSET values' => [
1735  [
1736  'first' => [
1737  'second' => 'second',
1738  'third' => 'third',
1739  ],
1740  'fifth' => [],
1741  ],
1742  [
1743  'first' => [
1744  'second' => 'overrule',
1745  'third' => '__UNSET',
1746  'fourth' => 'overrile',
1747  ],
1748  'fifth' => '__UNSET',
1749  ],
1750  true,
1751  true,
1752  true,
1753  [
1754  'first' => [
1755  'second' => 'overrule',
1756  'fourth' => 'overrile',
1757  ],
1758  ],
1759  ],
1760  'Override can add keys' => [
1761  [
1762  'first' => 'foo',
1763  ],
1764  [
1765  'second' => 'bar',
1766  ],
1767  true,
1768  true,
1769  true,
1770  [
1771  'first' => 'foo',
1772  'second' => 'bar',
1773  ],
1774  ],
1775  'Override does not add key if __UNSET' => [
1776  [
1777  'first' => 'foo',
1778  ],
1779  [
1780  'second' => '__UNSET',
1781  ],
1782  true,
1783  true,
1784  true,
1785  [
1786  'first' => 'foo',
1787  ],
1788  ],
1789  'Override does not add key if not requested' => [
1790  [
1791  'first' => 'foo',
1792  ],
1793  [
1794  'second' => 'bar',
1795  ],
1796  false, // no add keys
1797  true,
1798  true,
1799  [
1800  'first' => 'foo',
1801  ],
1802  ],
1803  'Override does not add key if not requested with add include empty values' => [
1804  [
1805  'first' => 'foo',
1806  ],
1807  [
1808  'second' => 'bar',
1809  ],
1810  false, // no add keys
1811  false, // no include empty values
1812  true,
1813  [
1814  'first' => 'foo',
1815  ],
1816  ],
1817  'Override does not override string with empty string if requested' => [
1818  [
1819  'first' => 'foo',
1820  ],
1821  [
1822  'first' => '',
1823  ],
1824  true,
1825  false, // no include empty values
1826  true,
1827  [
1828  'first' => 'foo',
1829  ],
1830  ],
1831  'Override array does merge instead of __UNSET if requested (weird!)' => [
1832  [
1833  'first' => [
1834  'second' => 'second',
1835  'third' => 'third',
1836  ],
1837  'fifth' => [],
1838  ],
1839  [
1840  'first' => [
1841  'second' => 'overrule',
1842  'third' => '__UNSET',
1843  'fourth' => 'overrile',
1844  ],
1845  'fifth' => '__UNSET',
1846  ],
1847  true,
1848  true,
1849  false,
1850  [
1851  'first' => [
1852  'second' => 'overrule',
1853  'third' => '__UNSET', // overruled
1854  'fourth' => 'overrile',
1855  ],
1856  'fifth' => [], // not overruled with string here, naive expectation: 'fifth' => '__UNSET'
1857  ],
1858  ],
1859  ];
1860  }
1861 
1872  public function mergeRecursiveWithOverruleCalculatesExpectedResult($input1, $input2, $addKeys, $includeEmptyValues, $enableUnsetFeature, $expected)
1873  {
1874  ArrayUtility::mergeRecursiveWithOverrule($input1, $input2, $addKeys, $includeEmptyValues, $enableUnsetFeature);
1875  $this->assertEquals($expected, $input1);
1876  }
1877 
1879  // Tests concerning inArray
1881 
1888  public function inArrayChecksStringExistenceWithinArray($array, $item, $expected)
1889  {
1890  $this->assertEquals($expected, ArrayUtility::inArray($array, $item));
1891  }
1892 
1898  public function inArrayDataProvider()
1899  {
1900  return [
1901  'Empty array' => [[], 'search', false],
1902  'One item array no match' => [['one'], 'two', false],
1903  'One item array match' => [['one'], 'one', true],
1904  'Multiple items array no match' => [['one', 2, 'three', 4], 'four', false],
1905  'Multiple items array match' => [['one', 2, 'three', 4], 'three', true],
1906  'Integer search items can match string values' => [['0', '1', '2'], 1, true],
1907  'Search item is not casted to integer for a match' => [[4], '4a', false],
1908  'Empty item won\'t match - in contrast to the php-builtin ' => [[0, 1, 2], '', false]
1909  ];
1910  }
1911 
1913  // Tests concerning removeArrayEntryByValue
1915 
1919  {
1920  $inputArray = [
1921  '0' => 'test1',
1922  '1' => 'test2',
1923  '2' => 'test3',
1924  '3' => 'test2'
1925  ];
1926  $compareValue = 'test2';
1927  $expectedResult = [
1928  '0' => 'test1',
1929  '2' => 'test3'
1930  ];
1931  $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
1932  $this->assertEquals($expectedResult, $actualResult);
1933  }
1934 
1939  {
1940  $inputArray = [
1941  '0' => 'foo',
1942  '1' => [
1943  '10' => 'bar'
1944  ],
1945  '2' => 'bar'
1946  ];
1947  $compareValue = 'bar';
1948  $expectedResult = [
1949  '0' => 'foo',
1950  '1' => []
1951  ];
1952  $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
1953  $this->assertEquals($expectedResult, $actualResult);
1954  }
1955 
1960  {
1961  $inputArray = [
1962  '0' => 'foo',
1963  '1' => '',
1964  '2' => 'bar'
1965  ];
1966  $compareValue = '';
1967  $expectedResult = [
1968  '0' => 'foo',
1969  '2' => 'bar'
1970  ];
1971  $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
1972  $this->assertEquals($expectedResult, $actualResult);
1973  }
1974 
1976  // Tests concerning keepItemsInArray
1978 
1985  public function keepItemsInArrayWorksWithOneArgument($search, $array, $expected)
1986  {
1987  $this->assertEquals($expected, ArrayUtility::keepItemsInArray($array, $search));
1988  }
1989 
1996  {
1997  $array = [
1998  'one' => 'one',
1999  'two' => 'two',
2000  'three' => 'three'
2001  ];
2002  return [
2003  'Empty argument will match "all" elements' => [null, $array, $array],
2004  'No match' => ['four', $array, []],
2005  'One match' => ['two', $array, ['two' => 'two']],
2006  'Multiple matches' => ['two,one', $array, ['one' => 'one', 'two' => 'two']],
2007  'Argument can be an array' => [['three'], $array, ['three' => 'three']]
2008  ];
2009  }
2010 
2019  {
2020  $array = [
2021  'aa' => ['first', 'second'],
2022  'bb' => ['third', 'fourth'],
2023  'cc' => ['fifth', 'sixth']
2024  ];
2025  $expected = ['bb' => ['third', 'fourth']];
2026  $keepItems = 'third';
2028  $array,
2029  $keepItems,
2030  function ($value) {
2031  return $value[0];
2032  }
2033  );
2034  $this->assertEquals($expected, $match);
2035  }
2036 
2038  // Tests concerning remapArrayKeys
2040 
2044  {
2045  $array = [
2046  'one' => 'one',
2047  'two' => 'two',
2048  'three' => 'three'
2049  ];
2050  $keyMapping = [
2051  'one' => '1',
2052  'two' => '2'
2053  ];
2054  $expected = [
2055  '1' => 'one',
2056  '2' => 'two',
2057  'three' => 'three'
2058  ];
2059  ArrayUtility::remapArrayKeys($array, $keyMapping);
2060  $this->assertEquals($expected, $array);
2061  }
2062 
2064  // Tests concerning arrayDiffAssocRecursive
2066 
2070  {
2071  $array1 = [
2072  'key1' => 'value1',
2073  'key2' => 'value2',
2074  'key3' => 'value3'
2075  ];
2076  $array2 = [
2077  'key1' => 'value1',
2078  'key3' => 'value3'
2079  ];
2080  $expectedResult = [
2081  'key2' => 'value2'
2082  ];
2083  $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2084  $this->assertEquals($expectedResult, $actualResult);
2085  }
2086 
2091  {
2092  $array1 = [
2093  'key1' => 'value1',
2094  'key2' => [
2095  'key21' => 'value21',
2096  'key22' => 'value22',
2097  'key23' => [
2098  'key231' => 'value231',
2099  'key232' => 'value232'
2100  ]
2101  ]
2102  ];
2103  $array2 = [
2104  'key1' => 'value1',
2105  'key2' => [
2106  'key21' => 'value21',
2107  'key23' => [
2108  'key231' => 'value231'
2109  ]
2110  ]
2111  ];
2112  $expectedResult = [
2113  'key2' => [
2114  'key22' => 'value22',
2115  'key23' => [
2116  'key232' => 'value232'
2117  ]
2118  ]
2119  ];
2120  $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2121  $this->assertEquals($expectedResult, $actualResult);
2122  }
2123 
2128  {
2129  $array1 = [
2130  'key1' => [
2131  'key11' => 'value11',
2132  'key12' => 'value12'
2133  ],
2134  'key2' => 'value2',
2135  'key3' => 'value3'
2136  ];
2137  $array2 = [
2138  'key1' => 'value1',
2139  'key2' => [
2140  'key21' => 'value21'
2141  ]
2142  ];
2143  $expectedResult = [
2144  'key3' => 'value3'
2145  ];
2146  $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2147  $this->assertEquals($expectedResult, $actualResult);
2148  }
2149 
2151  // Tests concerning naturalKeySortRecursive
2153 
2158  {
2159  $testArray = [
2160  'bb' => 'bb',
2161  'ab' => 'ab',
2162  '123' => '123',
2163  'aaa' => 'aaa',
2164  'abc' => 'abc',
2165  '23' => '23',
2166  'ba' => 'ba',
2167  'bad' => 'bad',
2168  '2' => '2',
2169  'zap' => 'zap',
2170  '210' => '210'
2171  ];
2172  $expectedResult = [
2173  '2',
2174  '23',
2175  '123',
2176  '210',
2177  'aaa',
2178  'ab',
2179  'abc',
2180  'ba',
2181  'bad',
2182  'bb',
2183  'zap'
2184  ];
2186  $this->assertEquals($expectedResult, array_values($testArray));
2187  }
2188 
2193  {
2194  $testArray = [
2195  '2' => '2',
2196  'bb' => 'bb',
2197  'ab' => 'ab',
2198  '23' => '23',
2199  'aaa' => [
2200  'bb' => 'bb',
2201  'ab' => 'ab',
2202  '123' => '123',
2203  'aaa' => 'aaa',
2204  '2' => '2',
2205  'abc' => 'abc',
2206  'ba' => 'ba',
2207  '23' => '23',
2208  'bad' => [
2209  'bb' => 'bb',
2210  'ab' => 'ab',
2211  '123' => '123',
2212  'aaa' => 'aaa',
2213  'abc' => 'abc',
2214  '23' => '23',
2215  'ba' => 'ba',
2216  'bad' => 'bad',
2217  '2' => '2',
2218  'zap' => 'zap',
2219  '210' => '210'
2220  ],
2221  '210' => '210',
2222  'zap' => 'zap'
2223  ],
2224  'abc' => 'abc',
2225  'ba' => 'ba',
2226  '210' => '210',
2227  'bad' => 'bad',
2228  '123' => '123',
2229  'zap' => 'zap'
2230  ];
2231  $expectedResult = [
2232  '2',
2233  '23',
2234  '123',
2235  '210',
2236  'aaa',
2237  'ab',
2238  'abc',
2239  'ba',
2240  'bad',
2241  'bb',
2242  'zap'
2243  ];
2245  $this->assertEquals($expectedResult, array_values(array_keys($testArray['aaa']['bad'])));
2246  $this->assertEquals($expectedResult, array_values(array_keys($testArray['aaa'])));
2247  $this->assertEquals($expectedResult, array_values(array_keys($testArray)));
2248  }
2249 
2256  {
2257  return [
2258  'ordered list of plain numeric keys' => [
2259  'input' => [
2260  '10' => 'foo',
2261  '20' => 'bar',
2262  ],
2263  'expected' => [
2264  10,
2265  20,
2266  ],
2267  ],
2268  'unordered list of plain numeric keys' => [
2269  'input' => [
2270  '20' => 'bar',
2271  '10' => 'foo',
2272  ],
2273  'expected' => [
2274  10,
2275  20,
2276  ],
2277  ],
2278  'list of string keys' => [
2279  'input' => [
2280  '10.' => [
2281  'wrap' => 'foo',
2282  ],
2283  '20.' => [
2284  'wrap' => 'bar',
2285  ],
2286  ],
2287  'expected' => [
2288  10,
2289  20,
2290  ],
2291  ],
2292  'list of mixed keys' => [
2293  'input' => [
2294  '10' => 'foo',
2295  '20.' => [
2296  'wrap' => 'bar',
2297  ],
2298  ],
2299  'expected' => [
2300  10,
2301  20,
2302  ],
2303  ],
2304  'list of mixed keys with one not interpreted as integer' => [
2305  'input' => [
2306  '10' => 'foo',
2307  'bla20.' => [
2308  'wrap' => 'bar',
2309  ],
2310  ],
2311  'expected' => [
2312  0,
2313  10,
2314  ],
2315  ],
2316  'list of mixed keys with more than one not interpreted as integer' => [
2317  'input' => [
2318  '10' => 'foo',
2319  'bla20.' => [
2320  'wrap' => 'bar',
2321  ],
2322  'bla21.' => [
2323  'wrap' => 'foobar',
2324  ],
2325  ],
2326  'expected' => [
2327  0,
2328  10,
2329  ],
2330  ],
2331  ];
2332  }
2333 
2342  {
2343  $result = ArrayUtility::filterAndSortByNumericKeys($input, true);
2344  $this->assertEquals($result, $expected);
2345  }
2346 
2353  {
2354  return [
2355  'ordered list of plain numeric keys' => [
2356  'input' => [
2357  '10' => 'foo',
2358  '20' => 'bar',
2359  ],
2360  'expected' => [
2361  10,
2362  20,
2363  ],
2364  ],
2365  'unordered list of plain numeric keys' => [
2366  'input' => [
2367  '20' => 'bar',
2368  '10' => 'foo',
2369  ],
2370  'expected' => [
2371  10,
2372  20,
2373  ],
2374  ],
2375  'list of string keys' => [
2376  'input' => [
2377  '10.' => [
2378  'wrap' => 'foo',
2379  ],
2380  '20.' => [
2381  'wrap' => 'bar',
2382  ],
2383  ],
2384  'expected' => [],
2385  ],
2386  'list of mixed keys' => [
2387  'input' => [
2388  '10' => 'foo',
2389  '20.' => [
2390  'wrap' => 'bar',
2391  ],
2392  ],
2393  'expected' => [
2394  10,
2395  ],
2396  ],
2397  ];
2398  }
2399 
2408  {
2409  $result = ArrayUtility::filterAndSortByNumericKeys($input);
2410  $this->assertEquals($result, $expected);
2411  }
2412 
2419  {
2420  return [
2421  [
2422  [
2423  '20' => 'test1',
2424  '11' => 'test2',
2425  '16' => 'test3',
2426  ],
2427  [
2428  '11' => 'test2',
2429  '16' => 'test3',
2430  '20' => 'test1',
2431  ]
2432  ],
2433  [
2434  [
2435  '20' => 'test1',
2436  '16.5' => 'test2',
2437  '16' => 'test3',
2438  ],
2439  [
2440  '20' => 'test1',
2441  '16.5' => 'test2',
2442  '16' => 'test3',
2443  ]
2444  ],
2445  [
2446  [
2447  '20' => 'test20',
2448  'somestring' => 'teststring',
2449  '16' => 'test16',
2450  ],
2451  [
2452  '20' => 'test20',
2453  'somestring' => 'teststring',
2454  '16' => 'test16',
2455  ]
2456  ],
2457  ];
2458  }
2459 
2468  public function sortArrayWithIntegerKeysSortsNumericArrays(array $arrayToSort, array $expectedArray)
2469  {
2470  $sortedArray = ArrayUtility::sortArrayWithIntegerKeys($arrayToSort);
2471  $this->assertSame($sortedArray, $expectedArray);
2472  }
2473 
2478  {
2479  $this->expectException(\InvalidArgumentException::class);
2480  $this->expectExceptionCode(1325697085);
2481 
2482  $arrayToTest = [
2483  'roger' => '',
2484  'francine' => '',
2485  'stan' => '',
2486  ];
2487 
2488  $allowedArrayKeys = [
2489  'roger',
2490  'francine',
2491  ];
2492 
2493  ArrayUtility::assertAllArrayKeysAreValid($arrayToTest, $allowedArrayKeys);
2494  }
2495 
2500  {
2501  $arrayToTest = [
2502  'roger' => '',
2503  'francine' => '',
2504  'stan' => '',
2505  ];
2506 
2507  $allowedArrayKeys = [
2508  'roger',
2509  'francine',
2510  'stan',
2511  ];
2512 
2513  $this->assertNull(ArrayUtility::assertAllArrayKeysAreValid($arrayToTest, $allowedArrayKeys));
2514  }
2515 
2520  {
2521  $input = [
2522  20 => 'b',
2523  10 => 'a',
2524  40 => 'd',
2525  30 => 'c',
2526  50 => [
2527  20 => 'a',
2528  10 => 'b',
2529  ],
2530  ];
2531 
2532  $expected = [
2533  10 => 'a',
2534  20 => 'b',
2535  30 => 'c',
2536  40 => 'd',
2537  50 => [
2538  10 => 'b',
2539  20 => 'a',
2540  ],
2541  ];
2542 
2543  $this->assertSame($expected, ArrayUtility::sortArrayWithIntegerKeysRecursive($input));
2544  }
2545 
2550  {
2551  $input = [
2552  'b' => 'b',
2553  10 => 'a',
2554  40 => 'd',
2555  30 => 'c',
2556  ];
2557 
2558  $expected = [
2559  'b' => 'b',
2560  10 => 'a',
2561  40 => 'd',
2562  30 => 'c',
2563  ];
2564 
2565  $this->assertSame($expected, ArrayUtility::sortArrayWithIntegerKeysRecursive($input));
2566  }
2567 
2572  {
2573  $input = [
2574  20 => 'b',
2575  10 => 'a',
2576  40 => 'd',
2577  30 => 'c',
2578  50 => [
2579  20 => 'a',
2580  10 => 'b',
2581  ],
2582  ];
2583 
2584  $expected = [
2585  0 => 'b',
2586  1 => 'a',
2587  2 => 'd',
2588  3 => 'c',
2589  4 => [
2590  0 => 'a',
2591  1 => 'b',
2592  ],
2593  ];
2594 
2595  $this->assertSame($expected, ArrayUtility::reIndexNumericArrayKeysRecursive($input));
2596  }
2597 
2602  {
2603  $input = [
2604  'a' => 'b',
2605  10 => 'a',
2606  40 => 'd',
2607  30 => 'c',
2608  50 => [
2609  20 => 'a',
2610  10 => 'b',
2611  ],
2612  ];
2613 
2614  $expected = [
2615  'a' => 'b',
2616  10 => 'a',
2617  40 => 'd',
2618  30 => 'c',
2619  50 => [
2620  0 => 'a',
2621  1 => 'b',
2622  ],
2623  ];
2624 
2625  $this->assertSame($expected, ArrayUtility::reIndexNumericArrayKeysRecursive($input));
2626  }
2627 
2632  {
2633  $input = [
2634  'a' => 'a',
2635  'b' => [
2636  'c' => null,
2637  'd' => 'd',
2638  ],
2639  ];
2640 
2641  $expected = [
2642  'a' => 'a',
2643  'b' => [
2644  'd' => 'd',
2645  ],
2646  ];
2647 
2648  $this->assertSame($expected, ArrayUtility::removeNullValuesRecursive($input));
2649  }
2650 
2655  {
2656  $input = [
2657  'a' => 'a',
2658  'b' => [
2659  'c' => '<b>i am evil</b>',
2660  'd' => 'd',
2661  ],
2662  ];
2663 
2664  $expected = [
2665  'a' => 'a',
2666  'b' => [
2667  'c' => 'i am evil',
2668  'd' => 'd',
2669  ],
2670  ];
2671 
2672  $this->assertSame($expected, ArrayUtility::stripTagsFromValuesRecursive($input));
2673  }
2674 
2679  {
2680  $input = [
2681  'a' => 'a',
2682  'b' => [
2683  'c' => 'true',
2684  'd' => 'd',
2685  ],
2686  ];
2687 
2688  $expected = [
2689  'a' => 'a',
2690  'b' => [
2691  'c' => true,
2692  'd' => 'd',
2693  ],
2694  ];
2695 
2696  $this->assertSame($expected, ArrayUtility::convertBooleanStringsToBooleanRecursive($input));
2697  }
2698 }
static assertAllArrayKeysAreValid(array $arrayToTest, array $allowedArrayKeys)
sortArrayWithIntegerKeysSortsNumericArrays(array $arrayToSort, array $expectedArray)
static renumberKeysToAvoidLeapsIfKeysAreAllNumeric(array $array=[], $level=0)
static sortArraysByKey(array $arrays, $key, $ascending=true)
setValueByPathSetsCorrectValue(array $array, $path, $value, $expectedResult)
static keepItemsInArray(array $array, $keepItems, $getValueFunc=null)
static arrayDiffAssocRecursive(array $array1, array $array2)
mergeRecursiveWithOverruleCalculatesExpectedResult($input1, $input2, $addKeys, $includeEmptyValues, $enableUnsetFeature, $expected)
static filterByValueRecursive($needle= '', array $haystack=[])
static remapArrayKeys(array &$array, array $mappingTable)
static getValueByPath(array $array, $path, $delimiter= '/')
static intersectRecursive(array $source, array $mask=[])
renumberKeysToAvoidLeapsIfKeysAreAllNumericReturnsExpectedOrder(array $inputArray, array $expected)
static removeByPath(array $array, $path, $delimiter= '/')
intersectRecursiveCalculatesExpectedResult(array $source, array $mask, array $expected)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
static filterAndSortByNumericKeys($setupArr, $acceptAnyKeys=false)
static setValueByPath(array $array, $path, $value, $delimiter= '/')
sortArraysByKeyCheckIfSortingIsCorrect(array $array, $key, $ascending, $expectedResult)
static isValidPath(array $array, $path, $delimiter= '/')
static removeArrayEntryByValue(array $array, $cmpValue)