Yaffs site version 1.1
[yaffs-website] / vendor / symfony / serializer / Tests / Normalizer / ObjectNormalizerTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\Serializer\Tests\Normalizer;
13
14 use Doctrine\Common\Annotations\AnnotationReader;
15 use PHPUnit\Framework\TestCase;
16 use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
17 use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
18 use Symfony\Component\Serializer\Serializer;
19 use Symfony\Component\Serializer\SerializerInterface;
20 use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
21 use Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy;
22 use Symfony\Component\Serializer\Tests\Fixtures\SiblingHolder;
23 use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
24 use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
25 use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy;
26
27 /**
28  * @author Kévin Dunglas <dunglas@gmail.com>
29  */
30 class ObjectNormalizerTest extends TestCase
31 {
32     /**
33      * @var ObjectNormalizer
34      */
35     private $normalizer;
36     /**
37      * @var SerializerInterface
38      */
39     private $serializer;
40
41     protected function setUp()
42     {
43         $this->serializer = $this->getMockBuilder(__NAMESPACE__.'\ObjectSerializerNormalizer')->getMock();
44         $this->normalizer = new ObjectNormalizer();
45         $this->normalizer->setSerializer($this->serializer);
46     }
47
48     public function testNormalize()
49     {
50         $obj = new ObjectDummy();
51         $object = new \stdClass();
52         $obj->setFoo('foo');
53         $obj->bar = 'bar';
54         $obj->setBaz(true);
55         $obj->setCamelCase('camelcase');
56         $obj->setObject($object);
57
58         $this->serializer
59             ->expects($this->once())
60             ->method('normalize')
61             ->with($object, 'any')
62             ->will($this->returnValue('string_object'))
63         ;
64
65         $this->assertEquals(
66             array(
67                 'foo' => 'foo',
68                 'bar' => 'bar',
69                 'baz' => true,
70                 'fooBar' => 'foobar',
71                 'camelCase' => 'camelcase',
72                 'object' => 'string_object',
73             ),
74             $this->normalizer->normalize($obj, 'any')
75         );
76     }
77
78     public function testDenormalize()
79     {
80         $obj = $this->normalizer->denormalize(
81             array('foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'),
82             __NAMESPACE__.'\ObjectDummy',
83             'any'
84         );
85         $this->assertEquals('foo', $obj->getFoo());
86         $this->assertEquals('bar', $obj->bar);
87         $this->assertTrue($obj->isBaz());
88     }
89
90     public function testDenormalizeWithObject()
91     {
92         $data = new \stdClass();
93         $data->foo = 'foo';
94         $data->bar = 'bar';
95         $data->fooBar = 'foobar';
96         $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\ObjectDummy', 'any');
97         $this->assertEquals('foo', $obj->getFoo());
98         $this->assertEquals('bar', $obj->bar);
99     }
100
101     /**
102      * @group legacy
103      */
104     public function testLegacyDenormalizeOnCamelCaseFormat()
105     {
106         $this->normalizer->setCamelizedAttributes(array('camel_case'));
107         $obj = $this->normalizer->denormalize(
108             array('camel_case' => 'camelCase'),
109             __NAMESPACE__.'\ObjectDummy'
110         );
111         $this->assertEquals('camelCase', $obj->getCamelCase());
112     }
113
114     public function testNameConverterSupport()
115     {
116         $this->normalizer = new ObjectNormalizer(null, new CamelCaseToSnakeCaseNameConverter());
117         $obj = $this->normalizer->denormalize(
118             array('camel_case' => 'camelCase'),
119             __NAMESPACE__.'\ObjectDummy'
120         );
121         $this->assertEquals('camelCase', $obj->getCamelCase());
122     }
123
124     public function testDenormalizeNull()
125     {
126         $this->assertEquals(new ObjectDummy(), $this->normalizer->denormalize(null, __NAMESPACE__.'\ObjectDummy'));
127     }
128
129     public function testConstructorDenormalize()
130     {
131         $obj = $this->normalizer->denormalize(
132             array('foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'),
133             __NAMESPACE__.'\ObjectConstructorDummy', 'any');
134         $this->assertEquals('foo', $obj->getFoo());
135         $this->assertEquals('bar', $obj->bar);
136         $this->assertTrue($obj->isBaz());
137     }
138
139     public function testConstructorDenormalizeWithNullArgument()
140     {
141         $obj = $this->normalizer->denormalize(
142             array('foo' => 'foo', 'bar' => null, 'baz' => true),
143             __NAMESPACE__.'\ObjectConstructorDummy', 'any');
144         $this->assertEquals('foo', $obj->getFoo());
145         $this->assertNull($obj->bar);
146         $this->assertTrue($obj->isBaz());
147     }
148
149     public function testConstructorDenormalizeWithMissingOptionalArgument()
150     {
151         $obj = $this->normalizer->denormalize(
152             array('foo' => 'test', 'baz' => array(1, 2, 3)),
153             __NAMESPACE__.'\ObjectConstructorOptionalArgsDummy', 'any');
154         $this->assertEquals('test', $obj->getFoo());
155         $this->assertEquals(array(), $obj->bar);
156         $this->assertEquals(array(1, 2, 3), $obj->getBaz());
157     }
158
159     /**
160      * @see https://bugs.php.net/62715
161      *
162      * @requires PHP 5.3.17
163      */
164     public function testConstructorDenormalizeWithOptionalDefaultArgument()
165     {
166         $obj = $this->normalizer->denormalize(
167             array('bar' => 'test'),
168             __NAMESPACE__.'\ObjectConstructorArgsWithDefaultValueDummy', 'any');
169         $this->assertEquals(array(), $obj->getFoo());
170         $this->assertEquals('test', $obj->getBar());
171     }
172
173     public function testConstructorWithObjectDenormalize()
174     {
175         $data = new \stdClass();
176         $data->foo = 'foo';
177         $data->bar = 'bar';
178         $data->baz = true;
179         $data->fooBar = 'foobar';
180         $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\ObjectConstructorDummy', 'any');
181         $this->assertEquals('foo', $obj->getFoo());
182         $this->assertEquals('bar', $obj->bar);
183     }
184
185     public function testGroupsNormalize()
186     {
187         $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
188         $this->normalizer = new ObjectNormalizer($classMetadataFactory);
189         $this->normalizer->setSerializer($this->serializer);
190
191         $obj = new GroupDummy();
192         $obj->setFoo('foo');
193         $obj->setBar('bar');
194         $obj->setFooBar('fooBar');
195         $obj->setSymfony('symfony');
196         $obj->setKevin('kevin');
197         $obj->setCoopTilleuls('coopTilleuls');
198
199         $this->assertEquals(array(
200             'bar' => 'bar',
201         ), $this->normalizer->normalize($obj, null, array(ObjectNormalizer::GROUPS => array('c'))));
202
203         $this->assertEquals(array(
204             'symfony' => 'symfony',
205             'foo' => 'foo',
206             'fooBar' => 'fooBar',
207             'bar' => 'bar',
208             'kevin' => 'kevin',
209             'coopTilleuls' => 'coopTilleuls',
210         ), $this->normalizer->normalize($obj, null, array(ObjectNormalizer::GROUPS => array('a', 'c'))));
211     }
212
213     public function testGroupsDenormalize()
214     {
215         $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
216         $this->normalizer = new ObjectNormalizer($classMetadataFactory);
217         $this->normalizer->setSerializer($this->serializer);
218
219         $obj = new GroupDummy();
220         $obj->setFoo('foo');
221
222         $toNormalize = array('foo' => 'foo', 'bar' => 'bar');
223
224         $normalized = $this->normalizer->denormalize(
225             $toNormalize,
226             'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy',
227             null,
228             array(ObjectNormalizer::GROUPS => array('a'))
229         );
230         $this->assertEquals($obj, $normalized);
231
232         $obj->setBar('bar');
233
234         $normalized = $this->normalizer->denormalize(
235             $toNormalize,
236             'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy',
237             null,
238             array(ObjectNormalizer::GROUPS => array('a', 'b'))
239         );
240         $this->assertEquals($obj, $normalized);
241     }
242
243     public function testNormalizeNoPropertyInGroup()
244     {
245         $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
246         $this->normalizer = new ObjectNormalizer($classMetadataFactory);
247         $this->normalizer->setSerializer($this->serializer);
248
249         $obj = new GroupDummy();
250         $obj->setFoo('foo');
251
252         $this->assertEquals(array(), $this->normalizer->normalize($obj, null, array('groups' => array('notExist'))));
253     }
254
255     public function testGroupsNormalizeWithNameConverter()
256     {
257         $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
258         $this->normalizer = new ObjectNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
259         $this->normalizer->setSerializer($this->serializer);
260
261         $obj = new GroupDummy();
262         $obj->setFooBar('@dunglas');
263         $obj->setSymfony('@coopTilleuls');
264         $obj->setCoopTilleuls('les-tilleuls.coop');
265
266         $this->assertEquals(
267             array(
268                 'bar' => null,
269                 'foo_bar' => '@dunglas',
270                 'symfony' => '@coopTilleuls',
271             ),
272             $this->normalizer->normalize($obj, null, array(ObjectNormalizer::GROUPS => array('name_converter')))
273         );
274     }
275
276     public function testGroupsDenormalizeWithNameConverter()
277     {
278         $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
279         $this->normalizer = new ObjectNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
280         $this->normalizer->setSerializer($this->serializer);
281
282         $obj = new GroupDummy();
283         $obj->setFooBar('@dunglas');
284         $obj->setSymfony('@coopTilleuls');
285
286         $this->assertEquals(
287             $obj,
288             $this->normalizer->denormalize(array(
289                 'bar' => null,
290                 'foo_bar' => '@dunglas',
291                 'symfony' => '@coopTilleuls',
292                 'coop_tilleuls' => 'les-tilleuls.coop',
293             ), 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', null, array(ObjectNormalizer::GROUPS => array('name_converter')))
294         );
295     }
296
297     /**
298      * @dataProvider provideCallbacks
299      */
300     public function testCallbacks($callbacks, $value, $result, $message)
301     {
302         $this->normalizer->setCallbacks($callbacks);
303
304         $obj = new ObjectConstructorDummy('', $value, true);
305
306         $this->assertEquals(
307             $result,
308             $this->normalizer->normalize($obj, 'any'),
309             $message
310         );
311     }
312
313     /**
314      * @expectedException \InvalidArgumentException
315      */
316     public function testUncallableCallbacks()
317     {
318         $this->normalizer->setCallbacks(array('bar' => null));
319
320         $obj = new ObjectConstructorDummy('baz', 'quux', true);
321
322         $this->normalizer->normalize($obj, 'any');
323     }
324
325     public function testIgnoredAttributes()
326     {
327         $this->normalizer->setIgnoredAttributes(array('foo', 'bar', 'baz', 'camelCase', 'object'));
328
329         $obj = new ObjectDummy();
330         $obj->setFoo('foo');
331         $obj->bar = 'bar';
332         $obj->setBaz(true);
333
334         $this->assertEquals(
335             array('fooBar' => 'foobar'),
336             $this->normalizer->normalize($obj, 'any')
337         );
338     }
339
340     public function testIgnoredAttributesDenormalize()
341     {
342         $this->normalizer->setIgnoredAttributes(array('fooBar', 'bar', 'baz'));
343
344         $obj = new ObjectDummy();
345         $obj->setFoo('foo');
346
347         $this->assertEquals(
348             $obj,
349             $this->normalizer->denormalize(array('fooBar' => 'fooBar', 'foo' => 'foo', 'baz' => 'baz'), __NAMESPACE__.'\ObjectDummy')
350         );
351     }
352
353     public function provideCallbacks()
354     {
355         return array(
356             array(
357                 array(
358                     'bar' => function ($bar) {
359                         return 'baz';
360                     },
361                 ),
362                 'baz',
363                 array('foo' => '', 'bar' => 'baz', 'baz' => true),
364                 'Change a string',
365             ),
366             array(
367                 array(
368                     'bar' => function ($bar) {
369                         return;
370                     },
371                 ),
372                 'baz',
373                 array('foo' => '', 'bar' => null, 'baz' => true),
374                 'Null an item',
375             ),
376             array(
377                 array(
378                     'bar' => function ($bar) {
379                         return $bar->format('d-m-Y H:i:s');
380                     },
381                 ),
382                 new \DateTime('2011-09-10 06:30:00'),
383                 array('foo' => '', 'bar' => '10-09-2011 06:30:00', 'baz' => true),
384                 'Format a date',
385             ),
386             array(
387                 array(
388                     'bar' => function ($bars) {
389                         $foos = '';
390                         foreach ($bars as $bar) {
391                             $foos .= $bar->getFoo();
392                         }
393
394                         return $foos;
395                     },
396                 ),
397                 array(new ObjectConstructorDummy('baz', '', false), new ObjectConstructorDummy('quux', '', false)),
398                 array('foo' => '', 'bar' => 'bazquux', 'baz' => true),
399                 'Collect a property',
400             ),
401             array(
402                 array(
403                     'bar' => function ($bars) {
404                         return count($bars);
405                     },
406                 ),
407                 array(new ObjectConstructorDummy('baz', '', false), new ObjectConstructorDummy('quux', '', false)),
408                 array('foo' => '', 'bar' => 2, 'baz' => true),
409                 'Count a property',
410             ),
411         );
412     }
413
414     /**
415      * @expectedException \Symfony\Component\Serializer\Exception\LogicException
416      * @expectedExceptionMessage Cannot normalize attribute "object" because injected serializer is not a normalizer
417      */
418     public function testUnableToNormalizeObjectAttribute()
419     {
420         $serializer = $this->getMockBuilder('Symfony\Component\Serializer\SerializerInterface')->getMock();
421         $this->normalizer->setSerializer($serializer);
422
423         $obj = new ObjectDummy();
424         $object = new \stdClass();
425         $obj->setObject($object);
426
427         $this->normalizer->normalize($obj, 'any');
428     }
429
430     /**
431      * @expectedException \Symfony\Component\Serializer\Exception\CircularReferenceException
432      */
433     public function testUnableToNormalizeCircularReference()
434     {
435         $serializer = new Serializer(array($this->normalizer));
436         $this->normalizer->setSerializer($serializer);
437         $this->normalizer->setCircularReferenceLimit(2);
438
439         $obj = new CircularReferenceDummy();
440
441         $this->normalizer->normalize($obj);
442     }
443
444     public function testSiblingReference()
445     {
446         $serializer = new Serializer(array($this->normalizer));
447         $this->normalizer->setSerializer($serializer);
448
449         $siblingHolder = new SiblingHolder();
450
451         $expected = array(
452             'sibling0' => array('coopTilleuls' => 'Les-Tilleuls.coop'),
453             'sibling1' => array('coopTilleuls' => 'Les-Tilleuls.coop'),
454             'sibling2' => array('coopTilleuls' => 'Les-Tilleuls.coop'),
455         );
456         $this->assertEquals($expected, $this->normalizer->normalize($siblingHolder));
457     }
458
459     public function testCircularReferenceHandler()
460     {
461         $serializer = new Serializer(array($this->normalizer));
462         $this->normalizer->setSerializer($serializer);
463         $this->normalizer->setCircularReferenceHandler(function ($obj) {
464             return get_class($obj);
465         });
466
467         $obj = new CircularReferenceDummy();
468
469         $expected = array('me' => 'Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy');
470         $this->assertEquals($expected, $this->normalizer->normalize($obj));
471     }
472
473     public function testDenormalizeNonExistingAttribute()
474     {
475         $this->assertEquals(
476             new ObjectDummy(),
477             $this->normalizer->denormalize(array('non_existing' => true), __NAMESPACE__.'\ObjectDummy')
478         );
479     }
480
481     public function testNoTraversableSupport()
482     {
483         $this->assertFalse($this->normalizer->supportsNormalization(new \ArrayObject()));
484     }
485
486     public function testNormalizeStatic()
487     {
488         $this->assertEquals(array('foo' => 'K'), $this->normalizer->normalize(new ObjectWithStaticPropertiesAndMethods()));
489     }
490
491     public function testNormalizeUpperCaseAttributes()
492     {
493         $this->assertEquals(array('Foo' => 'Foo', 'Bar' => 'BarBar'), $this->normalizer->normalize(new ObjectWithUpperCaseAttributeNames()));
494     }
495
496     public function testNormalizeNotSerializableContext()
497     {
498         $objectDummy = new ObjectDummy();
499         $expected = array(
500             'foo' => null,
501             'baz' => null,
502             'fooBar' => '',
503             'camelCase' => null,
504             'object' => null,
505             'bar' => null,
506         );
507
508         $this->assertEquals($expected, $this->normalizer->normalize($objectDummy, null, array('not_serializable' => function () {})));
509     }
510 }
511
512 class ObjectDummy
513 {
514     protected $foo;
515     public $bar;
516     private $baz;
517     protected $camelCase;
518     protected $object;
519
520     public function getFoo()
521     {
522         return $this->foo;
523     }
524
525     public function setFoo($foo)
526     {
527         $this->foo = $foo;
528     }
529
530     public function isBaz()
531     {
532         return $this->baz;
533     }
534
535     public function setBaz($baz)
536     {
537         $this->baz = $baz;
538     }
539
540     public function getFooBar()
541     {
542         return $this->foo.$this->bar;
543     }
544
545     public function getCamelCase()
546     {
547         return $this->camelCase;
548     }
549
550     public function setCamelCase($camelCase)
551     {
552         $this->camelCase = $camelCase;
553     }
554
555     public function otherMethod()
556     {
557         throw new \RuntimeException('Dummy::otherMethod() should not be called');
558     }
559
560     public function setObject($object)
561     {
562         $this->object = $object;
563     }
564
565     public function getObject()
566     {
567         return $this->object;
568     }
569 }
570
571 class ObjectConstructorDummy
572 {
573     protected $foo;
574     public $bar;
575     private $baz;
576
577     public function __construct($foo, $bar, $baz)
578     {
579         $this->foo = $foo;
580         $this->bar = $bar;
581         $this->baz = $baz;
582     }
583
584     public function getFoo()
585     {
586         return $this->foo;
587     }
588
589     public function isBaz()
590     {
591         return $this->baz;
592     }
593
594     public function otherMethod()
595     {
596         throw new \RuntimeException('Dummy::otherMethod() should not be called');
597     }
598 }
599
600 abstract class ObjectSerializerNormalizer implements SerializerInterface, NormalizerInterface
601 {
602 }
603
604 class ObjectConstructorOptionalArgsDummy
605 {
606     protected $foo;
607     public $bar;
608     private $baz;
609
610     public function __construct($foo, $bar = array(), $baz = array())
611     {
612         $this->foo = $foo;
613         $this->bar = $bar;
614         $this->baz = $baz;
615     }
616
617     public function getFoo()
618     {
619         return $this->foo;
620     }
621
622     public function getBaz()
623     {
624         return $this->baz;
625     }
626
627     public function otherMethod()
628     {
629         throw new \RuntimeException('Dummy::otherMethod() should not be called');
630     }
631 }
632
633 class ObjectConstructorArgsWithDefaultValueDummy
634 {
635     protected $foo;
636     protected $bar;
637
638     public function __construct($foo = array(), $bar)
639     {
640         $this->foo = $foo;
641         $this->bar = $bar;
642     }
643
644     public function getFoo()
645     {
646         return $this->foo;
647     }
648
649     public function getBar()
650     {
651         return $this->bar;
652     }
653
654     public function otherMethod()
655     {
656         throw new \RuntimeException('Dummy::otherMethod() should not be called');
657     }
658 }
659
660 class ObjectWithStaticPropertiesAndMethods
661 {
662     public $foo = 'K';
663     public static $bar = 'A';
664
665     public static function getBaz()
666     {
667         return 'L';
668     }
669 }
670
671 class ObjectWithUpperCaseAttributeNames
672 {
673     private $Foo = 'Foo';
674     public $Bar = 'BarBar';
675
676     public function getFoo()
677     {
678         return $this->Foo;
679     }
680 }