]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*- |
2 | * BSD LICENSE | |
3 | * | |
4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * | |
11 | * * Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * * Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in | |
15 | * the documentation and/or other materials provided with the | |
16 | * distribution. | |
17 | * * Neither the name of Intel Corporation nor the names of its | |
18 | * contributors may be used to endorse or promote products derived | |
19 | * from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
25 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
27 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #include <stdio.h> | |
35 | #include <string.h> | |
36 | #include <inttypes.h> | |
37 | ||
38 | #include <rte_string_fns.h> | |
39 | ||
40 | #include <cmdline_parse.h> | |
41 | #include <cmdline_parse_num.h> | |
42 | ||
43 | #include "test_cmdline.h" | |
44 | ||
45 | struct num_unsigned_str { | |
46 | const char * str; | |
47 | uint64_t result; | |
48 | }; | |
49 | ||
50 | struct num_signed_str { | |
51 | const char * str; | |
52 | int64_t result; | |
53 | }; | |
54 | ||
55 | const struct num_unsigned_str num_valid_positive_strs[] = { | |
56 | /* decimal positive */ | |
57 | {"0", 0 }, | |
58 | {"127", INT8_MAX }, | |
59 | {"128", INT8_MAX + 1 }, | |
60 | {"255", UINT8_MAX }, | |
61 | {"256", UINT8_MAX + 1 }, | |
62 | {"32767", INT16_MAX }, | |
63 | {"32768", INT16_MAX + 1 }, | |
64 | {"65535", UINT16_MAX }, | |
65 | {"65536", UINT16_MAX + 1 }, | |
66 | {"2147483647", INT32_MAX }, | |
67 | {"2147483648", INT32_MAX + 1U }, | |
68 | {"4294967295", UINT32_MAX }, | |
69 | {"4294967296", UINT32_MAX + 1ULL }, | |
70 | {"9223372036854775807", INT64_MAX }, | |
71 | {"9223372036854775808", INT64_MAX + 1ULL}, | |
72 | {"18446744073709551615", UINT64_MAX }, | |
73 | /* hexadecimal (no leading zeroes) */ | |
74 | {"0x0", 0 }, | |
75 | {"0x7F", INT8_MAX }, | |
76 | {"0x80", INT8_MAX + 1 }, | |
77 | {"0xFF", UINT8_MAX }, | |
78 | {"0x100", UINT8_MAX + 1 }, | |
79 | {"0x7FFF", INT16_MAX }, | |
80 | {"0x8000", INT16_MAX + 1 }, | |
81 | {"0xFFFF", UINT16_MAX }, | |
82 | {"0x10000", UINT16_MAX + 1 }, | |
83 | {"0x7FFFFFFF", INT32_MAX }, | |
84 | {"0x80000000", INT32_MAX + 1U }, | |
85 | {"0xFFFFFFFF", UINT32_MAX }, | |
86 | {"0x100000000", UINT32_MAX + 1ULL }, | |
87 | {"0x7FFFFFFFFFFFFFFF", INT64_MAX }, | |
88 | {"0x8000000000000000", INT64_MAX + 1ULL}, | |
89 | {"0xFFFFFFFFFFFFFFFF", UINT64_MAX }, | |
90 | /* hexadecimal (with leading zeroes) */ | |
91 | {"0x00", 0 }, | |
92 | {"0x7F", INT8_MAX }, | |
93 | {"0x80", INT8_MAX + 1 }, | |
94 | {"0xFF", UINT8_MAX }, | |
95 | {"0x0100", UINT8_MAX + 1 }, | |
96 | {"0x7FFF", INT16_MAX }, | |
97 | {"0x8000", INT16_MAX + 1 }, | |
98 | {"0xFFFF", UINT16_MAX }, | |
99 | {"0x00010000", UINT16_MAX + 1 }, | |
100 | {"0x7FFFFFFF", INT32_MAX }, | |
101 | {"0x80000000", INT32_MAX + 1U }, | |
102 | {"0xFFFFFFFF", UINT32_MAX }, | |
103 | {"0x0000000100000000", UINT32_MAX + 1ULL }, | |
104 | {"0x7FFFFFFFFFFFFFFF", INT64_MAX }, | |
105 | {"0x8000000000000000", INT64_MAX + 1ULL}, | |
106 | {"0xFFFFFFFFFFFFFFFF", UINT64_MAX }, | |
107 | /* check all characters */ | |
108 | {"0x1234567890ABCDEF", 0x1234567890ABCDEFULL }, | |
109 | {"0x1234567890abcdef", 0x1234567890ABCDEFULL }, | |
110 | /* binary (no leading zeroes) */ | |
111 | {"0b0", 0 }, | |
112 | {"0b1111111", INT8_MAX }, | |
113 | {"0b10000000", INT8_MAX + 1 }, | |
114 | {"0b11111111", UINT8_MAX }, | |
115 | {"0b100000000", UINT8_MAX + 1 }, | |
116 | {"0b111111111111111", INT16_MAX }, | |
117 | {"0b1000000000000000", INT16_MAX + 1 }, | |
118 | {"0b1111111111111111", UINT16_MAX }, | |
119 | {"0b10000000000000000", UINT16_MAX + 1 }, | |
120 | {"0b1111111111111111111111111111111", INT32_MAX }, | |
121 | {"0b10000000000000000000000000000000", INT32_MAX + 1U }, | |
122 | {"0b11111111111111111111111111111111", UINT32_MAX }, | |
123 | {"0b100000000000000000000000000000000", UINT32_MAX + 1ULL }, | |
124 | {"0b111111111111111111111111111111111111111111111111111111111111111", | |
125 | INT64_MAX }, | |
126 | {"0b1000000000000000000000000000000000000000000000000000000000000000", | |
127 | INT64_MAX + 1ULL}, | |
128 | {"0b1111111111111111111111111111111111111111111111111111111111111111", | |
129 | UINT64_MAX }, | |
130 | /* binary (with leading zeroes) */ | |
131 | {"0b01111111", INT8_MAX }, | |
132 | {"0b0000000100000000", UINT8_MAX + 1 }, | |
133 | {"0b0111111111111111", INT16_MAX }, | |
134 | {"0b00000000000000010000000000000000", UINT16_MAX + 1 }, | |
135 | {"0b01111111111111111111111111111111", INT32_MAX }, | |
136 | {"0b0000000000000000000000000000000100000000000000000000000000000000", | |
137 | UINT32_MAX + 1ULL }, | |
138 | {"0b0111111111111111111111111111111111111111111111111111111111111111", | |
139 | INT64_MAX }, | |
140 | /* octal */ | |
141 | {"00", 0 }, | |
142 | {"0177", INT8_MAX }, | |
143 | {"0200", INT8_MAX + 1 }, | |
144 | {"0377", UINT8_MAX }, | |
145 | {"0400", UINT8_MAX + 1 }, | |
146 | {"077777", INT16_MAX }, | |
147 | {"0100000", INT16_MAX + 1 }, | |
148 | {"0177777", UINT16_MAX }, | |
149 | {"0200000", UINT16_MAX + 1 }, | |
150 | {"017777777777", INT32_MAX }, | |
151 | {"020000000000", INT32_MAX + 1U }, | |
152 | {"037777777777", UINT32_MAX }, | |
153 | {"040000000000", UINT32_MAX + 1ULL }, | |
154 | {"0777777777777777777777", INT64_MAX }, | |
155 | {"01000000000000000000000", INT64_MAX + 1ULL}, | |
156 | {"01777777777777777777777", UINT64_MAX }, | |
157 | /* check all numbers */ | |
158 | {"012345670", 012345670 }, | |
159 | {"076543210", 076543210 }, | |
160 | }; | |
161 | ||
162 | const struct num_signed_str num_valid_negative_strs[] = { | |
163 | /* deciman negative */ | |
164 | {"-128", INT8_MIN }, | |
165 | {"-129", INT8_MIN - 1 }, | |
166 | {"-32768", INT16_MIN }, | |
167 | {"-32769", INT16_MIN - 1 }, | |
168 | {"-2147483648", INT32_MIN }, | |
169 | {"-2147483649", INT32_MIN - 1LL }, | |
170 | {"-9223372036854775808", INT64_MIN }, | |
171 | }; | |
172 | ||
173 | const struct num_unsigned_str num_garbage_positive_strs[] = { | |
174 | /* valid strings with garbage on the end, should still be valid */ | |
175 | /* decimal */ | |
176 | {"9223372036854775807\0garbage", INT64_MAX }, | |
177 | {"9223372036854775807\tgarbage", INT64_MAX }, | |
178 | {"9223372036854775807\rgarbage", INT64_MAX }, | |
179 | {"9223372036854775807\ngarbage", INT64_MAX }, | |
180 | {"9223372036854775807#garbage", INT64_MAX }, | |
181 | {"9223372036854775807 garbage", INT64_MAX }, | |
182 | /* hex */ | |
183 | {"0x7FFFFFFFFFFFFFFF\0garbage", INT64_MAX }, | |
184 | {"0x7FFFFFFFFFFFFFFF\tgarbage", INT64_MAX }, | |
185 | {"0x7FFFFFFFFFFFFFFF\rgarbage", INT64_MAX }, | |
186 | {"0x7FFFFFFFFFFFFFFF\ngarbage", INT64_MAX }, | |
187 | {"0x7FFFFFFFFFFFFFFF#garbage", INT64_MAX }, | |
188 | {"0x7FFFFFFFFFFFFFFF garbage", INT64_MAX }, | |
189 | /* binary */ | |
190 | {"0b1111111111111111111111111111111\0garbage", INT32_MAX }, | |
191 | {"0b1111111111111111111111111111111\rgarbage", INT32_MAX }, | |
192 | {"0b1111111111111111111111111111111\tgarbage", INT32_MAX }, | |
193 | {"0b1111111111111111111111111111111\ngarbage", INT32_MAX }, | |
194 | {"0b1111111111111111111111111111111#garbage", INT32_MAX }, | |
195 | {"0b1111111111111111111111111111111 garbage", INT32_MAX }, | |
196 | /* octal */ | |
197 | {"01777777777777777777777\0garbage", UINT64_MAX }, | |
198 | {"01777777777777777777777\rgarbage", UINT64_MAX }, | |
199 | {"01777777777777777777777\tgarbage", UINT64_MAX }, | |
200 | {"01777777777777777777777\ngarbage", UINT64_MAX }, | |
201 | {"01777777777777777777777#garbage", UINT64_MAX }, | |
202 | {"01777777777777777777777 garbage", UINT64_MAX }, | |
203 | }; | |
204 | ||
205 | const struct num_signed_str num_garbage_negative_strs[] = { | |
206 | /* valid strings with garbage on the end, should still be valid */ | |
207 | {"-9223372036854775808\0garbage", INT64_MIN }, | |
208 | {"-9223372036854775808\rgarbage", INT64_MIN }, | |
209 | {"-9223372036854775808\tgarbage", INT64_MIN }, | |
210 | {"-9223372036854775808\ngarbage", INT64_MIN }, | |
211 | {"-9223372036854775808#garbage", INT64_MIN }, | |
212 | {"-9223372036854775808 garbage", INT64_MIN }, | |
213 | }; | |
214 | ||
215 | const char * num_invalid_strs[] = { | |
216 | "18446744073709551616", /* out of range unsigned */ | |
217 | "-9223372036854775809", /* out of range negative signed */ | |
218 | "0x10000000000000000", /* out of range hex */ | |
219 | /* out of range binary */ | |
220 | "0b10000000000000000000000000000000000000000000000000000000000000000", | |
221 | "020000000000000000000000", /* out of range octal */ | |
222 | /* wrong chars */ | |
223 | "0123456239", | |
224 | "0x1234580AGE", | |
225 | "0b0111010101g001", | |
226 | "0b01110101017001", | |
227 | /* false negative numbers */ | |
228 | "-12345F623", | |
229 | "-0x1234580A", | |
230 | "-0b0111010101", | |
231 | /* too long (128+ chars) */ | |
232 | "0b1111000011110000111100001111000011110000111100001111000011110000" | |
233 | "1111000011110000111100001111000011110000111100001111000011110000", | |
234 | "1E3", | |
235 | "0A", | |
236 | "-B", | |
237 | "+4", | |
238 | "1.23G", | |
239 | "", | |
240 | " ", | |
241 | "#", | |
242 | "\r", | |
243 | "\t", | |
244 | "\n", | |
245 | "\0", | |
246 | }; | |
247 | ||
248 | #define NUM_POSITIVE_STRS_SIZE \ | |
249 | (sizeof(num_valid_positive_strs) / sizeof(num_valid_positive_strs[0])) | |
250 | #define NUM_NEGATIVE_STRS_SIZE \ | |
251 | (sizeof(num_valid_negative_strs) / sizeof(num_valid_negative_strs[0])) | |
252 | #define NUM_POSITIVE_GARBAGE_STRS_SIZE \ | |
253 | (sizeof(num_garbage_positive_strs) / sizeof(num_garbage_positive_strs[0])) | |
254 | #define NUM_NEGATIVE_GARBAGE_STRS_SIZE \ | |
255 | (sizeof(num_garbage_negative_strs) / sizeof(num_garbage_negative_strs[0])) | |
256 | #define NUM_INVALID_STRS_SIZE \ | |
257 | (sizeof(num_invalid_strs) / sizeof(num_invalid_strs[0])) | |
258 | ||
259 | ||
260 | ||
261 | static int | |
262 | can_parse_unsigned(uint64_t expected_result, enum cmdline_numtype type) | |
263 | { | |
264 | switch (type) { | |
265 | case UINT8: | |
266 | if (expected_result > UINT8_MAX) | |
267 | return 0; | |
268 | break; | |
269 | case UINT16: | |
270 | if (expected_result > UINT16_MAX) | |
271 | return 0; | |
272 | break; | |
273 | case UINT32: | |
274 | if (expected_result > UINT32_MAX) | |
275 | return 0; | |
276 | break; | |
277 | case INT8: | |
278 | if (expected_result > INT8_MAX) | |
279 | return 0; | |
280 | break; | |
281 | case INT16: | |
282 | if (expected_result > INT16_MAX) | |
283 | return 0; | |
284 | break; | |
285 | case INT32: | |
286 | if (expected_result > INT32_MAX) | |
287 | return 0; | |
288 | break; | |
289 | case INT64: | |
290 | if (expected_result > INT64_MAX) | |
291 | return 0; | |
292 | break; | |
293 | default: | |
294 | return 1; | |
295 | } | |
296 | return 1; | |
297 | } | |
298 | ||
299 | static int | |
300 | can_parse_signed(int64_t expected_result, enum cmdline_numtype type) | |
301 | { | |
302 | switch (type) { | |
303 | case UINT8: | |
304 | if (expected_result > UINT8_MAX || expected_result < 0) | |
305 | return 0; | |
306 | break; | |
307 | case UINT16: | |
308 | if (expected_result > UINT16_MAX || expected_result < 0) | |
309 | return 0; | |
310 | break; | |
311 | case UINT32: | |
312 | if (expected_result > UINT32_MAX || expected_result < 0) | |
313 | return 0; | |
314 | break; | |
315 | case UINT64: | |
316 | if (expected_result < 0) | |
317 | return 0; | |
318 | case INT8: | |
319 | if (expected_result > INT8_MAX || expected_result < INT8_MIN) | |
320 | return 0; | |
321 | break; | |
322 | case INT16: | |
323 | if (expected_result > INT16_MAX || expected_result < INT16_MIN) | |
324 | return 0; | |
325 | break; | |
326 | case INT32: | |
327 | if (expected_result > INT32_MAX || expected_result < INT32_MIN) | |
328 | return 0; | |
329 | break; | |
330 | default: | |
331 | return 1; | |
332 | } | |
333 | return 1; | |
334 | } | |
335 | ||
336 | /* test invalid parameters */ | |
337 | int | |
338 | test_parse_num_invalid_param(void) | |
339 | { | |
340 | char buf[CMDLINE_TEST_BUFSIZE]; | |
341 | uint32_t result; | |
342 | cmdline_parse_token_num_t token; | |
343 | int ret = 0; | |
344 | ||
345 | /* set up a token */ | |
346 | token.num_data.type = UINT32; | |
347 | ||
348 | /* copy string to buffer */ | |
349 | snprintf(buf, sizeof(buf), "%s", | |
350 | num_valid_positive_strs[0].str); | |
351 | ||
352 | /* try all null */ | |
353 | ret = cmdline_parse_num(NULL, NULL, NULL, 0); | |
354 | if (ret != -1) { | |
355 | printf("Error: parser accepted null parameters!\n"); | |
356 | return -1; | |
357 | } | |
358 | ||
359 | /* try null token */ | |
360 | ret = cmdline_parse_num(NULL, buf, (void*)&result, sizeof(result)); | |
361 | if (ret != -1) { | |
362 | printf("Error: parser accepted null token!\n"); | |
363 | return -1; | |
364 | } | |
365 | ||
366 | /* try null buf */ | |
367 | ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, NULL, | |
368 | (void*)&result, sizeof(result)); | |
369 | if (ret != -1) { | |
370 | printf("Error: parser accepted null string!\n"); | |
371 | return -1; | |
372 | } | |
373 | ||
374 | /* try null result */ | |
375 | ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, buf, | |
376 | NULL, 0); | |
377 | if (ret == -1) { | |
378 | printf("Error: parser rejected null result!\n"); | |
379 | return -1; | |
380 | } | |
381 | ||
382 | /* test help function */ | |
383 | memset(&buf, 0, sizeof(buf)); | |
384 | ||
385 | /* try all null */ | |
386 | ret = cmdline_get_help_num(NULL, NULL, 0); | |
387 | if (ret != -1) { | |
388 | printf("Error: help function accepted null parameters!\n"); | |
389 | return -1; | |
390 | } | |
391 | ||
392 | /* try null token */ | |
393 | ret = cmdline_get_help_num(NULL, buf, sizeof(buf)); | |
394 | if (ret != -1) { | |
395 | printf("Error: help function accepted null token!\n"); | |
396 | return -1; | |
397 | } | |
398 | ||
399 | /* coverage! */ | |
400 | ret = cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, buf, sizeof(buf)); | |
401 | if (ret < 0) { | |
402 | printf("Error: help function failed with valid parameters!\n"); | |
403 | return -1; | |
404 | } | |
405 | ||
406 | return 0; | |
407 | } | |
408 | /* test valid parameters but invalid data */ | |
409 | int | |
410 | test_parse_num_invalid_data(void) | |
411 | { | |
412 | enum cmdline_numtype type; | |
413 | int ret = 0; | |
414 | unsigned i; | |
415 | char buf[CMDLINE_TEST_BUFSIZE]; | |
416 | uint64_t result; /* pick largest buffer */ | |
417 | cmdline_parse_token_num_t token; | |
418 | ||
419 | /* cycle through all possible parsed types */ | |
420 | for (type = UINT8; type <= INT64; type++) { | |
421 | token.num_data.type = type; | |
422 | ||
423 | /* test full strings */ | |
424 | for (i = 0; i < NUM_INVALID_STRS_SIZE; i++) { | |
425 | ||
426 | memset(&result, 0, sizeof(uint64_t)); | |
427 | memset(&buf, 0, sizeof(buf)); | |
428 | ||
429 | ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, | |
430 | num_invalid_strs[i], (void*)&result, sizeof(result)); | |
431 | if (ret != -1) { | |
432 | /* get some info about what we are trying to parse */ | |
433 | cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, | |
434 | buf, sizeof(buf)); | |
435 | ||
436 | printf("Error: parsing %s as %s succeeded!\n", | |
437 | num_invalid_strs[i], buf); | |
438 | return -1; | |
439 | } | |
440 | } | |
441 | } | |
442 | return 0; | |
443 | } | |
444 | ||
445 | /* test valid parameters and data */ | |
446 | int | |
447 | test_parse_num_valid(void) | |
448 | { | |
449 | int ret = 0; | |
450 | enum cmdline_numtype type; | |
451 | unsigned i; | |
452 | char buf[CMDLINE_TEST_BUFSIZE]; | |
453 | uint64_t result; | |
454 | cmdline_parse_token_num_t token; | |
455 | ||
456 | /** valid strings **/ | |
457 | ||
458 | /* cycle through all possible parsed types */ | |
459 | for (type = UINT8; type <= INT64; type++) { | |
460 | token.num_data.type = type; | |
461 | ||
462 | /* test positive strings */ | |
463 | for (i = 0; i < NUM_POSITIVE_STRS_SIZE; i++) { | |
464 | result = 0; | |
465 | memset(&buf, 0, sizeof(buf)); | |
466 | ||
467 | cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, | |
468 | buf, sizeof(buf)); | |
469 | ||
470 | ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, | |
471 | num_valid_positive_strs[i].str, | |
472 | (void*)&result, sizeof(result)); | |
473 | ||
474 | /* if it should have passed but didn't, or if it should have failed but didn't */ | |
475 | if ((ret < 0) == (can_parse_unsigned(num_valid_positive_strs[i].result, type) > 0)) { | |
476 | printf("Error: parser behaves unexpectedly when parsing %s as %s!\n", | |
477 | num_valid_positive_strs[i].str, buf); | |
478 | return -1; | |
479 | } | |
480 | /* check if result matches what it should have matched | |
481 | * since unsigned numbers don't care about number of bits, we can just convert | |
482 | * everything to uint64_t without any worries. */ | |
483 | if (ret > 0 && num_valid_positive_strs[i].result != result) { | |
484 | printf("Error: parsing %s as %s failed: result mismatch!\n", | |
485 | num_valid_positive_strs[i].str, buf); | |
486 | return -1; | |
487 | } | |
488 | } | |
489 | ||
490 | /* test negative strings */ | |
491 | for (i = 0; i < NUM_NEGATIVE_STRS_SIZE; i++) { | |
492 | result = 0; | |
493 | memset(&buf, 0, sizeof(buf)); | |
494 | ||
495 | cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, | |
496 | buf, sizeof(buf)); | |
497 | ||
498 | ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, | |
499 | num_valid_negative_strs[i].str, | |
500 | (void*)&result, sizeof(result)); | |
501 | ||
502 | /* if it should have passed but didn't, or if it should have failed but didn't */ | |
503 | if ((ret < 0) == (can_parse_signed(num_valid_negative_strs[i].result, type) > 0)) { | |
504 | printf("Error: parser behaves unexpectedly when parsing %s as %s!\n", | |
505 | num_valid_negative_strs[i].str, buf); | |
506 | return -1; | |
507 | } | |
508 | /* check if result matches what it should have matched | |
509 | * the result is signed in this case, so we have to account for that */ | |
510 | if (ret > 0) { | |
511 | /* detect negative */ | |
512 | switch (type) { | |
513 | case INT8: | |
514 | result = (int8_t) result; | |
515 | break; | |
516 | case INT16: | |
517 | result = (int16_t) result; | |
518 | break; | |
519 | case INT32: | |
520 | result = (int32_t) result; | |
521 | break; | |
522 | default: | |
523 | break; | |
524 | } | |
525 | if (num_valid_negative_strs[i].result == (int64_t) result) | |
526 | continue; | |
527 | printf("Error: parsing %s as %s failed: result mismatch!\n", | |
528 | num_valid_negative_strs[i].str, buf); | |
529 | return -1; | |
530 | } | |
531 | } | |
532 | } | |
533 | ||
534 | /** garbage strings **/ | |
535 | ||
536 | /* cycle through all possible parsed types */ | |
537 | for (type = UINT8; type <= INT64; type++) { | |
538 | token.num_data.type = type; | |
539 | ||
540 | /* test positive garbage strings */ | |
541 | for (i = 0; i < NUM_POSITIVE_GARBAGE_STRS_SIZE; i++) { | |
542 | result = 0; | |
543 | memset(&buf, 0, sizeof(buf)); | |
544 | ||
545 | cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, | |
546 | buf, sizeof(buf)); | |
547 | ||
548 | ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, | |
549 | num_garbage_positive_strs[i].str, | |
550 | (void*)&result, sizeof(result)); | |
551 | ||
552 | /* if it should have passed but didn't, or if it should have failed but didn't */ | |
553 | if ((ret < 0) == (can_parse_unsigned(num_garbage_positive_strs[i].result, type) > 0)) { | |
554 | printf("Error: parser behaves unexpectedly when parsing %s as %s!\n", | |
555 | num_garbage_positive_strs[i].str, buf); | |
556 | return -1; | |
557 | } | |
558 | /* check if result matches what it should have matched | |
559 | * since unsigned numbers don't care about number of bits, we can just convert | |
560 | * everything to uint64_t without any worries. */ | |
561 | if (ret > 0 && num_garbage_positive_strs[i].result != result) { | |
562 | printf("Error: parsing %s as %s failed: result mismatch!\n", | |
563 | num_garbage_positive_strs[i].str, buf); | |
564 | return -1; | |
565 | } | |
566 | } | |
567 | ||
568 | /* test negative strings */ | |
569 | for (i = 0; i < NUM_NEGATIVE_GARBAGE_STRS_SIZE; i++) { | |
570 | result = 0; | |
571 | memset(&buf, 0, sizeof(buf)); | |
572 | ||
573 | cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, | |
574 | buf, sizeof(buf)); | |
575 | ||
576 | ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, | |
577 | num_garbage_negative_strs[i].str, | |
578 | (void*)&result, sizeof(result)); | |
579 | ||
580 | /* if it should have passed but didn't, or if it should have failed but didn't */ | |
581 | if ((ret < 0) == (can_parse_signed(num_garbage_negative_strs[i].result, type) > 0)) { | |
582 | printf("Error: parser behaves unexpectedly when parsing %s as %s!\n", | |
583 | num_garbage_negative_strs[i].str, buf); | |
584 | return -1; | |
585 | } | |
586 | /* check if result matches what it should have matched | |
587 | * the result is signed in this case, so we have to account for that */ | |
588 | if (ret > 0) { | |
589 | /* detect negative */ | |
590 | switch (type) { | |
591 | case INT8: | |
592 | if (result & (INT8_MAX + 1)) | |
593 | result |= 0xFFFFFFFFFFFFFF00ULL; | |
594 | break; | |
595 | case INT16: | |
596 | if (result & (INT16_MAX + 1)) | |
597 | result |= 0xFFFFFFFFFFFF0000ULL; | |
598 | break; | |
599 | case INT32: | |
600 | if (result & (INT32_MAX + 1ULL)) | |
601 | result |= 0xFFFFFFFF00000000ULL; | |
602 | break; | |
603 | default: | |
604 | break; | |
605 | } | |
606 | if (num_garbage_negative_strs[i].result == (int64_t) result) | |
607 | continue; | |
608 | printf("Error: parsing %s as %s failed: result mismatch!\n", | |
609 | num_garbage_negative_strs[i].str, buf); | |
610 | return -1; | |
611 | } | |
612 | } | |
613 | } | |
614 | ||
615 | memset(&buf, 0, sizeof(buf)); | |
616 | ||
617 | /* coverage! */ | |
618 | cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, | |
619 | buf, sizeof(buf)); | |
620 | ||
621 | return 0; | |
622 | } |