‪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  ];
1046  }
1047 
1053  #[DataProvider('sortArraysByKeyCheckIfSortingIsCorrectDataProvider')]
1054  #[Test]
1055  public function ‪sortArraysByKeyCheckIfSortingIsCorrect(array $array, $key, $ascending, $expectedResult): void
1056  {
1057  $sortedArray = ‪ArrayUtility::sortArraysByKey($array, $key, $ascending);
1058  self::assertSame($expectedResult, $sortedArray);
1059  }
1060 
1061  #[Test]
1063  {
1064  $this->expectException(\RuntimeException::class);
1065  $this->expectExceptionCode(1373727309);
1066 
1067  ‪ArrayUtility::sortArraysByKey([['a'], ['a']], 'dummy');
1068  }
1069 
1071  // Tests concerning arrayExport
1073  #[Test]
1075  {
1076  $array = [
1077  'foo' => [
1078  'bar' => 42,
1079  'bar2' => [
1080  'baz' => 'val\'ue',
1081  'baz2' => true,
1082  'baz3' => false,
1083  'baz4' => [],
1084  ],
1085  ],
1086  'baz' => 23,
1087  'foobar' => null,
1088  'qux' => 0.1,
1089  'qux2' => 0.000000001,
1090  ];
1091  $expected =
1092  '[' . LF .
1093  ' \'foo\' => [' . LF .
1094  ' \'bar\' => 42,' . LF .
1095  ' \'bar2\' => [' . LF .
1096  ' \'baz\' => \'val\\\'ue\',' . LF .
1097  ' \'baz2\' => true,' . LF .
1098  ' \'baz3\' => false,' . LF .
1099  ' \'baz4\' => [],' . LF .
1100  ' ],' . LF .
1101  ' ],' . LF .
1102  ' \'baz\' => 23,' . LF .
1103  ' \'foobar\' => null,' . LF .
1104  ' \'qux\' => 0.1,' . LF .
1105  ' \'qux2\' => 1.0E-9,' . LF .
1106  ']';
1107  self::assertSame($expected, ‪ArrayUtility::arrayExport($array));
1108  }
1109 
1110  #[Test]
1112  {
1113  $array = [
1114  'foo' => [
1115  'bar' => new \stdClass(),
1116  ],
1117  ];
1118 
1119  $this->expectException(\RuntimeException::class);
1120  $this->expectExceptionCode(1342294987);
1121 
1123  }
1124 
1125  #[Test]
1127  {
1128  $array = [
1129  'foo' => 'string key',
1130  23 => 'integer key',
1131  '42' => 'string key representing integer',
1132  ];
1133  $expected =
1134  '[' . LF .
1135  ' \'foo\' => \'string key\',' . LF .
1136  ' 23 => \'integer key\',' . LF .
1137  ' 42 => \'string key representing integer\',' . LF .
1138  ']';
1139  self::assertSame($expected, ‪ArrayUtility::arrayExport($array));
1140  }
1141 
1142  #[Test]
1144  {
1145  $array = [
1146  0 => 'zero',
1147  1 => 'one',
1148  2 => 'two',
1149  ];
1150  $expected =
1151  '[' . LF .
1152  ' \'zero\',' . LF .
1153  ' \'one\',' . LF .
1154  ' \'two\',' . LF .
1155  ']';
1156  self::assertSame($expected, ‪ArrayUtility::arrayExport($array));
1157  }
1158 
1159  #[Test]
1161  {
1162  $array = [
1163  0 => 'zero',
1164  1 => 'one',
1165  3 => 'three',
1166  4 => 'four',
1167  ];
1168  $expected =
1169  '[' . LF .
1170  ' 0 => \'zero\',' . LF .
1171  ' 1 => \'one\',' . LF .
1172  ' 3 => \'three\',' . LF .
1173  ' 4 => \'four\',' . LF .
1174  ']';
1175  self::assertSame($expected, ‪ArrayUtility::arrayExport($array));
1176  }
1177 
1178  public static function ‪flattenCalculatesExpectedResultDataProvider(): array
1179  {
1180  return [
1181  'plain array' => [
1182  [
1183  'first' => 1,
1184  'second' => 2,
1185  ],
1186  [
1187  'first' => 1,
1188  'second' => 2,
1189  ],
1190  ],
1191  'plain array with faulty dots' => [
1192  [
1193  'first.' => 1,
1194  'second.' => 2,
1195  ],
1196  [
1197  'first' => 1,
1198  'second' => 2,
1199  ],
1200  ],
1201  'nested array with integer key' => [
1202  [
1203  'templateRootPaths.' => [
1204  10 => '',
1205  ],
1206  ],
1207  [
1208  'templateRootPaths.10' => '',
1209  ],
1210  ],
1211  'nested array of 2 levels' => [
1212  [
1213  'first.' => [
1214  'firstSub' => 1,
1215  ],
1216  'second.' => [
1217  'secondSub' => 2,
1218  ],
1219  ],
1220  [
1221  'first.firstSub' => 1,
1222  'second.secondSub' => 2,
1223  ],
1224  ],
1225  'nested array of 2 levels and values on first level' => [
1226  [
1227  'first' => 'first',
1228  'first.' => [
1229  'firstSub' => 1,
1230  ],
1231  'second' => 'second',
1232  'second.' => [
1233  'secondSub' => 2,
1234  ],
1235  ],
1236  [
1237  'first' => 'first',
1238  'first.firstSub' => 1,
1239  'second' => 'second',
1240  'second.secondSub' => 2,
1241  ],
1242  ],
1243  'nested array of 2 levels with faulty dots' => [
1244  [
1245  'first.' => [
1246  'firstSub.' => 1,
1247  ],
1248  'second.' => [
1249  'secondSub.' => 2,
1250  ],
1251  ],
1252  [
1253  'first.firstSub' => 1,
1254  'second.secondSub' => 2,
1255  ],
1256  ],
1257  'nested array of 3 levels' => [
1258  [
1259  'first.' => [
1260  'firstSub.' => [
1261  'firstSubSub' => 1,
1262  ],
1263  ],
1264  'second.' => [
1265  'secondSub.' => [
1266  'secondSubSub' => 2,
1267  ],
1268  ],
1269  ],
1270  [
1271  'first.firstSub.firstSubSub' => 1,
1272  'second.secondSub.secondSubSub' => 2,
1273  ],
1274  ],
1275  'nested array of 3 levels with faulty dots' => [
1276  [
1277  'first.' => [
1278  'firstSub.' => [
1279  'firstSubSub.' => 1,
1280  ],
1281  ],
1282  'second.' => [
1283  'secondSub.' => [
1284  'secondSubSub.' => 2,
1285  ],
1286  ],
1287  ],
1288  [
1289  'first.firstSub.firstSubSub' => 1,
1290  'second.secondSub.secondSubSub' => 2,
1291  ],
1292  ],
1293  ];
1294  }
1295 
1296  #[DataProvider('flattenCalculatesExpectedResultDataProvider')]
1297  #[Test]
1298  public function ‪flattenCalculatesExpectedResult(array $array, array $expected): void
1299  {
1300  self::assertEquals($expected, ‪ArrayUtility::flatten($array));
1301  }
1302 
1304  {
1305  return [
1306  'plain array' => [
1307  [
1308  'first' => 1,
1309  'second' => 2,
1310  ],
1311  [
1312  'first' => 1,
1313  'second' => 2,
1314  ],
1315  ],
1316  'plain array with trailing dots' => [
1317  [
1318  'first.' => 1,
1319  'second.' => 2,
1320  ],
1321  [
1322  'first\.' => 1,
1323  'second\.' => 2,
1324  ],
1325  ],
1326  'nested array of 2 levels' => [
1327  [
1328  'first' => [
1329  'firstSub' => 1,
1330  ],
1331  'second' => [
1332  'secondSub' => 2,
1333  ],
1334  ],
1335  [
1336  'first.firstSub' => 1,
1337  'second.secondSub' => 2,
1338  ],
1339  ],
1340  'nested array of 2 levels with dots in keys' => [
1341  [
1342  'first.el' => [
1343  'firstSub.' => 1,
1344  ],
1345  'second.el' => [
1346  'secondSub.' => 2,
1347  ],
1348  ],
1349  [
1350  'first\.el.firstSub\.' => 1,
1351  'second\.el.secondSub\.' => 2,
1352  ],
1353  ],
1354  'nested array of 2 levels with dots inside keys' => [
1355  [
1356  'first' => [
1357  'first.sub' => 1,
1358  ],
1359  'second' => [
1360  'second.sub' => 2,
1361  ],
1362  ],
1363  [
1364  'first.first\.sub' => 1,
1365  'second.second\.sub' => 2,
1366  ],
1367  ],
1368  'nested array of 3 levels' => [
1369  [
1370  'first' => [
1371  'firstSub' => [
1372  'firstSubSub' => 1,
1373  ],
1374  ],
1375  'second' => [
1376  'secondSub' => [
1377  'secondSubSub' => 2,
1378  ],
1379  ],
1380  ],
1381  [
1382  'first.firstSub.firstSubSub' => 1,
1383  'second.secondSub.secondSubSub' => 2,
1384  ],
1385  ],
1386  'nested array of 3 levels with dots in keys' => [
1387  [
1388  'first.' => [
1389  'firstSub.' => [
1390  'firstSubSub.' => 1,
1391  ],
1392  ],
1393  'second.' => [
1394  'secondSub.' => [
1395  'secondSubSub.' => 2,
1396  ],
1397  ],
1398  ],
1399  [
1400  'first\..firstSub\..firstSubSub\.' => 1,
1401  'second\..secondSub\..secondSubSub\.' => 2,
1402  ],
1403  ],
1404  'duplicate keys, one with dot, one without' => [
1405  [
1406  'foo' => 'node',
1407  'foo.' => [
1408  'bar' => 'bla',
1409  ],
1410  ],
1411  [
1412  'foo' => 'node',
1413  'foo\..bar' => 'bla',
1414  ],
1415  ],
1416  'duplicate keys, one with dot with scalar value, one without, last wins' => [
1417  [
1418  'foo.' => 'dot',
1419  'foo' => 'node',
1420  ],
1421  [
1422  'foo\.' => 'dot',
1423  'foo' => 'node',
1424  ],
1425  ],
1426  'empty key' => [
1427  [
1428  '' => 'node',
1429  ],
1430  [
1431  '' => 'node',
1432  ],
1433  ],
1434  'dot key' => [
1435  [
1436  '.' => 'node',
1437  ],
1438  [
1439  '\.' => 'node',
1440  ],
1441  ],
1442  'empty array' => [
1443  [],
1444  [],
1445  ],
1446  'nested lists' => [
1447  [
1448  ['foo', 'bar'],
1449  ['bla', 'baz'],
1450  ],
1451  [
1452  '0.0' => 'foo',
1453  '0.1' => 'bar',
1454  '1.0' => 'bla',
1455  '1.1' => 'baz',
1456  ],
1457  ],
1458  ];
1459  }
1460 
1461  #[DataProvider('flattenPlainCalculatesExpectedResultDataProvider')]
1462  #[Test]
1463  public function ‪flattenPlainCalculatesExpectedResult(array $array, array $expected): void
1464  {
1465  self::assertEquals($expected, ‪ArrayUtility::flattenPlain($array));
1466  }
1467 
1469  {
1470  return [
1471  'plain array' => [
1472  [
1473  'first' => 1,
1474  'second' => 2,
1475  ],
1476  [
1477  'first' => 1,
1478  'second' => 2,
1479  ],
1480  ],
1481  'plain array with dots' => [
1482  [
1483  'first.' => 1,
1484  'second.' => 2,
1485  ],
1486  [
1487  'first.' => 1,
1488  'second.' => 2,
1489  ],
1490  ],
1491  'nested array of 2 levels' => [
1492  [
1493  'first.' => [
1494  'firstSub' => 1,
1495  ],
1496  'second.' => [
1497  'secondSub' => 2,
1498  ],
1499  ],
1500  [
1501  'first.firstSub' => 1,
1502  'second.secondSub' => 2,
1503  ],
1504  ],
1505  'nested array of 2 levels with dots' => [
1506  [
1507  'first.' => [
1508  'firstSub.' => 1,
1509  ],
1510  'second.' => [
1511  'secondSub.' => 2,
1512  ],
1513  ],
1514  [
1515  'first.firstSub.' => 1,
1516  'second.secondSub.' => 2,
1517  ],
1518  ],
1519  'nested array of 3 levels' => [
1520  [
1521  'first.' => [
1522  'firstSub.' => [
1523  'firstSubSub' => 1,
1524  ],
1525  ],
1526  'second.' => [
1527  'secondSub.' => [
1528  'secondSubSub' => 2,
1529  ],
1530  ],
1531  ],
1532  [
1533  'first.firstSub.firstSubSub' => 1,
1534  'second.secondSub.secondSubSub' => 2,
1535  ],
1536  ],
1537  'nested array of 3 levels with dots' => [
1538  [
1539  'first.' => [
1540  'firstSub.' => [
1541  'firstSubSub.' => 1,
1542  ],
1543  ],
1544  'second.' => [
1545  'secondSub.' => [
1546  'secondSubSub.' => 2,
1547  ],
1548  ],
1549  ],
1550  [
1551  'first.firstSub.firstSubSub.' => 1,
1552  'second.secondSub.secondSubSub.' => 2,
1553  ],
1554  ],
1555  'nested array of 3 levels with multi dots' => [
1556  [
1557  'first.' => [
1558  'firstSub..' => [
1559  'firstSubSub..' => 1,
1560  ],
1561  ],
1562  'second.' => [
1563  'secondSub..' => [
1564  'secondSubSub.' => 2,
1565  ],
1566  ],
1567  ],
1568  [
1569  'first.firstSub..firstSubSub..' => 1,
1570  'second.secondSub..secondSubSub.' => 2,
1571  ],
1572  ],
1573  ];
1574  }
1575 
1576  #[DataProvider('flattenWithKeepDotsCalculatesExpectedResultDataProvider')]
1577  #[Test]
1578  public function ‪flattenWithKeepDotsCalculatesExpectedResult(array $array, array $expected): void
1579  {
1580  self::assertEquals($expected, ‪ArrayUtility::flatten($array, '', true));
1581  }
1582 
1584  {
1585  return [
1586  'plain array' => [
1587  [
1588  'first' => 1,
1589  'second' => 2,
1590  ],
1591  [
1592  'first' => 1,
1593  'second' => 2,
1594  ],
1595  ],
1596  'plain array with trailing dots' => [
1597  [
1598  'first\.' => 1,
1599  'second\.' => 2,
1600  ],
1601  [
1602  'first.' => 1,
1603  'second.' => 2,
1604  ],
1605  ],
1606  'nested array of 2 levels' => [
1607  [
1608  'first.firstSub' => 1,
1609  'second.secondSub' => 2,
1610  ],
1611  [
1612  'first' => [
1613  'firstSub' => 1,
1614  ],
1615  'second' => [
1616  'secondSub' => 2,
1617  ],
1618  ],
1619  ],
1620  'nested array of 2 levels with dots in keys' => [
1621  [
1622  'first\.el.firstSub\.' => 1,
1623  'second\.el.secondSub\.' => 2,
1624  ],
1625  [
1626  'first.el' => [
1627  'firstSub.' => 1,
1628  ],
1629  'second.el' => [
1630  'secondSub.' => 2,
1631  ],
1632  ],
1633  ],
1634  'nested array of 2 levels with dots inside keys' => [
1635  [
1636  'first.first\.sub' => 1,
1637  'second.second\.sub' => 2,
1638  ],
1639  [
1640  'first' => [
1641  'first.sub' => 1,
1642  ],
1643  'second' => [
1644  'second.sub' => 2,
1645  ],
1646  ],
1647  ],
1648  'nested array of 3 levels' => [
1649  [
1650  'first.firstSub.firstSubSub' => 1,
1651  'second.secondSub.secondSubSub' => 2,
1652  ],
1653  [
1654  'first' => [
1655  'firstSub' => [
1656  'firstSubSub' => 1,
1657  ],
1658  ],
1659  'second' => [
1660  'secondSub' => [
1661  'secondSubSub' => 2,
1662  ],
1663  ],
1664  ],
1665  ],
1666  'nested array of 3 levels with dots in keys' => [
1667  [
1668  'first\..firstSub\..firstSubSub\.' => 1,
1669  'second\..secondSub\..secondSubSub\.' => 2,
1670  ],
1671  [
1672  'first.' => [
1673  'firstSub.' => [
1674  'firstSubSub.' => 1,
1675  ],
1676  ],
1677  'second.' => [
1678  'secondSub.' => [
1679  'secondSubSub.' => 2,
1680  ],
1681  ],
1682  ],
1683  ],
1684  'duplicate keys, one with dot, one without' => [
1685  [
1686  'foo' => 'node',
1687  'foo\..bar' => 'bla',
1688  ],
1689  [
1690  'foo' => 'node',
1691  'foo.' => [
1692  'bar' => 'bla',
1693  ],
1694  ],
1695  ],
1696  'duplicate keys, one with dot with scalar value, one without, last wins' => [
1697  [
1698  'foo\.' => 'dot',
1699  'foo' => 'node',
1700  ],
1701  [
1702  'foo.' => 'dot',
1703  'foo' => 'node',
1704  ],
1705  ],
1706  'empty key' => [
1707  [
1708  '' => 'node',
1709  ],
1710  [
1711  '' => 'node',
1712  ],
1713  ],
1714  'dot key' => [
1715  [
1716  '\.' => 'node',
1717  ],
1718  [
1719  '.' => 'node',
1720  ],
1721  ],
1722  'empty array' => [
1723  [],
1724  [],
1725  ],
1726  'nested lists' => [
1727  [
1728  '0.0' => 'foo',
1729  '0.1' => 'bar',
1730  '1.0' => 'bla',
1731  '1.1' => 'baz',
1732  ],
1733  [
1734  ['foo', 'bar'],
1735  ['bla', 'baz'],
1736  ],
1737  ],
1738  ];
1739  }
1740 
1741  #[DataProvider('unflattenCalculatesExpectedResultDataProvider')]
1742  #[Test]
1743  public function ‪unflattenCalculatesExpectedResult(array $array, array $expected): void
1744  {
1745  self::assertEquals($expected, ArrayUtility::unflatten($array));
1746  }
1747 
1749  {
1750  $sameObject = new \stdClass();
1751  return [
1752  // array($source, $mask, $expected)
1753  'empty array is returned if source is empty array' => [
1754  [],
1755  [
1756  'foo' => 'bar',
1757  ],
1758  [],
1759  ],
1760  'empty array is returned if mask is empty' => [
1761  [
1762  'foo' => 'bar',
1763  ],
1764  [],
1765  [],
1766  ],
1767  'key is kept on first level if exists in mask' => [
1768  [
1769  'foo' => 42,
1770  ],
1771  [
1772  'foo' => 42,
1773  ],
1774  [
1775  'foo' => 42,
1776  ],
1777  ],
1778  'value of key in source is kept if mask has different value' => [
1779  [
1780  'foo' => 42,
1781  ],
1782  [
1783  'foo' => new \stdClass(),
1784  ],
1785  [
1786  'foo' => 42,
1787  ],
1788  ],
1789  'key is kept on first level if according mask value is NULL' => [
1790  [
1791  'foo' => 42,
1792  ],
1793  [
1794  'foo' => null,
1795  ],
1796  [
1797  'foo' => 42,
1798  ],
1799  ],
1800  'null in source value is kept' => [
1801  [
1802  'foo' => null,
1803  ],
1804  [
1805  'foo' => 'bar',
1806  ],
1807  [
1808  'foo' => null,
1809  ],
1810  ],
1811  'mask does not add new keys' => [
1812  [
1813  'foo' => 42,
1814  ],
1815  [
1816  'foo' => 23,
1817  'bar' => [
1818  4711,
1819  ],
1820  ],
1821  [
1822  'foo' => 42,
1823  ],
1824  ],
1825  'mask does not overwrite simple values with arrays' => [
1826  [
1827  'foo' => 42,
1828  ],
1829  [
1830  'foo' => [
1831  'bar' => 23,
1832  ],
1833  ],
1834  [
1835  'foo' => 42,
1836  ],
1837  ],
1838  'key is kept on first level if according mask value is array' => [
1839  [
1840  'foo' => 42,
1841  ],
1842  [
1843  'foo' => [
1844  'bar' => 23,
1845  ],
1846  ],
1847  [
1848  'foo' => 42,
1849  ],
1850  ],
1851  'full array is kept if value is array and mask value is simple type' => [
1852  [
1853  'foo' => [
1854  'bar' => 23,
1855  ],
1856  ],
1857  [
1858  'foo' => 42,
1859  ],
1860  [
1861  'foo' => [
1862  'bar' => 23,
1863  ],
1864  ],
1865  ],
1866  'key handling is type agnostic' => [
1867  [
1868  42 => 'foo',
1869  ],
1870  [
1871  '42' => 'bar',
1872  ],
1873  [
1874  42 => 'foo',
1875  ],
1876  ],
1877  'value is same if value is object' => [
1878  [
1879  'foo' => $sameObject,
1880  ],
1881  [
1882  'foo' => 'something',
1883  ],
1884  [
1885  'foo' => $sameObject,
1886  ],
1887  ],
1888  'mask does not add simple value to result if key does not exist in source' => [
1889  [
1890  'foo' => '42',
1891  ],
1892  [
1893  'foo' => '42',
1894  'bar' => 23,
1895  ],
1896  [
1897  'foo' => '42',
1898  ],
1899  ],
1900  'array of source is kept if value of mask key exists but is no array' => [
1901  [
1902  'foo' => '42',
1903  'bar' => [
1904  'baz' => 23,
1905  ],
1906  ],
1907  [
1908  'foo' => 'value is not significant',
1909  'bar' => null,
1910  ],
1911  [
1912  'foo' => '42',
1913  'bar' => [
1914  'baz' => 23,
1915  ],
1916  ],
1917  ],
1918  'sub arrays are kept if mask has according sub array key and is similar array' => [
1919  [
1920  'first1' => 42,
1921  'first2' => [
1922  'second1' => 23,
1923  'second2' => 4711,
1924  ],
1925  ],
1926  [
1927  'first1' => 42,
1928  'first2' => [
1929  'second1' => 'exists but different',
1930  ],
1931  ],
1932  [
1933  'first1' => 42,
1934  'first2' => [
1935  'second1' => 23,
1936  ],
1937  ],
1938  ],
1939  ];
1940  }
1941 
1942  #[DataProvider('intersectRecursiveCalculatesExpectedResultDataProvider')]
1943  #[Test]
1944  public function ‪intersectRecursiveCalculatesExpectedResult(array $source, array $mask, array $expected): void
1945  {
1946  self::assertSame($expected, ArrayUtility::intersectRecursive($source, $mask));
1947  }
1948 
1950  {
1951  return [
1952  'empty array is returned if source is empty array' => [
1953  [],
1954  [],
1955  ],
1956  'returns self if array is already numerically keyed' => [
1957  [1, 2, 3],
1958  [1, 2, 3],
1959  ],
1960  'returns correctly if keys are numeric, but contains a leap' => [
1961  [0 => 'One', 1 => 'Two', 3 => 'Three'],
1962  [0 => 'One', 1 => 'Two', 2 => 'Three'],
1963  ],
1964  'returns correctly even though keys are strings but still numeric' => [
1965  ['0' => 'One', '1' => 'Two', '3' => 'Three'],
1966  [0 => 'One', 1 => 'Two', 2 => 'Three'],
1967  ],
1968  'returns correctly if just a single keys is not numeric' => [
1969  [0 => 'Zero', '1' => 'One', 'Two' => 'Two'],
1970  [0 => 'Zero', '1' => 'One', 'Two' => 'Two'],
1971  ],
1972  'returns unchanged if keys end with a dot' => [
1973  ['2.' => 'Two', '1.' => 'One', '0.' => 'Zero'],
1974  ['2.' => 'Two', '1.' => 'One', '0.' => 'Zero'],
1975  ],
1976  'return self with nested numerically keyed array' => [
1977  [
1978  'One',
1979  'Two',
1980  'Three',
1981  [
1982  'sub.One',
1983  'sub.Two',
1984  ],
1985  ],
1986  [
1987  'One',
1988  'Two',
1989  'Three',
1990  [
1991  'sub.One',
1992  'sub.Two',
1993  ],
1994  ],
1995  ],
1996  'returns correctly with nested numerically keyed array with leaps' => [
1997  [
1998  'One',
1999  'Two',
2000  'Three',
2001  [
2002  0 => 'sub.One',
2003  2 => 'sub.Two',
2004  ],
2005  ],
2006  [
2007  'One',
2008  'Two',
2009  'Three',
2010  [
2011  'sub.One',
2012  'sub.Two',
2013  ],
2014  ],
2015  ],
2016  'returns correctly with nested string-keyed array' => [
2017  [
2018  'One',
2019  'Two',
2020  'Three',
2021  [
2022  'one' => 'sub.One',
2023  'two' => 'sub.Two',
2024  ],
2025  ],
2026  [
2027  'One',
2028  'Two',
2029  'Three',
2030  [
2031  'one' => 'sub.One',
2032  'two' => 'sub.Two',
2033  ],
2034  ],
2035  ],
2036  'returns correctly with deeply nested arrays' => [
2037  [
2038  'One',
2039  'Two',
2040  [
2041  'one' => 1,
2042  'two' => 2,
2043  'three' => [
2044  2 => 'SubSubOne',
2045  5 => 'SubSubTwo',
2046  9 => [0, 1, 2],
2047  [],
2048  ],
2049  ],
2050  ],
2051  [
2052  'One',
2053  'Two',
2054  [
2055  'one' => 1,
2056  'two' => 2,
2057  'three' => [
2058  'SubSubOne',
2059  'SubSubTwo',
2060  [0, 1, 2],
2061  [],
2062  ],
2063  ],
2064  ],
2065  ],
2066  ];
2067  }
2068 
2069  #[DataProvider('renumberKeysToAvoidLeapsIfKeysAreAllNumericDataProvider')]
2070  #[Test]
2071  public function ‪renumberKeysToAvoidLeapsIfKeysAreAllNumericReturnsExpectedOrder(array $inputArray, array $expected): void
2072  {
2073  self::assertEquals($expected, ArrayUtility::renumberKeysToAvoidLeapsIfKeysAreAllNumeric($inputArray));
2074  }
2075 
2077  {
2078  return [
2079  'Override array can reset string to array' => [
2080  [
2081  'first' => [
2082  'second' => 'foo',
2083  ],
2084  ],
2085  [
2086  'first' => [
2087  'second' => ['third' => 'bar'],
2088  ],
2089  ],
2090  true,
2091  true,
2092  true,
2093  [
2094  'first' => [
2095  'second' => ['third' => 'bar'],
2096  ],
2097  ],
2098  ],
2099  'Override array does not reset array to string (weird!)' => [
2100  [
2101  'first' => [],
2102  ],
2103  [
2104  'first' => 'foo',
2105  ],
2106  true,
2107  true,
2108  true,
2109  [
2110  'first' => [], // This is rather unexpected, naive expectation: first => 'foo'
2111  ],
2112  ],
2113  'Override array does override string with null' => [
2114  [
2115  'first' => 'foo',
2116  ],
2117  [
2118  'first' => null,
2119  ],
2120  true,
2121  true,
2122  true,
2123  [
2124  'first' => null,
2125  ],
2126  ],
2127  'Override array does override null with string' => [
2128  [
2129  'first' => null,
2130  ],
2131  [
2132  'first' => 'foo',
2133  ],
2134  true,
2135  true,
2136  true,
2137  [
2138  'first' => 'foo',
2139  ],
2140  ],
2141  'Override array does override null with empty string' => [
2142  [
2143  'first' => null,
2144  ],
2145  [
2146  'first' => '',
2147  ],
2148  true,
2149  true,
2150  true,
2151  [
2152  'first' => '',
2153  ],
2154  ],
2155  'Override array does not override string with NULL if requested' => [
2156  [
2157  'first' => 'foo',
2158  ],
2159  [
2160  'first' => null,
2161  ],
2162  true,
2163  false, // no include empty values
2164  true,
2165  [
2166  'first' => 'foo',
2167  ],
2168  ],
2169  'Override array does override null with null' => [
2170  [
2171  'first' => null,
2172  ],
2173  [
2174  'first' => null,
2175  ],
2176  true,
2177  true,
2178  true,
2179  [
2180  'first' => '',
2181  ],
2182  ],
2183  'Override array can __UNSET values' => [
2184  [
2185  'first' => [
2186  'second' => 'second',
2187  'third' => 'third',
2188  ],
2189  'fifth' => [],
2190  ],
2191  [
2192  'first' => [
2193  'second' => 'overrule',
2194  'third' => '__UNSET',
2195  'fourth' => 'overrile',
2196  ],
2197  'fifth' => '__UNSET',
2198  ],
2199  true,
2200  true,
2201  true,
2202  [
2203  'first' => [
2204  'second' => 'overrule',
2205  'fourth' => 'overrile',
2206  ],
2207  ],
2208  ],
2209  'Override can add keys' => [
2210  [
2211  'first' => 'foo',
2212  ],
2213  [
2214  'second' => 'bar',
2215  ],
2216  true,
2217  true,
2218  true,
2219  [
2220  'first' => 'foo',
2221  'second' => 'bar',
2222  ],
2223  ],
2224  'Override does not add key if __UNSET' => [
2225  [
2226  'first' => 'foo',
2227  ],
2228  [
2229  'second' => '__UNSET',
2230  ],
2231  true,
2232  true,
2233  true,
2234  [
2235  'first' => 'foo',
2236  ],
2237  ],
2238  'Override does not add key if not requested' => [
2239  [
2240  'first' => 'foo',
2241  ],
2242  [
2243  'second' => 'bar',
2244  ],
2245  false, // no add keys
2246  true,
2247  true,
2248  [
2249  'first' => 'foo',
2250  ],
2251  ],
2252  'Override does not add key if not requested with add include empty values' => [
2253  [
2254  'first' => 'foo',
2255  ],
2256  [
2257  'second' => 'bar',
2258  ],
2259  false, // no add keys
2260  false, // no include empty values
2261  true,
2262  [
2263  'first' => 'foo',
2264  ],
2265  ],
2266  'Override does not override string with empty string if requested' => [
2267  [
2268  'first' => 'foo',
2269  ],
2270  [
2271  'first' => '',
2272  ],
2273  true,
2274  false, // no include empty values
2275  true,
2276  [
2277  'first' => 'foo',
2278  ],
2279  ],
2280  'Override array does merge instead of __UNSET if requested (weird!)' => [
2281  [
2282  'first' => [
2283  'second' => 'second',
2284  'third' => 'third',
2285  ],
2286  'fifth' => [],
2287  ],
2288  [
2289  'first' => [
2290  'second' => 'overrule',
2291  'third' => '__UNSET',
2292  'fourth' => 'overrile',
2293  ],
2294  'fifth' => '__UNSET',
2295  ],
2296  true,
2297  true,
2298  false,
2299  [
2300  'first' => [
2301  'second' => 'overrule',
2302  'third' => '__UNSET', // overruled
2303  'fourth' => 'overrile',
2304  ],
2305  'fifth' => [], // not overruled with string here, naive expectation: 'fifth' => '__UNSET'
2306  ],
2307  ],
2308  ];
2309  }
2310 
2319  #[DataProvider('mergeRecursiveWithOverruleCalculatesExpectedResultDataProvider')]
2320  #[Test]
2321  public function ‪mergeRecursiveWithOverruleCalculatesExpectedResult($input1, $input2, $addKeys, $includeEmptyValues, $enableUnsetFeature, $expected): void
2322  {
2323  ArrayUtility::mergeRecursiveWithOverrule($input1, $input2, $addKeys, $includeEmptyValues, $enableUnsetFeature);
2324  self::assertEquals($expected, $input1);
2325  }
2326 
2328  // Tests concerning removeArrayEntryByValue
2330  #[Test]
2332  {
2333  $inputArray = [
2334  '0' => 'test1',
2335  '1' => 'test2',
2336  '2' => 'test3',
2337  '3' => 'test2',
2338  ];
2339  $compareValue = 'test2';
2340  $expectedResult = [
2341  '0' => 'test1',
2342  '2' => 'test3',
2343  ];
2344  $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
2345  self::assertEquals($expectedResult, $actualResult);
2346  }
2347 
2348  #[Test]
2350  {
2351  $inputArray = [
2352  '0' => 'foo',
2353  '1' => [
2354  '10' => 'bar',
2355  ],
2356  '2' => 'bar',
2357  ];
2358  $compareValue = 'bar';
2359  $expectedResult = [
2360  '0' => 'foo',
2361  '1' => [],
2362  ];
2363  $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
2364  self::assertEquals($expectedResult, $actualResult);
2365  }
2366 
2367  #[Test]
2369  {
2370  $inputArray = [
2371  '0' => 'foo',
2372  '1' => '',
2373  '2' => 'bar',
2374  ];
2375  $compareValue = '';
2376  $expectedResult = [
2377  '0' => 'foo',
2378  '2' => 'bar',
2379  ];
2380  $actualResult = ArrayUtility::removeArrayEntryByValue($inputArray, $compareValue);
2381  self::assertEquals($expectedResult, $actualResult);
2382  }
2383 
2385  // Tests concerning keepItemsInArray
2387 
2392  #[DataProvider('keepItemsInArrayWorksWithOneArgumentDataProvider')]
2393  #[Test]
2394  public function ‪keepItemsInArrayWorksWithOneArgument($search, $array, $expected): void
2395  {
2396  self::assertEquals($expected, ArrayUtility::keepItemsInArray($array, $search));
2397  }
2398 
2403  {
2404  $array = [
2405  0 => 0,
2406  'one' => 'one',
2407  'two' => 'two',
2408  'three' => 'three',
2409  ];
2410  return [
2411  'Empty argument will match "all" elements' => [null, $array, $array],
2412  'No match' => ['four', $array, []],
2413  'One match' => ['two', $array, ['two' => 'two']],
2414  'Multiple matches' => ['two,one', $array, ['one' => 'one', 'two' => 'two']],
2415  'Argument can be an array' => [['three'], $array, ['three' => 'three']],
2416  ];
2417  }
2418 
2424  #[Test]
2425  public function ‪keepItemsInArrayCanUseClosure(): void
2426  {
2427  $array = [
2428  'aa' => ['first', 'second'],
2429  'bb' => ['third', 'fourth'],
2430  'cc' => ['fifth', 'sixth'],
2431  ];
2432  $expected = ['bb' => ['third', 'fourth']];
2433  $keepItems = 'third';
2434  $match = ArrayUtility::keepItemsInArray(
2435  $array,
2436  $keepItems,
2437  static function ($value) {
2438  return $value[0];
2439  }
2440  );
2441  self::assertEquals($expected, $match);
2442  }
2443 
2445  // Tests concerning remapArrayKeys
2447  #[Test]
2449  {
2450  $array = [
2451  'one' => 'one',
2452  'two' => 'two',
2453  'three' => 'three',
2454  ];
2455  $keyMapping = [
2456  'one' => '1',
2457  'two' => '2',
2458  ];
2459  $expected = [
2460  '1' => 'one',
2461  '2' => 'two',
2462  'three' => 'three',
2463  ];
2464  ArrayUtility::remapArrayKeys($array, $keyMapping);
2465  self::assertEquals($expected, $array);
2466  }
2467 
2469  // Tests concerning arrayDiffKeyRecursive
2471  #[Test]
2473  {
2474  $array1 = [
2475  'key1' => 'value1',
2476  'key2' => 'value2',
2477  'key3' => 'value3',
2478  ];
2479  $array2 = [
2480  'key1' => 'value1',
2481  'key3' => 'value3',
2482  ];
2483  $expectedResult = [
2484  'key2' => 'value2',
2485  ];
2486  $actualResult = ArrayUtility::arrayDiffKeyRecursive($array1, $array2);
2487  self::assertEquals($expectedResult, $actualResult);
2488  }
2489 
2490  #[Test]
2492  {
2493  $array1 = [
2494  'key1' => 'value1',
2495  'key2' => [
2496  'key21' => 'value21',
2497  'key22' => 'value22',
2498  'key23' => [
2499  'key231' => 'value231',
2500  'key232' => 'value232',
2501  ],
2502  ],
2503  ];
2504  $array2 = [
2505  'key1' => 'valueDoesNotMatter',
2506  'key2' => [
2507  'key21' => 'value21',
2508  'key23' => [
2509  'key231' => 'value231',
2510  ],
2511  ],
2512  ];
2513  $expectedResult = [
2514  'key2' => [
2515  'key22' => 'value22',
2516  'key23' => [
2517  'key232' => 'value232',
2518  ],
2519  ],
2520  ];
2521  $actualResult = ArrayUtility::arrayDiffKeyRecursive($array1, $array2);
2522  self::assertEquals($expectedResult, $actualResult);
2523  }
2524 
2525  #[Test]
2527  {
2528  $array1 = [
2529  'key1' => [
2530  'key11' => 'value11',
2531  'key12' => 'value12',
2532  ],
2533  'key2' => 'value2',
2534  'key3' => 'value3',
2535  ];
2536  $array2 = [
2537  'key1' => 'value1',
2538  'key2' => [
2539  'key21' => 'valueDoesNotMatter',
2540  ],
2541  ];
2542  $expectedResult = [
2543  'key3' => 'value3',
2544  ];
2545  $actualResult = ArrayUtility::arrayDiffKeyRecursive($array1, $array2);
2546  self::assertEquals($expectedResult, $actualResult);
2547  }
2548 
2549  #[Test]
2551  {
2552  $array1 = [
2553  'key1' => [
2554  'key11' => 'value11',
2555  'key12' => 'value12',
2556  ],
2557  'key2' => 'value2',
2558  'key3' => 'value3',
2559  ];
2560  $array2 = [
2561  'key1' => [
2562  'key11' => 'valueDoesNotMatter',
2563  'key12' => 'value12',
2564  ],
2565  'key2' => 'value2',
2566  'key3' => 'value3',
2567  ];
2568  $expectedResult = [];
2569  $actualResult = ArrayUtility::arrayDiffKeyRecursive($array1, $array2);
2570  self::assertEquals($expectedResult, $actualResult);
2571  }
2572 
2574  // Tests concerning arrayDiffAssocRecursive
2576  #[Test]
2578  {
2579  $array1 = [
2580  'key1' => 'value1',
2581  'key2' => 'value2',
2582  'key3' => 'value3',
2583  ];
2584  $array2 = [
2585  'key1' => 'value1',
2586  'key3' => 'value3',
2587  ];
2588  $expectedResult = [
2589  'key2' => 'value2',
2590  ];
2591  $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2592  self::assertEquals($expectedResult, $actualResult);
2593  }
2594 
2595  #[Test]
2597  {
2598  $array1 = [
2599  'key1' => 'value1',
2600  'key2' => [
2601  'key21' => 'value21',
2602  'key22' => 'value22',
2603  'key23' => [
2604  'key231' => 'value231',
2605  'key232' => 'value232',
2606  ],
2607  ],
2608  ];
2609  $array2 = [
2610  'key1' => 'value2',
2611  'key2' => [
2612  'key21' => 'value21',
2613  'key23' => [
2614  'key231' => 'value231',
2615  ],
2616  ],
2617  ];
2618  $expectedResult = [
2619  'key1' => 'value1',
2620  'key2' => [
2621  'key22' => 'value22',
2622  'key23' => [
2623  'key232' => 'value232',
2624  ],
2625  ],
2626  ];
2627  $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2628  self::assertEquals($expectedResult, $actualResult);
2629  }
2630 
2631  #[Test]
2633  {
2634  $array1 = [
2635  'key1' => [
2636  'key11' => 'value11',
2637  'key12' => 'value12',
2638  ],
2639  'key2' => 'value2',
2640  'key3' => 'value3',
2641  ];
2642  $array2 = [
2643  'key1' => 'value1',
2644  'key2' => [
2645  'key21' => 'valueDoesNotMatter',
2646  ],
2647  ];
2648  $expectedResult = [
2649  'key2' => 'value2',
2650  'key3' => 'value3',
2651  ];
2652  $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2653  self::assertEquals($expectedResult, $actualResult);
2654  }
2655 
2656  #[Test]
2658  {
2659  $array1 = [
2660  'key1' => [
2661  'key11' => 'value11',
2662  'key12' => 'value12',
2663  ],
2664  'key2' => 'value2',
2665  'key3' => 'value3',
2666  ];
2667  $array2 = [
2668  'key1' => [
2669  'key11' => 'value11',
2670  'key12' => 'value12',
2671  ],
2672  'key2' => 'value2',
2673  'key3' => 'value3',
2674  ];
2675  $expectedResult = [];
2676  $actualResult = ArrayUtility::arrayDiffAssocRecursive($array1, $array2);
2677  self::assertEquals($expectedResult, $actualResult);
2678  }
2679 
2681  // Tests concerning naturalKeySortRecursive
2683  #[Test]
2685  {
2686  $testArray = [
2687  'bb' => 'bb',
2688  'ab' => 'ab',
2689  '123' => '123',
2690  'aaa' => 'aaa',
2691  'abc' => 'abc',
2692  '23' => '23',
2693  'ba' => 'ba',
2694  'bad' => 'bad',
2695  '2' => '2',
2696  'zap' => 'zap',
2697  '210' => '210',
2698  ];
2699  $expectedResult = [
2700  '2',
2701  '23',
2702  '123',
2703  '210',
2704  'aaa',
2705  'ab',
2706  'abc',
2707  'ba',
2708  'bad',
2709  'bb',
2710  'zap',
2711  ];
2712  ArrayUtility::naturalKeySortRecursive($testArray);
2713  self::assertEquals($expectedResult, array_values($testArray));
2714  }
2715 
2716  #[Test]
2718  {
2719  $testArray = [
2720  '2' => '2',
2721  'bb' => 'bb',
2722  'ab' => 'ab',
2723  '23' => '23',
2724  'aaa' => [
2725  'bb' => 'bb',
2726  'ab' => 'ab',
2727  '123' => '123',
2728  'aaa' => 'aaa',
2729  '2' => '2',
2730  'abc' => 'abc',
2731  'ba' => 'ba',
2732  '23' => '23',
2733  'bad' => [
2734  'bb' => 'bb',
2735  'ab' => 'ab',
2736  '123' => '123',
2737  'aaa' => 'aaa',
2738  'abc' => 'abc',
2739  '23' => '23',
2740  'ba' => 'ba',
2741  'bad' => 'bad',
2742  '2' => '2',
2743  'zap' => 'zap',
2744  '210' => '210',
2745  ],
2746  '210' => '210',
2747  'zap' => 'zap',
2748  ],
2749  'abc' => 'abc',
2750  'ba' => 'ba',
2751  '210' => '210',
2752  'bad' => 'bad',
2753  '123' => '123',
2754  'zap' => 'zap',
2755  ];
2756  $expectedResult = [
2757  '2',
2758  '23',
2759  '123',
2760  '210',
2761  'aaa',
2762  'ab',
2763  'abc',
2764  'ba',
2765  'bad',
2766  'bb',
2767  'zap',
2768  ];
2769  ArrayUtility::naturalKeySortRecursive($testArray);
2770  self::assertEquals($expectedResult, array_values(array_keys($testArray['aaa']['bad'])));
2771  self::assertEquals($expectedResult, array_values(array_keys($testArray['aaa'])));
2772  self::assertEquals($expectedResult, array_values(array_keys($testArray)));
2773  }
2774 
2778  public static function ‪filterAndSortByNumericKeysWithAcceptAnyKey(): array
2779  {
2780  return [
2781  'ordered list of plain numeric keys' => [
2782  'input' => [
2783  '10' => 'foo',
2784  '20' => 'bar',
2785  ],
2786  'expected' => [
2787  10,
2788  20,
2789  ],
2790  ],
2791  'unordered list of plain numeric keys' => [
2792  'input' => [
2793  '20' => 'bar',
2794  '10' => 'foo',
2795  ],
2796  'expected' => [
2797  10,
2798  20,
2799  ],
2800  ],
2801  'list of string keys' => [
2802  'input' => [
2803  '10.' => [
2804  'wrap' => 'foo',
2805  ],
2806  '20.' => [
2807  'wrap' => 'bar',
2808  ],
2809  ],
2810  'expected' => [
2811  10,
2812  20,
2813  ],
2814  ],
2815  'list of mixed keys' => [
2816  'input' => [
2817  '10' => 'foo',
2818  '20.' => [
2819  'wrap' => 'bar',
2820  ],
2821  ],
2822  'expected' => [
2823  10,
2824  20,
2825  ],
2826  ],
2827  'list of mixed keys with one not interpreted as integer' => [
2828  'input' => [
2829  '10' => 'foo',
2830  'bla20.' => [
2831  'wrap' => 'bar',
2832  ],
2833  ],
2834  'expected' => [
2835  0,
2836  10,
2837  ],
2838  ],
2839  'list of mixed keys with more than one not interpreted as integer' => [
2840  'input' => [
2841  '10' => 'foo',
2842  'bla20.' => [
2843  'wrap' => 'bar',
2844  ],
2845  'bla21.' => [
2846  'wrap' => 'foobar',
2847  ],
2848  ],
2849  'expected' => [
2850  0,
2851  10,
2852  ],
2853  ],
2854  ];
2855  }
2856 
2861  #[DataProvider('filterAndSortByNumericKeysWithAcceptAnyKey')]
2862  #[Test]
2864  {
2865  $result = ArrayUtility::filterAndSortByNumericKeys($input, true);
2866  self::assertEquals($result, $expected);
2867  }
2868 
2873  {
2874  return [
2875  'ordered list of plain numeric keys' => [
2876  'input' => [
2877  '10' => 'foo',
2878  '20' => 'bar',
2879  ],
2880  'expected' => [
2881  10,
2882  20,
2883  ],
2884  ],
2885  'unordered list of plain numeric keys' => [
2886  'input' => [
2887  '20' => 'bar',
2888  '10' => 'foo',
2889  ],
2890  'expected' => [
2891  10,
2892  20,
2893  ],
2894  ],
2895  'list of string keys' => [
2896  'input' => [
2897  '10.' => [
2898  'wrap' => 'foo',
2899  ],
2900  '20.' => [
2901  'wrap' => 'bar',
2902  ],
2903  ],
2904  'expected' => [],
2905  ],
2906  'list of mixed keys' => [
2907  'input' => [
2908  '10' => 'foo',
2909  '20.' => [
2910  'wrap' => 'bar',
2911  ],
2912  ],
2913  'expected' => [
2914  10,
2915  ],
2916  ],
2917  ];
2918  }
2919 
2924  #[DataProvider('filterAndSortByNumericKeysWithoutAcceptAnyKey')]
2925  #[Test]
2927  {
2928  $result = ArrayUtility::filterAndSortByNumericKeys($input);
2929  self::assertEquals($result, $expected);
2930  }
2931 
2935  public static function ‪sortArrayWithIntegerKeysDataProvider(): array
2936  {
2937  return [
2938  [
2939  [
2940  '20' => 'test1',
2941  '11' => 'test2',
2942  '16' => 'test3',
2943  ],
2944  [
2945  '11' => 'test2',
2946  '16' => 'test3',
2947  '20' => 'test1',
2948  ],
2949  ],
2950  [
2951  [
2952  '20' => 'test1',
2953  '16.5' => 'test2',
2954  '16' => 'test3',
2955  ],
2956  [
2957  '20' => 'test1',
2958  '16.5' => 'test2',
2959  '16' => 'test3',
2960  ],
2961  ],
2962  [
2963  [
2964  '20' => 'test20',
2965  'somestring' => 'teststring',
2966  '16' => 'test16',
2967  ],
2968  [
2969  '20' => 'test20',
2970  'somestring' => 'teststring',
2971  '16' => 'test16',
2972  ],
2973  ],
2974  ];
2975  }
2976 
2977  #[DataProvider('sortArrayWithIntegerKeysDataProvider')]
2978  #[Test]
2979  public function ‪sortArrayWithIntegerKeysSortsNumericArrays(array $arrayToSort, array $expectedArray): void
2980  {
2981  $sortedArray = ArrayUtility::sortArrayWithIntegerKeys($arrayToSort);
2982  self::assertSame($sortedArray, $expectedArray);
2983  }
2984 
2985  #[Test]
2987  {
2988  $this->expectException(\InvalidArgumentException::class);
2989  $this->expectExceptionCode(1325697085);
2990 
2991  $arrayToTest = [
2992  'roger' => '',
2993  'francine' => '',
2994  'stan' => '',
2995  ];
2996 
2997  $allowedArrayKeys = [
2998  'roger',
2999  'francine',
3000  ];
3001 
3002  ‪ArrayUtility::assertAllArrayKeysAreValid($arrayToTest, $allowedArrayKeys);
3003  }
3004 
3005  #[Test]
3007  {
3008  $arrayToTest = [
3009  'roger' => '',
3010  'francine' => '',
3011  'stan' => '',
3012  ];
3013 
3014  $allowedArrayKeys = [
3015  'roger',
3016  'francine',
3017  'stan',
3018  ];
3019 
3020  ‪ArrayUtility::assertAllArrayKeysAreValid($arrayToTest, $allowedArrayKeys);
3021  }
3022 
3023  #[Test]
3025  {
3026  $input = [
3027  20 => 'b',
3028  10 => 'a',
3029  40 => 'd',
3030  30 => 'c',
3031  50 => [
3032  20 => 'a',
3033  10 => 'b',
3034  ],
3035  ];
3036 
3037  $expected = [
3038  10 => 'a',
3039  20 => 'b',
3040  30 => 'c',
3041  40 => 'd',
3042  50 => [
3043  10 => 'b',
3044  20 => 'a',
3045  ],
3046  ];
3047 
3048  self::assertSame($expected, ArrayUtility::sortArrayWithIntegerKeysRecursive($input));
3049  }
3050 
3051  #[Test]
3053  {
3054  $input = [
3055  'b' => 'b',
3056  10 => 'a',
3057  40 => 'd',
3058  30 => 'c',
3059  ];
3060 
3061  $expected = [
3062  'b' => 'b',
3063  10 => 'a',
3064  40 => 'd',
3065  30 => 'c',
3066  ];
3067 
3068  self::assertSame($expected, ArrayUtility::sortArrayWithIntegerKeysRecursive($input));
3069  }
3070 
3071  #[Test]
3073  {
3074  $input = [
3075  20 => 'b',
3076  10 => 'a',
3077  40 => 'd',
3078  30 => 'c',
3079  50 => [
3080  20 => 'a',
3081  10 => 'b',
3082  ],
3083  ];
3084 
3085  $expected = [
3086  0 => 'b',
3087  1 => 'a',
3088  2 => 'd',
3089  3 => 'c',
3090  4 => [
3091  0 => 'a',
3092  1 => 'b',
3093  ],
3094  ];
3095 
3096  self::assertSame($expected, ‪ArrayUtility::reIndexNumericArrayKeysRecursive($input));
3097  }
3098 
3099  #[Test]
3101  {
3102  $input = [
3103  'a' => 'b',
3104  10 => 'a',
3105  40 => 'd',
3106  30 => 'c',
3107  50 => [
3108  20 => 'a',
3109  10 => 'b',
3110  ],
3111  ];
3112 
3113  $expected = [
3114  'a' => 'b',
3115  10 => 'a',
3116  40 => 'd',
3117  30 => 'c',
3118  50 => [
3119  0 => 'a',
3120  1 => 'b',
3121  ],
3122  ];
3123 
3124  self::assertSame($expected, ‪ArrayUtility::reIndexNumericArrayKeysRecursive($input));
3125  }
3126 
3127  #[Test]
3129  {
3130  $input = [
3131  'a' => 'a',
3132  'b' => [
3133  'c' => null,
3134  'd' => 'd',
3135  ],
3136  ];
3137 
3138  $expected = [
3139  'a' => 'a',
3140  'b' => [
3141  'd' => 'd',
3142  ],
3143  ];
3144 
3145  self::assertSame($expected, ‪ArrayUtility::removeNullValuesRecursive($input));
3146  }
3147 
3148  #[Test]
3150  {
3151  $input = [
3152  'a' => 'a',
3153  'b' => [
3154  'c' => '<b>i am evil</b>',
3155  'd' => 'd',
3156  ],
3157  ];
3158 
3159  $expected = [
3160  'a' => 'a',
3161  'b' => [
3162  'c' => 'i am evil',
3163  'd' => 'd',
3164  ],
3165  ];
3166 
3167  self::assertSame($expected, ArrayUtility::stripTagsFromValuesRecursive($input));
3168  }
3169 
3170  #[Test]
3172  {
3173  $testObject = new \stdClass();
3174 
3175  $input = [
3176  'stringWithTags' => '<b>i am evil</b>',
3177  'boolean' => true,
3178  'integer' => 1,
3179  'float' => 1.9,
3180  'object' => $testObject,
3181  'objectWithStringConversion' => new class () {
3185  public function __toString()
3186  {
3187  return 'i am evil <b>too</b>';
3188  }
3189  },
3190  ];
3191 
3192  $expected = [
3193  'stringWithTags' => 'i am evil',
3194  'boolean' => true,
3195  'integer' => 1,
3196  'float' => 1.9,
3197  'object' => $testObject,
3198  'objectWithStringConversion' => 'i am evil too',
3199  ];
3200 
3201  self::assertSame($expected, ArrayUtility::stripTagsFromValuesRecursive($input));
3202  }
3203 
3204  #[Test]
3206  {
3207  $input = [
3208  'a' => 'a',
3209  'b' => [
3210  'c' => 'true',
3211  'd' => 'd',
3212  ],
3213  ];
3214 
3215  $expected = [
3216  'a' => 'a',
3217  'b' => [
3218  'c' => true,
3219  'd' => 'd',
3220  ],
3221  ];
3222 
3223  self::assertSame($expected, ‪ArrayUtility::convertBooleanStringsToBooleanRecursive($input));
3224  }
3225 
3230  {
3231  return [
3232  'filter all values which will be false when converted to boolean' => [
3233  // input
3234  [
3235  true,
3236  false,
3237  'foo1' => [
3238  'bar' => [
3239  'baz' => [
3240  '1',
3241  null,
3242  '',
3243  ],
3244  '' => 1,
3245  'bbd' => 0,
3246  ],
3247  ],
3248  'foo2' => 'foo',
3249  'foo3' => '',
3250  'foo4' => [
3251  'z' => 'bar',
3252  'bar' => 0,
3253  'baz' => [
3254  'foo' => [
3255  'bar' => '',
3256  'boo' => [],
3257  'bamboo' => 5,
3258  'fooAndBoo' => [0],
3259  ],
3260  ],
3261  ],
3262  ],
3263  // expected
3264  [
3265  true,
3266  'foo1' => [
3267  'bar' => [
3268  'baz' => [
3269  '1',
3270  ],
3271  '' => 1,
3272  ],
3273  ],
3274  'foo2' => 'foo',
3275  'foo4' => [
3276  'z' => 'bar',
3277  'baz' => [
3278  'foo' => [
3279  'bamboo' => 5,
3280  ],
3281  ],
3282  ],
3283  ],
3284  ],
3285  ];
3286  }
3287 
3288  #[DataProvider('filterRecursiveFiltersFalseElementsDataProvider')]
3289  #[Test]
3290  public function ‪filterRecursiveFiltersFalseElements(array $input, array $expectedResult): void
3291  {
3292  // If no callback is supplied, all entries of array equal to FALSE (see converting to boolean) will be removed.
3293  $result = ArrayUtility::filterRecursive($input);
3294  self::assertEquals($expectedResult, $result);
3295  }
3296 
3301  {
3302  return [
3303  'filter empty values, keep zero integers' => [
3304  // input
3305  [
3306  true,
3307  false,
3308  'foo1' => [
3309  'bar' => [
3310  'baz' => [
3311  '1',
3312  null,
3313  '',
3314  ],
3315  '' => 1,
3316  'bbd' => 0,
3317  ],
3318  ],
3319  'foo2' => 'foo',
3320  'foo3' => '',
3321  'foo4' => [
3322  'z' => 'bar',
3323  'bar' => 0,
3324  'baz' => [
3325  'foo' => [
3326  'bar' => '',
3327  'boo' => [],
3328  'bamboo' => 5,
3329  'fooAndBoo' => [0],
3330  ],
3331  ],
3332  ],
3333  ],
3334  // expected
3335  [
3336  true,
3337  false,
3338  'foo1' => [
3339  'bar' => [
3340  'baz' => [
3341  '1',
3342  ],
3343  '' => 1,
3344  'bbd' => 0,
3345  ],
3346  ],
3347  'foo2' => 'foo',
3348  'foo4' => [
3349  'z' => 'bar',
3350  'bar' => 0,
3351  'baz' => [
3352  'foo' => [
3353  'bamboo' => 5,
3354  'fooAndBoo' => [0],
3355  ],
3356  ],
3357  ],
3358  ],
3359  ],
3360  ];
3361  }
3362 
3363  #[DataProvider('filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerZeroByCallbackDataProvider')]
3364  #[Test]
3365  public function ‪filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerByCallback(array $input, array $expectedResult): void
3366  {
3367  // callback filters empty strings, array and null but keeps zero integers
3368  $result = ArrayUtility::filterRecursive(
3369  $input,
3370  static function ($item) {
3371  return $item !== '' && $item !== [] && $item !== null;
3372  }
3373  );
3374  self::assertEquals($expectedResult, $result);
3375  }
3376 
3381  {
3382  $input = [
3383  'foo' => 'remove',
3384  'bar' => [
3385  'baz' => 'remove',
3386  'keep1' => 'keep',
3387  ],
3388  'keep2' => 'keep',
3389  ];
3390  $expectedResult = [
3391  'bar' => [
3392  'keep1' => 'keep',
3393  ],
3394  'keep2' => 'keep',
3395  ];
3396 
3397  return [
3398  'filter using a closure' => [
3399  $input,
3400  $expectedResult,
3401  static function ($value): bool {
3402  return is_array($value) || $value === 'keep';
3403  },
3404  ],
3405  'filter using a callable "static class-method call" as string' => [
3406  $input,
3407  $expectedResult,
3408  ArrayUtilityFilterRecursiveCallbackFixture::class . '::callbackViaStaticMethod',
3409  ],
3410  'filter using a callable "static class-method call" as array' => [
3411  $input,
3412  $expectedResult,
3413  [ArrayUtilityFilterRecursiveCallbackFixture::class, 'callbackViaStaticMethod'],
3414  ],
3415  'filter using a callable "instance-method call" as array' => [
3416  $input,
3417  $expectedResult,
3418  [new ‪ArrayUtilityFilterRecursiveCallbackFixture(), 'callbackViaInstanceMethod'],
3419  ],
3420  'only keep2 key is kept' => [
3421  $input,
3422  ['keep2' => 'keep'],
3423  static fn($key): bool => $key === 'keep2',
3424  ARRAY_FILTER_USE_KEY,
3425  ],
3426  'keys baz, keep1 and empty arrays are removed' => [
3427  $input,
3428  ['foo' => 'remove', 'keep2' => 'keep'],
3429  static fn($value, $key): bool => $value !== [] && !in_array($key, ['baz', 'keep1'], true),
3430  ARRAY_FILTER_USE_BOTH,
3431  ],
3432  ];
3433  }
3434 
3440  #[DataProvider('filterRecursiveSupportsCallableCallbackDataProvider')]
3441  #[Test]
3442  public function ‪filterRecursiveSupportsCallableCallback(array $input, array $expectedResult, callable $callback, int $mode = 0): void
3443  {
3444  $result = ArrayUtility::filterRecursive($input, $callback, $mode);
3445  self::assertEquals($expectedResult, $result);
3446  }
3447 
3452  {
3453  return [
3454  'array without string keys' => [
3455  [
3456  0 => 'value 0',
3457  1 => 'value 1',
3458  ],
3459  false,
3460  ],
3461  'array with only string keys' => [
3462  [
3463  'key 0' => 'value 0',
3464  'key 1' => 'value 1',
3465  ],
3466  true,
3467  ],
3468  'array with mixed keys' => [
3469  [
3470  0 => 'value 0',
3471  1 => 'value 1',
3472  'key 2' => 'value 2',
3473  'key 3' => 'value 3',
3474  ],
3475  true,
3476  ],
3477  ];
3478  }
3479 
3480  #[DataProvider('isAssociativeCorrectlyFindsStringKeysDataProvider')]
3481  #[Test]
3482  public function ‪isAssociativeCorrectlyFindsStringKeys(array $array, bool $expectedResult): void
3483  {
3484  $result = ‪ArrayUtility::isAssociative($array);
3485  self::assertEquals($expectedResult, $result);
3486  }
3487 
3492  {
3493  return [
3494  'merge simple lists' => [
3495  [
3496  0 => 'keep',
3497  ],
3498  [
3499  0 => 'keep',
3500  ],
3501  [
3502  0 => 'keep',
3503  1 => 'keep',
3504  ],
3505  ],
3506  'merge simple list arrays' => [
3507  [
3508  'foo' => [
3509  0 => 'keep',
3510  ],
3511  ],
3512  [
3513  'foo' => [
3514  0 => 'keep',
3515  ],
3516  ],
3517  [
3518  'foo' => [
3519  0 => 'keep',
3520  1 => 'keep',
3521  ],
3522  ],
3523  ],
3524  'merge array and simple value' => [
3525  [
3526  'foo' => [
3527  0 => 'override',
3528  ],
3529  ],
3530  [
3531  'foo' => 'keep',
3532  ],
3533  [
3534  'foo' => 'keep',
3535  ],
3536  ],
3537  'merge simple values' => [
3538  [
3539  'foo' => 'override',
3540  ],
3541  [
3542  'foo' => 'keep',
3543  ],
3544  [
3545  'foo' => 'keep',
3546  ],
3547  ],
3548  'merge new keys' => [
3549  [
3550  'foo' => 'keep',
3551  ],
3552  [
3553  'bar' => 'keep',
3554  ],
3555  [
3556  'foo' => 'keep',
3557  'bar' => 'keep',
3558  ],
3559  ],
3560  ];
3561  }
3562 
3563  #[DataProvider('replaceAndAppendScalarValuesRecursiveCorrectlyMergesArraysDataProvider')]
3564  #[Test]
3565  public function ‪replaceAndAppendScalarValuesRecursiveCorrectlyMergesArrays(array $array1, array $array2, array $expectedResult): void
3566  {
3567  $result = ‪ArrayUtility::replaceAndAppendScalarValuesRecursive($array1, $array2);
3568  self::assertEquals($expectedResult, $result);
3569  }
3570 }
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayExportReturnsNoKeyIndexForConsecutiveCountedArrays
‪arrayExportReturnsNoKeyIndexForConsecutiveCountedArrays()
Definition: ArrayUtilityTest.php:1143
‪TYPO3\CMS\Core\Utility\ArrayUtility\isAssociative
‪static bool isAssociative(array $array)
Definition: ArrayUtility.php:960
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterRecursiveFiltersFalseElementsDataProvider
‪static filterRecursiveFiltersFalseElementsDataProvider()
Definition: ArrayUtilityTest.php:3229
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\removeNullValuesRecursiveExpectRemoval
‪removeNullValuesRecursiveExpectRemoval()
Definition: ArrayUtilityTest.php:3128
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\mergeRecursiveWithOverruleCalculatesExpectedResultDataProvider
‪static mergeRecursiveWithOverruleCalculatesExpectedResultDataProvider()
Definition: ArrayUtilityTest.php:2076
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayExportReturnsNumericArrayKeys
‪arrayExportReturnsNumericArrayKeys()
Definition: ArrayUtilityTest.php:1126
‪TYPO3\CMS\Core\Utility\ArrayUtility\flattenPlain
‪static flattenPlain(array $array)
Definition: ArrayUtility.php:496
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\assertAllArrayKeysAreValidThrowsExceptionOnNotAllowedArrayKeys
‪assertAllArrayKeysAreValidThrowsExceptionOnNotAllowedArrayKeys()
Definition: ArrayUtilityTest.php:2986
‪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:2935
‪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:3442
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\keepItemsInArrayWorksWithOneArgumentDataProvider
‪static keepItemsInArrayWorksWithOneArgumentDataProvider()
Definition: ArrayUtilityTest.php:2402
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterRecursiveSupportsCallableCallbackDataProvider
‪static filterRecursiveSupportsCallableCallbackDataProvider()
Definition: ArrayUtilityTest.php:3380
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\reIndexNumericArrayKeysRecursiveExpectNoReindexing
‪reIndexNumericArrayKeysRecursiveExpectNoReindexing()
Definition: ArrayUtilityTest.php:3100
‪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:1055
‪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:2872
‪TYPO3\CMS\Core\Tests\Unit\Utility
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\keepItemsInArrayWorksWithOneArgument
‪keepItemsInArrayWorksWithOneArgument($search, $array, $expected)
Definition: ArrayUtilityTest.php:2394
‪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:971
‪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:2321
‪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:386
‪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:2550
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest
Definition: ArrayUtilityTest.php:31
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\naturalKeySortRecursiveSortsMultiDimensionalArrayByNaturalOrder
‪naturalKeySortRecursiveSortsMultiDimensionalArrayByNaturalOrder()
Definition: ArrayUtilityTest.php:2717
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortArrayWithIntegerKeysSortsNumericArrays
‪sortArrayWithIntegerKeysSortsNumericArrays(array $arrayToSort, array $expectedArray)
Definition: ArrayUtilityTest.php:2979
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayExportReturnsKeyIndexForNonConsecutiveCountedArrays
‪arrayExportReturnsKeyIndexForNonConsecutiveCountedArrays()
Definition: ArrayUtilityTest.php:1160
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffKeyRecursiveHandlesOneDimensionalArrays
‪arrayDiffKeyRecursiveHandlesOneDimensionalArrays()
Definition: ArrayUtilityTest.php:2472
‪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:1743
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\flattenWithKeepDotsCalculatesExpectedResult
‪flattenWithKeepDotsCalculatesExpectedResult(array $array, array $expected)
Definition: ArrayUtilityTest.php:1578
‪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:3024
‪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:469
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\stripTagsFromValuesRecursiveExpectRemoval
‪stripTagsFromValuesRecursiveExpectRemoval()
Definition: ArrayUtilityTest.php:3149
‪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:3072
‪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:2863
‪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:1944
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\sortArraysByKeyThrowsExceptionForNonExistingKey
‪sortArraysByKeyThrowsExceptionForNonExistingKey()
Definition: ArrayUtilityTest.php:1062
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\flattenCalculatesExpectedResult
‪flattenCalculatesExpectedResult(array $array, array $expected)
Definition: ArrayUtilityTest.php:1298
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterAndSortByNumericKeysWithAcceptAnyKey
‪static filterAndSortByNumericKeysWithAcceptAnyKey()
Definition: ArrayUtilityTest.php:2778
‪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:1303
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\stripTagsFromValuesRecursiveExpectNoTypeCast
‪stripTagsFromValuesRecursiveExpectNoTypeCast()
Definition: ArrayUtilityTest.php:3171
‪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:3482
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffAssocRecursiveHandlesOneDimensionalArrays
‪arrayDiffAssocRecursiveHandlesOneDimensionalArrays()
Definition: ArrayUtilityTest.php:2577
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\convertBooleanStringsToBooleanRecursiveExpectConverting
‪convertBooleanStringsToBooleanRecursiveExpectConverting()
Definition: ArrayUtilityTest.php:3205
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\flattenWithKeepDotsCalculatesExpectedResultDataProvider
‪static flattenWithKeepDotsCalculatesExpectedResultDataProvider()
Definition: ArrayUtilityTest.php:1468
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerZeroByCallbackDataProvider
‪static filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerZeroByCallbackDataProvider()
Definition: ArrayUtilityTest.php:3300
‪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:3006
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\checkRemoveArrayEntryByValueRemovesEntryWithEmptyString
‪checkRemoveArrayEntryByValueRemovesEntryWithEmptyString()
Definition: ArrayUtilityTest.php:2368
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\unflattenCalculatesExpectedResultDataProvider
‪static unflattenCalculatesExpectedResultDataProvider()
Definition: ArrayUtilityTest.php:1583
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\flattenPlainCalculatesExpectedResult
‪flattenPlainCalculatesExpectedResult(array $array, array $expected)
Definition: ArrayUtilityTest.php:1463
‪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:1748
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayExportReturnsFormattedMultidimensionalArray
‪arrayExportReturnsFormattedMultidimensionalArray()
Definition: ArrayUtilityTest.php:1074
‪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:2448
‪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:2331
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\checkRemoveArrayEntryByValueRemovesEntriesFromMultiDimensionalArray
‪checkRemoveArrayEntryByValueRemovesEntriesFromMultiDimensionalArray()
Definition: ArrayUtilityTest.php:2349
‪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:3052
‪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:3290
‪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:2526
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\keepItemsInArrayCanUseClosure
‪keepItemsInArrayCanUseClosure()
Definition: ArrayUtilityTest.php:2425
‪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:2657
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffAssocRecursiveHandlesMixedArrays
‪arrayDiffAssocRecursiveHandlesMixedArrays()
Definition: ArrayUtilityTest.php:2632
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\renumberKeysToAvoidLeapsIfKeysAreAllNumericReturnsExpectedOrder
‪renumberKeysToAvoidLeapsIfKeysAreAllNumericReturnsExpectedOrder(array $inputArray, array $expected)
Definition: ArrayUtilityTest.php:2071
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\naturalKeySortRecursiveSortsOneDimensionalArrayByNaturalOrder
‪naturalKeySortRecursiveSortsOneDimensionalArrayByNaturalOrder()
Definition: ArrayUtilityTest.php:2684
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\isAssociativeCorrectlyFindsStringKeysDataProvider
‪static isAssociativeCorrectlyFindsStringKeysDataProvider()
Definition: ArrayUtilityTest.php:3451
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\flattenCalculatesExpectedResultDataProvider
‪static flattenCalculatesExpectedResultDataProvider()
Definition: ArrayUtilityTest.php:1178
‪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:2596
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayDiffKeyRecursiveHandlesMultiDimensionalArrays
‪arrayDiffKeyRecursiveHandlesMultiDimensionalArrays()
Definition: ArrayUtilityTest.php:2491
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\replaceAndAppendScalarValuesRecursiveCorrectlyMergesArraysDataProvider
‪static replaceAndAppendScalarValuesRecursiveCorrectlyMergesArraysDataProvider()
Definition: ArrayUtilityTest.php:3491
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\renumberKeysToAvoidLeapsIfKeysAreAllNumericDataProvider
‪static renumberKeysToAvoidLeapsIfKeysAreAllNumericDataProvider()
Definition: ArrayUtilityTest.php:1949
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerByCallback
‪filterRecursiveCallbackFiltersEmptyElementsWithoutIntegerByCallback(array $input, array $expectedResult)
Definition: ArrayUtilityTest.php:3365
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\replaceAndAppendScalarValuesRecursiveCorrectlyMergesArrays
‪replaceAndAppendScalarValuesRecursiveCorrectlyMergesArrays(array $array1, array $array2, array $expectedResult)
Definition: ArrayUtilityTest.php:3565
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\filterAndSortByNumericKeysBehavesCorrectlyForAcceptAnyKeysIsFalse
‪filterAndSortByNumericKeysBehavesCorrectlyForAcceptAnyKeysIsFalse($input, $expected)
Definition: ArrayUtilityTest.php:2926
‪TYPO3\CMS\Core\Tests\Unit\Utility\ArrayUtilityTest\arrayExportThrowsExceptionIfObjectShouldBeExported
‪arrayExportThrowsExceptionIfObjectShouldBeExported()
Definition: ArrayUtilityTest.php:1111