& what's to be done for 5.8.0?
[p5sagit/p5-mst-13.2.git] / ext / DB_File / t / db-recno.t
1 #!./perl -w
2
3 BEGIN {
4     chdir 't' if -d 't';
5     @INC = '../lib';
6     require Config; import Config;
7     if ($Config{'extensions'} !~ /\bDB_File\b/) {
8         print "1..0 # Skip: DB_File was not built\n";
9         exit 0;
10     }
11 }
12
13 use DB_File; 
14 use Fcntl;
15 use strict ;
16 use warnings;
17 use vars qw($dbh $Dfile $bad_ones $FA) ;
18
19 # full tied array support started in Perl 5.004_57
20 # Double check to see if it is available.
21
22 {
23     sub try::TIEARRAY { bless [], "try" }
24     sub try::FETCHSIZE { $FA = 1 }
25     $FA = 0 ;
26     my @a ; 
27     tie @a, 'try' ;
28     my $a = @a ;
29 }
30
31
32 sub ok
33 {
34     my $no = shift ;
35     my $result = shift ;
36
37     print "not " unless $result ;
38     print "ok $no\n" ;
39
40     return $result ;
41 }
42
43 {
44     package Redirect ;
45     use Symbol ;
46
47     sub new
48     {
49         my $class = shift ;
50         my $filename = shift ;
51         my $fh = gensym ;
52         open ($fh, ">$filename") || die "Cannot open $filename: $!" ;
53         my $real_stdout = select($fh) ;
54         return bless [$fh, $real_stdout ] ;
55
56     }
57     sub DESTROY
58     {
59         my $self = shift ;
60         close $self->[0] ;
61         select($self->[1]) ;
62     }
63 }
64
65 sub docat
66 {
67     my $file = shift;
68     local $/ = undef;
69     open(CAT,$file) || die "Cannot open $file:$!";
70     my $result = <CAT>;
71     close(CAT);
72     return $result;
73 }
74
75 sub docat_del
76
77     my $file = shift;
78     local $/ = undef;
79     open(CAT,$file) || die "Cannot open $file: $!";
80     my $result = <CAT>;
81     close(CAT);
82     unlink $file ;
83     return $result;
84 }   
85
86 sub bad_one
87 {
88     print STDERR <<EOM unless $bad_ones++ ;
89 #
90 # Some older versions of Berkeley DB version 1 will fail tests 51,
91 # 53 and 55.
92 #
93 # You can safely ignore the errors if you're never going to use the
94 # broken functionality (recno databases with a modified bval). 
95 # Otherwise you'll have to upgrade your DB library.
96 #
97 # If you want to use Berkeley DB version 1, then 1.85 and 1.86 are the
98 # last versions that were released. Berkeley DB version 2 is continually
99 # being updated -- Check out http://www.sleepycat.com/ for more details.
100 #
101 EOM
102 }
103
104 print "1..128\n";
105
106 my $Dfile = "recno.tmp";
107 unlink $Dfile ;
108
109 umask(0);
110
111 # Check the interface to RECNOINFO
112
113 my $dbh = new DB_File::RECNOINFO ;
114 ok(1, ! defined $dbh->{bval}) ;
115 ok(2, ! defined $dbh->{cachesize}) ;
116 ok(3, ! defined $dbh->{psize}) ;
117 ok(4, ! defined $dbh->{flags}) ;
118 ok(5, ! defined $dbh->{lorder}) ;
119 ok(6, ! defined $dbh->{reclen}) ;
120 ok(7, ! defined $dbh->{bfname}) ;
121
122 $dbh->{bval} = 3000 ;
123 ok(8, $dbh->{bval} == 3000 );
124
125 $dbh->{cachesize} = 9000 ;
126 ok(9, $dbh->{cachesize} == 9000 );
127
128 $dbh->{psize} = 400 ;
129 ok(10, $dbh->{psize} == 400 );
130
131 $dbh->{flags} = 65 ;
132 ok(11, $dbh->{flags} == 65 );
133
134 $dbh->{lorder} = 123 ;
135 ok(12, $dbh->{lorder} == 123 );
136
137 $dbh->{reclen} = 1234 ;
138 ok(13, $dbh->{reclen} == 1234 );
139
140 $dbh->{bfname} = 1234 ;
141 ok(14, $dbh->{bfname} == 1234 );
142
143
144 # Check that an invalid entry is caught both for store & fetch
145 eval '$dbh->{fred} = 1234' ;
146 ok(15, $@ =~ /^DB_File::RECNOINFO::STORE - Unknown element 'fred' at/ );
147 eval 'my $q = $dbh->{fred}' ;
148 ok(16, $@ =~ /^DB_File::RECNOINFO::FETCH - Unknown element 'fred' at/ );
149
150 # Now check the interface to RECNOINFO
151
152 my $X  ;
153 my @h ;
154 ok(17, $X = tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ;
155
156 ok(18, ((stat($Dfile))[2] & 0777) == (($^O eq 'os2' || $^O eq 'MacOS') ? 0666 : 0640)
157         ||  $^O eq 'MSWin32' ||  $^O eq 'NetWare' || $^O eq 'amigaos') ;
158
159 #my $l = @h ;
160 my $l = $X->length ;
161 ok(19, ($FA ? @h == 0 : !$l) );
162
163 my @data = qw( a b c d ever f g h  i j k longername m n o p) ;
164
165 $h[0] = shift @data ;
166 ok(20, $h[0] eq 'a' );
167
168 my $ i;
169 foreach (@data)
170   { $h[++$i] = $_ }
171
172 unshift (@data, 'a') ;
173
174 ok(21, defined $h[1] );
175 ok(22, ! defined $h[16] );
176 ok(23, $FA ? @h == @data : $X->length == @data );
177
178
179 # Overwrite an entry & check fetch it
180 $h[3] = 'replaced' ;
181 $data[3] = 'replaced' ;
182 ok(24, $h[3] eq 'replaced' );
183
184 #PUSH
185 my @push_data = qw(added to the end) ;
186 ($FA ? push(@h, @push_data) : $X->push(@push_data)) ;
187 push (@data, @push_data) ;
188 ok(25, $h[++$i] eq 'added' );
189 ok(26, $h[++$i] eq 'to' );
190 ok(27, $h[++$i] eq 'the' );
191 ok(28, $h[++$i] eq 'end' );
192
193 # POP
194 my $popped = pop (@data) ;
195 my $value = ($FA ? pop @h : $X->pop) ;
196 ok(29, $value eq $popped) ;
197
198 # SHIFT
199 $value = ($FA ? shift @h : $X->shift) ;
200 my $shifted = shift @data ;
201 ok(30, $value eq $shifted );
202
203 # UNSHIFT
204
205 # empty list
206 ($FA ? unshift @h,() : $X->unshift) ;
207 ok(31, ($FA ? @h == @data : $X->length == @data ));
208
209 my @new_data = qw(add this to the start of the array) ;
210 $FA ? unshift (@h, @new_data) : $X->unshift (@new_data) ;
211 unshift (@data, @new_data) ;
212 ok(32, $FA ? @h == @data : $X->length == @data );
213 ok(33, $h[0] eq "add") ;
214 ok(34, $h[1] eq "this") ;
215 ok(35, $h[2] eq "to") ;
216 ok(36, $h[3] eq "the") ;
217 ok(37, $h[4] eq "start") ;
218 ok(38, $h[5] eq "of") ;
219 ok(39, $h[6] eq "the") ;
220 ok(40, $h[7] eq "array") ;
221 ok(41, $h[8] eq $data[8]) ;
222
223 # SPLICE
224
225 # Now both arrays should be identical
226
227 my $ok = 1 ;
228 my $j = 0 ;
229 foreach (@data)
230 {
231    $ok = 0, last if $_ ne $h[$j ++] ; 
232 }
233 ok(42, $ok );
234
235 # Neagtive subscripts
236
237 # get the last element of the array
238 ok(43, $h[-1] eq $data[-1] );
239 ok(44, $h[-1] eq $h[ ($FA ? @h : $X->length) -1] );
240
241 # get the first element using a negative subscript
242 eval '$h[ - ( $FA ? @h : $X->length)] = "abcd"' ;
243 ok(45, $@ eq "" );
244 ok(46, $h[0] eq "abcd" );
245
246 # now try to read before the start of the array
247 eval '$h[ - (1 + ($FA ? @h : $X->length))] = 1234' ;
248 ok(47, $@ =~ '^Modification of non-creatable array value attempted' );
249
250 # IMPORTANT - $X must be undefined before the untie otherwise the
251 #             underlying DB close routine will not get called.
252 undef $X ;
253 untie(@h);
254
255 unlink $Dfile;
256
257
258 {
259     # Check bval defaults to \n
260
261     my @h = () ;
262     my $dbh = new DB_File::RECNOINFO ;
263     ok(48, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ;
264     $h[0] = "abc" ;
265     $h[1] = "def" ;
266     $h[3] = "ghi" ;
267     untie @h ;
268     my $x = docat($Dfile) ;
269     unlink $Dfile;
270     ok(49, $x eq "abc\ndef\n\nghi\n") ;
271 }
272
273 {
274     # Change bval
275
276     my @h = () ;
277     my $dbh = new DB_File::RECNOINFO ;
278     $dbh->{bval} = "-" ;
279     ok(50, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ;
280     $h[0] = "abc" ;
281     $h[1] = "def" ;
282     $h[3] = "ghi" ;
283     untie @h ;
284     my $x = docat($Dfile) ;
285     unlink $Dfile;
286     my $ok = ($x eq "abc-def--ghi-") ;
287     bad_one() unless $ok ;
288     ok(51, $ok) ;
289 }
290
291 {
292     # Check R_FIXEDLEN with default bval (space)
293
294     my @h = () ;
295     my $dbh = new DB_File::RECNOINFO ;
296     $dbh->{flags} = R_FIXEDLEN ;
297     $dbh->{reclen} = 5 ;
298     ok(52, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ;
299     $h[0] = "abc" ;
300     $h[1] = "def" ;
301     $h[3] = "ghi" ;
302     untie @h ;
303     my $x = docat($Dfile) ;
304     unlink $Dfile;
305     my $ok = ($x eq "abc  def       ghi  ") ;
306     bad_one() unless $ok ;
307     ok(53, $ok) ;
308 }
309
310 {
311     # Check R_FIXEDLEN with user-defined bval
312
313     my @h = () ;
314     my $dbh = new DB_File::RECNOINFO ;
315     $dbh->{flags} = R_FIXEDLEN ;
316     $dbh->{bval} = "-" ;
317     $dbh->{reclen} = 5 ;
318     ok(54, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ;
319     $h[0] = "abc" ;
320     $h[1] = "def" ;
321     $h[3] = "ghi" ;
322     untie @h ;
323     my $x = docat($Dfile) ;
324     unlink $Dfile;
325     my $ok = ($x eq "abc--def-------ghi--") ;
326     bad_one() unless $ok ;
327     ok(55, $ok) ;
328 }
329
330 {
331     # check that attempting to tie an associative array to a DB_RECNO will fail
332
333     my $filename = "xyz" ;
334     my %x ;
335     eval { tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0640, $DB_RECNO ; } ;
336     ok(56, $@ =~ /^DB_File can only tie an array to a DB_RECNO database/) ;
337     unlink $filename ;
338 }
339
340 {
341    # sub-class test
342
343    package Another ;
344
345    use warnings ;
346    use strict ;
347
348    open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ;
349    print FILE <<'EOM' ;
350
351    package SubDB ;
352
353    use warnings ;
354    use strict ;
355    use vars qw( @ISA @EXPORT) ;
356
357    require Exporter ;
358    use DB_File;
359    @ISA=qw(DB_File);
360    @EXPORT = @DB_File::EXPORT ;
361
362    sub STORE { 
363         my $self = shift ;
364         my $key = shift ;
365         my $value = shift ;
366         $self->SUPER::STORE($key, $value * 2) ;
367    }
368
369    sub FETCH { 
370         my $self = shift ;
371         my $key = shift ;
372         $self->SUPER::FETCH($key) - 1 ;
373    }
374
375    sub put { 
376         my $self = shift ;
377         my $key = shift ;
378         my $value = shift ;
379         $self->SUPER::put($key, $value * 3) ;
380    }
381
382    sub get { 
383         my $self = shift ;
384         $self->SUPER::get($_[0], $_[1]) ;
385         $_[1] -= 2 ;
386    }
387
388    sub A_new_method
389    {
390         my $self = shift ;
391         my $key = shift ;
392         my $value = $self->FETCH($key) ;
393         return "[[$value]]" ;
394    }
395
396    1 ;
397 EOM
398
399     close FILE ;
400
401     BEGIN { push @INC, '.'; } 
402     eval 'use SubDB ; ';
403     main::ok(57, $@ eq "") ;
404     my @h ;
405     my $X ;
406     eval '
407         $X = tie(@h, "SubDB","recno.tmp", O_RDWR|O_CREAT, 0640, $DB_RECNO );
408         ' ;
409
410     main::ok(58, $@ eq "") ;
411
412     my $ret = eval '$h[3] = 3 ; return $h[3] ' ;
413     main::ok(59, $@ eq "") ;
414     main::ok(60, $ret == 5) ;
415
416     my $value = 0;
417     $ret = eval '$X->put(1, 4) ; $X->get(1, $value) ; return $value' ;
418     main::ok(61, $@ eq "") ;
419     main::ok(62, $ret == 10) ;
420
421     $ret = eval ' R_NEXT eq main::R_NEXT ' ;
422     main::ok(63, $@ eq "" ) ;
423     main::ok(64, $ret == 1) ;
424
425     $ret = eval '$X->A_new_method(1) ' ;
426     main::ok(65, $@ eq "") ;
427     main::ok(66, $ret eq "[[11]]") ;
428
429     undef $X;
430     untie(@h);
431     unlink "SubDB.pm", "recno.tmp" ;
432
433 }
434
435 {
436
437     # test $#
438     my $self ;
439     unlink $Dfile;
440     ok(67, $self = tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ;
441     $h[0] = "abc" ;
442     $h[1] = "def" ;
443     $h[2] = "ghi" ;
444     $h[3] = "jkl" ;
445     ok(68, $FA ? $#h == 3 : $self->length() == 4) ;
446     undef $self ;
447     untie @h ;
448     my $x = docat($Dfile) ;
449     ok(69, $x eq "abc\ndef\nghi\njkl\n") ;
450
451     # $# sets array to same length
452     ok(70, $self = tie @h, 'DB_File', $Dfile, O_RDWR, 0640, $DB_RECNO ) ;
453     if ($FA)
454       { $#h = 3 }
455     else 
456       { $self->STORESIZE(4) }
457     ok(71, $FA ? $#h == 3 : $self->length() == 4) ;
458     undef $self ;
459     untie @h ;
460     $x = docat($Dfile) ;
461     ok(72, $x eq "abc\ndef\nghi\njkl\n") ;
462
463     # $# sets array to bigger
464     ok(73, $self = tie @h, 'DB_File', $Dfile, O_RDWR, 0640, $DB_RECNO ) ;
465     if ($FA)
466       { $#h = 6 }
467     else 
468       { $self->STORESIZE(7) }
469     ok(74, $FA ? $#h == 6 : $self->length() == 7) ;
470     undef $self ;
471     untie @h ;
472     $x = docat($Dfile) ;
473     ok(75, $x eq "abc\ndef\nghi\njkl\n\n\n\n") ;
474
475     # $# sets array smaller
476     ok(76, $self = tie @h, 'DB_File', $Dfile, O_RDWR, 0640, $DB_RECNO ) ;
477     if ($FA)
478       { $#h = 2 }
479     else 
480       { $self->STORESIZE(3) }
481     ok(77, $FA ? $#h == 2 : $self->length() == 3) ;
482     undef $self ;
483     untie @h ;
484     $x = docat($Dfile) ;
485     ok(78, $x eq "abc\ndef\nghi\n") ;
486
487     unlink $Dfile;
488
489
490 }
491
492 {
493    # DBM Filter tests
494    use warnings ;
495    use strict ;
496    my (@h, $db) ;
497    my ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
498    unlink $Dfile;
499
500    sub checkOutput
501    {
502        my($fk, $sk, $fv, $sv) = @_ ;
503        return
504            $fetch_key eq $fk && $store_key eq $sk && 
505            $fetch_value eq $fv && $store_value eq $sv &&
506            $_ eq 'original' ;
507    }
508    
509    ok(79, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) );
510
511    $db->filter_fetch_key   (sub { $fetch_key = $_ }) ;
512    $db->filter_store_key   (sub { $store_key = $_ }) ;
513    $db->filter_fetch_value (sub { $fetch_value = $_}) ;
514    $db->filter_store_value (sub { $store_value = $_ }) ;
515
516    $_ = "original" ;
517
518    $h[0] = "joe" ;
519    #                   fk   sk     fv   sv
520    ok(80, checkOutput( "", 0, "", "joe")) ;
521
522    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
523    ok(81, $h[0] eq "joe");
524    #                   fk  sk  fv    sv
525    ok(82, checkOutput( "", 0, "joe", "")) ;
526
527    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
528    ok(83, $db->FIRSTKEY() == 0) ;
529    #                    fk     sk  fv  sv
530    ok(84, checkOutput( 0, "", "", "")) ;
531
532    # replace the filters, but remember the previous set
533    my ($old_fk) = $db->filter_fetch_key   
534                         (sub { ++ $_ ; $fetch_key = $_ }) ;
535    my ($old_sk) = $db->filter_store_key   
536                         (sub { $_ *= 2 ; $store_key = $_ }) ;
537    my ($old_fv) = $db->filter_fetch_value 
538                         (sub { $_ = "[$_]"; $fetch_value = $_ }) ;
539    my ($old_sv) = $db->filter_store_value 
540                         (sub { s/o/x/g; $store_value = $_ }) ;
541    
542    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
543    $h[1] = "Joe" ;
544    #                   fk   sk     fv    sv
545    ok(85, checkOutput( "", 2, "", "Jxe")) ;
546
547    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
548    ok(86, $h[1] eq "[Jxe]");
549    #                   fk   sk     fv    sv
550    ok(87, checkOutput( "", 2, "[Jxe]", "")) ;
551
552    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
553    ok(88, $db->FIRSTKEY() == 1) ;
554    #                   fk   sk     fv    sv
555    ok(89, checkOutput( 1, "", "", "")) ;
556    
557    # put the original filters back
558    $db->filter_fetch_key   ($old_fk);
559    $db->filter_store_key   ($old_sk);
560    $db->filter_fetch_value ($old_fv);
561    $db->filter_store_value ($old_sv);
562
563    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
564    $h[0] = "joe" ;
565    ok(90, checkOutput( "", 0, "", "joe")) ;
566
567    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
568    ok(91, $h[0] eq "joe");
569    ok(92, checkOutput( "", 0, "joe", "")) ;
570
571    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
572    ok(93, $db->FIRSTKEY() == 0) ;
573    ok(94, checkOutput( 0, "", "", "")) ;
574
575    # delete the filters
576    $db->filter_fetch_key   (undef);
577    $db->filter_store_key   (undef);
578    $db->filter_fetch_value (undef);
579    $db->filter_store_value (undef);
580
581    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
582    $h[0] = "joe" ;
583    ok(95, checkOutput( "", "", "", "")) ;
584
585    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
586    ok(96, $h[0] eq "joe");
587    ok(97, checkOutput( "", "", "", "")) ;
588
589    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
590    ok(98, $db->FIRSTKEY() == 0) ;
591    ok(99, checkOutput( "", "", "", "")) ;
592
593    undef $db ;
594    untie @h;
595    unlink $Dfile;
596 }
597
598 {    
599     # DBM Filter with a closure
600
601     use warnings ;
602     use strict ;
603     my (@h, $db) ;
604
605     unlink $Dfile;
606     ok(100, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) );
607
608     my %result = () ;
609
610     sub Closure
611     {
612         my ($name) = @_ ;
613         my $count = 0 ;
614         my @kept = () ;
615
616         return sub { ++$count ; 
617                      push @kept, $_ ; 
618                      $result{$name} = "$name - $count: [@kept]" ;
619                    }
620     }
621
622     $db->filter_store_key(Closure("store key")) ;
623     $db->filter_store_value(Closure("store value")) ;
624     $db->filter_fetch_key(Closure("fetch key")) ;
625     $db->filter_fetch_value(Closure("fetch value")) ;
626
627     $_ = "original" ;
628
629     $h[0] = "joe" ;
630     ok(101, $result{"store key"} eq "store key - 1: [0]");
631     ok(102, $result{"store value"} eq "store value - 1: [joe]");
632     ok(103, ! defined $result{"fetch key"} );
633     ok(104, ! defined $result{"fetch value"} );
634     ok(105, $_ eq "original") ;
635
636     ok(106, $db->FIRSTKEY() == 0 ) ;
637     ok(107, $result{"store key"} eq "store key - 1: [0]");
638     ok(108, $result{"store value"} eq "store value - 1: [joe]");
639     ok(109, $result{"fetch key"} eq "fetch key - 1: [0]");
640     ok(110, ! defined $result{"fetch value"} );
641     ok(111, $_ eq "original") ;
642
643     $h[7]  = "john" ;
644     ok(112, $result{"store key"} eq "store key - 2: [0 7]");
645     ok(113, $result{"store value"} eq "store value - 2: [joe john]");
646     ok(114, $result{"fetch key"} eq "fetch key - 1: [0]");
647     ok(115, ! defined $result{"fetch value"} );
648     ok(116, $_ eq "original") ;
649
650     ok(117, $h[0] eq "joe");
651     ok(118, $result{"store key"} eq "store key - 3: [0 7 0]");
652     ok(119, $result{"store value"} eq "store value - 2: [joe john]");
653     ok(120, $result{"fetch key"} eq "fetch key - 1: [0]");
654     ok(121, $result{"fetch value"} eq "fetch value - 1: [joe]");
655     ok(122, $_ eq "original") ;
656
657     undef $db ;
658     untie @h;
659     unlink $Dfile;
660 }               
661
662 {
663    # DBM Filter recursion detection
664    use warnings ;
665    use strict ;
666    my (@h, $db) ;
667    unlink $Dfile;
668
669    ok(123, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) );
670
671    $db->filter_store_key (sub { $_ = $h[0] }) ;
672
673    eval '$h[1] = 1234' ;
674    ok(124, $@ =~ /^recursion detected in filter_store_key at/ );
675    
676    undef $db ;
677    untie @h;
678    unlink $Dfile;
679 }
680
681
682 {
683    # Examples from the POD
684
685   my $file = "xyzt" ;
686   {
687     my $redirect = new Redirect $file ;
688
689     use warnings FATAL => qw(all);
690     use strict ;
691     use DB_File ;
692
693     my $filename = "text" ;
694     unlink $filename ;
695
696     my @h ;
697     my $x = tie @h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_RECNO 
698         or die "Cannot open file 'text': $!\n" ;
699
700     # Add a few key/value pairs to the file
701     $h[0] = "orange" ;
702     $h[1] = "blue" ;
703     $h[2] = "yellow" ;
704
705     $FA ? push @h, "green", "black" 
706         : $x->push("green", "black") ;
707
708     my $elements = $FA ? scalar @h : $x->length ;
709     print "The array contains $elements entries\n" ;
710
711     my $last = $FA ? pop @h : $x->pop ;
712     print "popped $last\n" ;
713
714     $FA ? unshift @h, "white" 
715         : $x->unshift("white") ;
716     my $first = $FA ? shift @h : $x->shift ;
717     print "shifted $first\n" ;
718
719     # Check for existence of a key
720     print "Element 1 Exists with value $h[1]\n" if $h[1] ;
721
722     # use a negative index
723     print "The last element is $h[-1]\n" ;
724     print "The 2nd last element is $h[-2]\n" ;
725
726     undef $x ;
727     untie @h ;
728
729     unlink $filename ;
730   }  
731
732   ok(125, docat_del($file) eq <<'EOM') ;
733 The array contains 5 entries
734 popped black
735 shifted white
736 Element 1 Exists with value blue
737 The last element is green
738 The 2nd last element is yellow
739 EOM
740
741   my $save_output = "xyzt" ;
742   {
743     my $redirect = new Redirect $save_output ;
744
745     use warnings FATAL => qw(all);
746     use strict ;
747     use vars qw(@h $H $file $i) ;
748     use DB_File ;
749     use Fcntl ;
750     
751     $file = "text" ;
752
753     unlink $file ;
754
755     $H = tie @h, "DB_File", $file, O_RDWR|O_CREAT, 0640, $DB_RECNO 
756         or die "Cannot open file $file: $!\n" ;
757     
758     # first create a text file to play with
759     $h[0] = "zero" ;
760     $h[1] = "one" ;
761     $h[2] = "two" ;
762     $h[3] = "three" ;
763     $h[4] = "four" ;
764
765     
766     # Print the records in order.
767     #
768     # The length method is needed here because evaluating a tied
769     # array in a scalar context does not return the number of
770     # elements in the array.  
771
772     print "\nORIGINAL\n" ;
773     foreach $i (0 .. $H->length - 1) {
774         print "$i: $h[$i]\n" ;
775     }
776
777     # use the push & pop methods
778     $a = $H->pop ;
779     $H->push("last") ;
780     print "\nThe last record was [$a]\n" ;
781
782     # and the shift & unshift methods
783     $a = $H->shift ;
784     $H->unshift("first") ;
785     print "The first record was [$a]\n" ;
786
787     # Use the API to add a new record after record 2.
788     $i = 2 ;
789     $H->put($i, "Newbie", R_IAFTER) ;
790
791     # and a new record before record 1.
792     $i = 1 ;
793     $H->put($i, "New One", R_IBEFORE) ;
794
795     # delete record 3
796     $H->del(3) ;
797
798     # now print the records in reverse order
799     print "\nREVERSE\n" ;
800     for ($i = $H->length - 1 ; $i >= 0 ; -- $i)
801       { print "$i: $h[$i]\n" }
802
803     # same again, but use the API functions instead
804     print "\nREVERSE again\n" ;
805     my ($s, $k, $v)  = (0, 0, 0) ;
806     for ($s = $H->seq($k, $v, R_LAST) ; 
807              $s == 0 ; 
808              $s = $H->seq($k, $v, R_PREV))
809       { print "$k: $v\n" }
810
811     undef $H ;
812     untie @h ;    
813
814     unlink $file ;
815   }  
816
817   ok(126, docat_del($save_output) eq <<'EOM') ;
818
819 ORIGINAL
820 0: zero
821 1: one
822 2: two
823 3: three
824 4: four
825
826 The last record was [four]
827 The first record was [zero]
828
829 REVERSE
830 5: last
831 4: three
832 3: Newbie
833 2: one
834 1: New One
835 0: first
836
837 REVERSE again
838 5: last
839 4: three
840 3: Newbie
841 2: one
842 1: New One
843 0: first
844 EOM
845    
846 }
847
848 {
849     # Bug ID 20001013.009
850     #
851     # test that $hash{KEY} = undef doesn't produce the warning
852     #     Use of uninitialized value in null operation 
853     use warnings ;
854     use strict ;
855     use DB_File ;
856
857     unlink $Dfile;
858     my @h ;
859     my $a = "";
860     local $SIG{__WARN__} = sub {$a = $_[0]} ;
861     
862     tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_RECNO 
863         or die "Can't open file: $!\n" ;
864     $h[0] = undef;
865     ok(127, $a eq "") ;
866     untie @h ;
867     unlink $Dfile;
868 }
869
870 {
871     # test that %hash = () doesn't produce the warning
872     #     Argument "" isn't numeric in entersub
873     use warnings ;
874     use strict ;
875     use DB_File ;
876     my $a = "";
877     local $SIG{__WARN__} = sub {$a = $_[0]} ;
878
879     unlink $Dfile;
880     my @h ;
881     
882     tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_RECNO 
883         or die "Can't open file: $!\n" ;
884     @h = (); ;
885     ok(128, $a eq "") ;
886     untie @h ;
887     unlink $Dfile;
888 }
889
890 exit ;