4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Filesystem\Tests;
15 * Test class for Filesystem.
17 class FilesystemTest extends FilesystemTestCase
19 public function testCopyCreatesNewFile()
21 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
22 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
24 file_put_contents($sourceFilePath, 'SOURCE FILE');
26 $this->filesystem->copy($sourceFilePath, $targetFilePath);
28 $this->assertFileExists($targetFilePath);
29 $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
33 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
35 public function testCopyFails()
37 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
38 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
40 $this->filesystem->copy($sourceFilePath, $targetFilePath);
44 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
46 public function testCopyUnreadableFileFails()
48 // skip test on Windows; PHP can't easily set file as unreadable on Windows
49 if ('\\' === DIRECTORY_SEPARATOR) {
50 $this->markTestSkipped('This test cannot run on Windows.');
53 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
54 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
56 file_put_contents($sourceFilePath, 'SOURCE FILE');
58 // make sure target cannot be read
59 $this->filesystem->chmod($sourceFilePath, 0222);
61 $this->filesystem->copy($sourceFilePath, $targetFilePath);
64 public function testCopyOverridesExistingFileIfModified()
66 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
67 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
69 file_put_contents($sourceFilePath, 'SOURCE FILE');
70 file_put_contents($targetFilePath, 'TARGET FILE');
71 touch($targetFilePath, time() - 1000);
73 $this->filesystem->copy($sourceFilePath, $targetFilePath);
75 $this->assertFileExists($targetFilePath);
76 $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
79 public function testCopyDoesNotOverrideExistingFileByDefault()
81 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
82 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
84 file_put_contents($sourceFilePath, 'SOURCE FILE');
85 file_put_contents($targetFilePath, 'TARGET FILE');
87 // make sure both files have the same modification time
88 $modificationTime = time() - 1000;
89 touch($sourceFilePath, $modificationTime);
90 touch($targetFilePath, $modificationTime);
92 $this->filesystem->copy($sourceFilePath, $targetFilePath);
94 $this->assertFileExists($targetFilePath);
95 $this->assertEquals('TARGET FILE', file_get_contents($targetFilePath));
98 public function testCopyOverridesExistingFileIfForced()
100 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
101 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
103 file_put_contents($sourceFilePath, 'SOURCE FILE');
104 file_put_contents($targetFilePath, 'TARGET FILE');
106 // make sure both files have the same modification time
107 $modificationTime = time() - 1000;
108 touch($sourceFilePath, $modificationTime);
109 touch($targetFilePath, $modificationTime);
111 $this->filesystem->copy($sourceFilePath, $targetFilePath, true);
113 $this->assertFileExists($targetFilePath);
114 $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
118 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
120 public function testCopyWithOverrideWithReadOnlyTargetFails()
122 // skip test on Windows; PHP can't easily set file as unwritable on Windows
123 if ('\\' === DIRECTORY_SEPARATOR) {
124 $this->markTestSkipped('This test cannot run on Windows.');
127 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
128 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
130 file_put_contents($sourceFilePath, 'SOURCE FILE');
131 file_put_contents($targetFilePath, 'TARGET FILE');
133 // make sure both files have the same modification time
134 $modificationTime = time() - 1000;
135 touch($sourceFilePath, $modificationTime);
136 touch($targetFilePath, $modificationTime);
138 // make sure target is read-only
139 $this->filesystem->chmod($targetFilePath, 0444);
141 $this->filesystem->copy($sourceFilePath, $targetFilePath, true);
144 public function testCopyCreatesTargetDirectoryIfItDoesNotExist()
146 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
147 $targetFileDirectory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
148 $targetFilePath = $targetFileDirectory.DIRECTORY_SEPARATOR.'copy_target_file';
150 file_put_contents($sourceFilePath, 'SOURCE FILE');
152 $this->filesystem->copy($sourceFilePath, $targetFilePath);
154 $this->assertTrue(is_dir($targetFileDirectory));
155 $this->assertFileExists($targetFilePath);
156 $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
162 public function testCopyForOriginUrlsAndExistingLocalFileDefaultsToCopy()
164 $sourceFilePath = 'http://symfony.com/images/common/logo/logo_symfony_header.png';
165 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
167 file_put_contents($targetFilePath, 'TARGET FILE');
169 $this->filesystem->copy($sourceFilePath, $targetFilePath, false);
171 $this->assertFileExists($targetFilePath);
172 $this->assertEquals(file_get_contents($sourceFilePath), file_get_contents($targetFilePath));
175 public function testMkdirCreatesDirectoriesRecursively()
177 $directory = $this->workspace
178 .DIRECTORY_SEPARATOR.'directory'
179 .DIRECTORY_SEPARATOR.'sub_directory';
181 $this->filesystem->mkdir($directory);
183 $this->assertTrue(is_dir($directory));
186 public function testMkdirCreatesDirectoriesFromArray()
188 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
189 $directories = array(
190 $basePath.'1', $basePath.'2', $basePath.'3',
193 $this->filesystem->mkdir($directories);
195 $this->assertTrue(is_dir($basePath.'1'));
196 $this->assertTrue(is_dir($basePath.'2'));
197 $this->assertTrue(is_dir($basePath.'3'));
200 public function testMkdirCreatesDirectoriesFromTraversableObject()
202 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
203 $directories = new \ArrayObject(array(
204 $basePath.'1', $basePath.'2', $basePath.'3',
207 $this->filesystem->mkdir($directories);
209 $this->assertTrue(is_dir($basePath.'1'));
210 $this->assertTrue(is_dir($basePath.'2'));
211 $this->assertTrue(is_dir($basePath.'3'));
215 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
217 public function testMkdirCreatesDirectoriesFails()
219 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
220 $dir = $basePath.'2';
222 file_put_contents($dir, '');
224 $this->filesystem->mkdir($dir);
227 public function testTouchCreatesEmptyFile()
229 $file = $this->workspace.DIRECTORY_SEPARATOR.'1';
231 $this->filesystem->touch($file);
233 $this->assertFileExists($file);
237 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
239 public function testTouchFails()
241 $file = $this->workspace.DIRECTORY_SEPARATOR.'1'.DIRECTORY_SEPARATOR.'2';
243 $this->filesystem->touch($file);
246 public function testTouchCreatesEmptyFilesFromArray()
248 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
250 $basePath.'1', $basePath.'2', $basePath.'3',
253 $this->filesystem->touch($files);
255 $this->assertFileExists($basePath.'1');
256 $this->assertFileExists($basePath.'2');
257 $this->assertFileExists($basePath.'3');
260 public function testTouchCreatesEmptyFilesFromTraversableObject()
262 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
263 $files = new \ArrayObject(array(
264 $basePath.'1', $basePath.'2', $basePath.'3',
267 $this->filesystem->touch($files);
269 $this->assertFileExists($basePath.'1');
270 $this->assertFileExists($basePath.'2');
271 $this->assertFileExists($basePath.'3');
274 public function testRemoveCleansFilesAndDirectoriesIteratively()
276 $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
279 mkdir($basePath.'dir');
280 touch($basePath.'file');
282 $this->filesystem->remove($basePath);
284 $this->assertFileNotExists($basePath);
287 public function testRemoveCleansArrayOfFilesAndDirectories()
289 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
291 mkdir($basePath.'dir');
292 touch($basePath.'file');
295 $basePath.'dir', $basePath.'file',
298 $this->filesystem->remove($files);
300 $this->assertFileNotExists($basePath.'dir');
301 $this->assertFileNotExists($basePath.'file');
304 public function testRemoveCleansTraversableObjectOfFilesAndDirectories()
306 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
308 mkdir($basePath.'dir');
309 touch($basePath.'file');
311 $files = new \ArrayObject(array(
312 $basePath.'dir', $basePath.'file',
315 $this->filesystem->remove($files);
317 $this->assertFileNotExists($basePath.'dir');
318 $this->assertFileNotExists($basePath.'file');
321 public function testRemoveIgnoresNonExistingFiles()
323 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
325 mkdir($basePath.'dir');
328 $basePath.'dir', $basePath.'file',
331 $this->filesystem->remove($files);
333 $this->assertFileNotExists($basePath.'dir');
336 public function testRemoveCleansInvalidLinks()
338 $this->markAsSkippedIfSymlinkIsMissing();
340 $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
343 mkdir($basePath.'dir');
344 // create symlink to nonexistent file
345 @symlink($basePath.'file', $basePath.'file-link');
347 // create symlink to dir using trailing forward slash
348 $this->filesystem->symlink($basePath.'dir/', $basePath.'dir-link');
349 $this->assertTrue(is_dir($basePath.'dir-link'));
351 // create symlink to nonexistent dir
352 rmdir($basePath.'dir');
353 $this->assertFalse('\\' === DIRECTORY_SEPARATOR ? @readlink($basePath.'dir-link') : is_dir($basePath.'dir-link'));
355 $this->filesystem->remove($basePath);
357 $this->assertFileNotExists($basePath);
360 public function testFilesExists()
362 $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
365 touch($basePath.'file1');
366 mkdir($basePath.'folder');
368 $this->assertTrue($this->filesystem->exists($basePath.'file1'));
369 $this->assertTrue($this->filesystem->exists($basePath.'folder'));
373 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
375 public function testFilesExistsFails()
377 if ('\\' !== DIRECTORY_SEPARATOR) {
378 $this->markTestSkipped('Test covers edge case on Windows only.');
381 $basePath = $this->workspace.'\\directory\\';
386 $file = str_repeat('T', 259 - strlen($basePath));
387 $path = $basePath.$file;
388 exec('TYPE NUL >>'.$file); // equivalent of touch, we can not use the php touch() here because it suffers from the same limitation
389 $this->longPathNamesWindows[] = $path; // save this so we can clean up later
391 $this->filesystem->exists($path);
394 public function testFilesExistsTraversableObjectOfFilesAndDirectories()
396 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
398 mkdir($basePath.'dir');
399 touch($basePath.'file');
401 $files = new \ArrayObject(array(
402 $basePath.'dir', $basePath.'file',
405 $this->assertTrue($this->filesystem->exists($files));
408 public function testFilesNotExistsTraversableObjectOfFilesAndDirectories()
410 $basePath = $this->workspace.DIRECTORY_SEPARATOR;
412 mkdir($basePath.'dir');
413 touch($basePath.'file');
414 touch($basePath.'file2');
416 $files = new \ArrayObject(array(
417 $basePath.'dir', $basePath.'file', $basePath.'file2',
420 unlink($basePath.'file');
422 $this->assertFalse($this->filesystem->exists($files));
425 public function testInvalidFileNotExists()
427 $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
429 $this->assertFalse($this->filesystem->exists($basePath.time()));
432 public function testChmodChangesFileMode()
434 $this->markAsSkippedIfChmodIsMissing();
436 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
438 $file = $dir.DIRECTORY_SEPARATOR.'file';
441 $this->filesystem->chmod($file, 0400);
442 $this->filesystem->chmod($dir, 0753);
444 $this->assertFilePermissions(753, $dir);
445 $this->assertFilePermissions(400, $file);
448 public function testChmodWithWrongModLeavesPreviousPermissionsUntouched()
450 $this->markAsSkippedIfChmodIsMissing();
452 if (defined('HHVM_VERSION')) {
453 $this->markTestSkipped('chmod() changes permissions even when passing invalid modes on HHVM');
456 $dir = $this->workspace.DIRECTORY_SEPARATOR.'file';
459 $permissions = fileperms($dir);
461 $this->filesystem->chmod($dir, 'Wrongmode');
463 $this->assertSame($permissions, fileperms($dir));
466 public function testChmodRecursive()
468 $this->markAsSkippedIfChmodIsMissing();
470 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
472 $file = $dir.DIRECTORY_SEPARATOR.'file';
475 $this->filesystem->chmod($file, 0400, 0000, true);
476 $this->filesystem->chmod($dir, 0753, 0000, true);
478 $this->assertFilePermissions(753, $dir);
479 $this->assertFilePermissions(753, $file);
482 public function testChmodAppliesUmask()
484 $this->markAsSkippedIfChmodIsMissing();
486 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
489 $this->filesystem->chmod($file, 0770, 0022);
490 $this->assertFilePermissions(750, $file);
493 public function testChmodChangesModeOfArrayOfFiles()
495 $this->markAsSkippedIfChmodIsMissing();
497 $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
498 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
499 $files = array($directory, $file);
504 $this->filesystem->chmod($files, 0753);
506 $this->assertFilePermissions(753, $file);
507 $this->assertFilePermissions(753, $directory);
510 public function testChmodChangesModeOfTraversableFileObject()
512 $this->markAsSkippedIfChmodIsMissing();
514 $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
515 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
516 $files = new \ArrayObject(array($directory, $file));
521 $this->filesystem->chmod($files, 0753);
523 $this->assertFilePermissions(753, $file);
524 $this->assertFilePermissions(753, $directory);
527 public function testChmodChangesZeroModeOnSubdirectoriesOnRecursive()
529 $this->markAsSkippedIfChmodIsMissing();
531 $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
532 $subdirectory = $directory.DIRECTORY_SEPARATOR.'subdirectory';
535 mkdir($subdirectory);
536 chmod($subdirectory, 0000);
538 $this->filesystem->chmod($directory, 0753, 0000, true);
540 $this->assertFilePermissions(753, $subdirectory);
543 public function testChown()
545 $this->markAsSkippedIfPosixIsMissing();
547 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
550 $owner = $this->getFileOwner($dir);
551 $this->filesystem->chown($dir, $owner);
553 $this->assertSame($owner, $this->getFileOwner($dir));
556 public function testChownRecursive()
558 $this->markAsSkippedIfPosixIsMissing();
560 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
562 $file = $dir.DIRECTORY_SEPARATOR.'file';
565 $owner = $this->getFileOwner($dir);
566 $this->filesystem->chown($dir, $owner, true);
568 $this->assertSame($owner, $this->getFileOwner($file));
571 public function testChownSymlink()
573 $this->markAsSkippedIfSymlinkIsMissing();
575 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
576 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
580 $this->filesystem->symlink($file, $link);
582 $owner = $this->getFileOwner($link);
583 $this->filesystem->chown($link, $owner);
585 $this->assertSame($owner, $this->getFileOwner($link));
589 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
591 public function testChownSymlinkFails()
593 $this->markAsSkippedIfSymlinkIsMissing();
595 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
596 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
600 $this->filesystem->symlink($file, $link);
602 $this->filesystem->chown($link, 'user'.time().mt_rand(1000, 9999));
606 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
608 public function testChownFail()
610 $this->markAsSkippedIfPosixIsMissing();
612 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
615 $this->filesystem->chown($dir, 'user'.time().mt_rand(1000, 9999));
618 public function testChgrp()
620 $this->markAsSkippedIfPosixIsMissing();
622 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
625 $group = $this->getFileGroup($dir);
626 $this->filesystem->chgrp($dir, $group);
628 $this->assertSame($group, $this->getFileGroup($dir));
631 public function testChgrpRecursive()
633 $this->markAsSkippedIfPosixIsMissing();
635 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
637 $file = $dir.DIRECTORY_SEPARATOR.'file';
640 $group = $this->getFileGroup($dir);
641 $this->filesystem->chgrp($dir, $group, true);
643 $this->assertSame($group, $this->getFileGroup($file));
646 public function testChgrpSymlink()
648 $this->markAsSkippedIfSymlinkIsMissing();
650 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
651 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
655 $this->filesystem->symlink($file, $link);
657 $group = $this->getFileGroup($link);
658 $this->filesystem->chgrp($link, $group);
660 $this->assertSame($group, $this->getFileGroup($link));
664 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
666 public function testChgrpSymlinkFails()
668 $this->markAsSkippedIfSymlinkIsMissing();
670 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
671 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
675 $this->filesystem->symlink($file, $link);
677 $this->filesystem->chgrp($link, 'user'.time().mt_rand(1000, 9999));
681 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
683 public function testChgrpFail()
685 $this->markAsSkippedIfPosixIsMissing();
687 $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
690 $this->filesystem->chgrp($dir, 'user'.time().mt_rand(1000, 9999));
693 public function testRename()
695 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
696 $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
699 $this->filesystem->rename($file, $newPath);
701 $this->assertFileNotExists($file);
702 $this->assertFileExists($newPath);
706 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
708 public function testRenameThrowsExceptionIfTargetAlreadyExists()
710 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
711 $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
716 $this->filesystem->rename($file, $newPath);
719 public function testRenameOverwritesTheTargetIfItAlreadyExists()
721 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
722 $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
727 $this->filesystem->rename($file, $newPath, true);
729 $this->assertFileNotExists($file);
730 $this->assertFileExists($newPath);
734 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
736 public function testRenameThrowsExceptionOnError()
738 $file = $this->workspace.DIRECTORY_SEPARATOR.uniqid('fs_test_', true);
739 $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
741 $this->filesystem->rename($file, $newPath);
744 public function testSymlink()
746 if ('\\' === DIRECTORY_SEPARATOR) {
747 $this->markTestSkipped('Windows does not support creating "broken" symlinks');
750 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
751 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
753 // $file does not exists right now: creating "broken" links is a wanted feature
754 $this->filesystem->symlink($file, $link);
756 $this->assertTrue(is_link($link));
758 // Create the linked file AFTER creating the link
761 $this->assertEquals($file, readlink($link));
765 * @depends testSymlink
767 public function testRemoveSymlink()
769 $this->markAsSkippedIfSymlinkIsMissing();
771 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
773 $this->filesystem->remove($link);
775 $this->assertTrue(!is_link($link));
776 $this->assertTrue(!is_file($link));
777 $this->assertTrue(!is_dir($link));
780 public function testSymlinkIsOverwrittenIfPointsToDifferentTarget()
782 $this->markAsSkippedIfSymlinkIsMissing();
784 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
785 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
788 symlink($this->workspace, $link);
790 $this->filesystem->symlink($file, $link);
792 $this->assertTrue(is_link($link));
793 $this->assertEquals($file, readlink($link));
796 public function testSymlinkIsNotOverwrittenIfAlreadyCreated()
798 $this->markAsSkippedIfSymlinkIsMissing();
800 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
801 $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
804 symlink($file, $link);
806 $this->filesystem->symlink($file, $link);
808 $this->assertTrue(is_link($link));
809 $this->assertEquals($file, readlink($link));
812 public function testSymlinkCreatesTargetDirectoryIfItDoesNotExist()
814 $this->markAsSkippedIfSymlinkIsMissing();
816 $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
817 $link1 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'link';
818 $link2 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'subdir'.DIRECTORY_SEPARATOR.'link';
822 $this->filesystem->symlink($file, $link1);
823 $this->filesystem->symlink($file, $link2);
825 $this->assertTrue(is_link($link1));
826 $this->assertEquals($file, readlink($link1));
827 $this->assertTrue(is_link($link2));
828 $this->assertEquals($file, readlink($link2));
832 * @dataProvider providePathsForMakePathRelative
834 public function testMakePathRelative($endPath, $startPath, $expectedPath)
836 $path = $this->filesystem->makePathRelative($endPath, $startPath);
838 $this->assertEquals($expectedPath, $path);
844 public function providePathsForMakePathRelative()
847 array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component', '../'),
848 array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component/', '../'),
849 array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component', '../'),
850 array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component/', '../'),
851 array('var/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../'),
852 array('/usr/lib/symfony/', '/var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'),
853 array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/', 'src/Symfony/'),
854 array('/aa/bb', '/aa/bb', './'),
855 array('/aa/bb', '/aa/bb/', './'),
856 array('/aa/bb/', '/aa/bb', './'),
857 array('/aa/bb/', '/aa/bb/', './'),
858 array('/aa/bb/cc', '/aa/bb/cc/dd', '../'),
859 array('/aa/bb/cc', '/aa/bb/cc/dd/', '../'),
860 array('/aa/bb/cc/', '/aa/bb/cc/dd', '../'),
861 array('/aa/bb/cc/', '/aa/bb/cc/dd/', '../'),
862 array('/aa/bb/cc', '/aa', 'bb/cc/'),
863 array('/aa/bb/cc', '/aa/', 'bb/cc/'),
864 array('/aa/bb/cc/', '/aa', 'bb/cc/'),
865 array('/aa/bb/cc/', '/aa/', 'bb/cc/'),
866 array('/a/aab/bb', '/a/aa', '../aab/bb/'),
867 array('/a/aab/bb', '/a/aa/', '../aab/bb/'),
868 array('/a/aab/bb/', '/a/aa', '../aab/bb/'),
869 array('/a/aab/bb/', '/a/aa/', '../aab/bb/'),
870 array('/a/aab/bb/', '/', 'a/aab/bb/'),
871 array('/a/aab/bb/', '/b/aab', '../../a/aab/bb/'),
872 array('/aab/bb', '/aa', '../aab/bb/'),
873 array('/aab', '/aa', '../aab/'),
874 array('/aa/bb/cc', '/aa/dd/..', 'bb/cc/'),
875 array('/aa/../bb/cc', '/aa/dd/..', '../bb/cc/'),
876 array('/aa/bb/../../cc', '/aa/../dd/..', 'cc/'),
877 array('/../aa/bb/cc', '/aa/dd/..', 'bb/cc/'),
878 array('/../../aa/../bb/cc', '/aa/dd/..', '../bb/cc/'),
879 array('C:/aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'),
880 array('c:/aa/../bb/cc', 'c:/aa/dd/..', '../bb/cc/'),
881 array('C:/aa/bb/../../cc', 'C:/aa/../dd/..', 'cc/'),
882 array('C:/../aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'),
883 array('C:/../../aa/../bb/cc', 'C:/aa/dd/..', '../bb/cc/'),
886 if ('\\' === DIRECTORY_SEPARATOR) {
887 $paths[] = array('c:\var\lib/symfony/src/Symfony/', 'c:/var/lib/symfony/', 'src/Symfony/');
893 public function testMirrorCopiesFilesAndDirectoriesRecursively()
895 $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
896 $directory = $sourcePath.'directory'.DIRECTORY_SEPARATOR;
897 $file1 = $directory.'file1';
898 $file2 = $sourcePath.'file2';
902 file_put_contents($file1, 'FILE1');
903 file_put_contents($file2, 'FILE2');
905 $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
907 $this->filesystem->mirror($sourcePath, $targetPath);
909 $this->assertTrue(is_dir($targetPath));
910 $this->assertTrue(is_dir($targetPath.'directory'));
911 $this->assertFileEquals($file1, $targetPath.'directory'.DIRECTORY_SEPARATOR.'file1');
912 $this->assertFileEquals($file2, $targetPath.'file2');
914 $this->filesystem->remove($file1);
916 $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => false));
917 $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
919 $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
920 $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
922 file_put_contents($file1, 'FILE1');
924 $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
925 $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
927 $this->filesystem->remove($directory);
928 $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
929 $this->assertFalse($this->filesystem->exists($targetPath.'directory'));
930 $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
933 public function testMirrorCreatesEmptyDirectory()
935 $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
939 $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
941 $this->filesystem->mirror($sourcePath, $targetPath);
943 $this->assertTrue(is_dir($targetPath));
945 $this->filesystem->remove($sourcePath);
948 public function testMirrorCopiesLinks()
950 $this->markAsSkippedIfSymlinkIsMissing();
952 $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
955 file_put_contents($sourcePath.'file1', 'FILE1');
956 symlink($sourcePath.'file1', $sourcePath.'link1');
958 $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
960 $this->filesystem->mirror($sourcePath, $targetPath);
962 $this->assertTrue(is_dir($targetPath));
963 $this->assertFileEquals($sourcePath.'file1', $targetPath.'link1');
964 $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
967 public function testMirrorCopiesLinkedDirectoryContents()
969 $this->markAsSkippedIfSymlinkIsMissing(true);
971 $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
973 mkdir($sourcePath.'nested/', 0777, true);
974 file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1');
975 // Note: We symlink directory, not file
976 symlink($sourcePath.'nested', $sourcePath.'link1');
978 $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
980 $this->filesystem->mirror($sourcePath, $targetPath);
982 $this->assertTrue(is_dir($targetPath));
983 $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.'link1/file1.txt');
984 $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
987 public function testMirrorCopiesRelativeLinkedContents()
989 $this->markAsSkippedIfSymlinkIsMissing(true);
991 $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
994 mkdir($sourcePath.'nested/', 0777, true);
995 file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1');
996 // Note: Create relative symlink
998 symlink('nested', 'link1');
1002 $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
1004 $this->filesystem->mirror($sourcePath, $targetPath);
1006 $this->assertTrue(is_dir($targetPath));
1007 $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.'link1/file1.txt');
1008 $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
1009 $this->assertEquals('\\' === DIRECTORY_SEPARATOR ? realpath($sourcePath.'\nested') : 'nested', readlink($targetPath.DIRECTORY_SEPARATOR.'link1'));
1013 * @dataProvider providePathsForIsAbsolutePath
1015 public function testIsAbsolutePath($path, $expectedResult)
1017 $result = $this->filesystem->isAbsolutePath($path);
1019 $this->assertEquals($expectedResult, $result);
1025 public function providePathsForIsAbsolutePath()
1028 array('/var/lib', true),
1029 array('c:\\\\var\\lib', true),
1030 array('\\var\\lib', true),
1031 array('var/lib', false),
1032 array('../var/lib', false),
1038 public function testTempnam()
1040 $dirname = $this->workspace;
1042 $filename = $this->filesystem->tempnam($dirname, 'foo');
1044 $this->assertFileExists($filename);
1047 public function testTempnamWithFileScheme()
1049 $scheme = 'file://';
1050 $dirname = $scheme.$this->workspace;
1052 $filename = $this->filesystem->tempnam($dirname, 'foo');
1054 $this->assertStringStartsWith($scheme, $filename);
1055 $this->assertFileExists($filename);
1058 public function testTempnamWithMockScheme()
1060 stream_wrapper_register('mock', 'Symfony\Component\Filesystem\Tests\Fixtures\MockStream\MockStream');
1062 $scheme = 'mock://';
1063 $dirname = $scheme.$this->workspace;
1065 $filename = $this->filesystem->tempnam($dirname, 'foo');
1067 $this->assertStringStartsWith($scheme, $filename);
1068 $this->assertFileExists($filename);
1072 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
1074 public function testTempnamWithZlibSchemeFails()
1076 $scheme = 'compress.zlib://';
1077 $dirname = $scheme.$this->workspace;
1079 // The compress.zlib:// stream does not support mode x: creates the file, errors "failed to open stream: operation failed" and returns false
1080 $this->filesystem->tempnam($dirname, 'bar');
1083 public function testTempnamWithPHPTempSchemeFails()
1085 $scheme = 'php://temp';
1088 $filename = $this->filesystem->tempnam($dirname, 'bar');
1090 $this->assertStringStartsWith($scheme, $filename);
1092 // The php://temp stream deletes the file after close
1093 $this->assertFileNotExists($filename);
1097 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
1099 public function testTempnamWithPharSchemeFails()
1101 // Skip test if Phar disabled phar.readonly must be 0 in php.ini
1102 if (!\Phar::canWrite()) {
1103 $this->markTestSkipped('This test cannot run when phar.readonly is 1.');
1106 $scheme = 'phar://';
1107 $dirname = $scheme.$this->workspace;
1108 $pharname = 'foo.phar';
1110 new \Phar($this->workspace.'/'.$pharname, 0, $pharname);
1111 // The phar:// stream does not support mode x: fails to create file, errors "failed to open stream: phar error: "$filename" is not a file in phar "$pharname"" and returns false
1112 $this->filesystem->tempnam($dirname, $pharname.'/bar');
1116 * @expectedException \Symfony\Component\Filesystem\Exception\IOException
1118 public function testTempnamWithHTTPSchemeFails()
1120 $scheme = 'http://';
1121 $dirname = $scheme.$this->workspace;
1123 // The http:// scheme is read-only
1124 $this->filesystem->tempnam($dirname, 'bar');
1127 public function testTempnamOnUnwritableFallsBackToSysTmp()
1129 $scheme = 'file://';
1130 $dirname = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'does_not_exist';
1132 $filename = $this->filesystem->tempnam($dirname, 'bar');
1133 $realTempDir = realpath(sys_get_temp_dir());
1134 $this->assertStringStartsWith(rtrim($scheme.$realTempDir, DIRECTORY_SEPARATOR), $filename);
1135 $this->assertFileExists($filename);
1141 public function testDumpFile()
1143 $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
1145 $this->filesystem->dumpFile($filename, 'bar');
1147 $this->assertFileExists($filename);
1148 $this->assertSame('bar', file_get_contents($filename));
1154 public function testDumpFileAndSetPermissions()
1156 $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
1158 $this->filesystem->dumpFile($filename, 'bar', 0753);
1160 $this->assertFileExists($filename);
1161 $this->assertSame('bar', file_get_contents($filename));
1163 // skip mode check on Windows
1164 if ('\\' !== DIRECTORY_SEPARATOR) {
1165 $this->assertFilePermissions(753, $filename);
1169 public function testDumpFileWithNullMode()
1171 $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
1173 $this->filesystem->dumpFile($filename, 'bar', null);
1175 $this->assertFileExists($filename);
1176 $this->assertSame('bar', file_get_contents($filename));
1178 // skip mode check on Windows
1179 if ('\\' !== DIRECTORY_SEPARATOR) {
1180 $this->assertFilePermissions(600, $filename);
1184 public function testDumpFileOverwritesAnExistingFile()
1186 $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo.txt';
1187 file_put_contents($filename, 'FOO BAR');
1189 $this->filesystem->dumpFile($filename, 'bar');
1191 $this->assertFileExists($filename);
1192 $this->assertSame('bar', file_get_contents($filename));
1195 public function testDumpFileWithFileScheme()
1197 if (defined('HHVM_VERSION')) {
1198 $this->markTestSkipped('HHVM does not handle the file:// scheme correctly');
1201 $scheme = 'file://';
1202 $filename = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
1204 $this->filesystem->dumpFile($filename, 'bar', null);
1206 $this->assertFileExists($filename);
1207 $this->assertSame('bar', file_get_contents($filename));
1210 public function testDumpFileWithZlibScheme()
1212 $scheme = 'compress.zlib://';
1213 $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
1215 $this->filesystem->dumpFile($filename, 'bar', null);
1217 // Zlib stat uses file:// wrapper so remove scheme
1218 $this->assertFileExists(str_replace($scheme, '', $filename));
1219 $this->assertSame('bar', file_get_contents($filename));
1222 public function testDumpKeepsExistingPermissionsWhenOverwritingAnExistingFile()
1224 $this->markAsSkippedIfChmodIsMissing();
1226 $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo.txt';
1227 file_put_contents($filename, 'FOO BAR');
1228 chmod($filename, 0745);
1230 $this->filesystem->dumpFile($filename, 'bar', null);
1232 $this->assertFilePermissions(745, $filename);
1235 public function testCopyShouldKeepExecutionPermission()
1237 $this->markAsSkippedIfChmodIsMissing();
1239 $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
1240 $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
1242 file_put_contents($sourceFilePath, 'SOURCE FILE');
1243 chmod($sourceFilePath, 0745);
1245 $this->filesystem->copy($sourceFilePath, $targetFilePath);
1247 $this->assertFilePermissions(767, $targetFilePath);