Line data Source code
1 : // Author(s): Jeroen van der Wulp
2 : // Copyright: see the accompanying file COPYING or copy at
3 : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4 : //
5 : // Distributed under the Boost Software License, Version 1.0.
6 : // (See accompanying file LICENSE_1_0.txt or copy at
7 : // http://www.boost.org/LICENSE_1_0.txt)
8 : //
9 : /// \file command_line_interface_test.cpp
10 :
11 : #define BOOST_AUTO_TEST_MAIN
12 : #include <boost/test/included/unit_test.hpp>
13 :
14 : #include "mcrl2/utilities/command_line_interface.h"
15 :
16 : using namespace ::mcrl2::utilities;
17 :
18 : enum streamable_enum {
19 : foo,
20 : bar
21 : };
22 :
23 2 : std::istream& operator>>(std::istream& in, streamable_enum& out)
24 : {
25 2 : std::string word;
26 2 : in >> word;
27 2 : if (word == "foo")
28 : {
29 2 : out = foo;
30 : }
31 : else
32 0 : if (word == "bar")
33 : {
34 0 : out = bar;
35 : }
36 : else
37 : {
38 0 : in.setstate(std::ios_base::failbit);
39 : }
40 2 : return in;
41 2 : }
42 :
43 2 : std::ostream& operator<<(std::ostream& out, const streamable_enum& in)
44 : {
45 2 : switch (in)
46 : {
47 1 : case foo:
48 1 : return out << "foo";
49 1 : case bar:
50 1 : return out << "bar";
51 : }
52 0 : return out << "invalid_streamable_enum";
53 : }
54 :
55 2 : BOOST_AUTO_TEST_CASE(border_invalid)
56 : {
57 2 : interface_description test_interface("test", "TEST", "Kilroy", "[OPTIONS]... [PATH]", "whatis", "description");
58 :
59 : // Empty command line
60 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, ""));
61 1 : char c = '\0';
62 1 : char* pc = &c;
63 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, 0, &pc));
64 1 : wchar_t w = L'\0';
65 1 : wchar_t* pw = &w;
66 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, 0, &pw));
67 1 : }
68 :
69 2 : BOOST_AUTO_TEST_CASE(parsing)
70 : {
71 2 : interface_description test_interface("test", "TEST", "Kilroy", "[OPTIONS]... [PATH]", "whatis", "description");
72 :
73 : // Valid option -h
74 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test -v"));
75 : // Repeated options --help options
76 2 : BOOST_CHECK_THROW(command_line_parser(test_interface, "test --verbose -v -v"), std::runtime_error);
77 : // Invalid combination of short options
78 2 : BOOST_CHECK_THROW(command_line_parser(test_interface, "test -ve"), std::runtime_error);
79 :
80 : // Duplicate long option without argument
81 6 : BOOST_CHECK_THROW(test_interface.add_option("verbose","An option"), std::logic_error);
82 : // Duplicate long option with short option and without argument
83 6 : BOOST_CHECK_THROW(test_interface.add_option("verbose", "An option", 'h'), std::logic_error);
84 : // Duplicate long option with short option and with optional argument
85 9 : BOOST_CHECK_THROW(test_interface.add_option("verbose",make_mandatory_argument("STR"), "An option", 'v'), std::logic_error);
86 : // Duplicate long option with short option and with optional argument
87 11 : BOOST_CHECK_THROW(test_interface.add_option("verbose",make_optional_argument("STR", "XxXxX"), "An option", 'v'), std::logic_error);
88 :
89 1 : test_interface.add_option("mandatory", make_mandatory_argument("STR"), "option with mandatory argument", 'm');
90 : // Missing mandatory argument for option --mandatory
91 2 : BOOST_CHECK_THROW(command_line_parser(test_interface, "test --mandatory"), std::runtime_error);
92 : // Valid option with valid argument
93 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test --mandatory=test"));
94 : // Valid option with valid argument
95 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test -m=test"));
96 : // Valid option with valid argument
97 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test -m test"));
98 : // Valid short option v followed by option m with valid argument
99 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test -vm=test"));
100 :
101 1 : test_interface.add_option("optional", make_optional_argument("STR", "*XxXxX*"), "option with optional argument", 'o');
102 : // Missing mandatory argument for option --mandatory
103 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test --optional"));
104 : // Valid option with valid argument
105 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test --optional=test"));
106 : // Valid option with valid argument
107 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test -otest"));
108 : // Valid option without argument
109 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test -o test"));
110 : // Valid short option v followed by option m with valid argument
111 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test -vmtest"));
112 1 : }
113 :
114 2 : BOOST_AUTO_TEST_CASE(conformance)
115 : {
116 2 : interface_description test_interface("test", "TEST", "Kilroy", "[OPTIONS]... [PATH]", "whatis", "description");
117 :
118 : // Valid options -v, --verbose
119 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test -v"));
120 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test --verbose"));
121 : // Valid options -q, --quiet
122 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test -q"));
123 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test --quiet"));
124 : // Valid options -d, --debug
125 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test -d"));
126 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test --debug"));
127 :
128 : // Check conversion with wide characters
129 1 : wchar_t const* arguments[] = { L"test", L"--debug", L"--verbose=2" } ;
130 :
131 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, 2, arguments));
132 2 : BOOST_CHECK_THROW(command_line_parser(test_interface, 3, arguments), std::runtime_error);
133 1 : }
134 :
135 2 : BOOST_AUTO_TEST_CASE(custom_types)
136 : {
137 2 : auto arg = make_enum_argument<streamable_enum>("argument");
138 1 : arg.add_value_desc(foo, "Self-explanatory.");
139 1 : arg.add_value_desc(bar, "Also self-explanatory.", true);
140 2 : interface_description test_interface("test", "TEST", "Kilroy", "[OPTIONS]... [PATH]", "whatis", "description");
141 1 : test_interface.add_option("argument", arg, "either foo or bar.", 'a');
142 :
143 : // Missing mandatory argument for option --rewriter
144 2 : BOOST_CHECK_THROW(command_line_parser(test_interface, "test --argument"), std::runtime_error);
145 : // Valid rewriter option with valid argument
146 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test --argument=foo"));
147 : // Valid rewriter option with valid argument
148 1 : BOOST_CHECK_NO_THROW(command_line_parser(test_interface, "test -afoo"));
149 : // Valid rewriter option with invalid argument
150 2 : BOOST_CHECK_THROW(command_line_parser(test_interface, "test --argument=baz"), std::runtime_error);
151 1 : }
152 :
153 8 : inline std::string const& first_of(command_line_parser const& p, std::string const& option)
154 : {
155 8 : return p.options.equal_range(option).first->second;
156 : }
157 :
158 5 : inline std::string const& last_of(command_line_parser const& p, std::string const& option)
159 : {
160 5 : command_line_parser::option_map::const_iterator i(p.options.equal_range(option).second);
161 :
162 5 : return (--i)->second;
163 : }
164 :
165 2 : BOOST_AUTO_TEST_CASE(result_browsing)
166 : {
167 2 : interface_description test_interface("test", "TEST", "Kilroy", "[OPTIONS]... [PATH]", "whatis", "description");
168 :
169 : // disable check for duplicate options
170 1 : test_interface.add_option("cli-testing-no-duplicate-option-checking", "");
171 :
172 : {
173 1 : command_line_parser parser(test_interface, "test -v --debug -d --verbose");
174 :
175 1 : BOOST_CHECK(parser.options.size() == 4);
176 1 : BOOST_CHECK(parser.options.count("verbose") == 2);
177 1 : BOOST_CHECK(first_of(parser, "verbose").empty());
178 1 : BOOST_CHECK(last_of(parser, "verbose").empty());
179 4 : BOOST_CHECK_THROW(parser.option_argument("verbose"), std::logic_error);
180 1 : BOOST_CHECK(parser.options.count("debug") == 2);
181 1 : BOOST_CHECK(first_of(parser, "debug").empty());
182 1 : BOOST_CHECK(last_of(parser, "debug").empty());
183 1 : BOOST_CHECK(parser.options.count("quiet") == 0);
184 1 : BOOST_CHECK(parser.arguments.size() == 0);
185 1 : }
186 :
187 : {
188 1 : command_line_parser parser(test_interface, "test /bin/ls -v \\or\\more:1234567890|,<>.:;[]}{+-_=~!@#$%^&*()");
189 :
190 1 : BOOST_CHECK(parser.options.size() == 1);
191 1 : BOOST_CHECK(first_of(parser, "verbose").empty());
192 1 : BOOST_CHECK(parser.arguments.size() == 2);
193 1 : BOOST_CHECK(parser.arguments[0] == "/bin/ls");
194 1 : BOOST_CHECK(parser.arguments[1] == "\\or\\more:1234567890|,<>.:;[]}{+-_=~!@#$%^&*()");
195 1 : }
196 :
197 1 : test_interface.add_option("mandatory", make_mandatory_argument("STR"), "option with mandatory argument", 'm');
198 1 : test_interface.add_option("optional", make_optional_argument("STR", "4321"), "option with optional argument", 'o');
199 :
200 : {
201 1 : command_line_parser parser(test_interface, "test --mandatory=BLA --optional=1234 -vo -vmALB");
202 :
203 1 : BOOST_CHECK(parser.options.size() == 6);
204 1 : BOOST_CHECK(first_of(parser, "mandatory") != last_of(parser, "mandatory"));
205 1 : BOOST_CHECK((first_of(parser, "mandatory") == "BLA" && last_of(parser, "mandatory") == "ALB") ||
206 : (first_of(parser, "mandatory") == "ALB" && last_of(parser, "mandatory") == "BLA"));
207 1 : BOOST_CHECK((first_of(parser, "optional") == "4321" && last_of(parser, "optional") == "1234") ||
208 : (first_of(parser, "optional") == "1234" && last_of(parser, "optional") == "4321"));
209 1 : BOOST_CHECK(parser.option_argument_as< int >("optional") == 1234 ||
210 : parser.option_argument_as< int >("optional") == 4321);
211 1 : BOOST_CHECK(parser.arguments.size() == 0);
212 1 : }
213 : {
214 1 : command_line_parser parser(test_interface, "test -m BLA -o 1234");
215 :
216 1 : BOOST_CHECK(first_of(parser, "mandatory") == "BLA");
217 1 : BOOST_CHECK(parser.option_argument_as< int >("optional") == 4321);
218 1 : BOOST_CHECK(parser.arguments.size() == 1);
219 1 : }
220 1 : }
|