// @vitest-environment node import { createHash } from "node:crypto"; import { mkdtemp, readFile, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { buildRubyPack, RUBY_ENGINE_LOCK, verifyRubyPack, } from "./ruby-engine-pack.mjs"; const temporaryDirectories: string[] = []; afterEach(async () => { await Promise.all( temporaryDirectories .splice(0) .map((directory) => rm(directory, { recursive: true, force: true })), ); }); async function digest(file: string): Promise { return createHash("sha256") .update(await readFile(file)) .digest("hex"); } describe("Ruby engine-pack gate", () => { it("verifies the installed minimal CRuby runtime and native smoke cases", async () => { await expect( verifyRubyPack(path.resolve("public", "engines", "ruby")), ).resolves.toEqual( expect.objectContaining({ engineVersion: "CRuby 4.0.0 Regexp", platform: "wasm32-wasi", source: expect.objectContaining({ runtimeVariant: "minimal ruby.wasm (without bundled stdlib/debug)", }), }), ); }); it("pins exact runtime/host package and WebAssembly identities", () => { expect(RUBY_ENGINE_LOCK.packageVersion).toBe("2.9.3-2.9.4"); expect(RUBY_ENGINE_LOCK.rubyVersion).toBe("4.0.0"); expect(RUBY_ENGINE_LOCK.platform).toBe("wasm32-wasi"); expect(RUBY_ENGINE_LOCK.npm.runtime.integrity).toMatch(/^sha512-/u); expect(RUBY_ENGINE_LOCK.npm.host.integrity).toMatch(/^sha512-/u); expect(RUBY_ENGINE_LOCK.sourceAssets["ruby.wasm"]).toHaveLength(64); }); it("builds byte-identical closed packs from the pinned npm inputs", async () => { const directory = await mkdtemp(path.join(tmpdir(), "regex-ruby-pack-")); temporaryDirectories.push(directory); const first = path.join(directory, "first"); const second = path.join(directory, "second"); await buildRubyPack({ output: first }); await buildRubyPack({ output: second }); for (const file of [ "ruby.wasm", "engine-metadata.json", "SHA256SUMS", "LICENSE.ruby-wasm.txt", "NOTICE.txt", ]) { expect(await digest(path.join(first, file))).toBe( await digest(path.join(second, file)), ); } }, 30_000); });