1 | // Copyright Vladimir Prus 2002-2004. |
---|
2 | // Distributed under the Boost Software License, Version 1.0. |
---|
3 | // (See accompanying file LICENSE_1_0.txt |
---|
4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) |
---|
5 | |
---|
6 | #include <boost/program_options/cmdline.hpp> |
---|
7 | #include <boost/program_options/options_description.hpp> |
---|
8 | #include <boost/program_options/detail/cmdline.hpp> |
---|
9 | using namespace boost::program_options; |
---|
10 | using boost::program_options::detail::cmdline; |
---|
11 | |
---|
12 | |
---|
13 | #include <boost/test/test_tools.hpp> |
---|
14 | |
---|
15 | #include <iostream> |
---|
16 | #include <sstream> |
---|
17 | #include <vector> |
---|
18 | #include <cassert> |
---|
19 | using namespace std; |
---|
20 | |
---|
21 | /* To facilitate testing, declare a number of error codes. Otherwise, |
---|
22 | we'd have to specify the type of exception that should be thrown. |
---|
23 | */ |
---|
24 | |
---|
25 | const int s_success = 0; |
---|
26 | const int s_unknown_option = 1; |
---|
27 | const int s_ambiguous_option = 2; |
---|
28 | const int s_long_not_allowed = 3; |
---|
29 | const int s_long_adjacent_not_allowed = 4; |
---|
30 | const int s_short_adjacent_not_allowed = 5; |
---|
31 | const int s_empty_adjacent_parameter = 6; |
---|
32 | const int s_missing_parameter = 7; |
---|
33 | const int s_extra_parameter = 8; |
---|
34 | |
---|
35 | int translate_syntax_error_kind(invalid_command_line_syntax::kind_t k) |
---|
36 | { |
---|
37 | invalid_command_line_syntax::kind_t table[] = { |
---|
38 | invalid_command_line_syntax::long_not_allowed, |
---|
39 | invalid_command_line_syntax::long_adjacent_not_allowed, |
---|
40 | invalid_command_line_syntax::short_adjacent_not_allowed, |
---|
41 | invalid_command_line_syntax::empty_adjacent_parameter, |
---|
42 | invalid_command_line_syntax::missing_parameter, |
---|
43 | invalid_command_line_syntax::extra_parameter, |
---|
44 | }; |
---|
45 | invalid_command_line_syntax::kind_t *b, *e, *i; |
---|
46 | b = table; |
---|
47 | e = table + sizeof(table)/sizeof(table[0]); |
---|
48 | i = std::find(b, e, k); |
---|
49 | assert(i != e); |
---|
50 | return std::distance(b, i) + 3; |
---|
51 | } |
---|
52 | |
---|
53 | struct test_case { |
---|
54 | const char* input; |
---|
55 | int expected_status; |
---|
56 | const char* expected_result; |
---|
57 | }; |
---|
58 | |
---|
59 | |
---|
60 | /* Parses the syntax description in 'syntax' and initialized |
---|
61 | 'cmd' accordingly' |
---|
62 | The "boost::program_options" in parameter type is needed because CW9 |
---|
63 | has std::detail and it causes an ambiguity. |
---|
64 | */ |
---|
65 | void apply_syntax(options_description& desc, |
---|
66 | const char* syntax) |
---|
67 | { |
---|
68 | |
---|
69 | string s; |
---|
70 | stringstream ss; |
---|
71 | ss << syntax; |
---|
72 | while(ss >> s) { |
---|
73 | value_semantic* v = 0; |
---|
74 | |
---|
75 | if (*(s.end()-1) == '=') { |
---|
76 | v = value<string>(); |
---|
77 | s.resize(s.size()-1); |
---|
78 | } else if (*(s.end()-1) == '?') { |
---|
79 | //v = value<string>()->implicit(); |
---|
80 | v = value<string>(); |
---|
81 | s.resize(s.size()-1); |
---|
82 | } else if (*(s.end()-1) == '*') { |
---|
83 | v = value<vector<string> >()->multitoken(); |
---|
84 | s.resize(s.size()-1); |
---|
85 | } else if (*(s.end()-1) == '+') { |
---|
86 | v = value<vector<string> >()->multitoken(); |
---|
87 | s.resize(s.size()-1); |
---|
88 | } |
---|
89 | if (v) { |
---|
90 | desc.add_options() |
---|
91 | (s.c_str(), v, ""); |
---|
92 | } else { |
---|
93 | desc.add_options() |
---|
94 | (s.c_str(), ""); |
---|
95 | } |
---|
96 | } |
---|
97 | } |
---|
98 | |
---|
99 | void test_cmdline(const char* syntax, |
---|
100 | command_line_style::style_t style, |
---|
101 | const test_case* cases) |
---|
102 | { |
---|
103 | for (int i = 0; cases[i].input; ++i) { |
---|
104 | // Parse input |
---|
105 | vector<string> xinput; |
---|
106 | { |
---|
107 | string s; |
---|
108 | stringstream ss; |
---|
109 | ss << cases[i].input; |
---|
110 | while (ss >> s) { |
---|
111 | xinput.push_back(s); |
---|
112 | } |
---|
113 | } |
---|
114 | options_description desc; |
---|
115 | apply_syntax(desc, syntax); |
---|
116 | |
---|
117 | cmdline cmd(xinput); |
---|
118 | cmd.style(style); |
---|
119 | cmd.set_options_description(desc); |
---|
120 | |
---|
121 | |
---|
122 | string result; |
---|
123 | int status = 0; |
---|
124 | |
---|
125 | try { |
---|
126 | vector<option> options = cmd.run(); |
---|
127 | |
---|
128 | for(unsigned i = 0; i < options.size(); ++i) |
---|
129 | { |
---|
130 | option opt = options[i]; |
---|
131 | |
---|
132 | if (opt.position_key != -1) { |
---|
133 | if (!result.empty()) |
---|
134 | result += " "; |
---|
135 | result += opt.value[0]; |
---|
136 | } else { |
---|
137 | if (!result.empty()) |
---|
138 | result += " "; |
---|
139 | result += opt.string_key + ":"; |
---|
140 | for (size_t j = 0; j < opt.value.size(); ++j) { |
---|
141 | if (j != 0) |
---|
142 | result += "-"; |
---|
143 | result += opt.value[j]; |
---|
144 | } |
---|
145 | } |
---|
146 | } |
---|
147 | } |
---|
148 | catch(unknown_option& e) { |
---|
149 | status = s_unknown_option; |
---|
150 | } |
---|
151 | catch(ambiguous_option& e) { |
---|
152 | status = s_ambiguous_option; |
---|
153 | } |
---|
154 | catch(invalid_command_line_syntax& e) { |
---|
155 | status = translate_syntax_error_kind(e.kind()); |
---|
156 | } |
---|
157 | BOOST_CHECK_EQUAL(status, cases[i].expected_status); |
---|
158 | BOOST_CHECK_EQUAL(result, cases[i].expected_result); |
---|
159 | } |
---|
160 | } |
---|
161 | |
---|
162 | void test_long_options() |
---|
163 | { |
---|
164 | using namespace command_line_style; |
---|
165 | cmdline::style_t style = cmdline::style_t( |
---|
166 | allow_long | long_allow_adjacent); |
---|
167 | |
---|
168 | test_case test_cases1[] = { |
---|
169 | // Test that long options are recognized and everything else |
---|
170 | // is treated like arguments |
---|
171 | {"--foo foo -123 /asd", s_success, "foo: foo -123 /asd"}, |
---|
172 | |
---|
173 | // Unknown option |
---|
174 | {"--unk", s_unknown_option, ""}, |
---|
175 | |
---|
176 | // Test that abbreviated names do not work |
---|
177 | {"--fo", s_unknown_option, ""}, |
---|
178 | |
---|
179 | // Test for disallowed parameter |
---|
180 | {"--foo=13", s_extra_parameter, ""}, |
---|
181 | |
---|
182 | // Test option with required parameter |
---|
183 | {"--bar=", s_empty_adjacent_parameter, ""}, |
---|
184 | {"--bar", s_missing_parameter, ""}, |
---|
185 | |
---|
186 | {"--bar=123", s_success, "bar:123"}, |
---|
187 | {0} |
---|
188 | }; |
---|
189 | test_cmdline("foo bar=", style, test_cases1); |
---|
190 | |
---|
191 | |
---|
192 | style = cmdline::style_t( |
---|
193 | allow_long | long_allow_next); |
---|
194 | |
---|
195 | test_case test_cases2[] = { |
---|
196 | {"--bar 10", s_success, "bar:10"}, |
---|
197 | {"--bar", s_missing_parameter, ""}, |
---|
198 | // Since --bar accepts a parameter, --foo is |
---|
199 | // considered a value, even though it looks like |
---|
200 | // an option. |
---|
201 | {"--bar --foo", s_success, "bar:--foo"}, |
---|
202 | {0} |
---|
203 | }; |
---|
204 | test_cmdline("foo bar=", style, test_cases2); |
---|
205 | style = cmdline::style_t( |
---|
206 | allow_long | long_allow_adjacent |
---|
207 | | long_allow_next); |
---|
208 | |
---|
209 | test_case test_cases3[] = { |
---|
210 | {"--bar=10", s_success, "bar:10"}, |
---|
211 | {"--bar 11", s_success, "bar:11"}, |
---|
212 | {0} |
---|
213 | }; |
---|
214 | test_cmdline("foo bar=", style, test_cases3); |
---|
215 | |
---|
216 | style = cmdline::style_t( |
---|
217 | allow_long | long_allow_adjacent |
---|
218 | | long_allow_next | case_insensitive); |
---|
219 | |
---|
220 | // FIXME: restore |
---|
221 | #if 0 |
---|
222 | // Test case insensitive style. |
---|
223 | // Note that option names are normalized to lower case. |
---|
224 | test_case test_cases4[] = { |
---|
225 | {"--foo", s_success, "foo:"}, |
---|
226 | {"--Foo", s_success, "foo:"}, |
---|
227 | {"--bar=Ab", s_success, "bar:Ab"}, |
---|
228 | {"--Bar=ab", s_success, "bar:ab"}, |
---|
229 | {"--giz", s_success, "Giz:"}, |
---|
230 | {0} |
---|
231 | }; |
---|
232 | test_cmdline("foo bar= baz? Giz", style, test_cases4); |
---|
233 | #endif |
---|
234 | } |
---|
235 | |
---|
236 | void test_short_options() |
---|
237 | { |
---|
238 | using namespace command_line_style; |
---|
239 | cmdline::style_t style; |
---|
240 | |
---|
241 | style = cmdline::style_t( |
---|
242 | allow_short | allow_dash_for_short |
---|
243 | | short_allow_adjacent); |
---|
244 | |
---|
245 | test_case test_cases1[] = { |
---|
246 | {"-d d /bar", s_success, "-d: d /bar"}, |
---|
247 | // This is treated as error when long options are disabled |
---|
248 | {"--foo", s_success, "--foo"}, |
---|
249 | {"-d13", s_extra_parameter, ""}, |
---|
250 | {"-f14", s_success, "-f:14"}, |
---|
251 | {"-g -f1", s_success, "-g: -f:1"}, |
---|
252 | {"-f", s_missing_parameter, ""}, |
---|
253 | {0} |
---|
254 | }; |
---|
255 | test_cmdline(",d ,f= ,g", style, test_cases1); |
---|
256 | |
---|
257 | style = cmdline::style_t( |
---|
258 | allow_short | allow_dash_for_short |
---|
259 | | short_allow_next); |
---|
260 | |
---|
261 | test_case test_cases2[] = { |
---|
262 | {"-f 13", s_success, "-f:13"}, |
---|
263 | {"-f -13", s_success, "-f:-13"}, |
---|
264 | {"-f", s_missing_parameter, ""}, |
---|
265 | {"-f /foo", s_success, "-f:/foo"}, |
---|
266 | {"-f -d", s_success, "-f:-d"}, |
---|
267 | {0} |
---|
268 | }; |
---|
269 | test_cmdline(",d ,f=", style, test_cases2); |
---|
270 | |
---|
271 | style = cmdline::style_t( |
---|
272 | allow_short | short_allow_next |
---|
273 | | allow_dash_for_short | short_allow_adjacent); |
---|
274 | |
---|
275 | test_case test_cases3[] = { |
---|
276 | {"-f10", s_success, "-f:10"}, |
---|
277 | {"-f 10", s_success, "-f:10"}, |
---|
278 | {"-f -d", s_success, "-f:-d"}, |
---|
279 | {0} |
---|
280 | }; |
---|
281 | test_cmdline(",d ,f=", style, test_cases3); |
---|
282 | |
---|
283 | style = cmdline::style_t( |
---|
284 | allow_short | short_allow_next |
---|
285 | | allow_dash_for_short |
---|
286 | | short_allow_adjacent | allow_sticky); |
---|
287 | |
---|
288 | test_case test_cases4[] = { |
---|
289 | {"-de", s_success, "-d: -e:"}, |
---|
290 | {"-df10", s_success, "-d: -f:10"}, |
---|
291 | // FIXME: review |
---|
292 | //{"-d12", s_extra_parameter, ""}, |
---|
293 | {"-f12", s_success, "-f:12"}, |
---|
294 | {"-fe", s_success, "-f:e"}, |
---|
295 | {0} |
---|
296 | }; |
---|
297 | test_cmdline(",d ,f= ,e", style, test_cases4); |
---|
298 | |
---|
299 | } |
---|
300 | |
---|
301 | |
---|
302 | void test_dos_options() |
---|
303 | { |
---|
304 | using namespace command_line_style; |
---|
305 | cmdline::style_t style; |
---|
306 | |
---|
307 | style = cmdline::style_t( |
---|
308 | allow_short |
---|
309 | | allow_slash_for_short | short_allow_adjacent); |
---|
310 | |
---|
311 | test_case test_cases1[] = { |
---|
312 | {"/d d -bar", s_success, "-d: d -bar"}, |
---|
313 | {"--foo", s_success, "--foo"}, |
---|
314 | {"/d13", s_extra_parameter, ""}, |
---|
315 | {"/f14", s_success, "-f:14"}, |
---|
316 | {"/f", s_missing_parameter, ""}, |
---|
317 | {0} |
---|
318 | }; |
---|
319 | test_cmdline(",d ,f=", style, test_cases1); |
---|
320 | |
---|
321 | style = cmdline::style_t( |
---|
322 | allow_short |
---|
323 | | allow_slash_for_short | short_allow_next |
---|
324 | | short_allow_adjacent | allow_sticky); |
---|
325 | |
---|
326 | test_case test_cases2[] = { |
---|
327 | {"/de", s_extra_parameter, ""}, |
---|
328 | {"/fe", s_success, "-f:e"}, |
---|
329 | {0} |
---|
330 | }; |
---|
331 | test_cmdline(",d ,f= ,e", style, test_cases2); |
---|
332 | |
---|
333 | } |
---|
334 | |
---|
335 | |
---|
336 | void test_disguised_long() |
---|
337 | { |
---|
338 | using namespace command_line_style; |
---|
339 | cmdline::style_t style; |
---|
340 | |
---|
341 | style = cmdline::style_t( |
---|
342 | allow_short | short_allow_adjacent |
---|
343 | | allow_dash_for_short |
---|
344 | | short_allow_next | allow_long_disguise |
---|
345 | | long_allow_adjacent); |
---|
346 | |
---|
347 | test_case test_cases1[] = { |
---|
348 | {"-foo -f", s_success, "foo: foo:"}, |
---|
349 | {"-goo=x -gy", s_success, "goo:x goo:y"}, |
---|
350 | {"-bee=x -by", s_success, "bee:x bee:y"}, |
---|
351 | {0} |
---|
352 | }; |
---|
353 | test_cmdline("foo,f goo,g= bee,b?", style, test_cases1); |
---|
354 | |
---|
355 | style = cmdline::style_t(style | allow_slash_for_short); |
---|
356 | test_case test_cases2[] = { |
---|
357 | {"/foo -f", s_success, "foo: foo:"}, |
---|
358 | {"/goo=x", s_success, "goo:x"}, |
---|
359 | {0} |
---|
360 | }; |
---|
361 | test_cmdline("foo,f goo,g= bee,b?", style, test_cases2); |
---|
362 | } |
---|
363 | |
---|
364 | void test_guessing() |
---|
365 | { |
---|
366 | using namespace command_line_style; |
---|
367 | cmdline::style_t style; |
---|
368 | |
---|
369 | style = cmdline::style_t( |
---|
370 | allow_short | short_allow_adjacent |
---|
371 | | allow_dash_for_short |
---|
372 | | allow_long | long_allow_adjacent |
---|
373 | | allow_guessing | allow_long_disguise); |
---|
374 | |
---|
375 | test_case test_cases1[] = { |
---|
376 | {"--opt1", s_success, "opt123:"}, |
---|
377 | {"--opt", s_ambiguous_option, ""}, |
---|
378 | {"--f=1", s_success, "foo:1"}, |
---|
379 | {"-far", s_success, "foo:ar"}, |
---|
380 | {0} |
---|
381 | }; |
---|
382 | test_cmdline("opt123 opt56 foo,f=", style, test_cases1); |
---|
383 | } |
---|
384 | |
---|
385 | void test_arguments() |
---|
386 | { |
---|
387 | using namespace command_line_style; |
---|
388 | cmdline::style_t style; |
---|
389 | |
---|
390 | style = cmdline::style_t( |
---|
391 | allow_short | allow_long |
---|
392 | | allow_dash_for_short |
---|
393 | | short_allow_adjacent | long_allow_adjacent); |
---|
394 | |
---|
395 | test_case test_cases1[] = { |
---|
396 | {"-f file -gx file2", s_success, "-f: file -g:x file2"}, |
---|
397 | {"-f - -gx - -- -e", s_success, "-f: - -g:x - -e"}, |
---|
398 | {0} |
---|
399 | }; |
---|
400 | test_cmdline(",f ,g= ,e", style, test_cases1); |
---|
401 | |
---|
402 | // "--" should stop options regardless of whether long options are |
---|
403 | // allowed or not. |
---|
404 | |
---|
405 | style = cmdline::style_t( |
---|
406 | allow_short | short_allow_adjacent |
---|
407 | | allow_dash_for_short); |
---|
408 | |
---|
409 | test_case test_cases2[] = { |
---|
410 | {"-f - -gx - -- -e", s_success, "-f: - -g:x - -e"}, |
---|
411 | {0} |
---|
412 | }; |
---|
413 | test_cmdline(",f ,g= ,e", style, test_cases2); |
---|
414 | } |
---|
415 | |
---|
416 | void test_prefix() |
---|
417 | { |
---|
418 | using namespace command_line_style; |
---|
419 | cmdline::style_t style; |
---|
420 | |
---|
421 | style = cmdline::style_t( |
---|
422 | allow_short | allow_long |
---|
423 | | allow_dash_for_short |
---|
424 | | short_allow_adjacent | long_allow_adjacent |
---|
425 | ); |
---|
426 | |
---|
427 | test_case test_cases1[] = { |
---|
428 | {"--foo.bar=12", s_success, "foo.bar:12"}, |
---|
429 | {0} |
---|
430 | }; |
---|
431 | |
---|
432 | test_cmdline("foo*=", style, test_cases1); |
---|
433 | } |
---|
434 | |
---|
435 | |
---|
436 | pair<string, string> at_option_parser(string const&s) |
---|
437 | { |
---|
438 | if ('@' == s[0]) |
---|
439 | return std::make_pair(string("response-file"), s.substr(1)); |
---|
440 | else |
---|
441 | return pair<string, string>(); |
---|
442 | } |
---|
443 | |
---|
444 | pair<string, string> at_option_parser_broken(string const&s) |
---|
445 | { |
---|
446 | if ('@' == s[0]) |
---|
447 | return std::make_pair(string("some garbage"), s.substr(1)); |
---|
448 | else |
---|
449 | return pair<string, string>(); |
---|
450 | } |
---|
451 | |
---|
452 | |
---|
453 | |
---|
454 | void test_additional_parser() |
---|
455 | { |
---|
456 | options_description desc; |
---|
457 | desc.add_options() |
---|
458 | ("response-file", value<string>(), "response file") |
---|
459 | ("foo", value<int>(), "foo") |
---|
460 | ; |
---|
461 | |
---|
462 | vector<string> input; |
---|
463 | input.push_back("@config"); |
---|
464 | input.push_back("--foo=1"); |
---|
465 | |
---|
466 | cmdline cmd(input); |
---|
467 | cmd.set_options_description(desc); |
---|
468 | cmd.set_additional_parser(at_option_parser); |
---|
469 | |
---|
470 | vector<option> result = cmd.run(); |
---|
471 | |
---|
472 | BOOST_REQUIRE(result.size() == 2); |
---|
473 | BOOST_CHECK_EQUAL(result[0].string_key, "response-file"); |
---|
474 | BOOST_CHECK_EQUAL(result[0].value[0], "config"); |
---|
475 | BOOST_CHECK_EQUAL(result[1].string_key, "foo"); |
---|
476 | BOOST_CHECK_EQUAL(result[1].value[0], "1"); |
---|
477 | |
---|
478 | // Test that invalid options returned by additional style |
---|
479 | // parser are detected. |
---|
480 | cmdline cmd2(input); |
---|
481 | cmd2.set_options_description(desc); |
---|
482 | cmd2.set_additional_parser(at_option_parser_broken); |
---|
483 | |
---|
484 | BOOST_CHECK_THROW(cmd2.run(), unknown_option); |
---|
485 | |
---|
486 | } |
---|
487 | |
---|
488 | vector<option> at_option_parser2(vector<string>& args) |
---|
489 | { |
---|
490 | vector<option> result; |
---|
491 | if ('@' == args[0][0]) { |
---|
492 | // Simulate reading the response file. |
---|
493 | result.push_back(option("foo", vector<string>(1, "1"))); |
---|
494 | result.push_back(option("bar", vector<string>(1, "1"))); |
---|
495 | args.erase(args.begin()); |
---|
496 | } |
---|
497 | return result; |
---|
498 | } |
---|
499 | |
---|
500 | |
---|
501 | void test_style_parser() |
---|
502 | { |
---|
503 | options_description desc; |
---|
504 | desc.add_options() |
---|
505 | ("foo", value<int>(), "foo") |
---|
506 | ("bar", value<int>(), "bar") |
---|
507 | ; |
---|
508 | |
---|
509 | vector<string> input; |
---|
510 | input.push_back("@config"); |
---|
511 | |
---|
512 | cmdline cmd(input); |
---|
513 | cmd.set_options_description(desc); |
---|
514 | cmd.extra_style_parser(at_option_parser2); |
---|
515 | |
---|
516 | vector<option> result = cmd.run(); |
---|
517 | |
---|
518 | BOOST_REQUIRE(result.size() == 2); |
---|
519 | BOOST_CHECK_EQUAL(result[0].string_key, "foo"); |
---|
520 | BOOST_CHECK_EQUAL(result[0].value[0], "1"); |
---|
521 | BOOST_CHECK_EQUAL(result[1].string_key, "bar"); |
---|
522 | BOOST_CHECK_EQUAL(result[1].value[0], "1"); |
---|
523 | } |
---|
524 | |
---|
525 | void test_unregistered() |
---|
526 | { |
---|
527 | // Check unregisted option when no options are registed at all. |
---|
528 | options_description desc; |
---|
529 | |
---|
530 | vector<string> input; |
---|
531 | input.push_back("--foo=1"); |
---|
532 | input.push_back("--bar"); |
---|
533 | input.push_back("1"); |
---|
534 | input.push_back("-b"); |
---|
535 | input.push_back("-biz"); |
---|
536 | |
---|
537 | cmdline cmd(input); |
---|
538 | cmd.set_options_description(desc); |
---|
539 | cmd.allow_unregistered(); |
---|
540 | |
---|
541 | vector<option> result = cmd.run(); |
---|
542 | BOOST_REQUIRE(result.size() == 5); |
---|
543 | // --foo=1 |
---|
544 | BOOST_CHECK_EQUAL(result[0].string_key, "foo"); |
---|
545 | BOOST_CHECK_EQUAL(result[0].unregistered, true); |
---|
546 | BOOST_CHECK_EQUAL(result[0].value[0], "1"); |
---|
547 | // --bar |
---|
548 | BOOST_CHECK_EQUAL(result[1].string_key, "bar"); |
---|
549 | BOOST_CHECK_EQUAL(result[1].unregistered, true); |
---|
550 | BOOST_CHECK(result[1].value.empty()); |
---|
551 | // '1' is considered a positional option, not a value to |
---|
552 | // --bar |
---|
553 | BOOST_CHECK(result[2].string_key.empty()); |
---|
554 | BOOST_CHECK(result[2].position_key == 0); |
---|
555 | BOOST_CHECK_EQUAL(result[2].unregistered, false); |
---|
556 | BOOST_CHECK_EQUAL(result[2].value[0], "1"); |
---|
557 | // -b |
---|
558 | BOOST_CHECK_EQUAL(result[3].string_key, "-b"); |
---|
559 | BOOST_CHECK_EQUAL(result[3].unregistered, true); |
---|
560 | BOOST_CHECK(result[3].value.empty()); |
---|
561 | // -biz |
---|
562 | BOOST_CHECK_EQUAL(result[4].string_key, "-b"); |
---|
563 | BOOST_CHECK_EQUAL(result[4].unregistered, true); |
---|
564 | BOOST_CHECK_EQUAL(result[4].value[0], "iz"); |
---|
565 | |
---|
566 | // Check sticky short options together with unregisted options. |
---|
567 | |
---|
568 | desc.add_options() |
---|
569 | ("help,h", "") |
---|
570 | ("magic,m", value<string>(), "") |
---|
571 | ; |
---|
572 | |
---|
573 | input.clear(); |
---|
574 | input.push_back("-hc"); |
---|
575 | input.push_back("-mc"); |
---|
576 | |
---|
577 | |
---|
578 | cmdline cmd2(input); |
---|
579 | cmd2.set_options_description(desc); |
---|
580 | cmd2.allow_unregistered(); |
---|
581 | |
---|
582 | result = cmd2.run(); |
---|
583 | |
---|
584 | BOOST_REQUIRE(result.size() == 3); |
---|
585 | BOOST_CHECK_EQUAL(result[0].string_key, "help"); |
---|
586 | BOOST_CHECK_EQUAL(result[0].unregistered, false); |
---|
587 | BOOST_CHECK(result[0].value.empty()); |
---|
588 | BOOST_CHECK_EQUAL(result[1].string_key, "-c"); |
---|
589 | BOOST_CHECK_EQUAL(result[1].unregistered, true); |
---|
590 | BOOST_CHECK(result[1].value.empty()); |
---|
591 | BOOST_CHECK_EQUAL(result[2].string_key, "magic"); |
---|
592 | BOOST_CHECK_EQUAL(result[2].unregistered, false); |
---|
593 | BOOST_CHECK_EQUAL(result[2].value[0], "c"); |
---|
594 | |
---|
595 | // CONSIDER: |
---|
596 | // There's a corner case: |
---|
597 | // -foo |
---|
598 | // when 'allow_long_disguise' is set. Should this be considered |
---|
599 | // disguised long option 'foo' or short option '-f' with value 'oo'? |
---|
600 | // It's not clear yet, so I'm leaving the decision till later. |
---|
601 | } |
---|
602 | |
---|
603 | int test_main(int ac, char* av[]) |
---|
604 | { |
---|
605 | test_long_options(); |
---|
606 | test_short_options(); |
---|
607 | test_dos_options(); |
---|
608 | test_disguised_long(); |
---|
609 | test_guessing(); |
---|
610 | test_arguments(); |
---|
611 | test_prefix(); |
---|
612 | test_additional_parser(); |
---|
613 | test_style_parser(); |
---|
614 | test_unregistered(); |
---|
615 | |
---|
616 | return 0; |
---|
617 | } |
---|