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

testLoadWithoutTranslator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 0
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());
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
56
            }
57
58
            @rmdir($dir);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
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
Documentation introduced by
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);
0 ignored issues
show
Bug introduced by
It seems like $extension defined by $bundle->getContainerExtension() on line 488 can be null; however, Symfony\Component\Depend...er::registerExtension() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
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