1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2023 Oxide Computer Company
14  */
15 
16 /*
17  * Test the implementation of strtonum() and strtonumx()
18  */
19 
20 #include <limits.h>
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 bool fail = false;
27 
28 static void
runtestx(const char * nstr,long long minval,long long maxval,int base,long long expval,bool expect_pass)29 runtestx(const char *nstr, long long minval, long long maxval,
30     int base, long long expval, bool expect_pass)
31 {
32 	const char *errstr;
33 	char key[0x100];
34 	long long val;
35 
36 	if (base == -1) {
37 		val = strtonum(nstr, minval, maxval, &errstr);
38 		(void) snprintf(key, sizeof (key), "strtonum(%s)", nstr);
39 	} else {
40 		val = strtonumx(nstr, minval, maxval, &errstr, base);
41 		(void) snprintf(key, sizeof (key), "strtonumx(%s, %d)",
42 		    nstr, base);
43 	}
44 
45 	if (expect_pass) {
46 		if (errstr != NULL) {
47 			fprintf(stderr, "FAIL %s was rejected: "
48 			    "%s [%lld,%lld]\n",
49 			    key, errstr, minval, maxval);
50 			fail = true;
51 		} else {
52 			fprintf(stdout, "PASS %s was accepted: "
53 			    "[%lld,%lld] = %lld\n",
54 			    key, minval, maxval, val);
55 			if (val != expval) {
56 				fprintf(stderr, "FAIL %s returned wrong value: "
57 				    "[%lld,%lld] = %lld vs. %lld\n", key,
58 				    minval, maxval, val, expval);
59 				fail = true;
60 			}
61 		}
62 	} else {
63 		if (errstr == NULL) {
64 			fprintf(stderr, "FAIL %s was accepted: "
65 			    "[%lld,%lld] = %lld\n",
66 			    key, minval, maxval, val);
67 			fail = true;
68 		} else {
69 			fprintf(stdout, "PASS %s was rejected: "
70 			    "%s [%lld,%lld]\n",
71 			    key, errstr, minval, maxval);
72 		}
73 	}
74 }
75 
76 static void
runtest(const char * nstr,long long minval,long long maxval,long long expval,bool expect_pass)77 runtest(const char *nstr, long long minval, long long maxval, long long expval,
78     bool expect_pass)
79 {
80 	runtestx(nstr, minval, maxval, -1, expval, expect_pass);
81 	runtestx(nstr, minval, maxval, 10, expval, expect_pass);
82 	runtestx(nstr, minval, maxval,  0, expval, expect_pass);
83 }
84 
85 int
main(void)86 main(void)
87 {
88 	runtest("1", 0, 100, 1, true);
89 	runtest("0", -3, 7, 0, true);
90 	runtest("0", 2, 10, 0, false);
91 	runtest("0", 2, LLONG_MAX, 0, false);
92 	runtest("-2", 0, LLONG_MAX, 0, false);
93 	runtest("0", -5, LLONG_MAX, 0, true);
94 	runtest("-3", -3, LLONG_MAX, -3, true);
95 	runtest("-2", 10, -1, 0, false);
96 	runtest("-2", -10, -1, -2, true);
97 	runtest("-20", -10, -1, 0, false);
98 	runtest("20", -10, -1, 0, false);
99 
100 	runtest("-9223372036854775808", LLONG_MIN, LLONG_MAX, LLONG_MIN, true);
101 	runtest("-9223372036854775809", LLONG_MIN, LLONG_MAX, 0, false);
102 
103 	runtest("9223372036854775807", LLONG_MIN, LLONG_MAX, LLONG_MAX, true);
104 	runtest("9223372036854775808", LLONG_MIN, LLONG_MAX, 0, false);
105 
106 	for (int base = 2; base <= 36; base++)
107 		runtestx("1", 0, 100, base, 1, true);
108 
109 	runtestx("1", 0, 100, -2, 0, false);
110 	runtestx("1", 0, 100, 1, 0, false);
111 	runtestx("1", 0, 100, 37, 0, false);
112 
113 	runtestx("0x1234", 0, LLONG_MAX, 16, 0x1234, true);
114 	runtestx("0x1234", 0, LLONG_MAX, 0, 0x1234, true);
115 	runtestx("0x1234", 0, LLONG_MAX, 10, 0, false);
116 
117 	runtestx("AZbc123", 0, LLONG_MAX, 36, 23903176539, true);
118 	runtestx("AZbc123", 0, LLONG_MAX, 35, 0, false);
119 	runtestx("AYBC123", 0, LLONG_MAX, 35, 20185422673, true);
120 	runtestx("AYBC123", 0, LLONG_MAX, 34, 0, false);
121 
122 	runtestx("01234", 0, LLONG_MAX, 8, 01234, true);
123 	runtestx("01234", 0, LLONG_MAX, 0, 01234, true);
124 	runtestx("01234", 0, LLONG_MAX, 10, 1234, true);
125 
126 	if (fail) {
127 		printf("\nOverall status: FAIL\n");
128 		return (EXIT_FAILURE);
129 	}
130 
131 	printf("\nOverall status: PASS\n");
132 	return (EXIT_SUCCESS);
133 }
134