Passed
Push — master ( 085e78...e49660 )
by Andrii
12:52
created

ArrayHelperTest::testMergeWithReverseValues()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 14
c 1
b 0
f 0
dl 0
loc 21
rs 9.7998
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Yiisoft\Arrays\Tests;
4
5
use ArrayObject;
6
use InvalidArgumentException;
7
use PHPUnit\Framework\TestCase;
8
use stdClass;
9
use Yiisoft\Arrays\ArrayableInterface;
10
use Yiisoft\Arrays\ArrayHelper;
11
use Yiisoft\Arrays\Modifier\RemoveKeys;
12
use Yiisoft\Arrays\Modifier\ReverseValues;
13
use Yiisoft\Arrays\Modifier\ReplaceValue;
14
use Yiisoft\Arrays\Modifier\UnsetValue;
15
16
final class ArrayHelperTest extends TestCase
17
{
18
    public function testToArray(): void
19
    {
20
        $data = $this->getMockBuilder(ArrayableInterface::class)
21
            ->getMock()
22
            ->method('toArray')
23
            ->willReturn([]);
24
25
        $this->assertEquals([], ArrayHelper::toArray($data));
26
        $this->assertEquals(['foo'], ArrayHelper::toArray('foo'));
27
        $object = new Post1();
28
        $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object));
29
        $object = new Post2();
30
        $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object));
31
32
        $object1 = new Post1();
33
        $object2 = new Post2();
34
        $this->assertEquals(
35
            [
36
                get_object_vars($object1),
37
                get_object_vars($object2),
38
            ],
39
            ArrayHelper::toArray(
40
                [
41
                    $object1,
42
                    $object2,
43
                ]
44
            )
45
        );
46
47
        $object = new Post2();
48
        $this->assertEquals(
49
            [
50
                'id' => 123,
51
                'secret' => 's',
52
                '_content' => 'test',
53
                'length' => 4,
54
            ],
55
            ArrayHelper::toArray(
56
                $object,
57
                [
58
                    get_class($object) => [
59
                        'id',
60
                        'secret',
61
                        '_content' => 'content',
62
                        'length' => function ($post) {
63
                            return strlen($post->content);
64
                        },
65
                    ],
66
                ]
67
            )
68
        );
69
70
        $object = new Post3();
71
        $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object, [], false));
72
        $this->assertEquals(
73
            [
74
                'id' => 33,
75
                'subObject' => [
76
                    'id' => 123,
77
                    'content' => 'test',
78
                ],
79
            ],
80
            ArrayHelper::toArray($object)
81
        );
82
83
        //recursive with attributes of object and subobject
84
        $this->assertEquals(
85
            [
86
                'id' => 33,
87
                'id_plus_1' => 34,
88
                'subObject' => [
89
                    'id' => 123,
90
                    'id_plus_1' => 124,
91
                ],
92
            ],
93
            ArrayHelper::toArray(
94
                $object,
95
                [
96
                    get_class($object) => [
97
                        'id',
98
                        'subObject',
99
                        'id_plus_1' => static function ($post) {
100
                            return $post->id + 1;
101
                        },
102
                    ],
103
                    get_class($object->subObject) => [
104
                        'id',
105
                        'id_plus_1' => static function ($post) {
106
                            return $post->id + 1;
107
                        },
108
                    ],
109
                ]
110
            )
111
        );
112
113
        //recursive with attributes of subobject only
114
        $this->assertEquals(
115
            [
116
                'id' => 33,
117
                'subObject' => [
118
                    'id' => 123,
119
                    'id_plus_1' => 124,
120
                ],
121
            ],
122
            ArrayHelper::toArray(
123
                $object,
124
                [
125
                    get_class($object->subObject) => [
126
                        'id',
127
                        'id_plus_1' => static function ($post) {
128
                            return $post->id + 1;
129
                        },
130
                    ],
131
                ]
132
            )
133
        );
134
    }
135
136
    public function testRemove(): void
137
    {
138
        $array = ['name' => 'b', 'age' => 3];
139
        $name = ArrayHelper::remove($array, 'name');
140
141
        $this->assertEquals('b', $name);
142
        $this->assertEquals(['age' => 3], $array);
143
144
        $default = ArrayHelper::remove($array, 'nonExisting', 'defaultValue');
145
        $this->assertEquals('defaultValue', $default);
146
    }
147
148
    public function testRemoveValueMultiple(): void
149
    {
150
        $array = [
151
            'Bob' => 'Dylan',
152
            'Michael' => 'Jackson',
153
            'Mick' => 'Jagger',
154
            'Janet' => 'Jackson',
155
        ];
156
157
        $removed = ArrayHelper::removeValue($array, 'Jackson');
158
159
        $this->assertEquals(
160
            [
161
                'Bob' => 'Dylan',
162
                'Mick' => 'Jagger',
163
            ],
164
            $array
165
        );
166
        $this->assertEquals(
167
            [
168
                'Michael' => 'Jackson',
169
                'Janet' => 'Jackson',
170
            ],
171
            $removed
172
        );
173
    }
174
175
    public function testRemoveValueNotExisting(): void
