Crafter.Build/tests/RunSingleTestExit/main.cpp

87 lines
3.1 KiB
C++
Raw Normal View History

import std;
import Crafter.Build;
namespace fs = std::filesystem;
using namespace Crafter;
namespace {
int failures = 0;
void Check(bool cond, std::string_view msg) {
if (!cond) {
std::println(std::cerr, "FAIL: {}", msg);
++failures;
}
}
// Write a tiny POSIX shell script that exits with `code` and return its
// path. The harness invokes `<binary> <args>` through the host shell, so
// a #!/bin/sh script works as a stand-in for a real test binary.
fs::path WriteExitScript(const fs::path& dir, std::string_view stem, int code) {
fs::path script = dir / stem;
std::ofstream out(script);
out << "#!/bin/sh\nexit " << code << "\n";
out.close();
fs::permissions(script,
fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec
| fs::perms::group_read | fs::perms::group_exec
| fs::perms::others_read | fs::perms::others_exec,
fs::perm_options::replace);
return script;
}
}
// Drives RunSingleTest against shell-script fixtures and asserts the
// exit-code → TestOutcome mapping documented in the README:
// 0 -> Pass
// 77 -> Skipped (autoconf convention)
// anything else -> Fail
int main() {
fs::path dir = fs::temp_directory_path() / "crafter-build-run-single-test";
std::error_code ec;
fs::remove_all(dir, ec);
fs::create_directories(dir);
Test t;
t.runner = TestRunner::Local();
t.config.outputName = "run-single";
{
fs::path script = WriteExitScript(dir, "pass.sh", 0);
TestResult r = RunSingleTest(t, script, std::chrono::seconds(5));
Check(r.outcome == TestOutcome::Pass, "exit 0 -> Pass");
Check(r.exitCode == 0, "Pass carries exitCode 0");
}
{
fs::path script = WriteExitScript(dir, "skip.sh", 77);
TestResult r = RunSingleTest(t, script, std::chrono::seconds(5));
Check(r.outcome == TestOutcome::Skipped, "exit 77 -> Skipped");
Check(r.exitCode == 77, "Skipped carries exitCode 77");
}
{
fs::path script = WriteExitScript(dir, "fail.sh", 3);
TestResult r = RunSingleTest(t, script, std::chrono::seconds(5));
Check(r.outcome == TestOutcome::Fail, "non-zero/non-77 exit -> Fail");
Check(r.exitCode == 3, "Fail carries the original exitCode");
}
// Cmd-prefix runner: wrap the script in `sh {bin} {args}` so we exercise
// the templated-exec path through RunSingleTest. Probes don't run here
// (RunSingleTest doesn't probe — RunTests does), so any prefix that
// resolves on PATH is fine.
{
Test ct;
ct.runner = TestRunner::Cmd("sh");
ct.config.outputName = "run-single-prefix";
fs::path script = WriteExitScript(dir, "prefixed.sh", 0);
TestResult r = RunSingleTest(ct, script, std::chrono::seconds(5));
Check(r.outcome == TestOutcome::Pass, "Cmd-prefixed exit 0 -> Pass");
}
fs::remove_all(dir, ec);
if (failures > 0) {
std::println(std::cerr, "{} assertions failed", failures);
return 1;
}
return 0;
}