Test Failed
Pull Request — main (#20)
by Anatoly
31:11 queued 02:30
created

testHydrateCustomEnumContainedProperyWithUnknownValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 8
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Sunrise\Hydrator\Tests;
6
7
use PHPUnit\Framework\TestCase;
8
use Sunrise\Hydrator\Exception;
9
use Sunrise\Hydrator\Hydrator;
10
use Sunrise\Hydrator\HydratorInterface;
11
use InvalidArgumentException;
12
13
class HydratorTest extends TestCase
14
{
15
    public function testContracts() : void
16
    {
17
        $hydrator = new Hydrator();
18
19
        $this->assertInstanceOf(HydratorInterface::class, $hydrator);
20
    }
21
22
    public function testInvalidObject() : void
23
    {
24
        $this->expectException(InvalidArgumentException::class);
25
        $this->expectExceptionMessage('The ' . Hydrator::class . '::hydrate() method ' .
26
                                      'expects an object or name of an existing class.');
27
28
        (new Hydrator)->hydrate('Undefined', []);
29
    }
30
31
    public function testUninitializableObject() : void
32
    {
33
        $this->expectException(InvalidArgumentException::class);
34
        $this->expectExceptionMessage('The ' . Fixtures\UninitializableObject::class . ' object ' .
35
                                      'cannot be hydrated because its constructor has required parameters.');
36
37
        (new Hydrator)->hydrate(Fixtures\UninitializableObject::class, []);
38
    }
39
40
    public function testInvalidData() : void
41
    {
42
        $this->expectException(InvalidArgumentException::class);
43
        $this->expectExceptionMessage('The ' . Hydrator::class . '::hydrate(data) parameter ' .
44
                                      'expects an associative array or object.');
45
46
        (new Hydrator)->hydrate(Fixtures\ObjectWithString::class, null);
47
    }
48
49
    public function testInvalidJson() : void
50
    {
51
        $this->expectException(InvalidArgumentException::class);
52
        $this->expectExceptionMessage('Unable to decode JSON: Syntax error');
53
54
        (new Hydrator)->hydrateWithJson(Fixtures\ObjectWithString::class, '!');
55
    }
56
57
    public function testIgnoreStaticalProperty() : void
58
    {
59
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithStaticalProperty::class, ['value' => 'foo']);
60
61
        $this->assertNotSame('foo', $object::$value);
62
    }
63
64
    public function testUntypedProperty() : void
65
    {
66
        $this->expectException(Exception\UntypedPropertyException::class);
67
        $this->expectExceptionMessage('The ObjectWithUntypedProperty.value property ' .
68
                                      'is not typed.');
69
70
        (new Hydrator)->hydrate(Fixtures\ObjectWithUntypedProperty::class, []);
71
    }
72
73
    public function testUnionPropertyType() : void
74
    {
75
        if (\PHP_MAJOR_VERSION < 8) {
76
            $this->markTestSkipped('php >= 8 is required.');
77
        }
78
79
        $this->expectException(Exception\UnsupportedPropertyTypeException::class);
80
        $this->expectExceptionMessage('The ObjectWithIntOrFloat.value property ' .
81
                                      'contains an union type that is not supported.');
82
83
        (new Hydrator)->hydrate(Fixtures\ObjectWithIntOrFloat::class, []);
84
    }
85
86
    public function testHydrateAnnotatedProperty() : void
87
    {
88
        $object = (new Hydrator)
89
            ->useAnnotations()
90
            ->hydrate(Fixtures\ObjectWithAnnotatedAlias::class, ['non-normalized-value' => 'foo']);
91
92
        $this->assertSame('foo', $object->value);
93
    }
94
95
    public function testHydrateAnnotatedPropertyUsingNormalizedKey() : void
96
    {
97
        $object = (new Hydrator)
98
            ->useAnnotations()
99
            ->hydrate(Fixtures\ObjectWithAnnotatedAlias::class, ['value' => 'foo']);
100
101
        $this->assertSame('foo', $object->value);
102
    }
103
104
    public function testHydrateAnnotatedPropertyWhenDisabledAliasSupport() : void
105
    {
106
        $this->expectException(Exception\MissingRequiredValueException::class);
107
        $this->expectExceptionMessage('The ObjectWithAnnotatedAlias.value property ' .
108
                                      'is required.');
109
110
        (new Hydrator)
111
            ->useAnnotations()
112
            ->aliasSupport(false)
113
            ->hydrate(Fixtures\ObjectWithAnnotatedAlias::class, ['non-normalized-value' => 'foo']);
114
    }
115
116
    public function testHydrateAnnotatedPropertyWhenDisabledAnnotations() : void
117
    {
118
        $this->expectException(Exception\MissingRequiredValueException::class);
119
        $this->expectExceptionMessage('The ObjectWithAnnotatedAlias.value property ' .
120
                                      'is required.');
121
122
        (new Hydrator)->hydrate(Fixtures\ObjectWithAnnotatedAlias::class, ['non-normalized-value' => 'foo']);
123
    }
124
125
    public function testHydrateAttributedProperty() : void
126
    {
127
        if (\PHP_MAJOR_VERSION < 8) {
128
            $this->markTestSkipped('php >= 8 is required.');
129
        }
130
131
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithAttributedAlias::class, ['non-normalized-value' => 'foo']);
132
133
        $this->assertSame('foo', $object->value);
134
    }
