Passed
Pull Request — master (#24)
by
unknown
02:14
created

KeysetPaginatorTest.php$1 ➔ onePageDataProvider()   A

Complexity

Conditions 1

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 19
rs 9.6333
cc 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Yiisoft\Data\Tests\Paginator;
5
6
use Yiisoft\Data\Paginator\KeysetPaginator;
7
use Yiisoft\Data\Paginator\PaginatorInterface;
8
use Yiisoft\Data\Reader\IterableDataReader;
9
use Yiisoft\Data\Reader\Filter\FilterInterface;
10
use Yiisoft\Data\Reader\DataReaderInterface;
11
use Yiisoft\Data\Reader\FilterableDataInterface;
12
use Yiisoft\Data\Reader\Sort;
13
use Yiisoft\Data\Tests\TestCase;
14
15
final class KeysetPaginatorTest extends Testcase
16
{
17
    private function getDataSet(): array
18
    {
19
        return [
20
            [
21
                'id' => 1,
22
                'name' => 'Codename Boris',
23
            ],
24
            [
25
                'id' => 2,
26
                'name' => 'Codename Doris',
27
            ],
28
            [
29
                'id' => 3,
30
                'name' => 'Agent K',
31
            ],
32
            [
33
                'id' => 5,
34
                'name' => 'Agent J',
35
            ],
36
            [
37
                'id' => 6,
38
                'name' => '007',
39
            ],
40
        ];
41
    }
42
43
    public function testDataReaderWithoutFilterableInterface(): void
44
    {
45
        $nonFilterableDataReader = new class implements DataReaderInterface
46
        {
47
            public function withLimit(int $limit)
48
            {
49
                // do nothing
50
            }
51
52
            public function read(): iterable
53
            {
54
                return [];
55
            }
56
        };
57
58
        $this->expectException(\InvalidArgumentException::class);
59
60
        new KeysetPaginator($nonFilterableDataReader);
61
    }
62
63
    public function testDataReaderWithoutSortableInterface(): void
64
    {
65
        $nonSortableDataReader = new class implements DataReaderInterface, FilterableDataInterface
66
        {
67
            public function withLimit(int $limit)
68
            {
69
                // do nothing
70
            }
71
72
            public function read(): iterable
73
            {
74
                return [];
75
            }
76
77
            public function withFilter(FilterInterface $filter)
78
            {
79
                // do nothing
80
            }
81
        };
82
83
        $this->expectException(\InvalidArgumentException::class);
84
85
        new KeysetPaginator($nonSortableDataReader);
86
    }
87
88
    public function testPageSizeCannotBeLessThanOne(): void
89
    {
90
        $sort = new Sort(['id', 'name']);
91
        $dataReader = (new IterableDataReader($this->getDataSet()))
92
            ->withSort($sort);
93
        $paginator = new KeysetPaginator($dataReader);
94
95
        $this->expectException(\InvalidArgumentException::class);
96
        $paginator->withPageSize(0);
97
    }
98
99
    public function testThrowsExceptionWhenReaderHasNoSort(): void
100
    {
101
        $dataReader = new IterableDataReader($this->getDataSet());
102
103
        $this->expectException(\RuntimeException::class);
104
105
        new KeysetPaginator($dataReader);
106
    }
107
108
    public function testThrowsExceptionWhenNotSorted(): void
109
    {
110
        $sort = new Sort(['id', 'name']);
111
112
        $dataReader = (new IterableDataReader($this->getDataSet()))
113
            ->withSort($sort);
114
115
        $paginator = (new KeysetPaginator($dataReader))
116
            ->withPageSize(2)
117
            ->withNextPageToken("3");
118
119
        $this->expectException(\RuntimeException::class);
120
121
        $this->iterableToArray($paginator->read());
122
    }
123
124
    /**
125
     * @dataProvider onePageDataProvider
126
     */
127
    public function testOnePage(array $dataSet, int $pageSize): void
128
    {
129
        $sort = (new Sort(['id', 'name']))->withOrderString('id');
130
131
        $dataReader = (new IterableDataReader($dataSet))
132
            ->withSort($sort);
133
        $paginator = (new KeysetPaginator($dataReader))
134
            ->withPageSize($pageSize);
135
        $this->assertTrue($paginator->isOnFirstPage());
136
        $this->assertTrue($paginator->isOnLastPage());
137
    }
138
139
    public function onePageDataProvider() {
140
        return [
141
            [[], 1],
142
            [[], 2],
143
            [[], 3],
144
145
            [array_slice($this->getDataSet(), 0, 1), 1],
146
147
            [array_slice($this->getDataSet(), 0, 1), 2],
148
            [array_slice($this->getDataSet(), 0, 2), 2],
149
150
            [array_slice($this->getDataSet(), 0, 1), 3],
151
            [array_slice($this->getDataSet(), 0, 2), 3],
152
            [array_slice($this->getDataSet(), 0, 3), 3],
153
154
            [array_slice($this->getDataSet(), 0, 1), 4],
155
            [array_slice($this->getDataSet(), 0, 2), 4],
156
            [array_slice($this->getDataSet(), 0, 3), 4],
157
            [array_slice($this->getDataSet(), 0, 4), 4],
158
        ];
159
    }
160
161
    public function testReadFirstPage(): void
162
    {
163
        $sort = (new Sort(['id', 'name']))->withOrderString('id');
164
165
        $dataReader = (new IterableDataReader($this->getDataSet()))
166
            ->withSort($sort);
167
168
169
        $paginator = (new KeysetPaginator($dataReader))
170
            ->withPageSize(2);
171
172
        $expected = [
173
            [
174
                'id' => 1,
175
                'name' => 'Codename Boris',
176
            ],
177
            [
178
                'id' => 2,
179
                'name' => 'Codename Doris',
180
            ],
181
        ];
182
183
        $this->assertSame($expected, $this->iterableToArray($paginator->read()));
184
        $last = end($expected);
185
        $this->assertSame((string)$last['id'], $paginator->getNextPageToken());
186
        $this->assertSame(true, $paginator->isOnFirstPage());
187
    }
188
189
    public function testReadSecondPage(): void
190
    {
191
        $sort = (new Sort(['id', 'name']))->withOrderString('id');
192
193
        $dataReader = (new IterableDataReader($this->getDataSet()))
194
            ->withSort($sort);
195
196
        $paginator = (new KeysetPaginator($dataReader))
197
            ->withPageSize(2)
198
            ->withNextPageToken("2");
199
200
        $expected = [
201
            [
202
                'id' => 3,
203
                'name' => 'Agent K',
204
            ],
205
            [
206
                'id' => 5,
207
                'name' => 'Agent J',
208
            ],
209
        ];
210
211
        $this->assertSame($expected, $this->iterableToArray($paginator->read()));
212
        $last = end($expected);
213
        $this->assertSame((string)$last['id'], $paginator->getNextPageToken());
214
    }
215
216
    public function testReadSecondPageOrderedByName(): void
217
    {
218
        $sort = (new Sort(['id', 'name']))->withOrderString('name');
219
220
        $dataReader = (new IterableDataReader($this->getDataSet()))
221
            ->withSort($sort);
222
223
        $paginator = (new KeysetPaginator($dataReader))
224
            ->withPageSize(2)
225
            ->withNextPageToken('Agent J');
226
227
        $expected = [
228
            [
229
                'id' => 3,
230
                'name' => 'Agent K',
231
            ],
232
            [
233
                'id' => 1,
234
                'name' => 'Codename Boris',
235
            ],
236
        ];
237
238
        $this->assertSame($expected, $this->iterableToArray($paginator->read()));
239
        $last = end($expected);
240
        $this->assertSame((string)$last['name'], $paginator->getNextPageToken());
241
    }
242
243
    public function testBackwardPagination(): void
244
    {
245
        $sort = (new Sort(['id', 'name']))->withOrderString('id');
246
247
        $dataReader = (new IterableDataReader($this->getDataSet()))
248
            ->withSort($sort);
249
250
        $paginator = (new KeysetPaginator($dataReader))
251
            ->withPageSize(2)
252
            ->withPreviousPageToken("5");
253
254
        $expected = [
255
            [
256
                'id' => 2,
257
                'name' => 'Codename Doris',
258
            ],
259
            [
260
                'id' => 3,
261
                'name' => 'Agent K',
262
            ],
263
        ];
264
        $this->assertSame($expected, $this->iterableToArray($paginator->read()));
265
        $first = reset($expected);
266
        $last = end($expected);
267
        $this->assertSame((string)$last['id'], $paginator->getNextPageToken(), 'Last value fail!');
268
        $this->assertSame((string)$first['id'], $paginator->getPreviousPageToken(), 'First value fail!');
269
    }
270
271
    public function testForwardAndBackwardPagination(): void
272
    {
273
        $sort = (new Sort(['id', 'name']))->withOrderString('id');
274
275
        $dataReader = (new IterableDataReader($this->getDataSet()))
276
            ->withSort($sort);
277
278
        $paginator = (new KeysetPaginator($dataReader))
279
            ->withPageSize(2)
280
            ->withNextPageToken("2");
281
282
        $expected = [
283
            [
284
                'id' => 3,
285
                'name' => 'Agent K',
286
            ],
287
            [
288
                'id' => 5,
289
                'name' => 'Agent J',
290
            ],
291
        ];
292
        $this->assertSame($expected, $this->iterableToArray($paginator->read()));
293
        $first = reset($expected);
294
        $last = end($expected);
295
        $this->assertSame((string)$last['id'], $paginator->getNextPageToken(), 'Last value fail!');
296
        $this->assertSame((string)$first['id'], $paginator->getPreviousPageToken(), 'First value fail!');
297
298
        $expected = [
299
            [
300
                'id' => 1,
301
                'name' => 'Codename Boris',
302
            ],
303
            [
304
                'id' => 2,
305
                'name' => 'Codename Doris',
306
            ],
307
        ];
308
309
        $paginator = (new KeysetPaginator($dataReader))
310
            ->withPageSize(2)
311
            ->withPreviousPageToken($paginator->getPreviousPageToken());
312
313
        $this->assertSame($expected, $this->iterableToArray($paginator->read()));
314
        $last = end($expected);
315
        $this->assertSame((string)$last['id'], $paginator->getNextPageToken(), 'Last value fail!');
316
        $this->assertNull($paginator->getPreviousPageToken(), 'First value fail!');
317
    }
318
319
    public function testIsOnFirstPage(): void
320
    {
321
        $sort = (new Sort(['id']))->withOrderString('id');
322
        $dataReader = (new IterableDataReader($this->getDataSet()))
323
            ->withSort($sort);
324
        $paginator = (new KeysetPaginator($dataReader))
325
            ->withPageSize(2);
326
        $this->assertSame(true, $paginator->isOnFirstPage());
327
    }
328
329
    public function testIsOnLastPage(): void
330
    {
331
        $sort = (new Sort(['id']))->withOrderString('id');
332
        $dataReader = (new IterableDataReader($this->getDataSet()))
333
            ->withSort($sort);
334
        $paginator = (new KeysetPaginator($dataReader))
335
            ->withPageSize(2);
336
337
        $paginator = $paginator->withNextPageToken("6");
338
        $this->assertSame(true, $paginator->isOnLastPage());
339
        $paginator = $paginator->withNextPageToken("5");
340
        $this->assertSame(true, $paginator->isOnLastPage());
341
        $paginator = $paginator->withNextPageToken("4");
342
        $this->assertSame(true, $paginator->isOnLastPage());
343
        $paginator = $paginator->withNextPageToken("3");
344
        $this->assertSame(true, $paginator->isOnLastPage());
345
        $paginator = $paginator->withNextPageToken("2");
346
        $this->assertSame(false, $paginator->isOnLastPage());
347
    }
348
349
    public function testCurrentPageSize(): void
350
    {
351
        $sort = (new Sort(['id']))->withOrderString('id');
352
        $dataReader = (new IterableDataReader($this->getDataSet()))
353
            ->withSort($sort);
354
        $paginator = (new KeysetPaginator($dataReader))
355
            ->withPageSize(2);
356
        $this->assertSame(2, $paginator->getCurrentPageSize());
357
        $paginator = $paginator->withPreviousPageToken("1");
358
        $this->assertSame(0, $paginator->getCurrentPageSize());
359
        $paginator = $paginator->withPreviousPageToken("2");
360
        $this->assertSame(1, $paginator->getCurrentPageSize());
361
        $paginator = $paginator->withPreviousPageToken("3");
362
        $this->assertSame(2, $paginator->getCurrentPageSize());
363
364
        $paginator = $paginator->withNextPageToken("6");
365
        $this->assertSame(0, $paginator->getCurrentPageSize());
366
        $paginator = $paginator->withNextPageToken("5");
367
        $this->assertSame(1, $paginator->getCurrentPageSize());
368
        $paginator = $paginator->withNextPageToken("4");
369
        $this->assertSame(2, $paginator->getCurrentPageSize());
370
    }
371
372
    public function testReadCache()
373
    {
374
        $sort = (new Sort(['id']))->withOrderString('id');
375
        $dataSet = new class($this->getDataSet()) extends \ArrayIterator
376
        {
377
            private $rewindCounter = 0;
378
379
            public function rewind()
380
            {
381
                $this->rewindCounter++;
382
                parent::rewind();
383
            }
384
385
            public function getRewindCounter(): int
386
            {
387
                return $this->rewindCounter;
388
            }
389
        };
390
        $dataReader = (new IterableDataReader($dataSet))->withSort($sort);
391
        $paginator = (new KeysetPaginator($dataReader))
392
            ->withPageSize(2);
393
        // not use datase test
394
        $this->assertSame(0, $dataSet->getRewindCounter());
395
        // first use dataset test
396
        $paginator->getCurrentPageSize();
397
        $this->assertSame(1, $dataSet->getRewindCounter());
398
        // repeated use dataset test
399
        $paginator->getCurrentPageSize();
400
        $this->assertSame(1, $dataSet->getRewindCounter());
401
        $paginator->isOnFirstPage();
402
        $this->assertSame(1, $dataSet->getRewindCounter());
403
        $paginator->isOnLastPage();
404
        $this->assertSame(1, $dataSet->getRewindCounter());
405
        foreach ($paginator->read() as $void) ;
406
        $this->assertSame(1, $dataSet->getRewindCounter());
407
        // clear cache test
408
        $paginator = (new KeysetPaginator($dataReader))
409
            ->withPageSize(3);
410
        $this->assertSame(1, $dataSet->getRewindCounter());
411
        // recreate cache
412
        $paginator->getCurrentPageSize();
413
        $this->assertSame(2, $dataSet->getRewindCounter());
414
        $paginator->getCurrentPageSize();
415
        $this->assertSame(2, $dataSet->getRewindCounter());
416
    }
417
418
    public function testTokenResults(): void
419
    {
420
        $sort = (new Sort(['id']))->withOrderString('id');
421
        $dataReader = (new IterableDataReader($this->getDataSet()))
422
            ->withSort($sort);
423
        $paginator = (new KeysetPaginator($dataReader))
424
            ->withPageSize(2);
425
        $this->assertNotNull($paginator->getNextPageToken());
426
        $paginator = $paginator->withPreviousPageToken("1");
427
        try {
428
            $paginator->getNextPageToken();
429
            $this->assertTrue(false);
430
        } catch (\RuntimeException $e) {
431
            $this->assertTrue(true);
432
        }
433
        $this->assertNull($paginator->getPreviousPageToken());
434
        $paginator = $paginator->withPreviousPageToken("2");
435
        $this->assertNotNull($paginator->getNextPageToken());
436
        $this->assertSame("1", $paginator->getNextPageToken());
437
        $this->assertNull($paginator->getPreviousPageToken());
438
        $paginator = $paginator->withPreviousPageToken("3");
439
        $this->assertNotNull($paginator->getNextPageToken());
440
        $this->assertSame("2", $paginator->getNextPageToken());
441
        $this->assertNull($paginator->getPreviousPageToken());
442
443
        $paginator = $paginator->withNextPageToken("6");
444
        try {
445
            $paginator->getPreviousPageToken();
446
            $this->assertTrue(false);
447
        } catch (\RuntimeException $e) {
448
            $this->assertTrue(true);
449
        }
450
        $this->assertNull($paginator->getNextPageToken());
451
        $paginator = $paginator->withNextPageToken("5");
452
        $this->assertNotNull($paginator->getPreviousPageToken());
453
        $this->assertSame("6", $paginator->getPreviousPageToken());
454
        $this->assertNull($paginator->getNextPageToken());
455
        $paginator = $paginator->withNextPageToken("4");
456
        $this->assertNull($paginator->getNextPageToken());
457
        $this->assertNotNull($paginator->getPreviousPageToken());
458
        $this->assertSame("5", $paginator->getPreviousPageToken());
459
    }
460
461
}
462