[TASK] Tests: Isolate GeneralUtility tests from real filesystem 00/44300/6
authorMorton Jonuschat <m.jonuschat@mojocode.de>
Mon, 26 Oct 2015 18:15:53 +0000 (19:15 +0100)
committerStefan Neufeind <typo3.neufeind@speedpartner.de>
Fri, 30 Oct 2015 08:55:15 +0000 (09:55 +0100)
Use the vfsStream wrapper to provide a virtual filesystem on which to
run the unit tests. This allows isolationg the tests for filesystem
operations from the actual implementation of the filesystem and the
capabilities of the user running the test suite.

The group ownership tests were converted to work with numeric group ids
as PHP on OS X has problems changing the group of a file if the group
name contains a dot. This also fixes the selection of the secondary
group on OS X as the static group offset used in the test didn't ensure
that the returned group was different from the effective group at the
time.

Tests using symlinks could not be modified to use vfsStream as the
symlink method only works with real filesystems.

The GeneralUtility test for relative paths could not be changed either
as vfs paths are always "absolute".

Resolves: #71052
Releases: master
Change-Id: I81c3f1de4b09b971a7e7ab4b09672e4d34934995
Reviewed-on: https://review.typo3.org/44300
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Tested-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
typo3/sysext/core/Classes/Utility/GeneralUtility.php
typo3/sysext/core/Tests/Unit/Utility/Fixtures/GeneralUtilityFilesystemFixture.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php

index f5bf057..91fa603 100755 (executable)
@@ -2673,7 +2673,7 @@ Connection: close
             }
             // Change the permissions only if the file has just been created
             if ($changePermissions) {
-                self::fixPermissions($file);
+                static::fixPermissions($file);
             }
             return true;
         }
@@ -2694,10 +2694,10 @@ Connection: close
         }
         $result = false;
         // Make path absolute
