This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix a very subtle hash ordering dependency in op/smartkve.t
authorYves Orton <demerphq@gmail.com>
Tue, 28 Aug 2012 08:15:40 +0000 (10:15 +0200)
committerYves Orton <demerphq@gmail.com>
Fri, 26 Oct 2012 09:46:31 +0000 (11:46 +0200)
Currently our hash implementation is order dependent on insertion.

When two keys collide and have to be stored in the same bucket the
order in which they are inserted into the hash will govern the order
in which they are fetched out by things like keys() and values().

This means that a copy of such a hash may be different. It is possible
this can be fixed with a low cost, but until then you cannot rely on
two hashes with the same keys having the same ordering of those keys

Depending on the hash algorithm and the seed values used this test
would fail. By changing it so there is one initial hash and then all
tests are done on copies of that hash we avoid the problem.

t/op/smartkve.t

index ad56e6a..7e5d67e 100644 (file)
@@ -14,12 +14,24 @@ plan 'no_plan';
 
 sub j { join(":",@_) }
 
+# NOTE
+#
+# Hash insertion is currently unstable, in that
+# %hash= %otherhash will not necessarily result in
+# the same internal ordering of the data in the hash.
+# For instance when keys collide the copy may not
+# match the inserted order. So we declare one hash
+# and then make all our copies from that, which should
+# mean all the copies have the same internal structure.
+our %base_hash;
+
 BEGIN { # in BEGIN for "use constant ..." later
+  %base_hash= (  pi => 3.14, e => 2.72, i => -1 );
   $array = [ qw(pi e i) ];
   $values = [ 3.14, 2.72, -1 ];
-  $hash  = { pi => 3.14, e => 2.72, i => -1 } ;
+  $hash  = { %base_hash } ;
   $data = {
-    hash => { %$hash },
+    hash => { %base_hash },
     array => [ @$array ],
   };
 }
@@ -27,7 +39,7 @@ BEGIN { # in BEGIN for "use constant ..." later
 package Foo;
 sub new {
   my $self = {
-    hash => {%{$main::hash} },
+    hash => { %base_hash },
     array => [@{$main::array}]
   };
   bless $self, shift;
@@ -58,10 +70,10 @@ use overload '@{}' => sub { $main::array }, fallback => 1;
 
 package main;
 
-use constant CONST_HASH => { %$hash };
+use constant CONST_HASH => { %base_hash };
 use constant CONST_ARRAY => [ @$array ];
 
-my %a_hash = %$hash;
+my %a_hash = %base_hash;
 my @an_array = @$array;
 sub hash_sub { return \%a_hash; }
 sub array_sub { return \@an_array; }