• 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