1#!/usr/bin/perl 2 3use strict; 4use warnings; 5 6# 7# Unit tests for abstract cache implementation 8# 9# Test the following methods: 10# * new() 11# * is_empty() 12# * empty() 13# * lookup(key) 14# * remove(key) 15# * insert(key,val) 16# * update(key,val) 17# * rekey(okeys,nkeys) 18# * expire() 19# * keys() 20# * bytes() 21# DESTROY() 22# 23# 20020327 You somehow managed to miss: 24# * reduce_size_to(bytes) 25# 26 27# print "1..0\n"; exit; 28print "1..42\n"; 29 30my ($N, @R, $Q, $ar) = (1); 31 32use Tie::File; 33print "ok $N\n"; 34$N++; 35 36my $h = Tie::File::Cache->new(10000) or die; 37print "ok $N\n"; 38$N++; 39 40# (3) Are all the methods there? 41{ 42 my $good = 1; 43 for my $meth (qw(new is_empty empty lookup remove 44 insert update rekey expire ckeys bytes 45 set_limit adj_limit flush reduce_size_to 46 _produce _produce_lru )) { 47 unless ($h->can($meth)) { 48 print STDERR "# Method '$meth' is missing.\n"; 49 $good = 0; 50 } 51 } 52 print $good ? "ok $N\n" : "not ok $N\n"; 53 $N++; 54} 55 56# (4-5) Straight insert and removal FIFO test 57$ar = 'a0'; 58for (1..10) { 59 $h->insert($_, $ar++); 60} 611; 62for (1..10) { 63 push @R, $h->expire; 64} 65my $iota = iota('a',9); 66print "@R" eq $iota 67 ? "ok $N\n" : "not ok $N \# expected ($iota), got (@R)\n"; 68$N++; 69check($h); 70 71# (6-7) Remove from empty heap 72my $n = $h->expire; 73print ! defined $n ? "ok $N\n" : "not ok $N \# expected UNDEF, got $n"; 74$N++; 75check($h); 76 77# (8-9) Interleaved insert and removal 78$Q = 0; 79@R = (); 80for my $i (1..4) { 81 for my $j (1..$i) { 82 $h->insert($Q, "b$Q"); 83 $Q++; 84 } 85 for my $j (1..$i) { 86 push @R, $h->expire; 87 } 88} 89$iota = iota('b', 9); 90print "@R" eq $iota ? "ok $N\n" : "not ok $N \# expected ($iota), got (@R)\n"; 91$N++; 92check($h); 93 94# (10) It should be empty now 95print $h->is_empty ? "ok $N\n" : "not ok $N\n"; 96$N++; 97 98# (11-12) Insert and delete 99$Q = 1; 100for (1..10) { 101 $h->insert($_, "c$Q"); 102 $Q++; 103} 104for (2, 4, 6, 8, 10) { 105 $h->remove($_); 106} 107@R = (); 108push @R, $n while defined ($n = $h->expire); 109print "@R" eq "c1 c3 c5 c7 c9" ? 110 "ok $N\n" : "not ok $N \# expected (c1 c3 c5 c7 c9), got (@R)\n"; 111$N++; 112check($h); 113 114# (13-14) Interleaved insert and delete 115$Q = 1; my $QQ = 1; 116@R = (); 117for my $i (1..4) { 118 for my $j (1..$i) { 119 $h->insert($Q, "d$Q"); 120 $Q++; 121 } 122 for my $j (1..$i) { 123 $h->remove($QQ) if $QQ % 2 == 0; 124 $QQ++; 125 } 126} 127push @R, $n while defined ($n = $h->expire); 128print "@R" eq "d1 d3 d5 d7 d9" ? 129 "ok $N\n" : "not ok $N \# expected (d1 d3 d5 d7 d9), got (@R)\n"; 130$N++; 131check($h); 132 133# (15-16) Promote 134$h->empty; 135$Q = 1; 136for (1..10) { 137 $h->insert($_, "e$Q"); 138 unless ($h->_check_integrity) { 139 die "Integrity failed after inserting ($_, e$Q)\n"; 140 } 141 $Q++; 142} 1431; 144for (2, 4, 6, 8, 10) { 145 $h->_promote($_); 146} 147@R = (); 148push @R, $n while defined ($n = $h->expire); 149print "@R" eq "e1 e3 e5 e7 e9 e2 e4 e6 e8 e10" ? 150 "ok $N\n" : 151 "not ok $N \# expected (e1 e3 e5 e7 e9 e2 e4 e6 e8 e10), got (@R)\n"; 152$N++; 153check($h); 154 155# (17-22) Lookup 156$Q = 1; 157for (1..10) { 158 $h->insert($_, "f$Q"); 159 $Q++; 160} 1611; 162for (2, 4, 6, 4, 8) { 163 my $r = $h->lookup($_); 164 print $r eq "f$_" ? "ok $N\n" : "not ok $N \# expected f$_, got $r\n"; 165 $N++; 166} 167check($h); 168 169# (23) It shouldn't be empty 170print ! $h->is_empty ? "ok $N\n" : "not ok $N\n"; 171$N++; 172 173# (24-25) Lookup should have promoted the looked-up records 174@R = (); 175push @R, $n while defined ($n = $h->expire); 176print "@R" eq "f1 f3 f5 f7 f9 f10 f2 f6 f4 f8" ? 177 "ok $N\n" : 178 "not ok $N \# expected (f1 f3 f5 f7 f9 f10 f2 f6 f4 f8), got (@R)\n"; 179$N++; 180check($h); 181 182# (26-29) Typical 'rekey' operation 183$Q = 1; 184for (1..10) { 185 $h->insert($_, "g$Q"); 186 $Q++; 187} 188$h->rekey([6,7,8,9,10], [8,9,10,11,12]); 189my %x = qw(1 g1 2 g2 3 g3 4 g4 5 g5 190 8 g6 9 g7 10 g8 11 g9 12 g10); 191{ 192 my $good = 1; 193 for my $k (keys %x) { 194 my $v = $h->lookup($k); 195 $v = "UNDEF" unless defined $v; 196 unless ($v eq $x{$k}) { 197 print "# looked up $k, got $v, expected $x{$k}\n"; 198 $good = 0; 199 } 200 } 201 print $good ? "ok $N\n" : "not ok $N\n"; 202 $N++; 203} 204check($h); 205{ 206 my $good = 1; 207 for my $k (6, 7) { 208 my $v = $h->lookup($k); 209 if (defined $v) { 210 print "# looked up $k, got $v, should have been undef\n"; 211 $good = 0; 212 } 213 } 214 print $good ? "ok $N\n" : "not ok $N\n"; 215 $N++; 216} 217check($h); 218 219# (30-31) ckeys 220@R = sort { $a <=> $b } $h->ckeys; 221print "@R" eq "1 2 3 4 5 8 9 10 11 12" ? 222 "ok $N\n" : 223 "not ok $N \# expected (1 2 3 4 5 8 9 10 11 12) got (@R)\n"; 224$N++; 225check($h); 2261; 227# (32-33) update 228for (1..5, 8..12) { 229 $h->update($_, "h$_"); 230} 231@R = (); 232for (sort { $a <=> $b } $h->ckeys) { 233 push @R, $h->lookup($_); 234} 235print "@R" eq "h1 h2 h3 h4 h5 h8 h9 h10 h11 h12" ? 236 "ok $N\n" : 237 "not ok $N \# expected (h1 h2 h3 h4 h5 h8 h9 h10 h11 h12) got (@R)\n"; 238$N++; 239check($h); 240 241# (34-37) bytes 242my $B; 243$B = $h->bytes; 244print $B == 23 ? "ok $N\n" : "not ok $N \# expected 23, got $B\n"; 245$N++; 246check($h); 247$h->update('12', "yobgorgle"); 248$B = $h->bytes; 249print $B == 29 ? "ok $N\n" : "not ok $N \# expected 29, got $B\n"; 250$N++; 251check($h); 252 253# (38-41) empty 254$h->empty; 255print $h->is_empty ? "ok $N\n" : "not ok $N\n"; 256$N++; 257check($h); 258$n = $h->expire; 259print ! defined $n ? "ok $N\n" : "not ok $N \# expected UNDEF, got $n"; 260$N++; 261check($h); 262 263# (42) very weak testing of DESTROY 264undef $h; 265# are we still alive? 266print "ok $N\n"; 267$N++; 268 269sub check { 270 my $h = shift; 271 print $h->_check_integrity ? "ok $N\n" : "not ok $N\n"; 272 $N++; 273} 274 275sub iota { 276 my ($p, $n) = @_; 277 my $r; 278 my $i = 0; 279 while ($i <= $n) { 280 $r .= "$p$i "; 281 $i++; 282 } 283 chop $r; 284 $r; 285} 286