Commit | Line | Data |
---|---|---|
ffe53d21 NC |
1 | #!perl -w |
2 | use strict; | |
3 | ||
4 | use Test::More; | |
5 | use Config; | |
6 | use XS::APItest; | |
7 | use feature 'switch'; | |
0f539b13 | 8 | no warnings 'experimental::smartmatch'; |
ffe53d21 NC |
9 | use constant TRUTH => '0 but true'; |
10 | ||
11 | # Tests for grok_number. Not yet comprehensive. | |
12 | foreach my $leader ('', ' ', ' ') { | |
13 | foreach my $trailer ('', ' ', ' ') { | |
14 | foreach ((map {"0" x $_} 1 .. 12), | |
15 | (map {("0" x $_) . "1"} 0 .. 12), | |
16 | (map {"1" . ("0" x $_)} 1 .. 9), | |
17 | (map {1 << $_} 0 .. 31), | |
18 | (map {1 << $_} 0 .. 31), | |
19 | (map {0xFFFFFFFF >> $_} reverse (0 .. 31)), | |
20 | ) { | |
21 | foreach my $sign ('', '-', '+') { | |
22 | my $string = $leader . $sign . $_ . $trailer; | |
23 | my ($flags, $value) = grok_number($string); | |
24 | is($flags & IS_NUMBER_IN_UV, IS_NUMBER_IN_UV, | |
25 | "'$string' is a UV"); | |
26 | is($flags & IS_NUMBER_NEG, $sign eq '-' ? IS_NUMBER_NEG : 0, | |
27 | "'$string' sign"); | |
28 | is($value, abs $string, "value is correct"); | |
29 | } | |
30 | } | |
31 | ||
32 | { | |
33 | my (@UV, @NV); | |
34 | given ($Config{ivsize}) { | |
35 | when (4) { | |
36 | @UV = qw(429496729 4294967290 4294967294 4294967295); | |
37 | @NV = qw(4294967296 4294967297 4294967300 4294967304); | |
38 | } | |
39 | when (8) { | |
40 | @UV = qw(1844674407370955161 18446744073709551610 | |
41 | 18446744073709551614 18446744073709551615); | |
42 | @NV = qw(18446744073709551616 18446744073709551617 | |
43 | 18446744073709551620 18446744073709551624); | |
44 | } | |
45 | default { | |
46 | die "Unknown IV size $_"; | |
47 | } | |
48 | } | |
49 | foreach (@UV) { | |
50 | my $string = $leader . $_ . $trailer; | |
51 | my ($flags, $value) = grok_number($string); | |
52 | is($flags & IS_NUMBER_IN_UV, IS_NUMBER_IN_UV, | |
53 | "'$string' is a UV"); | |
54 | is($value, abs $string, "value is correct"); | |
55 | } | |
56 | foreach (@NV) { | |
57 | my $string = $leader . $_ . $trailer; | |
58 | my ($flags, $value) = grok_number($string); | |
59 | is($flags & IS_NUMBER_IN_UV, 0, "'$string' is an NV"); | |
60 | is($value, undef, "value is correct"); | |
61 | } | |
62 | } | |
63 | ||
64 | my $string = $leader . TRUTH . $trailer; | |
65 | my ($flags, $value) = grok_number($string); | |
66 | ||
67 | if ($string eq TRUTH) { | |
68 | is($flags & IS_NUMBER_IN_UV, IS_NUMBER_IN_UV, "'$string' is a UV"); | |
69 | is($value, 0); | |
70 | } else { | |
71 | is($flags, 0, "'$string' is not a number"); | |
72 | is($value, undef); | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
e222d7e2 TC |
77 | # format tests |
78 | my @groks = | |
79 | ( | |
80 | # input, in flags, out uv, out flags | |
81 | [ "1", 0, 1, IS_NUMBER_IN_UV ], | |
82 | [ "1x", 0, undef, 0 ], | |
83 | [ "1x", PERL_SCAN_TRAILING, 1, IS_NUMBER_IN_UV | IS_NUMBER_TRAILING ], | |
84 | [ "3.1", 0, 3, IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT ], | |
85 | [ "3.1a", 0, undef, 0 ], | |
86 | [ "3.1a", PERL_SCAN_TRAILING, 3, | |
87 | IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT | IS_NUMBER_TRAILING ], | |
88 | [ "3e5", 0, undef, IS_NUMBER_NOT_INT ], | |
89 | [ "3e", 0, undef, 0 ], | |
90 | [ "3e", PERL_SCAN_TRAILING, 3, IS_NUMBER_IN_UV | IS_NUMBER_TRAILING ], | |
91 | [ "3e+", 0, undef, 0 ], | |
92 | [ "3e+", PERL_SCAN_TRAILING, 3, IS_NUMBER_IN_UV | IS_NUMBER_TRAILING ], | |
93 | [ "Inf", 0, undef, | |
94 | IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT ], | |
95 | [ "In", 0, undef, 0 ], | |
a3c662ac | 96 | [ "Infin",0, undef, IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT | IS_NUMBER_TRAILING ], |
e222d7e2 TC |
97 | # this doesn't work and hasn't been needed yet |
98 | #[ "Infin",PERL_SCAN_TRAILING, undef, | |
99 | # IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT | IS_NUMBER_TRAILING ], | |
100 | [ "nan", 0, undef, IS_NUMBER_NAN | IS_NUMBER_NOT_INT ], | |
ae776a2c | 101 | # even without PERL_SCAN_TRAILING nan can have weird stuff trailing |
a3c662ac JH |
102 | [ "nanx", 0, undef, IS_NUMBER_NAN | IS_NUMBER_NOT_INT | IS_NUMBER_TRAILING ], |
103 | [ "nanx", PERL_SCAN_TRAILING, undef, IS_NUMBER_NAN | IS_NUMBER_NOT_INT | IS_NUMBER_TRAILING ], | |
e222d7e2 TC |
104 | ); |
105 | ||
c6303df5 JH |
106 | my $non_ieee_fp = ($Config{doublekind} == 9 || |
107 | $Config{doublekind} == 10 || | |
108 | $Config{doublekind} == 11); | |
109 | ||
110 | if ($non_ieee_fp) { | |
111 | @groks = grep { $_->[0] !~ /^(?:inf|nan)/i } @groks; | |
112 | } | |
113 | ||
e222d7e2 TC |
114 | for my $grok (@groks) { |
115 | my ($out_flags, $out_uv) = grok_number_flags($grok->[0], $grok->[1]); | |
116 | is($out_uv, $grok->[2], "'$grok->[0]' flags $grok->[1] - check number"); | |
117 | is($out_flags, $grok->[3], "'$grok->[0]' flags $grok->[1] - check flags"); | |
118 | } | |
119 | ||
dd52de80 JH |
120 | my $ATOU_MAX = ~0; |
121 | ||
122 | # atou tests | |
123 | my @atous = | |
124 | ( | |
125 | # [ input, endsv, out uv, out len ] | |
126 | ||
127 | # Basic cases. | |
128 | [ "0", "", 0, 1 ], | |
129 | [ "1", "", 1, 1 ], | |
130 | [ "2", "", 2, 1 ], | |
131 | [ "9", "", 9, 1 ], | |
132 | [ "12", "", 12, 2 ], | |
133 | [ "123", "", 123, 3 ], | |
134 | ||
135 | # Trailing whitespace is accepted or rejected, depending on endptr. | |
136 | [ "0 ", " ", 0, 1 ], | |
137 | [ "1 ", " ", 1, 1 ], | |
138 | [ "2 ", " ", 2, 1 ], | |
139 | [ "12 ", " ", 12, 2 ], | |
140 | ||
141 | # Trailing garbage is accepted or rejected, depending on endptr. | |
142 | [ "0x", "x", 0, 1 ], | |
143 | [ "1x", "x", 1, 1 ], | |
144 | [ "2x", "x", 2, 1 ], | |
145 | [ "12x", "x", 12, 2 ], | |
146 | ||
147 | # Leading whitespace is failure. | |
22ff3130 HS |
148 | [ " 0", undef, 0, 0 ], |
149 | [ " 1", undef, 0, 0 ], | |
150 | [ " 12", undef, 0, 0 ], | |
dd52de80 JH |
151 | |
152 | # Leading garbage is outright failure. | |
22ff3130 HS |
153 | [ "x0", undef, 0, 0 ], |
154 | [ "x1", undef, 0, 0 ], | |
155 | [ "x12", undef, 0, 0 ], | |
dd52de80 JH |
156 | |
157 | # We do not parse decimal point. | |
22ff3130 | 158 | [ "12.3", ".3", 12, 2 ], |
dd52de80 JH |
159 | |
160 | # Leading pluses or minuses are no good. | |
22ff3130 HS |
161 | [ "+12", undef, 0, 0 ], |
162 | [ "-12", undef, 0, 0 ], | |
dd52de80 | 163 | |
22ff3130 HS |
164 | # Extra leading zeros are no good. |
165 | [ "00", undef, $ATOU_MAX, 0 ], | |
166 | [ "01", undef, $ATOU_MAX, 0 ], | |
167 | [ "012", undef, $ATOU_MAX, 0 ], | |
dd52de80 JH |
168 | ); |
169 | ||
75feedba JH |
170 | # Values near overflow point. |
171 | if ($Config{uvsize} == 8) { | |
dd52de80 JH |
172 | push @atous, |
173 | ( | |
75feedba JH |
174 | # 32-bit values no problem for 64-bit. |
175 | [ "4294967293", "", 4294967293, 10, ], | |
dd52de80 JH |
176 | [ "4294967294", "", 4294967294, 10, ], |
177 | [ "4294967295", "", 4294967295, 10, ], | |
178 | [ "4294967296", "", 4294967296, 10, ], | |
75feedba | 179 | [ "4294967297", "", 4294967297, 10, ], |
dd52de80 | 180 | |
75feedba | 181 | # This is well within 64-bit. |
dd52de80 JH |
182 | [ "9999999999", "", 9999999999, 10, ], |
183 | ||
22ff3130 | 184 | # Values valid up to 64-bit, failing beyond. |
75feedba | 185 | [ "18446744073709551613", "", 18446744073709551613, 20, ], |
dd52de80 JH |
186 | [ "18446744073709551614", "", 18446744073709551614, 20, ], |
187 | [ "18446744073709551615", "", $ATOU_MAX, 20, ], | |
22ff3130 HS |
188 | [ "18446744073709551616", undef, $ATOU_MAX, 0, ], |
189 | [ "18446744073709551617", undef, $ATOU_MAX, 0, ], | |
dd52de80 | 190 | ); |
75feedba | 191 | } elsif ($Config{uvsize} == 4) { |
dd52de80 JH |
192 | push @atous, |
193 | ( | |
22ff3130 | 194 | # Values valid up to 32-bit, failing beyond. |
75feedba | 195 | [ "4294967293", "", 4294967293, 10, ], |
dd52de80 JH |
196 | [ "4294967294", "", 4294967294, 10, ], |
197 | [ "4294967295", "", $ATOU_MAX, 10, ], | |
22ff3130 HS |
198 | [ "4294967296", undef, $ATOU_MAX, 0, ], |
199 | [ "4294967297", undef, $ATOU_MAX, 0, ], | |
dd52de80 | 200 | |
75feedba | 201 | # Still beyond 32-bit. |
22ff3130 HS |
202 | [ "4999999999", undef, $ATOU_MAX, 0, ], |
203 | [ "5678901234", undef, $ATOU_MAX, 0, ], | |
204 | [ "6789012345", undef, $ATOU_MAX, 0, ], | |
205 | [ "7890123456", undef, $ATOU_MAX, 0, ], | |
206 | [ "8901234567", undef, $ATOU_MAX, 0, ], | |
207 | [ "9012345678", undef, $ATOU_MAX, 0, ], | |
208 | [ "9999999999", undef, $ATOU_MAX, 0, ], | |
209 | [ "10000000000", undef, $ATOU_MAX, 0, ], | |
210 | [ "12345678901", undef, $ATOU_MAX, 0, ], | |
dd52de80 | 211 | |
75feedba | 212 | # 64-bit values are way beyond. |
22ff3130 HS |
213 | [ "18446744073709551613", undef, $ATOU_MAX, 0, ], |
214 | [ "18446744073709551614", undef, $ATOU_MAX, 0, ], | |
215 | [ "18446744073709551615", undef, $ATOU_MAX, 0, ], | |
216 | [ "18446744073709551616", undef, $ATOU_MAX, 0, ], | |
217 | [ "18446744073709551617", undef, $ATOU_MAX, 0, ], | |
dd52de80 JH |
218 | ); |
219 | } | |
220 | ||
75feedba | 221 | # These will fail to fail once 128/256-bit systems arrive. |
dd52de80 JH |
222 | push @atous, |
223 | ( | |
22ff3130 HS |
224 | [ "23456789012345678901", undef, $ATOU_MAX, 0 ], |
225 | [ "34567890123456789012", undef, $ATOU_MAX, 0 ], | |
226 | [ "98765432109876543210", undef, $ATOU_MAX, 0 ], | |
227 | [ "98765432109876543211", undef, $ATOU_MAX, 0 ], | |
228 | [ "99999999999999999999", undef, $ATOU_MAX, 0 ], | |
dd52de80 JH |
229 | ); |
230 | ||
231 | for my $grok (@atous) { | |
232 | my $input = $grok->[0]; | |
233 | my $endsv = $grok->[1]; | |
22ff3130 HS |
234 | my $expect_ok = defined $endsv; |
235 | my $strict_ok = $expect_ok && $endsv eq ''; | |
dd52de80 | 236 | |
22ff3130 | 237 | my ($ok, $out_uv, $out_len); |
dd52de80 JH |
238 | |
239 | # First with endsv. | |
22ff3130 HS |
240 | ($ok, $out_uv, $out_len) = grok_atoUV($input, $endsv); |
241 | is($expect_ok, $ok, sprintf "'$input' expected %s, got %s", | |
242 | ($expect_ok ? 'success' : 'failure'), | |
243 | ($ok ? 'success' : 'failure'), | |
244 | ); | |
245 | if ($expect_ok) { | |
246 | is($expect_ok, $ok, "'$input' expect success"); | |
247 | is($out_uv, $grok->[2], | |
248 | "'$input' $endsv - number success (got $out_uv cf $grok->[2])"); | |
249 | ok($grok->[3] <= length $input, "'$input' $endsv - length sanity 1"); | |
250 | unless (length $grok->[1]) { | |
251 | is($out_len, $grok->[3], "'$input' $endsv - length sanity 2"); | |
252 | } # else { ... } ? | |
253 | if ($out_len) { | |
254 | is($endsv, substr($input, $out_len), | |
255 | "'$input' $endsv - length sanity 3"); | |
256 | } | |
257 | } else { | |
258 | is($expect_ok, $ok, "'$input' expect failure"); | |
259 | is(0xdeadbeef, $out_uv, "'$input' on failure expect value unchanged"); | |
75feedba | 260 | } |
dd52de80 JH |
261 | |
262 | # Then without endsv (undef == NULL). | |
22ff3130 HS |
263 | ($ok, $out_uv, $out_len) = grok_atoUV($input, undef); |
264 | if ($strict_ok) { | |
265 | is($strict_ok, $ok, "'$input' expect strict success"); | |
dd52de80 | 266 | is($out_uv, $grok->[2], |
22ff3130 HS |
267 | "'$input' $endsv - strict number success (got $out_uv cf $grok->[2])"); |
268 | } else { | |
269 | is($strict_ok, $ok, "'$input' expect strict failure"); | |
270 | is(0xdeadbeef, $out_uv, "'$input' on strict failure expect value unchanged"); | |
dd52de80 JH |
271 | } |
272 | } | |
273 | ||
ffe53d21 | 274 | done_testing(); |