135
136
    public function testHydrateAttributedPropertyUsingNormalizedKey() : void
137
    {
138
        if (\PHP_MAJOR_VERSION < 8) {
139
            $this->markTestSkipped('php >= 8 is required.');
140
        }
141
142
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithAttributedAlias::class, ['value' => 'foo']);
143
144
        $this->assertSame('foo', $object->value);
145
    }
146
147
    public function testHydrateAttributedPropertyWhenDisabledAliasSupport() : void
148
    {
149
        if (\PHP_MAJOR_VERSION < 8) {
150
            $this->markTestSkipped('php >= 8 is required.');
151
        }
152
153
        $this->expectException(Exception\MissingRequiredValueException::class);
154
        $this->expectExceptionMessage('The ObjectWithAttributedAlias.value property ' .
155
                                      'is required.');
156
157
        (new Hydrator)
158
            ->aliasSupport(false)
159
            ->hydrate(Fixtures\ObjectWithAttributedAlias::class, ['non-normalized-value' => 'foo']);
160
    }
161
162
    public function testRequiredProperty() : void
163
    {
164
        $this->expectException(Exception\MissingRequiredValueException::class);
165
        $this->expectExceptionMessage('The ObjectWithString.value property ' .
166
                                      'is required.');
167
168
        (new Hydrator)->hydrate(Fixtures\ObjectWithString::class, []);
169
    }
170
171
    public function testUnsupportedPropertyType() : void
172
    {
173
        $this->expectException(Exception\UnsupportedPropertyTypeException::class);
174
        $this->expectExceptionMessage('The ObjectWithUnsupportedType.value property ' .
175
                                      'contains an unsupported type iterable.');
176
177
        (new Hydrator)->hydrate(Fixtures\ObjectWithUnsupportedType::class, ['value' => false]);
178
    }
179
180
    public function testOptionalProperty() : void
181
    {
182
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithOptionalString::class, []);
183
184
        $this->assertSame('75c4c2a0-e352-4eda-b2ed-b7f713ffb9ff', $object->value);
185
    }
186
187
    public function testHydrateObject() : void
188
    {
189
        $source = new Fixtures\ObjectWithString();
190
191
        // should return the source object...
192
        $object = (new Hydrator)->hydrate($source, ['value' => 'foo']);
193
194
        $this->assertSame($source, $object);
195
        $this->assertSame('foo', $source->value);
196
    }
197
198
    public function testHydrateUsingDataObject() : void
199
    {
200
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithString::class, (object) ['value' => 'foo']);
201
202
        $this->assertSame('foo', $object->value);
203
    }
204
205
    public function testHydrateWithJson() : void
206
    {
207
        $object = (new Hydrator)->hydrateWithJson(Fixtures\ObjectWithString::class, '{"value": "foo"}');
208
209
        $this->assertSame('foo', $object->value);
210
    }
211
212
    public function testConvertEmptyStringToNullForNonStringType() : void