176
    {
177
        $array = [
178
            'Bob' => 'Dylan',
179
            'Michael' => 'Jackson',
180
            'Mick' => 'Jagger',
181
            'Janet' => 'Jackson',
182
        ];
183
184
        $removed = ArrayHelper::removeValue($array, 'Marley');
185
186
        $this->assertEquals(
187
            [
188
                'Bob' => 'Dylan',
189
                'Michael' => 'Jackson',
190
                'Mick' => 'Jagger',
191
                'Janet' => 'Jackson',
192
            ],
193
            $array
194
        );
195
        $this->assertEquals([], $removed);
196
    }
197
198
    public function testEmptyMerge(): void
199
    {
200
        $this->assertEquals([], ArrayHelper::merge(...[]));
201
    }
202
203
    public function testMerge(): void
204
    {
205
        $a = [
206
            'name' => 'Yii',
207
            'version' => '1.0',
208
            'options' => [
209
                'namespace' => false,
210
                'unittest' => false,
211
            ],
212
            'features' => [
213
                'mvc',
214
            ],
215
        ];
216
        $b = [
217
            'version' => '1.1',
218
            'options' => [
219
                'unittest' => true,
220
            ],
221
            'features' => [
222
                'gii',
223
            ],
224
        ];
225
        $c = [
226
            'version' => '2.0',
227
            'options' => [
228
                'namespace' => true,
229
            ],
230
            'features' => [
231
                'debug',
232
            ],
233
            'foo',
234
        ];
235
236
        $result = ArrayHelper::merge($a, $b, $c);
237
        $expected = [
238
            'name' => 'Yii',
239
            'version' => '2.0',
240
            'options' => [
241
                'namespace' => true,
242
                'unittest' => true,
243
            ],
244
            'features' => [
245
                'mvc',
246
                'gii',
247
                'debug',
248
            ],
249
            'foo',
250
        ];
251
252
        $this->assertEquals($expected, $result);
253
    }
254
255
    public function testMergeWithUnset(): void
256
    {
257
        $a = [
258
            'name' => 'Yii',
259
            'version' => '1.0',
260
            'options' => [
261
                'namespace' => false,
262
                'unittest' => false,
263
            ],
264
            'features' => [
265
                'mvc',
266
            ],
267
        ];
268
        $b = [
269
            'version' => '1.1',
270
            'options' => new UnsetValue(),
271
            'features' => [
272
                'gii',
273
            ],
274
        ];
275
276
        $result = ArrayHelper::merge($a, $b);
277
        $expected = [
278
            'name' => 'Yii',
279
            'version' => '1.1',
280
            'features' => [
281
                'mvc',
282
                'gii',
283
            ],
284
        ];
285
286
        $this->assertEquals($expected, $result);
287
    }
288
289
    public function testMergeWithReplace(): void
290
    {
291
        $a = [
292
            'name' => 'Yii',
293
            'version' => '1.0',
294
            'options' => [
295
                'namespace' => false,
296
                'unittest' => false,
297
            ],
298
            'features' => [
299
                'mvc',
300
            ],
301
        ];
302
        $b = [
303
            'version' => '1.1',
304
            'options' => [
305
                'unittest' => true,
306
            ],
307
            'features' => new ReplaceValue(
308
                [
309
                    'gii',
310
                ]
311
            ),
312
        ];
313
314
        $result = ArrayHelper::merge($a, $b);
315
        $expected = [
316
            'name' => 'Yii',
317
            'version' => '1.1',
318
            'options' => [
319
                'namespace' => false,
320
                'unittest' => true,
321
            ],
322
            'features' => [
323
                'gii',
324
            ],
325
        ];
326
327
        $this->assertEquals($expected, $result);
328
    }
329
330
    public function testMergeWithRemoveKeys(): void
331
    {
332
        $a = [
333
            'name' => 'Yii',
334
            'version' => '1.0',
335
        ];
336
        $b = [
337
            'version' => '1.1',
338
            'options' => [],
339
            new RemoveKeys(),
340
        ];
341
342
        $result = ArrayHelper::merge($a, $b);
343
        $expected = [
344
            'Yii',
345
            '1.1',
346
            [],
347
        ];
348
349
        $this->assertEquals($expected, $result);
350
    }
351
352
    public function testMergeWithReverseValues(): void
353
    {
354
        $a = [
355
            'name' => 'Yii',
356
            'version' => '1.0',
357
            ReverseValues::class => new ReverseValues(),
358
        ];
359
        $b = [
360
            'version' => '1.1',
361
            'options' => [],
362
            ReverseValues::class => new ReverseValues(),
363
        ];
364
365
        $result = ArrayHelper::merge($a, $b);
366
        $expected = [
367
            'options' => [],
368
            'version' => '1.1',
369
            'name' => 'Yii',
370
        ];
371
372
        $this->assertSame($expected, $result);
373
    }
374
375
    public function testMergeWithNullValues(): void
376
    {
377
        $a = [
378
            'firstValue',
379
            null,
380
        ];
381
        $b = [
382
            'secondValue',
383
            'thirdValue'
384
        ];
385
386
        $result = ArrayHelper::merge($a, $b);
387
        $expected = [
388
            'firstValue',
389
            null,
390
            'secondValue',
391
            'thirdValue',
392
        ];
393
394
        $this->assertEquals($expected, $result);
395
    }
396
397
398
    public function testMergeIntegerKeyedArraysWithSameValue(): void
