143003dfeSmillert#!/usr/bin/perl -Tw 243003dfeSmillert 343003dfeSmillertBEGIN { 443003dfeSmillert if ($ENV{PERL_CORE}) { 543003dfeSmillert require Config; import Config; 6b39c5158Smillert no warnings 'once'; 743003dfeSmillert if ($Config{extensions} !~ /\bHash\/Util\b/) { 843003dfeSmillert print "1..0 # Skip: Hash::Util was not built\n"; 943003dfeSmillert exit 0; 1043003dfeSmillert } 1143003dfeSmillert } 1243003dfeSmillert} 1343003dfeSmillert 1443003dfeSmillertuse strict; 1543003dfeSmillertuse Test::More; 16b8851fccSafresh1 17b8851fccSafresh1sub numbers_first { # Sort helper: All digit entries sort in front of others 18b8851fccSafresh1 # Makes sorting portable across ASCII/EBCDIC 19b8851fccSafresh1 return $a cmp $b if ($a =~ /^\d+$/) == ($b =~ /^\d+$/); 20b8851fccSafresh1 return -1 if $a =~ /^\d+$/; 21b8851fccSafresh1 return 1; 22b8851fccSafresh1} 23b8851fccSafresh1 2443003dfeSmillertmy @Exported_Funcs; 2543003dfeSmillertBEGIN { 2643003dfeSmillert @Exported_Funcs = qw( 2791f110e0Safresh1 fieldhash fieldhashes 2891f110e0Safresh1 2991f110e0Safresh1 all_keys 3043003dfeSmillert lock_keys unlock_keys 3143003dfeSmillert lock_value unlock_value 3243003dfeSmillert lock_hash unlock_hash 3391f110e0Safresh1 lock_keys_plus 3491f110e0Safresh1 hash_locked hash_unlocked 3591f110e0Safresh1 hashref_locked hashref_unlocked 3643003dfeSmillert hidden_keys legal_keys 3743003dfeSmillert 3843003dfeSmillert lock_ref_keys unlock_ref_keys 3943003dfeSmillert lock_ref_value unlock_ref_value 4043003dfeSmillert lock_hashref unlock_hashref 4191f110e0Safresh1 lock_ref_keys_plus 4243003dfeSmillert hidden_ref_keys legal_ref_keys 4343003dfeSmillert 4491f110e0Safresh1 hash_seed hash_value bucket_stats bucket_info bucket_array 4591f110e0Safresh1 hv_store 4691f110e0Safresh1 lock_hash_recurse unlock_hash_recurse 47b8851fccSafresh1 lock_hashref_recurse unlock_hashref_recurse 4843003dfeSmillert ); 49*eac174f2Safresh1 plan tests => 250 + @Exported_Funcs; 5043003dfeSmillert use_ok 'Hash::Util', @Exported_Funcs; 5143003dfeSmillert} 5243003dfeSmillertforeach my $func (@Exported_Funcs) { 5343003dfeSmillert can_ok __PACKAGE__, $func; 5443003dfeSmillert} 5543003dfeSmillert 5643003dfeSmillertmy %hash = (foo => 42, bar => 23, locked => 'yep'); 5743003dfeSmillertlock_keys(%hash); 5843003dfeSmillerteval { $hash{baz} = 99; }; 5943003dfeSmillertlike( $@, qr/^Attempt to access disallowed key 'baz' in a restricted hash/, 6043003dfeSmillert 'lock_keys()'); 6191f110e0Safresh1is( $hash{bar}, 23, '$hash{bar} == 23' ); 6243003dfeSmillertok( !exists $hash{baz},'!exists $hash{baz}' ); 6343003dfeSmillert 6443003dfeSmillertdelete $hash{bar}; 6543003dfeSmillertok( !exists $hash{bar},'!exists $hash{bar}' ); 6643003dfeSmillert$hash{bar} = 69; 6743003dfeSmillertis( $hash{bar}, 69 ,'$hash{bar} == 69'); 6843003dfeSmillert 6943003dfeSmillerteval { () = $hash{i_dont_exist} }; 7043003dfeSmillertlike( $@, qr/^Attempt to access disallowed key 'i_dont_exist' in a restricted hash/, 7143003dfeSmillert 'Disallowed 1' ); 7243003dfeSmillert 7343003dfeSmillertlock_value(%hash, 'locked'); 7443003dfeSmillerteval { print "# oops" if $hash{four} }; 7543003dfeSmillertlike( $@, qr/^Attempt to access disallowed key 'four' in a restricted hash/, 7643003dfeSmillert 'Disallowed 2' ); 7743003dfeSmillert 7843003dfeSmillerteval { $hash{"\x{2323}"} = 3 }; 7943003dfeSmillertlike( $@, qr/^Attempt to access disallowed key '(.*)' in a restricted hash/, 8043003dfeSmillert 'wide hex key' ); 8143003dfeSmillert 8243003dfeSmillerteval { delete $hash{locked} }; 8343003dfeSmillertlike( $@, qr/^Attempt to delete readonly key 'locked' from a restricted hash/, 8443003dfeSmillert 'trying to delete a locked key' ); 8543003dfeSmillerteval { $hash{locked} = 42; }; 8643003dfeSmillertlike( $@, qr/^Modification of a read-only value attempted/, 8743003dfeSmillert 'trying to change a locked key' ); 8891f110e0Safresh1is( $hash{locked}, 'yep', '$hash{locked} is yep' ); 8943003dfeSmillert 9043003dfeSmillerteval { delete $hash{I_dont_exist} }; 9143003dfeSmillertlike( $@, qr/^Attempt to delete disallowed key 'I_dont_exist' from a restricted hash/, 9243003dfeSmillert 'trying to delete a key that doesnt exist' ); 9343003dfeSmillert 9443003dfeSmillertok( !exists $hash{I_dont_exist},'!exists $hash{I_dont_exist}' ); 9543003dfeSmillert 9643003dfeSmillertunlock_keys(%hash); 9743003dfeSmillert$hash{I_dont_exist} = 42; 9843003dfeSmillertis( $hash{I_dont_exist}, 42, 'unlock_keys' ); 9943003dfeSmillert 10043003dfeSmillerteval { $hash{locked} = 42; }; 10143003dfeSmillertlike( $@, qr/^Modification of a read-only value attempted/, 10243003dfeSmillert ' individual key still readonly' ); 10343003dfeSmillerteval { delete $hash{locked} }, 10443003dfeSmillertis( $@, '', ' but can be deleted :(' ); 10543003dfeSmillert 10643003dfeSmillertunlock_value(%hash, 'locked'); 10743003dfeSmillert$hash{locked} = 42; 10843003dfeSmillertis( $hash{locked}, 42, 'unlock_value' ); 10943003dfeSmillert 11043003dfeSmillert 11143003dfeSmillert{ 11243003dfeSmillert my %hash = ( foo => 42, locked => 23 ); 11343003dfeSmillert 11443003dfeSmillert lock_keys(%hash); 11543003dfeSmillert eval { %hash = ( wubble => 42 ) }; # we know this will bomb 11643003dfeSmillert like( $@, qr/^Attempt to access disallowed key 'wubble'/,'Disallowed 3' ); 11743003dfeSmillert unlock_keys(%hash); 11843003dfeSmillert} 11943003dfeSmillert 12043003dfeSmillert{ 12143003dfeSmillert my %hash = (KEY => 'val', RO => 'val'); 12243003dfeSmillert lock_keys(%hash); 12343003dfeSmillert lock_value(%hash, 'RO'); 12443003dfeSmillert 12543003dfeSmillert eval { %hash = (KEY => 1) }; 12691f110e0Safresh1 like( $@, qr/^Attempt to delete readonly key 'RO' from a restricted hash/, 12791f110e0Safresh1 'attempt to delete readonly key from restricted hash' ); 12843003dfeSmillert} 12943003dfeSmillert 13043003dfeSmillert{ 13143003dfeSmillert my %hash = (KEY => 1, RO => 2); 13243003dfeSmillert lock_keys(%hash); 13343003dfeSmillert eval { %hash = (KEY => 1, RO => 2) }; 13491f110e0Safresh1 is( $@, '', 'No error message, as expected'); 13543003dfeSmillert} 13643003dfeSmillert 13743003dfeSmillert{ 13843003dfeSmillert my %hash = (); 13943003dfeSmillert lock_keys(%hash, qw(foo bar)); 14043003dfeSmillert is( keys %hash, 0, 'lock_keys() w/keyset shouldnt add new keys' ); 14143003dfeSmillert $hash{foo} = 42; 14291f110e0Safresh1 is( keys %hash, 1, '1 element in hash' ); 14343003dfeSmillert eval { $hash{wibble} = 42 }; 14443003dfeSmillert like( $@, qr/^Attempt to access disallowed key 'wibble' in a restricted hash/, 14543003dfeSmillert 'write threw error (locked)'); 14643003dfeSmillert 14743003dfeSmillert unlock_keys(%hash); 14843003dfeSmillert eval { $hash{wibble} = 23; }; 14943003dfeSmillert is( $@, '', 'unlock_keys' ); 15043003dfeSmillert} 15143003dfeSmillert 15243003dfeSmillert{ 15343003dfeSmillert my %hash = (foo => 42, bar => undef, baz => 0); 15443003dfeSmillert lock_keys(%hash, qw(foo bar baz up down)); 15543003dfeSmillert is( keys %hash, 3, 'lock_keys() w/keyset didnt add new keys' ); 15643003dfeSmillert is_deeply( \%hash, { foo => 42, bar => undef, baz => 0 },'is_deeply' ); 15743003dfeSmillert 15843003dfeSmillert eval { $hash{up} = 42; }; 15943003dfeSmillert is( $@, '','No error 1' ); 16043003dfeSmillert 16143003dfeSmillert eval { $hash{wibble} = 23 }; 16243003dfeSmillert like( $@, qr/^Attempt to access disallowed key 'wibble' in a restricted hash/, 16343003dfeSmillert 'locked "wibble"' ); 16443003dfeSmillert} 16543003dfeSmillert 16643003dfeSmillert{ 16743003dfeSmillert my %hash = (foo => 42, bar => undef); 16843003dfeSmillert eval { lock_keys(%hash, qw(foo baz)); }; 16991f110e0Safresh1 like( $@, qr/^Hash has key 'bar' which is not in the new key set/, 17043003dfeSmillert 'carp test' ); 17143003dfeSmillert} 17243003dfeSmillert 17343003dfeSmillert{ 17443003dfeSmillert my %hash = (foo => 42, bar => 23); 17543003dfeSmillert lock_hash( %hash ); 17691f110e0Safresh1 ok( hashref_locked( \%hash ), 'hashref_locked' ); 17791f110e0Safresh1 ok( hash_locked( %hash ), 'hash_locked' ); 17843003dfeSmillert 17943003dfeSmillert ok( Internals::SvREADONLY(%hash),'Was locked %hash' ); 18043003dfeSmillert ok( Internals::SvREADONLY($hash{foo}),'Was locked $hash{foo}' ); 18143003dfeSmillert ok( Internals::SvREADONLY($hash{bar}),'Was locked $hash{bar}' ); 18243003dfeSmillert 18343003dfeSmillert unlock_hash ( %hash ); 18491f110e0Safresh1 ok( hashref_unlocked( { %hash } ), 'hashref_unlocked' ); 18591f110e0Safresh1 ok( hash_unlocked( %hash ), 'hash_unlocked' ); 18643003dfeSmillert 18743003dfeSmillert ok( !Internals::SvREADONLY(%hash),'Was unlocked %hash' ); 18843003dfeSmillert ok( !Internals::SvREADONLY($hash{foo}),'Was unlocked $hash{foo}' ); 18943003dfeSmillert ok( !Internals::SvREADONLY($hash{bar}),'Was unlocked $hash{bar}' ); 19043003dfeSmillert} 19143003dfeSmillert 19291f110e0Safresh1{ 19391f110e0Safresh1 my %hash = (foo => 42, bar => 23); 19491f110e0Safresh1 ok( ! hashref_locked( { %hash } ), 'hashref_locked negated' ); 19591f110e0Safresh1 ok( ! hash_locked( %hash ), 'hash_locked negated' ); 19691f110e0Safresh1 19791f110e0Safresh1 lock_hash( %hash ); 19891f110e0Safresh1 ok( ! hashref_unlocked( \%hash ), 'hashref_unlocked negated' ); 19991f110e0Safresh1 ok( ! hash_unlocked( %hash ), 'hash_unlocked negated' ); 20091f110e0Safresh1} 20143003dfeSmillert 20243003dfeSmillertlock_keys(%ENV); 20343003dfeSmillerteval { () = $ENV{I_DONT_EXIST} }; 20491f110e0Safresh1like( 20591f110e0Safresh1 $@, 20691f110e0Safresh1 qr/^Attempt to access disallowed key 'I_DONT_EXIST' in a restricted hash/, 20791f110e0Safresh1 'locked %ENV' 20891f110e0Safresh1); 2096fb12b70Safresh1unlock_keys(%ENV); # Test::Builder cannot print test failures otherwise 21043003dfeSmillert 21143003dfeSmillert{ 21243003dfeSmillert my %hash; 21343003dfeSmillert 21443003dfeSmillert lock_keys(%hash, 'first'); 21543003dfeSmillert 21643003dfeSmillert is (scalar keys %hash, 0, "place holder isn't a key"); 21743003dfeSmillert $hash{first} = 1; 21843003dfeSmillert is (scalar keys %hash, 1, "we now have a key"); 21943003dfeSmillert delete $hash{first}; 22043003dfeSmillert is (scalar keys %hash, 0, "now no key"); 22143003dfeSmillert 22243003dfeSmillert unlock_keys(%hash); 22343003dfeSmillert 22443003dfeSmillert $hash{interregnum} = 1.5; 22543003dfeSmillert is (scalar keys %hash, 1, "key again"); 22643003dfeSmillert delete $hash{interregnum}; 22743003dfeSmillert is (scalar keys %hash, 0, "no key again"); 22843003dfeSmillert 22943003dfeSmillert lock_keys(%hash, 'second'); 23043003dfeSmillert 23143003dfeSmillert is (scalar keys %hash, 0, "place holder isn't a key"); 23243003dfeSmillert 23343003dfeSmillert eval {$hash{zeroeth} = 0}; 23443003dfeSmillert like ($@, 23543003dfeSmillert qr/^Attempt to access disallowed key 'zeroeth' in a restricted hash/, 23643003dfeSmillert 'locked key never mentioned before should fail'); 23743003dfeSmillert eval {$hash{first} = -1}; 23843003dfeSmillert like ($@, 23943003dfeSmillert qr/^Attempt to access disallowed key 'first' in a restricted hash/, 24043003dfeSmillert 'previously locked place holders should also fail'); 24143003dfeSmillert is (scalar keys %hash, 0, "and therefore there are no keys"); 24243003dfeSmillert $hash{second} = 1; 24343003dfeSmillert is (scalar keys %hash, 1, "we now have just one key"); 24443003dfeSmillert delete $hash{second}; 24543003dfeSmillert is (scalar keys %hash, 0, "back to zero"); 24643003dfeSmillert 24743003dfeSmillert unlock_keys(%hash); # We have deliberately left a placeholder. 24843003dfeSmillert 24943003dfeSmillert $hash{void} = undef; 25043003dfeSmillert $hash{nowt} = undef; 25143003dfeSmillert 25243003dfeSmillert is (scalar keys %hash, 2, "two keys, values both undef"); 25343003dfeSmillert 25443003dfeSmillert lock_keys(%hash); 25543003dfeSmillert 25643003dfeSmillert is (scalar keys %hash, 2, "still two keys after locking"); 25743003dfeSmillert 25843003dfeSmillert eval {$hash{second} = -1}; 25943003dfeSmillert like ($@, 26043003dfeSmillert qr/^Attempt to access disallowed key 'second' in a restricted hash/, 26143003dfeSmillert 'previously locked place holders should fail'); 26243003dfeSmillert 26343003dfeSmillert is ($hash{void}, undef, 26443003dfeSmillert "undef values should not be misunderstood as placeholders"); 26543003dfeSmillert is ($hash{nowt}, undef, 26643003dfeSmillert "undef values should not be misunderstood as placeholders (again)"); 26743003dfeSmillert} 26843003dfeSmillert 26943003dfeSmillert{ 27043003dfeSmillert # perl #18651 - tim@consultix-inc.com found a rather nasty data dependant 27143003dfeSmillert # bug whereby hash iterators could lose hash keys (and values, as the code 27243003dfeSmillert # is common) for restricted hashes. 27343003dfeSmillert 27443003dfeSmillert my @keys = qw(small medium large); 27543003dfeSmillert 27643003dfeSmillert # There should be no difference whether it is restricted or not 27743003dfeSmillert foreach my $lock (0, 1) { 27843003dfeSmillert # Try setting all combinations of the 3 keys 27943003dfeSmillert foreach my $usekeys (0..7) { 28043003dfeSmillert my @usekeys; 28143003dfeSmillert for my $bits (0,1,2) { 28243003dfeSmillert push @usekeys, $keys[$bits] if $usekeys & (1 << $bits); 28343003dfeSmillert } 28443003dfeSmillert my %clean = map {$_ => length $_} @usekeys; 28543003dfeSmillert my %target; 28643003dfeSmillert lock_keys ( %target, @keys ) if $lock; 28743003dfeSmillert 28843003dfeSmillert while (my ($k, $v) = each %clean) { 28943003dfeSmillert $target{$k} = $v; 29043003dfeSmillert } 29143003dfeSmillert 29243003dfeSmillert my $message 29343003dfeSmillert = ($lock ? 'locked' : 'not locked') . ' keys ' . join ',', @usekeys; 29443003dfeSmillert 29543003dfeSmillert is (scalar keys %target, scalar keys %clean, "scalar keys for $message"); 29643003dfeSmillert is (scalar values %target, scalar values %clean, 29743003dfeSmillert "scalar values for $message"); 29843003dfeSmillert # Yes. All these sorts are necessary. Even for "identical hashes" 29943003dfeSmillert # Because the data dependency of the test involves two of the strings 30043003dfeSmillert # colliding on the same bucket, so the iterator order (output of keys, 30143003dfeSmillert # values, each) depends on the addition order in the hash. And locking 30243003dfeSmillert # the keys of the hash involves behind the scenes key additions. 30343003dfeSmillert is_deeply( [sort keys %target] , [sort keys %clean], 30443003dfeSmillert "list keys for $message"); 30543003dfeSmillert is_deeply( [sort values %target] , [sort values %clean], 30643003dfeSmillert "list values for $message"); 30743003dfeSmillert 30843003dfeSmillert is_deeply( [sort %target] , [sort %clean], 30943003dfeSmillert "hash in list context for $message"); 31043003dfeSmillert 31143003dfeSmillert my (@clean, @target); 31243003dfeSmillert while (my ($k, $v) = each %clean) { 31343003dfeSmillert push @clean, $k, $v; 31443003dfeSmillert } 31543003dfeSmillert while (my ($k, $v) = each %target) { 31643003dfeSmillert push @target, $k, $v; 31743003dfeSmillert } 31843003dfeSmillert 31943003dfeSmillert is_deeply( [sort @target] , [sort @clean], 32043003dfeSmillert "iterating with each for $message"); 32143003dfeSmillert } 32243003dfeSmillert } 32343003dfeSmillert} 32443003dfeSmillert 32543003dfeSmillert# Check clear works on locked empty hashes - SEGVs on 5.8.2. 32643003dfeSmillert{ 32743003dfeSmillert my %hash; 32843003dfeSmillert lock_hash(%hash); 32943003dfeSmillert %hash = (); 33043003dfeSmillert ok(keys(%hash) == 0, 'clear empty lock_hash() hash'); 33143003dfeSmillert} 33243003dfeSmillert{ 33343003dfeSmillert my %hash; 33443003dfeSmillert lock_keys(%hash); 33543003dfeSmillert %hash = (); 33643003dfeSmillert ok(keys(%hash) == 0, 'clear empty lock_keys() hash'); 33743003dfeSmillert} 33843003dfeSmillert 3396fb12b70Safresh1# Copy-on-write scalars should not be deletable after lock_hash; 3406fb12b70Safresh1{ 3416fb12b70Safresh1 my %hash = (key=>__PACKAGE__); 3426fb12b70Safresh1 lock_hash(%hash); 3436fb12b70Safresh1 eval { delete $hash{key} }; 3446fb12b70Safresh1 like $@, qr/^Attempt to delete readonly key /, 3456fb12b70Safresh1 'COW scalars are not exempt from lock_hash (delete)'; 3466fb12b70Safresh1 eval { %hash = () }; 3476fb12b70Safresh1 like $@, qr/^Attempt to delete readonly key /, 3486fb12b70Safresh1 'COW scalars are not exempt from lock_hash (clear)'; 3496fb12b70Safresh1} 3506fb12b70Safresh1 35143003dfeSmillertmy $hash_seed = hash_seed(); 35291f110e0Safresh1ok(defined($hash_seed) && $hash_seed ne '', "hash_seed $hash_seed"); 35343003dfeSmillert 35443003dfeSmillert{ 35543003dfeSmillert package Minder; 35643003dfeSmillert my $counter; 35743003dfeSmillert sub DESTROY { 35843003dfeSmillert --$counter; 35943003dfeSmillert } 36043003dfeSmillert sub new { 36143003dfeSmillert ++$counter; 36243003dfeSmillert bless [], __PACKAGE__; 36343003dfeSmillert } 36443003dfeSmillert package main; 36543003dfeSmillert 36643003dfeSmillert for my $state ('', 'locked') { 36743003dfeSmillert my $a = Minder->new(); 36843003dfeSmillert is ($counter, 1, "There is 1 object $state"); 36943003dfeSmillert my %hash; 37043003dfeSmillert $hash{a} = $a; 37143003dfeSmillert is ($counter, 1, "There is still 1 object $state"); 37243003dfeSmillert 37343003dfeSmillert lock_keys(%hash) if $state; 37443003dfeSmillert 37543003dfeSmillert is ($counter, 1, "There is still 1 object $state"); 37643003dfeSmillert undef $a; 37743003dfeSmillert is ($counter, 1, "Still 1 object $state"); 37843003dfeSmillert delete $hash{a}; 37943003dfeSmillert is ($counter, 0, "0 objects when hash key is deleted $state"); 38043003dfeSmillert $hash{a} = undef; 38143003dfeSmillert is ($counter, 0, "Still 0 objects $state"); 38243003dfeSmillert %hash = (); 38343003dfeSmillert is ($counter, 0, "0 objects after clear $state"); 38443003dfeSmillert } 38543003dfeSmillert} 38643003dfeSmillert{ 38743003dfeSmillert my %hash = map {$_,$_} qw(fwiffffff foosht teeoo); 38843003dfeSmillert lock_keys(%hash); 38943003dfeSmillert delete $hash{fwiffffff}; 39043003dfeSmillert is (scalar keys %hash, 2,"Count of keys after delete on locked hash"); 39143003dfeSmillert unlock_keys(%hash); 39243003dfeSmillert is (scalar keys %hash, 2,"Count of keys after unlock"); 39343003dfeSmillert 39443003dfeSmillert my ($first, $value) = each %hash; 39543003dfeSmillert is ($hash{$first}, $value, "Key has the expected value before the lock"); 39643003dfeSmillert lock_keys(%hash); 39743003dfeSmillert is ($hash{$first}, $value, "Key has the expected value after the lock"); 39843003dfeSmillert 39943003dfeSmillert my ($second, $v2) = each %hash; 40043003dfeSmillert 40143003dfeSmillert is ($hash{$first}, $value, "Still correct after iterator advances"); 40243003dfeSmillert is ($hash{$second}, $v2, "Other key has the expected value"); 40343003dfeSmillert} 40443003dfeSmillert{ 40543003dfeSmillert my $x='foo'; 40643003dfeSmillert my %test; 40743003dfeSmillert hv_store(%test,'x',$x); 40843003dfeSmillert is($test{x},'foo','hv_store() stored'); 40943003dfeSmillert $test{x}='bar'; 41043003dfeSmillert is($x,'bar','hv_store() aliased'); 41143003dfeSmillert is($test{x},'bar','hv_store() aliased and stored'); 41243003dfeSmillert} 41343003dfeSmillert 41443003dfeSmillert{ 41543003dfeSmillert my %hash=map { $_ => 1 } qw( a b c d e f); 41643003dfeSmillert delete $hash{c}; 41743003dfeSmillert lock_keys(%hash); 41843003dfeSmillert ok(Internals::SvREADONLY(%hash),'lock_keys DDS/t 1'); 41943003dfeSmillert delete @hash{qw(b e)}; 42043003dfeSmillert my @hidden=sort(hidden_keys(%hash)); 42143003dfeSmillert my @legal=sort(legal_keys(%hash)); 42243003dfeSmillert my @keys=sort(keys(%hash)); 42343003dfeSmillert #warn "@legal\n@keys\n"; 42443003dfeSmillert is("@hidden","b e",'lock_keys @hidden DDS/t'); 42543003dfeSmillert is("@legal","a b d e f",'lock_keys @legal DDS/t'); 42643003dfeSmillert is("@keys","a d f",'lock_keys @keys DDS/t'); 42743003dfeSmillert} 42843003dfeSmillert{ 42943003dfeSmillert my %hash=(0..9); 43043003dfeSmillert lock_keys(%hash); 43143003dfeSmillert ok(Internals::SvREADONLY(%hash),'lock_keys DDS/t 2'); 43243003dfeSmillert Hash::Util::unlock_keys(%hash); 43343003dfeSmillert ok(!Internals::SvREADONLY(%hash),'unlock_keys DDS/t 2'); 43443003dfeSmillert} 43543003dfeSmillert{ 43643003dfeSmillert my %hash=(0..9); 43743003dfeSmillert lock_keys(%hash,keys(%hash),'a'..'f'); 43843003dfeSmillert ok(Internals::SvREADONLY(%hash),'lock_keys args DDS/t'); 439b8851fccSafresh1 my @hidden=sort numbers_first hidden_keys(%hash); 440b8851fccSafresh1 my @legal=sort numbers_first legal_keys(%hash); 441b8851fccSafresh1 my @keys=sort numbers_first keys(%hash); 44243003dfeSmillert is("@hidden","a b c d e f",'lock_keys() @hidden DDS/t 3'); 44343003dfeSmillert is("@legal","0 2 4 6 8 a b c d e f",'lock_keys() @legal DDS/t 3'); 44443003dfeSmillert is("@keys","0 2 4 6 8",'lock_keys() @keys'); 44543003dfeSmillert} 44643003dfeSmillert{ 44743003dfeSmillert my %hash=map { $_ => 1 } qw( a b c d e f); 44843003dfeSmillert delete $hash{c}; 44943003dfeSmillert lock_ref_keys(\%hash); 45043003dfeSmillert ok(Internals::SvREADONLY(%hash),'lock_ref_keys DDS/t'); 45143003dfeSmillert delete @hash{qw(b e)}; 45243003dfeSmillert my @hidden=sort(hidden_keys(%hash)); 45343003dfeSmillert my @legal=sort(legal_keys(%hash)); 45443003dfeSmillert my @keys=sort(keys(%hash)); 45543003dfeSmillert #warn "@legal\n@keys\n"; 45643003dfeSmillert is("@hidden","b e",'lock_ref_keys @hidden DDS/t 1'); 45743003dfeSmillert is("@legal","a b d e f",'lock_ref_keys @legal DDS/t 1'); 45843003dfeSmillert is("@keys","a d f",'lock_ref_keys @keys DDS/t 1'); 45943003dfeSmillert} 46043003dfeSmillert{ 46143003dfeSmillert my %hash=(0..9); 46243003dfeSmillert lock_ref_keys(\%hash,keys %hash,'a'..'f'); 46343003dfeSmillert ok(Internals::SvREADONLY(%hash),'lock_ref_keys args DDS/t'); 464b8851fccSafresh1 my @hidden=sort numbers_first hidden_keys(%hash); 465b8851fccSafresh1 my @legal=sort numbers_first legal_keys(%hash); 466b8851fccSafresh1 my @keys=sort numbers_first keys(%hash); 46743003dfeSmillert is("@hidden","a b c d e f",'lock_ref_keys() @hidden DDS/t 2'); 46843003dfeSmillert is("@legal","0 2 4 6 8 a b c d e f",'lock_ref_keys() @legal DDS/t 2'); 46943003dfeSmillert is("@keys","0 2 4 6 8",'lock_ref_keys() @keys DDS/t 2'); 47043003dfeSmillert} 47143003dfeSmillert{ 47243003dfeSmillert my %hash=(0..9); 47343003dfeSmillert lock_ref_keys_plus(\%hash,'a'..'f'); 47443003dfeSmillert ok(Internals::SvREADONLY(%hash),'lock_ref_keys_plus args DDS/t'); 475b8851fccSafresh1 my @hidden=sort numbers_first hidden_keys(%hash); 476b8851fccSafresh1 my @legal=sort numbers_first legal_keys(%hash); 477b8851fccSafresh1 my @keys=sort numbers_first keys(%hash); 47843003dfeSmillert is("@hidden","a b c d e f",'lock_ref_keys_plus() @hidden DDS/t'); 47943003dfeSmillert is("@legal","0 2 4 6 8 a b c d e f",'lock_ref_keys_plus() @legal DDS/t'); 48043003dfeSmillert is("@keys","0 2 4 6 8",'lock_ref_keys_plus() @keys DDS/t'); 48143003dfeSmillert} 48243003dfeSmillert{ 48391f110e0Safresh1 my %hash=(0..9, 'a' => 'alpha'); 48491f110e0Safresh1 lock_ref_keys_plus(\%hash,'a'..'f'); 48591f110e0Safresh1 ok(Internals::SvREADONLY(%hash),'lock_ref_keys_plus args overlap'); 486b8851fccSafresh1 my @hidden=sort numbers_first hidden_keys(%hash); 487b8851fccSafresh1 my @legal=sort numbers_first legal_keys(%hash); 488b8851fccSafresh1 my @keys=sort numbers_first keys(%hash); 48991f110e0Safresh1 is("@hidden","b c d e f",'lock_ref_keys_plus() @hidden overlap'); 49091f110e0Safresh1 is("@legal","0 2 4 6 8 a b c d e f",'lock_ref_keys_plus() @legal overlap'); 49191f110e0Safresh1 is("@keys","0 2 4 6 8 a",'lock_ref_keys_plus() @keys overlap'); 49291f110e0Safresh1} 49391f110e0Safresh1{ 49443003dfeSmillert my %hash=(0..9); 49543003dfeSmillert lock_keys_plus(%hash,'a'..'f'); 49643003dfeSmillert ok(Internals::SvREADONLY(%hash),'lock_keys_plus args DDS/t'); 497b8851fccSafresh1 my @hidden=sort numbers_first hidden_keys(%hash); 498b8851fccSafresh1 my @legal=sort numbers_first legal_keys(%hash); 499b8851fccSafresh1 my @keys=sort numbers_first keys(%hash); 50043003dfeSmillert is("@hidden","a b c d e f",'lock_keys_plus() @hidden DDS/t 3'); 50143003dfeSmillert is("@legal","0 2 4 6 8 a b c d e f",'lock_keys_plus() @legal DDS/t 3'); 50243003dfeSmillert is("@keys","0 2 4 6 8",'lock_keys_plus() @keys DDS/t 3'); 50343003dfeSmillert} 50491f110e0Safresh1{ 50591f110e0Safresh1 my %hash=(0..9, 'a' => 'alpha'); 50691f110e0Safresh1 lock_keys_plus(%hash,'a'..'f'); 50791f110e0Safresh1 ok(Internals::SvREADONLY(%hash),'lock_keys_plus args overlap non-ref'); 508b8851fccSafresh1 my @hidden=sort numbers_first hidden_keys(%hash); 509b8851fccSafresh1 my @legal=sort numbers_first legal_keys(%hash); 510b8851fccSafresh1 my @keys=sort numbers_first keys(%hash); 51191f110e0Safresh1 is("@hidden","b c d e f",'lock_keys_plus() @hidden overlap non-ref'); 51291f110e0Safresh1 is("@legal","0 2 4 6 8 a b c d e f",'lock_keys_plus() @legal overlap non-ref'); 51391f110e0Safresh1 is("@keys","0 2 4 6 8 a",'lock_keys_plus() @keys overlap non-ref'); 51491f110e0Safresh1} 51543003dfeSmillert 51643003dfeSmillert{ 51743003dfeSmillert my %hash = ('a'..'f'); 51843003dfeSmillert my @keys = (); 51943003dfeSmillert my @ph = (); 52043003dfeSmillert my @lock = ('a', 'c', 'e', 'g'); 52143003dfeSmillert lock_keys(%hash, @lock); 52243003dfeSmillert my $ref = all_keys(%hash, @keys, @ph); 52343003dfeSmillert my @crrack = sort(@keys); 52443003dfeSmillert my @ooooff = qw(a c e); 52543003dfeSmillert my @bam = qw(g); 52643003dfeSmillert 52743003dfeSmillert ok(ref $ref eq ref \%hash && $ref == \%hash, 52843003dfeSmillert "all_keys() - \$ref is a reference to \%hash"); 52943003dfeSmillert is_deeply(\@crrack, \@ooooff, "Keys are what they should be"); 53043003dfeSmillert is_deeply(\@ph, \@bam, "Placeholders in place"); 53143003dfeSmillert} 53243003dfeSmillert 53391f110e0Safresh1{ 534b8851fccSafresh1 # lock_hash_recurse / unlock_hash_recurse 53591f110e0Safresh1 my %hash = ( 53691f110e0Safresh1 a => 'alpha', 53791f110e0Safresh1 b => [ qw( beta gamma delta ) ], 53891f110e0Safresh1 c => [ 'epsilon', { zeta => 'eta' }, ], 53991f110e0Safresh1 d => { theta => 'iota' }, 54091f110e0Safresh1 ); 54191f110e0Safresh1 lock_hash_recurse(%hash); 54291f110e0Safresh1 ok( hash_locked(%hash), 54391f110e0Safresh1 "lock_hash_recurse(): top-level hash locked" ); 54491f110e0Safresh1 ok( hash_locked(%{$hash{d}}), 54591f110e0Safresh1 "lock_hash_recurse(): element which is hashref locked" ); 54691f110e0Safresh1 ok( ! hash_locked(%{$hash{c}[1]}), 54791f110e0Safresh1 "lock_hash_recurse(): element which is hashref in array ref not locked" ); 54891f110e0Safresh1 54991f110e0Safresh1 unlock_hash_recurse(%hash); 55091f110e0Safresh1 ok( hash_unlocked(%hash), 55191f110e0Safresh1 "unlock_hash_recurse(): top-level hash unlocked" ); 55291f110e0Safresh1 ok( hash_unlocked(%{$hash{d}}), 55391f110e0Safresh1 "unlock_hash_recurse(): element which is hashref unlocked" ); 554b8851fccSafresh1 { 555b8851fccSafresh1 local $@; 556b8851fccSafresh1 eval { $hash{d} = { theta => 'kappa' }; }; 557b8851fccSafresh1 ok(! $@, "No error; can assign to unlocked hash") 558b8851fccSafresh1 or diag($@); 559b8851fccSafresh1 } 560b8851fccSafresh1 ok( hash_unlocked(%{$hash{c}[1]}), 561b8851fccSafresh1 "unlock_hash_recurse(): element which is hashref in array ref not locked" ); 562b8851fccSafresh1} 563b8851fccSafresh1 564b8851fccSafresh1{ 565b8851fccSafresh1 # lock_hashref_recurse / unlock_hashref_recurse 566b8851fccSafresh1 my %hash = ( 567b8851fccSafresh1 a => 'alpha', 568b8851fccSafresh1 b => [ qw( beta gamma delta ) ], 569b8851fccSafresh1 c => [ 'epsilon', { zeta => 'eta' }, ], 570b8851fccSafresh1 d => { theta => 'iota' }, 571b8851fccSafresh1 ); 572b8851fccSafresh1 Hash::Util::lock_hashref_recurse(\%hash); 573b8851fccSafresh1 ok( hash_locked(%hash), 574b8851fccSafresh1 "lock_hash_recurse(): top-level hash locked" ); 575b8851fccSafresh1 ok( hash_locked(%{$hash{d}}), 576b8851fccSafresh1 "lock_hash_recurse(): element which is hashref locked" ); 577b8851fccSafresh1 ok( ! hash_locked(%{$hash{c}[1]}), 578b8851fccSafresh1 "lock_hash_recurse(): element which is hashref in array ref not locked" ); 579b8851fccSafresh1 580b8851fccSafresh1 Hash::Util::unlock_hashref_recurse(\%hash); 581b8851fccSafresh1 ok( hash_unlocked(%hash), 582b8851fccSafresh1 "unlock_hash_recurse(): top-level hash unlocked" ); 583b8851fccSafresh1 ok( hash_unlocked(%{$hash{d}}), 584b8851fccSafresh1 "unlock_hash_recurse(): element which is hashref unlocked" ); 585b8851fccSafresh1 { 586b8851fccSafresh1 local $@; 587b8851fccSafresh1 eval { $hash{d} = { theta => 'kappa' }; }; 588b8851fccSafresh1 ok(! $@, "No error; can assign to unlocked hash") 589b8851fccSafresh1 or diag($@); 590b8851fccSafresh1 } 59191f110e0Safresh1 ok( hash_unlocked(%{$hash{c}[1]}), 59291f110e0Safresh1 "unlock_hash_recurse(): element which is hashref in array ref not locked" ); 59391f110e0Safresh1} 59491f110e0Safresh1 59591f110e0Safresh1{ 59691f110e0Safresh1 my $h1= hash_value("foo"); 59791f110e0Safresh1 my $h2= hash_value("bar"); 59891f110e0Safresh1 is( $h1, hash_value("foo") ); 59991f110e0Safresh1 is( $h2, hash_value("bar") ); 600*eac174f2Safresh1 601*eac174f2Safresh1 my $seed= hash_seed(); 602*eac174f2Safresh1 my $h1s= hash_value("foo",$seed); 603*eac174f2Safresh1 my $h2s= hash_value("bar",$seed); 604*eac174f2Safresh1 605*eac174f2Safresh1 is( $h1s, hash_value("foo",$seed) ); 606*eac174f2Safresh1 is( $h2s, hash_value("bar",$seed) ); 607*eac174f2Safresh1 608*eac174f2Safresh1 $seed= join "", map { chr $_ } 1..length($seed); 609*eac174f2Safresh1 610*eac174f2Safresh1 my $h1s2= hash_value("foo",$seed); 611*eac174f2Safresh1 my $h2s2= hash_value("bar",$seed); 612*eac174f2Safresh1 613*eac174f2Safresh1 is( $h1s2, hash_value("foo",$seed) ); 614*eac174f2Safresh1 is( $h2s2, hash_value("bar",$seed) ); 615*eac174f2Safresh1 616*eac174f2Safresh1 isnt($h1s,$h1s2); 617*eac174f2Safresh1 isnt($h1s,$h1s2); 618*eac174f2Safresh1 61991f110e0Safresh1} 620*eac174f2Safresh1 62191f110e0Safresh1{ 62291f110e0Safresh1 my @info1= bucket_info({}); 62391f110e0Safresh1 my @info2= bucket_info({1..10}); 62491f110e0Safresh1 my @stats1= bucket_stats({}); 62591f110e0Safresh1 my @stats2= bucket_stats({1..10}); 62691f110e0Safresh1 my $array1= bucket_array({}); 62791f110e0Safresh1 my $array2= bucket_array({1..10}); 62891f110e0Safresh1 is("@info1","0 8 0"); 6299f11ffb7Safresh1 like("@info2[0,1]",qr/5 (?:8|16)/); 63091f110e0Safresh1 is("@stats1","0 8 0"); 6319f11ffb7Safresh1 like("@stats2[0,1]",qr/5 (?:8|16)/); 63291f110e0Safresh1 my @keys1= sort map { ref $_ ? @$_ : () } @$array1; 63391f110e0Safresh1 my @keys2= sort map { ref $_ ? @$_ : () } @$array2; 63491f110e0Safresh1 is("@keys1",""); 63591f110e0Safresh1 is("@keys2","1 3 5 7 9"); 63691f110e0Safresh1} 637