‪TYPO3CMS  ‪main
ArrayUtilityTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use PHPUnit\Framework\Attributes\DataProvider;
21 use PHPUnit\Framework\Attributes\Test;
25 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
26 
30 final class ‪ArrayUtilityTest extends UnitTestCase
31 {
33  // Tests concerning filterByValueRecursive
35 
43  public static function ‪filterByValueRecursive(): array
44  {
45  return [
46  'empty search array' => [
47  'banana',
48  [],
49  [],
50  ],
51  'empty string as needle' => [
52  '',
53  [
54  '',
55  'apple',
56  ],
57  [
58  '',
59  ],
60  ],
61  'flat array searching for string' => [
62  'banana',
63  [
64  'apple',
65  'banana',
66  ],
67  [
68  1 => 'banana',
69  ],
70  ],
71  'flat array searching for string with two matches' => [
72  'banana',
73  [
74  'foo' => 'apple',
75  'firstbanana' => 'banana',
76  'secondbanana' => 'banana',
77  ],
78  [
79  'firstbanana' => 'banana',
80  'secondbanana' => 'banana',
81  ],
82  ],
83  'multi dimensional array searching for string with multiple matches' => [
84  'banana',
85  [
86  'foo' => 'apple',
87  'firstbanana' => 'banana',
88  'grape' => [
89  'foo2' => 'apple2',
90  'secondbanana' => 'banana',
91  'foo3' => [],
92  ],
93  'bar' => 'orange',
94  ],
95  [
96  'firstbanana' => 'banana',
97  'grape' => [
98  'secondbanana' => 'banana',
99  ],
100  ],
101  ],
102  'multi dimensional array searching for integer with multiple matches' => [
103  42,
104  [
105  'foo' => 23,
106  'bar' => 42,
107  [
108  'foo' => 23,
109  'bar' => 42,
110  ],
111  ],
112  [
113  'bar' => 42,
114  [
115  'bar' => 42,
116  ],
117  ],
118  ],
119  'flat array searching for boolean TRUE' => [
120  true,
121  [
122  23 => false,
123  42 => true,
124  ],
125  [
126  42 => true,
127  ],
128  ],
129  'multi dimensional array searching for boolean FALSE' => [
130  false,
131  [
132  23 => false,
133  42 => true,
134  'foo' => [
135  23 => false,
136  42 => true,
137  ],
138  ],
139  [
140  23 => false,
141  'foo' => [
142  23 => false,
143  ],
144  ],
145  ],
146  'flat array searching for array' => [
147  [
148  'foo' => 'bar',
149  ],
150  [
151  'foo' => 'bar',
152  'foobar' => [
153  'foo' => 'bar',
154  ],
155  ],
156  [
157  'foobar' => [
158  'foo' => 'bar',
159  ],
160  ],
161  ],
162  ];
163  }
164 
170  #[DataProvider('filterByValueRecursive')]
171  #[Test]
172  public function ‪filterByValueRecursiveCorrectlyFiltersArray($needle, $haystack, $expectedResult): void
173  {
174  self::assertEquals(
175  $expectedResult,
176  ‪ArrayUtility::filterByValueRecursive($needle, $haystack)
177  );
178  }
179 
180  #[Test]
182  {
183  $instance = new \stdClass();
184  self::assertEquals(
185  [$instance],
186  ‪ArrayUtility::filterByValueRecursive($instance, [$instance])
187  );
188  }
189 
190  #[Test]
192  {
193  self::assertEquals(
194  [],
195  ‪ArrayUtility::filterByValueRecursive(new \stdClass(), [new \stdClass()])
196  );
197  }
198 
200  // Tests concerning isValidPath
202  #[Test]
204  {
205  self::assertTrue(‪ArrayUtility::isValidPath(['foo' => 'bar'], 'foo'));
206  }
207 
208  #[Test]
210  {
211  self::assertFalse(‪ArrayUtility::isValidPath(['foo' => 'bar'], 'bar'));
212  }
213 
214  #[Test]
216  {
217  self::assertTrue(‪ArrayUtility::isValidPath(['foo' => 'bar'], ['foo']));
218  }
219 
220  #[Test]
222  {
223  self::assertFalse(‪ArrayUtility::isValidPath(['foo' => 'bar'], ['bar']));
224  }
225 
227  // Tests concerning getValueByPath
229  #[Test]
231  {
232  $this->expectException(\RuntimeException::class);
233  $this->expectExceptionCode(1341397767);
234 
236  }
237 
238  #[Test]
240  {
241  self::assertSame('foo', ‪ArrayUtility::getValueByPath(['foo'], '0'));
242  }
243 
244  #[Test]
246  {
247  self::assertSame('bar', ‪ArrayUtility::getValueByPath(['foo' => ['bar']], 'foo/0'));
248  }
249 
257  public static function ‪getValueByPathInvalidPathDataProvider(): array
258  {
259  return [
260  'not existing index' => [
261  [
262  'foo' => ['foo'],
263  ],
264  'foo/1',
265  false,
266  ],
267  'not existing path 1' => [
268  [
269  'foo' => [],
270  ],
271  'foo/bar/baz',
272  false,
273  ],
274  'not existing path 2' => [
275  [
276  'foo' => [
277  'baz' => 42,
278  ],
279  'bar' => [],
280  ],
281  'foo/bar/baz',
282  false,
283  ],
284  'last segment is not an array' => [
285  [
286  'foo' => [
287  'baz' => 42,
288  ],
289  ],
290  'foo/baz/baz',
291  false,
292  ],
293  // Negative test: This could be improved and the test moved to
294  // the valid data provider if the method supports this
295  'doubletick encapsulated quoted doubletick does not work' => [
296  [
297  '"foo"bar"' => [
298  'baz' => 42,
299  ],
300  'bar' => [],
301  ],
302  '"foo\\"bar"/baz',
303  42,
304  ],
305  // Negative test: Method could be improved here
306  'path with doubletick does not work' => [
307  [
308  'fo"o' => [
309  'bar' => 42,
310  ],
311  ],
312  'fo"o/foobar',
313  42,
314  ],
315  ];
316  }
317 
321  #[DataProvider('getValueByPathInvalidPathDataProvider')]
322  #[Test]
323  public function ‪getValueByPathThrowsExceptionIfPathNotExists(array $array, $path): void
324  {
325  $this->expectException(\RuntimeException::class);
326  $this->expectExceptionCode(1341397869);
327  ‪ArrayUtility::getValueByPath($array, $path);
328  }
329 
330  #[DataProvider('getValueByPathInvalidPathDataProvider')]
331  #[Test]
332  public function ‪getValueByPathThrowsSpecificExceptionIfPathNotExists(array $array, string $path): void
333  {
334  $this->expectException(MissingArrayPathException::class);
335  $this->expectExceptionCode(1341397869);
336  ‪ArrayUtility::getValueByPath($array, $path);
337  }
338 
346  public static function ‪getValueByPathValidDataProvider(): array
347  {
348  $testObject = new \stdClass();
349  $testObject->foo = 'foo';
350  $testObject->bar = 'bar';
351  return [
352  'integer in multi level array' => [
353  [
354  'foo' => [
355  'bar' => [
356  'baz' => 42,
357  ],
358  'bar2' => [],
359  ],
360  ],
361  'foo/bar/baz',
362  42,
363  ],
364  'zero integer in multi level array' => [
365  [
366  'foo' => [
367  'bar' => [
368  'baz' => 0,
369  ],
370  ],
371  ],
372  'foo/bar/baz',
373  0,
374  ],
375  'NULL value in multi level array' => [
376  [
377  'foo' => [
378  'baz' => null,
379  ],
380  ],
381  'foo/baz',
382  null,
383  ],
384  'get string value' => [
385  [
386  'foo' => [
387  'baz' => 'this is a test string',
388  ],
389  ],
390  'foo/baz',
391  'this is a test string',
392  ],
393  'get boolean value: FALSE' => [
394  [
395  'foo' => [
396  'baz' => false,
397  ],
398  ],
399  'foo/baz',
400  false,
401  ],
402  'get boolean value: TRUE' => [
403  [
404  'foo' => [
405  'baz' => true,
406  ],
407  ],
408  'foo/baz',
409  true,
410  ],
411  'get object value' => [
412  [
413  'foo' => [
414  'baz' => $testObject,
415  ],
416  ],
417  'foo/baz',
418  $testObject,
419  ],
420  'sub array' => [
421  [
422  'foo' => [
423  'bar' => [
424  'baz' => 42,
425  ],
426  ],
427  ],
428  'foo/bar',
429  [
430  'baz' => 42,
431  ],
432  ],
433  'enclosed path' => [
434  [
435  'foo/bar' => [
436  'foobar' => 42,
437  ],
438  ],
439  '"foo/bar"/foobar',
440  42,
441  ],
442  ];
443  }
444 
449  #[DataProvider('getValueByPathValidDataProvider')]
450  #[Test]
451  public function ‪getValueByPathGetsCorrectValue(array $array, $path, $expectedResult): void
452  {
453  self::assertEquals($expectedResult, ‪ArrayUtility::getValueByPath($array, $path));
454  }
455 
456  #[Test]
458  {
459  $input = [
460  'foo' => [
461  'bar' => [
462  'baz' => 42,
463  ],
464  'bar2' => [],
465  ],
466  ];
467  $searchPath = 'foo%bar%baz';
468  $expected = 42;
469  $delimiter = '%';
470  self::assertEquals(
471  $expected,
472  ‪ArrayUtility::getValueByPath($input, $searchPath, $delimiter)
473  );
474  }
475 
477  // Tests concerning setValueByPath
479  #[Test]
481  {
482  $this->expectException(\RuntimeException::class);
483  $this->expectExceptionCode(1341406194);
484 
485  ‪ArrayUtility::setValueByPath([], '', null);
486  }
487 
488  #[Test]
490  {
491  $this->expectException(\RuntimeException::class);
492  $this->expectExceptionCode(1341406846);
493 
494  ‪ArrayUtility::setValueByPath(['foo' => 'bar'], '/foo', 'value');
495  }
496 
497  #[Test]
499  {
500  self::assertSame(['foo' => ['value']], ‪ArrayUtility::setValueByPath(['foo' => []], 'foo/0', 'value'));
501  }
502 
503  #[Test]
504  public function ‪setValueByPathCanUseZeroAsPath(): void
505  {
506  self::assertSame(['value', 'bar'], ‪ArrayUtility::setValueByPath(['foo', 'bar'], '0', 'value'));
507  }
508 
518  public static function ‪setValueByPathSetsCorrectValueDataProvider(): array
519  {
520  $testObject = new \stdClass();
521  $testObject->foo = 'foo';
522  $testObject->bar = 'bar';
523  return [
524  'set integer value: 42' => [
525  [
526  'foo' => [
527  'bar' => [
528  'baz' => 0,
529  ],
530  ],
531  ],
532  'foo/bar/baz',
533  42,
534  [
535  'foo' => [
536  'bar' => [
537  'baz' => 42,
538  ],
539  ],
540  ],
541  ],
542  'set integer value: 0' => [
543  [
544  'foo' => [
545  'bar' => [
546  'baz' => 42,
547  ],
548  ],
549  ],
550  'foo/bar/baz',
551  0,
552  [
553  'foo' => [
554  'bar' => [
555  'baz' => 0,
556  ],
557  ],
558  ],
559  ],
560  'set null value' => [
561  [
562  'foo' => [
563  'bar' => [
564  'baz' => 42,
565  ],
566  ],
567  ],
568  'foo/bar/baz',
569  null,
570  [
571  'foo' => [
572  'bar' => [
573  'baz' => null,
574  ],
575  ],
576  ],
577  ],
578  'set array value' => [
579  [
580  'foo' => [
581  'bar' => [
582  'baz' => 42,
583  ],
584  ],
585  ],
586  'foo/bar/baz',
587  [
588  'foo' => 123,
589  ],
590  [
591  'foo' => [
592  'bar' => [
593  'baz' => [
594  'foo' => 123,
595  ],
596  ],
597  ],
598  ],
599  ],
600  'set boolean value: FALSE' => [
601  [
602  'foo' => [
603  'bar' => [
604  'baz' => true,
605  ],
606  ],
607  ],
608  'foo/bar/baz',
609  false,
610  [
611  'foo' => [
612  'bar' => [
613  'baz' => false,
614  ],
615  ],
616  ],
617  ],
618  'set boolean value: TRUE' => [
619  [
620  'foo' => [
621  'bar' => [
622  'baz' => null,
623  ],
624  ],
625  ],
626  'foo/bar/baz',
627  true,
628  [
629  'foo' => [
630  'bar' => [
631  'baz' => true,
632  ],
633  ],
634  ],
635  ],
636  'set object value' => [
637  [
638  'foo' => [
639  'bar' => [
640  'baz' => null,
641  ],
642  ],
643  ],
644  'foo/bar/baz',
645  $testObject,
646  [
647  'foo' => [
648  'bar' => [
649  'baz' => $testObject,
650  ],
651  ],
652  ],
653  ],
654  'multi keys in array' => [
655  [
656  'foo' => [
657  'bar' => [
658  'baz' => 'value',
659  ],
660  'bar2' => [
661  'baz' => 'value',
662  ],
663  ],
664  ],
665  'foo/bar2/baz',
666  'newValue',
667  [
668  'foo' => [
669  'bar' => [
670  'baz' => 'value',
671  ],
672  'bar2' => [
673  'baz' => 'newValue',
674  ],
675  ],
676  ],
677  ],
678  'setting longer path' => [
679  [
680  'foo' => [
681  'bar' => 'value',
682  ],
683  ],
684  'foo/bar/baz/foobar',
685  'newValue',
686  [
687  'foo' => [
688  'bar' => [
689  'baz' => [
690  'foobar' => 'newValue',
691  ],
692  ],
693  ],
694  ],
695  ],
696  'setting longer path in existing array' => [
697  [
698  'foo' => [
699  'bar' => [
700  'existingKey' => 'lolli.did.this',
701  ],
702  ],
703  ],
704  'foo/bar/baz/foobar',
705  'newValue',
706  [
707  'foo' => [
708  'bar' => [
709  'existingKey' => 'lolli.did.this',
710  'baz' => [
711  'foobar' => 'newValue',
712  ],
713  ],
714  ],
715  ],
716  ],
717  ];
718  }
719 
725  #[DataProvider('setValueByPathSetsCorrectValueDataProvider')]
726  #[Test]
727  public function ‪setValueByPathSetsCorrectValue(array $array, $path, $value, $expectedResult): void
728  {
729  self::assertEquals(
730  $expectedResult,
731  ‪ArrayUtility::setValueByPath($array, $path, $value)
732  );
733  }
734 
735  /**********************
736  /* Tests concerning removeByPath
737  ***********************/
738  #[Test]
740  {
741  $this->expectException(\RuntimeException::class);
742  $this->expectExceptionCode(1371757718);
743 
745  }
746 
747  #[Test]
749  {
750  $inputArray = [
751  'foo' => [
752  'bar' => 42,
753  ],
754  ];
755 
756  $this->expectException(\RuntimeException::class);
757  $this->expectExceptionCode(1371757720);
758 
759  ‪ArrayUtility::removeByPath($inputArray, 'foo//bar');
760  }
761 
762  #[Test]
764  {
765  $inputArray = [
766  'foo' => ['bar'],
767  ];
768 
769  self::assertSame(['foo' => []], ‪ArrayUtility::removeByPath($inputArray, 'foo/0'));
770  }
771 
772  #[Test]
774  {
775  $inputArray = ['bar'];
776 
777  self::assertSame([], ‪ArrayUtility::removeByPath($inputArray, '0'));
778  }
779 
780  #[Test]
782  {
783  $inputArray = [
784  'foo' => [
785  'bar' => 42,
786  ],
787  ];
788 
789  $this->expectException(\RuntimeException::class);
790  $this->expectExceptionCode(1371758436);
791 
792  ‪ArrayUtility::removeByPath($inputArray, 'foo/baz');
793  }
794 
795  #[Test]
797  {
798  $inputArray = [
799  'foo' => [
800  'bar' => 42,
801  ],
802  ];
803 
804  $this->expectException(MissingArrayPathException::class);
805  $this->expectExceptionCode(1371758436);
806 
807  ‪ArrayUtility::removeByPath($inputArray, 'foo/baz');
808  }
809 
810  #[Test]
811  public function ‪removeByPathAcceptsGivenDelimiter(): void
812  {
813  $inputArray = [
814  'foo' => [
815  'toRemove' => 42,
816  'keep' => 23,
817  ],
818  ];
819  $path = 'foo.toRemove';
820  $expected = [
821  'foo' => [
822  'keep' => 23,
823  ],
824  ];
825  self::assertEquals(
826  $expected,
827  ‪ArrayUtility::removeByPath($inputArray, $path, '.')
828  );
829  }
830 
834  public static function ‪removeByPathRemovesCorrectPathDataProvider(): array
835  {
836  return [
837  'single value' => [
838  [
839  'foo' => [
840  'toRemove' => 42,
841  'keep' => 23,
842  ],
843  ],
844  'foo/toRemove',
845  [
846  'foo' => [
847  'keep' => 23,
848  ],
849  ],
850  ],
851  'whole array' => [
852  [
853  'foo' => [
854  'bar' => 42,
855  ],
856  ],
857  'foo',
858  [],
859  ],
860  'sub array' => [
861  [
862  'foo' => [
863  'keep' => 23,
864  'toRemove' => [
865  'foo' => 'bar',
866  ],
867  ],
868  ],
869  'foo/toRemove',
870  [
871  'foo' => [
872  'keep' => 23,
873  ],
874  ],
875  ],
876  ];
877  }
878 
883  #[DataProvider('removeByPathRemovesCorrectPathDataProvider')]
884  #[Test]
885  public function ‪removeByPathRemovesCorrectPath(array $array, $path, $expectedResult): void
886  {
887  self::assertEquals(
888  $expectedResult,
889  ‪ArrayUtility::removeByPath($array, $path)
890  );
891  }
892 
894  // Tests concerning sortByKeyRecursive
896  #[Test]
898  {
899  $unsortedArray = [
900  'z' => null,
901  'a' => null,
902  'd' => [
903  'c' => null,
904  'b' => null,
905  'd' => null,
906  'a' => null,
907  ],
908  ];
909  $expectedResult = [
910  'a' => null,
911  'd' => [
912  'a' => null,
913  'b' => null,
914  'c' => null,
915  'd' => null,
916  ],
917  'z' => null,
918  ];
919  self::assertSame($expectedResult, ‪ArrayUtility::sortByKeyRecursive($unsortedArray));
920  }
921 
923  // Tests concerning sortArraysByKey
925 
929  {
930  return [
931  'assoc array index' => [
932  [
933  '22' => [
934  'uid' => '22',
935  'title' => 'c',
936  'dummy' => 2,
937  ],
938  '24' => [
939  'uid' => '24',
940  'title' => 'a',
941  'dummy' => 3,
942  ],
943  '23' => [
944  'uid' => '23',
945  'title' => 'b',
946  'dummy' => 4,
947  ],
948  ],
949  'title',
950  true,
951  [
952  '24' => [
953  'uid' => '24',
954  'title' => 'a',
955  'dummy' => 3,
956  ],
957  '23' => [
958  'uid' => '23',
959  'title' => 'b',
960  'dummy' => 4,
961  ],
962  '22' => [
963  'uid' => '22',
964  'title' => 'c',
965  'dummy' => 2,
966  ],
967  ],
968  ],
969  'numeric array index' => [
970  [
971  22 => [
972  'uid' => '22',
973  'title' => 'c',
974  'dummy' => 2,
975  ],
976  24 => [
977  'uid' => '24',
978  'title' => 'a',
979  'dummy' => 3,
980  ],
981  23 => [
982  'uid' => '23',
983  'title' => 'b',
984  'dummy' => 4,
985  ],
986  ],
987  'title',
988  true,
989  [
990  24 => [
991  'uid' => '24',
992  'title' => 'a',
993  'dummy' => 3,
994  ],
995  23 => [
996  'uid' => '23',
997  'title' => 'b',
998  'dummy' => 4,
999  ],
1000  22 => [
1001  'uid' => '22',
1002  'title' => 'c',
1003  'dummy' => 2,
1004  ],
1005  ],
1006  ],
1007  'numeric array index DESC' => [
1008  [
1009  23 => [
1010  'uid' => '23',
1011  'title' => 'b',
1012  'dummy' => 4,
1013  ],
1014  22 => [
1015  'uid' => '22',
1016  'title' => 'c',
1017  'dummy' => 2,
1018  ],
1019  24 => [
1020  'uid' => '24',
1021  'title' => 'a',
1022  'dummy' => 3,
1023  ],
1024  ],
1025  'title',
1026  false,
1027  [
1028  22 => [
1029  'uid' => '22',
1030  'title' => 'c',
1031  'dummy' => 2,
1032  ],
1033  23 => [
1034  'uid' => '23',
1035  'title' => 'b',
1036  'dummy' => 4,
1037  ],
1038  24 => [
1039  'uid' => '24',
1040  'title' => 'a',
1041  'dummy' => 3,
1042  ],
1043  ],
1044  ],
1045  'order by integers as string' => [
1046  [
1047  0 => [
1048  'uid' => '23',
1049  'title' => 'b',
1050  'dummy' => 4,
1051  ],
1052  1 => [
1053  'uid' => '22',
1054  'title' => 'c',
1055  'dummy' => 2,
1056  ],
1057  2 => [
1058  'uid' => '24',
1059  'title' => 'a',
1060  'dummy' => 3,
1061  ],
1062  ],
1063  'uid',
1064  true,
1065  [
1066  1 => [
1067  'uid' => '22',
1068  'title' => 'c',
1069  'dummy' => 2,
1070  ],
1071  0 => [
1072  'uid' => '23',
1073  'title' => 'b',
1074  'dummy' => 4,
1075  ],
1076  2 => [
1077  'uid' => '24',
1078  'title' => 'a',
1079  'dummy' => 3,
1080  ],
1081  ],
1082  ],
1083  'order by integers' => [
1084  [
1085  0 => [
1086  'uid' => 23,
1087  'title' => 'b',
1088  'dummy' => 4,
1089  ],
1090  1 => [
1091  'uid' => 22,
1092  'title' => 'c',
1093  'dummy' => 2,
1094  ],
1095  2 => [
1096  'uid' => 24,
1097  'title' => 'a',
1098  'dummy' => 3,
1099  ],
1100  ],
1101  'uid',
1102  true,
1103  [
1104  1 => [
1105  'uid' => 22,
1106  'title' => 'c',
1107  'dummy' => 2,
1108  ],
1109  0 => [
1110  'uid' => 23,
1111  'title' => 'b',
1112  'dummy' => 4,
1113  ],
1114  2 => [
1115  'uid' => 24,
1116  'title' => 'a',
1117  'dummy' => 3,
1118  ],
1119  ],
1120  ],
1121  ];
1122  }
1123 
1129  #[DataProvider('sortArraysByKeyCheckIfSortingIsCorrectDataProvider')]
1130  #[Test]
1131  public function ‪sortArraysByKeyCheckIfSortingIsCorrect(array $array, $key, $ascending, $expectedResult): void
1132  {
1133  $sortedArray = ‪ArrayUtility::sortArraysByKey($array, $key, $ascending);
1134  self::assertSame($expectedResult, $sortedArray);
1135  }
1136 
1137  #[Test]
1139  {
1140  $this->expectException(\RuntimeException::class);
1141  $this->expectExceptionCode(1373727309);
1142 
1143  ‪ArrayUtility::sortArraysByKey([['a'], ['a']], 'dummy');
1144  }
1145 
1146  #[Test]
1148  {
1149  $this->expectException(\RuntimeException::class);
1150  $this->expectExceptionCode(1373727310);
1151 
1153  [
1154  [
1155  'uid' => '23',
1156  'value' => new \stdClass(),
1157  ],
1158  22 => [
1159  'uid' => '22',
1160  'value' => 123,
1161  ],
1162  ],
1163  'value'
1164  );
1165  }
1166 
1167  #[Test]
1169  {
1170  $this->expectException(\RuntimeException::class);
1171  $this->expectExceptionCode(1373727311);
1172 
1174  [
1175  [
1176  'uid' => '23',
1177  'value' => 123,
1178  ],
1179  22 => [
1180  'uid' => '22',
1181  'value' => [],
1182  ],
1183  ],
1184  'value'
1185  );
1186  }
1187 
1189  // Tests concerning arrayExport
1191  #[Test]
1193  {
1194  $array = [
1195  'foo' => [
1196  'bar' => 42,
1197  'bar2' => [
1198  'baz' => 'val\'ue',
1199  'baz2' => true,
1200  'baz3' => false,
1201  'baz4' => [],
1202  ],
1203  ],
1204  'baz' => 23,
1205  'foobar' => null,
1206  'qux' => 0.1,
1207  'qux2' => 0.000000001,
1208  ];
1209  $expected =
1210  '[' . LF .
1211  ' \'foo\' => [' . LF .
1212  ' \'bar\' => 42,' . LF .
1213  ' \'bar2\' => [' . LF .
1214  ' \'baz\' => \'val\\\'ue\',' . LF .
1215  ' \'baz2\' => true,' . LF .
1216  ' \'baz3\' => false,' . LF .
1217  ' \'baz4\' => [],' . LF .
1218  ' ],' . LF .
1219  ' ],' . LF .
1220  ' \'baz\' => 23,' . LF .
1221  ' \'foobar\' => null,' . LF .
1222  ' \'qux\' => 0.1,' . LF .
1223  ' \'qux2\' => 1.0E-9,' . LF .
1224  ']';
1225  self::assertSame($expected, ‪ArrayUtility::arrayExport($array));
1226  }
1227 
1228  #[Test]
1230  {
1231  $array = [
1232  'foo' => [
1233  'bar' => new \stdClass(),
1234  ],
1235  ];
1236 
1237  $this->expectException(\RuntimeException::class);
1238  $this->expectExceptionCode(1342294987);
1239 
1241  }
1242 
1243  #[Test]
1245  {
1246  $array = [
1247  'foo' => 'string key',
1248  23 => 'integer key',
1249  '42' => 'string key representing integer',
1250  ];
1251  $expected =
1252  '[' . LF .
1253  ' \'foo\' => \'string key\',' . LF .
1254  ' 23 => \'integer key\',' . LF .
1255  ' 42 => \'string key representing integer\',' . LF .
1256  ']';
1257  self::assertSame($expected, ‪ArrayUtility::arrayExport($array));
1258  }
1259 
1260  #[Test]
1262  {
1263  $array = [
1264  0 => 'zero',
1265  1 => 'one',
1266  2 => 'two',
1267  ];
1268  $expected =
1269  '[' . LF .
1270  ' \'zero\',' . LF .
1271  ' \'one\',' . LF .
1272  ' \'two\',' . LF .
1273  ']';
1274  self::assertSame($expected, ‪ArrayUtility::arrayExport($array));
1275  }
1276 
1277  #[Test]
1279  {
1280  $array = [
1281  0 => 'zero',
1282  1 => 'one',
1283  3 => 'three',
1284  4 => 'four',
1285  ];
1286  $expected =
1287  '[' . LF .
1288  ' 0 => \'zero\',' . LF .
1289  ' 1 => \'one\',' . LF .
1290  ' 3 => \'three\',' . LF .
1291  ' 4 => \'four\',' . LF .
1292  ']';
1293  self::assertSame($expected, ‪ArrayUtility::arrayExport($array));
1294  }
1295 
1296  public static function ‪flattenCalculatesExpectedResultDataProvider(): array
1297  {
1298  return [
1299  'plain array' => [
1300  [
1301  'first' => 1,
1302  'second' => 2,
1303  ],
1304  [
1305  'first' => 1,
1306  'second' => 2,
1307  ],
1308  ],
1309  'plain array with faulty dots' => [
1310  [
1311  'first.' => 1,
1312  'second.' => 2,
1313  ],
1314  [
1315  'first' => 1,
1316  'second' => 2,
1317  ],
1318  ],
1319  'nested array with integer key' => [
1320  [
1321  'templateRootPaths.' => [
1322  10 => '',
1323  ],
1324  ],
1325  [
1326  'templateRootPaths.10' => '',
1327  ],
1328  ],
1329  'nested array of 2 levels' => [
1330  [
1331  'first.' => [
1332  'firstSub' => 1,
1333  ],
1334  'second.' => [
1335  'secondSub' => 2,
1336  ],
1337  ],
1338  [
1339  'first.firstSub' => 1,
1340  'second.secondSub' => 2,
1341  ],
1342  ],
1343  'nested array of 2 levels and values on first level' => [
1344  [
1345  'first' => 'first',
1346  'first.' => [
1347  'firstSub' => 1,
1348  ],
1349  'second' => 'second',
1350  'second.' => [
1351  'secondSub' => 2,
1352  ],
1353  ],
1354  [
1355  'first' => 'first',
1356  'first.firstSub' => 1,
1357  'second' => 'second',
1358  'second.secondSub' => 2,
1359  ],
1360  ],
1361  'nested array of 2 levels with faulty dots' => [
1362  [
1363  'first.' => [
1364  'firstSub.' => 1,
1365  ],
1366  'second.' => [
1367  'secondSub.' => 2,
1368  ],
1369  ],
1370  [
1371  'first.firstSub' => 1,
1372  'second.secondSub' => 2,
1373  ],
1374  ],
1375  'nested array of 3 levels' => [
1376  [
1377  'first.' => [
1378  'firstSub.' => [
1379  'firstSubSub' => 1,
1380  ],
1381  ],
1382  'second.' => [
1383  'secondSub.' => [
1384  'secondSubSub' => 2,
1385  ],
1386  ],
1387  ],
1388  [
1389  'first.firstSub.firstSubSub' => 1,
1390  'second.secondSub.secondSubSub' => 2,
1391  ],
1392  ],
1393  'nested array of 3 levels with faulty dots' => [
1394  [
1395  'first.' => [
1396  'firstSub.' => [
1397  'firstSubSub.' => 1,
1398  ],
1399  ],
1400  'second.' => [
1401  'secondSub.' => [
1402  'secondSubSub.' => 2,
1403  ],
1404  ],
1405  ],
1406  [
1407  'first.firstSub.firstSubSub' => 1,
1408  'second.secondSub.secondSubSub' => 2,
1409  ],
1410  ],
1411  ];
1412  }
1413 
1414  #[DataProvider('flattenCalculatesExpectedResultDataProvider')]
1415  #[Test]
1416  public function ‪flattenCalculatesExpectedResult(array $array, array $expected): void
1417  {
1418  self::assertEquals($expected, ‪ArrayUtility::flatten($array));
1419  }
1420 
1422  {
1423  return [
1424  'plain array' => [
1425  [
1426  'first' => 1,
1427  'second' => 2,
1428  ],
1429  [
1430  'first' => 1,
1431  'second' => 2,
1432  ],
1433  ],
1434  'plain array with trailing dots' => [
1435  [
1436  'first.' => 1,
1437  'second.' => 2,
1438  ],
1439  [
1440  'first\.' => 1,
1441  'second\.' => 2,
1442  ],
1443  ],
1444  'nested array of 2 levels' => [
1445  [
1446  'first' => [
1447  'firstSub' => 1,
1448  ],
1449  'second' => [
1450  'secondSub' => 2,
1451  ],
1452  ],
1453  [
1454  'first.firstSub' => 1,
1455  'second.secondSub' => 2,
1456  ],
1457  ],
1458  'nested array of 2 levels with dots in keys' => [
1459  [
1460  'first.el' => [
1461  'firstSub.' => 1,
1462  ],
1463  'second.el' => [
1464  'secondSub.' => 2,
1465  ],
1466  ],
1467  [
1468  'first\.el.firstSub\.' => 1,
1469  'second\.el.secondSub\.' => 2,
1470  ],
1471  ],
1472  'nested array of 2 levels with dots inside keys' => [
1473  [
1474  'first' => [
1475  'first.sub' => 1,
1476  ],
1477  'second' => [
1478  'second.sub' => 2,
1479  ],
1480  ],
1481  [
1482  'first.first\.sub' => 1,
1483  'second.second\.sub' => 2,
1484  ],
1485  ],
1486  'nested array of 3 levels' => [
1487  [
1488  'first' => [
1489  'firstSub' => [
1490  'firstSubSub' => 1,
1491  ],
1492  ],
1493  'second' => [
1494  'secondSub' => [
1495  'secondSubSub' => 2,
1496  ],
1497  ],
1498  ],
1499  [
1500  'first.firstSub.firstSubSub' => 1,
1501  'second.secondSub.secondSubSub' => 2,
1502  ],
1503  ],
1504  'nested array of 3 levels with dots in keys' => [
1505  [
1506  'first.' => [
1507  'firstSub.' => [
1508  'firstSubSub.' => 1,
1509  ],
1510  ],
1511  'second.' => [
1512  'secondSub.' => [
1513  'secondSubSub.' => 2,
1514  ],
1515  ],
1516  ],
1517  [
1518  'first\..firstSub\..firstSubSub\.' => 1,
1519  'second\..secondSub\..secondSubSub\.' => 2,
1520  ],
1521  ],
1522  'duplicate keys, one with dot, one without' => [
1523  [
1524  'foo' => 'node',
1525  'foo.' => [
1526  'bar' => 'bla',
1527  ],
1528  ],
1529  [
1530  'foo' => 'node',
1531  'foo\..bar' => 'bla',
1532  ],
1533  ],
1534  'duplicate keys, one with dot with scalar value, one without, last wins' => [
1535  [
1536  'foo.' => 'dot',
1537  'foo' => 'node',
1538  ],
1539  [
1540  'foo\.' => 'dot',
1541  'foo' => 'node',
1542  ],
1543  ],
1544  'empty key' => [
1545  [
1546  '' => 'node',
1547  ],
1548  [
1549  '' => 'node',
1550  ],
1551  ],
1552  'dot key' => [
1553  [
1554  '.' => 'node',
1555  ],
1556  [
1557  '\.' => 'node',
1558  ],
1559  ],
1560  'empty array' => [
1561  [],
1562  [],
1563  ],
1564  'nested lists' => [
1565  [
1566  ['foo', 'bar'],
1567  ['bla', 'baz'],
1568  ],
1569  [
1570  '0.0' => 'foo',
1571  '0.1' => 'bar',
1572  '1.0' => 'bla',
1573  '1.1' => 'baz',
1574  ],
1575  ],
1576  ];
1577  }
1578 
1579  #[DataProvider('flattenPlainCalculatesExpectedResultDataProvider')]
1580  #[Test]
1581  public function ‪flattenPlainCalculatesExpectedResult(array $array, array $expected): void
1582  {
1583  self::assertEquals($expected, ‪ArrayUtility::flattenPlain($array));
1584  }
1585 
1587  {
1588  return [
1589  'plain array' => [
1590  [
1591  'first' => 1,
1592  'second' => 2,
1593  ],
1594  [
1595  'first' => 1,
1596  'second' => 2,
1597  ],
1598  ],
1599  'plain array with dots' => [
1600  [
1601  'first.' => 1,
1602  'second.' => 2,
1603  ],
1604  [
1605  'first.' => 1,
1606  'second.' => 2,
1607  ],
1608  ],
1609  'nested array of 2 levels' => [
1610  [
1611  'first.' => [
1612  'firstSub' => 1,
1613  ],
1614  'second.' => [
1615  'secondSub' => 2,
1616  ],
1617  ],
1618  [
1619  'first.firstSub' => 1,
1620  'second.secondSub' => 2,
1621  ],
1622  ],
1623  'nested array of 2 levels with dots' => [
1624  [
1625  'first.' => [
1626  'firstSub.' => 1,
1627  ],
1628  'second.' => [
1629  'secondSub.' => 2,
1630  ],
1631  ],
1632  [
1633  'first.firstSub.' => 1,
1634  'second.secondSub.' => 2,
1635  ],
1636  ],
1637  'nested array of 3 levels' => [
1638  [
1639  'first.' => [
1640  'firstSub.' => [
1641  'firstSubSub' => 1,
1642  ],
1643  ],
1644  'second.' => [
1645  'secondSub.' => [
1646  'secondSubSub' => 2,
1647  ],
1648  ],
1649  ],
1650  [
1651  'first.firstSub.firstSubSub' => 1,
1652  'second.secondSub.secondSubSub' => 2,
1653  ],
1654  ],
1655  'nested array of 3 levels with dots' => [
1656  [
1657  'first.' => [
1658  'firstSub.' => [
1659  'firstSubSub.' => 1,
1660  ],
1661  ],
1662  'second.' => [
1663  'secondSub.' => [
1664  'secondSubSub.' => 2,
1665  ],
1666  ],
1667  ],
1668  [
1669  'first.firstSub.firstSubSub.' => 1,
1670  'second.secondSub.secondSubSub.' => 2,
1671  ],
1672  ],
1673  'nested array of 3 levels with multi dots' => [
1674  [
1675  'first.' => [
1676  'firstSub..' => [
1677  'firstSubSub..' => 1,
1678  ],
1679  ],
1680  'second.' => [
1681  'secondSub..' => [
1682  'secondSubSub.' => 2,
1683  ],
1684  ],
1685  ],
1686  [
1687  'first.firstSub..firstSubSub..' => 1,
1688  'second.secondSub..secondSubSub.' => 2,
1689  ],
1690  ],
1691  ];
1692  }
1693 
1694  #[DataProvider('flattenWithKeepDotsCalculatesExpectedResultDataProvider')]
1695  #[Test]
1696  public function ‪flattenWithKeepDotsCalculatesExpectedResult(array $array, array $expected): void
1697  {
1698  self::assertEquals($expected, ‪ArrayUtility::flatten($array, '', true));
1699  }
1700 
1702  {
1703  return [
1704  'plain array' => [
1705  [
1706  'first' => 1,
1707  'second' => 2,
1708  ],
1709  [
1710  'first' => 1,
1711  'second' => 2,
1712  ],
1713  ],
1714  'plain array with trailing dots' => [
1715  [
1716  'first\.' => 1,
1717  'second\.' => 2,
1718  ],
1719  [
1720  'first.' => 1,
1721  'second.' => 2,
1722  ],
1723  ],
1724  'nested array of 2 levels' => [
1725  [
1726  'first.firstSub' => 1,
1727  'second.secondSub' => 2,
1728  ],
1729  [
1730  'first' => [
1731  'firstSub' => 1,
1732  ],
1733  'second' => [
1734  'secondSub' => 2,
1735  ],
1736  ],
1737  ],
1738  'nested array of 2 levels with dots in keys' => [
1739  [
1740  'first\.el.firstSub\.' => 1,
1741  'second\.el.secondSub\.' => 2,
1742  ],
1743  [
1744  'first.el' => [
1745  'firstSub.' => 1,
1746  ],
1747  'second.el' => [
1748  'secondSub.' => 2,
1749  ],
1750  ],
1751  ],
1752  'nested array of 2 levels with dots inside keys' => [
1753  [
1754  'first.first\.sub' => 1,
1755  'second.second\.sub' => 2,
1756  ],
1757  [
1758  'first' => [
1759  'first.sub' => 1,
1760  ],
1761  'second' => [
1762  'second.sub' => 2,
1763  ],
1764  ],
1765  ],
1766  'nested array of 3 levels' => [
1767  [
1768  'first.firstSub.firstSubSub' => 1,
1769  'second.secondSub.secondSubSub' => 2,
1770  ],
1771  [
1772  'first' => [
1773  'firstSub' => [
1774  'firstSubSub' => 1,
1775  ],
1776  ],
1777  'second' => [
1778  'secondSub' => [
1779  'secondSubSub' => 2,
1780  ],
1781  ],
1782  ],
1783  ],
1784  'nested array of 3 levels with dots in keys' => [
1785  [
1786  'first\..firstSub\..firstSubSub\.' => 1,
1787  'second\..secondSub\..secondSubSub\.' => 2,
1788  ],
1789  [
1790  'first.' => [
1791  'firstSub.' => [
1792  'firstSubSub.' => 1,
1793  ],
1794  ],
1795  'second.' => [
1796  'secondSub.' => [
1797  'secondSubSub.' => 2,
1798  ],
1799  ],
1800  ],
1801  ],
1802  'duplicate keys, one with dot, one without' => [
1803  [
1804  'foo' => 'node',
1805  'foo\..bar' => 'bla',
1806  ],
1807  [
1808  'foo' => 'node',
1809  'foo.' => [
1810  'bar' => 'bla',
1811  ],
1812  ],
1813  ],
1814  'duplicate keys, one with dot with scalar value, one without, last wins' => [
1815  [
1816  'foo\.' => 'dot',
1817  'foo' => 'node',
1818  ],
1819  [
1820  'foo.' => 'dot',
1821  'foo' => 'node',
1822  ],
1823  ],
1824  'empty key' => [
1825  [
1826  '' => 'node',
1827  ],
1828  [
1829  '' => 'node',
1830  ],
1831  ],
1832  'dot key' => [
1833  [
1834  '\.' => 'node',
1835  ],
1836  [
1837  '.' => 'node',
1838  ],
1839  ],
1840  'empty array' => [
1841  [],
1842  [],
1843  ],
1844  'nested lists' => [
1845  [
1846  '0.0' => 'foo',
1847  '0.1' => 'bar',
1848  '1.0' => 'bla',
1849  '1.1' => 'baz',
1850  ],
1851  [
1852  ['foo', 'bar'],
1853  ['bla', 'baz'],
1854  ],
1855  ],
1856  ];
1857  }
1858 
1859  #[DataProvider('unflattenCalculatesExpectedResultDataProvider')]
1860  #[Test]
1861  public function ‪unflattenCalculatesExpectedResult(array $array, array $expected): void
1862  {
1863  self::assertEquals($expected, ArrayUtility::unflatten($array));
1864  }
1865 
1867  {
1868  $sameObject = new \stdClass();
1869  return [
1870  // array($source, $mask, $expected)
1871  'empty array is returned if source is empty array' => [
1872  [],
1873  [
1874  'foo' => 'bar',
1875  ],
1876  [],
1877  ],
1878  'empty array is returned if mask is empty' => [
1879  [
1880  'foo' => 'bar',
1881  ],
1882  [],
1883  [],
1884  ],
1885  'key is kept on first level if exists in mask' => [
1886  [
1887  'foo' => 42,
1888  ],
1889  [
1890  'foo' => 42,
1891  ],
1892  [
1893  'foo' => 42,
1894  ],
1895  ],
1896  'value of key in source is kept if mask has different value' => [
1897  [
1898  'foo' => 42,
1899  ],
1900  [
1901  'foo' => new \stdClass(),
1902  ],
1903  [
1904  'foo' => 42,
1905  ],
1906  ],
1907  'key is kept on first level if according mask value is NULL' => [
1908  [
1909  'foo' => 42,
1910  ],
1911  [
1912  'foo' => null,
1913  ],
1914  [
1915  'foo' => 42,
1916  ],
1917  ],
1918  'null in source value is kept' => [
1919  [
1920  'foo' => null,
1921  ],
1922  [
1923  'foo' => 'bar',
1924  ],
1925  [
1926  'foo' => null,
1927  ],
1928  ],
1929  'mask does not add new keys' => [
1930  [
1931  'foo' => 42,
1932  ],
1933  [
1934  'foo' => 23,
1935  'bar' => [
1936  4711,
1937  ],
1938  ],
1939  [
1940  'foo' => 42,
1941  ],
1942  ],
1943  'mask does not overwrite simple values with arrays' => [
1944  [
1945  'foo' => 42,
1946  ],
1947  [
1948  'foo' => [
1949  'bar' => 23,
1950  ],
1951  ],
1952  [
1953  'foo' => 42,
1954  ],
1955  ],
1956  'key is kept on first level if according mask value is array' => [
1957  [
1958  'foo' => 42,
1959  ],
1960  [
1961  'foo' => [
1962  'bar' => 23,
1963  ],
1964  ],
1965  [
1966  'foo' => 42,
1967  ],
1968  ],
1969  'full array is kept if value is array and mask value is simple type' => [
1970  [
1971  'foo' => [
1972  'bar' => 23,
1973  ],
1974  ],
1975  [
1976  'foo' => 42,
1977  ],
1978  [
1979  'foo' => [
1980  'bar' => 23,
1981  ],
1982  ],
1983  ],
1984  'key handling is type agnostic' => [
1985  [
1986  42 => 'foo',
1987  ],
1988  [
1989  '42' => 'bar',
1990  ],
1991  [
1992  42 => 'foo',
1993  ],
1994  ],
1995  'value is same if value is object' => [
1996  [
1997  'foo' => $sameObject,
1998  ],
1999  [
2000  'foo' => 'something',
2001  ],
2002  [
2003  'foo' => $sameObject,
2004  ],
2005  ],
2006  'mask does not add simple value to result if key does not exist in source' => [
2007  [
2008  'foo' => '42',
2009  ],
2010  [
2011  'foo' => '42',
2012  'bar' => 23,
2013  ],
2014  [
2015  'foo' => '42',
2016  ],
2017  ],
2018  'array of source is kept if value of mask key exists but is no array' => [
2019  [
2020  'foo' => '42',
2021  'bar' => [
2022  'baz' => 23,
2023  ],
2024  ],
2025  [
2026  'foo' => 'value is not significant',
2027  'bar' => null,
2028  ],
2029  [
2030  'foo' => '42',
2031  'bar' => [
2032  'baz' => 23,
2033  ],
2034  ],
2035  ],
2036  'sub arrays are kept if mask has according sub array key and is similar array' => [
2037  [
2038  'first1' => 42,
2039  'first2' => [
2040  'second1' => 23,
2041  'second2' => 4711,
2042  ],
2043  ],
2044  [
2045  'first1' => 42,
2046  'first2' => [
2047  'second1' => 'exists but different',
2048  ],
2049  ],
2050  [
2051  'first1' => 42,
2052  'first2' => [
2053  'second1' => 23,
2054  ],
2055  ],
2056  ],
2057  ];
2058  }
2059 
2060  #[DataProvider('intersectRecursiveCalculatesExpectedResultDataProvider')]
2061  #[Test]
2062  public function ‪intersectRecursiveCalculatesExpectedResult(array $source, array $mask, array $expected): void
2063  {
2064  self::assertSame($expected, ArrayUtility::intersectRecursive($source, $mask));
2065  }
2066 
2068  {
2069  return [
2070  'empty array is returned if source is empty array' => [
2071  [],
2072  [],
2073  ],
2074  'returns self if array is already numerically keyed' => [
2075  [1, 2, 3],
2076  [1, 2, 3],
2077  ],
2078  'returns correctly if keys are numeric, but contains a leap' => [
2079  [0 => 'One', 1 => 'Two', 3 => 'Three'],
2080  [0 => 'One', 1 => 'Two', 2 => 'Three'],
2081  ],
2082  'returns correctly even though keys are strings but still numeric' => [
2083  ['0' => 'One', '1' => 'Two', '3' => 'Three'],
2084  [0 => 'One', 1 => 'Two', 2 => 'Three'],
2085  ],
2086  'returns correctly if just a single keys is not numeric' => [
2087  [0 => 'Zero', '1' => 'One', 'Two' => 'Two'],
2088  [0 => 'Zero', '1' => 'One', 'Two' => 'Two'],
2089  ],
2090  'returns unchanged if keys end with a dot' => [
2091  ['2.' => 'Two', '1.' => 'One', '0.' => 'Zero'],
2092  ['2.' => 'Two', '1.' => 'One', '0.' => 'Zero'],
2093  ],
2094  'return self with nested numerically keyed array' => [
2095  [
2096  'One',
2097  'Two',
2098  'Three',
2099  [
2100  'sub.One',
2101  'sub.Two',
2102  ],
2103  ],
2104  [
2105  'One',
2106  'Two',
2107  'Three',
2108  [
2109  'sub.One',
2110  'sub.Two',
2111  ],
2112  ],
2113  ],
2114  'returns correctly with nested numerically keyed array with leaps' => [
2115  [
2116  'One',
2117  'Two',
2118  'Three',
2119  [
2120  0 => 'sub.One',
2121  2 => 'sub.Two',
2122  ],
2123  ],
2124  [
2125  'One',
2126  'Two',
2127  'Three',
2128  [
2129  'sub.One',
2130  'sub.Two',
2131  ],
2132  ],
2133  ],
2134  'returns correctly with nested string-keyed array' => [
2135  [
2136  'One',
2137  'Two',
2138  'Three',
2139  [
2140  'one' => 'sub.One',
2141  'two' => 'sub.Two',
2142  ],
2143  ],
2144  [
2145  'One',
2146  'Two',
2147  'Three',
2148  [
2149  'one' => 'sub.One',
2150  'two' => 'sub.Two',
2151  ],
2152  ],
2153  ],
2154  'returns correctly with deeply nested arrays' => [
2155  [
2156  'One',
2157  'Two',
2158  [
2159  'one' => 1,
2160  'two' => 2,
2161  'three' => [
2162  2 => 'SubSubOne',
2163  5 => 'SubSubTwo',
2164  9 => [0, 1, 2],
2165  [],
2166  ],
2167  ],
2168  ],
2169  [
2170  'One',
2171  'Two',
2172  [
2173  'one' => 1,
2174  'two' => 2,
2175  'three' => [
2176  'SubSubOne',
2177  'SubSubTwo',
2178  [0, 1, 2],
2179  [],
2180  ],
2181  ],
2182  ],
2183  ],
2184  ];
2185  }
2186 
2187  #[DataProvider('renumberKeysToAvoidLeapsIfKeysAreAllNumericDataProvider')]
2188  #[Test]
2189  public function ‪renumberKeysToAvoidLeapsIfKeysAreAllNumericReturnsExpectedOrder(array $inputArray, array $expected): void
2190  {
2191  self::assertEquals($expected, ArrayUtility::renumberKeysToAvoidLeapsIfKeysAreAllNumeric($inputArray));
2192  }
2193 
2195  {
2196  return [
2197  'Override array can reset string to array' => [
2198  [
2199  'first' => [
2200  'second' => 'foo',
2201  ],
2202  ],
2203  [
2204  'first' => [
2205  'second' => ['third' => 'bar'],
2206  ],
2207  ],
2208  true,
2209  true,
2210  true,
2211  [
2212  'first' => [
2213  'second' => ['third' => 'bar'],
2214  ],
2215  ],
2216  ],
2217  'Override array does not reset array to string (weird!)' => [
2218  [
2219  'first' => [],
2220  ],
2221  [
2222  'first' => 'foo',
2223  ],
2224  true,
2225  true,
2226  true,
2227  [
2228  'first' => [], // This is rather unexpected, naive expectation: first => 'foo'
2229  ],
2230  ],
2231  'Override array does override string with null' => [
2232  [
2233  'first' => 'foo',
2234  ],
2235  [
2236  'first' => null,
2237  ],
2238  true,
2239  true,
2240  true,
2241  [
2242  'first' => null,
2243  ],
2244  ],
2245  'Override array does override null with string' => [
2246  [
2247  'first' => null,
2248  ],
2249  [
2250  'first' => 'foo',
2251  ],
2252  true,
2253  true,
2254  true,
2255  [
2256  'first' => 'foo',
2257  ],
2258  ],
2259  'Override array does override null with empty string' => [
2260  [
2261  'first' => null,
2262  ],
2263  [
2264  'first' => '',
2265  ],
2266  true,
2267  true,
2268  true,
2269  [
2270  'first' => '',
2271  ],
2272  ],
2273  'Override array does not override string with NULL if requested' => [
2274  [
2275  'first' => 'foo',
2276  ],
2277  [
2278  'first' => null,
2279  ],
2280  true,
2281  false, // no include empty values
2282  true,
2283  [
2284  'first' => 'foo',
2285  ],
2286  ],
2287  'Override array does override null with null' => [
2288  [
2289  'first' => null,
2290  ],
2291  [
2292  'first' => null,
2293  ],
2294  true,
2295  true,
2296  true,
2297  [
2298  'first' => '',
2299  ],
2300  ],
2301  'Override array can __UNSET values' => [
2302  [
2303  'first' => [
2304  'second' => 'second',
2305  'third' => 'third',
2306  ],
2307  'fifth' => [],
2308  ],
2309  [
2310  'first' => [
2311  'second' => 'overrule',
2312  'third' => '__UNSET',
2313  'fourth' => 'overrile',
2314  ],
2315  'fifth' => '__UNSET',
2316  ],
2317  true,
2318  true,
2319  true,
2320  [
2321  'first' => [
2322  'second' => 'overrule',
2323  'fourth' => 'overrile',
2324  ],
2325  ],
2326  ],
2327  'Override can add keys' => [
2328  [
2329  'first' => 'foo',
2330  ],
2331  [
2332  'second' => 'bar',
2333  ],
2334  true,
2335  true,
2336  true,
2337  [
2338  'first' => 'foo',
2339  'second' => 'bar',
2340  ],
2341  ],
2342  'Override does not add key if __UNSET' => [
2343  [
2344  'first' => 'foo',
2345  ],
2346  [
2347  'second' => '__UNSET',
2348  ],
2349  true,
2350  true,
2351  true,
2352  [
2353  'first' => 'foo',
2354  ],
2355  ],
2356  'Override does not add key if not requested' => [
2357  [
2358  'first' => 'foo',
2359  ],
2360  [
2361  'second' => 'bar',
2362  ],
2363  false, // no add keys
2364  true,
2365  true,
2366  [
2367  'first' => 'foo',
2368  ],
2369  ],
2370  'Override does not add key if not requested with add include empty values' => [
2371  [
2372  'first' => 'foo',
2373  ],
2374  [
2375  'second' => 'bar',
2376  ],
2377  false, // no add keys
2378  false, // no include empty values
2379  true,
2380  [
2381  'first' => 'foo',
2382  ],
2383  ],
2384  'Override does not override string with empty string if requested' => [
2385  [
2386  'first' => 'foo',
2387  ],
2388  [
2389  'first' => '',
2390  ],
2391  true,
2392  false, // no include empty values
2393  true,
2394  [
2395  'first' => 'foo',
2396  ],
2397  ],
2398  'Override array does merge instead of __UNSET if requested (weird!)' => [
2399  [
2400  'first' => [
2401  'second' => 'second',
2402  'third' => 'third',
2403  ],
2404  'fifth' => [],
2405  ],
2406  [
2407  'first' => [
2408  'second' => 'overrule',
2409  'third' => '__UNSET',
2410  'fourth' => 'overrile',
2411  ],
2412  'fifth' => '__UNSET',
2413  ],
2414  true,
2415  true,
2416  false,
2417  [
2418  'first' => [
2419  'second' => 'overrule',
2420  'third' => '__UNSET', // overruled
2421  'fourth' => 'overrile',
2422  ],
2423  'fifth' => [], // not overruled with string here, naive expectation: 'fifth' => '__UNSET'
2424  ],
2425  ],
2426  ];
2427  }
2428 
2437  #[DataProvider('mergeRecursiveWithOverruleCalculatesExpectedResultDataProvider')]
2438  #[Test]
2439  public function ‪mergeRecursiveWithOverruleCalculatesExpectedResult($input1, $input2, $addKeys, $includeEmptyValues, $enableUnsetFeature, $expected): void
2440  {
2441  ArrayUtility::mergeRecursiveWithOverrule($input1, $input2, $addKeys, $includeEmptyValues, $enableUnsetFeature);
2442  self::assertEquals($expected, $input1);
2443  }
2444 
2446  // Tests concerning removeArrayEntryByValue
2448  #[Test]
2450  {
2451  $inputArray = [
2452  '0' => 'test1',
2453  '1' => 'test2',
2454  '2' => 'test3',
2455  '3' => 'test2',
2456  ];
2457  $compareValue = 'test2';
2458  $expectedResult = [
2459  '0' => 'test1',
2460  '2' => 'test3',
2461  ];
2462  $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
2463  self::assertEquals($expectedResult, $actualResult);
2464  }
2465 
2466  #[Test]
2468  {
2469  $inputArray = [
2470  '0' => 'foo',
2471  '1' => [
2472  '10' => 'bar',
2473  ],
2474  '2' => 'bar',
2475  ];
2476  $compareValue = 'bar';
2477  $expectedResult = [
2478  '0' => 'foo',
2479  '1' => [],
2480  ];
2481  $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
2482  self::assertEquals($expectedResult, $actualResult);
2483  }
2484 
2485  #[Test]
2487  {
2488  $inputArray = [
2489  '0' => 'foo',
2490  '1' => '',
2491  '2' => 'bar',
2492  ];
2493  $compareValue = '';
2494  $expectedResult = [
2495  '0' => 'foo',
2496  '2' => 'bar',
2497  ];
2498  $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
2499  self::assertEquals($expectedResult, $actualResult);
2500  }
2501 
2503  // Tests concerning keepItemsInArray
2505 
2510  #[DataProvider('keepItemsInArrayWorksWithOneArgumentDataProvider')]
2511  #[Test]
2512  public function ‪keepItemsInArrayWorksWithOneArgument($search, $array, $expected): void
2513  {
2514  self::assertEquals($expected, ArrayUtility::keepItemsInArray($array, $search));
2515  }
2516 
2521  {
2522  $array = [
2523  0 => 0,
2524  'one' => 'one',
2525  'two' => 'two',
2526  'three' => 'three',
2527  ];
2528  return [
2529  'Empty argument will match "all" elements' => [null, $array, $array],
2530  'No match' => ['four', $array, []],
2531  'One match' => ['two', $array, ['two' => 'two']],
2532  'Multiple matches' => ['two,one', $array, ['one' => 'one', 'two' => 'two']],
2533  'Argument can be an array' => [['three'], $array, ['three' => 'three']],
2534  ];
2535  }
2536 
2542  #[Test]
2543  public function ‪keepItemsInArrayCanUseClosure(): void
2544  {
2545  $array = [
2546  'aa' => ['first', 'second'],
2547  'bb' => ['third', 'fourth'],
2548  'cc' => ['fifth', 'sixth'],
2549  ];
2550  $expected = ['bb' => ['third', 'fourth']];
2551  $keepItems = 'third';
2552  $match = ArrayUtility::keepItemsInArray(
2553  $array,
2554  $keepItems,
2555  static function ($value) {
2556  return $value[0];
2557  }
2558  );
2559  self::assertEquals($expected, $match);
2560  }
2561 
2563  // Tests concerning remapArrayKeys
2565  #[Test]
2567  {
2568  $array = [
2569  'one' => 'one',
2570  'two' => 'two',
2571  'three' => 'three',
2572  ];
2573  $keyMapping = [
2574  'one' => '1',
2575  'two' => '2',
2576  ];
2577  $expected = [
2578  '1' => 'one',
2579  '2' => 'two',
2580  'three' => 'three',
2581  ];
2582  ArrayUtility::remapArrayKeys($array, $keyMapping);
2583  self::assertEquals($expected, $array);
2584  }
2585 
2587  // Tests concerning arrayDiffKeyRecursive
2589  #[Test]
2591  {
2592  $array1 = [
2593  'key1' => 'value1',
2594  'key2' => 'value2',
2595  'key3' => 'value3',
2596  ];
2597  $array2 = [
2598  'key1' => 'value1',
2599  'key3' => 'value3',
2600  ];
2601  $expectedResult = [
2602  'key2' => 'value2',
2603  ];
2604  $actualResult = ArrayUtility::arrayDiffKeyRecursive($array1, $array2);
2605  self::assertEquals($expectedResult, $actualResult);
2606  }
2607 
2608  #[Test]
2610  {
2611  $array1 = [
2612  'key1' => 'value1',
2613  'key2' => [
2614  'key21' => 'value21',
2615  'key22' => 'value22',
2616  'key23' => [
2617  'key231' => 'value231',
2618  'key232' => 'value232',
2619  ],
2620  ],
2621  ];
2622  $array2 = [
2623  'key1' => 'valueDoesNotMatter',
2624  'key2' => [
2625  'key21' => 'value21',
2626  'key23' => [
2627  'key231' => 'value231',
2628  ],
2629  ],
2630  ];
2631  $expectedResult = [
2632  'key2' => [
2633  'key22' => 'value22',
2634  'key23' => [
2635  'key232' => 'value232',
2636  ],
2637  ],
2638  ];
2639  $actualResult = ArrayUtility::arrayDiffKeyRecursive($array1, $array2);
2640  self::assertEquals($expectedResult, $actualResult);
2641  }
2642 
2643  #[Test]
2645  {
2646  $array1 = [
2647  'key1' => [
2648  'key11' => 'value11',
2649  'key12' => 'value12',
2650  ],
2651  'key2' => 'value2',
2652  'key3' => 'value3',
2653  ];
2654  $array2 = [
2655  'key1' => 'value1',
2656  'key2' => [
2657  'key21' => 'valueDoesNotMatter',
2658  ],
2659  ];
2660  $expectedResult = [
2661  'key3' => 'value3',
2662  ];
2663  $actualResult = ArrayUtility::arrayDiffKeyRecursive($array1, $array2);
2664  self::assertEquals($expectedResult, $actualResult);
2665  }
2666 
2667  #[Test]
2669  {
2670  $array1 = [
2671  'key1' => [
2672  'key11' => 'value11',
2673  'key12' => 'value12',
2674  ],
2675  'key2' => 'value2',
2676  'key3' => 'value3',
2677  ];
2678  $array2 = [
2679  'key1' => [
2680  'key11' => 'valueDoesNotMatter',
2681  'key12' => 'value12',
2682  ],
2683  'key2' => 'value2',
2684  'key3' => 'value3',
2685  ];
2686  $expectedResult = [];
2687  $actualResult = ArrayUtility::arrayDiffKeyRecursive($array1, $array2);
2688  self::assertEquals($expectedResult, $actualResult);
2689  }
2690 
2692  // Tests concerning arrayDiffAssocRecursive
2694  #[Test]
2696  {
2697  $array1 = [
2698  'key1' => 'value1',
2699  'key2' => 'value2',
2700  'key3' => 'value3',
2701  ];
2702  $array2 = [
2703  'key1' => 'value1',
2704  'key3' => 'value3',
2705  ];
2706  $expectedResult = [
2707  'key2' => 'value2',
2708  ];
2709  $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2710  self::assertEquals($expectedResult, $actualResult);
2711  }
2712 
2713  #[Test]
2715  {
2716  $array1 = [
2717  'key1' => 'value1',
2718  'key2' => [
2719  'key21' => 'value21',
2720  'key22' => 'value22',
2721  'key23' => [
2722  'key231' => 'value231',
2723  'key232' => 'value232',
2724  ],
2725  ],
2726  ];
2727  $array2 = [
2728  'key1' => 'value2',
2729  'key2' => [
2730  'key21' => 'value21',
2731  'key23' => [
2732  'key231' => 'value231',
2733  ],
2734  ],
2735  ];
2736  $expectedResult = [
2737  'key1' => 'value1',
2738  'key2' => [
2739  'key22' => 'value22',
2740  'key23' => [
2741  'key232' => 'value232',
2742  ],
2743  ],
2744  ];
2745  $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2746  self::assertEquals($expectedResult, $actualResult);
2747  }
2748 
2749  #[Test]
2751  {
2752  $array1 = [
2753  'key1' => [
2754  'key11' => 'value11',
2755  'key12' => 'value12',
2756  ],
2757  'key2' => 'value2',
2758  'key3' => 'value3',
2759  ];
2760  $array2 = [
2761  'key1' => 'value1',
2762  'key2' => [
2763  'key21' => 'valueDoesNotMatter',
2764  ],
2765  ];
2766  $expectedResult = [
2767  'key2' => 'value2',
2768  'key3' => 'value3',
2769  ];
2770  $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2771  self::assertEquals($expectedResult, $actualResult);
2772  }
2773 
2774  #[Test]
2776  {
2777  $array1 = [
2778  'key1' => [
2779  'key11' => 'value11',
2780  'key12' => 'value12',
2781  ],
2782  'key2' => 'value2',
2783  'key3' => 'value3',
2784  ];
2785  $array2 = [
2786  'key1' => [
2787  'key11' => 'value11',
2788  'key12' => 'value12',
2789  ],
2790  'key2' => 'value2',
2791  'key3' => 'value3',
2792  ];
2793  $expectedResult = [];
2794  $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2795  self::assertEquals($expectedResult, $actualResult);
2796  }
2797 
2799  // Tests concerning naturalKeySortRecursive
2801  #[Test]
2803  {
2804  $testArray = [
2805  'bb' => 'bb',
2806  'ab' => 'ab',
2807  '123' => '123',
2808  'aaa' => 'aaa',
2809  'abc' => 'abc',
2810  '23' => '23',
2811  'ba' => 'ba',
2812  'bad' => 'bad',
2813  '2' => '2',
2814  'zap' => 'zap',
2815  '210' => '210',
2816  ];
2817  $expectedResult = [
2818  '2',
2819  '23',
2820  '123',
2821  '210',
2822  'aaa',
2823  'ab',
2824  'abc',
2825  'ba',
2826  'bad',
2827  'bb',
2828  'zap',
2829  ];
2830  ArrayUtility::naturalKeySortRecursive($testArray);
2831  self::assertEquals($expectedResult, array_values($testArray));
2832  }
2833 
2834  #[Test]
2836  {
2837  $testArray = [
2838  '2' => '2',
2839  'bb' => 'bb',
2840  'ab' => 'ab',
2841  '23' => '23',
2842  'aaa' => [
2843  'bb' => 'bb',
2844  'ab' => 'ab',
2845  '123' => '123',
2846  'aaa' => 'aaa',
2847  '2' => '2',
2848  'abc' => 'abc',
2849  'ba' => 'ba',
2850  '23' => '23',
2851  'bad' => [
2852  'bb' => 'bb',
2853  'ab' => 'ab',
2854  '123' => '123',
2855  'aaa' => 'aaa',
2856  'abc' => 'abc',
2857  '23' => '23',
2858  'ba' => 'ba',
2859  'bad' => 'bad',
2860  '2' => '2',
2861  'zap' => 'zap',
2862  '210' => '210',
2863  ],
2864  '210' => '210',
2865  'zap' => 'zap',
2866  ],
2867  'abc' => 'abc',
2868  'ba' => 'ba',
2869  '210' => '210',
2870  'bad' => 'bad',
2871  '123' => '123',
2872  'zap' => 'zap',
2873  ];
2874  $expectedResult = [
2875  '2',
2876  '23',
2877  '123',
2878  '210',
2879  'aaa',
2880  'ab',
2881  'abc',
2882  'ba',
2883  'bad',
2884  'bb',
2885  'zap',
2886  ];
2887  ArrayUtility::naturalKeySortRecursive($testArray);
2888  self::assertEquals($expectedResult, array_values(array_keys($testArray['aaa']['bad'])));
2889  self::assertEquals($expectedResult, array_values(array_keys($testArray['aaa'])));
2890  self::assertEquals($expectedResult, array_values(array_keys($testArray)));
2891  }
2892 
2896  public static function ‪filterAndSortByNumericKeysWithAcceptAnyKey(): array
2897  {
2898  return [
2899  'ordered list of plain numeric keys' => [
2900  'input' => [
2901  '10' => 'foo',
2902  '20' => 'bar',
2903  ],
2904  'expected' => [
2905  10,
2906  20,
2907  ],
2908  ],
2909  'unordered list of plain numeric keys' => [
2910  'input' => [
2911  '20' => 'bar',
2912  '10' => 'foo',
2913  ],
2914  'expected' => [
2915  10,
2916  20,
2917  ],
2918  ],
2919  'list of string keys' => [
2920  'input' => [
2921  '10.' => [
2922  'wrap' => 'foo',
2923  ],
2924  '20.' => [
2925  'wrap' => 'bar',
2926  ],
2927  ],
2928  'expected' => [
2929  10,
2930  20,
2931  ],
2932  ],
2933  'list of mixed keys' => [
2934  'input' => [
2935  '10' => 'foo',
2936  '20.' => [
2937  'wrap' => 'bar',
2938  ],
2939  ],
2940  'expected' => [
2941  10,
2942  20,
2943  ],
2944  ],
2945  'list of mixed keys with one not interpreted as integer' => [
2946  'input' => [
2947  '10' => 'foo',
2948  'bla20.' => [
2949  'wrap' => 'bar',
2950  ],
2951  ],
2952  'expected' => [
2953  0,
2954  10,
2955  ],
2956  ],
2957  'list of mixed keys with more than one not interpreted as integer' => [
2958  'input' => [
2959  '10' => 'foo',
2960  'bla20.' => [
2961  'wrap' => 'bar',
2962  ],
2963  'bla21.' => [
2964  'wrap' => 'foobar',
2965  ],
2966  ],
2967  'expected' => [
2968  0,
2969  10,
2970  ],
2971  ],
2972  ];
2973  }
2974 
2979  #[DataProvider('filterAndSortByNumericKeysWithAcceptAnyKey')]
2980  #[Test]
2982  {
2983  $result = ArrayUtility::filterAndSortByNumericKeys($input, true);
2984  self::assertEquals($result, $expected);
2985  }
2986 
2991  {
2992  return [
2993  'ordered list of plain numeric keys' => [
2994  'input' => [
2995  '10' => 'foo',
2996  '20' => 'bar',
2997  ],
2998  'expected' => [
2999  10,
3000  20,
3001  ],
3002  ],
3003  'unordered list of plain numeric keys' => [
3004  'input' => [
3005  '20' => 'bar',
3006  '10' => 'foo',
3007  ],
3008  'expected' => [
3009  10,
3010  20,
3011  ],
3012  ],
3013  'list of string keys' => [
3014  'input' => [
3015  '10.' => [
3016  'wrap' => 'foo',
3017  ],
3018  '20.' => [
3019  'wrap' => 'bar',
3020  ],
3021  ],
3022  'expected' => [],
3023  ],
3024  'list of mixed keys' => [
3025  'input' => [
3026  '10' => 'foo',
3027  '20.' => [
3028  'wrap' => 'bar',
3029  ],
3030  ],
3031  'expected' => [
3032  10,
3033  ],
3034  ],
3035  ];
3036  }
3037 
3042  #[DataProvider('filterAndSortByNumericKeysWithoutAcceptAnyKey')]
3043  #[Test]
3045  {
3046  $result = ArrayUtility::filterAndSortByNumericKeys($input);
3047  self::assertEquals($result, $expected);
3048  }
3049 
3053  public static function ‪sortArrayWithIntegerKeysDataProvider(): array
3054  {
3055  return [
3056  [
3057  [
3058  '20' => 'test1',
3059  '11' => 'test2',
3060  '16' => 'test3',
3061  ],
3062  [
3063  '11' => 'test2',
3064  '16' => 'test3',
3065  '20' => 'test1',
3066  ],
3067  ],
3068  [
3069  [
3070  '20' => 'test1',
3071  '16.5' => 'test2',
3072  '16' => 'test3',
3073  ],
3074  [
3075  '20' => 'test1',
3076  '16.5' => 'test2',
3077  '16' => 'test3',
3078  ],
3079  ],
3080  [
3081  [
3082  '20' => 'test20',
3083  'somestring' => 'teststring',
3084  '16' => 'test16',
3085  ],
3086  [
3087  '20' => 'test20',
3088  'somestring' => 'teststring',
3089  '16' => 'test16',
3090  ],
3091  ],
3092  ];
3093  }
3094 
3095  #[DataProvider('sortArrayWithIntegerKeysDataProvider')]
3096  #[Test]
3097  public function ‪sortArrayWithIntegerKeysSortsNumericArrays(array $arrayToSort, array $expectedArray): void
3098  {
3099  $sortedArray = ArrayUtility::sortArrayWithIntegerKeys($arrayToSort);
3100  self::assertSame($sortedArray, $expectedArray);
3101  }
3102 
3103  #[Test]
3105  {
3106  $this->expectException(\InvalidArgumentException::class);
3107  $this->expectExceptionCode(1325697085);
3108 
3109  $arrayToTest = [
3110  'roger' => '',
3111  'francine' => '',
3112  'stan' => '',
3113  ];
3114 
3115  $allowedArrayKeys = [
3116  'roger',
3117  'francine',
3118  ];
3119 
3120  ‪ArrayUtility::assertAllArrayKeysAreValid($arrayToTest, $allowedArrayKeys);
3121  }
3122 
3123  #[Test]
3125  {
3126  $arrayToTest = [
3127  'roger' => '',
3128  'francine' => '',
3129  'stan' => '',
3130  ];
3131 
3132  $allowedArrayKeys = [
3133  'roger',
3134  'francine',
3135  'stan',
3136  ];
3137 
3138  ‪ArrayUtility::assertAllArrayKeysAreValid($arrayToTest, $allowedArrayKeys);
3139  }
3140 
3141  #[Test]
3143  {
3144  $input = [
3145  20 => 'b',
3146  10 => 'a',
3147  40 => 'd',
3148  30 => 'c',
3149  50 => [
3150  20 => 'a',
3151  10 => 'b',
3152  ],
3153  ];
3154 
3155  $expected = [
3156  10 => 'a',
3157  20 => 'b',
3158  30 => 'c',
3159  40 => 'd',
3160  50 => [
3161  10 => 'b',
3162  20 => 'a',
3163  ],
3164  ];
3165 
3166  self::assertSame($expected, ArrayUtility::sortArrayWithIntegerKeysRecursive($input));
3167  }
3168 
3169  #[Test]
3171  {
3172  $input = [
3173  'b' => 'b',
3174  10 => 'a',
3175  40 => 'd',
3176  30 => 'c',
3177  ];
3178 
3179  $expected = [
3180  'b' => 'b',
3181  10 => 'a',
3182  40 => 'd',
3183  30 => 'c',
3184  ];
3185 
3186  self::assertSame($expected, ArrayUtility::sortArrayWithIntegerKeysRecursive($input));
3187  }
3188 
3189  #[Test]
3191  {
3192  $input = [
3193  20 => 'b',
3194  10 => 'a',
3195  40 => 'd',
3196  30 => 'c',
3197  50 => [
3198  20 => 'a',
3199  10 => 'b',
3200  ],
3201  ];
3202 
3203  $expected = [
3204  0 => 'b',
3205  1 => 'a',
3206  2 => 'd',
3207  3 => 'c',
3208  4 => [
3209  0 => 'a',
3210  1 => 'b',
3211  ],
3212  ];
3213 
3214  self::assertSame($expected, ‪ArrayUtility::reIndexNumericArrayKeysRecursive($input));
3215  }
3216 
3217  #[Test]
3219  {
3220  $input = [
3221  'a' => 'b',
3222  10 => 'a',
3223  40 => 'd',
3224  30 => 'c',
3225  50 => [
3226  20 => 'a',
3227  10 => 'b',
3228  ],
3229  ];
3230 
3231  $expected = [
3232  'a' => 'b',
3233  10 => 'a',
3234  40 => 'd',
3235  30 => 'c',
3236  50 => [
3237  0 => 'a',
3238  1 => 'b',
3239  ],
3240  ];
3241 
3242  self::assertSame($expected, ‪ArrayUtility::reIndexNumericArrayKeysRecursive($input));
3243  }
3244 
3245  #[Test]
3247  {
3248  $input = [
3249  'a' => 'a',
3250  'b' => [
3251  'c' => null,
3252  'd' => 'd',
3253  ],
3254  ];
3255 
3256  $expected = [
3257  'a' => 'a',
3258  'b' => [
3259  'd' => 'd',
3260  ],
3261  ];
3262 
3263  self::assertSame($expected, ‪ArrayUtility::removeNullValuesRecursive($input));
3264  }
3265 
3266  #[Test]
3268  {
3269  $input = [
3270  'a' => 'a',
3271  'b' => [
3272  'c' => '<b>i am evil</b>',
3273  'd' => 'd',
3274  ],
3275  ];
3276 
3277  $expected = [
3278  'a' => 'a',
3279  'b' => [
3280  'c' => 'i am evil',
3281  'd' => 'd',
3282  ],
3283  ];
3284 
3285  self::assertSame($expected, ArrayUtility::stripTagsFromValuesRecursive($input));
3286  }
3287 
3288  #[Test]
3290  {
3291  $testObject = new \stdClass();
3292 
3293  $input = [
3294  'stringWithTags' => '<b>i am evil</b>',
3295  'boolean' => true,
3296  'integer' => 1,
3297  'float' => 1.9,
3298  'object' => $testObject,
3299  'objectWithStringConversion' => new class () {
3303  public function __toString()
3304  {
3305  return 'i am evil <b>too</b>';
3306  }
3307  },
3308  ];
3309 
3310  $expected = [
3311  'stringWithTags' => 'i am evil',
3312  'boolean' => true,
3313  'integer' => 1,
3314  'float' => 1.9,
3315  'object' => $testObject,
3316  'objectWithStringConversion' => 'i am evil too',
3317  ];
3318 
3319  self::assertSame($expected, ArrayUtility::stripTagsFromValuesRecursive($input));
3320  }
3321 
3322  #[Test]
3324  {
3325  $input = [
3326  'a' => 'a',
3327  'b' => [
3328  'c' => 'true',
3329  'd' => 'd',
3330  ],
3331  ];
3332 
3333  $expected = [
3334  'a' => 'a',
3335  'b' => [
3336  'c' => true,
3337  'd' => 'd',
3338  ],
3339  ];
3340 
3341  self::assertSame($expected, ‪ArrayUtility::convertBooleanStringsToBooleanRecursive($input));
3342  }
3343 
3348  {
3349  return [
3350  'filter all values which will be false when converted to boolean' => [
3351  // input
3352  [
3353  true,
3354  false,
3355  'foo1' => [
3356  'bar' => [
3357  'baz' => [
3358  '1',
3359  null,
3360  '',
3361  ],
3362  '' => 1,
3363  'bbd' => 0,
3364  ],
3365  ],
3366  'foo2' => 'foo',
3367  'foo3' => '',
3368  'foo4' => [
3369  'z' => 'bar',
3370  'bar' => 0,
3371  'baz' => [
3372  'foo' => [
3373  'bar' => '',
3374  'boo' => [],
3375  'bamboo' => 5,
3376  'fooAndBoo' => [0],
3377  ],
3378  ],
3379  ],
3380  ],
3381  // expected
3382  [
3383  true,
3384  'foo1' => [
3385  'bar' => [
3386  'baz' => [
3387  '1',
3388  ],
3389  '' => 1,
3390  ],
3391  ],
3392  'foo2' => 'foo',
3393  'foo4' => [
3394  'z' => 'bar',
3395  'baz' => [
3396  'foo' => [
3397  'bamboo' => 5,
3398  ],
3399  ],
3400  ],
3401  ],
3402  ],
3403  ];
3404  }
3405 
3406  #[DataProvider('filterRecursiveFiltersFalseElementsDataProvider')]
3407  #[Test]
3408  public function ‪filterRecursiveFiltersFalseElements(array $input, array $expectedResult): void
3409  {
3410  // If no callback is supplied, all entries of array equal to FALSE (see converting to boolean) will be removed.
3411  $result = ArrayUtility::filterRecursive($input);
3412  self::assertEquals($expectedResult, $result);
3413  }
3414 
3419  {
3420  return [
3421  'filter empty values, keep zero integers' => [
3422  // input
3423  [
3424  true,
3425  false,
3426  'foo1' => [
3427  'bar' => [
3428  'baz' => [
3429  '1',
3430  null,
3431  '',
3432  ],
3433  '' => 1,
3434  'bbd' => 0,
3435  ],
3436  ],
3437  'foo2' => 'foo',
3438  'foo3' => '',
3439  'foo4' => [
3440  'z' => 'bar',
3441  'bar' => 0,
3442  'baz' => [
3443  'foo' => [
3444  'bar' => '',
3445  'boo' => [],
3446  'bamboo' => 5,
3447  'fooAndBoo' => [0],
3448  ],
3449  ],
3450  ],
3451  ],
3452  // expected
3453  [
3454  true,
3455  false,
3456  'foo1' => [
3457  'bar' => [
3458  'baz' => [
3459  '1',
3460  ],
3461  '' => 1,
3462  'bbd' => 0,
3463  ],
3464  ],
3465  'foo2' => 'foo',
3466  'foo4' => [
3467  'z' => 'bar',
3468  'bar' => 0,
3469  'baz' => [
3470  'foo' => [
3471  'bamboo' => 5,
3472  'fooAndBoo' => [0],
3473  ],
3474  ],
3475  ],
3476  ],
3477  ],
3478  ];
3479  }
3480 
3481  #[DataProvider('filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerZeroByCallbackDataProvider')]
3482  #[Test]
3483  public function ‪filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerByCallback(array $input, array $expectedResult): void
3484  {
3485  // callback filters empty strings, array and null but keeps zero integers
3486  $result = ArrayUtility::filterRecursive(
3487  $input,
3488  static function ($item) {
3489  return $item !== '' && $item !== [] && $item !== null;
3490  }
3491  );
3492  self::assertEquals($expectedResult, $result);
3493  }
3494 
3499  {
3500  $input = [
3501  'foo' => 'remove',
3502  'bar' => [
3503  'baz' => 'remove',
3504  'keep1' => 'keep',
3505  ],
3506  'keep2' => 'keep',
3507  ];
3508  $expectedResult = [
3509  'bar' => [
3510  'keep1' => 'keep',
3511  ],
3512  'keep2' => 'keep',
3513  ];
3514 
3515  return [
3516  'filter using a closure' => [
3517  $input,
3518  $expectedResult,
3519  static function ($value): bool {
3520  return is_array($value) || $value === 'keep';
3521  },
3522  ],
3523  'filter using a callable "static class-method call" as string' => [
3524  $input,
3525  $expectedResult,
3526  ArrayUtilityFilterRecursiveCallbackFixture::class . '::callbackViaStaticMethod',
3527  ],
3528  'filter using a callable "static class-method call" as array' => [
3529  $input,
3530  $expectedResult,
3531  [ArrayUtilityFilterRecursiveCallbackFixture::class, 'callbackViaStaticMethod'],
3532  ],
3533  'filter using a callable "instance-method call" as array' => [
3534  $input,
3535  $expectedResult,
3536  [new ‪ArrayUtilityFilterRecursiveCallbackFixture(), 'callbackViaInstanceMethod'],
3537  ],
3538  'only keep2 key is kept' => [
3539  $input,
3540  ['keep2' => 'keep'],
3541  static fn($key): bool => $key === 'keep2',
3542  ARRAY_FILTER_USE_KEY,
3543  ],
3544  'keys baz, keep1 and empty arrays are removed' => [
3545  $input,
3546  ['foo' => 'remove', 'keep2' => 'keep'],
3547  static fn($value, $key): bool => $value !== [] && !in_array($key, ['baz', 'keep1'], true),
3548  ARRAY_FILTER_USE_BOTH,
3549  ],
3550  ];
3551  }
3552 
3558  #[DataProvider('filterRecursiveSupportsCallableCallbackDataProvider')]
3559  #[Test]
3560  public function ‪filterRecursiveSupportsCallableCallback(array $input, array $expectedResult, callable $callback, int $mode = 0): void
3561  {
3562  $result = ArrayUtility::filterRecursive($input, $callback, $mode);
3563  self::assertEquals($expectedResult, $result);
3564  }
3565 
3570  {
3571  return [
3572  'array without string keys' => [
3573  [
3574  0 => 'value 0',
3575  1 => 'value 1',
3576  ],
3577  false,
3578  ],
3579  'array with only string keys' => [
3580  [
3581  'key 0' => 'value 0',
3582  'key 1' => 'value 1',
3583  ],
3584  true,
3585  ],
3586  'array with mixed keys' => [
3587  [
3588  0 => 'value 0',
3589  1 => 'value 1',
3590  'key 2' => 'value 2',
3591  'key 3' => 'value 3',
3592  ],
3593  true,
3594  ],
3595  ];
3596  }
3597 
3598  #[DataProvider('isAssociativeCorrectlyFindsStringKeysDataProvider')]
3599  #[Test]
3600  public function ‪isAssociativeCorrectlyFindsStringKeys(array $array, bool $expectedResult): void
3601  {
3602  $result = ‪ArrayUtility::isAssociative($array);
3603  self::assertEquals($expectedResult, $result);
3604  }
3605 
3610  {
3611  return [
3612  'merge simple lists' => [
3613  [
3614  0 => 'keep',
3615  ],
3616  [
3617  0 => 'keep',
3618  ],
3619  [
3620  0 => 'keep',
3621  1 => 'keep',
3622  ],
3623  ],
3624  'merge simple list arrays' => [
3625  [
3626  'foo' => [
3627  0 => 'keep',
3628  ],
3629  ],
3630  [
3631  'foo' => [
3632  0 => 'keep',
3633  ],
3634  ],
3635  [
3636  'foo' => [
3637  0 => 'keep',
3638  1 => 'keep',
3639  ],
3640  ],
3641  ],
3642  'merge array and simple value' => [
3643  [
3644  'foo' => [
3645  0 => 'override',
3646  ],
3647  ],
3648  [
3649  'foo' => 'keep',
3650  ],
3651  [
3652  'foo' => 'keep',
3653  ],
3654  ],
3655  'merge simple values' => [
3656  [
3657  'foo' => 'override',
3658  ],
3659  [
3660  'foo' => 'keep',
3661  ],
3662  [
3663  'foo' => 'keep',
3664  ],
3665  ],
3666  'merge new keys' => [
3667  [
3668  'foo' => 'keep',
3669  ],
3670  [
3671  'bar' => 'keep',
3672  ],
3673  [
3674  'foo' => 'keep',
3675  'bar' => 'keep',
3676  ],
3677  ],
3678  ];
3679  }
3680 
3681  #[DataProvider('replaceAndAppendScalarValuesRecursiveCorrectlyMergesArraysDataProvider')]
3682  #[Test]
3683  public function ‪replaceAndAppendScalarValuesRecursiveCorrectlyMergesArrays(array $array1, array $array2, array $expectedResult): void
3684  {
3685  $result = ‪ArrayUtility::replaceAndAppendScalarValuesRecursive($array1, $array2);
3686  self::assertEquals($expectedResult, $result);
3687  }
3688 }
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayExportReturnsNoKeyIndexForConsecutiveCountedArrays
‪arrayExportReturnsNoKeyIndexForConsecutiveCountedArrays()
Definition: ArrayUtilityTest.php:1261
‪TYPO3\CMS\Core\Utility\ArrayUtility\isAssociative
‪static bool isAssociative(array $array)
Definition: ArrayUtility.php:966
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterRecursiveFiltersFalseElementsDataProvider
‪static filterRecursiveFiltersFalseElementsDataProvider()
Definition: ArrayUtilityTest.php:3347
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\removeNullValuesRecursiveExpectRemoval
‪removeNullValuesRecursiveExpectRemoval()
Definition: ArrayUtilityTest.php:3246
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\mergeRecursiveWithOverruleCalculatesExpectedResultDataProvider
‪static mergeRecursiveWithOverruleCalculatesExpectedResultDataProvider()
Definition: ArrayUtilityTest.php:2194
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayExportReturnsNumericArrayKeys
‪arrayExportReturnsNumericArrayKeys()
Definition: ArrayUtilityTest.php:1244
‪TYPO3\CMS\Core\Utility\ArrayUtility\flattenPlain
‪static flattenPlain(array $array)
Definition: ArrayUtility.php:502
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\assertAllArrayKeysAreValidThrowsExceptionOnNotAllowedArrayKeys
‪assertAllArrayKeysAreValidThrowsExceptionOnNotAllowedArrayKeys()
Definition: ArrayUtilityTest.php:3104
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\getValueByPathThrowsExceptionIfPathIsEmpty
‪getValueByPathThrowsExceptionIfPathIsEmpty()
Definition: ArrayUtilityTest.php:230
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\getValueByPathGetsCorrectValue
‪getValueByPathGetsCorrectValue(array $array, $path, $expectedResult)
Definition: ArrayUtilityTest.php:451
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\setValueByPathThrowsExceptionIfPathSegmentIsEmpty
‪setValueByPathThrowsExceptionIfPathSegmentIsEmpty()
Definition: ArrayUtilityTest.php:489
‪TYPO3\CMS\Core\Utility\ArrayUtility\removeByPath
‪static array removeByPath(array $array, string $path, string $delimiter='/')
Definition: ArrayUtility.php:303
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\getValueByPathAcceptsDifferentDelimiter
‪getValueByPathAcceptsDifferentDelimiter()
Definition: ArrayUtilityTest.php:457
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortArrayWithIntegerKeysDataProvider
‪static sortArrayWithIntegerKeysDataProvider()
Definition: ArrayUtilityTest.php:3053
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterByValueRecursiveMatchesReferencesToSameObject
‪filterByValueRecursiveMatchesReferencesToSameObject()
Definition: ArrayUtilityTest.php:181
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterRecursiveSupportsCallableCallback
‪filterRecursiveSupportsCallableCallback(array $input, array $expectedResult, callable $callback, int $mode=0)
Definition: ArrayUtilityTest.php:3560
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\keepItemsInArrayWorksWithOneArgumentDataProvider
‪static keepItemsInArrayWorksWithOneArgumentDataProvider()
Definition: ArrayUtilityTest.php:2520
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterRecursiveSupportsCallableCallbackDataProvider
‪static filterRecursiveSupportsCallableCallbackDataProvider()
Definition: ArrayUtilityTest.php:3498
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\reIndexNumericArrayKeysRecursiveExpectNoReindexing
‪reIndexNumericArrayKeysRecursiveExpectNoReindexing()
Definition: ArrayUtilityTest.php:3218
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortByKeyRecursiveCheckIfSortingIsCorrect
‪sortByKeyRecursiveCheckIfSortingIsCorrect()
Definition: ArrayUtilityTest.php:897
‪TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException
Definition: MissingArrayPathException.php:27
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\removeByPathRemovesFirstIndexWithZeroAsPathSegment
‪removeByPathRemovesFirstIndexWithZeroAsPathSegment()
Definition: ArrayUtilityTest.php:763
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortArraysByKeyCheckIfSortingIsCorrect
‪sortArraysByKeyCheckIfSortingIsCorrect(array $array, $key, $ascending, $expectedResult)
Definition: ArrayUtilityTest.php:1131
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\removeByPathRemovesCorrectPathDataProvider
‪static removeByPathRemovesCorrectPathDataProvider()
Definition: ArrayUtilityTest.php:834
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterByValueRecursiveCorrectlyFiltersArray
‪filterByValueRecursiveCorrectlyFiltersArray($needle, $haystack, $expectedResult)
Definition: ArrayUtilityTest.php:172
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterAndSortByNumericKeysWithoutAcceptAnyKey
‪static filterAndSortByNumericKeysWithoutAcceptAnyKey()
Definition: ArrayUtilityTest.php:2990
‪TYPO3\CMS\Core\Tests\Unit\Utility
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortArraysByKeyThrowsExceptionForNonScalarKeyA
‪sortArraysByKeyThrowsExceptionForNonScalarKeyA()
Definition: ArrayUtilityTest.php:1147
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\keepItemsInArrayWorksWithOneArgument
‪keepItemsInArrayWorksWithOneArgument($search, $array, $expected)
Definition: ArrayUtilityTest.php:2512
‪TYPO3\CMS\Core\Utility\ArrayUtility\sortByKeyRecursive
‪static array sortByKeyRecursive(array $array)
Definition: ArrayUtility.php:338
‪TYPO3\CMS\Core\Utility\ArrayUtility\replaceAndAppendScalarValuesRecursive
‪static replaceAndAppendScalarValuesRecursive(array $array1, array $array2)
Definition: ArrayUtility.php:977
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\getValueByPathThrowsExceptionIfPathNotExists
‪getValueByPathThrowsExceptionIfPathNotExists(array $array, $path)
Definition: ArrayUtilityTest.php:323
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\setValueByPathCanUseZeroAsPath
‪setValueByPathCanUseZeroAsPath()
Definition: ArrayUtilityTest.php:504
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\mergeRecursiveWithOverruleCalculatesExpectedResult
‪mergeRecursiveWithOverruleCalculatesExpectedResult($input1, $input2, $addKeys, $includeEmptyValues, $enableUnsetFeature, $expected)
Definition: ArrayUtilityTest.php:2439
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\removeByPathRemovesCorrectPath
‪removeByPathRemovesCorrectPath(array $array, $path, $expectedResult)
Definition: ArrayUtilityTest.php:885
‪TYPO3\CMS\Core\Utility\ArrayUtility\arrayExport
‪static string arrayExport(array $array=[], int $level=0)
Definition: ArrayUtility.php:392
‪TYPO3\CMS\Core\Utility\ArrayUtility\isValidPath
‪static bool isValidPath(array $array, array|string $path, string $delimiter='/')
Definition: ArrayUtility.php:141
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\removeByPathThrowsExceptionIfPathDoesNotExistInArray
‪removeByPathThrowsExceptionIfPathDoesNotExistInArray()
Definition: ArrayUtilityTest.php:781
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffKeyRecursiveReturnsEmptyIfEqual
‪arrayDiffKeyRecursiveReturnsEmptyIfEqual()
Definition: ArrayUtilityTest.php:2668
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest
Definition: ArrayUtilityTest.php:31
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\naturalKeySortRecursiveSortsMultiDimensionalArrayByNaturalOrder
‪naturalKeySortRecursiveSortsMultiDimensionalArrayByNaturalOrder()
Definition: ArrayUtilityTest.php:2835
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortArrayWithIntegerKeysSortsNumericArrays
‪sortArrayWithIntegerKeysSortsNumericArrays(array $arrayToSort, array $expectedArray)
Definition: ArrayUtilityTest.php:3097
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayExportReturnsKeyIndexForNonConsecutiveCountedArrays
‪arrayExportReturnsKeyIndexForNonConsecutiveCountedArrays()
Definition: ArrayUtilityTest.php:1278
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffKeyRecursiveHandlesOneDimensionalArrays
‪arrayDiffKeyRecursiveHandlesOneDimensionalArrays()
Definition: ArrayUtilityTest.php:2590
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\removeByPathAcceptsGivenDelimiter
‪removeByPathAcceptsGivenDelimiter()
Definition: ArrayUtilityTest.php:811
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\unflattenCalculatesExpectedResult
‪unflattenCalculatesExpectedResult(array $array, array $expected)
Definition: ArrayUtilityTest.php:1861
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\flattenWithKeepDotsCalculatesExpectedResult
‪flattenWithKeepDotsCalculatesExpectedResult(array $array, array $expected)
Definition: ArrayUtilityTest.php:1696
‪TYPO3\CMS\Core\Utility\ArrayUtility\getValueByPath
‪static getValueByPath(array $array, array|string $path, string $delimiter='/')
Definition: ArrayUtility.php:176
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortArrayWithIntegerKeysRecursiveExpectSorting
‪sortArrayWithIntegerKeysRecursiveExpectSorting()
Definition: ArrayUtilityTest.php:3142
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\isValidPathReturnsTrueIfPathExistsStringVersion
‪isValidPathReturnsTrueIfPathExistsStringVersion()
Definition: ArrayUtilityTest.php:203
‪TYPO3\CMS\Core\Utility\ArrayUtility\flatten
‪static flatten(array $array, string $prefix='', bool $keepDots=false)
Definition: ArrayUtility.php:475
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\stripTagsFromValuesRecursiveExpectRemoval
‪stripTagsFromValuesRecursiveExpectRemoval()
Definition: ArrayUtilityTest.php:3267
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortArraysByKeyCheckIfSortingIsCorrectDataProvider
‪static sortArraysByKeyCheckIfSortingIsCorrectDataProvider()
Definition: ArrayUtilityTest.php:928
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\reIndexNumericArrayKeysRecursiveExpectReindexing
‪reIndexNumericArrayKeysRecursiveExpectReindexing()
Definition: ArrayUtilityTest.php:3190
‪TYPO3\CMS\Core\Tests\Unit\Utility\Fixtures\ArrayUtilityFilterRecursiveCallbackFixture
Definition: ArrayUtilityFilterRecursiveCallbackFixture.php:24
‪TYPO3\CMS\Core\Utility\ArrayUtility\removeNullValuesRecursive
‪static removeNullValuesRecursive(array $array)
Definition: ArrayUtility.php:222
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterAndSortByNumericKeysBehavesCorrectlyForAcceptAnyKeysIsTrue
‪filterAndSortByNumericKeysBehavesCorrectlyForAcceptAnyKeysIsTrue($input, $expected)
Definition: ArrayUtilityTest.php:2981
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\removeByPathThrowsExceptionWithEmptyPathSegment
‪removeByPathThrowsExceptionWithEmptyPathSegment()
Definition: ArrayUtilityTest.php:748
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\intersectRecursiveCalculatesExpectedResult
‪intersectRecursiveCalculatesExpectedResult(array $source, array $mask, array $expected)
Definition: ArrayUtilityTest.php:2062
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortArraysByKeyThrowsExceptionForNonExistingKey
‪sortArraysByKeyThrowsExceptionForNonExistingKey()
Definition: ArrayUtilityTest.php:1138
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\flattenCalculatesExpectedResult
‪flattenCalculatesExpectedResult(array $array, array $expected)
Definition: ArrayUtilityTest.php:1416
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterAndSortByNumericKeysWithAcceptAnyKey
‪static filterAndSortByNumericKeysWithAcceptAnyKey()
Definition: ArrayUtilityTest.php:2896
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\removeByPathRemovesFirstIndexWithZeroAsPath
‪removeByPathRemovesFirstIndexWithZeroAsPath()
Definition: ArrayUtilityTest.php:773
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\getValueByPathThrowsSpecificExceptionIfPathNotExists
‪getValueByPathThrowsSpecificExceptionIfPathNotExists(array $array, string $path)
Definition: ArrayUtilityTest.php:332
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\getValueByPathReturnsFirstIndexIfPathSegmentIsZero
‪getValueByPathReturnsFirstIndexIfPathSegmentIsZero()
Definition: ArrayUtilityTest.php:245
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\flattenPlainCalculatesExpectedResultDataProvider
‪static flattenPlainCalculatesExpectedResultDataProvider()
Definition: ArrayUtilityTest.php:1421
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\stripTagsFromValuesRecursiveExpectNoTypeCast
‪stripTagsFromValuesRecursiveExpectNoTypeCast()
Definition: ArrayUtilityTest.php:3289
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\setValueByPathThrowsExceptionIfPathIsEmpty
‪setValueByPathThrowsExceptionIfPathIsEmpty()
Definition: ArrayUtilityTest.php:480
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\isAssociativeCorrectlyFindsStringKeys
‪isAssociativeCorrectlyFindsStringKeys(array $array, bool $expectedResult)
Definition: ArrayUtilityTest.php:3600
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffAssocRecursiveHandlesOneDimensionalArrays
‪arrayDiffAssocRecursiveHandlesOneDimensionalArrays()
Definition: ArrayUtilityTest.php:2695
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\convertBooleanStringsToBooleanRecursiveExpectConverting
‪convertBooleanStringsToBooleanRecursiveExpectConverting()
Definition: ArrayUtilityTest.php:3323
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\flattenWithKeepDotsCalculatesExpectedResultDataProvider
‪static flattenWithKeepDotsCalculatesExpectedResultDataProvider()
Definition: ArrayUtilityTest.php:1586
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerZeroByCallbackDataProvider
‪static filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerZeroByCallbackDataProvider()
Definition: ArrayUtilityTest.php:3418
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\setValueByPathCanUseZeroAsPathSegment
‪setValueByPathCanUseZeroAsPathSegment()
Definition: ArrayUtilityTest.php:498
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\assertAllArrayKeysAreValidReturnsNullOnAllowedArrayKeys
‪assertAllArrayKeysAreValidReturnsNullOnAllowedArrayKeys()
Definition: ArrayUtilityTest.php:3124
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\checkRemoveArrayEntryByValueRemovesEntryWithEmptyString
‪checkRemoveArrayEntryByValueRemovesEntryWithEmptyString()
Definition: ArrayUtilityTest.php:2486
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\unflattenCalculatesExpectedResultDataProvider
‪static unflattenCalculatesExpectedResultDataProvider()
Definition: ArrayUtilityTest.php:1701
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\flattenPlainCalculatesExpectedResult
‪flattenPlainCalculatesExpectedResult(array $array, array $expected)
Definition: ArrayUtilityTest.php:1581
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\removeByPathThrowsExceptionIfPathIsEmpty
‪removeByPathThrowsExceptionIfPathIsEmpty()
Definition: ArrayUtilityTest.php:739
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\intersectRecursiveCalculatesExpectedResultDataProvider
‪static intersectRecursiveCalculatesExpectedResultDataProvider()
Definition: ArrayUtilityTest.php:1866
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayExportReturnsFormattedMultidimensionalArray
‪arrayExportReturnsFormattedMultidimensionalArray()
Definition: ArrayUtilityTest.php:1192
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterByValueRecursiveDoesNotMatchDifferentInstancesOfSameClass
‪filterByValueRecursiveDoesNotMatchDifferentInstancesOfSameClass()
Definition: ArrayUtilityTest.php:191
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\remapArrayKeysExchangesKeysWithGivenMapping
‪remapArrayKeysExchangesKeysWithGivenMapping()
Definition: ArrayUtilityTest.php:2566
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\isValidPathReturnsTrueIfPathExistsArrayVersion
‪isValidPathReturnsTrueIfPathExistsArrayVersion()
Definition: ArrayUtilityTest.php:215
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\getValueByPathInvalidPathDataProvider
‪static getValueByPathInvalidPathDataProvider()
Definition: ArrayUtilityTest.php:257
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterByValueRecursive
‪static filterByValueRecursive()
Definition: ArrayUtilityTest.php:43
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\checkRemoveArrayEntryByValueRemovesEntriesFromOneDimensionalArray
‪checkRemoveArrayEntryByValueRemovesEntriesFromOneDimensionalArray()
Definition: ArrayUtilityTest.php:2449
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\checkRemoveArrayEntryByValueRemovesEntriesFromMultiDimensionalArray
‪checkRemoveArrayEntryByValueRemovesEntriesFromMultiDimensionalArray()
Definition: ArrayUtilityTest.php:2467
‪TYPO3\CMS\Core\Utility\ArrayUtility\filterByValueRecursive
‪static array filterByValueRecursive(mixed $needle='', array $haystack=[])
Definition: ArrayUtility.php:101
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:26
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\setValueByPathSetsCorrectValue
‪setValueByPathSetsCorrectValue(array $array, $path, $value, $expectedResult)
Definition: ArrayUtilityTest.php:727
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\getValueByPathValidDataProvider
‪static getValueByPathValidDataProvider()
Definition: ArrayUtilityTest.php:346
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\isValidPathReturnsFalseIfPathDoesNotExistArrayVersion
‪isValidPathReturnsFalseIfPathDoesNotExistArrayVersion()
Definition: ArrayUtilityTest.php:221
‪TYPO3\CMS\Core\Utility\ArrayUtility\reIndexNumericArrayKeysRecursive
‪static reIndexNumericArrayKeysRecursive(array $array)
Definition: ArrayUtility.php:204
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortArrayWithIntegerKeysRecursiveExpectNoSorting
‪sortArrayWithIntegerKeysRecursiveExpectNoSorting()
Definition: ArrayUtilityTest.php:3170
‪TYPO3\CMS\Core\Utility\ArrayUtility\assertAllArrayKeysAreValid
‪static assertAllArrayKeysAreValid(array $arrayToTest, array $allowedArrayKeys)
Definition: ArrayUtility.php:33
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\isValidPathReturnsFalseIfPathDoesNotExistStringVersion
‪isValidPathReturnsFalseIfPathDoesNotExistStringVersion()
Definition: ArrayUtilityTest.php:209
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\removeByPathThrowsSpecificExceptionIfPathDoesNotExistInArray
‪removeByPathThrowsSpecificExceptionIfPathDoesNotExistInArray()
Definition: ArrayUtilityTest.php:796
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterRecursiveFiltersFalseElements
‪filterRecursiveFiltersFalseElements(array $input, array $expectedResult)
Definition: ArrayUtilityTest.php:3408
‪TYPO3\CMS\Core\Utility\ArrayUtility\sortArraysByKey
‪static array sortArraysByKey(array $arrays, string $key, bool $ascending=true)
Definition: ArrayUtility.php:358
‪TYPO3\CMS\Core\Utility\ArrayUtility\setValueByPath
‪static array setValueByPath(array $array, string|array|\ArrayAccess $path, mixed $value, string $delimiter='/')
Definition: ArrayUtility.php:261
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffKeyRecursiveHandlesMixedArrays
‪arrayDiffKeyRecursiveHandlesMixedArrays()
Definition: ArrayUtilityTest.php:2644
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\keepItemsInArrayCanUseClosure
‪keepItemsInArrayCanUseClosure()
Definition: ArrayUtilityTest.php:2543
‪TYPO3\CMS\Core\Utility\ArrayUtility\convertBooleanStringsToBooleanRecursive
‪static convertBooleanStringsToBooleanRecursive(array $array)
Definition: ArrayUtility.php:51
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffAssocRecursiveReturnsEmptyIfEqual
‪arrayDiffAssocRecursiveReturnsEmptyIfEqual()
Definition: ArrayUtilityTest.php:2775
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffAssocRecursiveHandlesMixedArrays
‪arrayDiffAssocRecursiveHandlesMixedArrays()
Definition: ArrayUtilityTest.php:2750
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\renumberKeysToAvoidLeapsIfKeysAreAllNumericReturnsExpectedOrder
‪renumberKeysToAvoidLeapsIfKeysAreAllNumericReturnsExpectedOrder(array $inputArray, array $expected)
Definition: ArrayUtilityTest.php:2189
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\naturalKeySortRecursiveSortsOneDimensionalArrayByNaturalOrder
‪naturalKeySortRecursiveSortsOneDimensionalArrayByNaturalOrder()
Definition: ArrayUtilityTest.php:2802
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\isAssociativeCorrectlyFindsStringKeysDataProvider
‪static isAssociativeCorrectlyFindsStringKeysDataProvider()
Definition: ArrayUtilityTest.php:3569
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortArraysByKeyThrowsExceptionForNonScalarKeyB
‪sortArraysByKeyThrowsExceptionForNonScalarKeyB()
Definition: ArrayUtilityTest.php:1168
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\flattenCalculatesExpectedResultDataProvider
‪static flattenCalculatesExpectedResultDataProvider()
Definition: ArrayUtilityTest.php:1296
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\getValueByPathReturnsFirstIndexIfPathIsZero
‪getValueByPathReturnsFirstIndexIfPathIsZero()
Definition: ArrayUtilityTest.php:239
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\setValueByPathSetsCorrectValueDataProvider
‪static setValueByPathSetsCorrectValueDataProvider()
Definition: ArrayUtilityTest.php:518
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffAssocRecursiveHandlesMultiDimensionalArrays
‪arrayDiffAssocRecursiveHandlesMultiDimensionalArrays()
Definition: ArrayUtilityTest.php:2714
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffKeyRecursiveHandlesMultiDimensionalArrays
‪arrayDiffKeyRecursiveHandlesMultiDimensionalArrays()
Definition: ArrayUtilityTest.php:2609
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\replaceAndAppendScalarValuesRecursiveCorrectlyMergesArraysDataProvider
‪static replaceAndAppendScalarValuesRecursiveCorrectlyMergesArraysDataProvider()
Definition: ArrayUtilityTest.php:3609
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\renumberKeysToAvoidLeapsIfKeysAreAllNumericDataProvider
‪static renumberKeysToAvoidLeapsIfKeysAreAllNumericDataProvider()
Definition: ArrayUtilityTest.php:2067
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerByCallback
‪filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerByCallback(array $input, array $expectedResult)
Definition: ArrayUtilityTest.php:3483
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\replaceAndAppendScalarValuesRecursiveCorrectlyMergesArrays
‪replaceAndAppendScalarValuesRecursiveCorrectlyMergesArrays(array $array1, array $array2, array $expectedResult)
Definition: ArrayUtilityTest.php:3683
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterAndSortByNumericKeysBehavesCorrectlyForAcceptAnyKeysIsFalse
‪filterAndSortByNumericKeysBehavesCorrectlyForAcceptAnyKeysIsFalse($input, $expected)
Definition: ArrayUtilityTest.php:3044
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayExportThrowsExceptionIfObjectShouldBeExported
‪arrayExportThrowsExceptionIfObjectShouldBeExported()
Definition: ArrayUtilityTest.php:1229