1b39c5158Smillert#!./perl -w 2b39c5158Smillert 3b39c5158Smillertuse strict; 4b39c5158Smillertuse Config; 5b39c5158Smillert 6b39c5158SmillertBEGIN { 7898184e3Ssthen if(-d "lib" && -f "TEST") { 8b39c5158Smillert if ($Config{'extensions'} !~ /\bDB_File\b/ ) { 9b39c5158Smillert print "1..0 # Skip: DB_File was not built\n"; 10b39c5158Smillert exit 0; 11b39c5158Smillert } 12b39c5158Smillert } 13b39c5158Smillert} 14b39c5158Smillert 15b39c5158Smillertuse DB_File; 16b39c5158Smillertuse Fcntl; 17f3efcd01Safresh1use File::Temp qw(tempdir) ; 18f3efcd01Safresh1 19b39c5158Smillertour ($dbh, $Dfile, $bad_ones, $FA); 20b39c5158Smillert 21b39c5158Smillert# full tied array support started in Perl 5.004_57 22b39c5158Smillert# Double check to see if it is available. 23b39c5158Smillert 24b39c5158Smillert{ 25b39c5158Smillert sub try::TIEARRAY { bless [], "try" } 26b39c5158Smillert sub try::FETCHSIZE { $FA = 1 } 27b39c5158Smillert $FA = 0 ; 28b39c5158Smillert my @a ; 29b39c5158Smillert tie @a, 'try' ; 30b39c5158Smillert my $a = @a ; 31b39c5158Smillert} 32b39c5158Smillert 33b39c5158Smillert 34b39c5158Smillertsub ok 35b39c5158Smillert{ 36b39c5158Smillert my $no = shift ; 37b39c5158Smillert my $result = shift ; 38b39c5158Smillert 39b39c5158Smillert print "not " unless $result ; 40b39c5158Smillert print "ok $no\n" ; 41b39c5158Smillert 42b39c5158Smillert return $result ; 43b39c5158Smillert} 44b39c5158Smillert 45b39c5158Smillert{ 46b39c5158Smillert package Redirect ; 47b39c5158Smillert use Symbol ; 48b39c5158Smillert 49b39c5158Smillert sub new 50b39c5158Smillert { 51b39c5158Smillert my $class = shift ; 52b39c5158Smillert my $filename = shift ; 53b39c5158Smillert my $fh = gensym ; 54b39c5158Smillert open ($fh, ">$filename") || die "Cannot open $filename: $!" ; 55b39c5158Smillert my $real_stdout = select($fh) ; 56b39c5158Smillert return bless [$fh, $real_stdout ] ; 57b39c5158Smillert 58b39c5158Smillert } 59b39c5158Smillert sub DESTROY 60b39c5158Smillert { 61b39c5158Smillert my $self = shift ; 62b39c5158Smillert close $self->[0] ; 63b39c5158Smillert select($self->[1]) ; 64b39c5158Smillert } 65b39c5158Smillert} 66b39c5158Smillert 67b39c5158Smillertsub docat 68b39c5158Smillert{ 69b39c5158Smillert my $file = shift; 70b39c5158Smillert local $/ = undef; 71b39c5158Smillert open(CAT,$file) || die "Cannot open $file:$!"; 72b39c5158Smillert my $result = <CAT>; 73b39c5158Smillert close(CAT); 74b39c5158Smillert normalise($result) ; 75b39c5158Smillert return $result; 76b39c5158Smillert} 77b39c5158Smillert 78b39c5158Smillertsub docat_del 79b39c5158Smillert{ 80b39c5158Smillert my $file = shift; 81b39c5158Smillert my $result = docat($file); 82b39c5158Smillert unlink $file ; 83b39c5158Smillert return $result; 84b39c5158Smillert} 85b39c5158Smillert 86b39c5158Smillertsub safeUntie 87b39c5158Smillert{ 88b39c5158Smillert my $hashref = shift ; 89b39c5158Smillert my $no_inner = 1; 90b39c5158Smillert local $SIG{__WARN__} = sub {-- $no_inner } ; 91b39c5158Smillert untie @$hashref; 92b39c5158Smillert return $no_inner; 93b39c5158Smillert} 94b39c5158Smillert 95b39c5158Smillertsub bad_one 96b39c5158Smillert{ 97b39c5158Smillert unless ($bad_ones++) { 98b39c5158Smillert print STDERR <<EOM ; 99b39c5158Smillert# 100b39c5158Smillert# Some older versions of Berkeley DB version 1 will fail db-recno 101b39c5158Smillert# tests 61, 63, 64 and 65. 102b39c5158SmillertEOM 103b39c5158Smillert if ($^O eq 'darwin' 104b39c5158Smillert && $Config{db_version_major} == 1 105b39c5158Smillert && $Config{db_version_minor} == 0 106b39c5158Smillert && $Config{db_version_patch} == 0) { 107b39c5158Smillert print STDERR <<EOM ; 108b39c5158Smillert# 109b39c5158Smillert# For example Mac OS X 10.2 (or earlier) has such an old 110b39c5158Smillert# version of Berkeley DB. 111b39c5158SmillertEOM 112b39c5158Smillert } 113b39c5158Smillert 114b39c5158Smillert print STDERR <<EOM ; 115b39c5158Smillert# 116b39c5158Smillert# You can safely ignore the errors if you're never going to use the 117b39c5158Smillert# broken functionality (recno databases with a modified bval). 118b39c5158Smillert# Otherwise you'll have to upgrade your DB library. 119b39c5158Smillert# 120b39c5158Smillert# If you want to use Berkeley DB version 1, then 1.85 and 1.86 are the 121b39c5158Smillert# last versions that were released. Berkeley DB version 2 is continually 122b39c5158Smillert# being updated -- Check out http://www.sleepycat.com/ for more details. 123b39c5158Smillert# 124b39c5158SmillertEOM 125b39c5158Smillert } 126b39c5158Smillert} 127b39c5158Smillert 128b39c5158Smillertsub normalise 129b39c5158Smillert{ 130b39c5158Smillert return unless $^O eq 'cygwin' ; 131b39c5158Smillert foreach (@_) 132b39c5158Smillert { s#\r\n#\n#g } 133b39c5158Smillert} 134b39c5158Smillert 135b39c5158SmillertBEGIN 136b39c5158Smillert{ 137b39c5158Smillert { 138b39c5158Smillert local $SIG{__DIE__} ; 139*256a93a4Safresh1 eval { require Data::Dumper; Data::Dumper->import(); } ; 140b39c5158Smillert } 141b39c5158Smillert 142b39c5158Smillert if ($@) { 143b39c5158Smillert *Dumper = sub { my $a = shift; return "[ @{ $a } ]" } ; 144b39c5158Smillert } 145b39c5158Smillert} 146b39c5158Smillert 147b39c5158Smillertmy $splice_tests = 10 + 12 + 1; # ten regressions, plus the randoms 148b39c5158Smillertmy $total_tests = 181 ; 149b39c5158Smillert$total_tests += $splice_tests if $FA ; 150b39c5158Smillertprint "1..$total_tests\n"; 151b39c5158Smillert 152f3efcd01Safresh1my $TEMPDIR = tempdir( CLEANUP => 1 ); 153f3efcd01Safresh1chdir $TEMPDIR; 154f3efcd01Safresh1 155b39c5158Smillert$Dfile = "recno.tmp"; 156b39c5158Smillertunlink $Dfile ; 157b39c5158Smillert 158b39c5158Smillertumask(0); 159b39c5158Smillert 160b39c5158Smillert# Check the interface to RECNOINFO 161b39c5158Smillert 162*256a93a4Safresh1$dbh = DB_File::RECNOINFO->new(); 163b39c5158Smillertok(1, ! defined $dbh->{bval}) ; 164b39c5158Smillertok(2, ! defined $dbh->{cachesize}) ; 165b39c5158Smillertok(3, ! defined $dbh->{psize}) ; 166b39c5158Smillertok(4, ! defined $dbh->{flags}) ; 167b39c5158Smillertok(5, ! defined $dbh->{lorder}) ; 168b39c5158Smillertok(6, ! defined $dbh->{reclen}) ; 169b39c5158Smillertok(7, ! defined $dbh->{bfname}) ; 170b39c5158Smillert 171b39c5158Smillert$dbh->{bval} = 3000 ; 172b39c5158Smillertok(8, $dbh->{bval} == 3000 ); 173b39c5158Smillert 174b39c5158Smillert$dbh->{cachesize} = 9000 ; 175b39c5158Smillertok(9, $dbh->{cachesize} == 9000 ); 176b39c5158Smillert 177b39c5158Smillert$dbh->{psize} = 400 ; 178b39c5158Smillertok(10, $dbh->{psize} == 400 ); 179b39c5158Smillert 180b39c5158Smillert$dbh->{flags} = 65 ; 181b39c5158Smillertok(11, $dbh->{flags} == 65 ); 182b39c5158Smillert 183b39c5158Smillert$dbh->{lorder} = 123 ; 184b39c5158Smillertok(12, $dbh->{lorder} == 123 ); 185b39c5158Smillert 186b39c5158Smillert$dbh->{reclen} = 1234 ; 187b39c5158Smillertok(13, $dbh->{reclen} == 1234 ); 188b39c5158Smillert 189b39c5158Smillert$dbh->{bfname} = 1234 ; 190b39c5158Smillertok(14, $dbh->{bfname} == 1234 ); 191b39c5158Smillert 192b39c5158Smillert 193b39c5158Smillert# Check that an invalid entry is caught both for store & fetch 194b39c5158Smillerteval '$dbh->{fred} = 1234' ; 195b39c5158Smillertok(15, $@ =~ /^DB_File::RECNOINFO::STORE - Unknown element 'fred' at/ ); 196b39c5158Smillerteval 'my $q = $dbh->{fred}' ; 197b39c5158Smillertok(16, $@ =~ /^DB_File::RECNOINFO::FETCH - Unknown element 'fred' at/ ); 198b39c5158Smillert 199b39c5158Smillert# Now check the interface to RECNOINFO 200b39c5158Smillert 201b39c5158Smillertmy $X ; 202b39c5158Smillertmy @h ; 203b39c5158Smillertok(17, $X = tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ; 204b39c5158Smillert 205b39c5158Smillertmy %noMode = map { $_, 1} qw( amigaos MSWin32 NetWare cygwin ) ; 206b39c5158Smillert 207b39c5158Smillertok(18, ((stat($Dfile))[2] & 0777) == (($^O eq 'os2' || $^O eq 'MacOS') ? 0666 : 0640) 208b39c5158Smillert || $noMode{$^O} ); 209b39c5158Smillert 210b39c5158Smillert#my $l = @h ; 211b39c5158Smillertmy $l = $X->length ; 212b39c5158Smillertok(19, ($FA ? @h == 0 : !$l) ); 213b39c5158Smillert 214b39c5158Smillertmy @data = qw( a b c d ever f g h i j k longername m n o p) ; 215b39c5158Smillert 216b39c5158Smillert$h[0] = shift @data ; 217b39c5158Smillertok(20, $h[0] eq 'a' ); 218b39c5158Smillert 219b39c5158Smillertmy $ i; 220b39c5158Smillertforeach (@data) 221b39c5158Smillert { $h[++$i] = $_ } 222b39c5158Smillert 223b39c5158Smillertunshift (@data, 'a') ; 224b39c5158Smillert 225b39c5158Smillertok(21, defined $h[1] ); 226b39c5158Smillertok(22, ! defined $h[16] ); 227b39c5158Smillertok(23, $FA ? @h == @data : $X->length == @data ); 228b39c5158Smillert 229b39c5158Smillert 230b39c5158Smillert# Overwrite an entry & check fetch it 231b39c5158Smillert$h[3] = 'replaced' ; 232b39c5158Smillert$data[3] = 'replaced' ; 233b39c5158Smillertok(24, $h[3] eq 'replaced' ); 234b39c5158Smillert 235b39c5158Smillert#PUSH 236b39c5158Smillertmy @push_data = qw(added to the end) ; 237b39c5158Smillert($FA ? push(@h, @push_data) : $X->push(@push_data)) ; 238b39c5158Smillertpush (@data, @push_data) ; 239b39c5158Smillertok(25, $h[++$i] eq 'added' ); 240b39c5158Smillertok(26, $h[++$i] eq 'to' ); 241b39c5158Smillertok(27, $h[++$i] eq 'the' ); 242b39c5158Smillertok(28, $h[++$i] eq 'end' ); 243b39c5158Smillert 244b39c5158Smillert# POP 245b39c5158Smillertmy $popped = pop (@data) ; 246b39c5158Smillertmy $value = ($FA ? pop @h : $X->pop) ; 247b39c5158Smillertok(29, $value eq $popped) ; 248b39c5158Smillert 249b39c5158Smillert# SHIFT 250b39c5158Smillert$value = ($FA ? shift @h : $X->shift) ; 251b39c5158Smillertmy $shifted = shift @data ; 252b39c5158Smillertok(30, $value eq $shifted ); 253b39c5158Smillert 254b39c5158Smillert# UNSHIFT 255b39c5158Smillert 256b39c5158Smillert# empty list 257b39c5158Smillert($FA ? unshift @h,() : $X->unshift) ; 258b39c5158Smillertok(31, ($FA ? @h == @data : $X->length == @data )); 259b39c5158Smillert 260b39c5158Smillertmy @new_data = qw(add this to the start of the array) ; 261b39c5158Smillert$FA ? unshift (@h, @new_data) : $X->unshift (@new_data) ; 262b39c5158Smillertunshift (@data, @new_data) ; 263b39c5158Smillertok(32, $FA ? @h == @data : $X->length == @data ); 264b39c5158Smillertok(33, $h[0] eq "add") ; 265b39c5158Smillertok(34, $h[1] eq "this") ; 266b39c5158Smillertok(35, $h[2] eq "to") ; 267b39c5158Smillertok(36, $h[3] eq "the") ; 268b39c5158Smillertok(37, $h[4] eq "start") ; 269b39c5158Smillertok(38, $h[5] eq "of") ; 270b39c5158Smillertok(39, $h[6] eq "the") ; 271b39c5158Smillertok(40, $h[7] eq "array") ; 272b39c5158Smillertok(41, $h[8] eq $data[8]) ; 273b39c5158Smillert 274b39c5158Smillert# Brief test for SPLICE - more thorough 'soak test' is later. 275b39c5158Smillertmy @old; 276b39c5158Smillertif ($FA) { 277b39c5158Smillert @old = splice(@h, 1, 2, qw(bananas just before)); 278b39c5158Smillert} 279b39c5158Smillertelse { 280b39c5158Smillert @old = $X->splice(1, 2, qw(bananas just before)); 281b39c5158Smillert} 282b39c5158Smillertok(42, $h[0] eq "add") ; 283b39c5158Smillertok(43, $h[1] eq "bananas") ; 284b39c5158Smillertok(44, $h[2] eq "just") ; 285b39c5158Smillertok(45, $h[3] eq "before") ; 286b39c5158Smillertok(46, $h[4] eq "the") ; 287b39c5158Smillertok(47, $h[5] eq "start") ; 288b39c5158Smillertok(48, $h[6] eq "of") ; 289b39c5158Smillertok(49, $h[7] eq "the") ; 290b39c5158Smillertok(50, $h[8] eq "array") ; 291b39c5158Smillertok(51, $h[9] eq $data[8]) ; 292b39c5158Smillert$FA ? splice(@h, 1, 3, @old) : $X->splice(1, 3, @old); 293b39c5158Smillert 294b39c5158Smillert# Now both arrays should be identical 295b39c5158Smillert 296b39c5158Smillertmy $ok = 1 ; 297b39c5158Smillertmy $j = 0 ; 298b39c5158Smillertforeach (@data) 299b39c5158Smillert{ 300b39c5158Smillert $ok = 0, last if $_ ne $h[$j ++] ; 301b39c5158Smillert} 302b39c5158Smillertok(52, $ok ); 303b39c5158Smillert 304b39c5158Smillert# Neagtive subscripts 305b39c5158Smillert 306b39c5158Smillert# get the last element of the array 307b39c5158Smillertok(53, $h[-1] eq $data[-1] ); 308b39c5158Smillertok(54, $h[-1] eq $h[ ($FA ? @h : $X->length) -1] ); 309b39c5158Smillert 310b39c5158Smillert# get the first element using a negative subscript 311b39c5158Smillerteval '$h[ - ( $FA ? @h : $X->length)] = "abcd"' ; 312b39c5158Smillertok(55, $@ eq "" ); 313b39c5158Smillertok(56, $h[0] eq "abcd" ); 314b39c5158Smillert 315b39c5158Smillert# now try to read before the start of the array 316b39c5158Smillerteval '$h[ - (1 + ($FA ? @h : $X->length))] = 1234' ; 317b39c5158Smillertok(57, $@ =~ '^Modification of non-creatable array value attempted' ); 318b39c5158Smillert 319b39c5158Smillert# IMPORTANT - $X must be undefined before the untie otherwise the 320b39c5158Smillert# underlying DB close routine will not get called. 321b39c5158Smillertundef $X ; 322b39c5158Smillertok(58, safeUntie \@h); 323b39c5158Smillert 324b39c5158Smillertunlink $Dfile; 325b39c5158Smillert 326b39c5158Smillert 327b39c5158Smillert{ 328b39c5158Smillert # Check bval defaults to \n 329b39c5158Smillert 330b39c5158Smillert my @h = () ; 331*256a93a4Safresh1 my $dbh = DB_File::RECNOINFO->new(); 332b39c5158Smillert ok(59, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ; 333b39c5158Smillert $h[0] = "abc" ; 334b39c5158Smillert $h[1] = "def" ; 335b39c5158Smillert $h[3] = "ghi" ; 336b39c5158Smillert ok(60, safeUntie \@h); 337b39c5158Smillert my $x = docat($Dfile) ; 338b39c5158Smillert unlink $Dfile; 339b39c5158Smillert ok(61, $x eq "abc\ndef\n\nghi\n") ; 340b39c5158Smillert} 341b39c5158Smillert 342b39c5158Smillert{ 343b39c5158Smillert # Change bval 344b39c5158Smillert 345b39c5158Smillert my @h = () ; 346*256a93a4Safresh1 my $dbh = DB_File::RECNOINFO->new(); 347b39c5158Smillert $dbh->{bval} = "-" ; 348b39c5158Smillert ok(62, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ; 349b39c5158Smillert $h[0] = "abc" ; 350b39c5158Smillert $h[1] = "def" ; 351b39c5158Smillert $h[3] = "ghi" ; 352b39c5158Smillert ok(63, safeUntie \@h); 353b39c5158Smillert my $x = docat($Dfile) ; 354b39c5158Smillert unlink $Dfile; 355b39c5158Smillert my $ok = ($x eq "abc-def--ghi-") ; 356b39c5158Smillert bad_one() unless $ok ; 357b39c5158Smillert ok(64, $ok) ; 358b39c5158Smillert} 359b39c5158Smillert 360b39c5158Smillert{ 361b39c5158Smillert # Check R_FIXEDLEN with default bval (space) 362b39c5158Smillert 363b39c5158Smillert my @h = () ; 364*256a93a4Safresh1 my $dbh = DB_File::RECNOINFO->new(); 365b39c5158Smillert $dbh->{flags} = R_FIXEDLEN ; 366b39c5158Smillert $dbh->{reclen} = 5 ; 367b39c5158Smillert ok(65, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ; 368b39c5158Smillert $h[0] = "abc" ; 369b39c5158Smillert $h[1] = "def" ; 370b39c5158Smillert $h[3] = "ghi" ; 371b39c5158Smillert ok(66, safeUntie \@h); 372b39c5158Smillert my $x = docat($Dfile) ; 373b39c5158Smillert unlink $Dfile; 374b39c5158Smillert my $ok = ($x eq "abc def ghi ") ; 375b39c5158Smillert bad_one() unless $ok ; 376b39c5158Smillert ok(67, $ok) ; 377b39c5158Smillert} 378b39c5158Smillert 379b39c5158Smillert{ 380b39c5158Smillert # Check R_FIXEDLEN with user-defined bval 381b39c5158Smillert 382b39c5158Smillert my @h = () ; 383*256a93a4Safresh1 my $dbh = DB_File::RECNOINFO->new(); 384b39c5158Smillert $dbh->{flags} = R_FIXEDLEN ; 385b39c5158Smillert $dbh->{bval} = "-" ; 386b39c5158Smillert $dbh->{reclen} = 5 ; 387b39c5158Smillert ok(68, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ; 388b39c5158Smillert $h[0] = "abc" ; 389b39c5158Smillert $h[1] = "def" ; 390b39c5158Smillert $h[3] = "ghi" ; 391b39c5158Smillert ok(69, safeUntie \@h); 392b39c5158Smillert my $x = docat($Dfile) ; 393b39c5158Smillert unlink $Dfile; 394b39c5158Smillert my $ok = ($x eq "abc--def-------ghi--") ; 395b39c5158Smillert bad_one() unless $ok ; 396b39c5158Smillert ok(70, $ok) ; 397b39c5158Smillert} 398b39c5158Smillert 399b39c5158Smillert{ 400b39c5158Smillert # check that attempting to tie an associative array to a DB_RECNO will fail 401b39c5158Smillert 402b39c5158Smillert my $filename = "xyz" ; 403b39c5158Smillert my %x ; 404b39c5158Smillert eval { tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0640, $DB_RECNO ; } ; 405b39c5158Smillert ok(71, $@ =~ /^DB_File can only tie an array to a DB_RECNO database/) ; 406b39c5158Smillert unlink $filename ; 407b39c5158Smillert} 408b39c5158Smillert 409b39c5158Smillert{ 410b39c5158Smillert # sub-class test 411b39c5158Smillert 412b39c5158Smillert package Another ; 413b39c5158Smillert 414b39c5158Smillert use warnings ; 415b39c5158Smillert use strict ; 416b39c5158Smillert 417b39c5158Smillert open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ; 418b39c5158Smillert print FILE <<'EOM' ; 419b39c5158Smillert 420b39c5158Smillert package SubDB ; 421b39c5158Smillert 422b39c5158Smillert use warnings ; 423b39c5158Smillert use strict ; 424b39c5158Smillert our (@ISA, @EXPORT); 425b39c5158Smillert 426b39c5158Smillert require Exporter ; 427b39c5158Smillert use DB_File; 428b39c5158Smillert @ISA=qw(DB_File); 429b39c5158Smillert @EXPORT = @DB_File::EXPORT ; 430b39c5158Smillert 431b39c5158Smillert sub STORE { 432b39c5158Smillert my $self = shift ; 433b39c5158Smillert my $key = shift ; 434b39c5158Smillert my $value = shift ; 435b39c5158Smillert $self->SUPER::STORE($key, $value * 2) ; 436b39c5158Smillert } 437b39c5158Smillert 438b39c5158Smillert sub FETCH { 439b39c5158Smillert my $self = shift ; 440b39c5158Smillert my $key = shift ; 441b39c5158Smillert $self->SUPER::FETCH($key) - 1 ; 442b39c5158Smillert } 443b39c5158Smillert 444b39c5158Smillert sub put { 445b39c5158Smillert my $self = shift ; 446b39c5158Smillert my $key = shift ; 447b39c5158Smillert my $value = shift ; 448b39c5158Smillert $self->SUPER::put($key, $value * 3) ; 449b39c5158Smillert } 450b39c5158Smillert 451b39c5158Smillert sub get { 452b39c5158Smillert my $self = shift ; 453b39c5158Smillert $self->SUPER::get($_[0], $_[1]) ; 454b39c5158Smillert $_[1] -= 2 ; 455b39c5158Smillert } 456b39c5158Smillert 457b39c5158Smillert sub A_new_method 458b39c5158Smillert { 459b39c5158Smillert my $self = shift ; 460b39c5158Smillert my $key = shift ; 461b39c5158Smillert my $value = $self->FETCH($key) ; 462b39c5158Smillert return "[[$value]]" ; 463b39c5158Smillert } 464b39c5158Smillert 465b39c5158Smillert 1 ; 466b39c5158SmillertEOM 467b39c5158Smillert 468b39c5158Smillert close FILE or die "Could not close: $!"; 469b39c5158Smillert 470b39c5158Smillert BEGIN { push @INC, '.'; } 471b39c5158Smillert eval 'use SubDB ; '; 472b39c5158Smillert main::ok(72, $@ eq "") ; 473b39c5158Smillert my @h ; 474b39c5158Smillert my $X ; 475b39c5158Smillert eval ' 476b39c5158Smillert $X = tie(@h, "SubDB","recno.tmp", O_RDWR|O_CREAT, 0640, $DB_RECNO ); 477b39c5158Smillert ' ; 478b39c5158Smillert die "Could not tie: $!" unless $X; 479b39c5158Smillert 480b39c5158Smillert main::ok(73, $@ eq "") ; 481b39c5158Smillert 482b39c5158Smillert my $ret = eval '$h[3] = 3 ; return $h[3] ' ; 483b39c5158Smillert main::ok(74, $@ eq "") ; 484b39c5158Smillert main::ok(75, $ret == 5) ; 485b39c5158Smillert 486b39c5158Smillert my $value = 0; 487b39c5158Smillert $ret = eval '$X->put(1, 4) ; $X->get(1, $value) ; return $value' ; 488b39c5158Smillert main::ok(76, $@ eq "") ; 489b39c5158Smillert main::ok(77, $ret == 10) ; 490b39c5158Smillert 491b39c5158Smillert $ret = eval ' R_NEXT eq main::R_NEXT ' ; 492b39c5158Smillert main::ok(78, $@ eq "" ) ; 493b39c5158Smillert main::ok(79, $ret == 1) ; 494b39c5158Smillert 495b39c5158Smillert $ret = eval '$X->A_new_method(1) ' ; 496b39c5158Smillert main::ok(80, $@ eq "") ; 497b39c5158Smillert main::ok(81, $ret eq "[[11]]") ; 498b39c5158Smillert 499b39c5158Smillert undef $X; 500b39c5158Smillert main::ok(82, main::safeUntie \@h); 501b39c5158Smillert unlink "SubDB.pm", "recno.tmp" ; 502b39c5158Smillert 503b39c5158Smillert} 504b39c5158Smillert 505b39c5158Smillert{ 506b39c5158Smillert 507b39c5158Smillert # test $# 508b39c5158Smillert my $self ; 509b39c5158Smillert unlink $Dfile; 510b39c5158Smillert ok(83, $self = tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ; 511b39c5158Smillert $h[0] = "abc" ; 512b39c5158Smillert $h[1] = "def" ; 513b39c5158Smillert $h[2] = "ghi" ; 514b39c5158Smillert $h[3] = "jkl" ; 515b39c5158Smillert ok(84, $FA ? $#h == 3 : $self->length() == 4) ; 516b39c5158Smillert undef $self ; 517b39c5158Smillert ok(85, safeUntie \@h); 518b39c5158Smillert my $x = docat($Dfile) ; 519b39c5158Smillert ok(86, $x eq "abc\ndef\nghi\njkl\n") ; 520b39c5158Smillert 521b39c5158Smillert # $# sets array to same length 522b39c5158Smillert $self = tie @h, 'DB_File', $Dfile, O_RDWR, 0640, $DB_RECNO ; 523b39c5158Smillert ok(87, $self) 524b39c5158Smillert or warn "# $DB_File::Error\n"; 525b39c5158Smillert if ($FA) 526b39c5158Smillert { $#h = 3 } 527b39c5158Smillert else 528b39c5158Smillert { $self->STORESIZE(4) } 529b39c5158Smillert ok(88, $FA ? $#h == 3 : $self->length() == 4) ; 530b39c5158Smillert undef $self ; 531b39c5158Smillert ok(89, safeUntie \@h); 532b39c5158Smillert $x = docat($Dfile) ; 533b39c5158Smillert ok(90, $x eq "abc\ndef\nghi\njkl\n") ; 534b39c5158Smillert 535b39c5158Smillert # $# sets array to bigger 536b39c5158Smillert ok(91, $self = tie @h, 'DB_File', $Dfile, O_RDWR, 0640, $DB_RECNO ) ; 537b39c5158Smillert if ($FA) 538b39c5158Smillert { $#h = 6 } 539b39c5158Smillert else 540b39c5158Smillert { $self->STORESIZE(7) } 541b39c5158Smillert ok(92, $FA ? $#h == 6 : $self->length() == 7) ; 542b39c5158Smillert undef $self ; 543b39c5158Smillert ok(93, safeUntie \@h); 544b39c5158Smillert $x = docat($Dfile) ; 545b39c5158Smillert ok(94, $x eq "abc\ndef\nghi\njkl\n\n\n\n") ; 546b39c5158Smillert 547b39c5158Smillert # $# sets array smaller 548b39c5158Smillert ok(95, $self = tie @h, 'DB_File', $Dfile, O_RDWR, 0640, $DB_RECNO ) ; 549b39c5158Smillert if ($FA) 550b39c5158Smillert { $#h = 2 } 551b39c5158Smillert else 552b39c5158Smillert { $self->STORESIZE(3) } 553b39c5158Smillert ok(96, $FA ? $#h == 2 : $self->length() == 3) ; 554b39c5158Smillert undef $self ; 555b39c5158Smillert ok(97, safeUntie \@h); 556b39c5158Smillert $x = docat($Dfile) ; 557b39c5158Smillert ok(98, $x eq "abc\ndef\nghi\n") ; 558b39c5158Smillert 559b39c5158Smillert unlink $Dfile; 560b39c5158Smillert 561b39c5158Smillert 562b39c5158Smillert} 563b39c5158Smillert 564b39c5158Smillert{ 565b39c5158Smillert # DBM Filter tests 566b39c5158Smillert use warnings ; 567b39c5158Smillert use strict ; 568b39c5158Smillert my (@h, $db) ; 569b39c5158Smillert my ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 570b39c5158Smillert unlink $Dfile; 571b39c5158Smillert 572b39c5158Smillert sub checkOutput 573b39c5158Smillert { 574b39c5158Smillert my($fk, $sk, $fv, $sv) = @_ ; 575b39c5158Smillert 576b39c5158Smillert print "# Fetch Key : expected '$fk' got '$fetch_key'\n" 577b39c5158Smillert if $fetch_key ne $fk ; 578b39c5158Smillert print "# Fetch Value : expected '$fv' got '$fetch_value'\n" 579b39c5158Smillert if $fetch_value ne $fv ; 580b39c5158Smillert print "# Store Key : expected '$sk' got '$store_key'\n" 581b39c5158Smillert if $store_key ne $sk ; 582b39c5158Smillert print "# Store Value : expected '$sv' got '$store_value'\n" 583b39c5158Smillert if $store_value ne $sv ; 584b39c5158Smillert print "# \$_ : expected 'original' got '$_'\n" 585b39c5158Smillert if $_ ne 'original' ; 586b39c5158Smillert 587b39c5158Smillert return 588b39c5158Smillert $fetch_key eq $fk && $store_key eq $sk && 589b39c5158Smillert $fetch_value eq $fv && $store_value eq $sv && 590b39c5158Smillert $_ eq 'original' ; 591b39c5158Smillert } 592b39c5158Smillert 593b39c5158Smillert ok(99, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ); 594b39c5158Smillert 595b39c5158Smillert $db->filter_fetch_key (sub { $fetch_key = $_ }) ; 596b39c5158Smillert $db->filter_store_key (sub { $store_key = $_ }) ; 597b39c5158Smillert $db->filter_fetch_value (sub { $fetch_value = $_}) ; 598b39c5158Smillert $db->filter_store_value (sub { $store_value = $_ }) ; 599b39c5158Smillert 600b39c5158Smillert $_ = "original" ; 601b39c5158Smillert 602b39c5158Smillert $h[0] = "joe" ; 603b39c5158Smillert # fk sk fv sv 604b39c5158Smillert ok(100, checkOutput( "", 0, "", "joe")) ; 605b39c5158Smillert 606b39c5158Smillert ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 607b39c5158Smillert ok(101, $h[0] eq "joe"); 608b39c5158Smillert # fk sk fv sv 609b39c5158Smillert ok(102, checkOutput( "", 0, "joe", "")) ; 610b39c5158Smillert 611b39c5158Smillert ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 612b39c5158Smillert ok(103, $db->FIRSTKEY() == 0) ; 613b39c5158Smillert # fk sk fv sv 614b39c5158Smillert ok(104, checkOutput( 0, "", "", "")) ; 615b39c5158Smillert 616b39c5158Smillert # replace the filters, but remember the previous set 617b39c5158Smillert my ($old_fk) = $db->filter_fetch_key 618b39c5158Smillert (sub { ++ $_ ; $fetch_key = $_ }) ; 619b39c5158Smillert my ($old_sk) = $db->filter_store_key 620b39c5158Smillert (sub { $_ *= 2 ; $store_key = $_ }) ; 621b39c5158Smillert my ($old_fv) = $db->filter_fetch_value 622b39c5158Smillert (sub { $_ = "[$_]"; $fetch_value = $_ }) ; 623b39c5158Smillert my ($old_sv) = $db->filter_store_value 624b39c5158Smillert (sub { s/o/x/g; $store_value = $_ }) ; 625b39c5158Smillert 626b39c5158Smillert ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 627b39c5158Smillert $h[1] = "Joe" ; 628b39c5158Smillert # fk sk fv sv 629b39c5158Smillert ok(105, checkOutput( "", 2, "", "Jxe")) ; 630b39c5158Smillert 631b39c5158Smillert ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 632b39c5158Smillert ok(106, $h[1] eq "[Jxe]"); 633b39c5158Smillert # fk sk fv sv 634b39c5158Smillert ok(107, checkOutput( "", 2, "[Jxe]", "")) ; 635b39c5158Smillert 636b39c5158Smillert ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 637b39c5158Smillert ok(108, $db->FIRSTKEY() == 1) ; 638b39c5158Smillert # fk sk fv sv 639b39c5158Smillert ok(109, checkOutput( 1, "", "", "")) ; 640b39c5158Smillert 641b39c5158Smillert # put the original filters back 642b39c5158Smillert $db->filter_fetch_key ($old_fk); 643b39c5158Smillert $db->filter_store_key ($old_sk); 644b39c5158Smillert $db->filter_fetch_value ($old_fv); 645b39c5158Smillert $db->filter_store_value ($old_sv); 646b39c5158Smillert 647b39c5158Smillert ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 648b39c5158Smillert $h[0] = "joe" ; 649b39c5158Smillert ok(110, checkOutput( "", 0, "", "joe")) ; 650b39c5158Smillert 651b39c5158Smillert ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 652b39c5158Smillert ok(111, $h[0] eq "joe"); 653b39c5158Smillert ok(112, checkOutput( "", 0, "joe", "")) ; 654b39c5158Smillert 655b39c5158Smillert ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 656b39c5158Smillert ok(113, $db->FIRSTKEY() == 0) ; 657b39c5158Smillert ok(114, checkOutput( 0, "", "", "")) ; 658b39c5158Smillert 659b39c5158Smillert # delete the filters 660b39c5158Smillert $db->filter_fetch_key (undef); 661b39c5158Smillert $db->filter_store_key (undef); 662b39c5158Smillert $db->filter_fetch_value (undef); 663b39c5158Smillert $db->filter_store_value (undef); 664b39c5158Smillert 665b39c5158Smillert ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 666b39c5158Smillert $h[0] = "joe" ; 667b39c5158Smillert ok(115, checkOutput( "", "", "", "")) ; 668b39c5158Smillert 669b39c5158Smillert ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 670b39c5158Smillert ok(116, $h[0] eq "joe"); 671b39c5158Smillert ok(117, checkOutput( "", "", "", "")) ; 672b39c5158Smillert 673b39c5158Smillert ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; 674b39c5158Smillert ok(118, $db->FIRSTKEY() == 0) ; 675b39c5158Smillert ok(119, checkOutput( "", "", "", "")) ; 676b39c5158Smillert 677b39c5158Smillert undef $db ; 678b39c5158Smillert ok(120, safeUntie \@h); 679b39c5158Smillert unlink $Dfile; 680b39c5158Smillert} 681b39c5158Smillert 682b39c5158Smillert{ 683b39c5158Smillert # DBM Filter with a closure 684b39c5158Smillert 685b39c5158Smillert use warnings ; 686b39c5158Smillert use strict ; 687b39c5158Smillert my (@h, $db) ; 688b39c5158Smillert 689b39c5158Smillert unlink $Dfile; 690b39c5158Smillert ok(121, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ); 691b39c5158Smillert 692b39c5158Smillert my %result = () ; 693b39c5158Smillert 694b39c5158Smillert sub Closure 695b39c5158Smillert { 696b39c5158Smillert my ($name) = @_ ; 697b39c5158Smillert my $count = 0 ; 698b39c5158Smillert my @kept = () ; 699b39c5158Smillert 700b39c5158Smillert return sub { ++$count ; 701b39c5158Smillert push @kept, $_ ; 702b39c5158Smillert $result{$name} = "$name - $count: [@kept]" ; 703b39c5158Smillert } 704b39c5158Smillert } 705b39c5158Smillert 706b39c5158Smillert $db->filter_store_key(Closure("store key")) ; 707b39c5158Smillert $db->filter_store_value(Closure("store value")) ; 708b39c5158Smillert $db->filter_fetch_key(Closure("fetch key")) ; 709b39c5158Smillert $db->filter_fetch_value(Closure("fetch value")) ; 710b39c5158Smillert 711b39c5158Smillert $_ = "original" ; 712b39c5158Smillert 713b39c5158Smillert $h[0] = "joe" ; 714b39c5158Smillert ok(122, $result{"store key"} eq "store key - 1: [0]"); 715b39c5158Smillert ok(123, $result{"store value"} eq "store value - 1: [joe]"); 716b39c5158Smillert ok(124, ! defined $result{"fetch key"} ); 717b39c5158Smillert ok(125, ! defined $result{"fetch value"} ); 718b39c5158Smillert ok(126, $_ eq "original") ; 719b39c5158Smillert 720b39c5158Smillert ok(127, $db->FIRSTKEY() == 0 ) ; 721b39c5158Smillert ok(128, $result{"store key"} eq "store key - 1: [0]"); 722b39c5158Smillert ok(129, $result{"store value"} eq "store value - 1: [joe]"); 723b39c5158Smillert ok(130, $result{"fetch key"} eq "fetch key - 1: [0]"); 724b39c5158Smillert ok(131, ! defined $result{"fetch value"} ); 725b39c5158Smillert ok(132, $_ eq "original") ; 726b39c5158Smillert 727b39c5158Smillert $h[7] = "john" ; 728b39c5158Smillert ok(133, $result{"store key"} eq "store key - 2: [0 7]"); 729b39c5158Smillert ok(134, $result{"store value"} eq "store value - 2: [joe john]"); 730b39c5158Smillert ok(135, $result{"fetch key"} eq "fetch key - 1: [0]"); 731b39c5158Smillert ok(136, ! defined $result{"fetch value"} ); 732b39c5158Smillert ok(137, $_ eq "original") ; 733b39c5158Smillert 734b39c5158Smillert ok(138, $h[0] eq "joe"); 735b39c5158Smillert ok(139, $result{"store key"} eq "store key - 3: [0 7 0]"); 736b39c5158Smillert ok(140, $result{"store value"} eq "store value - 2: [joe john]"); 737b39c5158Smillert ok(141, $result{"fetch key"} eq "fetch key - 1: [0]"); 738b39c5158Smillert ok(142, $result{"fetch value"} eq "fetch value - 1: [joe]"); 739b39c5158Smillert ok(143, $_ eq "original") ; 740b39c5158Smillert 741b39c5158Smillert undef $db ; 742b39c5158Smillert ok(144, safeUntie \@h); 743b39c5158Smillert unlink $Dfile; 744b39c5158Smillert} 745b39c5158Smillert 746b39c5158Smillert{ 747b39c5158Smillert # DBM Filter recursion detection 748b39c5158Smillert use warnings ; 749b39c5158Smillert use strict ; 750b39c5158Smillert my (@h, $db) ; 751b39c5158Smillert unlink $Dfile; 752b39c5158Smillert 753b39c5158Smillert ok(145, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ); 754b39c5158Smillert 755b39c5158Smillert $db->filter_store_key (sub { $_ = $h[0] }) ; 756b39c5158Smillert 757b39c5158Smillert eval '$h[1] = 1234' ; 758b39c5158Smillert ok(146, $@ =~ /^recursion detected in filter_store_key at/ ); 759b39c5158Smillert 760b39c5158Smillert undef $db ; 761b39c5158Smillert ok(147, safeUntie \@h); 762b39c5158Smillert unlink $Dfile; 763b39c5158Smillert} 764b39c5158Smillert 765b39c5158Smillert 766b39c5158Smillert{ 767b39c5158Smillert # Examples from the POD 768b39c5158Smillert 769b39c5158Smillert my $file = "xyzt" ; 770b39c5158Smillert { 771*256a93a4Safresh1 my $redirect = Redirect->new( $file ); 772b39c5158Smillert 773b39c5158Smillert use warnings FATAL => qw(all); 774b39c5158Smillert use strict ; 775b39c5158Smillert use DB_File ; 776b39c5158Smillert 777b39c5158Smillert my $filename = "text" ; 778b39c5158Smillert unlink $filename ; 779b39c5158Smillert 780b39c5158Smillert my @h ; 781b39c5158Smillert my $x = tie @h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_RECNO 782b39c5158Smillert or die "Cannot open file 'text': $!\n" ; 783b39c5158Smillert 784b39c5158Smillert # Add a few key/value pairs to the file 785b39c5158Smillert $h[0] = "orange" ; 786b39c5158Smillert $h[1] = "blue" ; 787b39c5158Smillert $h[2] = "yellow" ; 788b39c5158Smillert 789b39c5158Smillert $FA ? push @h, "green", "black" 790b39c5158Smillert : $x->push("green", "black") ; 791b39c5158Smillert 792b39c5158Smillert my $elements = $FA ? scalar @h : $x->length ; 793b39c5158Smillert print "The array contains $elements entries\n" ; 794b39c5158Smillert 795b39c5158Smillert my $last = $FA ? pop @h : $x->pop ; 796b39c5158Smillert print "popped $last\n" ; 797b39c5158Smillert 798b39c5158Smillert $FA ? unshift @h, "white" 799b39c5158Smillert : $x->unshift("white") ; 800b39c5158Smillert my $first = $FA ? shift @h : $x->shift ; 801b39c5158Smillert print "shifted $first\n" ; 802b39c5158Smillert 803b39c5158Smillert # Check for existence of a key 804b39c5158Smillert print "Element 1 Exists with value $h[1]\n" if $h[1] ; 805b39c5158Smillert 806b39c5158Smillert # use a negative index 807b39c5158Smillert print "The last element is $h[-1]\n" ; 808b39c5158Smillert print "The 2nd last element is $h[-2]\n" ; 809b39c5158Smillert 810b39c5158Smillert undef $x ; 811b39c5158Smillert untie @h ; 812b39c5158Smillert 813b39c5158Smillert unlink $filename ; 814b39c5158Smillert } 815b39c5158Smillert 816b39c5158Smillert ok(148, docat_del($file) eq <<'EOM') ; 817b39c5158SmillertThe array contains 5 entries 818b39c5158Smillertpopped black 819b39c5158Smillertshifted white 820b39c5158SmillertElement 1 Exists with value blue 821b39c5158SmillertThe last element is green 822b39c5158SmillertThe 2nd last element is yellow 823b39c5158SmillertEOM 824b39c5158Smillert 825b39c5158Smillert my $save_output = "xyzt" ; 826b39c5158Smillert { 827*256a93a4Safresh1 my $redirect = Redirect->new( $save_output ); 828b39c5158Smillert 829b39c5158Smillert use warnings FATAL => qw(all); 830b39c5158Smillert use strict ; 831b39c5158Smillert our (@h, $H, $file, $i); 832b39c5158Smillert use DB_File ; 833b39c5158Smillert use Fcntl ; 834b39c5158Smillert 835b39c5158Smillert $file = "text" ; 836b39c5158Smillert 837b39c5158Smillert unlink $file ; 838b39c5158Smillert 839b39c5158Smillert $H = tie @h, "DB_File", $file, O_RDWR|O_CREAT, 0640, $DB_RECNO 840b39c5158Smillert or die "Cannot open file $file: $!\n" ; 841b39c5158Smillert 842b39c5158Smillert # first create a text file to play with 843b39c5158Smillert $h[0] = "zero" ; 844b39c5158Smillert $h[1] = "one" ; 845b39c5158Smillert $h[2] = "two" ; 846b39c5158Smillert $h[3] = "three" ; 847b39c5158Smillert $h[4] = "four" ; 848b39c5158Smillert 849b39c5158Smillert 850b39c5158Smillert # Print the records in order. 851b39c5158Smillert # 852b39c5158Smillert # The length method is needed here because evaluating a tied 853b39c5158Smillert # array in a scalar context does not return the number of 854b39c5158Smillert # elements in the array. 855b39c5158Smillert 856b39c5158Smillert print "\nORIGINAL\n" ; 857b39c5158Smillert foreach $i (0 .. $H->length - 1) { 858b39c5158Smillert print "$i: $h[$i]\n" ; 859b39c5158Smillert } 860b39c5158Smillert 861b39c5158Smillert # use the push & pop methods 862b39c5158Smillert $a = $H->pop ; 863b39c5158Smillert $H->push("last") ; 864b39c5158Smillert print "\nThe last record was [$a]\n" ; 865b39c5158Smillert 866b39c5158Smillert # and the shift & unshift methods 867b39c5158Smillert $a = $H->shift ; 868b39c5158Smillert $H->unshift("first") ; 869b39c5158Smillert print "The first record was [$a]\n" ; 870b39c5158Smillert 871b39c5158Smillert # Use the API to add a new record after record 2. 872b39c5158Smillert $i = 2 ; 873b39c5158Smillert $H->put($i, "Newbie", R_IAFTER) ; 874b39c5158Smillert 875b39c5158Smillert # and a new record before record 1. 876b39c5158Smillert $i = 1 ; 877b39c5158Smillert $H->put($i, "New One", R_IBEFORE) ; 878b39c5158Smillert 879b39c5158Smillert # delete record 3 880b39c5158Smillert $H->del(3) ; 881b39c5158Smillert 882b39c5158Smillert # now print the records in reverse order 883b39c5158Smillert print "\nREVERSE\n" ; 884b39c5158Smillert for ($i = $H->length - 1 ; $i >= 0 ; -- $i) 885b39c5158Smillert { print "$i: $h[$i]\n" } 886b39c5158Smillert 887b39c5158Smillert # same again, but use the API functions instead 888b39c5158Smillert print "\nREVERSE again\n" ; 889b39c5158Smillert my ($s, $k, $v) = (0, 0, 0) ; 890b39c5158Smillert for ($s = $H->seq($k, $v, R_LAST) ; 891b39c5158Smillert $s == 0 ; 892b39c5158Smillert $s = $H->seq($k, $v, R_PREV)) 893b39c5158Smillert { print "$k: $v\n" } 894b39c5158Smillert 895b39c5158Smillert undef $H ; 896b39c5158Smillert untie @h ; 897b39c5158Smillert 898b39c5158Smillert unlink $file ; 899b39c5158Smillert } 900b39c5158Smillert 901b39c5158Smillert ok(149, docat_del($save_output) eq <<'EOM') ; 902b39c5158Smillert 903b39c5158SmillertORIGINAL 904b39c5158Smillert0: zero 905b39c5158Smillert1: one 906b39c5158Smillert2: two 907b39c5158Smillert3: three 908b39c5158Smillert4: four 909b39c5158Smillert 910b39c5158SmillertThe last record was [four] 911b39c5158SmillertThe first record was [zero] 912b39c5158Smillert 913b39c5158SmillertREVERSE 914b39c5158Smillert5: last 915b39c5158Smillert4: three 916b39c5158Smillert3: Newbie 917b39c5158Smillert2: one 918b39c5158Smillert1: New One 919b39c5158Smillert0: first 920b39c5158Smillert 921b39c5158SmillertREVERSE again 922b39c5158Smillert5: last 923b39c5158Smillert4: three 924b39c5158Smillert3: Newbie 925b39c5158Smillert2: one 926b39c5158Smillert1: New One 927b39c5158Smillert0: first 928b39c5158SmillertEOM 929b39c5158Smillert 930b39c5158Smillert} 931b39c5158Smillert 932b39c5158Smillert{ 933b39c5158Smillert # Bug ID 20001013.009 934b39c5158Smillert # 935b39c5158Smillert # test that $hash{KEY} = undef doesn't produce the warning 936b39c5158Smillert # Use of uninitialized value in null operation 937b39c5158Smillert use warnings ; 938b39c5158Smillert use strict ; 939b39c5158Smillert use DB_File ; 940b39c5158Smillert 941b39c5158Smillert unlink $Dfile; 942b39c5158Smillert my @h ; 943b39c5158Smillert my $a = ""; 944b39c5158Smillert local $SIG{__WARN__} = sub {$a = $_[0]} ; 945b39c5158Smillert 946b39c5158Smillert tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_RECNO 947b39c5158Smillert or die "Can't open file: $!\n" ; 948b39c5158Smillert $h[0] = undef; 949b39c5158Smillert ok(150, $a eq "") ; 950b39c5158Smillert ok(151, safeUntie \@h); 951b39c5158Smillert unlink $Dfile; 952b39c5158Smillert} 953b39c5158Smillert 954b39c5158Smillert{ 955b39c5158Smillert # test that %hash = () doesn't produce the warning 956b39c5158Smillert # Argument "" isn't numeric in entersub 957b39c5158Smillert use warnings ; 958b39c5158Smillert use strict ; 959b39c5158Smillert use DB_File ; 960b39c5158Smillert my $a = ""; 961b39c5158Smillert local $SIG{__WARN__} = sub {$a = $_[0]} ; 962b39c5158Smillert 963b39c5158Smillert unlink $Dfile; 964b39c5158Smillert my @h ; 965b39c5158Smillert 966b39c5158Smillert tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_RECNO 967b39c5158Smillert or die "Can't open file: $!\n" ; 968b39c5158Smillert @h = (); ; 969b39c5158Smillert ok(152, $a eq "") ; 970b39c5158Smillert ok(153, safeUntie \@h); 971b39c5158Smillert unlink $Dfile; 972b39c5158Smillert} 973b39c5158Smillert 974b39c5158Smillert{ 975b39c5158Smillert # Check that DBM Filter can cope with read-only $_ 976b39c5158Smillert 977b39c5158Smillert use warnings ; 978b39c5158Smillert use strict ; 979b39c5158Smillert my (@h, $db) ; 980b39c5158Smillert unlink $Dfile; 981b39c5158Smillert 982b39c5158Smillert ok(154, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ); 983b39c5158Smillert 984b39c5158Smillert $db->filter_fetch_key (sub { }) ; 985b39c5158Smillert $db->filter_store_key (sub { }) ; 986b39c5158Smillert $db->filter_fetch_value (sub { }) ; 987b39c5158Smillert $db->filter_store_value (sub { }) ; 988b39c5158Smillert 989b39c5158Smillert $_ = "original" ; 990b39c5158Smillert 991b39c5158Smillert $h[0] = "joe" ; 992b39c5158Smillert ok(155, $h[0] eq "joe"); 993b39c5158Smillert 994b39c5158Smillert eval { my @r= grep { $h[$_] } (1, 2, 3) }; 995b39c5158Smillert ok (156, ! $@); 996b39c5158Smillert 997b39c5158Smillert 998b39c5158Smillert # delete the filters 999b39c5158Smillert $db->filter_fetch_key (undef); 1000b39c5158Smillert $db->filter_store_key (undef); 1001b39c5158Smillert $db->filter_fetch_value (undef); 1002b39c5158Smillert $db->filter_store_value (undef); 1003b39c5158Smillert 1004b39c5158Smillert $h[1] = "joe" ; 1005b39c5158Smillert 1006b39c5158Smillert ok(157, $h[1] eq "joe"); 1007b39c5158Smillert 1008b39c5158Smillert eval { my @r= grep { $h[$_] } (1, 2, 3) }; 1009b39c5158Smillert ok (158, ! $@); 1010b39c5158Smillert 1011b39c5158Smillert undef $db ; 1012b39c5158Smillert untie @h; 1013b39c5158Smillert unlink $Dfile; 1014b39c5158Smillert} 1015b39c5158Smillert 1016b39c5158Smillert{ 1017b39c5158Smillert # Check low-level API works with filter 1018b39c5158Smillert 1019b39c5158Smillert use warnings ; 1020b39c5158Smillert use strict ; 1021b39c5158Smillert my (@h, $db) ; 1022b39c5158Smillert my $Dfile = "xxy.db"; 1023b39c5158Smillert unlink $Dfile; 1024b39c5158Smillert 1025b39c5158Smillert ok(159, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ); 1026b39c5158Smillert 1027b39c5158Smillert 1028b39c5158Smillert $db->filter_fetch_key (sub { ++ $_ } ); 1029b39c5158Smillert $db->filter_store_key (sub { -- $_ } ); 1030b39c5158Smillert $db->filter_fetch_value (sub { $_ = unpack("i", $_) } ); 1031b39c5158Smillert $db->filter_store_value (sub { $_ = pack("i", $_) } ); 1032b39c5158Smillert 1033b39c5158Smillert $_ = 'fred'; 1034b39c5158Smillert 1035b39c5158Smillert my $key = 22 ; 1036b39c5158Smillert my $value = 34 ; 1037b39c5158Smillert 1038b39c5158Smillert $db->put($key, $value) ; 1039b39c5158Smillert ok 160, $key == 22; 1040b39c5158Smillert ok 161, $value == 34 ; 1041b39c5158Smillert ok 162, $_ eq 'fred'; 1042b39c5158Smillert #print "k [$key][$value]\n" ; 1043b39c5158Smillert 1044b39c5158Smillert my $val ; 1045b39c5158Smillert $db->get($key, $val) ; 1046b39c5158Smillert ok 163, $key == 22; 1047b39c5158Smillert ok 164, $val == 34 ; 1048b39c5158Smillert ok 165, $_ eq 'fred'; 1049b39c5158Smillert 1050b39c5158Smillert $key = 51 ; 1051b39c5158Smillert $value = 454; 1052b39c5158Smillert $h[$key] = $value ; 1053b39c5158Smillert ok 166, $key == 51; 1054b39c5158Smillert ok 167, $value == 454 ; 1055b39c5158Smillert ok 168, $_ eq 'fred'; 1056b39c5158Smillert 1057b39c5158Smillert undef $db ; 1058b39c5158Smillert untie @h; 1059b39c5158Smillert unlink $Dfile; 1060b39c5158Smillert} 1061b39c5158Smillert 1062b39c5158Smillert 1063b39c5158Smillert{ 1064b39c5158Smillert # Regression Test for bug 30237 1065b39c5158Smillert # Check that substr can be used in the key to db_put 1066b39c5158Smillert # and that db_put does not trigger the warning 1067b39c5158Smillert # 1068b39c5158Smillert # Use of uninitialized value in subroutine entry 1069b39c5158Smillert 1070b39c5158Smillert 1071b39c5158Smillert use warnings ; 1072b39c5158Smillert use strict ; 1073b39c5158Smillert my (@h, $db) ; 1074b39c5158Smillert my $status ; 1075b39c5158Smillert my $Dfile = "xxy.db"; 1076b39c5158Smillert unlink $Dfile; 1077b39c5158Smillert 1078b39c5158Smillert ok(169, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO) ); 1079b39c5158Smillert 1080b39c5158Smillert my $warned = ''; 1081b39c5158Smillert local $SIG{__WARN__} = sub {$warned = $_[0]} ; 1082b39c5158Smillert 1083b39c5158Smillert # db-put with substr of key 1084b39c5158Smillert my %remember = () ; 1085b39c5158Smillert for my $ix ( 0 .. 2 ) 1086b39c5158Smillert { 1087b39c5158Smillert my $key = $ix . "data" ; 1088b39c5158Smillert my $value = "value$ix" ; 1089b39c5158Smillert $remember{substr($key,0, 1)} = $value ; 1090b39c5158Smillert $db->put(substr($key,0, 1), $value) ; 1091b39c5158Smillert } 1092b39c5158Smillert 1093b39c5158Smillert ok 170, $warned eq '' 1094b39c5158Smillert or print "# Caught warning [$warned]\n" ; 1095b39c5158Smillert 1096b39c5158Smillert # db-put with substr of value 1097b39c5158Smillert $warned = ''; 1098b39c5158Smillert for my $ix ( 3 .. 5 ) 1099b39c5158Smillert { 1100b39c5158Smillert my $key = $ix . "data" ; 1101b39c5158Smillert my $value = "value$ix" ; 1102b39c5158Smillert $remember{$ix} = $value ; 1103b39c5158Smillert $db->put($ix, substr($value,0)) ; 1104b39c5158Smillert } 1105b39c5158Smillert 1106b39c5158Smillert ok 171, $warned eq '' 1107b39c5158Smillert or print "# Caught warning [$warned]\n" ; 1108b39c5158Smillert 1109b39c5158Smillert # via the tied array is not a problem, but check anyway 1110b39c5158Smillert # substr of key 1111b39c5158Smillert $warned = ''; 1112b39c5158Smillert for my $ix ( 6 .. 8 ) 1113b39c5158Smillert { 1114b39c5158Smillert my $key = $ix . "data" ; 1115b39c5158Smillert my $value = "value$ix" ; 1116b39c5158Smillert $remember{substr($key,0,1)} = $value ; 1117b39c5158Smillert $h[substr($key,0,1)] = $value ; 1118b39c5158Smillert } 1119b39c5158Smillert 1120b39c5158Smillert ok 172, $warned eq '' 1121b39c5158Smillert or print "# Caught warning [$warned]\n" ; 1122b39c5158Smillert 1123b39c5158Smillert # via the tied array is not a problem, but check anyway 1124b39c5158Smillert # substr of value 1125b39c5158Smillert $warned = ''; 1126b39c5158Smillert for my $ix ( 9 .. 10 ) 1127b39c5158Smillert { 1128b39c5158Smillert my $key = $ix . "data" ; 1129b39c5158Smillert my $value = "value$ix" ; 1130b39c5158Smillert $remember{$ix} = $value ; 1131b39c5158Smillert $h[$ix] = substr($value,0) ; 1132b39c5158Smillert } 1133b39c5158Smillert 1134b39c5158Smillert ok 173, $warned eq '' 1135b39c5158Smillert or print "# Caught warning [$warned]\n" ; 1136b39c5158Smillert 1137b39c5158Smillert my %bad = () ; 1138b39c5158Smillert my $key = ''; 1139b39c5158Smillert for (my $status = $db->seq($key, $value, R_FIRST ) ; 1140b39c5158Smillert $status == 0 ; 1141b39c5158Smillert $status = $db->seq($key, $value, R_NEXT ) ) { 1142b39c5158Smillert 1143b39c5158Smillert #print "# key [$key] value [$value]\n" ; 1144b39c5158Smillert if (defined $remember{$key} && defined $value && 1145b39c5158Smillert $remember{$key} eq $value) { 1146b39c5158Smillert delete $remember{$key} ; 1147b39c5158Smillert } 1148b39c5158Smillert else { 1149b39c5158Smillert $bad{$key} = $value ; 1150b39c5158Smillert } 1151b39c5158Smillert } 1152b39c5158Smillert 1153b39c5158Smillert ok 174, keys %bad == 0 ; 1154b39c5158Smillert ok 175, keys %remember == 0 ; 1155b39c5158Smillert 1156b39c5158Smillert print "# missing -- $key $value\n" while ($key, $value) = each %remember; 1157b39c5158Smillert print "# bad -- $key $value\n" while ($key, $value) = each %bad; 1158b39c5158Smillert 1159b39c5158Smillert # Make sure this fix does not break code to handle an undef key 1160b39c5158Smillert my $value = 'fred'; 1161b39c5158Smillert $warned = ''; 1162b39c5158Smillert $status = $db->put(undef, $value) ; 1163b39c5158Smillert ok 176, $status == 0 1164b39c5158Smillert or print "# put failed - status $status\n"; 1165b39c5158Smillert ok 177, $warned eq '' 1166b39c5158Smillert or print "# Caught warning [$warned]\n" ; 1167b39c5158Smillert $warned = ''; 1168b39c5158Smillert 1169b39c5158Smillert print "# db_ver $DB_File::db_ver\n"; 1170b39c5158Smillert $value = '' ; 1171b39c5158Smillert $status = $db->get(undef, $value) ; 1172b39c5158Smillert ok 178, $status == 0 1173b39c5158Smillert or print "# get failed - status $status\n" ; 1174b39c5158Smillert ok(179, $db->get(undef, $value) == 0) or print "# get failed\n" ; 1175b39c5158Smillert ok 180, $value eq 'fred' or print "# got [$value]\n" ; 1176b39c5158Smillert ok 181, $warned eq '' 1177b39c5158Smillert or print "# Caught warning [$warned]\n" ; 1178b39c5158Smillert $warned = ''; 1179b39c5158Smillert 1180b39c5158Smillert undef $db ; 1181b39c5158Smillert untie @h; 1182b39c5158Smillert unlink $Dfile; 1183b39c5158Smillert} 1184b39c5158Smillert 1185b39c5158Smillert# Only test splice if this is a newish version of Perl 1186b39c5158Smillertexit unless $FA ; 1187b39c5158Smillert 1188b39c5158Smillert# Test SPLICE 1189b39c5158Smillert 1190b39c5158Smillert{ 1191b39c5158Smillert # check that the splice warnings are under the same lexical control 1192b39c5158Smillert # as their non-tied counterparts. 1193b39c5158Smillert 1194b39c5158Smillert use warnings; 1195b39c5158Smillert use strict; 1196b39c5158Smillert 1197b39c5158Smillert my $a = ''; 1198b39c5158Smillert my @a = (1); 1199b39c5158Smillert local $SIG{__WARN__} = sub {$a = $_[0]} ; 1200b39c5158Smillert 1201b39c5158Smillert unlink $Dfile; 1202b39c5158Smillert my @tied ; 1203b39c5158Smillert 1204b39c5158Smillert tie @tied, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_RECNO 1205b39c5158Smillert or die "Can't open file: $!\n" ; 1206b39c5158Smillert 1207b39c5158Smillert # uninitialized offset 1208b39c5158Smillert use warnings; 1209b39c5158Smillert my $offset ; 1210b39c5158Smillert $a = ''; 1211b39c5158Smillert splice(@a, $offset); 1212b39c5158Smillert ok(182, $a =~ /^Use of uninitialized value /); 1213b39c5158Smillert $a = ''; 1214b39c5158Smillert splice(@tied, $offset); 1215b39c5158Smillert ok(183, $a =~ /^Use of uninitialized value in splice/); 1216b39c5158Smillert 1217b39c5158Smillert no warnings 'uninitialized'; 1218b39c5158Smillert $a = ''; 1219b39c5158Smillert splice(@a, $offset); 1220b39c5158Smillert ok(184, $a eq ''); 1221b39c5158Smillert $a = ''; 1222b39c5158Smillert splice(@tied, $offset); 1223b39c5158Smillert ok(185, $a eq ''); 1224b39c5158Smillert 1225b39c5158Smillert # uninitialized length 1226b39c5158Smillert use warnings; 1227b39c5158Smillert my $length ; 1228b39c5158Smillert $a = ''; 1229b39c5158Smillert splice(@a, 0, $length); 1230b39c5158Smillert ok(186, $a =~ /^Use of uninitialized value /); 1231b39c5158Smillert $a = ''; 1232b39c5158Smillert splice(@tied, 0, $length); 1233b39c5158Smillert ok(187, $a =~ /^Use of uninitialized value in splice/); 1234b39c5158Smillert 1235b39c5158Smillert no warnings 'uninitialized'; 1236b39c5158Smillert $a = ''; 1237b39c5158Smillert splice(@a, 0, $length); 1238b39c5158Smillert ok(188, $a eq ''); 1239b39c5158Smillert $a = ''; 1240b39c5158Smillert splice(@tied, 0, $length); 1241b39c5158Smillert ok(189, $a eq ''); 1242b39c5158Smillert 1243b39c5158Smillert # offset past end of array 1244b39c5158Smillert use warnings; 1245b39c5158Smillert $a = ''; 1246b39c5158Smillert splice(@a, 3); 1247b39c5158Smillert my $splice_end_array = ($a =~ /^splice\(\) offset past end of array/); 1248b39c5158Smillert $a = ''; 1249b39c5158Smillert splice(@tied, 3); 1250b39c5158Smillert ok(190, !$splice_end_array || $a =~ /^splice\(\) offset past end of array/); 1251b39c5158Smillert 1252b39c5158Smillert no warnings 'misc'; 1253b39c5158Smillert $a = ''; 1254b39c5158Smillert splice(@a, 3); 1255b39c5158Smillert ok(191, $a eq ''); 1256b39c5158Smillert $a = ''; 1257b39c5158Smillert splice(@tied, 3); 1258b39c5158Smillert ok(192, $a eq ''); 1259b39c5158Smillert 1260b39c5158Smillert ok(193, safeUntie \@tied); 1261b39c5158Smillert unlink $Dfile; 1262b39c5158Smillert} 1263b39c5158Smillert 1264b39c5158Smillert# 1265b39c5158Smillert# These are a few regression tests: bundles of five arguments to pass 1266b39c5158Smillert# to test_splice(). The first four arguments correspond to those 1267b39c5158Smillert# given to splice(), and the last says which context to call it in 1268b39c5158Smillert# (scalar, list or void). 1269b39c5158Smillert# 1270b39c5158Smillert# The expected result is not needed because we get that by running 1271b39c5158Smillert# Perl's built-in splice(). 1272b39c5158Smillert# 1273b39c5158Smillertmy @tests = ([ [ 'falsely', 'dinosaur', 'remedy', 'commotion', 1274b39c5158Smillert 'rarely', 'paleness' ], 1275b39c5158Smillert -4, -2, 1276b39c5158Smillert [ 'redoubled', 'Taylorize', 'Zoe', 'halogen' ], 1277b39c5158Smillert 'void' ], 1278b39c5158Smillert 1279b39c5158Smillert [ [ 'a' ], -2, 1, [ 'B' ], 'void' ], 1280b39c5158Smillert 1281b39c5158Smillert [ [ 'Hartley', 'Islandia', 'assents', 'wishful' ], 1282b39c5158Smillert 0, -4, 1283b39c5158Smillert [ 'maids' ], 1284b39c5158Smillert 'void' ], 1285b39c5158Smillert 1286b39c5158Smillert [ [ 'visibility', 'pocketful', 'rectangles' ], 1287b39c5158Smillert -10, 0, 1288b39c5158Smillert [ 'garbages' ], 1289b39c5158Smillert 'void' ], 1290b39c5158Smillert 1291b39c5158Smillert [ [ 'sleeplessly' ], 1292b39c5158Smillert 8, -4, 1293b39c5158Smillert [ 'Margery', 'clearing', 'repercussion', 'clubs', 1294b39c5158Smillert 'arise' ], 1295b39c5158Smillert 'void' ], 1296b39c5158Smillert 1297b39c5158Smillert [ [ 'chastises', 'recalculates' ], 1298b39c5158Smillert 0, 0, 1299b39c5158Smillert [ 'momentariness', 'mediates', 'accents', 'toils', 1300b39c5158Smillert 'regaled' ], 1301b39c5158Smillert 'void' ], 1302b39c5158Smillert 1303b39c5158Smillert [ [ 'b', '' ], 1304b39c5158Smillert 9, 8, 1305b39c5158Smillert [ 'otrb', 'stje', 'ixrpw', 'vxfx', 'lhhf' ], 1306b39c5158Smillert 'scalar' ], 1307b39c5158Smillert 1308b39c5158Smillert [ [ 'b', '' ], 1309b39c5158Smillert undef, undef, 1310b39c5158Smillert [ 'otrb', 'stje', 'ixrpw', 'vxfx', 'lhhf' ], 1311b39c5158Smillert 'scalar' ], 1312b39c5158Smillert 1313b39c5158Smillert [ [ 'riheb' ], -8, undef, [], 'void' ], 1314b39c5158Smillert 1315b39c5158Smillert [ [ 'uft', 'qnxs', '' ], 1316b39c5158Smillert 6, -2, 1317b39c5158Smillert [ 'znp', 'mhnkh', 'bn' ], 1318b39c5158Smillert 'void' ], 1319b39c5158Smillert ); 1320b39c5158Smillert 1321b39c5158Smillertmy $testnum = 194; 1322b39c5158Smillertmy $failed = 0; 1323b39c5158Smillertmy $tmp = "dbr$$"; 1324b39c5158Smillertforeach my $test (@tests) { 1325b39c5158Smillert my $err = test_splice(@$test); 1326b39c5158Smillert if (defined $err) { 1327b39c5158Smillert print STDERR "# failed: ", Dumper($test); 1328b39c5158Smillert print STDERR "# error: $err\n"; 1329b39c5158Smillert $failed = 1; 1330b39c5158Smillert ok($testnum++, 0); 1331b39c5158Smillert } 1332b39c5158Smillert else { ok($testnum++, 1) } 1333b39c5158Smillert} 1334b39c5158Smillert 1335b39c5158Smillertif ($failed) { 1336b39c5158Smillert # Not worth running the random ones 1337b39c5158Smillert print STDERR '# skipping ', $testnum++, "\n"; 1338b39c5158Smillert} 1339b39c5158Smillertelse { 1340b39c5158Smillert # A thousand randomly-generated tests 1341b39c5158Smillert $failed = 0; 1342b39c5158Smillert srand(0); 1343b39c5158Smillert foreach (0 .. 1000 - 1) { 1344b39c5158Smillert my $test = rand_test(); 1345b39c5158Smillert my $err = test_splice(@$test); 1346b39c5158Smillert if (defined $err) { 1347b39c5158Smillert print STDERR "# failed: ", Dumper($test); 1348b39c5158Smillert print STDERR "# error: $err\n"; 1349b39c5158Smillert $failed = 1; 1350b39c5158Smillert print STDERR "# skipping any remaining random tests\n"; 1351b39c5158Smillert last; 1352b39c5158Smillert } 1353b39c5158Smillert } 1354b39c5158Smillert 1355b39c5158Smillert ok($testnum++, not $failed); 1356b39c5158Smillert} 1357b39c5158Smillert 1358b39c5158Smillertdie "testnum ($testnum) != total_tests ($total_tests) + 1" 1359b39c5158Smillert if $testnum != $total_tests + 1; 1360b39c5158Smillert 1361b39c5158Smillertexit ; 1362b39c5158Smillert 1363b39c5158Smillert# Subroutines for SPLICE testing 1364b39c5158Smillert 1365b39c5158Smillert# test_splice() 1366b39c5158Smillert# 1367b39c5158Smillert# Test the new splice() against Perl's built-in one. The first four 1368b39c5158Smillert# parameters are those passed to splice(), except that the lists must 1369b39c5158Smillert# be (explicitly) passed by reference, and are not actually modified. 1370b39c5158Smillert# (It's just a test!) The last argument specifies the context in 1371b39c5158Smillert# which to call the functions: 'list', 'scalar', or 'void'. 1372b39c5158Smillert# 1373b39c5158Smillert# Returns: 1374b39c5158Smillert# undef, if the two splices give the same results for the given 1375b39c5158Smillert# arguments and context; 1376b39c5158Smillert# 1377b39c5158Smillert# an error message showing the difference, otherwise. 1378b39c5158Smillert# 1379b39c5158Smillert# Reads global variable $tmp. 1380b39c5158Smillert# 1381b39c5158Smillertsub test_splice { 1382b39c5158Smillert die 'usage: test_splice(array, offset, length, list, context)' if @_ != 5; 1383b39c5158Smillert my ($array, $offset, $length, $list, $context) = @_; 1384b39c5158Smillert my @array = @$array; 1385b39c5158Smillert my @list = @$list; 1386b39c5158Smillert 1387b39c5158Smillert unlink $tmp; 1388b39c5158Smillert 1389b39c5158Smillert my @h; 1390b39c5158Smillert my $H = tie @h, 'DB_File', $tmp, O_CREAT|O_RDWR, 0644, $DB_RECNO 1391b39c5158Smillert or die "cannot open $tmp: $!"; 1392b39c5158Smillert 1393b39c5158Smillert my $i = 0; 1394b39c5158Smillert foreach ( @array ) { $h[$i++] = $_ } 1395b39c5158Smillert 1396b39c5158Smillert return "basic DB_File sanity check failed" 1397b39c5158Smillert if list_diff(\@array, \@h); 1398b39c5158Smillert 1399b39c5158Smillert # Output from splice(): 1400b39c5158Smillert # Returned value (munged a bit), error msg, warnings 1401b39c5158Smillert # 1402b39c5158Smillert my ($s_r, $s_error, @s_warnings); 1403b39c5158Smillert 1404b39c5158Smillert my $gather_warning = sub { push @s_warnings, $_[0] }; 1405b39c5158Smillert if ($context eq 'list') { 1406b39c5158Smillert my @r; 1407b39c5158Smillert eval { 1408b39c5158Smillert local $SIG{__WARN__} = $gather_warning; 1409b39c5158Smillert @r = splice @array, $offset, $length, @list; 1410b39c5158Smillert }; 1411b39c5158Smillert $s_error = $@; 1412b39c5158Smillert $s_r = \@r; 1413b39c5158Smillert } 1414b39c5158Smillert elsif ($context eq 'scalar') { 1415b39c5158Smillert my $r; 1416b39c5158Smillert eval { 1417b39c5158Smillert local $SIG{__WARN__} = $gather_warning; 1418b39c5158Smillert $r = splice @array, $offset, $length, @list; 1419b39c5158Smillert }; 1420b39c5158Smillert $s_error = $@; 1421b39c5158Smillert $s_r = [ $r ]; 1422b39c5158Smillert } 1423b39c5158Smillert elsif ($context eq 'void') { 1424b39c5158Smillert eval { 1425b39c5158Smillert local $SIG{__WARN__} = $gather_warning; 1426b39c5158Smillert splice @array, $offset, $length, @list; 1427b39c5158Smillert }; 1428b39c5158Smillert $s_error = $@; 1429b39c5158Smillert $s_r = []; 1430b39c5158Smillert } 1431b39c5158Smillert else { 1432b39c5158Smillert die "bad context $context"; 1433b39c5158Smillert } 1434b39c5158Smillert 1435b39c5158Smillert foreach ($s_error, @s_warnings) { 1436b39c5158Smillert chomp; 1437b39c5158Smillert s/ at \S+ line \d+\.$//; 1438b39c5158Smillert # only built-in splice identifies name of uninit value 1439b39c5158Smillert s/(uninitialized value) \$\w+/$1/; 1440b39c5158Smillert } 1441b39c5158Smillert 1442b39c5158Smillert # Now do the same for DB_File's version of splice 1443b39c5158Smillert my ($ms_r, $ms_error, @ms_warnings); 1444b39c5158Smillert $gather_warning = sub { push @ms_warnings, $_[0] }; 1445b39c5158Smillert if ($context eq 'list') { 1446b39c5158Smillert my @r; 1447b39c5158Smillert eval { 1448b39c5158Smillert local $SIG{__WARN__} = $gather_warning; 1449b39c5158Smillert @r = splice @h, $offset, $length, @list; 1450b39c5158Smillert }; 1451b39c5158Smillert $ms_error = $@; 1452b39c5158Smillert $ms_r = \@r; 1453b39c5158Smillert } 1454b39c5158Smillert elsif ($context eq 'scalar') { 1455b39c5158Smillert my $r; 1456b39c5158Smillert eval { 1457b39c5158Smillert local $SIG{__WARN__} = $gather_warning; 1458b39c5158Smillert $r = splice @h, $offset, $length, @list; 1459b39c5158Smillert }; 1460b39c5158Smillert $ms_error = $@; 1461b39c5158Smillert $ms_r = [ $r ]; 1462b39c5158Smillert } 1463b39c5158Smillert elsif ($context eq 'void') { 1464b39c5158Smillert eval { 1465b39c5158Smillert local $SIG{__WARN__} = $gather_warning; 1466b39c5158Smillert splice @h, $offset, $length, @list; 1467b39c5158Smillert }; 1468b39c5158Smillert $ms_error = $@; 1469b39c5158Smillert $ms_r = []; 1470b39c5158Smillert } 1471b39c5158Smillert else { 1472b39c5158Smillert die "bad context $context"; 1473b39c5158Smillert } 1474b39c5158Smillert 1475b39c5158Smillert foreach ($ms_error, @ms_warnings) { 1476b39c5158Smillert chomp; 1477b39c5158Smillert s/ at \S+(\s+\S+)*? line \d+\.?.*//s; 1478b39c5158Smillert } 1479b39c5158Smillert 1480b39c5158Smillert return "different errors: '$s_error' vs '$ms_error'" 1481b39c5158Smillert if $s_error ne $ms_error; 1482b39c5158Smillert return('different return values: ' . Dumper($s_r) . ' vs ' . Dumper($ms_r)) 1483b39c5158Smillert if list_diff($s_r, $ms_r); 1484b39c5158Smillert return('different changed list: ' . Dumper(\@array) . ' vs ' . Dumper(\@h)) 1485b39c5158Smillert if list_diff(\@array, \@h); 1486b39c5158Smillert 1487b39c5158Smillert if ((scalar @s_warnings) != (scalar @ms_warnings)) { 1488b39c5158Smillert return 'different number of warnings'; 1489b39c5158Smillert } 1490b39c5158Smillert 1491b39c5158Smillert while (@s_warnings) { 1492b39c5158Smillert my $sw = shift @s_warnings; 1493b39c5158Smillert my $msw = shift @ms_warnings; 1494b39c5158Smillert 1495b39c5158Smillert if (defined $sw and defined $msw) { 1496b39c5158Smillert $msw =~ s/ \(.+\)$//; 1497b39c5158Smillert $msw =~ s/ in splice$// if $] < 5.006; 1498b39c5158Smillert if ($sw ne $msw) { 1499b39c5158Smillert return "different warning: '$sw' vs '$msw'"; 1500b39c5158Smillert } 1501b39c5158Smillert } 1502b39c5158Smillert elsif (not defined $sw and not defined $msw) { 1503b39c5158Smillert # Okay. 1504b39c5158Smillert } 1505b39c5158Smillert else { 1506b39c5158Smillert return "one warning defined, another undef"; 1507b39c5158Smillert } 1508b39c5158Smillert } 1509b39c5158Smillert 1510b39c5158Smillert undef $H; 1511b39c5158Smillert untie @h; 1512b39c5158Smillert 1513b39c5158Smillert open(TEXT, $tmp) or die "cannot open $tmp: $!"; 1514b39c5158Smillert @h = <TEXT>; normalise @h; chomp @h; 1515b39c5158Smillert close TEXT or die "cannot close $tmp: $!"; 1516b39c5158Smillert return('list is different when re-read from disk: ' 1517b39c5158Smillert . Dumper(\@array) . ' vs ' . Dumper(\@h)) 1518b39c5158Smillert if list_diff(\@array, \@h); 1519b39c5158Smillert 1520b39c5158Smillert unlink $tmp; 1521b39c5158Smillert 1522b39c5158Smillert return undef; # success 1523b39c5158Smillert} 1524b39c5158Smillert 1525b39c5158Smillert 1526b39c5158Smillert# list_diff() 1527b39c5158Smillert# 1528b39c5158Smillert# Do two lists differ? 1529b39c5158Smillert# 1530b39c5158Smillert# Parameters: 1531b39c5158Smillert# reference to first list 1532b39c5158Smillert# reference to second list 1533b39c5158Smillert# 1534b39c5158Smillert# Returns true iff they differ. Only works for lists of (string or 1535b39c5158Smillert# undef). 1536b39c5158Smillert# 1537b39c5158Smillert# Surely there is a better way to do this? 1538b39c5158Smillert# 1539b39c5158Smillertsub list_diff { 1540b39c5158Smillert die 'usage: list_diff(ref to first list, ref to second list)' 1541b39c5158Smillert if @_ != 2; 1542b39c5158Smillert my ($a, $b) = @_; 1543b39c5158Smillert my @a = @$a; my @b = @$b; 1544b39c5158Smillert return 1 if (scalar @a) != (scalar @b); 1545b39c5158Smillert for (my $i = 0; $i < @a; $i++) { 1546b39c5158Smillert my ($ae, $be) = ($a[$i], $b[$i]); 1547b39c5158Smillert if (defined $ae and defined $be) { 1548b39c5158Smillert return 1 if $ae ne $be; 1549b39c5158Smillert } 1550b39c5158Smillert elsif (not defined $ae and not defined $be) { 1551b39c5158Smillert # Two undefined values are 'equal' 1552b39c5158Smillert } 1553b39c5158Smillert else { 1554b39c5158Smillert return 1; 1555b39c5158Smillert } 1556b39c5158Smillert } 1557b39c5158Smillert return 0; 1558b39c5158Smillert} 1559b39c5158Smillert 1560b39c5158Smillert 1561b39c5158Smillert# rand_test() 1562b39c5158Smillert# 1563b39c5158Smillert# Think up a random ARRAY, OFFSET, LENGTH, LIST, and context. 1564b39c5158Smillert# ARRAY or LIST might be empty, and OFFSET or LENGTH might be 1565b39c5158Smillert# undefined. Return a 'test' - a listref of these five things. 1566b39c5158Smillert# 1567b39c5158Smillertsub rand_test { 1568b39c5158Smillert die 'usage: rand_test()' if @_; 1569b39c5158Smillert my @contexts = qw<list scalar void>; 1570b39c5158Smillert my $context = $contexts[int(rand @contexts)]; 1571b39c5158Smillert return [ rand_list(), 1572b39c5158Smillert (rand() < 0.5) ? (int(rand(20)) - 10) : undef, 1573b39c5158Smillert (rand() < 0.5) ? (int(rand(20)) - 10) : undef, 1574b39c5158Smillert rand_list(), 1575b39c5158Smillert $context ]; 1576b39c5158Smillert} 1577b39c5158Smillert 1578b39c5158Smillert 1579b39c5158Smillertsub rand_list { 1580b39c5158Smillert die 'usage: rand_list()' if @_; 1581b39c5158Smillert my @r; 1582b39c5158Smillert 1583b39c5158Smillert while (rand() > 0.1 * (scalar @r + 1)) { 1584b39c5158Smillert push @r, rand_word(); 1585b39c5158Smillert } 1586b39c5158Smillert return \@r; 1587b39c5158Smillert} 1588b39c5158Smillert 1589b39c5158Smillert 1590b39c5158Smillertsub rand_word { 1591b39c5158Smillert die 'usage: rand_word()' if @_; 1592b39c5158Smillert my $r = ''; 1593b39c5158Smillert my @chars = qw<a b c d e f g h i j k l m n o p q r s t u v w x y z>; 1594b39c5158Smillert while (rand() > 0.1 * (length($r) + 1)) { 1595b39c5158Smillert $r .= $chars[int(rand(scalar @chars))]; 1596b39c5158Smillert } 1597b39c5158Smillert return $r; 1598b39c5158Smillert} 1599