• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
7 #include <boost/program_options/variables_map.hpp>
8 #include <boost/program_options/options_description.hpp>
9 #include <boost/program_options/parsers.hpp>
10 #include <boost/program_options/detail/utf8_codecvt_facet.hpp>
11 using namespace boost::program_options;
12 // We'll use po::value everywhere to workaround vc6 bug.
13 namespace po = boost::program_options;
14 
15 #include <boost/function.hpp>
16 using namespace boost;
17 
18 #include <sstream>
19 using namespace std;
20 
21 #include "minitest.hpp"
22 
sv(const char * array[],unsigned size)23 vector<string> sv(const char* array[], unsigned size)
24 {
25     vector<string> r;
26     for (unsigned i = 0; i < size; ++i)
27         r.push_back(array[i]);
28     return r;
29 }
30 
test_variable_map()31 void test_variable_map()
32 {
33     options_description desc;
34     desc.add_options()
35         ("foo,f", new untyped_value)
36         ("bar,b", po::value<string>())
37         ("biz,z", po::value<string>())
38         ("baz", new untyped_value())
39         ("output,o", new untyped_value(), "")
40         ;
41     const char* cmdline3_[] = { "--foo='12'", "--bar=11", "-z3", "-ofoo" };
42     vector<string> cmdline3 = sv(cmdline3_,
43                                  sizeof(cmdline3_)/sizeof(const char*));
44     parsed_options a3 = command_line_parser(cmdline3).options(desc).run();
45     variables_map vm;
46     store(a3, vm);
47     notify(vm);
48     BOOST_REQUIRE(vm.size() == 4);
49     BOOST_CHECK(vm["foo"].as<string>() == "'12'");
50     BOOST_CHECK(vm["bar"].as<string>() == "11");
51     BOOST_CHECK(vm.count("biz") == 1);
52     BOOST_CHECK(vm["biz"].as<string>() == "3");
53     BOOST_CHECK(vm["output"].as<string>() == "foo");
54 
55     int i;
56     desc.add_options()
57     ("zee", bool_switch(), "")
58     ("zak", po::value<int>(&i), "")
59     ("opt", bool_switch(), "");
60 
61     const char* cmdline4_[] = { "--zee", "--zak=13" };
62     vector<string> cmdline4 = sv(cmdline4_,
63                                  sizeof(cmdline4_)/sizeof(const char*));
64     parsed_options a4 = command_line_parser(cmdline4).options(desc).run();
65 
66     variables_map vm2;
67     store(a4, vm2);
68     notify(vm2);
69     BOOST_REQUIRE(vm2.size() == 3);
70     BOOST_CHECK(vm2["zee"].as<bool>() == true);
71     BOOST_CHECK(vm2["zak"].as<int>() == 13);
72     BOOST_CHECK(vm2["opt"].as<bool>() == false);
73     BOOST_CHECK(i == 13);
74 
75     options_description desc2;
76     desc2.add_options()
77     ("vee", po::value<string>()->default_value("42"))
78     ("voo", po::value<string>())
79     ("iii", po::value<int>()->default_value(123))
80     ;
81     const char* cmdline5_[] = { "--voo=1" };
82     vector<string> cmdline5 = sv(cmdline5_,
83                                  sizeof(cmdline5_)/sizeof(const char*));
84     parsed_options a5 = command_line_parser(cmdline5).options(desc2).run();
85 
86     variables_map vm3;
87     store(a5, vm3);
88     notify(vm3);
89     BOOST_REQUIRE(vm3.size() == 3);
90     BOOST_CHECK(vm3["vee"].as<string>() == "42");
91     BOOST_CHECK(vm3["voo"].as<string>() == "1");
92     BOOST_CHECK(vm3["iii"].as<int>() == 123);
93 
94     options_description desc3;
95     desc3.add_options()
96     ("imp", po::value<int>()->implicit_value(100))
97     ("iim", po::value<int>()->implicit_value(200)->default_value(201))
98     ("mmp,m", po::value<int>()->implicit_value(123)->default_value(124))
99     ("foo", po::value<int>())
100     ;
101     /* The -m option is implicit. It does not have value in inside the token,
102        and we should not grab the next token.  */
103     const char* cmdline6_[] = {  "--imp=1", "-m", "--foo=1" };
104     vector<string> cmdline6 = sv(cmdline6_,
105                                  sizeof(cmdline6_)/sizeof(const char*));
106     parsed_options a6 = command_line_parser(cmdline6).options(desc3).run();
107 
108     variables_map vm4;
109     store(a6, vm4);
110     notify(vm4);
111     BOOST_REQUIRE(vm4.size() == 4);
112     BOOST_CHECK(vm4["imp"].as<int>() == 1);
113     BOOST_CHECK(vm4["iim"].as<int>() == 201);
114     BOOST_CHECK(vm4["mmp"].as<int>() == 123);
115 }
116 
117 int stored_value;
notifier(const vector<int> & v)118 void notifier(const vector<int>& v)
119 {
120     stored_value = v.front();
121 }
122 
test_semantic_values()123 void test_semantic_values()
124 {
125     options_description desc;
126     desc.add_options()
127     ("foo", new untyped_value())
128     ("bar", po::value<int>())
129     ("biz", po::value< vector<string> >())
130     ("baz", po::value< vector<string> >()->multitoken())
131     ("int", po::value< vector<int> >()->notifier(&notifier))
132     ;
133 
134 
135     parsed_options parsed(&desc);
136     vector<option>& options = parsed.options;
137     vector<string> v;
138     v.push_back("q");
139     options.push_back(option("foo", vector<string>(1, "1")));
140     options.push_back(option("biz", vector<string>(1, "a")));
141     options.push_back(option("baz", v));
142     options.push_back(option("bar", vector<string>(1, "1")));
143     options.push_back(option("biz", vector<string>(1, "b x")));
144     v.push_back("w");
145     options.push_back(option("baz", v));
146 
147     variables_map vm;
148     store(parsed, vm);
149     notify(vm);
150     BOOST_REQUIRE(vm.count("biz") == 1);
151     BOOST_REQUIRE(vm.count("baz") == 1);
152     const vector<string> av = vm["biz"].as< vector<string> >();
153     const vector<string> av2 = vm["baz"].as< vector<string> >();
154     string exp1[] = { "a", "b x" };
155     BOOST_CHECK(av == vector<string>(exp1, exp1 + 2));
156     string exp2[] = { "q", "q", "w" };
157     BOOST_CHECK(av2 == vector<string>(exp2, exp2 + 3));
158 
159     options.push_back(option("int", vector<string>(1, "13")));
160 
161     variables_map vm2;
162     store(parsed, vm2);
163     notify(vm2);
164     BOOST_REQUIRE(vm2.count("int") == 1);
165     BOOST_CHECK(vm2["int"].as< vector<int> >() == vector<int>(1, 13));
166     BOOST_CHECK_EQUAL(stored_value, 13);
167 
168     vector<option> saved_options = options;
169 
170     options.push_back(option("bar", vector<string>(1, "2")));
171     variables_map vm3;
172     BOOST_CHECK_THROW(store(parsed, vm3), multiple_occurrences);
173 
174     options = saved_options;
175     // Now try passing two int in one 'argv' element.
176     // This should not work.
177     options.push_back(option("int", vector<string>(1, "2 3")));
178     variables_map vm4;
179     BOOST_CHECK_THROW(store(parsed, vm4), validation_error);
180 }
181 
test_priority()182 void test_priority()
183 {
184     options_description desc;
185     desc.add_options()
186     // Value of this option will be specified in two sources,
187     // and only first one should be used.
188     ("first", po::value< vector<int > >())
189     // Value of this option will have default value in the first source,
190     // and explicit assignment in the second, so the second should be used.
191     ("second", po::value< vector<int > >()->default_value(vector<int>(1, 1), ""))
192     ("aux", po::value< vector<int > >())
193      // This will have values in both sources, and values should be combined
194     ("include", po::value< vector<int> >()->composing())
195     ;
196 
197     const char* cmdline1_[] = { "--first=1", "--aux=10", "--first=3", "--include=1" };
198     vector<string> cmdline1 = sv(cmdline1_,
199                                  sizeof(cmdline1_)/sizeof(const char*));
200 
201     parsed_options p1 = command_line_parser(cmdline1).options(desc).run();
202 
203     const char* cmdline2_[] = { "--first=12", "--second=7", "--include=7" };
204     vector<string> cmdline2 = sv(cmdline2_,
205                                  sizeof(cmdline2_)/sizeof(const char*));
206 
207     parsed_options p2 = command_line_parser(cmdline2).options(desc).run();
208 
209     variables_map vm;
210     store(p1, vm);
211 
212     BOOST_REQUIRE(vm.count("first") == 1);
213     BOOST_REQUIRE(vm["first"].as< vector<int> >().size() == 2);
214     BOOST_CHECK_EQUAL(vm["first"].as< vector<int> >()[0], 1);
215     BOOST_CHECK_EQUAL(vm["first"].as< vector<int> >()[1], 3);
216 
217     BOOST_REQUIRE(vm.count("second") == 1);
218     BOOST_REQUIRE(vm["second"].as< vector<int> >().size() == 1);
219     BOOST_CHECK_EQUAL(vm["second"].as< vector<int> >()[0], 1);
220 
221     store(p2, vm);
222 
223     // Value should not change.
224     BOOST_REQUIRE(vm.count("first") == 1);
225     BOOST_REQUIRE(vm["first"].as< vector<int> >().size() == 2);
226     BOOST_CHECK_EQUAL(vm["first"].as< vector<int> >()[0], 1);
227     BOOST_CHECK_EQUAL(vm["first"].as< vector<int> >()[1], 3);
228 
229     // Value should change to 7
230     BOOST_REQUIRE(vm.count("second") == 1);
231     BOOST_REQUIRE(vm["second"].as< vector<int> >().size() == 1);
232     BOOST_CHECK_EQUAL(vm["second"].as< vector<int> >()[0], 7);
233 
234     BOOST_REQUIRE(vm.count("include") == 1);
235     BOOST_REQUIRE(vm["include"].as< vector<int> >().size() == 2);
236     BOOST_CHECK_EQUAL(vm["include"].as< vector<int> >()[0], 1);
237     BOOST_CHECK_EQUAL(vm["include"].as< vector<int> >()[1], 7);
238 }
239 
test_multiple_assignments_with_different_option_description()240 void test_multiple_assignments_with_different_option_description()
241 {
242     // Test that if we store option twice into the same variable_map,
243     // and some of the options stored the first time are not present
244     // in the options descrription provided the second time, we don't crash.
245 
246     options_description desc1("");
247     desc1.add_options()
248         ("help,h", "")
249         ("includes", po::value< vector<string> >()->composing(), "");
250         ;
251 
252     options_description desc2("");
253     desc2.add_options()
254         ("output,o", "");
255 
256     vector<string> input1;
257     input1.push_back("--help");
258     input1.push_back("--includes=a");
259     parsed_options p1 = command_line_parser(input1).options(desc1).run();
260 
261     vector<string> input2;
262     input1.push_back("--output");
263     parsed_options p2 = command_line_parser(input2).options(desc2).run();
264 
265     vector<string> input3;
266     input3.push_back("--includes=b");
267     parsed_options p3 = command_line_parser(input3).options(desc1).run();
268 
269 
270     variables_map vm;
271     store(p1, vm);
272     store(p2, vm);
273     store(p3, vm);
274 
275     BOOST_REQUIRE(vm.count("help") == 1);
276     BOOST_REQUIRE(vm.count("includes") == 1);
277     BOOST_CHECK_EQUAL(vm["includes"].as< vector<string> >()[0], "a");
278     BOOST_CHECK_EQUAL(vm["includes"].as< vector<string> >()[1], "b");
279 
280 }
281 
main(int,char * [])282 int main(int, char* [])
283 {
284     test_variable_map();
285     test_semantic_values();
286     test_priority();
287     test_multiple_assignments_with_different_option_description();
288     return 0;
289 }
290 
291