mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 08:52:12 +00:00
Conflicts left by stash pop or an automatic stash now get the same editor banner (File has unresolved merge conflicts, Resolve conflicts…) as merge conflicts. Complete conflict markers are reported as errors in every language and listed in Problems (severity under Settings › Editor › Inspections › Version Control). The toolbar shows Resolve/Continue and Abort next to the branch while conflicts or an interrupted operation exist, and the Commit view and Branches popup offer Resolve Conflicts even when no operation is in progress. Co-authored-by: ntbang0901 <[email protected]>
100 lines
3.6 KiB
TypeScript
100 lines
3.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { blockAt, mergeTitles, parseConflicts, resolveAll, resolutionText } from "../conflicts";
|
|
|
|
const text = [
|
|
"keep\n",
|
|
"<<<<<<< HEAD\n",
|
|
"ours 1\n",
|
|
"ours 2\n",
|
|
"||||||| base\n",
|
|
"base\n",
|
|
"=======\n",
|
|
"theirs\n",
|
|
">>>>>>> feature\n",
|
|
"tail\n",
|
|
"<<<<<<< HEAD\n",
|
|
"=======\n",
|
|
"only theirs\n",
|
|
">>>>>>> feature\n",
|
|
].join("");
|
|
|
|
describe("parseConflicts", () => {
|
|
it("parses diff3 and plain blocks", () => {
|
|
const blocks = parseConflicts(text);
|
|
expect(blocks).toHaveLength(2);
|
|
const [a, b] = blocks;
|
|
expect(a).toMatchObject({
|
|
ours: "ours 1\nours 2\n",
|
|
base: "base\n",
|
|
theirs: "theirs\n",
|
|
oursLabel: "HEAD",
|
|
theirsLabel: "feature",
|
|
});
|
|
expect(text.slice(a!.from, a!.to)).toMatch(/^<<<<<<< HEAD\n[\s\S]*>>>>>>> feature\n$/);
|
|
expect(b).toMatchObject({ ours: "", base: null, theirs: "only theirs\n" });
|
|
expect(blockAt(blocks, text.indexOf("theirs\n"))).toBe(a);
|
|
expect(blockAt(blocks, 0)).toBeUndefined();
|
|
});
|
|
|
|
it("locates the marker lines, without their terminators", () => {
|
|
const [a, b] = parseConflicts(text);
|
|
const lines = (block: typeof a) => block!.markers.map((m) => text.slice(m.from, m.to));
|
|
expect(lines(a)).toEqual(["<<<<<<< HEAD", "||||||| base", "=======", ">>>>>>> feature"]);
|
|
expect(lines(b)).toEqual(["<<<<<<< HEAD", "=======", ">>>>>>> feature"]);
|
|
const crlf = "<<<<<<< a\r\nx\r\n=======\r\ny\r\n>>>>>>> b\r\n";
|
|
expect(parseConflicts(crlf)[0]!.markers.map((m) => crlf.slice(m.from, m.to))).toEqual([
|
|
"<<<<<<< a",
|
|
"=======",
|
|
">>>>>>> b",
|
|
]);
|
|
});
|
|
|
|
it("ignores unterminated markers", () => {
|
|
expect(parseConflicts("<<<<<<< HEAD\nx\n=======\ny\n")).toEqual([]);
|
|
});
|
|
|
|
it("resolves blocks", () => {
|
|
expect(resolveAll(text, "ours")).toBe("keep\nours 1\nours 2\ntail\n");
|
|
expect(resolveAll(text, "theirs")).toBe("keep\ntheirs\ntail\nonly theirs\n");
|
|
const [a] = parseConflicts(text);
|
|
expect(resolutionText(a!, "both")).toBe("ours 1\nours 2\ntheirs\n");
|
|
expect(resolutionText(a!, "base")).toBe("base\n");
|
|
});
|
|
|
|
it("swaps sides during a rebase, where the user's commit is the >>>>>>> section", () => {
|
|
expect(resolveAll(text, "ours", true)).toBe("keep\ntheirs\ntail\nonly theirs\n");
|
|
expect(resolveAll(text, "theirs", true)).toBe("keep\nours 1\nours 2\ntail\n");
|
|
const [a] = parseConflicts(text);
|
|
expect(resolutionText(a!, "both", true)).toBe("theirs\nours 1\nours 2\n");
|
|
expect(resolutionText(a!, "base", true)).toBe("base\n");
|
|
});
|
|
});
|
|
|
|
describe("mergeTitles", () => {
|
|
const sides = (operation: string | null, extra: Record<string, string | boolean | null> = {}) => ({
|
|
operation,
|
|
reversed: operation === "rebase",
|
|
branch: "feature",
|
|
commit: "abc12345",
|
|
otherBranch: "main",
|
|
...extra,
|
|
});
|
|
it("names the sides like IDEA for each operation", () => {
|
|
expect(mergeTitles(sides("rebase"))).toEqual({
|
|
yours: "Rebasing abc12345 from feature",
|
|
theirs: "Already rebased commits and commits from main",
|
|
});
|
|
expect(mergeTitles(sides("rebase", { otherBranch: null })).theirs).toBe("Already rebased commits");
|
|
expect(mergeTitles(sides("merge"))).toEqual({ yours: "Changes from feature", theirs: "Changes from main" });
|
|
expect(mergeTitles(sides("cherry-pick"))).toEqual({
|
|
yours: "Local Changes",
|
|
theirs: "Changes from cherry-pick abc12345",
|
|
});
|
|
expect(mergeTitles(sides("unstash"))).toEqual({
|
|
yours: "Your uncommitted changes",
|
|
theirs: "Changes from feature",
|
|
});
|
|
expect(mergeTitles(null)).toEqual({ yours: "Your version", theirs: "Theirs (incoming)" });
|
|
});
|
|
});
|