Passed
Pull Request — main (#28)
by Anatoly
04:31
created

php$0 ➔ testDoctrineAnnotationReader()   A

Complexity

Conditions 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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

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

1634
        $hydrator->setAnnotationReader(/** @scrutinizer ignore-type */ new stdClass);
Loading history...
1635
    }
1636
1637
    public function testDoctrineAnnotationReader(): void
1638
    {
1639
        /** @var Hydrator $hydrator */
1640
        $hydrator = $this->createHydrator();
1641
        $hydrator->setAnnotationReader(new AnnotationReader());
1642
1643
        $this->assertInvalidValueExceptionCount(0);
1644
        $object = $hydrator->hydrate(ObjectWithAnnotatedAlias::class, ['non-normalized-value' => 'foo']);
1645
        $this->assertSame('foo', $object->value);
1646
    }
1647
1648
    public function testAnnotatedAlias(): void
1649
    {
1650
        /** @var Hydrator $hydrator */
1651
        $hydrator = $this->createHydrator();
1652
        $hydrator->useDefaultAnnotationReader();
0 ignored issues
show
Deprecated Code introduced by
The function Sunrise\Hydrator\Hydrato...faultAnnotationReader() has been deprecated: 3.1.0 Use the {@see setAnnotationReader()} method with {@see DoctrineAnnotationReader::default()}. ( Ignorable by Annotation )

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

1652
        /** @scrutinizer ignore-deprecated */ $hydrator->useDefaultAnnotationReader();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1653
1654
        $this->assertInvalidValueExceptionCount(0);
1655
        $object = $hydrator->hydrate(ObjectWithAnnotatedAlias::class, ['non-normalized-value' => 'foo']);
1656
        $this->assertSame('foo', $object->value);
1657
1658
        $this->assertInvalidValueExceptionCount(1);
1659
        $hydrator->hydrate(ObjectWithAnnotatedAlias::class, ['value' => 'foo']);
1660
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
1661
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
1662
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
1663
    }
1664
1665
    public function testAttributedAlias(): void
1666
    {
1667
        $this->phpRequired('8.0');
1668
1669
        /** @var Hydrator $hydrator */
1670
        $hydrator = $this->createHydrator();
1671
1672
        $this->assertInvalidValueExceptionCount(0);
1673
        $object = $hydrator->hydrate(ObjectWithAttributedAlias::class, ['non-normalized-value' => 'foo']);
1674
        $this->assertSame('foo', $object->value);
1675
1676
        $this->assertInvalidValueExceptionCount(1);
1677
        $hydrator->hydrate(ObjectWithAttributedAlias::class, ['value' => 'foo']);
1678
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
1679
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
1680
        $this->assertInvalidValueExceptionPropertyPath(0, 'value');
1681
    }
1682
1683
    public function testHydrateStore(): void
1684
    {
1685
        $this->phpRequired('8.1');
1686
1687
        $sold = Status::SOLD;
1688
1689
        $data = [];
1690
        $data['name'] = 'Some product';
1691
        $data['category']['name'] = 'Some category';
1692
        $data['tags'][]['name'] = 'foo';
1693
        $data['tags'][]['name'] = 'bar';
1694
        $data['status'] = $sold->value;
1695
        $data['createdAt'] = '2000-01-01 00:00:00';
1696
1697
        $this->assertInvalidValueExceptionCount(0);
1698
        $product = $this->createHydrator()->hydrate(Product::class, $data);
1699
        $this->assertSame('Some product', $product->name);
1700
        $this->assertSame('Some category', $product->category->name);
1701
        $this->assertCount(2, $product->tags);
1702
        $this->assertArrayHasKey(0, $product->tags);
1703
        $this->assertSame('foo', $product->tags[0]->name);
1704
        $this->assertArrayHasKey(1, $product->tags);
1705
        $this->assertSame('bar', $product->tags[1]->name);
1706
        $this->assertSame(Status::SOLD, $product->status);
1707
        $this->assertSame('2000-01-01 00:00:00', $product->createdAt->format('Y-m-d H:i:s'));
1708
1709
        unset($data['createdAt']);
1710
        $this->assertInvalidValueExceptionCount(0);
1711
        $product = $this->createHydrator()->hydrate(Product::class, $data);
1712
        $this->assertSame('2020-01-01 12:00:00', $product->createdAt->format('Y-m-d H:i:s'));
1713
    }
