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