diff --git a/pro/src/conflictLogic.ts b/pro/src/conflictLogic.ts index dfff399..f9744c2 100644 --- a/pro/src/conflictLogic.ts +++ b/pro/src/conflictLogic.ts @@ -38,9 +38,11 @@ export function isMergable(a: Entity, b?: Entity) { * @param b */ function mergeDigInModified(a: string, o: string, b: string) { - const { conflict, result } = mergeDigIn(a, o, b); + const { conflict, result } = mergeDigIn(a, o, b, { + stringSeparator: /\n/, + }); for (let index = 0; index < result.length; ++index) { - if (["<<<<<<<", "=======", ">>>>>>>"].contains(result[index])) { + if (["<<<<<<<", "=======", ">>>>>>>"].includes(result[index])) { result[index] = "`" + result[index] + "`"; } } @@ -72,7 +74,7 @@ function getLCSText(a: string, b: string) { * @param b * @returns */ -function twoWayMerge(a: string, b: string): string { +export function twoWayMerge(a: string, b: string): string { const aa = a.trim(); const bb = b.trim(); if (aa === "" && bb === "") { @@ -88,7 +90,10 @@ function twoWayMerge(a: string, b: string): string { // const c = getLCSText(a, b); // const patches = makePatches(c, a); // const [d] = applyPatches(patches, b); - const c = getLCSText(a, b); + const c = getLCSText(a, b); //.trim(); + // console.debug(`(start) LCS Text:`); + // console.debug(c); + // console.debug(`(end) LCS Text.`); const d = mergeDigInModified(a, c, b).result.join("\n"); return d; } @@ -100,7 +105,7 @@ function twoWayMerge(a: string, b: string): string { * @param orig * @returns */ -function threeWayMerge(a: string, b: string, orig: string) { +export function threeWayMerge(a: string, b: string, orig: string) { return mergeDigInModified(a, orig, b).result.join("\n"); } diff --git a/pro/tests/conflictLogic.test.ts b/pro/tests/conflictLogic.test.ts index f9b56e1..162a502 100644 --- a/pro/tests/conflictLogic.test.ts +++ b/pro/tests/conflictLogic.test.ts @@ -1,5 +1,9 @@ import { deepStrictEqual, rejects, throws } from "assert"; -import { getFileRenameForDup } from "../src/conflictLogic"; +import { + getFileRenameForDup, + threeWayMerge, + twoWayMerge, +} from "../src/conflictLogic"; describe("New name is generated", () => { it("should throw for empty file", async () => { @@ -69,3 +73,224 @@ describe("New name is generated", () => { ); }); }); + +describe("Two way merge", () => { + it("should correctly merge from zero files", async () => { + const a = "aaa"; + const b = "bbb"; + const res = twoWayMerge(a, b); + const expected = `\`<<<<<<<\` +aaa +\`=======\` +bbb +\`>>>>>>>\``; + deepStrictEqual(expected, res); + }); + + it("should correctly merge from common lines", async () => { + const a = ` +Something is cool. 中文1 +Other thing is cooler. 哈哈! +`; + const b = ` +Anything is cool. 中文2 +Other thing is cooler. 哈哈! +`; + const res = twoWayMerge(a, b); + // console.log(res); + const expected = ` +\`<<<<<<<\` +Something is cool. 中文1 +\`=======\` +Anything is cool. 中文2 +\`>>>>>>>\` +Other thing is cooler. 哈哈! +`; + deepStrictEqual(expected, res); + }); + + it("should merge by lines", async () => { + const a = ` +Something is cool. 中文1 +`; + const b = ` +Something is cooler. 中文2 +`; + const res = twoWayMerge(a, b); + // console.log(res); + const expected = ` +\`<<<<<<<\` +Something is cool. 中文1 +\`=======\` +Something is cooler. 中文2 +\`>>>>>>>\` +`; + deepStrictEqual(expected, res); + }); +}); + +describe("Three way merge", () => { + it("should correctly merge from zero files", async () => { + const orig = ""; + const a = "aaa"; + const b = "bbb"; + const res = threeWayMerge(a, b, orig); + const expected = `\`<<<<<<<\` +aaa +\`=======\` +bbb +\`>>>>>>>\``; + deepStrictEqual(expected, res); + }); + + it("should correctly merge after adding lines on both sides", async () => { + const orig = ` +* [ ] A1 +* [ ] A2 +* [ ] A3 +`; + const a = ` +* [ ] A1 +* [ ] new line after A1 +* [ ] A2 +* [ ] A3 +`; + const b = ` +* [ ] A1 +* [ ] A2 +* [ ] New line after A2 +* [ ] A3 +`; + const res = threeWayMerge(a, b, orig); + // console.log(res); + const expected = ` +* [ ] A1 +* [ ] new line after A1 +* [ ] A2 +* [ ] New line after A2 +* [ ] A3 +`; + deepStrictEqual(expected, res); + }); + + it("should correctly merge after adding lines on both sides (again)", async () => { + const orig = ` +* [ ] 中文 +* [ ] にほんご/にっぽんご +* [ ] A3 +`; + const a = ` +* [ ] 中文 +* [ ] new line after 中文 +* [ ] にほんご/にっぽんご +* [ ] A3 +`; + const b = ` +* [ ] 中文 +* [ ] にほんご/にっぽんご +* [ ] New line after にほんご/にっぽんご +* [ ] A3 +`; + const res = threeWayMerge(a, b, orig); + // console.log(res); + const expected = ` +* [ ] 中文 +* [ ] new line after 中文 +* [ ] にほんご/にっぽんご +* [ ] New line after にほんご/にっぽんご +* [ ] A3 +`; + deepStrictEqual(expected, res); + }); + + it("should correctly merge after deleting lines on both sides", async () => { + const orig = ` +* [ ] 中文 +* [ ] にほんご/にっぽんご +* [ ] A3 +* [ ] A4 +`; + const a = ` +* [ ] にほんご/にっぽんご +* [ ] A3 +* [ ] A4 +`; + const b = ` +* [ ] 中文 +* [ ] A3 +* [ ] A4 +`; + const res = threeWayMerge(a, b, orig); + // console.log(res); + const expected = ` +\`<<<<<<<\` +* [ ] にほんご/にっぽんご +\`=======\` +* [ ] 中文 +\`>>>>>>>\` +* [ ] A3 +* [ ] A4 +`; + deepStrictEqual(expected, res); + }); + + it("should correctly merge after adding on one side and deleting on other side", async () => { + const orig = ` +* [ ] 中文 +* [ ] A3 +* [ ] A4 +`; + const a = ` +* [ ] 中文 +* [ ] にほんご/にっぽんご +* [ ] A3 +* [ ] A4 +`; + const b = ` +* [ ] A3 +* [ ] A4 +`; + const res = threeWayMerge(a, b, orig); + // console.log(res); + const expected = ` +\`<<<<<<<\` +* [ ] 中文 +* [ ] にほんご/にっぽんご +\`=======\` +\`>>>>>>>\` +* [ ] A3 +* [ ] A4 +`; + deepStrictEqual(expected, res); + }); + + it("should correctly merge after adding on one side and deleting on other side (again)", async () => { + const orig = ` +* [ ] 中文 +* [ ] A3 +* [ ] A4 +`; + const a = ` +* [ ] A3 +* [ ] A4 +`; + const b = ` +* [ ] 中文 +* [ ] にほんご/にっぽんご +* [ ] A3 +* [ ] A4 +`; + const res = threeWayMerge(a, b, orig); + // console.log(res); + const expected = ` +\`<<<<<<<\` +\`=======\` +* [ ] 中文 +* [ ] にほんご/にっぽんご +\`>>>>>>>\` +* [ ] A3 +* [ ] A4 +`; + deepStrictEqual(expected, res); + }); +});