X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FFile%2FPath.t;h=3ecd8f646dbe1cd1e8e98c7667f07627b75cc098;hb=e63b33793c3cf76a134a6446d1f83479e030a15f;hp=1a5f326d2c15aefec3bf853e3b18134254233cdb;hpb=0b3d36bd61fec90809936fcf1a90441d970d875e;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/File/Path.t b/lib/File/Path.t index 1a5f326..3ecd8f6 100755 --- a/lib/File/Path.t +++ b/lib/File/Path.t @@ -2,16 +2,20 @@ use strict; -use Test::More tests => 93; +use Test::More tests => 120; +use Config; BEGIN { - use_ok('File::Path'); + use_ok('Cwd'); + use_ok('File::Path', qw(rmtree mkpath make_path remove_tree)); use_ok('File::Spec::Functions'); } eval "use Test::Output"; my $has_Test_Output = $@ ? 0 : 1; +my $Is_VMS = $^O eq 'VMS'; + # first check for stupid permissions second for full, so we clean up # behind ourselves for my $perm (0111,0777) { @@ -43,7 +47,7 @@ my @dir = ( ); # create them -my @created = mkpath(@dir); +my @created = mkpath([@dir]); is(scalar(@created), 7, "created list of directories"); @@ -52,24 +56,123 @@ is(scalar(@created), 7, "created list of directories"); is(scalar(@created), 0, "skipped making existing directory") or diag("unexpectedly recreated @created"); +# create a file +my $file_name = catfile( $tmp_base, 'a', 'delete.me' ); +my $file_count = 0; +if (open OUT, "> $file_name") { + print OUT "this file may be deleted\n"; + close OUT; + ++$file_count; +} +else { + diag( "Failed to create file $file_name: $!" ); +} + +SKIP: { + skip "cannot remove a file we failed to create", 1 + unless $file_count == 1; + my $count = rmtree($file_name); + is($count, 1, "rmtree'ed a file"); +} + @created = mkpath(''); is(scalar(@created), 0, "Can't create a directory named ''"); my $dir; my $dir2; +sub gisle { + # background info: @_ = 1; !shift # gives '' not 0 + # Message-Id: <3C820CE6-4400-4E91-AF43-A3D19B356E68@activestate.com> + # http://www.nntp.perl.org/group/perl.perl5.porters/2008/05/msg136625.html + mkpath(shift, !shift, 0755); +} + +sub count { + opendir D, shift or return -1; + my $count = () = readdir D; + closedir D or return -1; + return $count; +} + +{ + mkdir 'solo', 0755; + chdir 'solo'; + open my $f, '>', 'foo.dat'; + close $f; + my $before = count(curdir()); + cmp_ok($before, '>', 0, "baseline $before"); + + gisle('1st', 1); + is(count(curdir()), $before + 1, "first after $before"); + + $before = count(curdir()); + gisle('2nd', 1); + is(count(curdir()), $before + 1, "second after $before"); + + chdir updir(); + rmtree 'solo'; +} + +{ + mkdir 'solo', 0755; + chdir 'solo'; + open my $f, '>', 'foo.dat'; + close $f; + my $before = count(curdir()); + cmp_ok($before, '>', 0, "ARGV $before"); + { + local @ARGV = (1); + mkpath('3rd', !shift, 0755); + } + is(count(curdir()), $before + 1, "third after $before"); + + $before = count(curdir()); + { + local @ARGV = (1); + mkpath('4th', !shift, 0755); + } + is(count(curdir()), $before + 1, "fourth after $before"); + + chdir updir(); + rmtree 'solo'; +} + SKIP: { - $dir = catdir($tmp_base, 'B'); - $dir2 = catdir($dir, updir()); - # IOW: File::Spec->catdir( qw(foo bar), File::Spec->updir ) eq 'foo' - # rather than foo/bar/.. - skip "updir() canonicalises path on this platform", 2 - if $dir2 eq $tmp_base - or $^O eq 'cygwin'; - - @created = mkpath($dir2, {mask => 0700}); - is(scalar(@created), 1, "make directory with trailing parent segment"); - is($created[0], $dir, "made parent"); + # tests for rmtree() of ancestor directory + my $nr_tests = 6; + my $cwd = getcwd() or skip "failed to getcwd: $!", $nr_tests; + my $dir = catdir($cwd, 'remove'); + my $dir2 = catdir($cwd, 'remove', 'this', 'dir'); + + skip "failed to mkpath '$dir2': $!", $nr_tests + unless mkpath($dir2, {verbose => 0}); + skip "failed to chdir dir '$dir2': $!", $nr_tests + unless chdir($dir2); + + rmtree($dir, {error => \$error}); + my $nr_err = @$error; + is($nr_err, 1, "ancestor error"); + + if ($nr_err) { + my ($file, $message) = each %{$error->[0]}; + is($file, $dir, "ancestor named"); + my $ortho_dir = $^O eq 'MSWin32' ? File::Path::_slash_lc($dir2) : $dir2; + $^O eq 'MSWin32' and $message + =~ s/\A(cannot remove path when cwd is )(.*)\Z/$1 . File::Path::_slash_lc($2)/e; + is($message, "cannot remove path when cwd is $ortho_dir", "ancestor reason"); + ok(-d $dir2, "child not removed"); + ok(-d $dir, "ancestor not removed"); + } + else { + fail( "ancestor 1"); + fail( "ancestor 2"); + fail( "ancestor 3"); + fail( "ancestor 4"); + } + chdir $cwd; + rmtree($dir); + ok(!(-d $dir), "ancestor now removed"); }; my $count = rmtree({error => \$error}); @@ -82,8 +185,8 @@ is(scalar(@created), 0, "skipped making existing directories (old style 1)") $dir = catdir($tmp_base,'C'); # mkpath returns unix syntax filespecs on VMS -$dir = VMS::Filespec::unixify($dir) if $^O eq 'VMS'; -@created = mkpath($tmp_base, $dir); +$dir = VMS::Filespec::unixify($dir) if $Is_VMS; +@created = make_path($tmp_base, $dir); is(scalar(@created), 1, "created directory (new style 1)"); is($created[0], $dir, "created directory (new style 1) cross-check"); @@ -93,16 +196,17 @@ is(scalar(@created), 0, "skipped making existing directories (old style 2)") $dir2 = catdir($tmp_base,'D'); # mkpath returns unix syntax filespecs on VMS -$dir2 = VMS::Filespec::unixify($dir2) if $^O eq 'VMS'; -@created = mkpath($tmp_base, $dir, $dir2); +$dir2 = VMS::Filespec::unixify($dir2) if $Is_VMS; +@created = make_path($tmp_base, $dir, $dir2); is(scalar(@created), 1, "created directory (new style 2)"); is($created[0], $dir2, "created directory (new style 2) cross-check"); $count = rmtree($dir, 0); -is($count, 1, "removed directory (old style 1)"); +is($count, 1, "removed directory unsafe mode"); $count = rmtree($dir2, 0, 1); -is($count, 1, "removed directory (old style 2)"); +my $removed = $Is_VMS ? 0 : 1; +is($count, $removed, "removed directory safe mode"); # mkdir foo ./E/../Y # Y should exist @@ -113,7 +217,7 @@ cmp_ok(scalar(@created), '>=', 1, "made one or more dirs because of .."); cmp_ok(scalar(@created), '<=', 2, "made less than two dirs because of .."); ok( -d catdir($tmp_base, 'Y'), "directory after parent" ); -@created = mkpath(catdir(curdir(), $tmp_base)); +@created = make_path(catdir(curdir(), $tmp_base)); is(scalar(@created), 0, "nothing created") or diag(@created); @@ -137,7 +241,7 @@ ok(-d $dir2, "dir z still exists"); $dir = catdir($tmp_base,'F'); # mkpath returns unix syntax filespecs on VMS -$dir = VMS::Filespec::unixify($dir) if $^O eq 'VMS'; +$dir = VMS::Filespec::unixify($dir) if $Is_VMS; @created = mkpath($dir, undef, 0770); is(scalar(@created), 1, "created directory (old style 2 verbose undef)"); @@ -155,7 +259,7 @@ is($created[0], $dir, "created directory (old style 3 mode undef) cross-check"); is(rmtree($dir, 0, undef), 1, "removed directory 3 verbose undef"); $dir = catdir($tmp_base,'G'); -$dir = VMS::Filespec::unixify($dir) if $^O eq 'VMS'; +$dir = VMS::Filespec::unixify($dir) if $Is_VMS; @created = mkpath($dir, undef, 0200); is(scalar(@created), 1, "created write-only dir"); @@ -173,22 +277,22 @@ else { $dir = catdir('a', 'd1'); $dir2 = catdir('a', 'd2'); -@created = mkpath( $dir, 0, $dir2 ); +@created = make_path( $dir, 0, $dir2 ); is(scalar @created, 3, 'new-style 3 dirs created'); -$count = rmtree( $dir, 0, $dir2, ); +$count = remove_tree( $dir, 0, $dir2, ); is($count, 3, 'new-style 3 dirs removed'); -@created = mkpath( $dir, $dir2, 1 ); +@created = make_path( $dir, $dir2, 1 ); is(scalar @created, 3, 'new-style 3 dirs created (redux)'); -$count = rmtree( $dir, $dir2, 1 ); +$count = remove_tree( $dir, $dir2, 1 ); is($count, 3, 'new-style 3 dirs removed (redux)'); -@created = mkpath( $dir, $dir2 ); +@created = make_path( $dir, $dir2 ); is(scalar @created, 2, 'new-style 2 dirs created'); -$count = rmtree( $dir, $dir2 ); +$count = remove_tree( $dir, $dir2 ); is($count, 2, 'new-style 2 dirs removed'); if (chdir updir()) { @@ -198,6 +302,43 @@ else { fail("chdir parent: $!"); } +SKIP: { + # test bug http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=487319 + skip "Don't need Force_Writeable semantics on $^O", 4 + if grep {$^O eq $_} qw(amigaos dos epoc MSWin32 MacOS os2); + skip "Symlinks not available", 4 unless $Config{'d_symlink'}; + $dir = 'bug487319'; + $dir2 = 'bug487319-symlink'; + @created = make_path($dir, {mask => 0700}); + is(scalar @created, 1, 'bug 487319 setup'); + symlink($dir, $dir2); + ok(-e $dir2, "debian bug 487319 setup symlink") or diag($dir2); + + chmod 0500, $dir; + my $mask_initial = (stat $dir)[2]; + remove_tree($dir2); + + my $mask = (stat $dir)[2]; + is( $mask, $mask_initial, 'mask of symlink target dir unchanged (debian bug 487319)'); + + # now try a file + my $file = catfile($dir, 'file'); + open my $out, '>', $file; + close $out; + + chmod 0500, $file; + $mask_initial = (stat $file)[2]; + + my $file2 = catfile($dir, 'symlink'); + symlink($file, $file2); + remove_tree($file2); + + $mask = (stat $file)[2]; + is( $mask, $mask_initial, 'mask of symlink target file unchanged (debian bug 487319)'); + + remove_tree($dir); +} + # see what happens if a file exists where we want a directory SKIP: { my $entry = catdir($tmp_base, "file"); @@ -221,8 +362,9 @@ SKIP: { my $extra = catdir(curdir(), qw(EXTRA 1 a)); SKIP: { - skip "extra scenarios not set up, see eg/setup-extra-tests", 9 + skip "extra scenarios not set up, see eg/setup-extra-tests", 14 unless -e $extra; + skip "Symlinks not available", 14 unless $Config{'d_symlink'}; my ($list, $err); $dir = catdir( 'EXTRA', '1' ); @@ -238,17 +380,30 @@ SKIP: { $dir = catdir('EXTRA', '3', 'S'); rmtree($dir, {error => \$error}); is( scalar(@$error), 1, 'one error for an unreadable dir' ); + eval { ($file, $message) = each %{$error->[0]}}; + is( $file, $dir, 'unreadable dir reported in error' ) + or diag($message); $dir = catdir('EXTRA', '3', 'T'); rmtree($dir, {error => \$error}); - is( scalar(@$error), 1, 'one error for an unreadable dir' ); + is( scalar(@$error), 1, 'one error for an unreadable dir T' ); + eval { ($file, $message) = each %{$error->[0]}}; + is( $file, $dir, 'unreadable dir reported in error T' ); $dir = catdir( 'EXTRA', '4' ); rmtree($dir, {result => \$list, error => \$err} ); - is( @$list, 0, q{don't follow a symlinked dir} ); - is( @$err, 2, q{two errors when removing a symlink in r/o dir} ); + is( scalar(@$list), 0, q{don't follow a symlinked dir} ); + is( scalar(@$err), 2, q{two errors when removing a symlink in r/o dir} ); eval { ($file, $message) = each %{$err->[0]} }; is( $file, $dir, 'symlink reported in error' ); + + $dir = catdir('EXTRA', '3', 'U'); + $dir2 = catdir('EXTRA', '3', 'V'); + rmtree($dir, $dir2, {verbose => 0, error => \$err, result => \$list}); + is( scalar(@$list), 1, q{deleted 1 out of 2 directories} ); + is( scalar(@$error), 1, q{left behind 1 out of 2 directories} ); + eval { ($file, $message) = each %{$err->[0]} }; + is( $file, $dir, 'first dir reported in error' ); } { @@ -320,8 +475,8 @@ cannot restore permissions to \d+ for [^:]+: .* at \1 line \2}, "rmtree of empty dir carps sensibly" ); - stderr_is( sub { mkpath() }, '', "mkpath no args does not carp" ); - stderr_is( sub { rmtree() }, '', "rmtree no args does not carp" ); + stderr_is( sub { make_path() }, '', "make_path no args does not carp" ); + stderr_is( sub { remove_tree() }, '', "remove_tree no args does not carp" ); stdout_is( sub {@created = mkpath($dir, 1)}, @@ -391,6 +546,27 @@ SKIP: { } } -rmtree($tmp_base, {result => \$list} ); -is(ref($list), 'ARRAY', "received a final list of results"); -ok( !(-d $tmp_base), "test base directory gone" ); +SKIP: { + my $nr_tests = 6; + my $cwd = getcwd() or skip "failed to getcwd: $!", $nr_tests; + rmtree($tmp_base, {result => \$list} ); + is(ref($list), 'ARRAY', "received a final list of results"); + ok( !(-d $tmp_base), "test base directory gone" ); + + my $p = getcwd(); + my $x = "x$$"; + my $xx = $x . "x"; + + # setup + ok(mkpath($xx)); + ok(chdir($xx)); + END { + ok(chdir($p)); + ok(rmtree($xx)); + } + + # create and delete directory + my $px = catdir($p, $x); + ok(mkpath($px)); + ok(rmtree($px), "rmtree"); # fails in File-Path-2.07 +}