2 if( $ENV{PERL_CORE} ) {
3 chdir '../lib/Archive/Tar' if -d '../lib/Archive/Tar';
8 BEGIN { chdir 't' if -d 't' }
10 use Test::More 'no_plan';
20 use File::Spec::Unix ();
21 use File::Basename ();
25 use Archive::Tar::Constant;
28 ### * change to fullname
29 ### * add tests for global variables
31 ### set up the environment ###
33 ### dirs filename contents
34 [ [], 'c', qr/^iiiiiiiiiiii\s*$/ ],
35 [ [], 'd', qr/^uuuuuuuu\s*$/ ],
38 ### includes binary data
39 my $ALL_CHARS = join '', "\r\n", map( chr, 1..255 ), "zzz\n\r";
41 ### @EXPECTBIN is used to ensure that $tarbin is written in the right
42 ### order and that the contents and order match exactly when extracted
44 ### dirs filename contents ###
45 [ [], 'bIn11', $ALL_CHARS x 11 ],
46 [ [], 'bIn3', $ALL_CHARS x 3 ],
47 [ [], 'bIn4', $ALL_CHARS x 4 ],
48 [ [], 'bIn1', $ALL_CHARS ],
49 [ [], 'bIn2', $ALL_CHARS x 2 ],
52 ### @EXPECTX is used to ensure that $tarx is written in the right
53 ### order and that the contents and order match exactly when extracted
54 ### the 'x/x' extraction used to fail before A::T 1.08
56 ### dirs filename contents
57 [ [ 'x' ], 'k', '', ],
58 [ [ 'x' ], 'x', 'j', ], # failed before A::T 1.08
61 my $LONG_FILE = qq[directory/really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-long-directory-name/myfile];
63 ### wintendo can't deal with too long paths, so we might have to skip tests ###
64 my $TOO_LONG = ($^O eq 'MSWin32' or $^O eq 'cygwin' or $^O eq 'VMS')
65 && length( cwd(). $LONG_FILE ) > 247;
67 ### warn if we are going to skip long file names
69 diag("No long filename support - long filename extraction disabled") if ! $ENV{PERL_CORE};
71 push @EXPECT_NORMAL, [ [], $LONG_FILE, qr/^hello\s*$/];
74 my @ROOT = grep { length } 'src', $TOO_LONG ? 'short' : 'long';
76 my $ZLIB = eval { require IO::Zlib; 1 } ? 1 : 0;
77 my $NO_UNLINK = $ARGV[0] ? 1 : 0;
80 $Archive::Tar::DEBUG = 1 if $ARGV[1];
82 ### tests for binary and x/x files
83 my $TARBIN = Archive::Tar->new;
84 my $TARX = Archive::Tar->new;
86 ### paths to a .tar and .tgz file to use for tests
87 my $TAR_FILE = File::Spec->catfile( @ROOT, 'bar.tar' );
88 my $TGZ_FILE = File::Spec->catfile( @ROOT, 'foo.tgz' );
89 my $OUT_TAR_FILE = File::Spec->catfile( @ROOT, 'out.tar' );
90 my $OUT_TGZ_FILE = File::Spec->catfile( @ROOT, 'out.tgz' );
92 my $COMPRESS_FILE = 'copy';
93 $^O eq 'VMS' and $COMPRESS_FILE .= '.';
94 copy( File::Basename::basename($0), $COMPRESS_FILE );
95 chmod 0644, $COMPRESS_FILE;
97 ### done setting up environment ###
100 ### did we probe IO::Zlib support ok? ###
101 { is( Archive::Tar->can_handle_compressed_files, $ZLIB,
102 "Proper IO::Zlib support detected" );
107 { my $tar = Archive::Tar->new;
109 ok( $tar, "Object created" );
110 isa_ok( $tar, 'Archive::Tar');
112 local $Archive::Tar::WARN = 0;
114 ### should be empty to begin with
115 is( $tar->error, '', "The error string is empty" );
117 ### try a read on nothing
118 my @list = $tar->read();
120 ok(!(scalar @list), "Function read returns 0 files on error" );
121 ok( $tar->error, " error string is non empty" );
122 like( $tar->error, qr/No file to read from/,
123 " error string from create()" );
124 unlike( $tar->error, qr/add/, " error string does not contain add" );
126 ### now, add empty data
127 my $obj = $tar->add_data( '' );
129 ok( !$obj, "'add_data' returns undef on error" );
130 ok( $tar->error, " error string is non empty" );
131 like( $tar->error, qr/add/, " error string contains add" );
132 unlike( $tar->error, qr/create/," error string does not contain create" );
134 ### check if ->error eq $error
135 is( $tar->error, $Archive::Tar::error,
136 '$error matches error() method' );
138 ### check that 'contains_file' doesn't warn about missing files.
139 { ### turn on warnings in general!
140 local $Archive::Tar::WARN = 1;
143 local $SIG{__WARN__} = sub { $warnings .= "@_" };
145 my $rv = $tar->contains_file( $$ );
146 ok( !$rv, "Does not contain file '$$'" );
147 is( $warnings, '', " No warnings issued during lookup" );
152 { ### normal tar + gz compressed file
153 my $archive = $TAR_FILE;
154 my $compressed = $TGZ_FILE;
155 my $tar = Archive::Tar->new;
158 ### check we got the object
159 ok( $tar, "Object created" );
160 isa_ok( $tar, 'Archive::Tar');
162 for my $type( $archive, $compressed ) {
163 my $state = $gzip ? 'compressed' : 'uncompressed';
167 ### skip gz compressed archives wihtout IO::Zlib
168 skip( "No IO::Zlib - cannot read compressed archives",
169 4 + 2 * (scalar @EXPECT_NORMAL)
170 ) if( $gzip and !$ZLIB);
173 { my @list = $tar->read( $type );
174 my $cnt = scalar @list;
175 my $expect = scalar __PACKAGE__->get_expect();
177 ok( $cnt, "Reading $state file using 'read()'" );
178 is( $cnt, $expect, " All files accounted for" );
180 for my $file ( @list ) {
181 ok( $file, "Got File object" );
182 isa_ok( $file, "Archive::Tar::File" );
184 ### whitebox test -- make sure find_entry gets the
186 for my $test ( $file->full_path, $file ) {
187 is( $tar->_find_entry( $test ), $file,
188 " Found proper object" );
191 next unless $file->is_file;
193 my $name = $file->full_path;
194 my($expect_name, $expect_content) =
195 get_expect_name_and_contents( $name, \@EXPECT_NORMAL );
198 ok($expect_name," Found expected file '$name'" );
200 like($tar->get_content($name), $expect_content,
206 ### list_archive test
207 { my @list = Archive::Tar->list_archive( $archive );
208 my $cnt = scalar @list;
209 my $expect = scalar __PACKAGE__->get_expect();
211 ok( $cnt, "Reading $state file using 'list_archive'");
212 is( $cnt, $expect, " All files accounted for" );
214 for my $file ( @list ) {
215 next if __PACKAGE__->is_dir( $file ); # directories
217 my($expect_name, $expect_content) =
218 get_expect_name_and_contents( $file, \@EXPECT_NORMAL );
221 " Found expected file '$file'" );
226 ### now we try gz compressed archives
231 ### add files tests ###
232 { my @add = map { File::Spec->catfile( @ROOT, @$_ ) } ['b'];
233 my @addunix = map { File::Spec::Unix->catfile( @ROOT, @$_ ) } ['b'];
234 my $tar = Archive::Tar->new;
236 ### check we got the object
237 ok( $tar, "Object created" );
238 isa_ok( $tar, 'Archive::Tar');
241 { my @files = $tar->add_files( @add );
243 is( scalar @files, scalar @add,
245 is( $files[0]->name, 'b', " Proper name" );
248 skip( "You are building perl using symlinks", 1)
249 if ($ENV{PERL_CORE} and $Config{config_args} =~/Dmksymlinks/);
251 is( $files[0]->is_file, 1,
255 like( $files[0]->get_content, qr/^bbbbbbbbbbb\s*$/,
258 ### check if we have then in our tar object
259 for my $file ( @addunix ) {
260 ok( $tar->contains_file($file),
261 " File found in archive" );
265 ### check adding files doesn't conflict with a secondary archive
266 ### old A::T bug, we should keep testing for it
267 { my $tar2 = Archive::Tar->new;
268 my @added = $tar2->add_files( $COMPRESS_FILE );
269 my @count = $tar2->list_files;
271 is( scalar @added, 1, "Added files to secondary archive" );
272 is( scalar @added, scalar @count,
273 " Does not conflict with first archive" );
275 ### check the adding of directories
276 my @add_dirs = File::Spec->catfile( @ROOT );
277 my @dirs = $tar2->add_files( @add_dirs );
278 is( scalar @dirs, scalar @add_dirs,
280 ok( $dirs[0]->is_dir, " Proper type" );
284 ### add data tests ###
286 { ### standard data ###
287 my @to_add = ( 'a', 'aaaaa' );
288 my $tar = Archive::Tar->new;
290 ### check we got the object
291 ok( $tar, "Object created" );
292 isa_ok( $tar, 'Archive::Tar');
294 ### add a new file item as data
295 my $obj = $tar->add_data( @to_add );
297 ok( $obj, "Adding data" );
298 is( $obj->name, $to_add[0], " Proper name" );
299 is( $obj->is_file, 1, " Proper type" );
300 like( $obj->get_content, qr/^$to_add[1]\s*$/,
305 ### dir/file structure -- x/y always went ok, x/x used to extract
306 ### in the wrong way -- this test catches that
307 for my $list ( [$TARBIN, \@EXPECTBIN],
310 ### XXX GLOBAL! changes may affect other tests!
311 my($tar,$struct) = @$list;
313 for my $aref ( @$struct ) {
314 my ($dirs,$file,$data) = @$aref;
316 my $path = File::Spec::Unix->catfile(
317 grep { length } @$dirs, $file );
319 my $obj = $tar->add_data( $path, $data );
321 ok( $obj, "Adding data '$file'" );
322 is( $obj->full_path, $path,
324 ok( $obj->is_file, " Proper type" );
325 is( $obj->get_content, $data,
332 ### rename/replace_content tests ###
333 { my $tar = Archive::Tar->new;
337 ### read in the file, check the proper files are there
338 ok( $tar->read( $TAR_FILE ), "Read in '$TAR_FILE'" );
339 ok( $tar->get_files($from), " Found file '$from'" );
340 { local $Archive::Tar::WARN = 0;
341 ok(!$tar->get_files($to), " File '$to' not yet found" );
344 ### rename an entry, check the rename has happened
345 ok( $tar->rename( $from, $to ), " Renamed '$from' to '$to'" );
346 ok( $tar->get_files($to), " File '$to' now found" );
347 { local $Archive::Tar::WARN = 0;
348 ok(!$tar->get_files($from), " File '$from' no longer found'");
351 ### now, replace the content
352 my($expect_name, $expect_content) =
353 get_expect_name_and_contents( $from, \@EXPECT_NORMAL );
355 like( $tar->get_content($to), $expect_content,
356 "Original content of '$from' in '$to'" );
357 ok( $tar->replace_content( $to, $from ),
358 " Set content for '$to' to '$from'" );
359 is( $tar->get_content($to), $from,
360 " Content for '$to' is indeed '$from'" );
365 my $tar = Archive::Tar->new;
367 ok( $tar->read( $TAR_FILE ), "Read in '$TAR_FILE'" );
369 ### remove returns the files left, which should be equal to list_files
370 is( scalar($tar->remove($remove)), scalar($tar->list_files),
371 "Removing file '$remove'" );
373 ### so what's left should be all expected files minus 1
374 is( scalar($tar->list_files), scalar(__PACKAGE__->get_expect) - 1,
375 " Proper files remaining" );
378 ### write + read + extract tests ###
380 skip('no IO::String', 326) if !$Archive::Tar::HAS_PERLIO &&
381 !$Archive::Tar::HAS_IO_STRING;
383 my $tar = Archive::Tar->new;
384 my $new = Archive::Tar->new;
385 ok( $tar->read( $TAR_FILE ), "Read in '$TAR_FILE'" );
387 for my $aref ( [$tar, \@EXPECT_NORMAL],
388 [$TARBIN, \@EXPECTBIN],
391 my($obj,$struct) = @$aref;
393 ### check if we stringify it ok
394 { my $string = $obj->write;
395 ok( $string, "Stringified tar file has size" );
396 cmp_ok( length($string) % BLOCK, '==', 0,
397 "Tar archive stringified" );
401 { my $out = $OUT_TAR_FILE;
404 ok( $obj->write($out),
405 "Wrote tarfile using 'write'" );
406 check_tar_file( $out );
407 check_tar_object( $obj, $struct );
409 ### now read it in again
410 ok( $new->read( $out ),
411 "Read '$out' in again" );
413 check_tar_object( $new, $struct );
415 ### now extract it again
416 ok( $new->extract, "Extracted '$out' with 'extract'" );
417 check_tar_extract( $new, $struct );
419 rm( $out ) unless $NO_UNLINK;
423 { ### create_archive()
424 ok( Archive::Tar->create_archive( $out, 0, $COMPRESS_FILE ),
425 "Wrote tarfile using 'create_archive'" );
426 check_tar_file( $out );
428 ### now extract it again
429 ok( Archive::Tar->extract_archive( $out ),
430 "Extracted file using 'extract_archive'");
431 rm( $out ) unless $NO_UNLINK;
436 { my $out = $OUT_TGZ_FILE;
440 ### weird errors from scalar(@x,@y,@z), dot it this way...
442 map { $file_cnt += scalar @$_ } \@EXPECT_NORMAL, \@EXPECTBIN,
445 my $cnt = 5 + # the tests below
446 (5*3*2) + # check_tgz_file
447 # check_tar_object fixed tests
448 (3 * 2 * (2 + $file_cnt)) +
449 ((4*$file_cnt) + 1);# check_tar_extract tests
451 skip( "No IO::Zlib - cannot write compressed archives", $cnt )
455 ok($obj->write($out, 1),
456 "Writing compressed file using 'write'" );
457 check_tgz_file( $out );
458 check_tar_object( $obj, $struct );
460 ### now read it in again
461 ok( $new->read( $out ),
462 "Read '$out' in again" );
463 check_tar_object( $new, $struct );
465 ### now extract it again
467 "Extracted '$out' again" );
468 check_tar_extract( $new, $struct );
470 rm( $out ) unless $NO_UNLINK;
473 { ### create_archive()
474 ok( Archive::Tar->create_archive( $out, 1, $COMPRESS_FILE ),
475 "Wrote gzip file using 'create_archive'" );
476 check_tgz_file( $out );
478 ### now extract it again
479 ok( Archive::Tar->extract_archive( $out, 1 ),
480 "Extracted file using 'extract_archive'");
481 rm( $out ) unless $NO_UNLINK;
489 ### limited read + extract tests ###
490 { my $tar = Archive::Tar->new;
491 my @files = $tar->read( $TAR_FILE, 0, { limit => 1 } );
494 is( scalar @files, 1, "Limited read" );
496 my ($name,$content) = get_expect_name_and_contents(
497 $obj->full_path, \@EXPECT_NORMAL );
499 is( $obj->name, $name, " Expected file found" );
502 ### extract this single file to cwd()
503 for my $meth (qw[extract extract_file]) {
505 ### extract it by full path and object
506 for my $arg ( $obj, $obj->full_path ) {
508 ok( $tar->$meth( $arg ),
509 "Extracted '$name' to cwd() with $meth" );
510 ok( -e $obj->full_path, " Extracted file exists" );
511 rm( $obj->full_path ) unless $NO_UNLINK;
515 ### extract this file to @ROOT
516 ### can only do that with 'extract_file', not with 'extract'
517 for my $meth (qw[extract_file]) {
518 my $outpath = File::Spec->catdir( @ROOT );
519 my $outfile = File::Spec->catfile( $outpath, $$ ); #$obj->full_path );
521 ok( $tar->$meth( $obj->full_path, $outfile ),
522 "Extracted file '$name' to $outpath with $meth" );
523 ok( -e $outfile, " Extracted file '$outfile' exists" );
524 rm( $outfile ) unless $NO_UNLINK;
531 { my $tar = Archive::Tar->new;
532 my @files = $tar->read( $TAR_FILE );
534 my $cnt = $tar->list_files();
535 ok( $cnt, "Found old data" );
536 ok( $tar->clear, " Clearing old data" );
538 my $new_cnt = $tar->list_files;
539 ok( !$new_cnt, " Old data cleared" );
542 ### $DO_NOT_USE_PREFIX tests
543 { my $tar = Archive::Tar->new;
546 ### first write a tar file without prefix
547 { my ($obj) = $tar->add_files( $COMPRESS_FILE );
548 my $dir = ''; # dir is empty!
549 my $file = File::Basename::basename( $COMPRESS_FILE );
551 ok( $obj, "File added" );
552 isa_ok( $obj, "Archive::Tar::File" );
554 ### internal storage ###
555 is( $obj->name, $file, " Name set to '$file'" );
556 is( $obj->prefix, $dir, " Prefix set to '$dir'" );
558 ### write the tar file without a prefix in it
559 local $Archive::Tar::DO_NOT_USE_PREFIX = 1;
560 ok( $tar->write( $OUT_TAR_FILE ),
561 " Tar file written" );
563 ### and forget all about it...
567 ### now read it back in, there should be no prefix
568 { ok( $tar->read( $OUT_TAR_FILE ),
569 "Tar file read in again" );
571 my ($obj) = $tar->get_files;
572 ok( $obj, " File retrieved" );
573 isa_ok( $obj, "Archive::Tar::File" );
575 is( $obj->name, $COMPRESS_FILE,
576 " Name now set to '$COMPRESS_FILE'" );
577 is( $obj->prefix, '', " Prefix now empty" );
579 my $re = quotemeta $COMPRESS_FILE;
580 like( $obj->raw, qr/^$re/, " Prefix + name in name slot of header" );
583 rm( $OUT_TAR_FILE ) unless $NO_UNLINK;
588 for my $struct ( \@EXPECT_NORMAL, \@EXPECTBIN, \@EXPECTX ) {
589 for my $aref (@$struct) {
591 my $dir = $aref->[0]->[0];
592 rmtree $dir if $dir && -d $dir && not $NO_UNLINK;
596 my ($dir) = File::Spec::Unix->splitdir( $LONG_FILE );
597 rmtree $dir if $dir && -d $dir && not $NO_UNLINK;
598 1 while unlink $COMPRESS_FILE;
601 ###########################
603 ###########################
608 File::Spec::Unix->catfile(
609 grep { defined } @{$_->[0]}, $_->[1]
616 return $file =~ m|/$| ? 1 : 0;
630 my $filesize = -s $file;
631 my $contents = slurp_binfile( $file );
633 ok( defined( $contents ), " File read" );
634 ok( $filesize, " File written size=$filesize" );
636 cmp_ok( $filesize % BLOCK, '==', 0,
637 " File size is a multiple of 512" );
639 cmp_ok( length($contents), '==', $filesize,
640 " File contents match size" );
642 is( TAR_END x 2, substr( $contents, -(BLOCK*2) ),
643 " Ends with 1024 null bytes" );
650 my $filesize = -s $file;
651 my $contents = slurp_gzfile( $file );
652 my $uncompressedsize = length $contents;
654 ok( defined( $contents ), " File read and uncompressed" );
655 ok( $filesize, " File written size=$filesize uncompressed size=$uncompressedsize" );
657 cmp_ok( $uncompressedsize % BLOCK, '==', 0,
658 " Uncompressed size is a multiple of 512" );
660 is( TAR_END x 2, substr($contents, -(BLOCK*2)),
661 " Ends with 1024 null bytes" );
663 cmp_ok( $filesize, '<', $uncompressedsize,
664 " Compressed size < uncompressed size" );
669 sub check_tar_object {
671 my $struct = shift or return;
673 ### amount of files (not dirs!) there should be in the object
674 my $expect = scalar @$struct;
675 my @files = grep { $_->is_file } $obj->get_files;
677 ### count how many files there are in the object
678 ok( scalar @files, " Found some files in the archive" );
679 is( scalar @files, $expect, " Found expected number of files" );
681 for my $file (@files) {
684 #my $path = File::Spec::Unix->catfile(
685 # grep { length } $file->prefix, $file->name );
686 my($ename,$econtent) =
687 get_expect_name_and_contents( $file->full_path, $struct );
689 ok( $file->is_file, " It is a file" );
690 is( $file->full_path, $ename,
691 " Name matches expected name" );
692 like( $file->get_content, $econtent,
693 " Content as expected" );
697 sub check_tar_extract {
702 for my $file ($tar->get_files) {
703 push @dirs, $file && next if $file->is_dir;
706 my $path = $file->full_path;
707 my($ename,$econtent) =
708 get_expect_name_and_contents( $path, $struct );
711 is( $ename, $path, " Expected file found" );
712 ok( -e $path, " File '$path' exists" );
715 open $fh, "$path" or warn "Error opening file '$path': $!\n";
718 ok( $fh, " Opening file" );
720 my $content = do{local $/;<$fh>}; chomp $content;
721 like( $content, qr/$econtent/,
725 $NO_UNLINK or 1 while unlink $path;
727 ### alternate extract path tests
728 ### to abs and rel paths
729 { for my $outpath ( File::Spec->catdir( @ROOT ),
731 File::Spec->catdir( @ROOT )
735 my $outfile = File::Spec->catfile( $outpath, $$ );
737 ok( $tar->extract_file( $file->full_path, $outfile ),
738 " Extracted file '$path' to $outfile" );
739 ok( -e $outfile," Extracted file '$outfile' exists" );
741 rm( $outfile ) unless $NO_UNLINK;
746 ### now check if list_files is returning the same info as get_files
747 is_deeply( [$tar->list_files], [ map { $_->full_path } $tar->get_files],
748 " Verified via list_files as well" );
750 #do { rmtree $_->full_path if -d $_->full_path && not $NO_UNLINK }
756 my $fh = IO::File->new;
758 $fh->open( $file ) or warn( "Error opening '$file': $!" ), return undef;
771 my $fh = new IO::Zlib;
772 $fh->open( $file, READ_ONLY->(1) )
773 or warn( "Error opening '$file' with IO::Zlib" ), return undef;
775 $str .= $buff while $fh->read( $buff, 4096 ) > 0;
780 sub get_expect_name_and_contents {
782 my $struct = shift or return;
784 ### find the proper name + contents for this file from
785 ### the expect structure
786 my ($name, $content) =
793 File::Spec::Unix->catfile(
794 grep { length } @{$_->[0]}, $_->[1]
802 unless( ref $content ) {
803 my $x = quotemeta ($content || '');
808 warn "Could not find '$find' in " . Dumper $struct;
811 return ($name, $content);