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