1#! /usr/bin/env perl 2# Path.t -- tests for module File::Path 3 4use strict; 5 6use Test::More tests => 167; 7use Config; 8use Fcntl ':mode'; 9use lib './t'; 10use FilePathTest qw( 11 _run_for_warning 12 _run_for_verbose 13 _cannot_delete_safe_mode 14 _verbose_expected 15 create_3_level_subdirs 16 cleanup_3_level_subdirs 17); 18use Errno qw(:POSIX); 19use Carp; 20 21BEGIN { 22 use_ok('Cwd'); 23 use_ok('File::Path', qw(rmtree mkpath make_path remove_tree)); 24 use_ok('File::Spec::Functions'); 25} 26 27my $Is_VMS = $^O eq 'VMS'; 28 29my $fchmod_supported = 0; 30if (open my $fh, curdir()) { 31 my ($perm) = (stat($fh))[2]; 32 $perm &= 07777; 33 eval { $fchmod_supported = chmod( $perm, $fh); }; 34} 35 36# first check for stupid permissions second for full, so we clean up 37# behind ourselves 38for my $perm (0111,0777) { 39 my $path = catdir(curdir(), "mhx", "bar"); 40 mkpath($path); 41 chmod $perm, "mhx", $path; 42 43 my $oct = sprintf('0%o', $perm); 44 45 ok(-d "mhx", "mkdir parent dir $oct"); 46 ok(-d $path, "mkdir child dir $oct"); 47 48 rmtree("mhx"); 49 50 ok(! -e "mhx", "mhx does not exist $oct"); 51} 52 53# find a place to work 54my ($error, $list, $file, $message); 55my $tmp_base = catdir( 56 curdir(), 57 sprintf( 'test-%x-%x-%x', time, $$, rand(99999) ), 58); 59 60# invent some names 61my @dir = ( 62 catdir($tmp_base, qw(a b)), 63 catdir($tmp_base, qw(a c)), 64 catdir($tmp_base, qw(z b)), 65 catdir($tmp_base, qw(z c)), 66); 67 68# create them 69my @created = mkpath([@dir]); 70 71is(scalar(@created), 7, "created list of directories"); 72 73# pray for no race conditions blowing them out from under us 74@created = mkpath([$tmp_base]); 75is(scalar(@created), 0, "skipped making existing directory") 76 or diag("unexpectedly recreated @created"); 77 78# create a file 79my $file_name = catfile( $tmp_base, 'a', 'delete.me' ); 80my $file_count = 0; 81if (open OUT, "> $file_name") { 82 print OUT "this file may be deleted\n"; 83 close OUT; 84 ++$file_count; 85} 86else { 87 diag( "Failed to create file $file_name: $!" ); 88} 89 90SKIP: { 91 skip "cannot remove a file we failed to create", 1 92 unless $file_count == 1; 93 my $count = rmtree($file_name); 94 is($count, 1, "rmtree'ed a file"); 95} 96 97@created = mkpath(''); 98is(scalar(@created), 0, "Can't create a directory named ''"); 99 100my $dir; 101my $dir2; 102 103sub gisle { 104 # background info: @_ = 1; !shift # gives '' not 0 105 # Message-Id: <3C820CE6-4400-4E91-AF43-A3D19B356E68@activestate.com> 106 # http://www.nntp.perl.org/group/perl.perl5.porters/2008/05/msg136625.html 107 mkpath(shift, !shift, 0755); 108} 109 110sub count { 111 opendir D, shift or return -1; 112 my $count = () = readdir D; 113 closedir D or return -1; 114 return $count; 115} 116 117{ 118 mkdir 'solo', 0755; 119 chdir 'solo'; 120 open my $f, '>', 'foo.dat'; 121 close $f; 122 my $before = count(curdir()); 123 cmp_ok($before, '>', 0, "baseline $before"); 124 125 gisle('1st', 1); 126 is(count(curdir()), $before + 1, "first after $before"); 127 128 $before = count(curdir()); 129 gisle('2nd', 1); 130 131 is(count(curdir()), $before + 1, "second after $before"); 132 133 chdir updir(); 134 rmtree 'solo'; 135} 136 137{ 138 mkdir 'solo', 0755; 139 chdir 'solo'; 140 open my $f, '>', 'foo.dat'; 141 close $f; 142 my $before = count(curdir()); 143 144 cmp_ok($before, '>', 0, "ARGV $before"); 145 { 146 local @ARGV = (1); 147 mkpath('3rd', !shift, 0755); 148 } 149 150 is(count(curdir()), $before + 1, "third after $before"); 151 152 $before = count(curdir()); 153 { 154 local @ARGV = (1); 155 mkpath('4th', !shift, 0755); 156 } 157 158 is(count(curdir()), $before + 1, "fourth after $before"); 159 160 chdir updir(); 161 rmtree 'solo'; 162} 163 164SKIP: { 165 # tests for rmtree() of ancestor directory 166 my $nr_tests = 6; 167 my $cwd = getcwd() or skip "failed to getcwd: $!", $nr_tests; 168 my $dir = catdir($cwd, 'remove'); 169 my $dir2 = catdir($cwd, 'remove', 'this', 'dir'); 170 171 skip "failed to mkpath '$dir2': $!", $nr_tests 172 unless mkpath($dir2, {verbose => 0}); 173 skip "failed to chdir dir '$dir2': $!", $nr_tests 174 unless chdir($dir2); 175 176 rmtree($dir, {error => \$error}); 177 my $nr_err = @$error; 178 179 is($nr_err, 1, "ancestor error"); 180 181 if ($nr_err) { 182 my ($file, $message) = each %{$error->[0]}; 183 184 is($file, $dir, "ancestor named"); 185 my $ortho_dir = $^O eq 'MSWin32' ? File::Path::_slash_lc($dir2) : $dir2; 186 $^O eq 'MSWin32' and $message 187 =~ s/\A(cannot remove path when cwd is )(.*)\Z/$1 . File::Path::_slash_lc($2)/e; 188 189 is($message, "cannot remove path when cwd is $ortho_dir", "ancestor reason"); 190 191 ok(-d $dir2, "child not removed"); 192 193 ok(-d $dir, "ancestor not removed"); 194 } 195 else { 196 fail( "ancestor 1"); 197 fail( "ancestor 2"); 198 fail( "ancestor 3"); 199 fail( "ancestor 4"); 200 } 201 chdir $cwd; 202 rmtree($dir); 203 204 ok(!(-d $dir), "ancestor now removed"); 205}; 206 207my $count = rmtree({error => \$error}); 208 209is( $count, 0, 'rmtree of nothing, count of zero' ); 210 211is( scalar(@$error), 0, 'no diagnostic captured' ); 212 213@created = mkpath($tmp_base, 0); 214 215is(scalar(@created), 0, "skipped making existing directories (old style 1)") 216 or diag("unexpectedly recreated @created"); 217 218$dir = catdir($tmp_base,'C'); 219# mkpath returns unix syntax filespecs on VMS 220$dir = VMS::Filespec::unixify($dir) if $Is_VMS; 221@created = make_path($tmp_base, $dir); 222 223is(scalar(@created), 1, "created directory (new style 1)"); 224 225is($created[0], $dir, "created directory (new style 1) cross-check"); 226 227@created = mkpath($tmp_base, 0, 0700); 228 229is(scalar(@created), 0, "skipped making existing directories (old style 2)") 230 or diag("unexpectedly recreated @created"); 231 232$dir2 = catdir($tmp_base,'D'); 233# mkpath returns unix syntax filespecs on VMS 234$dir2 = VMS::Filespec::unixify($dir2) if $Is_VMS; 235@created = make_path($tmp_base, $dir, $dir2); 236 237is(scalar(@created), 1, "created directory (new style 2)"); 238 239is($created[0], $dir2, "created directory (new style 2) cross-check"); 240 241$count = rmtree($dir, 0); 242 243is($count, 1, "removed directory unsafe mode"); 244 245my $expected_count = _cannot_delete_safe_mode($dir2) ? 0 : 1; 246 247$count = rmtree($dir2, 0, 1); 248 249is($count, $expected_count, "removed directory safe mode"); 250 251# mkdir foo ./E/../Y 252# Y should exist 253# existence of E is neither here nor there 254$dir = catdir($tmp_base, 'E', updir(), 'Y'); 255@created =mkpath($dir); 256 257cmp_ok(scalar(@created), '>=', 1, "made one or more dirs because of .."); 258 259cmp_ok(scalar(@created), '<=', 2, "made less than two dirs because of .."); 260 261ok( -d catdir($tmp_base, 'Y'), "directory after parent" ); 262 263@created = make_path(catdir(curdir(), $tmp_base)); 264 265is(scalar(@created), 0, "nothing created") 266 or diag(@created); 267 268$dir = catdir($tmp_base, 'a'); 269$dir2 = catdir($tmp_base, 'z'); 270 271rmtree( $dir, $dir2, 272 { 273 error => \$error, 274 result => \$list, 275 keep_root => 1, 276 } 277); 278 279 280is(scalar(@$error), 0, "no errors unlinking a and z"); 281 282is(scalar(@$list), 4, "list contains 4 elements") 283 or diag("@$list"); 284 285ok(-d $dir, "dir a still exists"); 286 287ok(-d $dir2, "dir z still exists"); 288 289$dir = catdir($tmp_base,'F'); 290# mkpath returns unix syntax filespecs on VMS 291$dir = VMS::Filespec::unixify($dir) if $Is_VMS; 292 293@created = mkpath($dir, undef, 0770); 294 295is(scalar(@created), 1, "created directory (old style 2 verbose undef)"); 296 297is($created[0], $dir, "created directory (old style 2 verbose undef) cross-check"); 298 299is(rmtree($dir, undef, 0), 1, "removed directory 2 verbose undef"); 300 301@created = mkpath($dir, undef); 302 303is(scalar(@created), 1, "created directory (old style 2a verbose undef)"); 304 305is($created[0], $dir, "created directory (old style 2a verbose undef) cross-check"); 306 307is(rmtree($dir, undef), 1, "removed directory 2a verbose undef"); 308 309@created = mkpath($dir, 0, undef); 310 311is(scalar(@created), 1, "created directory (old style 3 mode undef)"); 312 313is($created[0], $dir, "created directory (old style 3 mode undef) cross-check"); 314 315is(rmtree($dir, 0, undef), 1, "removed directory 3 verbose undef"); 316 317SKIP: { 318 skip "fchmod of directories not supported on this platform", 3 unless $fchmod_supported; 319 $dir = catdir($tmp_base,'G'); 320 $dir = VMS::Filespec::unixify($dir) if $Is_VMS; 321 322 @created = mkpath($dir, undef, 0400); 323 324 is(scalar(@created), 1, "created read-only dir"); 325 326 is($created[0], $dir, "created read-only directory cross-check"); 327 328 is(rmtree($dir), 1, "removed read-only dir"); 329} 330 331# borderline new-style heuristics 332if (chdir $tmp_base) { 333 pass("chdir to temp dir"); 334} 335else { 336 fail("chdir to temp dir: $!"); 337} 338 339$dir = catdir('a', 'd1'); 340$dir2 = catdir('a', 'd2'); 341 342@created = make_path( $dir, 0, $dir2 ); 343 344is(scalar @created, 3, 'new-style 3 dirs created'); 345 346$count = remove_tree( $dir, 0, $dir2, ); 347 348is($count, 3, 'new-style 3 dirs removed'); 349 350@created = make_path( $dir, $dir2, 1 ); 351 352is(scalar @created, 3, 'new-style 3 dirs created (redux)'); 353 354$count = remove_tree( $dir, $dir2, 1 ); 355 356is($count, 3, 'new-style 3 dirs removed (redux)'); 357 358@created = make_path( $dir, $dir2 ); 359 360is(scalar @created, 2, 'new-style 2 dirs created'); 361 362$count = remove_tree( $dir, $dir2 ); 363 364is($count, 2, 'new-style 2 dirs removed'); 365 366$dir = catdir("a\nb", 'd1'); 367$dir2 = catdir("a\nb", 'd2'); 368 369SKIP: { 370 # Better to search for *nix derivatives? 371 # Not sure what else doesn't support newline in paths 372 skip "$^O doesn't allow newline in paths", 2 373 if $^O =~ m/^(MSWin32|VMS)$/; 374 375 @created = make_path( $dir, $dir2 ); 376 377 is(scalar @created, 3, 'new-style 3 dirs created in parent with newline'); 378 379 $count = remove_tree( $dir, $dir2 ); 380 381 is($count, 2, 'new-style 2 dirs removed in parent with newline'); 382} 383 384if (chdir updir()) { 385 pass("chdir parent"); 386} 387else { 388 fail("chdir parent: $!"); 389} 390 391SKIP: { 392 # test bug http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=487319 393 skip "Don't need Force_Writeable semantics on $^O", 6 394 if grep {$^O eq $_} qw(amigaos dos epoc MSWin32 MacOS os2); 395 skip "Symlinks not available", 6 unless $Config{d_symlink}; 396 $dir = 'bug487319'; 397 $dir2 = 'bug487319-symlink'; 398 @created = make_path($dir, {mask => 0700}); 399 400 is( scalar @created, 1, 'bug 487319 setup' ); 401 symlink($dir, $dir2); 402 403 ok(-e $dir2, "debian bug 487319 setup symlink") or diag($dir2); 404 405 chmod 0500, $dir; 406 my $mask_initial = (stat $dir)[2]; 407 remove_tree($dir2); 408 409 my $mask = (stat $dir)[2]; 410 411 is( $mask, $mask_initial, 'mask of symlink target dir unchanged (debian bug 487319)'); 412 413 # now try a file 414 #my $file = catfile($dir, 'file'); 415 my $file = 'bug487319-file'; 416 my $file2 = 'bug487319-file-symlink'; 417 open my $out, '>', $file; 418 close $out; 419 420 ok(-e $file, 'file exists'); 421 422 chmod 0500, $file; 423 $mask_initial = (stat $file)[2]; 424 425 symlink($file, $file2); 426 427 ok(-e $file2, 'file2 exists'); 428 remove_tree($file2); 429 430 $mask = (stat $file)[2]; 431 432 is( $mask, $mask_initial, 'mask of symlink target file unchanged (debian bug 487319)'); 433 434 remove_tree($dir); 435 remove_tree($file); 436} 437 438# see what happens if a file exists where we want a directory 439SKIP: { 440 my $entry = catfile($tmp_base, "file"); 441 skip "VMS can have a file and a directory with the same name.", 4 442 if $Is_VMS; 443 skip "Cannot create $entry", 4 unless open OUT, "> $entry"; 444 print OUT "test file, safe to delete\n", scalar(localtime), "\n"; 445 close OUT; 446 ok(-e $entry, "file exists in place of directory"); 447 448 mkpath( $entry, {error => \$error} ); 449 is( scalar(@$error), 1, "caught error condition" ); 450 ($file, $message) = each %{$error->[0]}; 451 is( $entry, $file, "and the message is: $message"); 452 453 eval {@created = mkpath($entry, 0, 0700)}; 454 $error = $@; 455 chomp $error; # just to remove silly # in TAP output 456 cmp_ok( $error, 'ne', "", "no directory created (old-style) err=$error" ) 457 or diag(@created); 458} 459 460{ 461 $dir = catdir($tmp_base, 'ZZ'); 462 @created = mkpath($dir); 463 is(scalar(@created), 1, "create a ZZ directory"); 464 465 local @ARGV = ($dir); 466 rmtree( [grep -e $_, @ARGV], 0, 0 ); 467 ok(!-e $dir, "blow it away via \@ARGV"); 468} 469 470SKIP : { 471 my $skip_count = 18; 472 # this test will fail on Windows, as per: 473 # http://perldoc.perl.org/perlport.html#chmod 474 475 skip "Windows chmod test skipped", $skip_count 476 if $^O eq 'MSWin32'; 477 skip "fchmod() on directories is not supported on this platform", $skip_count 478 unless $fchmod_supported; 479 my $mode; 480 my $octal_mode; 481 my @inputs = ( 482 0777, 0700, 0470, 0407, 483 0433, 0400, 0430, 0403, 484 0111, 0100, 0110, 0101, 485 0731, 0713, 0317, 0371, 486 0173, 0137); 487 my $input; 488 my $octal_input; 489 490 foreach (@inputs) { 491 $input = $_; 492 $dir = catdir($tmp_base, sprintf("chmod_test%04o", $input)); 493 # We can skip from here because 0 is last in the list. 494 skip "Mode of 0 means assume user defaults on VMS", 1 495 if ($input == 0 && $Is_VMS); 496 @created = mkpath($dir, {chmod => $input}); 497 $mode = (stat($dir))[2]; 498 $octal_mode = S_IMODE($mode); 499 $octal_input = sprintf "%04o", S_IMODE($input); 500 SKIP: { 501 skip "permissions are not fully supported by the filesystem", 1 502 if (($^O eq 'MSWin32' || $^O eq 'cygwin') && ((Win32::FsType())[1] & 8) == 0); 503 is($octal_mode,$input, "create a new directory with chmod $input ($octal_input)"); 504 } 505 rmtree( $dir ); 506 } 507} 508 509my $dir_base = catdir($tmp_base,'output'); 510my $dir_a = catdir($dir_base, 'A'); 511my $dir_b = catdir($dir_base, 'B'); 512 513is(_run_for_verbose(sub {@created = mkpath($dir_a, 1)}), 514 _verbose_expected('mkpath', $dir_base, 0, 1) 515 . _verbose_expected('mkpath', $dir_a, 0), 516 'mkpath verbose (old style 1)' 517); 518 519is(_run_for_verbose(sub {@created = mkpath([$dir_b], 1)}), 520 _verbose_expected('mkpath', $dir_b, 0), 521 'mkpath verbose (old style 2)' 522); 523 524my $verbose_expected; 525 526# Must determine expectations while directories still exist. 527$verbose_expected = _verbose_expected('rmtree', $dir_a, 1) 528 . _verbose_expected('rmtree', $dir_b, 1); 529 530is(_run_for_verbose(sub {$count = rmtree([$dir_a, $dir_b], 1, 1)}), 531 $verbose_expected, 532 'rmtree verbose (old style)' 533); 534 535# In case we didn't delete them in safe mode. 536rmtree($dir_a) if -d $dir_a; 537rmtree($dir_b) if -d $dir_b; 538 539is(_run_for_verbose(sub {@created = mkpath( $dir_a, 540 {verbose => 1, mask => 0750})}), 541 _verbose_expected('mkpath', $dir_a, 0), 542 'mkpath verbose (new style 1)' 543); 544 545is(_run_for_verbose(sub {@created = mkpath($dir_b, 1, 0771)}), 546 _verbose_expected('mkpath', $dir_b, 0), 547 'mkpath verbose (new style 2)' 548); 549 550$verbose_expected = _verbose_expected('rmtree', $dir_a, 1) 551 . _verbose_expected('rmtree', $dir_b, 1); 552 553is(_run_for_verbose(sub {$count = rmtree([$dir_a, $dir_b], 1, 1)}), 554 $verbose_expected, 555 'again: rmtree verbose (old style)' 556); 557 558rmtree($dir_a) if -d $dir_a; 559rmtree($dir_b) if -d $dir_b; 560 561is(_run_for_verbose(sub {@created = make_path( $dir_a, $dir_b, 562 {verbose => 1, mode => 0711});}), 563 _verbose_expected('make_path', $dir_a, 1) 564 . _verbose_expected('make_path', $dir_b, 1), 565 'make_path verbose with final hashref' 566); 567 568$verbose_expected = _verbose_expected('remove_tree', $dir_a, 0) 569 . _verbose_expected('remove_tree', $dir_b, 0); 570 571is(_run_for_verbose(sub {@created = remove_tree( $dir_a, $dir_b, 572 {verbose => 1});}), 573 $verbose_expected, 574 'remove_tree verbose with final hashref' 575); 576 577rmtree($dir_a) if -d $dir_a; 578rmtree($dir_b) if -d $dir_b; 579 580# Have to re-create these 2 directories so that next block is not skipped. 581@created = make_path( 582 $dir_a, 583 $dir_b, 584 { mode => 0711 } 585); 586is(@created, 2, "2 directories created"); 587 588SKIP: { 589 $file = catfile($dir_b, "file"); 590 skip "Cannot create $file", 2 unless open OUT, "> $file"; 591 print OUT "test file, safe to delete\n", scalar(localtime), "\n"; 592 close OUT; 593 594 $verbose_expected = _verbose_expected('rmtree', $dir_a, 1) 595 . _verbose_expected('unlink', $file, 0) 596 . _verbose_expected('rmtree', $dir_b, 1); 597 598 ok(-e $file, "file created in directory"); 599 600 is(_run_for_verbose(sub {$count = rmtree( $dir_a, $dir_b, 601 {verbose => 1, safe => 1})}), 602 $verbose_expected, 603 'rmtree safe verbose (new style)' 604 ); 605 rmtree($dir_a) if -d $dir_a; 606 rmtree($dir_b) if -d $dir_b; 607} 608 609{ 610 my $base = catdir( $tmp_base, 'output2'); 611 my $dir = catdir( $base, 'A'); 612 my $dir2 = catdir( $base, 'B'); 613 614 { 615 my $warn = _run_for_warning( sub { 616 my @created = make_path( 617 $dir, 618 $dir2, 619 { mode => 0711, foo => 1, bar => 1 } 620 ); 621 } ); 622 like($warn, 623 qr/Unrecognized option\(s\) passed to mkpath\(\) or make_path\(\):.*?bar.*?foo/, 624 'make_path with final hashref warned due to unrecognized options' 625 ); 626 } 627 628 { 629 my $warn = _run_for_warning( sub { 630 my @created = remove_tree( 631 $dir, 632 $dir2, 633 { foo => 1, bar => 1 } 634 ); 635 } ); 636 like($warn, 637 qr/Unrecognized option\(s\) passed to remove_tree\(\):.*?bar.*?foo/, 638 'remove_tree with final hashref failed due to unrecognized options' 639 ); 640 } 641} 642 643SKIP: { 644 my $nr_tests = 6; 645 my $cwd = getcwd() or skip "failed to getcwd: $!", $nr_tests; 646 rmtree($tmp_base, {result => \$list} ); 647 is(ref($list), 'ARRAY', "received a final list of results"); 648 ok( !(-d $tmp_base), "test base directory gone" ); 649 650 my $p = getcwd(); 651 my $x = "x$$"; 652 my $xx = $x . "x"; 653 654 # setup 655 ok(mkpath($xx), "make $xx"); 656 ok(chdir($xx), "... and chdir $xx"); 657 END { 658# ok(chdir($p), "... now chdir $p"); 659# ok(rmtree($xx), "... and finally rmtree $xx"); 660 chdir($p); 661 rmtree($xx); 662 } 663 664 # create and delete directory 665 my $px = catdir($p, $x); 666 ok(mkpath($px), 'create and delete directory 2.07'); 667 ok(rmtree($px), '.. rmtree fails in File-Path-2.07'); 668 chdir updir(); 669} 670 671my $windows_dir = 'C:\Path\To\Dir'; 672my $expect = 'c:/path/to/dir'; 673is( 674 File::Path::_slash_lc($windows_dir), 675 $expect, 676 "Windows path unixified as expected" 677); 678 679{ 680 my ($x, $message, $object, $expect, $rv, $arg, $error); 681 my ($k, $v, $second_error, $third_error); 682 local $! = ENOENT; 683 $x = $!; 684 685 $message = 'message in a bottle'; 686 $object = '/path/to/glory'; 687 $expect = "$message for $object: $x"; 688 $rv = _run_for_warning( sub { 689 File::Path::_error( 690 {}, 691 $message, 692 $object 693 ); 694 } ); 695 like($rv, qr/^$expect/, 696 "no \$arg->{error}: defined 2nd and 3rd args: got expected error message"); 697 698 $object = undef; 699 $expect = "$message: $x"; 700 $rv = _run_for_warning( sub { 701 File::Path::_error( 702 {}, 703 $message, 704 $object 705 ); 706 } ); 707 like($rv, qr/^$expect/, 708 "no \$arg->{error}: defined 2nd arg; undefined 3rd arg: got expected error message"); 709 710 $message = 'message in a bottle'; 711 $object = undef; 712 $expect = "$message: $x"; 713 $arg = { error => \$error }; 714 File::Path::_error( 715 $arg, 716 $message, 717 $object 718 ); 719 is(ref($error->[0]), 'HASH', 720 "first element of array inside \$error is hashref"); 721 ($k, $v) = %{$error->[0]}; 722 is($k, '', 'key of hash is empty string, since 3rd arg was undef'); 723 is($v, $expect, "value of hash is 2nd arg: $message"); 724 725 $message = ''; 726 $object = '/path/to/glory'; 727 $expect = "$message: $x"; 728 $arg = { error => \$second_error }; 729 File::Path::_error( 730 $arg, 731 $message, 732 $object 733 ); 734 is(ref($second_error->[0]), 'HASH', 735 "first element of array inside \$second_error is hashref"); 736 ($k, $v) = %{$second_error->[0]}; 737 is($k, $object, "key of hash is '$object', since 3rd arg was defined"); 738 is($v, $expect, "value of hash is 2nd arg: $message"); 739 740 $message = ''; 741 $object = undef; 742 $expect = "$message: $x"; 743 $arg = { error => \$third_error }; 744 File::Path::_error( 745 $arg, 746 $message, 747 $object 748 ); 749 is(ref($third_error->[0]), 'HASH', 750 "first element of array inside \$third_error is hashref"); 751 ($k, $v) = %{$third_error->[0]}; 752 is($k, '', "key of hash is empty string, since 3rd arg was undef"); 753 is($v, $expect, "value of hash is 2nd arg: $message"); 754} 755 756{ 757 # https://rt.cpan.org/Ticket/Display.html?id=117019 758 # remove_tree(): Permit re-use of options hash without issuing a warning 759 760 my ($least_deep, $next_deepest, $deepest) = 761 create_3_level_subdirs( qw| ZoYhvc6RmGnl S2CrQ0lju0o7 lvOqVYWpfhcP | ); 762 my @created; 763 @created = File::Path::make_path($deepest, { mode => 0711 }); 764 is(scalar(@created), 3, "Created 3 subdirectories"); 765 766 my $x = ''; 767 my $opts = { error => \$x }; 768 File::Path::remove_tree($deepest, $opts); 769 ok(! -d $deepest, "directory '$deepest' removed, as expected"); 770 771 my $warn; 772 $warn = _run_for_warning( sub { File::Path::remove_tree($next_deepest, $opts); } ); 773 ok(! $warn, "CPAN 117019: No warning thrown when re-using \$opts"); 774 ok(! -d $next_deepest, "directory '$next_deepest' removed, as expected"); 775 776 $warn = _run_for_warning( sub { File::Path::remove_tree($least_deep, $opts); } ); 777 ok(! $warn, "CPAN 117019: No warning thrown when re-using \$opts"); 778 ok(! -d $least_deep, "directory '$least_deep' removed, as expected"); 779} 780 781{ 782 # Corner cases with respect to arguments provided to functions 783 my $count; 784 785 $count = remove_tree(); 786 is($count, 0, 787 "If not provided with any paths, remove_tree() will return a count of 0 things deleted"); 788 789 $count = remove_tree(''); 790 is($count, 0, 791 "If not provided with any paths, remove_tree() will return a count of 0 things deleted"); 792 793 my $warn; 794 $warn = _run_for_warning( sub { $count = rmtree(); } ); 795 like($warn, qr/No root path\(s\) specified/s, "Got expected carp"); 796 is($count, 0, 797 "If not provided with any paths, remove_tree() will return a count of 0 things deleted"); 798 799 $warn = _run_for_warning( sub {$count = rmtree(undef); } ); 800 like($warn, qr/No root path\(s\) specified/s, "Got expected carp"); 801 is($count, 0, 802 "If provided only with an undefined value, remove_tree() will return a count of 0 things deleted"); 803 804 $warn = _run_for_warning( sub {$count = rmtree(''); } ); 805 like($warn, qr/No root path\(s\) specified/s, "Got expected carp"); 806 is($count, 0, 807 "If provided with an empty string for a path, remove_tree() will return a count of 0 things deleted"); 808 809 $count = make_path(); 810 is($count, 0, 811 "If not provided with any paths, make_path() will return a count of 0 things created"); 812 813 $count = mkpath(); 814 is($count, 0, 815 "If not provided with any paths, make_path() will return a count of 0 things created"); 816} 817 818SKIP: { 819 my $skip_count = 3; 820 skip "Windows will not set this error condition", $skip_count 821 if $^O eq 'MSWin32'; 822 823 # mkpath() with hashref: case of phony user 824 my ($least_deep, $next_deepest, $deepest) = 825 create_3_level_subdirs( qw| Hhu1KpF4EVAV vUj5k37bih8v Vkdw02POXJxj | ); 826 my (@created, $error); 827 my $user = join('_' => 'foobar', $$); 828 @created = mkpath($deepest, { mode => 0711, user => $user, error => \$error }); 829# TODO: { 830# local $TODO = "Notwithstanding the phony 'user', mkpath will actually create subdirectories; should it?"; 831# is(scalar(@created), 0, "No subdirectories created"); 832# } 833 is(scalar(@$error), 1, "caught error condition" ); 834 my ($file, $message) = each %{$error->[0]}; 835 like($message, 836 qr/unable to map $user to a uid, ownership not changed/s, 837 "Got expected error message for phony user", 838 ); 839 840 cleanup_3_level_subdirs($least_deep); 841} 842 843{ 844 # mkpath() with hashref: case of valid uid 845 my ($least_deep, $next_deepest, $deepest) = 846 create_3_level_subdirs( qw| b5wj8CJcc7gl XTJe2C3WGLg5 VZ_y2T0XfKu3 | ); 847 my (@created, $error); 848 my $warn; 849 local $SIG{__WARN__} = sub { $warn = shift }; 850 @created = mkpath($deepest, { mode => 0711, uid => $>, error => \$error }); 851 SKIP: { 852 my $skip_count = 1; 853 skip "Warning should only appear on Windows", $skip_count 854 unless $^O eq 'MSWin32'; 855 like($warn, 856 qr/Option\(s\) implausible on Win32 passed to mkpath\(\) or make_path\(\)/, 857 'make_path with final hashref warned due to options implausible on Win32' 858 ); 859 } 860 is(scalar(@created), 3, "Provide valid 'uid' argument: 3 subdirectories created"); 861 862 cleanup_3_level_subdirs($least_deep); 863} 864 865SKIP: { 866 my $skip_count = 3; 867 skip "getpwuid() and getgrgid() not implemented on Windows", $skip_count 868 if $^O eq 'MSWin32'; 869 870 # mkpath() with hashref: case of valid owner 871 my ($least_deep, $next_deepest, $deepest) = 872 create_3_level_subdirs( qw| aiJEDKaAEH25 nqhXsBM_7_bv qfRj4cur4Jrs | ); 873 my (@created, $error); 874 my $name = getpwuid($>); 875 @created = mkpath($deepest, { mode => 0711, owner => $name, error => \$error }); 876 is(scalar(@created), 3, "Provide valid 'owner' argument: 3 subdirectories created"); 877 878 cleanup_3_level_subdirs($least_deep); 879} 880 881SKIP: { 882 my $skip_count = 5; 883 skip "Windows will not set this error condition", $skip_count 884 if $^O eq 'MSWin32'; 885 886 # mkpath() with hashref: case of phony group 887 my ($least_deep, $next_deepest, $deepest) = 888 create_3_level_subdirs( qw| nOR4lGRMdLvz NnwkEHEVL5li _3f1Kv6q77yA | ); 889 my (@created, $error); 890 my $bad_group = join('_' => 'foobarbaz', $$); 891 @created = mkpath($deepest, { mode => 0711, group => $bad_group, error => \$error }); 892# TODO: { 893# local $TODO = "Notwithstanding the phony 'group', mkpath will actually create subdirectories; should it?"; 894# is(scalar(@created), 0, "No subdirectories created"); 895# } 896 is(scalar(@$error), 1, "caught error condition" ); 897 my ($file, $message) = each %{$error->[0]}; 898 like($message, 899 qr/unable to map $bad_group to a gid, group ownership not changed/s, 900 "Got expected error message for phony user", 901 ); 902 903 cleanup_3_level_subdirs($least_deep); 904} 905 906{ 907 # mkpath() with hashref: case of valid group 908 my ($least_deep, $next_deepest, $deepest) = 909 create_3_level_subdirs( qw| BEcigvaBNisY rd4lJ1iZRyeS OyQnDPIBxP2K | ); 910 my (@created, $error); 911 my $warn; 912 local $SIG{__WARN__} = sub { $warn = shift }; 913 @created = mkpath($deepest, { mode => 0711, group => $(, error => \$error }); 914 SKIP: { 915 my $skip_count = 1; 916 skip "Warning should only appear on Windows", $skip_count 917 unless $^O eq 'MSWin32'; 918 like($warn, 919 qr/Option\(s\) implausible on Win32 passed to mkpath\(\) or make_path\(\)/, 920 'make_path with final hashref warned due to options implausible on Win32' 921 ); 922 } 923 is(scalar(@created), 3, "Provide valid 'group' argument: 3 subdirectories created"); 924 925 cleanup_3_level_subdirs($least_deep); 926} 927 928SKIP: { 929 my $skip_count = 3; 930 skip "getpwuid() and getgrgid() not implemented on Windows", $skip_count 931 if $^O eq 'MSWin32'; 932 933 # mkpath() with hashref: case of valid group 934 my ($least_deep, $next_deepest, $deepest) = 935 create_3_level_subdirs( qw| IayhWFDvys8X gTd6gaeuFzmV VVI6UWLJCOEC | ); 936 my (@created, $error); 937 my $group_name = (getgrgid($())[0]; 938 @created = mkpath($deepest, { mode => 0711, group => $group_name, error => \$error }); 939 is(scalar(@created), 3, "Provide valid 'group' argument: 3 subdirectories created"); 940 941 cleanup_3_level_subdirs($least_deep); 942} 943 944SKIP: { 945 my $skip_count = 3; 946 skip "getpwuid() and getgrgid() not implemented on Windows", $skip_count 947 if $^O eq 'MSWin32'; 948 949 # mkpath() with hashref: case of valid owner and group 950 my ($least_deep, $next_deepest, $deepest) = 951 create_3_level_subdirs( qw| xsmOvlnxOqJc olsGlBSoVUpp tDuRilkD35rd | ); 952 my (@created, $error); 953 my $name = getpwuid($>); 954 my $group_name = (getgrgid($())[0]; 955 @created = mkpath($deepest, { mode => 0711, owner => $name, group => $group_name, error => \$error }); 956 is(scalar(@created), 3, "Provide valid 'owner' and 'group' 'group' arguments: 3 subdirectories created"); 957 958 cleanup_3_level_subdirs($least_deep); 959} 960