xref: /netbsd-src/external/bsd/kyua-cli/dist/cli/main_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 "cli/main.hpp"
30*6b3a42afSjmmv 
31*6b3a42afSjmmv extern "C" {
32*6b3a42afSjmmv #include <signal.h>
33*6b3a42afSjmmv }
34*6b3a42afSjmmv 
35*6b3a42afSjmmv #include <cstdlib>
36*6b3a42afSjmmv 
37*6b3a42afSjmmv #include <atf-c++.hpp>
38*6b3a42afSjmmv 
39*6b3a42afSjmmv #include "utils/cmdline/base_command.ipp"
40*6b3a42afSjmmv #include "utils/cmdline/exceptions.hpp"
41*6b3a42afSjmmv #include "utils/cmdline/globals.hpp"
42*6b3a42afSjmmv #include "utils/cmdline/options.hpp"
43*6b3a42afSjmmv #include "utils/cmdline/parser.hpp"
44*6b3a42afSjmmv #include "utils/cmdline/ui_mock.hpp"
45*6b3a42afSjmmv #include "utils/datetime.hpp"
46*6b3a42afSjmmv #include "utils/defs.hpp"
47*6b3a42afSjmmv #include "utils/env.hpp"
48*6b3a42afSjmmv #include "utils/fs/operations.hpp"
49*6b3a42afSjmmv #include "utils/fs/path.hpp"
50*6b3a42afSjmmv #include "utils/logging/macros.hpp"
51*6b3a42afSjmmv #include "utils/logging/operations.hpp"
52*6b3a42afSjmmv #include "utils/process/child.ipp"
53*6b3a42afSjmmv #include "utils/process/status.hpp"
54*6b3a42afSjmmv 
55*6b3a42afSjmmv namespace cmdline = utils::cmdline;
56*6b3a42afSjmmv namespace config = utils::config;
57*6b3a42afSjmmv namespace datetime = utils::datetime;
58*6b3a42afSjmmv namespace fs = utils::fs;
59*6b3a42afSjmmv namespace logging = utils::logging;
60*6b3a42afSjmmv namespace process = utils::process;
61*6b3a42afSjmmv 
62*6b3a42afSjmmv 
63*6b3a42afSjmmv namespace {
64*6b3a42afSjmmv 
65*6b3a42afSjmmv 
66*6b3a42afSjmmv /// Fake command implementation that crashes during its execution.
67*6b3a42afSjmmv class cmd_mock_crash : public cli::cli_command {
68*6b3a42afSjmmv public:
69*6b3a42afSjmmv     /// Constructs a new mock command.
70*6b3a42afSjmmv     ///
71*6b3a42afSjmmv     /// All command parameters are set to irrelevant values.
cmd_mock_crash(void)72*6b3a42afSjmmv     cmd_mock_crash(void) :
73*6b3a42afSjmmv         cli::cli_command("mock_error", "", 0, 0, "Mock command that crashes")
74*6b3a42afSjmmv     {
75*6b3a42afSjmmv     }
76*6b3a42afSjmmv 
77*6b3a42afSjmmv     /// Runs the mock command.
78*6b3a42afSjmmv     ///
79*6b3a42afSjmmv     /// \param unused_ui Object to interact with the I/O of the program.
80*6b3a42afSjmmv     /// \param unused_cmdline Representation of the command line to the
81*6b3a42afSjmmv     ///     subcommand.
82*6b3a42afSjmmv     /// \param unused_user_config The runtime configuration of the program.
83*6b3a42afSjmmv     ///
84*6b3a42afSjmmv     /// \return Nothing because this function always aborts.
85*6b3a42afSjmmv     int
run(cmdline::ui * UTILS_UNUSED_PARAM (ui),const cmdline::parsed_cmdline & UTILS_UNUSED_PARAM (cmdline),const config::tree & UTILS_UNUSED_PARAM (user_config))86*6b3a42afSjmmv     run(cmdline::ui* UTILS_UNUSED_PARAM(ui),
87*6b3a42afSjmmv         const cmdline::parsed_cmdline& UTILS_UNUSED_PARAM(cmdline),
88*6b3a42afSjmmv         const config::tree& UTILS_UNUSED_PARAM(user_config))
89*6b3a42afSjmmv     {
90*6b3a42afSjmmv         std::abort();
91*6b3a42afSjmmv     }
92*6b3a42afSjmmv };
93*6b3a42afSjmmv 
94*6b3a42afSjmmv 
95*6b3a42afSjmmv /// Fake command implementation that throws an exception during its execution.
96*6b3a42afSjmmv class cmd_mock_error : public cli::cli_command {
97*6b3a42afSjmmv     /// Whether the command raises an exception captured by the parent or not.
98*6b3a42afSjmmv     ///
99*6b3a42afSjmmv     /// If this is true, the command will raise a std::runtime_error exception
100*6b3a42afSjmmv     /// or a subclass of it.  The main program is in charge of capturing these
101*6b3a42afSjmmv     /// and reporting them appropriately.  If false, this raises another
102*6b3a42afSjmmv     /// exception that does not inherit from std::runtime_error.
103*6b3a42afSjmmv     bool _unhandled;
104*6b3a42afSjmmv 
105*6b3a42afSjmmv public:
106*6b3a42afSjmmv     /// Constructs a new mock command.
107*6b3a42afSjmmv     ///
108*6b3a42afSjmmv     /// \param unhandled If true, make run raise an exception not catched by the
109*6b3a42afSjmmv     ///     main program.
cmd_mock_error(const bool unhandled)110*6b3a42afSjmmv     cmd_mock_error(const bool unhandled) :
111*6b3a42afSjmmv         cli::cli_command("mock_error", "", 0, 0,
112*6b3a42afSjmmv                          "Mock command that raises an error"),
113*6b3a42afSjmmv         _unhandled(unhandled)
114*6b3a42afSjmmv     {
115*6b3a42afSjmmv     }
116*6b3a42afSjmmv 
117*6b3a42afSjmmv     /// Runs the mock command.
118*6b3a42afSjmmv     ///
119*6b3a42afSjmmv     /// \param unused_ui Object to interact with the I/O of the program.
120*6b3a42afSjmmv     /// \param unused_cmdline Representation of the command line to the
121*6b3a42afSjmmv     ///     subcommand.
122*6b3a42afSjmmv     /// \param unused_user_config The runtime configuration of the program.
123*6b3a42afSjmmv     ///
124*6b3a42afSjmmv     /// \return Nothing because this function always aborts.
125*6b3a42afSjmmv     ///
126*6b3a42afSjmmv     /// \throw std::logic_error If _unhandled is true.
127*6b3a42afSjmmv     /// \throw std::runtime_error If _unhandled is false.
128*6b3a42afSjmmv     int
run(cmdline::ui * UTILS_UNUSED_PARAM (ui),const cmdline::parsed_cmdline & UTILS_UNUSED_PARAM (cmdline),const config::tree & UTILS_UNUSED_PARAM (user_config))129*6b3a42afSjmmv     run(cmdline::ui* UTILS_UNUSED_PARAM(ui),
130*6b3a42afSjmmv         const cmdline::parsed_cmdline& UTILS_UNUSED_PARAM(cmdline),
131*6b3a42afSjmmv         const config::tree& UTILS_UNUSED_PARAM(user_config))
132*6b3a42afSjmmv     {
133*6b3a42afSjmmv         if (_unhandled)
134*6b3a42afSjmmv             throw std::logic_error("This is unhandled");
135*6b3a42afSjmmv         else
136*6b3a42afSjmmv             throw std::runtime_error("Runtime error");
137*6b3a42afSjmmv     }
138*6b3a42afSjmmv };
139*6b3a42afSjmmv 
140*6b3a42afSjmmv 
141*6b3a42afSjmmv /// Fake command implementation that prints messages during its execution.
142*6b3a42afSjmmv class cmd_mock_write : public cli::cli_command {
143*6b3a42afSjmmv public:
144*6b3a42afSjmmv     /// Constructs a new mock command.
145*6b3a42afSjmmv     ///
146*6b3a42afSjmmv     /// All command parameters are set to irrelevant values.
cmd_mock_write(void)147*6b3a42afSjmmv     cmd_mock_write(void) : cli::cli_command(
148*6b3a42afSjmmv         "mock_write", "", 0, 0, "Mock command that prints output")
149*6b3a42afSjmmv     {
150*6b3a42afSjmmv     }
151*6b3a42afSjmmv 
152*6b3a42afSjmmv     /// Runs the mock command.
153*6b3a42afSjmmv     ///
154*6b3a42afSjmmv     /// \param ui Object to interact with the I/O of the program.
155*6b3a42afSjmmv     /// \param unused_cmdline Representation of the command line to the
156*6b3a42afSjmmv     ///     subcommand.
157*6b3a42afSjmmv     /// \param unused_user_config The runtime configuration of the program.
158*6b3a42afSjmmv     ///
159*6b3a42afSjmmv     /// \return Nothing because this function always aborts.
160*6b3a42afSjmmv     int
run(cmdline::ui * ui,const cmdline::parsed_cmdline & UTILS_UNUSED_PARAM (cmdline),const config::tree & UTILS_UNUSED_PARAM (user_config))161*6b3a42afSjmmv     run(cmdline::ui* ui,
162*6b3a42afSjmmv         const cmdline::parsed_cmdline& UTILS_UNUSED_PARAM(cmdline),
163*6b3a42afSjmmv         const config::tree& UTILS_UNUSED_PARAM(user_config))
164*6b3a42afSjmmv     {
165*6b3a42afSjmmv         ui->out("stdout message from subcommand");
166*6b3a42afSjmmv         ui->err("stderr message from subcommand");
167*6b3a42afSjmmv         return EXIT_FAILURE;
168*6b3a42afSjmmv     }
169*6b3a42afSjmmv };
170*6b3a42afSjmmv 
171*6b3a42afSjmmv 
172*6b3a42afSjmmv }  // anonymous namespace
173*6b3a42afSjmmv 
174*6b3a42afSjmmv 
175*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__default_log_name__home);
ATF_TEST_CASE_BODY(detail__default_log_name__home)176*6b3a42afSjmmv ATF_TEST_CASE_BODY(detail__default_log_name__home)
177*6b3a42afSjmmv {
178*6b3a42afSjmmv     datetime::set_mock_now(2011, 2, 21, 21, 10, 30, 0);
179*6b3a42afSjmmv     cmdline::init("progname1");
180*6b3a42afSjmmv 
181*6b3a42afSjmmv     utils::setenv("HOME", "/home//fake");
182*6b3a42afSjmmv     utils::setenv("TMPDIR", "/do/not/use/this");
183*6b3a42afSjmmv     ATF_REQUIRE_EQ(
184*6b3a42afSjmmv         fs::path("/home/fake/.kyua/logs/progname1.20110221-211030.log"),
185*6b3a42afSjmmv         cli::detail::default_log_name());
186*6b3a42afSjmmv }
187*6b3a42afSjmmv 
188*6b3a42afSjmmv 
189*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__default_log_name__tmpdir);
ATF_TEST_CASE_BODY(detail__default_log_name__tmpdir)190*6b3a42afSjmmv ATF_TEST_CASE_BODY(detail__default_log_name__tmpdir)
191*6b3a42afSjmmv {
192*6b3a42afSjmmv     datetime::set_mock_now(2011, 2, 21, 21, 10, 50, 987);
193*6b3a42afSjmmv     cmdline::init("progname2");
194*6b3a42afSjmmv 
195*6b3a42afSjmmv     utils::unsetenv("HOME");
196*6b3a42afSjmmv     utils::setenv("TMPDIR", "/a/b//c");
197*6b3a42afSjmmv     ATF_REQUIRE_EQ(fs::path("/a/b/c/progname2.20110221-211050.log"),
198*6b3a42afSjmmv                    cli::detail::default_log_name());
199*6b3a42afSjmmv }
200*6b3a42afSjmmv 
201*6b3a42afSjmmv 
202*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(detail__default_log_name__hardcoded);
ATF_TEST_CASE_BODY(detail__default_log_name__hardcoded)203*6b3a42afSjmmv ATF_TEST_CASE_BODY(detail__default_log_name__hardcoded)
204*6b3a42afSjmmv {
205*6b3a42afSjmmv     datetime::set_mock_now(2011, 2, 21, 21, 15, 00, 123456);
206*6b3a42afSjmmv     cmdline::init("progname3");
207*6b3a42afSjmmv 
208*6b3a42afSjmmv     utils::unsetenv("HOME");
209*6b3a42afSjmmv     utils::unsetenv("TMPDIR");
210*6b3a42afSjmmv     ATF_REQUIRE_EQ(fs::path("/tmp/progname3.20110221-211500.log"),
211*6b3a42afSjmmv                    cli::detail::default_log_name());
212*6b3a42afSjmmv }
213*6b3a42afSjmmv 
214*6b3a42afSjmmv 
215*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__no_args);
ATF_TEST_CASE_BODY(main__no_args)216*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__no_args)
217*6b3a42afSjmmv {
218*6b3a42afSjmmv     logging::set_inmemory();
219*6b3a42afSjmmv     cmdline::init("progname");
220*6b3a42afSjmmv 
221*6b3a42afSjmmv     const int argc = 1;
222*6b3a42afSjmmv     const char* const argv[] = {"progname", NULL};
223*6b3a42afSjmmv 
224*6b3a42afSjmmv     cmdline::ui_mock ui;
225*6b3a42afSjmmv     ATF_REQUIRE_EQ(3, cli::main(&ui, argc, argv));
226*6b3a42afSjmmv     ATF_REQUIRE(ui.out_log().empty());
227*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_collection("Usage error: No command provided",
228*6b3a42afSjmmv                                             ui.err_log()));
229*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_collection("Type.*progname help",
230*6b3a42afSjmmv                                             ui.err_log()));
231*6b3a42afSjmmv }
232*6b3a42afSjmmv 
233*6b3a42afSjmmv 
234*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__unknown_command);
ATF_TEST_CASE_BODY(main__unknown_command)235*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__unknown_command)
236*6b3a42afSjmmv {
237*6b3a42afSjmmv     logging::set_inmemory();
238*6b3a42afSjmmv     cmdline::init("progname");
239*6b3a42afSjmmv 
240*6b3a42afSjmmv     const int argc = 2;
241*6b3a42afSjmmv     const char* const argv[] = {"progname", "foo", NULL};
242*6b3a42afSjmmv 
243*6b3a42afSjmmv     cmdline::ui_mock ui;
244*6b3a42afSjmmv     ATF_REQUIRE_EQ(3, cli::main(&ui, argc, argv));
245*6b3a42afSjmmv     ATF_REQUIRE(ui.out_log().empty());
246*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_collection("Usage error: Unknown command.*foo",
247*6b3a42afSjmmv                                             ui.err_log()));
248*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_collection("Type.*progname help",
249*6b3a42afSjmmv                                             ui.err_log()));
250*6b3a42afSjmmv }
251*6b3a42afSjmmv 
252*6b3a42afSjmmv 
253*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__logfile__default);
ATF_TEST_CASE_BODY(main__logfile__default)254*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__logfile__default)
255*6b3a42afSjmmv {
256*6b3a42afSjmmv     logging::set_inmemory();
257*6b3a42afSjmmv     datetime::set_mock_now(2011, 2, 21, 21, 30, 00, 0);
258*6b3a42afSjmmv     cmdline::init("progname");
259*6b3a42afSjmmv 
260*6b3a42afSjmmv     const int argc = 1;
261*6b3a42afSjmmv     const char* const argv[] = {"progname", NULL};
262*6b3a42afSjmmv 
263*6b3a42afSjmmv     cmdline::ui_mock ui;
264*6b3a42afSjmmv     ATF_REQUIRE(!fs::exists(fs::path(
265*6b3a42afSjmmv         ".kyua/logs/progname.20110221-213000.log")));
266*6b3a42afSjmmv     ATF_REQUIRE_EQ(3, cli::main(&ui, argc, argv));
267*6b3a42afSjmmv     ATF_REQUIRE(fs::exists(fs::path(
268*6b3a42afSjmmv         ".kyua/logs/progname.20110221-213000.log")));
269*6b3a42afSjmmv }
270*6b3a42afSjmmv 
271*6b3a42afSjmmv 
272*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__logfile__override);
ATF_TEST_CASE_BODY(main__logfile__override)273*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__logfile__override)
274*6b3a42afSjmmv {
275*6b3a42afSjmmv     logging::set_inmemory();
276*6b3a42afSjmmv     datetime::set_mock_now(2011, 2, 21, 21, 30, 00, 321);
277*6b3a42afSjmmv     cmdline::init("progname");
278*6b3a42afSjmmv 
279*6b3a42afSjmmv     const int argc = 2;
280*6b3a42afSjmmv     const char* const argv[] = {"progname", "--logfile=test.log", NULL};
281*6b3a42afSjmmv 
282*6b3a42afSjmmv     cmdline::ui_mock ui;
283*6b3a42afSjmmv     ATF_REQUIRE(!fs::exists(fs::path("test.log")));
284*6b3a42afSjmmv     ATF_REQUIRE_EQ(3, cli::main(&ui, argc, argv));
285*6b3a42afSjmmv     ATF_REQUIRE(!fs::exists(fs::path(
286*6b3a42afSjmmv         ".kyua/logs/progname.20110221-213000.log")));
287*6b3a42afSjmmv     ATF_REQUIRE(fs::exists(fs::path("test.log")));
288*6b3a42afSjmmv }
289*6b3a42afSjmmv 
290*6b3a42afSjmmv 
291*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__loglevel__default);
ATF_TEST_CASE_BODY(main__loglevel__default)292*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__loglevel__default)
293*6b3a42afSjmmv {
294*6b3a42afSjmmv     logging::set_inmemory();
295*6b3a42afSjmmv     cmdline::init("progname");
296*6b3a42afSjmmv 
297*6b3a42afSjmmv     const int argc = 2;
298*6b3a42afSjmmv     const char* const argv[] = {"progname", "--logfile=test.log", NULL};
299*6b3a42afSjmmv 
300*6b3a42afSjmmv     LD("Mock debug message");
301*6b3a42afSjmmv     LE("Mock error message");
302*6b3a42afSjmmv     LI("Mock info message");
303*6b3a42afSjmmv     LW("Mock warning message");
304*6b3a42afSjmmv 
305*6b3a42afSjmmv     cmdline::ui_mock ui;
306*6b3a42afSjmmv     ATF_REQUIRE_EQ(3, cli::main(&ui, argc, argv));
307*6b3a42afSjmmv     ATF_REQUIRE(!atf::utils::grep_file("Mock debug message", "test.log"));
308*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_file("Mock error message", "test.log"));
309*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_file("Mock info message", "test.log"));
310*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_file("Mock warning message", "test.log"));
311*6b3a42afSjmmv }
312*6b3a42afSjmmv 
313*6b3a42afSjmmv 
314*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__loglevel__higher);
ATF_TEST_CASE_BODY(main__loglevel__higher)315*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__loglevel__higher)
316*6b3a42afSjmmv {
317*6b3a42afSjmmv     logging::set_inmemory();
318*6b3a42afSjmmv     cmdline::init("progname");
319*6b3a42afSjmmv 
320*6b3a42afSjmmv     const int argc = 3;
321*6b3a42afSjmmv     const char* const argv[] = {"progname", "--logfile=test.log",
322*6b3a42afSjmmv                                 "--loglevel=debug", NULL};
323*6b3a42afSjmmv 
324*6b3a42afSjmmv     LD("Mock debug message");
325*6b3a42afSjmmv     LE("Mock error message");
326*6b3a42afSjmmv     LI("Mock info message");
327*6b3a42afSjmmv     LW("Mock warning message");
328*6b3a42afSjmmv 
329*6b3a42afSjmmv     cmdline::ui_mock ui;
330*6b3a42afSjmmv     ATF_REQUIRE_EQ(3, cli::main(&ui, argc, argv));
331*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_file("Mock debug message", "test.log"));
332*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_file("Mock error message", "test.log"));
333*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_file("Mock info message", "test.log"));
334*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_file("Mock warning message", "test.log"));
335*6b3a42afSjmmv }
336*6b3a42afSjmmv 
337*6b3a42afSjmmv 
338*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__loglevel__lower);
ATF_TEST_CASE_BODY(main__loglevel__lower)339*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__loglevel__lower)
340*6b3a42afSjmmv {
341*6b3a42afSjmmv     logging::set_inmemory();
342*6b3a42afSjmmv     cmdline::init("progname");
343*6b3a42afSjmmv 
344*6b3a42afSjmmv     const int argc = 3;
345*6b3a42afSjmmv     const char* const argv[] = {"progname", "--logfile=test.log",
346*6b3a42afSjmmv                                 "--loglevel=warning", NULL};
347*6b3a42afSjmmv 
348*6b3a42afSjmmv     LD("Mock debug message");
349*6b3a42afSjmmv     LE("Mock error message");
350*6b3a42afSjmmv     LI("Mock info message");
351*6b3a42afSjmmv     LW("Mock warning message");
352*6b3a42afSjmmv 
353*6b3a42afSjmmv     cmdline::ui_mock ui;
354*6b3a42afSjmmv     ATF_REQUIRE_EQ(3, cli::main(&ui, argc, argv));
355*6b3a42afSjmmv     ATF_REQUIRE(!atf::utils::grep_file("Mock debug message", "test.log"));
356*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_file("Mock error message", "test.log"));
357*6b3a42afSjmmv     ATF_REQUIRE(!atf::utils::grep_file("Mock info message", "test.log"));
358*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_file("Mock warning message", "test.log"));
359*6b3a42afSjmmv }
360*6b3a42afSjmmv 
361*6b3a42afSjmmv 
362*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__loglevel__error);
ATF_TEST_CASE_BODY(main__loglevel__error)363*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__loglevel__error)
364*6b3a42afSjmmv {
365*6b3a42afSjmmv     logging::set_inmemory();
366*6b3a42afSjmmv     cmdline::init("progname");
367*6b3a42afSjmmv 
368*6b3a42afSjmmv     const int argc = 3;
369*6b3a42afSjmmv     const char* const argv[] = {"progname", "--logfile=test.log",
370*6b3a42afSjmmv                                 "--loglevel=i-am-invalid", NULL};
371*6b3a42afSjmmv 
372*6b3a42afSjmmv     cmdline::ui_mock ui;
373*6b3a42afSjmmv     ATF_REQUIRE_EQ(3, cli::main(&ui, argc, argv));
374*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_collection("Usage error.*i-am-invalid",
375*6b3a42afSjmmv                                             ui.err_log()));
376*6b3a42afSjmmv     ATF_REQUIRE(!fs::exists(fs::path("test.log")));
377*6b3a42afSjmmv }
378*6b3a42afSjmmv 
379*6b3a42afSjmmv 
380*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__subcommand__ok);
ATF_TEST_CASE_BODY(main__subcommand__ok)381*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__subcommand__ok)
382*6b3a42afSjmmv {
383*6b3a42afSjmmv     logging::set_inmemory();
384*6b3a42afSjmmv     cmdline::init("progname");
385*6b3a42afSjmmv 
386*6b3a42afSjmmv     const int argc = 2;
387*6b3a42afSjmmv     const char* const argv[] = {"progname", "mock_write", NULL};
388*6b3a42afSjmmv 
389*6b3a42afSjmmv     cmdline::ui_mock ui;
390*6b3a42afSjmmv     ATF_REQUIRE_EQ(EXIT_FAILURE,
391*6b3a42afSjmmv                    cli::main(&ui, argc, argv,
392*6b3a42afSjmmv                              cli::cli_command_ptr(new cmd_mock_write())));
393*6b3a42afSjmmv     ATF_REQUIRE_EQ(1, ui.out_log().size());
394*6b3a42afSjmmv     ATF_REQUIRE_EQ("stdout message from subcommand", ui.out_log()[0]);
395*6b3a42afSjmmv     ATF_REQUIRE_EQ(1, ui.err_log().size());
396*6b3a42afSjmmv     ATF_REQUIRE_EQ("stderr message from subcommand", ui.err_log()[0]);
397*6b3a42afSjmmv }
398*6b3a42afSjmmv 
399*6b3a42afSjmmv 
400*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__subcommand__invalid_args);
ATF_TEST_CASE_BODY(main__subcommand__invalid_args)401*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__subcommand__invalid_args)
402*6b3a42afSjmmv {
403*6b3a42afSjmmv     logging::set_inmemory();
404*6b3a42afSjmmv     cmdline::init("progname");
405*6b3a42afSjmmv 
406*6b3a42afSjmmv     const int argc = 3;
407*6b3a42afSjmmv     const char* const argv[] = {"progname", "mock_write", "bar", NULL};
408*6b3a42afSjmmv 
409*6b3a42afSjmmv     cmdline::ui_mock ui;
410*6b3a42afSjmmv     ATF_REQUIRE_EQ(3,
411*6b3a42afSjmmv                    cli::main(&ui, argc, argv,
412*6b3a42afSjmmv                              cli::cli_command_ptr(new cmd_mock_write())));
413*6b3a42afSjmmv     ATF_REQUIRE(ui.out_log().empty());
414*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_collection(
415*6b3a42afSjmmv         "Usage error for command mock_write: Too many arguments.",
416*6b3a42afSjmmv         ui.err_log()));
417*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_collection("Type.*progname help",
418*6b3a42afSjmmv                                             ui.err_log()));
419*6b3a42afSjmmv }
420*6b3a42afSjmmv 
421*6b3a42afSjmmv 
422*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__subcommand__runtime_error);
ATF_TEST_CASE_BODY(main__subcommand__runtime_error)423*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__subcommand__runtime_error)
424*6b3a42afSjmmv {
425*6b3a42afSjmmv     logging::set_inmemory();
426*6b3a42afSjmmv     cmdline::init("progname");
427*6b3a42afSjmmv 
428*6b3a42afSjmmv     const int argc = 2;
429*6b3a42afSjmmv     const char* const argv[] = {"progname", "mock_error", NULL};
430*6b3a42afSjmmv 
431*6b3a42afSjmmv     cmdline::ui_mock ui;
432*6b3a42afSjmmv     ATF_REQUIRE_EQ(2, cli::main(&ui, argc, argv,
433*6b3a42afSjmmv         cli::cli_command_ptr(new cmd_mock_error(false))));
434*6b3a42afSjmmv     ATF_REQUIRE(ui.out_log().empty());
435*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_collection("progname: E: Runtime error.",
436*6b3a42afSjmmv                                             ui.err_log()));
437*6b3a42afSjmmv }
438*6b3a42afSjmmv 
439*6b3a42afSjmmv 
440*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__subcommand__unhandled_exception);
ATF_TEST_CASE_BODY(main__subcommand__unhandled_exception)441*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__subcommand__unhandled_exception)
442*6b3a42afSjmmv {
443*6b3a42afSjmmv     logging::set_inmemory();
444*6b3a42afSjmmv     cmdline::init("progname");
445*6b3a42afSjmmv 
446*6b3a42afSjmmv     const int argc = 2;
447*6b3a42afSjmmv     const char* const argv[] = {"progname", "mock_error", NULL};
448*6b3a42afSjmmv 
449*6b3a42afSjmmv     cmdline::ui_mock ui;
450*6b3a42afSjmmv     ATF_REQUIRE_THROW(std::logic_error, cli::main(&ui, argc, argv,
451*6b3a42afSjmmv         cli::cli_command_ptr(new cmd_mock_error(true))));
452*6b3a42afSjmmv }
453*6b3a42afSjmmv 
454*6b3a42afSjmmv 
455*6b3a42afSjmmv static void
do_subcommand_crash(void)456*6b3a42afSjmmv do_subcommand_crash(void)
457*6b3a42afSjmmv {
458*6b3a42afSjmmv     logging::set_inmemory();
459*6b3a42afSjmmv     cmdline::init("progname");
460*6b3a42afSjmmv 
461*6b3a42afSjmmv     const int argc = 2;
462*6b3a42afSjmmv     const char* const argv[] = {"progname", "mock_error", NULL};
463*6b3a42afSjmmv 
464*6b3a42afSjmmv     cmdline::ui_mock ui;
465*6b3a42afSjmmv     cli::main(&ui, argc, argv,
466*6b3a42afSjmmv               cli::cli_command_ptr(new cmd_mock_crash()));
467*6b3a42afSjmmv }
468*6b3a42afSjmmv 
469*6b3a42afSjmmv 
470*6b3a42afSjmmv ATF_TEST_CASE_WITHOUT_HEAD(main__subcommand__crash);
ATF_TEST_CASE_BODY(main__subcommand__crash)471*6b3a42afSjmmv ATF_TEST_CASE_BODY(main__subcommand__crash)
472*6b3a42afSjmmv {
473*6b3a42afSjmmv     const process::status status = process::child::fork_files(
474*6b3a42afSjmmv         do_subcommand_crash, fs::path("stdout.txt"),
475*6b3a42afSjmmv         fs::path("stderr.txt"))->wait();
476*6b3a42afSjmmv     ATF_REQUIRE(status.signaled());
477*6b3a42afSjmmv     ATF_REQUIRE_EQ(SIGABRT, status.termsig());
478*6b3a42afSjmmv     ATF_REQUIRE(atf::utils::grep_file("Fatal signal", "stderr.txt"));
479*6b3a42afSjmmv }
480*6b3a42afSjmmv 
481*6b3a42afSjmmv 
ATF_INIT_TEST_CASES(tcs)482*6b3a42afSjmmv ATF_INIT_TEST_CASES(tcs)
483*6b3a42afSjmmv {
484*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, detail__default_log_name__home);
485*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, detail__default_log_name__tmpdir);
486*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, detail__default_log_name__hardcoded);
487*6b3a42afSjmmv 
488*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__no_args);
489*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__unknown_command);
490*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__logfile__default);
491*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__logfile__override);
492*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__loglevel__default);
493*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__loglevel__higher);
494*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__loglevel__lower);
495*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__loglevel__error);
496*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__subcommand__ok);
497*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__subcommand__invalid_args);
498*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__subcommand__runtime_error);
499*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__subcommand__unhandled_exception);
500*6b3a42afSjmmv     ATF_ADD_TEST_CASE(tcs, main__subcommand__crash);
501*6b3a42afSjmmv }
502