1<?php
2
3declare(strict_types=1);
4
5namespace JMS\Serializer\Tests\Metadata\Driver;
6
7use JMS\Serializer\Exception\InvalidMetadataException;
8use JMS\Serializer\Expression\ExpressionEvaluator;
9use JMS\Serializer\Metadata\ClassMetadata;
10use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
11use JMS\Serializer\Metadata\PropertyMetadata;
12use JMS\Serializer\Metadata\VirtualPropertyMetadata;
13use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorChild;
14use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorParent;
15use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorChild;
16use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorParent;
17use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorChild;
18use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorParent;
19use JMS\Serializer\Tests\Fixtures\FirstClassListCollection;
20use JMS\Serializer\Tests\Fixtures\FirstClassMapCollection;
21use JMS\Serializer\Tests\Fixtures\ObjectWithExpressionVirtualPropertiesAndExcludeAll;
22use JMS\Serializer\Tests\Fixtures\ObjectWithInvalidExpression;
23use JMS\Serializer\Tests\Fixtures\ObjectWithVirtualPropertiesAndDuplicatePropName;
24use JMS\Serializer\Tests\Fixtures\ObjectWithVirtualPropertiesAndExcludeAll;
25use JMS\Serializer\Tests\Fixtures\ParentSkipWithEmptyChild;
26use Metadata\Driver\DriverInterface;
27use PHPUnit\Framework\TestCase;
28use Symfony\Component\ExpressionLanguage\ExpressionFunction;
29use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
30
31abstract class BaseDriverTest extends TestCase
32{
33    public function testLoadBlogPostMetadata()
34    {
35        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost'));
36
37        self::assertNotNull($m);
38        self::assertEquals('blog-post', $m->xmlRootName);
39        self::assertCount(4, $m->xmlNamespaces);
40        self::assertArrayHasKey('', $m->xmlNamespaces);
41        self::assertEquals('http://example.com/namespace', $m->xmlNamespaces['']);
42        self::assertArrayHasKey('gd', $m->xmlNamespaces);
43        self::assertEquals('http://schemas.google.com/g/2005', $m->xmlNamespaces['gd']);
44        self::assertArrayHasKey('atom', $m->xmlNamespaces);
45        self::assertEquals('http://www.w3.org/2005/Atom', $m->xmlNamespaces['atom']);
46        self::assertArrayHasKey('dc', $m->xmlNamespaces);
47        self::assertEquals('http://purl.org/dc/elements/1.1/', $m->xmlNamespaces['dc']);
48
49        self::assertFalse($m->isList);
50        self::assertFalse($m->isMap);
51
52        $p = new PropertyMetadata($m->name, 'id');
53        $p->type = ['name' => 'string', 'params' => []];
54        $p->groups = ['comments', 'post'];
55        $p->serializedName = 'id';
56        $p->xmlElementCData = false;
57        self::assertEquals($p, $m->propertyMetadata['id']);
58
59        $p = new PropertyMetadata($m->name, 'title');
60        $p->type = ['name' => 'string', 'params' => []];
61        $p->serializedName = 'title';
62        $p->groups = ['comments', 'post'];
63        $p->xmlNamespace = 'http://purl.org/dc/elements/1.1/';
64        self::assertEquals($p, $m->propertyMetadata['title']);
65
66        $p = new PropertyMetadata($m->name, 'createdAt');
67        $p->type = ['name' => 'DateTime', 'params' => []];
68        $p->serializedName = 'createdAt';
69        $p->xmlAttribute = true;
70        self::assertEquals($p, $m->propertyMetadata['createdAt']);
71
72        $p = new PropertyMetadata($m->name, 'published');
73        $p->serializedName = 'published';
74        $p->type = ['name' => 'boolean', 'params' => []];
75        $p->serializedName = 'is_published';
76        $p->xmlAttribute = true;
77        $p->groups = ['post'];
78        self::assertEquals($p, $m->propertyMetadata['published']);
79
80        $p = new PropertyMetadata($m->name, 'etag');
81        $p->serializedName = 'etag';
82        $p->type = ['name' => 'string', 'params' => []];
83        $p->xmlAttribute = true;
84        $p->groups = ['post'];
85        $p->xmlNamespace = 'http://schemas.google.com/g/2005';
86        self::assertEquals($p, $m->propertyMetadata['etag']);
87
88        $p = new PropertyMetadata($m->name, 'comments');
89        $p->serializedName = 'comments';
90        $p->type = ['name' => 'ArrayCollection', 'params' => [['name' => 'JMS\Serializer\Tests\Fixtures\Comment', 'params' => []]]];
91        $p->xmlCollection = true;
92        $p->xmlCollectionInline = true;
93        $p->xmlEntryName = 'comment';
94        $p->groups = ['comments'];
95        self::assertEquals($p, $m->propertyMetadata['comments']);
96
97        $p = new PropertyMetadata($m->name, 'author');
98        $p->serializedName = 'author';
99        $p->type = ['name' => 'JMS\Serializer\Tests\Fixtures\Author', 'params' => []];
100        $p->groups = ['post'];
101        $p->xmlNamespace = 'http://www.w3.org/2005/Atom';
102        self::assertEquals($p, $m->propertyMetadata['author']);
103
104        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Price'));
105        self::assertNotNull($m);
106
107        $p = new PropertyMetadata($m->name, 'price');
108        $p->serializedName = 'price';
109        $p->type = ['name' => 'float', 'params' => []];
110        $p->xmlValue = true;
111        self::assertEquals($p, $m->propertyMetadata['price']);
112    }
113
114    public function testXMLListAbsentNode()
115    {
116        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ObjectWithAbsentXmlListNode'));
117
118        self::assertArrayHasKey('absent', $m->propertyMetadata);
119        self::assertArrayHasKey('present', $m->propertyMetadata);
120        self::assertArrayHasKey('skipDefault', $m->propertyMetadata);
121
122        self::assertTrue($m->propertyMetadata['absent']->xmlCollectionSkipWhenEmpty);
123        self::assertTrue($m->propertyMetadata['skipDefault']->xmlCollectionSkipWhenEmpty);
124        self::assertFalse($m->propertyMetadata['present']->xmlCollectionSkipWhenEmpty);
125    }
126
127    public function testVirtualProperty()
128    {
129        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ObjectWithVirtualProperties'));
130
131        self::assertArrayHasKey('existField', $m->propertyMetadata);
132        self::assertArrayHasKey('virtualValue', $m->propertyMetadata);
133        self::assertArrayHasKey('virtualSerializedValue', $m->propertyMetadata);
134        self::assertArrayHasKey('typedVirtualProperty', $m->propertyMetadata);
135
136        self::assertEquals($m->propertyMetadata['virtualSerializedValue']->serializedName, 'test', 'Serialized name is missing');
137
138        $p = new VirtualPropertyMetadata($m->name, 'virtualValue');
139        $p->getter = 'getVirtualValue';
140        $p->serializedName = 'virtualValue';
141
142        self::assertEquals($p, $m->propertyMetadata['virtualValue']);
143    }
144
145    public function testFirstClassListCollection()
146    {
147        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(FirstClassListCollection::class));
148        self::assertTrue($m->isList);
149        self::assertFalse($m->isMap);
150    }
151
152    public function testFirstClassMapCollection()
153    {
154        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(FirstClassMapCollection::class));
155        self::assertFalse($m->isList);
156        self::assertTrue($m->isMap);
157    }
158
159    public function testXmlKeyValuePairs()
160    {
161        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairs'));
162
163        self::assertArrayHasKey('array', $m->propertyMetadata);
164        self::assertTrue($m->propertyMetadata['array']->xmlKeyValuePairs);
165    }
166
167    public function testInvalidExpression()
168    {
169        $this->expectException(InvalidMetadataException::class);
170
171        $a = new ObjectWithInvalidExpression();
172        $this->getDriver()->loadMetadataForClass(new \ReflectionClass($a));
173    }
174
175    public function testExpressionVirtualPropertyWithExcludeAll()
176    {
177        $a = new ObjectWithExpressionVirtualPropertiesAndExcludeAll();
178        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass($a));
179
180        self::assertArrayHasKey('virtualValue', $m->propertyMetadata);
181
182        $p = new ExpressionPropertyMetadata($m->name, 'virtualValue', 'object.getVirtualValue()');
183        $p->serializedName = 'virtualValue';
184        self::assertEquals($p, $m->propertyMetadata['virtualValue']);
185    }
186
187    public function testVirtualPropertyWithExcludeAll()
188    {
189        $a = new ObjectWithVirtualPropertiesAndExcludeAll();
190        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass($a));
191
192        self::assertArrayHasKey('virtualValue', $m->propertyMetadata);
193
194        $p = new VirtualPropertyMetadata($m->name, 'virtualValue');
195        $p->getter = 'getVirtualValue';
196        $p->serializedName = 'virtualValue';
197
198        self::assertEquals($p, $m->propertyMetadata['virtualValue']);
199    }
200
201    public function testReadOnlyDefinedBeforeGetterAndSetter()
202    {
203        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\AuthorReadOnly'));
204
205        self::assertNotNull($m);
206    }
207
208    public function testExpressionVirtualProperty()
209    {
210        /** @var ClassMetadata $m */
211        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\AuthorExpressionAccess'));
212
213        $keys = array_keys($m->propertyMetadata);
214        self::assertEquals(['firstName', 'lastName', 'id'], $keys);
215    }
216
217    public function testLoadDiscriminator()
218    {
219        /** @var ClassMetadata $m */
220        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle'));
221
222        self::assertNotNull($m);
223        self::assertEquals('type', $m->discriminatorFieldName);
224        self::assertEquals($m->name, $m->discriminatorBaseClass);
225        self::assertEquals(
226            [
227                'car' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Car',
228                'moped' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Moped',
229            ],
230            $m->discriminatorMap
231        );
232    }
233
234    public function testLoadDiscriminatorWhenParentIsInDiscriminatorMap()
235    {
236        /** @var ClassMetadata $m */
237        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Discriminator\Post'));
238
239        self::assertNotNull($m);
240        self::assertEquals('type', $m->discriminatorFieldName);
241        self::assertEquals($m->name, $m->discriminatorBaseClass);
242        self::assertEquals(
243            [
244                'post' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Post',
245                'image_post' => 'JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost',
246            ],
247            $m->discriminatorMap
248        );
249    }
250
251    public function testLoadXmlDiscriminator()
252    {
253        /** @var ClassMetadata $m */
254        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(ObjectWithXmlAttributeDiscriminatorParent::class));
255
256        self::assertNotNull($m);
257        self::assertEquals('type', $m->discriminatorFieldName);
258        self::assertEquals($m->name, $m->discriminatorBaseClass);
259        self::assertEquals(
260            [
261                'child' => ObjectWithXmlAttributeDiscriminatorChild::class,
262            ],
263            $m->discriminatorMap
264        );
265        self::assertTrue($m->xmlDiscriminatorAttribute);
266        self::assertFalse($m->xmlDiscriminatorCData);
267    }
268
269    public function testLoadXmlDiscriminatorWithNamespaces()
270    {
271        /** @var ClassMetadata $m */
272        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(ObjectWithXmlNamespaceDiscriminatorParent::class));
273
274        self::assertNotNull($m);
275        self::assertEquals('type', $m->discriminatorFieldName);
276        self::assertEquals($m->name, $m->discriminatorBaseClass);
277        self::assertEquals(
278            [
279                'child' => ObjectWithXmlNamespaceDiscriminatorChild::class,
280            ],
281            $m->discriminatorMap
282        );
283        self::assertEquals('http://example.com/', $m->xmlDiscriminatorNamespace);
284        self::assertFalse($m->xmlDiscriminatorAttribute);
285    }
286
287    public function testCanDefineMetadataForInternalClass()
288    {
289        /** @var ClassMetadata $m */
290        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(\PDOStatement::class));
291
292        self::assertNotNull($m);
293        self::assertSame('int', $m->propertyMetadata['queryString']->type['name']);
294
295        self::assertCount(1, $m->fileResources);
296    }
297
298    public function testLoadXmlDiscriminatorWithAttributeNamespaces()
299    {
300        /** @var ClassMetadata $m */
301        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(ObjectWithXmlNamespaceAttributeDiscriminatorParent::class));
302
303        self::assertNotNull($m);
304        self::assertEquals('type', $m->discriminatorFieldName);
305        self::assertEquals($m->name, $m->discriminatorBaseClass);
306        self::assertEquals(
307            [
308                'child' => ObjectWithXmlNamespaceAttributeDiscriminatorChild::class,
309            ],
310            $m->discriminatorMap
311        );
312        self::assertEquals('http://example.com/', $m->xmlDiscriminatorNamespace);
313        self::assertTrue($m->xmlDiscriminatorAttribute);
314    }
315
316    public function testLoadDiscriminatorWithGroup()
317    {
318        /** @var ClassMetadata $m */
319        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Vehicle'));
320
321        self::assertNotNull($m);
322        self::assertEquals('type', $m->discriminatorFieldName);
323        self::assertEquals(['foo'], $m->discriminatorGroups);
324        self::assertEquals($m->name, $m->discriminatorBaseClass);
325        self::assertEquals(
326            ['car' => 'JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Car'],
327            $m->discriminatorMap
328        );
329    }
330
331    public function testSkipWhenEmptyOption()
332    {
333        /** @var ClassMetadata $m */
334        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(ParentSkipWithEmptyChild::class));
335
336        self::assertNotNull($m);
337
338        self::assertInstanceOf(PropertyMetadata::class, $m->propertyMetadata['c']);
339        self::assertInstanceOf(PropertyMetadata::class, $m->propertyMetadata['d']);
340        self::assertInstanceOf(PropertyMetadata::class, $m->propertyMetadata['child']);
341        self::assertFalse($m->propertyMetadata['c']->skipWhenEmpty);
342        self::assertFalse($m->propertyMetadata['d']->skipWhenEmpty);
343        self::assertTrue($m->propertyMetadata['child']->skipWhenEmpty);
344    }
345
346    public function testLoadDiscriminatorSubClass()
347    {
348        /** @var ClassMetadata $m */
349        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Discriminator\Car'));
350
351        self::assertNotNull($m);
352        self::assertNull($m->discriminatorValue);
353        self::assertNull($m->discriminatorBaseClass);
354        self::assertNull($m->discriminatorFieldName);
355        self::assertEquals([], $m->discriminatorMap);
356    }
357
358    public function testLoadDiscriminatorSubClassWhenParentIsInDiscriminatorMap()
359    {
360        /** @var ClassMetadata $m */
361        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost'));
362
363        self::assertNotNull($m);
364        self::assertNull($m->discriminatorValue);
365        self::assertNull($m->discriminatorBaseClass);
366        self::assertNull($m->discriminatorFieldName);
367        self::assertEquals([], $m->discriminatorMap);
368    }
369
370    public function testLoadXmlObjectWithNamespacesMetadata()
371    {
372        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces'));
373        self::assertNotNull($m);
374        self::assertEquals('test-object', $m->xmlRootName);
375        self::assertEquals('ex', $m->xmlRootPrefix);
376        self::assertEquals('http://example.com/namespace', $m->xmlRootNamespace);
377        self::assertCount(3, $m->xmlNamespaces);
378        self::assertArrayHasKey('', $m->xmlNamespaces);
379        self::assertEquals('http://example.com/namespace', $m->xmlNamespaces['']);
380        self::assertArrayHasKey('gd', $m->xmlNamespaces);
381        self::assertEquals('http://schemas.google.com/g/2005', $m->xmlNamespaces['gd']);
382        self::assertArrayHasKey('atom', $m->xmlNamespaces);
383        self::assertEquals('http://www.w3.org/2005/Atom', $m->xmlNamespaces['atom']);
384
385        $p = new PropertyMetadata($m->name, 'title');
386        $p->serializedName = 'title';
387        $p->type = ['name' => 'string', 'params' => []];
388        $p->xmlNamespace = 'http://purl.org/dc/elements/1.1/';
389        self::assertEquals($p, $m->propertyMetadata['title']);
390
391        $p = new PropertyMetadata($m->name, 'createdAt');
392        $p->serializedName = 'createdAt';
393        $p->type = ['name' => 'DateTime', 'params' => []];
394        $p->xmlAttribute = true;
395        self::assertEquals($p, $m->propertyMetadata['createdAt']);
396
397        $p = new PropertyMetadata($m->name, 'etag');
398        $p->serializedName = 'etag';
399        $p->type = ['name' => 'string', 'params' => []];
400        $p->xmlAttribute = true;
401        $p->xmlNamespace = 'http://schemas.google.com/g/2005';
402        self::assertEquals($p, $m->propertyMetadata['etag']);
403
404        $p = new PropertyMetadata($m->name, 'author');
405        $p->serializedName = 'author';
406        $p->type = ['name' => 'string', 'params' => []];
407        $p->xmlAttribute = false;
408        $p->xmlNamespace = 'http://www.w3.org/2005/Atom';
409        self::assertEquals($p, $m->propertyMetadata['author']);
410
411        $p = new PropertyMetadata($m->name, 'language');
412        $p->serializedName = 'language';
413        $p->type = ['name' => 'string', 'params' => []];
414        $p->xmlAttribute = true;
415        $p->xmlNamespace = 'http://purl.org/dc/elements/1.1/';
416        self::assertEquals($p, $m->propertyMetadata['language']);
417    }
418
419    public function testMaxDepth()
420    {
421        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Node'));
422
423        self::assertEquals(2, $m->propertyMetadata['children']->maxDepth);
424    }
425
426    public function testPersonCData()
427    {
428        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Person'));
429
430        self::assertNotNull($m);
431        self::assertFalse($m->propertyMetadata['name']->xmlElementCData);
432    }
433
434    public function testXmlNamespaceInheritanceMetadata()
435    {
436        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\SimpleClassObject'));
437        self::assertNotNull($m);
438        self::assertCount(3, $m->xmlNamespaces);
439        self::assertArrayHasKey('old_foo', $m->xmlNamespaces);
440        self::assertEquals('http://old.foo.example.org', $m->xmlNamespaces['old_foo']);
441        self::assertArrayHasKey('foo', $m->xmlNamespaces);
442        self::assertEquals('http://foo.example.org', $m->xmlNamespaces['foo']);
443        self::assertArrayHasKey('new_foo', $m->xmlNamespaces);
444        self::assertEquals('http://new.foo.example.org', $m->xmlNamespaces['new_foo']);
445        self::assertCount(3, $m->propertyMetadata);
446
447        $p = new PropertyMetadata($m->name, 'foo');
448        $p->serializedName = 'foo';
449        $p->type = ['name' => 'string', 'params' => []];
450        $p->xmlNamespace = 'http://old.foo.example.org';
451        $p->xmlAttribute = true;
452        self::assertEquals($p, $m->propertyMetadata['foo']);
453
454        $p = new PropertyMetadata($m->name, 'bar');
455        $p->serializedName = 'bar';
456        $p->type = ['name' => 'string', 'params' => []];
457        $p->xmlNamespace = 'http://foo.example.org';
458        self::assertEquals($p, $m->propertyMetadata['bar']);
459
460        $p = new PropertyMetadata($m->name, 'moo');
461        $p->serializedName = 'moo';
462        $p->type = ['name' => 'string', 'params' => []];
463        $p->xmlNamespace = 'http://new.foo.example.org';
464        self::assertEquals($p, $m->propertyMetadata['moo']);
465
466        $subm = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\SimpleSubClassObject'));
467        self::assertNotNull($subm);
468        self::assertCount(2, $subm->xmlNamespaces);
469        self::assertArrayHasKey('old_foo', $subm->xmlNamespaces);
470        self::assertEquals('http://foo.example.org', $subm->xmlNamespaces['old_foo']);
471        self::assertArrayHasKey('foo', $subm->xmlNamespaces);
472        self::assertEquals('http://better.foo.example.org', $subm->xmlNamespaces['foo']);
473        self::assertCount(3, $subm->propertyMetadata);
474
475        $p = new PropertyMetadata($subm->name, 'moo');
476        $p->serializedName = 'moo';
477        $p->type = ['name' => 'string', 'params' => []];
478        $p->xmlNamespace = 'http://better.foo.example.org';
479        self::assertEquals($p, $subm->propertyMetadata['moo']);
480
481        $p = new PropertyMetadata($subm->name, 'baz');
482        $p->serializedName = 'baz';
483        $p->type = ['name' => 'string', 'params' => []];
484        $p->xmlNamespace = 'http://foo.example.org';
485        self::assertEquals($p, $subm->propertyMetadata['baz']);
486
487        $p = new PropertyMetadata($subm->name, 'qux');
488        $p->serializedName = 'qux';
489        $p->type = ['name' => 'string', 'params' => []];
490        $p->xmlNamespace = 'http://new.foo.example.org';
491        self::assertEquals($p, $subm->propertyMetadata['qux']);
492
493        $m->merge($subm);
494        self::assertNotNull($m);
495        self::assertCount(3, $m->xmlNamespaces);
496        self::assertArrayHasKey('old_foo', $m->xmlNamespaces);
497        self::assertEquals('http://foo.example.org', $m->xmlNamespaces['old_foo']);
498        self::assertArrayHasKey('foo', $m->xmlNamespaces);
499        self::assertEquals('http://better.foo.example.org', $m->xmlNamespaces['foo']);
500        self::assertArrayHasKey('new_foo', $m->xmlNamespaces);
501        self::assertEquals('http://new.foo.example.org', $m->xmlNamespaces['new_foo']);
502        self::assertCount(5, $m->propertyMetadata);
503
504        $p = new PropertyMetadata($m->name, 'foo');
505        $p->serializedName = 'foo';
506        $p->type = ['name' => 'string', 'params' => []];
507        $p->xmlNamespace = 'http://old.foo.example.org';
508        $p->xmlAttribute = true;
509        $p->class = 'JMS\Serializer\Tests\Fixtures\SimpleClassObject';
510        $this->assetMetadataEquals($p, $m->propertyMetadata['foo']);
511
512        $p = new PropertyMetadata($m->name, 'bar');
513        $p->serializedName = 'bar';
514        $p->type = ['name' => 'string', 'params' => []];
515        $p->xmlNamespace = 'http://foo.example.org';
516        $p->class = 'JMS\Serializer\Tests\Fixtures\SimpleClassObject';
517        $this->assetMetadataEquals($p, $m->propertyMetadata['bar']);
518
519        $p = new PropertyMetadata($m->name, 'moo');
520        $p->serializedName = 'moo';
521        $p->type = ['name' => 'string', 'params' => []];
522        $p->xmlNamespace = 'http://better.foo.example.org';
523        $this->assetMetadataEquals($p, $m->propertyMetadata['moo']);
524
525        $p = new PropertyMetadata($m->name, 'baz');
526        $p->serializedName = 'baz';
527        $p->type = ['name' => 'string', 'params' => []];
528        $p->xmlNamespace = 'http://foo.example.org';
529        $this->assetMetadataEquals($p, $m->propertyMetadata['baz']);
530
531        $p = new PropertyMetadata($m->name, 'qux');
532        $p->serializedName = 'qux';
533        $p->type = ['name' => 'string', 'params' => []];
534        $p->xmlNamespace = 'http://new.foo.example.org';
535        $this->assetMetadataEquals($p, $m->propertyMetadata['qux']);
536    }
537
538    private function assetMetadataEquals(PropertyMetadata $expected, PropertyMetadata $actual)
539    {
540        $expectedVars = get_object_vars($expected);
541        $actualVars = get_object_vars($actual);
542
543        self::assertEquals($expectedVars, $actualVars);
544    }
545
546    public function testExclusionIf()
547    {
548        $class = 'JMS\Serializer\Tests\Fixtures\PersonSecret';
549        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass($class));
550
551        $p = new PropertyMetadata($class, 'name');
552        $p->serializedName = 'name';
553        $p->type = ['name' => 'string', 'params' => []];
554        self::assertEquals($p, $m->propertyMetadata['name']);
555
556        $p = new PropertyMetadata($class, 'gender');
557        $p->serializedName = 'gender';
558        $p->type = ['name' => 'string', 'params' => []];
559        $p->excludeIf = "show_data('gender')";
560        self::assertEquals($p, $m->propertyMetadata['gender']);
561
562        $p = new PropertyMetadata($class, 'age');
563        $p->serializedName = 'age';
564        $p->type = ['name' => 'string', 'params' => []];
565        $p->excludeIf = "!(show_data('age'))";
566        self::assertEquals($p, $m->propertyMetadata['age']);
567    }
568
569    public function testObjectWithVirtualPropertiesAndDuplicatePropName()
570    {
571        $class = ObjectWithVirtualPropertiesAndDuplicatePropName::class;
572        $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass($class));
573
574        $p = new PropertyMetadata($class, 'id');
575        $p->serializedName = 'id';
576        self::assertEquals($p, $m->propertyMetadata['id']);
577
578        $p = new PropertyMetadata($class, 'name');
579        $p->serializedName = 'name';
580        self::assertEquals($p, $m->propertyMetadata['name']);
581
582        $p = new VirtualPropertyMetadata($class, 'foo');
583        $p->serializedName = 'id';
584        $p->getter = 'getId';
585
586        self::assertEquals($p, $m->propertyMetadata['foo']);
587
588        $p = new VirtualPropertyMetadata($class, 'bar');
589        $p->serializedName = 'mood';
590        $p->getter = 'getName';
591
592        self::assertEquals($p, $m->propertyMetadata['bar']);
593    }
594
595    public function testExcludePropertyNoPublicAccessorException()
596    {
597        $first = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ExcludePublicAccessor'));
598
599        if ($this instanceof PhpDriverTest) {
600            return;
601        }
602        self::assertArrayHasKey('id', $first->propertyMetadata);
603        self::assertArrayNotHasKey('iShallNotBeAccessed', $first->propertyMetadata);
604    }
605
606    /**
607     * @return DriverInterface
608     */
609    abstract protected function getDriver();
610
611    protected function getExpressionEvaluator()
612    {
613        $language = new ExpressionLanguage();
614
615        $language->addFunction(new ExpressionFunction('show_data', static function () {
616            return 'true';
617        }, static function () {
618            return true;
619        }));
620        return new ExpressionEvaluator($language);
621    }
622}
623