-        if (!self::isAbsPath($path)) {
-            $path = self::getFileAbsFileName($path, false);
+        if (!static::isAbsPath($path)) {
+            $path = static::getFileAbsFileName($path, false);
         }
-        if (self::isAllowedAbsPath($path)) {
+        if (static::isAllowedAbsPath($path)) {
             if (@is_file($path)) {
                 $targetFilePermissions = isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'])
                     ? octdec($GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'])
@@ -2727,9 +2727,9 @@ Connection: close
                     $recursionResult = null;
                     if ($file !== '.' && $file !== '..') {
                         if (@is_file(($path . '/' . $file))) {
-                            $recursionResult = self::fixPermissions($path . '/' . $file);
+                            $recursionResult = static::fixPermissions($path . '/' . $file);
                         } elseif (@is_dir(($path . '/' . $file))) {
-                            $recursionResult = self::fixPermissions($path . '/' . $file, true);
+                            $recursionResult = static::fixPermissions($path . '/' . $file, true);
                         }
                         if (isset($recursionResult) && !$recursionResult) {
                             $result = false;
@@ -2760,7 +2760,7 @@ Connection: close
         $fI = pathinfo($filepath);
         $fI['dirname'] .= '/';
         // Check parts:
-        if (!self::validPathStr($filepath) || !$fI['basename'] || strlen($fI['basename']) >= 60) {
+        if (!static::validPathStr($filepath) || !$fI['basename'] || strlen($fI['basename']) >= 60) {
             return 'Input filepath "' . $filepath . '" was generally invalid!';
         }
         // Setting main temporary directory name (standard)
@@ -2768,7 +2768,7 @@ Connection: close
         if (!@is_dir($dirName)) {
             return 'PATH_site + "typo3temp/" was not a directory!';
         }
-        if (!self::isFirstPartOfStr($fI['dirname'], $dirName)) {
+        if (!static::isFirstPartOfStr($fI['dirname'], $dirName)) {
             return '"' . $fI['dirname'] . '" was not within directory PATH_site + "typo3temp/"';
         }
         // Checking if the "subdir" is found:
@@ -2777,7 +2777,7 @@ Connection: close
             if (preg_match('/^[[:alnum:]_]+\\/$/', $subdir) || preg_match('/^[[:alnum:]_]+\\/[[:alnum:]_]+\\/$/', $subdir)) {
                 $dirName .= $subdir;
                 if (!@is_dir($dirName)) {
-                    self::mkdir_deep(PATH_site . 'typo3temp/', $subdir);
+                    static::mkdir_deep(PATH_site . 'typo3temp/', $subdir);
                 }
             } else {
                 return 'Subdir, "' . $subdir . '", was NOT on the form "[[:alnum:]_]/" or  "[[:alnum:]_]/[[:alnum:]_]/"';
@@ -2786,7 +2786,7 @@ Connection: close
         // Checking dir-name again (sub-dir might have been created):
         if (@is_dir($dirName)) {
             if ($filepath == $dirName . $fI['basename']) {
-                self::writeFile($filepath, $content);
+                static::writeFile($filepath, $content);
                 if (!@is_file($filepath)) {
                     return 'The file was not written to the disk. Please, check that you have write permissions to the typo3temp/ directory.';
                 }
@@ -2811,7 +2811,7 @@ Connection: close
     {
         $result = @mkdir($newFolder, octdec($GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask']));
         if ($result) {
-            self::fixPermissions($newFolder);
+            static::fixPermissions($newFolder);
         }
         return $result;
     }
@@ -2837,9 +2837,9 @@ Connection: close
         // Ensure there is only one slash
         $fullPath = rtrim($directory, '/') . '/' . ltrim($deepDirectory, '/');
         if ($fullPath !== '' && !is_dir($fullPath)) {
-            $firstCreatedPath = self::createDirectoryPath($fullPath);
+            $firstCreatedPath = static::createDirectoryPath($fullPath);
             if ($firstCreatedPath !== '') {
-                self::fixPermissions($firstCreatedPath, true);
+                static::fixPermissions($firstCreatedPath, true);
             }
         }
     }
@@ -2895,7 +2895,7 @@ Connection: close
                         if ($file == '.' || $file == '..') {
                             continue;
                         }
-                        $OK = self::rmdir($path . '/' . $file, $removeNonEmpty);
+                        $OK = static::rmdir($path . '/' . $file, $removeNonEmpty);
                     }
                     closedir($handle);
                 }
@@ -2937,10 +2937,10 @@ Connection: close
                     GeneralUtility::makeInstance(OpcodeCacheService::class)->clearAllActive($directory);
                 }
                 if ($keepOriginalDirectory) {
-                    self::mkdir($directory);
+                    static::mkdir($directory);
                 }
                 clearstatcache();
-                $result = self::rmdir($temporaryDirectory, true);
+                $result = static::rmdir($temporaryDirectory, true);
             }
         }
 
@@ -3850,14 +3850,14 @@ Connection: close
             if ((string)$extKey !== '' && ExtensionManagementUtility::isLoaded($extKey) && (string)$local !== '') {
                 $filename = ExtensionManagementUtility::extPath($extKey) . $local;
             }
-        } elseif (!self::isAbsPath($filename)) {
+        } elseif (!static::isAbsPath($filename)) {
             // relative. Prepended with $relPathPrefix
             $filename = $relPathPrefix . $filename;
-        } elseif ($onlyRelative && !self::isFirstPartOfStr($filename, $relPathPrefix)) {
+        } elseif ($onlyRelative && !static::isFirstPartOfStr($filename, $relPathPrefix)) {
             // absolute, but set to blank if not allowed
             $filename = '';
         }
-        if ((string)$filename !== '' && self::validPathStr($filename)) {
+        if ((string)$filename !== '' && static::validPathStr($filename)) {
             // checks backpath.
             return $filename;
         }
@@ -3902,9 +3902,9 @@ Connection: close
     public static function isAllowedAbsPath($path)
     {
         $lockRootPath = $GLOBALS['TYPO3_CONF_VARS']['BE']['lockRootPath'];
-        return self::isAbsPath($path) && self::validPathStr($path)
-            && (self::isFirstPartOfStr($path, PATH_site)
-                || $lockRootPath && self::isFirstPartOfStr($path, $lockRootPath));
+        return static::isAbsPath($path) && static::validPathStr($path)
+            && (static::isFirstPartOfStr($path, PATH_site)
+                || $lockRootPath && static::isFirstPartOfStr($path, $lockRootPath));
     }
 
     /**
diff --git a/typo3/sysext/core/Tests/Unit/Utility/Fixtures/GeneralUtilityFilesystemFixture.php b/typo3/sysext/core/Tests/Unit/Utility/Fixtures/GeneralUtilityFilesystemFixture.php
new file mode 100644 (file)
index 0000000..eb08077
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Utility\Fixtures;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * 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.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Class GeneralUtilityFilesystemFixture
+ */
+class GeneralUtilityFilesystemFixture extends GeneralUtility
+{
+    /**
+     * For testing we must allow vfs:// as first part of file path
+     *
+     * @param string $path File path to evaluate
+     * @return bool
+     */
+    public static function isAbsPath($path)
+    {
+        return self::isFirstPartOfStr($path, 'vfs://') || parent::isAbsPath($path);
+    }
+
+    /**
+     * For testing we must allow vfs:// as first part file path
+     *
+     * @param string $path File path to evaluate
+     * @return bool
+     */
+    public static function isAllowedAbsPath($path)
+    {
+        return self::isFirstPartOfStr($path, 'vfs://') || parent::isAllowedAbsPath($path);
+    }
+
+    /**
+     * For testing we must allow vfs:// as first part of file path
+     *
+     * @param string $theFile File path to evaluate
+     * @return bool TRUE, $theFile is allowed path string, FALSE otherwise
+     */
+    public static function validPathStr($theFile)
+    {
+        return self::isFirstPartOfStr($theFile, 'vfs://') || parent::validPathStr($theFile);
+    }
+
+    /**
+     * For testing we must skip the path checks
+     *
+     * @param string $filepath Absolute file path to write to inside "typo3temp/". First part of this string must match PATH_site."typo3temp/"
+     * @param string $content Content string to write
+     * @return string Returns NULL on success, otherwise an error string telling about the problem.
+     */
+    public static function writeFileToTypo3tempDir($filepath, $content)
+    {
+        static::writeFile($filepath, $content);
+    }
+}
index dca03d2..caebc4b 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Core\Tests\Unit\Utility;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Tests\Unit\Utility\Fixtures\GeneralUtilityFilesystemFixture;
 use TYPO3\CMS\Core\Tests\Unit\Utility\Fixtures\GeneralUtilityFixture;
 use TYPO3\CMS\Core\Tests\Unit\Utility\Fixtures\GeneralUtilityMinifyJavaScriptFixture;
 use TYPO3\CMS\Core\Tests\Unit\Utility\Fixtures\OriginalClassFixture;
@@ -68,6 +69,21 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         return $isConnected;
     }
 
+    /**
+     * Helper method to create a random directory in the virtual file system
+     * and return the path.
+     *
+     * @param string $prefix
+     * @return string
+     */
+    protected function getVirtualTestDir($prefix = 'root_')
+    {
+        $root = vfsStream::setup();
+        $path = $root->url() . '/typo3temp/' . $this->getUniqueId($prefix);
+        GeneralUtility::mkdir_deep($path);
+        return $path;
+    }
+
     ///////////////////////////
     // Tests concerning _GP
     ///////////////////////////
@@ -2794,13 +2810,12 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
             $this->markTestSkipped('The fixPermissionsSetsGroup() is not available on Mac OS because posix_getegid() always returns -1 on Mac OS.');
         }
         // Create and prepare test file
-        $filename = PATH_site . 'typo3temp/' . $this->getUniqueId('test_');
-        GeneralUtility::writeFileToTypo3tempDir($filename, '42');
-        $this->testFilesToDelete[] = $filename;
+        $filename = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
+        GeneralUtilityFilesystemFixture::writeFileToTypo3tempDir($filename, '42');
         $currentGroupId = posix_getegid();
         // Set target group and run method
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['createGroup'] = $currentGroupId;
-        GeneralUtility::fixPermissions($filename);
+        GeneralUtilityFilesystemFixture::fixPermissions($filename);
         clearstatcache();
         $this->assertEquals($currentGroupId, filegroup($filename));
     }
@@ -2810,17 +2825,16 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function fixPermissionsSetsPermissionsToFile()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('fixPermissions() tests not available on Windows');
         }
         // Create and prepare test file
-        $filename = PATH_site . 'typo3temp/' . $this->getUniqueId('test_');
-        GeneralUtility::writeFileToTypo3tempDir($filename, '42');
-        $this->testFilesToDelete[] = $filename;
+        $filename = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
+        GeneralUtilityFilesystemFixture::writeFileToTypo3tempDir($filename, '42');
         chmod($filename, 482);
         // Set target permissions and run method
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = '0660';
-        $fixPermissionsResult = GeneralUtility::fixPermissions($filename);
+        $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($filename);
         clearstatcache();
         $this->assertTrue($fixPermissionsResult);
         $this->assertEquals('0660', substr(decoct(fileperms($filename)), 2));
@@ -2831,17 +2845,16 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function fixPermissionsSetsPermissionsToHiddenFile()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('fixPermissions() tests not available on Windows');
         }
         // Create and prepare test file
-        $filename = PATH_site . 'typo3temp/' . $this->getUniqueId('.test_');
-        GeneralUtility::writeFileToTypo3tempDir($filename, '42');
-        $this->testFilesToDelete[] = $filename;
+        $filename = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
+        GeneralUtilityFilesystemFixture::writeFileToTypo3tempDir($filename, '42');
         chmod($filename, 482);
         // Set target permissions and run method
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = '0660';
-        $fixPermissionsResult = GeneralUtility::fixPermissions($filename);
+        $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($filename);
         clearstatcache();
         $this->assertTrue($fixPermissionsResult);
         $this->assertEquals('0660', substr(decoct(fileperms($filename)), 2));
@@ -2852,17 +2865,16 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function fixPermissionsSetsPermissionsToDirectory()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('fixPermissions() tests not available on Windows');
         }
         // Create and prepare test directory
-        $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('test_');
-        GeneralUtility::mkdir($directory);
-        $this->testFilesToDelete[] = $directory;
+        $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
+        GeneralUtilityFilesystemFixture::mkdir($directory);
         chmod($directory, 1551);
         // Set target permissions and run method
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0770';
-        $fixPermissionsResult = GeneralUtility::fixPermissions($directory);
+        $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($directory);
         clearstatcache();
         $this->assertTrue($fixPermissionsResult);
         $this->assertEquals('0770', substr(decoct(fileperms($directory)), 1));
@@ -2873,17 +2885,16 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function fixPermissionsSetsPermissionsToDirectoryWithTrailingSlash()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('fixPermissions() tests not available on Windows');
         }
         // Create and prepare test directory
-        $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('test_');
-        GeneralUtility::mkdir($directory);
-        $this->testFilesToDelete[] = $directory;
+        $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
+        GeneralUtilityFilesystemFixture::mkdir($directory);
         chmod($directory, 1551);
         // Set target permissions and run method
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0770';
-        $fixPermissionsResult = GeneralUtility::fixPermissions($directory . '/');
+        $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($directory . '/');
         // Get actual permissions and clean up
         clearstatcache();
         $this->assertTrue($fixPermissionsResult);
@@ -2895,17 +2906,16 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function fixPermissionsSetsPermissionsToHiddenDirectory()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('fixPermissions() tests not available on Windows');
         }
         // Create and prepare test directory
