xref: /freebsd-src/contrib/kyua/utils/cmdline/base_command_test.cpp (revision b0d29bc47dba79f6f38e67eabadfb4b32ffd9390)
1*b0d29bc4SBrooks Davis // Copyright 2010 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis //   documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis //   may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis //   without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis 
29*b0d29bc4SBrooks Davis #include "utils/cmdline/base_command.ipp"
30*b0d29bc4SBrooks Davis 
31*b0d29bc4SBrooks Davis #include <atf-c++.hpp>
32*b0d29bc4SBrooks Davis 
33*b0d29bc4SBrooks Davis #include "utils/cmdline/exceptions.hpp"
34*b0d29bc4SBrooks Davis #include "utils/cmdline/options.hpp"
35*b0d29bc4SBrooks Davis #include "utils/cmdline/parser.ipp"
36*b0d29bc4SBrooks Davis #include "utils/cmdline/ui_mock.hpp"
37*b0d29bc4SBrooks Davis #include "utils/defs.hpp"
38*b0d29bc4SBrooks Davis 
39*b0d29bc4SBrooks Davis namespace cmdline = utils::cmdline;
40*b0d29bc4SBrooks Davis 
41*b0d29bc4SBrooks Davis 
42*b0d29bc4SBrooks Davis namespace {
43*b0d29bc4SBrooks Davis 
44*b0d29bc4SBrooks Davis 
45*b0d29bc4SBrooks Davis /// Mock command to test the cmdline::base_command base class.
46*b0d29bc4SBrooks Davis ///
47*b0d29bc4SBrooks Davis /// \param Data The type of the opaque data object passed to main().
48*b0d29bc4SBrooks Davis /// \param ExpectedData The value run() will expect to find in the Data object
49*b0d29bc4SBrooks Davis ///     passed to main().
50*b0d29bc4SBrooks Davis template< typename Data, Data ExpectedData >
51*b0d29bc4SBrooks Davis class mock_cmd : public cmdline::base_command< Data > {
52*b0d29bc4SBrooks Davis public:
53*b0d29bc4SBrooks Davis     /// Indicates if run() has been called already and executed correctly.
54*b0d29bc4SBrooks Davis     bool executed;
55*b0d29bc4SBrooks Davis 
56*b0d29bc4SBrooks Davis     /// Contains the argument of --the_string after run() is executed.
57*b0d29bc4SBrooks Davis     std::string optvalue;
58*b0d29bc4SBrooks Davis 
59*b0d29bc4SBrooks Davis     /// Constructs a new mock command.
mock_cmd(void)60*b0d29bc4SBrooks Davis     mock_cmd(void) :
61*b0d29bc4SBrooks Davis         cmdline::base_command< Data >("mock", "arg1 [arg2 [arg3]]", 1, 3,
62*b0d29bc4SBrooks Davis                                       "Command for testing."),
63*b0d29bc4SBrooks Davis         executed(false)
64*b0d29bc4SBrooks Davis     {
65*b0d29bc4SBrooks Davis         this->add_option(cmdline::string_option("the_string", "Test option",
66*b0d29bc4SBrooks Davis                                                 "arg"));
67*b0d29bc4SBrooks Davis     }
68*b0d29bc4SBrooks Davis 
69*b0d29bc4SBrooks Davis     /// Executes the command.
70*b0d29bc4SBrooks Davis     ///
71*b0d29bc4SBrooks Davis     /// \param cmdline Representation of the command line to the subcommand.
72*b0d29bc4SBrooks Davis     /// \param data Arbitrary data cookie passed to the command.
73*b0d29bc4SBrooks Davis     ///
74*b0d29bc4SBrooks Davis     /// \return A hardcoded number for testing purposes.
75*b0d29bc4SBrooks Davis     int
run(cmdline::ui *,const cmdline::parsed_cmdline & cmdline,const Data & data)76*b0d29bc4SBrooks Davis     run(cmdline::ui* /* ui */,
77*b0d29bc4SBrooks Davis         const cmdline::parsed_cmdline& cmdline, const Data& data)
78*b0d29bc4SBrooks Davis     {
79*b0d29bc4SBrooks Davis         if (cmdline.has_option("the_string"))
80*b0d29bc4SBrooks Davis             optvalue = cmdline.get_option< cmdline::string_option >(
81*b0d29bc4SBrooks Davis                 "the_string");
82*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(ExpectedData, data);
83*b0d29bc4SBrooks Davis         executed = true;
84*b0d29bc4SBrooks Davis         return 1234;
85*b0d29bc4SBrooks Davis     }
86*b0d29bc4SBrooks Davis };
87*b0d29bc4SBrooks Davis 
88*b0d29bc4SBrooks Davis 
89*b0d29bc4SBrooks Davis /// Mock command to test the cmdline::base_command_no_data base class.
90*b0d29bc4SBrooks Davis class mock_cmd_no_data : public cmdline::base_command_no_data {
91*b0d29bc4SBrooks Davis public:
92*b0d29bc4SBrooks Davis     /// Indicates if run() has been called already and executed correctly.
93*b0d29bc4SBrooks Davis     bool executed;
94*b0d29bc4SBrooks Davis 
95*b0d29bc4SBrooks Davis     /// Contains the argument of --the_string after run() is executed.
96*b0d29bc4SBrooks Davis     std::string optvalue;
97*b0d29bc4SBrooks Davis 
98*b0d29bc4SBrooks Davis     /// Constructs a new mock command.
mock_cmd_no_data(void)99*b0d29bc4SBrooks Davis     mock_cmd_no_data(void) :
100*b0d29bc4SBrooks Davis         cmdline::base_command_no_data("mock", "arg1 [arg2 [arg3]]", 1, 3,
101*b0d29bc4SBrooks Davis                                       "Command for testing."),
102*b0d29bc4SBrooks Davis         executed(false)
103*b0d29bc4SBrooks Davis     {
104*b0d29bc4SBrooks Davis         add_option(cmdline::string_option("the_string", "Test option", "arg"));
105*b0d29bc4SBrooks Davis     }
106*b0d29bc4SBrooks Davis 
107*b0d29bc4SBrooks Davis     /// Executes the command.
108*b0d29bc4SBrooks Davis     ///
109*b0d29bc4SBrooks Davis     /// \param cmdline Representation of the command line to the subcommand.
110*b0d29bc4SBrooks Davis     ///
111*b0d29bc4SBrooks Davis     /// \return A hardcoded number for testing purposes.
112*b0d29bc4SBrooks Davis     int
run(cmdline::ui *,const cmdline::parsed_cmdline & cmdline)113*b0d29bc4SBrooks Davis     run(cmdline::ui* /* ui */,
114*b0d29bc4SBrooks Davis         const cmdline::parsed_cmdline& cmdline)
115*b0d29bc4SBrooks Davis     {
116*b0d29bc4SBrooks Davis         if (cmdline.has_option("the_string"))
117*b0d29bc4SBrooks Davis             optvalue = cmdline.get_option< cmdline::string_option >(
118*b0d29bc4SBrooks Davis                 "the_string");
119*b0d29bc4SBrooks Davis         executed = true;
120*b0d29bc4SBrooks Davis         return 1234;
121*b0d29bc4SBrooks Davis     }
122*b0d29bc4SBrooks Davis };
123*b0d29bc4SBrooks Davis 
124*b0d29bc4SBrooks Davis 
125*b0d29bc4SBrooks Davis /// Implementation of a command to get access to parse_cmdline().
126*b0d29bc4SBrooks Davis class parse_cmdline_portal : public cmdline::command_proto {
127*b0d29bc4SBrooks Davis public:
128*b0d29bc4SBrooks Davis     /// Constructs a new mock command.
parse_cmdline_portal(void)129*b0d29bc4SBrooks Davis     parse_cmdline_portal(void) :
130*b0d29bc4SBrooks Davis         cmdline::command_proto("portal", "arg1 [arg2 [arg3]]", 1, 3,
131*b0d29bc4SBrooks Davis                                "Command for testing.")
132*b0d29bc4SBrooks Davis     {
133*b0d29bc4SBrooks Davis         this->add_option(cmdline::string_option("the_string", "Test option",
134*b0d29bc4SBrooks Davis                                                 "arg"));
135*b0d29bc4SBrooks Davis     }
136*b0d29bc4SBrooks Davis 
137*b0d29bc4SBrooks Davis     /// Delegator for the internal parse_cmdline() method.
138*b0d29bc4SBrooks Davis     ///
139*b0d29bc4SBrooks Davis     /// \param args The input arguments to be parsed.
140*b0d29bc4SBrooks Davis     ///
141*b0d29bc4SBrooks Davis     /// \return The parsed command line, split in options and arguments.
142*b0d29bc4SBrooks Davis     cmdline::parsed_cmdline
operator ()(const cmdline::args_vector & args) const143*b0d29bc4SBrooks Davis     operator()(const cmdline::args_vector& args) const
144*b0d29bc4SBrooks Davis     {
145*b0d29bc4SBrooks Davis         return parse_cmdline(args);
146*b0d29bc4SBrooks Davis     }
147*b0d29bc4SBrooks Davis };
148*b0d29bc4SBrooks Davis 
149*b0d29bc4SBrooks Davis 
150*b0d29bc4SBrooks Davis }  // anonymous namespace
151*b0d29bc4SBrooks Davis 
152*b0d29bc4SBrooks Davis 
153*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(command_proto__parse_cmdline__ok);
ATF_TEST_CASE_BODY(command_proto__parse_cmdline__ok)154*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(command_proto__parse_cmdline__ok)
155*b0d29bc4SBrooks Davis {
156*b0d29bc4SBrooks Davis     cmdline::args_vector args;
157*b0d29bc4SBrooks Davis     args.push_back("portal");
158*b0d29bc4SBrooks Davis     args.push_back("--the_string=foo bar");
159*b0d29bc4SBrooks Davis     args.push_back("one arg");
160*b0d29bc4SBrooks Davis     args.push_back("another arg");
161*b0d29bc4SBrooks Davis     (void)parse_cmdline_portal()(args);
162*b0d29bc4SBrooks Davis }
163*b0d29bc4SBrooks Davis 
164*b0d29bc4SBrooks Davis 
165*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(command_proto__parse_cmdline__parse_fail);
ATF_TEST_CASE_BODY(command_proto__parse_cmdline__parse_fail)166*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(command_proto__parse_cmdline__parse_fail)
167*b0d29bc4SBrooks Davis {
168*b0d29bc4SBrooks Davis     cmdline::args_vector args;
169*b0d29bc4SBrooks Davis     args.push_back("portal");
170*b0d29bc4SBrooks Davis     args.push_back("--foo-bar");
171*b0d29bc4SBrooks Davis     ATF_REQUIRE_THROW_RE(cmdline::usage_error, "Unknown.*foo-bar",
172*b0d29bc4SBrooks Davis                          (void)parse_cmdline_portal()(args));
173*b0d29bc4SBrooks Davis }
174*b0d29bc4SBrooks Davis 
175*b0d29bc4SBrooks Davis 
176*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(command_proto__parse_cmdline__args_invalid);
ATF_TEST_CASE_BODY(command_proto__parse_cmdline__args_invalid)177*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(command_proto__parse_cmdline__args_invalid)
178*b0d29bc4SBrooks Davis {
179*b0d29bc4SBrooks Davis     cmdline::args_vector args;
180*b0d29bc4SBrooks Davis     args.push_back("portal");
181*b0d29bc4SBrooks Davis 
182*b0d29bc4SBrooks Davis     ATF_REQUIRE_THROW_RE(cmdline::usage_error, "Not enough arguments",
183*b0d29bc4SBrooks Davis                          (void)parse_cmdline_portal()(args));
184*b0d29bc4SBrooks Davis 
185*b0d29bc4SBrooks Davis     args.push_back("1");
186*b0d29bc4SBrooks Davis     args.push_back("2");
187*b0d29bc4SBrooks Davis     args.push_back("3");
188*b0d29bc4SBrooks Davis     args.push_back("4");
189*b0d29bc4SBrooks Davis     ATF_REQUIRE_THROW_RE(cmdline::usage_error, "Too many arguments",
190*b0d29bc4SBrooks Davis                          (void)parse_cmdline_portal()(args));
191*b0d29bc4SBrooks Davis }
192*b0d29bc4SBrooks Davis 
193*b0d29bc4SBrooks Davis 
194*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(base_command__getters);
ATF_TEST_CASE_BODY(base_command__getters)195*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(base_command__getters)
196*b0d29bc4SBrooks Davis {
197*b0d29bc4SBrooks Davis     mock_cmd< int, 584 > cmd;
198*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("mock", cmd.name());
199*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("arg1 [arg2 [arg3]]", cmd.arg_list());
200*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("Command for testing.", cmd.short_description());
201*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(1, cmd.options().size());
202*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("the_string", cmd.options()[0]->long_name());
203*b0d29bc4SBrooks Davis }
204*b0d29bc4SBrooks Davis 
205*b0d29bc4SBrooks Davis 
206*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(base_command__main__ok)
ATF_TEST_CASE_BODY(base_command__main__ok)207*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(base_command__main__ok)
208*b0d29bc4SBrooks Davis {
209*b0d29bc4SBrooks Davis     mock_cmd< int, 584 > cmd;
210*b0d29bc4SBrooks Davis 
211*b0d29bc4SBrooks Davis     cmdline::ui_mock ui;
212*b0d29bc4SBrooks Davis     cmdline::args_vector args;
213*b0d29bc4SBrooks Davis     args.push_back("mock");
214*b0d29bc4SBrooks Davis     args.push_back("--the_string=foo bar");
215*b0d29bc4SBrooks Davis     args.push_back("one arg");
216*b0d29bc4SBrooks Davis     args.push_back("another arg");
217*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(1234, cmd.main(&ui, args, 584));
218*b0d29bc4SBrooks Davis     ATF_REQUIRE(cmd.executed);
219*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("foo bar", cmd.optvalue);
220*b0d29bc4SBrooks Davis }
221*b0d29bc4SBrooks Davis 
222*b0d29bc4SBrooks Davis 
223*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(base_command__main__parse_cmdline_fail)
ATF_TEST_CASE_BODY(base_command__main__parse_cmdline_fail)224*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(base_command__main__parse_cmdline_fail)
225*b0d29bc4SBrooks Davis {
226*b0d29bc4SBrooks Davis     mock_cmd< int, 584 > cmd;
227*b0d29bc4SBrooks Davis 
228*b0d29bc4SBrooks Davis     cmdline::ui_mock ui;
229*b0d29bc4SBrooks Davis     cmdline::args_vector args;
230*b0d29bc4SBrooks Davis     args.push_back("mock");
231*b0d29bc4SBrooks Davis     args.push_back("--foo-bar");
232*b0d29bc4SBrooks Davis     ATF_REQUIRE_THROW_RE(cmdline::usage_error, "Unknown.*foo-bar",
233*b0d29bc4SBrooks Davis                          cmd.main(&ui, args, 584));
234*b0d29bc4SBrooks Davis     ATF_REQUIRE(!cmd.executed);
235*b0d29bc4SBrooks Davis }
236*b0d29bc4SBrooks Davis 
237*b0d29bc4SBrooks Davis 
238*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(base_command_no_data__getters);
ATF_TEST_CASE_BODY(base_command_no_data__getters)239*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(base_command_no_data__getters)
240*b0d29bc4SBrooks Davis {
241*b0d29bc4SBrooks Davis     mock_cmd_no_data cmd;
242*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("mock", cmd.name());
243*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("arg1 [arg2 [arg3]]", cmd.arg_list());
244*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("Command for testing.", cmd.short_description());
245*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(1, cmd.options().size());
246*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("the_string", cmd.options()[0]->long_name());
247*b0d29bc4SBrooks Davis }
248*b0d29bc4SBrooks Davis 
249*b0d29bc4SBrooks Davis 
250*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(base_command_no_data__main__ok)
ATF_TEST_CASE_BODY(base_command_no_data__main__ok)251*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(base_command_no_data__main__ok)
252*b0d29bc4SBrooks Davis {
253*b0d29bc4SBrooks Davis     mock_cmd_no_data cmd;
254*b0d29bc4SBrooks Davis 
255*b0d29bc4SBrooks Davis     cmdline::ui_mock ui;
256*b0d29bc4SBrooks Davis     cmdline::args_vector args;
257*b0d29bc4SBrooks Davis     args.push_back("mock");
258*b0d29bc4SBrooks Davis     args.push_back("--the_string=foo bar");
259*b0d29bc4SBrooks Davis     args.push_back("one arg");
260*b0d29bc4SBrooks Davis     args.push_back("another arg");
261*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(1234, cmd.main(&ui, args));
262*b0d29bc4SBrooks Davis     ATF_REQUIRE(cmd.executed);
263*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("foo bar", cmd.optvalue);
264*b0d29bc4SBrooks Davis }
265*b0d29bc4SBrooks Davis 
266*b0d29bc4SBrooks Davis 
267*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(base_command_no_data__main__parse_cmdline_fail)
ATF_TEST_CASE_BODY(base_command_no_data__main__parse_cmdline_fail)268*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(base_command_no_data__main__parse_cmdline_fail)
269*b0d29bc4SBrooks Davis {
270*b0d29bc4SBrooks Davis     mock_cmd_no_data cmd;
271*b0d29bc4SBrooks Davis 
272*b0d29bc4SBrooks Davis     cmdline::ui_mock ui;
273*b0d29bc4SBrooks Davis     cmdline::args_vector args;
274*b0d29bc4SBrooks Davis     args.push_back("mock");
275*b0d29bc4SBrooks Davis     args.push_back("--foo-bar");
276*b0d29bc4SBrooks Davis     ATF_REQUIRE_THROW_RE(cmdline::usage_error, "Unknown.*foo-bar",
277*b0d29bc4SBrooks Davis                          cmd.main(&ui, args));
278*b0d29bc4SBrooks Davis     ATF_REQUIRE(!cmd.executed);
279*b0d29bc4SBrooks Davis }
280*b0d29bc4SBrooks Davis 
281*b0d29bc4SBrooks Davis 
ATF_INIT_TEST_CASES(tcs)282*b0d29bc4SBrooks Davis ATF_INIT_TEST_CASES(tcs)
283*b0d29bc4SBrooks Davis {
284*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, command_proto__parse_cmdline__ok);
285*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, command_proto__parse_cmdline__parse_fail);
286*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, command_proto__parse_cmdline__args_invalid);
287*b0d29bc4SBrooks Davis 
288*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, base_command__getters);
289*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, base_command__main__ok);
290*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, base_command__main__parse_cmdline_fail);
291*b0d29bc4SBrooks Davis 
292*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, base_command_no_data__getters);
293*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, base_command_no_data__main__ok);
294*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, base_command_no_data__main__parse_cmdline_fail);
295*b0d29bc4SBrooks Davis }
296