Test Failed
Pull Request — main (#24)
by Anatoly
26:04 queued 21:36
created

HydratorTest.php$0 ➔ stringDataProvider()   A

Complexity

Conditions 1

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 22
rs 9.568
cc 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Sunrise\Hydrator\Tests;
6
7
use Doctrine\Common\Annotations\Reader;
8
use PHPUnit\Framework\TestCase;
9
use Sunrise\Hydrator\Annotation\Format;
10
use Sunrise\Hydrator\Dictionary\ErrorCode;
11
use Sunrise\Hydrator\Exception\InvalidDataException;
12
use Sunrise\Hydrator\Exception\UninitializableObjectException;
13
use Sunrise\Hydrator\Exception\UnsupportedPropertyTypeException;
14
use Sunrise\Hydrator\Exception\UntypedPropertyException;
15
use Sunrise\Hydrator\Hydrator;
16
use Sunrise\Hydrator\HydratorInterface;
17
use Sunrise\Hydrator\Tests\Fixtures\IntegerEnum;
18
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithAnnotatedAlias;
19
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithArray;
20
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithAttributedAlias;
21
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithBoolean;
22
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithInteger;
23
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithIntegerEnum;
24
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNullableArray;
25
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNullableBoolean;
26
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNullableInteger;
27
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNullableIntegerEnum;
28
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNullableNumber;
29
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNullableRelationship;
30
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNullableRelationships;
31
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNullableString;
32
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNullableStringEnum;
33
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNullableTimestamp;
34
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNullableUnixTimeStamp;
35
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithNumber;
36
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithOptionalArray;
37
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithOptionalBoolean;
38
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithOptionalInteger;
39
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithOptionalIntegerEnum;
40
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithOptionalNumber;
41
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithOptionalRelationship;
42
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithOptionalRelationships;
43
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithOptionalString;
44
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithOptionalStringEnum;
45
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithOptionalTimestamp;
46
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithOptionalUnixTimeStamp;
47
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithRelationship;
48
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithRelationshipWithNullableString;
49
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithRelationshipWithOptionalString;
50
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithRelationshipWithString;
51
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithRelationships;
52
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithRelationshipsWithLimit;
53
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithRelationshipsWithUnstantiableObject;
54
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithStaticalProperty;
55
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithString;
56
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithStringEnum;
57
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithTimestamp;
58
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithUnformattedTimestampProperty;
59
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithUnixTimeStamp;
60
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithUnstantiableRelationship;
61
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithUnsupportedProperty;
62
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithUnsupportedPropertyNotation;
63
use Sunrise\Hydrator\Tests\Fixtures\ObjectWithUntypedProperty;
64
use Sunrise\Hydrator\Tests\Fixtures\Store\Product;
65
use Sunrise\Hydrator\Tests\Fixtures\Store\Status;
66
use Sunrise\Hydrator\Tests\Fixtures\StringEnum;
67
use Sunrise\Hydrator\Tests\Fixtures\UnstantiableObject;
68
69
use function sprintf;
70
use function version_compare;
71
72
use const PHP_VERSION;
73
use const PHP_VERSION_ID;
74
75
class HydratorTest extends TestCase
76
{
77
    private ?int $invalidValueExceptionCount = null;
78
    private array $invalidValueExceptionMessage = [];
79
    private array $invalidValueExceptionPropertyPath = [];
80
    private array $invalidValueExceptionErrorCode = [];
81
82
    /**
83
     * @group boolean
84
     * @dataProvider strictBooleanDataProvider
85
     * @dataProvider nonStrictBooleanDataProvider
86
     */
87
    public function testHydrateBooleanProperty(array $data, bool $expected): void
88
    {
89
        $this->assertInvalidValueExceptionCount(0);
90
        $object = $this->createHydrator()->hydrate(ObjectWithBoolean::class, $data);
91
        $this->assertSame($expected, $object->value);
92
    }
93
94
    /**
95
     * @group boolean
96
     * @dataProvider strictBooleanDataProvider
97
     * @dataProvider nonStrictBooleanDataProvider
98
     * @dataProvider strictNullDataProvider
99
     * @dataProvider nonStrictNullDataProvider
100
     */
101
    public function testHydrateNullableBooleanProperty(array $data, ?bool $expected): void
102
    {
103
        $this->assertInvalidValueExceptionCount(0);
104
        $object = $this->createHydrator()->hydrate(ObjectWithNullableBoolean::class, $data);
105
        $this->assertSame($expected, $object->value);
106
    }
107
108
    /**
109
     * @group boolean
110
     * @dataProvider strictBooleanDataProvider
111
     * @dataProvider nonStrictBooleanDataProvider
112
     * @dataProvider emptyDataProvider
113
     */
114
    public function testHydrateOptionalBooleanProperty(array $data, bool $expected = true): void
115
    {
116
        $this->assertInvalidValueExceptionCount(0);
117
        $object = $this->createHydrator()->hydrate(ObjectWithOptionalBoolean::class, $data);
118
        $this->assertSame($expected, $object->value);
119
    }
120
121
    /**
122
     * @group boolean
123
     * @dataProvider strictNullDataProvider
124
     * @dataProvider nonStrictNullDataProvider
125
     */
126
    public function testHydrateNonNullableBooleanPropertyWithNull(array $data): void
127
    {
128
        $this->assertInvalidValueExceptionCount(1);
129
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
130
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
131
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
132
        $this->createHydrator()->hydrate(ObjectWithBoolean::class, $data);
133
    }
134
135
    /**
136
     * @group boolean
137
     * @dataProvider notBooleanDataProvider
138
     */
139
    public function testHydrateBooleanPropertyWithNonBooleanValue(array $data): void
140
    {
141
        $this->assertInvalidValueExceptionCount(1);
142
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type boolean.');
143
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_BOOLEAN);
144
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
145
        $this->createHydrator()->hydrate(ObjectWithBoolean::class, $data);
146
    }
147
148
    /**
149
     * @group boolean
150
     */
151
    public function testHydrateRequiredBooleanPropertyWithoutValue(): void
152
    {
153
        $this->assertInvalidValueExceptionCount(1);
154
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
155
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
156
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
157
        $this->createHydrator()->hydrate(ObjectWithBoolean::class, []);
158
    }
159
160
    /**
161
     * @group integer
162
     * @dataProvider strictIntegerDataProvider
163
     * @dataProvider nonStrictIntegerDataProvider
164
     */
165
    public function testHydrateIntegerProperty(array $data, int $expected): void
166
    {
167
        $this->assertInvalidValueExceptionCount(0);
168
        $object = $this->createHydrator()->hydrate(ObjectWithInteger::class, $data);
169
        $this->assertSame($expected, $object->value);
170
    }
171
172
    /**
173
     * @group integer
174
     * @dataProvider strictIntegerDataProvider
175
     * @dataProvider nonStrictIntegerDataProvider
176
     * @dataProvider strictNullDataProvider
177
     * @dataProvider nonStrictNullDataProvider
178
     */
179
    public function testHydrateNullableIntegerProperty(array $data, ?int $expected): void
180
    {
181
        $this->assertInvalidValueExceptionCount(0);
182
        $object = $this->createHydrator()->hydrate(ObjectWithNullableInteger::class, $data);
183
        $this->assertSame($expected, $object->value);
184
    }
185
186
    /**
187
     * @group integer
188
     * @dataProvider strictIntegerDataProvider
189
     * @dataProvider nonStrictIntegerDataProvider
190
     * @dataProvider emptyDataProvider
191
     */
192
    public function testHydrateOptionalIntegerProperty(array $data, int $expected = 42): void
193
    {
194
        $this->assertInvalidValueExceptionCount(0);
195
        $object = $this->createHydrator()->hydrate(ObjectWithOptionalInteger::class, $data);
196
        $this->assertSame($expected, $object->value);
197
    }
198
199
    /**
200
     * @group integer
201
     * @dataProvider strictNullDataProvider
202
     * @dataProvider nonStrictNullDataProvider
203
     */
204
    public function testHydrateNonNullableIntegerPropertyWithNull(array $data): void
205
    {
206
        $this->assertInvalidValueExceptionCount(1);
207
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
208
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
209
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
210
        $this->createHydrator()->hydrate(ObjectWithInteger::class, $data);
211
    }
212
213
    /**
214
     * @group integer
215
     * @dataProvider notIntegerDataProvider
216
     */
217
    public function testHydrateIntegerPropertyWithNotInteger(array $data): void
218
    {
219
        $this->assertInvalidValueExceptionCount(1);
220
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type integer.');
221
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_INTEGER);
222
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
223
        $this->createHydrator()->hydrate(ObjectWithInteger::class, $data);
224
    }