-        $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('.test_');
-        GeneralUtility::mkdir($directory);
-        $this->testFilesToDelete[] = $directory;
+        $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
+        GeneralUtilityFilesystemFixture::mkdir($directory);
         chmod($directory, 1551);
         // Set target permissions and run method
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0770';
-        $fixPermissionsResult = GeneralUtility::fixPermissions($directory);
+        $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($directory);
         // Get actual permissions and clean up
         clearstatcache();
         $this->assertTrue($fixPermissionsResult);
@@ -2917,21 +2927,20 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function fixPermissionsCorrectlySetsPermissionsRecursive()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('fixPermissions() tests not available on Windows');
         }
         // Create and prepare test directory and file structure
-        $baseDirectory = PATH_site . 'typo3temp/' . $this->getUniqueId('test_');
-        GeneralUtility::mkdir($baseDirectory);
-        $this->testFilesToDelete[] = $baseDirectory;
+        $baseDirectory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
+        GeneralUtilityFilesystemFixture::mkdir($baseDirectory);
         chmod($baseDirectory, 1751);
-        GeneralUtility::writeFileToTypo3tempDir($baseDirectory . '/file', '42');
+        GeneralUtilityFilesystemFixture::writeFileToTypo3tempDir($baseDirectory . '/file', '42');
         chmod($baseDirectory . '/file', 482);
