[BUGFIX] Make meta data editable for non-writable storages
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Resource / ResourceStorageTest.php
index 3357473..c1ebb56 100644 (file)
@@ -1,4 +1,6 @@
 <?php
+declare(strict_types = 1);
+
 namespace TYPO3\CMS\Core\Tests\Unit\Resource;
 
 /*
@@ -14,16 +16,21 @@ namespace TYPO3\CMS\Core\Tests\Unit\Resource;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\Database\DatabaseConnection;
+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\FolderInterface;
 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\Resource\ResourceStorageInterface;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
@@ -33,34 +40,33 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 class ResourceStorageTest extends BaseTestCase
 {
     /**
-     * @var array A backup of registered singleton instances
+     * @var bool Reset singletons created by subject
      */
-    protected $singletonInstances = array();
+    protected $resetSingletonInstances = true;
 
     /**
      * @var ResourceStorage|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $subject;
 
-    protected function setUp()
+    /**
+     * Set up
+     */
+    protected function setUp(): void
     {
         parent::setUp();
-        $this->singletonInstances = GeneralUtility::getSingletonInstances();
         /** @var FileRepository|\PHPUnit_Framework_MockObject_MockObject $fileRepositoryMock */
-        $fileRepositoryMock = $this->getMock(FileRepository::class);
+        $fileRepositoryMock = $this->createMock(FileRepository::class);
         GeneralUtility::setSingletonInstance(
             FileRepository::class,
             $fileRepositoryMock
         );
-        $databaseMock = $this->getMock(DatabaseConnection::class);
-        $databaseMock->expects($this->any())->method('exec_SELECTgetRows')->with('*', 'sys_file_storage', '1=1', '', 'name', '', 'uid')->willReturn(array());
-        $GLOBALS['TYPO3_DB'] = $databaseMock;
-    }
-
-    protected function tearDown()
-    {
-        GeneralUtility::resetSingletonInstances($this->singletonInstances);
-        parent::tearDown();
+        $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());
     }
 
     /**
@@ -70,24 +76,40 @@ class ResourceStorageTest extends BaseTestCase
      * @param bool $mockPermissionChecks
      * @param AbstractDriver|\PHPUnit_Framework_MockObject_MockObject $driverObject
      * @param array $storageRecord
-     */
-    protected function prepareSubject(array $configuration, $mockPermissionChecks = false, AbstractDriver $driverObject = null, array $storageRecord = array())
-    {
-        $permissionMethods = array('assureFileAddPermissions', 'checkFolderActionPermission', 'checkFileActionPermission', 'checkUserActionPermission', 'checkFileExtensionPermission', 'isWithinFileMountBoundaries');
-        $mockedMethods = array();
+     * @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 = array('configuration' => $configuration);
+        $overruleArray = ['configuration' => $configuration];
         ArrayUtility::mergeRecursiveWithOverrule($storageRecord, $overruleArray);
-        if ($driverObject == null) {
-            $driverObject = $this->getMockForAbstractClass(AbstractDriver::class, array(), '', false);
+        if ($driverObject === null) {
+            $driverObject = $this->getMockForAbstractClass(AbstractDriver::class, [], '', false);
         }
         if ($mockPermissionChecks) {
-            $mockedMethods = $permissionMethods;
+            $mockedMethods = array_merge($mockedMethods, $permissionMethods);
         }
         $mockedMethods[] = 'getIndexer';
 
-        $this->subject = $this->getMock(ResourceStorage::class, $mockedMethods, array($driverObject, $storageRecord));
-        $this->subject->expects($this->any())->method('getIndexer')->will($this->returnValue($this->getMock(\TYPO3\CMS\Core\Resource\Index\Indexer::class, array(), array(), '', false)));
+        $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));
@@ -102,11 +124,11 @@ class ResourceStorageTest extends BaseTestCase
      * @return string
      * @see GeneralUtility::array2xml()
      */
