1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 John Baldwin <jhb@FreeBSD.org> 5 * Copyright (c) 2025 Dag-Erling Smørgrav <des@FreeBSD.org> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <atf-c.h> 30 #include <errno.h> 31 #include <libutil.h> 32 #include <stdint.h> 33 34 static void 35 require_success(const char *str, int64_t exp_val) 36 { 37 int64_t val; 38 39 ATF_REQUIRE_MSG(expand_number(str, &val) == 0, 40 "Failed to parse '%s': %m", str); 41 ATF_REQUIRE_MSG(val == exp_val, 42 "String '%s' parsed as %jd instead of expected %jd", str, 43 (intmax_t)val, (intmax_t)exp_val); 44 } 45 46 static void 47 require_error(const char *str, int exp_errno) 48 { 49 int64_t val; 50 51 ATF_REQUIRE_MSG(expand_number(str, &val) == -1, 52 "String '%s' parsed as %jd instead of error", str, (intmax_t)val); 53 ATF_REQUIRE_MSG(errno == exp_errno, 54 "String '%s' failed with %d instead of expected %d", str, errno, 55 exp_errno); 56 } 57 58 ATF_TC_WITHOUT_HEAD(expand_number__ok); 59 ATF_TC_BODY(expand_number__ok, tp) 60 { 61 /* Bare numbers. */ 62 require_success("-0", 0); 63 require_success(" 0", 0); 64 require_success("+0", 0); 65 require_success("-1", -1); 66 require_success(" 1", 1); 67 require_success("+1", 1); 68 require_success("-10", -10); 69 require_success(" 10", 10); 70 require_success("+10", 10); 71 72 /* Uppercase suffixes. */ 73 require_success("1B", 1); 74 require_success("1K", 1LL << 10); 75 require_success("1M", 1LL << 20); 76 require_success("1G", 1LL << 30); 77 require_success("1T", 1LL << 40); 78 require_success("1P", 1LL << 50); 79 require_success("1E", 1LL << 60); 80 81 /* Lowercase suffixes. */ 82 require_success("2b", 2); 83 require_success("2k", 2LL << 10); 84 require_success("2m", 2LL << 20); 85 require_success("2g", 2LL << 30); 86 require_success("2t", 2LL << 40); 87 require_success("2p", 2LL << 50); 88 require_success("2e", 2LL << 60); 89 90 /* Suffixes with a trailing 'b'. */ 91 require_success("3KB", 3LL << 10); 92 require_success("3MB", 3LL << 20); 93 require_success("3GB", 3LL << 30); 94 require_success("3TB", 3LL << 40); 95 require_success("3PB", 3LL << 50); 96 require_success("3EB", 3LL << 60); 97 98 /* Negative numbers. */ 99 require_success("-1", -1); 100 require_success("-10", -10); 101 require_success("-1B", -1); 102 require_success("-1K", -(1LL << 10)); 103 require_success("-1M", -(1LL << 20)); 104 require_success("-1G", -(1LL << 30)); 105 require_success("-1T", -(1LL << 40)); 106 require_success("-1P", -(1LL << 50)); 107 require_success("-1E", -(1LL << 60)); 108 require_success("-2b", -2); 109 require_success("-2k", -(2LL << 10)); 110 require_success("-2m", -(2LL << 20)); 111 require_success("-2g", -(2LL << 30)); 112 require_success("-2t", -(2LL << 40)); 113 require_success("-2p", -(2LL << 50)); 114 require_success("-2e", -(2LL << 60)); 115 require_success("-3KB", -(3LL << 10)); 116 require_success("-3MB", -(3LL << 20)); 117 require_success("-3GB", -(3LL << 30)); 118 require_success("-3TB", -(3LL << 40)); 119 require_success("-3PB", -(3LL << 50)); 120 require_success("-3EB", -(3LL << 60)); 121 122 /* Maximum values. */ 123 require_success("7E", 7LL << 60); 124 require_success("8191P", 8191LL << 50); 125 require_success("8388607T", 8388607LL << 40); 126 require_success("8589934591G", 8589934591LL << 30); 127 require_success("8796093022207M", 8796093022207LL << 20); 128 require_success("9007199254740991K", 9007199254740991LL << 10); 129 require_success("9223372036854775807", INT64_MAX); 130 131 /* Minimum values. */ 132 require_success("-7E", -(7LL << 60)); 133 require_success("-8191P", -(8191LL << 50)); 134 require_success("-8388607T", -(8388607LL << 40)); 135 require_success("-8589934591G", -(8589934591LL << 30)); 136 require_success("-8796093022207M", -(8796093022207LL << 20)); 137 require_success("-9007199254740991K", -(9007199254740991LL << 10)); 138 require_success("-9223372036854775808", INT64_MIN); 139 } 140 141 ATF_TC_WITHOUT_HEAD(expand_number__bad); 142 ATF_TC_BODY(expand_number__bad, tp) 143 { 144 /* No digits. */ 145 require_error("", EINVAL); 146 require_error("b", EINVAL); 147 require_error("k", EINVAL); 148 require_error("m", EINVAL); 149 require_error("g", EINVAL); 150 require_error("t", EINVAL); 151 require_error("p", EINVAL); 152 require_error("e", EINVAL); 153 require_error("-", EINVAL); 154 require_error("-b", EINVAL); 155 require_error("-k", EINVAL); 156 require_error("-m", EINVAL); 157 require_error("-g", EINVAL); 158 require_error("-t", EINVAL); 159 require_error("-p", EINVAL); 160 require_error("-e", EINVAL); 161 162 require_error("not_a_number", EINVAL); 163 164 /* Invalid suffixes. */ 165 require_error("1a", EINVAL); 166 require_error("1c", EINVAL); 167 require_error("1d", EINVAL); 168 require_error("1f", EINVAL); 169 require_error("1h", EINVAL); 170 require_error("1i", EINVAL); 171 require_error("1j", EINVAL); 172 require_error("1l", EINVAL); 173 require_error("1n", EINVAL); 174 require_error("1o", EINVAL); 175 require_error("1q", EINVAL); 176 require_error("1r", EINVAL); 177 require_error("1s", EINVAL); 178 require_error("1u", EINVAL); 179 require_error("1v", EINVAL); 180 require_error("1w", EINVAL); 181 require_error("1x", EINVAL); 182 require_error("1y", EINVAL); 183 require_error("1z", EINVAL); 184 185 /* Trailing garbage. */ 186 require_error("1K foo", EINVAL); 187 require_error("1Mfoo", EINVAL); 188 189 /* Overflow. */ 190 require_error("8E", ERANGE); 191 require_error("8192P", ERANGE); 192 require_error("8388608T", ERANGE); 193 require_error("8589934592G", ERANGE); 194 require_error("8796093022208M", ERANGE); 195 require_error("9007199254740992K", ERANGE); 196 require_error("9223372036854775808", ERANGE); 197 198 /* Multiple signs */ 199 require_error("--1", EINVAL); 200 require_error("-+1", EINVAL); 201 require_error("+-1", EINVAL); 202 require_error("++1", EINVAL); 203 204 /* Whitespace after the sign */ 205 require_error(" - 1", EINVAL); 206 require_error(" + 1", EINVAL); 207 } 208 209 ATF_TP_ADD_TCS(tp) 210 { 211 ATF_TP_ADD_TC(tp, expand_number__ok); 212 ATF_TP_ADD_TC(tp, expand_number__bad); 213 214 return (atf_no_error()); 215 } 216