-        GeneralUtility::mkdir($baseDirectory . '/foo');
+        GeneralUtilityFilesystemFixture::mkdir($baseDirectory . '/foo');
         chmod($baseDirectory . '/foo', 1751);
-        GeneralUtility::writeFileToTypo3tempDir($baseDirectory . '/foo/file', '42');
+        GeneralUtilityFilesystemFixture::writeFileToTypo3tempDir($baseDirectory . '/foo/file', '42');
         chmod($baseDirectory . '/foo/file', 482);
-        GeneralUtility::mkdir($baseDirectory . '/.bar');
+        GeneralUtilityFilesystemFixture::mkdir($baseDirectory . '/.bar');
         chmod($baseDirectory . '/.bar', 1751);
         // Use this if writeFileToTypo3tempDir is fixed to create hidden files in subdirectories
         // \TYPO3\CMS\Core\Utility\GeneralUtility::writeFileToTypo3tempDir($baseDirectory . '/.bar/.file', '42');
@@ -2943,7 +2952,7 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         // Set target permissions and run method
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = '0660';
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0770';
-        $fixPermissionsResult = GeneralUtility::fixPermissions($baseDirectory, true);
+        $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($baseDirectory, true);
         // Get actual permissions
         clearstatcache();
         $resultBaseDirectoryPermissions = substr(decoct(fileperms($baseDirectory)), 1);
