1#!perl -w 2 3BEGIN { 4 chdir 't' if -d 't'; 5 @INC = '../lib'; 6 push @INC, "::lib:$MacPerl::Architecture:" if $^O eq 'MacOS'; 7 require Config; import Config; 8 if ($Config{'extensions'} !~ /\bXS\/APItest\b/) { 9 # Look, I'm using this fully-qualified variable more than once! 10 my $arch = $MacPerl::Architecture; 11 print "1..0 # Skip: XS::APItest was not built\n"; 12 exit 0; 13 } 14} 15 16use strict; 17use utf8; 18use Tie::Hash; 19use Test::More 'no_plan'; 20 21use_ok('XS::APItest'); 22 23sub preform_test; 24sub test_present; 25sub test_absent; 26sub test_delete_present; 27sub test_delete_absent; 28sub brute_force_exists; 29sub test_store; 30sub test_fetch_present; 31sub test_fetch_absent; 32 33my $utf8_for_258 = chr 258; 34utf8::encode $utf8_for_258; 35 36my @testkeys = ('N', chr 198, chr 256); 37my @keys = (@testkeys, $utf8_for_258); 38 39foreach (@keys) { 40 utf8::downgrade $_, 1; 41} 42main_tests (\@keys, \@testkeys, ''); 43 44foreach (@keys) { 45 utf8::upgrade $_; 46} 47main_tests (\@keys, \@testkeys, ' [utf8 hash]'); 48 49{ 50 my %h = (a=>'cheat'); 51 tie %h, 'Tie::StdHash'; 52 is (XS::APItest::Hash::store(\%h, chr 258, 1), 1); 53 54 ok (!exists $h{$utf8_for_258}, 55 "hv_store doesn't insert a key with the raw utf8 on a tied hash"); 56} 57 58exit; 59 60################################ The End ################################ 61 62sub main_tests { 63 my ($keys, $testkeys, $description) = @_; 64 foreach my $key (@$testkeys) { 65 my $lckey = ($key eq chr 198) ? chr 230 : lc $key; 66 my $unikey = $key; 67 utf8::encode $unikey; 68 69 utf8::downgrade $key, 1; 70 utf8::downgrade $lckey, 1; 71 utf8::downgrade $unikey, 1; 72 main_test_inner ($key, $lckey, $unikey, $keys, $description); 73 74 utf8::upgrade $key; 75 utf8::upgrade $lckey; 76 utf8::upgrade $unikey; 77 main_test_inner ($key, $lckey, $unikey, $keys, 78 $description . ' [key utf8 on]'); 79 } 80 81 # hv_exists was buggy for tied hashes, in that the raw utf8 key was being 82 # used - the utf8 flag was being lost. 83 perform_test (\&test_absent, (chr 258), $keys, ''); 84 85 perform_test (\&test_fetch_absent, (chr 258), $keys, ''); 86 perform_test (\&test_delete_absent, (chr 258), $keys, ''); 87} 88 89sub main_test_inner { 90 my ($key, $lckey, $unikey, $keys, $description) = @_; 91 perform_test (\&test_present, $key, $keys, $description); 92 perform_test (\&test_fetch_present, $key, $keys, $description); 93 perform_test (\&test_delete_present, $key, $keys, $description); 94 95 perform_test (\&test_store, $key, $keys, $description, [a=>'cheat']); 96 perform_test (\&test_store, $key, $keys, $description, []); 97 98 perform_test (\&test_absent, $lckey, $keys, $description); 99 perform_test (\&test_fetch_absent, $lckey, $keys, $description); 100 perform_test (\&test_delete_absent, $lckey, $keys, $description); 101 102 return if $unikey eq $key; 103 104 perform_test (\&test_absent, $unikey, $keys, $description); 105 perform_test (\&test_fetch_absent, $unikey, $keys, $description); 106 perform_test (\&test_delete_absent, $unikey, $keys, $description); 107} 108 109sub perform_test { 110 my ($test_sub, $key, $keys, $message, @other) = @_; 111 my $printable = join ',', map {ord} split //, $key; 112 113 my (%hash, %tiehash); 114 tie %tiehash, 'Tie::StdHash'; 115 116 @hash{@$keys} = @$keys; 117 @tiehash{@$keys} = @$keys; 118 119 &$test_sub (\%hash, $key, $printable, $message, @other); 120 &$test_sub (\%tiehash, $key, $printable, "$message tie", @other); 121} 122 123sub test_present { 124 my ($hash, $key, $printable, $message) = @_; 125 126 ok (exists $hash->{$key}, "hv_exists_ent present$message $printable"); 127 ok (XS::APItest::Hash::exists ($hash, $key), 128 "hv_exists present$message $printable"); 129} 130 131sub test_absent { 132 my ($hash, $key, $printable, $message) = @_; 133 134 ok (!exists $hash->{$key}, "hv_exists_ent absent$message $printable"); 135 ok (!XS::APItest::Hash::exists ($hash, $key), 136 "hv_exists absent$message $printable"); 137} 138 139sub test_delete_present { 140 my ($hash, $key, $printable, $message) = @_; 141 142 my $copy = {}; 143 my $class = tied %$hash; 144 if (defined $class) { 145 tie %$copy, ref $class; 146 } 147 $copy = {%$hash}; 148 ok (brute_force_exists ($copy, $key), 149 "hv_delete_ent present$message $printable"); 150 is (delete $copy->{$key}, $key, "hv_delete_ent present$message $printable"); 151 ok (!brute_force_exists ($copy, $key), 152 "hv_delete_ent present$message $printable"); 153 $copy = {%$hash}; 154 ok (brute_force_exists ($copy, $key), 155 "hv_delete present$message $printable"); 156 is (XS::APItest::Hash::delete ($copy, $key), $key, 157 "hv_delete present$message $printable"); 158 ok (!brute_force_exists ($copy, $key), 159 "hv_delete present$message $printable"); 160} 161 162sub test_delete_absent { 163 my ($hash, $key, $printable, $message) = @_; 164 165 my $copy = {}; 166 my $class = tied %$hash; 167 if (defined $class) { 168 tie %$copy, ref $class; 169 } 170 $copy = {%$hash}; 171 is (delete $copy->{$key}, undef, "hv_delete_ent absent$message $printable"); 172 $copy = {%$hash}; 173 is (XS::APItest::Hash::delete ($copy, $key), undef, 174 "hv_delete absent$message $printable"); 175} 176 177sub test_store { 178 my ($hash, $key, $printable, $message, $defaults) = @_; 179 my $HV_STORE_IS_CRAZY = 1; 180 181 # We are cheating - hv_store returns NULL for a store into an empty 182 # tied hash. This isn't helpful here. 183 184 my $class = tied %$hash; 185 186 my %h1 = @$defaults; 187 my %h2 = @$defaults; 188 if (defined $class) { 189 tie %h1, ref $class; 190 tie %h2, ref $class; 191 $HV_STORE_IS_CRAZY = undef unless @$defaults; 192 } 193 is (XS::APItest::Hash::store_ent(\%h1, $key, 1), 1, 194 "hv_store_ent$message $printable"); 195 ok (brute_force_exists (\%h1, $key), "hv_store_ent$message $printable"); 196 is (XS::APItest::Hash::store(\%h2, $key, 1), $HV_STORE_IS_CRAZY, 197 "hv_store$message $printable"); 198 ok (brute_force_exists (\%h2, $key), "hv_store$message $printable"); 199} 200 201sub test_fetch_present { 202 my ($hash, $key, $printable, $message) = @_; 203 204 is ($hash->{$key}, $key, "hv_fetch_ent present$message $printable"); 205 is (XS::APItest::Hash::fetch ($hash, $key), $key, 206 "hv_fetch present$message $printable"); 207} 208 209sub test_fetch_absent { 210 my ($hash, $key, $printable, $message) = @_; 211 212 is ($hash->{$key}, undef, "hv_fetch_ent absent$message $printable"); 213 is (XS::APItest::Hash::fetch ($hash, $key), undef, 214 "hv_fetch absent$message $printable"); 215} 216 217sub brute_force_exists { 218 my ($hash, $key) = @_; 219 foreach (keys %$hash) { 220 return 1 if $key eq $_; 221 } 222 return 0; 223} 224