1714
1715
    public function testSymfonyViolations(): void
1716
    {
1717
        $violations = null;
1718
        try {
1719
            $this->createHydrator()->hydrate(ObjectWithString::class, []);
1720
        } catch (InvalidDataException $e) {
1721
            $violations = $e->getViolations();
1722
        }
1723
1724
        $this->assertNotNull($violations);
1725
        $this->assertCount(1, $violations);
1726
        $this->assertTrue($violations->has(0));
1727
        $this->assertSame(ErrorCode::VALUE_SHOULD_BE_PROVIDED, $violations->get(0)->getCode());
1728
        $this->assertSame('This value should be provided.', $violations->get(0)->getMessage());
1729
        $this->assertSame('value', $violations->get(0)->getPropertyPath());
1730
    }
1731
1732
    public function emptyDataProvider(): array
1733
    {
1734
        return [
1735
            [[]],
1736
        ];
1737
    }
1738
1739
    public function strictNullDataProvider(): array
1740
    {
1741
        return [
1742
            [['value' => null], null],
1743
        ];
1744
    }
1745
1746
    public function nonStrictNullDataProvider(): array
1747
    {
1748
        return [
1749
            [['value' => ''], null],
1750
            [['value' => ' '], null],
1751
        ];
1752
    }
1753
1754
    public function strictBooleanDataProvider(): array
1755
    {
1756
        return [
1757
            [['value' => true], true],
1758
            [['value' => false], false],
1759
        ];
1760
    }
1761
1762
    public function nonStrictBooleanDataProvider(): array
1763
    {
1764
        return [
1765
            [['value' => '1'], true],
1766
            [['value' => '0'], false],
1767
            [['value' => 'true'], true],
1768
            [['value' => 'false'], false],
1769
            [['value' => 'yes'], true],
1770
            [['value' => 'no'], false],
1771
            [['value' => 'on'], true],
1772
            [['value' => 'off'], false],
1773
        ];
1774
    }
1775
1776
    public function notBooleanDataProvider(): array
1777
    {
1778
        return [
1779
            [['value' => 0]],
1780
            [['value' => 1]],
1781
            [['value' => 42]],
1782
            [['value' => 3.14159]],
1783
            [['value' => 'foo']],
1784
            [['value' => []]],
1785
        ];
1786
    }
1787
1788
    public function strictIntegerDataProvider(): array
1789
    {
1790
        return [
1791
            [['value' => -1], -1],
1792
            [['value' => 0], 0],
1793
            [['value' => 1], 1],
1794
        ];
1795
    }
1796
1797
    public function nonStrictIntegerDataProvider(): array
1798
    {
1799
        return [
1800
            [['value' => '-1'], -1],
1801
            [['value' => '0'], 0],
1802
            [['value' => '+1'], 1],
1803
        ];
1804
    }
1805
1806
    public function notIntegerDataProvider(): array
1807
    {
1808
        return [
1809
            [['value' => true]],
1810
            [['value' => false]],
1811
            [['value' => 3.14159]],
1812
            [['value' => 'foo']],
1813
            [['value' => []]],
1814
        ];
1815
    }
1816
1817
    public function strictNumberDataProvider(): array
1818
    {
1819
        return [
1820
            [['value' => -1], -1.],
1821
            [['value' => 0], 0.],
1822
            [['value' => 1], 1.],
1823
            [['value' => -1.], -1.],
1824
            [['value' => 0.], 0.],
1825
            [['value' => 1.], 1.],
1826
            [['value' => -.1], -.1],
1827
            [['value' => .0], .0],
1828
            [['value' => .1], .1],
1829
        ];
1830
    }
1831
1832
    public function nonStrictNumberDataProvider(): array
