From 4a2f3c088a2075a331768b652dc2a17dae3ab12b Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Wed, 8 Jul 2026 13:33:57 -0700 Subject: [PATCH] fix(diffutils): add recursive header and e2e --- docs-internal/registry-parity-worklist.md | 14 ++ software/diffutils/bin/diff | Bin 132845 -> 133043 bytes .../diffutils/native/crates/diff/src/lib.rs | 8 + software/diffutils/test/diff.test.ts | 145 ++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 software/diffutils/test/diff.test.ts diff --git a/docs-internal/registry-parity-worklist.md b/docs-internal/registry-parity-worklist.md index 86a297be21..a2385e2101 100644 --- a/docs-internal/registry-parity-worklist.md +++ b/docs-internal/registry-parity-worklist.md @@ -622,6 +622,20 @@ real e2e tests that prove Linux-parity behavior — not smoke tests. Biome is not applicable for this package test path; it reported the file is ignored by config in `2026-07-08T13-29-23-0700-item12-yq-biome-check.log`. Rev: `znlmtymu`. + - **diffutils — DONE.** Added package-local VM e2e coverage for the staged + `diff` command and fixed recursive directory output to print the compared + file pair before hunk output, matching the Linux `diff -r` shape. The suite + proves identical-file exit 0, normal and unified diffs, brief output, + ignore-case/whitespace/blank-line flags, recursive directory comparisons, + and missing-input errors through the packaged WASM command. Proof: + `2026-07-08T13-32-10-0700-item12-diffutils-toolchain-cmd-build.log`; + `2026-07-08T13-34-45-0700-item12-diffutils-package-build-after-recursive-header.log`; + `2026-07-08T13-35-04-0700-item12-diffutils-package-e2e-final.log`; + `2026-07-08T13-35-04-0700-item12-diffutils-check-types-final.log`; + `2026-07-08T13-35-04-0700-item12-diffutils-cargo-fmt-check-final.log`. + Biome is not applicable for this package test path; it reported the file is + ignored by config in + `2026-07-08T13-35-04-0700-item12-diffutils-biome-check.log`. - **jq — DONE.** Added package-local VM e2e coverage for the staged `jq` command and fixed the jaq-backed CLI wrapper to accept Linux-style file operands instead of only stdin. The suite now proves version output, diff --git a/software/diffutils/bin/diff b/software/diffutils/bin/diff index 003d074f991ab02defbcd71094b51e7ff272a97a..ccaee62a892bdadddc0393dfa97194d22b19e526 100644 GIT binary patch delta 17165 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 OQ=1m;Fr9j=ZvO+!QCp_~ delta 16976 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 diff --git a/software/diffutils/native/crates/diff/src/lib.rs b/software/diffutils/native/crates/diff/src/lib.rs index 04dbde97da..77e385a00e 100644 --- a/software/diffutils/native/crates/diff/src/lib.rs +++ b/software/diffutils/native/crates/diff/src/lib.rs @@ -272,6 +272,14 @@ fn diff_files(path_a: &Path, path_b: &Path, opts: &Options) -> Result { + if (!tempRoot) throw new Error("fixture root not initialized"); + const hostPath = join(tempRoot, path.replace(/^\/+/, "")); + await mkdir(dirname(hostPath), { recursive: true }); + await writeFile(hostPath, contents); +} + +async function createTestVFS(): Promise { + tempRoot = await mkdtemp(join(tmpdir(), "agentos-diff-")); + await writeFixture("/project/a.txt", "alpha\nbeta\ngamma\n"); + await writeFixture("/project/b.txt", "alpha\ndelta\ngamma\n"); + await writeFixture("/project/same.txt", "alpha\nbeta\ngamma\n"); + await writeFixture("/project/ws-a.txt", "Alpha\n\nbeta value\n"); + await writeFixture("/project/ws-b.txt", "alpha\n BETA VALUE\n"); + await writeFixture("/project/left/common.txt", "one\ntwo\nthree\n"); + await writeFixture("/project/right/common.txt", "one\n2\nthree\n"); + await writeFixture("/project/right/extra.txt", "only on right\n"); + return new NodeFileSystem({ root: tempRoot }); +} + +describeIf(hasDiffPackageBinary, "diff command", { timeout: 10_000 }, () => { + let kernel: Kernel | undefined; + + afterEach(async () => { + await kernel?.dispose(); + kernel = undefined; + if (tempRoot) { + await rm(tempRoot, { recursive: true, force: true }); + tempRoot = undefined; + } + }); + + async function mountFixture(): Promise { + const vfs = await createTestVFS(); + kernel = createKernel({ filesystem: vfs }); + await kernel.mount(createWasmVmRuntime({ commandDirs: [DIFF_COMMAND_DIR] })); + } + + async function runDiff(args: string[]) { + if (!kernel) throw new Error("kernel not mounted"); + let stdout = ""; + let stderr = ""; + const proc = kernel.spawn("diff", args, { + onStdout: (chunk) => { + stdout += Buffer.from(chunk).toString("utf8"); + }, + onStderr: (chunk) => { + stderr += Buffer.from(chunk).toString("utf8"); + }, + }); + const exitCode = await proc.wait(); + await new Promise((resolve) => setTimeout(resolve, 0)); + return { stdout, stderr, exitCode }; + } + + it("returns zero for identical files", async () => { + await mountFixture(); + + const result = await runDiff(["/project/a.txt", "/project/same.txt"]); + expect(result.exitCode, result.stderr || result.stdout).toBe(0); + expect(result.stdout).toBe(""); + }); + + it("prints normal diffs for changed files", async () => { + await mountFixture(); + + const result = await runDiff(["/project/a.txt", "/project/b.txt"]); + expect(result.exitCode).toBe(1); + expect(result.stdout).toContain("2c2"); + expect(result.stdout).toContain("< beta"); + expect(result.stdout).toContain("> delta"); + }); + + it("prints unified diffs", async () => { + await mountFixture(); + + const result = await runDiff(["-u", "/project/a.txt", "/project/b.txt"]); + expect(result.exitCode).toBe(1); + expect(result.stdout).toContain("--- /project/a.txt"); + expect(result.stdout).toContain("+++ /project/b.txt"); + expect(result.stdout).toContain("-beta"); + expect(result.stdout).toContain("+delta"); + }); + + it("prints brief output with -q", async () => { + await mountFixture(); + + const result = await runDiff(["-q", "/project/a.txt", "/project/b.txt"]); + expect(result.exitCode).toBe(1); + expect(result.stdout.trim()).toBe( + "Files /project/a.txt and /project/b.txt differ", + ); + }); + + it("honors ignore-case, whitespace, and blank-line flags", async () => { + await mountFixture(); + + const result = await runDiff([ + "-i", + "-w", + "-B", + "/project/ws-a.txt", + "/project/ws-b.txt", + ]); + expect(result.exitCode, result.stderr || result.stdout).toBe(0); + expect(result.stdout).toBe(""); + }); + + it("compares directories recursively", async () => { + await mountFixture(); + + const result = await runDiff(["-r", "/project/left", "/project/right"]); + expect(result.exitCode).toBe(1); + expect(result.stdout).toContain("Only in /project/right: extra.txt"); + expect(result.stdout).toContain("/project/left/common.txt"); + expect(result.stdout).toContain("/project/right/common.txt"); + }); + + it("returns an error for missing inputs", async () => { + await mountFixture(); + + const result = await runDiff(["/project/a.txt", "/project/missing.txt"]); + expect(result.exitCode).toBe(2); + expect(result.stderr).toContain("/project/missing.txt"); + }); +});