399
    {
400
        $a = ['2019-01-25'];
401
        $b = ['2019-01-25'];
402
        $c = ['2019-01-25'];
403
404
        $result = ArrayHelper::merge($a, $b, $c);
405
        $expected = ['2019-01-25'];
406
407
        $this->assertEquals($expected, $result);
408
    }
409
410
    /**
411
     * @see https://github.com/yiisoft/yii2/pull/11549
412
     */
413
    public function testFloatKey(): void
414
    {
415
        $array = [];
416
        $array[1.0] = 'some value';
417
418
        $result = ArrayHelper::getValue($array, 1.0);
419
420
        $this->assertEquals('some value', $result);
421
    }
422
423
    public function testIndex(): void
424
    {
425
        $array = [
426
            ['id' => '123', 'data' => 'abc'],
427
            ['id' => '345', 'data' => 'def'],
428
            ['id' => '345', 'data' => 'ghi'],
429
        ];
430
        $result = ArrayHelper::index($array, 'id');
431
        $this->assertEquals(
432
            [
433
                '123' => ['id' => '123', 'data' => 'abc'],
434
                '345' => ['id' => '345', 'data' => 'ghi'],
435
            ],
436
            $result
437
        );
438
439
        $result = ArrayHelper::index(
440
            $array,
441
            static function ($element) {
442
                return $element['data'];
443
            }
444
        );
445
        $this->assertEquals(
446
            [
447
                'abc' => ['id' => '123', 'data' => 'abc'],
448
                'def' => ['id' => '345', 'data' => 'def'],
449
                'ghi' => ['id' => '345', 'data' => 'ghi'],
450
            ],
451
            $result
452
        );
453
454
        $result = ArrayHelper::index($array, null);
455
        $this->assertEquals([], $result);
456
457
        $result = ArrayHelper::index(
458
            $array,
459
            static function () {
460
                return null;
461
            }
462
        );
463
        $this->assertEquals([], $result);
464
465
        $result = ArrayHelper::index(
466
            $array,
467
            static function ($element) {
468
                return $element['id'] === '345' ? null : $element['id'];
469
            }
470
        );
471
        $this->assertEquals(
472
            [
473
                '123' => ['id' => '123', 'data' => 'abc'],
474
            ],
475
            $result
476
        );
477
    }
478
479
    public function testIndexGroupBy(): void
480
    {
481
        $array = [
482
            ['id' => '123', 'data' => 'abc'],
483
            ['id' => '345', 'data' => 'def'],
484
            ['id' => '345', 'data' => 'ghi'],
485
        ];
486
487
        $expected = [
488
            '123' => [
489
                ['id' => '123', 'data' => 'abc'],
490
            ],
491
            '345' => [
492
                ['id' => '345', 'data' => 'def'],
493
                ['id' => '345', 'data' => 'ghi'],
494
            ],
495
        ];
496
        $result = ArrayHelper::index($array, null, ['id']);
497
        $this->assertEquals($expected, $result);
498
        $result = ArrayHelper::index($array, null, 'id');
499
        $this->assertEquals($expected, $result);
500
501
        $result = ArrayHelper::index($array, null, ['id', 'data']);
502
        $this->assertEquals(
503
            [
504
                '123' => [
505
                    'abc' => [
506
                        ['id' => '123', 'data' => 'abc'],
507
                    ],
508
                ],
509
                '345' => [
510
                    'def' => [
511
                        ['id' => '345', 'data' => 'def'],
512
                    ],
513
                    'ghi' => [
514
                        ['id' => '345', 'data' => 'ghi'],
515
                    ],
516
                ],
517
            ],
518
            $result
519
        );
520
521
        $expected = [
522
            '123' => [
523
                'abc' => ['id' => '123', 'data' => 'abc'],
524
            ],
525
            '345' => [
526
                'def' => ['id' => '345', 'data' => 'def'],
527
                'ghi' => ['id' => '345', 'data' => 'ghi'],
528
            ],
529
        ];
530
        $result = ArrayHelper::index($array, 'data', ['id']);
531
        $this->assertEquals($expected, $result);
532
        $result = ArrayHelper::index($array, 'data', 'id');
533
        $this->assertEquals($expected, $result);
534
        $result = ArrayHelper::index(
535
            $array,
536
            static function ($element) {
537
                return $element['data'];
538
            },
539
            'id'
540
        );
541
        $this->assertEquals($expected, $result);
542
543
        $expected = [
544
            '123' => [
545
                'abc' => [
546
                    'abc' => ['id' => '123', 'data' => 'abc'],
547
                ],
548
            ],
549
            '345' => [
550
                'def' => [
551
                    'def' => ['id' => '345', 'data' => 'def'],
552
                ],
553
                'ghi' => [
554
                    'ghi' => ['id' => '345', 'data' => 'ghi'],
555
                ],
556
            ],
557
        ];
558
        $result = ArrayHelper::index($array, 'data', ['id', 'data']);
559
        $this->assertEquals($expected, $result);
560
        $result = ArrayHelper::index(
561
            $array,
562
            static function ($element) {
563
                return $element['data'];
564
            },
565
            ['id', 'data']
566
        );
567
        $this->assertEquals($expected, $result);
568
    }
569
570
    /**
571
     * @see https://github.com/yiisoft/yii2/issues/11739
572
     */
573
    public function testIndexFloat(): void