1833
    {
1834
        return [
1835
            [['value' => '-1'], -1.],
1836
            [['value' => '0'], 0.],
1837
            [['value' => '+1'], 1.],
1838
            [['value' => '-1.'], -1.],
1839
            [['value' => '0.'], 0.],
1840
            [['value' => '+1.'], 1.],
1841
            [['value' => '-.1'], -.1],
1842
            [['value' => '.0'], .0],
1843
            [['value' => '+.1'], .1],
1844
            [['value' => '-1.0'], -1.],
1845
            [['value' => '0.0'], 0.],
1846
            [['value' => '+1.0'], 1.],
1847
            [['value' => '1e-1'], .1],
1848
            [['value' => '1e1'], 10.],
1849
            [['value' => '1e+1'], 10.],
1850
            [['value' => '1.e-1'], .1],
1851
            [['value' => '1.e1'], 10.],
1852
            [['value' => '1.e+1'], 10.],
1853
            [['value' => '.1e-1'], .01],
1854
            [['value' => '.1e1'], 1.],
1855
            [['value' => '.1e+1'], 1.],
1856
            [['value' => '1.0e-1'], .1],
1857
            [['value' => '1.0e1'], 10.],
1858
            [['value' => '1.0e+1'], 10.],
1859
        ];
1860
    }
1861
1862
    public function notNumberDataProvider(): array
1863
    {
1864
        return [
1865
            [['value' => true]],
1866
            [['value' => false]],
1867
            [['value' => 'foo']],
1868
            [['value' => []]],
1869
        ];
1870
    }
1871
1872
    public function stringDataProvider(): array
1873
    {
1874
        return [
1875
            [['value' => 'foo'], 'foo'],
1876
1877
            // Should not be cast to a null
1878
            [['value' => ''], ''],
1879
            [['value' => ' '], ' '],
1880
1881
            // Should not be cast to a boolean type
1882
            [['value' => '1'], '1'],
1883
            [['value' => '0'], '0'],
1884
            [['value' => 'true'], 'true'],
1885
            [['value' => 'false'], 'false'],
1886
            [['value' => 'yes'], 'yes'],
1887
            [['value' => 'no'], 'no'],
1888
            [['value' => 'on'], 'on'],
1889
            [['value' => 'off'], 'off'],
1890
1891
            // Should not be cast to a number
1892
            [['value' => '42'], '42'],
1893
            [['value' => '3.14159'], '3.14159'],
1894
        ];
1895
    }
1896
1897
    public function notStringDataProvider(): array
1898
    {
1899
        return [
1900
            [['value' => true]],
1901
            [['value' => false]],
1902
            [['value' => 42]],
1903
            [['value' => 3.14159]],
1904
            [['value' => []]],
1905
        ];
1906
    }
1907
1908
    public function arrayDataProvider(): array
1909
    {
1910
        return [
1911
            [['value' => ['foo']], ['foo']]
1912
        ];
1913
    }
1914
1915
    public function notArrayDataProvider(): array
1916
    {
1917
        return [
1918
            [['value' => true]],
1919
            [['value' => false]],
1920
            [['value' => 42]],
1921
            [['value' => 3.14159]],
1922
            [['value' => 'foo']],
1923
        ];
1924
    }
1925
1926
    public function timestampDataProvider(): array
1927
    {
1928
        return [
1929
            [['value' => '1970-01-01 00:00:00'], '1970-01-01 00:00:00', 'Y-m-d H:i:s'],
1930
        ];
1931
    }
1932
1933
    public function invalidTimestampDataProvider(): array
1934
    {
1935
        return [
1936
            [['value' => 'Tue, 06 Jun 23 16:50:23']],
1937
        ];
1938
    }
1939
1940
    public function notTimestampDataProvider(): array
1941
    {
1942
        return [
1943
            [['value' => true]],
1944
            [['value' => false]],
1945
            [['value' => 42]],
1946
            [['value' => 3.14159]],
1947
            [['value' => []]],
1948
        ];
1949
    }
1950
1951
    public function strictUnixTimeStampDataProvider(): array
1952
    {
1953
        return [
1954
            [['value' => -1], '1969-12-31 23:59:59', 'Y-m-d H:i:s'],
1955
            [['value' => 0], '1970-01-01 00:00:00', 'Y-m-d H:i:s'],
1956
            [['value' => 1], '1970-01-01 00:00:01', 'Y-m-d H:i:s'],
1957
        ];
1958
    }
1959
1960
    public function nonStrictUnixTimeStampDataProvider(): array
1961
    {
1962
        return [
1963
            [['value' => '-1'], '1969-12-31 23:59:59', 'Y-m-d H:i:s'],
1964
            [['value' => '0'], '1970-01-01 00:00:00', 'Y-m-d H:i:s'],
1965
            [['value' => '1'], '1970-01-01 00:00:01', 'Y-m-d H:i:s'],
1966
        ];
1967
    }