225
226
    /**
227
     * @group integer
228
     */
229
    public function testHydrateRequiredIntegerPropertyWithoutValue(): void
230
    {
231
        $this->assertInvalidValueExceptionCount(1);
232
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
233
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
234
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
235
        $this->createHydrator()->hydrate(ObjectWithInteger::class, []);
236
    }
237
238
    /**
239
     * @group number
240
     * @dataProvider strictNumberDataProvider
241
     * @dataProvider nonStrictNumberDataProvider
242
     */
243
    public function testHydrateNumericProperty(array $data, float $expected): void
244
    {
245
        $this->assertInvalidValueExceptionCount(0);
246
        $object = $this->createHydrator()->hydrate(ObjectWithNumber::class, $data);
247
        $this->assertSame($expected, $object->value);
248
    }
249
250
    /**
251
     * @group number
252
     * @dataProvider strictNumberDataProvider
253
     * @dataProvider nonStrictNumberDataProvider
254
     * @dataProvider strictNullDataProvider
255
     * @dataProvider nonStrictNullDataProvider
256
     */
257
    public function testHydrateNullableNumericProperty(array $data, ?float $expected): void
258
    {
259
        $this->assertInvalidValueExceptionCount(0);
260
        $object = $this->createHydrator()->hydrate(ObjectWithNullableNumber::class, $data);
261
        $this->assertSame($expected, $object->value);
262
    }
263
264
    /**
265
     * @group number
266
     * @dataProvider strictNumberDataProvider
267
     * @dataProvider nonStrictNumberDataProvider
268
     * @dataProvider emptyDataProvider
269
     */
270
    public function testHydrateOptionalNumericProperty(array $data, float $expected = 3.14159): void
271
    {
272
        $this->assertInvalidValueExceptionCount(0);
273
        $object = $this->createHydrator()->hydrate(ObjectWithOptionalNumber::class, $data);
274
        $this->assertSame($expected, $object->value);
275
    }
276
277
    /**
278
     * @group number
279
     * @dataProvider strictNullDataProvider
280
     * @dataProvider nonStrictNullDataProvider
281
     */
282
    public function testHydrateNonNullableNumericPropertyWithNull(array $data): void
283
    {
284
        $this->assertInvalidValueExceptionCount(1);
285
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
286
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
287
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
288
        $this->createHydrator()->hydrate(ObjectWithNumber::class, $data);
289
    }
290
291
    /**
292
     * @group number
293
     * @dataProvider notNumberDataProvider
294
     */
295
    public function testHydrateNumericPropertyWithNotNumber(array $data): void
296
    {
297
        $this->assertInvalidValueExceptionCount(1);
298
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type number.');
299
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_NUMBER);
300
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
301
        $this->createHydrator()->hydrate(ObjectWithNumber::class, $data);
302
    }
303
304
    /**
305
     * @group number
306
     */
307
    public function testHydrateRequiredNumericPropertyWithoutValue(): void
308
    {
309
        $this->assertInvalidValueExceptionCount(1);
310
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
311
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
312
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
313
        $this->createHydrator()->hydrate(ObjectWithNumber::class, []);
314
    }
315
316
    /**
317
     * @group string
318
     * @dataProvider stringDataProvider
319
     */
320
    public function testHydrateStringProperty(array $data, string $expected): void
321
    {
322
        $this->assertInvalidValueExceptionCount(0);
323
        $object = $this->createHydrator()->hydrate(ObjectWithString::class, $data);
324
        $this->assertSame($expected, $object->value);
325
    }
326
327
    /**
328
     * @group string
329
     * @dataProvider stringDataProvider
330
     * @dataProvider strictNullDataProvider
331
     */
332
    public function testHydrateNullableStringProperty(array $data, ?string $expected): void
333
    {
334
        $this->assertInvalidValueExceptionCount(0);
335
        $object = $this->createHydrator()->hydrate(ObjectWithNullableString::class, $data);
336
        $this->assertSame($expected, $object->value);
337
    }
338
339
    /**
340
     * @group string
341
     * @dataProvider stringDataProvider
342
     * @dataProvider emptyDataProvider
343
     */
344
    public function testHydrateOptionalStringProperty(array $data, string $expected = 'default'): void
345
    {
346
        $this->assertInvalidValueExceptionCount(0);
347
        $object = $this->createHydrator()->hydrate(ObjectWithOptionalString::class, $data);
348
        $this->assertSame($expected, $object->value);
349
    }
350
351
    /**
352
     * @group string
353
     * @dataProvider strictNullDataProvider
354
     */
355
    public function testHydrateNonNullableStringPropertyWithNull(array $data): void
356
    {
357
        $this->assertInvalidValueExceptionCount(1);
358
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
359
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
360
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
361
        $this->createHydrator()->hydrate(ObjectWithString::class, $data);
362
    }
363
364
    /**
365
     * @group string
366
     * @dataProvider notStringDataProvider
367
     */
368
    public function testHydrateStringPropertyWithNotString(array $data): void
369
    {
370
        $this->assertInvalidValueExceptionCount(1);
371
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type string.');
372
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_STRING);
373
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
374
        $this->createHydrator()->hydrate(ObjectWithString::class, $data);
375
    }
376
377
    /**
378
     * @group string
379
     */
380
    public function testHydrateRequiredStringPropertyWithoutValue(): void
381
    {
382
        $this->assertInvalidValueExceptionCount(1);
383
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
384
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
385
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
386
        $this->createHydrator()->hydrate(ObjectWithString::class, []);
387
    }
388
389
    /**
390
     * @group array
391
     * @dataProvider arrayDataProvider
392
     */
393
    public function testHydrateArrayProperty(array $data, array $expected): void
394
    {
395
        $this->assertInvalidValueExceptionCount(0);
396
        $object = $this->createHydrator()->hydrate(ObjectWithArray::class, $data);
397
        $this->assertSame($expected, $object->value);
398
    }
399
400
    /**
401
     * @group array
402
     * @dataProvider arrayDataProvider
403
     * @dataProvider strictNullDataProvider
404
     */
405
    public function testHydrateNullableArrayProperty(array $data, ?array $expected): void
406
    {
407
        $this->assertInvalidValueExceptionCount(0);
408
        $object = $this->createHydrator()->hydrate(ObjectWithNullableArray::class, $data);
409
        $this->assertSame($expected, $object->value);
410
    }
411
412
    /**
413
     * @group array
414
     * @dataProvider arrayDataProvider
415
     * @dataProvider emptyDataProvider
416
     */
417
    public function testHydrateOptionalArrayProperty(array $data, array $expected = []): void
418
    {
419
        $this->assertInvalidValueExceptionCount(0);
420
        $object = $this->createHydrator()->hydrate(ObjectWithOptionalArray::class, $data);
421
        $this->assertSame($expected, $object->value);
422
    }
423
424
    /**
425
     * @group array
426
     * @dataProvider strictNullDataProvider
427
     */
428
    public function testHydrateNonNullableArrayPropertyWithNull(array $data): void
429
    {
430
        $this->assertInvalidValueExceptionCount(1);
431
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
432
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
433
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
434
        $this->createHydrator()->hydrate(ObjectWithArray::class, $data);
435
    }
436
437
    /**
438
     * @group array
439
     * @dataProvider notArrayDataProvider
440
     */
441
    public function testHydrateArrayPropertyWithNotArray(array $data): void
442
    {
443
        $this->assertInvalidValueExceptionCount(1);
444
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type array.');
445
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_ARRAY);
446
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
447
        $this->createHydrator()->hydrate(ObjectWithArray::class, $data);
448
    }
449
450
    /**
451
     * @group array
452
     */
453
    public function testHydrateRequiredArrayPropertyWithoutValue(): void
454
    {
455
        $this->assertInvalidValueExceptionCount(1);
456
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
457
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
458
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
459
        $this->createHydrator()->hydrate(ObjectWithArray::class, []);
460
    }
461
462
    /**
463
     * @group datetimeTimestamp
464
     * @dataProvider timestampDataProvider
465
     */
466
    public function testHydrateTimestampProperty(array $data, string $expected, string $format): void
467
    {
468
        $this->assertInvalidValueExceptionCount(0);
469
        $object = $this->createHydrator()->hydrate(ObjectWithTimestamp::class, $data);
470
        $this->assertSame($expected, $object->value->format($format));
471
    }
472
473
    /**
474
     * @group datetimeTimestamp
475
     * @dataProvider timestampDataProvider
476
     * @dataProvider strictNullDataProvider
477
     * @dataProvider nonStrictNullDataProvider
478
     */