213
    {
214
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithNullableInt::class, ['value' => '']);
215
216
        $this->assertNull($object->value);
217
    }
218
219
    public function testHydrateNullablePropertyWithNull() : void
220
    {
221
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithNullableString::class, ['value' => null]);
222
223
        $this->assertNull($object->value);
224
    }
225
226
    public function testHydrateUnnullablePropertyWithNull() : void
227
    {
228
        $this->expectException(Exception\InvalidValueException::class);
229
        $this->expectExceptionMessage('The ObjectWithString.value property ' .
230
                                      'cannot accept null.');
231
232
        (new Hydrator)->hydrate(Fixtures\ObjectWithString::class, ['value' => null]);
233
    }
234
235
    /**
236
     * @dataProvider booleanValueProvider
237
     */
238
    public function testHydrateBooleanProperty($value, $expected) : void
239
    {
240
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithBool::class, ['value' => $value]);
241
242
        $this->assertSame($expected, $object->value);
243
    }
244
245
    public function booleanValueProvider() : array
246
    {
247
        return [
248
            [true, true],
249
            [1, true],
250
            ['1', true],
251
            ['on', true],
252
            ['yes', true],
253
            [false, false],
254
            [0, false],
255
            ['0', false],
256
            ['off', false],
257
            ['no', false],
258
        ];
259
    }
260
261
    public function testHydrateBooleanPropertyWithInvalidValue() : void
262
    {
263
        $this->expectException(Exception\InvalidValueException::class);
264
        $this->expectExceptionMessage('The ObjectWithBool.value property expects a boolean.');
265
266
        (new Hydrator)->hydrate(Fixtures\ObjectWithBool::class, ['value' => 'foo']);
267
    }
268
269
    /**
270
     * @dataProvider integerValueProvider
271
     */
272
    public function testHydrateIntegerProperty($value, $expected) : void
273
    {
274
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithInt::class, ['value' => $value]);
275
276
        $this->assertSame($expected, $object->value);
277
    }
278
279
    public function integerValueProvider() : array
280
    {
281
        return [
282
            [42, 42],
283
            ['42', 42],
284
        ];
285
    }
286
287
    public function testHydrateIntegerPropertyWithInvalidValue() : void
288
    {
289
        $this->expectException(Exception\InvalidValueException::class);
290
        $this->expectExceptionMessage('The ObjectWithInt.value property expects an integer.');
291
292
        (new Hydrator)->hydrate(Fixtures\ObjectWithInt::class, ['value' => 'foo']);
293
    }
294
295
    /**
296
     * @dataProvider numberValueProvider
297
     */
298
    public function testHydrateNumberProperty($value, $expected) : void
299
    {
300
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithFloat::class, ['value' => $value]);
301
302
        $this->assertSame($expected, $object->value);
303
    }
304
305
    public function numberValueProvider() : array
306
    {
307
        return [
308
            [42, 42.0],
309
            ['42', 42.0],
310
            [42.0, 42.0],
311
            ['42.0', 42.0],
312
        ];
313
    }
314
315
    public function testHydrateNumberPropertyWithInvalidValue() : void
316
    {
317
        $this->expectException(Exception\InvalidValueException::class);
318
        $this->expectExceptionMessage('The ObjectWithFloat.value property expects a number.');
319
320
        (new Hydrator)->hydrate(Fixtures\ObjectWithFloat::class, ['value' => 'foo']);
321
    }
322
323
    public function testHydrateStringableProperty() : void
324
    {
325
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithString::class, ['value' => 'foo']);
326
327
        $this->assertSame('foo', $object->value);
328
    }
329
330
    public function testHydrateStringablePropertyWithEmptyString() : void
331
    {
332
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithString::class, ['value' => '']);
333
334
        $this->assertSame('', $object->value);
335
    }
336
337
    public function testHydrateStringablePropertyWithInvalidValue() : void
338
    {
339
        $this->expectException(Exception\InvalidValueException::class);
340
        $this->expectExceptionMessage('The ObjectWithString.value property expects a string.');
341
342
        (new Hydrator)->hydrate(Fixtures\ObjectWithString::class, ['value' => 42]);
343
    }
