4a6a30ec56230ea36383e700845b6ef031c304c4
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Resource / ResourceStorageTest.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Core\Tests\Unit\Resource;
5
6 /*
7 * This file is part of the TYPO3 CMS project.
8 *
9 * It is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License, either version 2
11 * of the License, or any later version.
12 *
13 * For the full copyright and license information, please read the
14 * LICENSE.txt file that was distributed with this source code.
15 *
16 * The TYPO3 project - inspiring people to share!
17 */
18
19 use Prophecy\Argument;
20 use TYPO3\CMS\Core\Cache\CacheManager;
21 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
22 use TYPO3\CMS\Core\Resource\Driver\AbstractDriver;
23 use TYPO3\CMS\Core\Resource\Driver\LocalDriver;
24 use TYPO3\CMS\Core\Resource\DuplicationBehavior;
25 use TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException;
26 use TYPO3\CMS\Core\Resource\File;
27 use TYPO3\CMS\Core\Resource\FileInterface;
28 use TYPO3\CMS\Core\Resource\FileRepository;
29 use TYPO3\CMS\Core\Resource\Folder;
30 use TYPO3\CMS\Core\Resource\Index\FileIndexRepository;
31 use TYPO3\CMS\Core\Resource\Index\Indexer;
32 use TYPO3\CMS\Core\Resource\ResourceFactory;
33 use TYPO3\CMS\Core\Resource\ResourceStorage;
34 use TYPO3\CMS\Core\Utility\ArrayUtility;
35 use TYPO3\CMS\Core\Utility\GeneralUtility;
36
37 /**
38 * Test case for ResourceStorage class
39 */
40 class ResourceStorageTest extends BaseTestCase
41 {
42 /**
43 * @var bool Reset singletons created by subject
44 */
45 protected $resetSingletonInstances = true;
46
47 /**
48 * @var ResourceStorage|\PHPUnit_Framework_MockObject_MockObject
49 */
50 protected $subject;
51
52 /**
53 * Set up
54 */
55 protected function setUp(): void
56 {
57 parent::setUp();
58 /** @var FileRepository|\PHPUnit_Framework_MockObject_MockObject $fileRepositoryMock */
59 $fileRepositoryMock = $this->createMock(FileRepository::class);
60 GeneralUtility::setSingletonInstance(
61 FileRepository::class,
62 $fileRepositoryMock
63 );
64 $cacheManagerProphecy = $this->prophesize(CacheManager::class);
65 $cacheProphecy = $this->prophesize(FrontendInterface::class);
66 $cacheManagerProphecy->getCache('cache_runtime')->willReturn($cacheProphecy->reveal());
67 $cacheProphecy->get(Argument::cetera())->willReturn(false);
68 $cacheProphecy->set(Argument::cetera())->willReturn(false);
69 GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
70 }
71
72 /**
73 * Prepare ResourceStorage
74 *
75 * @param array $configuration
76 * @param bool $mockPermissionChecks
77 * @param AbstractDriver|\PHPUnit_Framework_MockObject_MockObject $driverObject
78 * @param array $storageRecord
79 * @param array $mockedMethods
80 */
81 protected function prepareSubject(
82 array $configuration,
83 bool $mockPermissionChecks = false,
84 AbstractDriver $driverObject = null,
85 array $storageRecord = [],
86 array $mockedMethods = []
87 ): void {
88 $permissionMethods = [
89 'assureFileAddPermissions',
90 'checkFolderActionPermission',
91 'checkFileActionPermission',
92 'checkUserActionPermission',
93 'checkFileExtensionPermission',
94 'isWithinFileMountBoundaries',
95 'assureFileRenamePermissions'
96 ];
97 $configuration = $this->convertConfigurationArrayToFlexformXml($configuration);
98 $overruleArray = ['configuration' => $configuration];
99 ArrayUtility::mergeRecursiveWithOverrule($storageRecord, $overruleArray);
100 if ($driverObject === null) {
101 $driverObject = $this->getMockForAbstractClass(AbstractDriver::class, [], '', false);
102 }
103 if ($mockPermissionChecks) {
104 $mockedMethods = array_merge($mockedMethods, $permissionMethods);
105 }
106 $mockedMethods[] = 'getIndexer';
107
108 $this->subject = $this->getMockBuilder(ResourceStorage::class)
109 ->setMethods(array_unique($mockedMethods))
110 ->setConstructorArgs([$driverObject, $storageRecord])
111 ->getMock();
112 $this->subject->expects($this->any())->method('getIndexer')->will($this->returnValue($this->createMock(Indexer::class)));
113 if ($mockPermissionChecks) {
114 foreach ($permissionMethods as $method) {
115 $this->subject->expects($this->any())->method($method)->will($this->returnValue(true));
116 }
117 }
118 }
119
120 /**
121 * Converts a simple configuration array into a FlexForm data structure serialized as XML
122 *
123 * @param array $configuration
124 * @return string
125 * @see GeneralUtility::array2xml()
126 */
127 protected function convertConfigurationArrayToFlexformXml(array $configuration): string
128 {
129 $flexFormArray = ['data' => ['sDEF' => ['lDEF' => []]]];
130 foreach ($configuration as $key => $value) {
131 $flexFormArray['data']['sDEF']['lDEF'][$key] = ['vDEF' => $value];
132 }
133 $configuration = GeneralUtility::array2xml($flexFormArray);
134 return $configuration;
135 }
136
137 /**
138 * Creates a driver fixture object, optionally using a given mount object.
139 *
140 * IMPORTANT: Call this only after setting up the virtual file system (with the addTo* methods)!
141 *
142 * @param $driverConfiguration
143 * @param ResourceStorage $storageObject
144 * @param array $mockedDriverMethods
145 * @return \TYPO3\CMS\Core\Resource\Driver\LocalDriver|\PHPUnit_Framework_MockObject_MockObject
146 */
147 protected function createDriverMock(
148 $driverConfiguration,
149 ResourceStorage $storageObject = null,
150 array $mockedDriverMethods = []
151 ) {
152 $this->initializeVfs();
153
154 if (!isset($driverConfiguration['basePath'])) {
155 $driverConfiguration['basePath'] = $this->getMountRootUrl();
156 }
157
158 if ($mockedDriverMethods === null) {
159 $driver = new LocalDriver($driverConfiguration);
160 } else {
161 // We are using the LocalDriver here because PHPUnit can't mock concrete methods in abstract classes, so
162 // when using the AbstractDriver we would be in trouble when wanting to mock away some concrete method
163 $driver = $this->getMockBuilder(LocalDriver::class)
164 ->setMethods($mockedDriverMethods)
165 ->setConstructorArgs([$driverConfiguration])
166 ->getMock();
167 }
168 if ($storageObject !== null) {
169 $storageObject->setDriver($driver);
170 }
171 $driver->setStorageUid(6);
172 $driver->processConfiguration();
173 $driver->initialize();
174 return $driver;
175 }
176
177 /**
178 * @return array
179 */
180 public function capabilitiesDataProvider(): array
181 {
182 return [
183 'only public' => [
184 [
185 'public' => true,
186 'writable' => false,
187 'browsable' => false
188 ]
189 ],
190 'only writable' => [
191 [
192 'public' => false,
193 'writable' => true,
194 'browsable' => false
195 ]
196 ],
197 'only browsable' => [
198 [
199 'public' => false,
200 'writable' => false,
201 'browsable' => true
202 ]
203 ],
204 'all capabilities' => [
205 [
206 'public' => true,
207 'writable' => true,
208 'browsable' => true
209 ]
210 ],
211 'none' => [
212 [
213 'public' => false,
214 'writable' => false,
215 'browsable' => false
216 ]
217 ]
218 ];
219 }
220
221 /**
222 * @test
223 * @dataProvider capabilitiesDataProvider
224 * @TODO: Rewrite or move to functional suite
225 * @param array $capabilities
226 */
227 public function capabilitiesOfStorageObjectAreCorrectlySet(array $capabilities): void
228 {
229 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
230 $storageRecord = [
231 'is_public' => $capabilities['public'],
232 'is_writable' => $capabilities['writable'],
233 'is_browsable' => $capabilities['browsable'],
234 'is_online' => true
235 ];
236 $mockedDriver = $this->createDriverMock(
237 [
238 'pathType' => 'relative',
239 'basePath' => 'fileadmin/',
240 ],
241 $this->subject,
242 null
243 );
244 $this->prepareSubject([], false, $mockedDriver, $storageRecord);
245 $this->assertEquals(
246 $capabilities['public'],
247 $this->subject->isPublic(),
248 'Capability "public" is not correctly set.'
249 );
250 $this->assertEquals(
251 $capabilities['writable'],
252 $this->subject->isWritable(),
253 'Capability "writable" is not correctly set.'
254 );
255 $this->assertEquals(
256 $capabilities['browsable'],
257 $this->subject->isBrowsable(),
258 'Capability "browsable" is not correctly set.'
259 );
260 }
261
262 /**
263 * @test
264 * @TODO: Rewrite or move to functional suite
265 */
266 public function fileAndFolderListFiltersAreInitializedWithDefaultFilters(): void
267 {
268 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
269 $this->prepareSubject([]);
270 $this->assertEquals(
271 $GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['defaultFilterCallbacks'],
272 $this->subject->getFileAndFolderNameFilters()
273 );
274 }
275
276 /**
277 * @test
278 */
279 public function addFileFailsIfFileDoesNotExist(): void
280 {
281 /** @var Folder|\PHPUnit_Framework_MockObject_MockObject $mockedFolder */
282 $mockedFolder = $this->createMock(Folder::class);
283 $this->expectException(\InvalidArgumentException::class);
284 $this->expectExceptionCode(1319552745);
285 $this->prepareSubject([]);
286 $this->subject->addFile('/some/random/file', $mockedFolder);
287 }
288
289 /**
290 * @test
291 */
292 public function getPublicUrlReturnsNullIfStorageIsNotOnline(): void
293 {
294 /** @var $driver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
295 $driver = $this->getMockBuilder(LocalDriver::class)
296 ->setConstructorArgs([['basePath' => $this->getMountRootUrl()]])
297 ->getMock();
298 /** @var $subject ResourceStorage|\PHPUnit_Framework_MockObject_MockObject */
299 $subject = $this->getMockBuilder(ResourceStorage::class)
300 ->setMethods(['isOnline'])
301 ->setConstructorArgs([$driver, ['configuration' => []]])
302 ->getMock();
303 $subject->expects($this->once())->method('isOnline')->will($this->returnValue(false));
304
305 $sourceFileIdentifier = '/sourceFile.ext';
306 $sourceFile = $this->getSimpleFileMock($sourceFileIdentifier);
307 $result = $subject->getPublicUrl($sourceFile);
308 $this->assertSame($result, null);
309 }
310
311 /**
312 * Data provider for checkFolderPermissionsRespectsFilesystemPermissions
313 *
314 * @return array
315 */
316 public function checkFolderPermissionsFilesystemPermissionsDataProvider(): array
317 {
318 return [
319 'read action on readable/writable folder' => [
320 'read',
321 ['r' => true, 'w' => true],
322 true
323 ],
324 'read action on unreadable folder' => [
325 'read',
326 ['r' => false, 'w' => true],
327 false
328 ],
329 'write action on read-only folder' => [
330 'write',
331 ['r' => true, 'w' => false],
332 false
333 ]
334 ];
335 }
336
337 /**
338 * @test
339 * @dataProvider checkFolderPermissionsFilesystemPermissionsDataProvider
340 * @param string $action 'read' or 'write'
341 * @param array $permissionsFromDriver The permissions as returned from the driver
342 * @param bool $expectedResult
343 */
344 public function checkFolderPermissionsRespectsFilesystemPermissions(
345 string $action,
346 array $permissionsFromDriver,
347 bool $expectedResult
348 ): void {
349 /** @var $mockedDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
350 $mockedDriver = $this->createMock(LocalDriver::class);
351 $mockedDriver->expects($this->any())->method('getPermissions')->will($this->returnValue($permissionsFromDriver));
352 /** @var $mockedFolder Folder|\PHPUnit_Framework_MockObject_MockObject */
353 $mockedFolder = $this->createMock(Folder::class);
354 // Let all other checks pass
355 /** @var $subject ResourceStorage|\PHPUnit_Framework_MockObject_MockObject */
356 $subject = $this->getMockBuilder(ResourceStorage::class)
357 ->setMethods(['isWritable', 'isBrowsable', 'checkUserActionPermission'])
358 ->setConstructorArgs([$mockedDriver, []])
359 ->getMock();
360 $subject->expects($this->any())->method('isWritable')->will($this->returnValue(true));
361 $subject->expects($this->any())->method('isBrowsable')->will($this->returnValue(true));
362 $subject->expects($this->any())->method('checkUserActionPermission')->will($this->returnValue(true));
363 $subject->setDriver($mockedDriver);
364
365 $this->assertSame($expectedResult, $subject->checkFolderActionPermission($action, $mockedFolder));
366 }
367
368 /**
369 * @test
370 */
371 public function checkUserActionPermissionsAlwaysReturnsTrueIfNoUserPermissionsAreSet(): void
372 {
373 $this->prepareSubject([]);
374 $this->assertTrue($this->subject->checkUserActionPermission('read', 'folder'));
375 }
376
377 /**
378 * @test
379 */
380 public function checkUserActionPermissionReturnsFalseIfPermissionIsSetToZero(): void
381 {
382 $this->prepareSubject([]);
383 $this->subject->setUserPermissions(['readFolder' => true, 'writeFile' => true]);
384 $this->assertTrue($this->subject->checkUserActionPermission('read', 'folder'));
385 }
386
387 /**
388 * @return array
389 */
390 public function checkUserActionPermission_arbitraryPermissionDataProvider(): array
391 {
392 return [
393 'all lower cased' => [
394 ['readFolder' => true],
395 'read',
396 'folder'
397 ],
398 'all upper case' => [
399 ['readFolder' => true],
400 'READ',
401 'FOLDER'
402 ],
403 'mixed case' => [
404 ['readFolder' => true],
405 'ReaD',
406 'FoLdEr'
407 ]
408 ];
409 }
410
411 /**
412 * @param array $permissions
413 * @param string $action
414 * @param string $type
415 * @test
416 * @dataProvider checkUserActionPermission_arbitraryPermissionDataProvider
417 */
418 public function checkUserActionPermissionAcceptsArbitrarilyCasedArguments(array $permissions, string $action, string $type): void
419 {
420 $this->prepareSubject([]);
421 $this->subject->setUserPermissions($permissions);
422 $this->assertTrue($this->subject->checkUserActionPermission($action, $type));
423 }
424
425 /**
426 * @test
427 */
428 public function userActionIsDisallowedIfPermissionIsSetToFalse(): void
429 {
430 $this->prepareSubject([]);
431 $this->subject->setEvaluatePermissions(true);
432 $this->subject->setUserPermissions(['readFolder' => false]);
433 $this->assertFalse($this->subject->checkUserActionPermission('read', 'folder'));
434 }
435
436 /**
437 * @test
438 */
439 public function userActionIsDisallowedIfPermissionIsNotSet(): void
440 {
441 $this->prepareSubject([]);
442 $this->subject->setEvaluatePermissions(true);
443 $this->subject->setUserPermissions(['readFolder' => true]);
444 $this->assertFalse($this->subject->checkUserActionPermission('write', 'folder'));
445 }
446
447 /**
448 * @test
449 */
450 public function getEvaluatePermissionsWhenSetFalse(): void
451 {
452 $this->prepareSubject([]);
453 $this->subject->setEvaluatePermissions(false);
454 $this->assertFalse($this->subject->getEvaluatePermissions());
455 }
456
457 /**
458 * @test
459 */
460 public function getEvaluatePermissionsWhenSetTrue(): void
461 {
462 $this->prepareSubject([]);
463 $this->subject->setEvaluatePermissions(true);
464 $this->assertTrue($this->subject->getEvaluatePermissions());
465 }
466
467 /**
468 * @test
469 * @group integration
470 * @TODO: Rewrite or move to functional suite
471 */
472 public function setFileContentsUpdatesObjectProperties(): void
473 {
474 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
475 $this->initializeVfs();
476 $driverObject = $this->getMockForAbstractClass(AbstractDriver::class, [], '', false);
477 $this->subject = $this->getMockBuilder(ResourceStorage::class)
478 ->setMethods(['getFileIndexRepository', 'checkFileActionPermission'])
479 ->setConstructorArgs([$driverObject, []])
480 ->getMock();
481 $this->subject->expects($this->any())->method('checkFileActionPermission')->will($this->returnValue(true));
482 $fileInfo = [
483 'storage' => 'A',
484 'identifier' => 'B',
485 'mtime' => 'C',
486 'ctime' => 'D',
487 'mimetype' => 'E',
488 'size' => 'F',
489 'name' => 'G',
490 ];
491 $newProperties = [
492 'storage' => $fileInfo['storage'],
493 'identifier' => $fileInfo['identifier'],
494 'tstamp' => $fileInfo['mtime'],
495 'crdate' => $fileInfo['ctime'],
496 'mime_type' => $fileInfo['mimetype'],
497 'size' => $fileInfo['size'],
498 'name' => $fileInfo['name']
499 ];
500 $hash = 'asdfg';
501 /** @var $mockedDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
502 $mockedDriver = $this->getMockBuilder(LocalDriver::class)
503 ->setConstructorArgs([['basePath' => $this->getMountRootUrl()]])
504 ->getMock();
505 $mockedDriver->expects($this->once())->method('getFileInfoByIdentifier')->will($this->returnValue($fileInfo));
506 $mockedDriver->expects($this->once())->method('hash')->will($this->returnValue($hash));
507 $this->subject->setDriver($mockedDriver);
508 $indexFileRepositoryMock = $this->createMock(FileIndexRepository::class);
509 $this->subject->expects($this->any())->method('getFileIndexRepository')->will($this->returnValue($indexFileRepositoryMock));
510 /** @var $mockedFile File|\PHPUnit_Framework_MockObject_MockObject */
511 $mockedFile = $this->createMock(File::class);
512 $mockedFile->expects($this->any())->method('getIdentifier')->will($this->returnValue($fileInfo['identifier']));
513 // called by indexer because the properties are updated
514 $this->subject->expects($this->any())->method('getFileInfoByIdentifier')->will($this->returnValue($newProperties));
515 $mockedFile->expects($this->any())->method('getStorage')->will($this->returnValue($this->subject));
516 $mockedFile->expects($this->any())->method('getProperties')->will($this->returnValue(array_keys($fileInfo)));
517 $mockedFile->expects($this->any())->method('getUpdatedProperties')->will($this->returnValue(array_keys($newProperties)));
518 // do not update directly; that's up to the indexer
519 $indexFileRepositoryMock->expects($this->never())->method('update');
520 $this->subject->setFileContents($mockedFile, $this->getUniqueId());
521 }
522
523 /**
524 * @test
525 * @group integration
526 * @TODO: Rewrite or move to functional suite
527 */
528 public function moveFileCallsDriversMethodsWithCorrectArguments(): void
529 {
530 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
531 $localFilePath = '/path/to/localFile';
532 $sourceFileIdentifier = '/sourceFile.ext';
533 $fileInfoDummy = [
534 'storage' => 'A',
535 'identifier' => 'B',
536 'mtime' => 'C',
537 'ctime' => 'D',
538 'mimetype' => 'E',
539 'size' => 'F',
540 'name' => 'G',
541 ];
542 $this->addToMount([
543 'targetFolder' => []
544 ]);
545 $this->initializeVfs();
546 $targetFolder = $this->getSimpleFolderMock('/targetFolder/');
547 /** @var $sourceDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
548 $sourceDriver = $this->createMock(LocalDriver::class);
549 $sourceDriver->expects($this->once())->method('deleteFile')->with($this->equalTo($sourceFileIdentifier));
550 $configuration = $this->convertConfigurationArrayToFlexformXml([]);
551 $sourceStorage = new ResourceStorage($sourceDriver, ['configuration' => $configuration]);
552 $sourceFile = $this->getSimpleFileMock($sourceFileIdentifier);
553 $sourceFile->expects($this->once())->method('getForLocalProcessing')->will($this->returnValue($localFilePath));
554 $sourceFile->expects($this->any())->method('getStorage')->will($this->returnValue($sourceStorage));
555 $sourceFile->expects($this->once())->method('getUpdatedProperties')->will($this->returnValue(array_keys($fileInfoDummy)));
556 $sourceFile->expects($this->once())->method('getProperties')->will($this->returnValue($fileInfoDummy));
557 /** @var $mockedDriver \TYPO3\CMS\Core\Resource\Driver\LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
558 $mockedDriver = $this->getMockBuilder(LocalDriver::class)
559 ->setConstructorArgs([['basePath' => $this->getMountRootUrl()]])
560 ->getMock();
561 $mockedDriver->expects($this->once())->method('getFileInfoByIdentifier')->will($this->returnValue($fileInfoDummy));
562 $mockedDriver->expects($this->once())->method('addFile')->with(
563 $localFilePath,
564 '/targetFolder/',
565 $this->equalTo('file.ext')
566 )->will($this->returnValue('/targetFolder/file.ext'));
567 /** @var $subject ResourceStorage */
568 $subject = $this->getMockBuilder(ResourceStorage::class)
569 ->setMethods(['assureFileMovePermissions'])
570 ->setConstructorArgs([$mockedDriver, ['configuration' => $configuration]])
571 ->getMock();
572 $subject->moveFile($sourceFile, $targetFolder, 'file.ext');
573 }
574
575 /**
576 * @test
577 * @group integration
578 * @TODO: Rewrite or move to functional suite
579 */
580 public function storageUsesInjectedFilemountsToCheckForMountBoundaries(): void
581 {
582 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
583 $mockedFile = $this->getSimpleFileMock('/mountFolder/file');
584 $this->addToMount([
585 'mountFolder' => [
586 'file' => 'asdfg'
587 ]
588 ]);
589 $mockedDriver = $this->createDriverMock(['basePath' => $this->getMountRootUrl()], null, null);
590 $this->initializeVfs();
591 $this->prepareSubject([], null, $mockedDriver);
592 $this->subject->addFileMount('/mountFolder');
593 $this->assertEquals(1, count($this->subject->getFileMounts()));
594 $this->subject->isWithinFileMountBoundaries($mockedFile);
595 }
596
597 /**
598 * @test
599 * @TODO: Rewrite or move to functional suite
600 */
601 public function createFolderChecksIfParentFolderExistsBeforeCreatingFolder(): void
602 {
603 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
604 $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
605 $mockedDriver = $this->createDriverMock([]);
606 $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(true));
607 $mockedDriver->expects($this->once())->method('createFolder')->with($this->equalTo('newFolder'))->will($this->returnValue($mockedParentFolder));
608 $this->prepareSubject([], true);
609 $this->subject->setDriver($mockedDriver);
610 $this->subject->createFolder('newFolder', $mockedParentFolder);
611 }
612
613 /**
614 * @test
615 */
616 public function deleteFolderThrowsExceptionIfFolderIsNotEmptyAndRecursiveDeleteIsDisabled(): void
617 {
618 $this->expectException(\RuntimeException::class);
619 $this->expectExceptionCode(1325952534);
620
621 /** @var \TYPO3\CMS\Core\Resource\Folder|\PHPUnit_Framework_MockObject_MockObject $folderMock */
622 $folderMock = $this->createMock(Folder::class);
623 /** @var $mockedDriver \TYPO3\CMS\Core\Resource\Driver\AbstractDriver|\PHPUnit_Framework_MockObject_MockObject */
624 $mockedDriver = $this->getMockForAbstractClass(AbstractDriver::class);
625 $mockedDriver->expects($this->once())->method('isFolderEmpty')->will($this->returnValue(false));
626 /** @var $subject ResourceStorage|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface */
627 $subject = $this->getAccessibleMock(ResourceStorage::class, ['checkFolderActionPermission'], [], '', false);
628 $subject->expects($this->any())->method('checkFolderActionPermission')->will($this->returnValue(true));
629 $subject->_set('driver', $mockedDriver);
630 $subject->deleteFolder($folderMock, false);
631 }
632
633 /**
634 * @test
635 * @TODO: Rewrite or move to functional suite
636 */
637 public function createFolderCallsDriverForFolderCreation(): void
638 {
639 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
640 $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
641 $this->prepareSubject([], true);
642 $mockedDriver = $this->createDriverMock([], $this->subject);
643 $mockedDriver->expects($this->once())->method('createFolder')->with(
644 $this->equalTo('newFolder'),
645 $this->equalTo('/someFolder/')
646 )->will($this->returnValue(true));
647 $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(true));
648 $this->subject->createFolder('newFolder', $mockedParentFolder);
649 }
650
651 /**
652 * @test
653 * @TODO: Rewrite or move to functional suite
654 */
655 public function createFolderCanRecursivelyCreateFolders(): void
656 {
657 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
658 $this->addToMount(['someFolder' => []]);
659 $mockedDriver = $this->createDriverMock(['basePath' => $this->getMountRootUrl()], null, null);
660 $this->prepareSubject([], true, $mockedDriver);
661 $parentFolder = $this->subject->getFolder('/someFolder/');
662 $newFolder = $this->subject->createFolder('subFolder/secondSubfolder', $parentFolder);
663 $this->assertEquals('secondSubfolder', $newFolder->getName());
664 $this->assertFileExists($this->getUrlInMount('/someFolder/subFolder/'));
665 $this->assertFileExists($this->getUrlInMount('/someFolder/subFolder/secondSubfolder/'));
666 }
667
668 /**
669 * @test
670 * @TODO: Rewrite or move to functional suite
671 */
672 public function createFolderUsesRootFolderAsParentFolderIfNotGiven(): void
673 {
674 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
675 $this->prepareSubject([], true);
676 $mockedDriver = $this->createDriverMock([], $this->subject);
677 $mockedDriver->expects($this->once())->method('getRootLevelFolder')->with()->will($this->returnValue('/'));
678 $mockedDriver->expects($this->once())->method('createFolder')->with($this->equalTo('someFolder'));
679 $this->subject->createFolder('someFolder');
680 }
681
682 /**
683 * @test
684 * @TODO: Rewrite or move to functional suite
685 */
686 public function createFolderCreatesNestedStructureEvenIfPartsAlreadyExist(): void
687 {
688 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
689 $this->addToMount([
690 'existingFolder' => []
691 ]);
692 $this->initializeVfs();
693 $mockedDriver = $this->createDriverMock(['basePath' => $this->getMountRootUrl()], null, null);
694 $this->prepareSubject([], true, $mockedDriver);
695 $rootFolder = $this->subject->getFolder('/');
696 $newFolder = $this->subject->createFolder('existingFolder/someFolder', $rootFolder);
697 $this->assertEquals('someFolder', $newFolder->getName());
698 $this->assertFileExists($this->getUrlInMount('existingFolder/someFolder'));
699 }
700
701 /**
702 * @test
703 */
704 public function createFolderThrowsExceptionIfParentFolderDoesNotExist(): void
705 {
706 $this->expectException(\InvalidArgumentException::class);
707 $this->expectExceptionCode(1325689164);
708 $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
709 $this->prepareSubject([], true);
710 $mockedDriver = $this->createDriverMock([], $this->subject);
711 $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(false));
712 $this->subject->createFolder('newFolder', $mockedParentFolder);
713 }
714
715 /**
716 * @test
717 */
718 public function renameFileRenamesFileAsRequested(): void
719 {
720 $mockedDriver = $this->createDriverMock([], $this->subject);
721 $mockedDriver->expects($this->once())->method('renameFile')->will($this->returnValue('bar'));
722 $this->prepareSubject([], true, $mockedDriver, [], ['emitPreFileRenameSignal', 'emitPostFileRenameSignal']);
723 /** @var File $file */
724 $file = new File(['identifier' => 'foo', 'name' => 'foo'], $this->subject);
725 $result = $this->subject->renameFile($file, 'bar');
726 // fake what the indexer does in updateIndexEntry
727 $result->updateProperties(['name' => $result->getIdentifier()]);
728 $this->assertSame('bar', $result->getName());
729 }
730
731 /**
732 * @test
733 */
734 public function renameFileRenamesWithUniqueNameIfConflictAndConflictModeIsRename(): void
735 {
736 $mockedDriver = $this->createDriverMock([], $this->subject);
737 $mockedDriver->expects($this->any())->method('renameFile')->will($this->onConsecutiveCalls($this->throwException(new ExistingTargetFileNameException(
738 'foo',
739 1489593090
740 )), 'bar_01'));
741 //$mockedDriver->expects($this->at(1))->method('renameFile')->will($this->returnValue('bar_01'));
742 $mockedDriver->expects($this->any())->method('sanitizeFileName')->will($this->onConsecutiveCalls(
743 'bar',
744 'bar_01'
745 ));
746 $this->prepareSubject(
747 [],
748 true,
749 $mockedDriver,
750 [],
751 ['emitPreFileRenameSignal', 'emitPostFileRenameSignal', 'getUniqueName']
752 );
753 /** @var File $file */
754 $file = new File(['identifier' => 'foo', 'name' => 'foo'], $this->subject);
755 $this->subject->expects($this->once())->method('getUniqueName')->will($this->returnValue('bar_01'));
756 $result = $this->subject->renameFile($file, 'bar');
757 // fake what the indexer does in updateIndexEntry
758 $result->updateProperties(['name' => $result->getIdentifier()]);
759 $this->assertSame('bar_01', $result->getName());
760 }
761
762 /**
763 * @test
764 */
765 public function renameFileThrowsExceptionIfConflictAndConflictModeIsCancel(): void
766 {
767 $mockedDriver = $this->createDriverMock([], $this->subject);
768 $mockedDriver->expects($this->once())->method('renameFile')->will($this->throwException(new ExistingTargetFileNameException(
769 'foo',
770 1489593099
771 )));
772 $this->prepareSubject([], true, $mockedDriver, [], ['emitPreFileRenameSignal', 'emitPostFileRenameSignal']);
773 /** @var File $file */
774 $file = new File(['identifier' => 'foo', 'name' => 'foo'], $this->subject);
775 $this->expectException(ExistingTargetFileNameException::class);
776 $this->subject->renameFile($file, 'bar', DuplicationBehavior::CANCEL);
777 }
778
779 /**
780 * @test
781 */
782 public function renameFileReplacesIfConflictAndConflictModeIsReplace(): void
783 {
784 $mockedDriver = $this->createDriverMock([], $this->subject);
785 $mockedDriver->expects($this->once())->method('renameFile')->will($this->throwException(new ExistingTargetFileNameException(
786 'foo',
787 1489593098
788 )));
789 $mockedDriver->expects($this->any())->method('sanitizeFileName')->will($this->returnValue('bar'));
790 $this->prepareSubject([], true, $mockedDriver, [], [
791 'emitPreFileRenameSignal',
792 'emitPostFileRenameSignal',
793 'replaceFile',
794 'getPublicUrl',
795 'getResourceFactoryInstance'
796 ]);
797 $this->subject->expects($this->once())->method('getPublicUrl')->will($this->returnValue('somePath'));
798 $resourceFactory = $this->prophesize(ResourceFactory::class);
799 $file = $this->prophesize(FileInterface::class);
800 $resourceFactory->getFileObjectFromCombinedIdentifier(Argument::any())->willReturn($file->reveal());
801 $this->subject->expects($this->once())->method('replaceFile')->will($this->returnValue($file->reveal()));
802 $this->subject->expects($this->any())->method('getResourceFactoryInstance')->will(self::returnValue($resourceFactory->reveal()));
803 /** @var File $file */
804 $file = new File(['identifier' => 'foo', 'name' => 'foo', 'missing' => false], $this->subject);
805 $this->subject->renameFile($file, 'bar', DuplicationBehavior::REPLACE);
806 }
807 }