479
    // phpcs:ignore Generic.Files.LineLength
480
    public function testHydrateNullableTimestampProperty(array $data, ?string $expected = null, ?string $format = null): void
481
    {
482
        $this->assertInvalidValueExceptionCount(0);
483
        $object = $this->createHydrator()->hydrate(ObjectWithNullableTimestamp::class, $data);
484
        $this->assertSame($expected, isset($object->value, $format) ? $object->value->format($format) : null);
485
    }
486
487
    /**
488
     * @group datetimeTimestamp
489
     * @dataProvider timestampDataProvider
490
     * @dataProvider emptyDataProvider
491
     */
492
    // phpcs:ignore Generic.Files.LineLength
493
    public function testHydrateOptionalTimestampProperty(array $data, ?string $expected = null, ?string $format = null): void
494
    {
495
        $this->assertInvalidValueExceptionCount(0);
496
        $object = $this->createHydrator()->hydrate(ObjectWithOptionalTimestamp::class, $data);
497
        $this->assertSame($expected, isset($object->value, $format) ? $object->value->format($format) : null);
498
    }
499
500
    /**
501
     * @group datetimeTimestamp
502
     * @dataProvider strictNullDataProvider
503
     * @dataProvider nonStrictNullDataProvider
504
     */
505
    public function testHydrateNonNullableTimestampPropertyWithNull(array $data): void
506
    {
507
        $this->assertInvalidValueExceptionCount(1);
508
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
509
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
510
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
511
        $this->createHydrator()->hydrate(ObjectWithTimestamp::class, $data);
512
    }
513
514
    /**
515
     * @group datetimeTimestamp
516
     * @dataProvider notStringDataProvider
517
     */
518
    public function testHydrateTimestampPropertyWithNotString(array $data): void
519
    {
520
        $this->assertInvalidValueExceptionCount(1);
521
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type string.');
522
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_STRING);
523
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
524
        $this->createHydrator()->hydrate(ObjectWithTimestamp::class, $data);
525
    }
526
527
    /**
528
     * @group datetimeTimestamp
529
     * @dataProvider invalidTimestampDataProvider
530
     */
531
    public function testHydrateTimestampPropertyWithInvalidTimestamp(array $data): void
532
    {
533
        $this->assertInvalidValueExceptionCount(1);
534
        $message = sprintf('This value is not a valid timestamp, expected format: %s.', ObjectWithTimestamp::FORMAT);
535
        $this->assertInvalidValueExceptionMessage(0, $message);
536
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::INVALID_TIMESTAMP);
537
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
538
        $this->createHydrator()->hydrate(ObjectWithTimestamp::class, $data);
539
    }
540
541
    /**
542
     * @group datetimeTimestamp
543
     */
544
    public function testHydrateRequiredTimestampPropertyWithoutValue(): void
545
    {
546
        $this->assertInvalidValueExceptionCount(1);
547
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
548
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
549
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
550
        $this->createHydrator()->hydrate(ObjectWithTimestamp::class, []);
551
    }
552
553
    /**
554
     * @group datetimeTimestamp
555
     * @dataProvider timestampDataProvider
556
     */
557
    public function testHydrateUnformattedTimestampProperty(array $data): void
558
    {
559
        $this->expectException(UnsupportedPropertyTypeException::class);
560
        $this->expectExceptionMessage(sprintf(
561
            'The property %1$s.%2$s must contain the attribute %3$s, ' .
562
            'for example: #[\%3$s(\DateTimeInterface::DATE_RFC3339)].',
563
            ObjectWithUnformattedTimestampProperty::class,
564
            'value',
565
            Format::class,
566
        ));
567
568
        $this->createHydrator()->hydrate(ObjectWithUnformattedTimestampProperty::class, $data);
569
    }
570
571
    /**
572
     * @group unixTimestamp
573
     * @dataProvider strictUnixTimeStampDataProvider
574
     * @dataProvider nonStrictUnixTimeStampDataProvider
575
     */
576
    public function testHydrateUnixTimeStampProperty(array $data, string $expected, string $format): void
577
    {
578
        $this->assertInvalidValueExceptionCount(0);
579
        $object = $this->createHydrator()->hydrate(ObjectWithUnixTimeStamp::class, $data);
580
        $this->assertSame($expected, $object->value->format($format));
581
    }
582
583
    /**
584
     * @group unixTimestamp
585
     * @dataProvider strictUnixTimeStampDataProvider
586
     * @dataProvider nonStrictUnixTimeStampDataProvider
587
     * @dataProvider strictNullDataProvider
588
     * @dataProvider nonStrictNullDataProvider
589
     */
590
    // phpcs:ignore Generic.Files.LineLength
591
    public function testHydrateNullableUnixTimeStampProperty(array $data, ?string $expected = null, ?string $format = null): void
592
    {
593
        $this->assertInvalidValueExceptionCount(0);
594
        $object = $this->createHydrator()->hydrate(ObjectWithNullableUnixTimeStamp::class, $data);
595
        $this->assertSame($expected, isset($object->value, $format) ? $object->value->format($format) : null);
596
    }
597
598
    /**
599
     * @group unixTimestamp
600
     * @dataProvider strictUnixTimeStampDataProvider
601
     * @dataProvider nonStrictUnixTimeStampDataProvider
602
     * @dataProvider emptyDataProvider
603
     */
604
    // phpcs:ignore Generic.Files.LineLength
605
    public function testHydrateOptionalUnixTimeStampProperty(array $data, ?string $expected = null, ?string $format = null): void
606
    {
607
        $this->assertInvalidValueExceptionCount(0);
608
        $object = $this->createHydrator()->hydrate(ObjectWithOptionalUnixTimeStamp::class, $data);
609
        $this->assertSame($expected, isset($object->value, $format) ? $object->value->format($format) : null);
610
    }
611
612
    /**
613
     * @group unixTimestamp
614
     * @dataProvider strictNullDataProvider
615
     * @dataProvider nonStrictNullDataProvider
616
     */
617
    public function testHydrateNonNullableUnixTimeStampPropertyWithNull(array $data): void
618
    {
619
        $this->assertInvalidValueExceptionCount(1);
620
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
621
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
622
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
623
        $this->createHydrator()->hydrate(ObjectWithUnixTimeStamp::class, $data);
624
    }
625
626
    /**
627
     * @group unixTimestamp
628
     * @dataProvider notIntegerDataProvider
629
     */
630
    public function testHydrateUnixTimeStampPropertyWithNotInteger(array $data): void
631
    {
632
        $this->assertInvalidValueExceptionCount(1);
633
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type integer.');
634
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_INTEGER);
635
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
636
        $this->createHydrator()->hydrate(ObjectWithUnixTimeStamp::class, $data);
637
    }
638
639
    /**
640
     * @group unixTimestamp
641
     */
642
    public function testHydrateRequiredUnixTimeStampPropertyWithoutValue(): void
643
    {
644
        $this->assertInvalidValueExceptionCount(1);
645
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
646
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
647
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
648
        $this->createHydrator()->hydrate(ObjectWithUnixTimeStamp::class, []);
649
    }
650
651
    /**
652
     * @group integerEnumeration
653
     * @dataProvider strictIntegerEnumerationDataProvider
654
     * @dataProvider nonStrictIntegerEnumerationDataProvider
655
     * @param IntegerEnum $expected
656
     */
657
    public function testHydrateIntegerEnumerationProperty(array $data, $expected): void
658
    {
659
        $this->phpRequired('8.1');
660
        $this->assertInvalidValueExceptionCount(0);
661
        $object = $this->createHydrator()->hydrate(ObjectWithIntegerEnum::class, $data);
662
        $this->assertSame($expected, $object->value);
663
    }
664
665
    /**
666
     * @group integerEnumeration
667
     * @dataProvider strictIntegerEnumerationDataProvider
668
     * @dataProvider nonStrictIntegerEnumerationDataProvider
669
     * @dataProvider strictNullDataProvider
670
     * @dataProvider nonStrictNullDataProvider
671
     * @param IntegerEnum|null $expected
672
     */
673
    public function testHydrateNullableIntegerEnumerationProperty(array $data, $expected): void
674
    {
675
        $this->phpRequired('8.1');
676
        $this->assertInvalidValueExceptionCount(0);
677
        $object = $this->createHydrator()->hydrate(ObjectWithNullableIntegerEnum::class, $data);
678
        $this->assertSame($expected, $object->value);
679
    }
680
681
    /**
682
     * @group integerEnumeration
683
     * @dataProvider strictIntegerEnumerationDataProvider
684
     * @dataProvider nonStrictIntegerEnumerationDataProvider
685
     * @dataProvider emptyDataProvider
686
     * @param IntegerEnum|null $expected
687
     */