574
    {
575
        $array = [
576
            ['id' => 1e6],
577
            ['id' => 1e32],
578
            ['id' => 1e64],
579
            ['id' => 1465540807.522109],
580
        ];
581
582
        $expected = [
583
            '1000000' => ['id' => 1e6],
584
            '1.0E+32' => ['id' => 1e32],
585
            '1.0E+64' => ['id' => 1e64],
586
            '1465540807.5221' => ['id' => 1465540807.522109],
587
        ];
588
589
        $result = ArrayHelper::index($array, 'id');
590
591
        $this->assertEquals($expected, $result);
592
    }
593
594
    public function testGetColumn(): void
595
    {
596
        $array = [
597
            'a' => ['id' => '123', 'data' => 'abc'],
598
            'b' => ['id' => '345', 'data' => 'def'],
599
        ];
600
        $result = ArrayHelper::getColumn($array, 'id');
601
        $this->assertEquals(['a' => '123', 'b' => '345'], $result);
602
        $result = ArrayHelper::getColumn($array, 'id', false);
603
        $this->assertEquals(['123', '345'], $result);
604
605
        $result = ArrayHelper::getColumn(
606
            $array,
607
            static function ($element) {
608
                return $element['data'];
609
            }
610
        );
611
        $this->assertEquals(['a' => 'abc', 'b' => 'def'], $result);
612
        $result = ArrayHelper::getColumn(
613
            $array,
614
            static function ($element) {
615
                return $element['data'];
616
            },
617
            false
618
        );
619
        $this->assertEquals(['abc', 'def'], $result);
620
    }
621
622
    public function testMap(): void
623
    {
624
        $array = [
625
            ['id' => '123', 'name' => 'aaa', 'class' => 'x'],
626
            ['id' => '124', 'name' => 'bbb', 'class' => 'x'],
627
            ['id' => '345', 'name' => 'ccc', 'class' => 'y'],
628
        ];
629
630
        $result = ArrayHelper::map($array, 'id', 'name');
631
        $this->assertEquals(
632
            [
633
                '123' => 'aaa',
634
                '124' => 'bbb',
635
                '345' => 'ccc',
636
            ],
637
            $result
638
        );
639
640
        $result = ArrayHelper::map($array, 'id', 'name', 'class');
641
        $this->assertEquals(
642
            [
643
                'x' => [
644
                    '123' => 'aaa',
645
                    '124' => 'bbb',
646
                ],
647
                'y' => [
648
                    '345' => 'ccc',
649
                ],
650
            ],
651
            $result
652
        );
653
    }
654
655
    public function testKeyExists(): void
656
    {
657
        $array = [
658
            'a' => 1,
659
            'B' => 2,
660
        ];
661
        $this->assertTrue(ArrayHelper::keyExists($array, 'a'));
662
        $this->assertFalse(ArrayHelper::keyExists($array, 'b'));
663
        $this->assertTrue(ArrayHelper::keyExists($array, 'B'));
664
        $this->assertFalse(ArrayHelper::keyExists($array, 'c'));
665
666
        $this->assertTrue(ArrayHelper::keyExists($array, 'a', false));
667
        $this->assertTrue(ArrayHelper::keyExists($array, 'b', false));
668
        $this->assertTrue(ArrayHelper::keyExists($array, 'B', false));
669
        $this->assertFalse(ArrayHelper::keyExists($array, 'c', false));
670
    }
671
672
    public function getValueFromArrayProvider(): array
673
    {
674
        return [
675
            ['name', 'test'],
676
            ['noname', null],
677
            ['noname', 'test', 'test'],
678
            ['post.id', 5],
679
            ['post.id', 5, 'test'],
680
            ['nopost.id', null],
681
            ['nopost.id', 'test', 'test'],
682
            ['post.author.name', 'cebe'],
683
            ['post.author.noname', null],
684
            ['post.author.noname', 'test', 'test'],
685
            ['post.author.profile.title', '1337'],
686
            ['admin.firstname', 'Qiang'],
687
            ['admin.firstname', 'Qiang', 'test'],
688
            ['admin.lastname', 'Xue'],
689
            [
690
                static function ($array, $defaultValue) {
691
                    return $array['date'] . $defaultValue;
692
                },
693
                '31-12-2113test',
694
                'test',
695
            ],
696
            [['version', '1.0', 'status'], 'released'],
697
            [['version', '1.0', 'date'], 'defaultValue', 'defaultValue'],
698
        ];
699
    }
700
701
    /**
702
     * @dataProvider getValueFromArrayProvider
703
     *
704
     * @param $key
705
     * @param $expected
706
     * @param null $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
707
     */
708
    public function testGetValueFromArray($key, $expected, $default = null): void
709
    {
710
        $array = [
711
            'name' => 'test',
712
            'date' => '31-12-2113',
713
            'post' => [
714
                'id' => 5,
715
                'author' => [
716
                    'name' => 'cebe',
717
                    'profile' => [
718
                        'title' => '1337',
719
                    ],
720
                ],
721
            ],
722
            'admin.firstname' => 'Qiang',
723
            'admin.lastname' => 'Xue',
724
            'admin' => [
725
                'lastname' => 'cebe',
726
            ],
727
            'version' => [
728
                '1.0' => [
729
                    'status' => 'released',
730
                ],
731
            ],
732
        ];
733
734
        $this->assertEquals($expected, ArrayHelper::getValue($array, $key, $default));
735
    }
