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