688
    // phpcs:ignore Generic.Files.LineLength
689
    public function testHydrateOptionalIntegerEnumerationProperty(array $data, $expected = null): void
690
    {
691
        $this->phpRequired('8.1');
692
        $this->assertInvalidValueExceptionCount(0);
693
        $object = $this->createHydrator()->hydrate(ObjectWithOptionalIntegerEnum::class, $data);
694
        $this->assertSame($expected ?? IntegerEnum::FOO, $object->value);
695
    }
696
697
    /**
698
     * @group integerEnumeration
699
     * @dataProvider strictNullDataProvider
700
     * @dataProvider nonStrictNullDataProvider
701
     */
702
    public function testHydrateNonNullableIntegerEnumerationPropertyWithNull(array $data): void
703
    {
704
        $this->phpRequired('8.1');
705
        $this->assertInvalidValueExceptionCount(1);
706
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
707
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
708
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
709
        $this->createHydrator()->hydrate(ObjectWithIntegerEnum::class, $data);
710
    }
711
712
    /**
713
     * @group integerEnumeration
714
     * @dataProvider notIntegerDataProvider
715
     */
716
    public function testHydrateIntegerEnumerationPropertyWithNotInteger(array $data): void
717
    {
718
        $this->phpRequired('8.1');
719
        $this->assertInvalidValueExceptionCount(1);
720
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type integer.');
721
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_INTEGER);
722
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
723
        $this->createHydrator()->hydrate(ObjectWithIntegerEnum::class, $data);
724
    }
725
726
    /**
727
     * @group integerEnumeration
728
     */
729
    public function testHydrateRequiredIntegerEnumerationPropertyWithoutValue(): void
730
    {
731
        $this->assertInvalidValueExceptionCount(1);
732
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
733
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
734
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
735
        $this->createHydrator()->hydrate(ObjectWithIntegerEnum::class, []);
736
    }
737
738
    /**
739
     * @group stringEnumeration
740
     */
741
    public function testHydrateIntegerEnumerationPropertyWithInvalidChoice(): void
742
    {
743
        $this->phpRequired('8.1');
744
        $this->assertInvalidValueExceptionCount(1);
745
        // phpcs:ignore Generic.Files.LineLength
746
        $this->assertInvalidValueExceptionMessage(0, 'This value is not a valid choice, expected choices: 1, 2, 3.');
747
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::INVALID_CHOICE);
748
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
749
        $this->createHydrator()->hydrate(ObjectWithIntegerEnum::class, ['value' => 42]);
750
    }
751
752
    /**
753
     * @group stringEnumeration
754
     * @dataProvider stringEnumerationDataProvider
755
     * @param StringEnum $expected
756
     */
757
    public function testHydrateStringEnumerationProperty(array $data, $expected): void
758
    {
759
        $this->phpRequired('8.1');
760
        $this->assertInvalidValueExceptionCount(0);
761
        $object = $this->createHydrator()->hydrate(ObjectWithStringEnum::class, $data);
762
        $this->assertSame($expected, $object->value);
763
    }
764
765
    /**
766
     * @group stringEnumeration
767
     * @dataProvider stringEnumerationDataProvider
768
     * @dataProvider strictNullDataProvider
769
     * @dataProvider nonStrictNullDataProvider
770
     * @param StringEnum|null $expected
771
     */
772
    public function testHydrateNullableStringEnumerationProperty(array $data, $expected): void
773
    {
774
        $this->phpRequired('8.1');
775
        $this->assertInvalidValueExceptionCount(0);
776
        $object = $this->createHydrator()->hydrate(ObjectWithNullableStringEnum::class, $data);
777
        $this->assertSame($expected, $object->value);
778
    }
779
780
    /**
781
     * @group stringEnumeration
782
     * @dataProvider stringEnumerationDataProvider
783
     * @dataProvider emptyDataProvider
784
     * @param StringEnum|null $expected
785
     */
786
    // phpcs:ignore Generic.Files.LineLength
787
    public function testHydrateOptionalStringEnumerationProperty(array $data, $expected = null): void
788
    {
789
        $this->phpRequired('8.1');
790
        $this->assertInvalidValueExceptionCount(0);
791
        $object = $this->createHydrator()->hydrate(ObjectWithOptionalStringEnum::class, $data);
792
        $this->assertSame($expected ?? StringEnum::FOO, $object->value);
793
    }
794
795
    /**
796
     * @group stringEnumeration
797
     * @dataProvider strictNullDataProvider
798
     * @dataProvider nonStrictNullDataProvider
799
     */
800
    public function testHydrateNonNullableStringEnumerationPropertyWithNull(array $data): void
801
    {
802
        $this->phpRequired('8.1');
803
        $this->assertInvalidValueExceptionCount(1);
804
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
805
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
806
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
807
        $this->createHydrator()->hydrate(ObjectWithStringEnum::class, $data);
808
    }
809
810
    /**
811
     * @group stringEnumeration
812
     * @dataProvider notStringDataProvider
813
     */
814
    public function testHydrateStringEnumerationPropertyWithNotInteger(array $data): void
815
    {
816
        $this->phpRequired('8.1');
817
        $this->assertInvalidValueExceptionCount(1);
818
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type string.');
819
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_STRING);
820
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
821
        $this->createHydrator()->hydrate(ObjectWithStringEnum::class, $data);
822
    }
823
824
    /**
825
     * @group stringEnumeration
826
     */
827
    public function testHydrateStringEnumerationPropertyWithInvalidChoice(): void
828
    {
829
        $this->phpRequired('8.1');
830
        $this->assertInvalidValueExceptionCount(1);
831
        // phpcs:ignore Generic.Files.LineLength
832
        $this->assertInvalidValueExceptionMessage(0, 'This value is not a valid choice, expected choices: foo, bar, baz.');
833
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::INVALID_CHOICE);
834
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
835
        $this->createHydrator()->hydrate(ObjectWithStringEnum::class, ['value' => 'unknown']);
836
    }
837
838
    /**
839
     * @group stringEnumeration
840
     */
841
    public function testHydrateRequiredStringEnumerationPropertyWithoutValue(): void
842
    {
843
        $this->assertInvalidValueExceptionCount(1);
844
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
845
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
846
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
847
        $this->createHydrator()->hydrate(ObjectWithStringEnum::class, []);
848
    }
849
850
    /**
851
     * @group relationship
852
     * @dataProvider stringDataProvider
853
     */
854
    public function testHydrateRelationshipProperty(array $data, string $expected): void
855
    {
856
        $this->assertInvalidValueExceptionCount(0);
857
        $object = $this->createHydrator()->hydrate(ObjectWithRelationship::class, ['value' => $data]);
858
        $this->assertSame($expected, $object->value->value);
859
    }
860
861
    /**
862
     * @group relationship
863
     * @dataProvider strictNullDataProvider
864
     */
865
    public function testHydrateNullableRelationshipProperty(array $data): void
866
    {
867
        $this->assertInvalidValueExceptionCount(0);
868
        $object = $this->createHydrator()->hydrate(ObjectWithNullableRelationship::class, $data);
869
        $this->assertNull($object->value);
870
    }
871
872
    /**
873
     * @group relationship
874
     * @dataProvider emptyDataProvider
875
     */
876
    public function testHydrateOptionalRelationshipProperty(array $data): void
877
    {
878
        $this->assertInvalidValueExceptionCount(0);
879
        $object = $this->createHydrator()->hydrate(ObjectWithOptionalRelationship::class, $data);
880
        $this->assertNull($object->value);
881
    }
882
883
    /**
884
     * @group relationship
885
     * @dataProvider strictNullDataProvider
886
     */
887
    public function testHydrateNonNullableRelationshipPropertyWithNull(array $data): void
888
    {
889
        $this->assertInvalidValueExceptionCount(1);
890
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
891
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
892
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
893
        $this->createHydrator()->hydrate(ObjectWithRelationship::class, $data);
894
    }
895
896
    /**
897
     * @group relationship
898
     * @dataProvider notArrayDataProvider
899
     */
900
    public function testHydrateRelationshipPropertyWithNotArray(array $data): void
901
    {
902
        $this->assertInvalidValueExceptionCount(1);
903
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type array.');
904
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_ARRAY);
905
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
906
        $this->createHydrator()->hydrate(ObjectWithRelationship::class, $data);
907
    }
908
909
    /**
910
     * @group relationship
911
     */
912
    public function testHydrateRequiredRelationshipPropertyWithoutValue(): void
