import { expect, it } from "vitest"; import { Il2cppMetadataService } from "./Il2cppMetadataService.js"; import { AnalysisCancelledError, AnalysisCapabilityUnavailableError, AnalysisInputError, AnalysisOutputError, } from "../../domain/analysisErrorCore.js"; import { IL2CPP_METADATA_SECTION_NAMES, type Il2cppMetadata, } from "../../domain/il2cpp/il2cppMetadata.js"; import { ok } from "../../domain/result.js"; const identity = { id: "fixture-il2cpp", name: "Source-owned IL2CPP reader seam", version: "1", }; const report: Il2cppMetadata = { artifact: { path: "/artifacts/global-metadata.dat", sha256: "a".repeat(64), bytes: 1024, }, magic: 0xfab11baf, metadata_version: 39, index_widths: { type_definition: 1, generic_container: 1, parameter: 1, type: 1, type_width_source: "interface-offsets-record", }, sections: IL2CPP_METADATA_SECTION_NAMES.map((name) => ({ name, offset: 380, size: 0, count: 0, })), images: [], types: [], methods: [], limitations: [], }; const serviceReturning = (value: Il2cppMetadata, calls = { count: 0 }) => new Il2cppMetadataService({ identity, inspect: () => { calls.count += 1; return Promise.resolve(ok(value)); }, }); it("rejects invalid paths and extra arguments before invoking the reader", async () => { const calls = { count: 0 }; const service = serviceReturning(report, calls); for (const input of [ { path: "relative/global-metadata.dat", detail: "complete" }, { path: "/artifacts/\0global-metadata.dat", detail: "complete" }, { path: report.artifact.path, detail: "complete", decrypt: true }, { path: report.artifact.path, detail: "rows" }, ]) { const result = await service.inspect(input); expect(result.ok).toBe(false); if (!result.ok) expect(result.error).toBeInstanceOf(AnalysisInputError); } expect(calls.count).toBe(0); }); it.each(["summary", undefined] as const)( "refuses %s summary delivery without Evidence retention before reading", async (detail) => { const calls = { count: 0 }; const result = await serviceReturning(report, calls).inspect({ path: report.artifact.path, ...(detail === undefined ? {} : { detail }), }); expect(result.ok).toBe(false); if (!result.ok) expect(result.error).toBeInstanceOf(AnalysisCapabilityUnavailableError); expect(calls.count).toBe(0); }, ); it("returns explicit complete artifact-bound Evidence without retention", async () => { const result = await serviceReturning(report).inspect({ path: report.artifact.path, detail: "complete", }); if (!result.ok) throw result.error; expect(result.value.parameters).toEqual({ path: report.artifact.path }); expect(result.value.normalized_result).toEqual(report); expect(result.value.subject).toMatchObject({ format: "file", local_path: report.artifact.path, digest: { sha256: report.artifact.sha256 }, }); }); it("rejects a reader that changes the selected artifact identity", async () => { const result = await serviceReturning({ ...report, artifact: { ...report.artifact, path: "/artifacts/other.dat" }, }).inspect({ path: report.artifact.path, detail: "complete" }); expect(result.ok).toBe(false); if (!result.ok) expect(result.error).toBeInstanceOf(AnalysisOutputError); }); it("reports cancellation before and after reading", async () => { const aborted = new AbortController(); aborted.abort(); const calls = { count: 0 }; const before = await serviceReturning(report, calls).inspect( { path: report.artifact.path, detail: "complete" }, { signal: aborted.signal }, ); expect(before.ok).toBe(false); if (!before.ok) { expect(before.error).toBeInstanceOf(AnalysisCancelledError); expect(before.error.cause).toBe(aborted.signal.reason); } expect(calls.count).toBe(0); const during = new AbortController(); const service = new Il2cppMetadataService({ identity, inspect: () => { during.abort(); return Promise.resolve(ok(report)); }, }); const after = await service.inspect( { path: report.artifact.path, detail: "complete" }, { signal: during.signal }, ); expect(after.ok).toBe(false); if (!after.ok) { expect(after.error).toBeInstanceOf(AnalysisCancelledError); expect(after.error.cause).toBe(during.signal.reason); expect(after.error.partialObservation).toMatchObject({ operation: "inspect_il2cpp_metadata", normalized_result: report, }); } });