Passed
Push — main ( b20692...5d02b0 )
by Anatoly
01:10 queued 12s
created

testJsonableObjectInvalidJsonSyntax()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 6
rs 10
1
<?php declare(strict_types=1);
2
3
namespace Sunrise\Hydrator\Tests;
4
5
/**
6
 * Import classes
7
 */
8
use PHPUnit\Framework\TestCase;
9
use Sunrise\Hydrator\Exception;
10
use Sunrise\Hydrator\Hydrator;
11
use Sunrise\Hydrator\HydratorInterface;
12
use DateTimeInterface;
13
14
/**
15
 * HydratorTest
16
 */
17
class HydratorTest extends TestCase
18
{
19
20
    /**
21
     * @return void
22
     */
23
    public function testContracts() : void
24
    {
25
        $hydrator = new Hydrator();
26
27
        $this->assertInstanceOf(HydratorInterface::class, $hydrator);
28
    }
29
30
    /**
31
     * @return void
32
     */
33
    public function testHydrate() : void
34
    {
35
        $data = [
36
            'static' => 'foo',
37
            'nullable' => null,
38
            'bool' => false,
39
            'int' => 0,
40
            'float' => 0.0,
41
            'string' => 'foo',
42
            'array' => [
43
                'foo',
44
                'bar',
45
                100,
46
            ],
47
            'dateTime' => '2005-08-15T15:52:01.000+00:00',
48
            'barDto' => [
49
                'value' => 'foo',
50
            ],
51
            'barDtoCollection' => [
52
                [
53
                    'value' => 'foo',
54
                ],
55
                [
56
                    'value' => 'bar',
57
                ],
58
            ],
59
            'simpleArray' => [
60
                'foo',
61
                'bar',
62
            ],
63
            'alias' => 'value',
64
        ];
65
66
        $object = new Fixture\FooDto();
67
        $hydrator = new Hydrator();
68
        $hydrator->hydrate($object, $data);
69
70
        $this->assertSame('default value', $object::$static);
71
        $this->assertSame('default value', $object->valuable);
72
        $this->assertSame($data['nullable'], $object->nullable);
73
        $this->assertSame($data['bool'], $object->bool);
74
        $this->assertSame($data['int'], $object->int);
75
        $this->assertSame($data['float'], $object->float);
76
        $this->assertSame($data['string'], $object->string);
77
        $this->assertSame($data['array'], $object->array->getArrayCopy());
78
        $this->assertSame($data['dateTime'], $object->dateTime->format(DateTimeInterface::RFC3339_EXTENDED));
79
        $this->assertSame($data['barDto']['value'], $object->barDto->value);
80
        $this->assertSame($data['barDtoCollection'][0]['value'], $object->barDtoCollection->getIterator()[0]->value);
81
        $this->assertSame($data['barDtoCollection'][1]['value'], $object->barDtoCollection->getIterator()[1]->value);
82
        $this->assertSame($data['simpleArray'], $object->simpleArray);
83
        $this->assertSame($data['alias'], $object->hidden);
84
    }
85
86
    /**
87
     * @return void
88
     */
89
    public function testJsonTypeArrayAccess() : void
90
    {
91
        $object = (new Hydrator)->hydrate(new Fixture\TestJsonTypeDto(), ['json' => '[]']);
92
93
        $this->assertFalse(isset($object->json['foo']));
94
        $this->assertNull($object->json['foo']);
95
96
        $object->json['foo'] = 1;
97
        $this->assertTrue(isset($object->json['foo']));
98
        $this->assertSame(1, $object->json['foo']);
99
100
        unset($object->json['foo']);
101
        $this->assertFalse(isset($object->json['foo']));
102
        $this->assertNull($object->json['foo']);
103
    }
104
105
    /**
106
     * @return void
107
     */
108
    public function testJsonTypeJsonSerialize() : void
109
    {
110
        $object = (new Hydrator)->hydrate(new Fixture\TestJsonTypeDto(), ['json' => '[]']);
111
112
        $object->json['foo'] = 1;
113
        $object->json['bar'] = 2;
114
115
        $this->assertSame([
116
            'foo' => 1,
117
            'bar' => 2,
118
        ], $object->json->jsonSerialize());
119
    }
120
121
    /**
122
     * @return void
123
     */
124
    public function testJsonTypeDeserializeJson() : void
125
    {
126
        $json = '{"foo":1,"bar":2,"baz":{"qux":3}}';
127
128
        $object = (new Hydrator)->hydrate(new Fixture\TestJsonTypeDto(), ['json' => $json]);
129
130
        $this->assertSame(1, $object->json['foo']);
131
        $this->assertSame(2, $object->json['bar']);
132
        $this->assertSame(3, $object->json['baz']['qux']);
133
    }
134
135
    /**
136
     * @return void
137
     */
138
    public function testJsonTypeInvalidJsonSyntax() : void
139
    {
140
        $this->expectException(Exception\InvalidValueException::class);
141
        $this->expectExceptionMessage(
142
            'The <TestJsonTypeDto.json> property only accepts valid JSON data (Syntax error).'
143
        );
144
145
        (new Hydrator)->hydrate(new Fixture\TestJsonTypeDto(), ['json' => '{']);
146
    }
147
148
    /**
149
     * @return void
150
     */
151
    public function testJsonTypeInvalidJsonType() : void
152
    {
153
        $this->expectException(Exception\InvalidValueException::class);
154
        $this->expectExceptionMessage('The <TestJsonTypeDto.json> property only accepts a string.');
155
156
        (new Hydrator)->hydrate(new Fixture\TestJsonTypeDto(), ['json' => []]);
157
    }
158
159
    /**
160
     * @return void
161
     */
162
    public function testJsonableObjectDeserializeJson() : void
163
    {
164
        $json = '{"foo":"foo:value","bar":"bar:value"}';
165
166
        $object = (new Hydrator)->hydrate(new Fixture\TestJsonDto(), ['json' => $json]);
167
168
        $this->assertSame('foo:value', $object->json->foo);
169
        $this->assertSame('bar:value', $object->json->bar);
170
    }
171
172
    /**
173
     * @return void
174
     */
175
    public function testJsonableObjectInvalidJsonSyntax() : void
176
    {
177
        $this->expectException(Exception\InvalidValueException::class);
178
        $this->expectExceptionMessage('The <TestJsonDto.json> property only accepts valid JSON data (Syntax error).');
179
180
        (new Hydrator)->hydrate(new Fixture\TestJsonDto(), ['json' => '{']);
181
    }
182
183
    /**
184
     * @return void
185
     */
186
    public function testJsonableObjectInvalidJsonType() : void
187
    {
188
        $this->expectException(Exception\InvalidValueException::class);
189
        $this->expectExceptionMessage('The <TestJsonDto.json> property only accepts a string.');
190
191
        (new Hydrator)->hydrate(new Fixture\TestJsonDto(), ['json' => []]);
192
    }
193
194
    /**
195
     * @return void
196
     */
197
    public function testMissingRequiredValueException() : void
198
    {
199
        $object = new Fixture\BarDto();
200
        $hydrator = new Hydrator();
201
202
        $this->expectException(Exception\MissingRequiredValueException::class);
203
        $this->expectExceptionMessage('The <BarDto.value> property is required.');
204
205
        $hydrator->hydrate($object, [
206
        ]);
207
    }
208
209
    /**
210
     * @return void
211
     */
212
    public function testUntypedObjectPropertyException() : void
213
    {
214
        $object = new Fixture\WithUntypedPropertyDto();
215
        $hydrator = new Hydrator();
216
217
        $this->expectException(Exception\UntypedObjectPropertyException::class);
218
        $this->expectExceptionMessage('The <WithUntypedPropertyDto.value> property is not typed.');
219
220
        $hydrator->hydrate($object, [
221
            'value' => 'foo',
222
        ]);
223
    }
224
225
    /**
226
     * @return void
227
     */
228
    public function testUnsupportedObjectPropertyTypeException() : void
229
    {
230
        $object = new Fixture\WithUnsupportedPropertyTypeDto();
231
        $hydrator = new Hydrator();
232
233
        $this->expectException(Exception\UnsupportedObjectPropertyTypeException::class);
234
        $this->expectExceptionMessage('The <WithUnsupportedPropertyTypeDto.value> property ' .
235
                                      'contains the <Traversable> unhydrable type.');
236
237
        $hydrator->hydrate($object, [
238
            'value' => 'foo',
239
        ]);
240
    }
241
242
    /**
243
     * @return void
244
     */
245
    public function testInvalidValueExceptionForNonNullableProperty() : void
246
    {
247
        $object = new Fixture\BazDto();
248
        $hydrator = new Hydrator();
249
250
        $this->expectException(Exception\InvalidValueException::class);
251
        $this->expectExceptionMessage('The <BazDto.nonNullable> property does not support null.');
252
253
        $hydrator->hydrate($object, [
254
            'nonNullable' => null,
255
        ]);
256
    }
257
258
    /**
259
     * @param mixed $nonScalarValue
260
     *
261
     * @return void
262
     *
263
     * @dataProvider nonScalarDataProvider
264
     */
265
    public function testInvalidValueExceptionForScalarProperty($nonScalarValue) : void
266
    {
267
        $object = new Fixture\BazDto();
268
        $hydrator = new Hydrator();
269
270
        $this->expectException(Exception\InvalidValueException::class);
271
        $this->expectExceptionMessage('The <BazDto.scalar> property only accepts a scalar value.');
272
273
        $hydrator->hydrate($object, [
274
            'scalar' => $nonScalarValue,
275
        ]);
276
    }
277
278
    /**
279
     * @param mixed $nonArrayValue
280
     *
281
     * @return void
282
     *
283
     * @dataProvider nonArrayDataProvider
284
     */
285
    public function testInvalidValueExceptionForArrayProperty($nonArrayValue) : void
286
    {
287
        $object = new Fixture\BazDto();
288
        $hydrator = new Hydrator();
289
290
        $this->expectException(Exception\InvalidValueException::class);
291
        $this->expectExceptionMessage('The <BazDto.array> property only accepts an array.');
292
293
        $hydrator->hydrate($object, [
294
            'array' => $nonArrayValue,
295
        ]);
296
    }
297
298
    /**
299
     * @param mixed $nonDateTimeValue
300
     *
301
     * @return void
302
     *
303
     * @dataProvider nonDateTimeDataProvider
304
     */
305
    public function testInvalidValueExceptionForDateTimeProperty($nonDateTimeValue) : void
306
    {
307
        $object = new Fixture\BazDto();
308
        $hydrator = new Hydrator();
309
310
        $this->expectException(Exception\InvalidValueException::class);
311
        $this->expectExceptionMessage('The <BazDto.dateTime> property only accepts a valid date-time string.');
312
313
        $hydrator->hydrate($object, [
314
            'dateTime' => $nonDateTimeValue,
315
        ]);
316
    }
317
318
    /**
319
     * @param mixed $nonArrayValue
320
     *
321
     * @return void
322
     *
323
     * @dataProvider nonArrayDataProvider
324
     */
325
    public function testInvalidValueExceptionForOneToOneProperty($nonArrayValue) : void
326
    {
327
        $object = new Fixture\BazDto();
328
        $hydrator = new Hydrator();
329
330
        $this->expectException(Exception\InvalidValueException::class);
331
        $this->expectExceptionMessage('The <BazDto.oneToOne> property only accepts an array.');
332
333
        $hydrator->hydrate($object, [
334
            'oneToOne' => $nonArrayValue,
335
        ]);
336
    }
337
338
    /**
339
     * @param mixed $nonArrayValue
340
     *
341
     * @return void
342
     *
343
     * @dataProvider nonArrayDataProvider
344
     */
345
    public function testInvalidValueExceptionForOneToManyProperty($nonArrayValue) : void
346
    {
347
        $object = new Fixture\BazDto();
348
        $hydrator = new Hydrator();
349
350
        $this->expectException(Exception\InvalidValueException::class);
351
        $this->expectExceptionMessage('The <BazDto.oneToMany> property only accepts an array.');
352
353
        $hydrator->hydrate($object, [
354
            'oneToMany' => $nonArrayValue,
355
        ]);
356
    }
357
358
    public function testEnumerableValue() : void
359
    {
360
        $object = (new Hydrator)->hydrate(new Fixture\TestEnumDto(), ['foo' => 'A']);
361
        $this->assertSame('A:value', $object->foo->getValue());
362
363
        $object = (new Hydrator)->hydrate(new Fixture\TestEnumDto(), ['foo' => 'B']);
364
        $this->assertSame('B:value', $object->foo->getValue());
365
366
        $object = (new Hydrator)->hydrate(new Fixture\TestEnumDto(), ['foo' => 'C']);
367
        $this->assertSame('C:value', $object->foo->getValue());
368
369
        $object = (new Hydrator)->hydrate(new Fixture\TestEnumDto(), ['foo' => '0']);
370
        $this->assertSame('0:value', $object->foo->getValue());
371
372
        $object = (new Hydrator)->hydrate(new Fixture\TestEnumDto(), ['foo' => '1']);
373
        $this->assertSame('1:value', $object->foo->getValue());
374
375
        $object = (new Hydrator)->hydrate(new Fixture\TestEnumDto(), ['foo' => '2']);
376
        $this->assertSame('2:value', $object->foo->getValue());
377
378
        $object = (new Hydrator)->hydrate(new Fixture\TestEnumDto(), ['foo' => 0]);
379
        $this->assertSame('0:value', $object->foo->getValue());
380
381
        $object = (new Hydrator)->hydrate(new Fixture\TestEnumDto(), ['foo' => 1]);
382
        $this->assertSame('1:value', $object->foo->getValue());
383
384
        $object = (new Hydrator)->hydrate(new Fixture\TestEnumDto(), ['foo' => 2]);
385
        $this->assertSame('2:value', $object->foo->getValue());
386
    }
387
388
    public function testUnknownEnumerableValue() : void
389
    {
390
        $this->expectException(Exception\InvalidValueException::class);
391
        $this->expectExceptionMessage('The <TestEnumDto.foo> property only accepts one of the <TestEnum> enum values.');
392
393
        (new Hydrator)->hydrate(new Fixture\TestEnumDto(), ['foo' => 'D']);
394
    }
395
396
    public function testInvalidEnumerableValue() : void
397
    {
398
        $this->expectException(Exception\InvalidValueException::class);
399
        $this->expectExceptionMessage('The <TestEnumDto.foo> property only accepts an integer or a string.');
400
401
        (new Hydrator)->hydrate(new Fixture\TestEnumDto(), ['foo' => []]);
402
    }
403
404
    /**
405
     * @return array<array>
406
     */
407
    public function nonScalarDataProvider() : array
408
    {
409
        return [
410
            [[]],
411
            [new \stdClass],
412
            [function () {
413
            }],
414
            [\STDOUT],
415
        ];
416
    }
417
418
    /**
419
     * @return array<array>
420
     */
421
    public function nonArrayDataProvider() : array
422
    {
423
        return [
424
            [true],
425
            [1],
426
            [1.1],
427
            [''],
428
            [new \stdClass],
429
            [function () {
430
            }],
431
            [\STDOUT],
432
        ];
433
    }
434
435
    /**
436
     * @return array<array>
437
     */
438
    public function nonDateTimeDataProvider() : array
439
    {
440
        return [
441
            [true],
442
            [1],
443
            [1.1],
444
            [''],
445
            ['0'],
446
            ['non-date-time-string'],
447
            [new \stdClass],
448
            [function () {
449
            }],
450
            [\STDOUT],
451
        ];
452
    }
453
}
454