1 /* $OpenBSD: fmt_test.c,v 1.19 2022/12/04 23:50:46 cheloha Exp $ */
2
3 /*
4 * Combined tests for fmt_scaled and scan_scaled.
5 * Ian Darwin, January 2001. Public domain.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <errno.h>
13 #include <limits.h>
14 #include <unistd.h>
15
16 #include <util.h>
17
18 static int fmt_test(void);
19 static int scan_test(void);
20
21 static void print_errno(int e);
22 static int assert_int(int testnum, int checknum, int expect, int result);
23 static int assert_errno(int testnum, int checknum, int expect, int result);
24 static int assert_llong(int testnum, int checknum, long long expect, long long result);
25 static int assert_str(int testnum, int checknum, char * expect, char * result);
26
27 extern char *__progname;
28 static int verbose = 0;
29
usage(int stat)30 __dead static void usage(int stat)
31 {
32 fprintf(stderr, "usage: %s [-v]\n", __progname);
33 exit(stat);
34 }
35
36 int
main(int argc,char ** argv)37 main(int argc, char **argv)
38 {
39 int i, ch;
40
41 while ((ch = getopt(argc, argv, "hv")) != -1) {
42 switch (ch) {
43 case 'v':
44 verbose = 1;
45 break;
46 case 'h':
47 usage(0);
48 default:
49 usage(1);
50 }
51 }
52 argc -= optind;
53 argv += optind;
54
55 if (verbose)
56 printf("Starting fmt_test\n");
57 i = fmt_test();
58 if (verbose)
59 printf("Starting scan_test\n");
60 i += scan_test();
61 if (i) {
62 printf("*** %d errors in libutil/fmt_scaled tests ***\n", i);
63 } else {
64 if (verbose)
65 printf("Tests done; no unexpected errors\n");
66 }
67 return i;
68 }
69
70 /************** tests for fmt_scaled *******************/
71
72 static struct { /* the test cases */
73 long long input;
74 char *expect;
75 int err;
76 } ddata[] = {
77 { 0, "0B", 0 },
78 { 1, "1B", 0 },
79 { -1, "-1B", 0 },
80 { 100, "100B", 0},
81 { -100, "-100B", 0},
82 { 999, "999B", 0 },
83 { 1000, "1000B", 0 },
84 { 1023, "1023B", 0 },
85 { -1023, "-1023B", 0 },
86 { 1024, "1.0K", 0 },
87 { 1025, "1.0K", 0 },
88 { 1234, "1.2K", 0 },
89 { -1234, "-1.2K", 0 },
90 { 1484, "1.4K", 0 }, /* rounding boundary, down */
91 { 1485, "1.5K", 0 }, /* rounding boundary, up */
92 { -1484, "-1.4K", 0 }, /* rounding boundary, down */
93 { -1485, "-1.5K", 0 }, /* rounding boundary, up */
94 { 1536, "1.5K", 0 },
95 { 1786, "1.7K", 0 },
96 { 1800, "1.8K", 0 },
97 { 2000, "2.0K", 0 },
98 { 123456, "121K", 0 },
99 { 578318, "565K", 0 },
100 { 902948, "882K", 0 },
101 { 1048576, "1.0M", 0},
102 { 1048628, "1.0M", 0},
103 { 1049447, "1.0M", 0},
104 { -102400, "-100K", 0},
105 { -103423, "-101K", 0 },
106 { 7299072, "7.0M", 0 },
107 { 409478144L, "391M", 0 },
108 { -409478144L, "-391M", 0 },
109 { 999999999L, "954M", 0 },
110 { 1499999999L, "1.4G", 0 },
111 { 12475423744LL, "11.6G", 0},
112 { 1LL<<61, "2.0E", 0 },
113 { 1LL<<62, "4.0E", 0 },
114 { 1LL<<63, "", ERANGE },
115 { 1099512676352LL, "1.0T", 0}
116 };
117 # define DDATA_LENGTH (sizeof ddata/sizeof *ddata)
118
119 static int
fmt_test(void)120 fmt_test(void)
121 {
122 unsigned int i, e, errs = 0;
123 int ret;
124 char buf[FMT_SCALED_STRSIZE];
125
126 for (i = 0; i < DDATA_LENGTH; i++) {
127 strlcpy(buf, "UNSET", FMT_SCALED_STRSIZE);
128 errno = 0;
129 ret = fmt_scaled(ddata[i].input, buf);
130 e = errno;
131 if (verbose) {
132 printf("%lld --> %s (%d)", ddata[i].input, buf, ret);
133 if (ret == -1)
134 print_errno(e);
135 printf("\n");
136 }
137 if (ret == -1)
138 errs += assert_int(i, 1, ret, ddata[i].err == 0 ? 0 : -1);
139 if (ddata[i].err)
140 errs += assert_errno(i, 2, ddata[i].err, e);
141 else
142 errs += assert_str(i, 3, ddata[i].expect, buf);
143 }
144
145 return errs;
146 }
147
148 /************** tests for scan_scaled *******************/
149
150
151 #define IMPROBABLE (-42)
152
153 struct { /* the test cases */
154 char *input;
155 long long result;
156 int err;
157 } sdata[] = {
158 { "0", 0, 0 },
159 { "123", 123, 0 },
160 { "1k", 1024, 0 }, /* lower case */
161 { "100.944", 100, 0 }, /* should --> 100 (truncates fraction) */
162 { "10099", 10099LL, 0 },
163 { "1M", 1048576LL, 0 },
164 { "1.1M", 1153433LL, 0 }, /* fractions */
165 { "1.111111111111111111M", 1165084LL, 0 }, /* fractions */
166 { "1.55M", 1625292LL, 0 }, /* fractions */
167 { "1.9M", 1992294LL, 0 }, /* fractions */
168 { "-2K", -2048LL, 0 }, /* negatives */
169 { "-2.2K", -2252LL, 0 }, /* neg with fract */
170 { "4.5k", 4608, 0 },
171 { "3.333755555555t", 3665502936412, 0 },
172 { "-3.333755555555t", -3665502936412, 0 },
173 { "4.5555555555555555K", 4664, 0 },
174 { "4.5555555555555555555K", 4664, 0 }, /* handle enough digits? */
175 { "4.555555555555555555555555555555K", 4664, 0 }, /* ignores extra digits? */
176 { "1G", 1073741824LL, 0 },
177 { "G", 0, 0 }, /* should == 0G? */
178 { "1234567890", 1234567890LL, 0 }, /* should work */
179 { "1.5E", 1729382256910270464LL, 0 }, /* big */
180 { "32948093840918378473209480483092", 0, ERANGE }, /* too big */
181 { "1.5Q", 0, EINVAL }, /* invalid multiplier */
182 { "1ab", 0, EINVAL }, /* ditto */
183 { "3&", 0, EINVAL }, /* ditto */
184 { "5.0e3", 0, EINVAL }, /* digits after */
185 { "5.0E3", 0, EINVAL }, /* ditto */
186 { "1..0", 0, EINVAL }, /* bad format */
187 { "", 0, 0 }, /* boundary */
188 { "--1", -1, EINVAL },
189 { "++42", -1, EINVAL },
190 { "-.060000000000000000E", -69175290276410818, 0 },
191 { "-.600000000000000000E", -691752902764108185, 0 },
192 { "-60000000000000000E", 0, ERANGE },
193 { "SCALE_OVERFLOW", 0, ERANGE },
194 { "SCALE_UNDERFLOW", 0, ERANGE },
195 { "LLONG_MAX_K", (LLONG_MAX / 1024) * 1024, 0 },
196 { "LLONG_MIN_K", (LLONG_MIN / 1024) * 1024, 0 },
197 { "LLONG_MAX", LLONG_MAX, 0 }, /* upper limit */
198
199 /*
200 * Lower limit is a bit special: because scan_scaled accumulates into a
201 * signed long long it can only handle up to the negative value of
202 * LLONG_MAX not LLONG_MIN.
203 */
204 { "NEGATIVE_LLONG_MAX", LLONG_MAX*-1, 0 }, /* lower limit */
205 { "LLONG_MIN", 0, ERANGE }, /* can't handle */
206 #if LLONG_MAX == 0x7fffffffffffffffLL
207 { "-9223372036854775807", -9223372036854775807, 0 },
208 { "9223372036854775807", 9223372036854775807, 0 },
209 { "9223372036854775808", 0, ERANGE },
210 { "9223372036854775809", 0, ERANGE },
211 #endif
212 #if LLONG_MIN == (-0x7fffffffffffffffLL-1)
213 { "-9223372036854775808", 0, ERANGE },
214 { "-9223372036854775809", 0, ERANGE },
215 { "-9223372036854775810", 0, ERANGE },
216 #endif
217 };
218 # define SDATA_LENGTH (sizeof sdata/sizeof *sdata)
219
220 static void
print_errno(int e)221 print_errno(int e)
222 {
223 switch(e) {
224 case EINVAL: printf("EINVAL"); break;
225 case EDOM: printf("EDOM"); break;
226 case ERANGE: printf("ERANGE"); break;
227 default: printf("errno %d", e);
228 }
229 }
230
231 /** Print one result */
232 static void
print(char * input,long long result,int ret,int e)233 print(char *input, long long result, int ret, int e)
234 {
235 printf("\"%40s\" --> %lld (%d)", input, result, ret);
236 if (ret == -1) {
237 printf(" -- ");
238 print_errno(e);
239 }
240 printf("\n");
241 }
242
243 static int
scan_test(void)244 scan_test(void)
245 {
246 unsigned int i, errs = 0, e;
247 int ret;
248 long long result;
249 char buf[1024], *input;
250
251 for (i = 0; i < SDATA_LENGTH; i++) {
252 result = IMPROBABLE;
253
254 input = sdata[i].input;
255 /* some magic values for architecture dependent limits */
256 if (strcmp(input, "LLONG_MAX") == 0) {
257 snprintf(buf, sizeof buf," %lld", LLONG_MAX);
258 input = buf;
259 } else if (strcmp(input, "LLONG_MIN") == 0) {
260 snprintf(buf, sizeof buf," %lld", LLONG_MIN);
261 input = buf;
262 } else if (strcmp(input, "LLONG_MAX_K") == 0) {
263 snprintf(buf, sizeof buf," %lldK", LLONG_MAX/1024);
264 input = buf;
265 } else if (strcmp(input, "LLONG_MIN_K") == 0) {
266 snprintf(buf, sizeof buf," %lldK", LLONG_MIN/1024);
267 input = buf;
268 } else if (strcmp(input, "SCALE_OVERFLOW") == 0) {
269 snprintf(buf, sizeof buf," %lldK", (LLONG_MAX/1024)+1);
270 input = buf;
271 } else if (strcmp(input, "SCALE_UNDERFLOW") == 0) {
272 snprintf(buf, sizeof buf," %lldK", (LLONG_MIN/1024)-1);
273 input = buf;
274 } else if (strcmp(input, "NEGATIVE_LLONG_MAX") == 0) {
275 snprintf(buf, sizeof buf," %lld", LLONG_MAX*-1);
276 input = buf;
277 }
278 if (verbose && input != sdata[i].input)
279 printf("expand '%s' -> '%s'\n", sdata[i].input,
280 input);
281
282 /* printf("Calling scan_scaled(%s, ...)\n", sdata[i].input); */
283 errno = 0;
284 ret = scan_scaled(input, &result);
285 e = errno; /* protect across printfs &c. */
286 if (verbose)
287 print(input, result, ret, e);
288 if (ret == -1)
289 errs += assert_int(i, 1, ret, sdata[i].err == 0 ? 0 : -1);
290 if (sdata[i].err)
291 errs += assert_errno(i, 2, sdata[i].err, e);
292 else
293 errs += assert_llong(i, 3, sdata[i].result, result);
294 }
295 return errs;
296 }
297
298 /************** common testing stuff *******************/
299
300 static int
assert_int(int testnum,int check,int expect,int result)301 assert_int(int testnum, int check, int expect, int result)
302 {
303 if (expect == result)
304 return 0;
305 printf("** FAILURE: test %d check %d, expect %d, result %d **\n",
306 testnum, check, expect, result);
307 return 1;
308 }
309
310 static int
assert_errno(int testnum,int check,int expect,int result)311 assert_errno(int testnum, int check, int expect, int result)
312 {
313 if (expect == result)
314 return 0;
315 printf("** FAILURE: test %d check %d, expect ",
316 testnum, check);
317 print_errno(expect);
318 printf(", got ");
319 print_errno(result);
320 printf(" **\n");
321 return 1;
322 }
323
324 static int
assert_llong(int testnum,int check,long long expect,long long result)325 assert_llong(int testnum, int check, long long expect, long long result)
326 {
327 if (expect == result)
328 return 0;
329 printf("** FAILURE: test %d check %d, expect %lld, result %lld **\n",
330 testnum, check, expect, result);
331 return 1;
332 }
333
334 static int
assert_str(int testnum,int check,char * expect,char * result)335 assert_str(int testnum, int check, char * expect, char * result)
336 {
337 if (strcmp(expect, result) == 0)
338 return 0;
339 printf("** FAILURE: test %d check %d, expect %s, result %s **\n",
340 testnum, check, expect, result);
341 return 1;
342 }
343