Passed
Push — master ( 44018e...e279c8 )
by Eric
01:50
created

testPaginateItemsPerPageNegativeOne()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 77
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 51
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 77
rs 9.069

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Pagination - Simple, lightweight and universal service that implements pagination on collections of things.
7
 *
8
 * @author    Eric Sizemore <[email protected]>
9
 * @version   2.0.1
10
 * @copyright (C) 2024 Eric Sizemore
11
 * @license   The MIT License (MIT)
12
 *
13
 * Copyright (C) 2024 Eric Sizemore<https://www.secondversion.com/>.
14
 * Copyright (c) 2015-2019 Ashley Dawson<[email protected]>
15
 *
16
 * Permission is hereby granted, free of charge, to any person obtaining a copy
17
 * of this software and associated documentation files (the "Software"), to
18
 * deal in the Software without restriction, including without limitation the
19
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
20
 * sell copies of the Software, and to permit persons to whom the Software is
21
 * furnished to do so, subject to the following conditions:
22
 *
23
 * The above copyright notice and this permission notice shall be included in
24
 * all copies or substantial portions of the Software.
25
 *
26
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
 * THE SOFTWARE.
33
 */
34
35
/**
36
 * Esi\Pagination is a fork of AshleyDawson\SimplePagination (https://github.com/AshleyDawson/SimplePagination) which is:
37
 *     Copyright (c) 2015-2019 Ashley Dawson
38
 *
39
 * For a list of changes made in Esi\Pagination in comparison to the original library {@see CHANGELOG.md}.
40
 */
41
42
namespace Esi\Pagination\Tests;
43
44
use ArrayIterator;
45
use Esi\Pagination\Exception\CallbackNotFoundException;
46
use Esi\Pagination\Exception\InvalidPageNumberException;
47
use Esi\Pagination\Pagination;
48
use Esi\Pagination\Paginator;
49
use PDO;
50
use PDOStatement;
51
use PHPUnit\Framework\Attributes\CoversClass;
52
use PHPUnit\Framework\Attributes\UsesClass;
53
use PHPUnit\Framework\TestCase;
54
55
use function array_merge;
56
use function array_slice;
57
use function count;
58
use function range;
59
use function sprintf;
60
61
/**
62
 * @internal
63
 */
