[TASK] Use variable argument-lists instead of func_get_args()
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Property / TypeConverter / PersistentObjectConverterTest.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter;
3
4 /* *
5 * This script belongs to the Extbase framework. *
6 * *
7 * It is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU Lesser General Public License as published by the *
9 * Free Software Foundation, either version 3 of the License, or (at your *
10 * option) any later version. *
11 * *
12 * This script is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
14 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
15 * General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with the script. *
19 * If not, see http://www.gnu.org/licenses/lgpl.html *
20 * *
21 * The TYPO3 project - inspiring people to share! *
22 * */
23 use TYPO3\CMS\Core\Tests\UnitTestCase;
24 use TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter;
25 use TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter\Fixtures\PersistentObjectEntityFixture;
26 use TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter\Fixtures\PersistentObjectFixture;
27 use TYPO3\CMS\Extbase\Tests\Unit\Property\TypeConverter\Fixtures\PersistentObjectValueObjectFixture;
28
29 /**
30 * Test case
31 */
32 class PersistentObjectConverterTest extends UnitTestCase
33 {
34 /**
35 * @var \TYPO3\CMS\Extbase\Property\TypeConverterInterface|\PHPUnit_Framework_MockObject_MockObject
36 */
37 protected $converter;
38
39 /**
40 * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService|\PHPUnit_Framework_MockObject_MockObject
41 */
42 protected $mockReflectionService;
43
44 /**
45 * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface|\PHPUnit_Framework_MockObject_MockObject
46 */
47 protected $mockPersistenceManager;
48
49 /**
50 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
51 */
52 protected $mockObjectManager;
53
54 /**
55 * @var \TYPO3\CMS\Extbase\Object\Container\Container|\PHPUnit_Framework_MockObject_MockObject
56 */
57 protected $mockContainer;
58
59 /**
60 * @throws \InvalidArgumentException
61 * @throws \PHPUnit_Framework_Exception
62 * @throws \RuntimeException
63 */
64 protected function setUp()
65 {
66 $this->converter = new PersistentObjectConverter();
67 $this->mockReflectionService = $this->getMock(\TYPO3\CMS\Extbase\Reflection\ReflectionService::class);
68 $this->inject($this->converter, 'reflectionService', $this->mockReflectionService);
69
70 $this->mockPersistenceManager = $this->getMock(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface::class);
71 $this->inject($this->converter, 'persistenceManager', $this->mockPersistenceManager);
72
73 $this->mockObjectManager = $this->getMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
74 $this->mockObjectManager->expects($this->any())
75 ->method('get')
76 ->will($this->returnCallback(function ($className, ...$arguments) {
77 $reflectionClass = new \ReflectionClass($className);
78 if (empty($arguments)) {
79 return $reflectionClass->newInstance();
80 } else {
81 return $reflectionClass->newInstanceArgs($arguments);
82 }
83 }));
84 $this->inject($this->converter, 'objectManager', $this->mockObjectManager);
85
86 $this->mockContainer = $this->getMock(\TYPO3\CMS\Extbase\Object\Container\Container::class);
87 $this->inject($this->converter, 'objectContainer', $this->mockContainer);
88 }
89
90 /**
91 * @test
92 */
93 public function checkMetadata()
94 {
95 $this->assertEquals(array('integer', 'string', 'array'), $this->converter->getSupportedSourceTypes(), 'Source types do not match');
96 $this->assertEquals('object', $this->converter->getSupportedTargetType(), 'Target type does not match');
97 $this->assertEquals(1, $this->converter->getPriority(), 'Priority does not match');
98 }
99
100 /**
101 * @return array
102 */
103 public function dataProviderForCanConvert()
104 {
105 return array(
106 array(true, false, true),
107 // is entity => can convert
108 array(false, true, true),
109 // is valueobject => can convert
110 array(false, false, false),
111 // is no entity and no value object => can not convert
112 );
113 }
114
115 /**
116 * @test
117 * @dataProvider dataProviderForCanConvert
118 */
119 public function canConvertFromReturnsTrueIfClassIsTaggedWithEntityOrValueObject($isEntity, $isValueObject, $expected)
120 {
121 $className = PersistentObjectFixture::class;
122
123 if ($isEntity) {
124 $className = PersistentObjectEntityFixture::class;
125 } elseif ($isValueObject) {
126 $className = PersistentObjectValueObjectFixture::class;
127 }
128 $this->assertEquals($expected, $this->converter->canConvertFrom('myInputData', $className));
129 }
130
131 /**
132 * @test
133 */
134 public function getSourceChildPropertiesToBeConvertedReturnsAllPropertiesExceptTheIdentityProperty()
135 {
136 $source = array(
137 'k1' => 'v1',
138 '__identity' => 'someIdentity',
139 'k2' => 'v2'
140 );
141 $expected = array(
142 'k1' => 'v1',
143 'k2' => 'v2'
144 );
145 $this->assertEquals($expected, $this->converter->getSourceChildPropertiesToBeConverted($source));
146 }
147
148 /**
149 * @test
150 */
151 public function getTypeOfChildPropertyShouldUseReflectionServiceToDetermineType()
152 {
153 $mockSchema = $this->getMockBuilder(\TYPO3\CMS\Extbase\Reflection\ClassSchema::class)->disableOriginalConstructor()->getMock();
154 $this->mockReflectionService->expects($this->any())->method('getClassSchema')->with('TheTargetType')->will($this->returnValue($mockSchema));
155
156 $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue('TheTargetType'));
157 $mockSchema->expects($this->any())->method('hasProperty')->with('thePropertyName')->will($this->returnValue(true));
158 $mockSchema->expects($this->any())->method('getProperty')->with('thePropertyName')->will($this->returnValue(array(
159 'type' => 'TheTypeOfSubObject',
160 'elementType' => null
161 )));
162 $configuration = $this->buildConfiguration(array());
163 $this->assertEquals('TheTypeOfSubObject', $this->converter->getTypeOfChildProperty('TheTargetType', 'thePropertyName', $configuration));
164 }
165
166 /**
167 * @test
168 */
169 public function getTypeOfChildPropertyShouldUseConfiguredTypeIfItWasSet()
170 {
171 $this->mockReflectionService->expects($this->never())->method('getClassSchema');
172 $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue('foo'));
173
174 $configuration = $this->buildConfiguration(array());
175 $configuration->forProperty('thePropertyName')->setTypeConverterOption(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, PersistentObjectConverter::CONFIGURATION_TARGET_TYPE, 'Foo\Bar');
176 $this->assertEquals('Foo\Bar', $this->converter->getTypeOfChildProperty('foo', 'thePropertyName', $configuration));
177 }
178
179 /**
180 * @test
181 */
182 public function convertFromShouldFetchObjectFromPersistenceIfUuidStringIsGiven()
183 {
184 $identifier = '17';
185 $object = new \stdClass();
186
187 $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
188 $this->assertSame($object, $this->converter->convertFrom($identifier, 'MySpecialType'));
189 }
190
191 /**
192 * @test
193 */
194 public function convertFromShouldFetchObjectFromPersistenceIfuidStringIsGiven()
195 {
196 $identifier = '17';
197 $object = new \stdClass();
198
199 $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
200 $this->assertSame($object, $this->converter->convertFrom($identifier, 'MySpecialType'));
201 }
202
203 /**
204 * @test
205 */
206 public function convertFromShouldFetchObjectFromPersistenceIfOnlyIdentityArrayGiven()
207 {
208 $identifier = '12345';
209 $object = new \stdClass();
210
211 $source = array(
212 '__identity' => $identifier
213 );
214 $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
215 $this->assertSame($object, $this->converter->convertFrom($source, 'MySpecialType'));
216 }
217
218 /**
219 * @test
220 * @expectedException \TYPO3\CMS\Extbase\Property\Exception\InvalidPropertyMappingConfigurationException
221 */
222 public function convertFromShouldThrowExceptionIfObjectNeedsToBeModifiedButConfigurationIsNotSet()
223 {
224 $identifier = '12345';
225 $object = new \stdClass();
226 $object->someProperty = 'asdf';
227
228 $source = array(
229 '__identity' => $identifier,
230 'foo' => 'bar'
231 );
232 $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with($identifier)->will($this->returnValue($object));
233 $this->converter->convertFrom($source, 'MySpecialType');
234 }
235
236 /**
237 * @param array $typeConverterOptions
238 * @return \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration
239 */
240 protected function buildConfiguration($typeConverterOptions)
241 {
242 $configuration = new \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration();
243 $configuration->setTypeConverterOptions(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, $typeConverterOptions);
244 return $configuration;
245 }
246
247 /**
248 * @param int $numberOfResults
249 * @param Matcher $howOftenIsGetFirstCalled
250 * @return \stdClass
251 */
252 public function setupMockQuery($numberOfResults, $howOftenIsGetFirstCalled)
253 {
254 $mockClassSchema = $this->getMock(\TYPO3\CMS\Extbase\Reflection\ClassSchema::class, array(), array('Dummy'));
255 $mockClassSchema->expects($this->any())->method('getIdentityProperties')->will($this->returnValue(array('key1' => 'someType')));
256 $this->mockReflectionService->expects($this->any())->method('getClassSchema')->with('SomeType')->will($this->returnValue($mockClassSchema));
257
258 $mockConstraint = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\Qom\Comparison::class)->disableOriginalConstructor()->getMock();
259
260 $mockObject = new \stdClass();
261 $mockQuery = $this->getMock(\TYPO3\CMS\Extbase\Persistence\QueryInterface::class);
262 $mockQueryResult = $this->getMock(\TYPO3\CMS\Extbase\Persistence\QueryResultInterface::class);
263 $mockQueryResult->expects($this->any())->method('count')->will($this->returnValue($numberOfResults));
264 $mockQueryResult->expects($howOftenIsGetFirstCalled)->method('getFirst')->will($this->returnValue($mockObject));
265 $mockQuery->expects($this->any())->method('equals')->with('key1', 'value1')->will($this->returnValue($mockConstraint));
266 $mockQuery->expects($this->any())->method('matching')->with($mockConstraint)->will($this->returnValue($mockQuery));
267 $mockQuery->expects($this->any())->method('execute')->will($this->returnValue($mockQueryResult));
268
269 $this->mockPersistenceManager->expects($this->any())->method('createQueryForType')->with('SomeType')->will($this->returnValue($mockQuery));
270
271 return $mockObject;
272 }
273
274 /**
275 * @test
276 * @expectedException \TYPO3\CMS\Extbase\Property\Exception\TargetNotFoundException
277 */
278 public function convertFromShouldReturnExceptionIfNoMatchingObjectWasFound()
279 {
280 $this->setupMockQuery(0, $this->never());
281 $this->mockReflectionService->expects($this->never())->method('getClassSchema');
282
283 $source = array(
284 '__identity' => 123
285 );
286 $actual = $this->converter->convertFrom($source, 'SomeType');
287 $this->assertNull($actual);
288 }
289
290 /**
291 * @test
292 * @expectedException \TYPO3\CMS\Extbase\Property\Exception\DuplicateObjectException
293 */
294 public function convertFromShouldThrowExceptionIfMoreThanOneObjectWasFound()
295 {
296 $this->setupMockQuery(2, $this->never());
297
298 $source = array(
299 '__identity' => 666
300 );
301 $this->mockPersistenceManager->expects($this->any())->method('getObjectByIdentifier')->with(666)->will($this->throwException(new \TYPO3\CMS\Extbase\Property\Exception\DuplicateObjectException));
302 $this->converter->convertFrom($source, 'SomeType');
303 }
304
305 /**
306 * @test
307 * @expectedException \TYPO3\CMS\Extbase\Property\Exception\InvalidPropertyMappingConfigurationException
308 */
309 public function convertFromShouldThrowExceptionIfObjectNeedsToBeCreatedButConfigurationIsNotSet()
310 {
311 $source = array(
312 'foo' => 'bar'
313 );
314 $this->converter->convertFrom($source, 'MySpecialType');
315 }
316
317 /**
318 * @test
319 */
320 public function convertFromShouldCreateObject()
321 {
322 $source = array(
323 'propertyX' => 'bar'
324 );
325 $convertedChildProperties = array(
326 'property1' => 'bar'
327 );
328 $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters();
329 $expectedObject->property1 = 'bar';
330
331 $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, '__construct')->will($this->throwException(new \ReflectionException()));
332 $this->mockObjectManager->expects($this->any())->method('getClassNameByObjectName')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class)->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class));
333 $configuration = $this->buildConfiguration(array(PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true));
334 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, $convertedChildProperties, $configuration);
335 $this->assertEquals($expectedObject, $result);
336 }
337
338 /**
339 * @test
340 * @expectedException \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException
341 */
342 public function convertFromShouldThrowExceptionIfPropertyOnTargetObjectCouldNotBeSet()
343 {
344 $source = array(
345 'propertyX' => 'bar'
346 );
347 $object = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters();
348 $convertedChildProperties = array(
349 'propertyNotExisting' => 'bar'
350 );
351 $this->mockObjectManager->expects($this->any())->method('get')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class)->will($this->returnValue($object));
352 $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, '__construct')->will($this->returnValue(array()));
353 $configuration = $this->buildConfiguration(array(PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true));
354 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSetters::class, $convertedChildProperties, $configuration);
355 $this->assertSame($object, $result);
356 }
357
358 /**
359 * @test
360 */
361 public function convertFromShouldCreateObjectWhenThereAreConstructorParameters()
362 {
363 $source = array(
364 'propertyX' => 'bar'
365 );
366 $convertedChildProperties = array(
367 'property1' => 'param1',
368 'property2' => 'bar'
369 );
370 $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('param1');
371 $expectedObject->setProperty2('bar');
372
373 $this->mockReflectionService
374 ->expects($this->any())
375 ->method('getMethodParameters')
376 ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
377 ->will($this->returnValue(array(
378 'property1' => array('optional' => false)
379 )));
380 $this->mockReflectionService
381 ->expects($this->any())
382 ->method('hasMethod')
383 ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
384 ->will($this->returnValue(true));
385 $this->mockObjectManager->expects($this->any())->method('getClassNameByObjectName')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class)->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
386 $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
387 $configuration = $this->buildConfiguration(array(PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true));
388 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, $convertedChildProperties, $configuration);
389 $this->assertEquals($expectedObject, $result);
390 $this->assertEquals('bar', $expectedObject->getProperty2());
391 }
392
393 /**
394 * @test
395 */
396 public function convertFromShouldCreateObjectWhenThereAreOptionalConstructorParameters()
397 {
398 $source = array(
399 'propertyX' => 'bar'
400 );
401 $expectedObject = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('thisIsTheDefaultValue');
402
403 $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')->will($this->returnValue(array(
404 'property1' => array('optional' => true, 'defaultValue' => 'thisIsTheDefaultValue')
405 )));
406 $this->mockReflectionService
407 ->expects($this->any())
408 ->method('hasMethod')
409 ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
410 ->will($this->returnValue(true));
411 $this->mockObjectManager->expects($this->any())->method('getClassNameByObjectName')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class)->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
412 $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
413 $configuration = $this->buildConfiguration(array(PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true));
414 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, array(), $configuration);
415 $this->assertEquals($expectedObject, $result);
416 }
417
418 /**
419 * @test
420 * @expectedException \TYPO3\CMS\Extbase\Property\Exception\InvalidTargetException
421 */
422 public function convertFromShouldThrowExceptionIfRequiredConstructorParameterWasNotFound()
423 {
424 $source = array(
425 'propertyX' => 'bar'
426 );
427 $object = new \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor('param1');
428 $convertedChildProperties = array(
429 'property2' => 'bar'
430 );
431
432 $this->mockReflectionService->expects($this->any())->method('getMethodParameters')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')->will($this->returnValue(array(
433 'property1' => array('optional' => false)
434 )));
435 $this->mockReflectionService
436 ->expects($this->any())
437 ->method('hasMethod')
438 ->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, '__construct')
439 ->will($this->returnValue(true));
440 $this->mockObjectManager->expects($this->any())->method('getClassNameByObjectName')->with(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class)->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
441 $this->mockContainer->expects($this->any())->method('getImplementationClassName')->will($this->returnValue(\TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class));
442 $configuration = $this->buildConfiguration(array(PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true));
443 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class, $convertedChildProperties, $configuration);
444 $this->assertSame($object, $result);
445 }
446
447 /**
448 * @test
449 */
450 public function convertFromShouldReturnNullForEmptyString()
451 {
452 $source = '';
453 $result = $this->converter->convertFrom($source, \TYPO3\CMS\Extbase\Tests\Fixture\ClassWithSettersAndConstructor::class);
454 $this->assertNull($result);
455 }
456 }