00aedb2c1e7dfd2a94a16e079382030ed58b9f34
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Mvc / View / JsonViewTest.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Tests\Unit\Mvc\View;
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 use TYPO3\CMS\Extbase\Mvc\View\JsonView;
18
19 /**
20 * Testcase for the JSON view
21 *
22 */
23 class JsonViewTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
24
25 /**
26 * @var \TYPO3\CMS\Extbase\Mvc\View\JsonView
27 */
28 protected $view;
29
30 /**
31 * @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
32 */
33 protected $controllerContext;
34
35 /**
36 * @var \TYPO3\CMS\Extbase\Mvc\Web\Response
37 */
38 protected $response;
39
40 /**
41 * Sets up this test case
42 * @return void
43 */
44 public function setUp() {
45 $this->view = $this->getMock('TYPO3\CMS\Extbase\Mvc\View\JsonView', array('loadConfigurationFromYamlFile'));
46 $this->controllerContext = $this->getMock('TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext', array(), array(), '', FALSE);
47 $this->response = $this->getMock('TYPO3\CMS\Extbase\Mvc\Web\Response', array());
48 $this->controllerContext->expects($this->any())->method('getResponse')->will($this->returnValue($this->response));
49 $this->view->setControllerContext($this->controllerContext);
50 }
51
52 /**
53 * data provider for testTransformValue()
54 * @return array
55 */
56 public function jsonViewTestData() {
57 $output = array();
58
59 $object = new \stdClass();
60 $object->value1 = 'foo';
61 $object->value2 = 1;
62 $configuration = array();
63 $expected = array('value1' => 'foo', 'value2' => 1);
64 $output[] = array($object, $configuration, $expected, 'all direct child properties should be serialized');
65
66 $configuration = array('_only' => array('value1'));
67 $expected = array('value1' => 'foo');
68 $output[] = array($object, $configuration, $expected, 'if "only" properties are specified, only these should be serialized');
69
70 $configuration = array('_exclude' => array('value1'));
71 $expected = array('value2' => 1);
72 $output[] = array($object, $configuration, $expected, 'if "exclude" properties are specified, they should not be serialized');
73
74 $object = new \stdClass();
75 $object->value1 = new \stdClass();
76 $object->value1->subvalue1 = 'Foo';
77 $object->value2 = 1;
78 $configuration = array();
79 $expected = array('value2' => 1);
80 $output[] = array($object, $configuration, $expected, 'by default, sub objects of objects should not be serialized.');
81
82 $object = new \stdClass();
83 $object->value1 = array('subarray' => 'value');
84 $object->value2 = 1;
85 $configuration = array();
86 $expected = array('value2' => 1);
87 $output[] = array($object, $configuration, $expected, 'by default, sub arrays of objects should not be serialized.');
88
89 $object = array('foo' => 'bar', 1 => 'baz', 'deep' => array('test' => 'value'));
90 $configuration = array();
91 $expected = array('foo' => 'bar', 1 => 'baz', 'deep' => array('test' => 'value'));
92 $output[] = array($object, $configuration, $expected, 'associative arrays should be serialized deeply');
93
94 $object = array('foo', 'bar');
95 $configuration = array();
96 $expected = array('foo', 'bar');
97 $output[] = array($object, $configuration, $expected, 'numeric arrays should be serialized');
98
99 $nestedObject = new \stdClass();
100 $nestedObject->value1 = 'foo';
101 $object = array($nestedObject);
102 $configuration = array();
103 $expected = array(array('value1' => 'foo'));
104 $output[] = array($object, $configuration, $expected, 'array of objects should be serialized');
105
106 $properties = array('foo' => 'bar', 'prohibited' => 'xxx');
107 $nestedObject = $this->getMock('Test' . md5(uniqid(mt_rand(), TRUE)), array('getName', 'getPath', 'getProperties', 'getOther'));
108 $nestedObject->expects($this->any())->method('getName')->will($this->returnValue('name'));
109 $nestedObject->expects($this->any())->method('getPath')->will($this->returnValue('path'));
110 $nestedObject->expects($this->any())->method('getProperties')->will($this->returnValue($properties));
111 $nestedObject->expects($this->never())->method('getOther');
112 $object = $nestedObject;
113 $configuration = array(
114 '_only' => array('name', 'path', 'properties'),
115 '_descend' => array(
116 'properties' => array(
117 '_exclude' => array('prohibited')
118 )
119 )
120 );
121 $expected = array(
122 'name' => 'name',
123 'path' => 'path',
124 'properties' => array('foo' => 'bar')
125 );
126 $output[] = array($object, $configuration, $expected, 'descending into arrays should be possible');
127
128 $nestedObject = new \stdClass();
129 $nestedObject->value1 = 'foo';
130 $value = new \SplObjectStorage();
131 $value->attach($nestedObject);
132 $configuration = array();
133 $expected = array(array('value1' => 'foo'));
134 $output[] = array($value, $configuration, $expected, 'SplObjectStorage with objects should be serialized');
135
136 $dateTimeObject = new \DateTime('2011-02-03T03:15:23', new \DateTimeZone('UTC'));
137 $configuration = array();
138 $expected = '2011-02-03T03:15:23+0000';
139 $output[] = array($dateTimeObject, $configuration, $expected, 'DateTime object in UTC time zone could not be serialized.');
140
141 $dateTimeObject = new \DateTime('2013-08-15T15:25:30', new \DateTimeZone('America/Los_Angeles'));
142 $configuration = array();
143 $expected = '2013-08-15T15:25:30-0700';
144 $output[] = array($dateTimeObject, $configuration, $expected, 'DateTime object in America/Los_Angeles time zone could not be serialized.');
145 return $output;
146 }
147
148 /**
149 * @test
150 * @dataProvider jsonViewTestData
151 */
152 public function testTransformValue($object, $configuration, $expected, $description) {
153 $jsonView = $this->getAccessibleMock('TYPO3\CMS\Extbase\Mvc\View\JsonView', array('dummy'), array(), '', FALSE);
154
155 $actual = $jsonView->_call('transformValue', $object, $configuration);
156
157 $this->assertEquals($expected, $actual, $description);
158 }
159
160 /**
161 * data provider for testTransformValueWithObjectIdentifierExposure()
162 * @return array
163 */
164 public function objectIdentifierExposureTestData() {
165 $output = array();
166
167 $dummyIdentifier = 'e4f40dfc-8c6e-4414-a5b1-6fd3c5cf7a53';
168
169 $object = new \stdClass();
170 $object->value1 = new \stdClass();
171 $configuration = array(
172 '_descend' => array(
173 'value1' => array(
174 '_exposeObjectIdentifier' => TRUE
175 )
176 )
177 );
178
179 $expected = array('value1' => array('__identity' => $dummyIdentifier));
180 $output[] = array($object, $configuration, $expected, $dummyIdentifier, 'boolean TRUE should result in __identity key');
181
182 $configuration['_descend']['value1']['_exposedObjectIdentifierKey'] = 'guid';
183 $expected = array('value1' => array('guid' => $dummyIdentifier));
184 $output[] = array($object, $configuration, $expected, $dummyIdentifier, 'string value should result in string-equal key');
185
186 return $output;
187 }
188
189 /**
190 * @test
191 * @dataProvider objectIdentifierExposureTestData
192 */
193 public function testTransformValueWithObjectIdentifierExposure($object, $configuration, $expected, $dummyIdentifier, $description) {
194 $persistenceManagerMock = $this->getMock('TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager', array('getIdentifierByObject'));
195 $jsonView = $this->getAccessibleMock('TYPO3\CMS\Extbase\Mvc\View\JsonView', array('dummy'), array(), '', FALSE);
196 $jsonView->_set('persistenceManager', $persistenceManagerMock);
197
198 $persistenceManagerMock->expects($this->once())->method('getIdentifierByObject')->with($object->value1)->will($this->returnValue($dummyIdentifier));
199
200 $actual = $jsonView->_call('transformValue', $object, $configuration);
201
202 $this->assertEquals($expected, $actual, $description);
203 }
204
205 /**
206 * A data provider
207 */
208 public function exposeClassNameSettingsAndResults() {
209 $className = 'DummyClass' . md5(uniqid(mt_rand(), TRUE));
210 $namespace = 'TYPO3\CMS\Extbase\Tests\Unit\Mvc\View\\' . $className;
211 return array(
212 array(
213 JsonView::EXPOSE_CLASSNAME_FULLY_QUALIFIED,
214 $className,
215 $namespace,
216 array('value1' => array('__class' => $namespace . '\\' . $className))
217 ),
218 array(
219 JsonView::EXPOSE_CLASSNAME_UNQUALIFIED,
220 $className,
221 $namespace,
222 array('value1' => array('__class' => $className))
223 ),
224 array(
225 NULL,
226 $className,
227 $namespace,
228 array('value1' => array())
229 )
230 );
231 }
232
233 /**
234 * @test
235 * @dataProvider exposeClassNameSettingsAndResults
236 */
237 public function viewExposesClassNameFullyIfConfiguredSo($exposeClassNameSetting, $className, $namespace, $expected) {
238 $fullyQualifiedClassName = $namespace . '\\' . $className;
239 if (class_exists($fullyQualifiedClassName) === FALSE) {
240 eval('namespace ' . $namespace . '; class ' . $className . ' {}');
241 }
242
243 $object = new \stdClass();
244 $object->value1 = new $fullyQualifiedClassName();
245 $configuration = array(
246 '_descend' => array(
247 'value1' => array(
248 '_exposeClassName' => $exposeClassNameSetting
249 )
250 )
251 );
252 $reflectionService = $this->getMock('TYPO3\CMS\Extbase\Reflection\ReflectionService');
253 $reflectionService->expects($this->any())->method('getClassNameByObject')->will($this->returnCallback(function($object) {
254 return get_class($object);
255 }));
256
257 $jsonView = $this->getAccessibleMock('TYPO3\CMS\Extbase\Mvc\View\JsonView', array('dummy'), array(), '', FALSE);
258 $this->inject($jsonView, 'reflectionService', $reflectionService);
259 $actual = $jsonView->_call('transformValue', $object, $configuration);
260 $this->assertEquals($expected, $actual);
261 }
262
263 /**
264 * @test
265 */
266 public function renderSetsContentTypeHeader() {
267 $this->response->expects($this->once())->method('setHeader')->with('Content-Type', 'application/json');
268
269 $this->view->render();
270 }
271
272 /**
273 * @test
274 */
275 public function renderReturnsJsonRepresentationOfAssignedObject() {
276 $object = new \stdClass();
277 $object->foo = 'Foo';
278 $this->view->assign('value', $object);
279
280 $expectedResult = '{"foo":"Foo"}';
281 $actualResult = $this->view->render();
282 $this->assertEquals($expectedResult, $actualResult);
283 }
284
285 /**
286 * @test
287 */
288 public function renderReturnsJsonRepresentationOfAssignedArray() {
289 $array = array('foo' => 'Foo', 'bar' => 'Bar');
290 $this->view->assign('value', $array);
291
292 $expectedResult = '{"foo":"Foo","bar":"Bar"}';
293 $actualResult = $this->view->render();
294 $this->assertEquals($expectedResult, $actualResult);
295 }
296
297 /**
298 * @test
299 */
300 public function renderReturnsJsonRepresentationOfAssignedSimpleValue() {
301 $value = 'Foo';
302 $this->view->assign('value', $value);
303
304 $expectedResult = '"Foo"';
305 $actualResult = $this->view->render();
306 $this->assertEquals($expectedResult, $actualResult);
307 }
308
309 /**
310 * @test
311 */
312 public function renderReturnsNullIfNameOfAssignedVariableIsNotEqualToValue() {
313 $value = 'Foo';
314 $this->view->assign('foo', $value);
315
316 $expectedResult = 'null';
317 $actualResult = $this->view->render();
318 $this->assertEquals($expectedResult, $actualResult);
319 }
320
321 /**
322 * @test
323 */
324 public function renderOnlyRendersVariableWithTheNameValue() {
325 $this->view
326 ->assign('value', 'Value')
327 ->assign('someOtherVariable', 'Foo');
328
329 $expectedResult = '"Value"';
330 $actualResult = $this->view->render();
331 $this->assertEquals($expectedResult, $actualResult);
332 }
333
334 /**
335 * @test
336 */
337 public function setVariablesToRenderOverridesValueToRender() {
338 $value = 'Foo';
339 $this->view->assign('foo', $value);
340 $this->view->setVariablesToRender(array('foo'));
341
342 $expectedResult = '"Foo"';
343 $actualResult = $this->view->render();
344 $this->assertEquals($expectedResult, $actualResult);
345 }
346
347 /**
348 * @test
349 */
350 public function renderRendersMultipleValuesIfTheyAreSpecifiedAsVariablesToRender() {
351 $this->view
352 ->assign('value', 'Value1')
353 ->assign('secondValue', 'Value2')
354 ->assign('someOtherVariable', 'Value3');
355 $this->view->setVariablesToRender(array('value', 'secondValue'));
356
357 $expectedResult = '{"value":"Value1","secondValue":"Value2"}';
358 $actualResult = $this->view->render();
359 $this->assertEquals($expectedResult, $actualResult);
360 }
361
362 /**
363 * @test
364 */
365 public function renderCanRenderMultipleComplexObjects() {
366 $array = array('foo' => array('bar' => 'Baz'));
367 $object = new \stdClass();
368 $object->foo = 'Foo';
369
370 $this->view
371 ->assign('array', $array)
372 ->assign('object', $object)
373 ->assign('someOtherVariable', 'Value3');
374 $this->view->setVariablesToRender(array('array', 'object'));
375
376 $expectedResult = '{"array":{"foo":{"bar":"Baz"}},"object":{"foo":"Foo"}}';
377 $actualResult = $this->view->render();
378 $this->assertEquals($expectedResult, $actualResult);
379 }
380
381 /**
382 * @test
383 */
384 public function renderCanRenderPlainArray() {
385 $array = array(array('name' => 'Foo', 'secret' => TRUE), array('name' => 'Bar', 'secret' => TRUE));
386
387 $this->view->assign('value', $array);
388 $this->view->setConfiguration(array(
389 'value' => array(
390 '_descendAll' => array(
391 '_only' => array('name')
392 )
393 )
394 ));
395
396 $expectedResult = '[{"name":"Foo"},{"name":"Bar"}]';
397 $actualResult = $this->view->render();
398 $this->assertEquals($expectedResult, $actualResult);
399 }
400
401 /**
402 * @test
403 */
404 public function descendAllKeepsArrayIndexes() {
405 $array = array(array('name' => 'Foo', 'secret' => TRUE), array('name' => 'Bar', 'secret' => TRUE));
406
407 $this->view->assign('value', $array);
408 $this->view->setConfiguration(array(
409 'value' => array(
410 '_descendAll' => array(
411 '_descendAll' => array()
412 )
413 )
414 ));
415
416 $expectedResult = '[{"name":"Foo","secret":true},{"name":"Bar","secret":true}]';
417 $actualResult = $this->view->render();
418 $this->assertEquals($expectedResult, $actualResult);
419 }
420 }