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