diff --git a/src/v3/core/_address.js b/src/v3/core/_address.js index fc5913f..e69864c 100644 --- a/src/v3/core/_address.js +++ b/src/v3/core/_address.js @@ -86,14 +86,18 @@ export function assertAddressArray(arr: $ReadOnlyArray) { }); } +function nullDelimited(components: $ReadOnlyArray): string { + return [...components, ""].join(SEPARATOR); +} + export function nodeAddress(arr: $ReadOnlyArray): NodeAddress { assertAddressArray(arr); - return [NODE_PREFIX, ...arr, ""].join(SEPARATOR); + return NODE_PREFIX + SEPARATOR + nullDelimited(arr); } export function edgeAddress(arr: $ReadOnlyArray): EdgeAddress { assertAddressArray(arr); - return [EDGE_PREFIX, ...arr, ""].join(SEPARATOR); + return EDGE_PREFIX + SEPARATOR + nullDelimited(arr); } export function toParts(a: GenericAddress): string[] { @@ -101,3 +105,21 @@ export function toParts(a: GenericAddress): string[] { const parts = a.split(SEPARATOR); return parts.slice(1, parts.length - 1); } + +export function nodeAppend( + base: NodeAddress, + ...components: string[] +): NodeAddress { + assertNodeAddress(base); + assertAddressArray(components); + return base + nullDelimited(components); +} + +export function edgeAppend( + base: EdgeAddress, + ...components: string[] +): EdgeAddress { + assertEdgeAddress(base); + assertAddressArray(components); + return base + nullDelimited(components); +} diff --git a/src/v3/core/_address.test.js b/src/v3/core/_address.test.js index bd38890..f8b2e26 100644 --- a/src/v3/core/_address.test.js +++ b/src/v3/core/_address.test.js @@ -1,10 +1,13 @@ // @flow +import type {NodeAddress, EdgeAddress} from "./_address"; import { assertNodeAddress, assertEdgeAddress, - nodeAddress, edgeAddress, + edgeAppend, + nodeAddress, + nodeAppend, toParts, } from "./_address"; @@ -79,6 +82,68 @@ describe("core/address", () => { }); }); + function checkAppend< + Good: NodeAddress | EdgeAddress, + Bad: NodeAddress | EdgeAddress + >( + f: (Good, ...string[]) => Good, + goodConstructor: (string[]) => Good, + badConstructor: (string[]) => Bad + ) { + describe(f.name, () => { + describe("errors on", () => { + [null, undefined].forEach((bad) => { + it(`${String(bad)} base input`, () => { + // $ExpectFlowError + expect(() => f(bad, "foo")).toThrow(String(bad)); + }); + it(`${String(bad)} component`, () => { + // $ExpectFlowError + expect(() => f(goodConstructor(["foo"]), bad)).toThrow(String(bad)); + }); + }); + it("malformed base", () => { + // $ExpectFlowError + expect(() => f("foo", "foo")).toThrow("Bad address"); + }); + it("base of wrong kind", () => { + // $ExpectFlowError + expect(() => f(badConstructor(["foo"]), "foo")).toThrow( + /Expected.*Address/ + ); + }); + it("invalid component", () => { + expect(() => f(goodConstructor(["foo"]), "foo\0oo")); + }); + }); + + describe("works on", () => { + function check( + description: string, + baseComponents: string[], + ...components: string[] + ) { + test(description, () => { + const base = goodConstructor(baseComponents); + const expectedParts = [...baseComponents, ...components]; + expect(toParts(f(base, ...components))).toEqual(expectedParts); + }); + } + check("the base address with no extra component", []); + check("the base address with empty component", [], ""); + check("the base address with nonempty component", [], "a"); + check("the base address with lots of components", [], "a", "b"); + + check("a longer address with no extra component", ["a", ""]); + check("a longer address with empty component", ["a", ""], ""); + check("a longer address with nonempty component", ["a", ""], "b"); + check("a longer address with lots of components", ["a", ""], "b", "c"); + }); + }); + } + checkAppend(nodeAppend, nodeAddress, edgeAddress); + checkAppend(edgeAppend, edgeAddress, nodeAddress); + describe("type assertions", () => { function checkAssertion(f, good, bad, badMsg) { describe(f.name, () => {