Completed
Push — master ( 4700f8...b32d7e )
by Tomasz
02:09
created

SerializardTest::testContext()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 32
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 32
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 22
nc 1
nop 0
1
<?php
2
namespace Thunder\Serializard\Tests;
3
4
use Thunder\Serializard\Format\ArrayFormat;
5
use Thunder\Serializard\Format\JsonFormat;
6
use Thunder\Serializard\Format\XmlFormat;
7
use Thunder\Serializard\Format\YamlFormat;
8
use Thunder\Serializard\FormatContainer\FormatContainer;
9
use Thunder\Serializard\Hydrator\ReflectionHydrator;
10
use Thunder\Serializard\HydratorContainer\FallbackHydratorContainer;
11
use Thunder\Serializard\HydratorContainer\HydratorContainerInterface as Hydrators;
12
use Thunder\Serializard\HydratorContainer\HydratorContainerInterface;
13
use Thunder\Serializard\Normalizer\ReflectionNormalizer;
14
use Thunder\Serializard\NormalizerContainer\FallbackNormalizerContainer;
15
use Thunder\Serializard\NormalizerContext\NormalizerContextInterface;
16
use Thunder\Serializard\Serializard;
17
use Thunder\Serializard\Tests\Fake\Context\FakeNormalizerContext;
18
use Thunder\Serializard\Tests\Fake\FakeArticle;
19
use Thunder\Serializard\Tests\Fake\FakeTag;
20
use Thunder\Serializard\Tests\Fake\FakeUser;
21
use Thunder\Serializard\Tests\Fake\FakeUserParent;
22
use Thunder\Serializard\Tests\Fake\FakeUserParentParent;
23
use Thunder\Serializard\Tests\Fake\Interfaces\TypeA;
24
use Thunder\Serializard\Tests\Fake\Interfaces\TypeB;
25
use Thunder\Serializard\Tests\Fake\Interfaces\TypeInterface;
26
use Thunder\Serializard\Utility\RootElementProviderUtility;
27
28
/**
29
 * @author Tomasz Kowalczyk <[email protected]>
30
 */
