Index: lib/libutil/tests/Makefile =================================================================== --- lib/libutil/tests/Makefile +++ lib/libutil/tests/Makefile @@ -1,5 +1,7 @@ # $FreeBSD$ +ATF_TESTS_C+= expand_number_test + TAP_TESTS_C+= flopen_test TAP_TESTS_C+= grp_test TAP_TESTS_C+= humanize_number_test Index: lib/libutil/tests/expand_number_test.c =================================================================== --- /dev/null +++ lib/libutil/tests/expand_number_test.c @@ -0,0 +1,203 @@ +/*- + * Copyright (c) 2019 John Baldwin + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +static void +require_success(const char *str, uint64_t exp_val) +{ + uint64_t val; + + ATF_REQUIRE_MSG(expand_number(str, &val) == 0, + "Failed to parse '%s': %s", str, strerror(errno)); + ATF_REQUIRE_MSG(val == exp_val, + "String '%s' parsed as %ju instead of expected %ju", str, + (uintmax_t)val, (uintmax_t)exp_val); +} + +static void +require_error(const char *str, int exp_errno) +{ + uint64_t val; + + ATF_REQUIRE_MSG(expand_number(str, &val) == -1, + "String '%s' parsed as %ju instead of error", str, (uintmax_t)val); + ATF_REQUIRE_MSG(errno == exp_errno, + "String '%s' failed with %d instead of expected %d", str, errno, + exp_errno); +} + +ATF_TC_WITHOUT_HEAD(expand_number__ok); +ATF_TC_BODY(expand_number__ok, tp) +{ + + /* Bare numbers. */ + require_success("0", 0); + require_success("1", 1); + require_success("10", 10); + + /* Uppercase suffixes. */ + require_success("1B", (uint64_t)1); + require_success("1K", (uint64_t)1 << 10); + require_success("1M", (uint64_t)1 << 20); + require_success("1G", (uint64_t)1 << 30); + require_success("1T", (uint64_t)1 << 40); + require_success("1P", (uint64_t)1 << 50); + require_success("1E", (uint64_t)1 << 60); + + /* Lowercase suffixes. */ + require_success("2b", (uint64_t)2); + require_success("2k", (uint64_t)2 << 10); + require_success("2m", (uint64_t)2 << 20); + require_success("2g", (uint64_t)2 << 30); + require_success("2t", (uint64_t)2 << 40); + require_success("2p", (uint64_t)2 << 50); + require_success("2e", (uint64_t)2 << 60); + + /* Suffixes with a trailing 'b'. */ + require_success("3KB", (uint64_t)3 << 10); + require_success("3MB", (uint64_t)3 << 20); + require_success("3GB", (uint64_t)3 << 30); + require_success("3TB", (uint64_t)3 << 40); + require_success("3PB", (uint64_t)3 << 50); + require_success("3EB", (uint64_t)3 << 60); + + /* Negative numbers. */ + require_success("-1", (uint64_t)-1); + require_success("-10", (uint64_t)-10); + require_success("-1B", (uint64_t)-1); +#if 0 + /* XXX: These don't work yet. */ + require_success("-1K", (uint64_t)-1 << 10); + require_success("-1M", (uint64_t)-1 << 20); + require_success("-1G", (uint64_t)-1 << 30); + require_success("-1T", (uint64_t)-1 << 40); + require_success("-1P", (uint64_t)-1 << 50); + require_success("-1E", (uint64_t)-1 << 60); + require_success("-2b", (uint64_t)-2); + require_success("-2k", (uint64_t)-2 << 10); + require_success("-2m", (uint64_t)-2 << 20); + require_success("-2g", (uint64_t)-2 << 30); + require_success("-2t", (uint64_t)-2 << 40); + require_success("-2p", (uint64_t)-2 << 50); + require_success("-2e", (uint64_t)-2 << 60); + require_success("-3KB", (uint64_t)-3 << 10); + require_success("-3MB", (uint64_t)-3 << 20); + require_success("-3GB", (uint64_t)-3 << 30); + require_success("-3TB", (uint64_t)-3 << 40); + require_success("-3PB", (uint64_t)-3 << 50); + require_success("-3EB", (uint64_t)-3 << 60); +#endif + + /* Maximum values. */ + require_success("15E", (uint64_t)15 << 60); + require_success("16383P", (uint64_t)16383 << 50); + require_success("16777215T", (uint64_t)16777215 << 40); + require_success("17179869183G", (uint64_t)17179869183 << 30); + require_success("17592186044415M", (uint64_t)17592186044415 << 20); + require_success("18014398509481983K", (uint64_t)18014398509481983 << 10); + require_success("18446744073709551615", 18446744073709551615U); + + /* + * XXX: Should this be allowed or should expand_number require + * decimal? + */ + require_success("0x10", 16); +} + +ATF_TC_WITHOUT_HEAD(expand_number__bad); +ATF_TC_BODY(expand_number__bad, tp) +{ + + /* No digits. */ + require_error("", EINVAL); + require_error("b", EINVAL); + require_error("k", EINVAL); + require_error("m", EINVAL); + require_error("g", EINVAL); + require_error("t", EINVAL); + require_error("p", EINVAL); + require_error("e", EINVAL); + require_error("-", EINVAL); + require_error("-b", EINVAL); + require_error("-k", EINVAL); + require_error("-m", EINVAL); + require_error("-g", EINVAL); + require_error("-t", EINVAL); + require_error("-p", EINVAL); + require_error("-e", EINVAL); + + require_error("not_a_number", EINVAL); + + /* Invalid suffixes. */ + require_error("1a", EINVAL); + require_error("1c", EINVAL); + require_error("1d", EINVAL); + require_error("1f", EINVAL); + require_error("1h", EINVAL); + require_error("1i", EINVAL); + require_error("1j", EINVAL); + require_error("1l", EINVAL); + require_error("1n", EINVAL); + require_error("1o", EINVAL); + require_error("1q", EINVAL); + require_error("1r", EINVAL); + require_error("1s", EINVAL); + require_error("1u", EINVAL); + require_error("1v", EINVAL); + require_error("1w", EINVAL); + require_error("1x", EINVAL); + require_error("1y", EINVAL); + require_error("1z", EINVAL); + + /* Trailing garbage. */ +#if 0 + require_error("1K foo", EINVAL); + require_error("1Mfoo", EINVAL); +#endif + + /* Overflow. */ + require_error("16E", ERANGE); + require_error("16384P", ERANGE); + require_error("16777216T", ERANGE); + require_error("17179869184G", ERANGE); + require_error("17592186044416M", ERANGE); + require_error("18014398509481984K", ERANGE); + require_error("18446744073709551616", ERANGE); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, expand_number__ok); + ATF_TP_ADD_TC(tp, expand_number__bad); + + return (atf_no_error()); +}