import std; import Crafter.Build; namespace fs = std::filesystem; using namespace Crafter; // POSIX env helper — std::setenv is non-standard. Linux-only is fine here; // project.cpp gates this test on x86_64-pc-linux-gnu. extern "C" int setenv(const char* name, const char* value, int overwrite); // EnableWasiBrowserRuntime stamps runtime.js, a generated index.html, and a // files.json manifest onto cfg.files so the build step copies them next to // the .wasm. We don't run the wasm build here (avoids requiring wasi-sdk + // the wasi-libc++ PCM rebuild on top of every test); we just verify the // helper produced the right artifacts and registered them on the config. int main() { Configuration cfg; cfg.path = fs::temp_directory_path() / "crafter-build-wasi-runtime-test"; cfg.name = "wasi-helper"; cfg.outputName = "wasi-helper"; cfg.target = "wasm32-wasip1"; cfg.type = ConfigurationType::Executable; std::error_code ec; fs::remove_all(cfg.path, ec); fs::create_directories(cfg.path); // EnableWasiBrowserRuntime looks up runtime.js + index.html.in under // GetCrafterBuildHome()/wasi-runtime. The test binary lives in // bin//, so the auto-detect walks parents and won't find a // share/crafter-build/Crafter.Build.cppm anchor — point CRAFTER_BUILD_HOME // at the repo root (cwd when crafter-build test runs) so it picks up // ./wasi-runtime/. Probe both repo root and the system-installed share // dir to also work from a packaged checkout. 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 near {} or {}", repoWasi.string(), systemHome.string()); return 77; // skipped — environmental, not a code defect } EnableWasiBrowserRuntime(cfg); // Three files registered: runtime.js, generated index.html, files.json. if (cfg.files.size() != 3) { std::println(std::cerr, "expected 3 cfg.files entries, got {}", cfg.files.size()); for (const auto& f : cfg.files) std::println(std::cerr, " - {}", f.string()); return 1; } auto findByName = [&](std::string_view name) -> const fs::path* { for (const fs::path& f : cfg.files) { if (f.filename() == name) return &f; } return nullptr; }; const fs::path* runtimeJs = findByName("runtime.js"); const fs::path* indexHtml = findByName("index.html"); const fs::path* manifest = findByName("files.json"); if (!runtimeJs) { std::println(std::cerr, "runtime.js not registered"); return 1; } if (!indexHtml) { std::println(std::cerr, "index.html not registered"); return 1; } if (!manifest) { std::println(std::cerr, "files.json not registered"); return 1; } // The generated index.html and manifest live under the project's build/ // wasi-runtime// directory and must actually exist on disk. if (!fs::exists(*indexHtml)) { std::println(std::cerr, "index.html not produced at {}", indexHtml->string()); return 1; } if (!fs::exists(*manifest)) { std::println(std::cerr, "files.json not produced at {}", manifest->string()); return 1; } // The template's {{WASM}} placeholder should have been replaced with // the configured outputName. std::ifstream in(*indexHtml); std::string html{std::istreambuf_iterator(in), std::istreambuf_iterator()}; if (html.find("wasi-helper.wasm") == std::string::npos) { std::println(std::cerr, "index.html missing wasi-helper.wasm reference"); return 1; } if (html.find("{{WASM}}") != std::string::npos) { std::println(std::cerr, "index.html still contains unreplaced {{WASM}} placeholder"); return 1; } fs::remove_all(cfg.path, ec); return 0; }