[FEATURE] Support 'has*' for properties in ObjectAccess
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Reflection / ObjectAccessTest.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Tests\Unit\Reflection;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * Test case
19 */
20 class ObjectAccessTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
21
22 protected $dummyObject;
23
24 public function setUp() {
25 $this->dummyObject = new \TYPO3\CMS\Extbase\Tests\Unit\Reflection\Fixture\DummyClassWithGettersAndSetters();
26 $this->dummyObject->setProperty('string1');
27 $this->dummyObject->setAnotherProperty(42);
28 $this->dummyObject->shouldNotBePickedUp = TRUE;
29 }
30
31 /**
32 * @test
33 */
34 public function getPropertyReturnsExpectedValueForGetterProperty() {
35 $property = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($this->dummyObject, 'property');
36 $this->assertEquals($property, 'string1');
37 }
38
39 /**
40 * @test
41 */
42 public function getPropertyReturnsExpectedValueForPublicProperty() {
43 $property = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($this->dummyObject, 'publicProperty2');
44 $this->assertEquals($property, 42, 'A property of a given object was not returned correctly.');
45 }
46
47 /**
48 * @test
49 */
50 public function getPropertyReturnsExpectedValueForUnexposedPropertyIfForceDirectAccessIsTrue() {
51 $property = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($this->dummyObject, 'unexposedProperty', TRUE);
52 $this->assertEquals($property, 'unexposed', 'A property of a given object was not returned correctly.');
53 }
54
55 /**
56 * @test
57 */
58 public function getPropertyReturnsExpectedValueForUnknownPropertyIfForceDirectAccessIsTrue() {
59 $this->dummyObject->unknownProperty = 'unknown';
60 $property = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($this->dummyObject, 'unknownProperty', TRUE);
61 $this->assertEquals($property, 'unknown', 'A property of a given object was not returned correctly.');
62 }
63
64 /**
65 * @test
66 * @expectedException \TYPO3\CMS\Extbase\Reflection\Exception\PropertyNotAccessibleException
67 */
68 public function getPropertyReturnsPropertyNotAccessibleExceptionForNotExistingPropertyIfForceDirectAccessIsTrue() {
69 $property = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($this->dummyObject, 'notExistingProperty', TRUE);
70 }
71
72 /**
73 * @test
74 * @expectedException \TYPO3\CMS\Extbase\Reflection\Exception\PropertyNotAccessibleException
75 */
76 public function getPropertyReturnsThrowsExceptionIfPropertyDoesNotExist() {
77 \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($this->dummyObject, 'notExistingProperty');
78 }
79
80 /**
81 * @test
82 * @expectedException \TYPO3\CMS\Extbase\Reflection\Exception\PropertyNotAccessibleException
83 */
84 public function getPropertyReturnsThrowsExceptionIfArrayKeyDoesNotExist() {
85 \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty(array(), 'notExistingProperty');
86 }
87
88 /**
89 * @test
90 */
91 public function getPropertyTriesToCallABooleanGetterMethodIfItExists() {
92 $property = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($this->dummyObject, 'booleanProperty');
93 $this->assertTrue($property);
94 }
95
96 /**
97 * @test
98 * @expectedException \InvalidArgumentException
99 */
100 public function getPropertyThrowsExceptionIfThePropertyNameIsNotAString() {
101 \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($this->dummyObject, new \ArrayObject());
102 }
103
104 /**
105 * @test
106 * @expectedException \InvalidArgumentException
107 */
108 public function setPropertyThrowsExceptionIfThePropertyNameIsNotAString() {
109 \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($this->dummyObject, new \ArrayObject(), 42);
110 }
111
112 /**
113 * @test
114 */
115 public function setPropertyReturnsFalseIfPropertyIsNotAccessible() {
116 $this->assertFalse(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($this->dummyObject, 'protectedProperty', 42));
117 }
118
119 /**
120 * @test
121 */
122 public function setPropertySetsValueIfPropertyIsNotAccessibleWhenForceDirectAccessIsTrue() {
123 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($this->dummyObject, 'unexposedProperty', 'was set anyway', TRUE));
124 $this->assertAttributeEquals('was set anyway', 'unexposedProperty', $this->dummyObject);
125 }
126
127 /**
128 * @test
129 */
130 public function setPropertySetsValueIfPropertyDoesNotExistWhenForceDirectAccessIsTrue() {
131 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($this->dummyObject, 'unknownProperty', 'was set anyway', TRUE));
132 $this->assertAttributeEquals('was set anyway', 'unknownProperty', $this->dummyObject);
133 }
134
135 /**
136 * @test
137 */
138 public function setPropertyCallsASetterMethodToSetThePropertyValueIfOneIsAvailable() {
139 \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($this->dummyObject, 'property', 4242);
140 $this->assertEquals($this->dummyObject->getProperty(), 4242, 'setProperty does not work with setter.');
141 }
142
143 /**
144 * @test
145 */
146 public function setPropertyWorksWithPublicProperty() {
147 \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($this->dummyObject, 'publicProperty', 4242);
148 $this->assertEquals($this->dummyObject->publicProperty, 4242, 'setProperty does not work with public property.');
149 }
150
151 /**
152 * @test
153 */
154 public function setPropertyCanDirectlySetValuesInAnArrayObjectOrArray() {
155 $arrayObject = new \ArrayObject();
156 $array = array();
157 \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($arrayObject, 'publicProperty', 4242);
158 \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($array, 'key', 'value');
159 $this->assertEquals(4242, $arrayObject['publicProperty']);
160 $this->assertEquals('value', $array['key']);
161 }
162
163 /**
164 * @test
165 */
166 public function getPropertyCanAccessPropertiesOfAnArrayObject() {
167 $arrayObject = new \ArrayObject(array('key' => 'value'));
168 $actual = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($arrayObject, 'key');
169 $this->assertEquals('value', $actual, 'getProperty does not work with ArrayObject property.');
170 }
171
172 /**
173 * @test
174 */
175 public function getPropertyCanAccessPropertiesOfAnObjectStorageObject() {
176 $objectStorage = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
177 $objectStorage->key = 'value';
178 $actual = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($objectStorage, 'key');
179 $this->assertEquals('value', $actual, 'getProperty does not work with ObjectStorage property.');
180 }
181
182 /**
183 * @test
184 */
185 public function getPropertyCanAccessPropertiesOfAnObjectImplementingArrayAccess() {
186 $arrayAccessInstance = new \TYPO3\CMS\Extbase\Tests\Unit\Reflection\Fixture\ArrayAccessClass(array('key' => 'value'));
187 $actual = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($arrayAccessInstance, 'key');
188 $this->assertEquals('value', $actual, 'getProperty does not work with Array Access property.');
189 }
190
191 /**
192 * @test
193 */
194 public function getPropertyCanAccessPropertiesOfAnArray() {
195 $array = array('key' => 'value');
196 $expected = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getProperty($array, 'key');
197 $this->assertEquals($expected, 'value', 'getProperty does not work with Array property.');
198 }
199
200 /**
201 * @test
202 */
203 public function getPropertyPathCanAccessPropertiesOfAnArray() {
204 $array = array('parent' => array('key' => 'value'));
205 $actual = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($array, 'parent.key');
206 $this->assertEquals('value', $actual, 'getPropertyPath does not work with Array property.');
207 }
208
209 /**
210 * @test
211 */
212 public function getPropertyPathCanAccessPropertiesOfAnObjectImplementingArrayAccess() {
213 $array = array('parent' => new \ArrayObject(array('key' => 'value')));
214 $actual = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($array, 'parent.key');
215 $this->assertEquals('value', $actual, 'getPropertyPath does not work with Array Access property.');
216 }
217
218 /**
219 * @test
220 */
221 public function getPropertyPathCanAccessPropertiesOfAnExtbaseObjectStorageObject() {
222 $objectStorage = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
223 $exampleObject = new \stdClass();
224 $exampleObject->key = 'value';
225 $exampleObject2 = new \stdClass();
226 $exampleObject2->key = 'value2';
227 $objectStorage->attach($exampleObject);
228 $objectStorage->attach($exampleObject2);
229 $array = array(
230 'parent' => $objectStorage,
231 );
232 $this->assertSame('value', \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($array, 'parent.0.key'));
233 $this->assertSame('value2', \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($array, 'parent.1.key'));
234 }
235
236 /**
237 * @test
238 */
239 public function getPropertyPathCanAccessPropertiesOfAnSplObjectStorageObject() {
240 $objectStorage = new \SplObjectStorage();
241 $exampleObject = new \stdClass();
242 $exampleObject->key = 'value';
243 $exampleObject2 = new \stdClass();
244 $exampleObject2->key = 'value2';
245 $objectStorage->attach($exampleObject);
246 $objectStorage->attach($exampleObject2);
247 $array = array(
248 'parent' => $objectStorage,
249 );
250 $this->assertSame('value', \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($array, 'parent.0.key'));
251 $this->assertSame('value2', \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($array, 'parent.1.key'));
252 }
253
254 /**
255 * @test
256 */
257 public function getGettablePropertyNamesReturnsAllPropertiesWhichAreAvailable() {
258 $gettablePropertyNames = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getGettablePropertyNames($this->dummyObject);
259 $expectedPropertyNames = array('anotherBooleanProperty', 'anotherProperty', 'booleanProperty', 'property', 'property2', 'publicProperty', 'publicProperty2');
260 $this->assertEquals($gettablePropertyNames, $expectedPropertyNames, 'getGettablePropertyNames returns not all gettable properties.');
261 }
262
263 /**
264 * @test
265 */
266 public function getSettablePropertyNamesReturnsAllPropertiesWhichAreAvailable() {
267 $settablePropertyNames = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getSettablePropertyNames($this->dummyObject);
268 $expectedPropertyNames = array('anotherBooleanProperty', 'anotherProperty', 'property', 'property2', 'publicProperty', 'publicProperty2', 'writeOnlyMagicProperty');
269 $this->assertEquals($settablePropertyNames, $expectedPropertyNames, 'getSettablePropertyNames returns not all settable properties.');
270 }
271
272 /**
273 * @test
274 */
275 public function getSettablePropertyNamesReturnsPropertyNamesOfStdClass() {
276 $stdClassObject = new \stdClass();
277 $stdClassObject->property = 'string1';
278 $stdClassObject->property2 = NULL;
279 $settablePropertyNames = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getSettablePropertyNames($stdClassObject);
280 $expectedPropertyNames = array('property', 'property2');
281 $this->assertEquals($expectedPropertyNames, $settablePropertyNames, 'getSettablePropertyNames returns not all settable properties.');
282 }
283
284 /**
285 * @test
286 */
287 public function getGettablePropertiesReturnsTheCorrectValuesForAllProperties() {
288 $allProperties = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getGettableProperties($this->dummyObject);
289 $expectedProperties = array(
290 'anotherBooleanProperty' => TRUE,
291 'anotherProperty' => 42,
292 'booleanProperty' => TRUE,
293 'property' => 'string1',
294 'property2' => NULL,
295 'publicProperty' => NULL,
296 'publicProperty2' => 42
297 );
298 $this->assertEquals($allProperties, $expectedProperties, 'expectedProperties did not return the right values for the properties.');
299 }
300
301 /**
302 * @test
303 */
304 public function getGettablePropertiesReturnsPropertiesOfStdClass() {
305 $stdClassObject = new \stdClass();
306 $stdClassObject->property = 'string1';
307 $stdClassObject->property2 = NULL;
308 $stdClassObject->publicProperty2 = 42;
309 $allProperties = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getGettableProperties($stdClassObject);
310 $expectedProperties = array(
311 'property' => 'string1',
312 'property2' => NULL,
313 'publicProperty2' => 42
314 );
315 $this->assertEquals($expectedProperties, $allProperties, 'expectedProperties did not return the right values for the properties.');
316 }
317
318 /**
319 * @test
320 */
321 public function isPropertySettableTellsIfAPropertyCanBeSet() {
322 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertySettable($this->dummyObject, 'writeOnlyMagicProperty'));
323 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertySettable($this->dummyObject, 'publicProperty'));
324 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertySettable($this->dummyObject, 'property'));
325 $this->assertFalse(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertySettable($this->dummyObject, 'privateProperty'));
326 $this->assertFalse(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertySettable($this->dummyObject, 'shouldNotBePickedUp'));
327 }
328
329 /**
330 * @test
331 */
332 public function isPropertySettableWorksOnStdClass() {
333 $stdClassObject = new \stdClass();
334 $stdClassObject->property = 'foo';
335 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertySettable($stdClassObject, 'property'));
336 $this->assertFalse(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertySettable($stdClassObject, 'undefinedProperty'));
337 }
338
339 /**
340 * @test
341 */
342 public function isPropertyGettableTellsIfAPropertyCanBeRetrieved() {
343 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($this->dummyObject, 'publicProperty'));
344 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($this->dummyObject, 'property'));
345 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($this->dummyObject, 'booleanProperty'));
346 $this->assertFalse(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($this->dummyObject, 'privateProperty'));
347 $this->assertFalse(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($this->dummyObject, 'writeOnlyMagicProperty'));
348 $this->assertFalse(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($this->dummyObject, 'shouldNotBePickedUp'));
349 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($this->dummyObject, 'anotherBooleanProperty'));
350 }
351
352 /**
353 * @test
354 */
355 public function isPropertyGettableWorksOnArrayAccessObjects() {
356 $arrayObject = new \ArrayObject();
357 $arrayObject['key'] = 'v';
358 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($arrayObject, 'key'));
359 $this->assertFalse(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($arrayObject, 'undefinedKey'));
360 }
361
362 /**
363 * @test
364 */
365 public function isPropertyGettableWorksOnStdClass() {
366 $stdClassObject = new \stdClass();
367 $stdClassObject->property = 'foo';
368 $this->assertTrue(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($stdClassObject, 'property'));
369 $this->assertFalse(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::isPropertyGettable($stdClassObject, 'undefinedProperty'));
370 }
371
372 /**
373 * @test
374 */
375 public function getPropertyPathCanRecursivelyGetPropertiesOfAnObject() {
376 $alternativeObject = new \TYPO3\CMS\Extbase\Tests\Unit\Reflection\Fixture\DummyClassWithGettersAndSetters();
377 $alternativeObject->setProperty('test');
378 $this->dummyObject->setProperty2($alternativeObject);
379 $expected = 'test';
380 $actual = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($this->dummyObject, 'property2.property');
381 $this->assertEquals($expected, $actual);
382 }
383
384 /**
385 * @test
386 */
387 public function getPropertyPathReturnsNullForNonExistingPropertyPath() {
388 $alternativeObject = new \TYPO3\CMS\Extbase\Tests\Unit\Reflection\Fixture\DummyClassWithGettersAndSetters();
389 $alternativeObject->setProperty(new \stdClass());
390 $this->dummyObject->setProperty2($alternativeObject);
391 $this->assertNull(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($this->dummyObject, 'property2.property.not.existing'));
392 }
393
394 /**
395 * @test
396 */
397 public function getPropertyPathReturnsNullIfSubjectIsNoObject() {
398 $string = 'Hello world';
399 $this->assertNull(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($string, 'property2'));
400 }
401
402 /**
403 * @test
404 */
405 public function getPropertyPathReturnsNullIfSubjectOnPathIsNoObject() {
406 $object = new \stdClass();
407 $object->foo = 'Hello World';
408 $this->assertNull(\TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($object, 'foo.bar'));
409 }
410
411 }