Add top-level address module error handling (#356)

Summary:
This commit implements all the code needed for the top-level
`makeAddressModule` function, without implementing any of the address
functions. This mostly comprises handling of errors in the module
options.

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

wchargin-branch: address-error-handling
This commit is contained in:
William Chargin 2018-06-07 09:10:11 -07:00 committed by GitHub
parent fc7e8886b1
commit c1a5e01a2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 1 deletions

View File

@ -1,5 +1,7 @@
// @flow
import stringify from "json-stable-stringify";
export interface AddressModule<Address> {
/**
* Assert at runtime that the provided address is actually a valid
@ -89,7 +91,31 @@ export type Options = {|
export function makeAddressModule(options: Options): AddressModule<string> {
type Address = string; // for readability and interface consistency
const _ = options;
const {name, nonce} = options;
const otherNonces = new Map(options.otherNonces || new Map());
const separator = "\0";
if (nonce.indexOf(separator) !== -1) {
throw new Error(`invalid nonce (contains NUL): ${stringify(nonce)}`);
}
const nonceWithSeparator = nonce + separator;
const otherNoncesWithSeparators = new Map();
for (const [otherNonce, otherName] of otherNonces.entries()) {
if (otherNonce === nonce) {
throw new Error(
`primary nonce listed as otherNonce: ${stringify(nonce)}`
);
}
if (otherNonce.indexOf(separator) !== -1) {
throw new Error(
`invalid otherNonce (contains NUL): ${stringify(otherNonce)}`
);
}
otherNoncesWithSeparators.set(otherNonce + separator, otherName);
}
const _ = {name, nonceWithSeparator};
function assertValid(address: Address, what?: string): void {
const _ = {address, what};

View File

@ -28,6 +28,29 @@ describe("core/address", () => {
it("makes address modules using all the options", () => {
makeModules();
});
it("rejects a module whose nonce contains NUL", () => {
expect(() => {
makeAddressModule({name: "BadAddress", nonce: "n\0o"});
}).toThrow("invalid nonce (contains NUL):");
});
it("rejects a module with `otherNonces` containing NUL", () => {
expect(() => {
makeAddressModule({
name: "GoodAddress",
nonce: "G",
otherNonces: new Map().set("n\0o", "BadAddress"),
});
}).toThrow("invalid otherNonce (contains NUL):");
});
it("rejects a module with `nonce` in `otherNonces`", () => {
expect(() => {
makeAddressModule({
name: "GoodAddress",
nonce: "G",
otherNonces: new Map().set("G", "WatAddress"),
});
}).toThrow("primary nonce listed as otherNonce");
});
it("returns an object with read-only properties", () => {
const {FooAddress} = makeModules();
expect(() => {