#!/usr/bin/perl use strict; use warnings; use File::Temp (); # # Unit tests of _downcopy function # # _downcopy($self, $data, $pos, $len) # Write $data into a block of length $len at position $pos, # moving everything in the block forwards to make room. # Instead of writing the last length($data) bytes from the block # (because there isn't room for them any longer) return them. # Make a temp dir under the OS's normal temp directory for creating # test files in. By using the OS's temp dir rather than the current # directory, we increase the chances that the tests are run on a tmpfs # file system or similar. This becomes important when the current # directory is on a very slow USB drive for example, as this test file # does lots of file creating, modifying and deleting. my $tempdir = File::Temp::tempdir("Tie-File-XXXXXX", TMPDIR => 1, CLEANUP => 1); print "1..718\n"; my $N = 1; use Tie::File; print "ok $N\n"; $N++; $: = Tie::File::_default_recsep(); my @subtests = qw(x x> 0); print "ok $N\n"; $N++; # (3-144) These were generated by 'gentests.pl' to cover all possible cases # (I hope) # Legend: # x: data is entirely contained within one block # x>: data runs from the middle to the end of the block # : data occupies precisely one block # x>: data runs from the middle of one block to the end of the next # : data occupies two blocks exactly # : data occupies three blocks exactly # 0: data is null # # For each possible alignment of the old and new data, we investigate # up to three situations: old data is shorter, old and new data are the # same length, and new data is shorter. # # try($pos, $old, $new) means to run a test where the data starts at # position $pos, the old data has length $old, # and the new data has length $new. try( 9659, 6635, 6691); # old=x , new=x ; old < new try( 8605, 2394, 2394); # old=x , new=x ; old = new try( 9768, 1361, 664); # old=x , new=x ; old > new try( 9955, 6429, 6429); # old=x> , new=x ; old = new try(10550, 5834, 4123); # old=x> , new=x ; old > new try(14580, 6158, 851); # old=x> new try(13442, 11134, 1572); # old=x> , new=x ; old > new try( 8394, 0, 5742); # old=0 , new=x ; old < new try( 8192, 2819, 6738); # old= new try( 8192, 8192, 8192); # old= , new= , new= new try( 8192, 10575, 6644); # old= new try( 8192, 16384, 5616); # old= , new= new try( 8192, 24576, 6253); # old=, new= new try( 8192, 0, 6870); # old=0 , new= ; old < new try( 9965, 6419, 6419); # old=x> , new=x> ; old = new try(16059, 6102, 325); # old=x> ; old > new try( 9503, 15073, 6881); # old=x> , new=x> ; old > new try( 9759, 0, 6625); # old=0 , new=x> ; old < new try( 8525, 2081, 8534); # old=x , new=x> , new=x> new try(14739, 9837, 9837); # old=x> , new=x> , new=x> new try(12602, 0, 8354); # old=0 , new=x> ; old < new try( 8192, 8192, 8192); # old= , new= ; old = new try( 8192, 14817, 8192); # old= ; old > new try( 8192, 16384, 8192); # old= , new= ; old > new try( 8192, 24576, 8192); # old=, new= ; old > new try( 8192, 0, 8192); # old=0 , new= ; old < new try( 8192, 6532, 10882); # old= , new= new try( 8192, 16384, 10781); # old= , new= new try( 8192, 24576, 9284); # old=, new= new try( 8192, 0, 12488); # old=0 , new= ; old < new try(13500, 2884, 11076); # old=x> , new=x> ; old < new try(14069, 4334, 10507); # old=x> ; old < new try(14761, 9815, 9815); # old=x> , new=x> ; old = new try(10469, 0, 14107); # old=0 , new=x> ; old < new try( 8192, 4181, 16384); # old= ; old < new try( 8192, 8192, 16384); # old= , new= ; old < new try( 8192, 12087, 16384); # old= ; old < new try( 8192, 16384, 16384); # old= , new= ; old = new try( 8192, 24576, 16384); # old=, new= ; old > new try( 8192, 0, 16384); # old=0 , new= ; old < new try( 8192, 4968, 24576); # old=; old < new try( 8192, 8192, 24576); # old= , new=; old < new try( 8192, 14163, 24576); # old=; old < new try( 8192, 16384, 24576); # old= , new=; old < new try( 8192, 24576, 24576); # old=, new=; old = new try( 8192, 0, 24576); # old=0 , new=; old < new try( 8771, 776, 0); # old=x , new=0 ; old > new try( 8192, 2813, 0); # old= new try(13945, 2439, 0); # old=x> , new=0 ; old > new try(14493, 6090, 0); # old=x> new try( 8192, 8192, 0); # old= , new=0 ; old > new try( 8192, 10030, 0); # old= new try(14983, 9593, 0); # old=x> , new=0 ; old > new try( 8192, 16384, 0); # old= , new=0 ; old > new try( 8192, 24576, 0); # old=, new=0 ; old > new try(10489, 0, 0); # old=0 , new=0 ; old = new # (142-223) # These tests all take place at the start of the file try( 0, 771, 1593); # old= new try( 0, 8192, 8192); # old= , new= , new= new try( 0, 11891, 1917); # old= new try( 0, 16384, 5155); # old= , new= new try( 0, 24576, 2953); # old=, new= new try( 0, 0, 1317); # old=0 , new= ; old < new try( 0, 8192, 8192); # old= , new= ; old = new try( 0, 11083, 8192); # old= ; old > new try( 0, 16384, 8192); # old= , new= ; old > new try( 0, 24576, 8192); # old=, new= ; old > new try( 0, 0, 8192); # old=0 , new= ; old < new try( 0, 6265, 9991); # old= , new= new try( 0, 16384, 13258); # old= , new= new try( 0, 24576, 14367); # old=, new= new try( 0, 0, 10881); # old=0 , new= ; old < new try( 0, 8192, 16384); # old= , new= ; old < new try( 0, 15082, 16384); # old= ; old < new try( 0, 16384, 16384); # old= , new= ; old = new try( 0, 24576, 16384); # old=, new= ; old > new try( 0, 0, 16384); # old=0 , new= ; old < new try( 0, 2421, 24576); # old=; old < new try( 0, 8192, 24576); # old= , new=; old < new try( 0, 11655, 24576); # old=; old < new try( 0, 16384, 24576); # old= , new=; old < new try( 0, 24576, 24576); # old=, new=; old = new try( 0, 0, 24576); # old=0 , new=; old < new try( 0, 6530, 0); # old= new try( 0, 8192, 0); # old= , new=0 ; old > new try( 0, 14707, 0); # old= new try( 0, 16384, 0); # old= , new=0 ; old > new try( 0, 24576, 0); # old=, new=0 ; old > new try( 0, 0, 0); # old=0 , new=0 ; old = new # (224-277) # These tests all take place at the end of the file my $FLEN = 40960; # Force the file to be exactly 40960 bytes long try(32768, 8192, 8192); # old= , new= , new= new try(24576, 16384, 1917); # old= , new= new try(16384, 24576, 3818); # old=, new= new try(40960, 0, 2779); # old=0 , new= , new= ; old = new try(24576, 16384, 8192); # old= , new= ; old > new try(16384, 24576, 8192); # old=, new= ; old > new try(40960, 0, 8192); # old=0 , new= ; old < new try(32768, 8192, 10724); # old= , new= , new= new try(16384, 24576, 15030); # old=, new= new try(40960, 0, 11752); # old=0 , new= , new= ; old < new try(24576, 16384, 16384); # old= , new= ; old = new try(16384, 24576, 16384); # old=, new= ; old > new try(40960, 0, 16384); # old=0 , new= ; old < new try(32768, 8192, 24576); # old= , new=; old < new try(24576, 16384, 24576); # old= , new=; old < new try(16384, 24576, 24576); # old=, new=; old = new try(40960, 0, 24576); # old=0 , new=; old < new try(35973, 4987, 0); # old=x> , new=0 ; old > new try(32768, 8192, 0); # old= , new=0 ; old > new try(29932, 11028, 0); # old=x> , new=0 ; old > new try(24576, 16384, 0); # old= , new=0 ; old > new try(16384, 24576, 0); # old=, new=0 ; old > new try(40960, 0, 0); # old=0 , new=0 ; old = new # (278-357) # These tests all take place at the end of the file $FLEN = 42000; # Force the file to be exactly 42000 bytes long try(41275, 725, 4059); # old=x , new=x ; old < new try(41683, 317, 317); # old=x , new=x ; old = new try(41225, 775, 405); # old=x , new=x ; old > new try(35709, 6291, 284); # old=x> new try(42000, 0, 2434); # old=0 , new=x ; old < new try(40960, 1040, 1608); # old= new try(32768, 9232, 5604); # old= new try(42000, 0, 6637); # old=0 , new= ; old < new try(39994, 2006, 966); # old=x> ; old > new try(42000, 0, 7152); # old=0 , new=x> ; old < new try(41613, 387, 10601); # old=x , new=x> new try(42000, 0, 9189); # old=0 , new=x> ; old < new try(32768, 9232, 8192); # old= ; old > new try(42000, 0, 8192); # old=0 , new= ; old < new try(40960, 1040, 11778); # old= new try(42000, 0, 8578); # old=0 , new= ; old < new try(39618, 2382, 9534); # old=x> ; old < new try(42000, 0, 15344); # old=0 , new=x> ; old < new try(40960, 1040, 16384); # old= ; old < new try(32768, 9232, 16384); # old= ; old < new try(42000, 0, 16384); # old=0 , new= ; old < new try(40960, 1040, 24576); # old=; old < new try(32768, 9232, 24576); # old=; old < new try(42000, 0, 24576); # old=0 , new=; old < new try(41500, 500, 0); # old=x , new=0 ; old > new try(40960, 1040, 0); # old= new try(35272, 6728, 0); # old=x> new try(32768, 9232, 0); # old= new try(42000, 0, 0); # old=0 , new=0 ; old = new sub try { my ($pos, $len, $newlen) = @_; try0($pos, $len, $newlen); # if len is undef, it implies 'to the end of the string' try0($pos, undef, $newlen); } sub try0 { my ($pos, $len, $newlen) = @_; my $line = (caller(1))[2]; my $desc = sprintf "try(%5s, %5s, %5s) FLEN=%5s called from line %d", map { defined $_ ? $_ : 'undef' } $pos, $len, $newlen, $FLEN, $line; my ($fh, $file) = File::Temp::tempfile("29-XXXXX", DIR => $tempdir); binmode $fh; # The record has exactly 17 characters. This will help ensure that # even if _downcopy screws up, the data doesn't coincidentally # look good because the remainder accidentally lines up. my $d = substr("0123456789abcdef$:", -17); my $recs = defined($FLEN) ? int($FLEN/length($d))+1 : # enough to make up at least $FLEN int(8192*5/length($d))+1; # at least 5 blocks' worth my $oldfile = $d x $recs; my $flen = defined($FLEN) ? $FLEN : $recs * 17; substr($oldfile, $FLEN) = "" if defined $FLEN; # truncate print $fh $oldfile; close $fh; die "wrong length!" unless -s $file == $flen; my $newdata = "-" x $newlen; my $expected = $oldfile; my $old = defined $len ? substr($expected, $pos, $len) : substr($expected, $pos); $old = "$newdata$old"; my $x_retval; if (defined $len) { substr($expected, $pos, $len, substr($old, 0, $len, "")); $x_retval = $old; } else { substr($expected, $pos) = $old; $x_retval = ""; } my $o = tie my @lines, 'Tie::File', $file or die $!; # allocate more time when are running tests in parallel my $alarm_time = $ENV{TEST_JOBS} || $ENV{HARNESS_OPTIONS} ? 20 : 10; local $SIG{ALRM} = sub { die "Alarm clock" }; my $a_retval = eval { alarm($alarm_time) unless $^P; $o->_downcopy($newdata, $pos, $len) }; my $err = $@; undef $o; untie @lines; alarm(0); if ($err) { if ($err =~ /^Alarm clock/) { print STDERR "# $0 Timeout after $alarm_time seconds at test $N - $desc\n"; print "not ok $N - exp $desc TIMEOUT\n"; $N++; print "not ok $N - ret $desc TIMEOUT\n"; $N++; return; } else { $@ = $err; die; } } open F, '<', $file or die "Couldn't open file $file: $!"; binmode F; my $actual; { local $/; $actual = ; } close F; my ($alen, $xlen) = (length $actual, length $expected); unless ($alen == $xlen) { my @ARGS = @_; for (@ARGS) { $_ = "UNDEF" unless defined } print "# try(@ARGS) expected file length $xlen, actual $alen!\n"; } print $actual eq $expected ? "ok $N - exp $desc\n" : "not ok $N - exp $desc\n"; $N++; print $a_retval eq $x_retval ? "ok $N - ret $desc\n" : "not ok $N - ret $desc\n"; $N++; }