mbuf: add a copy routine
[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 #define NUM_POSITIVE_STRS_SIZE \
220         (sizeof(num_valid_positive_strs) / sizeof(num_valid_positive_strs[0]))
221 #define NUM_NEGATIVE_STRS_SIZE \
222         (sizeof(num_valid_negative_strs) / sizeof(num_valid_negative_strs[0]))
223 #define NUM_POSITIVE_GARBAGE_STRS_SIZE \
224         (sizeof(num_garbage_positive_strs) / sizeof(num_garbage_positive_strs[0]))
225 #define NUM_NEGATIVE_GARBAGE_STRS_SIZE \
226         (sizeof(num_garbage_negative_strs) / sizeof(num_garbage_negative_strs[0]))
227 #define NUM_INVALID_STRS_SIZE \
228         (sizeof(num_invalid_strs) / sizeof(num_invalid_strs[0]))
229
230
231
232 static int
233 can_parse_unsigned(uint64_t expected_result, enum cmdline_numtype type)
234 {
235         switch (type) {
236         case UINT8:
237                 if (expected_result > UINT8_MAX)
238                         return 0;
239                 break;
240         case UINT16:
241                 if (expected_result > UINT16_MAX)
242                         return 0;
243                 break;
244         case UINT32:
245                 if (expected_result > UINT32_MAX)
246                         return 0;
247                 break;
248         case INT8:
249                 if (expected_result > INT8_MAX)
250                         return 0;
251                 break;
252         case INT16:
253                 if (expected_result > INT16_MAX)
254                         return 0;
255                 break;
256         case INT32:
257                 if (expected_result > INT32_MAX)
258                         return 0;
259                 break;
260         case INT64:
261                 if (expected_result > INT64_MAX)
262                         return 0;
263                 break;
264         default:
265                 return 1;
266         }
267         return 1;
268 }
269
270 static int
271 can_parse_signed(int64_t expected_result, enum cmdline_numtype type)
272 {
273         switch (type) {
274         case UINT8:
275                 if (expected_result > UINT8_MAX || expected_result < 0)
276                         return 0;
277                 break;
278         case UINT16:
279                 if (expected_result > UINT16_MAX || expected_result < 0)
280                         return 0;
281                 break;
282         case UINT32:
283                 if (expected_result > UINT32_MAX || expected_result < 0)
284                         return 0;
285                 break;
286         case UINT64:
287                 if (expected_result < 0)
288                         return 0;
289                 break;
290         case INT8:
291                 if (expected_result > INT8_MAX || expected_result < INT8_MIN)
292                         return 0;
293                 break;
294         case INT16:
295                 if (expected_result > INT16_MAX || expected_result < INT16_MIN)
296                         return 0;
297                 break;
298         case INT32:
299                 if (expected_result > INT32_MAX || expected_result < INT32_MIN)
300                         return 0;
301                 break;
302         default:
303                 return 1;
304         }
305         return 1;
306 }
307
308 /* test invalid parameters */
309 int
310 test_parse_num_invalid_param(void)
311 {
312         char buf[CMDLINE_TEST_BUFSIZE];
313         uint32_t result;
314         cmdline_parse_token_num_t token;
315         int ret = 0;
316
317         /* set up a token */
318         token.num_data.type = UINT32;
319
320         /* copy string to buffer */
321         strlcpy(buf, num_valid_positive_strs[0].str, sizeof(buf));
322
323         /* try all null */
324         ret = cmdline_parse_num(NULL, NULL, NULL, 0);
325         if (ret != -1) {
326                 printf("Error: parser accepted null parameters!\n");
327                 return -1;
328         }
329
330         /* try null token */
331         ret = cmdline_parse_num(NULL, buf, (void*)&result, sizeof(result));
332         if (ret != -1) {
333                 printf("Error: parser accepted null token!\n");
334                 return -1;
335         }
336
337         /* try null buf */
338         ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, NULL,
339                 (void*)&result, sizeof(result));
340         if (ret != -1) {
341                 printf("Error: parser accepted null string!\n");
342                 return -1;
343         }
344
345         /* try null result */
346         ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, buf,
347                 NULL, 0);
348         if (ret == -1) {
349                 printf("Error: parser rejected null result!\n");
350                 return -1;
351         }
352
353         /* test help function */
354         memset(&buf, 0, sizeof(buf));
355
356         /* try all null */
357         ret = cmdline_get_help_num(NULL, NULL, 0);
358         if (ret != -1) {
359                 printf("Error: help function accepted null parameters!\n");
360                 return -1;
361         }
362
363         /* try null token */
364         ret = cmdline_get_help_num(NULL, buf, sizeof(buf));
365         if (ret != -1) {
366                 printf("Error: help function accepted null token!\n");
367                 return -1;
368         }
369
370         /* coverage! */
371         ret = cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, buf, sizeof(buf));
372         if (ret < 0) {
373                 printf("Error: help function failed with valid parameters!\n");
374                 return -1;
375         }
376
377         return 0;
378 }
379 /* test valid parameters but invalid data */
380 int
381 test_parse_num_invalid_data(void)
382 {
383         enum cmdline_numtype type;
384         int ret = 0;
385         unsigned i;
386         char buf[CMDLINE_TEST_BUFSIZE];
387         uint64_t result; /* pick largest buffer */
388         cmdline_parse_token_num_t token;
389
390         /* cycle through all possible parsed types */
391         for (type = UINT8; type <= INT64; type++) {
392                 token.num_data.type = type;
393
394                 /* test full strings */
395                 for (i = 0; i < NUM_INVALID_STRS_SIZE; i++) {
396
397                         memset(&result, 0, sizeof(uint64_t));
398                         memset(&buf, 0, sizeof(buf));
399
400                         ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token,
401                                 num_invalid_strs[i], (void*)&result, sizeof(result));
402                         if (ret != -1) {
403                                 /* get some info about what we are trying to parse */
404                                 cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
405                                                 buf, sizeof(buf));
406
407                                 printf("Error: parsing %s as %s succeeded!\n",
408                                                 num_invalid_strs[i], buf);
409                                 return -1;
410                         }
411                 }
412         }
413         return 0;
414 }
415
416 /* test valid parameters and data */
417 int
418 test_parse_num_valid(void)
419 {
420         int ret = 0;
421         enum cmdline_numtype type;
422         unsigned i;
423         char buf[CMDLINE_TEST_BUFSIZE];
424         uint64_t result;
425         cmdline_parse_token_num_t token;
426
427         /** valid strings **/
428
429         /* cycle through all possible parsed types */
430         for (type = UINT8; type <= INT64; type++) {
431                 token.num_data.type = type;
432
433                 /* test positive strings */
434                 for (i = 0; i < NUM_POSITIVE_STRS_SIZE; i++) {
435                         result = 0;
436                         memset(&buf, 0, sizeof(buf));
437
438                         cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
439                                         buf, sizeof(buf));
440
441                         ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
442                                 num_valid_positive_strs[i].str,
443                                 (void*)&result, sizeof(result));
444
445                         /* if it should have passed but didn't, or if it should have failed but didn't */
446                         if ((ret < 0) == (can_parse_unsigned(num_valid_positive_strs[i].result, type) > 0)) {
447                                 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
448                                                 num_valid_positive_strs[i].str, buf);
449                                 return -1;
450                         }
451                         /* check if result matches what it should have matched
452                          * since unsigned numbers don't care about number of bits, we can just convert
453                          * everything to uint64_t without any worries. */
454                         if (ret > 0 && num_valid_positive_strs[i].result != result) {
455                                 printf("Error: parsing %s as %s failed: result mismatch!\n",
456                                                 num_valid_positive_strs[i].str, buf);
457                                 return -1;
458                         }
459                 }
460
461                 /* test negative strings */
462                 for (i = 0; i < NUM_NEGATIVE_STRS_SIZE; i++) {
463                         result = 0;
464                         memset(&buf, 0, sizeof(buf));
465
466                         cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
467                                         buf, sizeof(buf));
468
469                         ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
470                                 num_valid_negative_strs[i].str,
471                                 (void*)&result, sizeof(result));
472
473                         /* if it should have passed but didn't, or if it should have failed but didn't */
474                         if ((ret < 0) == (can_parse_signed(num_valid_negative_strs[i].result, type) > 0)) {
475                                 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
476                                                 num_valid_negative_strs[i].str, buf);
477                                 return -1;
478                         }
479                         /* check if result matches what it should have matched
480                          * the result is signed in this case, so we have to account for that */
481                         if (ret > 0) {
482                                 /* detect negative */
483                                 switch (type) {
484                                 case INT8:
485                                         result = (int8_t) result;
486                                         break;
487                                 case INT16:
488                                         result = (int16_t) result;
489                                         break;
490                                 case INT32:
491                                         result = (int32_t) result;
492                                         break;
493                                 default:
494                                         break;
495                                 }
496                                 if (num_valid_negative_strs[i].result == (int64_t) result)
497                                         continue;
498                                 printf("Error: parsing %s as %s failed: result mismatch!\n",
499                                                 num_valid_negative_strs[i].str, buf);
500                                 return -1;
501                         }
502                 }
503         }
504
505         /** garbage strings **/
506
507         /* cycle through all possible parsed types */
508         for (type = UINT8; type <= INT64; type++) {
509                 token.num_data.type = type;
510
511                 /* test positive garbage strings */
512                 for (i = 0; i < NUM_POSITIVE_GARBAGE_STRS_SIZE; i++) {
513                         result = 0;
514                         memset(&buf, 0, sizeof(buf));
515
516                         cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
517                                         buf, sizeof(buf));
518
519                         ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
520                                 num_garbage_positive_strs[i].str,
521                                 (void*)&result, sizeof(result));
522
523                         /* if it should have passed but didn't, or if it should have failed but didn't */
524                         if ((ret < 0) == (can_parse_unsigned(num_garbage_positive_strs[i].result, type) > 0)) {
525                                 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
526                                                 num_garbage_positive_strs[i].str, buf);
527                                 return -1;
528                         }
529                         /* check if result matches what it should have matched
530                          * since unsigned numbers don't care about number of bits, we can just convert
531                          * everything to uint64_t without any worries. */
532                         if (ret > 0 && num_garbage_positive_strs[i].result != result) {
533                                 printf("Error: parsing %s as %s failed: result mismatch!\n",
534                                                 num_garbage_positive_strs[i].str, buf);
535                                 return -1;
536                         }
537                 }
538
539                 /* test negative strings */
540                 for (i = 0; i < NUM_NEGATIVE_GARBAGE_STRS_SIZE; i++) {
541                         result = 0;
542                         memset(&buf, 0, sizeof(buf));
543
544                         cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
545                                         buf, sizeof(buf));
546
547                         ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
548                                 num_garbage_negative_strs[i].str,
549                                 (void*)&result, sizeof(result));
550
551                         /* if it should have passed but didn't, or if it should have failed but didn't */
552                         if ((ret < 0) == (can_parse_signed(num_garbage_negative_strs[i].result, type) > 0)) {
553                                 printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
554                                                 num_garbage_negative_strs[i].str, buf);
555                                 return -1;
556                         }
557                         /* check if result matches what it should have matched
558                          * the result is signed in this case, so we have to account for that */
559                         if (ret > 0) {
560                                 /* detect negative */
561                                 switch (type) {
562                                 case INT8:
563                                         if (result & (INT8_MAX + 1))
564                                                 result |= 0xFFFFFFFFFFFFFF00ULL;
565                                         break;
566                                 case INT16:
567                                         if (result & (INT16_MAX + 1))
568                                                 result |= 0xFFFFFFFFFFFF0000ULL;
569                                         break;
570                                 case INT32:
571                                         if (result & (INT32_MAX + 1ULL))
572                                                 result |= 0xFFFFFFFF00000000ULL;
573                                         break;
574                                 default:
575                                         break;
576                                 }
577                                 if (num_garbage_negative_strs[i].result == (int64_t) result)
578                                         continue;
579                                 printf("Error: parsing %s as %s failed: result mismatch!\n",
580                                                 num_garbage_negative_strs[i].str, buf);
581                                 return -1;
582                         }
583                 }
584         }
585
586         memset(&buf, 0, sizeof(buf));
587
588         /* coverage! */
589         cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
590                         buf, sizeof(buf));
591
592         return 0;
593 }