Passed
Push — master ( ded3f9...804eff )
by Chito
02:04
created

testSerializeAndUnserialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 3
c 1
b 0
f 1
dl 0
loc 5
rs 10
cc 1
nc 1
nop 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Lampager\Cake\Test\TestCase;
6
7
use ArrayIterator;
8
use Cake\Datasource\ConnectionManager;
9
use Cake\I18n\FrozenTime;
10
use Cake\ORM\Entity;
11
use Generator;
12
use IteratorAggregate;
13
use Lampager\Cake\PaginationResult;
14
use PHPUnit\Framework\MockObject\MockObject;
15
use Traversable;
16
17
class PaginationResultTest extends TestCase
18
{
19
    public function setUp(): void
20
    {
21
        parent::setUp();
22
        
23
        set_error_handler(
24
            static function ($errno, $errstr, $errfile, $errline) {
25
                throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
26
            },
27
            E_ALL
28
        );
29
    }
30
31
    public function tearDown(): void
32
    {
33
        restore_error_handler();
34
35
        parent::tearDown();
36
    }
37
38
    /**
39
     * @param Entity[]                     $entities
40
     * @param Entity[]|Traversable<Entity> $records
41
     * @param mixed[]                      $meta
42
     * @dataProvider arrayProvider
43
     * @dataProvider iteratorAggregateProvider
44
     */
45
    public function testIteratorCurrent(array $entities, $records, array $meta): void
46
    {
47
        $actual = new PaginationResult($records, $meta);
48
49
        $this->assertEquals($entities[0], $actual->current());
50
51
        $actual->next();
52
        $this->assertTrue($actual->valid());
53
        $this->assertEquals(1, $actual->key());
54
        $this->assertEquals($entities[1], $actual->current());
55
56
        $actual->next();
57
        $this->assertTrue($actual->valid());
58
        $this->assertEquals(2, $actual->key());
59
        $this->assertEquals($entities[2], $actual->current());
60
61
        $actual->next();
62
        $this->assertFalse($actual->valid());
63
64
        $actual->rewind();
65
        $this->assertTrue($actual->valid());
66
        $this->assertEquals(0, $actual->key());
67
        $this->assertEquals($entities[0], $actual->current());
68
    }
69
70
    /**
71
     * @param Entity[]                     $entities
72
     * @param Entity[]|Traversable<Entity> $records
73
     * @param mixed[]                      $meta
74
     * @dataProvider arrayProvider
75
     * @dataProvider iteratorAggregateProvider
76
     */
77
    public function testIteratorKey(array $entities, $records, array $meta): void
78
    {
79
        $actual = new PaginationResult($records, $meta);
80
81
        $this->assertEquals(0, $actual->key());
82
83
        $actual->next();
84
        $this->assertTrue($actual->valid());
85
        $this->assertEquals(1, $actual->key());
86
        $this->assertEquals($entities[1], $actual->current());
87
88
        $actual->next();
89
        $this->assertTrue($actual->valid());
90
        $this->assertEquals(2, $actual->key());
91
        $this->assertEquals($entities[2], $actual->current());
92
93
        $actual->next();
94
        $this->assertFalse($actual->valid());
95
96
        $actual->rewind();
97
        $this->assertTrue($actual->valid());
98
        $this->assertEquals(0, $actual->key());
99
        $this->assertEquals($entities[0], $actual->current());
100
    }
101
102
    /**
103
     * @param Entity[]                     $entities
104
     * @param Entity[]|Traversable<Entity> $records
105
     * @param mixed[]                      $meta
106
     * @dataProvider arrayProvider
107
     * @dataProvider iteratorAggregateProvider
108
     */
109
    public function testIteratorNext(array $entities, $records, array $meta): void
110
    {
111
        $actual = new PaginationResult($records, $meta);
112
113
        $actual->next();
114
        $this->assertTrue($actual->valid());
115
        $this->assertEquals(1, $actual->key());
116
        $this->assertEquals($entities[1], $actual->current());
117
118
        $actual->next();
119
        $this->assertTrue($actual->valid());
120
        $this->assertEquals(2, $actual->key());
121
        $this->assertEquals($entities[2], $actual->current());
122
123
        $actual->next();
124
        $this->assertFalse($actual->valid());
125
126
        $actual->rewind();
127
        $this->assertTrue($actual->valid());
128
        $this->assertEquals(0, $actual->key());
129
        $this->assertEquals($entities[0], $actual->current());
130
    }
131
132
    /**
133
     * @param Entity[]                     $entities
134
     * @param Entity[]|Traversable<Entity> $records
135
     * @param mixed[]                      $meta
136
     * @dataProvider arrayProvider
137
     * @dataProvider iteratorAggregateProvider
138
     */
139
    public function testIteratorValid(array $entities, $records, array $meta): void
140
    {
141
        $actual = new PaginationResult($records, $meta);
142
143
        $this->assertTrue($actual->valid());
144
        $this->assertEquals(0, $actual->key());
145
        $this->assertEquals($entities[0], $actual->current());
146
147
        $actual->next();
148
        $this->assertTrue($actual->valid());
149
        $this->assertEquals(1, $actual->key());
150
        $this->assertEquals($entities[1], $actual->current());
151
152
        $actual->next();
153
        $this->assertTrue($actual->valid());
154
        $this->assertEquals(2, $actual->key());
155
        $this->assertEquals($entities[2], $actual->current());
156
157
        $actual->next();
158
        $this->assertFalse($actual->valid());
159
160
        $actual->rewind();
161
        $this->assertTrue($actual->valid());
162
        $this->assertEquals(0, $actual->key());
163
        $this->assertEquals($entities[0], $actual->current());
164
    }
165
166
    /**
167
     * @param Entity[]                     $entities
168
     * @param Entity[]|Traversable<Entity> $records
169
     * @param mixed[]                      $meta
170
     * @dataProvider arrayProvider
171
     * @dataProvider iteratorAggregateProvider
172
     */
173
    public function testJsonSerialize(array $entities, $records, array $meta, string $expected): void
174
    {
175
        $actual = json_encode(new PaginationResult($records, $meta));
176
        $this->assertJsonStringEqualsJsonString($expected, $actual);
177
    }
178
179
    /**
180
     * @param Entity[]                     $entities
181
     * @param Entity[]|Traversable<Entity> $records
182
     * @param mixed[]                      $meta
183
     * @dataProvider arrayProvider
184
     * @dataProvider iteratorAggregateProvider
185
     */
186
    public function testSerializeAndUnserialize(array $entities, $records, array $meta): void
187
    {
188
        $actual = unserialize(serialize(new PaginationResult($records, $meta)));
189
        $expected = new PaginationResult($records, $meta);
190
        $this->assertJsonEquals($expected, $actual);
191
    }
192
193
    /**
194
     * @param Entity[]                     $entities
195
     * @param Entity[]|Traversable<Entity> $records
196
     * @param mixed[]                      $meta
197
     * @dataProvider arrayProvider
198
     * @dataProvider iteratorAggregateProvider
199
     */
200
    public function testDebugInfo(array $entities, $records, array $meta): void
201
    {
202
        $actual = (new PaginationResult($records, $meta))->__debugInfo();
203
204
        $this->assertEquals([
205
            '(help)' => 'This is a Lampager Pagination Result object.',
206
            'records' => $entities,
207
            'hasPrevious' => $meta['hasPrevious'],
208
            'previousCursor' => $meta['previousCursor'],
209
            'hasNext' => $meta['hasNext'],
210
            'nextCursor' => $meta['nextCursor'],
211
        ], $actual);
212
    }
213
214
    /**
215
     * @param Entity[]                     $entities
216
     * @param Entity[]|Traversable<Entity> $records
217
     * @param mixed[]                      $meta
218
     * @dataProvider arrayProvider
219
     * @dataProvider iteratorAggregateProvider
220
     */
221
    public function testPublicProperties(array $entities, $records, array $meta): void
222
    {
223
        $paginationResult = new PaginationResult($records, $meta);
224
225
        $this->assertEquals($meta['hasPrevious'], $paginationResult->hasPrevious);
226
        $this->assertEquals($meta['previousCursor'], $paginationResult->previousCursor);
227
        $this->assertEquals($meta['hasNext'], $paginationResult->hasNext);
228
        $this->assertEquals($meta['nextCursor'], $paginationResult->nextCursor);
229
    }
230
231
    /**
232
     * @param Entity[]                     $entities
233
     * @param Entity[]|Traversable<Entity> $records
234
     * @param mixed[]                      $meta
235
     * @dataProvider arrayProvider
236
     * @dataProvider iteratorAggregateProvider
237
     */
238
    public function testUndefinedProperties(array $entities, $records, array $meta): void
239
    {
240
        $this->expectException(\ErrorException::class);
241
        $this->expectExceptionMessageMatches('/^Undefined property via __get\(\): undefinedProperty/');
242
243
        $paginationResult = new PaginationResult($records, $meta);
244
        $paginationResult->undefinedProperty;
245
    }
246
247
    public function arrayProvider(): Generator
248
    {
249
        yield 'Array iteration' => [
250
            [
251
                new Entity([
252
                    'id' => 1,
253
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
254
                ]),
255
                new Entity([
256
                    'id' => 3,
257
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
258
                ]),
259
                new Entity([
260
                    'id' => 5,
261
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
262
                ]),
263
            ],
264
            [
265
                new Entity([
266
                    'id' => 1,
267
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
268
                ]),
269
                new Entity([
270
                    'id' => 3,
271
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
272
                ]),
273
                new Entity([
274
                    'id' => 5,
275
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
276
                ]),
277
            ],
278
            [
279
                'hasPrevious' => null,
280
                'previousCursor' => null,
281
                'hasNext' => true,
282
                'nextCursor' => [
283
                    'Posts.id' => 2,
284
                    'Posts.modified' => new FrozenTime('2017-01-01 11:00:00'),
285
                ],
286
            ],
287
            '{
288
                "records": [
289
                    {
290
                        "id": 1,
291
                        "modified": "2017-01-01T10:00:00+00:00"
292
                    },
293
                    {
294
                        "id": 3,
295
                        "modified": "2017-01-01T10:00:00+00:00"
296
                    },
297
                    {
298
                        "id": 5,
299
                        "modified": "2017-01-01T10:00:00+00:00"
300
                    }
301
                ],
302
                "hasPrevious": null,
303
                "previousCursor": null,
304
                "hasNext": true,
305
                "nextCursor": {
306
                    "Posts.id": 2,
307
                    "Posts.modified": "2017-01-01T11:00:00+00:00"
308
                }
309
            }',
310
        ];
311
312
        yield 'ArrayIterator iteration' => [
313
            [
314
                new Entity([
315
                    'id' => 1,
316
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
317
                ]),
318
                new Entity([
319
                    'id' => 3,
320
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
321
                ]),
322
                new Entity([
323
                    'id' => 5,
324
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
325
                ]),
326
            ],
327
            new ArrayIterator([
328
                new Entity([
329
                    'id' => 1,
330
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
331
                ]),
332
                new Entity([
333
                    'id' => 3,
334
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
335
                ]),
336
                new Entity([
337
                    'id' => 5,
338
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
339
                ]),
340
            ]),
341
            [
342
                'hasPrevious' => null,
343
                'previousCursor' => null,
344
                'hasNext' => true,
345
                'nextCursor' => [
346
                    'Posts.id' => 2,
347
                    'Posts.modified' => new FrozenTime('2017-01-01 11:00:00'),
348
                ],
349
            ],
350
            '{
351
                "records": [
352
                    {
353
                        "id": 1,
354
                        "modified": "2017-01-01T10:00:00+00:00"
355
                    },
356
                    {
357
                        "id": 3,
358
                        "modified": "2017-01-01T10:00:00+00:00"
359
                    },
360
                    {
361
                        "id": 5,
362
                        "modified": "2017-01-01T10:00:00+00:00"
363
                    }
364
                ],
365
                "hasPrevious": null,
366
                "previousCursor": null,
367
                "hasNext": true,
368
                "nextCursor": {
369
                    "Posts.id": 2,
370
                    "Posts.modified": "2017-01-01T11:00:00+00:00"
371
                }
372
            }',
373
        ];
