blob: 572f253f1a2f587e5c1aad065cccaf04673253f5 [file] [log] [blame]
import { DiffGenerator, DiffType } from "../src/utils/diff.js";
import { NodeBuilder, toPlainObject } from "./utils/tree.js";
const treeOne = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).build(),
new NodeBuilder().setId(3).build(),
new NodeBuilder().setId(4).build(),
]).build();
const treeTwo = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).build(),
new NodeBuilder().setId(3).setChildren([
new NodeBuilder().setId(5).build(),
]).build(),
new NodeBuilder().setId(4).build(),
]).build();
function checkDiffTreeWithNoModifiedCheck(oldTree, newTree, expectedDiffTree) {
const diffTree = new DiffGenerator(newTree)
.compareWith(oldTree)
.withUniqueNodeId(node => node.id)
.withModifiedCheck(() => false)
.generateDiffTree();
expect(diffTree).toEqual(expectedDiffTree);
}
describe("DiffGenerator", () => {
it("can generate a simple add diff", () => {
const oldTree = treeOne;
const newTree = treeTwo;
const expectedDiffTree = toPlainObject(
new NodeBuilder().setId(1).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(2).setDiffType(DiffType.NONE).build(),
new NodeBuilder().setId(3).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(5).setDiffType(DiffType.ADDED).build(),
]).build(),
new NodeBuilder().setId(4).setDiffType(DiffType.NONE).build(),
]).build()
);
checkDiffTreeWithNoModifiedCheck(oldTree, newTree, expectedDiffTree);
});
it("can generate a simple delete diff", () => {
const oldTree = treeTwo;
const newTree = treeOne;
const expectedDiffTree = toPlainObject(
new NodeBuilder().setId(1).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(2).setDiffType(DiffType.NONE).build(),
new NodeBuilder().setId(3).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(5).setDiffType(DiffType.DELETED).build(),
]).build(),
new NodeBuilder().setId(4).setDiffType(DiffType.NONE).build(),
]).build()
);
checkDiffTreeWithNoModifiedCheck(oldTree, newTree, expectedDiffTree);
});
it("can generate a simple move diff", () => {
const oldTree = treeTwo;
const newTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).build(),
new NodeBuilder().setId(3).build(),
new NodeBuilder().setId(4).setChildren([
new NodeBuilder().setId(5).build(),
]).build(),
]).build();
const expectedDiffTree = toPlainObject(
new NodeBuilder().setId(1).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(2).setDiffType(DiffType.NONE).build(),
new NodeBuilder().setId(3).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(5).setDiffType(DiffType.DELETED_MOVE).build(),
]).build(),
new NodeBuilder().setId(4).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(5).setDiffType(DiffType.ADDED_MOVE).build(),
]).build(),
]).build()
);
checkDiffTreeWithNoModifiedCheck(oldTree, newTree, expectedDiffTree);
});
it("can generate a simple modified diff", () => {
const oldTree = new NodeBuilder().setId(1).setData("xyz").setChildren([
new NodeBuilder().setId(2).setData("abc").build(),
new NodeBuilder().setId(3).setData("123").build(),
]).build();
const newTree = new NodeBuilder().setId(1).setData("xyz").setChildren([
new NodeBuilder().setId(2).setData("def").build(),
new NodeBuilder().setId(3).setData("123").build(),
]).build();
const expectedDiffTree = toPlainObject(
new NodeBuilder().setId(1).setData("xyz").setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(2).setData("def").setDiffType(DiffType.MODIFIED).build(),
new NodeBuilder().setId(3).setData("123").setDiffType(DiffType.NONE).build(),
]).build()
);
const diffTree = new DiffGenerator(newTree)
.compareWith(oldTree)
.withUniqueNodeId(node => node.id)
.withModifiedCheck(
(newNode, oldNode) => newNode.data != oldNode.data)
.generateDiffTree();
expect(diffTree).toEqual(expectedDiffTree);
});
it("can handle move and inner addition diff", () => {
const oldTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).build(),
new NodeBuilder().setId(3).setChildren([
new NodeBuilder().setId(4).build(),
]).build(),
]).build();
const newTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).setChildren([
new NodeBuilder().setId(4).setChildren([
new NodeBuilder().setId(5).build(),
]).build(),
]).build(),
new NodeBuilder().setId(3).build(),
]).build();
const expectedDiffTree = toPlainObject(
new NodeBuilder().setId(1).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(2).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(4).setDiffType(DiffType.ADDED_MOVE).setChildren([
new NodeBuilder().setId(5).setDiffType(DiffType.ADDED).build(),
]).build(),
]).build(),
new NodeBuilder().setId(3).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(4).setDiffType(DiffType.DELETED_MOVE).build(),
]).build(),
]).build()
);
checkDiffTreeWithNoModifiedCheck(oldTree, newTree, expectedDiffTree);
});
it("can handle move within same level", () => {
const oldTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).build(),
new NodeBuilder().setId(3).build(),
]).build();
const newTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(3).build(),
new NodeBuilder().setId(2).build(),
]).build();
const expectedDiffTree = toPlainObject(
new NodeBuilder().setId(1).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(3).setDiffType(DiffType.NONE).build(),
new NodeBuilder().setId(2).setDiffType(DiffType.NONE).build(),
]).build()
);
checkDiffTreeWithNoModifiedCheck(oldTree, newTree, expectedDiffTree);
});
it("can handle addition within middle of level", () => {
const oldTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).build(),
new NodeBuilder().setId(3).build(),
]).build();
const newTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).build(),
new NodeBuilder().setId(4).build(),
new NodeBuilder().setId(3).build(),
]).build();
const expectedDiffTree = toPlainObject(
new NodeBuilder().setId(1).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(2).setDiffType(DiffType.NONE).build(),
new NodeBuilder().setId(4).setDiffType(DiffType.ADDED).build(),
new NodeBuilder().setId(3).setDiffType(DiffType.NONE).build(),
]).build()
);
checkDiffTreeWithNoModifiedCheck(oldTree, newTree, expectedDiffTree);
});
it("can handle deletion within middle of level", () => {
const oldTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).build(),
new NodeBuilder().setId(3).build(),
new NodeBuilder().setId(4).build(),
]).build();
const newTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).build(),
new NodeBuilder().setId(4).build(),
]).build();
const expectedDiffTree = toPlainObject(
new NodeBuilder().setId(1).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(2).setDiffType(DiffType.NONE).build(),
new NodeBuilder().setId(3).setDiffType(DiffType.DELETED).build(),
new NodeBuilder().setId(4).setDiffType(DiffType.NONE).build(),
]).build()
);
checkDiffTreeWithNoModifiedCheck(oldTree, newTree, expectedDiffTree);
});
it("fully visits deletes nodes", () => {
const oldTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).setChildren([
new NodeBuilder().setId(3).setChildren([
new NodeBuilder().setId(4).build(),
]).build(),
]).build(),
]).build();
const newTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).build(),
new NodeBuilder().setId(3).setChildren([
new NodeBuilder().setId(4).build(),
]).build(),
]).build();
const expectedDiffTree = toPlainObject(
new NodeBuilder().setId(1).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(2).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(3).setDiffType(DiffType.DELETED_MOVE).setChildren([
new NodeBuilder().setId(4).setDiffType(DiffType.DELETED_MOVE).build(),
]).build(),
]).build(),
new NodeBuilder().setId(3).setDiffType(DiffType.ADDED_MOVE).setChildren([
new NodeBuilder().setId(4).setDiffType(DiffType.NONE).build(),
]).build(),
]).build()
);
checkDiffTreeWithNoModifiedCheck(oldTree, newTree, expectedDiffTree);
});
it("preserves node chips", () => {
const oldTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).setChips(["CHIP2"]).build(),
new NodeBuilder().setId(3).build(),
]).build();
const newTree = new NodeBuilder().setId(1).setChildren([
new NodeBuilder().setId(2).setChips(["CHIP2"]).build(),
new NodeBuilder().setId(4).setChips(["CHIP4"]).build(),
]).build();
const expectedDiffTree = toPlainObject(
new NodeBuilder().setId(1).setDiffType(DiffType.NONE).setChildren([
new NodeBuilder().setId(2).setChips(["CHIP2"]).setDiffType(DiffType.NONE).build(),
new NodeBuilder().setId(3).setDiffType(DiffType.DELETED).build(),
new NodeBuilder().setId(4).setChips(["CHIP4"]).setDiffType(DiffType.ADDED).build(),
]).build()
);
checkDiffTreeWithNoModifiedCheck(oldTree, newTree, expectedDiffTree);
});
});