[BUGFIX] create ClassSchema with ObjectManager::create()
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Property / PropertyMapperTest.php
1 <?php
2
3 /* *
4 * This script belongs to the Extbase framework. *
5 * *
6 * It is free software; you can redistribute it and/or modify it under *
7 * the terms of the GNU Lesser General Public License as published by the *
8 * Free Software Foundation, either version 3 of the License, or (at your *
9 * option) any later version. *
10 * *
11 * This script is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
13 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
14 * General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU Lesser General Public *
17 * License along with the script. *
18 * If not, see http://www.gnu.org/licenses/lgpl.html *
19 * *
20 * The TYPO3 project - inspiring people to share! *
21 * */
22
23 require_once (__DIR__ . '/../Fixtures/ClassWithSetters.php');
24
25 /**
26 * Testcase for the Property Mapper
27 *
28 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
29 * @covers Tx_Extbase_Property_PropertyMapper
30 */
31 class Tx_Extbase_Tests_Unit_Property_PropertyMapperTest extends Tx_Extbase_Tests_Unit_BaseTestCase {
32
33 protected $mockConfigurationBuilder;
34
35 protected $mockConfiguration;
36
37 /**
38 * Sets up this test case
39 *
40 * @return void
41 * @author Sebastian Kurfürst <sebastian@typo3.org>
42 */
43 public function setUp() {
44 $this->mockConfigurationBuilder = $this->getMock('Tx_Extbase_Property_PropertyMappingConfigurationBuilder');
45 $this->mockConfiguration = $this->getMock('Tx_Extbase_Property_PropertyMappingConfigurationInterface');
46 }
47
48 public function validSourceTypes() {
49 return array(
50 array('someString', 'string'),
51 array(42, 'integer'),
52 array(3.5, 'float'),
53 array(TRUE, 'boolean'),
54 array(array(), 'array')
55 );
56 }
57
58 /**
59 * @test
60 * @dataProvider validSourceTypes
61 * @author Sebastian Kurfürst <sebastian@typo3.org>
62 */
63 public function sourceTypeCanBeCorrectlyDetermined($source, $sourceType) {
64 $propertyMapper = $this->getAccessibleMock('Tx_Extbase_Property_PropertyMapper', array('dummy'));
65 $this->assertEquals($sourceType, $propertyMapper->_call('determineSourceType', $source));
66 }
67
68
69 public function invalidSourceTypes() {
70 return array(
71 array(NULL),
72 array(new stdClass()),
73 array(new ArrayObject())
74 );
75 }
76 /**
77 * @test
78 * @dataProvider invalidSourceTypes
79 * @expectedException Tx_Extbase_Property_Exception_InvalidSourceException
80 * @author Sebastian Kurfürst <sebastian@typo3.org>
81 */
82 public function sourceWhichIsNoSimpleTypeThrowsException($source) {
83 $propertyMapper = $this->getAccessibleMock('Tx_Extbase_Property_PropertyMapper', array('dummy'));
84 $propertyMapper->_call('determineSourceType', $source);
85 }
86
87 protected function getMockTypeConverter($name = '', $canConvertFrom = TRUE, $properties = array(), $typeOfSubObject = '') {
88 $mockTypeConverter = $this->getMock('Tx_Extbase_Property_TypeConverterInterface');
89 $mockTypeConverter->_name = $name;
90 $mockTypeConverter->expects($this->any())->method('canConvertFrom')->will($this->returnValue($canConvertFrom));
91 $mockTypeConverter->expects($this->any())->method('convertFrom')->will($this->returnValue($name));
92 $mockTypeConverter->expects($this->any())->method('getSourceChildPropertiesToBeConverted')->will($this->returnValue($properties));
93
94 $mockTypeConverter->expects($this->any())->method('getTypeOfChildProperty')->will($this->returnValue($typeOfSubObject));
95 return $mockTypeConverter;
96 }
97
98 /**
99 * @test
100 * @author Sebastian Kurfürst <sebastian@typo3.org>
101 */
102 public function findTypeConverterShouldReturnTypeConverterFromConfigurationIfItIsSet() {
103 $mockTypeConverter = $this->getMockTypeConverter();
104 $this->mockConfiguration->expects($this->any())->method('getTypeConverter')->will($this->returnValue($mockTypeConverter));
105
106 $propertyMapper = $this->getAccessibleMock('Tx_Extbase_Property_PropertyMapper', array('dummy'));
107 $this->assertSame($mockTypeConverter, $propertyMapper->_call('findTypeConverter', 'someSource', 'someTargetType', $this->mockConfiguration));
108 }
109
110 // Simple type conversion
111 public function dataProviderForFindTypeConverter() {
112 return array(
113 array('someStringSource', 'string', array(
114 'string' => array(
115 'string' => array(
116 10 => $this->getMockTypeConverter('string2string,prio10'),
117 1 => $this->getMockTypeConverter('string2string,prio1')
118 )
119 )), 'string2string,prio10'
120 ),
121 array(array('some' => 'array'), 'string', array(
122 'array' => array(
123 'string' => array(
124 10 => $this->getMockTypeConverter('array2string,prio10'),
125 1 => $this->getMockTypeConverter('array2string,prio1')
126 )
127 )), 'array2string,prio10'
128 )
129 );
130 }
131
132 /**
133 * @test
134 * @dataProvider dataProviderForFindTypeConverter
135 * @author Sebastian Kurfürst <sebastian@typo3.org>
136 */
137 public function findTypeConverterShouldReturnHighestPriorityTypeConverterForSimpleType($source, $targetType, $typeConverters, $expectedTypeConverter) {
138 $this->markTestSkipped('Fixme');
139 $mockTypeHandlingService = $this->getMock('Tx_Extbase_Service_TypeHandlingService');
140 $mockTypeHandlingService->expects($this->any())->method('isSimpleType')->will($this->returnValue(TRUE));
141 $propertyMapper = $this->getAccessibleMock('Tx_Extbase_Property_PropertyMapper', array('dummy'));
142 $propertyMapper->_set('typeHandlingService', $mockTypeHandlingService);
143 $propertyMapper->_set('typeConverters', $typeConverters);
144 $actualTypeConverter = $propertyMapper->_call('findTypeConverter', $source, $targetType, $this->mockConfiguration);
145 $this->assertSame($expectedTypeConverter, $actualTypeConverter->_name);
146 }
147
148 public function dataProviderForObjectTypeConverters() {
149 $data = array();
150
151
152 $className1 = uniqid('F3_FLOW3_Testclass1_', FALSE);
153 $className2 = uniqid('F3_FLOW3_Testclass2_', FALSE);
154 $className3 = uniqid('F3_FLOW3_Testclass3_', FALSE);
155
156 $interfaceName1 = uniqid('F3_FLOW3_TestInterface1_', FALSE);
157 $interfaceName2 = uniqid('F3_FLOW3_TestInterface2_', FALSE);
158 $interfaceName3 = uniqid('F3_FLOW3_TestInterface3_', FALSE);
159
160 eval("
161 interface $interfaceName2 {}
162 interface $interfaceName1 {}
163
164 interface $interfaceName3 extends $interfaceName2 {}
165
166 class $className1 implements $interfaceName1 {}
167 class $className2 extends $className1 {}
168 class $className3 extends $className2 implements $interfaceName3 {}
169 ");
170
171 // The most specific converter should win
172 $data[] = array(
173 'target' => $className3,
174 'expectedConverter' => 'Class3Converter',
175 'typeConverters' => array(
176 $className2 => array(0 => $this->getMockTypeConverter('Class2Converter')),
177 $className3 => array(0 => $this->getMockTypeConverter('Class3Converter')),
178
179 $interfaceName1 => array(0 => $this->getMockTypeConverter('Interface1Converter')),
180 $interfaceName2 => array(0 => $this->getMockTypeConverter('Interface2Converter')),
181 $interfaceName3 => array(0 => $this->getMockTypeConverter('Interface3Converter')),
182 )
183 );
184
185 // In case the most specific converter does not want to handle this conversion, the second one is taken.
186 $data[] = array(
187 'target' => $className3,
188 'expectedConverter' => 'Class2Converter',
189 'typeConverters' => array(
190 $className2 => array(0 => $this->getMockTypeConverter('Class2Converter')),
191 $className3 => array(0 => $this->getMockTypeConverter('Class3Converter', FALSE)),
192
193 $interfaceName1 => array(0 => $this->getMockTypeConverter('Interface1Converter')),
194 $interfaceName2 => array(0 => $this->getMockTypeConverter('Interface2Converter')),
195 $interfaceName3 => array(0 => $this->getMockTypeConverter('Interface3Converter')),
196 )
197 );
198
199 // In case there is no most-specific-converter, we climb ub the type hierarchy
200 $data[] = array(
201 'target' => $className3,
202 'expectedConverter' => 'Class2Converter-HighPriority',
203 'typeConverters' => array(
204 $className2 => array(0 => $this->getMockTypeConverter('Class2Converter'), 10 => $this->getMockTypeConverter('Class2Converter-HighPriority'))
205 )
206 );
207
208 // If no parent class converter wants to handle it, we ask for all interface converters.
209 $data[] = array(
210 'target' => $className3,
211 'expectedConverter' => 'Interface1Converter',
212 'typeConverters' => array(
213 $className2 => array(0 => $this->getMockTypeConverter('Class2Converter', FALSE), 10 => $this->getMockTypeConverter('Class2Converter-HighPriority', FALSE)),
214
215 $interfaceName1 => array(4 => $this->getMockTypeConverter('Interface1Converter')),
216 $interfaceName2 => array(1 => $this->getMockTypeConverter('Interface2Converter')),
217 $interfaceName3 => array(2 => $this->getMockTypeConverter('Interface3Converter')),
218 )
219 );
220
221 // If two interface converters have the same priority, an exception is thrown.
222 $data[] = array(
223 'target' => $className3,
224 'expectedConverter' => 'Interface1Converter',
225 'typeConverters' => array(
226 $className2 => array(0 => $this->getMockTypeConverter('Class2Converter', FALSE), 10 => $this->getMockTypeConverter('Class2Converter-HighPriority', FALSE)),
227
228 $interfaceName1 => array(4 => $this->getMockTypeConverter('Interface1Converter')),
229 $interfaceName2 => array(2 => $this->getMockTypeConverter('Interface2Converter')),
230 $interfaceName3 => array(2 => $this->getMockTypeConverter('Interface3Converter')),
231 ),
232 'shouldFailWithException' => 'Tx_Extbase_Property_Exception_DuplicateTypeConverterException'
233 );
234
235 // If no interface converter wants to handle it, a converter for "object" is looked up.
236 $data[] = array(
237 'target' => $className3,
238 'expectedConverter' => 'GenericObjectConverter-HighPriority',
239 'typeConverters' => array(
240 $className2 => array(0 => $this->getMockTypeConverter('Class2Converter', FALSE), 10 => $this->getMockTypeConverter('Class2Converter-HighPriority', FALSE)),
241
242 $interfaceName1 => array(4 => $this->getMockTypeConverter('Interface1Converter', FALSE)),
243 $interfaceName2 => array(3 => $this->getMockTypeConverter('Interface2Converter', FALSE)),
244 $interfaceName3 => array(2 => $this->getMockTypeConverter('Interface3Converter', FALSE)),
245 'object' => array(1 => $this->getMockTypeConverter('GenericObjectConverter'), 10 => $this->getMockTypeConverter('GenericObjectConverter-HighPriority'))
246 ),
247 );
248
249 // If the target is no valid class name and no simple type, an exception is thrown
250 $data[] = array(
251 'target' => 'SomeNotExistingClassName',
252 'expectedConverter' => 'GenericObjectConverter-HighPriority',
253 'typeConverters' => array(),
254 'shouldFailWithException' => 'Tx_Extbase_Property_Exception_InvalidTargetException'
255 );
256
257 // if the type converter is not found, we expect an exception
258 $data[] = array(
259 'target' => $className3,
260 'expectedConverter' => 'Class3Converter',
261 'typeConverters' => array(),
262 'shouldFailWithException' => 'Tx_Extbase_Property_Exception_TypeConverterException'
263 );
264
265 // If The target type is no string, we expect an exception.
266 $data[] = array(
267 'target' => new \stdClass,
268 'expectedConverter' => '',
269 'typeConverters' => array(),
270 'shouldFailWithException' => 'Tx_Extbase_Property_Exception_InvalidTargetException'
271 );
272 return $data;
273 }
274
275 /**
276 * @test
277 * @dataProvider dataProviderForObjectTypeConverters
278 * @author Sebastian Kurfürst <sebastian@typo3.org>
279 */
280 public function findTypeConverterShouldReturnConverterForTargetObjectIfItExists($targetClass, $expectedTypeConverter, $typeConverters, $shouldFailWithException = FALSE) {
281 $mockTypeHandlingService = $this->getMock('Tx_Extbase_Service_TypeHandlingService');
282 $mockTypeHandlingService->expects($this->any())->method('isSimpleType')->will($this->returnValue(FALSE));
283 $propertyMapper = $this->getAccessibleMock('Tx_Extbase_Property_PropertyMapper', array('dummy'));
284 $propertyMapper->injectTypeHandlingService($mockTypeHandlingService);
285 $propertyMapper->_set('typeConverters', array('string' => $typeConverters));
286 try {
287 $actualTypeConverter = $propertyMapper->_call('findTypeConverter', 'someSourceString', $targetClass, $this->mockConfiguration);
288 if ($shouldFailWithException) {
289 $this->fail('Expected exception ' . $shouldFailWithException . ' which was not thrown.');
290 }
291 $this->assertSame($expectedTypeConverter, $actualTypeConverter->_name);
292 } catch (Exception $e) {
293 if ($shouldFailWithException === FALSE) {
294 throw $e;
295 }
296 $this->assertInstanceOf($shouldFailWithException, $e);
297 }
298 }
299
300 /**
301 * @test
302 * @author Sebastian Kurfürst <sebastian@typo3.org>
303 */
304 public function convertShouldAskConfigurationBuilderForDefaultConfiguration() {
305 $mockTypeHandlingService = $this->getMock('Tx_Extbase_Service_TypeHandlingService');
306 $mockTypeHandlingService->expects($this->any())->method('isSimpleType')->will($this->returnValue(TRUE));
307 $propertyMapper = $this->getAccessibleMock('Tx_Extbase_Property_PropertyMapper', array('dummy'));
308 $propertyMapper->injectTypeHandlingService($mockTypeHandlingService);
309 $propertyMapper->injectPropertyMappingConfigurationBuilder($this->mockConfigurationBuilder);
310
311 $this->mockConfigurationBuilder->expects($this->once())->method('build')->will($this->returnValue($this->mockConfiguration));
312
313 $converter = $this->getMockTypeConverter('string2string');
314 $typeConverters = array(
315 'string' => array(
316 'string' => array(10 => $converter)
317 )
318 );
319
320 $propertyMapper->_set('typeConverters', $typeConverters);
321 $this->assertEquals('string2string', $propertyMapper->convert('source', 'string'));
322 }
323
324 /**
325 * @test
326 * @author Sebastian Kurfürst <sebastian@typo3.org>
327 */
328 public function findFirstEligibleTypeConverterInObjectHierarchyShouldReturnNullIfSourceTypeIsUnknown() {
329 $propertyMapper = $this->getAccessibleMock('Tx_Extbase_Property_PropertyMapper', array('dummy'));
330 $this->assertNull($propertyMapper->_call('findFirstEligibleTypeConverterInObjectHierarchy', 'source', 'unknownSourceType', 'Tx_Extbase_Core_Bootstrap'));
331 }
332 }
333 ?>