]>
Commit | Line | Data |
---|---|---|
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 | const char* syntax) | |
68 | { | |
69 | ||
70 | string s; | |
71 | stringstream ss; | |
72 | ss << syntax; | |
73 | while(ss >> s) { | |
74 | value_semantic* v = 0; | |
75 | ||
76 | if (*(s.end()-1) == '=') { | |
77 | v = value<string>(); | |
78 | s.resize(s.size()-1); | |
79 | } else if (*(s.end()-1) == '?') { | |
80 | v = value<string>()->implicit_value("default"); | |
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 j = 0; j < options.size(); ++j) | |
129 | { | |
130 | option opt = options[j]; | |
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 k = 0; k < opt.value.size(); ++k) { | |
141 | if (k != 0) | |
142 | result += "-"; | |
143 | result += opt.value[k]; | |
144 | } | |
145 | } | |
146 | } | |
147 | } | |
148 | catch(unknown_option&) { | |
149 | status = s_unknown_option; | |
150 | } | |
151 | catch(ambiguous_option&) { | |
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, 0, 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, 0, 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, 0, 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 | // Test case insensitive style. | |
221 | // Note that option names are normalized to lower case. | |
222 | test_case test_cases4[] = { | |
223 | {"--foo", s_success, "foo:"}, | |
224 | {"--Foo", s_success, "foo:"}, | |
225 | {"--bar=Ab", s_success, "bar:Ab"}, | |
226 | {"--Bar=ab", s_success, "bar:ab"}, | |
227 | {"--giz", s_success, "Giz:"}, | |
228 | {0, 0, 0} | |
229 | }; | |
230 | test_cmdline("foo bar= baz? Giz", style, test_cases4); | |
231 | } | |
232 | ||
233 | void test_short_options() | |
234 | { | |
235 | using namespace command_line_style; | |
236 | cmdline::style_t style; | |
237 | ||
238 | style = cmdline::style_t( | |
239 | allow_short | allow_dash_for_short | |
240 | | short_allow_adjacent); | |
241 | ||
242 | test_case test_cases1[] = { | |
243 | {"-d d /bar", s_success, "-d: d /bar"}, | |
244 | // This is treated as error when long options are disabled | |
245 | {"--foo", s_success, "--foo"}, | |
246 | {"-d13", s_extra_parameter, ""}, | |
247 | {"-f14", s_success, "-f:14"}, | |
248 | {"-g -f1", s_success, "-g: -f:1"}, | |
249 | {"-f", s_missing_parameter, ""}, | |
250 | {0, 0, 0} | |
251 | }; | |
252 | test_cmdline(",d ,f= ,g", style, test_cases1); | |
253 | ||
254 | style = cmdline::style_t( | |
255 | allow_short | allow_dash_for_short | |
256 | | short_allow_next); | |
257 | ||
258 | test_case test_cases2[] = { | |
259 | {"-f 13", s_success, "-f:13"}, | |
260 | {"-f -13", s_success, "-f:-13"}, | |
261 | {"-f", s_missing_parameter, ""}, | |
262 | {"-f /foo", s_success, "-f:/foo"}, | |
263 | {"-f -d", s_missing_parameter, ""}, | |
264 | {0, 0, 0} | |
265 | }; | |
266 | test_cmdline(",d ,f=", style, test_cases2); | |
267 | ||
268 | style = cmdline::style_t( | |
269 | allow_short | short_allow_next | |
270 | | allow_dash_for_short | short_allow_adjacent); | |
271 | ||
272 | test_case test_cases3[] = { | |
273 | {"-f10", s_success, "-f:10"}, | |
274 | {"-f 10", s_success, "-f:10"}, | |
275 | {"-f -d", s_missing_parameter, ""}, | |
276 | {0, 0, 0} | |
277 | }; | |
278 | test_cmdline(",d ,f=", style, test_cases3); | |
279 | ||
280 | style = cmdline::style_t( | |
281 | allow_short | short_allow_next | |
282 | | allow_dash_for_short | |
283 | | short_allow_adjacent | allow_sticky); | |
284 | ||
285 | test_case test_cases4[] = { | |
286 | {"-de", s_success, "-d: -e:"}, | |
287 | {"-df10", s_success, "-d: -f:10"}, | |
288 | // FIXME: review | |
289 | //{"-d12", s_extra_parameter, ""}, | |
290 | {"-f12", s_success, "-f:12"}, | |
291 | {"-fe", s_success, "-f:e"}, | |
292 | {0, 0, 0} | |
293 | }; | |
294 | test_cmdline(",d ,f= ,e", style, test_cases4); | |
295 | ||
296 | } | |
297 | ||
298 | ||
299 | void test_dos_options() | |
300 | { | |
301 | using namespace command_line_style; | |
302 | cmdline::style_t style; | |
303 | ||
304 | style = cmdline::style_t( | |
305 | allow_short | |
306 | | allow_slash_for_short | short_allow_adjacent); | |
307 | ||
308 | test_case test_cases1[] = { | |
309 | {"/d d -bar", s_success, "-d: d -bar"}, | |
310 | {"--foo", s_success, "--foo"}, | |
311 | {"/d13", s_extra_parameter, ""}, | |
312 | {"/f14", s_success, "-f:14"}, | |
313 | {"/f", s_missing_parameter, ""}, | |
314 | {0, 0, 0} | |
315 | }; | |
316 | test_cmdline(",d ,f=", style, test_cases1); | |
317 | ||
318 | style = cmdline::style_t( | |
319 | allow_short | |
320 | | allow_slash_for_short | short_allow_next | |
321 | | short_allow_adjacent | allow_sticky); | |
322 | ||
323 | test_case test_cases2[] = { | |
324 | {"/de", s_extra_parameter, ""}, | |
325 | {"/fe", s_success, "-f:e"}, | |
326 | {0, 0, 0} | |
327 | }; | |
328 | test_cmdline(",d ,f= ,e", style, test_cases2); | |
329 | ||
330 | } | |
331 | ||
332 | ||
333 | void test_disguised_long() | |
334 | { | |
335 | using namespace command_line_style; | |
336 | cmdline::style_t style; | |
337 | ||
338 | style = cmdline::style_t( | |
339 | allow_short | short_allow_adjacent | |
340 | | allow_dash_for_short | |
341 | | short_allow_next | allow_long_disguise | |
342 | | long_allow_adjacent); | |
343 | ||
344 | test_case test_cases1[] = { | |
345 | {"-foo -f", s_success, "foo: foo:"}, | |
346 | {"-goo=x -gy", s_success, "goo:x goo:y"}, | |
347 | {"-bee=x -by", s_success, "bee:x bee:y"}, | |
348 | {0, 0, 0} | |
349 | }; | |
350 | test_cmdline("foo,f goo,g= bee,b?", style, test_cases1); | |
351 | ||
352 | style = cmdline::style_t(style | allow_slash_for_short); | |
353 | test_case test_cases2[] = { | |
354 | {"/foo -f", s_success, "foo: foo:"}, | |
355 | {"/goo=x", s_success, "goo:x"}, | |
356 | {0, 0, 0} | |
357 | }; | |
358 | test_cmdline("foo,f goo,g= bee,b?", style, test_cases2); | |
359 | } | |
360 | ||
361 | void test_guessing() | |
362 | { | |
363 | using namespace command_line_style; | |
364 | cmdline::style_t style; | |
365 | ||
366 | style = cmdline::style_t( | |
367 | allow_short | short_allow_adjacent | |
368 | | allow_dash_for_short | |
369 | | allow_long | long_allow_adjacent | |
370 | | allow_guessing | allow_long_disguise); | |
371 | ||
372 | test_case test_cases1[] = { | |
373 | {"--opt1", s_success, "opt123:"}, | |
374 | {"--opt", s_ambiguous_option, ""}, | |
375 | {"--f=1", s_success, "foo:1"}, | |
376 | {"-far", s_success, "foo:ar"}, | |
377 | {0, 0, 0} | |
378 | }; | |
379 | test_cmdline("opt123 opt56 foo,f=", style, test_cases1); | |
380 | ||
381 | test_case test_cases2[] = { | |
382 | {"--fname file --fname2 file2", s_success, "fname: file fname2: file2"}, | |
383 | {"--fnam file --fnam file2", s_ambiguous_option, ""}, | |
384 | {"--fnam file --fname2 file2", s_ambiguous_option, ""}, | |
385 | {"--fname2 file2 --fnam file", s_ambiguous_option, ""}, | |
386 | {0, 0, 0} | |
387 | }; | |
388 | test_cmdline("fname fname2", style, test_cases2); | |
389 | } | |
390 | ||
391 | void test_arguments() | |
392 | { | |
393 | using namespace command_line_style; | |
394 | cmdline::style_t style; | |
395 | ||
396 | style = cmdline::style_t( | |
397 | allow_short | allow_long | |
398 | | allow_dash_for_short | |
399 | | short_allow_adjacent | long_allow_adjacent); | |
400 | ||
401 | test_case test_cases1[] = { | |
402 | {"-f file -gx file2", s_success, "-f: file -g:x file2"}, | |
403 | {"-f - -gx - -- -e", s_success, "-f: - -g:x - -e"}, | |
404 | {0, 0, 0} | |
405 | }; | |
406 | test_cmdline(",f ,g= ,e", style, test_cases1); | |
407 | ||
408 | // "--" should stop options regardless of whether long options are | |
409 | // allowed or not. | |
410 | ||
411 | style = cmdline::style_t( | |
412 | allow_short | short_allow_adjacent | |
413 | | allow_dash_for_short); | |
414 | ||
415 | test_case test_cases2[] = { | |
416 | {"-f - -gx - -- -e", s_success, "-f: - -g:x - -e"}, | |
417 | {0, 0, 0} | |
418 | }; | |
419 | test_cmdline(",f ,g= ,e", style, test_cases2); | |
420 | } | |
421 | ||
422 | void test_prefix() | |
423 | { | |
424 | using namespace command_line_style; | |
425 | cmdline::style_t style; | |
426 | ||
427 | style = cmdline::style_t( | |
428 | allow_short | allow_long | |
429 | | allow_dash_for_short | |
430 | | short_allow_adjacent | long_allow_adjacent | |
431 | ); | |
432 | ||
433 | test_case test_cases1[] = { | |
434 | {"--foo.bar=12", s_success, "foo.bar:12"}, | |
435 | {0, 0, 0} | |
436 | }; | |
437 | ||
438 | test_cmdline("foo*=", style, test_cases1); | |
439 | } | |
440 | ||
441 | ||
442 | pair<string, string> at_option_parser(string const&s) | |
443 | { | |
444 | if ('@' == s[0]) | |
445 | return std::make_pair(string("response-file"), s.substr(1)); | |
446 | else | |
447 | return pair<string, string>(); | |
448 | } | |
449 | ||
450 | pair<string, string> at_option_parser_broken(string const&s) | |
451 | { | |
452 | if ('@' == s[0]) | |
453 | return std::make_pair(string("some garbage"), s.substr(1)); | |
454 | else | |
455 | return pair<string, string>(); | |
456 | } | |
457 | ||
458 | ||
459 | ||
460 | void test_additional_parser() | |
461 | { | |
462 | options_description desc; | |
463 | desc.add_options() | |
464 | ("response-file", value<string>(), "response file") | |
465 | ("foo", value<int>(), "foo") | |
466 | ; | |
467 | ||
468 | vector<string> input; | |
469 | input.push_back("@config"); | |
470 | input.push_back("--foo=1"); | |
471 | ||
472 | cmdline cmd(input); | |
473 | cmd.set_options_description(desc); | |
474 | cmd.set_additional_parser(at_option_parser); | |
475 | ||
476 | vector<option> result = cmd.run(); | |
477 | ||
478 | BOOST_REQUIRE(result.size() == 2); | |
479 | BOOST_CHECK_EQUAL(result[0].string_key, "response-file"); | |
480 | BOOST_CHECK_EQUAL(result[0].value[0], "config"); | |
481 | BOOST_CHECK_EQUAL(result[1].string_key, "foo"); | |
482 | BOOST_CHECK_EQUAL(result[1].value[0], "1"); | |
483 | ||
484 | // Test that invalid options returned by additional style | |
485 | // parser are detected. | |
486 | cmdline cmd2(input); | |
487 | cmd2.set_options_description(desc); | |
488 | cmd2.set_additional_parser(at_option_parser_broken); | |
489 | ||
490 | BOOST_CHECK_THROW(cmd2.run(), unknown_option); | |
491 | ||
492 | } | |
493 | ||
494 | vector<option> at_option_parser2(vector<string>& args) | |
495 | { | |
496 | vector<option> result; | |
497 | if ('@' == args[0][0]) { | |
498 | // Simulate reading the response file. | |
499 | result.push_back(option("foo", vector<string>(1, "1"))); | |
500 | result.push_back(option("bar", vector<string>(1, "1"))); | |
501 | args.erase(args.begin()); | |
502 | } | |
503 | return result; | |
504 | } | |
505 | ||
506 | ||
507 | void test_style_parser() | |
508 | { | |
509 | options_description desc; | |
510 | desc.add_options() | |
511 | ("foo", value<int>(), "foo") | |
512 | ("bar", value<int>(), "bar") | |
513 | ; | |
514 | ||
515 | vector<string> input; | |
516 | input.push_back("@config"); | |
517 | ||
518 | cmdline cmd(input); | |
519 | cmd.set_options_description(desc); | |
520 | cmd.extra_style_parser(at_option_parser2); | |
521 | ||
522 | vector<option> result = cmd.run(); | |
523 | ||
524 | BOOST_REQUIRE(result.size() == 2); | |
525 | BOOST_CHECK_EQUAL(result[0].string_key, "foo"); | |
526 | BOOST_CHECK_EQUAL(result[0].value[0], "1"); | |
527 | BOOST_CHECK_EQUAL(result[1].string_key, "bar"); | |
528 | BOOST_CHECK_EQUAL(result[1].value[0], "1"); | |
529 | } | |
530 | ||
531 | void test_unregistered() | |
532 | { | |
533 | // Check unregisted option when no options are registed at all. | |
534 | options_description desc; | |
535 | ||
536 | vector<string> input; | |
537 | input.push_back("--foo=1"); | |
538 | input.push_back("--bar"); | |
539 | input.push_back("1"); | |
540 | input.push_back("-b"); | |
541 | input.push_back("-biz"); | |
542 | ||
543 | cmdline cmd(input); | |
544 | cmd.set_options_description(desc); | |
545 | cmd.allow_unregistered(); | |
546 | ||
547 | vector<option> result = cmd.run(); | |
548 | BOOST_REQUIRE(result.size() == 5); | |
549 | // --foo=1 | |
550 | BOOST_CHECK_EQUAL(result[0].string_key, "foo"); | |
551 | BOOST_CHECK_EQUAL(result[0].unregistered, true); | |
552 | BOOST_CHECK_EQUAL(result[0].value[0], "1"); | |
553 | // --bar | |
554 | BOOST_CHECK_EQUAL(result[1].string_key, "bar"); | |
555 | BOOST_CHECK_EQUAL(result[1].unregistered, true); | |
556 | BOOST_CHECK(result[1].value.empty()); | |
557 | // '1' is considered a positional option, not a value to | |
558 | // --bar | |
559 | BOOST_CHECK(result[2].string_key.empty()); | |
560 | BOOST_CHECK(result[2].position_key == 0); | |
561 | BOOST_CHECK_EQUAL(result[2].unregistered, false); | |
562 | BOOST_CHECK_EQUAL(result[2].value[0], "1"); | |
563 | // -b | |
564 | BOOST_CHECK_EQUAL(result[3].string_key, "-b"); | |
565 | BOOST_CHECK_EQUAL(result[3].unregistered, true); | |
566 | BOOST_CHECK(result[3].value.empty()); | |
567 | // -biz | |
568 | BOOST_CHECK_EQUAL(result[4].string_key, "-b"); | |
569 | BOOST_CHECK_EQUAL(result[4].unregistered, true); | |
570 | BOOST_CHECK_EQUAL(result[4].value[0], "iz"); | |
571 | ||
572 | // Check sticky short options together with unregisted options. | |
573 | ||
574 | desc.add_options() | |
575 | ("help,h", "") | |
576 | ("magic,m", value<string>(), "") | |
577 | ; | |
578 | ||
579 | input.clear(); | |
580 | input.push_back("-hc"); | |
581 | input.push_back("-mc"); | |
582 | ||
583 | ||
584 | cmdline cmd2(input); | |
585 | cmd2.set_options_description(desc); | |
586 | cmd2.allow_unregistered(); | |
587 | ||
588 | result = cmd2.run(); | |
589 | ||
590 | BOOST_REQUIRE(result.size() == 3); | |
591 | BOOST_CHECK_EQUAL(result[0].string_key, "help"); | |
592 | BOOST_CHECK_EQUAL(result[0].unregistered, false); | |
593 | BOOST_CHECK(result[0].value.empty()); | |
594 | BOOST_CHECK_EQUAL(result[1].string_key, "-c"); | |
595 | BOOST_CHECK_EQUAL(result[1].unregistered, true); | |
596 | BOOST_CHECK(result[1].value.empty()); | |
597 | BOOST_CHECK_EQUAL(result[2].string_key, "magic"); | |
598 | BOOST_CHECK_EQUAL(result[2].unregistered, false); | |
599 | BOOST_CHECK_EQUAL(result[2].value[0], "c"); | |
600 | ||
601 | // CONSIDER: | |
602 | // There's a corner case: | |
603 | // -foo | |
604 | // when 'allow_long_disguise' is set. Should this be considered | |
605 | // disguised long option 'foo' or short option '-f' with value 'oo'? | |
606 | // It's not clear yet, so I'm leaving the decision till later. | |
607 | } | |
608 | ||
609 | void test_implicit_value() | |
610 | { | |
611 | using namespace command_line_style; | |
612 | cmdline::style_t style; | |
613 | ||
614 | style = cmdline::style_t( | |
615 | allow_long | long_allow_adjacent | |
616 | ); | |
617 | ||
618 | test_case test_cases1[] = { | |
619 | // 'bar' does not even look like option, so is consumed | |
620 | {"--foo bar", s_success, "foo:bar"}, | |
621 | // '--bar' looks like option, and such option exists, so we don't consume this token | |
622 | {"--foo --bar", s_success, "foo: bar:"}, | |
623 | // '--biz' looks like option, but does not match any existing one. | |
624 | // Presently this results in parse error, since | |
625 | // (1) in cmdline.cpp:finish_option, we only consume following tokens if they are | |
626 | // requires | |
627 | // (2) in cmdline.cpp:run, we let options consume following positional options | |
628 | // For --biz, an exception is thrown between 1 and 2. | |
629 | // We might want to fix that in future. | |
630 | {"--foo --biz", s_unknown_option, ""}, | |
631 | {0, 0, 0} | |
632 | }; | |
633 | ||
634 | test_cmdline("foo? bar?", style, test_cases1); | |
635 | } | |
636 | ||
637 | int main(int /*ac*/, char** /*av*/) | |
638 | { | |
639 | test_long_options(); | |
640 | test_short_options(); | |
641 | test_dos_options(); | |
642 | test_disguised_long(); | |
643 | test_guessing(); | |
644 | test_arguments(); | |
645 | test_prefix(); | |
646 | test_additional_parser(); | |
647 | test_style_parser(); | |
648 | test_unregistered(); | |
649 | test_implicit_value(); | |
650 | ||
651 | return 0; | |
652 | } |