@@ -2969,18 +2978,14 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function fixPermissionsDoesNotSetPermissionsToNotAllowedPath()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('fixPermissions() tests not available on Windows');
         }
         // Create and prepare test file
         $filename = PATH_site . 'typo3temp/../typo3temp/' . $this->getUniqueId('test_');
-        touch($filename);
-        chmod($filename, 482);
         // Set target permissions and run method
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = '0660';
         $fixPermissionsResult = GeneralUtility::fixPermissions($filename);
-        clearstatcache();
-        $this->testFilesToDelete[] = $filename;
         $this->assertFalse($fixPermissionsResult);
     }
 
@@ -2989,7 +2994,7 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function fixPermissionsSetsPermissionsWithRelativeFileReference()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('fixPermissions() tests not available on Windows');
         }
         $filename = 'typo3temp/' . $this->getUniqueId('test_');
@@ -3009,15 +3014,14 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function fixPermissionsSetsDefaultPermissionsToFile()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('fixPermissions() tests not available on Windows');
         }
-        $filename = PATH_site . 'typo3temp/' . $this->getUniqueId('test_');
-        GeneralUtility::writeFileToTypo3tempDir($filename, '42');
-        $this->testFilesToDelete[] = $filename;
+        $filename = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
+        GeneralUtilityFilesystemFixture::writeFileToTypo3tempDir($filename, '42');
         chmod($filename, 482);
         unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask']);
-        $fixPermissionsResult = GeneralUtility::fixPermissions($filename);
+        $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($filename);
         clearstatcache();
         $this->assertTrue($fixPermissionsResult);
         $this->assertEquals('0644', substr(decoct(fileperms($filename)), 2));
@@ -3028,15 +3032,14 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function fixPermissionsSetsDefaultPermissionsToDirectory()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('fixPermissions() tests not available on Windows');
         }
-        $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('test_');
-        GeneralUtility::mkdir($directory);
-        $this->testFilesToDelete[] = $directory;
+        $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
+        GeneralUtilityFilesystemFixture::mkdir($directory);
         chmod($directory, 1551);
         unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask']);
-        $fixPermissionsResult = GeneralUtility::fixPermissions($directory);
+        $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($directory);
         clearstatcache();
         $this->assertTrue($fixPermissionsResult);
         $this->assertEquals('0755', substr(decoct(fileperms($directory)), 1));
