source: trunk/essentials/dev-lang/perl/t/op/pack.t

Last change on this file was 3181, checked in by bird, 19 years ago

perl 5.8.8

File size: 45.5 KB
Line 
1#!./perl
2# FIXME - why isn't this -w clean in maint?
3
4BEGIN {
5 chdir 't' if -d 't';
6 @INC = '../lib';
7 require './test.pl';
8}
9
10# This is truth in an if statement, and could be a skip message
11my $no_endianness = $] > 5.009 ? '' :
12 "Endianness pack modifiers not available on this perl";
13my $no_signedness = $] > 5.009 ? '' :
14 "Signed/unsigned pack modifiers not available on this perl";
15
16plan tests => 13864;
17
18use strict;
19# use warnings;
20use Config;
21
22my $Is_EBCDIC = (defined $Config{ebcdic} && $Config{ebcdic} eq 'define');
23my $Perl = which_perl();
24my @valid_errors = (qr/^Invalid type '\w'/);
25
26my $ByteOrder = 'unknown';
27my $maybe_not_avail = '(?:hto[bl]e|[bl]etoh)';
28if ($no_endianness) {
29 push @valid_errors, qr/^Invalid type '[<>]'/;
30} elsif ($Config{byteorder} =~ /^1234(?:5678)?$/) {
31 $ByteOrder = 'little';
32 $maybe_not_avail = '(?:htobe|betoh)';
33}
34elsif ($Config{byteorder} =~ /^(?:8765)?4321$/) {
35 $ByteOrder = 'big';
36 $maybe_not_avail = '(?:htole|letoh)';
37}
38else {
39 push @valid_errors, qr/^Can't (?:un)?pack (?:big|little)-endian .*? on this platform/;
40}
41
42if ($no_signedness) {
43 push @valid_errors, qr/^'!' allowed only after types sSiIlLxX in (?:un)?pack/;
44}
45
46for my $size ( 16, 32, 64 ) {
47 if (defined $Config{"u${size}size"} and $Config{"u${size}size"} != ($size >> 3)) {
48 push @valid_errors, qr/^Perl_my_$maybe_not_avail$size\(\) not available/;
49 }
50}
51
52my $IsTwosComplement = pack('i', -1) eq "\xFF" x $Config{intsize};
53print "# \$IsTwosComplement = $IsTwosComplement\n";
54
55sub is_valid_error
56{
57 my $err = shift;
58
59 for my $e (@valid_errors) {
60 $err =~ $e and return 1;
61 }
62
63 return 0;
64}
65
66sub encode_list {
67 my @result = map {_qq($_)} @_;
68 if (@result == 1) {
69 return @result;
70 }
71 return '(' . join (', ', @result) . ')';
72}
73
74
75sub list_eq ($$) {
76 my ($l, $r) = @_;
77 return 0 unless @$l == @$r;
78 for my $i (0..$#$l) {
79 if (defined $l->[$i]) {
80 return 0 unless defined ($r->[$i]) && $l->[$i] eq $r->[$i];
81 } else {
82 return 0 if defined $r->[$i]
83 }
84 }
85 return 1;
86}
87
88##############################################################################
89#
90# Here starteth the tests
91#
92
93{
94 my $format = "c2 x5 C C x s d i l a6";
95 # Need the expression in here to force ary[5] to be numeric. This avoids
96 # test2 failing because ary2 goes str->numeric->str and ary doesn't.
97 my @ary = (1,-100,127,128,32767,987.654321098 / 100.0,12345,123456,
98 "abcdef");
99 my $foo = pack($format,@ary);
100 my @ary2 = unpack($format,$foo);
101
102 is($#ary, $#ary2);
103
104 my $out1=join(':',@ary);
105 my $out2=join(':',@ary2);
106 # Using long double NVs may introduce greater accuracy than wanted.
107 $out1 =~ s/:9\.87654321097999\d*:/:9.87654321098:/;
108 $out2 =~ s/:9\.87654321097999\d*:/:9.87654321098:/;
109 is($out1, $out2);
110
111 like($foo, qr/def/);
112}
113# How about counting bits?
114
115{
116 my $x;
117 is( ($x = unpack("%32B*", "\001\002\004\010\020\040\100\200\377")), 16 );
118
119 is( ($x = unpack("%32b69", "\001\002\004\010\020\040\100\200\017")), 12 );
120
121 is( ($x = unpack("%32B69", "\001\002\004\010\020\040\100\200\017")), 9 );
122}
123
124{
125 my $sum = 129; # ASCII
126 $sum = 103 if $Is_EBCDIC;
127
128 my $x;
129 is( ($x = unpack("%32B*", "Now is the time for all good blurfl")), $sum );
130
131 my $foo;
132 open(BIN, $Perl) || die "Can't open $Perl: $!\n";
133 sysread BIN, $foo, 8192;
134 close BIN;
135
136 $sum = unpack("%32b*", $foo);
137 my $longway = unpack("b*", $foo);
138 is( $sum, $longway =~ tr/1/1/ );
139}
140
141{
142 my $x;
143 is( ($x = unpack("I",pack("I", 0xFFFFFFFF))), 0xFFFFFFFF );
144}
145
146{
147 # check 'w'
148 my @x = (5,130,256,560,32000,3097152,268435455,1073741844, 2**33,
149 '4503599627365785','23728385234614992549757750638446');
150 my $x = pack('w*', @x);
151 my $y = pack 'H*', '0581028200843081fa0081bd8440ffffff7f8480808014A0808'.
152 '0800087ffffffffffdb19caefe8e1eeeea0c2e1e3e8ede1ee6e';
153
154 is($x, $y);
155
156 my @y = unpack('w*', $y);
157 my $a;
158 while ($a = pop @x) {
159 my $b = pop @y;
160 is($a, $b);
161 }
162
163 @y = unpack('w2', $x);
164
165 is(scalar(@y), 2);
166 is($y[1], 130);
167 $x = pack('w*', 5000000000); $y = '';
168 eval {
169 use Math::BigInt;
170 $y = pack('w*', Math::BigInt::->new(5000000000));
171 };
172 is($x, $y);
173
174 $x = pack 'w', ~0;
175 $y = pack 'w', (~0).'';
176 is($x, $y);
177 is(unpack ('w',$x), ~0);
178 is(unpack ('w',$y), ~0);
179
180 $x = pack 'w', ~0 - 1;
181 $y = pack 'w', (~0) - 2;
182
183 if (~0 - 1 == (~0) - 2) {
184 is($x, $y, "NV arithmetic");
185 } else {
186 isnt($x, $y, "IV/NV arithmetic");
187 }
188 cmp_ok(unpack ('w',$x), '==', ~0 - 1);
189 cmp_ok(unpack ('w',$y), '==', ~0 - 2);
190
191 # These should spot that pack 'w' is using NV, not double, on platforms
192 # where IVs are smaller than doubles, and harmlessly pass elsewhere.
193 # (tests for change 16861)
194 my $x0 = 2**54+3;
195 my $y0 = 2**54-2;
196
197 $x = pack 'w', $x0;
198 $y = pack 'w', $y0;
199
200 if ($x0 == $y0) {
201 is($x, $y, "NV arithmetic");
202 } else {
203 isnt($x, $y, "IV/NV arithmetic");
204 }
205 cmp_ok(unpack ('w',$x), '==', $x0);
206 cmp_ok(unpack ('w',$y), '==', $y0);
207}
208
209
210{
211 print "# test exceptions\n";
212 my $x;
213 eval { $x = unpack 'w', pack 'C*', 0xff, 0xff};
214 like($@, qr/^Unterminated compressed integer/);
215
216 eval { $x = unpack 'w', pack 'C*', 0xff, 0xff, 0xff, 0xff};
217 like($@, qr/^Unterminated compressed integer/);
218
219 eval { $x = unpack 'w', pack 'C*', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
220 like($@, qr/^Unterminated compressed integer/);
221
222 eval { $x = pack 'w', -1 };
223 like ($@, qr/^Cannot compress negative numbers/);
224
225 eval { $x = pack 'w', '1'x(1 + length ~0) . 'e0' };
226 like ($@, qr/^Can only compress unsigned integers/);
227
228 # Check that the warning behaviour on the modifiers !, < and > is as we
229 # expect it for this perl.
230 my $can_endian = $no_endianness ? '' : 'sSiIlLqQjJfFdDpP';
231 my $can_shriek = 'sSiIlL';
232 $can_shriek .= 'nNvV' unless $no_signedness;
233 # h and H can't do either, so act as sanity checks in blead
234 foreach my $base (split '', 'hHsSiIlLqQjJfFdDpPnNvV') {
235 foreach my $mod ('', '<', '>', '!', '<!', '>!', '!<', '!>') {
236 SKIP: {
237 # Avoid void context warnings.
238 my $a = eval {pack "$base$mod"};
239 skip "pack can't $base", 1 if $@ =~ /^Invalid type '\w'/;
240 # Which error you get when 2 would be possible seems to be emergent
241 # behaviour of pack's format parser.
242
243 my $fails_shriek = $mod =~ /!/ && index ($can_shriek, $base) == -1;
244 my $fails_endian = $mod =~ /[<>]/ && index ($can_endian, $base) == -1;
245 my $shriek_first = $mod =~ /^!/;
246
247 if ($no_endianness and ($mod eq '<!' or $mod eq '>!')) {
248 # The ! isn't seem as part of $base. Instead it's seen as a modifier
249 # on > or <
250 $fails_shriek = 1;
251 undef $fails_endian;
252 } elsif ($fails_shriek and $fails_endian) {
253 if ($shriek_first) {
254 undef $fails_endian;
255 }
256 }
257
258 if ($fails_endian) {
259 if ($no_endianness) {
260 # < and > are seen as pattern letters, not modifiers
261 like ($@, qr/^Invalid type '[<>]'/, "pack can't $base$mod");
262 } else {
263 like ($@, qr/^'[<>]' allowed only after types/,
264 "pack can't $base$mod");
265 }
266 } elsif ($fails_shriek) {
267 like ($@, qr/^'!' allowed only after types/,
268 "pack can't $base$mod");
269 } else {
270 is ($@, '', "pack can $base$mod");
271 }
272 }
273 }
274 }
275
276 SKIP: {
277 skip $no_endianness, 2*3 + 2*8 if $no_endianness;
278 for my $mod (qw( ! < > )) {
279 eval { $x = pack "a$mod", 42 };
280 like ($@, qr/^'$mod' allowed only after types \S+ in pack/);
281
282 eval { $x = unpack "a$mod", 'x'x8 };
283 like ($@, qr/^'$mod' allowed only after types \S+ in unpack/);
284 }
285
286 for my $mod (qw( <> >< !<> !>< <!> >!< <>! ><! )) {
287 eval { $x = pack "sI${mod}s", 42, 47, 11 };
288 like ($@, qr/^Can't use both '<' and '>' after type 'I' in pack/);
289
290 eval { $x = unpack "sI${mod}s", 'x'x16 };
291 like ($@, qr/^Can't use both '<' and '>' after type 'I' in unpack/);
292 }
293 }
294
295 SKIP: {
296 # Is this a stupid thing to do on VMS, VOS and other unusual platforms?
297
298 skip("-- the IEEE infinity model is unavailable in this configuration.", 1)
299 if (($^O eq 'VMS') && !defined($Config{useieee}));
300
301 skip("-- $^O has serious fp indigestion on w-packed infinities", 1)
302 if (
303 ($^O eq 'mpeix')
304 ||
305 ($^O eq 'ultrix')
306 ||
307 ($^O =~ /^svr4/ && -f "/etc/issue" && -f "/etc/.relid") # NCR MP-RAS
308 );
309
310 my $inf = eval '2**1000000';
311
312 skip("Couldn't generate infinity - got error '$@'", 1)
313 unless defined $inf and $inf == $inf / 2 and $inf + 1 == $inf;
314
315 local our $TODO;
316 $TODO = "VOS needs a fix for posix-1022 to pass this test."
317 if ($^O eq 'vos');
318
319 eval { $x = pack 'w', $inf };
320 like ($@, qr/^Cannot compress integer/, "Cannot compress integer");
321 }
322