DB_File 1.806
[p5sagit/p5-mst-13.2.git] / ext / DB_File / t / db-hash.t
1 #!./perl 
2
3 BEGIN {
4     unless(grep /blib/, @INC) {
5         chdir 't' if -d 't';
6         @INC = '../lib' if -d '../lib';
7     }
8 }
9  
10 use warnings;
11 use strict;
12 use Config;
13  
14 BEGIN {
15     if(-d "lib" && -f "TEST") {
16         if ($Config{'extensions'} !~ /\bDB_File\b/ ) {
17             print "1..0 # Skip: DB_File was not built\n";
18             exit 0;
19         }
20     }
21 }
22
23 use DB_File; 
24 use Fcntl;
25
26 print "1..143\n";
27
28 unlink glob "__db.*";
29
30 sub ok
31 {
32     my $no = shift ;
33     my $result = shift ;
34  
35     print "not " unless $result ;
36     print "ok $no\n" ;
37 }
38
39 {
40     package Redirect ;
41     use Symbol ;
42
43     sub new
44     {
45         my $class = shift ;
46         my $filename = shift ;
47         my $fh = gensym ;
48         open ($fh, ">$filename") || die "Cannot open $filename: $!" ;
49         my $real_stdout = select($fh) ;
50         return bless [$fh, $real_stdout ] ;
51
52     }
53     sub DESTROY
54     {
55         my $self = shift ;
56         close $self->[0] ;
57         select($self->[1]) ;
58     }
59 }
60
61 sub docat_del
62
63     my $file = shift;
64     local $/ = undef;
65     open(CAT,$file) || die "Cannot open $file: $!";
66     my $result = <CAT>;
67     close(CAT);
68     $result = normalise($result) ;
69     unlink $file ;
70     return $result;
71 }   
72
73 sub normalise
74 {
75     my $data = shift ;
76     $data =~ s#\r\n#\n#g 
77         if $^O eq 'cygwin' ;
78     return $data ;
79 }
80
81 sub safeUntie
82 {
83     my $hashref = shift ;
84     my $no_inner = 1;
85     local $SIG{__WARN__} = sub {-- $no_inner } ;
86     untie %$hashref;
87     return $no_inner;
88 }
89
90
91 my $Dfile = "dbhash.tmp";
92 my $Dfile2 = "dbhash2.tmp";
93 my $null_keys_allowed = ($DB_File::db_ver < 2.004010 
94                                 || $DB_File::db_ver >= 3.1 );
95
96 unlink $Dfile;
97
98 umask(0);
99
100 # Check the interface to HASHINFO
101
102 my $dbh = new DB_File::HASHINFO ;
103
104 ok(1, ! defined $dbh->{bsize}) ;
105 ok(2, ! defined $dbh->{ffactor}) ;
106 ok(3, ! defined $dbh->{nelem}) ;
107 ok(4, ! defined $dbh->{cachesize}) ;
108 ok(5, ! defined $dbh->{hash}) ;
109 ok(6, ! defined $dbh->{lorder}) ;
110
111 $dbh->{bsize} = 3000 ;
112 ok(7, $dbh->{bsize} == 3000 );
113
114 $dbh->{ffactor} = 9000 ;
115 ok(8, $dbh->{ffactor} == 9000 );
116
117 $dbh->{nelem} = 400 ;
118 ok(9, $dbh->{nelem} == 400 );
119
120 $dbh->{cachesize} = 65 ;
121 ok(10, $dbh->{cachesize} == 65 );
122
123 my $some_sub = sub {} ;
124 $dbh->{hash} = $some_sub;
125 ok(11, $dbh->{hash} eq $some_sub );
126
127 $dbh->{lorder} = 1234 ;
128 ok(12, $dbh->{lorder} == 1234 );
129
130 # Check that an invalid entry is caught both for store & fetch
131 eval '$dbh->{fred} = 1234' ;
132 ok(13, $@ =~ /^DB_File::HASHINFO::STORE - Unknown element 'fred' at/ );
133 eval 'my $q = $dbh->{fred}' ;
134 ok(14, $@ =~ /^DB_File::HASHINFO::FETCH - Unknown element 'fred' at/ );
135
136
137 # Now check the interface to HASH
138 my ($X, %h);
139 ok(15, $X = tie(%h, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
140 die "Could not tie: $!" unless $X;
141
142 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
143    $blksize,$blocks) = stat($Dfile);
144
145 my %noMode = map { $_, 1} qw( amigaos MSWin32 NetWare cygwin ) ;
146
147 ok(16, ($mode & 0777) == (($^O eq 'os2' || $^O eq 'MacOS') ? 0666 : 0640) ||
148    $noMode{$^O} );
149
150 my ($key, $value, $i);
151 while (($key,$value) = each(%h)) {
152     $i++;
153 }
154 ok(17, !$i );
155
156 $h{'goner1'} = 'snork';
157
158 $h{'abc'} = 'ABC';
159 ok(18, $h{'abc'} eq 'ABC' );
160 ok(19, !defined $h{'jimmy'} );
161 ok(20, !exists $h{'jimmy'} );
162 ok(21, exists $h{'abc'} );
163
164 $h{'def'} = 'DEF';
165 $h{'jkl','mno'} = "JKL\034MNO";
166 $h{'a',2,3,4,5} = join("\034",'A',2,3,4,5);
167 $h{'a'} = 'A';
168
169 #$h{'b'} = 'B';
170 $X->STORE('b', 'B') ;
171
172 $h{'c'} = 'C';
173
174 #$h{'d'} = 'D';
175 $X->put('d', 'D') ;
176
177 $h{'e'} = 'E';
178 $h{'f'} = 'F';
179 $h{'g'} = 'X';
180 $h{'h'} = 'H';
181 $h{'i'} = 'I';
182
183 $h{'goner2'} = 'snork';
184 delete $h{'goner2'};
185
186
187 # IMPORTANT - $X must be undefined before the untie otherwise the
188 #             underlying DB close routine will not get called.
189 undef $X ;
190 untie(%h);
191
192
193 # tie to the same file again, do not supply a type - should default to HASH
194 ok(22, $X = tie(%h,'DB_File',$Dfile, O_RDWR, 0640) );
195
196 # Modify an entry from the previous tie
197 $h{'g'} = 'G';
198
199 $h{'j'} = 'J';
200 $h{'k'} = 'K';
201 $h{'l'} = 'L';
202 $h{'m'} = 'M';
203 $h{'n'} = 'N';
204 $h{'o'} = 'O';
205 $h{'p'} = 'P';
206 $h{'q'} = 'Q';
207 $h{'r'} = 'R';
208 $h{'s'} = 'S';
209 $h{'t'} = 'T';
210 $h{'u'} = 'U';
211 $h{'v'} = 'V';
212 $h{'w'} = 'W';
213 $h{'x'} = 'X';
214 $h{'y'} = 'Y';
215 $h{'z'} = 'Z';
216
217 $h{'goner3'} = 'snork';
218
219 delete $h{'goner1'};
220 $X->DELETE('goner3');
221
222 my @keys = keys(%h);
223 my @values = values(%h);
224
225 ok(23, $#keys == 29 && $#values == 29) ;
226
227 $i = 0 ;
228 while (($key,$value) = each(%h)) {
229     if ($key eq $keys[$i] && $value eq $values[$i] && $key eq lc($value)) {
230         $key =~ y/a-z/A-Z/;
231         $i++ if $key eq $value;
232     }
233 }
234
235 ok(24, $i == 30) ;
236
237 @keys = ('blurfl', keys(%h), 'dyick');
238 ok(25, $#keys == 31) ;
239
240 $h{'foo'} = '';
241 ok(26, $h{'foo'} eq '' );
242
243 # Berkeley DB from version 2.4.10 to 3.0 does not allow null keys.
244 # This feature was reenabled in version 3.1 of Berkeley DB.
245 my $result = 0 ;
246 if ($null_keys_allowed) {
247     $h{''} = 'bar';
248     $result = ( $h{''} eq 'bar' );
249 }
250 else
251   { $result = 1 }
252 ok(27, $result) ;
253
254 # check cache overflow and numeric keys and contents
255 my $ok = 1;
256 for ($i = 1; $i < 200; $i++) { $h{$i + 0} = $i + 0; }
257 for ($i = 1; $i < 200; $i++) { $ok = 0 unless $h{$i} == $i; }
258 ok(28, $ok );
259
260 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
261    $blksize,$blocks) = stat($Dfile);
262 ok(29, $size > 0 );
263
264 @h{0..200} = 200..400;
265 my @foo = @h{0..200};
266 ok(30, join(':',200..400) eq join(':',@foo) );
267
268
269 # Now check all the non-tie specific stuff
270
271 # Check NOOVERWRITE will make put fail when attempting to overwrite
272 # an existing record.
273  
274 my $status = $X->put( 'x', 'newvalue', R_NOOVERWRITE) ;
275 ok(31, $status == 1 );
276  
277 # check that the value of the key 'x' has not been changed by the 
278 # previous test
279 ok(32, $h{'x'} eq 'X' );
280
281 # standard put
282 $status = $X->put('key', 'value') ;
283 ok(33, $status == 0 );
284
285 #check that previous put can be retrieved
286 $value = 0 ;
287 $status = $X->get('key', $value) ;
288 ok(34, $status == 0 );
289 ok(35, $value eq 'value' );
290
291 # Attempting to delete an existing key should work
292
293 $status = $X->del('q') ;
294 ok(36, $status == 0 );
295
296 # Make sure that the key deleted, cannot be retrieved
297 {
298     no warnings 'uninitialized' ;
299     ok(37, $h{'q'} eq undef );
300 }
301
302 # Attempting to delete a non-existant key should fail
303
304 $status = $X->del('joe') ;
305 ok(38, $status == 1 );
306
307 # Check the get interface
308
309 # First a non-existing key
310 $status = $X->get('aaaa', $value) ;
311 ok(39, $status == 1 );
312
313 # Next an existing key
314 $status = $X->get('a', $value) ;
315 ok(40, $status == 0 );
316 ok(41, $value eq 'A' );
317
318 # seq
319 # ###
320
321 # ditto, but use put to replace the key/value pair.
322
323 # use seq to walk backwards through a file - check that this reversed is
324
325 # check seq FIRST/LAST
326
327 # sync
328 # ####
329
330 $status = $X->sync ;
331 ok(42, $status == 0 );
332
333
334 # fd
335 # ##
336
337 $status = $X->fd ;
338 ok(43, $status != 0 );
339
340 undef $X ;
341 untie %h ;
342
343 unlink $Dfile;
344
345 # clear
346 # #####
347
348 ok(44, tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
349 foreach (1 .. 10)
350   { $h{$_} = $_ * 100 }
351
352 # check that there are 10 elements in the hash
353 $i = 0 ;
354 while (($key,$value) = each(%h)) {
355     $i++;
356 }
357 ok(45, $i == 10);
358
359 # now clear the hash
360 %h = () ;
361
362 # check it is empty
363 $i = 0 ;
364 while (($key,$value) = each(%h)) {
365     $i++;
366 }
367 ok(46, $i == 0);
368
369 untie %h ;
370 unlink $Dfile ;
371
372
373 # Now try an in memory file
374 ok(47, $X = tie(%h, 'DB_File',undef, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
375
376 # fd with an in memory file should return fail
377 $status = $X->fd ;
378 ok(48, $status == -1 );
379
380 undef $X ;
381 untie %h ;
382
383 {
384     # check ability to override the default hashing
385     my %x ;
386     my $filename = "xyz" ;
387     my $hi = new DB_File::HASHINFO ;
388     $::count = 0 ;
389     $hi->{hash} = sub { ++$::count ; length $_[0] } ;
390     ok(49, tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0640, $hi ) ;
391     $h{"abc"} = 123 ;
392     ok(50, $h{"abc"} == 123) ;
393     untie %x ;
394     unlink $filename ;
395     ok(51, $::count >0) ;
396 }
397
398 {
399     # check that attempting to tie an array to a DB_HASH will fail
400
401     my $filename = "xyz" ;
402     my @x ;
403     eval { tie @x, 'DB_File', $filename, O_RDWR|O_CREAT, 0640, $DB_HASH ; } ;
404     ok(52, $@ =~ /^DB_File can only tie an associative array to a DB_HASH database/) ;
405     unlink $filename ;
406 }
407
408 {
409    # sub-class test
410
411    package Another ;
412
413    use warnings ;
414    use strict ;
415
416    open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ;
417    print FILE <<'EOM' ;
418
419    package SubDB ;
420
421    use warnings ;
422    use strict ;
423    our (@ISA, @EXPORT);
424
425    require Exporter ;
426    use DB_File;
427    @ISA=qw(DB_File);
428    @EXPORT = @DB_File::EXPORT ;
429
430    sub STORE { 
431         my $self = shift ;
432         my $key = shift ;
433         my $value = shift ;
434         $self->SUPER::STORE($key, $value * 2) ;
435    }
436
437    sub FETCH { 
438         my $self = shift ;
439         my $key = shift ;
440         $self->SUPER::FETCH($key) - 1 ;
441    }
442
443    sub put { 
444         my $self = shift ;
445         my $key = shift ;
446         my $value = shift ;
447         $self->SUPER::put($key, $value * 3) ;
448    }
449
450    sub get { 
451         my $self = shift ;
452         $self->SUPER::get($_[0], $_[1]) ;
453         $_[1] -= 2 ;
454    }
455
456    sub A_new_method
457    {
458         my $self = shift ;
459         my $key = shift ;
460         my $value = $self->FETCH($key) ;
461         return "[[$value]]" ;
462    }
463
464    1 ;
465 EOM
466
467     close FILE ;
468
469     BEGIN { push @INC, '.'; }             
470     eval 'use SubDB ; ';
471     main::ok(53, $@ eq "") ;
472     my %h ;
473     my $X ;
474     eval '
475         $X = tie(%h, "SubDB","dbhash.tmp", O_RDWR|O_CREAT, 0640, $DB_HASH );
476         ' ;
477
478     main::ok(54, $@ eq "") ;
479
480     my $ret = eval '$h{"fred"} = 3 ; return $h{"fred"} ' ;
481     main::ok(55, $@ eq "") ;
482     main::ok(56, $ret == 5) ;
483
484     my $value = 0;
485     $ret = eval '$X->put("joe", 4) ; $X->get("joe", $value) ; return $value' ;
486     main::ok(57, $@ eq "") ;
487     main::ok(58, $ret == 10) ;
488
489     $ret = eval ' R_NEXT eq main::R_NEXT ' ;
490     main::ok(59, $@ eq "" ) ;
491     main::ok(60, $ret == 1) ;
492
493     $ret = eval '$X->A_new_method("joe") ' ;
494     main::ok(61, $@ eq "") ;
495     main::ok(62, $ret eq "[[11]]") ;
496
497     undef $X;
498     untie(%h);
499     unlink "SubDB.pm", "dbhash.tmp" ;
500
501 }
502
503 {
504    # DBM Filter tests
505    use warnings ;
506    use strict ;
507    my (%h, $db) ;
508    my ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
509    unlink $Dfile;
510
511    sub checkOutput
512    {
513        no warnings 'uninitialized';
514        my($fk, $sk, $fv, $sv) = @_ ;
515
516        print "# Fetch Key   : expected '$fk' got '$fetch_key'\n" 
517            if $fetch_key ne $fk ;
518        print "# Fetch Value : expected '$fv' got '$fetch_value'\n" 
519            if $fetch_value ne $fv ;
520        print "# Store Key   : expected '$sk' got '$store_key'\n" 
521            if $store_key ne $sk ;
522        print "# Store Value : expected '$sv' got '$store_value'\n" 
523            if $store_value ne $sv ;
524        print "# \$_          : expected 'original' got '$_'\n" 
525            if $_ ne 'original' ;
526
527        return
528            $fetch_key   eq $fk && $store_key   eq $sk && 
529            $fetch_value eq $fv && $store_value eq $sv &&
530            $_ eq 'original' ;
531    }
532    
533    ok(63, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
534
535    $db->filter_fetch_key   (sub { $fetch_key = $_ }) ;
536    $db->filter_store_key   (sub { $store_key = $_ }) ;
537    $db->filter_fetch_value (sub { $fetch_value = $_}) ;
538    $db->filter_store_value (sub { $store_value = $_ }) ;
539
540    $_ = "original" ;
541
542    $h{"fred"} = "joe" ;
543    #                   fk   sk     fv   sv
544    ok(64, checkOutput( "", "fred", "", "joe")) ;
545
546    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
547    ok(65, $h{"fred"} eq "joe");
548    #                   fk    sk     fv    sv
549    ok(66, checkOutput( "", "fred", "joe", "")) ;
550
551    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
552    my ($k, $v) ;
553    $k = 'fred';
554    ok(67, ! $db->seq($k, $v, R_FIRST) ) ;
555    ok(68, $k eq "fred") ;
556    ok(69, $v eq "joe") ;
557    #                    fk     sk  fv  sv
558    ok(70, checkOutput( "fred", "fred", "joe", "")) ;
559
560    # replace the filters, but remember the previous set
561    my ($old_fk) = $db->filter_fetch_key   
562                         (sub { $_ = uc $_ ; $fetch_key = $_ }) ;
563    my ($old_sk) = $db->filter_store_key   
564                         (sub { $_ = lc $_ ; $store_key = $_ }) ;
565    my ($old_fv) = $db->filter_fetch_value 
566                         (sub { $_ = "[$_]"; $fetch_value = $_ }) ;
567    my ($old_sv) = $db->filter_store_value 
568                         (sub { s/o/x/g; $store_value = $_ }) ;
569    
570    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
571    $h{"Fred"} = "Joe" ;
572    #                   fk   sk     fv    sv
573    ok(71, checkOutput( "", "fred", "", "Jxe")) ;
574
575    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
576    ok(72, $h{"Fred"} eq "[Jxe]");
577    #                   fk   sk     fv    sv
578    ok(73, checkOutput( "", "fred", "[Jxe]", "")) ;
579
580    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
581    $k = 'Fred'; $v ='';
582    ok(74, ! $db->seq($k, $v, R_FIRST) ) ;
583    ok(75, $k eq "FRED") ;
584    ok(76, $v eq "[Jxe]") ;
585    #                   fk   sk     fv    sv
586    ok(77, checkOutput( "FRED", "fred", "[Jxe]", "")) ;
587
588    # put the original filters back
589    $db->filter_fetch_key   ($old_fk);
590    $db->filter_store_key   ($old_sk);
591    $db->filter_fetch_value ($old_fv);
592    $db->filter_store_value ($old_sv);
593
594    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
595    $h{"fred"} = "joe" ;
596    ok(78, checkOutput( "", "fred", "", "joe")) ;
597
598    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
599    ok(79, $h{"fred"} eq "joe");
600    ok(80, checkOutput( "", "fred", "joe", "")) ;
601
602    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
603    #ok(77, $db->FIRSTKEY() eq "fred") ;
604    $k = 'fred';
605    ok(81, ! $db->seq($k, $v, R_FIRST) ) ;
606    ok(82, $k eq "fred") ;
607    ok(83, $v eq "joe") ;
608    #                   fk   sk     fv    sv
609    ok(84, checkOutput( "fred", "fred", "joe", "")) ;
610
611    # delete the filters
612    $db->filter_fetch_key   (undef);
613    $db->filter_store_key   (undef);
614    $db->filter_fetch_value (undef);
615    $db->filter_store_value (undef);
616
617    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
618    $h{"fred"} = "joe" ;
619    ok(85, checkOutput( "", "", "", "")) ;
620
621    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
622    ok(86, $h{"fred"} eq "joe");
623    ok(87, checkOutput( "", "", "", "")) ;
624
625    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
626    $k = 'fred';
627    ok(88, ! $db->seq($k, $v, R_FIRST) ) ;
628    ok(89, $k eq "fred") ;
629    ok(90, $v eq "joe") ;
630    ok(91, checkOutput( "", "", "", "")) ;
631
632    undef $db ;
633    untie %h;
634    unlink $Dfile;
635 }
636
637 {    
638     # DBM Filter with a closure
639
640     use warnings ;
641     use strict ;
642     my (%h, $db) ;
643
644     unlink $Dfile;
645     ok(92, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
646
647     my %result = () ;
648
649     sub Closure
650     {
651         my ($name) = @_ ;
652         my $count = 0 ;
653         my @kept = () ;
654
655         return sub { ++$count ; 
656                      push @kept, $_ ; 
657                      $result{$name} = "$name - $count: [@kept]" ;
658                    }
659     }
660
661     $db->filter_store_key(Closure("store key")) ;
662     $db->filter_store_value(Closure("store value")) ;
663     $db->filter_fetch_key(Closure("fetch key")) ;
664     $db->filter_fetch_value(Closure("fetch value")) ;
665
666     $_ = "original" ;
667
668     $h{"fred"} = "joe" ;
669     ok(93, $result{"store key"} eq "store key - 1: [fred]");
670     ok(94, $result{"store value"} eq "store value - 1: [joe]");
671     ok(95, ! defined $result{"fetch key"} );
672     ok(96, ! defined $result{"fetch value"} );
673     ok(97, $_ eq "original") ;
674
675     ok(98, $db->FIRSTKEY() eq "fred") ;
676     ok(99, $result{"store key"} eq "store key - 1: [fred]");
677     ok(100, $result{"store value"} eq "store value - 1: [joe]");
678     ok(101, $result{"fetch key"} eq "fetch key - 1: [fred]");
679     ok(102, ! defined $result{"fetch value"} );
680     ok(103, $_ eq "original") ;
681
682     $h{"jim"}  = "john" ;
683     ok(104, $result{"store key"} eq "store key - 2: [fred jim]");
684     ok(105, $result{"store value"} eq "store value - 2: [joe john]");
685     ok(106, $result{"fetch key"} eq "fetch key - 1: [fred]");
686     ok(107, ! defined $result{"fetch value"} );
687     ok(108, $_ eq "original") ;
688
689     ok(109, $h{"fred"} eq "joe");
690     ok(110, $result{"store key"} eq "store key - 3: [fred jim fred]");
691     ok(111, $result{"store value"} eq "store value - 2: [joe john]");
692     ok(112, $result{"fetch key"} eq "fetch key - 1: [fred]");
693     ok(113, $result{"fetch value"} eq "fetch value - 1: [joe]");
694     ok(114, $_ eq "original") ;
695
696     undef $db ;
697     untie %h;
698     unlink $Dfile;
699 }               
700
701 {
702    # DBM Filter recursion detection
703    use warnings ;
704    use strict ;
705    my (%h, $db) ;
706    unlink $Dfile;
707
708    ok(115, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
709
710    $db->filter_store_key (sub { $_ = $h{$_} }) ;
711
712    eval '$h{1} = 1234' ;
713    ok(116, $@ =~ /^recursion detected in filter_store_key at/ );
714    
715    undef $db ;
716    untie %h;
717    unlink $Dfile;
718 }
719
720
721 {
722    # Examples from the POD
723
724   my $file = "xyzt" ;
725   {
726     my $redirect = new Redirect $file ;
727
728     use warnings FATAL => qw(all);
729     use strict ;
730     use DB_File ;
731     our (%h, $k, $v);
732
733     unlink "fruit" ;
734     tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0640, $DB_HASH 
735         or die "Cannot open file 'fruit': $!\n";
736
737     # Add a few key/value pairs to the file
738     $h{"apple"} = "red" ;
739     $h{"orange"} = "orange" ;
740     $h{"banana"} = "yellow" ;
741     $h{"tomato"} = "red" ;
742
743     # Check for existence of a key
744     print "Banana Exists\n\n" if $h{"banana"} ;
745
746     # Delete a key/value pair.
747     delete $h{"apple"} ;
748
749     # print the contents of the file
750     while (($k, $v) = each %h)
751       { print "$k -> $v\n" }
752
753     untie %h ;
754
755     unlink "fruit" ;
756   }  
757
758   ok(117, docat_del($file) eq <<'EOM') ;
759 Banana Exists
760
761 orange -> orange
762 tomato -> red
763 banana -> yellow
764 EOM
765    
766 }
767
768 {
769     # Bug ID 20001013.009
770     #
771     # test that $hash{KEY} = undef doesn't produce the warning
772     #     Use of uninitialized value in null operation 
773     use warnings ;
774     use strict ;
775     use DB_File ;
776
777     unlink $Dfile;
778     my %h ;
779     my $a = "";
780     local $SIG{__WARN__} = sub {$a = $_[0]} ;
781     
782     tie %h, 'DB_File', $Dfile or die "Can't open file: $!\n" ;
783     $h{ABC} = undef;
784     ok(118, $a eq "") ;
785     untie %h ;
786     unlink $Dfile;
787 }
788
789 {
790     # test that %hash = () doesn't produce the warning
791     #     Argument "" isn't numeric in entersub
792     use warnings ;
793     use strict ;
794     use DB_File ;
795
796     unlink $Dfile;
797     my %h ;
798     my $a = "";
799     local $SIG{__WARN__} = sub {$a = $_[0]} ;
800     
801     tie %h, 'DB_File', $Dfile or die "Can't open file: $!\n" ;
802     %h = (); ;
803     ok(119, $a eq "") ;
804     untie %h ;
805     unlink $Dfile;
806 }
807
808 {
809     # When iterating over a tied hash using "each", the key passed to FETCH
810     # will be recycled and passed to NEXTKEY. If a Source Filter modifies the
811     # key in FETCH via a filter_fetch_key method we need to check that the
812     # modified key doesn't get passed to NEXTKEY.
813     # Also Test "keys" & "values" while we are at it.
814
815     use warnings ;
816     use strict ;
817     use DB_File ;
818
819     unlink $Dfile;
820     my $bad_key = 0 ;
821     my %h = () ;
822     my $db ;
823     ok(120, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
824     $db->filter_fetch_key (sub { $_ =~ s/^Beta_/Alpha_/ if defined $_}) ;
825     $db->filter_store_key (sub { $bad_key = 1 if /^Beta_/ ; $_ =~ s/^Alpha_/Beta_/}) ;
826
827     $h{'Alpha_ABC'} = 2 ;
828     $h{'Alpha_DEF'} = 5 ;
829
830     ok(121, $h{'Alpha_ABC'} == 2);
831     ok(122, $h{'Alpha_DEF'} == 5);
832
833     my ($k, $v) = ("","");
834     while (($k, $v) = each %h) {}
835     ok(123, $bad_key == 0);
836
837     $bad_key = 0 ;
838     foreach $k (keys %h) {}
839     ok(124, $bad_key == 0);
840
841     $bad_key = 0 ;
842     foreach $v (values %h) {}
843     ok(125, $bad_key == 0);
844
845     undef $db ;
846     untie %h ;
847     unlink $Dfile;
848 }
849
850 {
851     # now an error to pass 'hash' a non-code reference
852     my $dbh = new DB_File::HASHINFO ;
853
854     eval { $dbh->{hash} = 2 };
855     ok(126, $@ =~ /^Key 'hash' not associated with a code reference at/);
856
857 }
858
859
860 #{
861 #    # recursion detection in hash
862 #    my %hash ;
863 #    my $Dfile = "xxx.db";
864 #    unlink $Dfile;
865 #    my $dbh = new DB_File::HASHINFO ;
866 #    $dbh->{hash} = sub { $hash{3} = 4 ; length $_[0] } ;
867
868
869 #    ok(127, tie(%hash, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $dbh ) );
870 #
871 #    eval {     $hash{1} = 2;
872 #               $hash{4} = 5;
873 #        };
874 #
875 #    ok(128, $@ =~ /^DB_File hash callback: recursion detected/);
876 #    {
877 #        no warnings;
878 #        untie %hash;
879 #    }
880 #    unlink $Dfile;
881 #}
882
883 ok(127,1);
884 ok(128,1);
885
886 {
887     # Check that two hash's don't interact
888     my %hash1 ;
889     my %hash2 ;
890     my $h1_count = 0;
891     my $h2_count = 0;
892     unlink $Dfile, $Dfile2;
893     my $dbh1 = new DB_File::HASHINFO ;
894     $dbh1->{hash} = sub { ++ $h1_count ; length $_[0] } ;
895
896     my $dbh2 = new DB_File::HASHINFO ;
897     $dbh2->{hash} = sub { ++ $h2_count ; length $_[0] } ;
898  
899  
900  
901     my (%h);
902     ok(129, tie(%hash1, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $dbh1 ) );
903     ok(130, tie(%hash2, 'DB_File',$Dfile2, O_RDWR|O_CREAT, 0640, $dbh2 ) );
904
905     $hash1{DEFG} = 5;
906     $hash1{XYZ} = 2;
907     $hash1{ABCDE} = 5;
908
909     $hash2{defg} = 5;
910     $hash2{xyz} = 2;
911     $hash2{abcde} = 5;
912
913     ok(131, $h1_count > 0);
914     ok(132, $h1_count == $h2_count);
915
916     ok(133, safeUntie \%hash1);
917     ok(134, safeUntie \%hash2);
918     unlink $Dfile, $Dfile2;
919 }
920
921 {
922     # Passing undef for flags and/or mode when calling tie could cause 
923     #     Use of uninitialized value in subroutine entry
924     
925
926     my $warn_count = 0 ;
927     #local $SIG{__WARN__} = sub { ++ $warn_count };
928     my %hash1;
929     unlink $Dfile;
930
931     tie %hash1, 'DB_File',$Dfile, undef;
932     ok(135, $warn_count == 0);
933     $warn_count = 0;
934     tie %hash1, 'DB_File',$Dfile, O_RDWR|O_CREAT, undef;
935     ok(136, $warn_count == 0);
936     tie %hash1, 'DB_File',$Dfile, undef, undef;
937     ok(137, $warn_count == 0);
938     $warn_count = 0;
939
940     unlink $Dfile;
941 }
942
943 {
944    # Check that DBM Filter can cope with read-only $_
945
946    use warnings ;
947    use strict ;
948    my (%h, $db) ;
949    my $Dfile = "xxy.db";
950    unlink $Dfile;
951
952    ok(138, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
953
954    $db->filter_fetch_key   (sub { }) ;
955    $db->filter_store_key   (sub { }) ;
956    $db->filter_fetch_value (sub { }) ;
957    $db->filter_store_value (sub { }) ;
958
959    $_ = "original" ;
960
961    $h{"fred"} = "joe" ;
962    ok(139, $h{"fred"} eq "joe");
963
964    eval { grep { $h{$_} } (1, 2, 3) };
965    ok (140, ! $@);
966
967
968    # delete the filters
969    $db->filter_fetch_key   (undef);
970    $db->filter_store_key   (undef);
971    $db->filter_fetch_value (undef);
972    $db->filter_store_value (undef);
973
974    $h{"fred"} = "joe" ;
975
976    ok(141, $h{"fred"} eq "joe");
977
978    ok(142, $db->FIRSTKEY() eq "fred") ;
979    
980    eval { grep { $h{$_} } (1, 2, 3) };
981    ok (143, ! $@);
982
983    undef $db ;
984    untie %h;
985    unlink $Dfile;
986 }
987
988
989 exit ;