64
#[CoversClass(Paginator::class)]
65
#[CoversClass(Pagination::class)]
66
#[UsesClass(CallbackNotFoundException::class)]
67
#[UsesClass(InvalidPageNumberException::class)]
68
class PaginatorTest extends TestCase
69
{
70
    /**
71
     * Paginator object used throughout testing.
72
     */
73
    protected Paginator $paginator;
74
75
    /**
76
     * PDO_SQLITE object for the database testing.
77
     */
78
    protected static PDO $dbObj;
79
80
    /**
81
     * Creates our Paginator and PDO objects.
82
     */
83
    protected function setUp(): void
84
    {
85
        parent::setUp();
86
87
        $this->paginator = new Paginator();
88
        self::$dbObj     = new PDO(sprintf('sqlite:%s/fixtures/factbook.db', __DIR__));
89
    }
90
91
    /**
92
     */
93
    public function testConstructionWithInvalidConfig(): void
94
    {
95
        // @phpstan-ignore-next-line
96
        $paginator = new Paginator([
97
            'itemTotalCallback' => '',
98
            'sliceCallback'     => '',
99
            'itemsPerPage'      => '',
100
            'pagesInRange'      => '',
101
            'nonexistent'       => '',
102
        ]);
103
104
        self::assertNull($paginator->getItemTotalCallback());
105
        self::assertNull($paginator->getSliceCallback());
106
        self::assertSame(10, $paginator->getItemsPerPage());
107
        self::assertSame(5, $paginator->getPagesInRange());
108
    }
109
110
    /**
111
     * Test pagination of database results. This test uses PDO and a SQLite db, though this is perfectly
112
     * valid for MySQL, etc. as well.
113
     *
114
     * Uses factbook.db, which is licensed under the CC0-1.0 (public domain).
115
     *
116
     * @see https://github.com/factbook/factbook.sql/releases
117
     * @see ../fixtures/factbook.db
118
     */
119
    public function testPaginateDbResults(): void
120
    {
121
        $paginator = new Paginator();
122
        $paginator
123
            ->setItemsPerPage(10)
124
            ->setPagesInRange(5);
125
126
        $paginator->setItemTotalCallback(static function (): int {
127
            /** @var PDOStatement $result */
128
            $result = self::$dbObj->query("SELECT COUNT(*) as totalCount FROM facts");
129
            $row    = $result->fetchColumn();
130
            return (int) $row;
131
        });
132
133
        // Pass our slice callback.
134
        $paginator->setSliceCallback(static function (int $offset, int $length): array {
135
            /** @var PDOStatement $result */
136
            $result     = self::$dbObj->query(sprintf('SELECT name, area FROM facts ORDER BY area DESC LIMIT %d, %d', $offset, $length), PDO::FETCH_ASSOC);
137
            $collection = [];
138
139
            foreach ($result as $row) {
140
                $collection[] = $row;
141
            }
142
143
            return $collection;
144
        });
145
146
        $pagination = $paginator->paginate();
147
148
        self::assertNotEmpty($pagination->getItems());
149
        self::assertSame(261, $pagination->getTotalNumberOfItems());
150
        self::assertSame([
151
            0 => [
152
                'name' => 'Russia',
153
                'area' => 17098242,
154
            ],
155
            1 => [
156
                'name' => 'Canada',
157
                'area' => 9984670,
158
            ],
159
            2 => [
160
                'name' => 'United States',
161
                'area' => 9826675,
162
            ],
163
            3 => [
164
                'name' => 'China',
165
                'area' => 9596960,
166
            ],
167
            4 => [
168
                'name' => 'Brazil',
169
                'area' => 8515770,
170
            ],
171
            5 => [
172
                'name' => 'Australia',
173
                'area' => 7741220,
174
            ],
175
            6 => [
176
                'name' => 'European Union',
177
                'area' => 4324782,
178
            ],
179
            7 => [
180
                'name' => 'India',
181
                'area' => 3287263,
182
            ],
183
            8 => [
184
                'name' => 'Argentina',
185
                'area' => 2780400,
186
            ],
187
            9 => [
188
                'name' => 'Kazakhstan',
189
                'area' => 2724900,
190
            ],
191
        ], $pagination->getItems());
192
193
        self::assertSame([
194
            0 => 1,
195
            1 => 2,
196
            2 => 3,
197
            3 => 4,
198
            4 => 5,
199
        ], $pagination->getPages());
200
201
        // Paginate the item collection, passing the current page number (e.g. from the current request).
202
        $pagination = $paginator->paginate(3);
203
204
        self::assertNotEmpty($pagination->getItems());
205
        self::assertSame([
206
            0 => [
207
                'name' => 'Peru',
208
                'area' => 1285216,
209
            ],
210
            1 => [
211
                'name' => 'Angola',
212
                'area' => 1246700,
213
            ],
214
            2 => [
215
                'name' => 'Mali',
216
                'area' => 1240192,
217
            ],
218
            3 => [
219
                'name' => 'South Africa',
220
                'area' => 1219090,
221
            ],
222
            4 => [
223
                'name' => 'Colombia',
224
                'area' => 1138910,
225
            ],
226
            5 => [
227
                'name' => 'Ethiopia',
228
                'area' => 1104300,
229
            ],
230
            6 => [
231
                'name' => 'Bolivia',
232
                'area' => 1098581,
233
            ],
234
            7 => [
235
                'name' => 'Mauritania',
236
                'area' => 1030700,
237
            ],
238
            8 => [
239
                'name' => 'Egypt',
240
                'area' => 1001450,
241
            ],
242
            9 => [
243
                'name' => 'Tanzania',
244
                'area' => 947300,
245
            ],
246
        ], $pagination->getItems());
247
248
        self::assertSame([
249
            0 => 1,
250
            1 => 2,
251
            2 => 3,
252
            3 => 4,
253
            4 => 5,
254
        ], $pagination->getPages());
255
256
        $pagination = $paginator->paginate(6);
257
258
        self::assertNotEmpty($pagination->getItems());
259
        self::assertSame([
260
            0 => [
261
                'name' => 'Spain',
262
                'area' => 505370,
263
            ],
264
            1 => [
265
                'name' => 'Turkmenistan',
266
                'area' => 488100,
267
            ],
268
            2 => [
269
                'name' => 'Cameroon',
270
                'area' => 475440,
271
            ],
272
            3 => [
273
                'name' => 'Papua New Guinea',
274
                'area' => 462840,
275
            ],
276
            4 => [
277
                'name' => 'Sweden',
278
                'area' => 450295,
279
            ],
280
            5 => [
281
                'name' => 'Uzbekistan',
282
                'area' => 447400,
283
            ],
284
            6 => [
285
                'name' => 'Morocco',
286
                'area' => 446550,
287
            ],
288
            7 => [
289
                'name' => 'Iraq',
290
                'area' => 438317,
291
            ],
292
            8 => [
293
                'name' => 'Paraguay',
294
                'area' => 406752,
295
            ],
296
            9 => [
297
                'name' => 'Zimbabwe',
298
                'area' => 390757,
299
            ],
300
        ], $pagination->getItems());
301
302
        self::assertSame([
303
            0 => 4,
304
            1 => 5,
305
            2 => 6,
306
            3 => 7,
307
            4 => 8,
308
        ], $pagination->getPages());
309
310
        $pagination = $paginator->paginate(50);
311
        self::assertCount(0, $pagination->getItems());
312
    }
313
314
    public function testSetSliceCallback(): void
315
    {
316
        $this->paginator->setSliceCallback(static fn (): string => 'slice_callback');
317
318
        $callback = $this->paginator->getSliceCallback();
319
320
        self::assertInstanceOf('\Closure', $callback);
321
322
        self::assertSame('slice_callback', $callback());
323
    }
324
325
    public function testSetItemTotalCallback(): void
326
    {
327
        $this->paginator->setItemTotalCallback(static fn (): string => 'item_total_callback');
328
329
        $callback = $this->paginator->getItemTotalCallback();
330
331
        self::assertInstanceOf('\Closure', $callback);
332
333
        self::assertSame('item_total_callback', $callback());
334
    }
335
336
    public function testSetItemsPerPage(): void
337
    {
338
        $this->paginator->setItemsPerPage(45);
339
340
        self::assertSame(45, $this->paginator->getItemsPerPage());
341
    }
342
343
    public function testSetPagesInRange(): void
344
    {
345
        $this->paginator->setPagesInRange(23);
346
347
        self::assertSame(23, $this->paginator->getPagesInRange());
348
    }
349
350
    public function testPaginateFailZeroPageNumber(): void
351
    {
352
        $this->expectException(InvalidPageNumberException::class);
353
        $this->expectException(CallbackNotFoundException::class);
354
        $this->paginator->paginate(0);
355
    }
356
357
    public function testBeforeAndAfterQueryCallbacksZeroPageNumber(): void
358
    {
359
        $items = range(0, 27);
360
361
        $paginator = new Paginator([
362
            'itemTotalCallback' => static fn (): int => count($items),
363
            'sliceCallback'     => static fn (int $offset, int $length): array => array_slice($items, $offset, $length),
364
            'itemsPerPage'      => 10,
365
            'pagesInRange'      => 5,
366
        ]);
367
368
        $beforeQueryFired = false;
369
        $paginator->setBeforeQueryCallback(static function () use (&$beforeQueryFired): void {
370
            $beforeQueryFired = true;
371
        });
372
373
        $afterQueryFired = false;
374
        $paginator->setAfterQueryCallback(static function () use (&$afterQueryFired): void {
375
            $afterQueryFired = true;
376
        });
377
378
        self::assertFalse($beforeQueryFired);
379
        self::assertFalse($afterQueryFired);
380
381
        $this->expectException(InvalidPageNumberException::class);
382
        $paginator->paginate(0);
383
    }
384
385
    public function testBeforeAndAfterQueryCallbacks(): void
386
    {
387
        $items = range(0, 27);
388
389
        $paginator = new Paginator([
390
            'itemTotalCallback' => static fn (): int => count($items),
391
            'sliceCallback'     => static fn (int $offset, int $length): array => array_slice($items, $offset, $length),
392
            'itemsPerPage'      => 10,
393
            'pagesInRange'      => 5,
394
        ]);
395
396
        $beforeQueryFired = false;
397
        $paginator->setBeforeQueryCallback(static function () use (&$beforeQueryFired): void {
398
            $beforeQueryFired = true;
399
        });
400
401
        $afterQueryFired = false;
402
        $paginator->setAfterQueryCallback(static function () use (&$afterQueryFired): void {
403
            $afterQueryFired = true;
404
        });
405
406
        self::assertFalse($beforeQueryFired);
407
        self::assertFalse($afterQueryFired);
408
409
        $paginator->paginate();
410
411
        self::assertTrue($beforeQueryFired); // @phpstan-ignore-line
412
        self::assertTrue($afterQueryFired); // @phpstan-ignore-line
413
414
        $beforeCallback = $paginator->getBeforeQueryCallback();
415
        $afterCallback  = $paginator->getAfterQueryCallback();
416
417
        self::assertInstanceOf('\Closure', $beforeCallback);
418
        self::assertInstanceOf('\Closure', $afterCallback);
419
420
        self::assertNull($beforeCallback());
421
        self::assertNull($afterCallback());
422
    }
423
424
    public function testPaginateLowVolumeConstructorConfig(): void
425
    {
426
        $items = range(0, 27);
427
428
        $paginator = new Paginator([
429
            'itemTotalCallback' => static fn (): int => count($items),
430
            'sliceCallback'     => static fn (int $offset, int $length): array => array_slice($items, $offset, $length),
431
            'itemsPerPage'      => 10,
432
            'pagesInRange'      => 5,
433
        ]);
434
435
        $pagination = $paginator->paginate();
436
437
        self::assertCount(10, $pagination->getItems());
438
        self::assertCount(3, $pagination->getPages());
439
440
        self::assertSame(3, $pagination->getTotalNumberOfPages());
441
        self::assertSame(1, $pagination->getCurrentPageNumber());
442
        self::assertSame(1, $pagination->getFirstPageNumber());
443
        self::assertSame(3, $pagination->getLastPageNumber());
444
445
        self::assertNull($pagination->getPreviousPageNumber());
446
447
        self::assertSame(2, $pagination->getNextPageNumber());
448
        self::assertSame(10, $pagination->getItemsPerPage());
449
        self::assertSame(28, $pagination->getTotalNumberOfItems());
450
        self::assertSame(1, $pagination->getFirstPageNumberInRange());
451
        self::assertSame(3, $pagination->getLastPageNumberInRange());
452
453
        // Increment page
454
        $pagination = $paginator->paginate(2);
455
456
        self::assertCount(10, $pagination->getItems());
457
        self::assertCount(3, $pagination->getPages());
458
459
        self::assertSame(3, $pagination->getTotalNumberOfPages());
460
        self::assertSame(2, $pagination->getCurrentPageNumber());
461
        self::assertSame(1, $pagination->getFirstPageNumber());
462
        self::assertSame(3, $pagination->getLastPageNumber());
463
        self::assertSame(1, $pagination->getPreviousPageNumber());
464
        self::assertSame(3, $pagination->getNextPageNumber());
465
        self::assertSame(10, $pagination->getItemsPerPage());
466
        self::assertSame(28, $pagination->getTotalNumberOfItems());
467
        self::assertSame(1, $pagination->getFirstPageNumberInRange());
468
        self::assertSame(3, $pagination->getLastPageNumberInRange());
469
470
        // Increment page
471
        $pagination = $paginator->paginate(3);
472
473
        self::assertCount(8, $pagination->getItems());
474
        self::assertCount(3, $pagination->getPages());
475
476
        self::assertSame(3, $pagination->getTotalNumberOfPages());
477
        self::assertSame(3, $pagination->getCurrentPageNumber());
478
        self::assertSame(1, $pagination->getFirstPageNumber());
479
        self::assertSame(3, $pagination->getLastPageNumber());
480
        self::assertSame(2, $pagination->getPreviousPageNumber());
481
482
        self::assertNull($pagination->getNextPageNumber());
483
484
        self::assertSame(10, $pagination->getItemsPerPage());
485
        self::assertSame(28, $pagination->getTotalNumberOfItems());
486
        self::assertSame(1, $pagination->getFirstPageNumberInRange());
487
        self::assertSame(3, $pagination->getLastPageNumberInRange());
488
    }
489
490
    public function testPaginationIteratorAggregate(): void
491
    {
492
        $items = range(0, 27);
493
494
        $paginator = new Paginator([
495
            'itemTotalCallback' => static fn (): int => count($items),
496
            'sliceCallback'     => static fn (int $offset, int $length): array => array_slice($items, $offset, $length),
497
            'itemsPerPage'      => 15,
498
            'pagesInRange'      => 5,
499
        ]);
500
501
        $pagination = $paginator->paginate();
502
503
        self::assertCount(15, $pagination);
504
505
        $iterations = 0;
506
507
        foreach ($pagination as $i => $item) {
508
            self::assertSame($i, $item);
509
510
            ++$iterations;
511
        }
512
513
        self::assertSame(15, $iterations);
514
    }
515
516
    public function testPaginateLowVolume(): void
517
    {
518
        $items = range(0, 27);
519
520
        $this->paginator->setItemsPerPage(10)->setPagesInRange(5);
521
522
        $this->paginator->setItemTotalCallback(static function (Pagination $pagination) use ($items): int {
523
            $pagination->setMeta(['meta_1']);
524
525
            return count($items);
526
        });
527
528
        $this->paginator->setSliceCallback(static function (int $offset, int $length, Pagination $pagination) use ($items): array {
529
            $pagination->setMeta(array_merge($pagination->getMeta(), ['meta_2']));
530
531
            return array_slice($items, $offset, $length);
532
        });
533
534
        $pagination = $this->paginator->paginate();
535
536
        self::assertContains('meta_1', $pagination->getMeta());
537
        self::assertContains('meta_2', $pagination->getMeta());
538
539
        self::assertCount(10, $pagination->getItems());
540
        self::assertCount(3, $pagination->getPages());
541
542
        self::assertSame(3, $pagination->getTotalNumberOfPages());
543
        self::assertSame(1, $pagination->getCurrentPageNumber());
544
        self::assertSame(1, $pagination->getFirstPageNumber());
545
        self::assertSame(3, $pagination->getLastPageNumber());
546
547
        self::assertNull($pagination->getPreviousPageNumber());
548
549
        self::assertSame(2, $pagination->getNextPageNumber());
550
        self::assertSame(10, $pagination->getItemsPerPage());
551
        self::assertSame(28, $pagination->getTotalNumberOfItems());
552
        self::assertSame(1, $pagination->getFirstPageNumberInRange());
553
        self::assertSame(3, $pagination->getLastPageNumberInRange());
554
555
        // Increment page
556
        $pagination = $this->paginator->paginate(2);
557
558
        self::assertCount(10, $pagination->getItems());
559
        self::assertCount(3, $pagination->getPages());
560
561
        self::assertSame(3, $pagination->getTotalNumberOfPages());
562
        self::assertSame(2, $pagination->getCurrentPageNumber());
563
        self::assertSame(1, $pagination->getFirstPageNumber());
564
        self::assertSame(3, $pagination->getLastPageNumber());
565
        self::assertSame(1, $pagination->getPreviousPageNumber());
566
        self::assertSame(3, $pagination->getNextPageNumber());
567
        self::assertSame(10, $pagination->getItemsPerPage());
568
        self::assertSame(28, $pagination->getTotalNumberOfItems());
569
        self::assertSame(1, $pagination->getFirstPageNumberInRange());
570
        self::assertSame(3, $pagination->getLastPageNumberInRange());
571
572
        // Increment page
573
        $pagination = $this->paginator->paginate(3);
574
575
        self::assertCount(8, $pagination->getItems());
576
        self::assertCount(3, $pagination->getPages());
577
578
        self::assertSame(3, $pagination->getTotalNumberOfPages());
579
        self::assertSame(3, $pagination->getCurrentPageNumber());
580
        self::assertSame(1, $pagination->getFirstPageNumber());
581
        self::assertSame(3, $pagination->getLastPageNumber());
582
        self::assertSame(2, $pagination->getPreviousPageNumber());
583
584
        self::assertNull($pagination->getNextPageNumber());
585
586
        self::assertSame(10, $pagination->getItemsPerPage());
587
        self::assertSame(28, $pagination->getTotalNumberOfItems());
588
        self::assertSame(1, $pagination->getFirstPageNumberInRange());
589
        self::assertSame(3, $pagination->getLastPageNumberInRange());
590
591
        self::assertContains('meta_1', $pagination->getMeta());
592
        self::assertContains('meta_2', $pagination->getMeta());
593
    }
594
595
    public function testPaginateHighVolume(): void
596
    {
597
        $items = range(0, 293832);
598
599
        $this->paginator->setItemsPerPage(10)->setPagesInRange(5);
600
601
        $this->paginator->setItemTotalCallback(static function (Pagination $pagination) use ($items): int {
602
            $pagination->setMeta(['meta_3']);
603
604
            return count($items);
605
        });
606
607
        $this->paginator->setSliceCallback(static function (int $offset, int $length, Pagination $pagination) use ($items): array {
608
            $pagination->setMeta(array_merge($pagination->getMeta(), ['meta_4']));
609
610
            return array_slice($items, $offset, $length);
611
        });
612
613
        $pagination = $this->paginator->paginate();
614
615
        self::assertContains('meta_3', $pagination->getMeta());
616
        self::assertContains('meta_4', $pagination->getMeta());
617
618
        self::assertCount(10, $pagination->getItems());
619
        self::assertCount(5, $pagination->getPages());
620
621
        self::assertSame(29384, $pagination->getTotalNumberOfPages());
622
        self::assertSame(1, $pagination->getCurrentPageNumber());
623
        self::assertSame(1, $pagination->getFirstPageNumber());
624
        self::assertSame(29384, $pagination->getLastPageNumber());
625
626
        self::assertNull($pagination->getPreviousPageNumber());
627
628
        self::assertSame(2, $pagination->getNextPageNumber());
629
        self::assertSame(10, $pagination->getItemsPerPage());
630
        self::assertSame(293833, $pagination->getTotalNumberOfItems());
631
        self::assertSame(1, $pagination->getFirstPageNumberInRange());
632
        self::assertSame(5, $pagination->getLastPageNumberInRange());
633
634
        // Move to random page
635
        $pagination = $this->paginator->paginate(4573);
636
637
        self::assertCount(10, $pagination->getItems());
638
        self::assertCount(5, $pagination->getPages());
639
640
        self::assertSame(29384, $pagination->getTotalNumberOfPages());
641
        self::assertSame(4573, $pagination->getCurrentPageNumber());
642
        self::assertSame(1, $pagination->getFirstPageNumber());
643
        self::assertSame(29384, $pagination->getLastPageNumber());
644
        self::assertSame(4572, $pagination->getPreviousPageNumber());
645
        self::assertSame(4574, $pagination->getNextPageNumber());
646
        self::assertSame(10, $pagination->getItemsPerPage());
647
        self::assertSame(293833, $pagination->getTotalNumberOfItems());
648
        self::assertSame(4571, $pagination->getFirstPageNumberInRange());
649
        self::assertSame(4575, $pagination->getLastPageNumberInRange());
650
651
        // Move to last page
652
        $pagination = $this->paginator->paginate(29384);
653
654
        self::assertCount(3, $pagination->getItems());
655
        self::assertCount(5, $pagination->getPages());
656
657
        self::assertSame(29384, $pagination->getTotalNumberOfPages());
658
        self::assertSame(29384, $pagination->getCurrentPageNumber());
659
        self::assertSame(1, $pagination->getFirstPageNumber());
660
        self::assertSame(29384, $pagination->getLastPageNumber());
661
        self::assertSame(29383, $pagination->getPreviousPageNumber());
662
663
        self::assertNull($pagination->getNextPageNumber());
664
665
        self::assertSame(10, $pagination->getItemsPerPage());
666
        self::assertSame(293833, $pagination->getTotalNumberOfItems());
667
        self::assertSame(29380, $pagination->getFirstPageNumberInRange());
668
        self::assertSame(29384, $pagination->getLastPageNumberInRange());
669
670
        self::assertContains('meta_3', $pagination->getMeta());
671
        self::assertContains('meta_4', $pagination->getMeta());
672
    }
673
674
    public function testPaginateItemsPerPageNegativeOne(): void
675
    {
676
        $items = range(0, 1000);
677
678
        $this->paginator->setItemsPerPage(-1)->setPagesInRange(5);
679
680
        $this->paginator->setItemTotalCallback(static function (Pagination $pagination) use ($items): int {
681
            $pagination->setMeta(['meta_3']);
682
683
            return count($items);
684
        });
685
686
        $this->paginator->setSliceCallback(static function (int $offset, int $length, Pagination $pagination) use ($items): array {
687
            $pagination->setMeta(array_merge($pagination->getMeta(), ['meta_4']));
688
689
            return array_slice($items, $offset, $length);
690
        });
691
692
        $pagination = $this->paginator->paginate();
693
694
        self::assertContains('meta_3', $pagination->getMeta());
695
        self::assertContains('meta_4', $pagination->getMeta());
696
697
        self::assertCount(1001, $pagination->getItems());
698
        self::assertCount(1003, $pagination->getPages());
699
700
        self::assertSame(-1001, $pagination->getTotalNumberOfPages());
701
        self::assertSame(1, $pagination->getCurrentPageNumber());
702
        self::assertSame(1, $pagination->getFirstPageNumber());
703
        self::assertSame(-1001, $pagination->getLastPageNumber());
704
705
        self::assertNull($pagination->getPreviousPageNumber());
706
707
        self::assertNull($pagination->getNextPageNumber());
708
        self::assertSame(-1, $pagination->getItemsPerPage());
709
        self::assertSame(1001, $pagination->getTotalNumberOfItems());
710
        self::assertSame(-1001, $pagination->getFirstPageNumberInRange());
711
        self::assertSame(1, $pagination->getLastPageNumberInRange());
712
713
        // Move to random page
714
        $pagination = $this->paginator->paginate(567);
715
716
        self::assertCount(1001, $pagination->getItems());
717
        self::assertCount(1003, $pagination->getPages());
718
719
        self::assertSame(-1001, $pagination->getTotalNumberOfPages());
720
        self::assertSame(567, $pagination->getCurrentPageNumber());
721
        self::assertSame(1, $pagination->getFirstPageNumber());
722
        self::assertSame(-1001, $pagination->getLastPageNumber());
723
        self::assertSame(566, $pagination->getPreviousPageNumber());
724
        self::assertNull($pagination->getNextPageNumber());
725
        self::assertSame(-1, $pagination->getItemsPerPage());
726
        self::assertSame(1001, $pagination->getTotalNumberOfItems());
727
        self::assertSame(-1001, $pagination->getFirstPageNumberInRange());
728
        self::assertSame(1, $pagination->getLastPageNumberInRange());
729
730
        // Move to last page
731
        $pagination = $this->paginator->paginate(1003);
732
733
        self::assertCount(1001, $pagination->getItems());
734
        self::assertCount(1003, $pagination->getPages());
735
736
        self::assertSame(-1001, $pagination->getTotalNumberOfPages());
737
        self::assertSame(1003, $pagination->getCurrentPageNumber());
738
        self::assertSame(1, $pagination->getFirstPageNumber());
739
        self::assertSame(-1001, $pagination->getLastPageNumber());
740
        self::assertSame(1002, $pagination->getPreviousPageNumber());
741
742
        self::assertNull($pagination->getNextPageNumber());
743
744
        self::assertSame(-1, $pagination->getItemsPerPage());
745
        self::assertSame(1001, $pagination->getTotalNumberOfItems());
746
        self::assertSame(-1001, $pagination->getFirstPageNumberInRange());
747
        self::assertSame(1, $pagination->getLastPageNumberInRange());
748
749
        self::assertContains('meta_3', $pagination->getMeta());
750
        self::assertContains('meta_4', $pagination->getMeta());
751
    }
752
753
    public function testPaginationIterator(): void
754
    {
755
        $items = range(0, 27);
756
757
        $paginator = new Paginator([
758
            'itemTotalCallback' => static fn (): int => count($items),
759
            'sliceCallback'     => static fn (int $offset, int $length): ArrayIterator => new ArrayIterator(array_slice($items, $offset, $length)),
760
            'itemsPerPage'      => 15,
761
            'pagesInRange'      => 5,
762
        ]);
763
764
        $pagination = $paginator->paginate();
765
766
        self::assertCount(15, $pagination);
767
768
        foreach ($pagination as $i => $item) {
769
            self::assertSame($i, $item);
770
        }
771
    }
772
773
    public function testItemTotalCallbackNotFound(): void
774
    {
775
        $this->paginator->setItemsPerPage(10)->setPagesInRange(5);
776
777
        $this->expectException(CallbackNotFoundException::class);
778
        $this->paginator->setItemTotalCallback(null);
779
        $this->paginator->setSliceCallback(static fn (): string => 'slice_callback');
780
        $this->paginator->paginate();
781
    }
782
783
    public function testSliceCallbackNotFound(): void
784
    {
785
        $this->paginator->setItemsPerPage(10)->setPagesInRange(5);
786
787
        $this->expectException(CallbackNotFoundException::class);
788
        $this->paginator->setItemTotalCallback(static fn (): string => 'item_total_callback');
789
        $this->paginator->setSliceCallback(null);
790
        $this->paginator->paginate();
791
    }
792
}
793