mirror of
https://github.com/status-im/sourcecred.git
synced 2025-01-14 14:46:30 +00:00
Use a Symbol
for DelegateNodeReference base ref (#313)
Summary: It’s critical, even more so than usual, that the “base reference” property of a `DelegateNodeReference` be a private property, because this class is designed for inheritance. In ECMAScript 6, we can achieve this by giving the property a `Symbol` key instead of a string key. Unfortunately, Flow doesn’t know about `Symbol`s, so we need a few casts through `any`, but they are localized to as small a scope as possible. Test Plan: Unit tests added. Note that they pass both before and after this change. wchargin-branch: symbol-base-ref
This commit is contained in:
parent
6663c4f8ad
commit
87b7df5957
@ -276,23 +276,28 @@ function findHandler(pluginMap: PluginMap, pluginName: string) {
|
||||
return pluginMap[pluginName];
|
||||
}
|
||||
|
||||
const DELEGATE_NODE_REFERENCE_BASE = Symbol("base");
|
||||
function getBase(dnr: DelegateNodeReference): NodeReference {
|
||||
// Flow doesn't know about Symbols, so we use this function to
|
||||
// localize the `any`-casts as much as possible.
|
||||
return (dnr: any)[DELEGATE_NODE_REFERENCE_BASE];
|
||||
}
|
||||
|
||||
export class DelegateNodeReference implements NodeReference {
|
||||
// TODO(@wchargin): Use a Symbol here.
|
||||
__DelegateNodeReference_base: NodeReference;
|
||||
constructor(base: NodeReference) {
|
||||
this.__DelegateNodeReference_base = base;
|
||||
(this: any)[DELEGATE_NODE_REFERENCE_BASE] = base;
|
||||
}
|
||||
graph() {
|
||||
return this.__DelegateNodeReference_base.graph();
|
||||
return getBase(this).graph();
|
||||
}
|
||||
address() {
|
||||
return this.__DelegateNodeReference_base.address();
|
||||
return getBase(this).address();
|
||||
}
|
||||
get() {
|
||||
return this.__DelegateNodeReference_base.get();
|
||||
return getBase(this).get();
|
||||
}
|
||||
neighbors(options?: NeighborsOptions) {
|
||||
return this.__DelegateNodeReference_base.neighbors(options);
|
||||
return getBase(this).neighbors(options);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ import stringify from "json-stable-stringify";
|
||||
import sortBy from "lodash.sortby";
|
||||
|
||||
import type {Node} from "./graph";
|
||||
import {Graph} from "./graph";
|
||||
import {DelegateNodeReference, Graph} from "./graph";
|
||||
|
||||
import {
|
||||
FooPayload,
|
||||
@ -213,3 +213,59 @@ describe("graph", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("DelegateNodeReference", () => {
|
||||
const makeBase = () => ({
|
||||
graph: jest.fn(),
|
||||
address: jest.fn(),
|
||||
get: jest.fn(),
|
||||
neighbors: jest.fn(),
|
||||
});
|
||||
|
||||
it("has a working constructor", () => {
|
||||
expect(new DelegateNodeReference(makeBase())).toBeInstanceOf(
|
||||
DelegateNodeReference
|
||||
);
|
||||
});
|
||||
|
||||
it("delegates `graph`", () => {
|
||||
const expected = new Graph([]);
|
||||
const ref = {
|
||||
...makeBase(),
|
||||
graph: jest.fn().mockReturnValueOnce(expected),
|
||||
};
|
||||
expect(new DelegateNodeReference(ref).graph()).toBe(expected);
|
||||
expect(ref.graph.mock.calls).toEqual([[]]);
|
||||
});
|
||||
|
||||
it("delegates `address`", () => {
|
||||
const expected = {owner: {plugin: "foo", type: "bar"}, id: "baz"};
|
||||
const ref = {
|
||||
...makeBase(),
|
||||
address: jest.fn().mockReturnValueOnce(expected),
|
||||
};
|
||||
expect(new DelegateNodeReference(ref).address()).toBe(expected);
|
||||
expect(ref.address.mock.calls).toEqual([[]]);
|
||||
});
|
||||
|
||||
it("delegates `get`", () => {
|
||||
const expected = {some: "node"};
|
||||
const ref = {
|
||||
...makeBase(),
|
||||
get: jest.fn().mockReturnValueOnce((expected: any)),
|
||||
};
|
||||
expect(new DelegateNodeReference(ref).get()).toBe(expected);
|
||||
expect(ref.get.mock.calls).toEqual([[]]);
|
||||
});
|
||||
|
||||
it("delegates `neighbors`, with proper options", () => {
|
||||
const options = {direction: "OUT", node: {plugin: "foo", type: "bar"}};
|
||||
const ref = {
|
||||
...makeBase(),
|
||||
neighbors: jest.fn().mockImplementationOnce((...args) => (args: any)),
|
||||
};
|
||||
const result = new DelegateNodeReference(ref).neighbors(options);
|
||||
expect(result).toEqual([options]);
|
||||
expect(ref.neighbors.mock.calls).toEqual([[options]]);
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user