Blame t/canonical.t

Packit 14c646
#!./perl
Packit 14c646
#
Packit 14c646
#  Copyright (c) 1995-2000, Raphael Manfredi
Packit 14c646
#  
Packit 14c646
#  You may redistribute only under the same terms as Perl 5, as specified
Packit 14c646
#  in the README file that comes with the distribution.
Packit 14c646
#  
Packit 14c646
Packit 14c646
sub BEGIN {
Packit 14c646
    unshift @INC, 't';
Packit 14c646
    unshift @INC, 't/compat' if $] < 5.006002;
Packit 14c646
    require Config; import Config;
Packit 14c646
    if ($ENV{PERL_CORE} and $Config{'extensions'} !~ /\bStorable\b/) {
Packit 14c646
        print "1..0 # Skip: Storable was not built\n";
Packit 14c646
        exit 0;
Packit 14c646
    }
Packit 14c646
}
Packit 14c646
Packit 14c646
Packit 14c646
use Storable qw(freeze thaw dclone);
Packit 14c646
our ($debugging, $verbose);
Packit 14c646
Packit 14c646
use Test::More tests => 8;
Packit 14c646
Packit 14c646
# Uncomment the following line to get a dump of the constructed data structure
Packit 14c646
# (you may want to reduce the size of the hashes too)
Packit 14c646
# $debugging = 1;
Packit 14c646
Packit 14c646
$hashsize = 100;
Packit 14c646
$maxhash2size = 100;
Packit 14c646
$maxarraysize = 100;
Packit 14c646
Packit 14c646
# Use Digest::MD5 if its available to make random string keys
Packit 14c646
Packit 14c646
eval { require Digest::MD5; };
Packit 14c646
$gotmd5 = !$@;
Packit 14c646
diag "Will use Digest::MD5" if $gotmd5;
Packit 14c646
Packit 14c646
# Use Data::Dumper if debugging and it is available to create an ASCII dump
Packit 14c646
Packit 14c646
if ($debugging) {
Packit 14c646
    eval { require "Data/Dumper.pm" };
Packit 14c646
    $gotdd  = !$@;
Packit 14c646
}
Packit 14c646
Packit 14c646
@fixed_strings = ("January", "February", "March", "April", "May", "June",
Packit 14c646
		  "July", "August", "September", "October", "November", "December" );
Packit 14c646
Packit 14c646
# Build some arbitrarily complex data structure starting with a top level hash
Packit 14c646
# (deeper levels contain scalars, references to hashes or references to arrays);
Packit 14c646
Packit 14c646
for (my $i = 0; $i < $hashsize; $i++) {
Packit 14c646
	my($k) = int(rand(1_000_000));
Packit 14c646
	$k = Digest::MD5::md5_hex($k) if $gotmd5 and int(rand(2));
Packit 14c646
	$a1{$k} = { key => "$k", "value" => $i };
Packit 14c646
Packit 14c646
	# A third of the elements are references to further hashes
Packit 14c646
Packit 14c646
	if (int(rand(1.5))) {
Packit 14c646
		my($hash2) = {};
Packit 14c646
		my($hash2size) = int(rand($maxhash2size));
Packit 14c646
		while ($hash2size--) {
Packit 14c646
			my($k2) = $k . $i . int(rand(100));
Packit 14c646
			$hash2->{$k2} = $fixed_strings[rand(int(@fixed_strings))];
Packit 14c646
		}
Packit 14c646
		$a1{$k}->{value} = $hash2;
Packit 14c646
	}
Packit 14c646
Packit 14c646
	# A further third are references to arrays
Packit 14c646
Packit 14c646
	elsif (int(rand(2))) {
Packit 14c646
		my($arr_ref) = [];
Packit 14c646
		my($arraysize) = int(rand($maxarraysize));
Packit 14c646
		while ($arraysize--) {
Packit 14c646
			push(@$arr_ref, $fixed_strings[rand(int(@fixed_strings))]);
Packit 14c646
		}
Packit 14c646
		$a1{$k}->{value} = $arr_ref;
Packit 14c646
	}	
Packit 14c646
}
Packit 14c646
Packit 14c646
Packit 14c646
print STDERR Data::Dumper::Dumper(\%a1) if ($verbose and $gotdd);
Packit 14c646
Packit 14c646
Packit 14c646
# Copy the hash, element by element in order of the keys
Packit 14c646
Packit 14c646
foreach $k (sort keys %a1) {
Packit 14c646
    $a2{$k} = { key => "$k", "value" => $a1{$k}->{value} };
Packit 14c646
}
Packit 14c646
Packit 14c646
# Deep clone the hash
Packit 14c646
Packit 14c646
$a3 = dclone(\%a1);
Packit 14c646
Packit 14c646
# In canonical mode the frozen representation of each of the hashes
Packit 14c646
# should be identical
Packit 14c646
Packit 14c646
$Storable::canonical = 1;
Packit 14c646
Packit 14c646
$x1 = freeze(\%a1);
Packit 14c646
$x2 = freeze(\%a2);
Packit 14c646
$x3 = freeze($a3);
Packit 14c646
Packit 14c646
cmp_ok(length $x1, '>', $hashsize);	# sanity check
Packit 14c646
is(length $x1, length $x2);		# idem
Packit 14c646
is($x1, $x2);
Packit 14c646
is($x1, $x3);
Packit 14c646
Packit 14c646
# In normal mode it is exceedingly unlikely that the frozen
Packit 14c646
# representations of all the hashes will be the same (normally the hash
Packit 14c646
# elements are frozen in the order they are stored internally,
Packit 14c646
# i.e. pseudo-randomly).
Packit 14c646
Packit 14c646
$Storable::canonical = 0;
Packit 14c646
Packit 14c646
$x1 = freeze(\%a1);
Packit 14c646
$x2 = freeze(\%a2);
Packit 14c646
$x3 = freeze($a3);
Packit 14c646
Packit 14c646
Packit 14c646
# Two out of three the same may be a coincidence, all three the same
Packit 14c646
# is much, much more unlikely.  Still it could happen, so this test
Packit 14c646
# may report a false negative.
Packit 14c646
Packit 14c646
ok(($x1 ne $x2) || ($x1 ne $x3));
Packit 14c646
Packit 14c646
Packit 14c646
# Ensure refs to "undef" values are properly shared
Packit 14c646
# Same test as in t/dclone.t to ensure the "canonical" code is also correct
Packit 14c646
Packit 14c646
my $hash;
Packit 14c646
push @{$$hash{''}}, \$$hash{a};
Packit 14c646
is($$hash{''}[0], \$$hash{a});
Packit 14c646
Packit 14c646
my $cloned = dclone(dclone($hash));
Packit 14c646
is($$cloned{''}[0], \$$cloned{a});
Packit 14c646
Packit 14c646
$$cloned{a} = "blah";
Packit 14c646
is($$cloned{''}[0], \$$cloned{a});