Passed
Push — 4 ( 059d8a...cd0765 )
by Maxime
08:13
created

ArrayListTest::testAddRemove()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
nc 1
nop 0
dl 0
loc 21
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\ORM\Tests;
4
5
use SilverStripe\Dev\Deprecation;
6
use SilverStripe\Dev\SapphireTest;
7
use SilverStripe\ORM\ArrayList;
8
use SilverStripe\ORM\DataObject;
9
use SilverStripe\ORM\Filterable;
10
use stdClass;
11
12
class ArrayListTest extends SapphireTest
13
{
14
15
    public function testPushOperator()
16
    {
17
        $list = new ArrayList(
18
            [
19
            ['Num' => 1]
20
            ]
21
        );
22
23
        $list[] = ['Num' => 2];
24
        $this->assertEquals(2, count($list));
25
        $this->assertEquals(['Num' => 2], $list->last());
26
27
        $list[] = ['Num' => 3];
28
        $this->assertEquals(3, count($list));
29
        $this->assertEquals(['Num' => 3], $list->last());
30
    }
31
32
    public function testArrayAccessExists()
33
    {
34
        $list = new ArrayList(
35
            [
36
            $one = new DataObject(['Title' => 'one']),
37
            $two = new DataObject(['Title' => 'two']),
0 ignored issues
show
Unused Code introduced by
The assignment to $two is dead and can be removed.
Loading history...
38
            $three = new DataObject(['Title' => 'three'])
0 ignored issues
show
Unused Code introduced by
The assignment to $three is dead and can be removed.
Loading history...
39
            ]
40
        );
41
        $this->assertEquals(count($list), 3);
42
        $this->assertTrue(isset($list[0]), 'First item in the set is set');
43
        $this->assertEquals($one, $list[0], 'First item in the set is accessible by array notation');
44
    }
45
46
    public function testArrayAccessUnset()
47
    {
48
        $list = new ArrayList(
49
            [
50
            $one = new DataObject(['Title' => 'one']),
0 ignored issues
show
Unused Code introduced by
The assignment to $one is dead and can be removed.
Loading history...
51
            $two = new DataObject(['Title' => 'two']),
0 ignored issues
show
Unused Code introduced by
The assignment to $two is dead and can be removed.
Loading history...
52
            $three = new DataObject(['Title' => 'three'])
0 ignored issues
show
Unused Code introduced by
The assignment to $three is dead and can be removed.
Loading history...
53
            ]
54
        );
55
        unset($list[0]);
56
        $this->assertEquals(count($list), 2);
57
    }
58
59
    public function testArrayAccessSet()
60
    {
61
        $list = new ArrayList();
62
        $this->assertEquals(0, count($list));
63
        $list['testing!'] = $test = new DataObject(['Title' => 'I\'m testing!']);
64
        $this->assertEquals($test, $list['testing!'], 'Set item is accessible by the key we set it as');
65
    }
66
67
    public function testCount()
68
    {
69
        $list = new ArrayList();
70
        $this->assertEquals(0, $list->count());
71
        $list = new ArrayList([1, 2, 3]);
72
        $this->assertEquals(3, $list->count());
73
    }
74
75
    public function testExists()
76
    {
77
        $list = new ArrayList();
78
        $this->assertFalse($list->exists());
79
        $list = new ArrayList([1, 2, 3]);
80
        $this->assertTrue($list->exists());
81
    }
82
83
    public function testToNestedArray()
84
    {
85
        $list = new ArrayList(
86
            [
87
            ['First' => 'FirstFirst', 'Second' => 'FirstSecond'],
88
            (object) ['First' => 'SecondFirst', 'Second' => 'SecondSecond'],
89
            new ArrayListTest\TestObject('ThirdFirst', 'ThirdSecond')
90
            ]
91
        );
92
93
        $this->assertEquals(
94
            $list->toNestedArray(),
95
            [
96
            ['First' => 'FirstFirst', 'Second' => 'FirstSecond'],
97
            ['First' => 'SecondFirst', 'Second' => 'SecondSecond'],
98
            ['First' => 'ThirdFirst', 'Second' => 'ThirdSecond']
99
            ]
100
        );
101
    }
102
103
    public function testEach()
104
    {
105
        $list = new ArrayList([1, 2, 3]);
106
107
        $count = 0;
108
        $test = $this;
109
110
        $list->each(
111
            function ($item) use (&$count, $test) {
112
                $count++;
113
114
                $test->assertTrue(is_int($item));
115
            }
116
        );
117
118
        $this->assertEquals($list->Count(), $count);
119
    }
120
121
    public function testLimit()
122
    {
123
        $list = new ArrayList(
124
            [
125
            ['Key' => 1], ['Key' => 2], ['Key' => 3]
126
            ]
127
        );
128
        $this->assertEquals(
129
            $list->limit(2, 1)->toArray(),
130
            [
131
            ['Key' => 2], ['Key' => 3]
132
            ]
133
        );
134
    }
135
136
    public function testAddRemove()
137
    {
138
        $list = new ArrayList(
139
            [
140
            ['Key' => 1], ['Key' => 2]
141
            ]
142
        );
143
144
        $list->add(['Key' => 3]);
145
        $this->assertEquals(
146
            $list->toArray(),
147
            [
148
            ['Key' => 1], ['Key' => 2], ['Key' => 3]
149
            ]
150
        );
151
152
        $list->remove(['Key' => 2]);
153
        $this->assertEquals(
154
            array_values($list->toArray()),
155
            [
156
            ['Key' => 1], ['Key' => 3]
157
            ]
158
        );
159
    }
160
161
    public function testReplace()
162
    {
163
        $list = new ArrayList(
164
            [
165
            ['Key' => 1],
166
            $two = (object) ['Key' => 2],
167
            (object) ['Key' => 3]
168
            ]
169
        );
170
171
        $this->assertEquals(['Key' => 1], $list[0]);
172
        $list->replace(['Key' => 1], ['Replaced' => 1]);
173
        $this->assertEquals(3, count($list));
174
        $this->assertEquals(['Replaced' => 1], $list[0]);
175
176
        $this->assertEquals($two, $list[1]);
177
        $list->replace($two, ['Replaced' => 2]);
178
        $this->assertEquals(3, count($list));
179
        $this->assertEquals(['Replaced' => 2], $list[1]);
180
    }
181
182
    public function testMerge()
183
    {
184
        $list = new ArrayList(
185
            [
186
            ['Num' => 1], ['Num' => 2]
187
            ]
188
        );
189
        $list->merge(
190
            [
191
            ['Num' => 3], ['Num' => 4]
192
            ]
193
        );
194
195
        $this->assertEquals(4, count($list));
196
        $this->assertEquals(
197
            $list->toArray(),
198
            [
199
            ['Num' => 1], ['Num' => 2], ['Num' => 3], ['Num' => 4]
200
            ]
201
        );
202
    }
203
204
    public function testRemoveDuplicates()
205
    {
206
        $list = new ArrayList(
207
            [
208
            ['ID' => 1, 'Field' => 1],
209
            ['ID' => 2, 'Field' => 2],
210
            ['ID' => 3, 'Field' => 3],
211
            ['ID' => 4, 'Field' => 1],
212
            (object) ['ID' => 5, 'Field' => 2]
213
            ]
214
        );
215
216
        $this->assertEquals(5, count($list));
217
        $list->removeDuplicates();
218
        $this->assertEquals(5, count($list));
219
220
        $list->removeDuplicates('Field');
221
        $this->assertEquals(3, count($list));
222
        $this->assertEquals([1, 2, 3], $list->column('Field'));
223
        $this->assertEquals([1, 2, 3], $list->column('ID'));
224
    }
225
226
    public function testPushPop()
227
    {
228
        $list = new ArrayList(['Num' => 1]);
229
        $this->assertEquals(1, count($list));
230
231
        $list->push(['Num' => 2]);
232
        $this->assertEquals(2, count($list));
233
        $this->assertEquals(['Num' => 2], $list->last());
234
235
        $list->push(['Num' => 3]);
236
        $this->assertEquals(3, count($list));
237
        $this->assertEquals(['Num' => 3], $list->last());
238
239
        $this->assertEquals(['Num' => 3], $list->pop());
240
        $this->assertEquals(2, count($list));
241
        $this->assertEquals(['Num' => 2], $list->last());
242
    }
243
244
    public function testShiftUnshift()
245
    {
246
        $list = new ArrayList(['Num' => 1]);
247
        $this->assertEquals(1, count($list));
248
249
        $list->unshift(['Num' => 2]);
250
        $this->assertEquals(2, count($list));
251
        $this->assertEquals(['Num' => 2], $list->first());
252
253
        $list->unshift(['Num' => 3]);
254
        $this->assertEquals(3, count($list));
255
        $this->assertEquals(['Num' => 3], $list->first());
256
257
        $this->assertEquals(['Num' => 3], $list->shift());
258
        $this->assertEquals(2, count($list));
259
        $this->assertEquals(['Num' => 2], $list->first());
260
    }
261
262
    public function testFirstLast()
263
    {
264
        $list = new ArrayList(
265
            [
266
            ['Key' => 1], ['Key' => 2], ['Key' => 3]
267
            ]
268
        );
269
        $this->assertEquals($list->first(), ['Key' => 1]);
270
        $this->assertEquals($list->last(), ['Key' => 3]);
271
    }
272
273
    public function testMap()
274
    {
275
        $list = new ArrayList(
276
            [
277
            ['ID' => 1, 'Name' => 'Steve',],
278
            (object) ['ID' => 3, 'Name' => 'Bob'],
279
            ['ID' => 5, 'Name' => 'John']
280
            ]
281
        );
282
        $map = $list->map('ID', 'Name');
283
        // Items added after calling map should not be included retroactively
284
        $list->add(['ID' => 7, 'Name' => 'Andrew']);
285
        $this->assertInstanceOf('SilverStripe\\ORM\\Map', $map);
286
        $this->assertEquals(
287
            [
288
            1 => 'Steve',
289
            3 => 'Bob',
290
            5 => 'John'
291
            ],
292
            $map->toArray()
293
        );
294
    }
295
296
    public function testFind()
297
    {
298
        $list = new ArrayList(
299
            [
300
            ['Name' => 'Steve'],
301
            (object) ['Name' => 'Bob'],
302
            ['Name' => 'John']
303
            ]
304
        );
305
        $this->assertEquals(
306
            $list->find('Name', 'Bob'),
307
            (object) [
308
            'Name' => 'Bob'
309
            ]
310
        );
311
    }
312
313
    public function testColumn()
314
    {
315
        $list = new ArrayList(
316
            [
317
            ['Name' => 'Steve'],
318
            (object) ['Name' => 'Bob'],
319
            ['Name' => 'John']
320
            ]
321
        );
322
        $this->assertEquals(
323
            $list->column('Name'),
324
            [
325
            'Steve', 'Bob', 'John'
326
            ]
327
        );
328
    }
329
330
    public function testSortSimpleDefaultIsSortedASC()
331
    {
332
        $list = new ArrayList(
333
            [
334
            ['Name' => 'Steve'],
335
            (object) ['Name' => 'Bob'],
336
            ['Name' => 'John'],
337
            ['Name' => 'bonny'],
338
            ]
339
        );
340
341
        // Unquoted name
342
        $list1 = $list->sort('Name');
343
        $this->assertEquals(
344
            [
345
            (object) ['Name' => 'Bob'],
346
            ['Name' => 'bonny'],
347
            ['Name' => 'John'],
348
            ['Name' => 'Steve'],
349
            ],
350
            $list1->toArray()
351
        );
352
353
        // Quoted name name
354
        $list2 = $list->sort('"Name"');
355
        $this->assertEquals(
356
            [
357
            (object) ['Name' => 'Bob'],
358
            ['Name' => 'bonny'],
359
            ['Name' => 'John'],
360
            ['Name' => 'Steve'],
361
            ],
362
            $list2->toArray()
363
        );
364
365
        // Array (non-associative)
366
        $list3 = $list->sort(['"Name"']);
367
        $this->assertEquals(
368
            [
369
            (object) ['Name' => 'Bob'],
370
            ['Name' => 'bonny'],
371
            ['Name' => 'John'],
372
            ['Name' => 'Steve'],
373
            ],
374
            $list3->toArray()
375
        );
376
377
        // Quoted name name with table
378
        $list4 = $list->sort('"Record"."Name"');
379
        $this->assertEquals(
380
            [
381
            (object) ['Name' => 'Bob'],
382
            ['Name' => 'bonny'],
383
            ['Name' => 'John'],
384
            ['Name' => 'Steve']
385
            ],
386
            $list4->toArray()
387
        );
388
389
        // Quoted name name with table (desc)
390
        $list5 = $list->sort('"Record"."Name" DESC');
391
        $this->assertEquals(
392
            [
393
            ['Name' => 'Steve'],
394
            ['Name' => 'John'],
395
            ['Name' => 'bonny'],
396
            (object) ['Name' => 'Bob']
397
            ],
398
            $list5->toArray()
399
        );
400
401
        // Table without quotes
402
        $list6 = $list->sort('Record.Name');
403
        $this->assertEquals(
404
            [
405
            (object) ['Name' => 'Bob'],
406
            ['Name' => 'bonny'],
407
            ['Name' => 'John'],
408
            ['Name' => 'Steve']
409
            ],
410
            $list6->toArray()
411
        );
412
413
        // Check original list isn't altered
414
        $this->assertEquals(
415
            [
416
            ['Name' => 'Steve'],
417
            (object) ['Name' => 'Bob'],
418
            ['Name' => 'John'],
419
            ['Name' => 'bonny'],
420
            ],
421
            $list->toArray()
422
        );
423
    }
424
425
    public function testMixedCaseSort()
426
    {
427
        // Note: Natural sorting is not expected, so if 'bonny10' were included
428
        // below we would expect it to appear between bonny1 and bonny2. That's
429
        // undesirable though so we're not enforcing it in tests.
430
        $original = [
431
            ['Name' => 'Steve'],
432
            (object) ['Name' => 'Bob'],
433
            ['Name' => 'John'],
434
            ['Name' => 'bonny'],
435
            ['Name' => 'bonny1'],
436
            //['Name' => 'bonny10'],
437
            ['Name' => 'bonny2'],
438
        ];
439
440
        $list = new ArrayList($original);
441
442
        $expected = [
443
            (object) ['Name' => 'Bob'],
444
            ['Name' => 'bonny'],
445
            ['Name' => 'bonny1'],
446
            //['Name' => 'bonny10'],
447
            ['Name' => 'bonny2'],
448
            ['Name' => 'John'],
449
            ['Name' => 'Steve'],
450
        ];
451
452
        // Unquoted name
453
        $list1 = $list->sort('Name');
454
        $this->assertEquals($expected, $list1->toArray());
455
456
        // Quoted name name
457
        $list2 = $list->sort('"Name"');
458
        $this->assertEquals($expected, $list2->toArray());
459
460
        // Array (non-associative)
461
        $list3 = $list->sort(['"Name"']);
462
        $this->assertEquals($expected, $list3->toArray());
463
464
        // Check original list isn't altered
465
        $this->assertEquals($original, $list->toArray());
466
    }
467
468
    public function testSortSimpleASCOrder()
469
    {
470
        $list = new ArrayList(
471
            [
472
            ['Name' => 'Steve'],
473
            (object) ['Name' => 'Bob'],
474
            ['Name' => 'John']
475
            ]
476
        );
477
478
        // Sort two arguments
479
        $list1 = $list->sort('Name', 'ASC');
480
        $this->assertEquals(
481
            $list1->toArray(),
482
            [
483
            (object) ['Name' => 'Bob'],
484
            ['Name' => 'John'],
485
            ['Name' => 'Steve']
486
            ]
487
        );
488
489
        // Sort single string
490
        $list2 = $list->sort('Name asc');
491
        $this->assertEquals(
492
            $list2->toArray(),
493
            [
494
            (object) ['Name' => 'Bob'],
495
            ['Name' => 'John'],
496
            ['Name' => 'Steve']
497
            ]
498
        );
499
500
        // Sort quoted string
501
        $list3 = $list->sort('"Name" ASCENDING');
502
        $this->assertEquals(
503
            $list3->toArray(),
504
            [
505
            (object) ['Name' => 'Bob'],
506
            ['Name' => 'John'],
507
            ['Name' => 'Steve']
508
            ]
509
        );
510
511
        // Sort array specifier
512
        $list4 = $list->sort(['Name' => 'ascending']);
513
        $this->assertEquals(
514
            $list4->toArray(),
515
            [
516
            (object) ['Name' => 'Bob'],
517
            ['Name' => 'John'],
518
            ['Name' => 'Steve']
519
            ]
520
        );
521
522
        // Check original list isn't altered
523
        $this->assertEquals(
524
            $list->toArray(),
525
            [
526
            ['Name' => 'Steve'],
527
            (object) ['Name' => 'Bob'],
528
            ['Name' => 'John']
529
            ]
530
        );
531
    }
532
533
    public function testSortSimpleDESCOrder()
534
    {
535
        $list = new ArrayList(
536
            [
537
            ['Name' => 'Steve'],
538
            (object) ['Name' => 'Bob'],
539
            ['Name' => 'John']
540
            ]
541
        );
542
543
        // Sort two arguments
544
        $list1 = $list->sort('Name', 'DESC');
545
        $this->assertEquals(
546
            $list1->toArray(),
547
            [
548
            ['Name' => 'Steve'],
549
            ['Name' => 'John'],
550
            (object) ['Name' => 'Bob']
551
            ]
552
        );
553
554
        // Sort single string
555
        $list2 = $list->sort('Name desc');
556
        $this->assertEquals(
557
            $list2->toArray(),
558
            [
559
            ['Name' => 'Steve'],
560
            ['Name' => 'John'],
561
            (object) ['Name' => 'Bob']
562
            ]
563
        );
564
565
        // Sort quoted string
566
        $list3 = $list->sort('"Name" DESCENDING');
567
        $this->assertEquals(
568
            $list3->toArray(),
569
            [
570
            ['Name' => 'Steve'],
571
            ['Name' => 'John'],
572
            (object) ['Name' => 'Bob']
573
            ]
574
        );
575
576
        // Sort array specifier
577
        $list4 = $list->sort(['Name' => 'descending']);
578
        $this->assertEquals(
579
            $list4->toArray(),
580
            [
581
            ['Name' => 'Steve'],
582
            ['Name' => 'John'],
583
            (object) ['Name' => 'Bob']
584
            ]
585
        );
586
587
        // Check original list isn't altered
588
        $this->assertEquals(
589
            $list->toArray(),
590
            [
591
            ['Name' => 'Steve'],
592
            (object) ['Name' => 'Bob'],
593
            ['Name' => 'John']
594
            ]
595
        );
596
    }
597
598
    public function testSortNumeric()
599
    {
600
        $list = new ArrayList(
601
            [
602
            ['Sort' => 0],
603
            ['Sort' => -1],
604
            ['Sort' => 1],
605
            ['Sort' => -2],
606
            ['Sort' => 2],
607
            ['Sort' => -10],
608
            ['Sort' => 10]
609
            ]
610
        );
611
612
        // Sort descending
613
        $list1 = $list->sort('Sort', 'DESC');
614
        $this->assertEquals(
615
            [
616
            ['Sort' => 10],
617
            ['Sort' => 2],
618
            ['Sort' => 1],
619
            ['Sort' => 0],
620
            ['Sort' => -1],
621
            ['Sort' => -2],
622
            ['Sort' => -10]
623
            ],
624
            $list1->toArray()
625
        );
626
627
        // Sort ascending
628
        $list1 = $list->sort('Sort', 'ASC');
629
        $this->assertEquals(
630
            [
631
            ['Sort' => -10],
632
            ['Sort' => -2],
633
            ['Sort' => -1],
634
            ['Sort' => 0],
635
            ['Sort' => 1],
636
            ['Sort' => 2],
637
            ['Sort' => 10]
638
            ],
639
            $list1->toArray()
640
        );
641
    }
642
643
    public function testReverse()
644
    {
645
        $list = new ArrayList(
646
            [
647
            ['Name' => 'John'],
648
            ['Name' => 'Bob'],
649
            ['Name' => 'Steve']
650
            ]
651
        );
652
653
        $list = $list->sort('Name', 'ASC');
654
        $list = $list->reverse();
655
656
        $this->assertEquals(
657
            $list->toArray(),
658
            [
659
            ['Name' => 'Steve'],
660
            ['Name' => 'John'],
661
            ['Name' => 'Bob']
662
            ]
663
        );
664
    }
665
666
    public function testSimpleMultiSort()
667
    {
668
        $list = new ArrayList(
669
            [
670
            (object) ['Name'=>'Object1', 'F1'=>1, 'F2'=>2, 'F3'=>3],
671
            (object) ['Name'=>'Object2', 'F1'=>2, 'F2'=>1, 'F3'=>4],
672
            (object) ['Name'=>'Object3', 'F1'=>5, 'F2'=>2, 'F3'=>2],
673
            ]
674
        );
675
676
        $list = $list->sort('F3', 'ASC');
677
        $this->assertEquals($list->first()->Name, 'Object3', 'Object3 should be first in the list');
678
        $this->assertEquals($list->last()->Name, 'Object2', 'Object2 should be last in the list');
679
680
        $list = $list->sort('F3', 'DESC');
681
        $this->assertEquals($list->first()->Name, 'Object2', 'Object2 should be first in the list');
682
        $this->assertEquals($list->last()->Name, 'Object3', 'Object3 should be last in the list');
683
    }
684
685
    public function testMultiSort()
686
    {
687
        $list = new ArrayList(
688
            [
689
            (object) ['ID'=>3, 'Name'=>'Bert', 'Importance'=>1],
690
            (object) ['ID'=>1, 'Name'=>'Aron', 'Importance'=>2],
691
            (object) ['ID'=>2, 'Name'=>'Aron', 'Importance'=>1],
692
            ]
693
        );
694
695
        $list = $list->sort(['Name'=>'ASC', 'Importance'=>'ASC']);
696
        $this->assertEquals($list->first()->ID, 2, 'Aron.2 should be first in the list');
697
        $this->assertEquals($list->last()->ID, 3, 'Bert.3 should be last in the list');
698
699
        $list = $list->sort(['Name'=>'ASC', 'Importance'=>'DESC']);
700
        $this->assertEquals($list->first()->ID, 1, 'Aron.2 should be first in the list');
701
        $this->assertEquals($list->last()->ID, 3, 'Bert.3 should be last in the list');
702
    }
703
704
    /**
705
     * Check that we don't cause recursion errors with array_multisort() and circular dependencies
706
     */
707
    public function testSortWithCircularDependencies()
708
    {
709
        $itemA = new stdClass;
710
        $childA = new stdClass;
711
        $itemA->child = $childA;
712
        $childA->parent = $itemA;
713
        $itemA->Sort = 1;
714
715
        $itemB = new stdClass;
716
        $childB = new stdClass;
717
        $itemB->child = $childB;
718
        $childB->parent = $itemB;
719
        $itemB->Sort = 1;
720
721
        $items = new ArrayList;
722
        $items->add($itemA);
723
        $items->add($itemB);
724
725
        // This call will trigger a fatal error if there are issues with circular dependencies
726
        $items->sort('Sort');
727
        $this->assertTrue(true, 'Sort with circular dependencies does not trigger an error.');
728
    }
729
730
    /**
731
     * $list->filter('Name', 'bob'); // only bob in the list
732
     */
733
    public function testSimpleFilter()
734
    {
735
        $list = new ArrayList(
736
            [
737
            ['Name' => 'Steve'],
738
            (object) ['Name' => 'Bob'],
739
            ['Name' => 'John']
740
            ]
741
        );
742
        $list = $list->filter('Name', 'Bob');
743
        $this->assertEquals([(object)['Name'=>'Bob']], $list->toArray(), 'List should only contain Bob');
744
    }
745
746
    /**
747
     * $list->filter('Name', ['Steve', 'John']; // Steve and John in list
748
     */
749
    public function testSimpleFilterWithMultiple()
750
    {
751
        $list = new ArrayList(
752
            [
753
            ['Name' => 'Steve'],
754
            (object) ['Name' => 'Bob'],
755
            ['Name' => 'John']
756
            ]
757
        );
758
759
        $expected = [
760
            ['Name' => 'Steve'],
761
            ['Name' => 'John']
762
        ];
763
        $list = $list->filter('Name', ['Steve','John']);
764
        $this->assertEquals($expected, $list->toArray(), 'List should only contain Steve and John');
765
    }
766
767
    /**
768
     * $list->filter('Name', ['Steve', 'John']; // negative version
769
     */
770
    public function testSimpleFilterWithMultipleNoMatch()
771
    {
772
        $list = new ArrayList(
773
            [
774
            ['Name' => 'Steve', 'ID' => 1],
775
            (object) ['Name' => 'Steve', 'ID' => 2],
776
            ['Name' => 'John', 'ID' => 2]
777
            ]
778
        );
779
        $list = $list->filter(['Name'=>'Clair']);
780
        $this->assertEquals([], $list->toArray(), 'List should be empty');
781
    }
782
783
    /**
784
     * $list->filter(['Name'=>'bob, 'Age'=>21]); // bob with the Age 21 in list
785
     */
786
    public function testMultipleFilter()
787
    {
788
        $list = new ArrayList(
789
            [
790
            ['Name' => 'Steve', 'ID' => 1],
791
            (object) ['Name' => 'Steve', 'ID' => 2],
792
            ['Name' => 'John', 'ID' => 2]
793
            ]
794
        );
795
        $list = $list->filter(['Name'=>'Steve', 'ID'=>2]);
796
        $this->assertEquals(
797
            [(object)['Name'=>'Steve', 'ID'=>2]],
798
            $list->toArray(),
799
            'List should only contain object Steve'
800
        );
801
    }
802
803
    /**
804
     * $list->filter(['Name'=>'bob, 'Age'=>21]); // negative version
805
     */
806
    public function testMultipleFilterNoMatch()
807
    {
808
        $list = new ArrayList(
809
            [
810
            ['Name' => 'Steve', 'ID' => 1],
811
            (object) ['Name' => 'Steve', 'ID' => 2],
812
            ['Name' => 'John', 'ID' => 2]
813
            ]
814
        );
815
        $list = $list->filter(['Name'=>'Steve', 'ID'=>4]);
816
        $this->assertEquals([], $list->toArray(), 'List should be empty');
817
    }
818
819
    /**
820
     * $list->filter(['Name'=>'Steve', 'Age'=>[21, 43]]); // Steve with the Age 21 or 43
821
     */
822
    public function testMultipleWithArrayFilter()
823
    {
824
        $list = new ArrayList(
825
            [
826
            ['Name' => 'Steve', 'ID' => 1, 'Age'=>21],
827
            ['Name' => 'Steve', 'ID' => 2, 'Age'=>18],
828
            ['Name' => 'Clair', 'ID' => 2, 'Age'=>21],
829
            ['Name' => 'Steve', 'ID' => 3, 'Age'=>43]
830
            ]
831
        );
832
833
        $list = $list->filter(['Name'=>'Steve','Age'=>[21, 43]]);
834
835
        $expected = [
836
            ['Name' => 'Steve', 'ID' => 1, 'Age'=>21],
837
            ['Name' => 'Steve', 'ID' => 3, 'Age'=>43]
838
        ];
839
        $this->assertEquals(2, $list->count());
840
        $this->assertEquals($expected, $list->toArray(), 'List should only contain Steve and Steve');
841
    }
842
843
    /**
844
     * $list->filter(['Name'=>['aziz','bob'], 'Age'=>[21, 43]]);
845
     */
846
    public function testMultipleWithArrayFilterAdvanced()
847
    {
848
        $list = new ArrayList(
849
            [
850
            ['Name' => 'Steve', 'ID' => 1, 'Age'=>21],
851
            ['Name' => 'Steve', 'ID' => 2, 'Age'=>18],
852
            ['Name' => 'Clair', 'ID' => 2, 'Age'=>21],
853
            ['Name' => 'Clair', 'ID' => 2, 'Age'=>52],
854
            ['Name' => 'Steve', 'ID' => 3, 'Age'=>43]
855
            ]
856
        );
857
858
        $list = $list->filter(['Name'=>['Steve','Clair'],'Age'=>[21, 43]]);
859
860
        $expected = [
861
            ['Name' => 'Steve', 'ID' => 1, 'Age'=>21],
862
            ['Name' => 'Clair', 'ID' => 2, 'Age'=>21],
863
            ['Name' => 'Steve', 'ID' => 3, 'Age'=>43]
864
        ];
865
866
        $this->assertEquals(3, $list->count());
867
        $this->assertEquals($expected, $list->toArray(), 'List should only contain Steve and Steve and Clair');
868
    }
869
870
    public function testFilterAny()
871
    {
872
873
        $list = new ArrayList(
874
            [
875
            $steve = ['Name' => 'Steve', 'ID' => 1, 'Age' => 21],
876
            $bob = ['Name' => 'Bob', 'ID' => 2, 'Age' => 18],
877
            $clair = ['Name' => 'Clair', 'ID' => 3, 'Age' => 21],
878
            $phil = ['Name' => 'Phil', 'ID' => 4, 'Age' => 21],
879
            $oscar = ['Name' => 'Oscar', 'ID' => 5, 'Age' => 52],
0 ignored issues
show
Unused Code introduced by
The assignment to $oscar is dead and can be removed.
Loading history...
880
            $mike = ['Name' => 'Mike', 'ID' => 6, 'Age' => 43],
881
            ]
882
        );
883
884
        // only bob in the list
885
        //$list = $list->filterAny('Name', 'bob');
886
        $filteredList = $list->filterAny('Name', 'Bob')->toArray();
887
        $this->assertCount(1, $filteredList);
888
        $this->assertContains($bob, $filteredList);
889
890
        // azis or bob in the list
891
        //$list = $list->filterAny('Name', ['aziz', 'bob']);
892
        $filteredList = $list->filterAny('Name', ['Aziz', 'Bob'])->toArray();
893
        $this->assertCount(1, $filteredList);
894
        $this->assertContains($bob, $filteredList);
895
896
        $filteredList = $list->filterAny('Name', ['Steve', 'Bob'])->toArray();
897
        $this->assertCount(2, $filteredList);
898
        $this->assertContains($steve, $filteredList);
899
        $this->assertContains($bob, $filteredList);
900
901
        // bob or anyone aged 21 in the list
902
        //$list = $list->filterAny(['Name'=>'bob, 'Age'=>21]);
903
        $filteredList = $list->filterAny(['Name' => 'Bob', 'Age' => 21])->toArray();
904
        $this->assertCount(4, $filteredList);
905
        $this->assertContains($bob, $filteredList);
906
        $this->assertContains($steve, $filteredList);
907
        $this->assertContains($clair, $filteredList);
908
        $this->assertContains($phil, $filteredList);
909
910
        // bob or anyone aged 21 or 43 in the list
911
        // $list = $list->filterAny(['Name'=>'bob, 'Age'=>[21, 43]]);
912
        $filteredList = $list->filterAny(['Name' => 'Bob', 'Age' => [21, 43]])->toArray();
913
        $this->assertCount(5, $filteredList);
914
        $this->assertContains($bob, $filteredList);
915
        $this->assertContains($steve, $filteredList);
916
        $this->assertContains($clair, $filteredList);
917
        $this->assertContains($mike, $filteredList);
918
        $this->assertContains($phil, $filteredList);
919
920
        // all bobs, phils or anyone aged 21 or 43 in the list
921
        //$list = $list->filterAny(['Name'=>['bob','phil'], 'Age'=>[21, 43]]);
922
        $filteredList = $list->filterAny(['Name' => ['Bob', 'Phil'], 'Age' => [21, 43]])->toArray();
923
        $this->assertCount(5, $filteredList);
924
        $this->assertContains($bob, $filteredList);
925
        $this->assertContains($steve, $filteredList);
926
        $this->assertContains($clair, $filteredList);
927
        $this->assertContains($mike, $filteredList);
928
        $this->assertContains($phil, $filteredList);
929
930
        $filteredList = $list->filterAny(['Name' => ['Bob', 'Nobody'], 'Age' => [21, 43]])->toArray();
931
        $this->assertCount(5, $filteredList);
932
        $this->assertContains($bob, $filteredList);
933
        $this->assertContains($steve, $filteredList);
934
        $this->assertContains($clair, $filteredList);
935
        $this->assertContains($mike, $filteredList);
936
        $this->assertContains($phil, $filteredList);
937
    }
938
939
    /**
940
     * $list = $list->filterByCallback(function($item, $list) { return $item->Age == 21; })
941
     */
942
    public function testFilterByCallback()
943
    {
944
        $list = new ArrayList(
945
            [
946
            $steve = ['Name' => 'Steve', 'ID' => 1, 'Age' => 21],
947
            ['Name' => 'Bob', 'ID' => 2, 'Age' => 18],
948
            $clair = ['Name' => 'Clair', 'ID' => 2, 'Age' => 21],
949
            ['Name' => 'Oscar', 'ID' => 2, 'Age' => 52],
950
            ['Name' => 'Mike', 'ID' => 3, 'Age' => 43]
951
            ]
952
        );
953
954
        $list = $list->filterByCallback(
955
            function ($item, $list) {
0 ignored issues
show
Unused Code introduced by
The parameter $list is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

955
            function ($item, /** @scrutinizer ignore-unused */ $list) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
956
                return $item->Age == 21;
957
            }
958
        );
959
960
        $this->assertEquals(2, $list->count());
961
        $this->assertEquals($steve, $list[0]->toMap(), 'List should only contain Steve and Clair');
962
        $this->assertEquals($clair, $list[1]->toMap(), 'List should only contain Steve and Clair');
963
        $this->assertTrue($list instanceof Filterable, 'The List should be of type SS_Filterable');
964
    }
965
966
    /**
967
     * $list->exclude('Name', 'bob'); // exclude bob from list
968
     */
969
    public function testSimpleExclude()
970
    {
971
        $list = new ArrayList(
972
            [
973
            ['Name' => 'Steve'],
974
            ['Name' => 'Bob'],
975
            ['Name' => 'John']
976
            ]
977
        );
978
979
        $list = $list->exclude('Name', 'Bob');
980
        $expected = [
981
            ['Name' => 'Steve'],
982
            ['Name' => 'John']
983
        ];
984
        $this->assertEquals(2, $list->count());
985
        $this->assertEquals($expected, $list->toArray(), 'List should not contain Bob');
986
    }
987
988
    /**
989
     * $list->exclude('Name', 'bob'); // No exclusion version
990
     */
991
    public function testSimpleExcludeNoMatch()
992
    {
993
        $list = new ArrayList(
994
            [
995
            ['Name' => 'Steve'],
996
            ['Name' => 'Bob'],
997
            ['Name' => 'John']
998
            ]
999
        );
1000
1001
        $list = $list->exclude('Name', 'Clair');
1002
        $expected = [
1003
            ['Name' => 'Steve'],
1004
            ['Name' => 'Bob'],
1005
            ['Name' => 'John']
1006
        ];
1007
        $this->assertEquals($expected, $list->toArray(), 'List should be unchanged');
1008
    }
1009
1010
    /**
1011
     * $list->exclude('Name', array('Steve','John'));
1012
     */
1013
    public function testSimpleExcludeWithArray()
1014
    {
1015
        $list = new ArrayList(
1016
            [
1017
            ['Name' => 'Steve'],
1018
            ['Name' => 'Bob'],
1019
            ['Name' => 'John']
1020
            ]
1021
        );
1022
        $list = $list->exclude('Name', ['Steve','John']);
1023
        $expected = [['Name' => 'Bob']];
1024
        $this->assertEquals(1, $list->count());
1025
        $this->assertEquals($expected, $list->toArray(), 'List should only contain Bob');
1026
    }
1027
1028
    /**
1029
     * $list->exclude(array('Name'=>'bob, 'Age'=>21)); // exclude all Bob that has Age 21
1030
     */
1031
    public function testExcludeWithTwoArrays()
1032
    {
1033
        $list = new ArrayList(
1034
            [
1035
            ['Name' => 'Bob' , 'Age' => 21],
1036
            ['Name' => 'Bob' , 'Age' => 32],
1037
            ['Name' => 'John', 'Age' => 21]
1038
            ]
1039
        );
1040
1041
        $list = $list->exclude(['Name' => 'Bob', 'Age' => 21]);
1042
1043
        $expected = [
1044
            ['Name' => 'Bob', 'Age' => 32],
1045
            ['Name' => 'John', 'Age' => 21]
1046
        ];
1047
1048
        $this->assertEquals(2, $list->count());
1049
        $this->assertEquals($expected, $list->toArray(), 'List should only contain John and Bob');
1050
    }
1051
1052
    /**
1053
     * $list->exclude(array('Name'=>array('bob','phil'), 'Age'=>array(10, 16)));
1054
     */
1055
    public function testMultipleExclude()
1056
    {
1057
        $list = new ArrayList(
1058
            [
1059
            ['Name' => 'bob', 'Age' => 10],
1060
            ['Name' => 'phil', 'Age' => 11],
1061
            ['Name' => 'bob', 'Age' => 12],
1062
            ['Name' => 'phil', 'Age' => 12],
1063
            ['Name' => 'bob', 'Age' => 14],
1064
            ['Name' => 'phil', 'Age' => 14],
1065
            ['Name' => 'bob', 'Age' => 16],
1066
            ['Name' => 'phil', 'Age' => 16]
1067
            ]
1068
        );
1069
1070
        $list = $list->exclude(['Name'=>['bob','phil'],'Age'=>[10, 16]]);
1071
        $expected = [
1072
            ['Name' => 'phil', 'Age' => 11],
1073
            ['Name' => 'bob', 'Age' => 12],
1074
            ['Name' => 'phil', 'Age' => 12],
1075
            ['Name' => 'bob', 'Age' => 14],
1076
            ['Name' => 'phil', 'Age' => 14],
1077
        ];
1078
        $this->assertEquals($expected, $list->toArray());
1079
    }
1080
1081
    /**
1082
     * $list->exclude(array('Name'=>array('bob','phil'), 'Age'=>array(10, 16), 'Bananas'=>true));
1083
     */
1084
    public function testMultipleExcludeNoMatch()
1085
    {
1086
        $list = new ArrayList(
1087
            [
1088
            ['Name' => 'bob', 'Age' => 10],
1089
            ['Name' => 'phil', 'Age' => 11],
1090
            ['Name' => 'bob', 'Age' => 12],
1091
            ['Name' => 'phil', 'Age' => 12],
1092
            ['Name' => 'bob', 'Age' => 14],
1093
            ['Name' => 'phil', 'Age' => 14],
1094
            ['Name' => 'bob', 'Age' => 16],
1095
            ['Name' => 'phil', 'Age' => 16]
1096
            ]
1097
        );
1098
1099
        $list = $list->exclude(['Name'=>['bob','phil'],'Age'=>[10, 16],'Bananas'=>true]);
1100
        $expected = [
1101
            ['Name' => 'bob', 'Age' => 10],
1102
            ['Name' => 'phil', 'Age' => 11],
1103
            ['Name' => 'bob', 'Age' => 12],
1104
            ['Name' => 'phil', 'Age' => 12],
1105
            ['Name' => 'bob', 'Age' => 14],
1106
            ['Name' => 'phil', 'Age' => 14],
1107
            ['Name' => 'bob', 'Age' => 16],
1108
            ['Name' => 'phil', 'Age' => 16]
1109
        ];
1110
        $this->assertEquals($expected, $list->toArray());
1111
    }
1112
1113
    /**
1114
     * $list->exclude(array('Name'=>array('bob','phil'), 'Age'=>array(10, 16), 'HasBananas'=>true));
1115
     */
1116
    public function testMultipleExcludeThreeArguments()
1117
    {
1118
        $list = new ArrayList(
1119
            [
1120
            ['Name' => 'bob', 'Age' => 10, 'HasBananas'=>false],
1121
            ['Name' => 'phil','Age' => 11, 'HasBananas'=>true],
1122
            ['Name' => 'bob', 'Age' => 12, 'HasBananas'=>true],
1123
            ['Name' => 'phil','Age' => 12, 'HasBananas'=>true],
1124
            ['Name' => 'bob', 'Age' => 14, 'HasBananas'=>false],
1125
            ['Name' => 'ann', 'Age' => 14, 'HasBananas'=>true],
1126
            ['Name' => 'phil','Age' => 14, 'HasBananas'=>false],
1127
            ['Name' => 'bob', 'Age' => 16, 'HasBananas'=>false],
1128
            ['Name' => 'phil','Age' => 16, 'HasBananas'=>true],
1129
            ['Name' => 'clair','Age' => 16, 'HasBananas'=>true]
1130
            ]
1131
        );
1132
1133
        $list = $list->exclude(['Name'=>['bob','phil'],'Age'=>[10, 16],'HasBananas'=>true]);
1134
        $expected = [
1135
            ['Name' => 'bob', 'Age' => 10, 'HasBananas'=>false],
1136
            ['Name' => 'phil','Age' => 11, 'HasBananas'=>true],
1137
            ['Name' => 'bob', 'Age' => 12, 'HasBananas'=>true],
1138
            ['Name' => 'phil','Age' => 12, 'HasBananas'=>true],
1139
            ['Name' => 'bob', 'Age' => 14, 'HasBananas'=>false],
1140
            ['Name' => 'ann', 'Age' => 14, 'HasBananas'=>true],
1141
            ['Name' => 'phil','Age' => 14, 'HasBananas'=>false],
1142
            ['Name' => 'bob', 'Age' => 16, 'HasBananas'=>false],
1143
            ['Name' => 'clair','Age' => 16, 'HasBananas'=>true]
1144
        ];
1145
        $this->assertEquals($expected, $list->toArray());
1146
    }
1147
1148
    public function testCanFilterBy()
1149
    {
1150
        $list = new ArrayList(
1151
            [
1152
            ['Name' => 'Steve'],
1153
            ['Name' => 'Bob'],
1154
            ['Name' => 'John']
1155
            ]
1156
        );
1157
1158
        $this->assertTrue($list->canFilterBy('Name'));
1159
        $this->assertFalse($list->canFilterBy('Age'));
1160
    }
1161
1162
    public function testCanFilterByEmpty()
1163
    {
1164
        $list = new ArrayList();
1165
1166
        $this->assertFalse($list->canFilterBy('Name'));
1167
        $this->assertFalse($list->canFilterBy('Age'));
1168
    }
1169
1170
    public function testByID()
1171
    {
1172
        $list = new ArrayList(
1173
            [
1174
            ['ID' => 1, 'Name' => 'Steve'],
1175
            ['ID' => 2, 'Name' => 'Bob'],
1176
            ['ID' => 3, 'Name' => 'John']
1177
            ]
1178
        );
1179
1180
        $element = $list->byID(1);
1181
        $this->assertEquals($element['Name'], 'Steve');
1182
1183
        $element = $list->byID(2);
1184
        $this->assertEquals($element['Name'], 'Bob');
1185
1186
        $element = $list->byID(4);
1187
        $this->assertNull($element);
1188
    }
1189
1190
    public function testByIDs()
1191
    {
1192
        $list = new ArrayList(
1193
            [
1194
            ['ID' => 1, 'Name' => 'Steve'],
1195
            ['ID' => 2, 'Name' => 'Bob'],
1196
            ['ID' => 3, 'Name' => 'John']
1197
            ]
1198
        );
1199
        $knownIDs = $list->column('ID');
1200
        $removedID = array_pop($knownIDs);
1201
        $filteredItems = $list->byIDs($knownIDs);
1202
        foreach ($filteredItems as $item) {
1203
            $this->assertContains($item->ID, $knownIDs);
1204
            $this->assertNotEquals($removedID, $item->ID);
1205
        }
1206
    }
1207
1208
    public function testByIDEmpty()
1209
    {
1210
        $list = new ArrayList();
1211
1212
        $element = $list->byID(1);
1213
        $this->assertNull($element);
1214
    }
1215
1216
    public function testDataClass()
1217
    {
1218
        $list = new ArrayList([
1219
            new DataObject(['Title' => 'one']),
1220
        ]);
1221
        $this->assertEquals(DataObject::class, $list->dataClass());
1222
        $list->pop();
1223
        $this->assertNull($list->dataClass());
1224
        $list->setDataClass(DataObject::class);
1225
        $this->assertEquals(DataObject::class, $list->dataClass());
1226
    }
1227
1228
    public function testShuffle()
1229
    {
1230
        $upperLimit = 50;
1231
1232
        $list = new ArrayList(range(1, $upperLimit));
1233
1234
        $list->shuffle();
1235
1236
        for ($i = 1; $i <= $upperLimit; $i++) {
1237
            $this->assertContains($i, $list);
1238
        }
1239
1240
        $this->assertNotEquals(range(1, $upperLimit), $list->toArray());
1241
    }
1242
1243
    public function testOffsetSet()
1244
    {
1245
        $list = new ArrayList(['first value', 'second value']);
1246
        $this->assertSame(2, $list->count());
1247
        $list->offsetSet(0, 'new value');
1248
        $this->assertSame(2, $list->count());
1249
        $this->assertSame('new value', $list->offsetGet(0));
1250
        $this->assertSame('second value', $list->offsetGet(1));
1251
    }
1252
}
1253