TYPO3 CMS  TYPO3_6-2
PropertyMapperTest.php
Go to the documentation of this file.
1 <?php
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 
28 
30 
31  protected $mockConfiguration;
32 
39  public function setUp() {
40  $this->mockConfigurationBuilder = $this->getMock('TYPO3\\CMS\\Extbase\\Property\\PropertyMappingConfigurationBuilder');
41  $this->mockConfiguration = $this->getMock('TYPO3\\CMS\\Extbase\\Property\\PropertyMappingConfigurationInterface');
42  }
43 
47  public function validSourceTypes() {
48  return array(
49  array('someString', 'string'),
50  array(42, 'integer'),
51  array(3.5, 'float'),
52  array(TRUE, 'boolean'),
53  array(array(), 'array')
54  );
55  }
56 
64  public function sourceTypeCanBeCorrectlyDetermined($source, $sourceType) {
66  $propertyMapper = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Property\\PropertyMapper', array('dummy'));
67  $this->assertEquals($sourceType, $propertyMapper->_call('determineSourceType', $source));
68  }
69 
73  public function invalidSourceTypes() {
74  return array(
75  array(NULL),
76  array(new \stdClass()),
77  array(new \ArrayObject())
78  );
79  }
80 
88  public function sourceWhichIsNoSimpleTypeThrowsException($source) {
90  $propertyMapper = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Property\\PropertyMapper', array('dummy'));
91  $propertyMapper->_call('determineSourceType', $source);
92  }
93 
101  protected function getMockTypeConverter($name = '', $canConvertFrom = TRUE, $properties = array(), $typeOfSubObject = '') {
102  $mockTypeConverter = $this->getMock('TYPO3\\CMS\\Extbase\\Property\\TypeConverterInterface');
103  $mockTypeConverter->_name = $name;
104  $mockTypeConverter->expects($this->any())->method('canConvertFrom')->will($this->returnValue($canConvertFrom));
105  $mockTypeConverter->expects($this->any())->method('convertFrom')->will($this->returnValue($name));
106  $mockTypeConverter->expects($this->any())->method('getSourceChildPropertiesToBeConverted')->will($this->returnValue($properties));
107  $mockTypeConverter->expects($this->any())->method('getTypeOfChildProperty')->will($this->returnValue($typeOfSubObject));
108  return $mockTypeConverter;
109  }
110 
115  public function findTypeConverterShouldReturnTypeConverterFromConfigurationIfItIsSet() {
116  $mockTypeConverter = $this->getMockTypeConverter();
117  $this->mockConfiguration->expects($this->any())->method('getTypeConverter')->will($this->returnValue($mockTypeConverter));
119  $propertyMapper = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Property\\PropertyMapper', array('dummy'));
120  $this->assertSame($mockTypeConverter, $propertyMapper->_call('findTypeConverter', 'someSource', 'someTargetType', $this->mockConfiguration));
121  }
122 
128  return array(
129  array('someStringSource', 'string', array(
130  'string' => array(
131  'string' => array(
132  10 => $this->getMockTypeConverter('string2string,prio10'),
133  1 => $this->getMockTypeConverter('string2string,prio1'),
134  )
135  )), 'string2string,prio10'
136  ),
137  array(array('some' => 'array'), 'string', array(
138  'array' => array(
139  'string' => array(
140  10 => $this->getMockTypeConverter('array2string,prio10'),
141  1 => $this->getMockTypeConverter('array2string,prio1'),
142  )
143  )), 'array2string,prio10'
144  ),
145  array('someStringSource', 'bool', array(
146  'string' => array(
147  'boolean' => array(
148  10 => $this->getMockTypeConverter('string2boolean,prio10'),
149  1 => $this->getMockTypeConverter('string2boolean,prio1'),
150  )
151  )), 'string2boolean,prio10'
152  ),
153  array('someStringSource', 'int', array(
154  'string' => array(
155  'integer' => array(
156  10 => $this->getMockTypeConverter('string2integer,prio10'),
157  1 => $this->getMockTypeConverter('string2integer,prio1'),
158  ),
159  )), 'string2integer,prio10'
160  )
161  );
162  }
163 
173  public function findTypeConverterShouldReturnHighestPriorityTypeConverterForSimpleType($source, $targetType, $typeConverters, $expectedTypeConverter) {
174  $propertyMapper = $this->getAccessibleMock('TYPO3\CMS\Extbase\Property\PropertyMapper', array('dummy'));
175  $propertyMapper->_set('typeConverters', $typeConverters);
176  $actualTypeConverter = $propertyMapper->_call('findTypeConverter', $source, $targetType, $this->mockConfiguration);
177  $this->assertSame($expectedTypeConverter, $actualTypeConverter->_name);
178  }
179 
184  $data = array();
185 
186  $className1 = $this->getUniqueId('TYPO3_Flow_Testclass1_', FALSE);
187  $className2 = $this->getUniqueId('TYPO3_Flow_Testclass2_', FALSE);
188  $className3 = $this->getUniqueId('TYPO3_Flow_Testclass3_', FALSE);
189 
190  $interfaceName1 = $this->getUniqueId('TYPO3_Flow_TestInterface1_', FALSE);
191  $interfaceName2 = $this->getUniqueId('TYPO3_Flow_TestInterface2_', FALSE);
192  $interfaceName3 = $this->getUniqueId('TYPO3_Flow_TestInterface3_', FALSE);
193 
194  eval("
195  interface $interfaceName2 {}
196  interface $interfaceName1 {}
197 
198  interface $interfaceName3 extends $interfaceName2 {}
199 
200  class $className1 implements $interfaceName1 {}
201  class $className2 extends $className1 {}
202  class $className3 extends $className2 implements $interfaceName3 {}
203  ");
204 
205  // The most specific converter should win
206  $data[] = array(
207  'target' => $className3,
208  'expectedConverter' => 'Class3Converter',
209  'typeConverters' => array(
210  $className2 => array(0 => $this->getMockTypeConverter('Class2Converter')),
211  $className3 => array(0 => $this->getMockTypeConverter('Class3Converter')),
212 
213  $interfaceName1 => array(0 => $this->getMockTypeConverter('Interface1Converter')),
214  $interfaceName2 => array(0 => $this->getMockTypeConverter('Interface2Converter')),
215  $interfaceName3 => array(0 => $this->getMockTypeConverter('Interface3Converter')),
216  )
217  );
218 
219  // In case the most specific converter does not want to handle this conversion, the second one is taken.
220  $data[] = array(
221  'target' => $className3,
222  'expectedConverter' => 'Class2Converter',
223  'typeConverters' => array(
224  $className2 => array(0 => $this->getMockTypeConverter('Class2Converter')),
225  $className3 => array(0 => $this->getMockTypeConverter('Class3Converter', FALSE)),
226 
227  $interfaceName1 => array(0 => $this->getMockTypeConverter('Interface1Converter')),
228  $interfaceName2 => array(0 => $this->getMockTypeConverter('Interface2Converter')),
229  $interfaceName3 => array(0 => $this->getMockTypeConverter('Interface3Converter')),
230  )
231  );
232 
233  // In case there is no most-specific-converter, we climb ub the type hierarchy
234  $data[] = array(
235  'target' => $className3,
236  'expectedConverter' => 'Class2Converter-HighPriority',
237  'typeConverters' => array(
238  $className2 => array(0 => $this->getMockTypeConverter('Class2Converter'), 10 => $this->getMockTypeConverter('Class2Converter-HighPriority'))
239  )
240  );
241 
242  // If no parent class converter wants to handle it, we ask for all interface converters.
243  $data[] = array(
244  'target' => $className3,
245  'expectedConverter' => 'Interface1Converter',
246  'typeConverters' => array(
247  $className2 => array(0 => $this->getMockTypeConverter('Class2Converter', FALSE), 10 => $this->getMockTypeConverter('Class2Converter-HighPriority', FALSE)),
248 
249  $interfaceName1 => array(4 => $this->getMockTypeConverter('Interface1Converter')),
250  $interfaceName2 => array(1 => $this->getMockTypeConverter('Interface2Converter')),
251  $interfaceName3 => array(2 => $this->getMockTypeConverter('Interface3Converter')),
252  )
253  );
254 
255  // If two interface converters have the same priority, an exception is thrown.
256  $data[] = array(
257  'target' => $className3,
258  'expectedConverter' => 'Interface1Converter',
259  'typeConverters' => array(
260  $className2 => array(0 => $this->getMockTypeConverter('Class2Converter', FALSE), 10 => $this->getMockTypeConverter('Class2Converter-HighPriority', FALSE)),
261 
262  $interfaceName1 => array(4 => $this->getMockTypeConverter('Interface1Converter')),
263  $interfaceName2 => array(2 => $this->getMockTypeConverter('Interface2Converter')),
264  $interfaceName3 => array(2 => $this->getMockTypeConverter('Interface3Converter')),
265  ),
266  'shouldFailWithException' => 'TYPO3\\CMS\\Extbase\\Property\\Exception\\DuplicateTypeConverterException'
267  );
268 
269  // If no interface converter wants to handle it, a converter for "object" is looked up.
270  $data[] = array(
271  'target' => $className3,
272  'expectedConverter' => 'GenericObjectConverter-HighPriority',
273  'typeConverters' => array(
274  $className2 => array(0 => $this->getMockTypeConverter('Class2Converter', FALSE), 10 => $this->getMockTypeConverter('Class2Converter-HighPriority', FALSE)),
275 
276  $interfaceName1 => array(4 => $this->getMockTypeConverter('Interface1Converter', FALSE)),
277  $interfaceName2 => array(3 => $this->getMockTypeConverter('Interface2Converter', FALSE)),
278  $interfaceName3 => array(2 => $this->getMockTypeConverter('Interface3Converter', FALSE)),
279  'object' => array(1 => $this->getMockTypeConverter('GenericObjectConverter'), 10 => $this->getMockTypeConverter('GenericObjectConverter-HighPriority'))
280  ),
281  );
282 
283  // If the target is no valid class name and no simple type, an exception is thrown
284  $data[] = array(
285  'target' => 'SomeNotExistingClassName',
286  'expectedConverter' => 'GenericObjectConverter-HighPriority',
287  'typeConverters' => array(),
288  'shouldFailWithException' => 'TYPO3\\CMS\\Extbase\\Property\\Exception\\InvalidTargetException'
289  );
290 
291  // if the type converter is not found, we expect an exception
292  $data[] = array(
293  'target' => $className3,
294  'expectedConverter' => 'Class3Converter',
295  'typeConverters' => array(),
296  'shouldFailWithException' => 'TYPO3\\CMS\\Extbase\\Property\\Exception\\TypeConverterException'
297  );
298 
299  // If The target type is no string, we expect an exception.
300  $data[] = array(
301  'target' => new \stdClass(),
302  'expectedConverter' => '',
303  'typeConverters' => array(),
304  'shouldFailWithException' => 'TYPO3\\CMS\\Extbase\\Property\\Exception\\InvalidTargetException'
305  );
306  return $data;
307  }
308 
320  public function findTypeConverterShouldReturnConverterForTargetObjectIfItExists($targetClass, $expectedTypeConverter, $typeConverters, $shouldFailWithException = FALSE) {
321  $propertyMapper = $this->getAccessibleMock('TYPO3\CMS\Extbase\Property\PropertyMapper', array('dummy'));
322  $propertyMapper->_set('typeConverters', array('string' => $typeConverters));
323  try {
324  $actualTypeConverter = $propertyMapper->_call('findTypeConverter', 'someSourceString', $targetClass, $this->mockConfiguration);
325  if ($shouldFailWithException) {
326  $this->fail('Expected exception ' . $shouldFailWithException . ' which was not thrown.');
327  }
328  $this->assertSame($expectedTypeConverter, $actualTypeConverter->_name);
329  } catch (\Exception $e) {
330  if ($shouldFailWithException === FALSE) {
331  throw $e;
332  }
333  $this->assertInstanceOf($shouldFailWithException, $e);
334  }
335  }
336 
341  $propertyMapper = $this->getAccessibleMock('TYPO3\CMS\Extbase\Property\PropertyMapper', array('dummy'));
342  $this->inject($propertyMapper, 'configurationBuilder', $this->mockConfigurationBuilder);
343 
344  $this->mockConfigurationBuilder->expects($this->once())->method('build')->will($this->returnValue($this->mockConfiguration));
345 
346  $converter = $this->getMockTypeConverter('string2string');
347  $typeConverters = array(
348  'string' => array(
349  'string' => array(10 => $converter)
350  )
351  );
352 
353  $propertyMapper->_set('typeConverters', $typeConverters);
354  $this->assertEquals('string2string', $propertyMapper->convert('source', 'string'));
355  }
356 
360  public function findFirstEligibleTypeConverterInObjectHierarchyShouldReturnNullIfSourceTypeIsUnknown() {
362  $propertyMapper = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Property\\PropertyMapper', array('dummy'));
363  $this->assertNull($propertyMapper->_call('findFirstEligibleTypeConverterInObjectHierarchy', 'source', 'unknownSourceType', 'TYPO3\\CMS\\Extbase\\Core\\Bootstrap'));
364  }
365 
370  $source = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
371  $targetType = 'TYPO3\CMS\Extbase\Persistence\ObjectStorage';
372  $propertyPath = '';
373  $propertyMapper = $this->getAccessibleMock('TYPO3\CMS\Extbase\Property\PropertyMapper', array('dummy'));
374  $this->assertSame($source, $propertyMapper->_callRef('doMapping', $source, $targetType, $this->mockConfiguration, $propertyPath));
375  }
376 
381  $source = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
382  $targetType = 'TYPO3\CMS\Extbase\Persistence\ObjectStorage<SomeEntity>';
383  $propertyPath = '';
384  $propertyMapper = $this->getAccessibleMock('TYPO3\CMS\Extbase\Property\PropertyMapper', array('dummy'));
385  $this->assertSame($source, $propertyMapper->_callRef('doMapping', $source, $targetType, $this->mockConfiguration, $propertyPath));
386  }
387 
392  $source = array('firstProperty' => 1, 'secondProperty' => 2);
393  $typeConverters = array(
394  'array' => array(
395  'stdClass' => array(10 => $this->getMockTypeConverter('array2object', TRUE, $source, 'integer'))
396  ),
397  'integer' => array(
398  'integer' => array(10 => $this->getMockTypeConverter('integer2integer'))
399  )
400  );
401  $configuration = new \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration();
402 
403  $propertyMapper = $this->getAccessibleMock('TYPO3\CMS\Extbase\Property\PropertyMapper', array('dummy'));
404  $propertyMapper->_set('typeConverters', $typeConverters);
405 
406  $propertyMapper->convert($source, 'stdClass', $configuration->allowProperties('firstProperty')->skipProperties('secondProperty'));
407  }
408 
413  $source = array('firstProperty' => 1, 'secondProperty' => 2);
414  $typeConverters = array(
415  'array' => array(
416  'stdClass' => array(10 => $this->getMockTypeConverter('array2object', TRUE, $source, 'integer'))
417  ),
418  'integer' => array(
419  'integer' => array(10 => $this->getMockTypeConverter('integer2integer'))
420  )
421  );
422  $configuration = new \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration();
423 
424  $propertyMapper = $this->getAccessibleMock('TYPO3\CMS\Extbase\Property\PropertyMapper', array('dummy'));
425  $propertyMapper->_set('typeConverters', $typeConverters);
426 
427  $propertyMapper->convert($source, 'stdClass', $configuration->allowProperties('firstProperty')->skipUnknownProperties());
428  }
429 }
inject($target, $name, $dependency)
findTypeConverterShouldReturnHighestPriorityTypeConverterForSimpleType($source, $targetType, $typeConverters, $expectedTypeConverter)
getMockTypeConverter($name='', $canConvertFrom=TRUE, $properties=array(), $typeOfSubObject='')
getAccessibleMock( $originalClassName, array $methods=array(), array $arguments=array(), $mockClassName='', $callOriginalConstructor=TRUE, $callOriginalClone=TRUE, $callAutoload=TRUE)
findTypeConverterShouldReturnConverterForTargetObjectIfItExists($targetClass, $expectedTypeConverter, $typeConverters, $shouldFailWithException=FALSE)