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 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 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 72static 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 119static int 120fmt_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 153struct { /* 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 220static void 221print_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 */ 232static void 233print(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 243static int 244scan_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 300static int 301assert_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 310static int 311assert_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 324static int 325assert_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 334static int 335assert_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