Implement `Graph.merge` (#375)

Tests are mostly copied over from the v2, as implemented in #320.
Some new tests were added, e.g. checking that Merge correctly handles
10 small graphs combined.

Test plan:
See unit tests.
This commit is contained in:
Dandelion Mané 2018-06-11 10:55:30 -07:00 committed by GitHub
parent 5fde1c10a5
commit 46751d2707
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 110 additions and 2 deletions

View File

@ -332,8 +332,16 @@ export class Graph {
} }
static merge(graphs: Iterable<Graph>): Graph { static merge(graphs: Iterable<Graph>): Graph {
const _ = graphs; const result = new Graph();
throw new Error("merge"); for (const graph of graphs) {
for (const node of graph.nodes()) {
result.addNode(node);
}
for (const edge of graph.edges()) {
result.addEdge(edge);
}
}
return result;
} }
} }

View File

@ -847,6 +847,106 @@ describe("core/graph", () => {
}); });
}); });
describe("merge", () => {
const foo = NodeAddress.fromParts(["foo"]);
const bar = NodeAddress.fromParts(["bar"]);
const zod = NodeAddress.fromParts(["zod"]);
const foofoo = () => ({
src: foo,
dst: foo,
address: EdgeAddress.fromParts(["foofoo"]),
});
const foobar = () => ({
src: foo,
dst: bar,
address: EdgeAddress.fromParts(["foobar"]),
});
const zodfoo = () => ({
src: zod,
dst: foo,
address: EdgeAddress.fromParts(["zodfoo"]),
});
const conflictingZodfoo = () => ({
src: zod,
dst: zod,
address: EdgeAddress.fromParts(["zodfoo"]),
});
it("yields empty graph on empty input", () => {
expect(Graph.merge([]).equals(new Graph())).toBe(true);
});
it("can be independently mutated from input", () => {
const g1 = new Graph();
const g2 = Graph.merge([g1]);
expect(g1.equals(g2)).toBe(true);
g2.addNode(foo);
expect(g1.equals(g2)).toBe(false);
});
it("is identity on a singleton input", () => {
const graph = new Graph()
.addNode(foo)
.addNode(bar)
.addEdge(foobar());
expect(graph.equals(Graph.merge([graph]))).toBe(true);
});
it("merges two graphs with no intersection", () => {
const g1 = new Graph()
.addNode(foo)
.addNode(bar)
.addEdge(foobar());
const g2 = new Graph().addNode(zod);
const g3_actual = Graph.merge([g1, g2]);
const g3_expected = new Graph()
.addNode(foo)
.addNode(bar)
.addNode(zod)
.addEdge(foobar());
expect(g3_actual.equals(g3_expected)).toBe(true);
});
it("merges two graphs with nontrivial intersection", () => {
const g1 = new Graph()
.addNode(foo)
.addNode(bar)
.addEdge(foobar())
.addEdge(foofoo());
const g2 = new Graph()
.addNode(foo)
.addNode(zod)
.addEdge(zodfoo())
.addEdge(foofoo());
const g3_actual = Graph.merge([g1, g2]);
const g3_expected = new Graph()
.addNode(foo)
.addNode(bar)
.addNode(zod)
.addEdge(foobar())
.addEdge(zodfoo())
.addEdge(foofoo());
expect(g3_actual.equals(g3_expected)).toBe(true);
});
it("merges many graphs", () => {
const graphs = [];
const expected = new Graph();
for (let i = 0; i < 10; i++) {
const node = NodeAddress.fromParts([String(i)]);
expected.addNode(node);
graphs.push(new Graph().addNode(node));
}
const actual = Graph.merge(graphs);
expect(actual.equals(expected)).toBe(true);
});
it("rejects graphs with conflicting edges", () => {
const g1 = new Graph()
.addNode(foo)
.addNode(zod)
.addEdge(zodfoo());
const g2 = new Graph()
.addNode(foo)
.addNode(zod)
.addEdge(conflictingZodfoo());
expect(() => Graph.merge([g1, g2])).toThrow("conflict between new edge");
});
});
describe("edgeToString", () => { describe("edgeToString", () => {
it("works", () => { it("works", () => {
const edge = { const edge = {