[BUGFIX] Make meta data editable for non-writable storages
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Resource / ResourceStorageTest.php
index ab92afd..c1ebb56 100644 (file)
 <?php
-namespace TYPO3\CMS\Core\Tests\Unit\Resource;
+declare(strict_types = 1);
 
-use TYPO3\CMS\Core\Resource\ResourceStorage;
+namespace TYPO3\CMS\Core\Tests\Unit\Resource;
 
-/***************************************************************
- * Copyright notice
- *
- * (c) 2011-2013 Andreas Wolf <andreas.wolf@ikt-werk.de>
- * All rights reserved
- *
- * This script is part of the TYPO3 project. The TYPO3 project is
- * free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+/*
+ * This file is part of the TYPO3 CMS project.
  *
- * The GNU General Public License can be found at
- * http://www.gnu.org/copyleft/gpl.html.
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
  *
- * This script is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
  *
- * This copyright notice MUST APPEAR in all copies of the script!
- ***************************************************************/
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Prophecy\Argument;
+use TYPO3\CMS\Core\Cache\CacheManager;
+use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
+use TYPO3\CMS\Core\Resource\Driver\AbstractDriver;
+use TYPO3\CMS\Core\Resource\Driver\LocalDriver;
+use TYPO3\CMS\Core\Resource\DuplicationBehavior;
+use TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException;
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Core\Resource\FileInterface;
+use TYPO3\CMS\Core\Resource\FileRepository;
+use TYPO3\CMS\Core\Resource\Folder;
+use TYPO3\CMS\Core\Resource\Index\FileIndexRepository;
+use TYPO3\CMS\Core\Resource\Index\Indexer;
+use TYPO3\CMS\Core\Resource\ResourceFactory;
+use TYPO3\CMS\Core\Resource\ResourceStorage;
+use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
- * Testcase for the VFS mount class
- *
- * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
+ * Test case for ResourceStorage class
  */
