Passed
Push — master ( 019716...f69765 )
by Alexander
07:16
created

anonymous//tests/Reader/IterableDataReaderTest.php$0   A

Complexity

Total Complexity 3

Size/Duplication

Total Lines 16
Duplicated Lines 0 %

Importance

Changes 3
Bugs 1 Features 1
Metric Value
c 3
b 1
f 1
dl 0
loc 16
rs 10
wmc 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Data\Tests\Reader;
6
7
use PHPUnit\Framework\TestCase;
8
use Yiisoft\Data\Reader\Filter\All;
9
use Yiisoft\Data\Reader\Filter\Any;
10
use Yiisoft\Data\Reader\Filter\Equals;
11
use Yiisoft\Data\Reader\Filter\FilterInterface;
12
use Yiisoft\Data\Reader\Filter\GreaterThan;
13
use Yiisoft\Data\Reader\Filter\GreaterThanOrEqual;
14
use Yiisoft\Data\Reader\Filter\In;
15
use Yiisoft\Data\Reader\Filter\LessThan;
16
use Yiisoft\Data\Reader\Filter\LessThanOrEqual;
17
use Yiisoft\Data\Reader\Filter\Like;
18
use Yiisoft\Data\Reader\Filter\Not;
19
use Yiisoft\Data\Reader\Iterable\IterableDataReader;
20
use Yiisoft\Data\Reader\Sort;
21
22
final class IterableDataReaderTest extends TestCase
23
{
24
    private function getDataSet(): array
25
    {
26
        return [
27
            [
28
                'id' => 1,
29
                'name' => 'Codename Boris',
30
            ],
31
            [
32
                'id' => 2,
33
                'name' => 'Codename Doris',
34
            ],
35
            [
36
                'id' => 3,
37
                'name' => 'Agent K',
38
            ],
39
            [
40
                'id' => 5,
41
                'name' => 'Agent J',
42
            ],
43
            [
44
                'id' => 6,
45
                'name' => '007',
46
            ],
47
        ];
48
    }
49
50
    private function getDataSetSortedByName(): array
51
    {
52
        return [
53
            [
54
                'id' => 6,
55
                'name' => '007',
56
            ],
57
            [
58
                'id' => 5,
59
                'name' => 'Agent J',
60
            ],
61
            [
62
                'id' => 3,
63
                'name' => 'Agent K',
64
            ],
65
            [
66
                'id' => 1,
67
                'name' => 'Codename Boris',
68
            ],
69
            [
70
                'id' => 2,
71
                'name' => 'Codename Doris',
72
            ],
73
        ];
74
    }
75
76
    public function testWithLimitIsImmutable(): void
77
    {
78
        $reader = new IterableDataReader([]);
79
80
        $this->assertNotSame($reader, $reader->withLimit(1));
81
    }
82
83
    public function testLimitIsApplied(): void
84
    {
85
        $reader = (new IterableDataReader($this->getDataSet()))
86
            ->withLimit(5);
87
88
        $data = $reader->read();
89
90
        $this->assertCount(5, $data);
91
        $this->assertSame(array_slice($this->getDataSet(), 0, 5), $data);
92
    }
93
94
    public function testOffsetIsApplied(): void
95
    {
96
        $reader = (new IterableDataReader($this->getDataSet()))
97
            ->withOffset(2);
98
99
        $data = $reader->read();
100
101
        $this->assertCount(3, $data);
102
        $this->assertSame(array_slice($this->getDataSet(), 2, 3), $data);
103
    }
104
105
    public function testsWithSortIsImmutable(): void
106
    {
107
        $reader = new IterableDataReader([]);
108
109
        $this->assertNotSame($reader, $reader->withSort(null));
110
    }
111
112
    public function testSorting(): void
113
    {
114
        $sorting = new Sort([
115
            'id',
116
            'name'
117
        ]);
118
119
        $sorting = $sorting->withOrder(['name' => 'asc']);
120
121
        $reader = (new IterableDataReader($this->getDataSet()))
122
            ->withSort($sorting);
123
124
        $data = $reader->read();
125
126
        $this->assertSame($this->getDataSetSortedByName(), $data);
127
    }
128
129
    public function testCounting(): void
130
    {
131
        $reader = new IterableDataReader($this->getDataSet());
132
        $this->assertSame(5, $reader->count());
133
        $this->assertCount(5, $reader);
134
    }
135
136
    public function testsWithFilterIsImmutable(): void
137
    {
138
        $reader = new IterableDataReader([]);
139
140
        $this->assertNotSame($reader, $reader->withFilter(null));
141
    }
142
143
    public function testEqualsFiltering(): void
144
    {
145
        $filter = new Equals('id', 3);
146
        $reader = (new IterableDataReader($this->getDataSet()))
147
            ->withFilter($filter);
148
149
        $this->assertSame([
150
            [
151
                'id' => 3,
152
                'name' => 'Agent K',
153
            ],
154
        ], $reader->read());
155
    }
156
157
    public function testGreaterThanFiltering(): void
158
    {
159
        $filter = new GreaterThan('id', 3);
160
        $reader = (new IterableDataReader($this->getDataSet()))
161
            ->withFilter($filter);
162
163
        $this->assertSame([
164
            [
165
                'id' => 5,
166
                'name' => 'Agent J',
167
            ],
168
            [
169
                'id' => 6,
170
                'name' => '007',
171
            ],
172
        ], $reader->read());
173
    }
174
175
    public function testGreaterThanOrEqualFiltering(): void
176
    {
177
        $filter = new GreaterThanOrEqual('id', 3);
178
        $reader = (new IterableDataReader($this->getDataSet()))
179
            ->withFilter($filter);
180
181
        $this->assertSame([
182
            [
183
                'id' => 3,
184
                'name' => 'Agent K',
185
            ],
186
            [
187
                'id' => 5,
188
                'name' => 'Agent J',
189
            ],
190
            [
191
                'id' => 6,
192
                'name' => '007',
193
            ],
194
        ], $reader->read());
195
    }
196
197
    public function testLessThanFiltering(): void
198
    {
199
        $filter = new LessThan('id', 3);
200
        $reader = (new IterableDataReader($this->getDataSet()))
201
            ->withFilter($filter);
202
203
        $this->assertSame([
204
            [
205
                'id' => 1,
206
                'name' => 'Codename Boris',
207
            ],
208
            [
209
                'id' => 2,
210
                'name' => 'Codename Doris',
211
            ],
212
        ], $reader->read());
213
    }
214
215
    public function testLessThanOrEqualFiltering(): void
216
    {
217
        $filter = new LessThanOrEqual('id', 3);
218
        $reader = (new IterableDataReader($this->getDataSet()))
219
            ->withFilter($filter);
220
221
        $this->assertSame([
222
            [
223
                'id' => 1,
224
                'name' => 'Codename Boris',
225
            ],
226
            [
227
                'id' => 2,
228
                'name' => 'Codename Doris',
229
            ],
230
            [
231
                'id' => 3,
232
                'name' => 'Agent K',
233
            ],
234
        ], $reader->read());
235
    }
236
237
    public function testInFiltering(): void
238
    {
239
        $filter = new In('id', [1, 2]);
240
        $reader = (new IterableDataReader($this->getDataSet()))
241
            ->withFilter($filter);
242
243
        $this->assertSame([
244
            [
245
                'id' => 1,
246
                'name' => 'Codename Boris',
247
            ],
248
            [
249
                'id' => 2,
250
                'name' => 'Codename Doris',
251
            ],
252
        ], $reader->read());
253
    }
254
255
    public function testLikeFiltering(): void
256
    {
257
        $filter = new Like('name', 'agent');
258
        $reader = (new IterableDataReader($this->getDataSet()))
259
            ->withFilter($filter);
260
261
        $this->assertSame([
262
            [
263
                'id' => 3,
264
                'name' => 'Agent K',
265
            ],
266
            [
267
                'id' => 5,
268
                'name' => 'Agent J',
269
            ],
270
        ], $reader->read());
271
    }
272
273
    public function testNotFiltering(): void
274
    {
275
        $filter = new Not(new Equals('id', 1));
276
        $reader = (new IterableDataReader($this->getDataSet()))
277
            ->withFilter($filter);
278
279
        $this->assertSame([
280
            [
281
                'id' => 2,
282
                'name' => 'Codename Doris',
283
            ],
284
            [
285
                'id' => 3,
286
                'name' => 'Agent K',
287
            ],
288
            [
289
                'id' => 5,
290
                'name' => 'Agent J',
291
            ],
292
            [
293
                'id' => 6,
294
                'name' => '007',
295
            ],
296
        ], $reader->read());
297
    }
298
299
    public function testAnyFiltering(): void
300
    {
301
        $filter = new Any(
302
            new Equals('id', 1),
303
            new Equals('id', 2)
304
        );
305
        $reader = (new IterableDataReader($this->getDataSet()))
306
            ->withFilter($filter);
307
308
        $this->assertSame([
309
            [
310
                'id' => 1,
311
                'name' => 'Codename Boris',
312
            ],
313
            [
314
                'id' => 2,
315
                'name' => 'Codename Doris',
316
            ],
317
        ], $reader->read());
318
    }
319
320
    public function testAllFiltering(): void
321
    {
322
        $filter = new All(
323
            new GreaterThan('id', 3),
324
            new Like('name', 'agent')
325
        );
326
        $reader = (new IterableDataReader($this->getDataSet()))
327
            ->withFilter($filter);
328
329
        $this->assertSame([
330
            [
331
                'id' => 5,
332
                'name' => 'Agent J',
333
            ],
334
        ], $reader->read());
335
    }
336
337
    public function testLimitedSort(): void
338
    {
339
        $readerMin = (new IterableDataReader($this->getDataSet()))
340
            ->withSort(
341
                (new Sort(['id']))->withOrder(['id' => 'asc'])
342
            )
343
            ->withLimit(1);
344
        $min = $readerMin->read()[0]['id'];
345
        $this->assertSame(1, $min, 'Wrong min value found');
346
347
        $readerMax = (new IterableDataReader($this->getDataSet()))
348
            ->withSort(
349
                (new Sort(['id']))->withOrder(['id' => 'desc'])
350
            )
351
            ->withLimit(1);
352
        $max = $readerMax->read()[0]['id'];
353
        $this->assertSame(6, $max, 'Wrong max value found');
354
    }
355
356
    public function testFilteredCount(): void
357
    {
358
        $reader = new IterableDataReader($this->getDataSet());
359
        $total = count($reader);
360
361
        $this->assertSame(5, $total, 'Wrong count of elements');
362
363
        $reader = $reader->withFilter(new Like('name', 'agent'));
364
        $totalAgents = count($reader);
365
        $this->assertSame(2, $totalAgents, 'Wrong count of filtered elements');
366
    }
367
368
    public function testIteratorIteratorAsDataSet(): void
369
    {
370
        $reader = new IterableDataReader(new \ArrayIterator($this->getDataSet()));
371
        $sorting = new Sort([
372
            'id',
373
            'name'
374
        ]);
375
        $sorting = $sorting->withOrder(['name' => 'asc']);
376
        $this->assertSame($this->getDataSetSortedByName(), $reader->withSort($sorting)->read());
377
    }
378
379
    private function getDataSetAsGenerator(): \Generator
380
    {
381
        yield from $this->getDataSet();
382
    }
383
384
    public function testGeneratorAsDataSet(): void
385
    {
386
        $reader = new IterableDataReader($this->getDataSetAsGenerator());
387
        $sorting = new Sort([
388
            'id',
389
            'name'
390
        ]);
391
        $sorting = $sorting->withOrder(['name' => 'asc']);
392
        $this->assertSame($this->getDataSetSortedByName(), $reader->withSort($sorting)->read());
393
    }
394
395
    public function testCustomFilter(): void
396
    {
397
        $digitalFilter = new class /*Digital*/ ('name') implements FilterInterface {
398
            private $field;
399
400
            public function __construct(string $field)
401
            {
402
                $this->field = $field;
403
            }
404
405
            public function toArray(): array
406
            {
407
                return [self::getOperator(), $this->field];
408
            }
409
410
            public static function getOperator(): string
411
            {
412
                return 'digital';
413
            }
414
        };
415
        $reader = new class($this->getDataSet()) extends IterableDataReader {
416
            protected function matchFilter(array $item, array $filter): bool
417
            {
418
                [$operation, $field] = $filter;
419
420
                if ($operation === 'digital' /*Digital::getOperator()*/) {
421
                    return ctype_digit($item[$field]);
422
                }
423
424
                return parent::matchFilter($item, $filter);
425
            }
426
        };
427
428
        $reader = $reader->withFilter($digitalFilter);
429
430
        $filtered = $reader->read();
431
        $this->assertCount(1, $filtered);
432
        $this->assertSame('007', $filtered[0]['name']);
433
    }
434
435
    public function testNotSupportedOperator(): void
436
    {
437
        $dataReader = (new IterableDataReader($this->getDataSet()))
438
            ->withFilter(new class('id', 2) extends Equals {
439
                public static function getOperator(): string
440
                {
441
                    return '----';
442
                }
443
            });
444
        $this->expectException(\RuntimeException::class);
445
        $dataReader->read();
446
    }
447
}
448