This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
7085d360eea389327662523d24dd15496b00c289
[perl5.git] / dist / Storable / t / canonical.t
1 #!./perl
2 #
3 #  Copyright (c) 1995-2000, Raphael Manfredi
4 #  
5 #  You may redistribute only under the same terms as Perl 5, as specified
6 #  in the README file that comes with the distribution.
7 #  
8
9 sub BEGIN {
10     unshift @INC, 't';
11     unshift @INC, 't/compat' if $] < 5.006002;
12     require Config; import Config;
13     if ($ENV{PERL_CORE} and $Config{'extensions'} !~ /\bStorable\b/) {
14         print "1..0 # Skip: Storable was not built\n";
15         exit 0;
16     }
17 }
18
19
20 use Storable qw(freeze thaw dclone);
21 use vars qw($debugging $verbose);
22
23 use Test::More tests => 8;
24
25 # Uncomment the following line to get a dump of the constructed data structure
26 # (you may want to reduce the size of the hashes too)
27 # $debugging = 1;
28
29 $hashsize = 100;
30 $maxhash2size = 100;
31 $maxarraysize = 100;
32
33 # Use MD5 if its available to make random string keys
34
35 eval { require "MD5.pm" };
36 $gotmd5 = !$@;
37
38 # Use Data::Dumper if debugging and it is available to create an ASCII dump
39
40 if ($debugging) {
41     eval { require "Data/Dumper.pm" };
42     $gotdd  = !$@;
43 }
44
45 @fixed_strings = ("January", "February", "March", "April", "May", "June",
46                   "July", "August", "September", "October", "November", "December" );
47
48 # Build some arbitrarily complex data structure starting with a top level hash
49 # (deeper levels contain scalars, references to hashes or references to arrays);
50
51 for (my $i = 0; $i < $hashsize; $i++) {
52         my($k) = int(rand(1_000_000));
53         $k = MD5->hexhash($k) if $gotmd5 and int(rand(2));
54         $a1{$k} = { key => "$k", "value" => $i };
55
56         # A third of the elements are references to further hashes
57
58         if (int(rand(1.5))) {
59                 my($hash2) = {};
60                 my($hash2size) = int(rand($maxhash2size));
61                 while ($hash2size--) {
62                         my($k2) = $k . $i . int(rand(100));
63                         $hash2->{$k2} = $fixed_strings[rand(int(@fixed_strings))];
64                 }
65                 $a1{$k}->{value} = $hash2;
66         }
67
68         # A further third are references to arrays
69
70         elsif (int(rand(2))) {
71                 my($arr_ref) = [];
72                 my($arraysize) = int(rand($maxarraysize));
73                 while ($arraysize--) {
74                         push(@$arr_ref, $fixed_strings[rand(int(@fixed_strings))]);
75                 }
76                 $a1{$k}->{value} = $arr_ref;
77         }       
78 }
79
80
81 print STDERR Data::Dumper::Dumper(\%a1) if ($verbose and $gotdd);
82
83
84 # Copy the hash, element by element in order of the keys
85
86 foreach $k (sort keys %a1) {
87     $a2{$k} = { key => "$k", "value" => $a1{$k}->{value} };
88 }
89
90 # Deep clone the hash
91
92 $a3 = dclone(\%a1);
93
94 # In canonical mode the frozen representation of each of the hashes
95 # should be identical
96
97 $Storable::canonical = 1;
98
99 $x1 = freeze(\%a1);
100 $x2 = freeze(\%a2);
101 $x3 = freeze($a3);
102
103 cmp_ok(length $x1, '>', $hashsize);     # sanity check
104 is(length $x1, length $x2);             # idem
105 is($x1, $x2);
106 is($x1, $x3);
107
108 # In normal mode it is exceedingly unlikely that the frozen
109 # representations of all the hashes will be the same (normally the hash
110 # elements are frozen in the order they are stored internally,
111 # i.e. pseudo-randomly).
112
113 $Storable::canonical = 0;
114
115 $x1 = freeze(\%a1);
116 $x2 = freeze(\%a2);
117 $x3 = freeze($a3);
118
119
120 # Two out of three the same may be a coincidence, all three the same
121 # is much, much more unlikely.  Still it could happen, so this test
122 # may report a false negative.
123
124 ok(($x1 ne $x2) || ($x1 ne $x3));
125
126
127 # Ensure refs to "undef" values are properly shared
128 # Same test as in t/dclone.t to ensure the "canonical" code is also correct
129
130 my $hash;
131 push @{$$hash{''}}, \$$hash{a};
132 is($$hash{''}[0], \$$hash{a});
133
134 my $cloned = dclone(dclone($hash));
135 is($$cloned{''}[0], \$$cloned{a});
136
137 $$cloned{a} = "blah";
138 is($$cloned{''}[0], \$$cloned{a});