v / vlib / strconv / atoi_test.v
447 lines · 407 sloc · 11.69 KB · 5c993bf8e8cde97fe82c6d6eec4befeb1527bdac
Raw
1import strconv
2
3struct StrInt { // test struct
4 str_value string
5 int_value int
6}
7
8// test what should be caught by atoi_common_check
9fn test_common_check() {
10 // Parsing of these strings should fail on all types.
11 ko := [
12 '', // Empty string
13 '-', // Only sign
14 '+', // Only sign
15 '_', // Only Underscore
16 '_10', // Start with underscore
17 '+_10', // Start with underscore after sign.
18 '-_16', // Start with underscore after sign.
19 '123_', // End with underscore
20 ]
21
22 for v in ko {
23 if r := strconv.atoi(v) {
24 // These conversions should fail so force assertion !
25 assert false, 'The string "${v}" should not succeed or be considered as valid ${r}).'
26 } else {
27 // println('Parsing fails as it should for : "${v}')
28 assert true
29 }
30 }
31}
32
33// Test things accepted, and rejected in atoi_common function.
34fn test_atoi_common() {
35 // Parsing of theses value should succeed on all types.
36 ok := [
37 StrInt{'1', 1},
38 StrInt{'-1', -1},
39 StrInt{'0', 0},
40 StrInt{'+0', 0},
41 StrInt{'-0', 0},
42 StrInt{'-0_00', 0},
43 StrInt{'+0_00', 0},
44 StrInt{'+1', 1},
45 StrInt{'+123', 123},
46 StrInt{'-1_2_1', -121},
47 StrInt{'00000006', 6},
48 StrInt{'0_0_0_0_0_0_0_6', 6},
49 ]
50
51 // Check that extracted int value matches its string.
52 for v in ok {
53 // println('Parsing ${v.str_value} should equals ${v.int_value}')
54 assert strconv.atoi(v.str_value)! == v.int_value
55 }
56
57 ko := [// Parsing of these strings should fail on all types.
58 '-3__1', // Two consecutives underscore.
59 '-3_1A', // Non radix 10 char.
60 'A42', // Non radix 10 char.
61 ]
62
63 for v in ko {
64 if r := strconv.atoi(v) {
65 // These conversions should fail so force assertion !
66 assert false, 'The string ${v} int extraction should not succeed or be considered as valid ${r}).'
67 } else {
68 // println('Parsing fails as it should for : "${v}')
69 assert true
70 }
71 }
72}
73
74// performs numeric (bounds) tests over int type.
75fn test_atoi() {
76 ok := [
77 StrInt{'1', 1},
78 StrInt{'-1', -1},
79 StrInt{'0', 0},
80 StrInt{'+3_14159', 314159},
81 StrInt{'-1_00_1', -1001},
82 StrInt{'-1_024', -1024},
83 StrInt{'123_456_789', 123456789},
84 StrInt{'00000006', 6},
85 StrInt{'0_0_0_0_0_0_0_6', 6},
86 StrInt{'2147483647', max_i32},
87 StrInt{'-2147483648', min_i32},
88 ]
89
90 // Check that extracted int value matches its string.
91 for v in ok {
92 // println('Parsing ${v.str_value} should equals ${v.int_value}')
93 assert strconv.atoi(v.str_value)! == v.int_value
94 }
95
96 // Parsing of these values should fail !
97 ko := [
98 '-2147483649', // 32bits underflow by 1.
99 '+2147483648', // 32 bit overflow by 1.
100 '+3147483648', // 32 bit overflow by a lot.
101 '-2147244836470', // Large underflow.
102 '+86842255899621148766244',
103 ]
104
105 for v in ko {
106 if r := strconv.atoi(v) {
107 // These conversions should fail so force assertion !
108 assert false, 'The string ${v} int extraction should not succeed or be considered as valid ${r}).'
109 } else {
110 // println('Parsing fails as it should for : "${v}')
111 assert true
112 }
113 }
114}
115
116// performs numeric (bounds) tests over i8 type.
117fn test_atoi8() {
118 struct StrI8 { // Inner test struct
119 str_value string
120 int_value i8
121 }
122
123 ok := [
124 StrI8{'0', 0}, // All kind of zeroes
125 StrI8{'+0', 0},
126 StrI8{'-0', 0},
127 StrI8{'-0_00', 0},
128 StrI8{'+0_00', 0},
129 StrI8{'1', 1},
130 StrI8{'+1', 1},
131 StrI8{'-1', -1},
132 StrI8{'+123', 123},
133 StrI8{'-1_2_1', -121},
134 StrI8{'0_0_0_0_0_0_0_6', 6},
135 StrI8{'127', max_i8},
136 StrI8{'-128', min_i8},
137 ]
138
139 // Check that extracted int value matches its string.
140 for v in ok {
141 // println('Parsing ${v.str_value} should equals ${v.int_value}')
142 assert strconv.atoi8(v.str_value)! == v.int_value
143 }
144
145 // Parsing of these values should fail !
146 ko := [
147 '-129', // i8 bits underflow by 1.
148 '+128', // i8 bit overflow by 1.
149 '+256', // i8 overflow with value equal to max u8.
150 '+3147483648', // i8 bit overflow by a lot.
151 '-4836470', // Large i8 underflow.
152 ]
153
154 for v in ko {
155 if r := strconv.atoi8(v) {
156 // These conversions should fail so force assertion !
157 assert false, 'The string ${v} int extraction should not succeed or be considered as valid ${r}).'
158 } else {
159 // println('Parsing fails as it should for : "${v}')
160 assert true
161 }
162 }
163}
164
165// performs numeric (bounds) tests over i16 type.
166fn test_atoi16() {
167 struct StrI16 { // Inner test struct
168 str_value string
169 int_value i16
170 }
171
172 ok := [
173 StrI16{'0', 0}, // All kind of zeroes
174 StrI16{'+0', 0},
175 StrI16{'-0', 0},
176 StrI16{'-0_00', 0},
177 StrI16{'+0_00', 0},
178 StrI16{'1', 1},
179 StrI16{'+1', 1},
180 StrI16{'-1', -1},
181 StrI16{'+123', 123},
182 StrI16{'-1_2_1', -121},
183 StrI16{'0_0_0_0_0_0_0_6', 6},
184 StrI16{'32767', max_i16},
185 StrI16{'-32768', min_i16},
186 ]
187
188 // Check that extracted int value matches its string.
189 for v in ok {
190 // println('Parsing ${v.str_value} should equals ${v.int_value}')
191 assert strconv.atoi16(v.str_value)! == v.int_value
192 }
193
194 // Parsing of these values should fail !
195 ko := [
196 '-32769', // i16 bits underflow by 1.
197 '+32768', // i16 bit overflow by 1.
198 '+45_000', // i16 bit overflow by a lot.
199 '65536', // i16 overflow with value equal to u16 max.
200 '-483_647_909', // Large i16 underflow.
201 ]
202
203 for v in ko {
204 if r := strconv.atoi16(v) {
205 // These conversions should fail so force assertion !
206 assert false, 'The string ${v} int extraction should not succeed or be considered as valid ${r}).'
207 } else {
208 // println('Parsing fails as it should for : "${v}')
209 assert true
210 }
211 }
212}
213
214// performs numeric (bounds) tests over i32 type. This test is redundant with atoi
215// which performs same on int (actually 32bits). In the future, int COULD be mapped
216// on arch with (e.g 64bits). That's why this test exists.
217fn test_atoi32() {
218 struct StrI32 { // Inner test struct
219 str_value string
220 int_value i32
221 }
222
223 ok := [
224 StrI32{'0', 0}, // All kind of zeroes
225 StrI32{'+0', 0},
226 StrI32{'-0', 0},
227 StrI32{'-0_00', 0},
228 StrI32{'+0_00', 0},
229 StrI32{'1', 1},
230 StrI32{'+1', 1},
231 StrI32{'-1', -1},
232 StrI32{'+123', 123},
233 StrI32{'-1_2_1', -121},
234 StrI32{'0_0_0_0_0_0_0_6', 6},
235 StrI32{'2147483647', max_i32},
236 StrI32{'-2147483648', min_i32},
237 ]
238
239 // Check that extracted int value matches its string.
240 for v in ok {
241 // println('Parsing ${v.str_value} should equals ${v.int_value}')
242 assert strconv.atoi32(v.str_value)! == v.int_value
243 }
244
245 // Parsing of these values should fail !
246 ko := [
247 '-2147483649', // i32 bits underflow by 1.
248 '+2147483648', // i32 bit overflow by 1.
249 '+4294967295', // Large Overflow but equal to u32 max.
250 '-483_647_909_912_754', // Large i32 underflow.
251 ]
252
253 for v in ko {
254 if r := strconv.atoi32(v) {
255 // These conversions should fail so force assertion !
256 assert false, 'The string ${v} int extraction should not succeed or be considered as valid ${r}).'
257 } else {
258 // println('Parsing fails as it should for : "${v}')
259 assert true
260 }
261 }
262}
263
264fn test_atoi64() {
265 struct StrI64 { // Inner test struct
266 str_value string
267 int_value i64
268 }
269
270 ok := [
271 StrI64{'0', 0}, // All kind of zeroes
272 StrI64{'+0', 0},
273 StrI64{'-0', 0},
274 StrI64{'-0_00', 0},
275 StrI64{'+0_00', 0},
276 StrI64{'1', 1},
277 StrI64{'+1', 1},
278 StrI64{'-1', -1},
279 StrI64{'+123', 123},
280 StrI64{'-1_2_1', -121},
281 StrI64{'0_0_0_0_0_0_0_6', 6},
282 StrI64{'9223372036854775807', max_i64},
283 StrI64{'-9223372036854775808', min_i64},
284 ]
285
286 // Check that extracted int value matches its string.
287 for v in ok {
288 // println('Parsing ${v.str_value} should equals ${v.int_value}')
289 assert strconv.atoi64(v.str_value)! == v.int_value
290 }
291
292 // Parsing of these values should fail !
293 ko := [
294 '-9223372036854775809', // i64 bits underflow by 1.
295 '+9223372036854775808', // i64 bit overflow by 1.
296 '+18446744073709551615', // Large Overflow but equal to u64 max.
297 '-483647909912754123456789', // Large i64 underflow.
298 ]
299
300 for v in ko {
301 if r := strconv.atoi64(v) {
302 // These conversions should fail so force assertion !
303 assert false, 'The string ${v} int extraction should not succeed or be considered as valid ${r}).'
304 } else {
305 // println('Parsing fails as it should for : "${v}')
306 assert true
307 }
308 }
309}
310
311fn test_parse_int() {
312 // symbols coverage
313 assert strconv.parse_int('1234567890', 10, 32)! == 1234567890
314 assert strconv.parse_int('19aAbBcCdDeEfF', 16, 64)! == 0x19aAbBcCdDeEfF
315 // Different bases
316 assert strconv.parse_int('16', 16, 0)! == 0x16
317 assert strconv.parse_int('16', 8, 0)! == 0o16
318 assert strconv.parse_int('11', 2, 0)! == 3
319 // Different bit sizes
320 assert strconv.parse_int('127', 10, 8)! == 127
321 assert strconv.parse_int('128', 10, 8)! == 127
322 assert strconv.parse_int('32767', 10, 16)! == 32767
323 assert strconv.parse_int('32768', 10, 16)! == 32767
324 assert strconv.parse_int('2147483647', 10, 32)! == 2147483647
325 assert strconv.parse_int('2147483648', 10, 32)! == 2147483647
326 assert strconv.parse_int('9223372036854775807', 10, 64)! == 9223372036854775807
327 assert strconv.parse_int('9223372036854775808', 10, 64)! == 9223372036854775807
328 assert strconv.parse_int('baobab', 36, 64)! == 683058467
329 // Invalid bit sizes
330 if x := strconv.parse_int('123', 10, -1) {
331 println(x)
332 assert false
333 } else {
334 assert true
335 }
336 if x := strconv.parse_int('123', 10, 65) {
337 println(x)
338 assert false
339 } else {
340 assert true
341 }
342}
343
344fn test_common_parse_int_error_on_high_digit() {
345 assert strconv.common_parse_int('9223372036854775808', 0, 64, false, true) or { 1 } == 1
346 assert strconv.common_parse_int('-9223372036854775809', 0, 64, false, true) or { 1 } == 1
347 assert strconv.common_parse_int('9223372036854775808', 0, 64, false, false) or { 1 } == max_i64
348 assert strconv.common_parse_int('-9223372036854775809', 0, 64, false, false) or { 1 } == min_i64
349}
350
351fn test_common_parse_uint2() {
352 mut result, mut error := strconv.common_parse_uint2('1', 10, 8)
353 assert result == 1
354 assert error == 0
355 result, error = strconv.common_parse_uint2('123', 10, 8)
356 assert result == 123
357 assert error == 0
358 result, error = strconv.common_parse_uint2('123', 10, 65)
359 assert result == 0
360 assert error == -2
361 result, error = strconv.common_parse_uint2('123', 10, -1)
362 assert result == 0
363 assert error == -2
364 result, error = strconv.common_parse_uint2('', 10, 8)
365 assert result == 0
366 assert error == 1
367 result, error = strconv.common_parse_uint2('1a', 10, 8)
368 assert result == 1
369 assert error == 2
370 result, error = strconv.common_parse_uint2('12a', 10, 8)
371 assert result == 12
372 assert error == 3
373 result, error = strconv.common_parse_uint2('123a', 10, 8)
374 assert result == 123
375 assert error == 4
376}
377
378fn test_common_parse_uint2_fail() {
379 mut ascii_characters := [' ', '!', '"', '#', '\$', '%', '&', "'", '(', ')', '*', '+', ',',
380 '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|',
381 '}', '~']
382 mut special_characters := [':', ';', '<', '=', '>', '?', '@', 'X', 'Y', 'Z', '[', '\\', ']',
383 '^', '_', '`']
384
385 num0, err0 := strconv.common_parse_uint2('1Ab', 16, 32)
386 assert num0 == 427
387 assert err0 == 0
388
389 for ch in ascii_characters {
390 // println("ch: [${ch}]")
391 txt_str := '${ch[0]:c}12Ab'
392 num, err := strconv.common_parse_uint2(txt_str, 16, 32)
393 assert err != 0
394 }
395
396 for ch in special_characters {
397 // println("ch: [${ch}]")
398 txt_str := '${ch[0]:c}12Ab'
399 num, err := strconv.common_parse_uint2(txt_str, 16, 32)
400 assert err != 0
401 }
402}
403
404fn test_common_parse_uint2_compatibility() {
405 test_list := [
406 '1234,1234',
407 '1_234,1234',
408 '1_2_34,1234',
409 '_12__34,1',
410 '12__34,1',
411 '_1234,1',
412 '1234_,1',
413 '0x1234,4660',
414 '0x_1234,4660',
415 '0x1_234,4660',
416 '0x1_2_3_4,4660',
417 '0_x1234,1',
418 '0x1234_,1',
419 '0o1234,668',
420 '0o_1234,668',
421 '0o1_234,668',
422 '0o1_2_3_4,668',
423 '0_o1234,1',
424 '0o1234_,1',
425 '0b111,7',
426 '0b_111,7',
427 '0b1_11,7',
428 '0b1_1_1,7',
429 '0_b111,1',
430 '0b111_,1',
431 '0xa,10',
432 '0xA,10',
433 '0xf,15',
434 '0xf,15',
435 '0_xf,1',
436 '0x_0_0_f_,1',
437 '0x_0_0__f,1',
438 '0x_0_0_f,15',
439 ]
440
441 for tst in test_list {
442 query := tst.split(',')
443 mut a0 := strconv.common_parse_uint(query[0], 0, 32, true, true) or { 1 }
444 // println("${a0} => ${query[1]}")
445 assert a0.str() == query[1]
446 }
447}
448