1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
4 *
5 * Portions of these tests were inspired by glibc's posix/bug-getopt1.c and
6 * posix/tst-getopt-cancel.c
7 */
8
9 #include <common.h>
10 #include <getopt.h>
11 #include <test/lib.h>
12 #include <test/test.h>
13 #include <test/ut.h>
14
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[])15 static int do_test_getopt(struct unit_test_state *uts, int line,
16 struct getopt_state *gs, const char *optstring,
17 int args, char *argv[], int expected_count,
18 int expected[])
19 {
20 int opt;
21
22 getopt_init_state(gs);
23 for (int i = 0; i < expected_count; i++) {
24 opt = getopt_silent(gs, args, argv, optstring);
25 if (expected[i] != opt) {
26 /*
27 * Fudge the line number so we can tell which test
28 * failed
29 */
30 ut_failf(uts, __FILE__, line, __func__,
31 "expected[i] == getopt()",
32 "Expected '%c' (%d) with i=%d, got '%c' (%d)",
33 expected[i], expected[i], i, opt, opt);
34 return CMD_RET_FAILURE;
35 }
36 }
37
38 opt = getopt_silent(gs, args, argv, optstring);
39 if (opt != -1) {
40 ut_failf(uts, __FILE__, line, __func__,
41 "getopt() != -1",
42 "Expected -1, got '%c' (%d)", opt, opt);
43 return CMD_RET_FAILURE;
44 }
45
46 return 0;
47 }
48
49 #define test_getopt(optstring, argv, expected) do { \
50 int ret = do_test_getopt(uts, __LINE__, &gs, optstring, \
51 ARRAY_SIZE(argv) - 1, argv, \
52 ARRAY_SIZE(expected), expected); \
53 if (ret) \
54 return ret; \
55 } while (0)
56
lib_test_getopt(struct unit_test_state * uts)57 static int lib_test_getopt(struct unit_test_state *uts)
58 {
59 struct getopt_state gs;
60
61 /* Happy path */
62 test_getopt("ab:c",
63 ((char *[]){ "program", "-cb", "x", "-a", "foo", 0 }),
64 ((int []){ 'c', 'b', 'a' }));
65 ut_asserteq(4, gs.index);
66
67 /* Make sure we pick up the optional argument */
68 test_getopt("a::b:c",
69 ((char *[]){ "program", "-cbx", "-a", "foo", 0 }),
70 ((int []){ 'c', 'b', 'a' }));
71 ut_asserteq(4, gs.index);
72
73 /* Test required arguments */
74 test_getopt("a:b", ((char *[]){ "program", "-a", 0 }),
75 ((int []){ ':' }));
76 ut_asserteq('a', gs.opt);
77 test_getopt("a:b", ((char *[]){ "program", "-b", "-a", 0 }),
78 ((int []){ 'b', ':' }));
79 ut_asserteq('a', gs.opt);
80
81 /* Test invalid arguments */
82 test_getopt("ab:c", ((char *[]){ "program", "-d", 0 }),
83 ((int []){ '?' }));
84 ut_asserteq('d', gs.opt);
85
86 /* Test arg */
87 test_getopt("a::b:c",
88 ((char *[]){ "program", "-a", 0 }),
89 ((int []){ 'a' }));
90 ut_asserteq(2, gs.index);
91 ut_assertnull(gs.arg);
92
93 test_getopt("a::b:c",
94 ((char *[]){ "program", "-afoo", 0 }),
95 ((int []){ 'a' }));
96 ut_asserteq(2, gs.index);
97 ut_assertnonnull(gs.arg);
98 ut_asserteq_str("foo", gs.arg);
99
100 test_getopt("a::b:c",
101 ((char *[]){ "program", "-a", "foo", 0 }),
102 ((int []){ 'a' }));
103 ut_asserteq(3, gs.index);
104 ut_assertnonnull(gs.arg);
105 ut_asserteq_str("foo", gs.arg);
106
107 test_getopt("a::b:c",
108 ((char *[]){ "program", "-bfoo", 0 }),
109 ((int []){ 'b' }));
110 ut_asserteq(2, gs.index);
111 ut_assertnonnull(gs.arg);
112 ut_asserteq_str("foo", gs.arg);
113
114 test_getopt("a::b:c",
115 ((char *[]){ "program", "-b", "foo", 0 }),
116 ((int []){ 'b' }));
117 ut_asserteq(3, gs.index);
118 ut_assertnonnull(gs.arg);
119 ut_asserteq_str("foo", gs.arg);
120
121 return 0;
122 }
123 LIB_TEST(lib_test_getopt, 0);
124