variable_map_test.cpp 9.7 KB

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