79 lines
2.5 KiB
C++
79 lines
2.5 KiB
C++
#include <catch2/catch_test_macros.hpp>
|
|
|
|
import cargoxx.exec;
|
|
import cargoxx.util;
|
|
import std;
|
|
|
|
using cargoxx::exec::ExecOptions;
|
|
using cargoxx::exec::ExecResult;
|
|
using cargoxx::exec::run;
|
|
using cargoxx::util::ErrorCode;
|
|
|
|
TEST_CASE("run captures stdout from echo", "[exec]") {
|
|
auto r = run("echo", {"hello", "world"});
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->exit_code == 0);
|
|
REQUIRE(r->stdout_text == "hello world\n");
|
|
REQUIRE(r->stderr_text.empty());
|
|
}
|
|
|
|
TEST_CASE("run returns 0 for true", "[exec]") {
|
|
auto r = run("true", {});
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->exit_code == 0);
|
|
}
|
|
|
|
TEST_CASE("run returns non-zero for false", "[exec]") {
|
|
auto r = run("false", {});
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->exit_code != 0);
|
|
}
|
|
|
|
TEST_CASE("run reports ExecToolNotFound for missing program", "[exec]") {
|
|
auto r = run("definitely-not-a-real-command-xyz-12345", {});
|
|
REQUIRE_FALSE(r.has_value());
|
|
REQUIRE(r.error().code == ErrorCode::ExecToolNotFound);
|
|
}
|
|
|
|
TEST_CASE("run honors cwd", "[exec]") {
|
|
auto cwd = std::filesystem::temp_directory_path();
|
|
auto r = run("pwd", {}, ExecOptions{.cwd = cwd});
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->exit_code == 0);
|
|
// pwd may print the canonical path; at minimum the result starts with /tmp
|
|
// (or whatever the temp dir's prefix is)
|
|
REQUIRE_FALSE(r->stdout_text.empty());
|
|
}
|
|
|
|
TEST_CASE("run captures stderr", "[exec]") {
|
|
auto r = run("ls", {"/this/path/does/not/exist/cargoxx-xyz"});
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->exit_code != 0);
|
|
REQUIRE_FALSE(r->stderr_text.empty());
|
|
}
|
|
|
|
TEST_CASE("run propagates env_overrides", "[exec]") {
|
|
auto r = run("env", {}, ExecOptions{
|
|
.env_overrides = {{"CARGOXX_TEST_VAR", "lemonade"}},
|
|
});
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->exit_code == 0);
|
|
REQUIRE(r->stdout_text.find("CARGOXX_TEST_VAR=lemonade") != std::string::npos);
|
|
}
|
|
|
|
TEST_CASE("run enforces a timeout", "[exec]") {
|
|
auto r = run("sleep", {"5"},
|
|
ExecOptions{.timeout = std::chrono::seconds{1}});
|
|
REQUIRE_FALSE(r.has_value());
|
|
REQUIRE(r.error().code == ErrorCode::ExecCommandFailed);
|
|
}
|
|
|
|
TEST_CASE("run handles many output bytes without deadlocking", "[exec]") {
|
|
// 64 KiB of zeros — exercises pipe-pumping past the typical 4 KiB buffer
|
|
// without producing unbounded output.
|
|
auto r = run("dd", {"if=/dev/zero", "bs=1024", "count=64", "status=none"});
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->exit_code == 0);
|
|
REQUIRE(r->stdout_text.size() == 64 * 1024);
|
|
}
|