31
final class SerializardTest extends AbstractTestCase
32
{
33
    /** @dataProvider provideExamples */
34
    public function testSerializard($prefix, $factory)
35
    {
36
        $object = $factory();
37
38
        $serializard = $this->getSerializard();
39
40
        $file = __DIR__.'/examples/'.$prefix;
41
42
        $json = $serializard->serialize($object, 'json');
43
        $yaml = $serializard->serialize($object, 'yaml');
44
        $xml = $serializard->serialize($object, 'xml');
45
        $array = $serializard->serialize($object, 'array');
46
47
        $this->assertSame(file_get_contents($file.'.json'), $json."\n");
48
        $this->assertSame(file_get_contents($file.'.yaml'), $yaml);
49
        $this->assertSame(file_get_contents($file.'.xml'), $xml);
50
        $this->assertSame(require $file.'.php', $array);
51
52
        $userClass = 'Thunder\Serializard\Tests\Fake\FakeUser';
53
54
        $this->assertSame($json, $serializard->serialize($serializard->unserialize($json, $userClass, 'json'), 'json'));
55
        $this->assertSame($yaml, $serializard->serialize($serializard->unserialize($yaml, $userClass, 'yaml'), 'yaml'));
56
        $this->assertSame($xml, $serializard->serialize($serializard->unserialize($xml, $userClass, 'xml'), 'xml'));
57
        $this->assertSame($array, $serializard->serialize($serializard->unserialize($array, $userClass, 'array'), 'array'));
58
    }
59
60
    public function provideExamples()
61
    {
62
        return array(
63
            array('simple', function() {
64
                $user = new FakeUser(1, 'Thomas', new FakeTag(100, 'various'));
65
                $user->addTag(new FakeTag(10, 'sth'));
66
                $user->addTag(new FakeTag(11, 'xyz'));
67
                $user->addTag(new FakeTag(12, 'rnd'));
68
69
                return $user;
70
            }),
71
        );
72
    }
73
74
    public function testInterfaces()
75
    {
76
        $interface = 'Thunder\Serializard\Tests\Fake\Interfaces\TypeInterface';
77
        $normalizers = new FallbackNormalizerContainer();
78
        $normalizers->add($interface, function(TypeInterface $type) {
79
            return array(
80
                'type' => $type->getType(),
81
                'value' => $type->getValue(),
82
            );
83
        });
84
85
        $hydrators = new FallbackHydratorContainer();
86
87
        $formats = new FormatContainer();
88
        $formats->add('array', new ArrayFormat());
89
90
        $serializard = new Serializard($formats, $normalizers, $hydrators);
91
92
        $this->assertSame(array('type' => 'typeA', 'value' => 'valueA'), $serializard->serialize(new TypeA(), 'array'));
93
        $this->assertSame(array('type' => 'typeB', 'value' => 'valueB'), $serializard->serialize(new TypeB(), 'array'));
94
    }
95
96
    /** @dataProvider provideCycles */
97
    public function testCycleException($var, $format)
98
    {
99
        $userClass = 'Thunder\Serializard\Tests\Fake\FakeUser';
100
        $tagClass = 'Thunder\Serializard\Tests\Fake\FakeTag';
101
102
        $normalizers = new FallbackNormalizerContainer();
103
        $normalizers->add($userClass, new ReflectionNormalizer());
104
        $normalizers->add($tagClass, new ReflectionNormalizer());
105
106
        $hydrators = new FallbackHydratorContainer();
107
108
        $formats = new FormatContainer();
109
        $formats->add('xml', new XmlFormat(new RootElementProviderUtility([
110
            FakeUser::class => 'user',
111
            FakeTag::class => 'tag',
112
        ])));
113
        $formats->add('yaml', new YamlFormat());
114
        $formats->add('json', new JsonFormat());
115
        $formats->add('array', new ArrayFormat());
116
117
        $serializard = new Serializard($formats, $normalizers, $hydrators);
118
119
        $this->expectException('RuntimeException');
120
        $serializard->serialize($var, $format);
121
    }
122
123
    public function provideCycles()
124
    {
125
        $user = new FakeUser(1, 'Thomas', new FakeTag(100, 'various'));
126
        $user->addTag(new FakeTag(10, 'sth'));
127
        $user->addTag(new FakeTag(11, 'xyz'));
128
        $user->addTag(new FakeTag(12, 'rnd'));
129
130
        return array(
131
            array($user, 'xml'),
132
            array($user, 'json'),
133
            array($user, 'yaml'),
134
            array($user, 'array'),
135
        );
136
    }
137
138
    private function getSerializard()
139
    {
140
        $userClass = 'Thunder\Serializard\Tests\Fake\FakeUser';
141
        $tagClass = 'Thunder\Serializard\Tests\Fake\FakeTag';
142
143
        $normalizers = new FallbackNormalizerContainer();
144
        $normalizers->add($userClass, new ReflectionNormalizer());
145
        $normalizers->add($tagClass, function(FakeTag $tag) {
146
            return array(
147
                'id' => $tag->getId(),
148
                'name' => $tag->getName(),
149
            );
150
        });
151
152
        $hydrators = new FallbackHydratorContainer();
153 View Code Duplication
        $hydrators->add($userClass, function(array $data, Hydrators $handlers) use($tagClass) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
154
            $tagHandler = $handlers->getHandler($tagClass);
155
156
            $user = new FakeUser($data['id'], $data['name'], $tagHandler($data['tag'], $handlers));
157
            foreach($data['tags'] as $tag) {
158
                $user->addTag($tagHandler($tag, $handlers));
159
            }
160
161
            return $user;
162
        });
163
        $hydrators->add($tagClass, function(array $data, Hydrators $handlers) {
0 ignored issues
show
Unused Code introduced by
The parameter $handlers is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
164
            return new FakeTag($data['id'], $data['name']);
165
        });
166
167
        $formats = new FormatContainer();
168
        $formats->add('xml', new XmlFormat(new RootElementProviderUtility([
169
            FakeUser::class => 'user',
170
            FakeTag::class => 'tag',
171
        ])));
172
        $formats->add('yaml', new YamlFormat());
173
        $formats->add('json', new JsonFormat());
174
        $formats->add('array', new ArrayFormat());
175
176
        return new Serializard($formats, $normalizers, $hydrators);
177
    }
178
179
    public function testParent()
