Add `toString` functions for addresses and edges (#347)

Summary:
If you just print out an address, depending on output context the NUL
separators may just disappear, which is really bad. Using `stringify` is
better, but causes these characters to appear as `\u0000`, which is not
very pretty.

This commit adds pretty-printing functions that clearly display the
addresses. A node address is printed as:

    nodeAddress(["array","of","parts"])

An edge address is printed as:

    edgeAddress(["array","of","parts"])

An edge in the graph is printed as:

    {address: edgeAddress(["one"]), src: nodeAddress(["two"]), dst: nodeAddress(["three"])}

Note that each of these is a valid JavaScript expression that evaluates
to the argument that was originally converted to string.

Paired with @decentralion.

Test Plan:
Unit tests added. Run `yarn travis`.

wchargin-branch: node-edge-tostring
This commit is contained in:
William Chargin 2018-06-05 13:05:03 -07:00 committed by GitHub
parent 4705bec20d
commit 051ca7034d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 1 deletions

View File

@ -130,3 +130,15 @@ export function edgeAppend(
assertAddressArray(components);
return base + nullDelimited(components);
}
export function nodeToString(a: NodeAddress): string {
assertNodeAddress(a);
const parts = toParts(a);
return `nodeAddress(${stringify(parts)})`;
}
export function edgeToString(a: EdgeAddress): string {
assertEdgeAddress(a);
const parts = toParts(a);
return `edgeAddress(${stringify(parts)})`;
}

View File

@ -6,8 +6,10 @@ import {
assertEdgeAddress,
edgeAddress,
edgeAppend,
edgeToString,
nodeAddress,
nodeAppend,
nodeToString,
toParts,
} from "./_address";
@ -144,6 +146,42 @@ describe("core/address", () => {
checkAppend(nodeAppend, nodeAddress, edgeAddress);
checkAppend(edgeAppend, edgeAddress, nodeAddress);
function checkToString<
Good: NodeAddress | EdgeAddress,
Bad: NodeAddress | EdgeAddress
>(
f: (Good) => string,
kind: "NodeAddress" | "EdgeAddress",
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)).toThrow(String(bad));
});
});
it("wrong kind", () => {
// $ExpectFlowError
expect(() => f(badConstructor(["foo"]))).toThrow(`expected ${kind}`);
});
});
describe("works on", () => {
const camelKind = kind.charAt(0).toLowerCase() + kind.substring(1);
expect(f(goodConstructor([]))).toEqual(`${camelKind}([])`);
expect(f(goodConstructor([""]))).toEqual(`${camelKind}([""])`);
expect(f(goodConstructor(["one", "", "two"]))).toEqual(
`${camelKind}(["one","","two"])`
);
});
});
}
checkToString(nodeToString, "NodeAddress", nodeAddress, edgeAddress);
checkToString(edgeToString, "EdgeAddress", edgeAddress, nodeAddress);
describe("type assertions", () => {
function checkAssertion(f, good, bad, badMsg) {
describe(f.name, () => {

View File

@ -110,3 +110,10 @@ export class Graph {
throw new Error("merge");
}
}
export function edgeToString(edge: Edge): string {
const address = Address.edgeToString(edge.address);
const src = Address.nodeToString(edge.src);
const dst = Address.nodeToString(edge.dst);
return `{address: ${address}, src: ${src}, dst: ${dst}}`;
}

View File

@ -1,6 +1,6 @@
// @flow
import {Address, Graph} from "./graph";
import {Address, Graph, edgeToString} from "./graph";
import type {NodeAddress, EdgeAddress} from "./graph";
describe("core/graph", () => {
@ -105,4 +105,21 @@ describe("core/graph", () => {
});
});
});
describe("edgeToString", () => {
it("works", () => {
const edge = {
address: Address.edgeAddress(["one", "two"]),
dst: Address.nodeAddress(["five", "six"]),
src: Address.nodeAddress(["three", "four"]),
};
const expected =
"{" +
'address: edgeAddress(["one","two"]), ' +
'src: nodeAddress(["three","four"]), ' +
'dst: nodeAddress(["five","six"])' +
"}";
expect(edgeToString(edge)).toEqual(expected);
});
});
});