344
345
    public function testHydrateArrayableProperty() : void
346
    {
347
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithArray::class, ['value' => ['foo']]);
348
349
        $this->assertSame(['foo'], $object->value);
350
    }
351
352
    public function testHydrateArrayablePropertyWithInvalidValue() : void
353
    {
354
        $this->expectException(Exception\InvalidValueException::class);
355
        $this->expectExceptionMessage('The ObjectWithArray.value property expects an array.');
356
357
        (new Hydrator)->hydrate(Fixtures\ObjectWithArray::class, ['value' => 'foo']);
358
    }
359
360
    public function testHydrateObjectableProperty() : void
361
    {
362
        $value = (object) ['value' => 'foo'];
363
364
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithObject::class, ['value' => $value]);
365
366
        $this->assertSame($value, $object->value);
367
    }
368
369
    public function testHydrateObjectablePropertyWithInvalidValue() : void
370
    {
371
        $this->expectException(Exception\InvalidValueException::class);
372
        $this->expectExceptionMessage('The ObjectWithObject.value property expects an object.');
373
374
        (new Hydrator)->hydrate(Fixtures\ObjectWithObject::class, ['value' => 'foo']);
375
    }
376
377
    /**
378
     * @dataProvider timestampValueProvider
379
     */
380
    public function testHydrateDateTimeProperty($value, $expected) : void
381
    {
382
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithDateTime::class, ['value' => $value]);
383
384
        $this->assertSame($expected, $object->value->format('Y-m-d'));
385
    }
386
387
    /**
388
     * @dataProvider timestampValueProvider
389
     */
390
    public function testHydrateDateTimeImmutableProperty($value, $expected) : void
391
    {
392
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithDateTimeImmutable::class, ['value' => $value]);
393
394
        $this->assertSame($expected, $object->value->format('Y-m-d'));
395
    }
396
397
    public function timestampValueProvider() : array
398
    {
399
        return [
400
            [1262304000, '2010-01-01'],
401
            ['1262304000', '2010-01-01'],
402
            ['2010-01-01', '2010-01-01'],
403
        ];
404
    }
405
406
    public function testHydrateDateTimePropertyWithInvalidValue() : void
407
    {
408
        $this->expectException(Exception\InvalidValueException::class);
409
        $this->expectExceptionMessage('The ObjectWithDateTime.value property ' .
410
                                      'expects a valid date-time string or timestamp.');
411
412
        (new Hydrator)->hydrate(Fixtures\ObjectWithDateTime::class, ['value' => 'foo']);
413
    }
414
415
    public function testHydrateDateTimeImmutablePropertyWithInvalidValue() : void
416
    {
417
        $this->expectException(Exception\InvalidValueException::class);
418
        $this->expectExceptionMessage('The ObjectWithDateTimeImmutable.value property ' .
419
                                      'expects a valid date-time string or timestamp.');
420
421
        (new Hydrator)->hydrate(Fixtures\ObjectWithDateTimeImmutable::class, ['value' => 'foo']);
422
    }
423
424
    public function testHydrateDateIntervalProperty() : void
425
    {
426
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithDateInterval::class, ['value' => 'P33Y']);
427
428
        $this->assertSame(33, $object->value->y);
429
    }
430
431
    public function testHydrateDateIntervalPropertyWithInvalidValue() : void
432
    {
433
        $this->expectException(Exception\InvalidValueException::class);
434
        $this->expectExceptionMessage('The ObjectWithDateInterval.value property ' .
435
                                      'expects a string.');
436
437
        (new Hydrator)->hydrate(Fixtures\ObjectWithDateInterval::class, ['value' => 42]);
438
    }
439
440
    public function testHydrateDateIntervalPropertyWithInvalidFormat() : void
441
    {
442
        $this->expectException(Exception\InvalidValueException::class);
443
        $this->expectExceptionMessage('The ObjectWithDateInterval.value property ' .
444
                                      'expects a valid date-interval string based on ISO 8601.');
445
446
        (new Hydrator)->hydrate(Fixtures\ObjectWithDateInterval::class, ['value' => 'foo']);
447
    }
448
449
    /**
450
     * @dataProvider customEnumValueProvider
451
     */