180
    {
181
        $userClass = 'Thunder\Serializard\Tests\Fake\FakeUser';
182
        $user = new FakeUser(1, '[email protected]', new FakeTag(1, 'tag'));
183
184
        $formats = new FormatContainer();
185
        $formats->add('array', new ArrayFormat());
186
        $normalizers = new FallbackNormalizerContainer();
187
        $hydrators = new FallbackHydratorContainer();
188
        $serializard = new Serializard($formats, $normalizers, $hydrators);
189
190
        $normalizers->add($userClass.'ParentParent', function(FakeUserParentParent $user) { return 'ancestor'; });
0 ignored issues
show
Unused Code introduced by
The parameter $user is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
191
        $this->assertSame('ancestor', $serializard->serialize($user, 'array'));
192
193
        $normalizers->add($userClass.'Parent', function(FakeUserParent $user) { return 'parent'; });
0 ignored issues
show
Unused Code introduced by
The parameter $user is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
194
        $this->assertSame('parent', $serializard->serialize($user, 'array'));
195
196
        $normalizers->add($userClass, function(FakeUser $user) { return 'user'; });
0 ignored issues
show
Unused Code introduced by
The parameter $user is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
197
        $this->assertSame('user', $serializard->serialize($user, 'array'));
198
    }
199
200
    public function testContext()
201
    {
202
        $userClass = 'Thunder\Serializard\Tests\Fake\FakeUser';
203
        $articleClass = 'Thunder\Serializard\Tests\Fake\FakeArticle';
204
        $tagClass = 'Thunder\Serializard\Tests\Fake\FakeTag';
205
206
        $formats = new FormatContainer();
207
        $formats->add('format', new ArrayFormat());
208
209
        $hydrators = new FallbackHydratorContainer();
210
        $normalizers = new FallbackNormalizerContainer();
211
        $normalizers->add($articleClass, function(FakeArticle $article) {
212
            return $article->getTag();
213
        });
214
        $normalizers->add($userClass, function(FakeUser $user) {
215
            return $user->getTag();
216
        });
217
        $normalizers->add($tagClass, function(FakeTag $tag, NormalizerContextInterface $context) {
218
            return get_class($context->getParent());
219
        });
220
221
        $serializard = new Serializard($formats, $normalizers, $hydrators);
222
223
        $tag = new FakeTag(1, 'name');
224
        $user = new FakeUser(1, 'name', $tag);
225
        $article = new FakeArticle(1, 'title', $user, $tag);
226
227
        $this->assertSame($userClass, $serializard->serialize($user, 'format', new FakeNormalizerContext()));
228
        $context = new FakeNormalizerContext();
229
        $this->assertSame($articleClass, $serializard->serialize($article, 'format', $context));
230
        $this->assertSame(2, $context->getLevel());
231
    }
232
233
    public function testProcessWithCallbacks()
234
    {
235
        $userClass = 'Thunder\Serializard\Tests\Fake\FakeUser';
236
        $articleClass = 'Thunder\Serializard\Tests\Fake\FakeArticle';
237
        $tagClass = 'Thunder\Serializard\Tests\Fake\FakeTag';
238
239
        $formats = new FormatContainer();
240
        $formats->add('json', new JsonFormat());
241
242
        $hydrators = new FallbackHydratorContainer();
243
        $hydrators->add($articleClass, function(array $data, FallbackHydratorContainer $hydrators) use($tagClass, $userClass) {
244
            $user = $hydrators->hydrate($userClass, $data['user']);
245
            $tag = $hydrators->hydrate($tagClass, $data['tag']);
246
247
            return new FakeArticle($data['id'], $data['title'], $user, $tag);
248
        });
249 View Code Duplication
        $hydrators->add($userClass, function(array $data, FallbackHydratorContainer $hydrators) use($tagClass) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
250
            $tag = $hydrators->hydrate($tagClass, $data['tag']);
251
252
            $user = new FakeUser($data['id'], $data['name'], $tag);
253
            foreach($data['tags'] as $tagData) {
254
                $user->addTag(call_user_func($hydrators->getHandler($tagClass), $tagData, $hydrators));
255
            }
256
257
            return $user;
258
        });
259
        $hydrators->add($tagClass, function(array $data, HydratorContainerInterface $hydrators) {
0 ignored issues
show
Unused Code introduced by
The parameter $hydrators is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
260
            return new FakeTag($data['id'], $data['name']);
261
        });
