1<?php 2 3declare(strict_types=1); 4 5namespace JMS\Serializer\Tests\Serializer; 6 7use Doctrine\Common\Annotations\AnnotationReader; 8use JMS\Serializer\Accessor\DefaultAccessorStrategy; 9use JMS\Serializer\Construction\UnserializeObjectConstructor; 10use JMS\Serializer\DeserializationContext; 11use JMS\Serializer\EventDispatcher\EventDispatcher; 12use JMS\Serializer\Exclusion\ExclusionStrategyInterface; 13use JMS\Serializer\GraphNavigator\DeserializationGraphNavigator; 14use JMS\Serializer\GraphNavigator\SerializationGraphNavigator; 15use JMS\Serializer\GraphNavigatorInterface; 16use JMS\Serializer\Handler\HandlerRegistry; 17use JMS\Serializer\Handler\SubscribingHandlerInterface; 18use JMS\Serializer\Metadata\Driver\AnnotationDriver; 19use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; 20use JMS\Serializer\SerializationContext; 21use JMS\Serializer\Visitor\DeserializationVisitorInterface; 22use JMS\Serializer\Visitor\SerializationVisitorInterface; 23use Metadata\MetadataFactory; 24use PHPUnit\Framework\TestCase; 25 26class GraphNavigatorTest extends TestCase 27{ 28 private $metadataFactory; 29 private $handlerRegistry; 30 private $objectConstructor; 31 private $dispatcher; 32 private $serializationNavigator; 33 private $deserializationNavigator; 34 private $context; 35 private $deserializationContext; 36 private $accessor; 37 38 private $serializationVisitor; 39 private $deserializationVisitor; 40 41 /** 42 * @expectedException JMS\Serializer\Exception\RuntimeException 43 * @expectedExceptionMessage Resources are not supported in serialized data. 44 */ 45 public function testResourceThrowsException() 46 { 47 $this->serializationNavigator->accept(STDIN, null); 48 } 49 50 public function testNavigatorPassesInstanceOnSerialization() 51 { 52 $object = new SerializableClass(); 53 $metadata = $this->metadataFactory->getMetadataForClass(get_class($object)); 54 55 $self = $this; 56 $this->context = $this->getMockBuilder(SerializationContext::class)->getMock(); 57 $context = $this->context; 58 $exclusionStrategy = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(); 59 $exclusionStrategy->expects($this->once()) 60 ->method('shouldSkipClass') 61 ->will($this->returnCallback(static function ($passedMetadata, $passedContext) use ($metadata, $context, $self) { 62 $self->assertSame($metadata, $passedMetadata); 63 $self->assertSame($context, $passedContext); 64 return false; 65 })); 66 $exclusionStrategy->expects($this->once()) 67 ->method('shouldSkipProperty') 68 ->will($this->returnCallback(static function ($propertyMetadata, $passedContext) use ($context, $metadata, $self) { 69 $self->assertSame($metadata->propertyMetadata['foo'], $propertyMetadata); 70 $self->assertSame($context, $passedContext); 71 return false; 72 })); 73 74 $this->context->expects($this->once()) 75 ->method('getExclusionStrategy') 76 ->will($this->returnValue($exclusionStrategy)); 77 78 $navigator = new SerializationGraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->accessor, $this->dispatcher); 79 $navigator->initialize($this->serializationVisitor, $this->context); 80 $navigator->accept($object, null); 81 } 82 83 public function testNavigatorPassesNullOnDeserialization() 84 { 85 $class = __NAMESPACE__ . '\SerializableClass'; 86 $metadata = $this->metadataFactory->getMetadataForClass($class); 87 88 $this->context = $this->getMockBuilder(DeserializationContext::class)->getMock(); 89 90 $context = $this->context; 91 $exclusionStrategy = $this->getMockBuilder(ExclusionStrategyInterface::class)->getMock(); 92 $exclusionStrategy->expects($this->once()) 93 ->method('shouldSkipClass') 94 ->with($metadata, $this->callback(static function ($navigatorContext) use ($context) { 95 return $navigatorContext === $context; 96 })); 97 98 $exclusionStrategy->expects($this->once()) 99 ->method('shouldSkipProperty') 100 ->with($metadata->propertyMetadata['foo'], $this->callback(static function ($navigatorContext) use ($context) { 101 return $navigatorContext === $context; 102 })); 103 104 $this->context->expects($this->once()) 105 ->method('getExclusionStrategy') 106 ->will($this->returnValue($exclusionStrategy)); 107 108 $navigator = new DeserializationGraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->objectConstructor, $this->accessor, $this->dispatcher); 109 $navigator->initialize($this->deserializationVisitor, $this->context); 110 $navigator->accept('random', ['name' => $class, 'params' => []]); 111 } 112 113 /** 114 * @doesNotPerformAssertions 115 */ 116 public function testNavigatorChangeTypeOnSerialization() 117 { 118 $object = new SerializableClass(); 119 $typeName = 'JsonSerializable'; 120 121 $this->dispatcher->addListener('serializer.pre_serialize', static function ($event) use ($typeName) { 122 $type = $event->getType(); 123 $type['name'] = $typeName; 124 $event->setType($type['name'], $type['params']); 125 }); 126 127 $this->handlerRegistry->registerSubscribingHandler(new TestSubscribingHandler()); 128 129 $navigator = new SerializationGraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->accessor, $this->dispatcher); 130 $navigator->initialize($this->serializationVisitor, $this->context); 131 $navigator->accept($object, null); 132 } 133 134 protected function setUp() 135 { 136 $this->deserializationVisitor = $this->getMockBuilder(DeserializationVisitorInterface::class)->getMock(); 137 $this->serializationVisitor = $this->getMockBuilder(SerializationVisitorInterface::class)->getMock(); 138 139 $this->context = $this->getMockBuilder(SerializationContext::class) 140 ->enableOriginalConstructor() 141 ->setMethodsExcept(['getExclusionStrategy']) 142 ->getMock(); 143 144 $this->deserializationContext = $this->getMockBuilder(DeserializationContext::class) 145 ->enableOriginalConstructor() 146 ->setMethodsExcept(['getExclusionStrategy']) 147 ->getMock(); 148 149 $this->dispatcher = new EventDispatcher(); 150 $this->accessor = new DefaultAccessorStrategy(); 151 $this->handlerRegistry = new HandlerRegistry(); 152 $this->objectConstructor = new UnserializeObjectConstructor(); 153 154 $this->metadataFactory = new MetadataFactory(new AnnotationDriver(new AnnotationReader(), new IdenticalPropertyNamingStrategy())); 155 156 $this->serializationNavigator = new SerializationGraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->accessor, $this->dispatcher); 157 $this->serializationNavigator->initialize($this->serializationVisitor, $this->context); 158 159 $this->deserializationNavigator = new DeserializationGraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->objectConstructor, $this->accessor, $this->dispatcher); 160 $this->deserializationNavigator->initialize($this->deserializationVisitor, $this->deserializationContext); 161 } 162} 163 164class SerializableClass 165{ 166 public $foo = 'bar'; 167} 168 169class TestSubscribingHandler implements SubscribingHandlerInterface 170{ 171 public static function getSubscribingMethods() 172 { 173 return [[ 174 'type' => 'JsonSerializable', 175 'format' => 'foo', 176 'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION, 177 'method' => 'serialize', 178 ], 179 ]; 180 } 181} 182