1<?php 2 3declare(strict_types=1); 4 5namespace JMS\Serializer\Tests\Serializer; 6 7use JMS\Serializer\Context; 8use JMS\Serializer\DeserializationContext; 9use JMS\Serializer\Exception\InvalidArgumentException; 10use JMS\Serializer\GraphNavigatorInterface; 11use JMS\Serializer\Handler\DateHandler; 12use JMS\Serializer\Handler\HandlerRegistryInterface; 13use JMS\Serializer\Metadata\StaticPropertyMetadata; 14use JMS\Serializer\SerializationContext; 15use JMS\Serializer\SerializerBuilder; 16use JMS\Serializer\Tests\Fixtures\AccessorSetter; 17use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorChild; 18use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorParent; 19use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorChild; 20use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorParent; 21use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorChild; 22use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorParent; 23use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNotCDataDiscriminatorChild; 24use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNotCDataDiscriminatorParent; 25use JMS\Serializer\Tests\Fixtures\Input; 26use JMS\Serializer\Tests\Fixtures\InvalidUsageOfXmlValue; 27use JMS\Serializer\Tests\Fixtures\ObjectWithNamespacesAndList; 28use JMS\Serializer\Tests\Fixtures\ObjectWithNamespacesAndNestedList; 29use JMS\Serializer\Tests\Fixtures\ObjectWithVirtualXmlProperties; 30use JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairs; 31use JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairsWithObjectType; 32use JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairsWithType; 33use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces; 34use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespacesAndObjectProperty; 35use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespacesAndObjectPropertyAuthor; 36use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespacesAndObjectPropertyVirtual; 37use JMS\Serializer\Tests\Fixtures\ObjectWithXmlRootNamespace; 38use JMS\Serializer\Tests\Fixtures\Person; 39use JMS\Serializer\Tests\Fixtures\PersonCollection; 40use JMS\Serializer\Tests\Fixtures\PersonLocation; 41use JMS\Serializer\Tests\Fixtures\SimpleClassObject; 42use JMS\Serializer\Tests\Fixtures\SimpleSubClassObject; 43use JMS\Serializer\Visitor\Factory\XmlDeserializationVisitorFactory; 44use JMS\Serializer\Visitor\Factory\XmlSerializationVisitorFactory; 45use JMS\Serializer\XmlSerializationVisitor; 46 47class XmlSerializationTest extends BaseSerializationTest 48{ 49 /** 50 * @expectedException \JMS\Serializer\Exception\RuntimeException 51 */ 52 public function testInvalidUsageOfXmlValue() 53 { 54 $obj = new InvalidUsageOfXmlValue(); 55 $this->serialize($obj); 56 } 57 58 /** 59 * @dataProvider getXMLBooleans 60 */ 61 public function testXMLBooleans($xmlBoolean, $boolean) 62 { 63 if ($this->hasDeserializer()) { 64 self::assertSame($boolean, $this->deserialize('<result>' . $xmlBoolean . '</result>', 'boolean')); 65 } 66 } 67 68 public function getXMLBooleans() 69 { 70 return [['true', true], ['false', false], ['1', true], ['0', false]]; 71 } 72 73 public function testAccessorSetterDeserialization() 74 { 75 /** @var AccessorSetter $object */ 76 $object = $this->deserialize( 77 '<?xml version="1.0"?> 78 <AccessorSetter> 79 <element attribute="attribute">element</element> 80 <collection> 81 <entry>collectionEntry</entry> 82 </collection> 83 </AccessorSetter>', 84 'JMS\Serializer\Tests\Fixtures\AccessorSetter' 85 ); 86 87 self::assertInstanceOf('stdClass', $object->getElement()); 88 self::assertInstanceOf('JMS\Serializer\Tests\Fixtures\AccessorSetterElement', $object->getElement()->element); 89 self::assertEquals('attribute-different', $object->getElement()->element->getAttribute()); 90 self::assertEquals('element-different', $object->getElement()->element->getElement()); 91 self::assertEquals(['collectionEntry' => 'collectionEntry'], $object->getCollection()); 92 } 93 94 public function testPropertyIsObjectWithAttributeAndValue() 95 { 96 $personCollection = new PersonLocation(); 97 $person = new Person(); 98 $person->name = 'Matthias Noback'; 99 $person->age = 28; 100 $personCollection->person = $person; 101 $personCollection->location = 'The Netherlands'; 102 103 self::assertEquals($this->getContent('person_location'), $this->serialize($personCollection)); 104 } 105 106 public function testPropertyIsCollectionOfObjectsWithAttributeAndValue() 107 { 108 $personCollection = new PersonCollection(); 109 $person = new Person(); 110 $person->name = 'Matthias Noback'; 111 $person->age = 28; 112 $personCollection->persons->add($person); 113 $personCollection->location = 'The Netherlands'; 114 115 self::assertEquals($this->getContent('person_collection'), $this->serialize($personCollection)); 116 } 117 118 /** 119 * @expectedException JMS\Serializer\Exception\InvalidArgumentException 120 * @expectedExceptionMessage The document type "<!DOCTYPE author [<!ENTITY foo SYSTEM "php://filter/read=convert.base64-encode/resource=XmlSerializationTest.php">]>" is not allowed. If it is safe, you may add it to the whitelist configuration. 121 */ 122 public function testExternalEntitiesAreDisabledByDefault() 123 { 124 $this->deserialize('<?xml version="1.0"?> 125 <!DOCTYPE author [ 126 <!ENTITY foo SYSTEM "php://filter/read=convert.base64-encode/resource=' . basename(__FILE__) . '"> 127 ]> 128 <result> 129 &foo; 130 </result>', 'stdClass'); 131 } 132 133 /** 134 * @expectedException JMS\Serializer\Exception\InvalidArgumentException 135 * @expectedExceptionMessage The document type "<!DOCTYPE foo>" is not allowed. If it is safe, you may add it to the whitelist configuration. 136 */ 137 public function testDocumentTypesAreNotAllowed() 138 { 139 $this->deserialize('<?xml version="1.0"?><!DOCTYPE foo><foo></foo>', 'stdClass'); 140 } 141 142 /** 143 * @doesNotPerformAssertions 144 */ 145 public function testWhitelistedDocumentTypesAreAllowed() 146 { 147 $xmlVisitor = new XmlDeserializationVisitorFactory(); 148 149 $xmlVisitor->setDoctypeWhitelist([ 150 '<!DOCTYPE authorized SYSTEM "http://authorized_url.dtd">', 151 '<!DOCTYPE author [<!ENTITY foo SYSTEM "php://filter/read=convert.base64-encode/resource=' . basename(__FILE__) . '">]>', 152 ]); 153 154 $builder = SerializerBuilder::create(); 155 $builder->setDeserializationVisitor('xml', $xmlVisitor); 156 $serializer = $builder->build(); 157 158 $serializer->deserialize('<?xml version="1.0"?> 159 <!DOCTYPE authorized SYSTEM "http://authorized_url.dtd"> 160 <foo></foo>', 'stdClass', 'xml'); 161 162 $serializer->deserialize('<?xml version="1.0"?> 163 <!DOCTYPE author [ 164 <!ENTITY foo SYSTEM "php://filter/read=convert.base64-encode/resource=' . basename(__FILE__) . '"> 165 ]> 166 <foo></foo>', 'stdClass', 'xml'); 167 } 168 169 public function testVirtualAttributes() 170 { 171 self::assertEquals( 172 $this->getContent('virtual_attributes'), 173 $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['attributes'])) 174 ); 175 } 176 177 public function testVirtualValues() 178 { 179 self::assertEquals( 180 $this->getContent('virtual_values'), 181 $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['values'])) 182 ); 183 } 184 185 public function testVirtualXmlList() 186 { 187 self::assertEquals( 188 $this->getContent('virtual_properties_list'), 189 $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['list'])) 190 ); 191 } 192 193 public function testVirtualXmlMap() 194 { 195 self::assertEquals( 196 $this->getContent('virtual_properties_map'), 197 $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['map'])) 198 ); 199 } 200 201 public function testUnserializeMissingArray() 202 { 203 $xml = '<result></result>'; 204 $object = $this->serializer->deserialize($xml, 'JMS\Serializer\Tests\Fixtures\ObjectWithAbsentXmlListNode', 'xml'); 205 self::assertEquals($object->absentAndNs, []); 206 207 $xml = '<result xmlns:x="http://www.example.com"> 208 <absent_and_ns> 209 <x:entry>foo</x:entry> 210 </absent_and_ns> 211 </result>'; 212 $object = $this->serializer->deserialize($xml, 'JMS\Serializer\Tests\Fixtures\ObjectWithAbsentXmlListNode', 'xml'); 213 self::assertEquals($object->absentAndNs, ['foo']); 214 } 215 216 public function testObjectWithNamespacesAndList() 217 { 218 $object = new ObjectWithNamespacesAndList(); 219 $object->name = 'name'; 220 $object->nameAlternativeB = 'nameB'; 221 222 $object->phones = ['111', '222']; 223 $object->addresses = ['A' => 'Street 1', 'B' => 'Street 2']; 224 225 $object->phonesAlternativeB = ['555', '666']; 226 $object->addressesAlternativeB = ['A' => 'Street 5', 'B' => 'Street 6']; 227 228 $object->phonesAlternativeC = ['777', '888']; 229 $object->addressesAlternativeC = ['A' => 'Street 7', 'B' => 'Street 8']; 230 231 $object->phonesAlternativeD = ['999', 'AAA']; 232 $object->addressesAlternativeD = ['A' => 'Street 9', 'B' => 'Street A']; 233 234 self::assertEquals( 235 $this->getContent('object_with_namespaces_and_list'), 236 $this->serialize($object, SerializationContext::create()) 237 ); 238 self::assertEquals( 239 $object, 240 $this->deserialize($this->getContent('object_with_namespaces_and_list'), get_class($object)) 241 ); 242 } 243 244 public function testObjectWithNamespaceAndNestedList() 245 { 246 $object = new ObjectWithNamespacesAndNestedList(); 247 $personCollection = new PersonCollection(); 248 $personA = new Person(); 249 $personA->age = 11; 250 $personA->name = 'AAA'; 251 252 $personB = new Person(); 253 $personB->age = 22; 254 $personB->name = 'BBB'; 255 256 $personCollection->persons->add($personA); 257 $personCollection->persons->add($personB); 258 259 $object->personCollection = $personCollection; 260 261 self::assertEquals( 262 $this->getContent('object_with_namespaces_and_nested_list'), 263 $this->serialize($object, SerializationContext::create()) 264 ); 265 self::assertEquals( 266 $object, 267 $this->deserialize($this->getContent('object_with_namespaces_and_nested_list'), get_class($object)) 268 ); 269 } 270 271 public function testArrayKeyValues() 272 { 273 self::assertEquals($this->getContent('array_key_values'), $this->serializer->serialize(new ObjectWithXmlKeyValuePairs(), 'xml')); 274 } 275 276 public function testDeserializeArrayKeyValues() 277 { 278 $xml = $this->getContent('array_key_values_with_type_1'); 279 $result = $this->serializer->deserialize($xml, ObjectWithXmlKeyValuePairsWithType::class, 'xml'); 280 281 self::assertInstanceOf(ObjectWithXmlKeyValuePairsWithType::class, $result); 282 self::assertEquals(ObjectWithXmlKeyValuePairsWithType::create1(), $result); 283 284 $xml2 = $this->getContent('array_key_values_with_type_2'); 285 $result2 = $this->serializer->deserialize($xml2, ObjectWithXmlKeyValuePairsWithType::class, 'xml'); 286 287 self::assertInstanceOf(ObjectWithXmlKeyValuePairsWithType::class, $result2); 288 self::assertEquals(ObjectWithXmlKeyValuePairsWithType::create2(), $result2); 289 } 290 291 public function testDeserializeTypedAndNestedArrayKeyValues() 292 { 293 $xml = $this->getContent('array_key_values_with_nested_type'); 294 $result = $this->serializer->deserialize($xml, ObjectWithXmlKeyValuePairsWithObjectType::class, 'xml'); 295 296 self::assertInstanceOf(ObjectWithXmlKeyValuePairsWithObjectType::class, $result); 297 self::assertEquals(ObjectWithXmlKeyValuePairsWithObjectType::create1(), $result); 298 } 299 300 /** 301 * @dataProvider getDateTime 302 * @group datetime 303 */ 304 public function testDateTimeNoCData($key, $value, $type) 305 { 306 $builder = SerializerBuilder::create(); 307 $builder->configureHandlers(static function (HandlerRegistryInterface $handlerRegistry) { 308 $handlerRegistry->registerSubscribingHandler(new DateHandler(\DateTime::ATOM, 'UTC', false)); 309 }); 310 $serializer = $builder->build(); 311 312 self::assertEquals($this->getContent($key . '_no_cdata'), $serializer->serialize($value, $this->getFormat())); 313 } 314 315 /** 316 * @dataProvider getDateTimeImmutable 317 * @group datetime 318 */ 319 public function testDateTimeImmutableNoCData($key, $value, $type) 320 { 321 $builder = SerializerBuilder::create(); 322 $builder->configureHandlers(static function (HandlerRegistryInterface $handlerRegistry) { 323 $handlerRegistry->registerSubscribingHandler(new DateHandler(\DateTime::ATOM, 'UTC', false)); 324 }); 325 $serializer = $builder->build(); 326 327 self::assertEquals($this->getContent($key . '_no_cdata'), $serializer->serialize($value, $this->getFormat())); 328 } 329 330 /** 331 * @expectedException JMS\Serializer\Exception\RuntimeException 332 * @expectedExceptionMessage Unsupported value type for XML attribute map. Expected array but got object 333 */ 334 public function testXmlAttributeMapWithoutArray() 335 { 336 $attributes = new \ArrayObject(['type' => 'text']); 337 338 $this->serializer->serialize(new Input($attributes), $this->getFormat()); 339 } 340 341 public function testObjectWithOnlyNamespacesAndList() 342 { 343 $object = new ObjectWithNamespacesAndList(); 344 345 $object->phones = []; 346 $object->addresses = []; 347 348 $object->phonesAlternativeB = []; 349 $object->addressesAlternativeB = []; 350 351 $object->phonesAlternativeC = ['777', '888']; 352 $object->addressesAlternativeC = ['A' => 'Street 7', 'B' => 'Street 8']; 353 354 $object->phonesAlternativeD = []; 355 $object->addressesAlternativeD = []; 356 357 self::assertEquals( 358 $this->getContent('object_with_only_namespaces_and_list'), 359 $this->serialize($object, SerializationContext::create()) 360 ); 361 362 $deserialized = $this->deserialize($this->getContent('object_with_only_namespaces_and_list'), get_class($object)); 363 self::assertEquals($object, $deserialized); 364 } 365 366 public function testDeserializingNull() 367 { 368 $this->markTestSkipped('Not supported in XML.'); 369 } 370 371 public function testObjectWithXmlNamespaces() 372 { 373 $object = new ObjectWithXmlNamespaces('This is a nice title.', 'Foo Bar', new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), 'en'); 374 375 $serialized = $this->serialize($object); 376 self::assertEquals($this->getContent('object_with_xml_namespaces'), $serialized); 377 378 $xml = simplexml_load_string($this->serialize($object)); 379 $xml->registerXPathNamespace('ns1', 'http://purl.org/dc/elements/1.1/'); 380 $xml->registerXPathNamespace('ns2', 'http://schemas.google.com/g/2005'); 381 $xml->registerXPathNamespace('ns3', 'http://www.w3.org/2005/Atom'); 382 383 self::assertEquals('2011-07-30T00:00:00+00:00', $this->xpathFirstToString($xml, './@created_at')); 384 self::assertEquals('e86ce85cdb1253e4fc6352f5cf297248bceec62b', $this->xpathFirstToString($xml, './@ns2:etag')); 385 self::assertEquals('en', $this->xpathFirstToString($xml, './@ns1:language')); 386 self::assertEquals('This is a nice title.', $this->xpathFirstToString($xml, './ns1:title')); 387 self::assertEquals('Foo Bar', $this->xpathFirstToString($xml, './ns3:author')); 388 389 $deserialized = $this->deserialize($this->getContent('object_with_xml_namespacesalias'), get_class($object)); 390 self::assertEquals('2011-07-30T00:00:00+00:00', $this->getField($deserialized, 'createdAt')->format(\DateTime::ATOM)); 391 self::assertAttributeEquals('This is a nice title.', 'title', $deserialized); 392 self::assertAttributeSame('e86ce85cdb1253e4fc6352f5cf297248bceec62b', 'etag', $deserialized); 393 self::assertAttributeSame('en', 'language', $deserialized); 394 self::assertAttributeEquals('Foo Bar', 'author', $deserialized); 395 } 396 397 public function testObjectWithXmlNamespacesAndBackReferencedNamespaces() 398 { 399 $author = new ObjectWithXmlNamespacesAndObjectPropertyAuthor('mr', 'smith'); 400 $object = new ObjectWithXmlNamespacesAndObjectProperty('This is a nice title.', $author); 401 402 $serialized = $this->serialize($object); 403 self::assertEquals($this->getContent('object_with_xml_namespaces_and_object_property'), $serialized); 404 } 405 406 public function testObjectWithXmlNamespacesAndBackReferencedNamespacesWithListeners() 407 { 408 $author = new ObjectWithXmlNamespacesAndObjectPropertyAuthor('mr', 'smith'); 409 $object = new ObjectWithXmlNamespacesAndObjectPropertyVirtual('This is a nice title.', new \stdClass()); 410 411 $this->handlerRegistry->registerHandler( 412 GraphNavigatorInterface::DIRECTION_SERIALIZATION, 413 'ObjectWithXmlNamespacesAndObjectPropertyAuthorVirtual', 414 $this->getFormat(), 415 static function (XmlSerializationVisitor $visitor, $data, $type, Context $context) use ($author) { 416 $factory = $context->getMetadataFactory(get_class($author)); 417 $classMetadata = $factory->getMetadataForClass(get_class($author)); 418 419 $metadata = new StaticPropertyMetadata(get_class($author), 'foo', $author); 420 $metadata->xmlNamespace = $classMetadata->xmlRootNamespace; 421 $metadata->xmlNamespace = $classMetadata->xmlRootNamespace; 422 423 $visitor->visitProperty($metadata, $author); 424 } 425 ); 426 427 $serialized = $this->serialize($object); 428 self::assertEquals($this->getContent('object_with_xml_namespaces_and_object_property_virtual'), $serialized); 429 } 430 431 public function testObjectWithXmlRootNamespace() 432 { 433 $object = new ObjectWithXmlRootNamespace('This is a nice title.', 'Foo Bar', new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), 'en'); 434 self::assertEquals($this->getContent('object_with_xml_root_namespace'), $this->serialize($object)); 435 } 436 437 public function testXmlNamespacesInheritance() 438 { 439 $object = new SimpleClassObject(); 440 $object->foo = 'foo'; 441 $object->bar = 'bar'; 442 $object->moo = 'moo'; 443 444 self::assertEquals($this->getContent('simple_class_object'), $this->serialize($object)); 445 446 $childObject = new SimpleSubClassObject(); 447 $childObject->foo = 'foo'; 448 $childObject->bar = 'bar'; 449 $childObject->moo = 'moo'; 450 $childObject->baz = 'baz'; 451 $childObject->qux = 'qux'; 452 453 self::assertEquals($this->getContent('simple_subclass_object'), $this->serialize($childObject)); 454 } 455 456 public function testWithoutFormatedOutputByXmlSerializationVisitor() 457 { 458 $xmlVisitor = new XmlSerializationVisitorFactory(); 459 $xmlVisitor->setFormatOutput(false); 460 461 $builder = SerializerBuilder::create(); 462 $builder->setSerializationVisitor('xml', $xmlVisitor); 463 $serializer = $builder->build(); 464 465 $object = new SimpleClassObject(); 466 $object->foo = 'foo'; 467 $object->bar = 'bar'; 468 $object->moo = 'moo'; 469 470 $stringXml = $serializer->serialize($object, $this->getFormat()); 471 self::assertXmlStringEqualsXmlString($this->getContent('simple_class_object_minified'), $stringXml); 472 } 473 474 public function testDiscriminatorAsXmlAttribute() 475 { 476 $xml = $this->serialize(new ObjectWithXmlAttributeDiscriminatorChild()); 477 self::assertEquals($this->getContent('xml_discriminator_attribute'), $xml); 478 self::assertInstanceOf( 479 ObjectWithXmlAttributeDiscriminatorChild::class, 480 $this->deserialize( 481 $xml, 482 ObjectWithXmlAttributeDiscriminatorParent::class 483 ) 484 ); 485 } 486 487 public function testDiscriminatorAsNotCData() 488 { 489 $xml = $this->serialize(new ObjectWithXmlNotCDataDiscriminatorChild()); 490 self::assertEquals($this->getContent('xml_discriminator_not_cdata'), $xml); 491 self::assertInstanceOf( 492 ObjectWithXmlNotCDataDiscriminatorChild::class, 493 $this->deserialize( 494 $xml, 495 ObjectWithXmlNotCDataDiscriminatorParent::class 496 ) 497 ); 498 } 499 500 public function testDiscriminatorWithNamespace() 501 { 502 $xml = $this->serialize(new ObjectWithXmlNamespaceDiscriminatorChild()); 503 self::assertEquals($this->getContent('xml_discriminator_namespace'), $xml); 504 505 self::assertInstanceOf( 506 ObjectWithXmlNamespaceDiscriminatorChild::class, 507 $this->deserialize( 508 $xml, 509 ObjectWithXmlNamespaceDiscriminatorParent::class 510 ) 511 ); 512 } 513 514 public function testDiscriminatorAsXmlAttributeWithNamespace() 515 { 516 $xml = $this->serialize(new ObjectWithXmlNamespaceAttributeDiscriminatorChild()); 517 self::assertEquals($this->getContent('xml_discriminator_namespace_attribute'), $xml); 518 519 self::assertInstanceOf( 520 ObjectWithXmlNamespaceAttributeDiscriminatorChild::class, 521 $this->deserialize( 522 $xml, 523 ObjectWithXmlNamespaceAttributeDiscriminatorParent::class 524 ) 525 ); 526 } 527 528 /** 529 * @expectedException \JMS\Serializer\Exception\XmlErrorException 530 */ 531 public function testDeserializeEmptyString() 532 { 533 $this->deserialize('', 'stdClass'); 534 } 535 536 public function testEvaluatesToNull() 537 { 538 $context = $this->getMockBuilder(DeserializationContext::class)->getMock(); 539 $navigator = $this->getMockBuilder(GraphNavigatorInterface::class)->getMock(); 540 541 $visitor = (new XmlDeserializationVisitorFactory())->getVisitor($navigator, $context); 542 $xsdNilAsTrueElement = simplexml_load_string('<empty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>'); 543 $xsdNilAsOneElement = simplexml_load_string('<empty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="1"/>'); 544 545 self::assertTrue($visitor->isNull($xsdNilAsTrueElement)); 546 self::assertTrue($visitor->isNull($xsdNilAsOneElement)); 547 self::assertTrue($visitor->isNull(null)); 548 } 549 550 public function testDoubleEncoding() 551 { 552 $context = $this->getMockBuilder(DeserializationContext::class)->getMock(); 553 $navigator = $this->getMockBuilder(GraphNavigatorInterface::class)->getMock(); 554 555 $visitor = (new XmlSerializationVisitorFactory())->getVisitor($navigator, $context); 556 557 // Setting locale with comma fractional separator 558 $locale = setlocale(LC_ALL, 0); 559 if (!setlocale(LC_ALL, 'ru_RU.UTF-8')) { 560 $this->markTestIncomplete('Required locale not available'); 561 } 562 563 self::assertEquals('0.0', $visitor->visitDouble(0, [])->data); 564 self::assertEquals('1.0', $visitor->visitDouble(1, [])->data); 565 self::assertEquals('1.1', $visitor->visitDouble(1.1, [])->data); 566 self::assertEquals('1.123456789', $visitor->visitDouble(1.123456789, [])->data); 567 568 // Switching locale back 569 setlocale(LC_ALL, $locale); 570 } 571 572 private function xpathFirstToString(\SimpleXMLElement $xml, $xpath) 573 { 574 $nodes = $xml->xpath($xpath); 575 return (string) reset($nodes); 576 } 577 578 /** 579 * @param string $key 580 */ 581 protected function getContent($key) 582 { 583 if (!file_exists($file = __DIR__ . '/xml/' . $key . '.xml')) { 584 throw new InvalidArgumentException(sprintf('The key "%s" is not supported.', $key)); 585 } 586 587 return file_get_contents($file); 588 } 589 590 protected function getFormat() 591 { 592 return 'xml'; 593 } 594} 595