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