[FEATURE] Ext:form - extend the extension location functionality
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Tests / Unit / Mvc / Persistence / FormPersistenceManagerTest.php
1 <?php
2 namespace TYPO3\CMS\Form\Tests\Unit\Mvc\Persistence;
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\Core\Resource\File;
18 use TYPO3\CMS\Core\Resource\ResourceStorage;
19 use TYPO3\CMS\Core\Resource\StorageRepository;
20 use TYPO3\CMS\Form\Mvc\Persistence\Exception\NoUniqueIdentifierException;
21 use TYPO3\CMS\Form\Mvc\Persistence\Exception\PersistenceManagerException;
22 use TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager;
23
24 /**
25 * Test case
26 */
27 class FormPersistenceManagerTest extends \TYPO3\CMS\Components\TestingFramework\Core\UnitTestCase
28 {
29
30 /**
31 * @test
32 */
33 public function loadThrowsExceptionIfPersistenceIdentifierHasNoYamlExtension()
34 {
35 $this->expectException(PersistenceManagerException::class);
36 $this->expectExceptionCode(1477679819);
37
38 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
39 'dummy'
40 ], [], '', false);
41
42 $input = '-1:/user_uploads/_example.php';
43 $mockFormPersistenceManager->_call('load', $input);
44 }
45
46 /**
47 * @test
48 */
49 public function loadThrowsExceptionIfPersistenceIdentifierIsAExtensionLocationWhichIsNotAllowed()
50 {
51 $this->expectException(PersistenceManagerException::class);
52 $this->expectExceptionCode(1484071985);
53
54 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
55 'dummy'
56 ], [], '', false);
57
58 $mockFormPersistenceManager->_set('formSettings', [
59 'persistenceManager' => [
60 'allowedExtensionPaths' => [],
61 ],
62 ]);
63
64 $input = 'EXT:form/Resources/Forms/_example.yaml';
65 $mockFormPersistenceManager->_call('load', $input);
66 }
67
68 /**
69 * @test
70 */
71 public function saveThrowsExceptionIfPersistenceIdentifierHasNoYamlExtension()
72 {
73 $this->expectException(PersistenceManagerException::class);
74 $this->expectExceptionCode(1477679820);
75
76 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
77 'dummy'
78 ], [], '', false);
79
80 $input = '-1:/user_uploads/_example.php';
81 $mockFormPersistenceManager->_call('save', $input, []);
82 }
83
84 /**
85 * @test
86 */
87 public function saveThrowsExceptionIfPersistenceIdentifierIsAExtensionLocationAndSaveToExtensionLocationIsNotAllowed()
88 {
89 $this->expectException(PersistenceManagerException::class);
90 $this->expectExceptionCode(1477680881);
91
92 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
93 'dummy'
94 ], [], '', false);
95
96 $mockFormPersistenceManager->_set('formSettings', [
97 'persistenceManager' => [
98 'allowSaveToExtensionPaths' => false,
99 ],
100 ]);
101
102 $input = 'EXT:form/Resources/Forms/_example.yaml';
103 $mockFormPersistenceManager->_call('save', $input, []);
104 }
105
106 /**
107 * @test
108 */
109 public function saveThrowsExceptionIfPersistenceIdentifierIsAExtensionLocationWhichIsNotAllowed()
110 {
111 $this->expectException(PersistenceManagerException::class);
112 $this->expectExceptionCode(1484073571);
113
114 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
115 'dummy'
116 ], [], '', false);
117
118 $mockFormPersistenceManager->_set('formSettings', [
119 'persistenceManager' => [
120 'allowSaveToExtensionPaths' => true,
121 'allowedExtensionPaths' => [],
122 ],
123 ]);
124
125 $input = 'EXT:form/Resources/Forms/_example.yaml';
126 $mockFormPersistenceManager->_call('save', $input, []);
127 }
128
129 /**
130 * @test
131 */
132 public function deleteThrowsExceptionIfPersistenceIdentifierHasNoYamlExtension()
133 {
134 $this->expectException(PersistenceManagerException::class);
135 $this->expectExceptionCode(1472239534);
136
137 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
138 'dummy'
139 ], [], '', false);
140
141 $input = '-1:/user_uploads/_example.php';
142 $mockFormPersistenceManager->_call('delete', $input);
143 }
144
145 /**
146 * @test
147 */
148 public function deleteThrowsExceptionIfPersistenceIdentifierFileDoesNotExists()
149 {
150 $this->expectException(PersistenceManagerException::class);
151 $this->expectExceptionCode(1472239535);
152
153 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
154 'exists'
155 ], [], '', false);
156
157 $mockFormPersistenceManager
158 ->expects($this->any())
159 ->method('exists')
160 ->willReturn(false);
161
162 $input = '-1:/user_uploads/_example.yaml';
163 $mockFormPersistenceManager->_call('delete', $input);
164 }
165
166 /**
167 * @test
168 */
169 public function deleteThrowsExceptionIfPersistenceIdentifierIsExtensionLocationAndDeleteFromExtensionLocationsIsNotAllowed()
170 {
171 $this->expectException(PersistenceManagerException::class);
172 $this->expectExceptionCode(1472239536);
173
174 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
175 'exists'
176 ], [], '', false);
177
178 $mockFormPersistenceManager
179 ->expects($this->any())
180 ->method('exists')
181 ->willReturn(true);
182
183 $mockFormPersistenceManager->_set('formSettings', [
184 'persistenceManager' => [
185 'allowDeleteFromExtensionPaths' => false,
186 ],
187 ]);
188
189 $input = 'EXT:form/Resources/Forms/_example.yaml';
190 $mockFormPersistenceManager->_call('delete', $input);
191 }
192
193 /**
194 * @test
195 */
196 public function deleteThrowsExceptionIfPersistenceIdentifierIsExtensionLocationWhichIsNotAllowed()
197 {
198 $this->expectException(PersistenceManagerException::class);
199 $this->expectExceptionCode(1484073878);
200
201 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
202 'exists'
203 ], [], '', false);
204
205 $mockFormPersistenceManager
206 ->expects($this->any())
207 ->method('exists')
208 ->willReturn(true);
209
210 $mockFormPersistenceManager->_set('formSettings', [
211 'persistenceManager' => [
212 'allowDeleteFromExtensionPaths' => true,
213 'allowedExtensionPaths' => [],
214 ],
215 ]);
216
217 $input = 'EXT:form/Resources/Forms/_example.yaml';
218 $mockFormPersistenceManager->_call('delete', $input);
219 }
220
221 /**
222 * @test
223 */
224 public function deleteThrowsExceptionIfPersistenceIdentifierIsStorageLocationAndDeleteFromStorageIsNotAllowed()
225 {
226 $this->expectException(PersistenceManagerException::class);
227 $this->expectExceptionCode(1472239516);
228
229 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
230 'getStorageByUid',
231 'exists'
232 ], [], '', false);
233
234 $mockStorage = $this->getMockBuilder(ResourceStorage::class)
235 ->disableOriginalConstructor()
236 ->getMock();
237
238 $mockStorage
239 ->expects($this->any())
240 ->method('checkFileActionPermission')
241 ->willReturn(false);
242
243 $file = new File(['identifier' => '', 'mime_type' => ''], $mockStorage);
244 $mockStorage
245 ->expects($this->any())
246 ->method('getFile')
247 ->willReturn($file);
248
249 $mockFormPersistenceManager
250 ->expects($this->any())
251 ->method('getStorageByUid')
252 ->willReturn($mockStorage);
253
254 $mockFormPersistenceManager
255 ->expects($this->any())
256 ->method('exists')
257 ->willReturn(true);
258
259 $input = '-1:/user_uploads/_example.yaml';
260 $mockFormPersistenceManager->_call('delete', $input);
261 }
262
263 /**
264 * @test
265 */
266 public function existsReturnsTrueIfPersistenceIdentifierIsExtensionLocationAndFileExistsAndFileHasYamlExtension()
267 {
268 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
269 'dummy'
270 ], [], '', false);
271
272 $mockFormPersistenceManager->_set('formSettings', [
273 'persistenceManager' => [
274 'allowedExtensionPaths' => [
275 'EXT:form/Tests/Unit/Mvc/Persistence/Fixtures/'
276 ],
277 ],
278 ]);
279
280 $input = 'EXT:form/Tests/Unit/Mvc/Persistence/Fixtures/BlankForm.yaml';
281 $this->assertTrue($mockFormPersistenceManager->_call('exists', $input));
282 }
283
284 /**
285 * @test
286 */
287 public function existsReturnsFalseIfPersistenceIdentifierIsExtensionLocationAndFileExistsAndFileHasNoYamlExtension()
288 {
289 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
290 'dummy'
291 ], [], '', false);
292
293 $input = 'EXT:form/Tests/Unit/Mvc/Persistence/Fixtures/BlankForm.txt';
294 $this->assertFalse($mockFormPersistenceManager->_call('exists', $input));
295 }
296
297 /**
298 * @test
299 */
300 public function existsReturnsFalseIfPersistenceIdentifierIsExtensionLocationAndFileExistsAndExtensionLocationIsNotAllowed()
301 {
302 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
303 'dummy'
304 ], [], '', false);
305
306 $mockFormPersistenceManager->_set('formSettings', [
307 'persistenceManager' => [
308 'allowedExtensionPaths' => [],
309 ],
310 ]);
311
312 $input = 'EXT:form/Tests/Unit/Mvc/Persistence/Fixtures/BlankForm.yaml';
313 $this->assertFalse($mockFormPersistenceManager->_call('exists', $input));
314 }
315
316 /**
317 * @test
318 */
319 public function existsReturnsFalseIfPersistenceIdentifierIsExtensionLocationAndFileNotExistsAndFileHasYamlExtension()
320 {
321 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
322 'dummy'
323 ], [], '', false);
324
325 $input = 'EXT:form/Tests/Unit/Mvc/Persistence/Fixtures/_BlankForm.yaml';
326 $this->assertFalse($mockFormPersistenceManager->_call('exists', $input));
327 }
328
329 /**
330 * @test
331 */
332 public function existsReturnsTrueIfPersistenceIdentifierIsStorageLocationAndFileExistsAndFileHasYamlExtension()
333 {
334 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
335 'getStorageByUid'
336 ], [], '', false);
337
338 $mockStorage = $this->getMockBuilder(ResourceStorage::class)
339 ->disableOriginalConstructor()
340 ->getMock();
341 $mockStorage
342 ->expects($this->any())
343 ->method('hasFile')
344 ->willReturn(true);
345
346 $mockFormPersistenceManager
347 ->expects($this->any())
348 ->method('getStorageByUid')
349 ->willReturn($mockStorage);
350
351 $input = '-1:/user_uploads/_example.yaml';
352 $this->assertTrue($mockFormPersistenceManager->_call('exists', $input));
353 }
354
355 /**
356 * @test
357 */
358 public function existsReturnsFalseIfPersistenceIdentifierIsStorageLocationAndFileExistsAndFileNoYamlExtension()
359 {
360 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
361 'getStorageByUid'
362 ], [], '', false);
363
364 $mockStorage = $this->getMockBuilder(ResourceStorage::class)
365 ->disableOriginalConstructor()
366 ->getMock();
367 $mockStorage
368 ->expects($this->any())
369 ->method('hasFile')
370 ->willReturn(true);
371
372 $mockFormPersistenceManager
373 ->expects($this->any())
374 ->method('getStorageByUid')
375 ->willReturn($mockStorage);
376
377 $input = '-1:/user_uploads/_example.php';
378 $this->assertFalse($mockFormPersistenceManager->_call('exists', $input));
379 }
380
381 /**
382 * @test
383 */
384 public function existsReturnsFalseIfPersistenceIdentifierIsStorageLocationAndFileNotExistsAndFileHasYamlExtension()
385 {
386 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
387 'getStorageByUid'
388 ], [], '', false);
389
390 $mockStorage = $this->getMockBuilder(ResourceStorage::class)
391 ->disableOriginalConstructor()
392 ->getMock();
393 $mockStorage
394 ->expects($this->any())
395 ->method('hasFile')
396 ->willReturn(false);
397
398 $mockFormPersistenceManager
399 ->expects($this->any())
400 ->method('getStorageByUid')
401 ->willReturn($mockStorage);
402
403 $input = '-1:/user_uploads/_example.yaml';
404 $this->assertFalse($mockFormPersistenceManager->_call('exists', $input));
405 }
406
407 /**
408 * @test
409 */
410 public function getUniquePersistenceIdentifierAppendNumberIfPersistenceIdentifierExists()
411 {
412 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
413 'exists'
414 ], [], '', false);
415
416 $mockFormPersistenceManager
417 ->expects($this->at(0))
418 ->method('exists')
419 ->willReturn(true);
420
421 $mockFormPersistenceManager
422 ->expects($this->at(1))
423 ->method('exists')
424 ->willReturn(true);
425
426 $mockFormPersistenceManager
427 ->expects($this->at(2))
428 ->method('exists')
429 ->willReturn(false);
430
431 $input = 'example';
432 $expected = '-1:/user_uploads/example_2.yaml';
433 $this->assertSame($expected, $mockFormPersistenceManager->_call('getUniquePersistenceIdentifier', $input, '-1:/user_uploads/'));
434 }
435
436 /**
437 * @test
438 */
439 public function getUniquePersistenceIdentifierAppendTimestampIfPersistenceIdentifierExists()
440 {
441 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
442 'exists'
443 ], [], '', false);
444
445 for ($attempts = 0; $attempts <= 99; $attempts++) {
446 $mockFormPersistenceManager
447 ->expects($this->at($attempts))
448 ->method('exists')
449 ->willReturn(true);
450 }
451
452 $mockFormPersistenceManager
453 ->expects($this->at(100))
454 ->method('exists')
455 ->willReturn(false);
456
457 $input = 'example';
458 $expected = '#^-1:/user_uploads/example_([0-9]{10}).yaml$#';
459
460 $returnValue = $mockFormPersistenceManager->_call('getUniquePersistenceIdentifier', $input, '-1:/user_uploads/');
461 $this->assertEquals(1, preg_match($expected, $returnValue));
462 }
463
464 /**
465 * @test
466 */
467 public function getUniqueIdentifierThrowsExceptionIfIdentifierExists()
468 {
469 $this->expectException(NoUniqueIdentifierException::class);
470 $this->expectExceptionCode(1477688567);
471
472 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
473 'checkForDuplicateIdentifier'
474 ], [], '', false);
475
476 $mockFormPersistenceManager
477 ->expects($this->any())
478 ->method('checkForDuplicateIdentifier')
479 ->willReturn(true);
480
481 $input = 'example';
482 $mockFormPersistenceManager->_call('getUniqueIdentifier', $input);
483 }
484
485 /**
486 * @test
487 */
488 public function getUniqueIdentifierAppendTimestampIfIdentifierExists()
489 {
490 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
491 'checkForDuplicateIdentifier'
492 ], [], '', false);
493
494 for ($attempts = 0; $attempts <= 99; $attempts++) {
495 $mockFormPersistenceManager
496 ->expects($this->at($attempts))
497 ->method('checkForDuplicateIdentifier')
498 ->willReturn(true);
499 }
500
501 $mockFormPersistenceManager
502 ->expects($this->at(100))
503 ->method('checkForDuplicateIdentifier')
504 ->willReturn(false);
505
506 $input = 'example';
507 $expected = '#^example_([0-9]{10})$#';
508
509 $returnValue = $mockFormPersistenceManager->_call('getUniqueIdentifier', $input);
510 $this->assertEquals(1, preg_match($expected, $returnValue));
511 }
512
513 /**
514 * @test
515 */
516 public function checkForDuplicateIdentifierReturnsTrueIfIdentifierIsUsed()
517 {
518 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
519 'listForms'
520 ], [], '', false);
521
522 $mockFormPersistenceManager
523 ->expects($this->at($attempts))
524 ->method('listForms')
525 ->willReturn([
526 0 => [
527 'identifier' => 'example',
528 ],
529 ]);
530
531 $input = 'example';
532 $this->assertTrue($mockFormPersistenceManager->_call('checkForDuplicateIdentifier', $input));
533 }
534
535 /**
536 * @test
537 */
538 public function checkForDuplicateIdentifierReturnsFalseIfIdentifierIsUsed()
539 {
540 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
541 'listForms'
542 ], [], '', false);
543
544 $mockFormPersistenceManager
545 ->expects($this->at($attempts))
546 ->method('listForms')
547 ->willReturn([
548 0 => [
549 'identifier' => 'example',
550 ],
551 ]);
552
553 $input = 'other-example';
554 $this->assertFalse($mockFormPersistenceManager->_call('checkForDuplicateIdentifier', $input));
555 }
556
557 /**
558 * @test
559 */
560 public function getFileByIdentifierThrowsExceptionIfReadFromStorageIsNotAllowed()
561 {
562 $this->expectException(PersistenceManagerException::class);
563 $this->expectExceptionCode(1471630578);
564
565 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
566 'getStorageByUid',
567 ], [], '', false);
568
569 $mockStorage = $this->getMockBuilder(ResourceStorage::class)
570 ->disableOriginalConstructor()
571 ->getMock();
572
573 $mockStorage
574 ->expects($this->any())
575 ->method('checkFileActionPermission')
576 ->willReturn(false);
577
578 $file = new File(['identifier' => '', 'mime_type' => ''], $mockStorage);
579 $mockStorage
580 ->expects($this->any())
581 ->method('getFile')
582 ->willReturn($file);
583
584 $mockFormPersistenceManager
585 ->expects($this->any())
586 ->method('getStorageByUid')
587 ->willReturn($mockStorage);
588
589 $input = '-1:/user_uploads/example.yaml';
590 $mockFormPersistenceManager->_call('getFileByIdentifier', $input);
591 }
592
593 /**
594 * @test
595 */
596 public function getOrCreateFileThrowsExceptionIfFolderNotExistsInStorage()
597 {
598 $this->expectException(PersistenceManagerException::class);
599 $this->expectExceptionCode(1471630579);
600
601 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
602 'getStorageByUid',
603 ], [], '', false);
604
605 $mockStorage = $this->getMockBuilder(ResourceStorage::class)
606 ->disableOriginalConstructor()
607 ->getMock();
608
609 $mockStorage
610 ->expects($this->any())
611 ->method('hasFolder')
612 ->willReturn(false);
613
614 $mockFormPersistenceManager
615 ->expects($this->any())
616 ->method('getStorageByUid')
617 ->willReturn($mockStorage);
618
619 $input = '-1:/user_uploads/example.yaml';
620 $mockFormPersistenceManager->_call('getOrCreateFile', $input);
621 }
622
623 /**
624 * @test
625 */
626 public function getOrCreateFileThrowsExceptionIfWriteToStorageIsNotAllowed()
627 {
628 $this->expectException(PersistenceManagerException::class);
629 $this->expectExceptionCode(1471630580);
630
631 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
632 'getStorageByUid',
633 ], [], '', false);
634
635 $mockStorage = $this->getMockBuilder(ResourceStorage::class)
636 ->disableOriginalConstructor()
637 ->getMock();
638
639 $mockStorage
640 ->expects($this->any())
641 ->method('hasFolder')
642 ->willReturn(true);
643
644 $mockStorage
645 ->expects($this->any())
646 ->method('checkFileActionPermission')
647 ->willReturn(false);
648
649 $file = new File(['identifier' => '', 'mime_type' => ''], $mockStorage);
650 $mockStorage
651 ->expects($this->any())
652 ->method('getFile')
653 ->willReturn($file);
654
655 $mockFormPersistenceManager
656 ->expects($this->any())
657 ->method('getStorageByUid')
658 ->willReturn($mockStorage);
659
660 $input = '-1:/user_uploads/example.yaml';
661 $mockFormPersistenceManager->_call('getOrCreateFile', $input);
662 }
663
664 /**
665 * @test
666 */
667 public function getStorageByUidThrowsExceptionIfStorageNotExists()
668 {
669 $this->expectException(PersistenceManagerException::class);
670 $this->expectExceptionCode(1471630581);
671
672 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
673 'dummy',
674 ], [], '', false);
675
676 $mockStorageRepository = $this->getMockBuilder(StorageRepository::class)
677 ->disableOriginalConstructor()
678 ->getMock();
679
680 $mockStorageRepository
681 ->expects($this->any())
682 ->method('findByUid')
683 ->willReturn(null);
684
685 $mockFormPersistenceManager->_set('storageRepository', $mockStorageRepository);
686 $mockFormPersistenceManager->_call('getStorageByUid', -1);
687 }
688
689 /**
690 * @test
691 */
692 public function getStorageByUidThrowsExceptionIfStorageIsNotBrowsable()
693 {
694 $this->expectException(PersistenceManagerException::class);
695 $this->expectExceptionCode(1471630581);
696
697 $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
698 'dummy',
699 ], [], '', false);
700
701 $mockStorageRepository = $this->getMockBuilder(StorageRepository::class)
702 ->disableOriginalConstructor()
703 ->getMock();
704
705 $mockStorage = $this->getMockBuilder(ResourceStorage::class)
706 ->disableOriginalConstructor()
707 ->getMock();
708
709 $mockStorage
710 ->expects($this->any())
711 ->method('isBrowsable')
712 ->willReturn(false);
713
714 $mockStorageRepository
715 ->expects($this->any())
716 ->method('findByUid')
717 ->willReturn($mockStorage);
718
719 $mockFormPersistenceManager->_set('storageRepository', $mockStorageRepository);
720 $mockFormPersistenceManager->_call('getStorageByUid', -1);
721 }
722 }