736
737
    /**
738
     * @see https://github.com/yiisoft/arrays/issues/1
739
     */
740
    public function testGetValueConsistentWithSetValue(): void
741
    {
742
        $array = [
743
            'a.b' => [
744
                'c' => 'value1',
745
            ],
746
        ];
747
        $this->assertEquals(null, ArrayHelper::getValue($array, 'a.b.c'));
748
        ArrayHelper::setValue($array, 'a.b.c', 'newValue');
749
        $this->assertEquals('newValue', ArrayHelper::getValue($array, 'a.b.c'));
750
    }
751
752
    public function testGetValueObjects(): void
753
    {
754
        $arrayObject = new ArrayObject(['id' => 23], ArrayObject::ARRAY_AS_PROPS);
755
        $this->assertEquals(23, ArrayHelper::getValue($arrayObject, 'id'));
756
757
        $object = new Post1();
758
        $this->assertEquals(23, ArrayHelper::getValue($object, 'id'));
759
    }
760
761
    public function testGetNestedObjectsValueFromObject(): void
762
    {
763
        $object = new stdClass();
764
        $object->subObject = new stdClass();
765
        $object->subObject->id = 155;
766
767
        $this->assertEquals(155, ArrayHelper::getValue($object, 'subObject.id'));
768
    }
769
770
    public function testGetNestedValueFromObjectThatFromArrayFromObject(): void
771
    {
772
        $subObject = new stdClass();
773
        $subObject->id = 200;
774
775
        $object = new stdClass();
776
        $object->subObject = ['sub' => $subObject];
777
778
        $this->assertEquals(200, ArrayHelper::getValue($object, 'subObject.sub.id'));
779
    }
780
781
    public function testGetNestedValueFromObjectFromArray(): void
782
    {
783
        $stdClass = new stdClass();
784
        $stdClass->id = 250;
785
        $object = ['main' => $stdClass];
786
787
        $this->assertEquals(250, ArrayHelper::getValue($object, 'main.id'));
788
    }
789
790
    /**
791
     * This is expected to result in a PHP error.
792
     */
793
    public function testGetValueNonexistingProperties1(): void
794
    {
795
        $this->expectError();
796
        $object = new Post1();
797
        $this->assertNull(ArrayHelper::getValue($object, 'nonExisting'));
798
    }
799
800
    /**
801
     * This is expected to result in a PHP error.
802
     */
803
    public function testGetValueNonexistingProperties2(): void
804
    {
805
        $this->expectError();
806
        $arrayObject = new ArrayObject(['id' => 23], ArrayObject::ARRAY_AS_PROPS);
807
        $this->assertEquals(23, ArrayHelper::getValue($arrayObject, 'nonExisting'));
808
    }
809
810
    /**
811
     * Data provider for [[testSetValue()]].
812
     * @return array test data
813
     */
814
    public function dataProviderSetValue(): array
