2 namespace TYPO3\CMS\Extbase\Tests\Unit\Mvc\View
;
5 * This file is part of the TYPO3 CMS project.
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.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use TYPO3\CMS\Extbase\Mvc\View\JsonView
;
20 * Testcase for the JSON view
22 class JsonViewTest
extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
25 * @var \TYPO3\CMS\Extbase\Mvc\View\JsonView
30 * @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
32 protected $controllerContext;
35 * @var \TYPO3\CMS\Extbase\Mvc\Web\Response
40 * Sets up this test case
42 protected function setUp()
44 $this->view
= $this->getMockBuilder(\TYPO3\CMS\Extbase\Mvc\View\JsonView
::class)
45 ->setMethods(['loadConfigurationFromYamlFile'])
47 $this->controllerContext
= $this->createMock(\TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
::class);
48 $this->response
= $this->createMock(\TYPO3\CMS\Extbase\Mvc\Web\Response
::class);
49 $this->controllerContext
->expects($this->any())->method('getResponse')->will($this->returnValue($this->response
));
50 $this->view
->setControllerContext($this->controllerContext
);
54 * data provider for testTransformValue()
57 public function jsonViewTestData()
61 $object = new \
stdClass();
62 $object->value1
= 'foo';
65 $expected = ['value1' => 'foo', 'value2' => 1];
66 $output[] = [$object, $configuration, $expected, 'all direct child properties should be serialized'];
68 $configuration = ['_only' => ['value1']];
69 $expected = ['value1' => 'foo'];
70 $output[] = [$object, $configuration, $expected, 'if "only" properties are specified, only these should be serialized'];
72 $configuration = ['_exclude' => ['value1']];
73 $expected = ['value2' => 1];
74 $output[] = [$object, $configuration, $expected, 'if "exclude" properties are specified, they should not be serialized'];
76 $object = new \
stdClass();
77 $object->value1
= new \
stdClass();
78 $object->value1
->subvalue1
= 'Foo';
81 $expected = ['value2' => 1];
82 $output[] = [$object, $configuration, $expected, 'by default, sub objects of objects should not be serialized.'];
84 $object = new \
stdClass();
85 $object->value1
= ['subarray' => 'value'];
88 $expected = ['value2' => 1];
89 $output[] = [$object, $configuration, $expected, 'by default, sub arrays of objects should not be serialized.'];
91 $object = ['foo' => 'bar', 1 => 'baz', 'deep' => ['test' => 'value']];
93 $expected = ['foo' => 'bar', 1 => 'baz', 'deep' => ['test' => 'value']];
94 $output[] = [$object, $configuration, $expected, 'associative arrays should be serialized deeply'];
96 $object = ['foo', 'bar'];
98 $expected = ['foo', 'bar'];
99 $output[] = [$object, $configuration, $expected, 'numeric arrays should be serialized'];
101 $nestedObject = new \
stdClass();
102 $nestedObject->value1
= 'foo';
103 $object = [$nestedObject];
105 $expected = [['value1' => 'foo']];
106 $output[] = [$object, $configuration, $expected, 'array of objects should be serialized'];
108 $properties = ['foo' => 'bar', 'prohibited' => 'xxx'];
109 $nestedObject = $this->getMockBuilder($this->getUniqueId('Test'))
110 ->setMethods(['getName', 'getPath', 'getProperties', 'getOther'])
112 $nestedObject->expects($this->any())->method('getName')->will($this->returnValue('name'));
113 $nestedObject->expects($this->any())->method('getPath')->will($this->returnValue('path'));
114 $nestedObject->expects($this->any())->method('getProperties')->will($this->returnValue($properties));
115 $nestedObject->expects($this->never())->method('getOther');
116 $object = $nestedObject;
118 '_only' => ['name', 'path', 'properties'],
121 '_exclude' => ['prohibited']
128 'properties' => ['foo' => 'bar']
130 $output[] = [$object, $configuration, $expected, 'descending into arrays should be possible'];
132 $nestedObject = new \
stdClass();
133 $nestedObject->value1
= 'foo';
134 $value = new \
SplObjectStorage();
135 $value->attach($nestedObject);
137 $expected = [['value1' => 'foo']];
138 $output[] = [$value, $configuration, $expected, 'SplObjectStorage with objects should be serialized'];
140 $dateTimeObject = new \
DateTime('2011-02-03T03:15:23', new \
DateTimeZone('UTC'));
142 $expected = '2011-02-03T03:15:23+00:00';
143 $output[] = [$dateTimeObject, $configuration, $expected, 'DateTime object in UTC time zone could not be serialized.'];
145 $dateTimeObject = new \
DateTime('2013-08-15T15:25:30', new \
DateTimeZone('America/Los_Angeles'));
147 $expected = '2013-08-15T15:25:30-07:00';
148 $output[] = [$dateTimeObject, $configuration, $expected, 'DateTime object in America/Los_Angeles time zone could not be serialized.'];
154 * @dataProvider jsonViewTestData
156 public function testTransformValue($object, $configuration, $expected, $description)
158 $jsonView = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Mvc\View\JsonView
::class, ['dummy'], [], '', false);
160 $actual = $jsonView->_call('transformValue', $object, $configuration);
162 $this->assertEquals($expected, $actual, $description);
166 * data provider for testTransformValueWithObjectIdentifierExposure()
169 public function objectIdentifierExposureTestData()
173 $dummyIdentifier = 'e4f40dfc-8c6e-4414-a5b1-6fd3c5cf7a53';
175 $object = new \
stdClass();
176 $object->value1
= new \
stdClass();
180 '_exposeObjectIdentifier' => true
185 $expected = ['value1' => ['__identity' => $dummyIdentifier]];
186 $output[] = [$object, $configuration, $expected, $dummyIdentifier, 'boolean TRUE should result in __identity key'];
188 $configuration['_descend']['value1']['_exposedObjectIdentifierKey'] = 'guid';
189 $expected = ['value1' => ['guid' => $dummyIdentifier]];
190 $output[] = [$object, $configuration, $expected, $dummyIdentifier, 'string value should result in string-equal key'];
197 * @dataProvider objectIdentifierExposureTestData
199 public function testTransformValueWithObjectIdentifierExposure($object, $configuration, $expected, $dummyIdentifier, $description)
201 $persistenceManagerMock = $this->getMockBuilder(\TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
::class)
202 ->setMethods(['getIdentifierByObject'])
204 $jsonView = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Mvc\View\JsonView
::class, ['dummy'], [], '', false);
205 $jsonView->_set('persistenceManager', $persistenceManagerMock);
207 $persistenceManagerMock->expects($this->once())->method('getIdentifierByObject')->with($object->value1
)->will($this->returnValue($dummyIdentifier));
209 $actual = $jsonView->_call('transformValue', $object, $configuration);
211 $this->assertEquals($expected, $actual, $description);
217 public function exposeClassNameSettingsAndResults()
219 $className = $this->getUniqueId('DummyClass');
220 $namespace = 'TYPO3\CMS\Extbase\Tests\Unit\Mvc\View\\' . $className;
223 JsonView
::EXPOSE_CLASSNAME_FULLY_QUALIFIED
,
226 ['value1' => ['__class' => $namespace . '\\' . $className]]
229 JsonView
::EXPOSE_CLASSNAME_UNQUALIFIED
,
232 ['value1' => ['__class' => $className]]
245 * @dataProvider exposeClassNameSettingsAndResults
247 public function viewExposesClassNameFullyIfConfiguredSo($exposeClassNameSetting, $className, $namespace, $expected)
249 $fullyQualifiedClassName = $namespace . '\\' . $className;
250 if (class_exists($fullyQualifiedClassName) === false) {
251 eval('namespace ' . $namespace . '; class ' . $className . ' {}');
254 $object = new \
stdClass();
255 $object->value1
= new $fullyQualifiedClassName();
259 '_exposeClassName' => $exposeClassNameSetting
263 $reflectionService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Reflection\ReflectionService
::class)
264 ->setMethods([ 'getClassNameByObject' ])
266 $reflectionService->expects($this->any())->method('getClassNameByObject')->will($this->returnCallback(function ($object) {
267 return get_class($object);
270 $jsonView = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Mvc\View\JsonView
::class, ['dummy'], [], '', false);
271 $this->inject($jsonView, 'reflectionService', $reflectionService);
272 $actual = $jsonView->_call('transformValue', $object, $configuration);
273 $this->assertEquals($expected, $actual);
279 public function renderSetsContentTypeHeader()
281 $this->response
->expects($this->once())->method('setHeader')->with('Content-Type', 'application/json');
283 $this->view
->render();
289 public function renderReturnsJsonRepresentationOfAssignedObject()
291 $object = new \
stdClass();
292 $object->foo
= 'Foo';
293 $this->view
->assign('value', $object);
295 $expectedResult = '{"foo":"Foo"}';
296 $actualResult = $this->view
->render();
297 $this->assertEquals($expectedResult, $actualResult);
303 public function renderReturnsJsonRepresentationOfAssignedArray()
305 $array = ['foo' => 'Foo', 'bar' => 'Bar'];
306 $this->view
->assign('value', $array);
308 $expectedResult = '{"foo":"Foo","bar":"Bar"}';
309 $actualResult = $this->view
->render();
310 $this->assertEquals($expectedResult, $actualResult);
316 public function renderReturnsJsonRepresentationOfAssignedSimpleValue()
319 $this->view
->assign('value', $value);
321 $expectedResult = '"Foo"';
322 $actualResult = $this->view
->render();
323 $this->assertEquals($expectedResult, $actualResult);
329 public function renderKeepsUtf8CharactersUnescaped(): void
332 $this->view
->assign('value', $value);
334 $actualResult = $this->view
->render();
336 $expectedResult = '"' . $value . '"';
337 $this->assertSame($expectedResult, $actualResult);
343 public function escapeCharacterDataProvider(): array
346 'backslash' => ['\\'],
347 'double quote' => ['"'],
353 * @param string $character
354 * @dataProvider escapeCharacterDataProvider
356 public function renderEscapesEscapeCharacters(string $character): void
358 $this->view
->assign('value', $character);
360 $actualResult = $this->view
->render();
362 $expectedResult = '"\\' . $character . '"';
363 $this->assertSame($expectedResult, $actualResult);
369 public function renderReturnsNullIfNameOfAssignedVariableIsNotEqualToValue()
372 $this->view
->assign('foo', $value);
374 $expectedResult = 'null';
375 $actualResult = $this->view
->render();
376 $this->assertEquals($expectedResult, $actualResult);
382 public function renderOnlyRendersVariableWithTheNameValue()
385 ->assign('value', 'Value')
386 ->assign('someOtherVariable', 'Foo');
388 $expectedResult = '"Value"';
389 $actualResult = $this->view
->render();
390 $this->assertEquals($expectedResult, $actualResult);
396 public function setVariablesToRenderOverridesValueToRender()
399 $this->view
->assign('foo', $value);
400 $this->view
->setVariablesToRender(['foo']);
402 $expectedResult = '"Foo"';
403 $actualResult = $this->view
->render();
404 $this->assertEquals($expectedResult, $actualResult);
410 public function renderRendersMultipleValuesIfTheyAreSpecifiedAsVariablesToRender()
413 ->assign('value', 'Value1')
414 ->assign('secondValue', 'Value2')
415 ->assign('someOtherVariable', 'Value3');
416 $this->view
->setVariablesToRender(['value', 'secondValue']);
418 $expectedResult = '{"value":"Value1","secondValue":"Value2"}';
419 $actualResult = $this->view
->render();
420 $this->assertEquals($expectedResult, $actualResult);
426 public function renderCanRenderMultipleComplexObjects()
428 $array = ['foo' => ['bar' => 'Baz']];
429 $object = new \
stdClass();
430 $object->foo
= 'Foo';
433 ->assign('array', $array)
434 ->assign('object', $object)
435 ->assign('someOtherVariable', 'Value3');
436 $this->view
->setVariablesToRender(['array', 'object']);
438 $expectedResult = '{"array":{"foo":{"bar":"Baz"}},"object":{"foo":"Foo"}}';
439 $actualResult = $this->view
->render();
440 $this->assertEquals($expectedResult, $actualResult);
446 public function renderCanRenderPlainArray()
448 $array = [['name' => 'Foo', 'secret' => true], ['name' => 'Bar', 'secret' => true]];
450 $this->view
->assign('value', $array);
451 $this->view
->setConfiguration([
459 $expectedResult = '[{"name":"Foo"},{"name":"Bar"}]';
460 $actualResult = $this->view
->render();
461 $this->assertEquals($expectedResult, $actualResult);
467 public function descendAllKeepsArrayIndexes()
469 $array = [['name' => 'Foo', 'secret' => true], ['name' => 'Bar', 'secret' => true]];
471 $this->view
->assign('value', $array);
472 $this->view
->setConfiguration([
480 $expectedResult = '[{"name":"Foo","secret":true},{"name":"Bar","secret":true}]';
481 $actualResult = $this->view
->render();
482 $this->assertEquals($expectedResult, $actualResult);