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