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 | |
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(options: parse_command_line(argc: sizeof(cmdline)/sizeof(const char*), |
36 | argv: const_cast<char**>(cmdline), desc), m&: 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 | |
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(options: parse_command_line(argc: sizeof(cmdline)/sizeof(const char*), |
62 | argv: const_cast<char**>(cmdline), desc), m&: 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 | |
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(options: parse_command_line(argc: sizeof(cmdline)/sizeof(const char*), |
86 | argv: const_cast<char**>(cmdline), desc), m&: 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 | |
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(options: parse_command_line(argc: sizeof(cmdline)/sizeof(const char*), |
111 | argv: const_cast<char**>(cmdline), desc), m&: 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 | |
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(options: parse_command_line(argc: sizeof(cmdline)/sizeof(const char*), |
135 | argv: const_cast<char**>(cmdline), desc), m&: vm); |
136 | notify(m&: 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 | |
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(options: parse_command_line(argc: sizeof(cmdline)/sizeof(const char*), |
165 | argv: const_cast<char**>(cmdline), desc), m&: vm); |
166 | notify(m&: 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 | |
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(options: parse_command_line(argc: sizeof(cmdline)/sizeof(const char*), |
187 | argv: const_cast<char**>(cmdline), desc), m&: vm); |
188 | notify(m&: 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 | |
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(options: parse_command_line(argc: sizeof(cmdline)/sizeof(const char*), |
213 | argv: const_cast<char**>(cmdline), desc), m&: vm); |
214 | notify(m&: 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 | |
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(options: parse_command_line(argc: sizeof(cmdline)/sizeof(const char*), |
238 | argv: const_cast<char**>(cmdline), desc), m&: vm); |
239 | notify(m&: 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 | |
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 | |