452
    public function testHydrateCustomEnumContainedPropery($value, $expected) : void
453
    {
454
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithCustomEnum::class, ['value' => $value]);
455
456
        $this->assertSame($expected, $object->value);
457
    }
458
459
    public function customEnumValueProvider() : array
460
    {
461
        return [
462
            [1, Fixtures\CustomEnum::Int1()],
463
            ['1', Fixtures\CustomEnum::Int1()],
464
            [2, Fixtures\CustomEnum::Int2()],
465
            ['2', Fixtures\CustomEnum::Int2()],
466
            ['foo', Fixtures\CustomEnum::String1()],
467
            ['bar', Fixtures\CustomEnum::String2()],
468
        ];
469
    }
470
471
    public function testHydrateCustomEnumContainedProperyWithUnknownValue() : void
472
    {
473
        $this->expectException(Exception\InvalidValueException::class);
474
        $this->expectExceptionMessage('The ObjectWithCustomEnum.value property ' .
475
                                      'expects one of the following values: ' .
476
                                      \implode(', ', Fixtures\CustomEnum::values()) . '.');
477
478
        (new Hydrator)->hydrate(Fixtures\ObjectWithCustomEnum::class, ['value' => 'unknown']);
479
    }
480
481
    /**
482
     * @dataProvider stringableEnumValueProvider
483
     */
484
    public function testHydrateStringableEnumProperty($value, $expected) : void
485
    {
486
        if (\PHP_VERSION_ID < 80100) {
487
            $this->markTestSkipped('php >= 8.1 is required.');
488
        }
489
490
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithStringableEnum::class, ['value' => $value]);
491
492
        $this->assertSame($expected, $object->value);
493
    }
494
495
    public function stringableEnumValueProvider() : array
496
    {
497
        if (\PHP_VERSION_ID < 80100) {
498
            return [];
499
        }
500
501
        return [
502
            ['c1200a7e-136e-4a11-9bc3-cc937046e90f', Fixtures\StringableEnum::foo],
503
            ['a2b29b37-1c5a-4b36-9981-097ddd25c740', Fixtures\StringableEnum::bar],
504
            ['c1ea3762-9827-4c0c-808b-53be3febae6d', Fixtures\StringableEnum::baz],
505
        ];
506
    }
507
508
    public function testHydrateStringableEnumPropertyWithInvalidValue() : void
509
    {
510
        if (\PHP_VERSION_ID < 80100) {
511
            $this->markTestSkipped('php >= 8.1 is required.');
512
        }
513
514
        $this->expectException(Exception\InvalidValueException::class);
515
        $this->expectExceptionMessage('The ObjectWithStringableEnum.value property ' .
516
                                      'expects the following type: string.');
517
518
        (new Hydrator)->hydrate(Fixtures\ObjectWithStringableEnum::class, ['value' => 42]);
519
    }
520
521
    public function testHydrateStringableEnumPropertyWithInvalidUnknownCase() : void
522
    {
523
        if (\PHP_VERSION_ID < 80100) {
524
            $this->markTestSkipped('php >= 8.1 is required.');
525
        }
526
527
        $this->expectException(Exception\InvalidValueException::class);
528
        $this->expectExceptionMessage('The ObjectWithStringableEnum.value property ' .
529
                                      'expects one of the following values: ' .
530
                                      \implode(', ', Fixtures\StringableEnum::values()) . '.');
531
532
        (new Hydrator)->hydrate(Fixtures\ObjectWithStringableEnum::class, ['value' => 'foo']);
533
    }
534
535
    /**
536
     * @dataProvider numerableEnumValueProvider
537
     */
538
    public function testHydrateNumerableEnumProperty($value, $expected) : void
539
    {
540
        if (\PHP_VERSION_ID < 80100) {
541
            $this->markTestSkipped('php >= 8.1 is required.');
542
        }
543
544
        $object = (new Hydrator)->hydrate(Fixtures\ObjectWithNumerableEnum::class, ['value' => $value]);
545
546
        $this->assertSame($expected, $object->value);
547
    }
548
549
    public function numerableEnumValueProvider() : array
