Completed
Pull Request — master (#556)
by Evgenij
02:53
created

getJsonVisitorConfigs()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 34
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 34
rs 8.8571
cc 2
eloc 17
nc 2
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 JMS\Serializer\SerializationContext;
22
use JMS\SerializerBundle\Tests\DependencyInjection\Fixture\ObjectUsingExpressionLanguage;
23
use JMS\SerializerBundle\Tests\DependencyInjection\Fixture\ObjectUsingExpressionProperties;
24
use Doctrine\Common\Annotations\AnnotationReader;
25
use JMS\SerializerBundle\JMSSerializerBundle;
26
use JMS\SerializerBundle\Tests\DependencyInjection\Fixture\SimpleObject;
27
use JMS\SerializerBundle\Tests\DependencyInjection\Fixture\VersionedObject;
28
use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionTemplatesPass;
29
use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass;
30
use Symfony\Component\DependencyInjection\ContainerBuilder;
31
use Symfony\Component\DependencyInjection\Definition;
32
use Symfony\Component\HttpKernel\KernelInterface;
33
34
class JMSSerializerExtensionTest extends \PHPUnit_Framework_TestCase
35
{
36
    protected function setUp()
37
    {
38
        $this->clearTempDir();
39
    }
40
41
    protected function tearDown()
42
    {
43
        $this->clearTempDir();
44
    }
45
46
    private function clearTempDir()
47
    {
48
        // clear temporary directory
49
        $dir = sys_get_temp_dir().'/serializer';
50
        if (is_dir($dir)) {
51
            foreach (new \RecursiveDirectoryIterator($dir) as $file) {
52
                $filename = $file->getFileName();
53
                if ('.' === $filename || '..' === $filename) {
54
                    continue;
55
                }
56
57
                @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...
58
            }
59
60
            @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...
61
        }
62
    }
63
64
    public function testHasContextFactories()
65
    {
66
        $container = $this->getContainerForConfig(array(array()));
67
68
        $factory = $container->get('jms_serializer.configured_serialization_context_factory');
69
        $this->assertInstanceOf('JMS\Serializer\ContextFactory\SerializationContextFactoryInterface', $factory);
70
71
        $factory = $container->get('jms_serializer.configured_deserialization_context_factory');
72
        $this->assertInstanceOf('JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface', $factory);
73
    }
74
75
    public function testSerializerContextFactoriesAreSet()
76
    {
77
        $container = $this->getContainerForConfig(array(array()));
78
79
        $def = $container->getDefinition('jms_serializer.serializer');
80
        $calls = $def->getMethodCalls();
81
82
        $this->assertCount(2, $calls);
83
84
        $serializationCall = $calls[0];
85
        $this->assertEquals('setSerializationContextFactory', $serializationCall[0]);
86
        $this->assertEquals('jms_serializer.serialization_context_factory', (string)$serializationCall[1][0]);
87
88
        $serializationCall = $calls[1];
89
        $this->assertEquals('setDeserializationContextFactory', $serializationCall[0]);
90
        $this->assertEquals('jms_serializer.deserialization_context_factory', (string)$serializationCall[1][0]);
91
92
        $this->assertEquals('jms_serializer.configured_deserialization_context_factory', (string)$container->getAlias('jms_serializer.deserialization_context_factory'));
93
        $this->assertEquals('jms_serializer.configured_serialization_context_factory', (string)$container->getAlias('jms_serializer.serialization_context_factory'));
94
    }
95
96
    public function testSerializerContextFactoriesWithId()
97
    {
98
        $config = array(
99
            'default_context' => array(
100
                'serialization' => array(
101
                    'id' => 'foo'
102
                ),
103
                'deserialization' => array(
104
                    'id' => 'bar'
105
                )
106
            )
107
        );
108
109
        $container = $this->getContainerForConfig(array($config));
110
111
        $def = $container->getDefinition('jms_serializer.serializer');
112
        $calls = $def->getMethodCalls();
113
114
        $this->assertCount(2, $calls);
115
116
        $serializationCall = $calls[0];
117
        $this->assertEquals('setSerializationContextFactory', $serializationCall[0]);
118
        $this->assertEquals('jms_serializer.serialization_context_factory', (string)$serializationCall[1][0]);
119
120
        $serializationCall = $calls[1];
121
        $this->assertEquals('setDeserializationContextFactory', $serializationCall[0]);
122
        $this->assertEquals('jms_serializer.deserialization_context_factory', (string)$serializationCall[1][0]);
123
124
        $this->assertEquals('bar', (string)$container->getAlias('jms_serializer.deserialization_context_factory'));
125
        $this->assertEquals('foo', (string)$container->getAlias('jms_serializer.serialization_context_factory'));
126
    }
127
128
    public function testConfiguringContextFactories()
129
    {
130
        $container = $this->getContainerForConfig(array(array()));
131
132
        $def = $container->getDefinition('jms_serializer.configured_serialization_context_factory');
133
        $this->assertCount(0, $def->getMethodCalls());
134
135
        $def = $container->getDefinition('jms_serializer.configured_deserialization_context_factory');
136
        $this->assertCount(0, $def->getMethodCalls());
137
    }
138
139
    public function testConfiguringContextFactoriesWithParams()
140
    {
141
        $config = array(
142
            'default_context' => array(
143
                'serialization' => array(
144
                    'version' => 1600,
145
                    'serialize_null' => true,
146
                    'attributes' => array('x' => 1720),
147
                    'groups' => array('Default', 'Registration')
148
                ),
149
                'deserialization' => array(
150
                    'version' => 1640,
151
                    'serialize_null' => false,
152
                    'attributes' => array('x' => 1740),
153
                    'groups' => array('Default', 'Profile')
154
                )
155
            )
156
        );
157
158
        $container = $this->getContainerForConfig(array($config));
159
        $services  = [
160
            'serialization' => 'jms_serializer.configured_serialization_context_factory',
161
            'deserialization' => 'jms_serializer.configured_deserialization_context_factory',
162
        ];
163
        foreach ($services as $configKey => $serviceId) {
164
            $def    = $container->getDefinition($serviceId);
165
            $values = $config['default_context'][$configKey];
166
167
            $this->assertEquals($values['version'], $this->getDefinitionMethodCall($def, 'setVersion')[0]);
168
            $this->assertEquals($values['serialize_null'], $this->getDefinitionMethodCall($def, 'setSerializeNulls')[0]);
169
            $this->assertEquals($values['attributes'], $this->getDefinitionMethodCall($def, 'setAttributes')[0]);
170
            $this->assertEquals($values['groups'], $this->getDefinitionMethodCall($def, 'setGroups')[0]);
171
        }
172
    }
173
174
    public function testConfiguringContextFactoriesWithNullDefaults()
175
    {
176
        $config = array(
177
            'default_context' => array(
178
                'serialization' => array(
179
                    'version' => null,
180
                    'serialize_null' => null,
181
                    'attributes' => [],
182
                    'groups' => null,
183
                ),
184
                'deserialization' => array(
185
                    'version' => null,
186
                    'serialize_null' => null,
187
                    'attributes' => null,
188
                    'groups' => null,
189
                )
190
            )
191
        );
192
193
        $container = $this->getContainerForConfig(array($config));
194
        $services = [
195
            'serialization' => 'jms_serializer.configured_serialization_context_factory',
196
            'deserialization' => 'jms_serializer.configured_deserialization_context_factory',
197
        ];
198
        foreach ($services as $configKey => $serviceId) {
199
            $def = $container->getDefinition($serviceId);
200
            $this->assertCount(0, $def->getMethodCalls());
201
        }
202
    }
203
204
    private function getDefinitionMethodCall(Definition $def, $method)
205
    {
206
        foreach ($def->getMethodCalls() as $call) {
207
            if ($call[0] === $method) {
208
                return $call[1];
209
            }
210
        }
211
        return false;
212
    }
213
214
    public function testLoad()
215
    {
216
        $container = $this->getContainerForConfig(array(array()));
217
218
        $simpleObject = new SimpleObject('foo', 'bar');
219
        $versionedObject  = new VersionedObject('foo', 'bar');
220
        $serializer = $container->get('serializer');
221
222
        // test that all components have been wired correctly
223
        $this->assertEquals(json_encode(array('name' => 'bar')), $serializer->serialize($versionedObject, 'json'));
224
        $this->assertEquals($simpleObject, $serializer->deserialize($serializer->serialize($simpleObject, 'json'), get_class($simpleObject), 'json'));
225
        $this->assertEquals($simpleObject, $serializer->deserialize($serializer->serialize($simpleObject, 'xml'), get_class($simpleObject), 'xml'));
226
227
        $this->assertEquals(json_encode(array('name' => 'foo')), $serializer->serialize($versionedObject, 'json', SerializationContext::create()->setVersion('0.0.1')));
228
229
        $this->assertEquals(json_encode(array('name' => 'bar')), $serializer->serialize($versionedObject, 'json', SerializationContext::create()->setVersion('1.1.1')));
230
    }
231
232
    /**
233
     * @dataProvider getJsonVisitorConfigs
234
     */
235
    public function testJsonVisitorOptions($expectedOptions, $config)
236
    {
237
        $container = $this->getContainerForConfig(array($config));
238
        $this->assertSame($expectedOptions, $container->get('jms_serializer.json_serialization_visitor')->getOptions());
239
    }
240
241
    public function getJsonVisitorConfigs()
242
    {
243
        $configs = array();
244
245
        if (version_compare(PHP_VERSION, '5.4', '>=')) {
246
            $configs[] = array(JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT, array(
247
                'visitors' => array(
248
                    'json' => array(
249
                        'options' => array('JSON_UNESCAPED_UNICODE', 'JSON_PRETTY_PRINT')
250
                    )
251
                )
252
            ));
253
254
            $configs[] = array(JSON_UNESCAPED_UNICODE, array(
255
                'visitors' => array(
256
                    'json' => array(
257
                        'options' => 'JSON_UNESCAPED_UNICODE'
258
                    )
259
                )
260
            ));
261
        }
262
263
        $configs[] = array(128, array(
264
            'visitors' => array(
265
                'json' => array(
266
                    'options' => 128
267
                )
268
            )
269
        ));
270
271
        $configs[] = array(0, array());
272
273
        return $configs;
274
    }
275
276
    public function testExpressionLanguage()
277
    {
278
        if (!interface_exists('Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface')) {
279
            $this->markTestSkipped("The Symfony Expression Language is not available");
280
        }
281
        $container = $this->getContainerForConfig(array(array()));
282
        $serializer = $container->get('serializer');
283
        // test that all components have been wired correctly
284
        $object = new ObjectUsingExpressionLanguage('foo', true);
285
        $this->assertEquals('{"name":"foo"}', $serializer->serialize($object, 'json'));
286
        $object = new ObjectUsingExpressionLanguage('foo', false);
287
        $this->assertEquals('{}', $serializer->serialize($object, 'json'));
288
    }
289
290
    public function testExpressionLanguageVirtualProperties()
291
    {
292
        if (!interface_exists('Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface')) {
293
            $this->markTestSkipped("The Symfony Expression Language is not available");
294
        }
295
        $container = $this->getContainerForConfig(array(array()));
296
        $serializer = $container->get('serializer');
297
        // test that all components have been wired correctly
298
        $object = new ObjectUsingExpressionProperties('foo');
299
        $this->assertEquals('{"v_prop_name":"foo"}', $serializer->serialize($object, 'json'));
300
    }
301
302
    /**
303
     * @expectedException \JMS\Serializer\Exception\ExpressionLanguageRequiredException
304
     */
305
    public function testExpressionLanguageDisabledVirtualProperties()
306
    {
307
        if (!interface_exists('Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface')) {
308
            $this->markTestSkipped("The Symfony Expression Language is not available");
309
        }
310
        $container = $this->getContainerForConfig(array(array('expression_evaluator' => array('id' => null))));
311
        $serializer = $container->get('serializer');
312
        // test that all components have been wired correctly
313
        $object = new ObjectUsingExpressionProperties('foo');
314
        $serializer->serialize($object, 'json');
315
    }
316
317
    /**
318
     * @expectedException \JMS\Serializer\Exception\ExpressionLanguageRequiredException
319
     * @expectedExceptionMessage  To use conditional exclude/expose in JMS\SerializerBundle\Tests\DependencyInjection\Fixture\ObjectUsingExpressionLanguage you must configure the expression language.
320
     */
321
    public function testExpressionLanguageNotLoaded()
322
    {
323
        $container = $this->getContainerForConfig(array(array('expression_evaluator' => array('id' => null))));
324
        $serializer = $container->get('serializer');
325
        // test that all components have been wired correctly
326
        $object = new ObjectUsingExpressionLanguage('foo', true);
327
        $serializer->serialize($object, 'json');
328
    }
329
330
    /**
331
     * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
332
     * @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
333
     */
334
    public function testExpressionInvalidEvaluator()
335
    {
336
        if (is_dir(__DIR__ . '/../../vendor/symfony/expression-language')) {
337
            $this->markTestSkipped('To pass this test the "symfony/expression-language" component should be removed');
338
        }
339
        $this->getContainerForConfig(array(array('expression_evaluator' => array('id' => 'foo'))));
340
    }
341
342
    /**
343
     * @dataProvider getXmlVisitorWhitelists
344
     */
345
    public function testXmlVisitorOptions($expectedOptions, $config)
346
    {
347
        $container = $this->getContainerForConfig(array($config));
348
        $this->assertSame($expectedOptions, $container->get('jms_serializer.xml_deserialization_visitor')->getDoctypeWhitelist());
349
    }
350
351
    public function getXmlVisitorWhitelists()
352
    {
353
        $configs = array();
354
355
        $configs[] = array(array('good document', 'other good document'), array(
356
            'visitors' => array(
357
                'xml' => array(
358
                    'doctype_whitelist' => array('good document', 'other good document'),
359
                )
360
            )
361
        ));
362
363
        $configs[] = array(array(), array());
364
365
        return $configs;
366
    }
367
368
    public function testXmlVisitorFormatOutput()
369
    {
370
        $config = array(
371
            'visitors' => array(
372
                'xml' => array(
373
                    'format_output' => false,
374
                )
375
            )
376
        );
377
        $container = $this->getContainerForConfig(array($config));
378
379
        $this->assertFalse($container->get('jms_serializer.xml_serialization_visitor')->isFormatOutput());
380
    }
381
382
    public function testXmlVisitorDefaultValueToFormatOutput()
383
    {
384
        $container = $this->getContainerForConfig(array());
385
        $this->assertTrue($container->get('jms_serializer.xml_serialization_visitor')->isFormatOutput());
386
    }
387
388
    private function getContainerForConfig(array $configs, KernelInterface $kernel = null)
389
    {
390
        if (null === $kernel) {
391
            $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\KernelInterface')->getMock();
392
            $kernel
393
                ->expects($this->any())
394
                ->method('getBundles')
395
                ->will($this->returnValue(array()))
396
            ;
397
        }
398
399
        $bundle = new JMSSerializerBundle($kernel);
0 ignored issues
show
Unused Code introduced by
The call to JMSSerializerBundle::__construct() has too many arguments starting with $kernel.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
400
        $extension = $bundle->getContainerExtension();
401
402
        $container = new ContainerBuilder();
403
        $container->setParameter('kernel.debug', true);
404
        $container->setParameter('kernel.cache_dir', sys_get_temp_dir().'/serializer');
405
        $container->setParameter('kernel.bundles', array());
406
        $container->set('annotation_reader', new AnnotationReader());
407
        $container->set('translator', $this->getMockBuilder('Symfony\\Component\\Translation\\TranslatorInterface')->getMock());
408
        $container->set('debug.stopwatch', $this->getMockBuilder('Symfony\\Component\\Stopwatch\\Stopwatch')->getMock());
409
        $container->registerExtension($extension);
0 ignored issues
show
Bug introduced by
It seems like $extension defined by $bundle->getContainerExtension() on line 400 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...
410
        $extension->load($configs, $container);
411
412
        $bundle->build($container);
413
414
        $container->getCompilerPassConfig()->setOptimizationPasses(array(
415
            new ResolveParameterPlaceHoldersPass(),
416
            new ResolveDefinitionTemplatesPass(),
417
        ));
418
        $container->getCompilerPassConfig()->setRemovingPasses(array());
419
        $container->compile();
420
421
        return $container;
422
    }
423
}
424