test: broaden self-test coverage beyond the compile smoke test
All checks were successful
CI / build-test-release (pull_request) Successful in 7m26s
All checks were successful
CI / build-test-release (pull_request) Successful in 7m26s
The suite had only HelloWorld, which built and exited an empty exe. Add in-process tests covering each public surface area users actually touch: - StaticLib / ModuleInterface / DependencyLink — Build() against fixtures for libraries, project-local module interfaces, and cross-config module deps with link verification (runs the built exe). - ShaderCompile — drives Shader::Compile directly, validates SPIR-V magic + Check() idempotency. - StandardArgs — covers --debug, --target=, --march=, --mtune=, --lib/--shared promotions, and ArgQuery::Has / Get. - TestRunnerSpec — FromSpec parse rules, ForTarget routing for host, wasm32-wasip1, aarch64-linux-gnu (+ sysroot QEMU_LD_PREFIX), i686 → qemu-i386 rewrite, mingw → wine on Linux hosts, FromEnv. - VariantId — confirms type / debug / sysroot / defines / compileFlags / target / march all perturb the cache key, plus PcmDir routing. - WasiBrowserRuntime — calls EnableWasiBrowserRuntime, asserts the three cfg.files entries get registered and index.html had its template placeholder substituted. - RunSingleTestExit — drives RunSingleTest against tiny sh scripts and pins the documented exit-code mapping (0/77/non-zero) and the Cmd-prefix runner path. Closes #12. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
603840879d
commit
124c2285f9
16 changed files with 794 additions and 0 deletions
87
tests/RunSingleTestExit/main.cpp
Normal file
87
tests/RunSingleTestExit/main.cpp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue