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