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