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 ` ` 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; }