Yaffs site version 1.1
[yaffs-website] / vendor / symfony / filesystem / Tests / FilesystemTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\Filesystem\Tests;
13
14 /**
15  * Test class for Filesystem.
16  */
17 class FilesystemTest extends FilesystemTestCase
18 {
19     public function testCopyCreatesNewFile()
20     {
21         $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
22         $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
23
24         file_put_contents($sourceFilePath, 'SOURCE FILE');
25
26         $this->filesystem->copy($sourceFilePath, $targetFilePath);
27
28         $this->assertFileExists($targetFilePath);
29         $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
30     }
31
32     /**
33      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
34      */
35     public function testCopyFails()
36     {
37         $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
38         $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
39
40         $this->filesystem->copy($sourceFilePath, $targetFilePath);
41     }
42
43     /**
44      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
45      */
46     public function testCopyUnreadableFileFails()
47     {
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.');
51         }
52
53         $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
54         $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
55
56         file_put_contents($sourceFilePath, 'SOURCE FILE');
57
58         // make sure target cannot be read
59         $this->filesystem->chmod($sourceFilePath, 0222);
60
61         $this->filesystem->copy($sourceFilePath, $targetFilePath);
62     }
63
64     public function testCopyOverridesExistingFileIfModified()
65     {
66         $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
67         $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
68
69         file_put_contents($sourceFilePath, 'SOURCE FILE');
70         file_put_contents($targetFilePath, 'TARGET FILE');
71         touch($targetFilePath, time() - 1000);
72
73         $this->filesystem->copy($sourceFilePath, $targetFilePath);
74
75         $this->assertFileExists($targetFilePath);
76         $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
77     }
78
79     public function testCopyDoesNotOverrideExistingFileByDefault()
80     {
81         $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
82         $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
83
84         file_put_contents($sourceFilePath, 'SOURCE FILE');
85         file_put_contents($targetFilePath, 'TARGET FILE');
86
87         // make sure both files have the same modification time
88         $modificationTime = time() - 1000;
89         touch($sourceFilePath, $modificationTime);
90         touch($targetFilePath, $modificationTime);
91
92         $this->filesystem->copy($sourceFilePath, $targetFilePath);
93
94         $this->assertFileExists($targetFilePath);
95         $this->assertEquals('TARGET FILE', file_get_contents($targetFilePath));
96     }
97
98     public function testCopyOverridesExistingFileIfForced()
99     {
100         $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
101         $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
102
103         file_put_contents($sourceFilePath, 'SOURCE FILE');
104         file_put_contents($targetFilePath, 'TARGET FILE');
105
106         // make sure both files have the same modification time
107         $modificationTime = time() - 1000;
108         touch($sourceFilePath, $modificationTime);
109         touch($targetFilePath, $modificationTime);
110
111         $this->filesystem->copy($sourceFilePath, $targetFilePath, true);
112
113         $this->assertFileExists($targetFilePath);
114         $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
115     }
116
117     /**
118      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
119      */
120     public function testCopyWithOverrideWithReadOnlyTargetFails()
121     {
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.');
125         }
126
127         $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
128         $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
129
130         file_put_contents($sourceFilePath, 'SOURCE FILE');
131         file_put_contents($targetFilePath, 'TARGET FILE');
132
133         // make sure both files have the same modification time
134         $modificationTime = time() - 1000;
135         touch($sourceFilePath, $modificationTime);
136         touch($targetFilePath, $modificationTime);
137
138         // make sure target is read-only
139         $this->filesystem->chmod($targetFilePath, 0444);
140
141         $this->filesystem->copy($sourceFilePath, $targetFilePath, true);
142     }
143
144     public function testCopyCreatesTargetDirectoryIfItDoesNotExist()
145     {
146         $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
147         $targetFileDirectory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
148         $targetFilePath = $targetFileDirectory.DIRECTORY_SEPARATOR.'copy_target_file';
149
150         file_put_contents($sourceFilePath, 'SOURCE FILE');
151
152         $this->filesystem->copy($sourceFilePath, $targetFilePath);
153
154         $this->assertTrue(is_dir($targetFileDirectory));
155         $this->assertFileExists($targetFilePath);
156         $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
157     }
158
159     /**
160      * @group network
161      */
162     public function testCopyForOriginUrlsAndExistingLocalFileDefaultsToCopy()
163     {
164         $sourceFilePath = 'http://symfony.com/images/common/logo/logo_symfony_header.png';
165         $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
166
167         file_put_contents($targetFilePath, 'TARGET FILE');
168
169         $this->filesystem->copy($sourceFilePath, $targetFilePath, false);
170
171         $this->assertFileExists($targetFilePath);
172         $this->assertEquals(file_get_contents($sourceFilePath), file_get_contents($targetFilePath));
173     }
174
175     public function testMkdirCreatesDirectoriesRecursively()
176     {
177         $directory = $this->workspace
178             .DIRECTORY_SEPARATOR.'directory'
179             .DIRECTORY_SEPARATOR.'sub_directory';
180
181         $this->filesystem->mkdir($directory);
182
183         $this->assertTrue(is_dir($directory));
184     }
185
186     public function testMkdirCreatesDirectoriesFromArray()
187     {
188         $basePath = $this->workspace.DIRECTORY_SEPARATOR;
189         $directories = array(
190             $basePath.'1', $basePath.'2', $basePath.'3',
191         );
192
193         $this->filesystem->mkdir($directories);
194
195         $this->assertTrue(is_dir($basePath.'1'));
196         $this->assertTrue(is_dir($basePath.'2'));
197         $this->assertTrue(is_dir($basePath.'3'));
198     }
199
200     public function testMkdirCreatesDirectoriesFromTraversableObject()
201     {
202         $basePath = $this->workspace.DIRECTORY_SEPARATOR;
203         $directories = new \ArrayObject(array(
204             $basePath.'1', $basePath.'2', $basePath.'3',
205         ));
206
207         $this->filesystem->mkdir($directories);
208
209         $this->assertTrue(is_dir($basePath.'1'));
210         $this->assertTrue(is_dir($basePath.'2'));
211         $this->assertTrue(is_dir($basePath.'3'));
212     }
213
214     /**
215      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
216      */
217     public function testMkdirCreatesDirectoriesFails()
218     {
219         $basePath = $this->workspace.DIRECTORY_SEPARATOR;
220         $dir = $basePath.'2';
221
222         file_put_contents($dir, '');
223
224         $this->filesystem->mkdir($dir);
225     }
226
227     public function testTouchCreatesEmptyFile()
228     {
229         $file = $this->workspace.DIRECTORY_SEPARATOR.'1';
230
231         $this->filesystem->touch($file);
232
233         $this->assertFileExists($file);
234     }
235
236     /**
237      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
238      */
239     public function testTouchFails()
240     {
241         $file = $this->workspace.DIRECTORY_SEPARATOR.'1'.DIRECTORY_SEPARATOR.'2';
242
243         $this->filesystem->touch($file);
244     }
245
246     public function testTouchCreatesEmptyFilesFromArray()
247     {
248         $basePath = $this->workspace.DIRECTORY_SEPARATOR;
249         $files = array(
250             $basePath.'1', $basePath.'2', $basePath.'3',
251         );
252
253         $this->filesystem->touch($files);
254
255         $this->assertFileExists($basePath.'1');
256         $this->assertFileExists($basePath.'2');
257         $this->assertFileExists($basePath.'3');
258     }
259
260     public function testTouchCreatesEmptyFilesFromTraversableObject()
261     {
262         $basePath = $this->workspace.DIRECTORY_SEPARATOR;
263         $files = new \ArrayObject(array(
264             $basePath.'1', $basePath.'2', $basePath.'3',
265         ));
266
267         $this->filesystem->touch($files);
268
269         $this->assertFileExists($basePath.'1');
270         $this->assertFileExists($basePath.'2');
271         $this->assertFileExists($basePath.'3');
272     }
273
274     public function testRemoveCleansFilesAndDirectoriesIteratively()
275     {
276         $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
277
278         mkdir($basePath);
279         mkdir($basePath.'dir');
280         touch($basePath.'file');
281
282         $this->filesystem->remove($basePath);
283
284         $this->assertFileNotExists($basePath);
285     }
286
287     public function testRemoveCleansArrayOfFilesAndDirectories()
288     {
289         $basePath = $this->workspace.DIRECTORY_SEPARATOR;
290
291         mkdir($basePath.'dir');
292         touch($basePath.'file');
293
294         $files = array(
295             $basePath.'dir', $basePath.'file',
296         );
297
298         $this->filesystem->remove($files);
299
300         $this->assertFileNotExists($basePath.'dir');
301         $this->assertFileNotExists($basePath.'file');
302     }
303
304     public function testRemoveCleansTraversableObjectOfFilesAndDirectories()
305     {
306         $basePath = $this->workspace.DIRECTORY_SEPARATOR;
307
308         mkdir($basePath.'dir');
309         touch($basePath.'file');
310
311         $files = new \ArrayObject(array(
312             $basePath.'dir', $basePath.'file',
313         ));
314
315         $this->filesystem->remove($files);
316
317         $this->assertFileNotExists($basePath.'dir');
318         $this->assertFileNotExists($basePath.'file');
319     }
320
321     public function testRemoveIgnoresNonExistingFiles()
322     {
323         $basePath = $this->workspace.DIRECTORY_SEPARATOR;
324
325         mkdir($basePath.'dir');
326
327         $files = array(
328             $basePath.'dir', $basePath.'file',
329         );
330
331         $this->filesystem->remove($files);
332
333         $this->assertFileNotExists($basePath.'dir');
334     }
335
336     public function testRemoveCleansInvalidLinks()
337     {
338         $this->markAsSkippedIfSymlinkIsMissing();
339
340         $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
341
342         mkdir($basePath);
343         mkdir($basePath.'dir');
344         // create symlink to nonexistent file
345         @symlink($basePath.'file', $basePath.'file-link');
346
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'));
350
351         // create symlink to nonexistent dir
352         rmdir($basePath.'dir');
353         $this->assertFalse('\\' === DIRECTORY_SEPARATOR ? @readlink($basePath.'dir-link') : is_dir($basePath.'dir-link'));
354
355         $this->filesystem->remove($basePath);
356
357         $this->assertFileNotExists($basePath);
358     }
359
360     public function testFilesExists()
361     {
362         $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
363
364         mkdir($basePath);
365         touch($basePath.'file1');
366         mkdir($basePath.'folder');
367
368         $this->assertTrue($this->filesystem->exists($basePath.'file1'));
369         $this->assertTrue($this->filesystem->exists($basePath.'folder'));
370     }
371
372     /**
373      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
374      */
375     public function testFilesExistsFails()
376     {
377         if ('\\' !== DIRECTORY_SEPARATOR) {
378             $this->markTestSkipped('Test covers edge case on Windows only.');
379         }
380
381         $basePath = $this->workspace.'\\directory\\';
382
383         $oldPath = getcwd();
384         mkdir($basePath);
385         chdir($basePath);
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
390         chdir($oldPath);
391         $this->filesystem->exists($path);
392     }
393
394     public function testFilesExistsTraversableObjectOfFilesAndDirectories()
395     {
396         $basePath = $this->workspace.DIRECTORY_SEPARATOR;
397
398         mkdir($basePath.'dir');
399         touch($basePath.'file');
400
401         $files = new \ArrayObject(array(
402             $basePath.'dir', $basePath.'file',
403         ));
404
405         $this->assertTrue($this->filesystem->exists($files));
406     }
407
408     public function testFilesNotExistsTraversableObjectOfFilesAndDirectories()
409     {
410         $basePath = $this->workspace.DIRECTORY_SEPARATOR;
411
412         mkdir($basePath.'dir');
413         touch($basePath.'file');
414         touch($basePath.'file2');
415
416         $files = new \ArrayObject(array(
417             $basePath.'dir', $basePath.'file', $basePath.'file2',
418         ));
419
420         unlink($basePath.'file');
421
422         $this->assertFalse($this->filesystem->exists($files));
423     }
424
425     public function testInvalidFileNotExists()
426     {
427         $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
428
429         $this->assertFalse($this->filesystem->exists($basePath.time()));
430     }
431
432     public function testChmodChangesFileMode()
433     {
434         $this->markAsSkippedIfChmodIsMissing();
435
436         $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
437         mkdir($dir);
438         $file = $dir.DIRECTORY_SEPARATOR.'file';
439         touch($file);
440
441         $this->filesystem->chmod($file, 0400);
442         $this->filesystem->chmod($dir, 0753);
443
444         $this->assertFilePermissions(753, $dir);
445         $this->assertFilePermissions(400, $file);
446     }
447
448     public function testChmodWithWrongModLeavesPreviousPermissionsUntouched()
449     {
450         $this->markAsSkippedIfChmodIsMissing();
451
452         if (defined('HHVM_VERSION')) {
453             $this->markTestSkipped('chmod() changes permissions even when passing invalid modes on HHVM');
454         }
455
456         $dir = $this->workspace.DIRECTORY_SEPARATOR.'file';
457         touch($dir);
458
459         $permissions = fileperms($dir);
460
461         $this->filesystem->chmod($dir, 'Wrongmode');
462
463         $this->assertSame($permissions, fileperms($dir));
464     }
465
466     public function testChmodRecursive()
467     {
468         $this->markAsSkippedIfChmodIsMissing();
469
470         $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
471         mkdir($dir);
472         $file = $dir.DIRECTORY_SEPARATOR.'file';
473         touch($file);
474
475         $this->filesystem->chmod($file, 0400, 0000, true);
476         $this->filesystem->chmod($dir, 0753, 0000, true);
477
478         $this->assertFilePermissions(753, $dir);
479         $this->assertFilePermissions(753, $file);
480     }
481
482     public function testChmodAppliesUmask()
483     {
484         $this->markAsSkippedIfChmodIsMissing();
485
486         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
487         touch($file);
488
489         $this->filesystem->chmod($file, 0770, 0022);
490         $this->assertFilePermissions(750, $file);
491     }
492
493     public function testChmodChangesModeOfArrayOfFiles()
494     {
495         $this->markAsSkippedIfChmodIsMissing();
496
497         $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
498         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
499         $files = array($directory, $file);
500
501         mkdir($directory);
502         touch($file);
503
504         $this->filesystem->chmod($files, 0753);
505
506         $this->assertFilePermissions(753, $file);
507         $this->assertFilePermissions(753, $directory);
508     }
509
510     public function testChmodChangesModeOfTraversableFileObject()
511     {
512         $this->markAsSkippedIfChmodIsMissing();
513
514         $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
515         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
516         $files = new \ArrayObject(array($directory, $file));
517
518         mkdir($directory);
519         touch($file);
520
521         $this->filesystem->chmod($files, 0753);
522
523         $this->assertFilePermissions(753, $file);
524         $this->assertFilePermissions(753, $directory);
525     }
526
527     public function testChmodChangesZeroModeOnSubdirectoriesOnRecursive()
528     {
529         $this->markAsSkippedIfChmodIsMissing();
530
531         $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
532         $subdirectory = $directory.DIRECTORY_SEPARATOR.'subdirectory';
533
534         mkdir($directory);
535         mkdir($subdirectory);
536         chmod($subdirectory, 0000);
537
538         $this->filesystem->chmod($directory, 0753, 0000, true);
539
540         $this->assertFilePermissions(753, $subdirectory);
541     }
542
543     public function testChown()
544     {
545         $this->markAsSkippedIfPosixIsMissing();
546
547         $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
548         mkdir($dir);
549
550         $owner = $this->getFileOwner($dir);
551         $this->filesystem->chown($dir, $owner);
552
553         $this->assertSame($owner, $this->getFileOwner($dir));
554     }
555
556     public function testChownRecursive()
557     {
558         $this->markAsSkippedIfPosixIsMissing();
559
560         $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
561         mkdir($dir);
562         $file = $dir.DIRECTORY_SEPARATOR.'file';
563         touch($file);
564
565         $owner = $this->getFileOwner($dir);
566         $this->filesystem->chown($dir, $owner, true);
567
568         $this->assertSame($owner, $this->getFileOwner($file));
569     }
570
571     public function testChownSymlink()
572     {
573         $this->markAsSkippedIfSymlinkIsMissing();
574
575         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
576         $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
577
578         touch($file);
579
580         $this->filesystem->symlink($file, $link);
581
582         $owner = $this->getFileOwner($link);
583         $this->filesystem->chown($link, $owner);
584
585         $this->assertSame($owner, $this->getFileOwner($link));
586     }
587
588     /**
589      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
590      */
591     public function testChownSymlinkFails()
592     {
593         $this->markAsSkippedIfSymlinkIsMissing();
594
595         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
596         $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
597
598         touch($file);
599
600         $this->filesystem->symlink($file, $link);
601
602         $this->filesystem->chown($link, 'user'.time().mt_rand(1000, 9999));
603     }
604
605     /**
606      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
607      */
608     public function testChownFail()
609     {
610         $this->markAsSkippedIfPosixIsMissing();
611
612         $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
613         mkdir($dir);
614
615         $this->filesystem->chown($dir, 'user'.time().mt_rand(1000, 9999));
616     }
617
618     public function testChgrp()
619     {
620         $this->markAsSkippedIfPosixIsMissing();
621
622         $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
623         mkdir($dir);
624
625         $group = $this->getFileGroup($dir);
626         $this->filesystem->chgrp($dir, $group);
627
628         $this->assertSame($group, $this->getFileGroup($dir));
629     }
630
631     public function testChgrpRecursive()
632     {
633         $this->markAsSkippedIfPosixIsMissing();
634
635         $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
636         mkdir($dir);
637         $file = $dir.DIRECTORY_SEPARATOR.'file';
638         touch($file);
639
640         $group = $this->getFileGroup($dir);
641         $this->filesystem->chgrp($dir, $group, true);
642
643         $this->assertSame($group, $this->getFileGroup($file));
644     }
645
646     public function testChgrpSymlink()
647     {
648         $this->markAsSkippedIfSymlinkIsMissing();
649
650         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
651         $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
652
653         touch($file);
654
655         $this->filesystem->symlink($file, $link);
656
657         $group = $this->getFileGroup($link);
658         $this->filesystem->chgrp($link, $group);
659
660         $this->assertSame($group, $this->getFileGroup($link));
661     }
662
663     /**
664      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
665      */
666     public function testChgrpSymlinkFails()
667     {
668         $this->markAsSkippedIfSymlinkIsMissing();
669
670         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
671         $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
672
673         touch($file);
674
675         $this->filesystem->symlink($file, $link);
676
677         $this->filesystem->chgrp($link, 'user'.time().mt_rand(1000, 9999));
678     }
679
680     /**
681      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
682      */
683     public function testChgrpFail()
684     {
685         $this->markAsSkippedIfPosixIsMissing();
686
687         $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
688         mkdir($dir);
689
690         $this->filesystem->chgrp($dir, 'user'.time().mt_rand(1000, 9999));
691     }
692
693     public function testRename()
694     {
695         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
696         $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
697         touch($file);
698
699         $this->filesystem->rename($file, $newPath);
700
701         $this->assertFileNotExists($file);
702         $this->assertFileExists($newPath);
703     }
704
705     /**
706      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
707      */
708     public function testRenameThrowsExceptionIfTargetAlreadyExists()
709     {
710         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
711         $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
712
713         touch($file);
714         touch($newPath);
715
716         $this->filesystem->rename($file, $newPath);
717     }
718
719     public function testRenameOverwritesTheTargetIfItAlreadyExists()
720     {
721         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
722         $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
723
724         touch($file);
725         touch($newPath);
726
727         $this->filesystem->rename($file, $newPath, true);
728
729         $this->assertFileNotExists($file);
730         $this->assertFileExists($newPath);
731     }
732
733     /**
734      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
735      */
736     public function testRenameThrowsExceptionOnError()
737     {
738         $file = $this->workspace.DIRECTORY_SEPARATOR.uniqid('fs_test_', true);
739         $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
740
741         $this->filesystem->rename($file, $newPath);
742     }
743
744     public function testSymlink()
745     {
746         if ('\\' === DIRECTORY_SEPARATOR) {
747             $this->markTestSkipped('Windows does not support creating "broken" symlinks');
748         }
749
750         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
751         $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
752
753         // $file does not exists right now: creating "broken" links is a wanted feature
754         $this->filesystem->symlink($file, $link);
755
756         $this->assertTrue(is_link($link));
757
758         // Create the linked file AFTER creating the link
759         touch($file);
760
761         $this->assertEquals($file, readlink($link));
762     }
763
764     /**
765      * @depends testSymlink
766      */
767     public function testRemoveSymlink()
768     {
769         $this->markAsSkippedIfSymlinkIsMissing();
770
771         $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
772
773         $this->filesystem->remove($link);
774
775         $this->assertTrue(!is_link($link));
776         $this->assertTrue(!is_file($link));
777         $this->assertTrue(!is_dir($link));
778     }
779
780     public function testSymlinkIsOverwrittenIfPointsToDifferentTarget()
781     {
782         $this->markAsSkippedIfSymlinkIsMissing();
783
784         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
785         $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
786
787         touch($file);
788         symlink($this->workspace, $link);
789
790         $this->filesystem->symlink($file, $link);
791
792         $this->assertTrue(is_link($link));
793         $this->assertEquals($file, readlink($link));
794     }
795
796     public function testSymlinkIsNotOverwrittenIfAlreadyCreated()
797     {
798         $this->markAsSkippedIfSymlinkIsMissing();
799
800         $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
801         $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
802
803         touch($file);
804         symlink($file, $link);
805
806         $this->filesystem->symlink($file, $link);
807
808         $this->assertTrue(is_link($link));
809         $this->assertEquals($file, readlink($link));
810     }
811
812     public function testSymlinkCreatesTargetDirectoryIfItDoesNotExist()
813     {
814         $this->markAsSkippedIfSymlinkIsMissing();
815
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';
819
820         touch($file);
821
822         $this->filesystem->symlink($file, $link1);
823         $this->filesystem->symlink($file, $link2);
824
825         $this->assertTrue(is_link($link1));
826         $this->assertEquals($file, readlink($link1));
827         $this->assertTrue(is_link($link2));
828         $this->assertEquals($file, readlink($link2));
829     }
830
831     /**
832      * @dataProvider providePathsForMakePathRelative
833      */
834     public function testMakePathRelative($endPath, $startPath, $expectedPath)
835     {
836         $path = $this->filesystem->makePathRelative($endPath, $startPath);
837
838         $this->assertEquals($expectedPath, $path);
839     }
840
841     /**
842      * @return array
843      */
844     public function providePathsForMakePathRelative()
845     {
846         $paths = array(
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/'),
884         );
885
886         if ('\\' === DIRECTORY_SEPARATOR) {
887             $paths[] = array('c:\var\lib/symfony/src/Symfony/', 'c:/var/lib/symfony/', 'src/Symfony/');
888         }
889
890         return $paths;
891     }
892
893     public function testMirrorCopiesFilesAndDirectoriesRecursively()
894     {
895         $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
896         $directory = $sourcePath.'directory'.DIRECTORY_SEPARATOR;
897         $file1 = $directory.'file1';
898         $file2 = $sourcePath.'file2';
899
900         mkdir($sourcePath);
901         mkdir($directory);
902         file_put_contents($file1, 'FILE1');
903         file_put_contents($file2, 'FILE2');
904
905         $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
906
907         $this->filesystem->mirror($sourcePath, $targetPath);
908
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');
913
914         $this->filesystem->remove($file1);
915
916         $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => false));
917         $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
918
919         $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
920         $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
921
922         file_put_contents($file1, 'FILE1');
923
924         $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
925         $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
926
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'));
931     }
932
933     public function testMirrorCreatesEmptyDirectory()
934     {
935         $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
936
937         mkdir($sourcePath);
938
939         $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
940
941         $this->filesystem->mirror($sourcePath, $targetPath);
942
943         $this->assertTrue(is_dir($targetPath));
944
945         $this->filesystem->remove($sourcePath);
946     }
947
948     public function testMirrorCopiesLinks()
949     {
950         $this->markAsSkippedIfSymlinkIsMissing();
951
952         $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
953
954         mkdir($sourcePath);
955         file_put_contents($sourcePath.'file1', 'FILE1');
956         symlink($sourcePath.'file1', $sourcePath.'link1');
957
958         $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
959
960         $this->filesystem->mirror($sourcePath, $targetPath);
961
962         $this->assertTrue(is_dir($targetPath));
963         $this->assertFileEquals($sourcePath.'file1', $targetPath.'link1');
964         $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
965     }
966
967     public function testMirrorCopiesLinkedDirectoryContents()
968     {
969         $this->markAsSkippedIfSymlinkIsMissing(true);
970
971         $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
972
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');
977
978         $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
979
980         $this->filesystem->mirror($sourcePath, $targetPath);
981
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'));
985     }
986
987     public function testMirrorCopiesRelativeLinkedContents()
988     {
989         $this->markAsSkippedIfSymlinkIsMissing(true);
990
991         $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
992         $oldPath = getcwd();
993
994         mkdir($sourcePath.'nested/', 0777, true);
995         file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1');
996         // Note: Create relative symlink
997         chdir($sourcePath);
998         symlink('nested', 'link1');
999
1000         chdir($oldPath);
1001
1002         $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
1003
1004         $this->filesystem->mirror($sourcePath, $targetPath);
1005
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'));
1010     }
1011
1012     /**
1013      * @dataProvider providePathsForIsAbsolutePath
1014      */
1015     public function testIsAbsolutePath($path, $expectedResult)
1016     {
1017         $result = $this->filesystem->isAbsolutePath($path);
1018
1019         $this->assertEquals($expectedResult, $result);
1020     }
1021
1022     /**
1023      * @return array
1024      */
1025     public function providePathsForIsAbsolutePath()
1026     {
1027         return array(
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),
1033             array('', false),
1034             array(null, false),
1035         );
1036     }
1037
1038     public function testTempnam()
1039     {
1040         $dirname = $this->workspace;
1041
1042         $filename = $this->filesystem->tempnam($dirname, 'foo');
1043
1044         $this->assertFileExists($filename);
1045     }
1046
1047     public function testTempnamWithFileScheme()
1048     {
1049         $scheme = 'file://';
1050         $dirname = $scheme.$this->workspace;
1051
1052         $filename = $this->filesystem->tempnam($dirname, 'foo');
1053
1054         $this->assertStringStartsWith($scheme, $filename);
1055         $this->assertFileExists($filename);
1056     }
1057
1058     public function testTempnamWithMockScheme()
1059     {
1060         stream_wrapper_register('mock', 'Symfony\Component\Filesystem\Tests\Fixtures\MockStream\MockStream');
1061
1062         $scheme = 'mock://';
1063         $dirname = $scheme.$this->workspace;
1064
1065         $filename = $this->filesystem->tempnam($dirname, 'foo');
1066
1067         $this->assertStringStartsWith($scheme, $filename);
1068         $this->assertFileExists($filename);
1069     }
1070
1071     /**
1072      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
1073      */
1074     public function testTempnamWithZlibSchemeFails()
1075     {
1076         $scheme = 'compress.zlib://';
1077         $dirname = $scheme.$this->workspace;
1078
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');
1081     }
1082
1083     public function testTempnamWithPHPTempSchemeFails()
1084     {
1085         $scheme = 'php://temp';
1086         $dirname = $scheme;
1087
1088         $filename = $this->filesystem->tempnam($dirname, 'bar');
1089
1090         $this->assertStringStartsWith($scheme, $filename);
1091
1092         // The php://temp stream deletes the file after close
1093         $this->assertFileNotExists($filename);
1094     }
1095
1096     /**
1097      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
1098      */
1099     public function testTempnamWithPharSchemeFails()
1100     {
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.');
1104         }
1105
1106         $scheme = 'phar://';
1107         $dirname = $scheme.$this->workspace;
1108         $pharname = 'foo.phar';
1109
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');
1113     }
1114
1115     /**
1116      * @expectedException \Symfony\Component\Filesystem\Exception\IOException
1117      */
1118     public function testTempnamWithHTTPSchemeFails()
1119     {
1120         $scheme = 'http://';
1121         $dirname = $scheme.$this->workspace;
1122
1123         // The http:// scheme is read-only
1124         $this->filesystem->tempnam($dirname, 'bar');
1125     }
1126
1127     public function testTempnamOnUnwritableFallsBackToSysTmp()
1128     {
1129         $scheme = 'file://';
1130         $dirname = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'does_not_exist';
1131
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);
1136
1137         // Tear down
1138         @unlink($filename);
1139     }
1140
1141     public function testDumpFile()
1142     {
1143         $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
1144
1145         $this->filesystem->dumpFile($filename, 'bar');
1146
1147         $this->assertFileExists($filename);
1148         $this->assertSame('bar', file_get_contents($filename));
1149     }
1150
1151     /**
1152      * @group legacy
1153      */
1154     public function testDumpFileAndSetPermissions()
1155     {
1156         $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
1157
1158         $this->filesystem->dumpFile($filename, 'bar', 0753);
1159
1160         $this->assertFileExists($filename);
1161         $this->assertSame('bar', file_get_contents($filename));
1162
1163         // skip mode check on Windows
1164         if ('\\' !== DIRECTORY_SEPARATOR) {
1165             $this->assertFilePermissions(753, $filename);
1166         }
1167     }
1168
1169     public function testDumpFileWithNullMode()
1170     {
1171         $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
1172
1173         $this->filesystem->dumpFile($filename, 'bar', null);
1174
1175         $this->assertFileExists($filename);
1176         $this->assertSame('bar', file_get_contents($filename));
1177
1178         // skip mode check on Windows
1179         if ('\\' !== DIRECTORY_SEPARATOR) {
1180             $this->assertFilePermissions(600, $filename);
1181         }
1182     }
1183
1184     public function testDumpFileOverwritesAnExistingFile()
1185     {
1186         $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo.txt';
1187         file_put_contents($filename, 'FOO BAR');
1188
1189         $this->filesystem->dumpFile($filename, 'bar');
1190
1191         $this->assertFileExists($filename);
1192         $this->assertSame('bar', file_get_contents($filename));
1193     }
1194
1195     public function testDumpFileWithFileScheme()
1196     {
1197         if (defined('HHVM_VERSION')) {
1198             $this->markTestSkipped('HHVM does not handle the file:// scheme correctly');
1199         }
1200
1201         $scheme = 'file://';
1202         $filename = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
1203
1204         $this->filesystem->dumpFile($filename, 'bar', null);
1205
1206         $this->assertFileExists($filename);
1207         $this->assertSame('bar', file_get_contents($filename));
1208     }
1209
1210     public function testDumpFileWithZlibScheme()
1211     {
1212         $scheme = 'compress.zlib://';
1213         $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
1214
1215         $this->filesystem->dumpFile($filename, 'bar', null);
1216
1217         // Zlib stat uses file:// wrapper so remove scheme
1218         $this->assertFileExists(str_replace($scheme, '', $filename));
1219         $this->assertSame('bar', file_get_contents($filename));
1220     }
1221
1222     public function testDumpKeepsExistingPermissionsWhenOverwritingAnExistingFile()
1223     {
1224         $this->markAsSkippedIfChmodIsMissing();
1225
1226         $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo.txt';
1227         file_put_contents($filename, 'FOO BAR');
1228         chmod($filename, 0745);
1229
1230         $this->filesystem->dumpFile($filename, 'bar', null);
1231
1232         $this->assertFilePermissions(745, $filename);
1233     }
1234
1235     public function testCopyShouldKeepExecutionPermission()
1236     {
1237         $this->markAsSkippedIfChmodIsMissing();
1238
1239         $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
1240         $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
1241
1242         file_put_contents($sourceFilePath, 'SOURCE FILE');
1243         chmod($sourceFilePath, 0745);
1244
1245         $this->filesystem->copy($sourceFilePath, $targetFilePath);
1246
1247         $this->assertFilePermissions(767, $targetFilePath);
1248     }
1249 }