fix(contracts): Catch cases where the actual error differs from the expected error (#1032)

* Catch cases where the actual error differs from the expected error

* Add tests for testWithReferenceFuncAsync

* Small style and comment fixes
This commit is contained in:
Alex Browne
2018-08-27 16:07:38 -07:00
committed by GitHub
parent fb5ea5d99f
commit 2eab0e30b7
2 changed files with 109 additions and 26 deletions

View File

@@ -6,6 +6,34 @@ import { chaiSetup } from './chai_setup';
chaiSetup.configure();
const expect = chai.expect;
class Value<T> {
public value: T;
constructor(value: T) {
this.value = value;
}
}
// tslint:disable-next-line: max-classes-per-file
class ErrorMessage {
public error: string;
constructor(message: string) {
this.error = message;
}
}
type PromiseResult<T> = Value<T> | ErrorMessage;
// TODO(albrow): This seems like a generic utility function that could exist in
// lodash. We should replace it by a library implementation, or move it to our
// own.
async function evaluatePromise<T>(promise: Promise<T>): Promise<PromiseResult<T>> {
try {
return new Value<T>(await promise);
} catch (e) {
return new ErrorMessage(e.message);
}
}
export async function testWithReferenceFuncAsync<P0, R>(
referenceFunc: (p0: P0) => Promise<R>,
testFunc: (p0: P0) => Promise<R>,
@@ -64,39 +92,31 @@ export async function testWithReferenceFuncAsync(
testFuncAsync: (...args: any[]) => Promise<any>,
values: any[],
): Promise<void> {
let expectedResult: any;
let expectedErr: string | undefined;
try {
expectedResult = await referenceFuncAsync(...values);
} catch (e) {
expectedErr = e.message;
}
let actualResult: any | undefined;
try {
actualResult = await testFuncAsync(...values);
if (!_.isUndefined(expectedErr)) {
// Measure correct behaviour
const expected = await evaluatePromise(referenceFuncAsync(...values));
// Measure actual behaviour
const actual = await evaluatePromise(testFuncAsync(...values));
// Compare behaviour
if (expected instanceof ErrorMessage) {
// If we expected an error, check if the actual error message contains the
// expected error message.
if (!(actual instanceof ErrorMessage)) {
throw new Error(
`Expected error containing ${expectedErr} but got no error\n\tTest case: ${_getTestCaseString(
`Expected error containing ${expected.error} but got no error\n\tTest case: ${_getTestCaseString(
referenceFuncAsync,
values,
)}`,
);
}
} catch (e) {
if (_.isUndefined(expectedErr)) {
throw new Error(`${e.message}\n\tTest case: ${_getTestCaseString(referenceFuncAsync, values)}`);
} else {
expect(e.message).to.contain(
expectedErr,
`${e.message}\n\tTest case: ${_getTestCaseString(referenceFuncAsync, values)}`,
);
}
}
if (!_.isUndefined(actualResult) && !_.isUndefined(expectedResult)) {
expect(actualResult).to.deep.equal(
expectedResult,
`Test case: ${_getTestCaseString(referenceFuncAsync, values)}`,
expect(actual.error).to.contain(
expected.error,
`${actual.error}\n\tTest case: ${_getTestCaseString(referenceFuncAsync, values)}`,
);
} else {
// If we do not expect an error, compare actual and expected directly.
expect(actual).to.deep.equal(expected, `Test case ${_getTestCaseString(referenceFuncAsync, values)}`);
}
}