550
    {
551
        if (\PHP_VERSION_ID < 80100) {
552
            return [];
553
        }
554
555
        return [
556
            [1, Fixtures\NumerableEnum::foo],
557
            [2, Fixtures\NumerableEnum::bar],
558
            [3, Fixtures\NumerableEnum::baz],
559
560
            // should convert strings to integers...
561
            ['1', Fixtures\NumerableEnum::foo],
562
            ['2', Fixtures\NumerableEnum::bar],
563
            ['3', Fixtures\NumerableEnum::baz],
564
        ];
565
    }
566
567
    public function testHydrateNumerableEnumPropertyWithInvalidValue() : void
568
    {
569
        if (\PHP_VERSION_ID < 80100) {
570
            $this->markTestSkipped('php >= 8.1 is required.');
571
        }
572
573
        $this->expectException(Exception\InvalidValueException::class);
574
        $this->expectExceptionMessage('The ObjectWithNumerableEnum.value property ' .
575
                                      'expects the following type: int.');
576
577
        (new Hydrator)->hydrate(Fixtures\ObjectWithNumerableEnum::class, ['value' => 'foo']);
578
    }
579
580
    public function testHydrateNumerableEnumPropertyWithInvalidUnknownCase() : void
581
    {
582
        if (\PHP_VERSION_ID < 80100) {
583
            $this->markTestSkipped('php >= 8.1 is required.');
584
        }
585
586
        $this->expectException(Exception\InvalidValueException::class);
587
        $this->expectExceptionMessage('The ObjectWithNumerableEnum.value property ' .
588
                                      'expects one of the following values: ' .
589
                                      \implode(', ', Fixtures\NumerableEnum::values()) . '.');
590
591
        (new Hydrator)->hydrate(Fixtures\ObjectWithNumerableEnum::class, ['value' => 42]);
592
    }
593
594
    public function testHydrateAssociatedProperty() : void
595
    {
596
        $o = (new Hydrator)->hydrate(Fixtures\ObjectWithAssociation::class, ['value' => ['value' => 'foo']]);
597
598
        $this->assertSame('foo', $o->value->value);
599
    }
600
601
    public function testHydrateAssociatedPropertyUsingDataObject() : void
602
    {
603
        $o = (new Hydrator)->hydrate(Fixtures\ObjectWithAssociation::class, ['value' => (object) ['value' => 'foo']]);
604
605
        $this->assertSame('foo', $o->value->value);
606
    }
607
608
    public function testHydrateAssociatedPropertyWithInvalidData() : void
609
    {
610
        $this->expectException(Exception\InvalidValueException::class);
611
        $this->expectExceptionMessage('The ObjectWithAssociation.value property ' .
612
                                      'expects an associative array or object.');
613
614
        (new Hydrator)->hydrate(Fixtures\ObjectWithAssociation::class, ['value' => 'foo']);
615
    }
616
617
    public function testHydrateAssociationCollectionProperty() : void
618
    {
619
        $o = (new Hydrator)->hydrate(Fixtures\ObjectWithAssociations::class, ['value' => [
620
            'foo' => ['value' => 'foo'],
621
            'bar' => ['value' => 'bar'],
622
        ]]);
623
624
        $this->assertTrue($o->value->has('foo'));
625
        $this->assertSame('foo', $o->value->get('foo')->value);
626
627
        $this->assertTrue($o->value->has('bar'));
628
        $this->assertSame('bar', $o->value->get('bar')->value);
629
    }
630
631
    public function testHydrateAssociationCollectionPropertyUsingDataObject() : void
632
    {
633
        $o = (new Hydrator)->hydrate(Fixtures\ObjectWithAssociations::class, ['value' => (object) [
634
            'foo' => (object) ['value' => 'foo'],
635
            'bar' => (object) ['value' => 'bar'],
636
        ]]);
637
638
        $this->assertTrue($o->value->has('foo'));
639
        $this->assertSame('foo', $o->value->get('foo')->value);
640
641
        $this->assertTrue($o->value->has('bar'));
642
        $this->assertSame('bar', $o->value->get('bar')->value);
643
    }
644
645
    public function testHydrateAssociationCollectionPropertyWithInvalidData() : void
