Completed
Push — 4 ( 72282d...a8d121 )
by Sam
29s queued 20s
created

ArrayListTest::testOffsetSet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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

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