]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/ceph_argparse.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / test / ceph_argparse.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include "common/ceph_argparse.h"
16
17 #include "gtest/gtest.h"
18 #include <vector>
19 #include "include/stringify.h"
20
21 using namespace std;
22
23 /* Holds a std::vector with C-strings.
24 * Will free() them properly in the destructor.
25 *
26 * Note: the ceph_argparse functions modify the vector, removing elements as
27 * they find them. So we keep a parallel vector, orig, to make sure that we
28 * never forget to delete a string.
29 */
30 class VectorContainer
31 {
32 public:
33 explicit VectorContainer(const char** arr_) {
34 for (const char **a = arr_; *a; ++a) {
35 const char *str = (const char*)strdup(*a);
36 arr.push_back(str);
37 orig.push_back(str);
38 }
39 }
40 ~VectorContainer() {
41 for (std::vector<const char*>::iterator i = orig.begin();
42 i != orig.end(); ++i)
43 {
44 free((void*)*i);
45 }
46 }
47 void refresh() {
48 arr.assign(orig.begin(), orig.end());
49 }
50 std::vector < const char* > arr;
51
52 private:
53 std::vector < const char* > orig;
54 };
55
56 TEST(CephArgParse, SimpleArgParse) {
57 const char *BAR5[] = { "./myprog", "--bar", "5", NULL };
58 const char *FOO[] = { "./myprog", "--foo", "--baz", NULL };
59 const char *NONE[] = { "./myprog", NULL };
60
61 bool found_foo = false;
62 std::string found_bar;
63 VectorContainer bar5(BAR5);
64 for (std::vector<const char*>::iterator i = bar5.arr.begin();
65 i != bar5.arr.end(); )
66 {
67 if (ceph_argparse_flag(bar5.arr, i, "--foo", (char*)NULL)) {
68 found_foo = true;
69 }
70 else if (ceph_argparse_witharg(bar5.arr, i, &found_bar, "--bar", (char*)NULL)) {
71 }
72 else
73 ++i;
74 }
75 ASSERT_EQ(found_foo, false);
76 ASSERT_EQ(found_bar, "5");
77
78 found_foo = false;
79 found_bar = "";
80 bool baz_found = false;
81 std::string found_baz = "";
82 VectorContainer foo(FOO);
83 ostringstream err;
84 for (std::vector<const char*>::iterator i = foo.arr.begin();
85 i != foo.arr.end(); )
86 {
87 if (ceph_argparse_flag(foo.arr, i, "--foo", (char*)NULL)) {
88 found_foo = true;
89 }
90 else if (ceph_argparse_witharg(foo.arr, i, &found_bar, "--bar", (char*)NULL)) {
91 }
92 else if (ceph_argparse_witharg(foo.arr, i, &found_baz, err, "--baz", (char*)NULL)) {
93 ASSERT_NE(string(""), err.str());
94 baz_found = true;
95 }
96 else
97 ++i;
98 }
99 ASSERT_EQ(found_foo, true);
100 ASSERT_EQ(found_bar, "");
101 ASSERT_EQ(baz_found, true);
102 ASSERT_EQ(found_baz, "");
103
104 found_foo = false;
105 found_bar = "";
106 VectorContainer none(NONE);
107 for (std::vector<const char*>::iterator i = none.arr.begin();
108 i != none.arr.end(); )
109 {
110 if (ceph_argparse_flag(none.arr, i, "--foo", (char*)NULL)) {
111 found_foo = true;
112 }
113 else if (ceph_argparse_witharg(none.arr, i, &found_bar, "--bar", (char*)NULL)) {
114 }
115 else
116 ++i;
117 }
118 ASSERT_EQ(found_foo, false);
119 ASSERT_EQ(found_bar, "");
120 }
121
122 TEST(CephArgParse, DoubleDash) {
123 const char *ARGS[] = { "./myprog", "--foo", "5", "--", "--bar", "6", NULL };
124
125 int foo = -1, bar = -1;
126 VectorContainer args(ARGS);
127 for (std::vector<const char*>::iterator i = args.arr.begin();
128 i != args.arr.end(); )
129 {
130 std::string myarg;
131 if (ceph_argparse_double_dash(args.arr, i)) {
132 break;
133 }
134 else if (ceph_argparse_witharg(args.arr, i, &myarg, "--foo", (char*)NULL)) {
135 foo = atoi(myarg.c_str());
136 }
137 else if (ceph_argparse_witharg(args.arr, i, &myarg, "--bar", (char*)NULL)) {
138 bar = atoi(myarg.c_str());
139 }
140 else
141 ++i;
142 }
143 ASSERT_EQ(foo, 5);
144 ASSERT_EQ(bar, -1);
145 }
146
147
148 TEST(CephArgParse, WithDashesAndUnderscores) {
149 const char *BAZSTUFF1[] = { "./myprog", "--goo", "--baz-stuff", "50", "--end", NULL };
150 const char *BAZSTUFF2[] = { "./myprog", "--goo2", "--baz_stuff", "50", NULL };
151 const char *BAZSTUFF3[] = { "./myprog", "--goo2", "--baz-stuff=50", "50", NULL };
152 const char *BAZSTUFF4[] = { "./myprog", "--goo2", "--baz_stuff=50", "50", NULL };
153 const char *NONE1[] = { "./myprog", NULL };
154 const char *NONE2[] = { "./myprog", "--goo2", "--baz_stuff2", "50", NULL };
155 const char *NONE3[] = { "./myprog", "--goo2", "__baz_stuff", "50", NULL };
156
157 // as flag
158 std::string found_baz;
159 VectorContainer bazstuff1(BAZSTUFF1);
160 for (std::vector<const char*>::iterator i = bazstuff1.arr.begin();
161 i != bazstuff1.arr.end(); )
162 {
163 if (ceph_argparse_flag(bazstuff1.arr, i, "--baz-stuff", (char*)NULL)) {
164 found_baz = "true";
165 }
166 else
167 ++i;
168 }
169 ASSERT_EQ(found_baz, "true");
170
171 // as flag
172 found_baz = "";
173 VectorContainer bazstuff2(BAZSTUFF2);
174 for (std::vector<const char*>::iterator i = bazstuff2.arr.begin();
175 i != bazstuff2.arr.end(); )
176 {
177 if (ceph_argparse_flag(bazstuff2.arr, i, "--baz-stuff", (char*)NULL)) {
178 found_baz = "true";
179 }
180 else
181 ++i;
182 }
183 ASSERT_EQ(found_baz, "true");
184
185 // with argument
186 found_baz = "";
187 bazstuff1.refresh();
188 for (std::vector<const char*>::iterator i = bazstuff1.arr.begin();
189 i != bazstuff1.arr.end(); )
190 {
191 if (ceph_argparse_witharg(bazstuff1.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) {
192 }
193 else
194 ++i;
195 }
196 ASSERT_EQ(found_baz, "50");
197
198 // with argument
199 found_baz = "";
200 bazstuff2.refresh();
201 for (std::vector<const char*>::iterator i = bazstuff2.arr.begin();
202 i != bazstuff2.arr.end(); )
203 {
204 if (ceph_argparse_witharg(bazstuff2.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) {
205 }
206 else
207 ++i;
208 }
209 ASSERT_EQ(found_baz, "50");
210
211 // with argument
212 found_baz = "";
213 VectorContainer bazstuff3(BAZSTUFF3);
214 for (std::vector<const char*>::iterator i = bazstuff3.arr.begin();
215 i != bazstuff3.arr.end(); )
216 {
217 if (ceph_argparse_witharg(bazstuff3.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) {
218 }
219 else
220 ++i;
221 }
222 ASSERT_EQ(found_baz, "50");
223
224 // with argument
225 found_baz = "";
226 VectorContainer bazstuff4(BAZSTUFF4);
227 for (std::vector<const char*>::iterator i = bazstuff4.arr.begin();
228 i != bazstuff4.arr.end(); )
229 {
230 if (ceph_argparse_witharg(bazstuff4.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) {
231 }
232 else
233 ++i;
234 }
235 ASSERT_EQ(found_baz, "50");
236
237 // not found
238 found_baz = "";
239 VectorContainer none1(NONE1);
240 for (std::vector<const char*>::iterator i = none1.arr.begin();
241 i != none1.arr.end(); )
242 {
243 if (ceph_argparse_flag(none1.arr, i, "--baz-stuff", (char*)NULL)) {
244 found_baz = "true";
245 }
246 else if (ceph_argparse_witharg(none1.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) {
247 }
248 else
249 ++i;
250 }
251 ASSERT_EQ(found_baz, "");
252
253 // not found
254 found_baz = "";
255 VectorContainer none2(NONE2);
256 for (std::vector<const char*>::iterator i = none2.arr.begin();
257 i != none2.arr.end(); )
258 {
259 if (ceph_argparse_flag(none2.arr, i, "--baz-stuff", (char*)NULL)) {
260 found_baz = "true";
261 }
262 else if (ceph_argparse_witharg(none2.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) {
263 }
264 else
265 ++i;
266 }
267 ASSERT_EQ(found_baz, "");
268
269 // not found
270 found_baz = "";
271 VectorContainer none3(NONE3);
272 for (std::vector<const char*>::iterator i = none3.arr.begin();
273 i != none3.arr.end(); )
274 {
275 if (ceph_argparse_flag(none3.arr, i, "--baz-stuff", (char*)NULL)) {
276 found_baz = "true";
277 }
278 else if (ceph_argparse_witharg(none3.arr, i, &found_baz, "--baz-stuff", (char*)NULL)) {
279 }
280 else
281 ++i;
282 }
283 ASSERT_EQ(found_baz, "");
284 }
285
286 TEST(CephArgParse, WithFloat) {
287 const char *BAZSTUFF1[] = { "./myprog", "--foo", "50.5", "--bar", "52", NULL };
288
289 VectorContainer bazstuff1(BAZSTUFF1);
290 ostringstream err;
291 float foo;
292 int bar = -1;
293 for (std::vector<const char*>::iterator i = bazstuff1.arr.begin();
294 i != bazstuff1.arr.end(); )
295 {
296 if (ceph_argparse_double_dash(bazstuff1.arr, i)) {
297 break;
298 } else if (ceph_argparse_witharg(bazstuff1.arr, i, &foo, err, "--foo", (char*)NULL)) {
299 ASSERT_EQ(string(""), err.str());
300 } else if (ceph_argparse_witharg(bazstuff1.arr, i, &bar, err, "--bar", (char*)NULL)) {
301 ASSERT_EQ(string(""), err.str());
302 }
303 else {
304 ++i;
305 }
306 }
307 ASSERT_EQ(foo, 50.5);
308 ASSERT_EQ(bar, 52);
309 }
310
311 TEST(CephArgParse, WithInt) {
312 const char *BAZSTUFF1[] = { "./myprog", "--foo", "50", "--bar", "52", NULL };
313 const char *BAZSTUFF2[] = { "./myprog", "--foo", "--bar", "52", NULL };
314 const char *BAZSTUFF3[] = { "./myprog", "--foo", "40", "--", "--bar", "42", NULL };
315
316 // normal test
317 VectorContainer bazstuff1(BAZSTUFF1);
318 ostringstream err;
319 int foo = -1, bar = -1;
320 for (std::vector<const char*>::iterator i = bazstuff1.arr.begin();
321 i != bazstuff1.arr.end(); )
322 {
323 if (ceph_argparse_double_dash(bazstuff1.arr, i)) {
324 break;
325 } else if (ceph_argparse_witharg(bazstuff1.arr, i, &foo, err, "--foo", (char*)NULL)) {
326 ASSERT_EQ(string(""), err.str());
327 } else if (ceph_argparse_witharg(bazstuff1.arr, i, &bar, err, "--bar", (char*)NULL)) {
328 ASSERT_EQ(string(""), err.str());
329 }
330 else {
331 ++i;
332 }
333 }
334 ASSERT_EQ(foo, 50);
335 ASSERT_EQ(bar, 52);
336
337 // parse error test
338 VectorContainer bazstuff2(BAZSTUFF2);
339 ostringstream err2;
340 for (std::vector<const char*>::iterator i = bazstuff2.arr.begin();
341 i != bazstuff2.arr.end(); )
342 {
343 if (ceph_argparse_double_dash(bazstuff2.arr, i)) {
344 break;
345 } else if (ceph_argparse_witharg(bazstuff2.arr, i, &foo, err2, "--foo", (char*)NULL)) {
346 ASSERT_NE(string(""), err2.str());
347 }
348 else {
349 ++i;
350 }
351 }
352
353 // double dash test
354 VectorContainer bazstuff3(BAZSTUFF3);
355 foo = -1, bar = -1;
356 for (std::vector<const char*>::iterator i = bazstuff3.arr.begin();
357 i != bazstuff3.arr.end(); )
358 {
359 if (ceph_argparse_double_dash(bazstuff3.arr, i)) {
360 break;
361 } else if (ceph_argparse_witharg(bazstuff3.arr, i, &foo, err, "--foo", (char*)NULL)) {
362 ASSERT_EQ(string(""), err.str());
363 } else if (ceph_argparse_witharg(bazstuff3.arr, i, &bar, err, "--bar", (char*)NULL)) {
364 ASSERT_EQ(string(""), err.str());
365 }
366 else {
367 ++i;
368 }
369 }
370 ASSERT_EQ(foo, 40);
371 ASSERT_EQ(bar, -1);
372 }
373
374 TEST(CephArgParse, env_to_vec) {
375 {
376 std::vector<const char*> args;
377 unsetenv("CEPH_ARGS");
378 unsetenv("WHATEVER");
379 clear_g_str_vec();
380 env_to_vec(args);
381 EXPECT_EQ(0u, args.size());
382 clear_g_str_vec();
383 env_to_vec(args, "WHATEVER");
384 EXPECT_EQ(0u, args.size());
385 args.push_back("a");
386 setenv("CEPH_ARGS", "b c", 0);
387 clear_g_str_vec();
388 env_to_vec(args);
389 EXPECT_EQ(3u, args.size());
390 EXPECT_EQ(string("b"), args[0]);
391 EXPECT_EQ(string("c"), args[1]);
392 EXPECT_EQ(string("a"), args[2]);
393 setenv("WHATEVER", "d e", 0);
394 clear_g_str_vec();
395 env_to_vec(args, "WHATEVER");
396 EXPECT_EQ(5u, args.size());
397 EXPECT_EQ(string("d"), args[0]);
398 EXPECT_EQ(string("e"), args[1]);
399 }
400 {
401 std::vector<const char*> args;
402 unsetenv("CEPH_ARGS");
403 args.push_back("a");
404 args.push_back("--");
405 args.push_back("c");
406 setenv("CEPH_ARGS", "b -- d", 0);
407 clear_g_str_vec();
408 env_to_vec(args);
409 EXPECT_EQ(5u, args.size());
410 EXPECT_EQ(string("b"), args[0]);
411 EXPECT_EQ(string("a"), args[1]);
412 EXPECT_EQ(string("--"), args[2]);
413 EXPECT_EQ(string("d"), args[3]);
414 EXPECT_EQ(string("c"), args[4]);
415 }
416 {
417 std::vector<const char*> args;
418 unsetenv("CEPH_ARGS");
419 args.push_back("a");
420 args.push_back("--");
421 setenv("CEPH_ARGS", "b -- c", 0);
422 clear_g_str_vec();
423 env_to_vec(args);
424 EXPECT_EQ(4u, args.size());
425 EXPECT_EQ(string("b"), args[0]);
426 EXPECT_EQ(string("a"), args[1]);
427 EXPECT_EQ(string("--"), args[2]);
428 EXPECT_EQ(string("c"), args[3]);
429 }
430 {
431 std::vector<const char*> args;
432 unsetenv("CEPH_ARGS");
433 args.push_back("--");
434 args.push_back("c");
435 setenv("CEPH_ARGS", "b -- d", 0);
436 clear_g_str_vec();
437 env_to_vec(args);
438 EXPECT_EQ(4u, args.size());
439 EXPECT_EQ(string("b"), args[0]);
440 EXPECT_EQ(string("--"), args[1]);
441 EXPECT_EQ(string("d"), args[2]);
442 EXPECT_EQ(string("c"), args[3]);
443 }
444 {
445 std::vector<const char*> args;
446 unsetenv("CEPH_ARGS");
447 args.push_back("b");
448 setenv("CEPH_ARGS", "c -- d", 0);
449 clear_g_str_vec();
450 env_to_vec(args);
451 EXPECT_EQ(4u, args.size());
452 EXPECT_EQ(string("c"), args[0]);
453 EXPECT_EQ(string("b"), args[1]);
454 EXPECT_EQ(string("--"), args[2]);
455 EXPECT_EQ(string("d"), args[3]);
456 }
457 {
458 std::vector<const char*> args;
459 unsetenv("CEPH_ARGS");
460 args.push_back("a");
461 args.push_back("--");
462 args.push_back("c");
463 setenv("CEPH_ARGS", "-- d", 0);
464 clear_g_str_vec();
465 env_to_vec(args);
466 EXPECT_EQ(4u, args.size());
467 EXPECT_EQ(string("a"), args[0]);
468 EXPECT_EQ(string("--"), args[1]);
469 EXPECT_EQ(string("d"), args[2]);
470 EXPECT_EQ(string("c"), args[3]);
471 }
472 {
473 std::vector<const char*> args;
474 unsetenv("CEPH_ARGS");
475 args.push_back("a");
476 args.push_back("--");
477 args.push_back("c");
478 setenv("CEPH_ARGS", "d", 0);
479 clear_g_str_vec();
480 env_to_vec(args);
481 EXPECT_EQ(4u, args.size());
482 EXPECT_EQ(string("d"), args[0]);
483 EXPECT_EQ(string("a"), args[1]);
484 EXPECT_EQ(string("--"), args[2]);
485 EXPECT_EQ(string("c"), args[3]);
486 }
487 }
488
489 TEST(CephArgParse, parse_ip_port_vec) {
490 struct {
491 const char *from;
492 int type;
493 const char *to;
494 } tests[] = {
495 { "1.2.3.4", entity_addr_t::TYPE_MSGR2,
496 "v2:1.2.3.4:0/0\n" },
497 { "v1:1.2.3.4", entity_addr_t::TYPE_MSGR2,
498 "v1:1.2.3.4:0/0\n" },
499 { "1.2.3.4", entity_addr_t::TYPE_LEGACY,
500 "v1:1.2.3.4:0/0\n" },
501 { "[::],1.2.3.4", entity_addr_t::TYPE_LEGACY,
502 "v1:[::]:0/0\nv1:1.2.3.4:0/0\n" },
503 { "v2:1.2.3.4:111,v1:5.6.7.8:222", entity_addr_t::TYPE_LEGACY,
504 "v2:1.2.3.4:111/0\nv1:5.6.7.8:222/0\n" },
505 { "v2:1.2.3.4:111 v1:5.6.7.8:222", entity_addr_t::TYPE_LEGACY,
506 "v2:1.2.3.4:111/0\nv1:5.6.7.8:222/0\n" },
507 { "[v2:1.2.3.4:111,v1:5.6.7.8:222] [v2:[::]:3300,v1:[::]:6789]",
508 entity_addr_t::TYPE_LEGACY,
509 "[v2:1.2.3.4:111/0,v1:5.6.7.8:222/0]\n[v2:[::]:3300/0,v1:[::]:6789/0]\n" },
510 { "[v2:1.2.3.4:111,v1:5.6.7.8:222],[v2:[::]:3300,v1:[::]:6789]",
511 entity_addr_t::TYPE_LEGACY,
512 "[v2:1.2.3.4:111/0,v1:5.6.7.8:222/0]\n[v2:[::]:3300/0,v1:[::]:6789/0]\n" },
513 { 0, 0, 0 },
514 };
515
516 for (unsigned i = 0; tests[i].from; ++i) {
517 vector<entity_addrvec_t> v;
518 cout << "-- " << tests[i].from << " type " << tests[i].type
519 << " ->\n" << tests[i].to;
520 ASSERT_TRUE(parse_ip_port_vec(tests[i].from, v, tests[i].type));
521 string actual;
522 for (auto s : v) {
523 actual += stringify(s) + "\n";
524 }
525 ASSERT_EQ(actual, tests[i].to);
526 }
527
528 const char *bad[] = {
529 "1.2.3.4 foo",
530 0
531 };
532 for (unsigned i = 0; bad[i]; ++i) {
533 vector<entity_addrvec_t> v;
534 cout << "bad " << bad[i] << std::endl;
535 ASSERT_FALSE(parse_ip_port_vec(bad[i], v));
536 }
537 }
538
539
540 /*
541 * Local Variables:
542 * compile-command: "cd .. ; make unittest_ceph_argparse && ./unittest_ceph_argparse"
543 * End:
544 */