[TASK] Performance optimizations for the form manager module
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Tests / Unit / Controller / FormManagerControllerTest.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Form\Tests\Unit\Controller;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Prophecy\Argument;
19 use TYPO3\CMS\Core\Imaging\Icon;
20 use TYPO3\CMS\Core\Imaging\IconFactory;
21 use TYPO3\CMS\Core\Resource\Folder;
22 use TYPO3\CMS\Core\Resource\ResourceStorage;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24 use TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext;
25 use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
26 use TYPO3\CMS\Extbase\Object\ObjectManager;
27 use TYPO3\CMS\Form\Controller\FormManagerController;
28 use TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager;
29 use TYPO3\CMS\Form\Service\DatabaseService;
30 use TYPO3\CMS\Form\Service\TranslationService;
31 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
32
33 /**
34 * Test case
35 */
36 class FormManagerControllerTest extends UnitTestCase
37 {
38 /**
39 * @var bool Reset singletons created by subject
40 */
41 protected $resetSingletonInstances = true;
42
43 /**
44 * @test
45 */
46 public function getAccessibleFormStorageFoldersReturnsProcessedArray(): void
47 {
48 $mockController = $this->getAccessibleMock(FormManagerController::class, [
49 'dummy'
50 ], [], '', false);
51
52 $formPersistenceManagerProphecy = $this->prophesize(FormPersistenceManager::class);
53
54 $mockStorage = $this->getMockBuilder(ResourceStorage::class)
55 ->disableOriginalConstructor()
56 ->getMock();
57 $mockController->_set('formPersistenceManager', $formPersistenceManagerProphecy->reveal());
58
59 $mockController->_set('formSettings', [
60 'persistenceManager' => [
61 'allowSaveToExtensionPaths' => true,
62 ],
63 ]);
64
65 $folder1 = new Folder($mockStorage, '/user_upload/', 'user_upload');
66 $folder2 = new Folder($mockStorage, '/forms/', 'forms');
67
68 $formPersistenceManagerProphecy->getAccessibleFormStorageFolders(Argument::cetera())->willReturn([
69 '1:/user_upload/' => $folder1,
70 '2:/forms/' => $folder2,
71 ]);
72
73 $formPersistenceManagerProphecy->getAccessibleExtensionFolders(Argument::cetera())->willReturn([
74 'EXT:form/Resources/Forms/' => '/some/path/form/Resources/Forms/',
75 'EXT:form_additions/Resources/Forms/' => '/some/path/form_additions/Resources/Forms/',
76 ]);
77
78 $expected = [
79 0 => [
80 'label' => 'user_upload',
81 'value' => '1:/user_upload/',
82 ],
83 1 => [
84 'label' => 'forms',
85 'value' => '2:/forms/',
86 ],
87 2 => [
88 'label' => 'EXT:form/Resources/Forms/',
89 'value' => 'EXT:form/Resources/Forms/',
90 ],
91 3 => [
92 'label' => 'EXT:form_additions/Resources/Forms/',
93 'value' => 'EXT:form_additions/Resources/Forms/',
94 ],
95 ];
96
97 $this->assertSame($expected, $mockController->_call('getAccessibleFormStorageFolders'));
98 }
99
100 /**
101 * @test
102 */
103 public function getFormManagerAppInitialDataReturnsProcessedArray(): void
104 {
105 $objectManagerProphecy = $this->prophesize(ObjectManager::class);
106 GeneralUtility::setSingletonInstance(ObjectManager::class, $objectManagerProphecy->reveal());
107
108 $mockTranslationService = $this->getAccessibleMock(TranslationService::class, [
109 'translateValuesRecursive'
110 ], [], '', false);
111
112 $mockTranslationService
113 ->expects($this->any())
114 ->method('translateValuesRecursive')
115 ->willReturnArgument(0);
116
117 $objectManagerProphecy
118 ->get(TranslationService::class)
119 ->willReturn($mockTranslationService);
120
121 $mockController = $this->getAccessibleMock(FormManagerController::class, [
122 'getAccessibleFormStorageFolders'
123 ], [], '', false);
124
125 $mockUriBuilder = $this->createMock(UriBuilder::class);
126 $mockControllerContext = $this->createMock(ControllerContext::class);
127 $mockControllerContext
128 ->expects($this->any())
129 ->method('getUriBuilder')
130 ->will($this->returnValue($mockUriBuilder));
131
132 $mockController->_set('controllerContext', $mockControllerContext);
133
134 $mockController->_set('formSettings', [
135 'formManager' => [
136 'selectablePrototypesConfiguration' => [],
137 ],
138 ]);
139
140 $mockUriBuilder->expects($this->any())->method('uriFor')->willReturn(
141 '/typo3/index.php?some=param'
142 );
143
144 $mockController
145 ->expects($this->any())
146 ->method('getAccessibleFormStorageFolders')
147 ->willReturn([
148 0 => [
149 'label' => 'user_upload',
150 'value' => '1:/user_upload/',
151 ],
152 ]);
153
154 $expected = [
155 'selectablePrototypesConfiguration' => [],
156 'accessibleFormStorageFolders' => [
157 0 => [
158 'label' => 'user_upload',
159 'value' => '1:/user_upload/',
160 ],
161 ],
162 'endpoints' => [
163 'create' => '/typo3/index.php?some=param',
164 'duplicate' => '/typo3/index.php?some=param',
165 'delete' => '/typo3/index.php?some=param',
166 'references' => '/typo3/index.php?some=param',
167 ],
168 ];
169
170 $this->assertSame(json_encode($expected), $mockController->_call('getFormManagerAppInitialData'));
171 }
172
173 /**
174 * @test
175 */
176 public function getAvailableFormDefinitionsReturnsProcessedArray(): void
177 {
178 $mockController = $this->getAccessibleMock(FormManagerController::class, [
179 'dummy'
180 ], [], '', false);
181
182 $formPersistenceManagerProphecy = $this->prophesize(FormPersistenceManager::class);
183 $mockController->_set('formPersistenceManager', $formPersistenceManagerProphecy->reveal());
184
185 $databaseService = $this->prophesize(DatabaseService::class);
186 $mockController->_set('databaseService', $databaseService->reveal());
187
188 $formPersistenceManagerProphecy->listForms(Argument::cetera())->willReturn([
189 0 => [
190 'identifier' => 'ext-form-identifier',
191 'name' => 'some name',
192 'persistenceIdentifier' => '1:/user_uploads/someFormName.yaml',
193 'readOnly' => false,
194 'removable' => true,
195 'location' => 'storage',
196 'duplicateIdentifier' => false,
197 ],
198 ]);
199
200 $databaseService->getAllReferencesForFileUid(Argument::cetera())->willReturn([
201 0 => 0,
202 ]);
203
204 $databaseService->getAllReferencesForPersistenceIdentifier(Argument::cetera())->willReturn([
205 '1:/user_uploads/someFormName.yaml' => 2,
206 ]);
207
208 $expected = [
209 0 => [
210 'identifier' => 'ext-form-identifier',
211 'name' => 'some name',
212 'persistenceIdentifier' => '1:/user_uploads/someFormName.yaml',
213 'readOnly' => false,
214 'removable' => true,
215 'location' => 'storage',
216 'duplicateIdentifier' => false,
217 'referenceCount' => 2,
218 ],
219 ];
220
221 $this->assertSame($expected, $mockController->_call('getAvailableFormDefinitions'));
222 }
223
224 /**
225 * @test
226 */
227 public function getProcessedReferencesRowsThrowsExceptionIfPersistenceIdentifierIsEmpty(): void
228 {
229 $this->expectException(\InvalidArgumentException::class);
230 $this->expectExceptionCode(1477071939);
231
232 $mockController = $this->getAccessibleMock(FormManagerController::class, [
233 'dummy'
234 ], [], '', false);
235
236 $mockController->_call('getProcessedReferencesRows', '');
237 }
238
239 /**
240 * @test
241 */
242 public function getProcessedReferencesRowsReturnsProcessedArray()
243 {
244 $iconFactoryProphecy = $this->prophesize(IconFactory::class);
245 GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
246 $iconProphecy = $this->prophesize(Icon::class);
247 $iconFactoryProphecy->getIconForRecord(Argument::cetera())->willReturn($iconProphecy->reveal());
248 $iconProphecy->render()->shouldBeCalled()->willReturn('');
249
250 $mockController = $this->getAccessibleMock(FormManagerController::class, [
251 'getModuleUrl',
252 'getRecord',
253 'getRecordTitle',
254 ], [], '', false);
255
256 $databaseService = $this->prophesize(DatabaseService::class);
257 $mockController->_set('databaseService', $databaseService->reveal());
258
259 $databaseService->getReferencesByPersistenceIdentifier(Argument::cetera())->willReturn([
260 0 => [
261 'tablename' => 'tt_content',
262 'recuid' => -1,
263 ],
264 ]);
265
266 $mockController
267 ->expects($this->any())
268 ->method('getModuleUrl')
269 ->willReturn('/typo3/index.php?some=param');
270
271 $mockController
272 ->expects($this->any())
273 ->method('getRecord')
274 ->willReturn([ 'uid' => 1, 'pid' => 0 ]);
275
276 $mockController
277 ->expects($this->any())
278 ->method('getRecordTitle')
279 ->willReturn('record title');
280
281 $expected = [
282 0 => [
283 'recordPageTitle' => 'record title',
284 'recordTitle' => 'record title',
285 'recordIcon' => '',
286 'recordUid' => -1,
287 'recordEditUrl' => '/typo3/index.php?some=param',
288 ],
289 ];
290
291 $this->assertSame($expected, $mockController->_call('getProcessedReferencesRows', 'fake'));
292 }
293
294 /**
295 * @test
296 */
297 public function isValidTemplatePathReturnsTrueIfTemplateIsDefinedAndExists(): void
298 {
299 $mockController = $this->getAccessibleMock(FormManagerController::class, [
300 'dummy'
301 ], [], '', false);
302
303 $mockController->_set('formSettings', [
304 'formManager' => [
305 'selectablePrototypesConfiguration' => [
306 0 => [
307 'identifier' => 'standard',
308 'label' => 'some label',
309 'newFormTemplates' => [
310 0 => [
311 'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/BlankForm.yaml',
312 'label' => 'some label',
313 ],
314 1 => [
315 'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml',
316 'label' => 'some other label',
317 ],
318 ],
319 ],
320 ],
321 ],
322 ]);
323
324 $this->assertTrue($mockController->_call('isValidTemplatePath', 'standard', 'EXT:form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml'));
325 }
326
327 /**
328 * @test
329 */
330 public function isValidTemplatePathReturnsFalseIfTemplateIsDefinedButNotExists(): void
331 {
332 $mockController = $this->getAccessibleMock(FormManagerController::class, [
333 'dummy'
334 ], [], '', false);
335
336 $mockController->_set('formSettings', [
337 'formManager' => [
338 'selectablePrototypesConfiguration' => [
339 0 => [
340 'identifier' => 'standard',
341 'label' => 'some label',
342 'newFormTemplates' => [
343 0 => [
344 'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/BlankForm.yaml',
345 'label' => 'some label',
346 ],
347 1 => [
348 'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml',
349 'label' => 'some other label',
350 ],
351 ],
352 ],
353 ],
354 ],
355 ]);
356
357 $this->assertFalse($mockController->_call('isValidTemplatePath', 'standard', 'EXT:form/Tests/Unit/Controller/Fixtures/NonExistingForm.yaml'));
358 }
359
360 /**
361 * @test
362 */
363 public function isValidTemplatePathReturnsFalseIfTemplateIsNotDefinedAndExists(): void
364 {
365 $mockController = $this->getAccessibleMock(FormManagerController::class, [
366 'dummy'
367 ], [], '', false);
368
369 $mockController->_set('formSettings', [
370 'formManager' => [
371 'selectablePrototypesConfiguration' => [
372 0 => [
373 'identifier' => 'standard',
374 'label' => 'some label',
375 'newFormTemplates' => [
376 0 => [
377 'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/BlankForm.yaml',
378 'label' => 'some label',
379 ],
380 1 => [
381 'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml',
382 'label' => 'some other label',
383 ],
384 ],
385 ],
386 1 => [
387 'identifier' => 'other',
388 'label' => 'some label',
389 'newFormTemplates' => [
390 0 => [
391 'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/BlankForm.yaml',
392 'label' => 'some label',
393 ],
394 ],
395 ],
396 ],
397 ],
398 ]);
399
400 $this->assertFalse($mockController->_call('isValidTemplatePath', 'other', 'EXT:form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml'));
401 }
402
403 /**
404 * @test
405 */
406 public function convertFormNameToIdentifierRemoveSpaces(): void
407 {
408 $mockController = $this->getAccessibleMock(FormManagerController::class, [
409 'dummy'
410 ], [], '', false);
411
412 $input = 'test form';
413 $expected = 'testform';
414 $this->assertSame($expected, $mockController->_call('convertFormNameToIdentifier', $input));
415 }
416
417 /**
418 * @test
419 */
420 public function convertFormNameToIdentifierRemoveSpecialChars(): void
421 {
422 $mockController = $this->getAccessibleMock(FormManagerController::class, [
423 'dummy'
424 ], [], '', false);
425
426 $input = 'test form รค#!_-01';
427 $expected = 'testform_-01';
428 $this->assertSame($expected, $mockController->_call('convertFormNameToIdentifier', $input));
429 }
430 }