1968
1969
    public function notUnixTimeStampDataProvider(): array
1970
    {
1971
        return [
1972
            [['value' => true]],
1973
            [['value' => false]],
1974
            [['value' => 'foo']],
1975
            [['value' => []]],
1976
        ];
1977
    }
1978
1979
    public function timezoneDataProvider(): array
1980
    {
1981
        return [
1982
            [['value' => 'Europe/Belgrade'], 'Europe/Belgrade'],
1983
        ];
1984
    }
1985
1986
    public function invalidTimezoneDataProvider(): array
1987
    {
1988
        return [
1989
            [['value' => 'Haafingar/Solitude']],
1990
        ];
1991
    }
1992
1993
    public function uidDataProvider(): array
1994
    {
1995
        return [
1996
            [['value' => '207ddb61-c300-4368-9f26-33d0a99eac00'], '207ddb61-c300-4368-9f26-33d0a99eac00'],
1997
        ];
1998
    }
1999
2000
    public function invalidUidDataProvider(): array
2001
    {
2002
        return [
2003
            [['value' => '207ddb61-c300-4368-9f26-33d0a99eac0']],
2004
            [['value' => '207ddb61-c300-4368-9f26-33d0a99eac0x']],
2005
            [['value' => '207ddb61-c300-4368-9f26-33d0a99eac000']],
2006
        ];
2007
    }
2008
2009
    public function strictIntegerEnumerationDataProvider(): array
2010
    {
2011
        if (PHP_VERSION_ID < 80100) {
2012
            return [[[], null]];
2013
        }
2014
2015
        $foo = IntegerEnum::FOO;
2016
        $bar = IntegerEnum::BAR;
2017
        $baz = IntegerEnum::BAZ;
2018
2019
        return [
2020
            [['value' => $foo->value], $foo],
2021
            [['value' => $bar->value], $bar],
2022
            [['value' => $baz->value], $baz],
2023
        ];
2024
    }
2025
2026
    public function nonStrictIntegerEnumerationDataProvider(): array
2027
    {
2028
        if (PHP_VERSION_ID < 80100) {
2029
            return [[[], null]];
2030
        }
2031
2032
        $foo = IntegerEnum::FOO;
2033
        $bar = IntegerEnum::BAR;
2034
        $baz = IntegerEnum::BAZ;
2035
2036
        return [
2037
            [['value' => (string) $foo->value], $foo],
2038
            [['value' => (string) $bar->value], $bar],
2039
            [['value' => (string) $baz->value], $baz],
2040
        ];
2041
    }
2042
2043
    public function stringEnumerationDataProvider(): array
2044
    {
2045
        if (PHP_VERSION_ID < 80100) {
2046
            return [[[], null]];
2047
        }
2048
2049
        $foo = StringEnum::FOO;
2050
        $bar = StringEnum::BAR;
2051
        $baz = StringEnum::BAZ;
2052
2053
        return [
2054
            [['value' => $foo->value], $foo],
2055
            [['value' => $bar->value], $bar],
2056
            [['value' => $baz->value], $baz],
2057
        ];
2058
    }
2059
2060
    public function testIssue25(): void
2061
    {
2062
        $this->assertInvalidValueExceptionCount(1);
2063
        $this->assertInvalidValueExceptionMessage(0, 'This value should be provided.');
2064
        $this->assertInvalidValueExceptionErrorCode(0, ErrorCode::VALUE_SHOULD_BE_PROVIDED);
2065
        $this->assertInvalidValueExceptionPropertyPath(0, 'foo');
2066
        $this->createHydrator()->hydrate(Issue25::class, []);
2067
    }
2068
2069
    private function createHydrator(): HydratorInterface
2070
    {
2071
        $hydrator = new Hydrator();
2072
        if (PHP_VERSION_ID < 80000) {
2073
            $hydrator->useDefaultAnnotationReader();
0 ignored issues
show
Deprecated Code introduced by
The function Sunrise\Hydrator\Hydrato...faultAnnotationReader() has been deprecated: 3.1.0 Use the {@see setAnnotationReader()} method with {@see DoctrineAnnotationReader::default()}. ( Ignorable by Annotation )

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

2073
            /** @scrutinizer ignore-deprecated */ $hydrator->useDefaultAnnotationReader();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
2074
        }
2075
2076
        return $hydrator;
2077
    }
