xref: /openbsd-src/gnu/usr.bin/perl/t/lib/dbmt_common.pl (revision 898184e3e61f9129feb5978fad5a8c6865f00b92)
1*898184e3Ssthen#!perl
2*898184e3SsthenBEGIN {
3*898184e3Ssthen}
4*898184e3Ssthen
5*898184e3Ssthenuse strict;
6*898184e3Ssthenuse warnings;
7*898184e3Ssthen
8*898184e3Ssthenuse Test::More;
9*898184e3Ssthenuse Config;
10*898184e3Ssthen
11*898184e3Ssthenour $DBM_Class;
12*898184e3Ssthen
13*898184e3Ssthenmy ($create, $write);
14*898184e3SsthenBEGIN {
15*898184e3Ssthen    plan(skip_all => "$DBM_Class was not built")
16*898184e3Ssthen	unless $Config{extensions} =~ /\b$DBM_Class\b/;
17*898184e3Ssthen    plan(skip_all => "$DBM_Class not compatible with C++")
18*898184e3Ssthen	 if $DBM_Class eq 'ODBM_File' && $Config{d_cplusplus};
19*898184e3Ssthen
20*898184e3Ssthen    use_ok($DBM_Class);
21*898184e3Ssthen
22*898184e3Ssthen    if ($::Create_and_Write) {
23*898184e3Ssthen	($create, $write) = eval $::Create_and_Write;
24*898184e3Ssthen	isnt($create, undef, "(eval q{$::Create_and_Write})[0]");
25*898184e3Ssthen	isnt($write, undef, "(eval q{$::Create_and_Write})[1]");
26*898184e3Ssthen    } else {
27*898184e3Ssthen	#If Fcntl is not available, try 0x202 or 0x102 for O_RDWR|O_CREAT
28*898184e3Ssthen	use_ok('Fcntl');
29*898184e3Ssthen	$create = O_RDWR()|O_CREAT();
30*898184e3Ssthen	$write = O_RDWR();
31*898184e3Ssthen    }
32*898184e3Ssthen}
33*898184e3Ssthen
34*898184e3Ssthenunlink <Op_dbmx.*>;
35*898184e3Ssthen
36*898184e3Ssthenumask(0);
37*898184e3Ssthenmy %h;
38*898184e3Ssthenisa_ok(tie(%h, $DBM_Class, 'Op_dbmx', $create, 0640), $DBM_Class);
39*898184e3Ssthen
40*898184e3Ssthenmy $Dfile = "Op_dbmx.pag";
41*898184e3Ssthenif (! -e $Dfile) {
42*898184e3Ssthen	($Dfile) = <Op_dbmx*>;
43*898184e3Ssthen}
44*898184e3SsthenSKIP: {
45*898184e3Ssthen    skip "different file permission semantics on $^O", 1
46*898184e3Ssthen	if $^O eq 'amigaos' || $^O eq 'os2' || $^O eq 'MSWin32' || $^O eq 'NetWare' || $^O eq 'dos' || $^O eq 'cygwin' || $^O eq 'vos';
47*898184e3Ssthen    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
48*898184e3Ssthen	$blksize,$blocks) = stat($Dfile);
49*898184e3Ssthen    is($mode & 0777, 0640);
50*898184e3Ssthen}
51*898184e3Ssthenmy $i = 0;
52*898184e3Ssthenwhile (my ($key,$value) = each(%h)) {
53*898184e3Ssthen    $i++;
54*898184e3Ssthen}
55*898184e3Ssthenis($i, 0);
56*898184e3Ssthen
57*898184e3Ssthen$h{'goner1'} = 'snork';
58*898184e3Ssthen
59*898184e3Ssthen$h{'abc'} = 'ABC';
60*898184e3Ssthen$h{'def'} = 'DEF';
61*898184e3Ssthen$h{'jkl','mno'} = "JKL\034MNO";
62*898184e3Ssthen$h{'a',2,3,4,5} = join("\034",'A',2,3,4,5);
63*898184e3Ssthen$h{'a'} = 'A';
64*898184e3Ssthen$h{'b'} = 'B';
65*898184e3Ssthen$h{'c'} = 'C';
66*898184e3Ssthen$h{'d'} = 'D';
67*898184e3Ssthen$h{'e'} = 'E';
68*898184e3Ssthen$h{'f'} = 'F';
69*898184e3Ssthen$h{'g'} = 'G';
70*898184e3Ssthen$h{'h'} = 'H';
71*898184e3Ssthen$h{'i'} = 'I';
72*898184e3Ssthen
73*898184e3Ssthen$h{'goner2'} = 'snork';
74*898184e3Ssthendelete $h{'goner2'};
75*898184e3Ssthen
76*898184e3Ssthenuntie(%h);
77*898184e3Ssthenisa_ok(tie(%h, $DBM_Class, 'Op_dbmx', $write, 0640), $DBM_Class);
78*898184e3Ssthen
79*898184e3Ssthen$h{'j'} = 'J';
80*898184e3Ssthen$h{'k'} = 'K';
81*898184e3Ssthen$h{'l'} = 'L';
82*898184e3Ssthen$h{'m'} = 'M';
83*898184e3Ssthen$h{'n'} = 'N';
84*898184e3Ssthen$h{'o'} = 'O';
85*898184e3Ssthen$h{'p'} = 'P';
86*898184e3Ssthen$h{'q'} = 'Q';
87*898184e3Ssthen$h{'r'} = 'R';
88*898184e3Ssthen$h{'s'} = 'S';
89*898184e3Ssthen$h{'t'} = 'T';
90*898184e3Ssthen$h{'u'} = 'U';
91*898184e3Ssthen$h{'v'} = 'V';
92*898184e3Ssthen$h{'w'} = 'W';
93*898184e3Ssthen$h{'x'} = 'X';
94*898184e3Ssthen$h{'y'} = 'Y';
95*898184e3Ssthen$h{'z'} = 'Z';
96*898184e3Ssthen
97*898184e3Ssthen$h{'goner3'} = 'snork';
98*898184e3Ssthen
99*898184e3Ssthendelete $h{'goner1'};
100*898184e3Ssthendelete $h{'goner3'};
101*898184e3Ssthen
102*898184e3Ssthenmy @keys = keys(%h);
103*898184e3Ssthenmy @values = values(%h);
104*898184e3Ssthen
105*898184e3Ssthenis($#keys, 29);
106*898184e3Ssthenis($#values, 29);
107*898184e3Ssthen
108*898184e3Ssthenwhile (my ($key, $value) = each(%h)) {
109*898184e3Ssthen    if ($key eq $keys[$i] && $value eq $values[$i] && $key eq lc($value)) {
110*898184e3Ssthen	$key =~ y/a-z/A-Z/;
111*898184e3Ssthen	$i++ if $key eq $value;
112*898184e3Ssthen    }
113*898184e3Ssthen}
114*898184e3Ssthen
115*898184e3Ssthenis($i, 30);
116*898184e3Ssthen
117*898184e3Ssthen@keys = ('blurfl', keys(%h), 'dyick');
118*898184e3Ssthenis($#keys, 31);
119*898184e3Ssthen
120*898184e3Ssthen$h{'foo'} = '';
121*898184e3Ssthen$h{''} = 'bar';
122*898184e3Ssthen
123*898184e3Ssthenmy $ok = 1;
124*898184e3Ssthenfor ($i = 1; $i < 200; $i++) { $h{$i + 0} = $i + 0; }
125*898184e3Ssthenfor ($i = 1; $i < 200; $i++) { $ok = 0 unless $h{$i} == $i; }
126*898184e3Ssthenis($ok, 1, 'check cache overflow and numeric keys and contents');
127*898184e3Ssthen
128*898184e3Ssthenmy ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
129*898184e3Ssthen   $blksize,$blocks) = stat($Dfile);
130*898184e3Ssthencmp_ok($size, '>', 0);
131*898184e3Ssthen
132*898184e3Ssthen@h{0..200} = 200..400;
133*898184e3Ssthenmy @foo = @h{0..200};
134*898184e3Ssthenis(join(':',200..400), join(':',@foo));
135*898184e3Ssthen
136*898184e3Ssthenis($h{'foo'}, '');
137*898184e3Ssthenis($h{''}, 'bar');
138*898184e3Ssthen
139*898184e3Ssthenif($DBM_Class eq 'SDBM_File') {
140*898184e3Ssthen    is(exists $h{goner1}, '');
141*898184e3Ssthen    is(exists $h{foo}, 1);
142*898184e3Ssthen}
143*898184e3Ssthen
144*898184e3Ssthenuntie %h;
145*898184e3Ssthenunlink <Op_dbmx*>, $Dfile;
146*898184e3Ssthen
147*898184e3Ssthen{
148*898184e3Ssthen   # sub-class test
149*898184e3Ssthen
150*898184e3Ssthen   package Another;
151*898184e3Ssthen
152*898184e3Ssthen   open my $file, '>', 'SubDB.pm' or die "Cannot open SubDB.pm: $!\n";
153*898184e3Ssthen   printf $file <<'EOM', $DBM_Class, $DBM_Class, $DBM_Class;
154*898184e3Ssthen
155*898184e3Ssthen   package SubDB;
156*898184e3Ssthen
157*898184e3Ssthen   use strict;
158*898184e3Ssthen   use warnings;
159*898184e3Ssthen   use vars qw(@ISA @EXPORT);
160*898184e3Ssthen
161*898184e3Ssthen   require Exporter;
162*898184e3Ssthen   use %s;
163*898184e3Ssthen   @ISA=qw(%s);
164*898184e3Ssthen   @EXPORT = @%s::EXPORT;
165*898184e3Ssthen
166*898184e3Ssthen   sub STORE {
167*898184e3Ssthen	my $self = shift;
168*898184e3Ssthen        my $key = shift;
169*898184e3Ssthen        my $value = shift;
170*898184e3Ssthen        $self->SUPER::STORE($key, $value * 2);
171*898184e3Ssthen   }
172*898184e3Ssthen
173*898184e3Ssthen   sub FETCH {
174*898184e3Ssthen	my $self = shift;
175*898184e3Ssthen        my $key = shift;
176*898184e3Ssthen        $self->SUPER::FETCH($key) - 1;
177*898184e3Ssthen   }
178*898184e3Ssthen
179*898184e3Ssthen   sub A_new_method
180*898184e3Ssthen   {
181*898184e3Ssthen	my $self = shift;
182*898184e3Ssthen        my $key = shift;
183*898184e3Ssthen        my $value = $self->FETCH($key);
184*898184e3Ssthen	return "[[$value]]";
185*898184e3Ssthen   }
186*898184e3Ssthen
187*898184e3Ssthen   1;
188*898184e3SsthenEOM
189*898184e3Ssthen
190*898184e3Ssthen    close $file or die "Could not close: $!";
191*898184e3Ssthen
192*898184e3Ssthen    BEGIN { push @INC, '.'; }
193*898184e3Ssthen    unlink <dbhash_tmp*>;
194*898184e3Ssthen
195*898184e3Ssthen    main::use_ok('SubDB');
196*898184e3Ssthen    my %h;
197*898184e3Ssthen    my $X;
198*898184e3Ssthen    eval '
199*898184e3Ssthen	$X = tie(%h, "SubDB", "dbhash_tmp", $create, 0640 );
200*898184e3Ssthen	';
201*898184e3Ssthen
202*898184e3Ssthen    main::is($@, "");
203*898184e3Ssthen
204*898184e3Ssthen    my $ret = eval '$h{"fred"} = 3; return $h{"fred"} ';
205*898184e3Ssthen    main::is($@, "");
206*898184e3Ssthen    main::is($ret, 5);
207*898184e3Ssthen
208*898184e3Ssthen    $ret = eval '$X->A_new_method("fred") ';
209*898184e3Ssthen    main::is($@, "");
210*898184e3Ssthen    main::is($ret, "[[5]]");
211*898184e3Ssthen
212*898184e3Ssthen    if ($DBM_Class eq 'GDBM_File') {
213*898184e3Ssthen        $ret = eval 'GDBM_WRCREAT eq main::GDBM_WRCREAT';
214*898184e3Ssthen        main::is($@, "");
215*898184e3Ssthen        main::is($ret, 1);
216*898184e3Ssthen    }
217*898184e3Ssthen
218*898184e3Ssthen    undef $X;
219*898184e3Ssthen    untie(%h);
220*898184e3Ssthen    unlink "SubDB.pm", <dbhash_tmp*>;
221*898184e3Ssthen
222*898184e3Ssthen}
223*898184e3Ssthen
224*898184e3Ssthenuntie %h;
225*898184e3Ssthenunlink <Op_dbmx*>, $Dfile;
226*898184e3Ssthen
227*898184e3Ssthen{
228*898184e3Ssthen   # DBM Filter tests
229*898184e3Ssthen   my (%h, $db);
230*898184e3Ssthen   my ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
231*898184e3Ssthen
232*898184e3Ssthen   sub checkOutput
233*898184e3Ssthen   {
234*898184e3Ssthen       my($fk, $sk, $fv, $sv) = @_;
235*898184e3Ssthen       local $Test::Builder::Level = $Test::Builder::Level + 1;
236*898184e3Ssthen       is($fetch_key, $fk);
237*898184e3Ssthen       is($store_key, $sk);
238*898184e3Ssthen       is($fetch_value, $fv);
239*898184e3Ssthen       is($store_value, $sv);
240*898184e3Ssthen       is($_, 'original');
241*898184e3Ssthen   }
242*898184e3Ssthen
243*898184e3Ssthen   unlink <Op_dbmx*>;
244*898184e3Ssthen   $db = tie %h, $DBM_Class, 'Op_dbmx', $create, 0640;
245*898184e3Ssthen   isa_ok($db, $DBM_Class);
246*898184e3Ssthen
247*898184e3Ssthen   $db->filter_fetch_key   (sub { $fetch_key = $_ });
248*898184e3Ssthen   $db->filter_store_key   (sub { $store_key = $_ });
249*898184e3Ssthen   $db->filter_fetch_value (sub { $fetch_value = $_});
250*898184e3Ssthen   $db->filter_store_value (sub { $store_value = $_ });
251*898184e3Ssthen
252*898184e3Ssthen   $_ = "original";
253*898184e3Ssthen
254*898184e3Ssthen   $h{"fred"} = "joe";
255*898184e3Ssthen   #                   fk   sk     fv   sv
256*898184e3Ssthen   checkOutput("", "fred", "", "joe");
257*898184e3Ssthen
258*898184e3Ssthen   ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
259*898184e3Ssthen   is($h{"fred"}, "joe");
260*898184e3Ssthen   #                   fk    sk     fv    sv
261*898184e3Ssthen   checkOutput("", "fred", "joe", "");
262*898184e3Ssthen
263*898184e3Ssthen   ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
264*898184e3Ssthen   is($db->FIRSTKEY(), "fred");
265*898184e3Ssthen   #                    fk     sk  fv  sv
266*898184e3Ssthen   checkOutput("fred", "", "", "");
267*898184e3Ssthen
268*898184e3Ssthen   # replace the filters, but remember the previous set
269*898184e3Ssthen   my ($old_fk) = $db->filter_fetch_key
270*898184e3Ssthen   			(sub { $_ = uc $_; $fetch_key = $_ });
271*898184e3Ssthen   my ($old_sk) = $db->filter_store_key
272*898184e3Ssthen   			(sub { $_ = lc $_; $store_key = $_ });
273*898184e3Ssthen   my ($old_fv) = $db->filter_fetch_value
274*898184e3Ssthen   			(sub { $_ = "[$_]"; $fetch_value = $_ });
275*898184e3Ssthen   my ($old_sv) = $db->filter_store_value
276*898184e3Ssthen   			(sub { s/o/x/g; $store_value = $_ });
277*898184e3Ssthen
278*898184e3Ssthen   ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
279*898184e3Ssthen   $h{"Fred"} = "Joe";
280*898184e3Ssthen   #                   fk   sk     fv    sv
281*898184e3Ssthen   checkOutput("", "fred", "", "Jxe");
282*898184e3Ssthen
283*898184e3Ssthen   ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
284*898184e3Ssthen   is($h{"Fred"}, "[Jxe]");
285*898184e3Ssthen   #                   fk   sk     fv    sv
286*898184e3Ssthen   checkOutput("", "fred", "[Jxe]", "");
287*898184e3Ssthen
288*898184e3Ssthen   ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
289*898184e3Ssthen   is($db->FIRSTKEY(), "FRED");
290*898184e3Ssthen   #                   fk   sk     fv    sv
291*898184e3Ssthen   checkOutput("FRED", "", "", "");
292*898184e3Ssthen
293*898184e3Ssthen   # put the original filters back
294*898184e3Ssthen   $db->filter_fetch_key   ($old_fk);
295*898184e3Ssthen   $db->filter_store_key   ($old_sk);
296*898184e3Ssthen   $db->filter_fetch_value ($old_fv);
297*898184e3Ssthen   $db->filter_store_value ($old_sv);
298*898184e3Ssthen
299*898184e3Ssthen   ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
300*898184e3Ssthen   $h{"fred"} = "joe";
301*898184e3Ssthen   checkOutput("", "fred", "", "joe");
302*898184e3Ssthen
303*898184e3Ssthen   ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
304*898184e3Ssthen   is($h{"fred"}, "joe");
305*898184e3Ssthen   checkOutput("", "fred", "joe", "");
306*898184e3Ssthen
307*898184e3Ssthen   ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
308*898184e3Ssthen   is($db->FIRSTKEY(), "fred");
309*898184e3Ssthen   checkOutput("fred", "", "", "");
310*898184e3Ssthen
311*898184e3Ssthen   # delete the filters
312*898184e3Ssthen   $db->filter_fetch_key   (undef);
313*898184e3Ssthen   $db->filter_store_key   (undef);
314*898184e3Ssthen   $db->filter_fetch_value (undef);
315*898184e3Ssthen   $db->filter_store_value (undef);
316*898184e3Ssthen
317*898184e3Ssthen   ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
318*898184e3Ssthen   $h{"fred"} = "joe";
319*898184e3Ssthen   checkOutput("", "", "", "");
320*898184e3Ssthen
321*898184e3Ssthen   ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
322*898184e3Ssthen   is($h{"fred"}, "joe");
323*898184e3Ssthen   checkOutput("", "", "", "");
324*898184e3Ssthen
325*898184e3Ssthen   ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4;
326*898184e3Ssthen   is($db->FIRSTKEY(), "fred");
327*898184e3Ssthen   checkOutput("", "", "", "");
328*898184e3Ssthen
329*898184e3Ssthen   undef $db;
330*898184e3Ssthen   untie %h;
331*898184e3Ssthen   unlink <Op_dbmx*>;
332*898184e3Ssthen}
333*898184e3Ssthen
334*898184e3Ssthen{
335*898184e3Ssthen    # DBM Filter with a closure
336*898184e3Ssthen
337*898184e3Ssthen    my (%h, $db);
338*898184e3Ssthen
339*898184e3Ssthen    unlink <Op_dbmx*>;
340*898184e3Ssthen    $db = tie %h, $DBM_Class, 'Op_dbmx', $create, 0640;
341*898184e3Ssthen    isa_ok($db, $DBM_Class);
342*898184e3Ssthen
343*898184e3Ssthen    my %result = ();
344*898184e3Ssthen
345*898184e3Ssthen    sub Closure
346*898184e3Ssthen    {
347*898184e3Ssthen        my ($name) = @_;
348*898184e3Ssthen	my $count = 0;
349*898184e3Ssthen	my @kept = ();
350*898184e3Ssthen
351*898184e3Ssthen	return sub { ++$count;
352*898184e3Ssthen		     push @kept, $_;
353*898184e3Ssthen		     $result{$name} = "$name - $count: [@kept]";
354*898184e3Ssthen		   }
355*898184e3Ssthen    }
356*898184e3Ssthen
357*898184e3Ssthen    $db->filter_store_key(Closure("store key"));
358*898184e3Ssthen    $db->filter_store_value(Closure("store value"));
359*898184e3Ssthen    $db->filter_fetch_key(Closure("fetch key"));
360*898184e3Ssthen    $db->filter_fetch_value(Closure("fetch value"));
361*898184e3Ssthen
362*898184e3Ssthen    $_ = "original";
363*898184e3Ssthen
364*898184e3Ssthen    $h{"fred"} = "joe";
365*898184e3Ssthen    is($result{"store key"}, "store key - 1: [fred]");
366*898184e3Ssthen    is($result{"store value"}, "store value - 1: [joe]");
367*898184e3Ssthen    is($result{"fetch key"}, undef);
368*898184e3Ssthen    is($result{"fetch value"}, undef);
369*898184e3Ssthen    is($_, "original");
370*898184e3Ssthen
371*898184e3Ssthen    is($db->FIRSTKEY(), "fred");
372*898184e3Ssthen    is($result{"store key"}, "store key - 1: [fred]");
373*898184e3Ssthen    is($result{"store value"}, "store value - 1: [joe]");
374*898184e3Ssthen    is($result{"fetch key"}, "fetch key - 1: [fred]");
375*898184e3Ssthen    is($result{"fetch value"}, undef);
376*898184e3Ssthen    is($_, "original");
377*898184e3Ssthen
378*898184e3Ssthen    $h{"jim"}  = "john";
379*898184e3Ssthen    is($result{"store key"}, "store key - 2: [fred jim]");
380*898184e3Ssthen    is($result{"store value"}, "store value - 2: [joe john]");
381*898184e3Ssthen    is($result{"fetch key"}, "fetch key - 1: [fred]");
382*898184e3Ssthen    is($result{"fetch value"}, undef);
383*898184e3Ssthen    is($_, "original");
384*898184e3Ssthen
385*898184e3Ssthen    is($h{"fred"}, "joe");
386*898184e3Ssthen    is($result{"store key"}, "store key - 3: [fred jim fred]");
387*898184e3Ssthen    is($result{"store value"}, "store value - 2: [joe john]");
388*898184e3Ssthen    is($result{"fetch key"}, "fetch key - 1: [fred]");
389*898184e3Ssthen    is($result{"fetch value"}, "fetch value - 1: [joe]");
390*898184e3Ssthen    is($_, "original");
391*898184e3Ssthen
392*898184e3Ssthen    undef $db;
393*898184e3Ssthen    untie %h;
394*898184e3Ssthen    unlink <Op_dbmx*>;
395*898184e3Ssthen}
396*898184e3Ssthen
397*898184e3Ssthen{
398*898184e3Ssthen   # DBM Filter recursion detection
399*898184e3Ssthen   my (%h, $db);
400*898184e3Ssthen   unlink <Op_dbmx*>;
401*898184e3Ssthen
402*898184e3Ssthen   $db = tie %h, $DBM_Class, 'Op_dbmx', $create, 0640;
403*898184e3Ssthen   isa_ok($db, $DBM_Class);
404*898184e3Ssthen
405*898184e3Ssthen   $db->filter_store_key (sub { $_ = $h{$_} });
406*898184e3Ssthen
407*898184e3Ssthen   eval '$h{1} = 1234';
408*898184e3Ssthen   like($@, qr/^recursion detected in filter_store_key at/);
409*898184e3Ssthen
410*898184e3Ssthen   undef $db;
411*898184e3Ssthen   untie %h;
412*898184e3Ssthen   unlink <Op_dbmx*>;
413*898184e3Ssthen}
414*898184e3Ssthen
415*898184e3Ssthen{
416*898184e3Ssthen    # Bug ID 20001013.009
417*898184e3Ssthen    #
418*898184e3Ssthen    # test that $hash{KEY} = undef doesn't produce the warning
419*898184e3Ssthen    #     Use of uninitialized value in null operation
420*898184e3Ssthen
421*898184e3Ssthen    unlink <Op_dbmx*>;
422*898184e3Ssthen    my %h;
423*898184e3Ssthen    my $a = "";
424*898184e3Ssthen    local $SIG{__WARN__} = sub {$a = $_[0]};
425*898184e3Ssthen
426*898184e3Ssthen    isa_ok(tie(%h, $DBM_Class, 'Op_dbmx', $create, 0640), $DBM_Class);
427*898184e3Ssthen    $h{ABC} = undef;
428*898184e3Ssthen    is($a, "");
429*898184e3Ssthen    untie %h;
430*898184e3Ssthen    unlink <Op_dbmx*>;
431*898184e3Ssthen}
432*898184e3Ssthen
433*898184e3Ssthen{
434*898184e3Ssthen    # When iterating over a tied hash using "each", the key passed to FETCH
435*898184e3Ssthen    # will be recycled and passed to NEXTKEY. If a Source Filter modifies the
436*898184e3Ssthen    # key in FETCH via a filter_fetch_key method we need to check that the
437*898184e3Ssthen    # modified key doesn't get passed to NEXTKEY.
438*898184e3Ssthen    # Also Test "keys" & "values" while we are at it.
439*898184e3Ssthen
440*898184e3Ssthen    unlink <Op_dbmx*>;
441*898184e3Ssthen    my $bad_key = 0;
442*898184e3Ssthen    my %h = ();
443*898184e3Ssthen    my $db = tie %h, $DBM_Class, 'Op_dbmx', $create, 0640;
444*898184e3Ssthen    isa_ok($db, $DBM_Class);
445*898184e3Ssthen    $db->filter_fetch_key (sub { $_ =~ s/^Beta_/Alpha_/ if defined $_});
446*898184e3Ssthen    $db->filter_store_key (sub { $bad_key = 1 if /^Beta_/; $_ =~ s/^Alpha_/Beta_/});
447*898184e3Ssthen
448*898184e3Ssthen    $h{'Alpha_ABC'} = 2;
449*898184e3Ssthen    $h{'Alpha_DEF'} = 5;
450*898184e3Ssthen
451*898184e3Ssthen    is($h{'Alpha_ABC'}, 2);
452*898184e3Ssthen    is($h{'Alpha_DEF'}, 5);
453*898184e3Ssthen
454*898184e3Ssthen    my ($k, $v) = ("", "");
455*898184e3Ssthen    while (($k, $v) = each %h) {}
456*898184e3Ssthen    is($bad_key, 0);
457*898184e3Ssthen
458*898184e3Ssthen    $bad_key = 0;
459*898184e3Ssthen    foreach $k (keys %h) {}
460*898184e3Ssthen    is($bad_key, 0);
461*898184e3Ssthen
462*898184e3Ssthen    $bad_key = 0;
463*898184e3Ssthen    foreach $v (values %h) {}
464*898184e3Ssthen    is($bad_key, 0);
465*898184e3Ssthen
466*898184e3Ssthen    undef $db;
467*898184e3Ssthen    untie %h;
468*898184e3Ssthen    unlink <Op_dbmx*>;
469*898184e3Ssthen}
470*898184e3Ssthen
471*898184e3Ssthen{
472*898184e3Ssthen   # Check that DBM Filter can cope with read-only $_
473*898184e3Ssthen
474*898184e3Ssthen   my %h;
475*898184e3Ssthen   unlink <Op1_dbmx*>;
476*898184e3Ssthen
477*898184e3Ssthen   my $db = tie %h, $DBM_Class, 'Op1_dbmx', $create, 0640;
478*898184e3Ssthen   isa_ok($db, $DBM_Class);
479*898184e3Ssthen
480*898184e3Ssthen   $db->filter_fetch_key   (sub { });
481*898184e3Ssthen   $db->filter_store_key   (sub { });
482*898184e3Ssthen   $db->filter_fetch_value (sub { });
483*898184e3Ssthen   $db->filter_store_value (sub { });
484*898184e3Ssthen
485*898184e3Ssthen   $_ = "original";
486*898184e3Ssthen
487*898184e3Ssthen   $h{"fred"} = "joe";
488*898184e3Ssthen   is($h{"fred"}, "joe");
489*898184e3Ssthen
490*898184e3Ssthen   is_deeply([eval { map { $h{$_} } (1, 2, 3) }], [undef, undef, undef]);
491*898184e3Ssthen   is($@, '');
492*898184e3Ssthen
493*898184e3Ssthen
494*898184e3Ssthen   # delete the filters
495*898184e3Ssthen   $db->filter_fetch_key   (undef);
496*898184e3Ssthen   $db->filter_store_key   (undef);
497*898184e3Ssthen   $db->filter_fetch_value (undef);
498*898184e3Ssthen   $db->filter_store_value (undef);
499*898184e3Ssthen
500*898184e3Ssthen   $h{"fred"} = "joe";
501*898184e3Ssthen
502*898184e3Ssthen   is($h{"fred"}, "joe");
503*898184e3Ssthen
504*898184e3Ssthen   is($db->FIRSTKEY(), "fred");
505*898184e3Ssthen
506*898184e3Ssthen   is_deeply([eval { map { $h{$_} } (1, 2, 3) }], [undef, undef, undef]);
507*898184e3Ssthen   is($@, '');
508*898184e3Ssthen
509*898184e3Ssthen   undef $db;
510*898184e3Ssthen   untie %h;
511*898184e3Ssthen   unlink <Op1_dbmx*>;
512*898184e3Ssthen}
513*898184e3Ssthen
514*898184e3Ssthendone_testing();
515*898184e3Ssthen1;
516