xref: /freebsd/contrib/kyua/cli/cmd_debug.cpp (revision 6b8222793fbb4c0e162232716bc454dad31b709f)
1b0d29bc4SBrooks Davis // Copyright 2011 The Kyua Authors.
2b0d29bc4SBrooks Davis // All rights reserved.
3b0d29bc4SBrooks Davis //
4b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6b0d29bc4SBrooks Davis // met:
7b0d29bc4SBrooks Davis //
8b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer.
10b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
12b0d29bc4SBrooks Davis //   documentation and/or other materials provided with the distribution.
13b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14b0d29bc4SBrooks Davis //   may be used to endorse or promote products derived from this software
15b0d29bc4SBrooks Davis //   without specific prior written permission.
16b0d29bc4SBrooks Davis //
17b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28b0d29bc4SBrooks Davis 
29b0d29bc4SBrooks Davis #include "cli/cmd_debug.hpp"
30b0d29bc4SBrooks Davis 
31b0d29bc4SBrooks Davis #include <cstdlib>
32*6b822279SIgor Ostapenko #include <iostream>
33b0d29bc4SBrooks Davis 
34b0d29bc4SBrooks Davis #include "cli/common.ipp"
35b0d29bc4SBrooks Davis #include "drivers/debug_test.hpp"
36b0d29bc4SBrooks Davis #include "engine/filters.hpp"
37b0d29bc4SBrooks Davis #include "utils/cmdline/exceptions.hpp"
38b0d29bc4SBrooks Davis #include "utils/cmdline/options.hpp"
39b0d29bc4SBrooks Davis #include "utils/cmdline/parser.ipp"
40b0d29bc4SBrooks Davis #include "utils/cmdline/ui.hpp"
41b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
42*6b822279SIgor Ostapenko #include "utils/process/executor.hpp"
43b0d29bc4SBrooks Davis 
44b0d29bc4SBrooks Davis namespace cmdline = utils::cmdline;
45b0d29bc4SBrooks Davis namespace config = utils::config;
46*6b822279SIgor Ostapenko namespace executor = utils::process::executor;
47b0d29bc4SBrooks Davis 
48b0d29bc4SBrooks Davis using cli::cmd_debug;
49b0d29bc4SBrooks Davis 
50b0d29bc4SBrooks Davis 
51*6b822279SIgor Ostapenko namespace {
52*6b822279SIgor Ostapenko 
53*6b822279SIgor Ostapenko 
54*6b822279SIgor Ostapenko const cmdline::bool_option pause_before_cleanup_upon_fail_option(
55*6b822279SIgor Ostapenko     'p',
56*6b822279SIgor Ostapenko     "pause-before-cleanup-upon-fail",
57*6b822279SIgor Ostapenko     "Pauses right before the test cleanup upon fail");
58*6b822279SIgor Ostapenko 
59*6b822279SIgor Ostapenko 
60*6b822279SIgor Ostapenko const cmdline::bool_option pause_before_cleanup_option(
61*6b822279SIgor Ostapenko     "pause-before-cleanup",
62*6b822279SIgor Ostapenko     "Pauses right before the test cleanup");
63*6b822279SIgor Ostapenko 
64*6b822279SIgor Ostapenko 
65*6b822279SIgor Ostapenko /// The debugger interface implementation.
66*6b822279SIgor Ostapenko class dbg : public engine::debugger {
67*6b822279SIgor Ostapenko     /// Object to interact with the I/O of the program.
68*6b822279SIgor Ostapenko     cmdline::ui* _ui;
69*6b822279SIgor Ostapenko 
70*6b822279SIgor Ostapenko     /// Representation of the command line to the subcommand.
71*6b822279SIgor Ostapenko     const cmdline::parsed_cmdline& _cmdline;
72*6b822279SIgor Ostapenko 
73*6b822279SIgor Ostapenko public:
74*6b822279SIgor Ostapenko     /// Constructor.
75*6b822279SIgor Ostapenko     ///
76*6b822279SIgor Ostapenko     /// \param ui_ Object to interact with the I/O of the program.
77*6b822279SIgor Ostapenko     /// \param cmdline Representation of the command line to the subcommand.
dbg(cmdline::ui * ui,const cmdline::parsed_cmdline & cmdline)78*6b822279SIgor Ostapenko     dbg(cmdline::ui* ui, const cmdline::parsed_cmdline& cmdline) :
79*6b822279SIgor Ostapenko         _ui(ui), _cmdline(cmdline)
80*6b822279SIgor Ostapenko     {}
81*6b822279SIgor Ostapenko 
before_cleanup(const model::test_program_ptr &,const model::test_case &,optional<model::test_result> & result,executor::exit_handle & eh) const82*6b822279SIgor Ostapenko     void before_cleanup(
83*6b822279SIgor Ostapenko         const model::test_program_ptr&,
84*6b822279SIgor Ostapenko         const model::test_case&,
85*6b822279SIgor Ostapenko         optional< model::test_result >& result,
86*6b822279SIgor Ostapenko         executor::exit_handle& eh) const
87*6b822279SIgor Ostapenko     {
88*6b822279SIgor Ostapenko         if (_cmdline.has_option(pause_before_cleanup_upon_fail_option
89*6b822279SIgor Ostapenko             .long_name())) {
90*6b822279SIgor Ostapenko             if (result && !result.get().good()) {
91*6b822279SIgor Ostapenko                 _ui->out("The test failed and paused right before its cleanup "
92*6b822279SIgor Ostapenko                     "routine.");
93*6b822279SIgor Ostapenko                 _ui->out(F("Test work dir: %s") % eh.work_directory().str());
94*6b822279SIgor Ostapenko                 _ui->out("Press any key to continue...");
95*6b822279SIgor Ostapenko                 (void) std::cin.get();
96*6b822279SIgor Ostapenko             }
97*6b822279SIgor Ostapenko         } else if (_cmdline.has_option(pause_before_cleanup_option
98*6b822279SIgor Ostapenko             .long_name())) {
99*6b822279SIgor Ostapenko             _ui->out("The test paused right before its cleanup routine.");
100*6b822279SIgor Ostapenko             _ui->out(F("Test work dir: %s") % eh.work_directory().str());
101*6b822279SIgor Ostapenko             _ui->out("Press any key to continue...");
102*6b822279SIgor Ostapenko             (void) std::cin.get();
103*6b822279SIgor Ostapenko         }
104*6b822279SIgor Ostapenko     };
105*6b822279SIgor Ostapenko 
106*6b822279SIgor Ostapenko };
107*6b822279SIgor Ostapenko 
108*6b822279SIgor Ostapenko 
109*6b822279SIgor Ostapenko }  // anonymous namespace
110*6b822279SIgor Ostapenko 
111*6b822279SIgor Ostapenko 
112b0d29bc4SBrooks Davis /// Default constructor for cmd_debug.
cmd_debug(void)113b0d29bc4SBrooks Davis cmd_debug::cmd_debug(void) : cli_command(
114b0d29bc4SBrooks Davis     "debug", "test_case", 1, 1,
115b0d29bc4SBrooks Davis     "Executes a single test case providing facilities for debugging")
116b0d29bc4SBrooks Davis {
117b0d29bc4SBrooks Davis     add_option(build_root_option);
118b0d29bc4SBrooks Davis     add_option(kyuafile_option);
119b0d29bc4SBrooks Davis 
120*6b822279SIgor Ostapenko     add_option(pause_before_cleanup_upon_fail_option);
121*6b822279SIgor Ostapenko     add_option(pause_before_cleanup_option);
122*6b822279SIgor Ostapenko 
123b0d29bc4SBrooks Davis     add_option(cmdline::path_option(
124b0d29bc4SBrooks Davis         "stdout", "Where to direct the standard output of the test case",
125b0d29bc4SBrooks Davis         "path", "/dev/stdout"));
126b0d29bc4SBrooks Davis 
127b0d29bc4SBrooks Davis     add_option(cmdline::path_option(
128b0d29bc4SBrooks Davis         "stderr", "Where to direct the standard error of the test case",
129b0d29bc4SBrooks Davis         "path", "/dev/stderr"));
130b0d29bc4SBrooks Davis }
131b0d29bc4SBrooks Davis 
132b0d29bc4SBrooks Davis 
133b0d29bc4SBrooks Davis /// Entry point for the "debug" subcommand.
134b0d29bc4SBrooks Davis ///
135b0d29bc4SBrooks Davis /// \param ui Object to interact with the I/O of the program.
136b0d29bc4SBrooks Davis /// \param cmdline Representation of the command line to the subcommand.
137b0d29bc4SBrooks Davis /// \param user_config The runtime debuguration of the program.
138b0d29bc4SBrooks Davis ///
139b0d29bc4SBrooks Davis /// \return 0 if everything is OK, 1 if any of the necessary documents cannot be
140b0d29bc4SBrooks Davis /// opened.
141b0d29bc4SBrooks Davis int
run(cmdline::ui * ui,const cmdline::parsed_cmdline & cmdline,const config::tree & user_config)142b0d29bc4SBrooks Davis cmd_debug::run(cmdline::ui* ui, const cmdline::parsed_cmdline& cmdline,
143b0d29bc4SBrooks Davis                const config::tree& user_config)
144b0d29bc4SBrooks Davis {
145b0d29bc4SBrooks Davis     const std::string& test_case_name = cmdline.arguments()[0];
146b0d29bc4SBrooks Davis     if (test_case_name.find(':') == std::string::npos)
147b0d29bc4SBrooks Davis         throw cmdline::usage_error(F("'%s' is not a test case identifier "
148b0d29bc4SBrooks Davis                                      "(missing ':'?)") % test_case_name);
149b0d29bc4SBrooks Davis     const engine::test_filter filter = engine::test_filter::parse(
150b0d29bc4SBrooks Davis         test_case_name);
151b0d29bc4SBrooks Davis 
152*6b822279SIgor Ostapenko     auto debugger = std::shared_ptr< engine::debugger >(new dbg(ui, cmdline));
153*6b822279SIgor Ostapenko 
154b0d29bc4SBrooks Davis     const drivers::debug_test::result result = drivers::debug_test::drive(
155*6b822279SIgor Ostapenko         debugger,
156b0d29bc4SBrooks Davis         kyuafile_path(cmdline), build_root_path(cmdline), filter, user_config,
157b0d29bc4SBrooks Davis         cmdline.get_option< cmdline::path_option >("stdout"),
158b0d29bc4SBrooks Davis         cmdline.get_option< cmdline::path_option >("stderr"));
159b0d29bc4SBrooks Davis 
160b0d29bc4SBrooks Davis     ui->out(F("%s  ->  %s") % cli::format_test_case_id(result.test_case) %
161b0d29bc4SBrooks Davis             cli::format_result(result.test_result));
162b0d29bc4SBrooks Davis 
163b0d29bc4SBrooks Davis     return result.test_result.good() ? EXIT_SUCCESS : EXIT_FAILURE;
164b0d29bc4SBrooks Davis }
165