* Copyright 2018 by Intra2net AG
*/
-#define BOOST_TEST_IGNORE_NON_ZERO_CHILD_CODE
+#include <boost/version.hpp>
+#if BOOST_VERSION > /* guessed */ 104400
+/*
+ * Boost overeagerly terminates a unit test when a child exits non-zero
+ * without offering a means of disabling this behavior locally. All we
+ * have is below macro which isn’t even available on older versions of
+ * the unittest runner.
+ */
+# define BOOST_TEST_IGNORE_NON_ZERO_CHILD_CODE
+#else
+/* Boost too old; skip test that validate error handling. */
+# define NO_CHILD_FAIL_TESTS
+#endif
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(abspath_zeros_shell_ok_result)
{
- ExecResult exres;
+ ExecResult exres = ExecResult ();
const std::string result =
capture_exec (I2n::join_string (zero_bytes_argv, " "),
exres);
BOOST_AUTO_TEST_CASE(abspath_zeros_noshell_ok_result)
{
- ExecResult exres;
+ ExecResult exres = ExecResult ();
const std::string result = capture_exec (zero_bytes_argv, exres);
BOOST_CHECK(exres.normal_exit);
const char *const bad_command [] = { "/does_not_exist", NULL };
+# ifndef NO_CHILD_FAIL_TESTS
BOOST_AUTO_TEST_CASE(abspath_bad_shell_fail)
{
assert (access(bad_command [0], X_OK) != 0);
- ExecResult exres;
+ ExecResult exres = ExecResult ();
+ /*
+ * Note that the next line will make the unit test spew a message
+ * to stderr which cannot be prevented due to the limitations of
+ * popen(3).
+ */
const std::string result =
capture_exec (I2n::join_string (bad_command, " "));
+ BOOST_CHECK(!exres.normal_exit);
BOOST_CHECK_EQUAL(result.size (), 0);
}
+# endif /* [!NO_CHILD_FAIL_TESTS] */
+# ifndef NO_CHILD_FAIL_TESTS
BOOST_AUTO_TEST_CASE(abspath_bad_noshell_fail)
{
assert (access(bad_command [0], X_OK) != 0);
- ExecResult exres;
+ ExecResult exres = ExecResult ();
const std::string result = capture_exec (bad_command, exres);
+ BOOST_CHECK(!exres.normal_exit); /* failed to exec() */
BOOST_CHECK(!exres.terminated_by_signal);
BOOST_CHECK_EQUAL(result.size (), 0);
+ BOOST_CHECK_EQUAL(exres.error_message,
+ "child failed to exec(): "
+ "error 2 (No such file or directory)");
}
+# endif /* [!NO_CHILD_FAIL_TESTS] */
+# ifndef NO_CHILD_FAIL_TESTS
BOOST_AUTO_TEST_CASE(abspath_bad_noshell_stderr)
{
assert (access(bad_command [0], X_OK) != 0);
- ExecResult exres;
+ ExecResult exres = ExecResult ();
const std::string result = capture_exec (bad_command, exres, false, true);
- BOOST_CHECK_NE(result.size (), 0);
+ BOOST_CHECK(!exres.normal_exit); /* failed to exec() */
+ BOOST_CHECK(!exres.terminated_by_signal);
+ BOOST_CHECK_EQUAL(result.size (), 0);
+ BOOST_CHECK_EQUAL(exres.error_message,
+ "child failed to exec(): "
+ "error 2 (No such file or directory)");
}
+# endif /* [!NO_CHILD_FAIL_TESTS] */
- const char *const false_argv [] = { "/bin/false", NULL };
+ const char *const false_argv_abs [] = { "/bin/false", NULL };
+ const char *const true_argv_abs [] = { "/bin/true" , NULL };
+ const char *const false_argv_rel [] = { "false" , NULL };
+ const char *const true_argv_rel [] = { "true" , NULL };
+# ifndef NO_CHILD_FAIL_TESTS
BOOST_AUTO_TEST_CASE(abspath_false_noshell_fail_exit)
{
- ExecResult exres;
- const std::string result = capture_exec (false_argv, exres, true, false);
+ ExecResult exres = ExecResult ();
+ const std::string result =
+ capture_exec (false_argv_abs, exres, true, false, false);
BOOST_CHECK(exres.normal_exit);
BOOST_CHECK_EQUAL(exres.return_code, EXIT_FAILURE);
BOOST_CHECK_EQUAL(result.size (), 0);
}
+# endif /* [!NO_CHILD_FAIL_TESTS] */
+# ifndef NO_CHILD_FAIL_TESTS
BOOST_AUTO_TEST_CASE(abspath_false_shell_fail_exit)
{
- ExecResult exres;
+ ExecResult exres = ExecResult ();
const std::string result =
- capture_exec (std::string (false_argv [0]), exres);
+ capture_exec (std::string (false_argv_abs [0]), exres);
BOOST_CHECK(exres.normal_exit);
BOOST_CHECK_EQUAL(exres.return_code, EXIT_FAILURE);
BOOST_CHECK_EQUAL(result.size (), 0);
}
+# endif /* [!NO_CHILD_FAIL_TESTS] */
+
+ BOOST_AUTO_TEST_CASE(relpath_true_noshell_ok)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string result =
+ capture_exec (true_argv_rel, exres, true, false, true);
+
+ BOOST_CHECK(exres.normal_exit);
+ BOOST_CHECK_EQUAL(exres.return_code, EXIT_SUCCESS);
+ BOOST_CHECK_EQUAL(result.size (), 0);
+ }
+
+# ifndef NO_CHILD_FAIL_TESTS
+ BOOST_AUTO_TEST_CASE(relpath_true_noshell_fail)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string result =
+ capture_exec (true_argv_rel, exres, true, false, false);
+
+ BOOST_CHECK(!exres.normal_exit); /* failed to exec() */
+ /* no return code check since we couldn't exit */
+ BOOST_CHECK_EQUAL(result.size (), 0);
+ BOOST_CHECK_EQUAL(exres.error_message,
+ "child failed to exec(): "
+ "error 2 (No such file or directory)");
+ }
+# endif /* [!NO_CHILD_FAIL_TESTS] */
+
+ BOOST_AUTO_TEST_CASE(abspath_true_noshell_ok)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string result =
+ capture_exec (true_argv_abs, exres, true, false, true);
+
+ BOOST_CHECK(exres.normal_exit);
+ BOOST_CHECK_EQUAL(exres.return_code, EXIT_SUCCESS);
+ BOOST_CHECK_EQUAL(result.size (), 0);
+ }
+
+# ifndef NO_CHILD_FAIL_TESTS
+ BOOST_AUTO_TEST_CASE(relpath_false_noshell_fail)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string result =
+ capture_exec (false_argv_rel, exres, true, false, true);
+
+ BOOST_CHECK(exres.normal_exit);
+ /* no return code check since we couldn't exit */
+ BOOST_CHECK_EQUAL(result.size (), 0);
+ }
+# endif /* [!NO_CHILD_FAIL_TESTS] */
+
+ const char *const echo_abs = "/bin/echo";
+ const char *const echo_rel = "echo";
+
+ static std::vector<std::string>
+ mk_echo_argv (const std::string &text, const bool absolute=true)
+ {
+ std::vector<std::string> ret;
+
+ ret.push_back (absolute ? echo_abs : echo_rel);
+ ret.push_back ("-n");
+ ret.push_back (text);
+
+ return ret;
+ }
+
+ BOOST_AUTO_TEST_CASE(abspath_echo_noshell_capture_ok)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string text = "The significant owl hoots in the night.";
+ const std::vector<std::string> argv = mk_echo_argv (text);
+ const std::string result = capture_exec (argv, exres, true, false, true);
+
+ BOOST_CHECK(exres.normal_exit);
+ BOOST_CHECK_EQUAL(exres.return_code, EXIT_SUCCESS);
+ BOOST_CHECK_EQUAL(result, text);
+ }
+
+ BOOST_AUTO_TEST_CASE(relpath_echo_noshell_capture_ok)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string text = "Yet many grey lords go sadly to the masterless men.";
+ const std::vector<std::string> argv = mk_echo_argv (text, false);
+ const std::string result = capture_exec (argv, exres, true, false, true);
+
+ BOOST_CHECK(exres.normal_exit);
+ BOOST_CHECK_EQUAL(exres.return_code, EXIT_SUCCESS);
+ BOOST_CHECK_EQUAL(result, text);
+ }
+
+ static std::vector<std::string>
+ mk_errcho_argv (const std::string &text)
+ {
+ /*
+ * Hack cause there’s no way to make echo print to stderr without
+ * redirection.
+ */
+ std::vector<std::string> ret;
+
+ ret.push_back ("/bin/sh");
+ ret.push_back ("-c");
+ ret.push_back (std::string ("1>&- 1>&2 echo -n '") + text + "'"); /* brr */
+
+ return ret;
+ }
+
+ BOOST_AUTO_TEST_CASE(sh_errcho_capture_ok)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string text = "Hooray, hooray for the spinster’s sister’s daughter.";
+ const std::vector<std::string> argv = mk_errcho_argv (text);
+ const std::string result = capture_exec (argv, exres, false, true, true);
+
+ BOOST_CHECK(exres.normal_exit);
+ BOOST_CHECK_EQUAL(exres.return_code, EXIT_SUCCESS);
+ BOOST_CHECK_EQUAL(result, text);
+ }
+
+ BOOST_AUTO_TEST_CASE(sh_errcho_stdout_empty_ok)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string text = "To the axeman, all supplicants are the same height.";
+ const std::vector<std::string> argv = mk_errcho_argv (text);
+ const std::string result = capture_exec (argv, exres, true, false, true);
+
+ BOOST_CHECK(exres.normal_exit);
+ BOOST_CHECK_EQUAL(exres.return_code, EXIT_SUCCESS);
+ BOOST_CHECK_EQUAL(result.size (), 0);
+ }
BOOST_AUTO_TEST_SUITE_END() /* [pipestream->read] */