1#!./perl -w 2# 3# Copyright 2002, Larry Wall. 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# I ought to keep this test easily backwards compatible to 5.004, so no 10# qr//; 11 12# This test checks downgrade behaviour on pre-5.8 perls when new 5.8 features 13# are encountered. 14 15sub BEGIN { 16 if ($ENV{PERL_CORE}){ 17 chdir('t') if -d 't'; 18 @INC = ('.', '../lib'); 19 } else { 20 unshift @INC, 't'; 21 } 22 require Config; import Config; 23 if ($ENV{PERL_CORE} and $Config{'extensions'} !~ /\bStorable\b/) { 24 print "1..0 # Skip: Storable was not built\n"; 25 exit 0; 26 } 27} 28 29use Test::More; 30use Storable qw (dclone store retrieve freeze thaw nstore nfreeze); 31use strict; 32 33my $max_uv = ~0; 34my $max_uv_m1 = ~0 ^ 1; 35# Express it in this way so as not to use any addition, as 5.6 maths would 36# do this in NVs on 64 bit machines, and we're overflowing IVs so can't use 37# use integer. 38my $max_iv_p1 = $max_uv ^ ($max_uv >> 1); 39my $lots_of_9C = do { 40 my $temp = sprintf "%#x", ~0; 41 $temp =~ s/ff/9c/g; 42 local $^W; 43 eval $temp; 44}; 45 46my $max_iv = ~0 >> 1; 47my $min_iv = do {use integer; -$max_iv-1}; # 2s complement assumption 48 49my @processes = (["dclone", \&do_clone], 50 ["freeze/thaw", \&freeze_and_thaw], 51 ["nfreeze/thaw", \&nfreeze_and_thaw], 52 ["store/retrieve", \&store_and_retrieve], 53 ["nstore/retrieve", \&nstore_and_retrieve], 54 ); 55my @numbers = 56 (# IV bounds of 8 bits 57 -1, 0, 1, -127, -128, -129, 42, 126, 127, 128, 129, 254, 255, 256, 257, 58 # IV bounds of 32 bits 59 -2147483647, -2147483648, -2147483649, 2147483646, 2147483647, 2147483648, 60 # IV bounds 61 $min_iv, do {use integer; $min_iv + 1}, do {use integer; $max_iv - 1}, 62 $max_iv, 63 # UV bounds at 32 bits 64 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFF, 0xDEADBEEF, 65 # UV bounds 66 $max_iv_p1, $max_uv_m1, $max_uv, $lots_of_9C, 67 # NV-UV conversion 68 2559831922.0, 69 ); 70 71plan tests => @processes * @numbers * 5; 72 73my $file = "integer.$$"; 74die "Temporary file '$file' already exists" if -e $file; 75 76END { while (-f $file) {unlink $file or die "Can't unlink '$file': $!" }} 77 78sub do_clone { 79 my $data = shift; 80 my $copy = eval {dclone $data}; 81 is ($@, '', 'Should be no error dcloning'); 82 ok (1, "dlcone is only 1 process, not 2"); 83 return $copy; 84} 85 86sub freeze_and_thaw { 87 my $data = shift; 88 my $frozen = eval {freeze $data}; 89 is ($@, '', 'Should be no error freezing'); 90 my $copy = eval {thaw $frozen}; 91 is ($@, '', 'Should be no error thawing'); 92 return $copy; 93} 94 95sub nfreeze_and_thaw { 96 my $data = shift; 97 my $frozen = eval {nfreeze $data}; 98 is ($@, '', 'Should be no error nfreezing'); 99 my $copy = eval {thaw $frozen}; 100 is ($@, '', 'Should be no error thawing'); 101 return $copy; 102} 103 104sub store_and_retrieve { 105 my $data = shift; 106 my $frozen = eval {store $data, $file}; 107 is ($@, '', 'Should be no error storing'); 108 my $copy = eval {retrieve $file}; 109 is ($@, '', 'Should be no error retrieving'); 110 return $copy; 111} 112 113sub nstore_and_retrieve { 114 my $data = shift; 115 my $frozen = eval {nstore $data, $file}; 116 is ($@, '', 'Should be no error storing'); 117 my $copy = eval {retrieve $file}; 118 is ($@, '', 'Should be no error retrieving'); 119 return $copy; 120} 121 122foreach (@processes) { 123 my ($process, $sub) = @$_; 124 foreach my $number (@numbers) { 125 # as $number is an alias into @numbers, we don't want any side effects of 126 # conversion macros affecting later runs, so pass a copy to Storable: 127 my $copy1 = my $copy2 = my $copy0 = $number; 128 my $copy_s = &$sub (\$copy0); 129 if (is (ref $copy_s, "SCALAR", "got back a scalar ref?")) { 130 # Test inside use integer to see if the bit pattern is identical 131 # and outside to see if the sign is right. 132 # On 5.8 we don't need this trickery anymore. 133 # We really do need 2 copies here, as conversion may have side effect 134 # bugs. In particular, I know that this happens: 135 # perl5.00503 -le '$a = "-2147483649"; $a & 0; print $a; print $a+1' 136 # -2147483649 137 # 2147483648 138 139 my $copy_s1 = my $copy_s2 = $$copy_s; 140 # On 5.8 can do this with a straight ==, due to the integer/float maths 141 # on 5.6 can't do this with 142 # my $eq = do {use integer; $copy_s1 == $copy1} && $copy_s1 == $copy1; 143 # because on builds with IV as long long it tickles bugs. 144 # (Uncomment it and the Devel::Peek line below to see the messed up 145 # state of the scalar, with PV showing the correct string for the 146 # number, and IV holding a bogus value which has been truncated to 32 bits 147 148 # So, check the bit patterns are identical, and check that the sign is the 149 # same. This works on all the versions in all the sizes. 150 # $eq = && (($copy_s1 <=> 0) == ($copy1 <=> 0)); 151 # Split this into 2 tests, to cater for 5.005_03 152 153 # Aargh. Even this doesn't work because 5.6.x sends values with (same 154 # number of decimal digits as ~0 + 1) via atof. So ^ is getting strings 155 # cast to doubles cast to integers. And that truncates low order bits. 156 # my $bit = ok (($copy_s1 ^ $copy1) == 0, "$process $copy1 (bitpattern)"); 157 158 # Oh well; at least the parser gets it right. :-) 159 my $copy_s3 = eval $copy_s1; 160 die "Was supposed to have number $copy_s3, got error $@" 161 unless defined $copy_s3; 162 my $bit = ok (($copy_s3 ^ $copy1) == 0, "$process $copy1 (bitpattern)"); 163 # This is sick. 5.005_03 survives without the IV/UV flag, and somehow 164 # gets it right, providing you don't have side effects of conversion. 165# local $TODO; 166# $TODO = "pre 5.6 doesn't have flag to distinguish IV/UV" 167# if $[ < 5.005_56 and $copy1 > $max_iv; 168 my $sign = ok (($copy_s2 <=> 0) == ($copy2 <=> 0), 169 "$process $copy1 (sign)"); 170 171 unless ($bit and $sign) { 172 printf "# Passed in %s (%#x, %i)\n# got back '%s' (%#x, %i)\n", 173 $copy1, $copy1, $copy1, $copy_s1, $copy_s1, $copy_s1; 174 # use Devel::Peek; Dump $number; Dump $copy1; Dump $copy_s1; 175 } 176 # unless ($bit) { use Devel::Peek; Dump $copy_s1; Dump $$copy_s; } 177 } else { 178 fail ("$process $copy1"); 179 fail ("$process $copy1"); 180 } 181 } 182} 183