815
    {
816
        return [
817
            [
818
                [
819
                    'key1' => 'val1',
820
                    'key2' => 'val2',
821
                ],
822
                'key',
823
                'val',
824
                [
825
                    'key1' => 'val1',
826
                    'key2' => 'val2',
827
                    'key' => 'val',
828
                ],
829
            ],
830
            [
831
                [
832
                    'key1' => 'val1',
833
                    'key2' => 'val2',
834
                ],
835
                'key2',
836
                'val',
837
                [
838
                    'key1' => 'val1',
839
                    'key2' => 'val',
840
                ],
841
            ],
842
843
            [
844
                [
845
                    'key1' => 'val1',
846
                ],
847
                'key.in',
848
                'val',
849
                [
850
                    'key1' => 'val1',
851
                    'key' => ['in' => 'val'],
852
                ],
853
            ],
854
            [
855
                [
856
                    'key' => 'val1',
857
                ],
858
                'key.in',
859
                'val',
860
                [
861
                    'key' => [
862
                        'val1',
863
                        'in' => 'val',
864
                    ],
865
                ],
866
            ],
867
            [
868
                [
869
                    'key' => 'val1',
870
                ],
871
                'key',
872
                ['in' => 'val'],
873
                [
874
                    'key' => ['in' => 'val'],
875
                ],
876
            ],
877
878
            [
879
                [
880
                    'key1' => 'val1',
881
                ],
882
                'key.in.0',
883
                'val',
884
                [
885
                    'key1' => 'val1',
886
                    'key' => [
887
                        'in' => ['val'],
888
                    ],
889
                ],
890
            ],
891
892
            [
893
                [
894
                    'key1' => 'val1',
895
                ],
896
                'key.in.arr',
897
                'val',
898
                [
899
                    'key1' => 'val1',
900
                    'key' => [
901
                        'in' => [
902
                            'arr' => 'val',
903
                        ],
904
                    ],
905
                ],
906
            ],
907
            [
908
                [
909
                    'key1' => 'val1',
910
                ],
911
                'key.in.arr',
912
                ['val'],
913
                [
914
                    'key1' => 'val1',
915
                    'key' => [
916
                        'in' => [
917
                            'arr' => ['val'],
918
                        ],
919
                    ],
920
                ],
921
            ],
922
            [
923
                [
924
                    'key' => [
925
                        'in' => ['val1'],
926
                    ],
927
                ],
928
                'key.in.arr',
929
                'val',
930
                [
931
                    'key' => [
932
                        'in' => [
933
                            'val1',
934
                            'arr' => 'val',
935
                        ],
936
                    ],
937
                ],
938
            ],
939
940
            [
941
                [
942
                    'key' => ['in' => 'val1'],
943
                ],
944
                'key.in.arr',
945
                ['val'],
946
                [
947
                    'key' => [
948
                        'in' => [
949
                            'val1',
950
                            'arr' => ['val'],
951
                        ],
952
                    ],
953
                ],
954
            ],
955
            [
956
                [
957
                    'key' => [
958
                        'in' => [
959
                            'val1',
960
                            'key' => 'val',
961
                        ],
962
                    ],
963
                ],
964
                'key.in.0',
965
                ['arr' => 'val'],
966
                [
967
                    'key' => [
968
                        'in' => [
969
                            ['arr' => 'val'],
970
                            'key' => 'val',
971
                        ],
972
                    ],
973
                ],
974
            ],
975
            [
976
                [
977
                    'key' => [
978
                        'in' => [
979
                            'val1',
980
                            'key' => 'val',
981
                        ],
982
                    ],
983
                ],
984
                'key.in',
985
                ['arr' => 'val'],
986
                [
987
                    'key' => [
988
                        'in' => ['arr' => 'val'],
989
                    ],
990
                ],
991
            ],
992
            [
993
                [
994
                    'key' => [
995
                        'in' => [
996
                            'key' => 'val',
997
                            'data' => [
998
                                'attr1',
999
                                'attr2',
1000
                                'attr3',
1001
                            ],
1002
                        ],
1003
                    ],
1004
                ],
1005
                'key.in.schema',
1006
                'array',
1007
                [
1008
                    'key' => [
1009
                        'in' => [
1010
                            'key' => 'val',
1011
                            'schema' => 'array',
1012
                            'data' => [
1013
                                'attr1',
1014
                                'attr2',
1015
                                'attr3',
1016
                            ],
1017
                        ],
1018
                    ],
1019
                ],
1020
            ],
1021
            [
1022
                [
1023
                    'key' => [
1024
                        'in.array' => [
1025
                            'key' => 'val',
1026
                        ],
1027
                    ],
1028
                ],
1029
                ['key', 'in.array', 'ok.schema'],
1030
                'array',
1031
                [
1032
                    'key' => [
1033
                        'in.array' => [
1034
                            'key' => 'val',
1035
                            'ok.schema' => 'array',
1036
                        ],
1037
                    ],
1038
                ],
1039
            ],
1040
            [
1041
                [
1042
                    'key' => ['val'],
1043
                ],
1044
                null,
1045
                'data',
1046
                'data',
1047
            ],
1048
        ];
1049
    }
1050
1051
    /**
1052
     * @dataProvider dataProviderSetValue
1053
     *
1054
     * @param array $arrayInput
1055
     * @param string|array|null $key
1056
     * @param mixed $value
1057
     * @param mixed $expected
1058
     */
1059
    public function testSetValue(array $arrayInput, $key, $value, $expected): void
1060
    {
1061
        ArrayHelper::setValue($arrayInput, $key, $value);
1062
        $this->assertEquals($expected, $arrayInput);
1063
    }
1064
1065
    public function testIsAssociative(): void
