Completed
Push — master ( a61272...cb5e47 )
by Asmir
03:28
created

DependencyInjection/JMSSerializerExtensionTest.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * Copyright 2011 Johannes M. Schmitt <[email protected]>
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace JMS\SerializerBundle\Tests\DependencyInjection;
20
21
use Doctrine\Common\Annotations\AnnotationReader;
22
use JMS\Serializer\SerializationContext;
23
use JMS\SerializerBundle\JMSSerializerBundle;
24
use JMS\SerializerBundle\Tests\DependencyInjection\Fixture\ObjectUsingExpressionLanguage;
25
use JMS\SerializerBundle\Tests\DependencyInjection\Fixture\ObjectUsingExpressionProperties;
26
use JMS\SerializerBundle\Tests\DependencyInjection\Fixture\SimpleObject;
27
use JMS\SerializerBundle\Tests\DependencyInjection\Fixture\VersionedObject;
28
use PHPUnit\Framework\TestCase;
29
use Symfony\Component\DependencyInjection\ContainerBuilder;
30
use Symfony\Component\DependencyInjection\Definition;
31
32
class JMSSerializerExtensionTest extends TestCase
33
{
34
    protected function setUp()
35
    {
36
        $this->clearTempDir();
37
    }
38
39
    protected function tearDown()
40
    {
41
        $this->clearTempDir();
42
    }
43
44
    private function clearTempDir()
45
    {
46
        // clear temporary directory
47
        $dir = sys_get_temp_dir() . '/serializer';
48
        if (is_dir($dir)) {
49
            foreach (new \RecursiveDirectoryIterator($dir) as $file) {
50
                $filename = $file->getFileName();
51
                if ('.' === $filename || '..' === $filename) {
52
                    continue;
53
                }
54
55
                @unlink($file->getPathName());
56
            }
57
58
            @rmdir($dir);
59
        }
60
    }
61
62
    public function testHasContextFactories()
63
    {
64
        $container = $this->getContainerForConfig(array(array()));
65
66
        $factory = $container->get('jms_serializer.serialization_context_factory');
67
        $this->assertInstanceOf('JMS\Serializer\ContextFactory\SerializationContextFactoryInterface', $factory);
68
69
        $factory = $container->get('jms_serializer.deserialization_context_factory');
70
        $this->assertInstanceOf('JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface', $factory);
71
    }
72
73
    public function testSerializerContextFactoriesAreSet()
74
    {
75
        $container = $this->getContainerForConfig(array(array()));
76
77
        $def = $container->getDefinition('jms_serializer');
78
        $calls = $def->getMethodCalls();
79
80
        $this->assertCount(2, $calls);
81
82
        $serializationCall = $calls[0];
83
        $this->assertEquals('setSerializationContextFactory', $serializationCall[0]);
84
        $this->assertEquals('jms_serializer.serialization_context_factory', (string)$serializationCall[1][0]);
85
86
        $serializationCall = $calls[1];
87
        $this->assertEquals('setDeserializationContextFactory', $serializationCall[0]);
88
        $this->assertEquals('jms_serializer.deserialization_context_factory', (string)$serializationCall[1][0]);
89
    }
90
91
    public function testSerializerContextFactoriesWithId()
92
    {
93
        $config = array(
94
            'default_context' => array(
95
                'serialization' => array(
96
                    'id' => 'foo'
97
                ),
98
                'deserialization' => array(
99
                    'id' => 'bar'
100
                )
101
            )
102
        );
103
104
        $container = $this->getContainerForConfig(array($config), function(ContainerBuilder $containerBuilder){
105
            $containerBuilder->setDefinition('foo', new Definition('stdClass'));
106
            $containerBuilder->setDefinition('bar', new Definition('stdClass'));
107
        });
108
109
        $def = $container->getDefinition('jms_serializer');
110
        $calls = $def->getMethodCalls();
111
112
        $this->assertCount(2, $calls);
113
114
        $serializationCall = $calls[0];
115
        $this->assertEquals('setSerializationContextFactory', $serializationCall[0]);
116
        $this->assertEquals('foo', (string)$serializationCall[1][0]);
117
118
        $serializationCall = $calls[1];
119
        $this->assertEquals('setDeserializationContextFactory', $serializationCall[0]);
120
        $this->assertEquals('bar', (string)$serializationCall[1][0]);
121
122
        $this->assertEquals('bar', (string)$container->getAlias('jms_serializer.deserialization_context_factory'));
123
        $this->assertEquals('foo', (string)$container->getAlias('jms_serializer.serialization_context_factory'));
124
    }
125
126
    public function testLoadWithoutTranslator()
127
    {
128
        $container = $this->getContainerForConfig(array(array()), function(ContainerBuilder $containerBuilder){
129
            $containerBuilder->set('translator', null);
0 ignored issues
show
null is of type null, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
130
        });
131
132
        $def = $container->getDefinition('jms_serializer.form_error_handler');
133
        $this->assertSame(null, $def->getArgument(0));
134
    }
135
136
    public function testConfiguringContextFactories()
137
    {
138
        $container = $this->getContainerForConfig(array(array()));
139
140
        $def = $container->getDefinition('jms_serializer.serialization_context_factory');
141
        $this->assertCount(0, $def->getMethodCalls());
142
143
        $def = $container->getDefinition('jms_serializer.deserialization_context_factory');
144
        $this->assertCount(0, $def->getMethodCalls());
145
    }
146
147
    public function testConfiguringContextFactoriesWithParams()
148
    {
149
        $config = array(
150
            'default_context' => array(
151
                'serialization' => array(
152
                    'version' => 1600,
153
                    'serialize_null' => true,
154
                    'attributes' => array('x' => 1720),
155
                    'groups' => array('Default', 'Registration'),
156
                    'enable_max_depth_checks' => true,
157
                ),
158
                'deserialization' => array(
159
                    'version' => 1640,
160
                    'serialize_null' => false,
161
                    'attributes' => array('x' => 1740),
162
                    'groups' => array('Default', 'Profile'),
163
                    'enable_max_depth_checks' => true,
164
                )
165
            )
166
        );
167
168
        $container = $this->getContainerForConfig(array($config));
169
        $services = [
170
            'serialization' => 'jms_serializer.serialization_context_factory',
171
            'deserialization' => 'jms_serializer.deserialization_context_factory',
172
        ];
173
        foreach ($services as $configKey => $serviceId) {
174
            $def = $container->getDefinition($serviceId);
175
            $values = $config['default_context'][$configKey];
176
177
            $this->assertSame($values['version'], $this->getDefinitionMethodCall($def, 'setVersion')[0]);
178
            $this->assertSame($values['serialize_null'], $this->getDefinitionMethodCall($def, 'setSerializeNulls')[0]);
179
            $this->assertSame($values['attributes'], $this->getDefinitionMethodCall($def, 'setAttributes')[0]);
180
            $this->assertSame($values['groups'], $this->getDefinitionMethodCall($def, 'setGroups')[0]);
181
            $this->assertSame($values['groups'], $this->getDefinitionMethodCall($def, 'setGroups')[0]);
182
            $this->assertSame(array(), $this->getDefinitionMethodCall($def, 'enableMaxDepthChecks'));
183
        }
184
    }
185
186
    public function testConfiguringContextFactoriesWithNullDefaults()
187
    {
188
        $config = array(
189
            'default_context' => array(
190
                'serialization' => array(
191
                    'version' => null,
192
                    'serialize_null' => null,
193
                    'attributes' => [],
194
                    'groups' => null,
195
                ),
196
                'deserialization' => array(
197
                    'version' => null,
198
                    'serialize_null' => null,
199
                    'attributes' => null,
200
                    'groups' => null,
201
                )
202
            )
203
        );
204
205
        $container = $this->getContainerForConfig(array($config));
206
        $services = [
207
            'serialization' => 'jms_serializer.serialization_context_factory',
208
            'deserialization' => 'jms_serializer.deserialization_context_factory',
209
        ];
210
        foreach ($services as $configKey => $serviceId) {
211
            $def = $container->getDefinition($serviceId);
212
            $this->assertCount(0, $def->getMethodCalls());
213
        }
214
    }
215
216
    private function getDefinitionMethodCall(Definition $def, $method)
217
    {
218
        foreach ($def->getMethodCalls() as $call) {
219
            if ($call[0] === $method) {
220
                return $call[1];
221
            }
222
        }
223
        return false;
224
    }
225
226
    public function testLoad()
227
    {
228
        $container = $this->getContainerForConfig(array(array()), function(ContainerBuilder $container) {
229
            $container->getDefinition('jms_serializer.doctrine_object_constructor')->setPublic(true);
230
            $container->getAlias('JMS\Serializer\SerializerInterface')->setPublic(true);
231
            $container->getAlias('JMS\Serializer\ArrayTransformerInterface')->setPublic(true);
232
        });
233
234
        $simpleObject = new SimpleObject('foo', 'bar');
235
        $versionedObject = new VersionedObject('foo', 'bar');
236
        $serializer = $container->get('jms_serializer');
237
238
        $this->assertTrue($container->has('JMS\Serializer\SerializerInterface'), 'Alias should be defined to allow autowiring');
239
        $this->assertTrue($container->has('JMS\Serializer\ArrayTransformerInterface'), 'Alias should be defined to allow autowiring');
240
241
        $this->assertFalse($container->getDefinition('jms_serializer.array_collection_handler')->getArgument(0));
242
243
        // the logic is inverted because arg 0 on doctrine_proxy_subscriber is $skipVirtualTypeInit = false
244
        $this->assertTrue($container->getDefinition('jms_serializer.doctrine_proxy_subscriber')->getArgument(0));
245
        $this->assertFalse($container->getDefinition('jms_serializer.doctrine_proxy_subscriber')->getArgument(1));
246
247
        $this->assertEquals("null", $container->getDefinition('jms_serializer.doctrine_object_constructor')->getArgument(2));
248
249
        // test that all components have been wired correctly
250
        $this->assertEquals(json_encode(array('name' => 'bar')), $serializer->serialize($versionedObject, 'json'));
251
        $this->assertEquals($simpleObject, $serializer->deserialize($serializer->serialize($simpleObject, 'json'), get_class($simpleObject), 'json'));
252
        $this->assertEquals($simpleObject, $serializer->deserialize($serializer->serialize($simpleObject, 'xml'), get_class($simpleObject), 'xml'));
253
254
        $this->assertEquals(json_encode(array('name' => 'foo')), $serializer->serialize($versionedObject, 'json', SerializationContext::create()->setVersion('0.0.1')));
255
256
        $this->assertEquals(json_encode(array('name' => 'bar')), $serializer->serialize($versionedObject, 'json', SerializationContext::create()->setVersion('1.1.1')));
257
    }
258
259
    public function testLoadWithOptions()
260
    {
261
        $container = $this->getContainerForConfig(array(array(
262
            'subscribers' => [
263
                'doctrine_proxy' => [
264
                    'initialize_virtual_types' => true,
265
                    'initialize_excluded' => true,
266
                ],
267
            ],
268
            'object_constructors' => [
269
                'doctrine' => [
270
                    'fallback_strategy' => "exception",
271
                ],
272
            ],
273
            'handlers' => [
274
                'array_collection' => [
275
                    'initialize_excluded' => true,
276
                ],
277
            ],
278
        )), function($container){
279
            $container->getDefinition('jms_serializer.doctrine_object_constructor')->setPublic(true);
280
        });
281
282
        $this->assertTrue($container->getDefinition('jms_serializer.array_collection_handler')->getArgument(0));
283
284
        // the logic is inverted because arg 0 on doctrine_proxy_subscriber is $skipVirtualTypeInit = false
285
        $this->assertFalse($container->getDefinition('jms_serializer.doctrine_proxy_subscriber')->getArgument(0));
286
        $this->assertTrue($container->getDefinition('jms_serializer.doctrine_proxy_subscriber')->getArgument(1));
287
288
        $this->assertEquals("exception", $container->getDefinition('jms_serializer.doctrine_object_constructor')->getArgument(2));
289
    }
290
291
    public function testLoadExistentMetadataDir()
292
    {
293
        $container = $this->getContainerForConfig(array(array(
294
            'metadata' => [
295
                'directories' => [
296
                    'foo' => [
297
                        'namespace_prefix' => 'foo_ns',
298
                        'path' => __DIR__,
299
                    ]
300
                ]
301
            ]
302
        )), function ($container){
303
            $container->getDefinition('jms_serializer.metadata.file_locator')->setPublic(true);
304
        });
305
306
        $fileLocatorDef = $container->getDefinition('jms_serializer.metadata.file_locator');
307
        $directories = $fileLocatorDef->getArgument(0);
308
        $this->assertEquals(['foo_ns' => __DIR__], $directories);
309
    }
310
311
    /**
312
     * @expectedException \JMS\Serializer\Exception\RuntimeException
313
     * @expectedExceptionMessage  The metadata directory "foo_dir" does not exist for the namespace "foo_ns"
314
     */
315
    public function testLoadNotExistentMetadataDir()
316
    {
317
        $this->getContainerForConfig(array(array(
318
            'metadata' => [
319
                'directories' => [
320
                    'foo' => [
321
                        'namespace_prefix' => 'foo_ns',
322
                        'path' => 'foo_dir',
323
                    ]
324
                ]
325
            ]
326
        )));
327
    }
328
329
    /**
330
     * @dataProvider getJsonVisitorConfigs
331
     */
332
    public function testJsonVisitorOptions($expectedOptions, $config)
333
    {
334
        $container = $this->getContainerForConfig(array($config));
335
        $this->assertSame($expectedOptions, $container->get('jms_serializer.json_serialization_visitor')->getOptions());
336
    }
337
338
    public function getJsonVisitorConfigs()
339
    {
340
        $configs = array();
341
342
        if (version_compare(PHP_VERSION, '5.4', '>=')) {
343
            $configs[] = array(JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT, array(
344
                'visitors' => array(
345
                    'json' => array(
346
                        'options' => array('JSON_UNESCAPED_UNICODE', 'JSON_PRETTY_PRINT')
347
                    )
348
                )
349
            ));
350
351
            $configs[] = array(JSON_UNESCAPED_UNICODE, array(
352
                'visitors' => array(
353
                    'json' => array(
354
                        'options' => 'JSON_UNESCAPED_UNICODE'
355
                    )
356
                )
357
            ));
358
        }
359
360
        $configs[] = array(128, array(
361
            'visitors' => array(
362
                'json' => array(
363
                    'options' => 128
364
                )
365
            )
366
        ));
367
368
        $configs[] = array(0, array());
369
370
        return $configs;
371
    }
372
373
    public function testExpressionLanguage()
374
    {
375
        if (!interface_exists('Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface')) {
376
            $this->markTestSkipped("The Symfony Expression Language is not available");
377
        }
378
        $container = $this->getContainerForConfig(array(array()));
379
        $serializer = $container->get('jms_serializer');
380
        // test that all components have been wired correctly
381
        $object = new ObjectUsingExpressionLanguage('foo', true);
382
        $this->assertEquals('{"name":"foo"}', $serializer->serialize($object, 'json'));
383
        $object = new ObjectUsingExpressionLanguage('foo', false);
384
        $this->assertEquals('{}', $serializer->serialize($object, 'json'));
385
    }
386
387
    public function testExpressionLanguageVirtualProperties()
388
    {
389
        if (!interface_exists('Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface')) {
390
            $this->markTestSkipped("The Symfony Expression Language is not available");
391
        }
392
        $container = $this->getContainerForConfig(array(array()));
393
        $serializer = $container->get('jms_serializer');
394
        // test that all components have been wired correctly
395
        $object = new ObjectUsingExpressionProperties('foo');
396
        $this->assertEquals('{"v_prop_name":"foo"}', $serializer->serialize($object, 'json'));
397
    }
398
399
    /**
400
     * @expectedException \JMS\Serializer\Exception\ExpressionLanguageRequiredException
401
     */
402
    public function testExpressionLanguageDisabledVirtualProperties()
403
    {
404
        if (!interface_exists('Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface')) {
405
            $this->markTestSkipped("The Symfony Expression Language is not available");
406
        }
407
        $container = $this->getContainerForConfig(array(array('expression_evaluator' => array('id' => null))));
408
        $serializer = $container->get('jms_serializer');
409
        // test that all components have been wired correctly
410
        $object = new ObjectUsingExpressionProperties('foo');
411
        $serializer->serialize($object, 'json');
412
    }
413
414
    /**
415
     * @expectedException \JMS\Serializer\Exception\ExpressionLanguageRequiredException
416
     * @expectedExceptionMessage  To use conditional exclude/expose in JMS\SerializerBundle\Tests\DependencyInjection\Fixture\ObjectUsingExpressionLanguage you must configure the expression language.
417
     */
418
    public function testExpressionLanguageNotLoaded()
419
    {
420
        $container = $this->getContainerForConfig(array(array('expression_evaluator' => array('id' => null))));
421
        $serializer = $container->get('jms_serializer');
422
        // test that all components have been wired correctly
423
        $object = new ObjectUsingExpressionLanguage('foo', true);
424
        $serializer->serialize($object, 'json');
425
    }
426
427
    /**
428
     * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
429
     * @expectedExceptionMessage Invalid configuration for path "jms_serializer.expression_evaluator.id": You need at least symfony/expression language v2.6 or v3.0 to use the expression evaluator features
430
     */
431
    public function testExpressionInvalidEvaluator()
432
    {
433
        if (interface_exists('Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface')) {
434
            $this->markTestSkipped('To pass this test the "symfony/expression-language" component should be available');
435
        }
436
        $this->getContainerForConfig(array(array('expression_evaluator' => array('id' => 'foo'))));
437
    }
438
439
    /**
440
     * @dataProvider getXmlVisitorWhitelists
441
     */
442
    public function testXmlVisitorOptions($expectedOptions, $config)
443
    {
444
        $container = $this->getContainerForConfig(array($config));
445
        $this->assertSame($expectedOptions, $container->get('jms_serializer.xml_deserialization_visitor')->getDoctypeWhitelist());
446
    }
447
448
    public function getXmlVisitorWhitelists()
449
    {
450
        $configs = array();
451
452
        $configs[] = array(array('good document', 'other good document'), array(
453
            'visitors' => array(
454
                'xml' => array(
455
                    'doctype_whitelist' => array('good document', 'other good document'),
456
                )
457
            )
458
        ));
459
460
        $configs[] = array(array(), array());
461
462
        return $configs;
463
    }
464
465
    public function testXmlVisitorFormatOutput()
466
    {
467
        $config = array(
468
            'visitors' => array(
469
                'xml' => array(
470
                    'format_output' => false,
471
                )
472
            )
473
        );
474
        $container = $this->getContainerForConfig(array($config));
475
476
        $this->assertFalse($container->get('jms_serializer.xml_serialization_visitor')->isFormatOutput());
477
    }
478
479
    public function testXmlVisitorDefaultValueToFormatOutput()
480
    {
481
        $container = $this->getContainerForConfig(array());
482
        $this->assertTrue($container->get('jms_serializer.xml_serialization_visitor')->isFormatOutput());
483
    }
484
485
    private function getContainerForConfig(array $configs, callable $configurator = null)
486
    {
487
        $bundle = new JMSSerializerBundle();
488
        $extension = $bundle->getContainerExtension();
489
490
        $container = new ContainerBuilder();
491
        $container->setParameter('kernel.debug', true);
492
        $container->setParameter('kernel.cache_dir', sys_get_temp_dir() . '/serializer');
493
        $container->setParameter('kernel.bundles', array());
494
        $container->set('annotation_reader', new AnnotationReader());
495
        $container->setDefinition('doctrine', new Definition(Registry::class));
496
        $container->set('translator', $this->getMockBuilder('Symfony\\Component\\Translation\\TranslatorInterface')->getMock());
497
        $container->set('debug.stopwatch', $this->getMockBuilder('Symfony\\Component\\Stopwatch\\Stopwatch')->getMock());
498
        $container->registerExtension($extension);
499
        $extension->load($configs, $container);
500
501
        $bundle->build($container);
502
503
        if ($configurator) {
504
            call_user_func($configurator, $container);
505
        }
506
507
        $container->compile();
508
509
        return $container;
510
    }
511
}
512