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