2078
2079
    private function phpRequired(string $version): void
2080
    {
2081
        if (version_compare(PHP_VERSION, $version, '<')) {
2082
            $this->markTestSkipped(sprintf('PHP %s is required.', $version));
2083
        }
2084
    }
2085
2086
    private function assertInvalidValueExceptionCount(int $expectedCount): void
2087
    {
2088
        $this->invalidValueExceptionCount = $expectedCount;
2089
    }
2090
2091
    private function assertInvalidValueExceptionMessage(int $exceptionIndex, string $expectedMessage): void
2092
    {
2093
        $this->invalidValueExceptionMessage[] = [$exceptionIndex, $expectedMessage];
2094
    }
2095
2096
    private function assertInvalidValueExceptionPropertyPath(int $exceptionIndex, string $expectedPropertyPath): void
2097
    {
2098
        $this->invalidValueExceptionPropertyPath[] = [$exceptionIndex, $expectedPropertyPath];
2099
    }
2100
2101
    private function assertInvalidValueExceptionErrorCode(int $exceptionIndex, string $expectedErrorCode): void
2102
    {
2103
        $this->invalidValueExceptionErrorCode[] = [$exceptionIndex, $expectedErrorCode];
2104
    }
2105
2106
    protected function runTest(): void
2107
    {
2108
        $invalidDataExceptionHandled = false;
2109
2110
        try {
2111
            parent::runTest();
2112
        } catch (InvalidDataException $invalidDataException) {
2113
            $invalidDataExceptionMessages = [];
2114
            foreach ($invalidDataException->getExceptions() as $invalidValueException) {
2115
                $invalidDataExceptionMessages[] = sprintf(
2116
                    '[%s] %s',
2117
                    $invalidValueException->getPropertyPath(),
2118
                    $invalidValueException->getMessage(),
2119
                );
2120
            }
2121
2122
            if (isset($this->invalidValueExceptionCount)) {
2123
                $invalidDataExceptionHandled = true;
2124
                $this->assertCount(
2125
                    $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

2125
                    /** @scrutinizer ignore-type */ $this->invalidValueExceptionCount,
Loading history...
2126
                    $invalidDataException->getExceptions(),
2127
                    \join(\PHP_EOL, $invalidDataExceptionMessages),
2128
                );
2129
            }
2130
2131
            foreach ($this->invalidValueExceptionMessage as [$index, $invalidValueExceptionMessage]) {
2132
                $invalidDataExceptionHandled = true;
2133
                $this->assertArrayHasKey($index, $invalidDataException->getExceptions());
2134
                $this->assertSame(
2135
                    $invalidValueExceptionMessage,
2136
                    $invalidDataException->getExceptions()[$index]->getMessage(),
2137
                );
2138
            }
2139
2140
            foreach ($this->invalidValueExceptionPropertyPath as [$index, $invalidValueExceptionPropertyPath]) {
2141
                $invalidDataExceptionHandled = true;
2142
                $this->assertArrayHasKey($index, $invalidDataException->getExceptions());
2143
                $this->assertSame(
2144
                    $invalidValueExceptionPropertyPath,
2145
                    $invalidDataException->getExceptions()[$index]->getPropertyPath(),
2146
                );
2147
            }
2148
2149
            foreach ($this->invalidValueExceptionErrorCode as [$index, $invalidValueExceptionErrorCode]) {
2150
                $invalidDataExceptionHandled = true;
2151
                $this->assertArrayHasKey($index, $invalidDataException->getExceptions());
2152
                $this->assertSame(
2153
                    $invalidValueExceptionErrorCode,
2154
                    $invalidDataException->getExceptions()[$index]->getErrorCode(),
2155
                );
2156
            }
2157
2158
            if (!$invalidDataExceptionHandled) {
2159
                throw $invalidDataException;
2160
            }
2161
        } finally {
2162
            $this->invalidValueExceptionCount = null;
2163
            $this->invalidValueExceptionMessage = [];
2164
            $this->invalidValueExceptionPropertyPath = [];
2165
            $this->invalidValueExceptionErrorCode = [];
2166
2167
            if ($invalidDataExceptionHandled) {
2168
                $this->assertTrue(true);
2169
            }
2170
        }
2171
    }
2172
}
2173