a747113422afaa29ce72d2c5ba7f0b7ea9ec2054Evan Hunt// Copyright (c) 2008 The NetBSD Foundation, Inc.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// All rights reserved.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// Redistribution and use in source and binary forms, with or without
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// modification, are permitted provided that the following conditions
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// 1. Redistributions of source code must retain the above copyright
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// notice, this list of conditions and the following disclaimer.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// 2. Redistributions in binary form must reproduce the above copyright
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// notice, this list of conditions and the following disclaimer in the
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// documentation and/or other materials provided with the distribution.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt#include "atf-c++/check.hpp"
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt#include "atf-c++/detail/application.hpp"
a747113422afaa29ce72d2c5ba7f0b7ea9ec2054Evan Hunt#include "atf-c++/detail/auto_array.hpp"
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include "atf-c++/detail/env.hpp"
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt#include "atf-c++/detail/exceptions.hpp"
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt#include "atf-c++/detail/fs.hpp"
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt#include "atf-c++/detail/process.hpp"
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt#include "atf-c++/detail/sanity.hpp"
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt#include "atf-c++/detail/text.hpp"
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// ------------------------------------------------------------------------
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// Auxiliary functions.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// ------------------------------------------------------------------------
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt status_check(const status_check_t& p_type, const bool p_negated,
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const int p_value) :
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt output_check(const output_check_t& p_type, const bool p_negated,
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews atf::auto_array< char > buf(new char[file.str().length() + 1]);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::system_error("atf_check::temp_file::temp_file(" +
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt // Ignore deletion errors.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt if (::write(m_fd, text.c_str(), text.size()) == -1)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::system_error("atf_check", "write(2) failed", errno);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt} // anonymous namespace
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::application::usage_error("Invalid exit code for -s option; "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt "must be an integer in range 0-255");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt struct name_number* iter = signal_names_to_numbers;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt if (str == iter->name || str == std::string("sig") + iter->name)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::application::usage_error("Invalid signal name or number "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt "in -s option");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const std::string::size_type delimiter = arg.find(':');
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const std::string action_str = arg.substr(0, delimiter);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const std::string action = negated ? action_str.substr(4) : action_str;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt delimiter == std::string::npos ? "" : arg.substr(delimiter + 1));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt // Deprecated; use exit instead. TODO: Remove after 0.10.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::application::usage_error("Cannot negate eq checker");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::application::usage_error("Cannot negate ignore checker");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt // Deprecated; use not-exit instead. TODO: Remove after 0.10.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::application::usage_error("Cannot negate ne checker");
a747113422afaa29ce72d2c5ba7f0b7ea9ec2054Evan Hunt throw atf::application::usage_error("Invalid status checker");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const std::string::size_type delimiter = arg.find(':');
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const bool negated = (arg.compare(0, 4, "not-") == 0);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const std::string action_str = arg.substr(0, delimiter);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const std::string action = negated ? action_str.substr(4) : action_str;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::application::usage_error("Cannot negate ignore checker");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::application::usage_error("Cannot negate save checker");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::application::usage_error("Invalid output checker");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt return output_check(type, negated, arg.substr(delimiter + 1));
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews // TODO: This should go to stderr... but fixing it now may be hard as test
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews // cases out there might be relying on stderr being silent.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews sh_argv[0] = atf::env::get("ATF_SHELL", ATF_SHELL).c_str();
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw std::runtime_error("Failed to open " + path.str());
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntgrep_file(const atf::fs::path& path, const std::string& regexp)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw std::runtime_error("Failed to open " + path.str());
a747113422afaa29ce72d2c5ba7f0b7ea9ec2054Evan Hunt while (!found && !std::getline(stream, line).fail()) {
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt return (f.get_size() == 0);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntcompare_files(const atf::fs::path& p1, const atf::fs::path& p2)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw std::runtime_error("Failed to open " + p1.str());
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw std::runtime_error("Failed to open " + p1.str());
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw std::runtime_error("Failed to read from " + p1.str());
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw std::runtime_error("Failed to read from " + p1.str());
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntprint_diff(const atf::fs::path& p1, const atf::fs::path& p2)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt atf::process::argv_array("diff", "-u", p1.c_str(),
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt while (i < s.length()) {
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt char c = s[i++];
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt if (c == '\\') {
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt switch (s[i++]) {
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt case 'c': break;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt case '\\': break;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt while (--count >= 0 && (unsigned)(s[i] - '0') < 8)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntrun_status_check(const status_check& sc, const atf::check::check_result& cr)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt << "anything else\n";
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt std::cerr << "Fail: program did not exit cleanly\n";
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt << "anything else\n";
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt } else if (cr.signaled() && sc.value == INT_MIN) {
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt std::cerr << "Fail: program did not receive a signal\n";
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt if (result == false) {
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntrun_status_checks(const std::vector< status_check >& checks,
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt for (std::vector< status_check >::const_iterator iter = checks.begin();
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntrun_output_check(const output_check oc, const atf::fs::path& path,
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt std::cerr << "Fail: " << stdxxx << " not empty\n";
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const bool equals = compare_files(path, atf::fs::path(oc.value));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt std::cerr << "Fail: " << stdxxx << " does not match golden "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt std::cerr << "Fail: " << stdxxx << " matches golden output\n";
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const bool equals = compare_files(path, temp.get_path());
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt std::cerr << "Fail: " << stdxxx << " does not match expected "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt std::cerr << "Fail: " << stdxxx << " matches expected value\n";
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt std::cerr << "Fail: regexp " + oc.value + " not in " << stdxxx
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt std::cerr << "Fail: regexp " + oc.value + " is in " << stdxxx
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt std::ifstream ifs(path.c_str(), std::fstream::binary);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt std::ofstream ofs(oc.value.c_str(), std::fstream::binary
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntrun_output_checks(const std::vector< output_check >& checks,
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const atf::fs::path& path, const std::string& stdxxx)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt for (std::vector< output_check >::const_iterator iter = checks.begin();
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// ------------------------------------------------------------------------
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// The "atf_check" application.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt// ------------------------------------------------------------------------
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt bool run_output_checks(const atf::check::check_result&,
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt void process_option(int, const char*);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt} // anonymous namespace
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt "atf-check executes given command and analyzes its results.";
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_check::run_output_checks(const atf::check::check_result& r,
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt return false;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt return "<command>";
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt opts.insert(option('s', "qual:value", "Handle status. Qualifier "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt "must be one of: ignore exit:<num> signal:<name|num>"));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt opts.insert(option('o', "action:arg", "Handle stdout. Action must be "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt "one of: empty ignore file:<path> inline:<val> match:regexp "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt "save:<path>"));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt opts.insert(option('e', "action:arg", "Handle stderr. Action must be "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt "one of: empty ignore file:<path> inline:<val> match:regexp "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt "save:<path>"));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt opts.insert(option('x', "", "Execute command as a shell command"));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt m_status_checks.push_back(parse_status_check_arg(arg));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt m_stdout_checks.push_back(parse_output_check_arg(arg));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt m_stderr_checks.push_back(parse_output_check_arg(arg));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::application::usage_error("No command specified");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt m_xflag ? execute_with_shell(m_argv) : execute(m_argv);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt m_status_checks.push_back(status_check(sc_exit, false, EXIT_SUCCESS));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt // TODO: Remove this restriction.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt throw atf::application::usage_error("Cannot specify -s more than once");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt m_stdout_checks.push_back(output_check(oc_empty, false, ""));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt m_stderr_checks.push_back(output_check(oc_empty, false, ""));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt if ((run_status_checks(m_status_checks, *r) == false) ||