| 1 |
// The process wrapper against the real oxy binary on a scratch repository. |
| 2 |
// Runs with `npm test`; needs oxy on PATH, at ~/.local/bin/oxy, or in OXY_BIN. |
| 3 |
|
| 4 |
import { test } from "node:test"; |
| 5 |
import assert from "node:assert/strict"; |
| 6 |
import { mkdtempSync, writeFileSync, mkdirSync } from "node:fs"; |
| 7 |
import { tmpdir } from "node:os"; |
| 8 |
import { join } from "node:path"; |
| 9 |
import { Oxy, findBinary } from "../out/oxy.mjs"; |
| 10 |
|
| 11 |
const binary = process.env.OXY_BIN ?? findBinary(undefined); |
| 12 |
const oxy = new Oxy(binary); |
| 13 |
|
| 14 |
test("root, status, cat, log and commit round trip", async () => { |
| 15 |
const dir = mkdtempSync(join(tmpdir(), "oxy-vscode-")); |
| 16 |
const home = join(dir, "home"); |
| 17 |
mkdirSync(home); |
| 18 |
process.env.OXY_HOME = home; |
| 19 |
await oxy.check(dir, ["init", "repo"]); |
| 20 |
const root = join(dir, "repo"); |
| 21 |
await oxy.check(root, ["identity", "create", "--name", "Test", "--email", "[email protected]"]); |
| 22 |
|
| 23 |
const version = await oxy.version(); |
| 24 |
assert.equal(version.protocol, 1); |
| 25 |
assert.equal(await oxy.root(dir), null, "outside a repository"); |
| 26 |
const info = await oxy.root(root); |
| 27 |
assert.equal(info?.bookmark, "main"); |
| 28 |
assert.ok(info?.root.endsWith("repo")); |
| 29 |
|
| 30 |
writeFileSync(join(root, "a.txt"), "one\n"); |
| 31 |
let status = await oxy.status(root); |
| 32 |
assert.deepEqual(status.paths, [{ path: "a.txt", status: "Added" }]); |
| 33 |
assert.equal(status.clean, false); |
| 34 |
await oxy.commit(root, "first"); |
| 35 |
status = await oxy.status(root); |
| 36 |
assert.equal(status.clean, true); |
| 37 |
|
| 38 |
writeFileSync(join(root, "a.txt"), "one\ntwo\n"); |
| 39 |
assert.equal((await oxy.cat(root, "a.txt")).toString(), "one\n", "the base version"); |
| 40 |
const log = await oxy.log(root, 10); |
| 41 |
assert.equal(log.changes.filter((c) => !c.working_copy).length, 1); |
| 42 |
assert.equal(log.changes.find((c) => !c.working_copy)?.signature?.status, "unsigned"); |
| 43 |
assert.ok((await oxy.prompt(root)).includes("main")); |
| 44 |
const bookmarks = await oxy.bookmarks(root); |
| 45 |
assert.deepEqual(bookmarks.map((b) => [b.name, b.current]), [["main", true]]); |
| 46 |
await assert.rejects(oxy.cat(root, "missing.txt"), /not in that state/); |
| 47 |
|
| 48 |
// Amend folds the edit into the single head. |
| 49 |
await oxy.amend(root, "first, amended"); |
| 50 |
assert.equal((await oxy.status(root)).clean, true); |
| 51 |
assert.ok((await oxy.log(root, 10)).changes.some((c) => c.message === "first, amended")); |
| 52 |
|
| 53 |
// Hunks: commit only b.txt's, leave a.txt's edit, then discard it. |
| 54 |
writeFileSync(join(root, "a.txt"), "one\ntwo\nthree\n"); |
| 55 |
writeFileSync(join(root, "b.txt"), "b\n"); |
| 56 |
const hunks = await oxy.hunks(root); |
| 57 |
assert.ok(hunks.length >= 2, JSON.stringify(hunks)); |
| 58 |
const bHunk = hunks.find((h) => h.path === "b.txt"); |
| 59 |
await oxy.commitHunks(root, "b only", [bHunk.index]); |
| 60 |
status = await oxy.status(root); |
| 61 |
assert.deepEqual(status.paths.map((p) => p.path), ["a.txt"], "a.txt stays uncommitted"); |
| 62 |
assert.equal((await oxy.cat(root, "b.txt")).toString(), "b\n", "committed with its content"); |
| 63 |
await oxy.discard(root, ["a.txt"]); |
| 64 |
assert.equal((await oxy.status(root)).clean, true); |
| 65 |
|
| 66 |
// The operation log, and undo of the last operation (the commit). |
| 67 |
const ops = await oxy.opLog(root); |
| 68 |
assert.ok(ops[0].current && ops.length > 3); |
| 69 |
assert.match(await oxy.undo(root), /Undone/); |
| 70 |
status = await oxy.status(root); |
| 71 |
assert.ok(status.paths.some((p) => p.path === "b.txt"), "the commit is undone; b.txt is uncommitted work again"); |
| 72 |
}); |