1*71db0c75SAndroid Build Coastguard Worker //===-- Unittests for getopt ----------------------------------------------===//
2*71db0c75SAndroid Build Coastguard Worker //
3*71db0c75SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*71db0c75SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information.
5*71db0c75SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*71db0c75SAndroid Build Coastguard Worker //
7*71db0c75SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*71db0c75SAndroid Build Coastguard Worker
9*71db0c75SAndroid Build Coastguard Worker #include "src/unistd/getopt.h"
10*71db0c75SAndroid Build Coastguard Worker #include "test/UnitTest/Test.h"
11*71db0c75SAndroid Build Coastguard Worker
12*71db0c75SAndroid Build Coastguard Worker #include "src/__support/CPP/array.h"
13*71db0c75SAndroid Build Coastguard Worker #include "src/stdio/fflush.h"
14*71db0c75SAndroid Build Coastguard Worker #include "src/stdio/fopencookie.h"
15*71db0c75SAndroid Build Coastguard Worker
16*71db0c75SAndroid Build Coastguard Worker using LIBC_NAMESPACE::cpp::array;
17*71db0c75SAndroid Build Coastguard Worker
18*71db0c75SAndroid Build Coastguard Worker namespace test_globals {
19*71db0c75SAndroid Build Coastguard Worker char *optarg;
20*71db0c75SAndroid Build Coastguard Worker int optind = 1;
21*71db0c75SAndroid Build Coastguard Worker int optopt;
22*71db0c75SAndroid Build Coastguard Worker int opterr = 1;
23*71db0c75SAndroid Build Coastguard Worker
24*71db0c75SAndroid Build Coastguard Worker unsigned optpos;
25*71db0c75SAndroid Build Coastguard Worker } // namespace test_globals
26*71db0c75SAndroid Build Coastguard Worker
27*71db0c75SAndroid Build Coastguard Worker // This can't be a constructor because it will get run before the constructor
28*71db0c75SAndroid Build Coastguard Worker // which sets the default state in getopt.
set_state(FILE * errstream)29*71db0c75SAndroid Build Coastguard Worker void set_state(FILE *errstream) {
30*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::impl::set_getopt_state(
31*71db0c75SAndroid Build Coastguard Worker &test_globals::optarg, &test_globals::optind, &test_globals::optopt,
32*71db0c75SAndroid Build Coastguard Worker &test_globals::optpos, &test_globals::opterr, errstream);
33*71db0c75SAndroid Build Coastguard Worker }
34*71db0c75SAndroid Build Coastguard Worker
my_memcpy(char * dest,const char * src,size_t size)35*71db0c75SAndroid Build Coastguard Worker static void my_memcpy(char *dest, const char *src, size_t size) {
36*71db0c75SAndroid Build Coastguard Worker for (size_t i = 0; i < size; i++)
37*71db0c75SAndroid Build Coastguard Worker dest[i] = src[i];
38*71db0c75SAndroid Build Coastguard Worker }
39*71db0c75SAndroid Build Coastguard Worker
cookie_write(void * cookie,const char * buf,size_t size)40*71db0c75SAndroid Build Coastguard Worker ssize_t cookie_write(void *cookie, const char *buf, size_t size) {
41*71db0c75SAndroid Build Coastguard Worker char **pos = static_cast<char **>(cookie);
42*71db0c75SAndroid Build Coastguard Worker my_memcpy(*pos, buf, size);
43*71db0c75SAndroid Build Coastguard Worker *pos += size;
44*71db0c75SAndroid Build Coastguard Worker return size;
45*71db0c75SAndroid Build Coastguard Worker }
46*71db0c75SAndroid Build Coastguard Worker
47*71db0c75SAndroid Build Coastguard Worker static cookie_io_functions_t cookie{nullptr, &cookie_write, nullptr, nullptr};
48*71db0c75SAndroid Build Coastguard Worker
49*71db0c75SAndroid Build Coastguard Worker // TODO: <stdio> could be either llvm-libc's or the system libc's. The former
50*71db0c75SAndroid Build Coastguard Worker // doesn't currently support fmemopen but does have fopencookie. In the future
51*71db0c75SAndroid Build Coastguard Worker // just use that instead. This memopen does no error checking for the size
52*71db0c75SAndroid Build Coastguard Worker // of the buffer, etc.
memopen(char ** pos)53*71db0c75SAndroid Build Coastguard Worker FILE *memopen(char **pos) {
54*71db0c75SAndroid Build Coastguard Worker return LIBC_NAMESPACE::fopencookie(pos, "w", cookie);
55*71db0c75SAndroid Build Coastguard Worker }
56*71db0c75SAndroid Build Coastguard Worker
57*71db0c75SAndroid Build Coastguard Worker struct LlvmLibcGetoptTest : public LIBC_NAMESPACE::testing::Test {
58*71db0c75SAndroid Build Coastguard Worker FILE *errstream;
59*71db0c75SAndroid Build Coastguard Worker char buf[256];
60*71db0c75SAndroid Build Coastguard Worker char *pos = buf;
61*71db0c75SAndroid Build Coastguard Worker
reset_errstreamLlvmLibcGetoptTest62*71db0c75SAndroid Build Coastguard Worker void reset_errstream() { pos = buf; }
get_error_msgLlvmLibcGetoptTest63*71db0c75SAndroid Build Coastguard Worker const char *get_error_msg() {
64*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fflush(errstream);
65*71db0c75SAndroid Build Coastguard Worker return buf;
66*71db0c75SAndroid Build Coastguard Worker }
67*71db0c75SAndroid Build Coastguard Worker
SetUpLlvmLibcGetoptTest68*71db0c75SAndroid Build Coastguard Worker void SetUp() override {
69*71db0c75SAndroid Build Coastguard Worker ASSERT_TRUE(!!(errstream = memopen(&pos)));
70*71db0c75SAndroid Build Coastguard Worker set_state(errstream);
71*71db0c75SAndroid Build Coastguard Worker ASSERT_EQ(test_globals::optind, 1);
72*71db0c75SAndroid Build Coastguard Worker }
73*71db0c75SAndroid Build Coastguard Worker
TearDownLlvmLibcGetoptTest74*71db0c75SAndroid Build Coastguard Worker void TearDown() override {
75*71db0c75SAndroid Build Coastguard Worker test_globals::optind = 1;
76*71db0c75SAndroid Build Coastguard Worker test_globals::opterr = 1;
77*71db0c75SAndroid Build Coastguard Worker }
78*71db0c75SAndroid Build Coastguard Worker };
79*71db0c75SAndroid Build Coastguard Worker
80*71db0c75SAndroid Build Coastguard Worker // This is safe because getopt doesn't currently permute argv like GNU's getopt
81*71db0c75SAndroid Build Coastguard Worker // does so this just helps silence warnings.
operator ""_c(const char * c,size_t)82*71db0c75SAndroid Build Coastguard Worker char *operator"" _c(const char *c, size_t) { return const_cast<char *>(c); }
83*71db0c75SAndroid Build Coastguard Worker
TEST_F(LlvmLibcGetoptTest,NoMatch)84*71db0c75SAndroid Build Coastguard Worker TEST_F(LlvmLibcGetoptTest, NoMatch) {
85*71db0c75SAndroid Build Coastguard Worker array<char *, 3> argv{"prog"_c, "arg1"_c, nullptr};
86*71db0c75SAndroid Build Coastguard Worker
87*71db0c75SAndroid Build Coastguard Worker // optind >= argc
88*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(1, argv.data(), "..."), -1);
89*71db0c75SAndroid Build Coastguard Worker
90*71db0c75SAndroid Build Coastguard Worker // argv[optind] == nullptr
91*71db0c75SAndroid Build Coastguard Worker test_globals::optind = 2;
92*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(100, argv.data(), "..."), -1);
93*71db0c75SAndroid Build Coastguard Worker
94*71db0c75SAndroid Build Coastguard Worker // argv[optind][0] != '-'
95*71db0c75SAndroid Build Coastguard Worker test_globals::optind = 1;
96*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "a"), -1);
97*71db0c75SAndroid Build Coastguard Worker ASSERT_EQ(test_globals::optind, 1);
98*71db0c75SAndroid Build Coastguard Worker
99*71db0c75SAndroid Build Coastguard Worker // argv[optind] == "-"
100*71db0c75SAndroid Build Coastguard Worker argv[1] = "-"_c;
101*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "a"), -1);
102*71db0c75SAndroid Build Coastguard Worker ASSERT_EQ(test_globals::optind, 1);
103*71db0c75SAndroid Build Coastguard Worker
104*71db0c75SAndroid Build Coastguard Worker // argv[optind] == "--", then return -1 and incremement optind
105*71db0c75SAndroid Build Coastguard Worker argv[1] = "--"_c;
106*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "a"), -1);
107*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(test_globals::optind, 2);
108*71db0c75SAndroid Build Coastguard Worker }
109*71db0c75SAndroid Build Coastguard Worker
TEST_F(LlvmLibcGetoptTest,WrongMatch)110*71db0c75SAndroid Build Coastguard Worker TEST_F(LlvmLibcGetoptTest, WrongMatch) {
111*71db0c75SAndroid Build Coastguard Worker array<char *, 3> argv{"prog"_c, "-b"_c, nullptr};
112*71db0c75SAndroid Build Coastguard Worker
113*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "a"), int('?'));
114*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(test_globals::optopt, (int)'b');
115*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(test_globals::optind, 1);
116*71db0c75SAndroid Build Coastguard Worker EXPECT_STREQ(get_error_msg(), "prog: illegal option -- b\n");
117*71db0c75SAndroid Build Coastguard Worker }
118*71db0c75SAndroid Build Coastguard Worker
TEST_F(LlvmLibcGetoptTest,OpterrFalse)119*71db0c75SAndroid Build Coastguard Worker TEST_F(LlvmLibcGetoptTest, OpterrFalse) {
120*71db0c75SAndroid Build Coastguard Worker array<char *, 3> argv{"prog"_c, "-b"_c, nullptr};
121*71db0c75SAndroid Build Coastguard Worker
122*71db0c75SAndroid Build Coastguard Worker test_globals::opterr = 0;
123*71db0c75SAndroid Build Coastguard Worker set_state(errstream);
124*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "a"), int('?'));
125*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(test_globals::optopt, (int)'b');
126*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(test_globals::optind, 1);
127*71db0c75SAndroid Build Coastguard Worker EXPECT_STREQ(get_error_msg(), "");
128*71db0c75SAndroid Build Coastguard Worker }
129*71db0c75SAndroid Build Coastguard Worker
TEST_F(LlvmLibcGetoptTest,MissingArg)130*71db0c75SAndroid Build Coastguard Worker TEST_F(LlvmLibcGetoptTest, MissingArg) {
131*71db0c75SAndroid Build Coastguard Worker array<char *, 3> argv{"prog"_c, "-b"_c, nullptr};
132*71db0c75SAndroid Build Coastguard Worker
133*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), ":b:"), (int)':');
134*71db0c75SAndroid Build Coastguard Worker ASSERT_EQ(test_globals::optind, 1);
135*71db0c75SAndroid Build Coastguard Worker EXPECT_STREQ(get_error_msg(), "prog: option requires an argument -- b\n");
136*71db0c75SAndroid Build Coastguard Worker reset_errstream();
137*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "b:"), int('?'));
138*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(test_globals::optind, 1);
139*71db0c75SAndroid Build Coastguard Worker EXPECT_STREQ(get_error_msg(), "prog: option requires an argument -- b\n");
140*71db0c75SAndroid Build Coastguard Worker }
141*71db0c75SAndroid Build Coastguard Worker
TEST_F(LlvmLibcGetoptTest,ParseArgInCurrent)142*71db0c75SAndroid Build Coastguard Worker TEST_F(LlvmLibcGetoptTest, ParseArgInCurrent) {
143*71db0c75SAndroid Build Coastguard Worker array<char *, 3> argv{"prog"_c, "-barg"_c, nullptr};
144*71db0c75SAndroid Build Coastguard Worker
145*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "b:"), (int)'b');
146*71db0c75SAndroid Build Coastguard Worker EXPECT_STREQ(test_globals::optarg, "arg");
147*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(test_globals::optind, 2);
148*71db0c75SAndroid Build Coastguard Worker }
149*71db0c75SAndroid Build Coastguard Worker
TEST_F(LlvmLibcGetoptTest,ParseArgInNext)150*71db0c75SAndroid Build Coastguard Worker TEST_F(LlvmLibcGetoptTest, ParseArgInNext) {
151*71db0c75SAndroid Build Coastguard Worker array<char *, 4> argv{"prog"_c, "-b"_c, "arg"_c, nullptr};
152*71db0c75SAndroid Build Coastguard Worker
153*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(3, argv.data(), "b:"), (int)'b');
154*71db0c75SAndroid Build Coastguard Worker EXPECT_STREQ(test_globals::optarg, "arg");
155*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(test_globals::optind, 3);
156*71db0c75SAndroid Build Coastguard Worker }
157*71db0c75SAndroid Build Coastguard Worker
TEST_F(LlvmLibcGetoptTest,ParseMutliInOne)158*71db0c75SAndroid Build Coastguard Worker TEST_F(LlvmLibcGetoptTest, ParseMutliInOne) {
159*71db0c75SAndroid Build Coastguard Worker array<char *, 3> argv{"prog"_c, "-abc"_c, nullptr};
160*71db0c75SAndroid Build Coastguard Worker
161*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "abc"), (int)'a');
162*71db0c75SAndroid Build Coastguard Worker ASSERT_EQ(test_globals::optind, 1);
163*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "abc"), (int)'b');
164*71db0c75SAndroid Build Coastguard Worker ASSERT_EQ(test_globals::optind, 1);
165*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(LIBC_NAMESPACE::getopt(2, argv.data(), "abc"), (int)'c');
166*71db0c75SAndroid Build Coastguard Worker EXPECT_EQ(test_globals::optind, 2);
167*71db0c75SAndroid Build Coastguard Worker }
168