OXYGENHUB
# d2c9a5843004 oxygen-vscode / test / oxy.test.mjs
6.5 KiB · last changed Milestone 0.6: Subrepos group, Bisect and Trust views, verify, tags, add workspace, clone 1 month ago source blame history raw
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
});
73
74
test("bookmarks, remotes and sync against a local origin", async () => {
75
  const dir = mkdtempSync(join(tmpdir(), "oxy-vscode-sync-"));
76
  const home = join(dir, "home");
77
  mkdirSync(home);
78
  process.env.OXY_HOME = home;
79
  await oxy.check(dir, ["init", "origin"]);
80
  await oxy.clone(dir, join(dir, "origin"), join(dir, "work"));
81
  const root = join(dir, "work");
82
  writeFileSync(join(root, "a.txt"), "a\n");
83
  await oxy.commit(root, "a");
84
  const remotes = await oxy.remotes(root);
85
  assert.equal(remotes[0].name, "origin");
86
  let push = await oxy.push(root);
87
  assert.equal(push[0].ok, true);
88
  let bookmarks = await oxy.bookmarks(root);
89
  assert.deepEqual(bookmarks.map((b) => [b.name, b.current, b.ahead, b.behind]), [["main", true, 0, 0]]);
90
91
  await oxy.bookmarkCreate(root, "feature");
92
  await oxy.bookmarkSwitch(root, "feature");
93
  writeFileSync(join(root, "a.txt"), "a\nfeature\n");
94
  await oxy.commit(root, "feature work");
95
  bookmarks = await oxy.bookmarks(root);
96
  assert.equal(bookmarks.find((b) => b.current)?.name, "feature");
97
  await oxy.bookmarkSwitch(root, "main");
98
  assert.equal((await oxy.cat(root, "a.txt")).toString(), "a\n");
99
  writeFileSync(join(root, "b.txt"), "b\n");
100
  await assert.rejects(oxy.bookmarkSwitch(root, "feature"), /has changes/);
101
  await oxy.commit(root, "b on main");
102
  assert.match(await oxy.merge(root, "feature"), /Merged/);
103
  assert.equal((await oxy.cat(root, "a.txt")).toString(), "a\nfeature\n");
104
  push = await oxy.push(root, "origin", "feature");
105
  assert.equal(push[0].ok, true);
106
  push = await oxy.push(root);
107
  assert.equal(push[0].ok, true);
108
  const fetch = await oxy.fetch(root);
109
  assert.equal(fetch.remote, "origin");
110
  const pull = await oxy.pull(root);
111
  assert.equal(pull.changed, false);
112
  await oxy.bookmarkDelete(root, "feature");
113
  bookmarks = await oxy.bookmarks(root);
114
  assert.deepEqual(bookmarks.map((b) => b.name), ["main"]);
115
116
  // Blame, show, diff text, and file history.
117
  const blame = await oxy.blame(root, "a.txt");
118
  assert.deepEqual(blame.map((l) => l.line), [1, 2]);
119
  assert.notEqual(blame[0].hash, blame[1].hash, "two changes introduced the two lines");
120
  const show = await oxy.show(root, `#${blame[1].hash.slice(0, 12)}`);
121
  assert.equal(show.message, "feature work");
122
  assert.deepEqual(show.files.map((f) => f.path), ["a.txt"]);
123
  assert.match(await oxy.diffText(root, `#${blame[1].hash.slice(0, 12)}`), /\+feature/);
124
  const history = await oxy.log(root, 50, "a.txt");
125
  assert.equal(history.changes.filter((c) => !c.working_copy).length, 2);
126
127
  // Tags, workspaces, trust, bisect status, subrepos.
128
  await oxy.tagCreate(root, "v1", [], "first");
129
  const tags = await oxy.tags(root);
130
  assert.deepEqual(tags.map((t) => [t.name, t.message]), [["v1", "first"]]);
131
  const workspaces = await oxy.workspaces(root);
132
  assert.equal(workspaces.length, 1);
133
  assert.equal(workspaces[0].current, true);
134
  assert.equal(await oxy.policyShow(root), null, "no policy yet");
135
  const verify = await oxy.verify(root);
136
  assert.ok(verify.every((v) => v.status === "unsigned"));
137
  assert.equal(await oxy.bisectStatus(root), null);
138
  assert.deepEqual(await oxy.submodules(root), []);
139
  await oxy.bisectStart(root);
140
  assert.equal((await oxy.bisectStatus(root))?.state, "need-marks");
141
  await oxy.bisectReset(root);
142
});
143