@@ -3050,9 +3053,8 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function mkdirCreatesDirectory()
     {
-        $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('test_');
-        $mkdirResult = GeneralUtility::mkdir($directory);
-        $this->testFilesToDelete[] = $directory;
+        $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
+        $mkdirResult = GeneralUtilityFilesystemFixture::mkdir($directory);
         clearstatcache();
         $this->assertTrue($mkdirResult);
         $this->assertTrue(is_dir($directory));
@@ -3063,9 +3065,8 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function mkdirCreatesHiddenDirectory()
     {
-        $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('.test_');
-        $mkdirResult = GeneralUtility::mkdir($directory);
-        $this->testFilesToDelete[] = $directory;
+        $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('.test_');
+        $mkdirResult = GeneralUtilityFilesystemFixture::mkdir($directory);
         clearstatcache();
         $this->assertTrue($mkdirResult);
         $this->assertTrue(is_dir($directory));
@@ -3076,9 +3077,8 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function mkdirCreatesDirectoryWithTrailingSlash()
     {
-        $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('test_') . '/';
-        $mkdirResult = GeneralUtility::mkdir($directory);
-        $this->testFilesToDelete[] = $directory;
+        $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_') . '/';
+        $mkdirResult = GeneralUtilityFilesystemFixture::mkdir($directory);
         clearstatcache();
         $this->assertTrue($mkdirResult);
         $this->assertTrue(is_dir($directory));
@@ -3089,14 +3089,13 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function mkdirSetsPermissionsOfCreatedDirectory()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('mkdirSetsPermissionsOfCreatedDirectory() test not available on Windows');
         }
-        $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('test_');
+        $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
         $oldUmask = umask(19);
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0772';
-        GeneralUtility::mkdir($directory);
-        $this->testFilesToDelete[] = $directory;
+        GeneralUtilityFilesystemFixture::mkdir($directory);
         clearstatcache();
         $resultDirectoryPermissions = substr(decoct(fileperms($directory)), 1);
         umask($oldUmask);
@@ -3108,21 +3107,13 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function mkdirSetsGroupOwnershipOfCreatedDirectory()
     {
-        if (!function_exists('posix_getegid')) {
-            $this->markTestSkipped('Function posix_getegid() not available, mkdirSetsGroupOwnershipOfCreatedDirectory() tests skipped');
-        }
-        if (posix_getegid() === -1) {
-            $this->markTestSkipped('The mkdirSetsGroupOwnershipOfCreatedDirectory() is not available on Mac OS because posix_getegid() always returns -1 on Mac OS.');
-        }
         $swapGroup = $this->checkGroups(__FUNCTION__);
         if ($swapGroup !== false) {
             $GLOBALS['TYPO3_CONF_VARS']['SYS']['createGroup'] = $swapGroup;
-            $directory = $this->getUniqueId('mkdirtest_');
-            GeneralUtility::mkdir(PATH_site . 'typo3temp/' . $directory);
-            $this->testFilesToDelete[] = PATH_site . 'typo3temp/' . $directory;
+            $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('mkdirtest_');
+            GeneralUtilityFilesystemFixture::mkdir($directory);
             clearstatcache();
-            $resultDirectoryGroupInfo = posix_getgrgid(filegroup(PATH_site . 'typo3temp/' . $directory));
-            $resultDirectoryGroup = $resultDirectoryGroupInfo['name'];
+            $resultDirectoryGroup = filegroup($directory);
             $this->assertEquals($resultDirectoryGroup, $swapGroup);
         }
     }
@@ -3134,31 +3125,34 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      * Check if test on filesystem group ownership can be done in this environment
      * If so, return second group of webserver user
      *
-     * @param string calling method name
-     * @return mixed FALSE if test cannot be run, string name of the second group of webserver user
+     * @param string $methodName calling method name
+     * @return mixed FALSE if test cannot be run, int group id of the second group of webserver user
      */
     private function checkGroups($methodName)
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped($methodName . '() test not available on Windows.');
             return false;
         }
+        if (!function_exists('posix_getegid')) {
+            $this->markTestSkipped('Function posix_getegid() not available, ' . $methodName . '() tests skipped');
+            return false;
+        }
+        if (posix_getegid() === -1) {
+            $this->markTestSkipped('Function posix_getegid() returns -1, ' . $methodName . '() tests skipped');
+            return false;
+        }
         if (!function_exists('posix_getgroups')) {
             $this->markTestSkipped('Function posix_getgroups() not available, ' . $methodName . '() tests skipped');
+            return false;
         }
         $groups = posix_getgroups();
         if (count($groups) <= 1) {
             $this->markTestSkipped($methodName . '() test cannot be done when the web server user is only member of 1 group.');
             return false;
         }
-        $uname = strtolower(php_uname());
-        $groupOffset = 1;
-        if (strpos($uname, 'darwin') !== false) {
-            // We are on OSX and it seems that the first group needs to be fetched since Mavericks
-            $groupOffset = 0;
-        }
-        $groupInfo = posix_getgrgid($groups[$groupOffset]);
-        return $groupInfo['name'];
+        $secondaryGroups = array_diff($groups, [posix_getegid()]);
+        return array_shift($secondaryGroups);
     }
 
     ///////////////////////////////