913
    {
914
        $this->assertInvalidValueExceptionCount(1);
915
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
916
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
917
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
918
        $this->createHydrator()->hydrate(ObjectWithRelationship::class, []);
919
    }
920
921
    /**
922
     * @group relationship
923
     * @dataProvider stringDataProvider
924
     */
925
    public function testHydrateRelationshipWithStringProperty(array $data, string $expected): void
926
    {
927
        $this->assertInvalidValueExceptionCount(0);
928
        $object = $this->createHydrator()->hydrate(ObjectWithRelationshipWithString::class, ['value' => $data]);
929
        $this->assertSame($expected, $object->value->value);
930
    }
931
932
    /**
933
     * @group relationship
934
     * @dataProvider stringDataProvider
935
     * @dataProvider strictNullDataProvider
936
     */
937
    public function testHydrateRelationshipWithNullableStringProperty(array $data, ?string $expected): void
938
    {
939
        $this->assertInvalidValueExceptionCount(0);
940
        $object = $this->createHydrator()->hydrate(ObjectWithRelationshipWithNullableString::class, ['value' => $data]);
941
        $this->assertSame($expected, $object->value->value);
942
    }
943
944
    /**
945
     * @group relationship
946
     * @dataProvider stringDataProvider
947
     * @dataProvider emptyDataProvider
948
     */
949
    public function testHydrateRelationshipWithOptionalStringProperty(array $data, string $expected = 'default'): void
950
    {
951
        $this->assertInvalidValueExceptionCount(0);
952
        $object = $this->createHydrator()->hydrate(ObjectWithRelationshipWithOptionalString::class, ['value' => $data]);
953
        $this->assertSame($expected, $object->value->value);
954
    }
955
956
    /**
957
     * @group relationship
958
     * @dataProvider strictNullDataProvider
959
     */
960
    public function testHydrateRelationshipWithNonNullablePropertyWithNull(array $data): void
961
    {
962
        $this->assertInvalidValueExceptionCount(1);
963
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
964
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
965
        $this->assertInvalidValueExceptionPropertyPath(0, 'value.value');
966
        $this->createHydrator()->hydrate(ObjectWithRelationshipWithString::class, ['value' => $data]);
967
    }
968
969
    /**
970
     * @group relationship
971
     * @dataProvider notStringDataProvider
972
     */
973
    public function testHydrateRelationshipWithStringPropertyWithNotString(array $data): void
974
    {
975
        $this->assertInvalidValueExceptionCount(1);
976
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type string.');
977
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_STRING);
978
        $this->assertInvalidValueExceptionPropertyPath(0, 'value.value');
979
        $this->createHydrator()->hydrate(ObjectWithRelationshipWithString::class, ['value' => $data]);
980
    }
981
982
    /**
983
     * @group relationship
984
     */
985
    public function testHydrateRelationshipWithRequiredStringPropertyWithoutValue(): void
986
    {
987
        $this->assertInvalidValueExceptionCount(1);
988
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
989
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
990
        $this->assertInvalidValueExceptionPropertyPath(0, 'value.value');
991
        $this->createHydrator()->hydrate(ObjectWithRelationshipWithString::class, ['value' => []]);
992
    }
993
994
    /**
995
     * @group relationship
996
     */
997
    public function testHydrateUnstantiableRelationshipProperty(): void
998
    {
999
        $this->expectException(UnsupportedPropertyTypeException::class);
1000
        $this->expectExceptionMessage(sprintf(
1001
            'The property %s.%s refers to a non-instantiable class %s.',
1002
            ObjectWithUnstantiableRelationship::class,
1003
            'value',
1004
            UnstantiableObject::class,
1005
        ));
1006
1007
        $this->createHydrator()->hydrate(ObjectWithUnstantiableRelationship::class, ['value' => []]);
1008
    }
1009
1010
    /**
1011
     * @group relationships
1012
     */
1013
    public function testHydrateRelationshipsProperty(): void
1014
    {
1015
        $data = ['value' => [['value' => ['value' => 'foo']], ['value' => ['value' => 'bar']]]];
1016
1017
        $this->assertInvalidValueExceptionCount(0);
1018
        $object = $this->createHydrator()->hydrate(ObjectWithRelationships::class, $data);
1019
        $this->assertCount(2, $object->value);
1020
        $this->assertArrayHasKey(0, $object->value);
1021
        $this->assertSame($data['value'][0]['value']['value'], $object->value[0]->value->value);
1022
        $this->assertArrayHasKey(1, $object->value);
1023
        $this->assertSame($data['value'][1]['value']['value'], $object->value[1]->value->value);
1024
    }
1025
1026
    /**
1027
     * @group relationships
1028
     * @dataProvider strictNullDataProvider
1029
     */
1030
    public function testHydrateNullableRelationshipsProperty(array $data): void
1031
    {
1032
        $this->assertInvalidValueExceptionCount(0);
1033
        $object = $this->createHydrator()->hydrate(ObjectWithNullableRelationships::class, $data);
1034
        $this->assertNull($object->value);
1035
    }
1036
1037
    /**
1038
     * @group relationships
1039
     * @dataProvider emptyDataProvider
1040
     */
1041
    public function testHydrateOptionalRelationshipsProperty(array $data): void
1042
    {
1043
        $this->assertInvalidValueExceptionCount(0);
1044
        $object = $this->createHydrator()->hydrate(ObjectWithOptionalRelationships::class, $data);
1045
        $this->assertSame([], $object->value);
1046
    }
1047
1048
    /**
1049
     * @group relationships
1050
     * @dataProvider strictNullDataProvider
1051
     */
1052
    public function testHydrateNonNullableRelationshipsPropertyWithNull(array $data): void
1053
    {
1054
        $this->assertInvalidValueExceptionCount(1);
1055
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
1056
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
1057
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
1058
        $this->createHydrator()->hydrate(ObjectWithRelationships::class, $data);
1059
    }
1060
1061
    /**
1062
     * @group relationships
1063
     * @dataProvider notArrayDataProvider
1064
     */
1065
    public function testHydrateRelationshipsPropertyWithNotArray(array $data): void
1066
    {
1067
        $this->assertInvalidValueExceptionCount(1);
1068
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type array.');
1069
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_ARRAY);
1070
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
1071
        $this->createHydrator()->hydrate(ObjectWithRelationships::class, $data);
1072
    }
1073
1074
    /**
1075
     * @group relationships
1076
     */
1077
    public function testHydrateRequiredRelationshipsPropertyWithoutValue(): void
1078
    {
1079
        $this->assertInvalidValueExceptionCount(1);
1080
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
1081
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
1082
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
1083
        $this->createHydrator()->hydrate(ObjectWithRelationships::class, []);
1084
    }
1085
1086
    /**
1087
     * @group relationships
1088
     * @dataProvider strictNullDataProvider
1089
     */
1090
    public function testHydrateRelationshipsPropertyWithNullsForNonNullableValues(array $data): void
1091
    {
1092
        $this->assertInvalidValueExceptionCount(1);
1093
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
1094
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
1095
        $this->assertInvalidValueExceptionPropertyPath(0, 'value.0.value.value');
1096
        $this->createHydrator()->hydrate(ObjectWithRelationships::class, ['value' => [['value' => $data]]]);
1097
    }
1098
1099
    /**
1100
     * @group relationships
1101
     * @dataProvider notStringDataProvider
1102
     */
1103
    public function testHydrateRelationshipsPropertyWithNotStringForStringValue(array $data): void
1104
    {
1105
        $this->assertInvalidValueExceptionCount(1);
1106
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type string.');
1107
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_STRING);
1108
        $this->assertInvalidValueExceptionPropertyPath(0, 'value.0.value.value');
1109
        $this->createHydrator()->hydrate(ObjectWithRelationships::class, ['value' => [['value' => $data]]]);
1110
    }
1111
1112
    /**
1113
     * @group relationships
1114
     */
1115
    public function testHydrateRelationshipsPropertyWithoutValueForRequiredValue(): void
1116
    {
1117
        $this->assertInvalidValueExceptionCount(1);
1118
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
1119
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
1120
        $this->assertInvalidValueExceptionPropertyPath(0, 'value.0.value.value');
1121
        $this->createHydrator()->hydrate(ObjectWithRelationships::class, ['value' => [['value' => []]]]);
1122
    }
1123
1124
    /**
1125
     * @group relationships
1126
     */
1127
    public function testHydrateRelationshipsPropertyWithNotArrayForRelation(): void
1128
    {
1129
        $this->assertInvalidValueExceptionCount(1);
1130
        $this->assertInvalidValueExceptionMessage(0, 'This value should be of type array.');
1131
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_ARRAY);
1132
        $this->assertInvalidValueExceptionPropertyPath(0, 'value.0');