374
    }
375
376
    public function iteratorAggregateProvider(): Generator
377
    {
378
        /** @var IteratorAggregate&MockObject $iteratorAggregate */
379
        $iteratorAggregate = $this->getMockForAbstractClass(IteratorAggregate::class);
380
        $iteratorAggregate->method('getIterator')->willReturn(new ArrayIterator([
381
            new Entity([
382
                'id' => 1,
383
                'modified' => new FrozenTime('2017-01-01 10:00:00'),
384
            ]),
385
            new Entity([
386
                'id' => 3,
387
                'modified' => new FrozenTime('2017-01-01 10:00:00'),
388
            ]),
389
            new Entity([
390
                'id' => 5,
391
                'modified' => new FrozenTime('2017-01-01 10:00:00'),
392
            ]),
393
        ]));
394
395
        yield 'IteratorAggregate iteration' => [
396
            [
397
                new Entity([
398
                    'id' => 1,
399
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
400
                ]),
401
                new Entity([
402
                    'id' => 3,
403
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
404
                ]),
405
                new Entity([
406
                    'id' => 5,
407
                    'modified' => new FrozenTime('2017-01-01 10:00:00'),
408
                ]),
409
            ],
410
            $iteratorAggregate,
411
            [
412
                'hasPrevious' => null,
413
                'previousCursor' => null,
414
                'hasNext' => true,
415
                'nextCursor' => [
416
                    'Posts.id' => 2,
417
                    'Posts.modified' => new FrozenTime('2017-01-01 11:00:00'),
418
                ],
419
            ],
420
            '{
421
                "records": [
422
                    {
423
                        "id": 1,
424
                        "modified": "2017-01-01T10:00:00+00:00"
425
                    },
426
                    {
427
                        "id": 3,
428
                        "modified": "2017-01-01T10:00:00+00:00"
429
                    },
430
                    {
431
                        "id": 5,
432
                        "modified": "2017-01-01T10:00:00+00:00"
433
                    }
434
                ],
435
                "hasPrevious": null,
436
                "previousCursor": null,
437
                "hasNext": true,
438
                "nextCursor": {
439
                    "Posts.id": 2,
440
                    "Posts.modified": "2017-01-01T11:00:00+00:00"
441
                }
442
            }',
443
        ];
444
    }
445
}
446