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