diff --git a/contrib/atf/atf-c++/check.cpp b/contrib/atf/atf-c++/check.cpp index e4d7db4d49a6..5d8580023a15 100644 --- a/contrib/atf/atf-c++/check.cpp +++ b/contrib/atf/atf-c++/check.cpp @@ -1,154 +1,154 @@ // Copyright (c) 2007 The NetBSD Foundation, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "atf-c++/check.hpp" #include extern "C" { #include "atf-c/build.h" #include "atf-c/error.h" } #include "atf-c++/detail/exceptions.hpp" #include "atf-c++/detail/process.hpp" #include "atf-c++/detail/sanity.hpp" namespace impl = atf::check; #define IMPL_NAME "atf::check" // ------------------------------------------------------------------------ // The "check_result" class. // ------------------------------------------------------------------------ impl::check_result::check_result(const atf_check_result_t* result) { std::memcpy(&m_result, result, sizeof(m_result)); } impl::check_result::~check_result(void) { atf_check_result_fini(&m_result); } bool impl::check_result::exited(void) const { return atf_check_result_exited(&m_result); } int impl::check_result::exitcode(void) const { PRE(exited()); return atf_check_result_exitcode(&m_result); } bool impl::check_result::signaled(void) const { return atf_check_result_signaled(&m_result); } int impl::check_result::termsig(void) const { PRE(signaled()); return atf_check_result_termsig(&m_result); } const std::string impl::check_result::stdout_path(void) const { return atf_check_result_stdout(&m_result); } const std::string impl::check_result::stderr_path(void) const { return atf_check_result_stderr(&m_result); } // ------------------------------------------------------------------------ // Free functions. // ------------------------------------------------------------------------ bool impl::build_c_o(const std::string& sfile, const std::string& ofile, const atf::process::argv_array& optargs) { bool success; atf_error_t err = atf_check_build_c_o(sfile.c_str(), ofile.c_str(), optargs.exec_argv(), &success); if (atf_is_error(err)) throw_atf_error(err); return success; } bool impl::build_cpp(const std::string& sfile, const std::string& ofile, const atf::process::argv_array& optargs) { bool success; atf_error_t err = atf_check_build_cpp(sfile.c_str(), ofile.c_str(), optargs.exec_argv(), &success); if (atf_is_error(err)) throw_atf_error(err); return success; } bool impl::build_cxx_o(const std::string& sfile, const std::string& ofile, const atf::process::argv_array& optargs) { bool success; atf_error_t err = atf_check_build_cxx_o(sfile.c_str(), ofile.c_str(), optargs.exec_argv(), &success); if (atf_is_error(err)) throw_atf_error(err); return success; } -std::auto_ptr< impl::check_result > +std::unique_ptr< impl::check_result > impl::exec(const atf::process::argv_array& argva) { atf_check_result_t result; atf_error_t err = atf_check_exec_array(argva.exec_argv(), &result); if (atf_is_error(err)) throw_atf_error(err); - return std::auto_ptr< impl::check_result >(new impl::check_result(&result)); + return std::unique_ptr< impl::check_result >(new impl::check_result(&result)); } diff --git a/contrib/atf/atf-c++/check.hpp b/contrib/atf/atf-c++/check.hpp index 0144dedb2841..4d7f079d1ac1 100644 --- a/contrib/atf/atf-c++/check.hpp +++ b/contrib/atf/atf-c++/check.hpp @@ -1,131 +1,131 @@ // Copyright (c) 2007 The NetBSD Foundation, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if !defined(ATF_CXX_CHECK_HPP) #define ATF_CXX_CHECK_HPP extern "C" { #include } #include #include #include #include namespace atf { namespace process { class argv_array; } // namespace process namespace check { // ------------------------------------------------------------------------ // The "check_result" class. // ------------------------------------------------------------------------ //! //! \brief A class that contains results of executed command. //! //! The check_result class holds information about results //! of executing arbitrary command and manages files containing //! its output. //! class check_result { // Non-copyable. check_result(const check_result&); check_result& operator=(const check_result&); //! //! \brief Internal representation of a result. //! atf_check_result_t m_result; //! //! \brief Constructs a results object and grabs ownership of the //! parameter passed in. //! check_result(const atf_check_result_t* result); friend check_result test_constructor(const char* const*); - friend std::auto_ptr< check_result > exec(const atf::process::argv_array&); + friend std::unique_ptr< check_result > exec(const atf::process::argv_array&); public: //! //! \brief Destroys object and removes all managed files. //! ~check_result(void); //! //! \brief Returns whether the command exited correctly or not. //! bool exited(void) const; //! //! \brief Returns command's exit status. //! int exitcode(void) const; //! //! \brief Returns whether the command received a signal or not. //! bool signaled(void) const; //! //! \brief Returns the signal that terminated the command. //! int termsig(void) const; //! //! \brief Returns the path to file contaning command's stdout. //! const std::string stdout_path(void) const; //! //! \brief Returns the path to file contaning command's stderr. //! const std::string stderr_path(void) const; }; // ------------------------------------------------------------------------ // Free functions. // ------------------------------------------------------------------------ bool build_c_o(const std::string&, const std::string&, const atf::process::argv_array&); bool build_cpp(const std::string&, const std::string&, const atf::process::argv_array&); bool build_cxx_o(const std::string&, const std::string&, const atf::process::argv_array&); -std::auto_ptr< check_result > exec(const atf::process::argv_array&); +std::unique_ptr< check_result > exec(const atf::process::argv_array&); // Useful for testing only. check_result test_constructor(void); } // namespace check } // namespace atf #endif // !defined(ATF_CXX_CHECK_HPP) diff --git a/contrib/atf/atf-c++/check_test.cpp b/contrib/atf/atf-c++/check_test.cpp index 7baf3fa19692..ecb5a9380e8f 100644 --- a/contrib/atf/atf-c++/check_test.cpp +++ b/contrib/atf/atf-c++/check_test.cpp @@ -1,394 +1,394 @@ // Copyright (c) 2007 The NetBSD Foundation, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "atf-c++/check.hpp" extern "C" { #include #include #include } #include #include #include #include #include #include #include #include #include "atf-c++/detail/fs.hpp" #include "atf-c++/detail/process.hpp" #include "atf-c++/detail/test_helpers.hpp" #include "atf-c++/detail/text.hpp" #include "atf-c++/utils.hpp" // ------------------------------------------------------------------------ // Auxiliary functions. // ------------------------------------------------------------------------ static -std::auto_ptr< atf::check::check_result > +std::unique_ptr< atf::check::check_result > do_exec(const atf::tests::tc* tc, const char* helper_name) { std::vector< std::string > argv; argv.push_back(get_process_helpers_path(*tc, false).str()); argv.push_back(helper_name); std::cout << "Executing " << argv[0] << " " << argv[1] << "\n"; atf::process::argv_array argva(argv); return atf::check::exec(argva); } static -std::auto_ptr< atf::check::check_result > +std::unique_ptr< atf::check::check_result > do_exec(const atf::tests::tc* tc, const char* helper_name, const char *carg2) { std::vector< std::string > argv; argv.push_back(get_process_helpers_path(*tc, false).str()); argv.push_back(helper_name); argv.push_back(carg2); std::cout << "Executing " << argv[0] << " " << argv[1] << " " << argv[2] << "\n"; atf::process::argv_array argva(argv); return atf::check::exec(argva); } // ------------------------------------------------------------------------ // Helper test cases for the free functions. // ------------------------------------------------------------------------ ATF_TEST_CASE(h_build_c_o_ok); ATF_TEST_CASE_HEAD(h_build_c_o_ok) { set_md_var("descr", "Helper test case for build_c_o"); } ATF_TEST_CASE_BODY(h_build_c_o_ok) { std::ofstream sfile("test.c"); sfile << "#include \n"; sfile.close(); ATF_REQUIRE(atf::check::build_c_o("test.c", "test.o", atf::process::argv_array())); } ATF_TEST_CASE(h_build_c_o_fail); ATF_TEST_CASE_HEAD(h_build_c_o_fail) { set_md_var("descr", "Helper test case for build_c_o"); } ATF_TEST_CASE_BODY(h_build_c_o_fail) { std::ofstream sfile("test.c"); sfile << "void foo(void) { int a = UNDEFINED_SYMBOL; }\n"; sfile.close(); ATF_REQUIRE(!atf::check::build_c_o("test.c", "test.o", atf::process::argv_array())); } ATF_TEST_CASE(h_build_cpp_ok); ATF_TEST_CASE_HEAD(h_build_cpp_ok) { set_md_var("descr", "Helper test case for build_cpp"); } ATF_TEST_CASE_BODY(h_build_cpp_ok) { std::ofstream sfile("test.c"); sfile << "#define A foo\n"; sfile << "#define B bar\n"; sfile << "A B\n"; sfile.close(); ATF_REQUIRE(atf::check::build_cpp("test.c", "test.p", atf::process::argv_array())); } ATF_TEST_CASE(h_build_cpp_fail); ATF_TEST_CASE_HEAD(h_build_cpp_fail) { set_md_var("descr", "Helper test case for build_cpp"); } ATF_TEST_CASE_BODY(h_build_cpp_fail) { std::ofstream sfile("test.c"); sfile << "#include \"./non-existent.h\"\n"; sfile.close(); ATF_REQUIRE(!atf::check::build_cpp("test.c", "test.p", atf::process::argv_array())); } ATF_TEST_CASE(h_build_cxx_o_ok); ATF_TEST_CASE_HEAD(h_build_cxx_o_ok) { set_md_var("descr", "Helper test case for build_cxx_o"); } ATF_TEST_CASE_BODY(h_build_cxx_o_ok) { std::ofstream sfile("test.cpp"); sfile << "#include \n"; sfile.close(); ATF_REQUIRE(atf::check::build_cxx_o("test.cpp", "test.o", atf::process::argv_array())); } ATF_TEST_CASE(h_build_cxx_o_fail); ATF_TEST_CASE_HEAD(h_build_cxx_o_fail) { set_md_var("descr", "Helper test case for build_cxx_o"); } ATF_TEST_CASE_BODY(h_build_cxx_o_fail) { std::ofstream sfile("test.cpp"); sfile << "void foo(void) { int a = UNDEFINED_SYMBOL; }\n"; sfile.close(); ATF_REQUIRE(!atf::check::build_cxx_o("test.cpp", "test.o", atf::process::argv_array())); } // ------------------------------------------------------------------------ // Test cases for the free functions. // ------------------------------------------------------------------------ ATF_TEST_CASE(build_c_o); ATF_TEST_CASE_HEAD(build_c_o) { set_md_var("descr", "Tests the build_c_o function"); } ATF_TEST_CASE_BODY(build_c_o) { ATF_TEST_CASE_USE(h_build_c_o_ok); run_h_tc< ATF_TEST_CASE_NAME(h_build_c_o_ok) >(); ATF_REQUIRE(atf::utils::grep_file("-o test.o", "stdout")); ATF_REQUIRE(atf::utils::grep_file("-c test.c", "stdout")); ATF_TEST_CASE_USE(h_build_c_o_fail); run_h_tc< ATF_TEST_CASE_NAME(h_build_c_o_fail) >(); ATF_REQUIRE(atf::utils::grep_file("-o test.o", "stdout")); ATF_REQUIRE(atf::utils::grep_file("-c test.c", "stdout")); ATF_REQUIRE(atf::utils::grep_file("test.c", "stderr")); ATF_REQUIRE(atf::utils::grep_file("UNDEFINED_SYMBOL", "stderr")); } ATF_TEST_CASE(build_cpp); ATF_TEST_CASE_HEAD(build_cpp) { set_md_var("descr", "Tests the build_cpp function"); } ATF_TEST_CASE_BODY(build_cpp) { ATF_TEST_CASE_USE(h_build_cpp_ok); run_h_tc< ATF_TEST_CASE_NAME(h_build_cpp_ok) >(); ATF_REQUIRE(atf::utils::grep_file("-o.*test.p", "stdout")); ATF_REQUIRE(atf::utils::grep_file("test.c", "stdout")); ATF_REQUIRE(atf::utils::grep_file("foo bar", "test.p")); ATF_TEST_CASE_USE(h_build_cpp_fail); run_h_tc< ATF_TEST_CASE_NAME(h_build_cpp_fail) >(); ATF_REQUIRE(atf::utils::grep_file("-o test.p", "stdout")); ATF_REQUIRE(atf::utils::grep_file("test.c", "stdout")); ATF_REQUIRE(atf::utils::grep_file("test.c", "stderr")); ATF_REQUIRE(atf::utils::grep_file("non-existent.h", "stderr")); } ATF_TEST_CASE(build_cxx_o); ATF_TEST_CASE_HEAD(build_cxx_o) { set_md_var("descr", "Tests the build_cxx_o function"); } ATF_TEST_CASE_BODY(build_cxx_o) { ATF_TEST_CASE_USE(h_build_cxx_o_ok); run_h_tc< ATF_TEST_CASE_NAME(h_build_cxx_o_ok) >(); ATF_REQUIRE(atf::utils::grep_file("-o test.o", "stdout")); ATF_REQUIRE(atf::utils::grep_file("-c test.cpp", "stdout")); ATF_TEST_CASE_USE(h_build_cxx_o_fail); run_h_tc< ATF_TEST_CASE_NAME(h_build_cxx_o_fail) >(); ATF_REQUIRE(atf::utils::grep_file("-o test.o", "stdout")); ATF_REQUIRE(atf::utils::grep_file("-c test.cpp", "stdout")); ATF_REQUIRE(atf::utils::grep_file("test.cpp", "stderr")); ATF_REQUIRE(atf::utils::grep_file("UNDEFINED_SYMBOL", "stderr")); } ATF_TEST_CASE(exec_cleanup); ATF_TEST_CASE_HEAD(exec_cleanup) { set_md_var("descr", "Tests that exec properly cleans up the temporary " "files it creates"); } ATF_TEST_CASE_BODY(exec_cleanup) { - std::auto_ptr< atf::fs::path > out; - std::auto_ptr< atf::fs::path > err; + std::unique_ptr< atf::fs::path > out; + std::unique_ptr< atf::fs::path > err; { - std::auto_ptr< atf::check::check_result > r = + std::unique_ptr< atf::check::check_result > r = do_exec(this, "exit-success"); out.reset(new atf::fs::path(r->stdout_path())); err.reset(new atf::fs::path(r->stderr_path())); ATF_REQUIRE(atf::fs::exists(*out.get())); ATF_REQUIRE(atf::fs::exists(*err.get())); } ATF_REQUIRE(!atf::fs::exists(*out.get())); ATF_REQUIRE(!atf::fs::exists(*err.get())); } ATF_TEST_CASE(exec_exitstatus); ATF_TEST_CASE_HEAD(exec_exitstatus) { set_md_var("descr", "Tests that exec properly captures the exit " "status of the executed command"); } ATF_TEST_CASE_BODY(exec_exitstatus) { { - std::auto_ptr< atf::check::check_result > r = + std::unique_ptr< atf::check::check_result > r = do_exec(this, "exit-success"); ATF_REQUIRE(r->exited()); ATF_REQUIRE(!r->signaled()); ATF_REQUIRE_EQ(r->exitcode(), EXIT_SUCCESS); } { - std::auto_ptr< atf::check::check_result > r = + std::unique_ptr< atf::check::check_result > r = do_exec(this, "exit-failure"); ATF_REQUIRE(r->exited()); ATF_REQUIRE(!r->signaled()); ATF_REQUIRE_EQ(r->exitcode(), EXIT_FAILURE); } { - std::auto_ptr< atf::check::check_result > r = + std::unique_ptr< atf::check::check_result > r = do_exec(this, "exit-signal"); ATF_REQUIRE(!r->exited()); ATF_REQUIRE(r->signaled()); ATF_REQUIRE_EQ(r->termsig(), SIGKILL); } } static void check_lines(const std::string& path, const char* outname, const char* resname) { std::ifstream f(path.c_str()); ATF_REQUIRE(f); std::string line; std::getline(f, line); ATF_REQUIRE_EQ(line, std::string("Line 1 to ") + outname + " for " + resname); std::getline(f, line); ATF_REQUIRE_EQ(line, std::string("Line 2 to ") + outname + " for " + resname); } ATF_TEST_CASE(exec_stdout_stderr); ATF_TEST_CASE_HEAD(exec_stdout_stderr) { set_md_var("descr", "Tests that exec properly captures the stdout " "and stderr streams of the child process"); } ATF_TEST_CASE_BODY(exec_stdout_stderr) { - std::auto_ptr< atf::check::check_result > r1 = + std::unique_ptr< atf::check::check_result > r1 = do_exec(this, "stdout-stderr", "result1"); ATF_REQUIRE(r1->exited()); ATF_REQUIRE_EQ(r1->exitcode(), EXIT_SUCCESS); - std::auto_ptr< atf::check::check_result > r2 = + std::unique_ptr< atf::check::check_result > r2 = do_exec(this, "stdout-stderr", "result2"); ATF_REQUIRE(r2->exited()); ATF_REQUIRE_EQ(r2->exitcode(), EXIT_SUCCESS); const std::string out1 = r1->stdout_path(); const std::string out2 = r2->stdout_path(); const std::string err1 = r1->stderr_path(); const std::string err2 = r2->stderr_path(); ATF_REQUIRE(out1.find("check.XXXXXX") == std::string::npos); ATF_REQUIRE(out2.find("check.XXXXXX") == std::string::npos); ATF_REQUIRE(err1.find("check.XXXXXX") == std::string::npos); ATF_REQUIRE(err2.find("check.XXXXXX") == std::string::npos); ATF_REQUIRE(out1.find("/check") != std::string::npos); ATF_REQUIRE(out2.find("/check") != std::string::npos); ATF_REQUIRE(err1.find("/check") != std::string::npos); ATF_REQUIRE(err2.find("/check") != std::string::npos); ATF_REQUIRE(out1.find("/stdout") != std::string::npos); ATF_REQUIRE(out2.find("/stdout") != std::string::npos); ATF_REQUIRE(err1.find("/stderr") != std::string::npos); ATF_REQUIRE(err2.find("/stderr") != std::string::npos); ATF_REQUIRE(out1 != out2); ATF_REQUIRE(err1 != err2); check_lines(out1, "stdout", "result1"); check_lines(out2, "stdout", "result2"); check_lines(err1, "stderr", "result1"); check_lines(err2, "stderr", "result2"); } ATF_TEST_CASE(exec_unknown); ATF_TEST_CASE_HEAD(exec_unknown) { set_md_var("descr", "Tests that running a non-existing binary " "is handled correctly"); } ATF_TEST_CASE_BODY(exec_unknown) { std::vector< std::string > argv; argv.push_back("/foo/bar/non-existent"); atf::process::argv_array argva(argv); - std::auto_ptr< atf::check::check_result > r = atf::check::exec(argva); + std::unique_ptr< atf::check::check_result > r = atf::check::exec(argva); ATF_REQUIRE(r->exited()); ATF_REQUIRE_EQ(r->exitcode(), 127); } // ------------------------------------------------------------------------ // Main. // ------------------------------------------------------------------------ ATF_INIT_TEST_CASES(tcs) { // Add the test cases for the free functions. ATF_ADD_TEST_CASE(tcs, build_c_o); ATF_ADD_TEST_CASE(tcs, build_cpp); ATF_ADD_TEST_CASE(tcs, build_cxx_o); ATF_ADD_TEST_CASE(tcs, exec_cleanup); ATF_ADD_TEST_CASE(tcs, exec_exitstatus); ATF_ADD_TEST_CASE(tcs, exec_stdout_stderr); ATF_ADD_TEST_CASE(tcs, exec_unknown); } diff --git a/contrib/atf/atf-c++/detail/process_test.cpp b/contrib/atf/atf-c++/detail/process_test.cpp index 0686d2a1911c..97f9a08e2504 100644 --- a/contrib/atf/atf-c++/detail/process_test.cpp +++ b/contrib/atf/atf-c++/detail/process_test.cpp @@ -1,354 +1,354 @@ // Copyright (c) 2008 The NetBSD Foundation, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "atf-c++/detail/process.hpp" #include #include #include #include "atf-c++/detail/test_helpers.hpp" // TODO: Testing the fork function is a huge task and I'm afraid of // copy/pasting tons of stuff from the C version. I'd rather not do that // until some code can be shared, which cannot happen until the C++ binding // is cleaned by a fair amount. Instead... just rely (at the moment) on // the system tests for the tools using this module. // ------------------------------------------------------------------------ // Auxiliary functions. // ------------------------------------------------------------------------ static std::size_t array_size(const char* const* array) { std::size_t size = 0; for (const char* const* ptr = array; *ptr != NULL; ptr++) size++; return size; } static atf::process::status exec_process_helpers(const atf::tests::tc& tc, const char* helper_name) { using atf::process::exec; std::vector< std::string > argv; argv.push_back(get_process_helpers_path(tc, true).leaf_name()); argv.push_back(helper_name); return exec(get_process_helpers_path(tc, true), atf::process::argv_array(argv), atf::process::stream_inherit(), atf::process::stream_inherit()); } // ------------------------------------------------------------------------ // Tests for the "argv_array" type. // ------------------------------------------------------------------------ ATF_TEST_CASE(argv_array_init_carray); ATF_TEST_CASE_HEAD(argv_array_init_carray) { set_md_var("descr", "Tests that argv_array is correctly constructed " "from a C-style array of strings"); } ATF_TEST_CASE_BODY(argv_array_init_carray) { { const char* const carray[] = { NULL }; atf::process::argv_array argv(carray); ATF_REQUIRE_EQ(argv.size(), 0); } { const char* const carray[] = { "arg0", NULL }; atf::process::argv_array argv(carray); ATF_REQUIRE_EQ(argv.size(), 1); ATF_REQUIRE(std::strcmp(argv[0], carray[0]) == 0); } { const char* const carray[] = { "arg0", "arg1", "arg2", NULL }; atf::process::argv_array argv(carray); ATF_REQUIRE_EQ(argv.size(), 3); ATF_REQUIRE(std::strcmp(argv[0], carray[0]) == 0); ATF_REQUIRE(std::strcmp(argv[1], carray[1]) == 0); ATF_REQUIRE(std::strcmp(argv[2], carray[2]) == 0); } } ATF_TEST_CASE(argv_array_init_col); ATF_TEST_CASE_HEAD(argv_array_init_col) { set_md_var("descr", "Tests that argv_array is correctly constructed " "from a string collection"); } ATF_TEST_CASE_BODY(argv_array_init_col) { { std::vector< std::string > col; atf::process::argv_array argv(col); ATF_REQUIRE_EQ(argv.size(), 0); } { std::vector< std::string > col; col.push_back("arg0"); atf::process::argv_array argv(col); ATF_REQUIRE_EQ(argv.size(), 1); ATF_REQUIRE_EQ(argv[0], col[0]); } { std::vector< std::string > col; col.push_back("arg0"); col.push_back("arg1"); col.push_back("arg2"); atf::process::argv_array argv(col); ATF_REQUIRE_EQ(argv.size(), 3); ATF_REQUIRE_EQ(argv[0], col[0]); ATF_REQUIRE_EQ(argv[1], col[1]); ATF_REQUIRE_EQ(argv[2], col[2]); } } ATF_TEST_CASE(argv_array_init_empty); ATF_TEST_CASE_HEAD(argv_array_init_empty) { set_md_var("descr", "Tests that argv_array is correctly constructed " "by the default constructor"); } ATF_TEST_CASE_BODY(argv_array_init_empty) { atf::process::argv_array argv; ATF_REQUIRE_EQ(argv.size(), 0); } ATF_TEST_CASE(argv_array_init_varargs); ATF_TEST_CASE_HEAD(argv_array_init_varargs) { set_md_var("descr", "Tests that argv_array is correctly constructed " "from a variable list of arguments"); } ATF_TEST_CASE_BODY(argv_array_init_varargs) { { atf::process::argv_array argv("arg0", NULL); ATF_REQUIRE_EQ(argv.size(), 1); ATF_REQUIRE_EQ(argv[0], std::string("arg0")); } { atf::process::argv_array argv("arg0", "arg1", "arg2", NULL); ATF_REQUIRE_EQ(argv.size(), 3); ATF_REQUIRE_EQ(argv[0], std::string("arg0")); ATF_REQUIRE_EQ(argv[1], std::string("arg1")); ATF_REQUIRE_EQ(argv[2], std::string("arg2")); } } ATF_TEST_CASE(argv_array_assign); ATF_TEST_CASE_HEAD(argv_array_assign) { set_md_var("descr", "Tests that assigning an argv_array works"); } ATF_TEST_CASE_BODY(argv_array_assign) { using atf::process::argv_array; const char* const carray1[] = { "arg1", NULL }; const char* const carray2[] = { "arg1", "arg2", NULL }; - std::auto_ptr< argv_array > argv1(new argv_array(carray1)); - std::auto_ptr< argv_array > argv2(new argv_array(carray2)); + std::unique_ptr< argv_array > argv1(new argv_array(carray1)); + std::unique_ptr< argv_array > argv2(new argv_array(carray2)); *argv2 = *argv1; ATF_REQUIRE_EQ(argv2->size(), argv1->size()); ATF_REQUIRE(std::strcmp((*argv2)[0], (*argv1)[0]) == 0); ATF_REQUIRE(argv2->exec_argv() != argv1->exec_argv()); argv1.release(); { const char* const* eargv2 = argv2->exec_argv(); ATF_REQUIRE(std::strcmp(eargv2[0], carray1[0]) == 0); ATF_REQUIRE_EQ(eargv2[1], static_cast< const char* >(NULL)); } argv2.release(); } ATF_TEST_CASE(argv_array_copy); ATF_TEST_CASE_HEAD(argv_array_copy) { set_md_var("descr", "Tests that copying an argv_array constructed from " "a C-style array of strings works"); } ATF_TEST_CASE_BODY(argv_array_copy) { using atf::process::argv_array; const char* const carray[] = { "arg0", NULL }; - std::auto_ptr< argv_array > argv1(new argv_array(carray)); - std::auto_ptr< argv_array > argv2(new argv_array(*argv1)); + std::unique_ptr< argv_array > argv1(new argv_array(carray)); + std::unique_ptr< argv_array > argv2(new argv_array(*argv1)); ATF_REQUIRE_EQ(argv2->size(), argv1->size()); ATF_REQUIRE(std::strcmp((*argv2)[0], (*argv1)[0]) == 0); ATF_REQUIRE(argv2->exec_argv() != argv1->exec_argv()); argv1.release(); { const char* const* eargv2 = argv2->exec_argv(); ATF_REQUIRE(std::strcmp(eargv2[0], carray[0]) == 0); ATF_REQUIRE_EQ(eargv2[1], static_cast< const char* >(NULL)); } argv2.release(); } ATF_TEST_CASE(argv_array_exec_argv); ATF_TEST_CASE_HEAD(argv_array_exec_argv) { set_md_var("descr", "Tests that the exec argv provided by an argv_array " "is correct"); } ATF_TEST_CASE_BODY(argv_array_exec_argv) { using atf::process::argv_array; { argv_array argv; const char* const* eargv = argv.exec_argv(); ATF_REQUIRE_EQ(array_size(eargv), 0); ATF_REQUIRE_EQ(eargv[0], static_cast< const char* >(NULL)); } { const char* const carray[] = { "arg0", NULL }; argv_array argv(carray); const char* const* eargv = argv.exec_argv(); ATF_REQUIRE_EQ(array_size(eargv), 1); ATF_REQUIRE(std::strcmp(eargv[0], "arg0") == 0); ATF_REQUIRE_EQ(eargv[1], static_cast< const char* >(NULL)); } { std::vector< std::string > col; col.push_back("arg0"); argv_array argv(col); const char* const* eargv = argv.exec_argv(); ATF_REQUIRE_EQ(array_size(eargv), 1); ATF_REQUIRE(std::strcmp(eargv[0], "arg0") == 0); ATF_REQUIRE_EQ(eargv[1], static_cast< const char* >(NULL)); } } ATF_TEST_CASE(argv_array_iter); ATF_TEST_CASE_HEAD(argv_array_iter) { set_md_var("descr", "Tests that an argv_array can be iterated"); } ATF_TEST_CASE_BODY(argv_array_iter) { using atf::process::argv_array; std::vector< std::string > vector; vector.push_back("arg0"); vector.push_back("arg1"); vector.push_back("arg2"); argv_array argv(vector); ATF_REQUIRE_EQ(argv.size(), 3); std::vector< std::string >::size_type pos = 0; for (argv_array::const_iterator iter = argv.begin(); iter != argv.end(); iter++) { ATF_REQUIRE_EQ(*iter, vector[pos]); pos++; } } // ------------------------------------------------------------------------ // Tests cases for the free functions. // ------------------------------------------------------------------------ ATF_TEST_CASE(exec_failure); ATF_TEST_CASE_HEAD(exec_failure) { set_md_var("descr", "Tests execing a command that reports failure"); } ATF_TEST_CASE_BODY(exec_failure) { const atf::process::status s = exec_process_helpers(*this, "exit-failure"); ATF_REQUIRE(s.exited()); ATF_REQUIRE_EQ(s.exitstatus(), EXIT_FAILURE); } ATF_TEST_CASE(exec_success); ATF_TEST_CASE_HEAD(exec_success) { set_md_var("descr", "Tests execing a command that reports success"); } ATF_TEST_CASE_BODY(exec_success) { const atf::process::status s = exec_process_helpers(*this, "exit-success"); ATF_REQUIRE(s.exited()); ATF_REQUIRE_EQ(s.exitstatus(), EXIT_SUCCESS); } // ------------------------------------------------------------------------ // Main. // ------------------------------------------------------------------------ ATF_INIT_TEST_CASES(tcs) { // Add the test cases for the "argv_array" type. ATF_ADD_TEST_CASE(tcs, argv_array_assign); ATF_ADD_TEST_CASE(tcs, argv_array_copy); ATF_ADD_TEST_CASE(tcs, argv_array_exec_argv); ATF_ADD_TEST_CASE(tcs, argv_array_init_carray); ATF_ADD_TEST_CASE(tcs, argv_array_init_col); ATF_ADD_TEST_CASE(tcs, argv_array_init_empty); ATF_ADD_TEST_CASE(tcs, argv_array_init_varargs); ATF_ADD_TEST_CASE(tcs, argv_array_iter); // Add the test cases for the free functions. ATF_ADD_TEST_CASE(tcs, exec_failure); ATF_ADD_TEST_CASE(tcs, exec_success); } diff --git a/contrib/atf/atf-sh/atf-check.cpp b/contrib/atf/atf-sh/atf-check.cpp index 4cb1e33a005a..911e004432f3 100644 --- a/contrib/atf/atf-sh/atf-check.cpp +++ b/contrib/atf/atf-sh/atf-check.cpp @@ -1,943 +1,943 @@ // Copyright (c) 2008 The NetBSD Foundation, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. extern "C" { #include #include #include #include #include #include } #include #include #include #include #include #include #include #include #include #include #include "atf-c++/check.hpp" #include "atf-c++/detail/application.hpp" #include "atf-c++/detail/auto_array.hpp" #include "atf-c++/detail/env.hpp" #include "atf-c++/detail/exceptions.hpp" #include "atf-c++/detail/fs.hpp" #include "atf-c++/detail/process.hpp" #include "atf-c++/detail/sanity.hpp" #include "atf-c++/detail/text.hpp" static const useconds_t seconds_in_useconds = (1000 * 1000); static const useconds_t mseconds_in_useconds = 1000; static const useconds_t useconds_in_nseconds = 1000; // ------------------------------------------------------------------------ // Auxiliary functions. // ------------------------------------------------------------------------ namespace { enum status_check_t { sc_exit, sc_ignore, sc_signal, }; struct status_check { status_check_t type; bool negated; int value; status_check(const status_check_t& p_type, const bool p_negated, const int p_value) : type(p_type), negated(p_negated), value(p_value) { } }; enum output_check_t { oc_ignore, oc_inline, oc_file, oc_empty, oc_match, oc_save }; struct output_check { output_check_t type; bool negated; std::string value; output_check(const output_check_t& p_type, const bool p_negated, const std::string& p_value) : type(p_type), negated(p_negated), value(p_value) { } }; class temp_file : public std::ostream { - std::auto_ptr< atf::fs::path > m_path; + std::unique_ptr< atf::fs::path > m_path; int m_fd; public: temp_file(const char* pattern) : std::ostream(NULL), m_fd(-1) { const atf::fs::path file = atf::fs::path( atf::env::get("TMPDIR", "/tmp")) / pattern; atf::auto_array< char > buf(new char[file.str().length() + 1]); std::strcpy(buf.get(), file.c_str()); m_fd = ::mkstemp(buf.get()); if (m_fd == -1) throw atf::system_error("atf_check::temp_file::temp_file(" + file.str() + ")", "mkstemp(3) failed", errno); m_path.reset(new atf::fs::path(buf.get())); } ~temp_file(void) { close(); try { remove(*m_path); } catch (const atf::system_error&) { // Ignore deletion errors. } } const atf::fs::path& get_path(void) const { return *m_path; } void write(const std::string& text) { if (::write(m_fd, text.c_str(), text.size()) == -1) throw atf::system_error("atf_check", "write(2) failed", errno); } void close(void) { if (m_fd != -1) { flush(); ::close(m_fd); m_fd = -1; } } }; } // anonymous namespace static useconds_t get_monotonic_useconds(void) { struct timespec ts; useconds_t res; int rc; rc = clock_gettime(CLOCK_MONOTONIC, &ts); if (rc != 0) throw std::runtime_error("clock_gettime: " + std::string(strerror(errno))); res = ts.tv_sec * seconds_in_useconds; res += ts.tv_nsec / useconds_in_nseconds; return res; } static bool timo_expired(useconds_t timeout) { if (get_monotonic_useconds() >= timeout) return true; return false; } static int parse_exit_code(const std::string& str) { try { const int value = atf::text::to_type< int >(str); if (value < 0 || value > 255) throw std::runtime_error("Unused reason"); return value; } catch (const std::runtime_error&) { throw atf::application::usage_error("Invalid exit code for -s option; " "must be an integer in range 0-255"); } } static struct name_number { const char *name; int signo; } signal_names_to_numbers[] = { { "hup", SIGHUP }, { "int", SIGINT }, { "quit", SIGQUIT }, { "trap", SIGTRAP }, { "abrt", SIGABRT }, { "kill", SIGKILL }, { "segv", SIGSEGV }, { "pipe", SIGPIPE }, { "alrm", SIGALRM }, { "term", SIGTERM }, { "usr1", SIGUSR1 }, { "usr2", SIGUSR2 }, { NULL, INT_MIN }, }; static int signal_name_to_number(const std::string& str) { struct name_number* iter = signal_names_to_numbers; int signo = INT_MIN; while (signo == INT_MIN && iter->name != NULL) { if (str == iter->name || str == std::string("sig") + iter->name) signo = iter->signo; else iter++; } return signo; } static int parse_signal(const std::string& str) { const int signo = signal_name_to_number(str); if (signo == INT_MIN) { try { return atf::text::to_type< int >(str); } catch (const std::runtime_error&) { throw atf::application::usage_error("Invalid signal name or number " "in -s option"); } } INV(signo != INT_MIN); return signo; } static status_check parse_status_check_arg(const std::string& arg) { const std::string::size_type delimiter = arg.find(':'); bool negated = (arg.compare(0, 4, "not-") == 0); const std::string action_str = arg.substr(0, delimiter); const std::string action = negated ? action_str.substr(4) : action_str; const std::string value_str = ( delimiter == std::string::npos ? "" : arg.substr(delimiter + 1)); int value; status_check_t type; if (action == "eq") { // Deprecated; use exit instead. TODO: Remove after 0.10. type = sc_exit; if (negated) throw atf::application::usage_error("Cannot negate eq checker"); negated = false; value = parse_exit_code(value_str); } else if (action == "exit") { type = sc_exit; if (value_str.empty()) value = INT_MIN; else value = parse_exit_code(value_str); } else if (action == "ignore") { if (negated) throw atf::application::usage_error("Cannot negate ignore checker"); type = sc_ignore; value = INT_MIN; } else if (action == "ne") { // Deprecated; use not-exit instead. TODO: Remove after 0.10. type = sc_exit; if (negated) throw atf::application::usage_error("Cannot negate ne checker"); negated = true; value = parse_exit_code(value_str); } else if (action == "signal") { type = sc_signal; if (value_str.empty()) value = INT_MIN; else value = parse_signal(value_str); } else throw atf::application::usage_error("Invalid status checker"); return status_check(type, negated, value); } static output_check parse_output_check_arg(const std::string& arg) { const std::string::size_type delimiter = arg.find(':'); const bool negated = (arg.compare(0, 4, "not-") == 0); const std::string action_str = arg.substr(0, delimiter); const std::string action = negated ? action_str.substr(4) : action_str; output_check_t type; if (action == "empty") type = oc_empty; else if (action == "file") type = oc_file; else if (action == "ignore") { if (negated) throw atf::application::usage_error("Cannot negate ignore checker"); type = oc_ignore; } else if (action == "inline") type = oc_inline; else if (action == "match") type = oc_match; else if (action == "save") { if (negated) throw atf::application::usage_error("Cannot negate save checker"); type = oc_save; } else throw atf::application::usage_error("Invalid output checker"); return output_check(type, negated, arg.substr(delimiter + 1)); } static void parse_repeat_check_arg(const std::string& arg, useconds_t *m_timo, useconds_t *m_interval) { const std::string::size_type delimiter = arg.find(':'); const bool has_interval = (delimiter != std::string::npos); const std::string timo_str = arg.substr(0, delimiter); long l; char *end; // There is no reason this couldn't be a non-integer number of seconds, // this was just easy to do for now. errno = 0; l = strtol(timo_str.c_str(), &end, 10); if (errno == ERANGE) throw atf::application::usage_error("Bogus timeout in seconds"); else if (errno != 0) throw atf::application::usage_error("Timeout must be a number"); if (*end != 0) throw atf::application::usage_error("Timeout must be a number"); *m_timo = get_monotonic_useconds() + (l * seconds_in_useconds); // 50 milliseconds is chosen arbitrarily. There is a tradeoff between // longer and shorter poll times. A shorter poll time makes for faster // tests. A longer poll time makes for lower CPU overhead for the polled // operation. 50ms is chosen with these tradeoffs in mind: on // microcontrollers, the hope is that we can still avoid meaningful CPU use // with a small test every 50ms. And on typical fast x86 hardware, our // tests can be much more precise with time wasted than they typically are // without this feature. *m_interval = 50 * mseconds_in_useconds; if (!has_interval) return; const std::string intv_str = arg.substr(delimiter + 1, std::string::npos); // Same -- this could be non-integer milliseconds. errno = 0; l = strtol(intv_str.c_str(), &end, 10); if (errno == ERANGE) throw atf::application::usage_error( "Bogus repeat interval in milliseconds"); else if (errno != 0) throw atf::application::usage_error( "Repeat interval must be a number"); if (*end != 0) throw atf::application::usage_error( "Repeat interval must be a number"); *m_interval = l * mseconds_in_useconds; } static std::string flatten_argv(char* const* argv) { std::string cmdline; char* const* arg = &argv[0]; while (*arg != NULL) { if (arg != &argv[0]) cmdline += ' '; cmdline += *arg; arg++; } return cmdline; } static -std::auto_ptr< atf::check::check_result > +std::unique_ptr< atf::check::check_result > execute(const char* const* argv) { // TODO: This should go to stderr... but fixing it now may be hard as test // cases out there might be relying on stderr being silent. std::cout << "Executing command [ "; for (int i = 0; argv[i] != NULL; ++i) std::cout << argv[i] << " "; std::cout << "]\n"; std::cout.flush(); atf::process::argv_array argva(argv); return atf::check::exec(argva); } static -std::auto_ptr< atf::check::check_result > +std::unique_ptr< atf::check::check_result > execute_with_shell(char* const* argv) { const std::string cmd = flatten_argv(argv); const std::string shell = atf::env::get("ATF_SHELL", ATF_SHELL); const char* sh_argv[4]; sh_argv[0] = shell.c_str(); sh_argv[1] = "-c"; sh_argv[2] = cmd.c_str(); sh_argv[3] = NULL; return execute(sh_argv); } static void cat_file(const atf::fs::path& path) { std::ifstream stream(path.c_str()); if (!stream) throw std::runtime_error("Failed to open " + path.str()); stream >> std::noskipws; std::istream_iterator< char > begin(stream), end; std::ostream_iterator< char > out(std::cerr); std::copy(begin, end, out); stream.close(); } static bool grep_file(const atf::fs::path& path, const std::string& regexp) { std::ifstream stream(path.c_str()); if (!stream) throw std::runtime_error("Failed to open " + path.str()); bool found = false; std::string line; while (!found && !std::getline(stream, line).fail()) { if (atf::text::match(line, regexp)) found = true; } stream.close(); return found; } static bool file_empty(const atf::fs::path& p) { atf::fs::file_info f(p); return (f.get_size() == 0); } static bool compare_files(const atf::fs::path& p1, const atf::fs::path& p2) { bool equal = false; std::ifstream f1(p1.c_str()); if (!f1) throw std::runtime_error("Failed to open " + p1.str()); std::ifstream f2(p2.c_str()); if (!f2) throw std::runtime_error("Failed to open " + p2.str()); for (;;) { char buf1[512], buf2[512]; f1.read(buf1, sizeof(buf1)); if (f1.bad()) throw std::runtime_error("Failed to read from " + p1.str()); f2.read(buf2, sizeof(buf2)); if (f2.bad()) throw std::runtime_error("Failed to read from " + p2.str()); if ((f1.gcount() == 0) && (f2.gcount() == 0)) { equal = true; break; } if ((f1.gcount() != f2.gcount()) || (std::memcmp(buf1, buf2, f1.gcount()) != 0)) { break; } } return equal; } static void print_diff(const atf::fs::path& p1, const atf::fs::path& p2) { const atf::process::status s = atf::process::exec(atf::fs::path("diff"), atf::process::argv_array("diff", "-u", p1.c_str(), p2.c_str(), NULL), atf::process::stream_connect(STDOUT_FILENO, STDERR_FILENO), atf::process::stream_inherit()); if (!s.exited()) std::cerr << "Failed to run diff(3)\n"; if (s.exitstatus() != 1) std::cerr << "Error while running diff(3)\n"; } static std::string decode(const std::string& s) { size_t i; std::string res; res.reserve(s.length()); i = 0; while (i < s.length()) { char c = s[i++]; if (c == '\\') { switch (s[i++]) { case 'a': c = '\a'; break; case 'b': c = '\b'; break; case 'c': break; case 'e': c = 033; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; case '\\': break; case '0': { int count = 3; c = 0; while (--count >= 0 && (unsigned)(s[i] - '0') < 8) c = (c << 3) + (s[i++] - '0'); break; } default: --i; break; } } res.push_back(c); } return res; } static bool run_status_check(const status_check& sc, const atf::check::check_result& cr) { bool result; if (sc.type == sc_exit) { if (cr.exited() && sc.value != INT_MIN) { const int status = cr.exitcode(); if (!sc.negated && sc.value != status) { std::cerr << "Fail: incorrect exit status: " << status << ", expected: " << sc.value << "\n"; result = false; } else if (sc.negated && sc.value == status) { std::cerr << "Fail: incorrect exit status: " << status << ", expected: " << "anything else\n"; result = false; } else result = true; } else if (cr.exited() && sc.value == INT_MIN) { result = true; } else { std::cerr << "Fail: program did not exit cleanly\n"; result = false; } } else if (sc.type == sc_ignore) { result = true; } else if (sc.type == sc_signal) { if (cr.signaled() && sc.value != INT_MIN) { const int status = cr.termsig(); if (!sc.negated && sc.value != status) { std::cerr << "Fail: incorrect signal received: " << status << ", expected: " << sc.value << "\n"; result = false; } else if (sc.negated && sc.value == status) { std::cerr << "Fail: incorrect signal received: " << status << ", expected: " << "anything else\n"; result = false; } else result = true; } else if (cr.signaled() && sc.value == INT_MIN) { result = true; } else { std::cerr << "Fail: program did not receive a signal\n"; result = false; } } else { UNREACHABLE; result = false; } if (result == false) { std::cerr << "stdout:\n"; cat_file(atf::fs::path(cr.stdout_path())); std::cerr << "\n"; std::cerr << "stderr:\n"; cat_file(atf::fs::path(cr.stderr_path())); std::cerr << "\n"; } return result; } static bool run_status_checks(const std::vector< status_check >& checks, const atf::check::check_result& result) { bool ok = false; for (std::vector< status_check >::const_iterator iter = checks.begin(); !ok && iter != checks.end(); iter++) { ok |= run_status_check(*iter, result); } return ok; } static bool run_output_check(const output_check oc, const atf::fs::path& path, const std::string& stdxxx) { bool result; if (oc.type == oc_empty) { const bool is_empty = file_empty(path); if (!oc.negated && !is_empty) { std::cerr << "Fail: " << stdxxx << " not empty\n"; print_diff(atf::fs::path("/dev/null"), path); result = false; } else if (oc.negated && is_empty) { std::cerr << "Fail: " << stdxxx << " is empty\n"; result = false; } else result = true; } else if (oc.type == oc_file) { const bool equals = compare_files(path, atf::fs::path(oc.value)); if (!oc.negated && !equals) { std::cerr << "Fail: " << stdxxx << " does not match golden " "output\n"; print_diff(atf::fs::path(oc.value), path); result = false; } else if (oc.negated && equals) { std::cerr << "Fail: " << stdxxx << " matches golden output\n"; cat_file(atf::fs::path(oc.value)); result = false; } else result = true; } else if (oc.type == oc_ignore) { result = true; } else if (oc.type == oc_inline) { temp_file temp("atf-check.XXXXXX"); temp.write(decode(oc.value)); temp.close(); const bool equals = compare_files(path, temp.get_path()); if (!oc.negated && !equals) { std::cerr << "Fail: " << stdxxx << " does not match expected " "value\n"; print_diff(temp.get_path(), path); result = false; } else if (oc.negated && equals) { std::cerr << "Fail: " << stdxxx << " matches expected value\n"; cat_file(temp.get_path()); result = false; } else result = true; } else if (oc.type == oc_match) { const bool matches = grep_file(path, oc.value); if (!oc.negated && !matches) { std::cerr << "Fail: regexp " + oc.value + " not in " << stdxxx << "\n"; cat_file(path); result = false; } else if (oc.negated && matches) { std::cerr << "Fail: regexp " + oc.value + " is in " << stdxxx << "\n"; cat_file(path); result = false; } else result = true; } else if (oc.type == oc_save) { INV(!oc.negated); std::ifstream ifs(path.c_str(), std::fstream::binary); ifs >> std::noskipws; std::istream_iterator< char > begin(ifs), end; std::ofstream ofs(oc.value.c_str(), std::fstream::binary | std::fstream::trunc); std::ostream_iterator obegin(ofs); std::copy(begin, end, obegin); result = true; } else { UNREACHABLE; result = false; } return result; } static bool run_output_checks(const std::vector< output_check >& checks, const atf::fs::path& path, const std::string& stdxxx) { bool ok = true; for (std::vector< output_check >::const_iterator iter = checks.begin(); iter != checks.end(); iter++) { ok &= run_output_check(*iter, path, stdxxx); } return ok; } // ------------------------------------------------------------------------ // The "atf_check" application. // ------------------------------------------------------------------------ namespace { class atf_check : public atf::application::app { bool m_rflag; bool m_xflag; useconds_t m_timo; useconds_t m_interval; std::vector< status_check > m_status_checks; std::vector< output_check > m_stdout_checks; std::vector< output_check > m_stderr_checks; static const char* m_description; bool run_output_checks(const atf::check::check_result&, const std::string&) const; std::string specific_args(void) const; options_set specific_options(void) const; void process_option(int, const char*); void process_option_s(const std::string&); public: atf_check(void); int main(void); }; } // anonymous namespace const char* atf_check::m_description = "atf-check executes given command and analyzes its results."; atf_check::atf_check(void) : app(m_description, "atf-check(1)"), m_rflag(false), m_xflag(false) { } bool atf_check::run_output_checks(const atf::check::check_result& r, const std::string& stdxxx) const { if (stdxxx == "stdout") { return ::run_output_checks(m_stdout_checks, atf::fs::path(r.stdout_path()), "stdout"); } else if (stdxxx == "stderr") { return ::run_output_checks(m_stderr_checks, atf::fs::path(r.stderr_path()), "stderr"); } else { UNREACHABLE; return false; } } std::string atf_check::specific_args(void) const { return ""; } atf_check::options_set atf_check::specific_options(void) const { using atf::application::option; options_set opts; opts.insert(option('s', "qual:value", "Handle status. Qualifier " "must be one of: ignore exit: signal:")); opts.insert(option('o', "action:arg", "Handle stdout. Action must be " "one of: empty ignore file: inline: match:regexp " "save:")); opts.insert(option('e', "action:arg", "Handle stderr. Action must be " "one of: empty ignore file: inline: match:regexp " "save:")); opts.insert(option('r', "timeout[:interval]", "Repeat failed check until " "the timeout expires.")); opts.insert(option('x', "", "Execute command as a shell command")); return opts; } void atf_check::process_option(int ch, const char* arg) { switch (ch) { case 's': m_status_checks.push_back(parse_status_check_arg(arg)); break; case 'o': m_stdout_checks.push_back(parse_output_check_arg(arg)); break; case 'e': m_stderr_checks.push_back(parse_output_check_arg(arg)); break; case 'r': m_rflag = true; parse_repeat_check_arg(arg, &m_timo, &m_interval); break; case 'x': m_xflag = true; break; default: UNREACHABLE; } } int atf_check::main(void) { if (m_argc < 1) throw atf::application::usage_error("No command specified"); int status = EXIT_FAILURE; if (m_status_checks.empty()) m_status_checks.push_back(status_check(sc_exit, false, EXIT_SUCCESS)); else if (m_status_checks.size() > 1) { // TODO: Remove this restriction. throw atf::application::usage_error("Cannot specify -s more than once"); } if (m_stdout_checks.empty()) m_stdout_checks.push_back(output_check(oc_empty, false, "")); if (m_stderr_checks.empty()) m_stderr_checks.push_back(output_check(oc_empty, false, "")); do { - std::auto_ptr< atf::check::check_result > r = + std::unique_ptr< atf::check::check_result > r = m_xflag ? execute_with_shell(m_argv) : execute(m_argv); if ((run_status_checks(m_status_checks, *r) == false) || (run_output_checks(*r, "stderr") == false) || (run_output_checks(*r, "stdout") == false)) status = EXIT_FAILURE; else status = EXIT_SUCCESS; if (m_rflag && status == EXIT_FAILURE) { if (timo_expired(m_timo)) break; usleep(m_interval); } } while (m_rflag && status == EXIT_FAILURE); return status; } int main(int argc, char* const* argv) { return atf_check().run(argc, argv); } diff --git a/lib/atf/Makefile.inc b/lib/atf/Makefile.inc index c776c2f8f84e..f8f329842eb4 100644 --- a/lib/atf/Makefile.inc +++ b/lib/atf/Makefile.inc @@ -1,32 +1,29 @@ #- # Copyright (c) 2011 Google, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # CFLAGS+= -DHAVE_CONFIG_H WARNS?= 3 - -# Permit use of auto_ptr for compilers defaulting to C++17 or later -CXXSTD= c++11 diff --git a/lib/atf/libatf-c++/Makefile b/lib/atf/libatf-c++/Makefile index 221a16657c2a..985a79b7dc03 100644 --- a/lib/atf/libatf-c++/Makefile +++ b/lib/atf/libatf-c++/Makefile @@ -1,82 +1,79 @@ #- # Copyright (c) 2011 Google, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # .include .include PACKAGE= tests LIB_CXX= atf-c++ PRIVATELIB= true SHLIB_MAJOR= 2 # libatf-c++ depends on the C version of the ATF library to build. LIBADD+= atf_c LDFLAGS+= -L${.OBJDIR:H}/libatf-c ATF= ${SRCTOP}/contrib/atf .PATH: ${ATF} .PATH: ${ATF}/atf-c++ .PATH: ${ATF}/atf-c++/detail CFLAGS+= -I${ATF} CFLAGS+= -I${.CURDIR:H}/libatf-c CFLAGS+= -I. CFLAGS+= -DHAVE_CONFIG_H -# Silence warnings about usage of deprecated std::auto_ptr -CXXWARNFLAGS+= -Wno-deprecated-declarations - SRCS= application.cpp \ build.cpp \ check.cpp \ env.cpp \ exceptions.cpp \ fs.cpp \ process.cpp \ tests.cpp \ text.cpp \ utils.cpp INCS= build.hpp \ check.hpp \ macros.hpp \ tests.hpp \ utils.hpp INCSDIR= ${INCLUDEDIR}/atf-c++ INCS+= atf-c++.hpp INCSDIR_atf-c++.hpp= ${INCLUDEDIR} MAN= atf-c++.3 MLINKS+= atf-c++.3 atf-c-api++.3 # Backwards compatibility. HAS_TESTS= SUBDIR.${MK_TESTS}+= tests .include "../common.mk" .include diff --git a/libexec/atf/atf-check/Makefile b/libexec/atf/atf-check/Makefile index e1ccdce95ec8..87d7a7cfdada 100644 --- a/libexec/atf/atf-check/Makefile +++ b/libexec/atf/atf-check/Makefile @@ -1,50 +1,46 @@ #- # Copyright (c) 2011 Google, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # .include .include ATF= ${SRCTOP}/contrib/atf .PATH: ${ATF}/atf-sh PACKAGE= tests PROG_CXX= atf-check SRCS= atf-check.cpp MAN= atf-check.1 CFLAGS+= -I${ATF} CFLAGS+= -DATF_SHELL='"/bin/sh"' -# Silence warnings about usage of deprecated std::auto_ptr -CXXWARNFLAGS+= -Wno-deprecated-declarations -CXXSTD= c++11 - LIBADD= atf_cxx HAS_TESTS= SUBDIR.${MK_TESTS}+= tests .include diff --git a/libexec/atf/atf-sh/Makefile b/libexec/atf/atf-sh/Makefile index 3c06afa446c4..ba949fd3072e 100644 --- a/libexec/atf/atf-sh/Makefile +++ b/libexec/atf/atf-sh/Makefile @@ -1,83 +1,80 @@ #- # Copyright (c) 2011 Google, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # .include .include ATF= ${SRCTOP}/contrib/atf .PATH: ${ATF}/atf-sh PACKAGE= tests PROG_CXX= atf-sh SRCS= atf-sh.cpp MAN= atf-sh.1 atf-sh.3 # Backwards compatibility. MLINKS+= atf-sh.3 atf-sh-api.3 MLINKS+= \ atf-sh.3 atf_add_test_case.3 \ atf-sh.3 atf_check.3 \ atf-sh.3 atf_check_equal.3 \ atf-sh.3 atf_config_get.3 \ atf-sh.3 atf_config_has.3 \ atf-sh.3 atf_expect_death.3 \ atf-sh.3 atf_expect_exit.3 \ atf-sh.3 atf_expect_fail.3 \ atf-sh.3 atf_expect_pass.3 \ atf-sh.3 atf_expect_signal.3 \ atf-sh.3 atf_expect_timeout.3 \ atf-sh.3 atf_fail.3 \ atf-sh.3 atf_get.3 \ atf-sh.3 atf_get_srcdir.3 \ atf-sh.3 atf_init_test_cases.3 \ atf-sh.3 atf_pass.3 \ atf-sh.3 atf_require_prog.3 \ atf-sh.3 atf_set.3 \ atf-sh.3 atf_skip.3 \ atf-sh.3 atf_test_case.3 CFLAGS+= -DHAVE_CONFIG_H CFLAGS+= -DATF_LIBEXECDIR='"${LIBEXECDIR}"' CFLAGS+= -DATF_PKGDATADIR='"${SHAREDIR}/atf"' CFLAGS+= -DATF_SHELL='"/bin/sh"' CFLAGS+= -I${ATF} -# Silence warnings about usage of deprecated std::auto_ptr -CXXWARNFLAGS+= -Wno-deprecated-declarations - LIBADD= atf_cxx FILESGROUPS= SUBR SUBRDIR= ${SHAREDIR}/atf SUBR= libatf-sh.subr SUBRTAGS= package=tests HAS_TESTS= SUBDIR.${MK_TESTS}+= tests .include "../../../lib/atf/common.mk" .include diff --git a/share/mk/atf.test.mk b/share/mk/atf.test.mk index f7696641ffb0..16dc836f5141 100644 --- a/share/mk/atf.test.mk +++ b/share/mk/atf.test.mk @@ -1,157 +1,155 @@ # # You must include bsd.test.mk instead of this file from your Makefile. # # Logic to build and install ATF test programs; i.e. test programs linked # against the ATF libraries. .if !target(____) .error atf.test.mk cannot be included directly. .endif # List of C, C++ and shell test programs to build. # # Programs listed here are built using PROGS, PROGS_CXX and SCRIPTS, # respectively, from bsd.prog.mk. However, the build rules are tweaked to # require the ATF libraries. # # Test programs registered in this manner are set to be installed into TESTSDIR # (which should be overridden by the Makefile) and are not required to provide a # manpage. ATF_TESTS_C?= ATF_TESTS_CXX?= ATF_TESTS_SH?= ATF_TESTS_KSH93?= ATF_TESTS_PYTEST?= .if !empty(ATF_TESTS_C) PROGS+= ${ATF_TESTS_C} _TESTS+= ${ATF_TESTS_C} .for _T in ${ATF_TESTS_C} BINDIR.${_T}= ${TESTSDIR} MAN.${_T}?= # empty SRCS.${_T}?= ${_T}.c DPADD.${_T}+= ${LIBATF_C} .if empty(LDFLAGS:M-static) && empty(LDFLAGS.${_T}:M-static) LDADD.${_T}+= ${LDADD_atf_c} .else LDADD.${_T}+= ${LIBATF_C} .endif TEST_INTERFACE.${_T}= atf .endfor .endif .if !empty(ATF_TESTS_CXX) PROGS_CXX+= ${ATF_TESTS_CXX} _TESTS+= ${ATF_TESTS_CXX} .for _T in ${ATF_TESTS_CXX} BINDIR.${_T}= ${TESTSDIR} MAN.${_T}?= # empty SRCS.${_T}?= ${_T}${CXX_SUFFIX:U.cc} DPADD.${_T}+= ${LIBATF_CXX} ${LIBATF_C} .if empty(LDFLAGS:M-static) && empty(LDFLAGS.${_T}:M-static) LDADD.${_T}+= ${LDADD_atf_cxx} ${LDADD_atf_c} .else LDADD.${_T}+= ${LIBATF_CXX} ${LIBATF_C} .endif TEST_INTERFACE.${_T}= atf .endfor -# Silence warnings about usage of deprecated std::auto_ptr -CXXWARNFLAGS+= -Wno-deprecated-declarations .endif .if !empty(ATF_TESTS_SH) SCRIPTS+= ${ATF_TESTS_SH} _TESTS+= ${ATF_TESTS_SH} .for _T in ${ATF_TESTS_SH} SCRIPTSDIR_${_T}= ${TESTSDIR} TEST_INTERFACE.${_T}= atf CLEANFILES+= ${_T} ${_T}.tmp # TODO(jmmv): It seems to me that this SED and SRC functionality should # exist in bsd.prog.mk along the support for SCRIPTS. Move it there if # this proves to be useful within the tests. ATF_TESTS_SH_SED_${_T}?= # empty ATF_TESTS_SH_SRC_${_T}?= ${_T}.sh ${_T}: ${ATF_TESTS_SH_SRC_${_T}} echo '#! /usr/libexec/atf-sh' > ${.TARGET}.tmp .if empty(ATF_TESTS_SH_SED_${_T}) cat ${.ALLSRC:N*Makefile*} >>${.TARGET}.tmp .else cat ${.ALLSRC:N*Makefile*} \ | sed ${ATF_TESTS_SH_SED_${_T}} >>${.TARGET}.tmp .endif chmod +x ${.TARGET}.tmp mv ${.TARGET}.tmp ${.TARGET} .endfor .endif .if !empty(ATF_TESTS_KSH93) SCRIPTS+= ${ATF_TESTS_KSH93} _TESTS+= ${ATF_TESTS_KSH93} .for _T in ${ATF_TESTS_KSH93} SCRIPTSDIR_${_T}= ${TESTSDIR} TEST_INTERFACE.${_T}= atf TEST_METADATA.${_T}+= required_programs="ksh93" CLEANFILES+= ${_T} ${_T}.tmp # TODO(jmmv): It seems to me that this SED and SRC functionality should # exist in bsd.prog.mk along the support for SCRIPTS. Move it there if # this proves to be useful within the tests. ATF_TESTS_KSH93_SED_${_T}?= # empty ATF_TESTS_KSH93_SRC_${_T}?= ${_T}.sh ${_T}: ${ATF_TESTS_KSH93_SRC_${_T}} echo '#! /usr/libexec/atf-sh -s/usr/local/bin/ksh93' > ${.TARGET}.tmp .if empty(ATF_TESTS_KSH93_SED_${_T}) cat ${.ALLSRC:N*Makefile*} >>${.TARGET}.tmp .else cat ${.ALLSRC:N*Makefile*} \ | sed ${ATF_TESTS_KSH93_SED_${_T}} >>${.TARGET}.tmp .endif chmod +x ${.TARGET}.tmp mv ${.TARGET}.tmp ${.TARGET} .endfor .endif .if !empty(ATF_TESTS_PYTEST) # bsd.prog.mk SCRIPTS interface removes file extension unless # SCRIPTSNAME is set, which is not possible to do here. # Workaround this by appending another extension (.xtmp) to the # file name. Use separate loop to avoid dealing with explicitly # stating expansion for each and every variable. # # ATF_TESTS_PYTEST -> contains list of files as is (test_something.py ..) # _ATF_TESTS_PYTEST -> (test_something.py.xtmp ..) # # Former array is iterated to construct Kyuafile, where original file # names need to be written. # Latter array is iterated to enable bsd.prog.mk scripts framework - # namely, installing scripts without .xtmp prefix. Note: this allows to # not bother about the fact that make target needs to be different from # the source file. _TESTS+= ${ATF_TESTS_PYTEST} _ATF_TESTS_PYTEST= .for _T in ${ATF_TESTS_PYTEST} _ATF_TESTS_PYTEST += ${_T}.xtmp TEST_INTERFACE.${_T}= atf TEST_METADATA.${_T}+= required_programs="pytest" .endfor SCRIPTS+= ${_ATF_TESTS_PYTEST} .for _T in ${_ATF_TESTS_PYTEST} SCRIPTSDIR_${_T}= ${TESTSDIR} CLEANFILES+= ${_T} ${_T}.tmp # TODO(jmmv): It seems to me that this SED and SRC functionality should # exist in bsd.prog.mk along the support for SCRIPTS. Move it there if # this proves to be useful within the tests. ATF_TESTS_PYTEST_SED_${_T}?= # empty ATF_TESTS_PYTEST_SRC_${_T}?= ${.CURDIR}/${_T:S,.xtmp$,,} ${_T}: ${_T:S/.xtmp//} echo "#! /usr/libexec/atf_pytest_wrapper -P ${TESTSBASE}" > ${.TARGET}.tmp .if empty(ATF_TESTS_PYTEST_SED_${_T}) cat ${ATF_TESTS_PYTEST_SRC_${_T}} >>${.TARGET}.tmp .else cat ${ATF_TESTS_PYTEST_SRC_${_T}} \ | sed ${ATF_TESTS_PYTEST_SED_${_T}} >>${.TARGET}.tmp .endif chmod +x ${.TARGET}.tmp mv ${.TARGET}.tmp ${.TARGET} .endfor .endif