UniRef: add GithubReferenceDetector (#1543)

As a RelationalView is not designed for multiple repositories, we
should implement our own merging of mappings obtained from
RelationalViews.

fromRelationalViews is a factory function which does this for us.
And by accepting an array of RelationalViews it's more apparent
it should be used this way.
This commit is contained in:
Robin van Boven 2020-01-13 14:13:30 +01:00 committed by GitHub
parent f16119af43
commit 063c08d974
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 112 additions and 0 deletions

View File

@ -0,0 +1,37 @@
// @flow
import dedent from "../../util/dedent";
import {type NodeAddressT, NodeAddress} from "../../core/graph";
import {MappedReferenceDetector, type URL} from "../../core/references";
import {RelationalView} from "./relationalView";
/**
* Builds a GithubReferenceDetector using multiple RelationalView.
* As RelationalView should only be used for one repository at a time, you will
* commonly want to compose several of them into one GithubReferenceDetector.
*
* Note: duplicates are normally expected. However for any URL, the corresponding
* NodeAddressT should be the same, or we'll throw an error.
*/
export function fromRelationalViews(
views: $ReadOnlyArray<RelationalView>
): GithubReferenceDetector {
const map: Map<URL, NodeAddressT> = new Map();
for (const view of views) {
for (const [url, addr] of view.urlReferenceMap().entries()) {
const existing = map.get(url);
if (existing && existing != addr) {
throw new Error(dedent`\
An entry for ${url} already existed, but with a different NodeAddressT.
This is probably a bug with SourceCred. Please report it on GitHub.
Old: ${NodeAddress.toString(existing)}
New: ${NodeAddress.toString(addr)}
`);
}
map.set(url, addr);
}
}
return new GithubReferenceDetector(map);
}
export const GithubReferenceDetector = MappedReferenceDetector;

View File

@ -0,0 +1,75 @@
// @flow
import {exampleRelationalView} from "./example/example";
import {RelationalView} from "./relationalView";
import {
GithubReferenceDetector,
fromRelationalViews,
} from "./referenceDetector";
import {MappedReferenceDetector} from "../../core/references";
import {NodeAddress} from "../../core/graph";
import dedent from "../../util/dedent";
describe("plugins/github/referenceDetector", () => {
describe("GithubReferenceDetector", () => {
it("should be a MappedReferenceDetector", () => {
// Given
const map = new Map();
// When
const refs = new GithubReferenceDetector(map);
// Then
expect(refs).toBeInstanceOf(MappedReferenceDetector);
});
});
describe("fromRelationalViews", () => {
it("should use urlReferenceMap to create the instance", () => {
// Given
const rv = new RelationalView();
const urlReferenceMap = jest.spyOn(rv, "urlReferenceMap");
// When
const refs = fromRelationalViews([rv, rv]);
// Then
expect(refs).toBeInstanceOf(MappedReferenceDetector);
expect(urlReferenceMap).toBeCalledTimes(2);
});
it("should deduplicate silently given the same entries", () => {
// Given
const rv = exampleRelationalView();
// When
const refs = fromRelationalViews([rv, rv]);
// Then
expect(refs.map).toEqual(rv.urlReferenceMap());
});
it("should throw when encountering duplicate keys with different values", () => {
// Given
const url = "http://foo.bar";
const nodeA = NodeAddress.fromParts(["test", "A"]);
const nodeB = NodeAddress.fromParts(["test", "B"]);
const rv1 = new RelationalView();
const rv2 = new RelationalView();
const rv1Spy = jest.spyOn(rv1, "urlReferenceMap");
const rv2Spy = jest.spyOn(rv2, "urlReferenceMap");
rv1Spy.mockReturnValue(new Map([[url, nodeA]]));
rv2Spy.mockReturnValue(new Map([[url, nodeB]]));
// When
const fn = () => fromRelationalViews([rv1, rv2]);
// Then
expect(fn).toThrow(dedent`\
An entry for http://foo.bar already existed, but with a different NodeAddressT.
This is probably a bug with SourceCred. Please report it on GitHub.
Old: NodeAddress["test","A"]
New: NodeAddress["test","B"]`);
});
});
});