Implement `mergeConservative` for GraphV2 (#320)
Summary: I dropped the `edgeDecomposition` and `neighborhoodDecomposition` test cases, because (a) we don’t have a canonical “interesting graph” on which to run them, compounding that (b) it’s not clear how much value they add. Test Plan: New unit tests suffice. wchargin-branch: mergeConservative-v2
This commit is contained in:
parent
c7854c1154
commit
760fd00427
|
@ -313,8 +313,16 @@ export class Graph {
|
|||
plugins: Plugins,
|
||||
graphs: $ReadOnlyArray<Graph>
|
||||
): Graph {
|
||||
const _ = {plugins, graphs};
|
||||
throw new Error("Graphv2 is not yet implemented");
|
||||
const result = new Graph(plugins);
|
||||
graphs.forEach((graph) => {
|
||||
for (const node of graph.nodes()) {
|
||||
result.addNode(node.payload);
|
||||
}
|
||||
for (const edge of graph.edges()) {
|
||||
result.addEdge(edge);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -625,6 +625,109 @@ describe("graph", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("mergeConservative", () => {
|
||||
const merge = (graphs) => Graph.mergeConservative([new Handler()], graphs);
|
||||
|
||||
it("installs appropriate plugin handlers", () => {
|
||||
const plugins = [new Handler()];
|
||||
expect(Graph.mergeConservative(plugins, []).plugins()).toEqual(plugins);
|
||||
});
|
||||
|
||||
it("yields the empty graph on empty input", () => {
|
||||
expect(merge([]).equals(newGraph())).toBe(true);
|
||||
});
|
||||
|
||||
it("is the identity on a singleton input", () => {
|
||||
const g = () =>
|
||||
newGraph()
|
||||
.addNode(new FooPayload())
|
||||
.addEdge({
|
||||
address: {
|
||||
owner: {plugin: EXAMPLE_PLUGIN_NAME, type: "EDGE"},
|
||||
id: "edge",
|
||||
},
|
||||
src: new FooPayload().address(),
|
||||
dst: new BarPayload(1, "hello").address(),
|
||||
payload: "nothing",
|
||||
});
|
||||
expect(merge([g()]).equals(g())).toBe(true);
|
||||
});
|
||||
|
||||
it("merges two graphs with nontrivial intersection", () => {
|
||||
const nodes = {
|
||||
a: () => new BarPayload(1, "alpha"),
|
||||
b: () => new BarPayload(2, "bravo"),
|
||||
absent: () => new FooPayload(),
|
||||
};
|
||||
const edge = (srcPayload, dstPayload, id): Edge<string> => ({
|
||||
address: {owner: {plugin: EXAMPLE_PLUGIN_NAME, type: "EDGE"}, id},
|
||||
src: srcPayload.address(),
|
||||
dst: dstPayload.address(),
|
||||
payload: "not much",
|
||||
});
|
||||
const edges: {[string]: () => Edge<string>} = {
|
||||
a_b: () => edge(nodes.a(), nodes.b(), "a_b"),
|
||||
a_absent: () => edge(nodes.a(), nodes.absent(), "a_absent"),
|
||||
b_absent: () => edge(nodes.b(), nodes.absent(), "b_absent"),
|
||||
};
|
||||
const g = newGraph()
|
||||
.addNode(nodes.a())
|
||||
.addEdge(edges.a_b())
|
||||
.addEdge(edges.a_absent());
|
||||
const h = newGraph()
|
||||
.addNode(nodes.b())
|
||||
.addEdge(edges.a_b())
|
||||
.addEdge(edges.b_absent());
|
||||
const merged = merge([g, h]);
|
||||
const expected = newGraph()
|
||||
.addNode(nodes.a())
|
||||
.addNode(nodes.b())
|
||||
.addEdge(edges.a_b())
|
||||
.addEdge(edges.a_absent())
|
||||
.addEdge(edges.b_absent());
|
||||
expect(merged.equals(expected)).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects graphs with conflicting nodes", () => {
|
||||
const g = newGraph().addNode(new BarPayload(1, "hello"));
|
||||
const h = newGraph().addNode(new BarPayload(1, "there"));
|
||||
expect(() => {
|
||||
merge([g, h]);
|
||||
}).toThrow(/node.*exists with distinct contents/);
|
||||
});
|
||||
|
||||
it("rejects graphs with conflicting edges", () => {
|
||||
const e = (payload) => ({
|
||||
address: {owner: {plugin: EXAMPLE_PLUGIN_NAME, type: "EDGE"}, id: "e"},
|
||||
src: new FooPayload().address(),
|
||||
dst: new FooPayload().address(),
|
||||
payload,
|
||||
});
|
||||
const g = newGraph().addEdge(e(1));
|
||||
const h = newGraph().addEdge(e(2));
|
||||
expect(() => {
|
||||
merge([g, h]);
|
||||
}).toThrow(/edge.*exists with distinct contents/);
|
||||
});
|
||||
|
||||
it("copies its input", () => {
|
||||
const g = newGraph();
|
||||
const h = merge([g]);
|
||||
expect(g).not.toBe(h);
|
||||
g.addNode(new FooPayload());
|
||||
expect(g.equals(h)).toBe(false);
|
||||
});
|
||||
|
||||
it("yields `ref`s pointing to the proper graphs", () => {
|
||||
const g = newGraph().addNode(new FooPayload());
|
||||
const gRef = g.ref(new FooPayload().address());
|
||||
const h = merge([g]);
|
||||
const hRef = h.ref(new FooPayload().address());
|
||||
expect(gRef.graph()).toBe(g);
|
||||
expect(hRef.graph()).toBe(h);
|
||||
});
|
||||
});
|
||||
|
||||
describe("equals", () => {
|
||||
const srcPayload = () => new BarPayload(1, "first");
|
||||
const dstPayload = () => new BarPayload(2, "second");
|
||||
|
|
Loading…
Reference in New Issue