1133
        $this->createHydrator()->hydrate(ObjectWithRelationships::class, ['value' => [null]]);
1134
    }
1135
1136
    /**
1137
     * @group relationships
1138
     */
1139
    public function testSeveralErrorsWhenHydratingRelationshipsProperty(): void
1140
    {
1141
        $this->assertInvalidValueExceptionCount(3);
1142
        $this->assertInvalidValueExceptionMessage(0, 'This value should not be empty.');
1143
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_NOT_BE_EMPTY);
1144
        $this->assertInvalidValueExceptionPropertyPath(0, 'value.0.value.value');
1145
        $this->assertInvalidValueExceptionMessage(1, 'This value should be of type string.');
1146
        $this->assertInvalidValueExceptionErrorCode(1, ErrorCode::VALUE_SHOULD_BE_STRING);
1147
        $this->assertInvalidValueExceptionPropertyPath(1, 'value.1.value.value');
1148
        $this->assertInvalidValueExceptionMessage(2, 'This value should be provided.');
1149
        $this->assertInvalidValueExceptionErrorCode(2, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
1150
        $this->assertInvalidValueExceptionPropertyPath(2, 'value.2.value.value');
1151
        $this->createHydrator()->hydrate(ObjectWithRelationships::class, ['value' => [
1152
            ['value' => ['value' => null]],
1153
            ['value' => ['value' => []]],
1154
            ['value' => []]
1155
        ]]);
1156
    }
1157
1158
    /**
1159
     * @group relationships
1160
     */
1161
    public function testHydrateLimitedRelationshipsProperty(): void
1162
    {
1163
        $this->assertInvalidValueExceptionCount(1);
1164
        $this->assertInvalidValueExceptionMessage(0, 'This element is redundant, limit: 1.');
1165
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::REDUNDANT_ELEMENT);
1166
        $this->assertInvalidValueExceptionPropertyPath(0, 'value.1');
1167
        $this->createHydrator()->hydrate(ObjectWithRelationshipsWithLimit::class, ['value' => [
1168
            ['value' => 'foo'],
1169
            ['value' => 'bar'],
1170
        ]]);
1171
    }
1172
1173
    /**
1174
     * @group relationships
1175
     */
1176
    public function testHydrateRelationshipsPropertyWithUnstantiableObject(): void
1177
    {
1178
        $this->expectException(UnsupportedPropertyTypeException::class);
1179
        $this->expectExceptionMessage(sprintf(
1180
            'The property %s.%s refers to a non-instantiable class %s.',
1181
            ObjectWithRelationshipsWithUnstantiableObject::class,
1182
            'value',
1183
            UnstantiableObject::class,
1184
        ));
1185
1186
        $this->createHydrator()->hydrate(
1187
            ObjectWithRelationshipsWithUnstantiableObject::class,
1188
            ['value' => [['value' => []]]],
1189
        );
1190
    }
1191
1192
    /**
1193
     * @group json
1194
     */
1195
    public function testHydrateObjectWithJson(): void
1196
    {
1197
        $this->assertInvalidValueExceptionCount(0);
1198
        $object = $this->createHydrator()->hydrateWithJson(ObjectWithString::class, '{"value": "foo"}');
1199
        $this->assertSame('foo', $object->value);
1200
    }
1201
1202
    /**
1203
     * @group json
1204
     */
1205
    public function testHydrateObjectWithInvalidJson(): void
1206
    {
1207
        $this->expectException(InvalidDataException::class);
1208
        $this->expectExceptionMessage('Invalid JSON: Maximum stack depth exceeded');
1209
        $this->createHydrator()->hydrateWithJson(ObjectWithString::class, '[]', 0, 1);
1210
    }
1211
1212
    /**
1213
     * @group json
1214
     */
1215
    public function testHydrateObjectWithNonObjectableJson(): void
1216
    {
1217
        $this->expectException(InvalidDataException::class);
1218
        $this->expectExceptionMessage('JSON must be an object.');
1219
        $this->createHydrator()->hydrateWithJson(ObjectWithString::class, 'null');
1220
    }
1221
1222
    public function testInstantedObject(): void
1223
    {
1224
        $object = new class {
1225
            public string $value;
1226
        };
1227
1228
        $this->assertInvalidValueExceptionCount(0);
1229
        $this->createHydrator()->hydrate($object, ['value' => 'foo']);
1230
        $this->assertSame('foo', $object->value);
1231
    }
1232
1233
    public function testUnstantiableObject(): void
1234
    {
1235
        $this->expectException(UninitializableObjectException::class);
1236
        $this->expectExceptionMessage(sprintf(
1237
            'The class %s cannot be hydrated because it is an uninstantiable class.',
1238
            UnstantiableObject::class,
1239
        ));
1240
1241
        $this->createHydrator()->hydrate(UnstantiableObject::class, []);
1242
    }
1243
1244
    public function testStaticalProperty(): void
1245
    {
1246
        $this->assertInvalidValueExceptionCount(0);
1247
        $this->createHydrator()->hydrate(ObjectWithStaticalProperty::class, ['value' => 'foo']);
1248
        $this->assertNotSame('foo', ObjectWithStaticalProperty::$value);
1249
    }
1250
1251
    public function testUnsupportedPropertyType(): void
1252
    {
1253
        $this->expectException(UnsupportedPropertyTypeException::class);
1254
        $this->expectExceptionMessage(sprintf(
1255
            'The property %s.%s contains an unsupported type %s.',
1256
            ObjectWithUnsupportedProperty::class,
1257
            'value',
1258
            'iterable',
1259
        ));
1260
1261
        $this->createHydrator()->hydrate(ObjectWithUnsupportedProperty::class, ['value' => []]);
1262
    }
1263
1264
    public function testUnsupportedPropertyTypeNotation(): void
1265
    {
1266
        $this->phpRequired('8.0');
1267
1268
        $this->expectException(UnsupportedPropertyTypeException::class);
1269
        $this->expectExceptionMessage(sprintf(
1270
            'The property %s.%s contains an unsupported type %s.',
1271
            ObjectWithUnsupportedPropertyNotation::class,
1272
            'value',
1273
            'int|float',
1274
        ));
1275
1276
        $this->createHydrator()->hydrate(ObjectWithUnsupportedPropertyNotation::class, ['value' => []]);
1277
    }
1278
1279
    public function testUntypedProperty(): void
1280
    {
1281
        $this->expectException(UntypedPropertyException::class);
1282
        $this->expectExceptionMessage(sprintf(
1283
            'The property %s.%s is not typed.',
1284
            ObjectWithUntypedProperty::class,
1285
            'value',
1286
        ));
1287
1288
        $this->createHydrator()->hydrate(ObjectWithUntypedProperty::class, ['value' => []]);
1289
    }
1290
1291
    public function testAnnotatedAlias(): void
1292
    {
1293
        /** @var Hydrator $hydrator */
1294
        $hydrator = $this->createHydrator();
1295
        $hydrator->useDefaultAnnotationReader();
1296
1297
        $this->assertInvalidValueExceptionCount(0);
1298
        $object = $hydrator->hydrate(ObjectWithAnnotatedAlias::class, ['non-normalized-value' => 'foo']);
1299
        $this->assertSame('foo', $object->value);
1300
1301
        $this->assertInvalidValueExceptionCount(1);
1302
        $hydrator->hydrate(ObjectWithAnnotatedAlias::class, ['value' => 'foo']);
1303
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
1304
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
1305
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
1306
    }
1307
1308
    public function testAttributedAlias(): void
1309
    {
1310
        $this->phpRequired('8.0');
1311
1312
        /** @var Hydrator $hydrator */
1313
        $hydrator = $this->createHydrator();
1314
1315
        $this->assertInvalidValueExceptionCount(0);
1316
        $object = $hydrator->hydrate(ObjectWithAttributedAlias::class, ['non-normalized-value' => 'foo']);
1317
        $this->assertSame('foo', $object->value);
1318
1319
        $this->assertInvalidValueExceptionCount(1);
1320
        $hydrator->hydrate(ObjectWithAttributedAlias::class, ['value' => 'foo']);
1321
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
1322
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
1323
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
1324
    }
1325
1326
    public function testAnnotationReader(): void
