1 /* $NetBSD: t_humanize_number.c,v 1.1 2010/12/28 12:46:15 pgoyette Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <atf-c.h> 33 34 #include <err.h> 35 #include <inttypes.h> 36 #include <stdarg.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <util.h> 41 42 const struct hnopts { 43 size_t ho_len; 44 int64_t ho_num; 45 const char *ho_suffix; 46 int ho_scale; 47 int ho_flags; 48 int ho_retval; /* expected return value */ 49 const char *ho_retstr; /* expected string in buffer */ 50 } hnopts[] = { 51 /* 52 * Rev. 1.6 produces "10.0". 53 */ 54 { 5, 10737418236ULL * 1024, "", 55 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 3, "10T" }, 56 57 { 5, 10450000, "", 58 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 3, "10M" }, 59 { 5, 10500000, "", /* just for reference */ 60 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 3, "10M" }, 61 62 /* 63 * Trailing space. Rev. 1.7 produces "1 ". 64 */ 65 { 5, 1, "", 0, HN_NOSPACE, 1, "1" }, 66 67 { 5, 1, "", 0, 0, 2, "1 " }, /* just for reference */ 68 { 5, 1, "", 0, HN_B, 3, "1 B" }, /* and more ... */ 69 { 5, 1, "", 0, HN_DECIMAL, 2, "1 " }, 70 { 5, 1, "", 0, HN_NOSPACE | HN_B, 2, "1B" }, 71 { 5, 1, "", 0, HN_B | HN_DECIMAL, 3, "1 B" }, 72 { 5, 1, "", 0, HN_NOSPACE | HN_B | HN_DECIMAL, 2, "1B" }, 73 74 /* 75 * Space and HN_B. Rev. 1.7 produces "1B". 76 */ 77 { 5, 1, "", HN_AUTOSCALE, HN_B, 3, "1 B" }, 78 { 5, 1000, "", /* just for reference */ 79 HN_AUTOSCALE, HN_B, 3, "1 K" }, 80 81 /* 82 * Truncated output. Rev. 1.7 produces "1.0 K". 83 */ 84 { 6, 1000, "A", HN_AUTOSCALE, HN_DECIMAL, -1, "" }, 85 86 /* 87 * Failure case reported by Greg Troxel <gdt@NetBSD.org>. 88 * Rev. 1.11 incorrectly returns 5 with filling the buffer 89 * with "1000". 90 */ 91 { 5, 1048258238, "", 92 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 4, "1.0G" }, 93 /* Similar case it prints 1000 where it shouldn't */ 94 { 5, 1023488, "", 95 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 4, "1.0M" }, 96 { 5, 1023999, "", 97 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL, 4, "1.0M" }, 98 }; 99 100 struct hnflags { 101 int hf_flags; 102 const char *hf_name; 103 }; 104 105 const struct hnflags scale_flags[] = { 106 { HN_GETSCALE, "HN_GETSCALE" }, 107 { HN_AUTOSCALE, "HN_AUTOSCALE" }, 108 }; 109 const struct hnflags normal_flags[] = { 110 { HN_DECIMAL, "HN_DECIMAL" }, 111 { HN_NOSPACE, "HN_NOSPACE" }, 112 { HN_B, "HN_B" }, 113 { HN_DIVISOR_1000, "HN_DIVISOR_1000" }, 114 }; 115 116 const char * 117 formatflags(char *, size_t, const struct hnflags *, size_t, int); 118 void newline(void); 119 void w_printf(const char *, ...); 120 int main(int, char *[]); 121 122 const char * 123 formatflags(char *buf, size_t buflen, const struct hnflags *hfs, 124 size_t hfslen, int flags) 125 { 126 const struct hnflags *hf; 127 char *p = buf; 128 ssize_t len = buflen; 129 unsigned int i, found; 130 int n; 131 132 if (flags == 0) { 133 snprintf(buf, buflen, "0"); 134 return (buf); 135 } 136 for (i = found = 0; i < hfslen && flags & ~found; i++) { 137 hf = &hfs[i]; 138 if (flags & hf->hf_flags) { 139 found |= hf->hf_flags; 140 n = snprintf(p, len, "|%s", hf->hf_name); 141 if (n >= len) { 142 p = buf; 143 len = buflen; 144 /* Print `flags' as number */ 145 goto bad; 146 } 147 p += n; 148 len -= n; 149 } 150 } 151 flags &= ~found; 152 if (flags) 153 bad: 154 snprintf(p, len, "|0x%x", flags); 155 return (*buf == '|' ? buf + 1 : buf); 156 } 157 158 static int col, bol = 1; 159 void 160 newline(void) 161 { 162 163 fprintf(stderr, "\n"); 164 col = 0; 165 bol = 1; 166 } 167 168 void 169 w_printf(const char *fmt, ...) 170 { 171 char buf[80]; 172 va_list ap; 173 int n; 174 175 va_start(ap, fmt); 176 if (col >= 0) { 177 n = vsnprintf(buf, sizeof(buf), fmt, ap); 178 if (n >= (int)sizeof(buf)) { 179 col = -1; 180 goto overflow; 181 } else if (n == 0) 182 goto out; 183 184 if (!bol) { 185 if (col + n > 75) 186 fprintf(stderr, "\n "), col = 4; 187 else 188 fprintf(stderr, " "), col++; 189 } 190 fprintf(stderr, "%s", buf); 191 col += n; 192 bol = 0; 193 } else { 194 overflow: 195 vfprintf(stderr, fmt, ap); 196 } 197 out: 198 va_end(ap); 199 } 200 201 ATF_TC(humanize); 202 203 ATF_TC_HEAD(humanize, tc) 204 { 205 206 atf_tc_set_md_var(tc, "descr", "Test humanize_number(3)"); 207 } 208 209 ATF_TC_BODY(humanize, tc) 210 { 211 char fbuf[128]; 212 const struct hnopts *ho; 213 char *buf = NULL; 214 size_t buflen = 0; 215 unsigned int i; 216 int rv = 0; 217 218 for (i = 0; i < __arraycount(hnopts); i++) { 219 ho = &hnopts[i]; 220 if (buflen < ho->ho_len) { 221 buflen = ho->ho_len; 222 buf = realloc(buf, buflen); 223 if (buf == NULL) 224 atf_tc_fail("realloc(..., %d) failed", buflen); 225 } 226 227 rv = humanize_number(buf, ho->ho_len, ho->ho_num, 228 ho->ho_suffix, ho->ho_scale, ho->ho_flags); 229 230 if (rv == ho->ho_retval && 231 (rv == -1 || strcmp(buf, ho->ho_retstr) == 0)) 232 continue; 233 234 w_printf("humanize_number(\"%s\", %d, %" PRId64 ",", 235 ho->ho_retstr, ho->ho_len, ho->ho_num); 236 w_printf("\"%s\",", ho->ho_suffix); 237 w_printf("%s,", formatflags(fbuf, sizeof(fbuf), scale_flags, 238 sizeof(scale_flags) / sizeof(scale_flags[0]), 239 ho->ho_scale)); 240 w_printf("%s)", formatflags(fbuf, sizeof(fbuf), normal_flags, 241 sizeof(normal_flags) / sizeof(normal_flags[0]), 242 ho->ho_flags)); 243 w_printf("= %d,", ho->ho_retval); 244 w_printf("but got"); 245 w_printf("%d/[%s]", rv, rv == -1 ? "" : buf); 246 newline(); 247 atf_tc_fail_nonfatal("Failed for table entry %d", i); 248 } 249 } 250 251 ATF_TP_ADD_TCS(tp) 252 { 253 254 ATF_TP_ADD_TC(tp, humanize); 255 256 return atf_no_error(); 257 } 258