1 // Copyright Sascha Ochsenknecht 2009.
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 
7 #include <boost/program_options/parsers.hpp>
8 #include <boost/program_options/options_description.hpp>
9 #include <boost/program_options/variables_map.hpp>
10 #include <boost/program_options/cmdline.hpp>
11 using namespace boost::program_options;
12 
13 #include <iostream>
14 #include <sstream>
15 #include <vector>
16 #include <cassert>
17 using namespace std;
18 
19 #include "minitest.hpp"
20 
21 
test_ambiguous()22 void test_ambiguous()
23 {
24     options_description desc;
25     desc.add_options()
26         ("cfgfile,c", value<string>()->multitoken(), "the config file")
27         ("output,c", value<string>(), "the output file")
28         ("output,o", value<string>(), "the output file")
29     ;
30 
31     const char* cmdline[] = {"program", "-c", "file", "-o", "anotherfile"};
32 
33     variables_map vm;
34     try {
35        store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
36                                     const_cast<char**>(cmdline), desc), vm);
37     }
38     catch (ambiguous_option& e)
39     {
40         BOOST_CHECK_EQUAL(e.alternatives().size(), 2);
41         BOOST_CHECK_EQUAL(e.get_option_name(), "-c");
42         BOOST_CHECK_EQUAL(e.alternatives()[0], "cfgfile");
43         BOOST_CHECK_EQUAL(e.alternatives()[1], "output");
44     }
45 }
46 
47 
test_ambiguous_long()48 void test_ambiguous_long()
49 {
50     options_description desc;
51     desc.add_options()
52         ("cfgfile,c", value<string>()->multitoken(), "the config file")
53         ("output,c", value<string>(), "the output file")
54         ("output,o", value<string>(), "the output file")
55     ;
56 
57     const char* cmdline[] = {"program", "--cfgfile", "file", "--output", "anotherfile"};
58 
59     variables_map vm;
60     try {
61        store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
62                                     const_cast<char**>(cmdline), desc), vm);
63     }
64     catch (ambiguous_option& e)
65     {
66         BOOST_CHECK_EQUAL(e.alternatives().size(), 2);
67         BOOST_CHECK_EQUAL(e.get_option_name(), "--output");
68         BOOST_CHECK_EQUAL(e.alternatives()[0], "output");
69         BOOST_CHECK_EQUAL(e.alternatives()[1], "output");
70     }
71 }
72 
test_ambiguous_multiple_long_names()73 void test_ambiguous_multiple_long_names()
74 {
75     options_description desc;
76     desc.add_options()
77         ("cfgfile,foo,c", value<string>()->multitoken(), "the config file")
78         ("output,foo,o", value<string>(), "the output file")
79     ;
80 
81     const char* cmdline[] = {"program", "--foo", "file"};
82 
83     variables_map vm;
84     try {
85        store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
86                                     const_cast<char**>(cmdline), desc), vm);
87     }
88     catch (ambiguous_option& e)
89     {
90         BOOST_CHECK_EQUAL(e.alternatives().size(), 2);
91         BOOST_CHECK_EQUAL(e.get_option_name(), "--foo");
92         BOOST_CHECK_EQUAL(e.alternatives()[0], "cfgfile");
93         BOOST_CHECK_EQUAL(e.alternatives()[1], "output");
94     }
95 }
96 
97 
98 
test_unknown_option()99 void test_unknown_option()
100 {
101    options_description desc;
102    desc.add_options()
103         ("cfgfile,c", value<string>(), "the configfile")
104       ;
105 
106    const char* cmdline[] = {"program", "-c", "file", "-f", "anotherfile"};
107 
108    variables_map vm;
109    try {
110       store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
111                                     const_cast<char**>(cmdline), desc), vm);
112    }
113    catch (unknown_option& e)
114    {
115       BOOST_CHECK_EQUAL(e.get_option_name(), "-f");
116       BOOST_CHECK_EQUAL(string(e.what()), "unrecognised option '-f'");
117    }
118 }
119 
120 
121 
test_multiple_values()122 void test_multiple_values()
123 {
124    options_description desc;
125    desc.add_options()
126         ("cfgfile,c", value<string>()->multitoken(), "the config file")
127         ("output,o", value<string>(), "the output file")
128       ;
129 
130    const char* cmdline[] = { "program", "-o", "fritz", "hugo", "--cfgfile", "file", "c", "-o", "text.out" };
131 
132    variables_map vm;
133    try {
134       store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
135                                     const_cast<char**>(cmdline), desc), vm);
136       notify(vm);
137    }
138    catch (validation_error& e)
139    {
140       // TODO: this is currently validation_error, shouldn't it be multiple_values ???
141       //
142       //   multiple_values is thrown only at one place untyped_value::xparse(),
143       //    but I think this can never be reached
144       //   because: untyped_value always has one value and this is filtered before reach specific
145       //   validation and parsing
146       //
147       BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
148       BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' only takes a single argument");
149    }
150 }
151 
152 
test_multiple_occurrences()153 void test_multiple_occurrences()
154 {
155    options_description desc;
156    desc.add_options()
157         ("cfgfile,c", value<string>(), "the configfile")
158       ;
159 
160    const char* cmdline[] = {"program", "--cfgfile", "file", "-c", "anotherfile"};
161 
162    variables_map vm;
163    try {
164       store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
165                                     const_cast<char**>(cmdline), desc), vm);
166       notify(vm);
167    }
168    catch (multiple_occurrences& e)
169    {
170       BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
171       BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' cannot be specified more than once");
172    }
173 }
174 
test_multiple_occurrences_with_different_names()175 void test_multiple_occurrences_with_different_names()
176 {
177    options_description desc;
178    desc.add_options()
179         ("cfgfile,config-file,c", value<string>(), "the configfile")
180       ;
181 
182    const char* cmdline[] = {"program", "--config-file", "file", "--cfgfile", "anotherfile"};
183 
184    variables_map vm;
185    try {
186       store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
187                                     const_cast<char**>(cmdline), desc), vm);
188       notify(vm);
189    }
190    catch (multiple_occurrences& e)
191    {
192       BOOST_CHECK( (e.get_option_name() == "--cfgfile") || (e.get_option_name() == "--config-file"));
193       BOOST_CHECK(
194          (string(e.what()) == "option '--cfgfile' cannot be specified more than once") ||
195          (string(e.what()) == "option '--config-file' cannot be specified more than once")
196       );
197    }
198 }
199 
200 
test_multiple_occurrences_with_non_key_names()201 void test_multiple_occurrences_with_non_key_names()
202 {
203    options_description desc;
204    desc.add_options()
205         ("cfgfile,config-file,c", value<string>(), "the configfile")
206       ;
207 
208    const char* cmdline[] = {"program", "--config-file", "file", "-c", "anotherfile"};
209 
210    variables_map vm;
211    try {
212       store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
213                                     const_cast<char**>(cmdline), desc), vm);
214       notify(vm);
215    }
216    catch (multiple_occurrences& e)
217    {
218        BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
219        BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' cannot be specified more than once");
220    }
221 }
222 
223 
test_missing_value()224 void test_missing_value()
225 {
226     options_description desc;
227     desc.add_options()
228         ("cfgfile,c", value<string>()->multitoken(), "the config file")
229         ("output,o", value<string>(), "the output file")
230     ;
231     // missing value for option '-c'
232     const char* cmdline[] = { "program", "-c", "-c", "output.txt"};
233 
234     variables_map vm;
235 
236     try {
237       store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
238                                        const_cast<char**>(cmdline), desc), vm);
239       notify(vm);
240    }
241    catch (invalid_command_line_syntax& e)
242    {
243       BOOST_CHECK_EQUAL(e.kind(), invalid_syntax::missing_parameter);
244       BOOST_CHECK_EQUAL(e.tokens(), "--cfgfile");
245    }
246 }
247 
248 
249 
main(int,char **)250 int main(int /*ac*/, char** /*av*/)
251 {
252    test_ambiguous();
253    test_ambiguous_long();
254    test_ambiguous_multiple_long_names();
255    test_unknown_option();
256    test_multiple_values();
257    test_multiple_occurrences();
258    test_multiple_occurrences_with_different_names();
259    test_multiple_occurrences_with_non_key_names();
260    test_missing_value();
261 
262    return 0;
263 }
264 
265