Completed
Pull Request — master (#615)
by Asmir
05:17
created

testWarmUpWithDirsWithNoPaths()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
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
    public function testWarmUpWithDirs()
312
    {
313
        $container = $this->getContainerForConfig([[
314
            'metadata' => [
315
                'warmup' => [
316
                    'paths' => [
317
                        'included' => ['a'],
318
                        'excluded' => ['b']
319
                    ]
320
                ]
321
            ]
322
        ]], function ($container){
323
            $container->getDefinition('jms_serializer.cache.cache_warmer')->setPublic(true);
324
        });
325
326
        $this->assertTrue($container->hasDefinition('jms_serializer.cache.cache_warmer'));
327
328
        $def = $container->getDefinition('jms_serializer.cache.cache_warmer');
329
330
        $this->assertEquals(['a'], $def->getArgument(0));
331
        $this->assertEquals(['b'], $def->getArgument(2));
332
    }
333
334
    public function testWarmUpWithDirsWithNoPaths()
335
    {
336
        $this->getContainerForConfig([[]], function ($container) {
337
            $this->assertFalse($container->hasDefinition('jms_serializer.cache.cache_warmer'));
338
        });
339
    }
340
341
    /**
342
     * @expectedException \JMS\Serializer\Exception\RuntimeException
343
     * @expectedExceptionMessage  The metadata directory "foo_dir" does not exist for the namespace "foo_ns"
344
     */
345
    public function testLoadNotExistentMetadataDir()
346
    {
347
        $this->getContainerForConfig(array(array(
348
            'metadata' => [
349
                'directories' => [
350
                    'foo' => [
351
                        'namespace_prefix' => 'foo_ns',
352
                        'path' => 'foo_dir',
353
                    ]
354
                ]
355
            ]
356
        )));
357
    }
358
359
    /**
360
     * @dataProvider getJsonVisitorConfigs
361
     */
362
    public function testJsonVisitorOptions($expectedOptions, $config)
363
    {
364
        $container = $this->getContainerForConfig(array($config));
365
        $this->assertSame($expectedOptions, $container->get('jms_serializer.json_serialization_visitor')->getOptions());
366
    }
367
368
    public function getJsonVisitorConfigs()
369
    {
370
        $configs = array();
371
372
        if (version_compare(PHP_VERSION, '5.4', '>=')) {
373
            $configs[] = array(JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT, array(
374
                'visitors' => array(
375
                    'json' => array(
376
                        'options' => array('JSON_UNESCAPED_UNICODE', 'JSON_PRETTY_PRINT')
377
                    )
378
                )
379
            ));
380
381
            $configs[] = array(JSON_UNESCAPED_UNICODE, array(
382
                'visitors' => array(
383
                    'json' => array(
384
                        'options' => 'JSON_UNESCAPED_UNICODE'
385
                    )
386
                )
387
            ));
388
        }
389
390
        $configs[] = array(128, array(
391
            'visitors' => array(
392
                'json' => array(
393
                    'options' => 128
394
                )
395
            )
396
        ));
397
398
        $configs[] = array(0, array());
399
400
        return $configs;
401
    }
402
403
    public function testExpressionLanguage()
404
    {
405
        if (!interface_exists('Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface')) {
406
            $this->markTestSkipped("The Symfony Expression Language is not available");
407
        }
408
        $container = $this->getContainerForConfig(array(array()));
409
        $serializer = $container->get('jms_serializer');
410
        // test that all components have been wired correctly
411
        $object = new ObjectUsingExpressionLanguage('foo', true);
412
        $this->assertEquals('{"name":"foo"}', $serializer->serialize($object, 'json'));
413
        $object = new ObjectUsingExpressionLanguage('foo', false);
414
        $this->assertEquals('{}', $serializer->serialize($object, 'json'));
415
    }
416
417
    public function testExpressionLanguageVirtualProperties()
418
    {
419
        if (!interface_exists('Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface')) {
420
            $this->markTestSkipped("The Symfony Expression Language is not available");
421
        }
422
        $container = $this->getContainerForConfig(array(array()));
423
        $serializer = $container->get('jms_serializer');
424
        // test that all components have been wired correctly
425
        $object = new ObjectUsingExpressionProperties('foo');
426
        $this->assertEquals('{"v_prop_name":"foo"}', $serializer->serialize($object, 'json'));
427
    }
428
429
    /**
430
     * @expectedException \JMS\Serializer\Exception\ExpressionLanguageRequiredException
431
     */
432
    public function testExpressionLanguageDisabledVirtualProperties()
433
    {
434
        if (!interface_exists('Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface')) {
435
            $this->markTestSkipped("The Symfony Expression Language is not available");
436
        }
437
        $container = $this->getContainerForConfig(array(array('expression_evaluator' => array('id' => null))));
438
        $serializer = $container->get('jms_serializer');
439
        // test that all components have been wired correctly
440
        $object = new ObjectUsingExpressionProperties('foo');
441
        $serializer->serialize($object, 'json');
442
    }
443
444
    /**
445
     * @expectedException \JMS\Serializer\Exception\ExpressionLanguageRequiredException
446
     * @expectedExceptionMessage  To use conditional exclude/expose in JMS\SerializerBundle\Tests\DependencyInjection\Fixture\ObjectUsingExpressionLanguage you must configure the expression language.
447
     */
448
    public function testExpressionLanguageNotLoaded()
449
    {
450
        $container = $this->getContainerForConfig(array(array('expression_evaluator' => array('id' => null))));
451
        $serializer = $container->get('jms_serializer');
452
        // test that all components have been wired correctly
453
        $object = new ObjectUsingExpressionLanguage('foo', true);
454
        $serializer->serialize($object, 'json');
455
    }
456
457
    /**
458
     * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
459
     * @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
460
     */
461
    public function testExpressionInvalidEvaluator()
462
    {
463
        if (interface_exists('Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface')) {
464
            $this->markTestSkipped('To pass this test the "symfony/expression-language" component should be available');
465
        }
466
        $this->getContainerForConfig(array(array('expression_evaluator' => array('id' => 'foo'))));
467
    }
468
469
    /**
470
     * @dataProvider getXmlVisitorWhitelists
471
     */
472
    public function testXmlVisitorOptions($expectedOptions, $config)
473
    {
474
        $container = $this->getContainerForConfig(array($config));
475
        $this->assertSame($expectedOptions, $container->get('jms_serializer.xml_deserialization_visitor')->getDoctypeWhitelist());
476
    }
477
478
    public function getXmlVisitorWhitelists()
479
    {
480
        $configs = array();
481
482
        $configs[] = array(array('good document', 'other good document'), array(
483
            'visitors' => array(
484
                'xml' => array(
485
                    'doctype_whitelist' => array('good document', 'other good document'),
486
                )
487
            )
488
        ));
489
490
        $configs[] = array(array(), array());
491
492
        return $configs;
493
    }
494
495
    public function testXmlVisitorFormatOutput()
496
    {
497
        $config = array(
498
            'visitors' => array(
499
                'xml' => array(
500
                    'format_output' => false,
501
                )
502
            )
503
        );
504
        $container = $this->getContainerForConfig(array($config));
505
506
        $this->assertFalse($container->get('jms_serializer.xml_serialization_visitor')->isFormatOutput());
507
    }
508
509
    public function testXmlVisitorDefaultValueToFormatOutput()
510
    {
511
        $container = $this->getContainerForConfig(array());
512
        $this->assertTrue($container->get('jms_serializer.xml_serialization_visitor')->isFormatOutput());
513
    }
514
515
    private function getContainerForConfig(array $configs, callable $configurator = null)
516
    {
517
        $bundle = new JMSSerializerBundle();
518
        $extension = $bundle->getContainerExtension();
519
520
        $container = new ContainerBuilder();
521
        $container->setParameter('kernel.debug', true);
522
        $container->setParameter('kernel.cache_dir', sys_get_temp_dir() . '/serializer');
523
        $container->setParameter('kernel.bundles', array());
524
        $container->set('annotation_reader', new AnnotationReader());
525
        $container->setDefinition('doctrine', new Definition(Registry::class));
526
        $container->set('translator', $this->getMockBuilder('Symfony\\Component\\Translation\\TranslatorInterface')->getMock());
527
        $container->set('debug.stopwatch', $this->getMockBuilder('Symfony\\Component\\Stopwatch\\Stopwatch')->getMock());
528
        $container->registerExtension($extension);
0 ignored issues
show
Bug introduced by
It seems like $extension defined by $bundle->getContainerExtension() on line 518 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...
529
        $extension->load($configs, $container);
530
531
        $bundle->build($container);
532
533
        if ($configurator) {
534
            call_user_func($configurator, $container);
535
        }
536
537
        $container->compile();
538
539
        return $container;
540
    }
541
}
542