[!!!][TASK] Replace ClassInfo with ClassSchema
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Property / TypeConverter / PersistentObjectConverterTest.php
index 6d7cccd..a289057 100644 (file)
@@ -20,368 +20,451 @@ namespace TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter;
  *                                                                        *
  * The TYPO3 project - inspiring people to share!                         *
  *                                                                        */
-
-require_once __DIR__ . '/../../../Fixture/ClassWithSetters.php';
-require_once __DIR__ . '/../../../Fixture/ClassWithSettersAndConstructor.php';
+use TYPO3\CMS\Extbase\Property\Exception\DuplicateObjectException;
+use TYPO3\CMS\Extbase\Property\Exception\InvalidPropertyMappingConfigurationException;
+use TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException;
+use TYPO3\CMS\Extbase\Property\Exception\TargetNotFoundException;
+use TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter;
+use TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter\Fixtures\PersistentObjectEntityFixture;
+use TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter\Fixtures\PersistentObjectFixture;
+use TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter\Fixtures\PersistentObjectValueObjectFixture;
 
 /**
- * Testcase for the PersistentObjectConverter
- *
- * @covers \TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter<extended>
+ * Test case
  */
-class PersistentObjectConverterTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
-
-       /**
-        * @var \TYPO3\CMS\Extbase\Property\TypeConverterInterface
-        */
-       protected $converter;
-
-       protected $mockReflectionService;
-       protected $mockPersistenceManager;
-       protected $mockObjectManager;
-
-       public function setUp() {
-               $this->converter = new \TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter();
-               $this->mockReflectionService = $this->getMock('TYPO3\CMS\Extbase\Reflection\ReflectionService');
-               $this->inject($this->converter, 'reflectionService', $this->mockReflectionService);
-
-               $this->mockPersistenceManager = $this->getMock('TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface');
-               $this->inject($this->converter, 'persistenceManager', $this->mockPersistenceManager);
-
-               $this->mockObjectManager = $this->getMock('TYPO3\CMS\Extbase\Object\ObjectManagerInterface');
-               $this->mockObjectManager->expects($this->any())
-                       ->method('get')
-                       ->will($this->returnCallback(function() {
-                                       $args = func_get_args();
-                                       $reflectionClass = new \ReflectionClass(array_shift($args));
-                                       if (empty($args)) {
-                                               return $reflectionClass->newInstance();
-                                       } else {
-                                               return $reflectionClass->newInstanceArgs($args);
-                                       }
-                               }));
-               $this->inject($this->converter, 'objectManager', $this->mockObjectManager);
-       }
-
-       /**
-        * @test
-        */
-       public function checkMetadata() {
-               $this->assertEquals(array('string', 'array'), $this->converter->getSupportedSourceTypes(), 'Source types do not match');
-               $this->assertEquals('object', $this->converter->getSupportedTargetType(), 'Target type does not match');
-               $this->assertEquals(1, $this->converter->getPriority(), 'Priority does not match');
-       }
-
-       public function dataProviderForCanConvert() {
-               return array(
-                       array(TRUE, FALSE, TRUE),
-                       // is entity => can convert
-                       array(FALSE, TRUE, TRUE),
-                       // is valueobject => can convert
-                       array(FALSE, FALSE, FALSE),
-                       // is no entity and no value object => can not convert
-               );
-       }
-
-       /**
-        * @test
-        * @dataProvider dataProviderForCanConvert
-        */
-       public function canConvertFromReturnsTrueIfClassIsTaggedWithEntityOrValueObject($isEntity, $isValueObject, $expected) {
-               $className = uniqid('Test_Class');
-               if ($isEntity) {
-                       eval("class {$className} extends Tx_Extbase_DomainObject_AbstractEntity {}");
-               } elseif ($isValueObject) {
-                       eval("class {$className} extends Tx_Extbase_DomainObject_AbstractValueObject {}");
-               } else {
-                       eval("class {$className} {}");
-               }
-               $this->assertEquals($expected, $this->converter->canConvertFrom('myInputData', $className));
-       }
-
-       /**
-        * @test
-        */
-       public function getSourceChildPropertiesToBeConvertedReturnsAllPropertiesExceptTheIdentityProperty() {
-               $source = array(
-                       'k1' => 'v1',
-                       '__identity' => 'someIdentity',
-                       'k2' => 'v2'
-               );
-               $expected = array(
-                       'k1' => 'v1',
-                       'k2' => 'v2'
-               );
-               $this->assertEquals($expected, $this->converter->getSourceChildPropertiesToBeConverted($source));
-       }
-
-       /**
-        * @test
-        */
-       public function getTypeOfChildPropertyShouldUseReflectionServiceToDetermineType() {
-               $mockSchema = $this->getMockBuilder('TYPO3\\CMS\\Extbase\\Reflection\\ClassSchema')->disableOriginalConstructor()->getMock();
-               $this->mockReflectionService->expects($this->any())->method('getClassSchema')->with('TheTargetType')->will($this->returnValue($mockSchema));
-
-               $mockSchema->expects($this->any())->method('hasProperty')->with('thePropertyName')->will($this->returnValue(TRUE));
-               $mockSchema->expects($this->any())->method('getProperty')->with('thePropertyName')->will($this->returnValue(array(
-                       'type' => 'TheTypeOfSubObject',
-                       'elementType' => NULL
-               )));
-               $configuration = $this->buildConfiguration(array());
-               $this->assertEquals('TheTypeOfSubObject', $this->converter->getTypeOfChildProperty('TheTargetType', 'thePropertyName', $configuration));
-       }
-
-       /**
-        * @test
-        */
-       public function getTypeOfChildPropertyShouldUseConfiguredTypeIfItWasSet() {
-               $this->mockReflectionService->expects($this->never())->method('getClassSchema');
-
-               $configuration = $this->buildConfiguration(array());
-               $configuration->forProperty('thePropertyName')->setTypeConverterOption('TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter', \TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_TARGET_TYPE, 'Foo\Bar');
-               $this->assertEquals('Foo\Bar', $this->converter->getTypeOfChildProperty('foo', 'thePropertyName', $configuration));
-       }
-
-       /**
-        * @test
-        */
-       public function convertFromShouldFetchObjectFromPersistenceIfUuidStringIsGiven() {
-               $identifier = '17';
-               $object = new \stdClass();
-
-               $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
-               $this->assertSame($object, $this->converter->convertFrom($identifier, 'MySpecialType'));
-       }
-
-       /**
-        * @test
-        */
-       public function convertFromShouldFetchObjectFromPersistenceIfuidStringIsGiven() {
-               $identifier = '17';
-               $object = new \stdClass();
-
-               $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
-               $this->assertSame($object, $this->converter->convertFrom($identifier, 'MySpecialType'));
-       }
-
-       /**
-        * @test
-        */
-       public function convertFromShouldFetchObjectFromPersistenceIfOnlyIdentityArrayGiven() {
-               $identifier = '12345';
-               $object = new \stdClass();
-
-               $source = array(
-                       '__identity' => $identifier
-               );
-               $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
-               $this->assertSame($object, $this->converter->convertFrom($source, 'MySpecialType'));
-       }
-
-       /**
-        * @test
-        * @expectedException \TYPO3\CMS\Extbase\Property\Exception\InvalidPropertyMappingConfigurationException
-        */
-       public function convertFromShouldThrowExceptionIfObjectNeedsToBeModifiedButConfigurationIsNotSet() {
-               $identifier = '12345';
-               $object = new \stdClass();
-               $object->someProperty = 'asdf';
-
-               $source = array(
-                       '__identity' => $identifier,
-                       'foo' => 'bar'
-               );
-               $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
-               $this->converter->convertFrom($source, 'MySpecialType');
-       }
-
-       /**
-        * @param array $typeConverterOptions
-        * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration
-        */
-       protected function buildConfiguration($typeConverterOptions) {
-               $configuration = new \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration();
-               $configuration->setTypeConverterOptions('TYPO3\\CMS\\Extbase\\Property\\TypeConverter\\PersistentObjectConverter', $typeConverterOptions);
-               return $configuration;
-       }
-
-       /**
-        * @param integer $numberOfResults
-        * @param Matcher $howOftenIsGetFirstCalled
-        * @return \stdClass
-        */
-       public function setupMockQuery($numberOfResults, $howOftenIsGetFirstCalled) {
-               $mockClassSchema = $this->getMock('TYPO3\\CMS\\Extbase\\Reflection\\ClassSchema', array(), array('Dummy'));
-               $mockClassSchema->expects($this->any())->method('getIdentityProperties')->will($this->returnValue(array('key1' => 'someType')));
-               $this->mockReflectionService->expects($this->any())->method('getClassSchema')->with('SomeType')->will($this->returnValue($mockClassSchema));
-
-               $mockConstraint = $this->getMockBuilder('TYPO3\CMS\Extbase\Persistence\Generic\Qom\Comparison')->disableOriginalConstructor()->getMock();
-
-               $mockObject = new \stdClass();
-               $mockQuery = $this->getMock('TYPO3\\CMS\\Extbase\\Persistence\\QueryInterface');
-               $mockQueryResult = $this->getMock('TYPO3\\CMS\\Extbase\\Persistence\\QueryResultInterface');
-               $mockQueryResult->expects($this->any())->method('count')->will($this->returnValue($numberOfResults));
-               $mockQueryResult->expects($howOftenIsGetFirstCalled)->method('getFirst')->will($this->returnValue($mockObject));
-               $mockQuery->expects($this->any())->method('equals')->with('key1', 'value1')->will($this->returnValue($mockConstraint));
-               $mockQuery->expects($this->any())->method('matching')->with($mockConstraint)->will($this->returnValue($mockQuery));
-               $mockQuery->expects($this->any())->method('execute')->will($this->returnValue($mockQueryResult));
-
-               $this->mockPersistenceManager->expects($this->any())->method('createQueryForType')->with('SomeType')->will($this->returnValue($mockQuery));
-
-               return $mockObject;
-       }
-
-       /**
-        * @test
-        * @expectedException \TYPO3\CMS\Extbase\Property\Exception\TargetNotFoundException
-        */
-       public function convertFromShouldReturnExceptionIfNoMatchingObjectWasFound() {
-               $this->setupMockQuery(0, $this->never());
-               $this->mockReflectionService->expects($this->never())->method('getClassSchema');
-
-               $source = array(
-                       '__identity' => 123
-               );
-               $actual = $this->converter->convertFrom($source, 'SomeType');
-               $this->assertNull($actual);
-       }
-
-       /**
-        * @test
-        * @expectedException \TYPO3\CMS\Extbase\Property\Exception\DuplicateObjectException
-        */
-       public function convertFromShouldThrowExceptionIfMoreThanOneObjectWasFound() {
-               $this->setupMockQuery(2, $this->never());
-
-               $source = array(
-                       '__identity' => 666
-               );
-               $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with(666)->will($this->throwException(new \TYPO3\CMS\Extbase\Property\Exception\DuplicateObjectException));
-               $this->converter->convertFrom($source, 'SomeType');
-       }
-
-       /**
-        * @test
-        * @expectedException \TYPO3\CMS\Extbase\Property\Exception\InvalidPropertyMappingConfigurationException
-        */
-       public function convertFromShouldThrowExceptionIfObjectNeedsToBeCreatedButConfigurationIsNotSet() {
-               $source = array(
-                       'foo' => 'bar'
-               );
-               $this->converter->convertFrom($source, 'MySpecialType');
-       }
-
-       /**
-        * @test
-        */
-       public function convertFromShouldCreateObject() {
-               $source = array(
-                       'propertyX' => 'bar'
-               );
-               $convertedChildProperties = array(
-                       'property1' => 'bar'
-               );
-               $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters();
-               $expectedObject->property1 = 'bar';
-
-               $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters', '__construct')->will($this->throwException(new \ReflectionException()));
-               $this->mockObjectManager->expects($this->any())->method('getClassNameByObjectName')->with('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters')->will($this->returnValue('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters'));
-               $configuration = $this->buildConfiguration(array(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => TRUE));
-               $result = $this->converter->convertFrom($source, 'TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters', $convertedChildProperties, $configuration);
-               $this->assertEquals($expectedObject, $result);
-       }
-
-       /**
-        * @test
-        * @expectedException \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException
-        */
-       public function convertFromShouldThrowExceptionIfPropertyOnTargetObjectCouldNotBeSet() {
-               $source = array(
-                       'propertyX' => 'bar'
-               );
-               $object = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters();
-               $convertedChildProperties = array(
-                       'propertyNotExisting' => 'bar'
-               );
-               $this->mockObjectManager->expects($this->any())->method('get')->with('TYPO3\\CMS\\Extbase\\Tests\\Fixture\\ClassWithSetters')->will($this->returnValue($object));
-               $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with('TYPO3\\CMS\\Extbase\\Tests\\Fixture\\ClassWithSetters', '__construct')->will($this->returnValue(array()));
-               $configuration = $this->buildConfiguration(array(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => TRUE));
-               $result = $this->converter->convertFrom($source, 'TYPO3\\CMS\\Extbase\\Tests\\Fixture\\ClassWithSetters', $convertedChildProperties, $configuration);
-               $this->assertSame($object, $result);
-       }
-
-       /**
-        * @test
-        */
-       public function convertFromShouldCreateObjectWhenThereAreConstructorParameters() {
-               $source = array(
-                       'propertyX' => 'bar'
-               );
-               $convertedChildProperties = array(
-                       'property1' => 'param1',
-                       'property2' => 'bar'
-               );
-               $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('param1');
-               $expectedObject->setProperty2('bar');
-
-               $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor', '__construct')->will($this->returnValue(array(
-                       'property1' => array('optional' => FALSE)
-               )));
-               $this->mockObjectManager->expects($this->any())->method('getClassNameByObjectName')->with('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor')->will($this->returnValue('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor'));
-               $configuration = $this->buildConfiguration(array(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => TRUE));
-               $result = $this->converter->convertFrom($source, 'TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor', $convertedChildProperties, $configuration);
-               $this->assertEquals($expectedObject, $result);
-               $this->assertEquals('bar', $expectedObject->getProperty2());
-       }
-
-       /**
-        * @test
-        */
-       public function convertFromShouldCreateObjectWhenThereAreOptionalConstructorParameters() {
-               $source = array(
-                       'propertyX' => 'bar'
-               );
-               $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('thisIsTheDefaultValue');
-
-               $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor', '__construct')->will($this->returnValue(array(
-                       'property1' => array('optional' => TRUE, 'defaultValue' => 'thisIsTheDefaultValue')
-               )));
-               $this->mockObjectManager->expects($this->any())->method('getClassNameByObjectName')->with('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor')->will($this->returnValue('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor'));
-               $configuration = $this->buildConfiguration(array(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => TRUE));
-               $result = $this->converter->convertFrom($source, 'TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor', array(), $configuration);
-               $this->assertEquals($expectedObject, $result);
-       }
-
-       /**
-        * @test
-        * @expectedException \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException
-        */
-       public function convertFromShouldThrowExceptionIfRequiredConstructorParameterWasNotFound() {
-               $source = array(
-                       'propertyX' => 'bar'
-               );
-               $object = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('param1');
-               $convertedChildProperties = array(
-                       'property2' => 'bar'
-               );
-
-               $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor', '__construct')->will($this->returnValue(array(
-                       'property1' => array('optional' => FALSE)
-               )));
-               $this->mockObjectManager->expects($this->any())->method('getClassNameByObjectName')->with('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor')->will($this->returnValue('TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor'));
-               $configuration = $this->buildConfiguration(array(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => TRUE));
-               $result = $this->converter->convertFrom($source, 'TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor', $convertedChildProperties, $configuration);
-               $this->assertSame($object, $result);
-       }
-
-       /**
-        * @test
-        */
-       public function convertFromShouldReturnNullForEmptyString() {
-               $source = '';
-               $result = $this->converter->convertFrom($source, 'TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor');
-               $this->assertNull($result);
-       }
-
+class PersistentObjectConverterTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
+{
+    /**
+     * @var \TYPO3\CMS\Extbase\Property\TypeConverterInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $converter;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $mockReflectionService;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $mockPersistenceManager;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $mockObjectManager;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Object\Container\Container|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $mockContainer;
+
+    /**
+     * @throws \InvalidArgumentException
+     * @throws \PHPUnit\Framework\Exception
+     * @throws \RuntimeException
+     */
+    protected function setUp()
+    {
+        $this->converter = new PersistentObjectConverter();
+        $this->mockReflectionService = $this->createMock(\TYPO3\CMS\Extbase\Reflection\ReflectionService::class);
+        $this->inject($this->converter, 'reflectionService', $this->mockReflectionService);
+
+        $this->mockPersistenceManager = $this->createMock(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface::class);
+        $this->inject($this->converter, 'persistenceManager', $this->mockPersistenceManager);
+
+        $this->mockObjectManager = $this->createMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
+        $this->mockObjectManager->expects($this->any())
+            ->method('get')
+            ->will($this->returnCallback(function ($className, ...$arguments) {
+                $reflectionClass = new \ReflectionClass($className);
+                if (empty($arguments)) {
+                    return $reflectionClass->newInstance();
+                }
+                return $reflectionClass->newInstanceArgs($arguments);
+            }));
+        $this->inject($this->converter, 'objectManager', $this->mockObjectManager);
+
+        $this->mockContainer = $this->createMock(\TYPO3\CMS\Extbase\Object\Container\Container::class);
+        $this->inject($this->converter, 'objectContainer', $this->mockContainer);
+    }
+
+    /**
+     * @test
+     */
+    public function checkMetadata()
+    {
+        $this->assertEquals(['integer', 'string', 'array'], $this->converter->getSupportedSourceTypes(), 'Source types do not match');
+        $this->assertEquals('object', $this->converter->getSupportedTargetType(), 'Target type does not match');
+        $this->assertEquals(20, $this->converter->getPriority(), 'Priority does not match');
+    }
+
+    /**
+     * @return array
+     */
+    public function dataProviderForCanConvert()
+    {
+        return [
+            [true, false, true],
+            // is entity => can convert
+            [false, true, true],
+            // is valueobject => can convert
+            [false, false, false],
+            // is no entity and no value object => can not convert
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider dataProviderForCanConvert
+     */
+    public function canConvertFromReturnsTrueIfClassIsTaggedWithEntityOrValueObject($isEntity, $isValueObject, $expected)
+    {
+        $className = PersistentObjectFixture::class;
+
+        if ($isEntity) {
+            $className = PersistentObjectEntityFixture::class;
+        } elseif ($isValueObject) {
+            $className = PersistentObjectValueObjectFixture::class;
+        }
+        $this->assertEquals($expected, $this->converter->canConvertFrom('myInputData', $className));
+    }
+
+    /**
+     * @test
+     */
+    public function getSourceChildPropertiesToBeConvertedReturnsAllPropertiesExceptTheIdentityProperty()
+    {
+        $source = [
+            'k1' => 'v1',
+            '__identity' => 'someIdentity',
+            'k2' => 'v2'
+        ];
+        $expected = [
+            'k1' => 'v1',
+            'k2' => 'v2'
+        ];
+        $this->assertEquals($expected, $this->converter->getSourceChildPropertiesToBeConverted($source));
+    }
+
+    /**
+     * @test
+     */
+    public function getTypeOfChildPropertyShouldUseReflectionServiceToDetermineType()
+    {
+        $mockSchema = $this->getMockBuilder(\TYPO3\CMS\Extbase\Reflection\ClassSchema::class)->disableOriginalConstructor()->getMock();
+        $this->mockReflectionService->expects($this->any())->method('getClassSchema')->with('TheTargetType')->will($this->returnValue($mockSchema));
+
+        $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue('TheTargetType'));
+        $mockSchema->expects($this->any())->method('hasProperty')->with('thePropertyName')->will($this->returnValue(true));
+        $mockSchema->expects($this->any())->method('getProperty')->with('thePropertyName')->will($this->returnValue([
+            'type' => 'TheTypeOfSubObject',
+            'elementType' => null
+        ]));
+        $configuration = $this->buildConfiguration([]);
+        $this->assertEquals('TheTypeOfSubObject', $this->converter->getTypeOfChildProperty('TheTargetType', 'thePropertyName', $configuration));
+    }
+
+    /**
+     * @test
+     */
+    public function getTypeOfChildPropertyShouldUseConfiguredTypeIfItWasSet()
+    {
+        $this->mockReflectionService->expects($this->never())->method('getClassSchema');
+        $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue('foo'));
+
+        $configuration = $this->buildConfiguration([]);
+        $configuration->forProperty('thePropertyName')->setTypeConverterOption(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, PersistentObjectConverter::CONFIGURATION_TARGET_TYPE, 'Foo\Bar');
+        $this->assertEquals('Foo\Bar', $this->converter->getTypeOfChildProperty('foo', 'thePropertyName', $configuration));
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldFetchObjectFromPersistenceIfUuidStringIsGiven()
+    {
+        $identifier = '17';
+        $object = new \stdClass();
+
+        $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
+        $this->assertSame($object, $this->converter->convertFrom($identifier, 'MySpecialType'));
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldFetchObjectFromPersistenceIfuidStringIsGiven()
+    {
+        $identifier = '17';
+        $object = new \stdClass();
+
+        $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
+        $this->assertSame($object, $this->converter->convertFrom($identifier, 'MySpecialType'));
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldFetchObjectFromPersistenceIfOnlyIdentityArrayGiven()
+    {
+        $identifier = '12345';
+        $object = new \stdClass();
+
+        $source = [
+            '__identity' => $identifier
+        ];
+        $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
+        $this->assertSame($object, $this->converter->convertFrom($source, 'MySpecialType'));
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldThrowExceptionIfObjectNeedsToBeModifiedButConfigurationIsNotSet()
+    {
+        $this->expectException(InvalidPropertyMappingConfigurationException::class);
+        $this->expectExceptionCode(1297932028);
+        $identifier = '12345';
+        $object = new \stdClass();
+        $object->someProperty = 'asdf';
+
+        $source = [
+            '__identity' => $identifier,
+            'foo' => 'bar'
+        ];
+        $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
+        $this->converter->convertFrom($source, 'MySpecialType');
+    }
+
+    /**
+     * @param array $typeConverterOptions
+     * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration
+     */
+    protected function buildConfiguration($typeConverterOptions)
+    {
+        $configuration = new \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration();
+        $configuration->setTypeConverterOptions(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, $typeConverterOptions);
+        return $configuration;
+    }
+
+    /**
+     * @param int $numberOfResults
+     * @param Matcher $howOftenIsGetFirstCalled
+     * @return \stdClass
+     */
+    public function setupMockQuery($numberOfResults, $howOftenIsGetFirstCalled)
+    {
+        $mockClassSchema = $this->getMockBuilder(\TYPO3\CMS\Extbase\Reflection\ClassSchema::class)
+            ->setConstructorArgs([\TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter\Fixtures\Query::class])
+            ->getMock();
+        $mockClassSchema->expects($this->any())->method('getIdentityProperties')->will($this->returnValue(['key1' => 'someType']));
+        $this->mockReflectionService->expects($this->any())->method('getClassSchema')->with('SomeType')->will($this->returnValue($mockClassSchema));
+
+        $mockConstraint = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Comparison::class)->disableOriginalConstructor()->getMock();
+
+        $mockObject = new \stdClass();
+        $mockQuery = $this->createMock(\TYPO3\CMS\Extbase\Persistence\QueryInterface::class);
+        $mockQueryResult = $this->createMock(\TYPO3\CMS\Extbase\Persistence\QueryResultInterface::class);
+        $mockQueryResult->expects($this->any())->method('count')->will($this->returnValue($numberOfResults));
+        $mockQueryResult->expects($howOftenIsGetFirstCalled)->method('getFirst')->will($this->returnValue($mockObject));
+        $mockQuery->expects($this->any())->method('equals')->with('key1', 'value1')->will($this->returnValue($mockConstraint));
+        $mockQuery->expects($this->any())->method('matching')->with($mockConstraint)->will($this->returnValue($mockQuery));
+        $mockQuery->expects($this->any())->method('execute')->will($this->returnValue($mockQueryResult));
+
+        $this->mockPersistenceManager->expects($this->any())->method('createQueryForType')->with('SomeType')->will($this->returnValue($mockQuery));
+
+        return $mockObject;
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldReturnExceptionIfNoMatchingObjectWasFound()
+    {
+        $this->expectException(TargetNotFoundException::class);
+        $this->expectExceptionCode(1297933823);
+        $this->setupMockQuery(0, $this->never());
+        $this->mockReflectionService->expects($this->never())->method('getClassSchema');
+
+        $source = [
+            '__identity' => 123
+        ];
+        $actual = $this->converter->convertFrom($source, 'SomeType');
+        $this->assertNull($actual);
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldThrowExceptionIfMoreThanOneObjectWasFound()
+    {
+        $this->expectException(DuplicateObjectException::class);
+        // @TODO expectExceptionCode is 0
+        $this->setupMockQuery(2, $this->never());
+
+        $source = [
+            '__identity' => 666
+        ];
+        $this->mockPersistenceManager
+            ->expects($this->any())
+            ->method('getObjectByIdentifier')
+            ->with(666)
+            ->will($this->throwException(new DuplicateObjectException('testing', 1476107580)));
+        $this->converter->convertFrom($source, 'SomeType');
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldThrowExceptionIfObjectNeedsToBeCreatedButConfigurationIsNotSet()
+    {
+        $this->expectException(InvalidPropertyMappingConfigurationException::class);
+        // @TODO expectExceptionCode is 0
+        $source = [
+            'foo' => 'bar'
+        ];
+        $this->converter->convertFrom($source, 'MySpecialType');
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldCreateObject()
+    {
+        $source = [
+            'propertyX' => 'bar'
+        ];
+        $convertedChildProperties = [
+            'property1' => 'bar'
+        ];
+        $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters();
+        $expectedObject->property1 = 'bar';
+
+        $this->mockReflectionService
+            ->expects($this->any())
+            ->method('getMethodParameters')
+            ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, '__construct')
+            ->will($this->throwException(new \ReflectionException('testing', 1476107618)));
+        $configuration = $this->buildConfiguration([PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true]);
+        $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, $convertedChildProperties, $configuration);
+        $this->assertEquals($expectedObject, $result);
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldThrowExceptionIfPropertyOnTargetObjectCouldNotBeSet()
+    {
+        $this->expectException(InvalidTargetException::class);
+        $this->expectExceptionCode(1297935345);
+        $source = [
+            'propertyX' => 'bar'
+        ];
+        $object = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters();
+        $convertedChildProperties = [
+            'propertyNotExisting' => 'bar'
+        ];
+        $this->mockObjectManager->expects($this->any())->method('get')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class)->will($this->returnValue($object));
+        $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, '__construct')->will($this->returnValue([]));
+        $configuration = $this->buildConfiguration([PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true]);
+        $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, $convertedChildProperties, $configuration);
+        $this->assertSame($object, $result);
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldCreateObjectWhenThereAreConstructorParameters()
+    {
+        $source = [
+            'propertyX' => 'bar'
+        ];
+        $convertedChildProperties = [
+            'property1' => 'param1',
+            'property2' => 'bar'
+        ];
+        $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('param1');
+        $expectedObject->setProperty2('bar');
+
+        $this->mockReflectionService
+                ->expects($this->any())
+                ->method('getMethodParameters')
+                ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
+                ->will($this->returnValue([
+                    'property1' => ['optional' => false]
+                ]));
+        $this->mockReflectionService
+                ->expects($this->any())
+                ->method('hasMethod')
+                ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
+                ->will($this->returnValue(true));
+        $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
+        $configuration = $this->buildConfiguration([PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true]);
+        $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, $convertedChildProperties, $configuration);
+        $this->assertEquals($expectedObject, $result);
+        $this->assertEquals('bar', $expectedObject->getProperty2());
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldCreateObjectWhenThereAreOptionalConstructorParameters()
+    {
+        $source = [
+            'propertyX' => 'bar'
+        ];
+        $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('thisIsTheDefaultValue');
+
+        $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')->will($this->returnValue([
+            'property1' => ['optional' => true, 'defaultValue' => 'thisIsTheDefaultValue']
+        ]));
+        $this->mockReflectionService
+                ->expects($this->any())
+                ->method('hasMethod')
+                ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
+                ->will($this->returnValue(true));
+        $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
+        $configuration = $this->buildConfiguration([PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true]);
+        $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, [], $configuration);
+        $this->assertEquals($expectedObject, $result);
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldThrowExceptionIfRequiredConstructorParameterWasNotFound()
+    {
+        $this->expectException(InvalidTargetException::class);
+        $this->expectExceptionCode(1268734872);
+        $source = [
+            'propertyX' => 'bar'
+        ];
+        $object = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('param1');
+        $convertedChildProperties = [
+            'property2' => 'bar'
+        ];
+
+        $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')->will($this->returnValue([
+            'property1' => ['optional' => false]
+        ]));
+        $this->mockReflectionService
+                ->expects($this->any())
+                ->method('hasMethod')
+                ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
+                ->will($this->returnValue(true));
+        $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
+        $configuration = $this->buildConfiguration([PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true]);
+        $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, $convertedChildProperties, $configuration);
+        $this->assertSame($object, $result);
+    }
+
+    /**
+     * @test
+     */
+    public function convertFromShouldReturnNullForEmptyString()
+    {
+        $source = '';
+        $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class);
+        $this->assertNull($result);
+    }
 }
-?>
\ No newline at end of file