1327
    {
1328
        /** @var Hydrator $hydrator */
1329
        $hydrator = $this->createHydrator();
1330
1331
        $hydrator->setAnnotationReader(null);
1332
        $this->assertNull($hydrator->getAnnotationReader());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $hydrator->getAnnotationReader() targeting Sunrise\Hydrator\Hydrator::getAnnotationReader() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1333
1334
        $reader = $this->createMock(Reader::class);
1335
        $hydrator->setAnnotationReader($reader);
1336
        $this->assertSame($reader, $hydrator->getAnnotationReader());
1337
1338
        $hydrator->setAnnotationReader(null);
1339
        $this->assertNull($hydrator->getAnnotationReader());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $hydrator->getAnnotationReader() targeting Sunrise\Hydrator\Hydrator::getAnnotationReader() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1340
    }
1341
1342
    public function testHydrateStore(): void
1343
    {
1344
        $this->phpRequired('8.1');
1345
1346
        $sold = Status::SOLD;
1347
1348
        $data = [];
1349
        $data['name'] = 'Some product';
1350
        $data['category']['name'] = 'Some category';
1351
        $data['tags'][]['name'] = 'foo';
1352
        $data['tags'][]['name'] = 'bar';
1353
        $data['status'] = $sold->value;
1354
        $data['createdAt'] = '2000-01-01 00:00:00';
1355
1356
        $this->assertInvalidValueExceptionCount(0);
1357
        $product = $this->createHydrator()->hydrate(Product::class, $data);
1358
        $this->assertSame('Some product', $product->name);
1359
        $this->assertSame('Some category', $product->category->name);
1360
        $this->assertCount(2, $product->tags);
1361
        $this->assertArrayHasKey(0, $product->tags);
1362
        $this->assertSame('foo', $product->tags[0]->name);
1363
        $this->assertArrayHasKey(1, $product->tags);
1364
        $this->assertSame('bar', $product->tags[1]->name);
1365
        $this->assertSame(Status::SOLD, $product->status);
1366
        $this->assertSame('2000-01-01 00:00:00', $product->createdAt->format('Y-m-d H:i:s'));
1367
1368
        unset($data['createdAt']);
1369
        $this->assertInvalidValueExceptionCount(0);
1370
        $product = $this->createHydrator()->hydrate(Product::class, $data);
1371
        $this->assertSame('2020-01-01 12:00:00', $product->createdAt->format('Y-m-d H:i:s'));
1372
    }
1373
1374
    public function testSymfonyViolations(): void
1375
    {
1376
        $violations = null;
1377
        try {
1378
            $this->createHydrator()->hydrate(ObjectWithString::class, []);
1379
        } catch (InvalidDataException $e) {
1380
            $violations = $e->getViolations();
1381
        }
1382
1383
        $this->assertNotNull($violations);
1384
        $this->assertCount(1, $violations);
1385
        $this->assertTrue($violations->has(0));
1386
        $this->assertSame(ErrorCode::VALUE_SHOULD_BE_PROVIDED, $violations->get(0)->getCode());
1387
        $this->assertSame('This value should be provided.', $violations->get(0)->getMessage());
1388
        $this->assertSame('value', $violations->get(0)->getPropertyPath());
1389
    }
1390
1391
    public function emptyDataProvider(): array
1392
    {
1393
        return [
1394
            [[]],
1395
        ];
1396
    }
1397
1398
    public function strictNullDataProvider(): array
1399
    {
1400
        return [
1401
            [['value' => null], null],
1402
        ];
1403
    }
1404
1405
    public function nonStrictNullDataProvider(): array
1406
    {
1407
        return [
1408
            [['value' => ''], null],
1409
            [['value' => ' '], null],
1410
        ];
1411
    }
1412
1413
    public function strictBooleanDataProvider(): array
1414
    {
1415
        return [
1416
            [['value' => true], true],
1417
            [['value' => false], false],
1418
        ];
1419
    }
1420
1421
    public function nonStrictBooleanDataProvider(): array
1422
    {
1423
        return [
1424
            [['value' => '1'], true],
1425
            [['value' => '0'], false],
1426
            [['value' => 'true'], true],
1427
            [['value' => 'false'], false],
1428
            [['value' => 'yes'], true],
1429
            [['value' => 'no'], false],
1430
            [['value' => 'on'], true],
1431
            [['value' => 'off'], false],
1432
        ];
1433
    }
1434
1435
    public function notBooleanDataProvider(): array
1436
    {
1437
        return [
1438
            [['value' => 0]],
1439
            [['value' => 1]],
1440
            [['value' => 42]],
1441
            [['value' => 3.14159]],
1442
            [['value' => 'foo']],
1443
            [['value' => []]],
1444
        ];
1445
    }
1446
1447
    public function strictIntegerDataProvider(): array
1448
    {
1449
        return [
1450
            [['value' => -1], -1],
1451
            [['value' => 0], 0],
1452
            [['value' => 1], 1],
1453
        ];
1454
    }
1455
1456
    public function nonStrictIntegerDataProvider(): array
1457
    {
1458
        return [
1459
            [['value' => '-1'], -1],
1460
            [['value' => '0'], 0],
1461
            [['value' => '+1'], 1],
1462
        ];
1463
    }
1464
1465
    public function notIntegerDataProvider(): array
1466
    {
1467
        return [
1468
            [['value' => true]],
1469
            [['value' => false]],
1470
            [['value' => 3.14159]],
1471
            [['value' => 'foo']],
1472
            [['value' => []]],
1473
        ];
1474
    }
1475
1476
    public function strictNumberDataProvider(): array
1477
    {
1478
        return [
1479
            [['value' => -1], -1.],
1480
            [['value' => 0], 0.],
1481
            [['value' => 1], 1.],
1482
            [['value' => -1.], -1.],
1483
            [['value' => 0.], 0.],
1484
            [['value' => 1.], 1.],
1485
            [['value' => -.1], -.1],
1486
            [['value' => .0], .0],
1487
            [['value' => .1], .1],
1488
        ];
1489
    }
1490
1491
    public function nonStrictNumberDataProvider(): array
1492
    {
1493
        return [
1494
            [['value' => '-1'], -1.],
1495
            [['value' => '0'], 0.],
1496
            [['value' => '+1'], 1.],
1497
            [['value' => '-1.'], -1.],
1498
            [['value' => '0.'], 0.],
1499
            [['value' => '+1.'], 1.],
1500
            [['value' => '-.1'], -.1],
1501
            [['value' => '.0'], .0],
1502
            [['value' => '+.1'], .1],
1503
            [['value' => '-1.0'], -1.],
1504
            [['value' => '0.0'], 0.],
1505
            [['value' => '+1.0'], 1.],
1506
            [['value' => '1e-1'], .1],
1507
            [['value' => '1e1'], 10.],
1508
            [['value' => '1e+1'], 10.],
1509
            [['value' => '1.e-1'], .1],
1510
            [['value' => '1.e1'], 10.],
1511
            [['value' => '1.e+1'], 10.],
1512
            [['value' => '.1e-1'], .01],
1513
            [['value' => '.1e1'], 1.],
1514
            [['value' => '.1e+1'], 1.],
1515
            [['value' => '1.0e-1'], .1],
1516
            [['value' => '1.0e1'], 10.],
1517
            [['value' => '1.0e+1'], 10.],
1518
        ];
1519
    }
1520
1521
    public function notNumberDataProvider(): array
1522
    {
1523
        return [
1524
            [['value' => true]],
1525
            [['value' => false]],
1526
            [['value' => 'foo']],
1527
            [['value' => []]],
1528
        ];
1529
    }
1530
1531
    public function stringDataProvider(): array
1532
    {
1533
        return [
1534
            [['value' => 'foo'], 'foo'],
1535
1536
            // Should not be cast to a null
1537
            [['value' => ''], ''],
1538
            [['value' => ' '], ' '],
1539
1540
            // Should not be cast to a boolean type
1541
            [['value' => '1'], '1'],
1542
            [['value' => '0'], '0'],
1543
            [['value' => 'true'], 'true'],
1544
            [['value' => 'false'], 'false'],
1545
            [['value' => 'yes'], 'yes'],
1546
            [['value' => 'no'], 'no'],
1547
            [['value' => 'on'], 'on'],
1548
            [['value' => 'off'], 'off'],
1549
1550
            // Should not be cast to a number
1551
            [['value' => '42'], '42'],
1552
            [['value' => '3.14159'], '3.14159'],
1553
        ];
1554
    }
1555
1556
    public function notStringDataProvider(): array
1557
    {
1558
        return [
1559
            [['value' => true]],
1560
            [['value' => false]],
1561
            [['value' => 42]],
1562
            [['value' => 3.14159]],
1563
            [['value' => []]],
1564
        ];
1565
    }
1566
1567
    public function arrayDataProvider(): array
1568
    {
1569
        return [
1570
            [['value' => ['foo']], ['foo']]
1571
        ];
1572
    }