1066
    {
1067
        $this->assertFalse(ArrayHelper::isAssociative([]));
1068
        $this->assertFalse(ArrayHelper::isAssociative([1, 2, 3]));
1069
        $this->assertFalse(ArrayHelper::isAssociative([1], false));
1070
        $this->assertTrue(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test']));
1071
        $this->assertFalse(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test', 3]));
1072
        $this->assertTrue(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test', 3], false));
1073
    }
1074
1075
    public function testIsIndexed(): void
1076
    {
1077
        $this->assertTrue(ArrayHelper::isIndexed([]));
1078
        $this->assertTrue(ArrayHelper::isIndexed([1, 2, 3]));
1079
        $this->assertTrue(ArrayHelper::isIndexed([2 => 'a', 3 => 'b']));
1080
        $this->assertFalse(ArrayHelper::isIndexed([2 => 'a', 3 => 'b'], true));
1081
        $this->assertFalse(ArrayHelper::isIndexed(['a' => 'b'], false));
1082
    }
1083
1084
    public function testHtmlEncode(): void
1085
    {
1086
        $array = [
1087
            'abc' => '123',
1088
            '<' => '>',
1089
            'cde' => false,
1090
            3 => 'blank',
1091
            [
1092
                '<>' => 'a<>b',
1093
                '23' => true,
1094
            ],
1095
            'invalid' => "a\x80b",
1096
        ];
1097
        $this->assertEquals(
1098
            [
1099
                'abc' => '123',
1100
                '<' => '&gt;',
1101
                'cde' => false,
1102
                3 => 'blank',
1103
                [
1104
                    '<>' => 'a&lt;&gt;b',
1105
                    '23' => true,
1106
                ],
1107
                'invalid' => 'a�b',
1108
            ],
1109
            ArrayHelper::htmlEncode($array)
1110
        );
1111
        $this->assertEquals(
1112
            [
1113
                'abc' => '123',
1114
                '&lt;' => '&gt;',
1115
                'cde' => false,
1116
                3 => 'blank',
1117
                [
1118
                    '&lt;&gt;' => 'a&lt;&gt;b',
1119
                    '23' => true,
1120
                ],
1121
                'invalid' => 'a�b',
1122
            ],
1123
            ArrayHelper::htmlEncode($array, false)
1124
        );
1125
    }
1126
1127
    public function testHtmlDecode(): void
1128
    {
1129
        $array = [
1130
            'abc' => '123',
1131
            '&lt;' => '&gt;',
1132
            'cde' => false,
1133
            3 => 'blank',
1134
            [
1135
                '<>' => 'a&lt;&gt;b',
1136
                '23' => true,
1137
            ],
1138
        ];
1139
        $this->assertEquals(
1140
            [
1141
                'abc' => '123',
1142
                '&lt;' => '>',
1143
                'cde' => false,
1144
                3 => 'blank',
1145
                [
1146
                    '<>' => 'a<>b',
1147
                    '23' => true,
1148
                ],
1149
            ],
1150
            ArrayHelper::htmlDecode($array)
1151
        );
1152
        $this->assertEquals(
1153
            [
1154
                'abc' => '123',
1155
                '<' => '>',
1156
                'cde' => false,
1157
                3 => 'blank',
1158
                [
1159
                    '<>' => 'a<>b',
1160
                    '23' => true,
1161
                ],
1162
            ],
1163
            ArrayHelper::htmlDecode($array, false)
1164
        );
1165
    }
1166
1167
    public function testIsIn(): void
1168
    {
1169
        $this->assertTrue(ArrayHelper::isIn('a', new ArrayObject(['a', 'b'])));
1170
        $this->assertTrue(ArrayHelper::isIn('a', ['a', 'b']));
1171
1172
        $this->assertTrue(ArrayHelper::isIn('1', new ArrayObject([1, 'b'])));
1173
        $this->assertTrue(ArrayHelper::isIn('1', [1, 'b']));
1174
1175
        $this->assertFalse(ArrayHelper::isIn('1', new ArrayObject([1, 'b']), true));
1176
        $this->assertFalse(ArrayHelper::isIn('1', [1, 'b'], true));
1177
1178
        $this->assertTrue(ArrayHelper::isIn(['a'], new ArrayObject([['a'], 'b'])));
1179
        $this->assertFalse(ArrayHelper::isIn('a', new ArrayObject([['a'], 'b'])));
1180
        $this->assertFalse(ArrayHelper::isIn('a', [['a'], 'b']));
1181
    }
1182
1183
    public function testIsInStrict(): void
1184
    {
1185
        // strict comparison
1186
        $this->assertTrue(ArrayHelper::isIn(1, new ArrayObject([1, 'a']), true));
1187
        $this->assertTrue(ArrayHelper::isIn(1, [1, 'a'], true));
1188
1189
        $this->assertFalse(ArrayHelper::isIn('1', new ArrayObject([1, 'a']), true));
1190
        $this->assertFalse(ArrayHelper::isIn('1', [1, 'a'], true));
1191
    }
1192
1193
    public function testIsSubset(): void
1194
    {
1195
        $this->assertTrue(ArrayHelper::isSubset(['a'], new ArrayObject(['a', 'b'])));
1196
        $this->assertTrue(ArrayHelper::isSubset(new ArrayObject(['a']), ['a', 'b']));
1197
1198
        $this->assertTrue(ArrayHelper::isSubset([1], new ArrayObject(['1', 'b'])));
1199
        $this->assertTrue(ArrayHelper::isSubset(new ArrayObject([1]), ['1', 'b']));
1200
1201
        $this->assertFalse(ArrayHelper::isSubset([1], new ArrayObject(['1', 'b']), true));
1202
        $this->assertFalse(ArrayHelper::isSubset(new ArrayObject([1]), ['1', 'b'], true));
1203
    }
1204
1205
    public function testIsArray(): void
1206
    {
1207
        $this->assertTrue(ArrayHelper::isTraversable(['a']));
1208
        $this->assertTrue(ArrayHelper::isTraversable(new ArrayObject(['1'])));
1209
        $this->assertFalse(ArrayHelper::isTraversable(new stdClass()));
1210
        $this->assertFalse(ArrayHelper::isTraversable('A,B,C'));
1211
        $this->assertFalse(ArrayHelper::isTraversable(12));
1212
        $this->assertFalse(ArrayHelper::isTraversable(false));
1213
        $this->assertFalse(ArrayHelper::isTraversable(null));
1214
    }
1215
1216
    public function testFilter(): void
1217
    {
1218
        $array = [
1219
            'A' => [
1220
                'B' => 1,
1221
                'C' => 2,
1222
                'D' => [
1223
                    'E' => 1,
1224
                    'F' => 2,
1225
                ],
1226
            ],
1227
            'G' => 1,
1228
        ];
1229
1230
        // Include tests
1231
        $this->assertEquals(
1232
            [
1233
                'A' => [
1234
                    'B' => 1,
1235
                    'C' => 2,
1236
                    'D' => [
1237
                        'E' => 1,
1238
                        'F' => 2,
1239
                    ],
1240
                ],
1241
            ],
1242
            ArrayHelper::filter($array, ['A'])
1243
        );
1244
1245
        $this->assertEquals(
1246
            [
1247
                'A' => [
1248
                    'B' => 1,
1249
                ],
1250
            ],
1251
            ArrayHelper::filter($array, ['A.B'])
1252
        );
1253
1254
        $this->assertEquals(
1255
            [
1256
                'A' => [
1257
                    'D' => [
1258
                        'E' => 1,
1259
                        'F' => 2,
1260
                    ],
1261
                ],
1262
            ],
1263
            ArrayHelper::filter($array, ['A.D'])
1264
        );
1265
1266
        $this->assertEquals(
1267
            [
1268
                'A' => [
1269
                    'D' => [
1270
                        'E' => 1,
1271
                    ],
1272
                ],
1273
            ],
1274
            ArrayHelper::filter($array, ['A.D.E'])
1275
        );
1276
1277
        $this->assertEquals(
1278
            [
1279
                'A' => [
1280
                    'B' => 1,
1281
                    'C' => 2,
1282
                    'D' => [
1283
                        'E' => 1,
1284
                        'F' => 2,
1285
                    ],
1286
                ],
1287
                'G' => 1,
1288
            ],
1289
            ArrayHelper::filter($array, ['A', 'G'])
1290
        );
1291
1292
        $this->assertEquals(
1293
            [
1294
                'A' => [
1295
                    'D' => [
1296
                        'E' => 1,
1297
                    ],
1298
                ],
1299
                'G' => 1,
1300
            ],
1301
            ArrayHelper::filter($array, ['A.D.E', 'G'])
1302
        );
1303
1304
        // Exclude (combined with include) tests
1305
        $this->assertEquals(
1306
            [
1307
                'A' => [
1308
                    'C' => 2,
1309
                    'D' => [
1310
                        'E' => 1,
1311
                        'F' => 2,
1312
                    ],
1313
                ],
1314
            ],
1315
            ArrayHelper::filter($array, ['A', '!A.B'])
1316
        );
1317
1318
        $this->assertEquals(
1319
            [
1320
                'A' => [
1321
                    'C' => 2,
1322
                    'D' => [
1323
                        'E' => 1,
1324
                        'F' => 2,
1325
                    ],
1326
                ],
1327
            ],
1328
            ArrayHelper::filter($array, ['!A.B', 'A'])
1329
        );
1330
1331
        $this->assertEquals(
1332
            [
1333
                'A' => [
1334
                    'B' => 1,
1335
                    'C' => 2,
1336
                    'D' => [
1337
                        'F' => 2,
1338
                    ],
1339
                ],
1340
            ],
1341
            ArrayHelper::filter($array, ['A', '!A.D.E'])
1342
        );
1343
1344
        $this->assertEquals(
1345
            [
1346
                'A' => [
1347
                    'B' => 1,
1348
                    'C' => 2,
1349
                ],
1350
            ],
1351
            ArrayHelper::filter($array, ['A', '!A.D'])
1352
        );
1353
    }
1354
1355
    public function testFilterNonExistingKeys(): void
1356
    {
1357
        $array = [
1358
            'A' => [
1359
                'B' => 1,
1360
                'C' => 2,
1361
                'D' => [
1362
                    'E' => 1,
1363
                    'F' => 2,
1364
                ],
1365
            ],
1366
            'G' => 1,
1367
        ];
1368
1369
        $this->assertEquals([], ArrayHelper::filter($array, ['X']));
1370
        $this->assertEquals([], ArrayHelper::filter($array, ['X.Y']));
1371
        $this->assertEquals([], ArrayHelper::filter($array, ['A.X']));
1372
    }
1373
1374
    /**
1375
     * Values that evaluate to `true` with `empty()` tests
1376
     */
1377
    public function testFilterEvaluatedToEmpty(): void
1378
    {
1379
        $input = [
1380
            'a' => 0,
1381
            'b' => '',
1382
            'c' => false,
1383
            'd' => null,
1384
            'e' => true,
1385
        ];
1386
1387
        $this->assertEquals(ArrayHelper::filter($input, array_keys($input)), $input);
1388
    }
1389
1390
    public function testExistingMagicObjectProperty(): void
1391
    {
1392
        $magic = new Magic(['name' => 'Wilmer']);
1393
        $this->assertEquals('Wilmer', ArrayHelper::getValue($magic, 'name'));
1394
    }
1395
1396
    public function testNonExistingMagicObjectProperty(): void
1397
    {
1398
        $magic = new Magic([]);
1399
1400
        $this->expectException(\InvalidArgumentException::class);
1401
1402
        ArrayHelper::getValue($magic, 'name');
1403
    }
1404
1405
    public function testExistingNestedMagicObjectProperty(): void
1406
    {
1407
        $storage = new stdClass();
1408
        $storage->magic = new Magic(['name' => 'Wilmer']);
1409
        $this->assertEquals('Wilmer', ArrayHelper::getValue($storage, 'magic.name'));
1410
    }
1411
1412
    public function testNonExistingNestedMagicObjectProperty(): void
1413
    {
1414
        $order = new stdClass();
1415
        $order->magic = new Magic([]);
1416
1417
        $this->expectException(\InvalidArgumentException::class);
1418
        ArrayHelper::getValue($order, 'magic.name');
1419
    }
1420
}
1421