-    protected function convertConfigurationArrayToFlexformXml(array $configuration)
+    protected function convertConfigurationArrayToFlexformXml(array $configuration): string
     {
-        $flexFormArray = array('data' => array('sDEF' => array('lDEF' => array())));
+        $flexFormArray = ['data' => ['sDEF' => ['lDEF' => []]]];
         foreach ($configuration as $key => $value) {
-            $flexFormArray['data']['sDEF']['lDEF'][$key] = array('vDEF' => $value);
+            $flexFormArray['data']['sDEF']['lDEF'][$key] = ['vDEF' => $value];
         }
         $configuration = GeneralUtility::array2xml($flexFormArray);
         return $configuration;
@@ -122,8 +144,11 @@ class ResourceStorageTest extends BaseTestCase
      * @param array $mockedDriverMethods
      * @return \TYPO3\CMS\Core\Resource\Driver\LocalDriver|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected function createDriverMock($driverConfiguration, ResourceStorage $storageObject = null, $mockedDriverMethods = array())
-    {
+    protected function createDriverMock(
+        $driverConfiguration,
+        ResourceStorage $storageObject = null,
+        array $mockedDriverMethods = []
+    ) {
         $this->initializeVfs();
 
         if (!isset($driverConfiguration['basePath'])) {
@@ -134,8 +159,11 @@ class ResourceStorageTest extends BaseTestCase
             $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->getMock(LocalDriver::class, $mockedDriverMethods, array($driverConfiguration));
+            // 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);
@@ -149,198 +177,129 @@ class ResourceStorageTest extends BaseTestCase
     /**
      * @return array
      */
-    public function isWithinFileMountBoundariesDataProvider()
-    {
-        return array(
-            'Access to file in ro file mount denied for write request' => array(
-                '$fileIdentifier' => '/fooBaz/bar.txt',
-                '$fileMountFolderIdentifier' => '/fooBaz/',
-                '$isFileMountReadOnly' => true,
-                '$checkWriteAccess' => true,
-                '$expectedResult' => false,
-            ),
-            'Access to file in ro file mount allowed for read request' => array(
-                '$fileIdentifier' => '/fooBaz/bar.txt',
-                '$fileMountFolderIdentifier' => '/fooBaz/',
-                '$isFileMountReadOnly' => true,
-                '$checkWriteAccess' => false,
-                '$expectedResult' => true,
-            ),
-            'Access to file in rw file mount allowed for write request' => array(
-                '$fileIdentifier' => '/fooBaz/bar.txt',
-                '$fileMountFolderIdentifier' => '/fooBaz/',
-                '$isFileMountReadOnly' => false,
-                '$checkWriteAccess' => true,
-                '$expectedResult' => true,
-            ),
-            'Access to file in rw file mount allowed for read request' => array(
-                '$fileIdentifier' => '/fooBaz/bar.txt',
-                '$fileMountFolderIdentifier' => '/fooBaz/',
-                '$isFileMountReadOnly' => false,
-                '$checkWriteAccess' => false,
-                '$expectedResult' => true,
-            ),
-            'Access to file not in file mount denied for write request' => array(
-                '$fileIdentifier' => '/fooBaz/bar.txt',
-                '$fileMountFolderIdentifier' => '/barBaz/',
-                '$isFileMountReadOnly' => false,
-                '$checkWriteAccess' => true,
-                '$expectedResult' => false,
-            ),
-            'Access to file not in file mount denied for read request' => array(
-                '$fileIdentifier' => '/fooBaz/bar.txt',
-                '$fileMountFolderIdentifier' => '/barBaz/',
-                '$isFileMountReadOnly' => false,
-                '$checkWriteAccess' => false,
-                '$expectedResult' => false,
-            ),
-        );
-    }
-
-    /**
-     * @param string $fileIdentifier
-     * @param string $fileMountFolderIdentifier
-     * @param bool $isFileMountReadOnly
-     * @param bool $checkWriteAccess
-     * @param bool $expectedResult
-     * @throws \TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException
-     * @test
-     * @dataProvider isWithinFileMountBoundariesDataProvider
-     */
-    public function isWithinFileMountBoundariesRespectsReadOnlyFileMounts($fileIdentifier, $fileMountFolderIdentifier, $isFileMountReadOnly, $checkWriteAccess, $expectedResult)
-    {
-        /** @var AbstractDriver|\PHPUnit_Framework_MockObject_MockObject $driverMock */
-        $driverMock = $this->getMockForAbstractClass(AbstractDriver::class, array(), '', false);
-        $driverMock->expects($this->any())
-            ->method('getFolderInfoByIdentifier')
-            ->willReturnCallback(function ($identifier) use ($isFileMountReadOnly) {
-                return array(
-                    'identifier' => $identifier,
-                    'name' => trim($identifier, '/'),
-                );
-            });
-        $driverMock->expects($this->any())
-            ->method('isWithin')
-            ->willReturnCallback(function ($folderIdentifier, $fileIdentifier) {
-                if ($fileIdentifier === ResourceStorageInterface::DEFAULT_ProcessingFolder . '/') {
-                    return false;
-                } else {
-                    return strpos($fileIdentifier, $folderIdentifier) === 0;
-                }
-            });
-        $this->prepareSubject(array(), false, $driverMock);
-        $fileMock = $this->getSimpleFileMock($fileIdentifier);
-        $this->subject->setEvaluatePermissions(true);
-        $this->subject->addFileMount('/' . $this->getUniqueId('random') . '/', array('read_only' => false));
-        $this->subject->addFileMount($fileMountFolderIdentifier, array('read_only' => $isFileMountReadOnly));
-        $this->subject->addFileMount('/' . $this->getUniqueId('random') . '/', array('read_only' => false));
-        $this->assertSame($expectedResult, $this->subject->isWithinFileMountBoundaries($fileMock, $checkWriteAccess));
-    }
-
-    /**
-     * @return array
-     */
-    public function capabilitiesDataProvider()
+    public function capabilitiesDataProvider(): array
     {
-        return array(
-            'only public' => array(
-                array(
+        return [
+            'only public' => [
+                [
                     'public' => true,
                     'writable' => false,
                     'browsable' => false
-                )
-            ),
-            'only writable' => array(
-                array(
+                ]
+            ],
+            'only writable' => [
+                [
                     'public' => false,
                     'writable' => true,
                     'browsable' => false
-                )
-            ),
-            'only browsable' => array(
-                array(
+                ]
+            ],
+            'only browsable' => [
+                [
                     'public' => false,
                     'writable' => false,
                     'browsable' => true
-                )
-            ),
-            'all capabilities' => array(
-                array(
+                ]
+            ],
+            'all capabilities' => [
+                [
                     'public' => true,
                     'writable' => true,
                     'browsable' => true
-                )
-            ),
-            'none' => array(
-                array(
+                ]
+            ],
+            '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)
+    public function capabilitiesOfStorageObjectAreCorrectlySet(array $capabilities): void
     {
         $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
-        $storageRecord = array(
+        $storageRecord = [
             'is_public' => $capabilities['public'],
             'is_writable' => $capabilities['writable'],
             'is_browsable' => $capabilities['browsable'],
             'is_online' => true
-        );
+        ];
         $mockedDriver = $this->createDriverMock(
-            array(
+            [
                 'pathType' => 'relative',
                 'basePath' => 'fileadmin/',
-            ),
+            ],
             $this->subject,
             null
         );
-        $this->prepareSubject(array(), 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.');
+        $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()
+    public function fileAndFolderListFiltersAreInitializedWithDefaultFilters(): void
     {
         $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
-        $this->prepareSubject(array());
-        $this->assertEquals($GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['defaultFilterCallbacks'], $this->subject->getFileAndFolderNameFilters());
+        $this->prepareSubject([]);
+        $this->assertEquals(
+            $GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['defaultFilterCallbacks'],
+            $this->subject->getFileAndFolderNameFilters()
+        );
     }
 
     /**
      * @test
      */
-    public function addFileFailsIfFileDoesNotExist()
+    public function addFileFailsIfFileDoesNotExist(): void
     {
         /** @var Folder|\PHPUnit_Framework_MockObject_MockObject $mockedFolder */
-        $mockedFolder = $this->getMock(Folder::class, array(), array(), '', false);
-        $this->setExpectedException('InvalidArgumentException', '', 1319552745);
-        $this->prepareSubject(array());
+        $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()
+    public function getPublicUrlReturnsNullIfStorageIsNotOnline(): void
     {
         /** @var $driver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
-        $driver = $this->getMock(LocalDriver::class, array(), array(array('basePath' => $this->getMountRootUrl())));
+        $driver = $this->getMockBuilder(LocalDriver::class)
+            ->setConstructorArgs([['basePath' => $this->getMountRootUrl()]])
+            ->getMock();
         /** @var $subject ResourceStorage|\PHPUnit_Framework_MockObject_MockObject */
-        $subject = $this->getMock(ResourceStorage::class, array('isOnline'), array($driver, array('configuration' => array())));
+        $subject = $this->getMockBuilder(ResourceStorage::class)
+            ->setMethods(['isOnline'])
+            ->setConstructorArgs([$driver, ['configuration' => []]])
+            ->getMock();
         $subject->expects($this->once())->method('isOnline')->will($this->returnValue(false));
 
         $sourceFileIdentifier = '/sourceFile.ext';
@@ -354,25 +313,25 @@ class ResourceStorageTest extends BaseTestCase
      *
      * @return array
      */
-    public function checkFolderPermissionsFilesystemPermissionsDataProvider()
+    public function checkFolderPermissionsFilesystemPermissionsDataProvider(): array
     {
-        return array(
-            'read action on readable/writable folder' => array(
+        return [
+            'read action on readable/writable folder' => [
                 'read',
-                array('r' => true, 'w' => true),
+                ['r' => true, 'w' => true],
                 true
-            ),
-            'read action on unreadable folder' => array(
+            ],
+            'read action on unreadable folder' => [
                 'read',
-                array('r' => false, 'w' => true),
+                ['r' => false, 'w' => true],
                 false
-            ),
-            'write action on read-only folder' => array(
+            ],
+            'write action on read-only folder' => [
                 'write',
-                array('r' => true, 'w' => false),
+                ['r' => true, 'w' => false],
                 false
-            )
-        );
+            ]
+        ];
     }
 
     /**
@@ -382,16 +341,22 @@ class ResourceStorageTest extends BaseTestCase
      * @param array $permissionsFromDriver The permissions as returned from the driver
      * @param bool $expectedResult
      */
-    public function checkFolderPermissionsRespectsFilesystemPermissions($action, $permissionsFromDriver, $expectedResult)
-    {
+    public function checkFolderPermissionsRespectsFilesystemPermissions(
+        string $action,
+        array $permissionsFromDriver,
+        bool $expectedResult
+    ): void {
         /** @var $mockedDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
-        $mockedDriver = $this->getMock(LocalDriver::class);
+        $mockedDriver = $this->createMock(LocalDriver::class);
         $mockedDriver->expects($this->any())->method('getPermissions')->will($this->returnValue($permissionsFromDriver));
-        /** @var $mockedFolder Folder|\PHPUnit_Framework_MockObject_MockObject  */
-        $mockedFolder = $this->getMock(Folder::class, array(), array(), '', false);
-            // Let all other checks pass
+        /** @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->getMock(ResourceStorage::class, array('isWritable', 'isBrowsable', 'checkUserActionPermission'), array($mockedDriver, array()), '', false);
+        $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));
@@ -403,41 +368,44 @@ class ResourceStorageTest extends BaseTestCase
     /**
      * @test
      */
-    public function checkUserActionPermissionsAlwaysReturnsTrueIfNoUserPermissionsAreSet()
+    public function checkUserActionPermissionsAlwaysReturnsTrueIfNoUserPermissionsAreSet(): void
     {
-        $this->prepareSubject(array());
+        $this->prepareSubject([]);
         $this->assertTrue($this->subject->checkUserActionPermission('read', 'folder'));
     }
 
     /**
      * @test
      */
-    public function checkUserActionPermissionReturnsFalseIfPermissionIsSetToZero()
+    public function checkUserActionPermissionReturnsFalseIfPermissionIsSetToZero(): void
     {
-        $this->prepareSubject(array());
-        $this->subject->setUserPermissions(array('readFolder' => true, 'writeFile' => true));
+        $this->prepareSubject([]);
+        $this->subject->setUserPermissions(['readFolder' => true, 'writeFile' => true]);
         $this->assertTrue($this->subject->checkUserActionPermission('read', 'folder'));
     }
 
-    public function checkUserActionPermission_arbitraryPermissionDataProvider()
+    /**
+     * @return array
+     */
+    public function checkUserActionPermission_arbitraryPermissionDataProvider(): array
     {
-        return array(
-            'all lower cased' => array(
-                array('readFolder' => true),
+        return [
+            'all lower cased' => [
+                ['readFolder' => true],
                 'read',
                 'folder'
-            ),
-            'all upper case' => array(
-                array('readFolder' => true),
+            ],
+            'all upper case' => [
+                ['readFolder' => true],
                 'READ',
                 'FOLDER'
-            ),
-            'mixed case' => array(
-                array('readFolder' => true),
+            ],
+            'mixed case' => [
+                ['readFolder' => true],
                 'ReaD',
                 'FoLdEr'
-            )
-        );
+            ]
+        ];
     }
 
     /**
@@ -447,9 +415,9 @@ class ResourceStorageTest extends BaseTestCase
      * @test
      * @dataProvider checkUserActionPermission_arbitraryPermissionDataProvider
      */
-    public function checkUserActionPermissionAcceptsArbitrarilyCasedArguments(array $permissions, $action, $type)
+    public function checkUserActionPermissionAcceptsArbitrarilyCasedArguments(array $permissions, string $action, string $type): void
     {
-        $this->prepareSubject(array());
+        $this->prepareSubject([]);
         $this->subject->setUserPermissions($permissions);
         $this->assertTrue($this->subject->checkUserActionPermission($action, $type));
     }
@@ -457,31 +425,96 @@ class ResourceStorageTest extends BaseTestCase
     /**
      * @test
      */
-    public function userActionIsDisallowedIfPermissionIsSetToFalse()
+    public function userActionIsDisallowedIfPermissionIsSetToFalse(): void
     {
-        $this->prepareSubject(array());
+        $this->prepareSubject([]);
         $this->subject->setEvaluatePermissions(true);
-        $this->subject->setUserPermissions(array('readFolder' => false));
+        $this->subject->setUserPermissions(['readFolder' => false]);
         $this->assertFalse($this->subject->checkUserActionPermission('read', 'folder'));
     }
 
     /**
      * @test
      */
-    public function userActionIsDisallowedIfPermissionIsNotSet()
+    public function userActionIsDisallowedIfPermissionIsNotSet(): void
     {
-        $this->prepareSubject(array());
+        $this->prepareSubject([]);
         $this->subject->setEvaluatePermissions(true);
-        $this->subject->setUserPermissions(array('readFolder' => true));
+        $this->subject->setUserPermissions(['readFolder' => true]);
         $this->assertFalse($this->subject->checkUserActionPermission('write', 'folder'));
     }
 
     /**
      * @test
      */
-    public function getEvaluatePermissionsWhenSetFalse()
+    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
     {
-        $this->prepareSubject(array());
+        $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());
     }
@@ -489,9 +522,9 @@ class ResourceStorageTest extends BaseTestCase
     /**
      * @test
      */
-    public function getEvaluatePermissionsWhenSetTrue()
+    public function getEvaluatePermissionsWhenSetTrue(): void
     {
-        $this->prepareSubject(array());
+        $this->prepareSubject([]);
         $this->subject->setEvaluatePermissions(true);
         $this->assertTrue($this->subject->getEvaluatePermissions());
     }
@@ -501,14 +534,17 @@ class ResourceStorageTest extends BaseTestCase
      * @group integration
      * @TODO: Rewrite or move to functional suite
      */
-    public function setFileContentsUpdatesObjectProperties()
+    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, array(), '', false);
-        $this->subject = $this->getMock(ResourceStorage::class, array('getFileIndexRepository', 'checkFileActionPermission'), array($driverObject, array()));
+        $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 = array(
+        $fileInfo = [
             'storage' => 'A',
             'identifier' => 'B',
             'mtime' => 'C',
@@ -516,8 +552,8 @@ class ResourceStorageTest extends BaseTestCase
             'mimetype' => 'E',
             'size' => 'F',
             'name' => 'G',
-        );
-        $newProperties = array(
+        ];
+        $newProperties = [
             'storage' => $fileInfo['storage'],
             'identifier' => $fileInfo['identifier'],
             'tstamp' => $fileInfo['mtime'],
@@ -525,17 +561,19 @@ class ResourceStorageTest extends BaseTestCase
             'mime_type' => $fileInfo['mimetype'],
             'size' => $fileInfo['size'],
             'name' => $fileInfo['name']
-        );
+        ];
         $hash = 'asdfg';
         /** @var $mockedDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
-        $mockedDriver = $this->getMock(LocalDriver::class, array(), array(array('basePath' => $this->getMountRootUrl())));
+        $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->getMock(FileIndexRepository::class);
+        $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->getMock(File::class, array(), array(), '', false);
+        $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));
@@ -552,12 +590,12 @@ class ResourceStorageTest extends BaseTestCase
      * @group integration
      * @TODO: Rewrite or move to functional suite
      */
-    public function moveFileCallsDriversMethodsWithCorrectArguments()
+    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 = array(
+        $fileInfoDummy = [
             'storage' => 'A',
             'identifier' => 'B',
             'mtime' => 'C',
@@ -565,28 +603,37 @@ class ResourceStorageTest extends BaseTestCase
             'mimetype' => 'E',
             'size' => 'F',
             'name' => 'G',
-        );
-        $this->addToMount(array(
-            'targetFolder' => array()
-        ));
+        ];
+        $this->addToMount([
+            'targetFolder' => []
+        ]);
         $this->initializeVfs();
         $targetFolder = $this->getSimpleFolderMock('/targetFolder/');
         /** @var $sourceDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
-        $sourceDriver = $this->getMock(LocalDriver::class);
+        $sourceDriver = $this->createMock(LocalDriver::class);
         $sourceDriver->expects($this->once())->method('deleteFile')->with($this->equalTo($sourceFileIdentifier));
-        $configuration = $this->convertConfigurationArrayToFlexformXml(array());
-        $sourceStorage = new ResourceStorage($sourceDriver, array('configuration' => $configuration));
+        $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->getMock(LocalDriver::class, array(), array(array('basePath' => $this->getMountRootUrl())));
+        $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'));
+        $mockedDriver->expects($this->once())->method('addFile')->with(
+            $localFilePath,
+            '/targetFolder/',
+            $this->equalTo('file.ext')
+        )->will($this->returnValue('/targetFolder/file.ext'));
         /** @var $subject ResourceStorage */
-        $subject = $this->getMock(ResourceStorage::class, array('assureFileMovePermissions'), array($mockedDriver, array('configuration' => $configuration)));
+        $subject = $this->getMockBuilder(ResourceStorage::class)
+            ->setMethods(['assureFileMovePermissions'])
+            ->setConstructorArgs([$mockedDriver, ['configuration' => $configuration]])
+            ->getMock();
         $subject->moveFile($sourceFile, $targetFolder, 'file.ext');
     }
 
@@ -595,18 +642,18 @@ class ResourceStorageTest extends BaseTestCase
      * @group integration
      * @TODO: Rewrite or move to functional suite
      */
-    public function storageUsesInjectedFilemountsToCheckForMountBoundaries()
+    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(array(
-            'mountFolder' => array(
+        $this->addToMount([
+            'mountFolder' => [
                 'file' => 'asdfg'
-            )
-        ));
-        $mockedDriver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), null, null);
+            ]
+        ]);
+        $mockedDriver = $this->createDriverMock(['basePath' => $this->getMountRootUrl()], null, null);
         $this->initializeVfs();
-        $this->prepareSubject(array(), null, $mockedDriver);
+        $this->prepareSubject([], null, $mockedDriver);
         $this->subject->addFileMount('/mountFolder');
         $this->assertEquals(1, count($this->subject->getFileMounts()));
         $this->subject->isWithinFileMountBoundaries($mockedFile);
@@ -616,31 +663,33 @@ class ResourceStorageTest extends BaseTestCase
      * @test
      * @TODO: Rewrite or move to functional suite
      */
-    public function createFolderChecksIfParentFolderExistsBeforeCreatingFolder()
+    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(array());
+        $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(array(), true);
+        $this->prepareSubject([], true);
         $this->subject->setDriver($mockedDriver);
         $this->subject->createFolder('newFolder', $mockedParentFolder);
     }
 
     /**
      * @test
-     * @expectedException \RuntimeException
      */
-    public function deleteFolderThrowsExceptionIfFolderIsNotEmptyAndRecursiveDeleteIsDisabled()
+    public function deleteFolderThrowsExceptionIfFolderIsNotEmptyAndRecursiveDeleteIsDisabled(): void
     {
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionCode(1325952534);
+
         /** @var \TYPO3\CMS\Core\Resource\Folder|\PHPUnit_Framework_MockObject_MockObject $folderMock */
-        $folderMock = $this->getMock(Folder::class, array(), array(), '', false);
+        $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\CMS\Core\Tests\AccessibleObjectInterface */
-        $subject = $this->getAccessibleMock(ResourceStorage::class, array('checkFolderActionPermission'), array(), '', 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);
@@ -650,13 +699,16 @@ class ResourceStorageTest extends BaseTestCase
      * @test
      * @TODO: Rewrite or move to functional suite
      */
-    public function createFolderCallsDriverForFolderCreation()
+    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(array(), true);
-        $mockedDriver = $this->createDriverMock(array(), $this->subject);
-        $mockedDriver->expects($this->once())->method('createFolder')->with($this->equalTo('newFolder'), $this->equalTo('/someFolder/'))->will($this->returnValue(true));
+        $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);
     }
@@ -665,12 +717,12 @@ class ResourceStorageTest extends BaseTestCase
      * @test
      * @TODO: Rewrite or move to functional suite
      */
-    public function createFolderCanRecursivelyCreateFolders()
+    public function createFolderCanRecursivelyCreateFolders(): void
     {
         $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
-        $this->addToMount(array('someFolder' => array()));
-        $mockedDriver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), null, null);
-        $this->prepareSubject(array(), true, $mockedDriver);
+        $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());
@@ -682,11 +734,11 @@ class ResourceStorageTest extends BaseTestCase
      * @test
      * @TODO: Rewrite or move to functional suite
      */
-    public function createFolderUsesRootFolderAsParentFolderIfNotGiven()
+    public function createFolderUsesRootFolderAsParentFolderIfNotGiven(): void
     {
         $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
-        $this->prepareSubject(array(), true);
-        $mockedDriver = $this->createDriverMock(array(), $this->subject);
+        $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');
@@ -696,15 +748,15 @@ class ResourceStorageTest extends BaseTestCase
      * @test
      * @TODO: Rewrite or move to functional suite
      */
-    public function createFolderCreatesNestedStructureEvenIfPartsAlreadyExist()
+    public function createFolderCreatesNestedStructureEvenIfPartsAlreadyExist(): void
     {
         $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
-        $this->addToMount(array(
-            'existingFolder' => array()
-        ));
+        $this->addToMount([
+            'existingFolder' => []
+        ]);
         $this->initializeVfs();
-        $mockedDriver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), null, null);
-        $this->prepareSubject(array(), true, $mockedDriver);
+        $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());
@@ -714,12 +766,13 @@ class ResourceStorageTest extends BaseTestCase
     /**
      * @test
      */
-    public function createFolderThrowsExceptionIfParentFolderDoesNotExist()
+    public function createFolderThrowsExceptionIfParentFolderDoesNotExist(): void
     {
-        $this->setExpectedException('InvalidArgumentException', '', 1325689164);
+        $this->expectException(\InvalidArgumentException::class);
+        $this->expectExceptionCode(1325689164);
         $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
-        $this->prepareSubject(array(), true);
-        $mockedDriver = $this->createDriverMock(array(), $this->subject);
+        $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);
     }
@@ -727,29 +780,93 @@ class ResourceStorageTest extends BaseTestCase
     /**
      * @test
      */
-    public function replaceFileFailsIfLocalFileDoesNotExist()
+    public function renameFileRenamesFileAsRequested(): void
     {
-        $this->setExpectedException('InvalidArgumentException', '', 1325842622);
-        $this->prepareSubject(array(), true);
-        $mockedFile = $this->getSimpleFileMock('/someFile');
-        $this->subject->replaceFile($mockedFile, PATH_site . $this->getUniqueId());
+        $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
-     * @TODO: Rewrite or move to functional suite
      */
-    public function getRoleReturnsDefaultForRegularFolders()
-    {
-        $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
-        $folderIdentifier = $this->getUniqueId();
-        $this->addToMount(array(
-            $folderIdentifier => array()
+    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(array());
+        $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());
+    }
 
-        $role = $this->subject->getRole($this->getSimpleFolderMock('/' . $folderIdentifier . '/'));
+    /**
+     * @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);
+    }
 
-        $this->assertSame(FolderInterface::ROLE_DEFAULT, $role);
+    /**
+     * @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);
     }
 }