-class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCase {
-
-       /**
-        * @var array A backup of registered singleton instances
-        */
-       protected $singletonInstances = array();
-
-       /**
-        * @var \TYPO3\CMS\Core\Resource\ResourceStorage
-        */
-       private $fixture;
-
-       public function setUp() {
-               parent::setUp();
-               $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
-               \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
-               \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance(
-                       'TYPO3\\CMS\\Core\\Resource\\FileRepository',
-                       $this->getMock('TYPO3\\CMS\\Core\\Resource\\FileRepository')
-               );
-
-       }
-
-       public function tearDown() {
-               parent::tearDown();
-               \TYPO3\CMS\Core\Utility\GeneralUtility::resetSingletonInstances($this->singletonInstances);
-       }
-
-       /**
-        * Prepare fixture
-        *
-        * @param array $configuration
-        * @param boolean $mockPermissionChecks
-        * @return void
-        */
-       protected function prepareFixture($configuration, $mockPermissionChecks = FALSE, $driverObject = NULL, array $storageRecord = array()) {
-               $permissionMethods = array('assureFileAddPermissions', 'checkFolderActionPermission', 'checkFileActionPermission', 'checkUserActionPermission', 'checkFileExtensionPermission', 'isWithinFileMountBoundaries');
-               $mockedMethods = array();
-               $configuration = $this->convertConfigurationArrayToFlexformXml($configuration);
-               $overruleArray = array('configuration' => $configuration);
-               \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($storageRecord, $overruleArray);
-               if ($driverObject == NULL) {
-                       /** @var $mockedDriver \TYPO3\CMS\Core\Resource\Driver\AbstractDriver */
-                       $driverObject = $this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Driver\\AbstractDriver', array(), '', FALSE);
-               }
-               if ($mockPermissionChecks) {
-                       $mockedMethods = $permissionMethods;
-               }
-               $mockedMethods[] = 'getIndexer';
-
-
-               $this->fixture = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', $mockedMethods, array($driverObject, $storageRecord));
-               $this->fixture->expects($this->any())->method('getIndexer')->will($this->returnValue($this->getMock('TYPO3\CMS\Core\Resource\Index\Indexer', array(), array(), '', FALSE)));
-               foreach ($permissionMethods as $method) {
-                       $this->fixture->expects($this->any())->method($method)->will($this->returnValue(TRUE));
-               }
-       }
-
-       /**
-        * Converts a simple configuration array into a FlexForm data structure serialized as XML
-        *
-        * @param array $configuration
-        * @return string
-        * @see \TYPO3\CMS\Core\Utility\GeneralUtility::array2xml()
-        */
-       protected function convertConfigurationArrayToFlexformXml(array $configuration) {
-               $flexformArray = array('data' => array('sDEF' => array('lDEF' => array())));
-               foreach ($configuration as $key => $value) {
-                       $flexformArray['data']['sDEF']['lDEF'][$key] = array('vDEF' => $value);
-               }
-               $configuration = \TYPO3\CMS\Core\Utility\GeneralUtility::array2xml($flexformArray);
-               return $configuration;
-       }
-
-       /**
-        * Creates a driver fixture object, optionally using a given mount object.
-        *
-        * IMPORTANT: Call this only after setting up the virtual file system (with the addTo* methods)!
-        *
-        * @param $driverConfiguration
-        * @param \TYPO3\CMS\Core\Resource\ResourceStorage $storageObject
-        * @param array $mockedDriverMethods
-        * @return \TYPO3\CMS\Core\Resource\Driver\LocalDriver
-        */
-       protected function createDriverMock($driverConfiguration, \TYPO3\CMS\Core\Resource\ResourceStorage $storageObject = NULL, $mockedDriverMethods = array()) {
-               $this->initializeVfs();
-               if ($storageObject == NULL) {
-                       $storageObject = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array(), array(), '', FALSE);
-               }
-
-               if (!isset($driverConfiguration['basePath'])) {
-                       $driverConfiguration['basePath'] = $this->getMountRootUrl();
-               }
-
-               if ($mockedDriverMethods === NULL) {
-                       $driver = new \TYPO3\CMS\Core\Resource\Driver\LocalDriver($driverConfiguration);
-               } else {
-                               // We are using the LocalDriver here because PHPUnit can't mock concrete methods in abstract classes, so
-                               // when using the AbstractDriver we would be in trouble when wanting to mock away some concrete method
-                       $driver = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver', $mockedDriverMethods, array($driverConfiguration));
-               }
-               $storageObject->setDriver($driver);
-               $driver->setStorageUid(6);
-               $driver->processConfiguration();
-               $driver->initialize();
-               return $driver;
-       }
-
-       /**
-        * @test
-        */
-       public function baseUriGetsSlashAppended() {
-               $uri = 'http://example.org/somewhere/else';
-               $this->prepareFixture(array('baseUri' => $uri));
-               $this->assertEquals($uri . '/', $this->fixture->getBaseUri());
-       }
-
-       /**
-        * @return array
-        */
-       public function capabilitiesDataProvider() {
-               return array(
-                       'only public' => array(
-                               array(
-                                       'public' => TRUE,
-                                       'writable' => FALSE,
-                                       'browsable' => FALSE
-                               )
-                       ),
-                       'only writable' => array(
-                               array(
-                                       'public' => FALSE,
-                                       'writable' => TRUE,
-                                       'browsable' => FALSE
-                               )
-                       ),
-                       'only browsable' => array(
-                               array(
-                                       'public' => FALSE,
-                                       'writable' => FALSE,
-                                       'browsable' => TRUE
-                               )
-                       ),
-                       'all capabilities' => array(
-                               array(
-                                       'public' => TRUE,
-                                       'writable' => TRUE,
-                                       'browsable' => TRUE
-                               )
-                       ),
-                       'none' => array(
-                               array(
-                                       'public' => FALSE,
-                                       'writable' => FALSE,
-                                       'browsable' => FALSE
-                               )
-                       )
-               );
-       }
-
-       /**
-        * @test
-        * @dataProvider capabilitiesDataProvider
-        */
-       public function capabilitiesOfStorageObjectAreCorrectlySet(array $capabilites) {
-               $storageRecord = array(
-                       'is_public' => $capabilites['public'],
-                       'is_writable' => $capabilites['writable'],
-                       'is_browsable' => $capabilites['browsable'],
-                       'is_online' => TRUE
-               );
-               $mockedDriver = $this->createDriverMock(array(), $this->fixture, array('hasCapability'));
-               $mockedDriver->expects($this->any())->method('hasCapability')->will($this->returnValue(TRUE));
-               $this->prepareFixture(array(), FALSE, $mockedDriver, $storageRecord);
-               $this->assertEquals($capabilites['public'], $this->fixture->isPublic(), 'Capability "public" is not correctly set.');
-               $this->assertEquals($capabilites['writable'], $this->fixture->isWritable(), 'Capability "writable" is not correctly set.');
-               $this->assertEquals($capabilites['browsable'], $this->fixture->isBrowsable(), 'Capability "browsable" is not correctly set.');
-       }
-
-       /**
-        * @test
-        */
-       public function fileAndFolderListFiltersAreInitializedWithDefaultFilters() {
-               $this->prepareFixture(array());
-               $this->assertEquals($GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['defaultFilterCallbacks'], $this->fixture->getFileAndFolderNameFilters());
-       }
-
-       /**
-        * @test
-        */
-       public function addFileFailsIfFileDoesNotExist() {
-               $mockedFolder = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Folder', array(), array(), '', FALSE);
-               $this->setExpectedException('InvalidArgumentException', '', 1319552745);
-               $this->prepareFixture(array());
-               $this->fixture->addFile('/some/random/file', $mockedFolder);
-       }
-
-       /**
-        * @test
-        */
-       public function getPublicUrlReturnsNullIfStorageIsNotOnline() {
-               /** @var $driver \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
-               $driver = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver', array(), array(array('basePath' => $this->getMountRootUrl())));
-               /** @var $fixture \TYPO3\CMS\Core\Resource\ResourceStorage */
-               $fixture = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array('isOnline'), array($driver, array('configuration' => array())));
-               $fixture->expects($this->once())->method('isOnline')->will($this->returnValue(FALSE));
-
-               $sourceFileIdentifier = '/sourceFile.ext';
-               $sourceFile = $this->getSimpleFileMock($sourceFileIdentifier);
-               $result = $fixture->getPublicUrl($sourceFile);
-               $this->assertSame($result, NULL);
-       }
-
-       /**
-        * Data provider for checkFolderPermissionsRespectsFilesystemPermissions
-        *
-        * @return array
-        */
-       public function checkFolderPermissionsFilesystemPermissionsDataProvider() {
-               return array(
-                       'read action on readable/writable folder' => array(
-                               'read',
-                               array('r' => TRUE, 'w' => TRUE),
-                               TRUE
-                       ),
-                       'read action on unreadable folder' => array(
-                               'read',
-                               array('r' => FALSE, 'w' => TRUE),
-                               FALSE
-                       ),
-                       'write action on read-only folder' => array(
-                               'write',
-                               array('r' => TRUE, 'w' => FALSE),
-                               FALSE
-                       )
-               );
-       }
-
-       /**
-        * @test
-        * @dataProvider checkFolderPermissionsFilesystemPermissionsDataProvider
-        * @param string $action 'read' or 'write'
-        * @param array $permissionsFromDriver The permissions as returned from the driver
-        * @param boolean $expectedResult
-        */
-       public function checkFolderPermissionsRespectsFilesystemPermissions($action, $permissionsFromDriver, $expectedResult) {
-               $mockedDriver = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver');
-               $mockedDriver->expects($this->any())->method('getPermissions')->will($this->returnValue($permissionsFromDriver));
-               $mockedFolder = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Folder', array(), array(), '', FALSE);
-                       // Let all other checks pass
-               /** @var $fixture \TYPO3\CMS\Core\Resource\ResourceStorage */
-               $fixture = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array('isWritable', 'isBrowsable', 'checkUserActionPermission'), array($mockedDriver, array()), '', FALSE);
-               $fixture->expects($this->any())->method('isWritable')->will($this->returnValue(TRUE));
-               $fixture->expects($this->any())->method('isBrowsable')->will($this->returnValue(TRUE));
-               $fixture->expects($this->any())->method('checkUserActionPermission')->will($this->returnValue(TRUE));
-               $fixture->setDriver($mockedDriver);
-
-               $this->assertSame($expectedResult, $fixture->checkFolderActionPermission($action, $mockedFolder));
-       }
-
-       /**
-        * @test
-        */
-       public function checkUserActionPermissionsAlwaysReturnsTrueIfNoUserPermissionsAreSet() {
-               $this->prepareFixture(array());
-               $this->assertTrue($this->fixture->checkUserActionPermission('read', 'folder'));
-       }
-
-       /**
-        * @test
-        */
-       public function checkUserActionPermissionReturnsFalseIfPermissionIsSetToZero() {
-               $this->prepareFixture(array());
-               $this->fixture->setUserPermissions(array('readFolder' => TRUE, 'writeFile' => TRUE));
-               $this->assertTrue($this->fixture->checkUserActionPermission('read', 'folder'));
-       }
-
-       public function checkUserActionPermission_arbitraryPermissionDataProvider() {
-               return array(
-                       'all lower cased' => array(
-                               array('readFolder' => TRUE),
-                               'read',
-                               'folder'
-                       ),
-                       'all upper case' => array(
-                               array('readFolder' => TRUE),
-                               'READ',
-                               'FOLDER'
-                       ),
-                       'mixed case' => array(
-                               array('readFolder' => TRUE),
-                               'ReaD',
-                               'FoLdEr'
-                       )
-               );
-       }
-
-       /**
-        * @test
-        * @dataProvider checkUserActionPermission_arbitraryPermissionDataProvider
-        */
-       public function checkUserActionPermissionAcceptsArbitrarilyCasedArguments($permissions, $action, $type) {
-               $this->prepareFixture(array());
-               $this->fixture->setUserPermissions($permissions);
-               $this->assertTrue($this->fixture->checkUserActionPermission($action, $type));
-       }
-
-       /**
-        * @test
-        */
-       public function userActionIsDisallowedIfPermissionIsSetToFalse() {
-               $this->prepareFixture(array());
-               $this->fixture->setEvaluatePermissions(TRUE);
-               $this->fixture->setUserPermissions(array('readFolder' => FALSE));
-               $this->assertFalse($this->fixture->checkUserActionPermission('read', 'folder'));
-       }
-
-       /**
-        * @test
-        */
-       public function userActionIsDisallowedIfPermissionIsNotSet() {
-               $this->prepareFixture(array());
-               $this->fixture->setEvaluatePermissions(TRUE);
-               $this->fixture->setUserPermissions(array('readFolder' => TRUE));
-               $this->assertFalse($this->fixture->checkUserActionPermission('write', 'folder'));
-       }
-
-       /**
-        * @test
-        * @group integration
-        */
-       public function setFileContentsUpdatesObjectProperties() {
-               $this->initializeVfs();
-               $driverObject = $this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Driver\\AbstractDriver', array(), '', FALSE);
-               $this->fixture = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array('getFileIndexRepository', 'checkFileActionPermission'), array($driverObject, array()));
-               $this->fixture->expects($this->any())->method('checkFileActionPermission')->will($this->returnValue(TRUE));
-               $fileInfo = array(
-                       'storage' => 'A',
-                       'identifier' => 'B',
-                       'mtime' => 'C',
-                       'ctime' => 'D',
-                       'mimetype' => 'E',
-                       'size' => 'F',
-                       'name' => 'G',
-               );
-               $newProperties = array(
-                       'storage' => $fileInfo['storage'],
-                       'identifier' => $fileInfo['identifier'],
-                       'tstamp' => $fileInfo['mtime'],
-                       'crdate' => $fileInfo['ctime'],
-                       'mime_type' => $fileInfo['mimetype'],
-                       'size' => $fileInfo['size'],
-                       'name' => $fileInfo['name']
-               );
-               $hash = 'asdfg';
-               $driver = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver', array(), array(array('basePath' => $this->getMountRootUrl())));
-               $driver->expects($this->once())->method('getFileInfoByIdentifier')->will($this->returnValue($fileInfo));
-               $driver->expects($this->once())->method('hash')->will($this->returnValue($hash));
-               $this->fixture->setDriver($driver);
-               $indexFileRepositoryMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Index\\FileIndexRepository');
-               $this->fixture->expects($this->any())->method('getFileIndexRepository')->will($this->returnValue($indexFileRepositoryMock));
-               $mockedFile = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
-               $mockedFile->expects($this->any())->method('getIdentifier')->will($this->returnValue($fileInfo['identifier']));
-               // called by indexer because the properties are updated
-               $this->fixture->expects($this->any())->method('getFileInfoByIdentifier')->will($this->returnValue($newProperties));
-               $mockedFile->expects($this->any())->method('getStorage')->will($this->returnValue($this->fixture));
-               $mockedFile->expects($this->any())->method('getProperties')->will($this->returnValue(array_keys($fileInfo)));
-               $mockedFile->expects($this->any())->method('getUpdatedProperties')->will($this->returnValue(array_keys($newProperties)));
-               // do not update directly; that's up to the indexer
-               $indexFileRepositoryMock->expects($this->never())->method('update');
-               $this->fixture->setFileContents($mockedFile, uniqid());
-       }
-
-       /**
-        * @test
-        * @group integration
-        */
-       public function moveFileCallsDriversMethodsWithCorrectArguments() {
-               $localFilePath = '/path/to/localFile';
-               $sourceFileIdentifier = '/sourceFile.ext';
-               $fileInfoDummy = array(
-                       'storage' => 'A',
-                       'identifier' => 'B',
-                       'mtime' => 'C',
-                       'ctime' => 'D',
-                       'mimetype' => 'E',
-                       'size' => 'F',
-                       'name' => 'G',
-               );
-               $this->addToMount(array(
-                       'targetFolder' => array()
-               ));
-               $this->initializeVfs();
-               $targetFolder = $this->getSimpleFolderMock('/targetFolder/');
-               $sourceDriver = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver');
-               $sourceDriver->expects($this->once())->method('deleteFile')->with($this->equalTo($sourceFileIdentifier));
-               $configuration = $this->convertConfigurationArrayToFlexformXml(array());
-               $sourceStorage = new \TYPO3\CMS\Core\Resource\ResourceStorage($sourceDriver, array('configuration' => $configuration));
-               $sourceFile = $this->getSimpleFileMock($sourceFileIdentifier);
-               $sourceFile->expects($this->once())->method('getForLocalProcessing')->will($this->returnValue($localFilePath));
-               $sourceFile->expects($this->any())->method('getStorage')->will($this->returnValue($sourceStorage));
-               $sourceFile->expects($this->once())->method('getUpdatedProperties')->will($this->returnValue(array_keys($fileInfoDummy)));
-               $sourceFile->expects($this->once())->method('getProperties')->will($this->returnValue($fileInfoDummy));
-               /** @var $driver \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
-               $driver = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver', array(), array(array('basePath' => $this->getMountRootUrl())));
-               $driver->expects($this->once())->method('getFileInfoByIdentifier')->will($this->returnValue($fileInfoDummy));
-               $driver->expects($this->once())->method('addFile')->with($localFilePath, '/targetFolder/', $this->equalTo('file.ext'))->will($this->returnValue('/targetFolder/file.ext'));
-               /** @var $fixture \TYPO3\CMS\Core\Resource\ResourceStorage */
-               $fixture = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array('assureFileMovePermissions'), array($driver, array('configuration' => $configuration)));
-               $fixture->moveFile($sourceFile, $targetFolder, 'file.ext');
-       }
-
-       /**
-        * @test
-        * @group integration
-        */
-       public function storageUsesInjectedFilemountsToCheckForMountBoundaries() {
-               $mockedFile = $this->getSimpleFileMock('/mountFolder/file');
-               $this->addToMount(array(
-                       'mountFolder' => array(
-                               'file' => 'asdfg'
-                       )
-               ));
-               $mockedDriver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), NULL, NULL);
-               $this->initializeVfs();
-               $this->prepareFixture(array(), NULL, $mockedDriver);
-               $this->fixture->addFileMount('/mountFolder');
-               $this->assertEquals(1, count($this->fixture->getFileMounts()));
-               $this->fixture->isWithinFileMountBoundaries($mockedFile);
-       }
-
-
-       /**
-        * @test
-        */
-       public function createFolderChecksIfParentFolderExistsBeforeCreatingFolder() {
-               $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
-               $mockedDriver = $this->createDriverMock(array());
-               $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(TRUE));
-               $mockedDriver->expects($this->once())->method('createFolder')->with($this->equalTo('newFolder'))->will($this->returnValue($mockedParentFolder));
-               $this->prepareFixture(array(), TRUE);
-               $this->fixture->setDriver($mockedDriver);
-               $this->fixture->createFolder('newFolder', $mockedParentFolder);
-       }
-
-       /**
-        * @test
-        * @expectedException \RuntimeException
-        */
-       public function deleteFolderThrowsExceptionIfFolderIsNotEmptyAndRecursiveDeleteIsDisabled() {
-               /** @var \TYPO3\CMS\Core\Resource\Folder|\PHPUnit_Framework_MockObject_MockObject $folderMock */
-               $folderMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Folder', array(), array(), '', FALSE);
-               /** @var \TYPO3\CMS\Core\Resource\Driver\AbstractDriver|\PHPUnit_Framework_MockObject_MockObject $driverMock */
-               $driverMock = $this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Driver\\AbstractDriver');
-               $driverMock->expects($this->once())->method('isFolderEmpty')->will($this->returnValue(FALSE));
-               /** @var \TYPO3\CMS\Core\Resource\ResourceStorage|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $fixture */
-               $fixture = $this->getAccessibleMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array('checkFolderActionPermission'), array(), '', FALSE);
-               $fixture->expects($this->any())->method('checkFolderActionPermission')->will($this->returnValue(TRUE));
-               $fixture->_set('driver', $driverMock);
-               $fixture->deleteFolder($folderMock, FALSE);
-       }
-
-       /**
-        * @test
-        */
-       public function createFolderCallsDriverForFolderCreation() {
-               $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
-               $this->prepareFixture(array(), TRUE);
-               $mockedDriver = $this->createDriverMock(array(), $this->fixture);
-               $mockedDriver->expects($this->once())->method('createFolder')->with($this->equalTo('newFolder'), $this->equalTo('/someFolder/'))->will($this->returnValue(TRUE));
-               $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(TRUE));
-               $this->fixture->createFolder('newFolder', $mockedParentFolder);
-       }
-
-       /**
-        * @test
-        */
-       public function createFolderCanRecursivelyCreateFolders() {
-               $this->addToMount(array('someFolder' => array()));
-               $mockedDriver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), NULL, NULL);
-               $this->prepareFixture(array(), TRUE, $mockedDriver);
-               $parentFolder = $this->fixture->getFolder('/someFolder/');
-               $newFolder = $this->fixture->createFolder('subFolder/secondSubfolder', $parentFolder);
-               $this->assertEquals('secondSubfolder', $newFolder->getName());
-               $this->assertFileExists($this->getUrlInMount('/someFolder/subFolder/'));
-               $this->assertFileExists($this->getUrlInMount('/someFolder/subFolder/secondSubfolder/'));
-       }
-
-       /**
-        * @test
-        */
-       public function createFolderUsesRootFolderAsParentFolderIfNotGiven() {
-               $this->prepareFixture(array(), TRUE);
-               $mockedDriver = $this->createDriverMock(array(), $this->fixture);
-               $mockedDriver->expects($this->once())->method('getRootLevelFolder')->with()->will($this->returnValue('/'));
-               $mockedDriver->expects($this->once())->method('createFolder')->with($this->equalTo('someFolder'));
-               $this->fixture->createFolder('someFolder');
-       }
-
-       /**
-        * @test
-        */
-       public function createFolderCreatesNestedStructureEvenIfPartsAlreadyExist() {
-               $this->addToMount(array(
-                       'existingFolder' => array()
-               ));
-               $this->initializeVfs();
-               $mockedDriver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), NULL, NULL);
-               $this->prepareFixture(array(), TRUE, $mockedDriver);
-               $rootFolder = $this->fixture->getFolder('/');
-               $newFolder = $this->fixture->createFolder('existingFolder/someFolder', $rootFolder);
-               $this->assertEquals('someFolder', $newFolder->getName());
-               $this->assertFileExists($this->getUrlInMount('existingFolder/someFolder'));
-       }
-
-       /**
-        * @test
-        */
-       public function createFolderThrowsExceptionIfParentFolderDoesNotExist() {
-               $this->setExpectedException('InvalidArgumentException', '', 1325689164);
-               $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
-               $this->prepareFixture(array(), TRUE);
-               $mockedDriver = $this->createDriverMock(array(), $this->fixture);
-               $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(FALSE));
-               $this->fixture->createFolder('newFolder', $mockedParentFolder);
-       }
-
-       /**
-        * @test
-        */
-       public function replaceFileFailsIfLocalFileDoesNotExist() {
-               $this->setExpectedException('InvalidArgumentException', '', 1325842622);
-               $this->prepareFixture(array(), TRUE);
-               $mockedFile = $this->getSimpleFileMock('/someFile');
-               $this->fixture->replaceFile($mockedFile, PATH_site . uniqid());
-       }
-
-       /**
-        * @test
-        */
-       public function getRoleReturnsDefaultForRegularFolders() {
-               $folderIdentifier = uniqid();
-               $this->addToMount(array(
-                       $folderIdentifier => array()
-               ));
-               $this->prepareFixture(array());
-
-               $role = $this->fixture->getRole($this->getSimpleFolderMock('/' . $folderIdentifier . '/'));
-
-               $this->assertSame(\TYPO3\CMS\Core\Resource\FolderInterface::ROLE_DEFAULT, $role);
-       }
-
+class ResourceStorageTest extends BaseTestCase
+{
+    /**
+     * @var bool Reset singletons created by subject
+     */
+    protected $resetSingletonInstances = true;
+
+    /**
+     * @var ResourceStorage|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $subject;
+
+    /**
+     * Set up
+     */
+    protected function setUp(): void
+    {
+        parent::setUp();
+        /** @var FileRepository|\PHPUnit_Framework_MockObject_MockObject $fileRepositoryMock */
+        $fileRepositoryMock = $this->createMock(FileRepository::class);
+        GeneralUtility::setSingletonInstance(
+            FileRepository::class,
+            $fileRepositoryMock
+        );
+        $cacheManagerProphecy = $this->prophesize(CacheManager::class);
+        $cacheProphecy = $this->prophesize(FrontendInterface::class);
+        $cacheManagerProphecy->getCache('cache_runtime')->willReturn($cacheProphecy->reveal());
+        $cacheProphecy->get(Argument::cetera())->willReturn(false);
+        $cacheProphecy->set(Argument::cetera())->willReturn(false);
+        GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
+    }
+
+    /**
+     * Prepare ResourceStorage
+     *
+     * @param array $configuration
+     * @param bool $mockPermissionChecks
+     * @param AbstractDriver|\PHPUnit_Framework_MockObject_MockObject $driverObject
+     * @param array $storageRecord
+     * @param array $mockedMethods
+     */
+    protected function prepareSubject(
+        array $configuration,
+        bool $mockPermissionChecks = false,
+        AbstractDriver $driverObject = null,
+        array $storageRecord = [],
+        array $mockedMethods = []
+    ): void {
+        $permissionMethods = [
+            'assureFileAddPermissions',
+            'checkFolderActionPermission',
+            'checkFileActionPermission',
+            'checkUserActionPermission',
+            'checkFileExtensionPermission',
+            'isWithinFileMountBoundaries',
+            'assureFileRenamePermissions'
+        ];
+        $configuration = $this->convertConfigurationArrayToFlexformXml($configuration);
+        $overruleArray = ['configuration' => $configuration];
+        ArrayUtility::mergeRecursiveWithOverrule($storageRecord, $overruleArray);
+        if ($driverObject === null) {
+            $driverObject = $this->getMockForAbstractClass(AbstractDriver::class, [], '', false);
+        }
+        if ($mockPermissionChecks) {
+            $mockedMethods = array_merge($mockedMethods, $permissionMethods);
+        }
+        $mockedMethods[] = 'getIndexer';
+
+        $this->subject = $this->getMockBuilder(ResourceStorage::class)
+            ->setMethods(array_unique($mockedMethods))
+            ->setConstructorArgs([$driverObject, $storageRecord])
+            ->getMock();
+        $this->subject->expects($this->any())->method('getIndexer')->will($this->returnValue($this->createMock(Indexer::class)));
+        if ($mockPermissionChecks) {
+            foreach ($permissionMethods as $method) {
+                $this->subject->expects($this->any())->method($method)->will($this->returnValue(true));
+            }
+        }
+    }
+
+    /**
+     * Converts a simple configuration array into a FlexForm data structure serialized as XML
+     *
+     * @param array $configuration
+     * @return string
+     * @see GeneralUtility::array2xml()
+     */
+    protected function convertConfigurationArrayToFlexformXml(array $configuration): string
+    {
+        $flexFormArray = ['data' => ['sDEF' => ['lDEF' => []]]];
+        foreach ($configuration as $key => $value) {
+            $flexFormArray['data']['sDEF']['lDEF'][$key] = ['vDEF' => $value];
+        }
+        $configuration = GeneralUtility::array2xml($flexFormArray);
+        return $configuration;
+    }
+
+    /**
+     * Creates a driver fixture object, optionally using a given mount object.
+     *
+     * IMPORTANT: Call this only after setting up the virtual file system (with the addTo* methods)!
+     *
+     * @param $driverConfiguration
+     * @param ResourceStorage $storageObject
+     * @param array $mockedDriverMethods
+     * @return \TYPO3\CMS\Core\Resource\Driver\LocalDriver|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected function createDriverMock(
+        $driverConfiguration,
+        ResourceStorage $storageObject = null,
+        array $mockedDriverMethods = []
+    ) {
+        $this->initializeVfs();
+
+        if (!isset($driverConfiguration['basePath'])) {
+            $driverConfiguration['basePath'] = $this->getMountRootUrl();
+        }
+
+        if ($mockedDriverMethods === null) {
+            $driver = new LocalDriver($driverConfiguration);
+        } else {
+            // We are using the LocalDriver here because PHPUnit can't mock concrete methods in abstract classes, so
+            // when using the AbstractDriver we would be in trouble when wanting to mock away some concrete method
+            $driver = $this->getMockBuilder(LocalDriver::class)
+                ->setMethods($mockedDriverMethods)
+                ->setConstructorArgs([$driverConfiguration])
+                ->getMock();
+        }
+        if ($storageObject !== null) {
+            $storageObject->setDriver($driver);
+        }
+        $driver->setStorageUid(6);
+        $driver->processConfiguration();
+        $driver->initialize();
+        return $driver;
+    }
+
+    /**
+     * @return array
+     */
+    public function capabilitiesDataProvider(): array
+    {
+        return [
+            'only public' => [
+                [
+                    'public' => true,
+                    'writable' => false,
+                    'browsable' => false
+                ]
+            ],
+            'only writable' => [
+                [
+                    'public' => false,
+                    'writable' => true,
+                    'browsable' => false
+                ]
+            ],
+            'only browsable' => [
+                [
+                    'public' => false,
+                    'writable' => false,
+                    'browsable' => true
+                ]
+            ],
+            'all capabilities' => [
+                [
+                    'public' => true,
+                    'writable' => true,
+                    'browsable' => true
+                ]
+            ],
+            'none' => [
+                [
+                    'public' => false,
+                    'writable' => false,
+                    'browsable' => false
+                ]
+            ]
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider capabilitiesDataProvider
+     * @TODO: Rewrite or move to functional suite
+     * @param array $capabilities
+     */
+    public function capabilitiesOfStorageObjectAreCorrectlySet(array $capabilities): void
+    {
+        $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
+        $storageRecord = [
+            'is_public' => $capabilities['public'],
+            'is_writable' => $capabilities['writable'],
+            'is_browsable' => $capabilities['browsable'],
+            'is_online' => true
+        ];
+        $mockedDriver = $this->createDriverMock(
+            [
+                'pathType' => 'relative',
+                'basePath' => 'fileadmin/',
+            ],
+            $this->subject,
+            null
+        );
+        $this->prepareSubject([], false, $mockedDriver, $storageRecord);
+        $this->assertEquals(
+            $capabilities['public'],
+            $this->subject->isPublic(),
+            'Capability "public" is not correctly set.'
+        );
+        $this->assertEquals(
+            $capabilities['writable'],
+            $this->subject->isWritable(),
+            'Capability "writable" is not correctly set.'
+        );
+        $this->assertEquals(
+            $capabilities['browsable'],
+            $this->subject->isBrowsable(),
+            'Capability "browsable" is not correctly set.'
+        );
+    }
+
+    /**
+     * @test
+     * @TODO: Rewrite or move to functional suite
+     */
+    public function fileAndFolderListFiltersAreInitializedWithDefaultFilters(): void
+    {
+        $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
+        $this->prepareSubject([]);
+        $this->assertEquals(
+            $GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['defaultFilterCallbacks'],
+            $this->subject->getFileAndFolderNameFilters()
+        );
+    }
+
+    /**
+     * @test
+     */
+    public function addFileFailsIfFileDoesNotExist(): void
+    {
+        /** @var Folder|\PHPUnit_Framework_MockObject_MockObject $mockedFolder */
+        $mockedFolder = $this->createMock(Folder::class);
+        $this->expectException(\InvalidArgumentException::class);
+        $this->expectExceptionCode(1319552745);
+        $this->prepareSubject([]);
+        $this->subject->addFile('/some/random/file', $mockedFolder);
+    }
+
+    /**
+     * @test
+     */
+    public function getPublicUrlReturnsNullIfStorageIsNotOnline(): void
+    {
+        /** @var $driver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
+        $driver = $this->getMockBuilder(LocalDriver::class)
+            ->setConstructorArgs([['basePath' => $this->getMountRootUrl()]])
+            ->getMock();
+        /** @var $subject ResourceStorage|\PHPUnit_Framework_MockObject_MockObject */
+        $subject = $this->getMockBuilder(ResourceStorage::class)
+            ->setMethods(['isOnline'])
+            ->setConstructorArgs([$driver, ['configuration' => []]])
+            ->getMock();
+        $subject->expects($this->once())->method('isOnline')->will($this->returnValue(false));
+
+        $sourceFileIdentifier = '/sourceFile.ext';
+        $sourceFile = $this->getSimpleFileMock($sourceFileIdentifier);
+        $result = $subject->getPublicUrl($sourceFile);
+        $this->assertSame($result, null);
+    }
+
+    /**
+     * Data provider for checkFolderPermissionsRespectsFilesystemPermissions
+     *
+     * @return array
+     */
+    public function checkFolderPermissionsFilesystemPermissionsDataProvider(): array
+    {
+        return [
+            'read action on readable/writable folder' => [
+                'read',
+                ['r' => true, 'w' => true],
+                true
+            ],
+            'read action on unreadable folder' => [
+                'read',
+                ['r' => false, 'w' => true],
+                false
+            ],
+            'write action on read-only folder' => [
+                'write',
+                ['r' => true, 'w' => false],
+                false
+            ]
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider checkFolderPermissionsFilesystemPermissionsDataProvider
+     * @param string $action 'read' or 'write'
+     * @param array $permissionsFromDriver The permissions as returned from the driver
+     * @param bool $expectedResult
+     */
+    public function checkFolderPermissionsRespectsFilesystemPermissions(
+        string $action,
+        array $permissionsFromDriver,
+        bool $expectedResult
+    ): void {
+        /** @var $mockedDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
+        $mockedDriver = $this->createMock(LocalDriver::class);
+        $mockedDriver->expects($this->any())->method('getPermissions')->will($this->returnValue($permissionsFromDriver));
+        /** @var $mockedFolder Folder|\PHPUnit_Framework_MockObject_MockObject */
+        $mockedFolder = $this->createMock(Folder::class);
+        // Let all other checks pass
+        /** @var $subject ResourceStorage|\PHPUnit_Framework_MockObject_MockObject */
+        $subject = $this->getMockBuilder(ResourceStorage::class)
+            ->setMethods(['isWritable', 'isBrowsable', 'checkUserActionPermission'])
+            ->setConstructorArgs([$mockedDriver, []])
+            ->getMock();
+        $subject->expects($this->any())->method('isWritable')->will($this->returnValue(true));
+        $subject->expects($this->any())->method('isBrowsable')->will($this->returnValue(true));
+        $subject->expects($this->any())->method('checkUserActionPermission')->will($this->returnValue(true));
+        $subject->setDriver($mockedDriver);
+
+        $this->assertSame($expectedResult, $subject->checkFolderActionPermission($action, $mockedFolder));
+    }
+
+    /**
+     * @test
+     */
+    public function checkUserActionPermissionsAlwaysReturnsTrueIfNoUserPermissionsAreSet(): void
+    {
+        $this->prepareSubject([]);
+        $this->assertTrue($this->subject->checkUserActionPermission('read', 'folder'));
+    }
+
+    /**
+     * @test
+     */
+    public function checkUserActionPermissionReturnsFalseIfPermissionIsSetToZero(): void
+    {
+        $this->prepareSubject([]);
+        $this->subject->setUserPermissions(['readFolder' => true, 'writeFile' => true]);
+        $this->assertTrue($this->subject->checkUserActionPermission('read', 'folder'));
+    }
+
+    /**
+     * @return array
+     */
+    public function checkUserActionPermission_arbitraryPermissionDataProvider(): array
+    {
+        return [
+            'all lower cased' => [
+                ['readFolder' => true],
+                'read',
+                'folder'
+            ],
+            'all upper case' => [
+                ['readFolder' => true],
+                'READ',
+                'FOLDER'
+            ],
+            'mixed case' => [
+                ['readFolder' => true],
+                'ReaD',
+                'FoLdEr'
+            ]
+        ];
+    }
+
+    /**
+     * @param array $permissions
+     * @param string $action
+     * @param string $type
+     * @test
+     * @dataProvider checkUserActionPermission_arbitraryPermissionDataProvider
+     */
+    public function checkUserActionPermissionAcceptsArbitrarilyCasedArguments(array $permissions, string $action, string $type): void
+    {
+        $this->prepareSubject([]);
+        $this->subject->setUserPermissions($permissions);
+        $this->assertTrue($this->subject->checkUserActionPermission($action, $type));
+    }
+
+    /**
+     * @test
+     */
+    public function userActionIsDisallowedIfPermissionIsSetToFalse(): void
+    {
+        $this->prepareSubject([]);
+        $this->subject->setEvaluatePermissions(true);
+        $this->subject->setUserPermissions(['readFolder' => false]);
+        $this->assertFalse($this->subject->checkUserActionPermission('read', 'folder'));
+    }
+
+    /**
+     * @test
+     */
+    public function userActionIsDisallowedIfPermissionIsNotSet(): void
+    {
+        $this->prepareSubject([]);
+        $this->subject->setEvaluatePermissions(true);
+        $this->subject->setUserPermissions(['readFolder' => true]);
+        $this->assertFalse($this->subject->checkUserActionPermission('write', 'folder'));
+    }
+
+    /**
+     * @test
+     */
+    public function metaDataEditIsNotAllowedWhenWhenNoFileMountsAreSet(): void
+    {
+        $this->prepareSubject([], false, null, [], ['isWithinProcessingFolder']);
+        $this->subject->setEvaluatePermissions(true);
+        $this->assertFalse($this->subject->checkFileActionPermission('editMeta', new File(['identifier' => '/foo/bar.jpg'], $this->subject)));
+    }
+
+    /**
+     * @test
+     */
+    public function metaDataEditIsAllowedWhenWhenInFileMount(): void
+    {
+        $driverMock = $this->getMockForAbstractClass(AbstractDriver::class, [], '', false);
+        $this->prepareSubject([], false, $driverMock, [], ['isWithinProcessingFolder']);
+
+        $fileStub = new File(['identifier' => '/foo/bar.jpg'], $this->subject);
+        $folderStub = new Folder($this->subject, '/foo/', 'foo');
+        $driverMock->expects($this->once())
+            ->method('isWithin')
+            ->with($folderStub->getIdentifier(), $fileStub->getIdentifier())
+            ->willReturn(true);
+
+        $this->subject->setEvaluatePermissions(true);
+        $fileMounts = [
+            '/foo/' => [
+                'path' => '/foo/',
+                'title' => 'Foo',
+                'folder' => $folderStub,
+            ]
+        ];
+        $this->inject($this->subject, 'fileMounts', $fileMounts);
+        $this->assertTrue($this->subject->checkFileActionPermission('editMeta', $fileStub));
+    }
+
+    /**
+     * @test
+     */
+    public function metaDataEditIsNotAllowedWhenWhenInReadOnlyFileMount(): void
+    {
+        $driverMock = $this->getMockForAbstractClass(AbstractDriver::class, [], '', false);
+        $this->prepareSubject([], false, $driverMock, [], ['isWithinProcessingFolder']);
+
+        $fileStub = new File(['identifier' => '/foo/bar.jpg'], $this->subject);
+        $folderStub = new Folder($this->subject, '/foo/', 'foo');
+        $driverMock->expects($this->once())
+            ->method('isWithin')
+            ->with($folderStub->getIdentifier(), $fileStub->getIdentifier())
+            ->willReturn(true);
+
+        $this->subject->setEvaluatePermissions(true);
+        $fileMounts = [
+            '/foo/' => [
+                'path' => '/foo/',
+                'title' => 'Foo',
+                'folder' => $folderStub,
+                'read_only' => true,
+            ]
+        ];
+        $this->inject($this->subject, 'fileMounts', $fileMounts);
+        $this->assertFalse($this->subject->checkFileActionPermission('editMeta', $fileStub));
+    }
+
+    /**
+     * @test
+     */
+    public function getEvaluatePermissionsWhenSetFalse(): void
+    {
+        $this->prepareSubject([]);
+        $this->subject->setEvaluatePermissions(false);
+        $this->assertFalse($this->subject->getEvaluatePermissions());
+    }
+
+    /**
+     * @test
+     */
+    public function getEvaluatePermissionsWhenSetTrue(): void
+    {
+        $this->prepareSubject([]);
+        $this->subject->setEvaluatePermissions(true);
+        $this->assertTrue($this->subject->getEvaluatePermissions());
+    }
+
+    /**
+     * @test
+     * @group integration
+     * @TODO: Rewrite or move to functional suite
+     */
+    public function setFileContentsUpdatesObjectProperties(): void
+    {
+        $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
+        $this->initializeVfs();
+        $driverObject = $this->getMockForAbstractClass(AbstractDriver::class, [], '', false);
+        $this->subject = $this->getMockBuilder(ResourceStorage::class)
+            ->setMethods(['getFileIndexRepository', 'checkFileActionPermission'])
+            ->setConstructorArgs([$driverObject, []])
+            ->getMock();
+        $this->subject->expects($this->any())->method('checkFileActionPermission')->will($this->returnValue(true));
+        $fileInfo = [
+            'storage' => 'A',
+            'identifier' => 'B',
+            'mtime' => 'C',
+            'ctime' => 'D',
+            'mimetype' => 'E',
+            'size' => 'F',
+            'name' => 'G',
+        ];
+        $newProperties = [
+            'storage' => $fileInfo['storage'],
+            'identifier' => $fileInfo['identifier'],
+            'tstamp' => $fileInfo['mtime'],
+            'crdate' => $fileInfo['ctime'],
+            'mime_type' => $fileInfo['mimetype'],
+            'size' => $fileInfo['size'],
+            'name' => $fileInfo['name']
+        ];
+        $hash = 'asdfg';
+        /** @var $mockedDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
+        $mockedDriver = $this->getMockBuilder(LocalDriver::class)
+            ->setConstructorArgs([['basePath' => $this->getMountRootUrl()]])
+            ->getMock();
+        $mockedDriver->expects($this->once())->method('getFileInfoByIdentifier')->will($this->returnValue($fileInfo));
+        $mockedDriver->expects($this->once())->method('hash')->will($this->returnValue($hash));
+        $this->subject->setDriver($mockedDriver);
+        $indexFileRepositoryMock = $this->createMock(FileIndexRepository::class);
+        $this->subject->expects($this->any())->method('getFileIndexRepository')->will($this->returnValue($indexFileRepositoryMock));
+        /** @var $mockedFile File|\PHPUnit_Framework_MockObject_MockObject */
+        $mockedFile = $this->createMock(File::class);
+        $mockedFile->expects($this->any())->method('getIdentifier')->will($this->returnValue($fileInfo['identifier']));
+        // called by indexer because the properties are updated
+        $this->subject->expects($this->any())->method('getFileInfoByIdentifier')->will($this->returnValue($newProperties));
+        $mockedFile->expects($this->any())->method('getStorage')->will($this->returnValue($this->subject));
+        $mockedFile->expects($this->any())->method('getProperties')->will($this->returnValue(array_keys($fileInfo)));
+        $mockedFile->expects($this->any())->method('getUpdatedProperties')->will($this->returnValue(array_keys($newProperties)));
+        // do not update directly; that's up to the indexer
+        $indexFileRepositoryMock->expects($this->never())->method('update');
+        $this->subject->setFileContents($mockedFile, $this->getUniqueId());
+    }
+
+    /**
+     * @test
+     * @group integration
+     * @TODO: Rewrite or move to functional suite
+     */
+    public function moveFileCallsDriversMethodsWithCorrectArguments(): void
+    {
+        $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
+        $localFilePath = '/path/to/localFile';
+        $sourceFileIdentifier = '/sourceFile.ext';
+        $fileInfoDummy = [
+            'storage' => 'A',
+            'identifier' => 'B',
+            'mtime' => 'C',
+            'ctime' => 'D',
+            'mimetype' => 'E',
+            'size' => 'F',
+            'name' => 'G',
+        ];
+        $this->addToMount([
+            'targetFolder' => []
+        ]);
+        $this->initializeVfs();
+        $targetFolder = $this->getSimpleFolderMock('/targetFolder/');
+        /** @var $sourceDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
+        $sourceDriver = $this->createMock(LocalDriver::class);
+        $sourceDriver->expects($this->once())->method('deleteFile')->with($this->equalTo($sourceFileIdentifier));
+        $configuration = $this->convertConfigurationArrayToFlexformXml([]);
+        $sourceStorage = new ResourceStorage($sourceDriver, ['configuration' => $configuration]);
+        $sourceFile = $this->getSimpleFileMock($sourceFileIdentifier);
+        $sourceFile->expects($this->once())->method('getForLocalProcessing')->will($this->returnValue($localFilePath));
+        $sourceFile->expects($this->any())->method('getStorage')->will($this->returnValue($sourceStorage));
+        $sourceFile->expects($this->once())->method('getUpdatedProperties')->will($this->returnValue(array_keys($fileInfoDummy)));
+        $sourceFile->expects($this->once())->method('getProperties')->will($this->returnValue($fileInfoDummy));
+        /** @var $mockedDriver \TYPO3\CMS\Core\Resource\Driver\LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
+        $mockedDriver = $this->getMockBuilder(LocalDriver::class)
+            ->setConstructorArgs([['basePath' => $this->getMountRootUrl()]])
+            ->getMock();
+        $mockedDriver->expects($this->once())->method('getFileInfoByIdentifier')->will($this->returnValue($fileInfoDummy));
+        $mockedDriver->expects($this->once())->method('addFile')->with(
+            $localFilePath,
+            '/targetFolder/',
+            $this->equalTo('file.ext')
+        )->will($this->returnValue('/targetFolder/file.ext'));
+        /** @var $subject ResourceStorage */
+        $subject = $this->getMockBuilder(ResourceStorage::class)
+            ->setMethods(['assureFileMovePermissions'])
+            ->setConstructorArgs([$mockedDriver, ['configuration' => $configuration]])
+            ->getMock();
+        $subject->moveFile($sourceFile, $targetFolder, 'file.ext');
+    }
+
+    /**
+     * @test
+     * @group integration
+     * @TODO: Rewrite or move to functional suite
+     */
+    public function storageUsesInjectedFilemountsToCheckForMountBoundaries(): void
+    {
+        $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
+        $mockedFile = $this->getSimpleFileMock('/mountFolder/file');
+        $this->addToMount([
+            'mountFolder' => [
+                'file' => 'asdfg'
+            ]
+        ]);
+        $mockedDriver = $this->createDriverMock(['basePath' => $this->getMountRootUrl()], null, null);
+        $this->initializeVfs();
+        $this->prepareSubject([], null, $mockedDriver);
+        $this->subject->addFileMount('/mountFolder');
+        $this->assertEquals(1, count($this->subject->getFileMounts()));
+        $this->subject->isWithinFileMountBoundaries($mockedFile);
+    }
+
+    /**
+     * @test
+     * @TODO: Rewrite or move to functional suite
+     */
+    public function createFolderChecksIfParentFolderExistsBeforeCreatingFolder(): void
+    {
+        $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
+        $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
+        $mockedDriver = $this->createDriverMock([]);
+        $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(true));
+        $mockedDriver->expects($this->once())->method('createFolder')->with($this->equalTo('newFolder'))->will($this->returnValue($mockedParentFolder));
+        $this->prepareSubject([], true);
+        $this->subject->setDriver($mockedDriver);
+        $this->subject->createFolder('newFolder', $mockedParentFolder);
+    }
+
+    /**
+     * @test
+     */
+    public function deleteFolderThrowsExceptionIfFolderIsNotEmptyAndRecursiveDeleteIsDisabled(): void
+    {
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionCode(1325952534);
+
+        /** @var \TYPO3\CMS\Core\Resource\Folder|\PHPUnit_Framework_MockObject_MockObject $folderMock */
+        $folderMock = $this->createMock(Folder::class);
+        /** @var $mockedDriver \TYPO3\CMS\Core\Resource\Driver\AbstractDriver|\PHPUnit_Framework_MockObject_MockObject */
+        $mockedDriver = $this->getMockForAbstractClass(AbstractDriver::class);
+        $mockedDriver->expects($this->once())->method('isFolderEmpty')->will($this->returnValue(false));
+        /** @var $subject ResourceStorage|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface */
+        $subject = $this->getAccessibleMock(ResourceStorage::class, ['checkFolderActionPermission'], [], '', false);
+        $subject->expects($this->any())->method('checkFolderActionPermission')->will($this->returnValue(true));
+        $subject->_set('driver', $mockedDriver);
+        $subject->deleteFolder($folderMock, false);
+    }
+
+    /**
+     * @test
+     * @TODO: Rewrite or move to functional suite
+     */
+    public function createFolderCallsDriverForFolderCreation(): void
+    {
+        $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
+        $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
+        $this->prepareSubject([], true);
+        $mockedDriver = $this->createDriverMock([], $this->subject);
+        $mockedDriver->expects($this->once())->method('createFolder')->with(
+            $this->equalTo('newFolder'),
+            $this->equalTo('/someFolder/')
+        )->will($this->returnValue(true));
+        $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(true));
+        $this->subject->createFolder('newFolder', $mockedParentFolder);
+    }
+
+    /**
+     * @test
+     * @TODO: Rewrite or move to functional suite
+     */
+    public function createFolderCanRecursivelyCreateFolders(): void
+    {
+        $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
+        $this->addToMount(['someFolder' => []]);
+        $mockedDriver = $this->createDriverMock(['basePath' => $this->getMountRootUrl()], null, null);
+        $this->prepareSubject([], true, $mockedDriver);
+        $parentFolder = $this->subject->getFolder('/someFolder/');
+        $newFolder = $this->subject->createFolder('subFolder/secondSubfolder', $parentFolder);
+        $this->assertEquals('secondSubfolder', $newFolder->getName());
+        $this->assertFileExists($this->getUrlInMount('/someFolder/subFolder/'));
+        $this->assertFileExists($this->getUrlInMount('/someFolder/subFolder/secondSubfolder/'));
+    }
+
+    /**
+     * @test
+     * @TODO: Rewrite or move to functional suite
+     */
+    public function createFolderUsesRootFolderAsParentFolderIfNotGiven(): void
+    {
+        $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
+        $this->prepareSubject([], true);
+        $mockedDriver = $this->createDriverMock([], $this->subject);
+        $mockedDriver->expects($this->once())->method('getRootLevelFolder')->with()->will($this->returnValue('/'));
+        $mockedDriver->expects($this->once())->method('createFolder')->with($this->equalTo('someFolder'));
+        $this->subject->createFolder('someFolder');
+    }
+
+    /**
+     * @test
+     * @TODO: Rewrite or move to functional suite
+     */
+    public function createFolderCreatesNestedStructureEvenIfPartsAlreadyExist(): void
+    {
+        $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
+        $this->addToMount([
+            'existingFolder' => []
+        ]);
+        $this->initializeVfs();
+        $mockedDriver = $this->createDriverMock(['basePath' => $this->getMountRootUrl()], null, null);
+        $this->prepareSubject([], true, $mockedDriver);
+        $rootFolder = $this->subject->getFolder('/');
+        $newFolder = $this->subject->createFolder('existingFolder/someFolder', $rootFolder);
+        $this->assertEquals('someFolder', $newFolder->getName());
+        $this->assertFileExists($this->getUrlInMount('existingFolder/someFolder'));
+    }
+
+    /**
+     * @test
+     */
+    public function createFolderThrowsExceptionIfParentFolderDoesNotExist(): void
+    {
+        $this->expectException(\InvalidArgumentException::class);
+        $this->expectExceptionCode(1325689164);
+        $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
+        $this->prepareSubject([], true);
+        $mockedDriver = $this->createDriverMock([], $this->subject);
+        $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(false));
+        $this->subject->createFolder('newFolder', $mockedParentFolder);
+    }
+
+    /**
+     * @test
+     */
+    public function renameFileRenamesFileAsRequested(): void
+    {
+        $mockedDriver = $this->createDriverMock([], $this->subject);
+        $mockedDriver->expects($this->once())->method('renameFile')->will($this->returnValue('bar'));
+        $this->prepareSubject([], true, $mockedDriver, [], ['emitPreFileRenameSignal', 'emitPostFileRenameSignal']);
+        /** @var File $file */
+        $file = new File(['identifier' => 'foo', 'name' => 'foo'], $this->subject);
+        $result = $this->subject->renameFile($file, 'bar');
+        // fake what the indexer does in updateIndexEntry
+        $result->updateProperties(['name' => $result->getIdentifier()]);
+        $this->assertSame('bar', $result->getName());
+    }
+
+    /**
+     * @test
+     */
+    public function renameFileRenamesWithUniqueNameIfConflictAndConflictModeIsRename(): void
+    {
+        $mockedDriver = $this->createDriverMock([], $this->subject);
+        $mockedDriver->expects($this->any())->method('renameFile')->will($this->onConsecutiveCalls($this->throwException(new ExistingTargetFileNameException(
+            'foo',
+            1489593090
+        )), 'bar_01'));
+        //$mockedDriver->expects($this->at(1))->method('renameFile')->will($this->returnValue('bar_01'));
+        $mockedDriver->expects($this->any())->method('sanitizeFileName')->will($this->onConsecutiveCalls(
+            'bar',
+            'bar_01'
+        ));
+        $this->prepareSubject(
+            [],
+            true,
+            $mockedDriver,
+            [],
+            ['emitPreFileRenameSignal', 'emitPostFileRenameSignal', 'getUniqueName']
+        );
+        /** @var File $file */
+        $file = new File(['identifier' => 'foo', 'name' => 'foo'], $this->subject);
+        $this->subject->expects($this->once())->method('getUniqueName')->will($this->returnValue('bar_01'));
+        $result = $this->subject->renameFile($file, 'bar');
+        // fake what the indexer does in updateIndexEntry
+        $result->updateProperties(['name' => $result->getIdentifier()]);
+        $this->assertSame('bar_01', $result->getName());
+    }
+
+    /**
+     * @test
+     */
+    public function renameFileThrowsExceptionIfConflictAndConflictModeIsCancel(): void
+    {
+        $mockedDriver = $this->createDriverMock([], $this->subject);
+        $mockedDriver->expects($this->once())->method('renameFile')->will($this->throwException(new ExistingTargetFileNameException(
+            'foo',
+            1489593099
+        )));
+        $this->prepareSubject([], true, $mockedDriver, [], ['emitPreFileRenameSignal', 'emitPostFileRenameSignal']);
+        /** @var File $file */
+        $file = new File(['identifier' => 'foo', 'name' => 'foo'], $this->subject);
+        $this->expectException(ExistingTargetFileNameException::class);
+        $this->subject->renameFile($file, 'bar', DuplicationBehavior::CANCEL);
+    }
+
+    /**
+     * @test
+     */
+    public function renameFileReplacesIfConflictAndConflictModeIsReplace(): void
+    {
+        $mockedDriver = $this->createDriverMock([], $this->subject);
+        $mockedDriver->expects($this->once())->method('renameFile')->will($this->throwException(new ExistingTargetFileNameException(
+            'foo',
+            1489593098
+        )));
+        $mockedDriver->expects($this->any())->method('sanitizeFileName')->will($this->returnValue('bar'));
+        $this->prepareSubject([], true, $mockedDriver, [], [
+            'emitPreFileRenameSignal',
+            'emitPostFileRenameSignal',
+            'replaceFile',
+            'getPublicUrl',
+            'getResourceFactoryInstance'
+        ]);
+        $this->subject->expects($this->once())->method('getPublicUrl')->will($this->returnValue('somePath'));
+        $resourceFactory = $this->prophesize(ResourceFactory::class);
+        $file = $this->prophesize(FileInterface::class);
+        $resourceFactory->getFileObjectFromCombinedIdentifier(Argument::any())->willReturn($file->reveal());
+        $this->subject->expects($this->once())->method('replaceFile')->will($this->returnValue($file->reveal()));
+        $this->subject->expects($this->any())->method('getResourceFactoryInstance')->will(self::returnValue($resourceFactory->reveal()));
+        /** @var File $file */
+        $file = new File(['identifier' => 'foo', 'name' => 'foo', 'missing' => false], $this->subject);
+        $this->subject->renameFile($file, 'bar', DuplicationBehavior::REPLACE);
+    }
 }