import std; import Crafter.Build; namespace fs = std::filesystem; using namespace Crafter; extern "C" int setenv(const char* name, const char* value, int overwrite); // Covers the browser-wasm variant plumbing that does NOT require a wasm // toolchain run: EnableWasiRelaxedSimdVariant's registration, the // variants.json manifest EnableWasiBrowserRuntime emits, and the VariantId // perturbation that keeps each variant's objects in their own build dir. The // actual multi-.wasm production is exercised by a real wasm build (manual / // integration), not here — same boundary the WasiBrowserRuntime test draws. namespace { int failures = 0; void Check(bool cond, std::string_view msg) { if (!cond) { std::println(std::cerr, "FAIL: {}", msg); ++failures; } } } int main() { // ── EnableWasiRelaxedSimdVariant: registration + idempotency ────────── { Configuration cfg; cfg.target = "wasm32-wasip1"; EnableWasiRelaxedSimdVariant(cfg); Check(cfg.wasmVariants.size() == 1, "one variant registered"); if (!cfg.wasmVariants.empty()) { const WasmVariant& v = cfg.wasmVariants.front(); Check(v.label == "relaxed-simd", "label is relaxed-simd"); Check(v.flags.size() == 1 && v.flags.front() == "-mrelaxed-simd", "flag is -mrelaxed-simd"); Check(v.probes.size() == 1 && v.probes.front() == "relaxed-simd", "probe is relaxed-simd"); } EnableWasiRelaxedSimdVariant(cfg); Check(cfg.wasmVariants.size() == 1, "second call is idempotent"); } // ── wasmVariantFlags perturbs VariantId / BuildDir / BinDir ────────── // Configuration owns move-only members (unique_ptr), so build the // two cases independently rather than copying. { auto make = [] { Configuration c; c.path = "/tmp/wasm-variant-id-test"; c.name = "wv"; c.outputName = "wv"; c.target = "wasm32-wasip1"; c.type = ConfigurationType::Executable; return c; }; Configuration a = make(); Configuration b = make(); b.wasmVariantFlags = {"-mrelaxed-simd"}; Check(a.VariantId() != b.VariantId(), "wasmVariantFlags perturbs VariantId"); Check(a.BuildDir() != b.BuildDir(), "wasmVariantFlags perturbs BuildDir"); Check(a.BinDir() != b.BinDir(), "wasmVariantFlags perturbs BinDir"); } // ── variants.json manifest contents ────────────────────────────────── { fs::path repoWasi = fs::current_path() / "wasi-runtime"; fs::path systemHome = "/usr/local/share/crafter-build"; if (fs::exists(repoWasi / "runtime.js")) { setenv("CRAFTER_BUILD_HOME", fs::current_path().c_str(), 1); } else if (fs::exists(systemHome / "wasi-runtime" / "runtime.js")) { setenv("CRAFTER_BUILD_HOME", systemHome.c_str(), 1); } else { std::println(std::cerr, "wasi-runtime assets not found; skipping manifest check"); return failures ? 1 : 77; } Configuration cfg; cfg.path = fs::temp_directory_path() / "crafter-build-wasm-variants-test"; cfg.name = "wvhelper"; cfg.outputName = "wvhelper"; cfg.target = "wasm32-wasip1"; cfg.type = ConfigurationType::Executable; std::error_code ec; fs::remove_all(cfg.path, ec); fs::create_directories(cfg.path); EnableWasiRelaxedSimdVariant(cfg); EnableWasiBrowserRuntime(cfg); const fs::path* variants = nullptr; for (const fs::path& f : cfg.files) { if (f.filename() == "variants.json") variants = &f; } Check(variants != nullptr, "variants.json registered"); if (variants) { std::ifstream vin(*variants); std::string j{std::istreambuf_iterator(vin), std::istreambuf_iterator()}; // relaxed-simd entry, with its labelled url + probe. Check(j.find("\"label\":\"relaxed-simd\"") != std::string::npos, "manifest has relaxed-simd label"); Check(j.find("\"wvhelper.relaxed-simd.wasm\"") != std::string::npos, "manifest has labelled url"); Check(j.find("\"relaxed-simd\"") != std::string::npos, "manifest has relaxed-simd probe"); // baseline fallback entry. Check(j.find("\"wvhelper.wasm\"") != std::string::npos, "manifest has baseline url"); // The relaxed-simd variant must precede the baseline so the runtime // prefers it when probes pass. auto relaxedPos = j.find("relaxed-simd"); auto baselinePos = j.find("\"wvhelper.wasm\""); Check(relaxedPos != std::string::npos && baselinePos != std::string::npos && relaxedPos < baselinePos, "relaxed-simd entry precedes baseline"); } fs::remove_all(cfg.path, ec); } if (failures > 0) { std::println(std::cerr, "{} assertions failed", failures); return 1; } return 0; }