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:
@@ -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)}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user