@@ -3169,10 +3163,9 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function mkdirDeepCreatesDirectory()
     {
-        $directory = 'typo3temp/' . $this->getUniqueId('test_');
-        GeneralUtility::mkdir_deep(PATH_site, $directory);
-        $this->testFilesToDelete[] = PATH_site . $directory;
-        $this->assertTrue(is_dir(PATH_site . $directory));
+        $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
+        GeneralUtility::mkdir_deep($directory);
+        $this->assertTrue(is_dir($directory));
     }
 
     /**
@@ -3180,11 +3173,10 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function mkdirDeepCreatesSubdirectoriesRecursive()
     {
-        $directory = 'typo3temp/' . $this->getUniqueId('test_');
+        $directory = $this->getVirtualTestDir() . '/typo3temp/' . $this->getUniqueId('test_');
         $subDirectory = $directory . '/foo';
-        GeneralUtility::mkdir_deep(PATH_site, $subDirectory);
-        $this->testFilesToDelete[] = PATH_site . $directory;
-        $this->assertTrue(is_dir(PATH_site . $subDirectory));
+        GeneralUtility::mkdir_deep($subDirectory);
+        $this->assertTrue(is_dir($subDirectory));
     }
 
     /**
@@ -3219,7 +3211,7 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function mkdirDeepFixesPermissionsOfCreatedDirectory()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('mkdirDeepFixesPermissionsOfCreatedDirectory() test not available on Windows.');
         }
         $directory = $this->getUniqueId('mkdirdeeptest_');
@@ -3237,7 +3229,7 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function mkdirDeepFixesPermissionsOnNewParentDirectory()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('mkdirDeepFixesPermissionsOnNewParentDirectory() test not available on Windows.');
         }
         $directory = $this->getUniqueId('mkdirdeeptest_');
@@ -3256,7 +3248,7 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function mkdirDeepDoesNotChangePermissionsOfExistingSubDirectories()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('mkdirDeepDoesNotChangePermissionsOfExistingSubDirectories() test not available on Windows.');
         }
         $baseDirectory = PATH_site . 'typo3temp/';
@@ -3281,8 +3273,7 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
             GeneralUtility::mkdir_deep(PATH_site . 'typo3temp/', $directory);
             $this->testFilesToDelete[] = PATH_site . 'typo3temp/' . $directory;
             clearstatcache();
-            $resultDirectoryGroupInfo = posix_getgrgid(filegroup(PATH_site . 'typo3temp/' . $directory));
-            $resultDirectoryGroup = $resultDirectoryGroupInfo['name'];
+            $resultDirectoryGroup = filegroup(PATH_site . 'typo3temp/' . $directory);
             $this->assertEquals($resultDirectoryGroup, $swapGroup);
         }
     }
@@ -3300,8 +3291,7 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
             GeneralUtility::mkdir_deep(PATH_site . 'typo3temp/', $subDirectory);
             $this->testFilesToDelete[] = PATH_site . 'typo3temp/' . $directory;
             clearstatcache();
-            $resultDirectoryGroupInfo = posix_getgrgid(filegroup(PATH_site . 'typo3temp/' . $directory));
-            $resultDirectoryGroup = $resultDirectoryGroupInfo['name'];
+            $resultDirectoryGroup = filegroup(PATH_site . 'typo3temp/' . $directory);
             $this->assertEquals($resultDirectoryGroup, $swapGroup);
         }
     }
@@ -3319,8 +3309,7 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
             GeneralUtility::mkdir_deep(PATH_site . 'typo3temp/', $subDirectory);
             $this->testFilesToDelete[] = PATH_site . 'typo3temp/' . $directory;
             clearstatcache();
-            $resultDirectoryGroupInfo = posix_getgrgid(filegroup(PATH_site . 'typo3temp/' . $subDirectory));
-            $resultDirectoryGroup = $resultDirectoryGroupInfo['name'];
+            $resultDirectoryGroup = filegroup(PATH_site . 'typo3temp/' . $directory);
             $this->assertEquals($resultDirectoryGroup, $swapGroup);
         }
     }
@@ -4405,7 +4394,7 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function syslogFixesPermissionsOnFileIfUsingFileLogging()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('syslogFixesPermissionsOnFileIfUsingFileLogging() test not available on Windows.');
         }
         // Fake all required settings
@@ -4427,7 +4416,7 @@ class GeneralUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function deprecationLogFixesPermissionsOnLogFile()
     {
-        if (TYPO3_OS == 'WIN') {
+        if (TYPO3_OS === 'WIN') {
             $this->markTestSkipped('deprecationLogFixesPermissionsOnLogFile() test not available on Windows.');
         }
         $filePath = PATH_site . GeneralUtilityFixture::DEPRECATION_LOG_PATH;