xref: /openbsd-src/regress/lib/libutil/fmt_scaled/fmt_test.c (revision d7259957e8a5d4370d76bfccd4a30d5d1fe80f38)
1*d7259957Scheloha /* $OpenBSD: fmt_test.c,v 1.19 2022/12/04 23:50:46 cheloha Exp $ */
2f02338f6Sian 
3f02338f6Sian /*
4f02338f6Sian  * Combined tests for fmt_scaled and scan_scaled.
5f02338f6Sian  * Ian Darwin, January 2001. Public domain.
6f02338f6Sian  */
7f02338f6Sian 
8f02338f6Sian #include <stdio.h>
9f02338f6Sian #include <stdlib.h>
10f02338f6Sian #include <string.h>
11f02338f6Sian #include <sys/types.h>
12f02338f6Sian #include <errno.h>
136c947a19Sdtucker #include <limits.h>
149ae1fb7fSjsg #include <unistd.h>
15f02338f6Sian 
16f02338f6Sian #include <util.h>
17f02338f6Sian 
18db3296cfSderaadt static int fmt_test(void);
19db3296cfSderaadt static int scan_test(void);
20f02338f6Sian 
21f02338f6Sian static void print_errno(int e);
22f02338f6Sian static int assert_int(int testnum, int checknum, int expect, int result);
23f02338f6Sian static int assert_errno(int testnum, int checknum, int expect, int result);
244c8432e8Sguenther static int assert_llong(int testnum, int checknum, long long expect, long long result);
25f02338f6Sian static int assert_str(int testnum, int checknum, char * expect, char * result);
26f02338f6Sian 
27f02338f6Sian extern char *__progname;
28f02338f6Sian static int verbose = 0;
29f02338f6Sian 
usage(int stat)30f02338f6Sian __dead static void usage(int stat)
31f02338f6Sian {
32f02338f6Sian 	fprintf(stderr, "usage: %s [-v]\n", __progname);
33f02338f6Sian 	exit(stat);
34f02338f6Sian }
35f02338f6Sian 
36f02338f6Sian int
main(int argc,char ** argv)37f02338f6Sian main(int argc, char **argv)
38f02338f6Sian {
39f02338f6Sian 	int i, ch;
40f02338f6Sian 
41f02338f6Sian 	while ((ch = getopt(argc, argv, "hv")) != -1) {
42f02338f6Sian 			switch (ch) {
43f02338f6Sian 			case 'v':
44f02338f6Sian 					verbose = 1;
45f02338f6Sian 					break;
46f02338f6Sian 			case 'h':
47f02338f6Sian 					usage(0);
48f02338f6Sian 			default:
49f02338f6Sian 					usage(1);
50f02338f6Sian 			}
51f02338f6Sian 	}
52f02338f6Sian 	argc -= optind;
53f02338f6Sian 	argv += optind;
54f02338f6Sian 
55f02338f6Sian 	if (verbose)
56f02338f6Sian 		printf("Starting fmt_test\n");
57f02338f6Sian 	i = fmt_test();
58f02338f6Sian 	if (verbose)
59f02338f6Sian 		printf("Starting scan_test\n");
60f02338f6Sian 	i += scan_test();
61f02338f6Sian 	if (i) {
62f02338f6Sian 		printf("*** %d errors in libutil/fmt_scaled tests ***\n", i);
63f02338f6Sian 	} else {
64f02338f6Sian 		if (verbose)
65f02338f6Sian 			printf("Tests done; no unexpected errors\n");
66f02338f6Sian 	}
67f02338f6Sian 	return i;
68f02338f6Sian }
69f02338f6Sian 
70f02338f6Sian /************** tests for fmt_scaled *******************/
71f02338f6Sian 
72f02338f6Sian static struct {			/* the test cases */
734c8432e8Sguenther 	long long input;
74f02338f6Sian 	char *expect;
759602cc96Sdavid 	int err;
76f02338f6Sian } ddata[] = {
77f02338f6Sian 	{ 0, "0B", 0 },
7846b408a8Sotto 	{ 1, "1B", 0 },
7946b408a8Sotto 	{ -1, "-1B", 0 },
8046b408a8Sotto 	{ 100, "100B", 0},
8146b408a8Sotto 	{ -100, "-100B", 0},
82f02338f6Sian 	{ 999, "999B", 0 },
83f02338f6Sian 	{ 1000, "1000B", 0 },
84f02338f6Sian 	{ 1023, "1023B", 0 },
85f02338f6Sian 	{ -1023, "-1023B", 0 },
86f02338f6Sian 	{ 1024, "1.0K", 0 },
87f02338f6Sian 	{ 1025, "1.0K", 0 },
88f02338f6Sian 	{ 1234, "1.2K", 0 },
89f02338f6Sian 	{ -1234, "-1.2K", 0 },
905c4c8ca9Sian 	{ 1484, "1.4K", 0 },		/* rounding boundary, down */
915c4c8ca9Sian 	{ 1485, "1.5K", 0 },		/* rounding boundary, up   */
925c4c8ca9Sian 	{ -1484, "-1.4K", 0 },		/* rounding boundary, down */
935c4c8ca9Sian 	{ -1485, "-1.5K", 0 },		/* rounding boundary, up   */
94f02338f6Sian 	{ 1536, "1.5K", 0 },
95f02338f6Sian 	{ 1786, "1.7K", 0 },
96f02338f6Sian 	{ 1800, "1.8K", 0 },
97f02338f6Sian 	{ 2000, "2.0K", 0 },
980ccfa65fSotto 	{ 123456, "121K", 0 },
990ccfa65fSotto 	{ 578318, "565K", 0 },
1000ccfa65fSotto 	{ 902948, "882K", 0 },
10115fe0d73Sotto 	{ 1048576, "1.0M", 0},
10215fe0d73Sotto 	{ 1048628, "1.0M", 0},
10315fe0d73Sotto 	{ 1049447, "1.0M", 0},
10446b408a8Sotto 	{ -102400, "-100K", 0},
10546b408a8Sotto 	{ -103423, "-101K", 0 },
106f02338f6Sian 	{ 7299072, "7.0M", 0 },
1070ccfa65fSotto 	{ 409478144L, "391M", 0 },
1080ccfa65fSotto 	{ -409478144L, "-391M", 0 },
1090ccfa65fSotto 	{ 999999999L, "954M", 0 },
110f02338f6Sian 	{ 1499999999L, "1.4G", 0 },
111f02338f6Sian 	{ 12475423744LL, "11.6G", 0},
112f02338f6Sian 	{ 1LL<<61, "2.0E", 0 },
113f02338f6Sian 	{ 1LL<<62, "4.0E", 0 },
114f02338f6Sian 	{ 1LL<<63, "", ERANGE },
115df8f77adSotto 	{ 1099512676352LL, "1.0T", 0}
116f02338f6Sian };
117f02338f6Sian #	define DDATA_LENGTH (sizeof ddata/sizeof *ddata)
118f02338f6Sian 
119f02338f6Sian static int
fmt_test(void)120db3296cfSderaadt fmt_test(void)
121f02338f6Sian {
122f02338f6Sian 	unsigned int i, e, errs = 0;
123f02338f6Sian 	int ret;
124f02338f6Sian 	char buf[FMT_SCALED_STRSIZE];
125f02338f6Sian 
126f02338f6Sian 	for (i = 0; i < DDATA_LENGTH; i++) {
127f02338f6Sian 		strlcpy(buf, "UNSET", FMT_SCALED_STRSIZE);
128cd187117Sdtucker 		errno = 0;
129f02338f6Sian 		ret = fmt_scaled(ddata[i].input, buf);
130f02338f6Sian 		e = errno;
131f02338f6Sian 		if (verbose) {
132f02338f6Sian 			printf("%lld --> %s (%d)", ddata[i].input, buf, ret);
133f02338f6Sian 			if (ret == -1)
134f02338f6Sian 				print_errno(e);
135f02338f6Sian 			printf("\n");
136f02338f6Sian 		}
137f02338f6Sian 		if (ret == -1)
1389602cc96Sdavid 			errs += assert_int(i, 1, ret, ddata[i].err == 0 ? 0 : -1);
1399602cc96Sdavid 		if (ddata[i].err)
140cd187117Sdtucker 			errs += assert_errno(i, 2, ddata[i].err, e);
141f02338f6Sian 		else
142f02338f6Sian 			errs += assert_str(i, 3, ddata[i].expect, buf);
143f02338f6Sian 	}
144f02338f6Sian 
145f02338f6Sian 	return errs;
146f02338f6Sian }
147f02338f6Sian 
148f02338f6Sian /************** tests for scan_scaled *******************/
149f02338f6Sian 
150f02338f6Sian 
151f02338f6Sian #define	IMPROBABLE	(-42)
152f02338f6Sian 
153f02338f6Sian struct {					/* the test cases */
154f02338f6Sian 	char *input;
1554c8432e8Sguenther 	long long result;
1569602cc96Sdavid 	int err;
157f02338f6Sian } sdata[] = {
158f02338f6Sian 	{ "0",		0, 0 },
159f02338f6Sian 	{ "123",	123, 0 },
160f02338f6Sian 	{ "1k",		1024, 0 },		/* lower case */
161f02338f6Sian 	{ "100.944", 100, 0 },	/* should --> 100 (truncates fraction) */
162f02338f6Sian 	{ "10099",	10099LL, 0 },
163f02338f6Sian 	{ "1M",		1048576LL, 0 },
164f02338f6Sian 	{ "1.1M",	1153433LL, 0 },		/* fractions */
165f02338f6Sian 	{ "1.111111111111111111M",	1165084LL, 0 },		/* fractions */
166f02338f6Sian 	{ "1.55M",	1625292LL, 0 },	/* fractions */
167f02338f6Sian 	{ "1.9M",	1992294LL, 0 },		/* fractions */
168f02338f6Sian 	{ "-2K",	-2048LL, 0 },		/* negatives */
169f02338f6Sian 	{ "-2.2K",	-2252LL, 0 },	/* neg with fract */
170f02338f6Sian 	{ "4.5k", 4608, 0 },
17129ce5829Stb 	{ "3.333755555555t", 3665502936412, 0 },
17229ce5829Stb 	{ "-3.333755555555t", -3665502936412, 0 },
173f02338f6Sian 	{ "4.5555555555555555K", 4664, 0 },
174f02338f6Sian 	{ "4.5555555555555555555K", 4664, 0 },	/* handle enough digits? */
175f02338f6Sian 	{ "4.555555555555555555555555555555K", 4664, 0 }, /* ignores extra digits? */
176f02338f6Sian 	{ "1G",		1073741824LL, 0 },
177f02338f6Sian 	{ "G", 		0, 0 },			/* should == 0G? */
178f02338f6Sian 	{ "1234567890", 1234567890LL, 0 },	/* should work */
179f02338f6Sian 	{ "1.5E",	1729382256910270464LL, 0 },		/* big */
180f02338f6Sian 	{ "32948093840918378473209480483092", 0, ERANGE },  /* too big */
1812ff576deShalex 	{ "1.5Q",	0, EINVAL },		/* invalid multiplier */
1822ff576deShalex 	{ "1ab",	0, EINVAL },		/* ditto */
1832ff576deShalex 	{ "3&",		0, EINVAL },		/* ditto */
184f02338f6Sian 	{ "5.0e3",	0, EINVAL },	/* digits after */
185f02338f6Sian 	{ "5.0E3",	0, EINVAL },	/* ditto */
186f02338f6Sian 	{ "1..0",	0, EINVAL },		/* bad format */
187f02338f6Sian 	{ "",		0, 0 },			/* boundary */
188f02338f6Sian 	{ "--1", -1, EINVAL },
189f02338f6Sian 	{ "++42", -1, EINVAL },
19039af7dccSdtucker 	{ "-.060000000000000000E", -69175290276410818, 0 },
19139af7dccSdtucker 	{ "-.600000000000000000E", -691752902764108185, 0 },
19239af7dccSdtucker 	{ "-60000000000000000E", 0, ERANGE },
1936c947a19Sdtucker 	{ "SCALE_OVERFLOW", 0, ERANGE },
1946c947a19Sdtucker 	{ "SCALE_UNDERFLOW", 0, ERANGE },
1956c947a19Sdtucker 	{ "LLONG_MAX_K", (LLONG_MAX / 1024) * 1024, 0 },
1966c947a19Sdtucker 	{ "LLONG_MIN_K", (LLONG_MIN / 1024) * 1024, 0 },
1976c947a19Sdtucker 	{ "LLONG_MAX", LLONG_MAX, 0 },	/* upper limit */
19869175851Sdtucker 
19969175851Sdtucker 	/*
20069175851Sdtucker 	 * Lower limit is a bit special: because scan_scaled accumulates into a
20169175851Sdtucker 	 * signed long long it can only handle up to the negative value of
20269175851Sdtucker 	 * LLONG_MAX not LLONG_MIN.
20369175851Sdtucker 	 */
20469175851Sdtucker 	{ "NEGATIVE_LLONG_MAX", LLONG_MAX*-1, 0 },	/* lower limit */
20569175851Sdtucker 	{ "LLONG_MIN", 0, ERANGE },	/* can't handle */
2066c947a19Sdtucker #if LLONG_MAX == 0x7fffffffffffffffLL
20769175851Sdtucker 	{ "-9223372036854775807", -9223372036854775807, 0 },
20869175851Sdtucker 	{ "9223372036854775807", 9223372036854775807, 0 },
2096c947a19Sdtucker 	{ "9223372036854775808", 0, ERANGE },
2106c947a19Sdtucker 	{ "9223372036854775809", 0, ERANGE },
2116c947a19Sdtucker #endif
2126c947a19Sdtucker #if LLONG_MIN == (-0x7fffffffffffffffLL-1)
21369175851Sdtucker 	{ "-9223372036854775808", 0, ERANGE },
2146c947a19Sdtucker 	{ "-9223372036854775809", 0, ERANGE },
2156c947a19Sdtucker 	{ "-9223372036854775810", 0, ERANGE },
2166c947a19Sdtucker #endif
217f02338f6Sian };
218f02338f6Sian #	define SDATA_LENGTH (sizeof sdata/sizeof *sdata)
219f02338f6Sian 
220f02338f6Sian static void
print_errno(int e)221f02338f6Sian print_errno(int e)
222f02338f6Sian {
223f02338f6Sian 	switch(e) {
224f02338f6Sian 		case EINVAL: printf("EINVAL"); break;
225f02338f6Sian 		case EDOM:   printf("EDOM"); break;
226f02338f6Sian 		case ERANGE: printf("ERANGE"); break;
227cd187117Sdtucker 		default: printf("errno %d", e);
228f02338f6Sian 	}
229f02338f6Sian }
230f02338f6Sian 
231f02338f6Sian /** Print one result */
232f02338f6Sian static void
print(char * input,long long result,int ret,int e)233cd187117Sdtucker print(char *input, long long result, int ret, int e)
234f02338f6Sian {
235cd187117Sdtucker 	printf("\"%40s\" --> %lld (%d)", input, result, ret);
236f02338f6Sian 	if (ret == -1) {
237f02338f6Sian 		printf(" -- ");
238f02338f6Sian 		print_errno(e);
239f02338f6Sian 	}
240f02338f6Sian 	printf("\n");
241f02338f6Sian }
242f02338f6Sian 
243f02338f6Sian static int
scan_test(void)244db3296cfSderaadt scan_test(void)
245f02338f6Sian {
246f02338f6Sian 	unsigned int i, errs = 0, e;
247f02338f6Sian 	int ret;
2484c8432e8Sguenther 	long long result;
2496c947a19Sdtucker 	char buf[1024], *input;
250f02338f6Sian 
251f02338f6Sian 	for (i = 0; i < SDATA_LENGTH; i++) {
252f02338f6Sian 		result = IMPROBABLE;
2536c947a19Sdtucker 
2546c947a19Sdtucker 		input = sdata[i].input;
2556c947a19Sdtucker 		/* some magic values for architecture dependent limits */
2566c947a19Sdtucker 		if (strcmp(input, "LLONG_MAX") == 0) {
2576c947a19Sdtucker 			snprintf(buf, sizeof buf," %lld", LLONG_MAX);
2586c947a19Sdtucker 			input = buf;
2596c947a19Sdtucker 		} else if (strcmp(input, "LLONG_MIN") == 0) {
2606c947a19Sdtucker 			snprintf(buf, sizeof buf," %lld", LLONG_MIN);
2616c947a19Sdtucker 			input = buf;
2626c947a19Sdtucker 		} else if (strcmp(input, "LLONG_MAX_K") == 0) {
2636c947a19Sdtucker 			snprintf(buf, sizeof buf," %lldK", LLONG_MAX/1024);
2646c947a19Sdtucker 			input = buf;
2656c947a19Sdtucker 		} else if (strcmp(input, "LLONG_MIN_K") == 0) {
2666c947a19Sdtucker 			snprintf(buf, sizeof buf," %lldK", LLONG_MIN/1024);
2676c947a19Sdtucker 			input = buf;
2686c947a19Sdtucker 		} else if (strcmp(input, "SCALE_OVERFLOW") == 0) {
2696c947a19Sdtucker 			snprintf(buf, sizeof buf," %lldK", (LLONG_MAX/1024)+1);
2706c947a19Sdtucker 			input = buf;
2716c947a19Sdtucker 		} else if (strcmp(input, "SCALE_UNDERFLOW") == 0) {
2726c947a19Sdtucker 			snprintf(buf, sizeof buf," %lldK", (LLONG_MIN/1024)-1);
2736c947a19Sdtucker 			input = buf;
27469175851Sdtucker 		} else if (strcmp(input, "NEGATIVE_LLONG_MAX") == 0) {
27569175851Sdtucker 			snprintf(buf, sizeof buf," %lld", LLONG_MAX*-1);
27669175851Sdtucker 			input = buf;
2776c947a19Sdtucker 		}
27869175851Sdtucker 		if (verbose && input != sdata[i].input)
27969175851Sdtucker 			printf("expand '%s' -> '%s'\n", sdata[i].input,
28069175851Sdtucker 			    input);
2816c947a19Sdtucker 
282f02338f6Sian 		/* printf("Calling scan_scaled(%s, ...)\n", sdata[i].input); */
28369175851Sdtucker 		errno = 0;
2846c947a19Sdtucker 		ret = scan_scaled(input, &result);
285f02338f6Sian 		e = errno;	/* protect across printfs &c. */
286f02338f6Sian 		if (verbose)
2876c947a19Sdtucker 			print(input, result, ret, e);
288f02338f6Sian 		if (ret == -1)
2899602cc96Sdavid 			errs += assert_int(i, 1, ret, sdata[i].err == 0 ? 0 : -1);
2909602cc96Sdavid 		if (sdata[i].err)
291cd187117Sdtucker 			errs += assert_errno(i, 2, sdata[i].err, e);
292f02338f6Sian 		else
2934c8432e8Sguenther 			errs += assert_llong(i, 3, sdata[i].result, result);
294f02338f6Sian 	}
295f02338f6Sian 	return errs;
296f02338f6Sian }
297f02338f6Sian 
298f02338f6Sian /************** common testing stuff *******************/
299f02338f6Sian 
300f02338f6Sian static int
assert_int(int testnum,int check,int expect,int result)301f02338f6Sian assert_int(int testnum, int check, int expect, int result)
302f02338f6Sian {
303f02338f6Sian 	if (expect == result)
304f02338f6Sian 		return 0;
305f02338f6Sian 	printf("** FAILURE: test %d check %d, expect %d, result %d **\n",
306f02338f6Sian 		testnum, check, expect, result);
307f02338f6Sian 	return 1;
308f02338f6Sian }
309f02338f6Sian 
310f02338f6Sian static int
assert_errno(int testnum,int check,int expect,int result)311f02338f6Sian assert_errno(int testnum, int check, int expect, int result)
312f02338f6Sian {
313f02338f6Sian 	if (expect == result)
314f02338f6Sian 		return 0;
315f02338f6Sian 	printf("** FAILURE: test %d check %d, expect ",
316f02338f6Sian 		testnum, check);
317f02338f6Sian 	print_errno(expect);
318f02338f6Sian 	printf(", got ");
319f02338f6Sian 	print_errno(result);
320f02338f6Sian 	printf(" **\n");
321f02338f6Sian 	return 1;
322f02338f6Sian }
323f02338f6Sian 
324f02338f6Sian static int
assert_llong(int testnum,int check,long long expect,long long result)3254c8432e8Sguenther assert_llong(int testnum, int check, long long expect, long long result)
326f02338f6Sian {
327f02338f6Sian 	if (expect == result)
328f02338f6Sian 		return 0;
329f02338f6Sian 	printf("** FAILURE: test %d check %d, expect %lld, result %lld **\n",
330f02338f6Sian 		testnum, check, expect, result);
331f02338f6Sian 	return 1;
332f02338f6Sian }
333f02338f6Sian 
334f02338f6Sian static int
assert_str(int testnum,int check,char * expect,char * result)335f02338f6Sian assert_str(int testnum, int check, char * expect, char * result)
336f02338f6Sian {
337f02338f6Sian 	if (strcmp(expect, result) == 0)
338f02338f6Sian 		return 0;
339f02338f6Sian 	printf("** FAILURE: test %d check %d, expect %s, result %s **\n",
340f02338f6Sian 		testnum, check, expect, result);
341f02338f6Sian 	return 1;
342f02338f6Sian }
343