1#!./perl 2 3BEGIN { 4 chdir 't' if -d 't'; 5 require './test.pl'; 6 set_up_inc('../lib'); 7} 8 9plan(tests => 75); 10 11my %seen; 12 13package Implement; 14 15sub TIEARRAY { 16 $seen{'TIEARRAY'}++; 17 my ($class,@val) = @_; 18 return bless \@val,$class; 19} 20 21sub STORESIZE { 22 $seen{'STORESIZE'}++; 23 my ($ob,$sz) = @_; 24 return $#{$ob} = $sz-1; 25} 26 27sub EXTEND { 28 $seen{'EXTEND'}++; 29 my ($ob,$sz) = @_; 30 return @$ob = $sz; 31} 32 33sub FETCHSIZE { 34 $seen{'FETCHSIZE'}++; 35 return scalar(@{$_[0]}); 36} 37 38sub FETCH { 39 $seen{'FETCH'}++; 40 my ($ob,$id) = @_; 41 return $ob->[$id]; 42} 43 44sub STORE { 45 $seen{'STORE'}++; 46 my ($ob,$id,$val) = @_; 47 $ob->[$id] = $val; 48} 49 50sub UNSHIFT { 51 $seen{'UNSHIFT'}++; 52 my $ob = shift; 53 unshift(@$ob,@_); 54} 55 56sub PUSH { 57 $seen{'PUSH'}++; 58 my $ob = shift;; 59 push(@$ob,@_); 60} 61 62sub CLEAR { 63 $seen{'CLEAR'}++; 64 @{$_[0]} = (); 65} 66 67sub DESTROY { 68 $seen{'DESTROY'}++; 69} 70 71sub POP { 72 $seen{'POP'}++; 73 my ($ob) = @_; 74 return pop(@$ob); 75} 76 77sub SHIFT { 78 $seen{'SHIFT'}++; 79 my ($ob) = @_; 80 return shift(@$ob); 81} 82 83sub SPLICE { 84 $seen{'SPLICE'}++; 85 my $ob = shift; 86 my $off = @_ ? shift : 0; 87 my $len = @_ ? shift : @$ob-1; 88 return splice(@$ob,$off,$len,@_); 89} 90 91package NegIndex; # 20020220 MJD 92@ISA = 'Implement'; 93 94# simulate indices -2 .. 2 95my $offset = 2; 96$NegIndex::NEGATIVE_INDICES = 1; 97 98sub FETCH { 99 my ($ob,$id) = @_; 100 #print "# FETCH @_\n"; 101 $id += $offset; 102 $ob->[$id]; 103} 104 105sub STORE { 106 my ($ob,$id,$value) = @_; 107 #print "# STORE @_\n"; 108 $id += $offset; 109 $ob->[$id] = $value; 110} 111 112sub DELETE { 113 my ($ob,$id) = @_; 114 #print "# DELETE @_\n"; 115 $id += $offset; 116 delete $ob->[$id]; 117} 118 119sub EXISTS { 120 my ($ob,$id) = @_; 121 #print "# EXISTS @_\n"; 122 $id += $offset; 123 exists $ob->[$id]; 124} 125 126# 127# Returning -1 from FETCHSIZE used to get casted to U32 causing a 128# segfault 129# 130 131package NegFetchsize; 132 133sub TIEARRAY { bless [] } 134sub FETCH { } 135sub FETCHSIZE { -1 } 136 137 138package main; 139 140{ 141 $seen{'DESTROY'} = 0; 142 my @ary; 143 144 { 145 my $ob = tie @ary,'Implement',3,2,1; 146 ok($ob); 147 is(tied(@ary), $ob); 148 } 149 150 is(@ary, 3); 151 is($#ary, 2); 152 is(join(':',@ary), '3:2:1'); 153 cmp_ok($seen{'FETCH'}, '>=', 3); 154 155 @ary = (1,2,3); 156 157 cmp_ok($seen{'STORE'}, '>=', 3); 158 is(join(':',@ary), '1:2:3'); 159 160 { 161 my @thing = @ary; 162 is(join(':',@thing), '1:2:3'); 163 164 tie @thing,'Implement'; 165 @thing = @ary; 166 is(join(':',@thing), '1:2:3'); 167 } 168 is($seen{'DESTROY'}, 1, "thing freed"); 169 170 is(pop(@ary), 3); 171 is($seen{'POP'}, 1); 172 is(join(':',@ary), '1:2'); 173 174 is(push(@ary,4), 3); 175 is($seen{'PUSH'}, 1); 176 is(join(':',@ary), '1:2:4'); 177 178 my @x = splice(@ary,1,1,7); 179 180 is($seen{'SPLICE'}, 1); 181 is(@x, 1); 182 is($x[0], 2); 183 is(join(':',@ary), '1:7:4'); 184 185 is(shift(@ary), 1); 186 is($seen{'SHIFT'}, 1); 187 is(join(':',@ary), '7:4'); 188 189 my $n = unshift(@ary,5,6); 190 is($seen{'UNSHIFT'}, 1); 191 is($n, 4); 192 is(join(':',@ary), '5:6:7:4'); 193 194 @ary = split(/:/,'1:2:3'); 195 is(join(':',@ary), '1:2:3'); 196 197 my $t = 0; 198 foreach $n (@ary) { 199 is($n, ++$t); 200 } 201 202 # (30-33) 20020303 mjd-perl-patch+@plover.com 203 @ary = (); 204 $seen{POP} = 0; 205 pop @ary; # this didn't used to call POP at all 206 is($seen{POP}, 1); 207 $seen{SHIFT} = 0; 208 shift @ary; # this didn't used to call SHIFT at all 209 is($seen{SHIFT}, 1); 210 $seen{PUSH} = 0; 211 my $got = push @ary; # this didn't used to call PUSH at all 212 is($got, 0); 213 is($seen{PUSH}, 1); 214 $seen{UNSHIFT} = 0; 215 $got = unshift @ary; # this didn't used to call UNSHIFT at all 216 is($got, 0); 217 is($seen{UNSHIFT}, 1); 218 219 @ary = qw(3 2 1); 220 is(join(':',@ary), '3:2:1'); 221 222 $#ary = 1; 223 is($seen{'STORESIZE'}, 1, 'seen STORESIZE'); 224 is(join(':',@ary), '3:2'); 225 226 sub arysize :lvalue { $#ary } 227 arysize()--; 228 is($seen{'STORESIZE'}, 2, 'seen STORESIZE'); 229 is(join(':',@ary), '3'); 230 231 untie @ary; 232} 233is($seen{'DESTROY'}, 2, "ary freed"); 234 235# 20020401 mjd-perl-patch+@plover.com 236# Thanks to Dave Mitchell for the small test case and the fix 237{ 238 my @a; 239 240 sub X::TIEARRAY { bless {}, 'X' } 241 242 sub X::SPLICE { 243 do '/dev/null'; 244 die; 245 } 246 247 tie @a, 'X'; 248 eval { splice(@a) }; 249 # If we survived this far. 250 pass(); 251} 252 253# 20020220 mjd-perl-patch+@plover.com 254{ 255 $seen{'DESTROY'} = 0; 256 257 my @n; 258 tie @n => 'NegIndex', ('A' .. 'E'); 259 260 # FETCH 261 is($n[0], 'C'); 262 is($n[1], 'D'); 263 is($n[2], 'E'); 264 is($n[-1], 'B'); 265 is($n[-2], 'A'); 266 267 # STORE 268 $n[-2] = 'a'; 269 is($n[-2], 'a'); 270 $n[-1] = 'b'; 271 is($n[-1], 'b'); 272 $n[0] = 'c'; 273 is($n[0], 'c'); 274 $n[1] = 'd'; 275 is($n[1], 'd'); 276 $n[2] = 'e'; 277 is($n[2], 'e'); 278 279 # DELETE and EXISTS 280 for (-2 .. 2) { 281 ok($n[$_]); 282 delete $n[$_]; 283 is(defined($n[$_]), ''); 284 is(exists($n[$_]), ''); 285 } 286} 287is($seen{'DESTROY'}, 1, "n freed"); 288 289{ 290 tie my @dummy, "NegFetchsize"; 291 eval { "@dummy"; }; 292 like($@, qr/^FETCHSIZE returned a negative value/, 293 " - croak on negative FETCHSIZE"); 294} 295 296{ 297 # check that a tied element assigned to an array doesn't remain tied 298 299 package Magical; 300 301 my $i = 10; 302 303 sub TIEARRAY { bless [1] } 304 sub TIEHASH { bless [1] } 305 sub FETCHSIZE { 1; } 306 sub FETCH { $i++ } 307 sub STORE { $_[0][0] = $_[1]; } 308 sub FIRSTKEY { 0 } 309 sub NEXTKEY { } 310 311 package main; 312 313 my (@a, @b); 314 tie @a, 'Magical'; 315 @b = @a; 316 is ($b[0], 10, "Magical array fetch 1"); 317 $b[0] = 100; 318 is ($b[0], 100, "Magical array fetch 2"); 319 320 my (%a, %b); 321 tie %a, 'Magical'; 322 %b = %a; 323 is ($b{0}, 11, "Magical hash fetch 1"); 324 $b{0} = 100; 325 is ($b{0}, 100, "Magical hash fetch 2"); 326} 327