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