1573
1574
    public function notArrayDataProvider(): array
1575
    {
1576
        return [
1577
            [['value' => true]],
1578
            [['value' => false]],
1579
            [['value' => 42]],
1580
            [['value' => 3.14159]],
1581
            [['value' => 'foo']],
1582
        ];
1583
    }
1584
1585
    public function timestampDataProvider(): array
1586
    {
1587
        return [
1588
            [['value' => '1970-01-01 00:00:00'], '1970-01-01 00:00:00', 'Y-m-d H:i:s'],
1589
        ];
1590
    }
1591
1592
    public function invalidTimestampDataProvider(): array
1593
    {
1594
        return [
1595
            [['value' => 'Tue, 06 Jun 23 16:50:23']],
1596
        ];
1597
    }
1598
1599
    public function notTimestampDataProvider(): array
1600
    {
1601
        return [
1602
            [['value' => true]],
1603
            [['value' => false]],
1604
            [['value' => 42]],
1605
            [['value' => 3.14159]],
1606
            [['value' => []]],
1607
        ];
1608
    }
1609
1610
    public function strictUnixTimeStampDataProvider(): array
1611
    {
1612
        return [
1613
            [['value' => -1], '1969-12-31 23:59:59', 'Y-m-d H:i:s'],
1614
            [['value' => 0], '1970-01-01 00:00:00', 'Y-m-d H:i:s'],
1615
            [['value' => 1], '1970-01-01 00:00:01', 'Y-m-d H:i:s'],
1616
        ];
1617
    }
1618
1619
    public function nonStrictUnixTimeStampDataProvider(): array
1620
    {
1621
        return [
1622
            [['value' => '-1'], '1969-12-31 23:59:59', 'Y-m-d H:i:s'],
1623
            [['value' => '0'], '1970-01-01 00:00:00', 'Y-m-d H:i:s'],
1624
            [['value' => '1'], '1970-01-01 00:00:01', 'Y-m-d H:i:s'],
1625
        ];
1626
    }
1627
1628
    public function notUnixTimeStampDataProvider(): array
1629
    {
1630
        return [
1631
            [['value' => true]],
1632
            [['value' => false]],
1633
            [['value' => 'foo']],
1634
            [['value' => []]],
1635
        ];
1636
    }
1637
1638
    public function strictIntegerEnumerationDataProvider(): array
1639
    {
1640
        if (PHP_VERSION_ID < 80000) {
1641
            return [[[], null]];
1642
        }
1643
1644
        $foo = IntegerEnum::FOO;
1645
        $bar = IntegerEnum::BAR;
1646
        $baz = IntegerEnum::BAZ;
1647
1648
        return [
1649
            [['value' => $foo->value], $foo],
1650
            [['value' => $bar->value], $bar],
1651
            [['value' => $baz->value], $baz],
1652
        ];
1653
    }
1654
1655
    public function nonStrictIntegerEnumerationDataProvider(): array
1656
    {
1657
        if (PHP_VERSION_ID < 80000) {
1658
            return [[[], null]];
1659
        }
1660
1661
        $foo = IntegerEnum::FOO;
1662
        $bar = IntegerEnum::BAR;
1663
        $baz = IntegerEnum::BAZ;
1664
1665
        return [
1666
            [['value' => (string) $foo->value], $foo],
1667
            [['value' => (string) $bar->value], $bar],
1668
            [['value' => (string) $baz->value], $baz],
1669
        ];
1670
    }
1671
1672
    public function stringEnumerationDataProvider(): array
1673
    {
1674
        if (PHP_VERSION_ID < 80000) {
1675
            return [[[], null]];
1676
        }
1677
1678
        $foo = StringEnum::FOO;
1679
        $bar = StringEnum::BAR;
1680
        $baz = StringEnum::BAZ;
1681
1682
        return [
1683
            [['value' => $foo->value], $foo],
1684
            [['value' => $bar->value], $bar],
1685
            [['value' => $baz->value], $baz],
1686
        ];
1687
    }
1688
1689
    private function createHydrator(): HydratorInterface
1690
    {
1691
        $hydrator = new Hydrator();
1692
        if (PHP_VERSION_ID < 80000) {
1693
            $hydrator->useDefaultAnnotationReader();
1694
        }
1695
1696
        return $hydrator;
1697
    }
1698
1699
    private function phpRequired(string $version): void
1700
    {
1701
        if (version_compare(PHP_VERSION, $version, '<')) {
1702
            $this->markTestSkipped(sprintf('PHP %s is required.', $version));
1703
        }
1704
    }
1705
1706
    private function assertInvalidValueExceptionCount(int $expectedCount): void
1707
    {
1708
        $this->invalidValueExceptionCount = $expectedCount;
1709
    }
1710
1711
    private function assertInvalidValueExceptionMessage(int $exceptionIndex, string $expectedMessage): void
1712
    {
1713
        $this->invalidValueExceptionMessage[] = [$exceptionIndex, $expectedMessage];
1714
    }
1715
1716
    private function assertInvalidValueExceptionPropertyPath(int $exceptionIndex, string $expectedPropertyPath): void
1717
    {
1718
        $this->invalidValueExceptionPropertyPath[] = [$exceptionIndex, $expectedPropertyPath];
1719
    }
1720
1721
    private function assertInvalidValueExceptionErrorCode(int $exceptionIndex, string $expectedErrorCode): void
1722
    {
1723
        $this->invalidValueExceptionErrorCode[] = [$exceptionIndex, $expectedErrorCode];
1724
    }
1725
1726
    protected function runTest(): void
1727
    {
1728
        $invalidDataExceptionHandled = false;
1729
1730
        try {
1731
            parent::runTest();
1732
        } catch (InvalidDataException $invalidDataException) {
1733
            $invalidDataExceptionMessages = [];
1734
            foreach ($invalidDataException->getExceptions() as $invalidValueException) {
1735
                $invalidDataExceptionMessages[] = sprintf(
1736
                    '[%s] %s',
1737
                    $invalidValueException->getPropertyPath(),
1738
                    $invalidValueException->getMessage(),
1739
                );
1740
            }
1741
1742
            if (isset($this->invalidValueExceptionCount)) {
1743
                $invalidDataExceptionHandled = true;
1744
                $this->assertCount(
1745
                    $this->invalidValueExceptionCount,
0 ignored issues
show
Bug introduced by
It seems like $this->invalidValueExceptionCount can also be of type null; however, parameter $expectedCount of PHPUnit\Framework\Assert::assertCount() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1745
                    /** @scrutinizer ignore-type */ $this->invalidValueExceptionCount,
Loading history...
1746
                    $invalidDataException->getExceptions(),
1747
                    \join(\PHP_EOL, $invalidDataExceptionMessages),
1748
                );
1749
            }
1750
1751
            foreach ($this->invalidValueExceptionMessage as [$index, $invalidValueExceptionMessage]) {
1752
                $invalidDataExceptionHandled = true;
1753
                $this->assertArrayHasKey($index, $invalidDataException->getExceptions());
1754
                $this->assertSame(
1755
                    $invalidValueExceptionMessage,
1756
                    $invalidDataException->getExceptions()[$index]->getMessage(),
1757
                );
1758
            }
1759
1760
            foreach ($this->invalidValueExceptionPropertyPath as [$index, $invalidValueExceptionPropertyPath]) {
1761
                $invalidDataExceptionHandled = true;
1762
                $this->assertArrayHasKey($index, $invalidDataException->getExceptions());
1763
                $this->assertSame(
1764
                    $invalidValueExceptionPropertyPath,
1765
                    $invalidDataException->getExceptions()[$index]->getPropertyPath(),
1766
                );
1767
            }
1768
1769
            foreach ($this->invalidValueExceptionErrorCode as [$index, $invalidValueExceptionErrorCode]) {
1770
                $invalidDataExceptionHandled = true;
1771
                $this->assertArrayHasKey($index, $invalidDataException->getExceptions());
1772
                $this->assertSame(
1773
                    $invalidValueExceptionErrorCode,
1774
                    $invalidDataException->getExceptions()[$index]->getErrorCode(),
1775
                );
1776
            }
1777
1778
            if (!$invalidDataExceptionHandled) {
1779
                throw $invalidDataException;
1780
            }
1781
        } finally {
1782
            $this->invalidValueExceptionCount = null;
1783
            $this->invalidValueExceptionMessage = [];
1784
            $this->invalidValueExceptionPropertyPath = [];
1785
            $this->invalidValueExceptionErrorCode = [];
1786
1787
            if ($invalidDataExceptionHandled) {
1788
                $this->assertTrue(true);
1789
            }
1790
        }
1791
    }
1792
}
1793