646
    {
647
        $this->expectException(Exception\InvalidValueException::class);
648
        $this->expectExceptionMessage('The ObjectWithAssociations.value property ' .
649
                                      'expects an associative array or object.');
650
651
        (new Hydrator)->hydrate(Fixtures\ObjectWithAssociations::class, ['value' => 'foo']);
652
    }
653
654
    public function testHydrateAssociationCollectionPropertyWithInvalidChild() : void
655
    {
656
        $this->expectException(Exception\InvalidValueException::class);
657
        $this->expectExceptionMessage('The ObjectWithAssociations.value[0] property ' .
658
                                      'expects an associative array or object.');
659
660
        (new Hydrator)->hydrate(Fixtures\ObjectWithAssociations::class, ['value' => ['foo']]);
661
    }
662
663
    public function testInvalidValueExceptionProperty() : void
664
    {
665
        try {
666
            (new Hydrator)->hydrate(Fixtures\ObjectWithString::class, ['value' => 42]);
667
        } catch (Exception\InvalidValueException $e) {
668
            $this->assertSame('value', $e->getProperty()->getName());
669
            $this->assertSame('ObjectWithString.value', $e->getPropertyPath());
670
        }
671
    }
672
673
    public function testHydrateProductWithJsonAsArray() : void
674
    {
675
        if (\PHP_VERSION_ID < 80100) {
676
            $this->markTestSkipped('php >= 8.1 is required.');
677
        }
678
679
        $json = <<<JSON
680
        {
681
            "name": "ac7ce13e-9b2e-4b09-ae7a-973769ea43df",
682
            "category": {
683
                "name": "a0127d1b-28b6-40a9-9a62-cfb2e2b44abd"
684
            },
685
            "tags": [
686
                {
687
                    "name": "a9878435-506c-4757-92b0-69ea2bd15bc3"
688
                },
689
                {
690
                    "name": "73dc4db1-7965-41b6-88cb-4dc9df6fb3ea"
691
                }
692
            ],
693
            "status": 2
694
        }
695
        JSON;
696
697
        $product = (new Hydrator)->hydrateWithJson(Fixtures\Store\Product::class, $json);
698
699
        $this->assertSame('ac7ce13e-9b2e-4b09-ae7a-973769ea43df', $product->name);
700
        $this->assertSame('a0127d1b-28b6-40a9-9a62-cfb2e2b44abd', $product->category->name);
701
        $this->assertSame('a9878435-506c-4757-92b0-69ea2bd15bc3', $product->tags->get(0)->name);
702
        $this->assertSame('73dc4db1-7965-41b6-88cb-4dc9df6fb3ea', $product->tags->get(1)->name);
703
        $this->assertSame(2, $product->status->value);
704
    }
705
706
    public function testHydrateProductWithJsonAsObject() : void
707
    {
708
        if (\PHP_VERSION_ID < 80100) {
709
            $this->markTestSkipped('php >= 8.1 is required.');
710
        }
711
712
        $json = <<<JSON
713
        {
714
            "name": "0f61ac0e-f732-4088-8082-cc396e7dcb80",
715
            "category": {
716
                "name": "d342d030-3c0c-431e-be54-2e933b722b7c"
717
            },
718
            "tags": [
719
                {
720
                    "name": "3635627a-e348-4ca4-8e62-4e5cd78043d2"
721
                },
722
                {
723
                    "name": "dccd816f-bb28-41f3-b1a9-ddaff1fdec5b"
724
                }
725
            ],
726
            "status": 2
727
        }
728
        JSON;
729
730
        $product = (new Hydrator)->hydrateWithJson(Fixtures\Store\Product::class, $json, 0);
731
732
        $this->assertSame('0f61ac0e-f732-4088-8082-cc396e7dcb80', $product->name);
733
        $this->assertSame('d342d030-3c0c-431e-be54-2e933b722b7c', $product->category->name);
734
        $this->assertSame('3635627a-e348-4ca4-8e62-4e5cd78043d2', $product->tags->get(0)->name);
735
        $this->assertSame('dccd816f-bb28-41f3-b1a9-ddaff1fdec5b', $product->tags->get(1)->name);
736
        $this->assertSame(2, $product->status->value);
737
    }
738
}
739