mirror of
https://github.com/status-im/sourcecred.git
synced 2025-03-01 04:30:29 +00:00
Create canonical demoAdapters for testing (#735)
PluginAdapters and Node/Edge types are increasingly fundamental to the cred explorer. Prior to this commit, we had no canonical demo adapters/types, and we would create ad-hoc and messy adapters whenever we needed them. This creates unnecessary repetition and lowers test quality. This commit creates a canonical demo adapter (loosely themed based on the wonderful game [Factorio]) and refactors most existing test cases to use the demo adapters. In particular, the horrible mess of pagerankTable adapters has been removed. [Factorio]: https://www.factorio.com/ I left `aggregate.test.js` untouched because I would have needed to materially re-write the tests to port them over. I added a comment so that if we ever do re-write those tests, we'll use the new demo adapters. Test plan: `yarn test` passes.
This commit is contained in:
parent
761b0f1282
commit
fc5c9ea589
@ -1,91 +1,22 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import {
|
import {NodeAddress, EdgeAddress, Graph} from "../../core/graph";
|
||||||
NodeAddress,
|
import {FactorioStaticAdapter} from "./demoAdapters";
|
||||||
EdgeAddress,
|
|
||||||
type NodeAddressT,
|
|
||||||
Graph,
|
|
||||||
} from "../../core/graph";
|
|
||||||
import type {DynamicPluginAdapter} from "./pluginAdapter";
|
|
||||||
import {StaticAdapterSet} from "./adapterSet";
|
import {StaticAdapterSet} from "./adapterSet";
|
||||||
import {FallbackStaticAdapter, FALLBACK_NAME} from "./fallbackAdapter";
|
import {FallbackStaticAdapter, FALLBACK_NAME} from "./fallbackAdapter";
|
||||||
import {Assets} from "../assets";
|
import {Assets} from "../assets";
|
||||||
import {makeRepo, type Repo} from "../../core/repo";
|
import {makeRepo} from "../../core/repo";
|
||||||
|
|
||||||
describe("app/adapters/adapterSet", () => {
|
describe("app/adapters/adapterSet", () => {
|
||||||
class TestStaticPluginAdapter {
|
|
||||||
loadingMock: Function;
|
|
||||||
constructor() {
|
|
||||||
this.loadingMock = jest.fn();
|
|
||||||
}
|
|
||||||
name() {
|
|
||||||
return "other plugin";
|
|
||||||
}
|
|
||||||
nodePrefix() {
|
|
||||||
return NodeAddress.fromParts(["other"]);
|
|
||||||
}
|
|
||||||
edgePrefix() {
|
|
||||||
return EdgeAddress.fromParts(["other"]);
|
|
||||||
}
|
|
||||||
nodeTypes() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
name: "other1",
|
|
||||||
pluralName: "others1",
|
|
||||||
defaultWeight: 0,
|
|
||||||
prefix: NodeAddress.fromParts(["other", "1"]),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "other2",
|
|
||||||
pluralName: "others2",
|
|
||||||
defaultWeight: 0,
|
|
||||||
prefix: NodeAddress.fromParts(["other", "2"]),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
edgeTypes() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
forwardName: "others_1",
|
|
||||||
backwardName: "othered_by_1",
|
|
||||||
prefix: EdgeAddress.fromParts(["other", "1"]),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
forwardName: "others_2",
|
|
||||||
backwardName: "othered_by_2",
|
|
||||||
prefix: EdgeAddress.fromParts(["other", "2"]),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
load(assets: Assets, repo: Repo) {
|
|
||||||
return this.loadingMock(assets, repo).then(
|
|
||||||
() => new TestDynamicPluginAdapter()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestDynamicPluginAdapter implements DynamicPluginAdapter {
|
|
||||||
graph() {
|
|
||||||
return new Graph().addNode(NodeAddress.fromParts(["other1", "example"]));
|
|
||||||
}
|
|
||||||
nodeDescription(x: NodeAddressT) {
|
|
||||||
return `Node from the test plugin: ${NodeAddress.toString(x)}`;
|
|
||||||
}
|
|
||||||
static() {
|
|
||||||
return new TestStaticPluginAdapter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("StaticAdapterSet", () => {
|
describe("StaticAdapterSet", () => {
|
||||||
function example() {
|
function example() {
|
||||||
const x = new TestStaticPluginAdapter();
|
const x = new FactorioStaticAdapter();
|
||||||
const fallback = new FallbackStaticAdapter();
|
const fallback = new FallbackStaticAdapter();
|
||||||
const sas = new StaticAdapterSet([x]);
|
const sas = new StaticAdapterSet([x]);
|
||||||
return {x, fallback, sas};
|
return {x, fallback, sas};
|
||||||
}
|
}
|
||||||
it("errors if two plugins have the same name", () => {
|
it("errors if two plugins have the same name", () => {
|
||||||
const x = new TestStaticPluginAdapter();
|
const x = new FactorioStaticAdapter();
|
||||||
const shouldError = () => new StaticAdapterSet([x, x]);
|
const shouldError = () => new StaticAdapterSet([x, x]);
|
||||||
expect(shouldError).toThrowError("Multiple plugins with name");
|
expect(shouldError).toThrowError("Multiple plugins with name");
|
||||||
});
|
});
|
||||||
@ -100,24 +31,30 @@ describe("app/adapters/adapterSet", () => {
|
|||||||
it("aggregates NodeTypes across plugins", () => {
|
it("aggregates NodeTypes across plugins", () => {
|
||||||
const {sas} = example();
|
const {sas} = example();
|
||||||
const nodeTypes = sas.nodeTypes();
|
const nodeTypes = sas.nodeTypes();
|
||||||
expect(nodeTypes).toHaveLength(3);
|
const expectedNumNodeTypes =
|
||||||
|
new FactorioStaticAdapter().nodeTypes().length +
|
||||||
|
new FallbackStaticAdapter().nodeTypes().length;
|
||||||
|
expect(nodeTypes).toHaveLength(expectedNumNodeTypes);
|
||||||
});
|
});
|
||||||
it("aggregates EdgeTypes across plugins", () => {
|
it("aggregates EdgeTypes across plugins", () => {
|
||||||
const {sas} = example();
|
const {sas} = example();
|
||||||
const edgeTypes = sas.edgeTypes();
|
const edgeTypes = sas.edgeTypes();
|
||||||
expect(edgeTypes).toHaveLength(3);
|
const expectedNumEdgeTypes =
|
||||||
|
new FactorioStaticAdapter().edgeTypes().length +
|
||||||
|
new FallbackStaticAdapter().edgeTypes().length;
|
||||||
|
expect(edgeTypes).toHaveLength(expectedNumEdgeTypes);
|
||||||
});
|
});
|
||||||
it("finds adapter matching a node", () => {
|
it("finds adapter matching a node", () => {
|
||||||
const {x, sas} = example();
|
const {x, sas} = example();
|
||||||
const matching = sas.adapterMatchingNode(
|
const matching = sas.adapterMatchingNode(
|
||||||
NodeAddress.fromParts(["other", "foo"])
|
NodeAddress.fromParts(["factorio", "inserter"])
|
||||||
);
|
);
|
||||||
expect(matching.name()).toBe(x.name());
|
expect(matching.name()).toBe(x.name());
|
||||||
});
|
});
|
||||||
it("finds adapter matching an edge", () => {
|
it("finds adapter matching an edge", () => {
|
||||||
const {x, sas} = example();
|
const {x, sas} = example();
|
||||||
const matching = sas.adapterMatchingEdge(
|
const matching = sas.adapterMatchingEdge(
|
||||||
EdgeAddress.fromParts(["other", "foo"])
|
EdgeAddress.fromParts(["factorio", "assembles"])
|
||||||
);
|
);
|
||||||
expect(matching.name()).toBe(x.name());
|
expect(matching.name()).toBe(x.name());
|
||||||
});
|
});
|
||||||
@ -134,16 +71,16 @@ describe("app/adapters/adapterSet", () => {
|
|||||||
it("finds type matching a node", () => {
|
it("finds type matching a node", () => {
|
||||||
const {sas} = example();
|
const {sas} = example();
|
||||||
const type = sas.typeMatchingNode(
|
const type = sas.typeMatchingNode(
|
||||||
NodeAddress.fromParts(["other", "1", "foo"])
|
NodeAddress.fromParts(["factorio", "inserter", "1", "foo"])
|
||||||
);
|
);
|
||||||
expect(type.name).toBe("other1");
|
expect(type.name).toBe("inserter");
|
||||||
});
|
});
|
||||||
it("finds type matching an edge", () => {
|
it("finds type matching an edge", () => {
|
||||||
const {sas} = example();
|
const {sas} = example();
|
||||||
const type = sas.typeMatchingEdge(
|
const type = sas.typeMatchingEdge(
|
||||||
EdgeAddress.fromParts(["other", "1", "foo"])
|
EdgeAddress.fromParts(["factorio", "assembles", "other", "1", "foo"])
|
||||||
);
|
);
|
||||||
expect(type.forwardName).toBe("others_1");
|
expect(type.forwardName).toBe("assembles");
|
||||||
});
|
});
|
||||||
it("finds fallback type for unregistered node", () => {
|
it("finds fallback type for unregistered node", () => {
|
||||||
const {sas} = example();
|
const {sas} = example();
|
||||||
@ -161,6 +98,7 @@ describe("app/adapters/adapterSet", () => {
|
|||||||
});
|
});
|
||||||
it("loads a dynamicAdapterSet", async () => {
|
it("loads a dynamicAdapterSet", async () => {
|
||||||
const {x, sas} = example();
|
const {x, sas} = example();
|
||||||
|
x.loadingMock = jest.fn();
|
||||||
x.loadingMock.mockResolvedValue();
|
x.loadingMock.mockResolvedValue();
|
||||||
expect(x.loadingMock).toHaveBeenCalledTimes(0);
|
expect(x.loadingMock).toHaveBeenCalledTimes(0);
|
||||||
const assets = new Assets("/my/gateway/");
|
const assets = new Assets("/my/gateway/");
|
||||||
@ -176,9 +114,8 @@ describe("app/adapters/adapterSet", () => {
|
|||||||
|
|
||||||
describe("DynamicAdapterSet", () => {
|
describe("DynamicAdapterSet", () => {
|
||||||
async function example() {
|
async function example() {
|
||||||
const x = new TestStaticPluginAdapter();
|
const x = new FactorioStaticAdapter();
|
||||||
const sas = new StaticAdapterSet([x]);
|
const sas = new StaticAdapterSet([x]);
|
||||||
x.loadingMock.mockResolvedValue();
|
|
||||||
const das = await sas.load(
|
const das = await sas.load(
|
||||||
new Assets("/my/gateway/"),
|
new Assets("/my/gateway/"),
|
||||||
makeRepo("foo", "bar")
|
makeRepo("foo", "bar")
|
||||||
@ -203,14 +140,14 @@ describe("app/adapters/adapterSet", () => {
|
|||||||
it("finds adapter matching a node", async () => {
|
it("finds adapter matching a node", async () => {
|
||||||
const {x, das} = await example();
|
const {x, das} = await example();
|
||||||
const matching = das.adapterMatchingNode(
|
const matching = das.adapterMatchingNode(
|
||||||
NodeAddress.fromParts(["other", "foo"])
|
NodeAddress.fromParts(["factorio", "inserter"])
|
||||||
);
|
);
|
||||||
expect(matching.static().name()).toBe(x.name());
|
expect(matching.static().name()).toBe(x.name());
|
||||||
});
|
});
|
||||||
it("finds adapter matching an edge", async () => {
|
it("finds adapter matching an edge", async () => {
|
||||||
const {x, das} = await example();
|
const {x, das} = await example();
|
||||||
const matching = das.adapterMatchingEdge(
|
const matching = das.adapterMatchingEdge(
|
||||||
EdgeAddress.fromParts(["other", "foo"])
|
EdgeAddress.fromParts(["factorio", "assembles"])
|
||||||
);
|
);
|
||||||
expect(matching.static().name()).toBe(x.name());
|
expect(matching.static().name()).toBe(x.name());
|
||||||
});
|
});
|
||||||
|
129
src/app/adapters/demoAdapters.js
Normal file
129
src/app/adapters/demoAdapters.js
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import {Assets} from "../assets";
|
||||||
|
import {
|
||||||
|
Graph,
|
||||||
|
NodeAddress,
|
||||||
|
type NodeAddressT,
|
||||||
|
EdgeAddress,
|
||||||
|
} from "../../core/graph";
|
||||||
|
import type {
|
||||||
|
StaticPluginAdapter,
|
||||||
|
DynamicPluginAdapter,
|
||||||
|
EdgeType,
|
||||||
|
NodeType,
|
||||||
|
} from "./pluginAdapter";
|
||||||
|
|
||||||
|
import {StaticAdapterSet} from "./adapterSet";
|
||||||
|
import {makeRepo, type Repo} from "../../core/repo";
|
||||||
|
|
||||||
|
export const inserterNodeType: NodeType = Object.freeze({
|
||||||
|
name: "inserter",
|
||||||
|
pluralName: "inserters",
|
||||||
|
prefix: NodeAddress.fromParts(["factorio", "inserter"]),
|
||||||
|
defaultWeight: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const machineNodeType: NodeType = Object.freeze({
|
||||||
|
name: "machine",
|
||||||
|
pluralName: "machines",
|
||||||
|
prefix: NodeAddress.fromParts(["factorio", "machine"]),
|
||||||
|
defaultWeight: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const assemblesEdgeType: EdgeType = Object.freeze({
|
||||||
|
forwardName: "assembles",
|
||||||
|
backwardName: "is assembled by",
|
||||||
|
prefix: EdgeAddress.fromParts(["factorio", "assembles"]),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const transportsEdgeType: EdgeType = Object.freeze({
|
||||||
|
forwardName: "transports",
|
||||||
|
backwardName: "is transported by",
|
||||||
|
prefix: EdgeAddress.fromParts(["factorio", "transports"]),
|
||||||
|
});
|
||||||
|
|
||||||
|
export class FactorioStaticAdapter implements StaticPluginAdapter {
|
||||||
|
loadingMock: Function;
|
||||||
|
name() {
|
||||||
|
return "Factorio demo adapter";
|
||||||
|
}
|
||||||
|
nodePrefix() {
|
||||||
|
return NodeAddress.fromParts(["factorio"]);
|
||||||
|
}
|
||||||
|
nodeTypes() {
|
||||||
|
return [inserterNodeType, machineNodeType];
|
||||||
|
}
|
||||||
|
edgePrefix() {
|
||||||
|
return EdgeAddress.fromParts(["factorio"]);
|
||||||
|
}
|
||||||
|
edgeTypes() {
|
||||||
|
return [assemblesEdgeType, transportsEdgeType];
|
||||||
|
}
|
||||||
|
async load(assets: Assets, repo: Repo): Promise<DynamicPluginAdapter> {
|
||||||
|
if (this.loadingMock) {
|
||||||
|
return this.loadingMock(assets, repo).then(
|
||||||
|
() => new FactorioDynamicAdapter()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Promise.resolve(new FactorioDynamicAdapter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const factorioNodes = Object.freeze({
|
||||||
|
inserter1: NodeAddress.fromParts(["factorio", "inserter", "1"]),
|
||||||
|
machine1: NodeAddress.fromParts(["factorio", "machine", "1"]),
|
||||||
|
inserter2: NodeAddress.fromParts(["factorio", "inserter", "2"]),
|
||||||
|
machine2: NodeAddress.fromParts(["factorio", "machine", "2"]),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const factorioEdges = Object.freeze({
|
||||||
|
transports1: Object.freeze({
|
||||||
|
src: factorioNodes.inserter1,
|
||||||
|
dst: factorioNodes.machine1,
|
||||||
|
address: EdgeAddress.fromParts(["factorio", "transports", "1"]),
|
||||||
|
}),
|
||||||
|
assembles1: Object.freeze({
|
||||||
|
src: factorioNodes.machine1,
|
||||||
|
dst: factorioNodes.inserter2,
|
||||||
|
address: EdgeAddress.fromParts(["factorio", "assembles", "1"]),
|
||||||
|
}),
|
||||||
|
transports2: Object.freeze({
|
||||||
|
src: factorioNodes.inserter2,
|
||||||
|
dst: factorioNodes.machine2,
|
||||||
|
address: EdgeAddress.fromParts(["factorio", "assembles", "2"]),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
export function factorioGraph() {
|
||||||
|
return new Graph()
|
||||||
|
.addNode(factorioNodes.inserter1)
|
||||||
|
.addNode(factorioNodes.inserter2)
|
||||||
|
.addNode(factorioNodes.machine1)
|
||||||
|
.addNode(factorioNodes.machine2)
|
||||||
|
.addEdge(factorioEdges.transports1)
|
||||||
|
.addEdge(factorioEdges.transports2)
|
||||||
|
.addEdge(factorioEdges.assembles1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FactorioDynamicAdapter implements DynamicPluginAdapter {
|
||||||
|
graph() {
|
||||||
|
return factorioGraph();
|
||||||
|
}
|
||||||
|
nodeDescription(x: NodeAddressT) {
|
||||||
|
return NodeAddress.toString(x);
|
||||||
|
}
|
||||||
|
static() {
|
||||||
|
return new FactorioStaticAdapter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function staticAdapterSet() {
|
||||||
|
return new StaticAdapterSet([new FactorioStaticAdapter()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function dynamicAdapterSet() {
|
||||||
|
return await staticAdapterSet().load(
|
||||||
|
new Assets("/gateway/"),
|
||||||
|
makeRepo("foo", "bar")
|
||||||
|
);
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {shallow} from "enzyme";
|
import {shallow} from "enzyme";
|
||||||
|
|
||||||
import * as NullUtil from "../../../util/null";
|
import * as NullUtil from "../../../util/null";
|
||||||
import {NodeAddress, EdgeAddress} from "../../../core/graph";
|
import {NodeAddress, EdgeAddress} from "../../../core/graph";
|
||||||
import type {NodeType, EdgeType} from "../../adapters/pluginAdapter";
|
import type {NodeType, EdgeType} from "../../adapters/pluginAdapter";
|
||||||
@ -15,6 +16,7 @@ import {Badge} from "./shared";
|
|||||||
import {example} from "./sharedTestUtils";
|
import {example} from "./sharedTestUtils";
|
||||||
import {aggregateFlat, type FlatAggregation} from "./aggregate";
|
import {aggregateFlat, type FlatAggregation} from "./aggregate";
|
||||||
import {TableRow} from "./TableRow";
|
import {TableRow} from "./TableRow";
|
||||||
|
import {factorioNodes} from "../../adapters/demoAdapters";
|
||||||
|
|
||||||
require("../../testUtil").configureEnzyme();
|
require("../../testUtil").configureEnzyme();
|
||||||
|
|
||||||
@ -31,8 +33,8 @@ describe("app/credExplorer/pagerankTable/Aggregation", () => {
|
|||||||
});
|
});
|
||||||
describe("AggregationRowList", () => {
|
describe("AggregationRowList", () => {
|
||||||
it("instantiates AggregationRows for each aggregation", async () => {
|
it("instantiates AggregationRows for each aggregation", async () => {
|
||||||
const {adapters, pnd, nodes} = await example();
|
const {adapters, pnd} = await example();
|
||||||
const node = nodes.bar1;
|
const node = factorioNodes.inserter1;
|
||||||
const depth = 20;
|
const depth = 20;
|
||||||
const maxEntriesPerList = 50;
|
const maxEntriesPerList = 50;
|
||||||
const sharedProps = {adapters, pnd, maxEntriesPerList};
|
const sharedProps = {adapters, pnd, maxEntriesPerList};
|
||||||
@ -66,9 +68,9 @@ describe("app/credExplorer/pagerankTable/Aggregation", () => {
|
|||||||
|
|
||||||
describe("AggregationRow", () => {
|
describe("AggregationRow", () => {
|
||||||
async function setup() {
|
async function setup() {
|
||||||
const {pnd, adapters, nodes} = await example();
|
const {pnd, adapters} = await example();
|
||||||
const sharedProps = {adapters, pnd, maxEntriesPerList: 123};
|
const sharedProps = {adapters, pnd, maxEntriesPerList: 123};
|
||||||
const target = nodes.bar1;
|
const target = factorioNodes.inserter1;
|
||||||
const {scoredConnections} = NullUtil.get(pnd.get(target));
|
const {scoredConnections} = NullUtil.get(pnd.get(target));
|
||||||
const aggregations = aggregateFlat(
|
const aggregations = aggregateFlat(
|
||||||
scoredConnections,
|
scoredConnections,
|
||||||
|
@ -9,6 +9,7 @@ import {ConnectionRowList, ConnectionRow, ConnectionView} from "./Connection";
|
|||||||
import {example} from "./sharedTestUtils";
|
import {example} from "./sharedTestUtils";
|
||||||
import {TableRow} from "./TableRow";
|
import {TableRow} from "./TableRow";
|
||||||
import {NodeRow} from "./Node";
|
import {NodeRow} from "./Node";
|
||||||
|
import {factorioNodes} from "../../adapters/demoAdapters";
|
||||||
|
|
||||||
require("../../testUtil").configureEnzyme();
|
require("../../testUtil").configureEnzyme();
|
||||||
|
|
||||||
@ -26,9 +27,9 @@ describe("app/credExplorer/pagerankTable/Connection", () => {
|
|||||||
|
|
||||||
describe("ConnectionRowList", () => {
|
describe("ConnectionRowList", () => {
|
||||||
async function setup(maxEntriesPerList: number = 100000) {
|
async function setup(maxEntriesPerList: number = 100000) {
|
||||||
const {adapters, pnd, nodes} = await example();
|
const {adapters, pnd} = await example();
|
||||||
const depth = 2;
|
const depth = 2;
|
||||||
const node = nodes.bar1;
|
const node = factorioNodes.inserter1;
|
||||||
const sharedProps = {adapters, pnd, maxEntriesPerList};
|
const sharedProps = {adapters, pnd, maxEntriesPerList};
|
||||||
const connections = NullUtil.get(sharedProps.pnd.get(node))
|
const connections = NullUtil.get(sharedProps.pnd.get(node))
|
||||||
.scoredConnections;
|
.scoredConnections;
|
||||||
@ -76,15 +77,11 @@ describe("app/credExplorer/pagerankTable/Connection", () => {
|
|||||||
|
|
||||||
describe("ConnectionRow", () => {
|
describe("ConnectionRow", () => {
|
||||||
async function setup() {
|
async function setup() {
|
||||||
const {pnd, adapters, nodes} = await example();
|
const {pnd, adapters} = await example();
|
||||||
const sharedProps = {adapters, pnd, maxEntriesPerList: 123};
|
const sharedProps = {adapters, pnd, maxEntriesPerList: 123};
|
||||||
const target = nodes.bar1;
|
const target = factorioNodes.inserter1;
|
||||||
const {scoredConnections} = NullUtil.get(pnd.get(target));
|
const {scoredConnections} = NullUtil.get(pnd.get(target));
|
||||||
const alphaConnections = scoredConnections.filter(
|
const scoredConnection = scoredConnections[0];
|
||||||
(sc) => sc.source === nodes.fooAlpha
|
|
||||||
);
|
|
||||||
expect(alphaConnections).toHaveLength(1);
|
|
||||||
const scoredConnection = alphaConnections[0];
|
|
||||||
const depth = 2;
|
const depth = 2;
|
||||||
const component = (
|
const component = (
|
||||||
<ConnectionRow
|
<ConnectionRow
|
||||||
@ -160,8 +157,8 @@ describe("app/credExplorer/pagerankTable/Connection", () => {
|
|||||||
});
|
});
|
||||||
describe("ConnectionView", () => {
|
describe("ConnectionView", () => {
|
||||||
async function setup() {
|
async function setup() {
|
||||||
const {pnd, adapters, nodes} = await example();
|
const {pnd, adapters} = await example();
|
||||||
const {scoredConnections} = NullUtil.get(pnd.get(nodes.bar1));
|
const {scoredConnections} = NullUtil.get(pnd.get(factorioNodes.machine1));
|
||||||
const connections = scoredConnections.map((sc) => sc.connection);
|
const connections = scoredConnections.map((sc) => sc.connection);
|
||||||
function connectionByType(t) {
|
function connectionByType(t) {
|
||||||
return NullUtil.get(
|
return NullUtil.get(
|
||||||
@ -208,8 +205,10 @@ describe("app/credExplorer/pagerankTable/Connection", () => {
|
|||||||
const outerSpan = view.find("span").first();
|
const outerSpan = view.find("span").first();
|
||||||
const badge = outerSpan.find("Badge");
|
const badge = outerSpan.find("Badge");
|
||||||
const description = outerSpan.children().find("span");
|
const description = outerSpan.children().find("span");
|
||||||
expect(badge.children().text()).toEqual("is barred by");
|
expect(badge.children().text()).toEqual("is transported by");
|
||||||
expect(description.text()).toEqual('bar: NodeAddress["bar","a","1"]');
|
expect(description.text()).toEqual(
|
||||||
|
'NodeAddress["factorio","inserter","1"]'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it("for outward connections, renders a `Badge` and description", async () => {
|
it("for outward connections, renders a `Badge` and description", async () => {
|
||||||
const {cvForConnection, outConnection} = await setup();
|
const {cvForConnection, outConnection} = await setup();
|
||||||
@ -217,8 +216,10 @@ describe("app/credExplorer/pagerankTable/Connection", () => {
|
|||||||
const outerSpan = view.find("span").first();
|
const outerSpan = view.find("span").first();
|
||||||
const badge = outerSpan.find("Badge");
|
const badge = outerSpan.find("Badge");
|
||||||
const description = outerSpan.children().find("span");
|
const description = outerSpan.children().find("span");
|
||||||
expect(badge.children().text()).toEqual("bars");
|
expect(badge.children().text()).toEqual("assembles");
|
||||||
expect(description.text()).toEqual("xox node!");
|
expect(description.text()).toEqual(
|
||||||
|
'NodeAddress["factorio","inserter","2"]'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it("for synthetic connections, renders only a `Badge`", async () => {
|
it("for synthetic connections, renders only a `Badge`", async () => {
|
||||||
const {cvForConnection, syntheticConnection} = await setup();
|
const {cvForConnection, syntheticConnection} = await setup();
|
||||||
|
@ -7,11 +7,12 @@ import * as NullUtil from "../../../util/null";
|
|||||||
import {TableRow} from "./TableRow";
|
import {TableRow} from "./TableRow";
|
||||||
import {AggregationRowList} from "./Aggregation";
|
import {AggregationRowList} from "./Aggregation";
|
||||||
|
|
||||||
import {type NodeAddressT, NodeAddress} from "../../../core/graph";
|
import type {NodeAddressT} from "../../../core/graph";
|
||||||
|
|
||||||
import {nodeDescription} from "./shared";
|
import {nodeDescription} from "./shared";
|
||||||
import {example} from "./sharedTestUtils";
|
import {example} from "./sharedTestUtils";
|
||||||
import {NodeRowList, NodeRow, type NodeRowProps} from "./Node";
|
import {NodeRowList, NodeRow, type NodeRowProps} from "./Node";
|
||||||
|
import {factorioNodes} from "../../adapters/demoAdapters";
|
||||||
|
|
||||||
require("../../testUtil").configureEnzyme();
|
require("../../testUtil").configureEnzyme();
|
||||||
|
|
||||||
@ -32,14 +33,8 @@ describe("app/credExplorer/pagerankTable/Node", () => {
|
|||||||
}
|
}
|
||||||
async function setup(maxEntriesPerList: number = 100000) {
|
async function setup(maxEntriesPerList: number = 100000) {
|
||||||
const {adapters, pnd} = await example();
|
const {adapters, pnd} = await example();
|
||||||
const nodes = sortedByScore(Array.from(pnd.keys()), pnd)
|
const nodes = Array.from(pnd.keys());
|
||||||
.reverse() // ascending order!
|
|
||||||
.filter((x) =>
|
|
||||||
NodeAddress.hasPrefix(x, NodeAddress.fromParts(["foo"]))
|
|
||||||
);
|
|
||||||
expect(nodes).not.toHaveLength(0);
|
expect(nodes).not.toHaveLength(0);
|
||||||
expect(nodes).not.toHaveLength(1);
|
|
||||||
expect(nodes).not.toHaveLength(pnd.size);
|
|
||||||
const sharedProps = {adapters, pnd, maxEntriesPerList};
|
const sharedProps = {adapters, pnd, maxEntriesPerList};
|
||||||
const component = <NodeRowList sharedProps={sharedProps} nodes={nodes} />;
|
const component = <NodeRowList sharedProps={sharedProps} nodes={nodes} />;
|
||||||
const element = shallow(component);
|
const element = shallow(component);
|
||||||
@ -86,9 +81,9 @@ describe("app/credExplorer/pagerankTable/Node", () => {
|
|||||||
describe("NodeRow", () => {
|
describe("NodeRow", () => {
|
||||||
async function setup(props: $Shape<{...NodeRowProps}>) {
|
async function setup(props: $Shape<{...NodeRowProps}>) {
|
||||||
props = props || {};
|
props = props || {};
|
||||||
const {pnd, adapters, nodes} = await example();
|
const {pnd, adapters} = await example();
|
||||||
const sharedProps = {adapters, pnd, maxEntriesPerList: 123};
|
const sharedProps = {adapters, pnd, maxEntriesPerList: 123};
|
||||||
const node = nodes.bar1;
|
const node = factorioNodes.inserter1;
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<NodeRow
|
<NodeRow
|
||||||
node={NullUtil.orElse(props.node, node)}
|
node={NullUtil.orElse(props.node, node)}
|
||||||
|
@ -70,8 +70,9 @@ describe("app/credExplorer/pagerankTable/Table", () => {
|
|||||||
});
|
});
|
||||||
it("with the ability to filter nodes passed to NodeRowList", async () => {
|
it("with the ability to filter nodes passed to NodeRowList", async () => {
|
||||||
const {element, options} = await setup();
|
const {element, options} = await setup();
|
||||||
const option1 = options.at(1);
|
const option = options.at(2);
|
||||||
const value = option1.prop("value");
|
|
||||||
|
const value = option.prop("value");
|
||||||
expect(value).not.toEqual(NodeAddress.empty);
|
expect(value).not.toEqual(NodeAddress.empty);
|
||||||
const previousNodes = element.find("NodeRowList").prop("nodes");
|
const previousNodes = element.find("NodeRowList").prop("nodes");
|
||||||
expect(
|
expect(
|
||||||
@ -89,7 +90,7 @@ describe("app/credExplorer/pagerankTable/Table", () => {
|
|||||||
expect(element.state().topLevelFilter).toEqual(NodeAddress.empty);
|
expect(element.state().topLevelFilter).toEqual(NodeAddress.empty);
|
||||||
});
|
});
|
||||||
it("filter defaults to defaultNodeFilter if available", async () => {
|
it("filter defaults to defaultNodeFilter if available", async () => {
|
||||||
const filter = NodeAddress.fromParts(["foo", "a"]);
|
const filter = NodeAddress.fromParts(["factorio", "inserter"]);
|
||||||
const {element} = await setup(filter);
|
const {element} = await setup(filter);
|
||||||
expect(element.state().topLevelFilter).toEqual(filter);
|
expect(element.state().topLevelFilter).toEqual(filter);
|
||||||
});
|
});
|
||||||
|
@ -13,44 +13,18 @@ Array [
|
|||||||
"style": Object {
|
"style": Object {
|
||||||
"fontWeight": "bold",
|
"fontWeight": "bold",
|
||||||
},
|
},
|
||||||
"text": "bar",
|
"text": "Factorio demo adapter",
|
||||||
"valueString": "NodeAddress[\\"bar\\"]",
|
"valueString": "NodeAddress[\\"factorio\\"]",
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"style": undefined,
|
"style": undefined,
|
||||||
"text": " alpha",
|
"text": " inserter",
|
||||||
"valueString": "NodeAddress[\\"bar\\",\\"a\\"]",
|
"valueString": "NodeAddress[\\"factorio\\",\\"inserter\\"]",
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"style": Object {
|
|
||||||
"fontWeight": "bold",
|
|
||||||
},
|
|
||||||
"text": "foo",
|
|
||||||
"valueString": "NodeAddress[\\"foo\\"]",
|
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"style": undefined,
|
"style": undefined,
|
||||||
"text": " alpha",
|
"text": " machine",
|
||||||
"valueString": "NodeAddress[\\"foo\\",\\"a\\"]",
|
"valueString": "NodeAddress[\\"factorio\\",\\"machine\\"]",
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"style": undefined,
|
|
||||||
"text": " beta",
|
|
||||||
"valueString": "NodeAddress[\\"foo\\",\\"b\\"]",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"style": Object {
|
|
||||||
"fontWeight": "bold",
|
|
||||||
},
|
|
||||||
"text": "unused",
|
|
||||||
"valueString": "NodeAddress[\\"unused\\"]",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"style": Object {
|
|
||||||
"fontWeight": "bold",
|
|
||||||
},
|
|
||||||
"text": "xox",
|
|
||||||
"valueString": "NodeAddress[\\"xox\\"]",
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
@ -11,6 +11,9 @@ import {
|
|||||||
} from "./aggregate";
|
} from "./aggregate";
|
||||||
|
|
||||||
describe("app/credExplorer/aggregate", () => {
|
describe("app/credExplorer/aggregate", () => {
|
||||||
|
// TODO: If making major modifications to these tests, consider switching
|
||||||
|
// from the hand-maintained connections and types, and instead use the demo
|
||||||
|
// adadpters from app/adapters/demoAdapters
|
||||||
function example() {
|
function example() {
|
||||||
const nodes = {
|
const nodes = {
|
||||||
root: NodeAddress.fromParts(["root"]),
|
root: NodeAddress.fromParts(["root"]),
|
||||||
|
@ -1,151 +1,17 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import {Graph, NodeAddress, EdgeAddress} from "../../../core/graph";
|
import {dynamicAdapterSet} from "../../adapters/demoAdapters";
|
||||||
|
|
||||||
import {StaticAdapterSet, DynamicAdapterSet} from "../../adapters/adapterSet";
|
|
||||||
import type {DynamicPluginAdapter} from "../../adapters/pluginAdapter";
|
|
||||||
import {pagerank} from "../../../core/attribution/pagerank";
|
import {pagerank} from "../../../core/attribution/pagerank";
|
||||||
|
|
||||||
export const COLUMNS = () => ["Description", "", "Cred"];
|
export const COLUMNS = () => ["Description", "", "Cred"];
|
||||||
|
|
||||||
export async function example() {
|
export async function example() {
|
||||||
const graph = new Graph();
|
const adapters = await dynamicAdapterSet();
|
||||||
const nodes = {
|
const graph = adapters.graph();
|
||||||
fooAlpha: NodeAddress.fromParts(["foo", "a", "1"]),
|
|
||||||
fooBeta: NodeAddress.fromParts(["foo", "b", "2"]),
|
|
||||||
bar1: NodeAddress.fromParts(["bar", "a", "1"]),
|
|
||||||
bar2: NodeAddress.fromParts(["bar", "2"]),
|
|
||||||
xox: NodeAddress.fromParts(["xox"]),
|
|
||||||
empty: NodeAddress.empty,
|
|
||||||
};
|
|
||||||
Object.values(nodes).forEach((n) => graph.addNode((n: any)));
|
|
||||||
|
|
||||||
function addEdge(parts, src, dst) {
|
|
||||||
const edge = {address: EdgeAddress.fromParts(parts), src, dst};
|
|
||||||
graph.addEdge(edge);
|
|
||||||
return edge;
|
|
||||||
}
|
|
||||||
|
|
||||||
const edges = {
|
|
||||||
fooA: addEdge(["foo", "a"], nodes.fooAlpha, nodes.fooBeta),
|
|
||||||
fooB: addEdge(["foo", "b"], nodes.fooAlpha, nodes.bar1),
|
|
||||||
fooC: addEdge(["foo", "c"], nodes.fooAlpha, nodes.xox),
|
|
||||||
barD: addEdge(["bar", "d"], nodes.bar1, nodes.bar1),
|
|
||||||
barE: addEdge(["bar", "e"], nodes.bar1, nodes.xox),
|
|
||||||
barF: addEdge(["bar", "f"], nodes.bar1, nodes.xox),
|
|
||||||
};
|
|
||||||
|
|
||||||
const dynamicAdapters: DynamicPluginAdapter[] = [
|
|
||||||
{
|
|
||||||
static: () => ({
|
|
||||||
name: () => "foo",
|
|
||||||
nodePrefix: () => NodeAddress.fromParts(["foo"]),
|
|
||||||
edgePrefix: () => EdgeAddress.fromParts(["foo"]),
|
|
||||||
nodeTypes: () => [
|
|
||||||
{
|
|
||||||
pluralName: "alphas",
|
|
||||||
name: "alpha",
|
|
||||||
prefix: NodeAddress.fromParts(["foo", "a"]),
|
|
||||||
defaultWeight: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pluralName: "betas",
|
|
||||||
name: "beta",
|
|
||||||
prefix: NodeAddress.fromParts(["foo", "b"]),
|
|
||||||
defaultWeight: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
edgeTypes: () => [
|
|
||||||
{
|
|
||||||
prefix: EdgeAddress.fromParts(["foo"]),
|
|
||||||
forwardName: "foos",
|
|
||||||
backwardName: "is fooed by",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
load: (_unused_repo) => {
|
|
||||||
throw new Error("unused");
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
graph: () => {
|
|
||||||
throw new Error("unused");
|
|
||||||
},
|
|
||||||
nodeDescription: (x) => `foo: ${NodeAddress.toString(x)}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
static: () => ({
|
|
||||||
name: () => "bar",
|
|
||||||
nodePrefix: () => NodeAddress.fromParts(["bar"]),
|
|
||||||
edgePrefix: () => EdgeAddress.fromParts(["bar"]),
|
|
||||||
nodeTypes: () => [
|
|
||||||
{
|
|
||||||
name: "alpha",
|
|
||||||
pluralName: "alphas",
|
|
||||||
prefix: NodeAddress.fromParts(["bar", "a"]),
|
|
||||||
defaultWeight: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
edgeTypes: () => [
|
|
||||||
{
|
|
||||||
prefix: EdgeAddress.fromParts(["bar"]),
|
|
||||||
forwardName: "bars",
|
|
||||||
backwardName: "is barred by",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
load: (_unused_repo) => {
|
|
||||||
throw new Error("unused");
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
graph: () => {
|
|
||||||
throw new Error("unused");
|
|
||||||
},
|
|
||||||
nodeDescription: (x) => `bar: ${NodeAddress.toString(x)}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
static: () => ({
|
|
||||||
name: () => "xox",
|
|
||||||
nodePrefix: () => NodeAddress.fromParts(["xox"]),
|
|
||||||
edgePrefix: () => EdgeAddress.fromParts(["xox"]),
|
|
||||||
nodeTypes: () => [],
|
|
||||||
edgeTypes: () => [],
|
|
||||||
load: (_unused_repo) => {
|
|
||||||
throw new Error("unused");
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
graph: () => {
|
|
||||||
throw new Error("unused");
|
|
||||||
},
|
|
||||||
nodeDescription: (_unused_arg) => `xox node!`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
static: () => ({
|
|
||||||
nodePrefix: () => NodeAddress.fromParts(["unused"]),
|
|
||||||
edgePrefix: () => EdgeAddress.fromParts(["unused"]),
|
|
||||||
nodeTypes: () => [],
|
|
||||||
edgeTypes: () => [],
|
|
||||||
name: () => "unused",
|
|
||||||
load: (_unused_repo) => {
|
|
||||||
throw new Error("unused");
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
graph: () => {
|
|
||||||
throw new Error("unused");
|
|
||||||
},
|
|
||||||
nodeDescription: () => {
|
|
||||||
throw new Error("Unused");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const staticAdapters = dynamicAdapters.map((x) => x.static());
|
|
||||||
const adapters = new DynamicAdapterSet(
|
|
||||||
new StaticAdapterSet(staticAdapters),
|
|
||||||
dynamicAdapters
|
|
||||||
);
|
|
||||||
|
|
||||||
const pnd = await pagerank(graph, (_unused_Edge) => ({
|
const pnd = await pagerank(graph, (_unused_Edge) => ({
|
||||||
toWeight: 1,
|
toWeight: 1,
|
||||||
froWeight: 1,
|
froWeight: 1,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return {adapters, nodes, edges, graph, pnd};
|
return {adapters, pnd};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user