xref: /6.0.3/platform/tests/getopt/getopt_test.cc (revision 38010ba3)
1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2#include <gtest/gtest.h>
3#include <platform/cb_malloc.h>
4#include <platform/cbassert.h>
5#include <platform/getopt.h>
6#include <cstdlib>
7#include <cstring>
8#include <iostream>
9#include <string>
10#include <vector>
11
12char **vec2array(const std::vector<std::string> &vec) {
13    auto** arr = new char*[vec.size()];
14    for (unsigned int ii = 0; ii < (unsigned int)vec.size(); ++ii) {
15        arr[ii] = cb_strdup(vec[ii].c_str());
16    }
17    return arr;
18}
19
20static void release(char **arr, size_t size) {
21    for (size_t ii = 0; ii < size; ++ii) {
22        cb_free(arr[ii]);
23    }
24    delete []arr;
25}
26
27typedef std::vector<std::string> getoptvec;
28
29class GetoptTest : public ::testing::Test {
30protected:
31    void SetUp() override {
32        cb::getopt::mute_stderr();
33        cb::getopt::reset();
34    }
35};
36
37TEST_F(GetoptTest, NormalWithOneUnknownProvided) {
38    getoptvec vec;
39    vec.push_back("program");
40    vec.push_back("-a");
41    vec.push_back("-b");
42    auto argc = (int)vec.size();
43    auto** argv = vec2array(vec);
44    ASSERT_EQ(1, cb::getopt::optind);
45    ASSERT_EQ('a', cb::getopt::getopt(argc, argv, "a"));
46    ASSERT_EQ(2, cb::getopt::optind);
47    ASSERT_EQ('?', cb::getopt::getopt(argc, argv, "a"));
48    ASSERT_EQ(3, cb::getopt::optind);
49
50    release(argv, vec.size());
51}
52
53TEST_F(GetoptTest, NormalWithTermination) {
54    getoptvec vec;
55    vec.push_back("program");
56    vec.push_back("-a");
57    vec.push_back("--");
58    vec.push_back("-b");
59    auto argc = (int)vec.size();
60    auto** argv = vec2array(vec);
61    ASSERT_EQ('a', cb::getopt::getopt(argc, argv, "a"));
62    ASSERT_EQ(-1, cb::getopt::getopt(argc, argv, "a"));
63    ASSERT_EQ(3, cb::getopt::optind);
64
65    release(argv, vec.size());
66}
67
68TEST_F(GetoptTest, RegressionTestFromEpEngine) {
69    getoptvec vec;
70    vec.push_back("..\\memcached\\engine_testapp");
71    vec.push_back("-E");
72    vec.push_back("ep.dll");
73    vec.push_back("-T");
74    vec.push_back("ep_testsuite.dll");
75    vec.push_back("-e");
76    vec.push_back("flushall_enabled=true;ht_size=13;ht_locks=7");
77    vec.push_back("-v");
78    vec.push_back("-C");
79    vec.push_back("7");
80    vec.push_back("-s");
81    vec.push_back("foo");
82
83    auto argc = (int)vec.size();
84    auto** argv = vec2array(vec);
85
86    ASSERT_EQ('E', cb::getopt::getopt(argc, argv, "E:T:e:vC:s"));
87    ASSERT_STREQ(argv[2], cb::getopt::optarg);
88    ASSERT_EQ('T', cb::getopt::getopt(argc, argv, "E:T:e:vC:s"));
89    ASSERT_STREQ(argv[4], cb::getopt::optarg);
90    ASSERT_EQ('e', cb::getopt::getopt(argc, argv, "E:T:e:vC:s"));
91    ASSERT_STREQ(argv[6], cb::getopt::optarg);
92    ASSERT_EQ('v', cb::getopt::getopt(argc, argv, "E:T:e:vC:s"));
93    ASSERT_EQ('C', cb::getopt::getopt(argc, argv, "E:T:e:vC:s"));
94    ASSERT_STREQ(argv[9], cb::getopt::optarg);
95    ASSERT_EQ('s', cb::getopt::getopt(argc, argv, "E:T:e:vC:s"));
96    ASSERT_EQ(-1, cb::getopt::getopt(argc, argv, "E:T:e:vC:s"));
97    ASSERT_EQ(11, cb::getopt::optind);
98
99    release(argv, vec.size());
100}
101
102TEST_F(GetoptTest, TestLongOptions) {
103    static cb::getopt::option long_options[] =
104    {
105        {"first",  cb::getopt::no_argument, 0, 'f'},
106        {"second", cb::getopt::no_argument, 0, 's'},
107        {"third",  cb::getopt::no_argument, 0, 't'},
108        {0, 0, 0, 0}
109    };
110
111    getoptvec vec;
112
113    vec.push_back("getopt_long_test");
114    vec.push_back("--first");
115    vec.push_back("--wrong");
116    vec.push_back("--second");
117    vec.push_back("--third");
118
119    auto argc = (int)vec.size();
120    auto** argv = vec2array(vec);
121
122    int option_index = 0;
123    int c = 1;
124
125    bool first, second, third;
126    first = second = third = false;
127
128    while ( (c = cb::getopt::getopt_long(argc, argv, "fst",
129                             long_options, &option_index)) != -1 )  {
130        switch (c) {
131        case 'f':
132            first = true;
133            break;
134        case 's':
135            second = true;
136            break;
137        case 't':
138            third = true;
139            break;
140        }
141    }
142    EXPECT_TRUE(first) << "--first not found";
143    EXPECT_TRUE(second) << "--second not found";
144    EXPECT_TRUE(third) << "--third not found";
145
146    release(argv, vec.size());
147}
148
149TEST_F(GetoptTest, TestLongOptionsWithArguments) {
150    static cb::getopt::option long_options[] = {
151            {"host", cb::getopt::required_argument, nullptr, 'h'},
152            {"port", cb::getopt::required_argument, nullptr, 'p'},
153            {nullptr, 0, nullptr, 0}};
154
155    getoptvec vec;
156
157    vec.push_back("TestLongOptionsWithArguments");
158    vec.push_back("--host=localhost");
159    vec.push_back("--port");
160    vec.push_back("11210");
161
162    auto argc = (int)vec.size();
163    auto** argv = vec2array(vec);
164
165    int option_index = 0;
166    int c;
167
168    std::string host;
169    std::string port;
170
171    while ((c = cb::getopt::getopt_long(
172                    argc, argv, "h:p:", long_options, &option_index)) != -1) {
173        switch (c) {
174        case 'h':
175            ASSERT_NE(nullptr, cb::getopt::optarg)
176                    << "host should have argument";
177            host.assign(cb::getopt::optarg);
178            break;
179        case 'p':
180            ASSERT_NE(nullptr, cb::getopt::optarg)
181                    << "port should have argument";
182            port.assign(cb::getopt::optarg);
183            break;
184        default:
185            FAIL() << "getopt_long returned " << char(c);
186        }
187    }
188
189    EXPECT_EQ(host, "localhost");
190    EXPECT_EQ(port, "11210");
191
192    release(argv, vec.size());
193}
194
195TEST_F(GetoptTest, TestLongOptionsWithMissingLastArguments) {
196    static cb::getopt::option long_options[] = {
197            {"port", cb::getopt::required_argument, nullptr, 'p'},
198            {nullptr, 0, nullptr, 0}};
199
200    getoptvec vec;
201
202    vec.push_back("TestLongOptionsWithMissingLastArguments");
203    vec.push_back("--port");
204
205    auto argc = (int)vec.size();
206    auto** argv = vec2array(vec);
207
208    int option_index = 0;
209    ASSERT_EQ('?',
210              cb::getopt::getopt_long(
211                      argc, argv, "p:", long_options, &option_index));
212
213    release(argv, vec.size());
214}
215
216TEST_F(GetoptTest, TestLongOptionsWithOptionalArguments) {
217    static cb::getopt::option long_options[] = {
218            {"none", cb::getopt::optional_argument, nullptr, 'n'},
219            {"with", cb::getopt::optional_argument, nullptr, 'w'},
220            {nullptr, 0, nullptr, 0}};
221
222    getoptvec vec;
223
224    vec.push_back("TestLongOptionsWithOptionalArguments");
225    vec.push_back("--none");
226    vec.push_back("--with=true");
227
228    auto argc = (int)vec.size();
229    auto** argv = vec2array(vec);
230
231    int option_index = 0;
232    int c;
233    bool none = false;
234    bool with = false;
235
236    while ((c = cb::getopt::getopt_long(
237                    argc, argv, "n:w:", long_options, &option_index)) != -1) {
238        switch (c) {
239        case 'n':
240            ASSERT_EQ(nullptr, cb::getopt::optarg);
241            none = true;
242            break;
243        case 'w':
244            ASSERT_STREQ("true", cb::getopt::optarg);
245            with = true;
246            break;
247        default:
248            FAIL() << "getopt_long returned " << char(c);
249        }
250    }
251
252    EXPECT_TRUE(none);
253    EXPECT_TRUE(with);
254
255    release(argv, vec.size());
256}