// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2020 Sean Anderson * * Portions of these tests were inspired by glibc's posix/bug-getopt1.c and * posix/tst-getopt-cancel.c */ #include #include #include #include #include static int do_test_getopt(struct unit_test_state *uts, int line, struct getopt_state *gs, const char *optstring, int args, char *argv[], int expected_count, int expected[]) { int opt; getopt_init_state(gs); for (int i = 0; i < expected_count; i++) { opt = getopt_silent(gs, args, argv, optstring); if (expected[i] != opt) { /* * Fudge the line number so we can tell which test * failed */ ut_failf(uts, __FILE__, line, __func__, "expected[i] == getopt()", "Expected '%c' (%d) with i=%d, got '%c' (%d)", expected[i], expected[i], i, opt, opt); return CMD_RET_FAILURE; } } opt = getopt_silent(gs, args, argv, optstring); if (opt != -1) { ut_failf(uts, __FILE__, line, __func__, "getopt() != -1", "Expected -1, got '%c' (%d)", opt, opt); return CMD_RET_FAILURE; } return 0; } #define test_getopt(optstring, argv, expected) do { \ int ret = do_test_getopt(uts, __LINE__, &gs, optstring, \ ARRAY_SIZE(argv) - 1, argv, \ ARRAY_SIZE(expected), expected); \ if (ret) \ return ret; \ } while (0) static int lib_test_getopt(struct unit_test_state *uts) { struct getopt_state gs; /* Happy path */ test_getopt("ab:c", ((char *[]){ "program", "-cb", "x", "-a", "foo", 0 }), ((int []){ 'c', 'b', 'a' })); ut_asserteq(4, gs.index); /* Make sure we pick up the optional argument */ test_getopt("a::b:c", ((char *[]){ "program", "-cbx", "-a", "foo", 0 }), ((int []){ 'c', 'b', 'a' })); ut_asserteq(4, gs.index); /* Test required arguments */ test_getopt("a:b", ((char *[]){ "program", "-a", 0 }), ((int []){ ':' })); ut_asserteq('a', gs.opt); test_getopt("a:b", ((char *[]){ "program", "-b", "-a", 0 }), ((int []){ 'b', ':' })); ut_asserteq('a', gs.opt); /* Test invalid arguments */ test_getopt("ab:c", ((char *[]){ "program", "-d", 0 }), ((int []){ '?' })); ut_asserteq('d', gs.opt); /* Test arg */ test_getopt("a::b:c", ((char *[]){ "program", "-a", 0 }), ((int []){ 'a' })); ut_asserteq(2, gs.index); ut_assertnull(gs.arg); test_getopt("a::b:c", ((char *[]){ "program", "-afoo", 0 }), ((int []){ 'a' })); ut_asserteq(2, gs.index); ut_assertnonnull(gs.arg); ut_asserteq_str("foo", gs.arg); test_getopt("a::b:c", ((char *[]){ "program", "-a", "foo", 0 }), ((int []){ 'a' })); ut_asserteq(3, gs.index); ut_assertnonnull(gs.arg); ut_asserteq_str("foo", gs.arg); test_getopt("a::b:c", ((char *[]){ "program", "-bfoo", 0 }), ((int []){ 'b' })); ut_asserteq(2, gs.index); ut_assertnonnull(gs.arg); ut_asserteq_str("foo", gs.arg); test_getopt("a::b:c", ((char *[]){ "program", "-b", "foo", 0 }), ((int []){ 'b' })); ut_asserteq(3, gs.index); ut_assertnonnull(gs.arg); ut_asserteq_str("foo", gs.arg); return 0; } LIB_TEST(lib_test_getopt, 0);