262
263
        $normalizers = new FallbackNormalizerContainer();
264
        $normalizers->add($articleClass, function(FakeArticle $article, NormalizerContextInterface $context) {
0 ignored issues
show
Unused Code introduced by
The parameter $context is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
265
            return array(
266
                'id' => $article->getId(),
267
                'title' => $article->getTitle(),
268
                'user' => $article->getUser(),
269
                'tag' => $article->getTag(),
270
            );
271
        });
272
        $normalizers->add($userClass, function(FakeUser $user, NormalizerContextInterface $context) {
0 ignored issues
show
Unused Code introduced by
The parameter $context is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
273
            return array(
274
                'id' => $user->getId(),
275
                'name' => $user->getName(),
276
                'tag' => $user->getTag(),
277
                'tags' => $user->getTags(),
278
            );
279
        });
280
        $normalizers->add($tagClass, function(FakeTag $tag, NormalizerContextInterface $context) {
0 ignored issues
show
Unused Code introduced by
The parameter $context is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
281
            return array(
282
                'id' => $tag->getId(),
283
                'name' => $tag->getName(),
284
            );
285
        });
286
287
        $serializard = new Serializard($formats, $normalizers, $hydrators);
288
289
        $tag = new FakeTag(1, 'tag');
290
        $user = new FakeUser(1, 'user', $tag);
291
        $user->addTag(new FakeTag(1, 'tag'));
292
        $article = new FakeArticle(1, 'title', $user, $tag);
293
294
        $json = $serializard->serialize($article, 'json', new FakeNormalizerContext());
295
296
        $this->assertEquals($article, $serializard->unserialize($json, $articleClass, 'json'));
297
    }
298
299
    public function testProcessWithReflection()
300
    {
301
        $userClass = 'Thunder\Serializard\Tests\Fake\FakeUser';
302
        $articleClass = 'Thunder\Serializard\Tests\Fake\FakeArticle';
303
        $tagClass = 'Thunder\Serializard\Tests\Fake\FakeTag';
304
305
        $formats = new FormatContainer();
306
        $formats->add('json', new JsonFormat());
307
308
        $hydrators = new FallbackHydratorContainer();
309
        $hydrators->add($articleClass, new ReflectionHydrator($articleClass, array(
310
            'user' => $userClass,
311
            'tag' => $tagClass,
312
        )));
313
        $hydrators->add($userClass, new ReflectionHydrator($userClass, array(
314
            'tag' => $tagClass,
315
            'tags' => $tagClass.'[]',
316
        )));
317
        $hydrators->add($tagClass, new ReflectionHydrator($tagClass, array()));
318
319
        $normalizers = new FallbackNormalizerContainer();
320
        $normalizers->add($articleClass, new ReflectionNormalizer());
321
        $normalizers->add($userClass, new ReflectionNormalizer());
322
        $normalizers->add($tagClass, new ReflectionNormalizer(array('user')));
323
324
        $serializard = new Serializard($formats, $normalizers, $hydrators);
325
326
        $tag = new FakeTag(1, 'tag');
327
        $user = new FakeUser(1, 'user', $tag);
328
        $user->addTag(new FakeTag(1, 'tag'));
329
        $tags = $user->getTags();
330
        $tags[0]->clearUser();
331
        $article = new FakeArticle(1, 'title', $user, $tag);
332
333
        $json = $serializard->serialize($article, 'json', new FakeNormalizerContext());
334
335
        $this->assertEquals($article, $serializard->unserialize($json, $articleClass, 'json'));
336
    }
337
338
    public function testInvalidSerializationFormat()
339
    {
340
        $this->expectException('RuntimeException');
341
        $this->getSerializard()->serialize(new \stdClass(), 'invalid');
342
    }
343
344
    public function testInvalidUnserializationFormat()
345
    {
346
        $this->expectException('RuntimeException');
347
        $this->getSerializard()->unserialize(new \stdClass(), 'stdClass', 'invalid');
348
    }
349
350
    public function testMissingClassSerializationHandler()
351
    {
352
        $this->expectException('RuntimeException');
353
        $this->getSerializard()->serialize(new \stdClass(), 'json');
354
    }
355
}
356