From e603a81a46fb0dc8159670df7f44cd3d7c030a2d Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Wed, 16 Oct 2019 18:43:06 -0700 Subject: [PATCH] `@0x:contracts-integrations` Simplified the tests --- .../contracts/test/TestFramework.sol | 53 ++++------- .../integrations/test/examples/simple.ts | 75 ---------------- .../function_assertion_test.ts | 87 +++++++++---------- .../test/utils/function_assertions.ts | 1 - 4 files changed, 60 insertions(+), 156 deletions(-) delete mode 100644 contracts/integrations/test/examples/simple.ts diff --git a/contracts/integrations/contracts/test/TestFramework.sol b/contracts/integrations/contracts/test/TestFramework.sol index a715dddeb9..e8bf6cfdad 100644 --- a/contracts/integrations/contracts/test/TestFramework.sol +++ b/contracts/integrations/contracts/test/TestFramework.sol @@ -1,64 +1,45 @@ pragma solidity ^0.5.9; +import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; + +// This contract is intended to be used in the unit tests that test the typescript +// test framework found in `test/utils/` contract TestFramework { - event SomeEvent(uint256 someNumber); + event Event(string input); - uint256 public counter; + // bytes4(keccak256("RichRevertErrorSelector(string)")) + bytes4 internal constant RICH_REVERT_ERROR_SELECTOR = 0x49a7e246; - function setCounter(uint256 newCounter) + function emitEvent(string calldata input) external { - counter = newCounter; + emit Event(input); } - function revertSideEffect(uint256 returnValue) + function emptyRevert() external - returns (uint256) { - if (counter != 0) { - revert("Revert"); - } - - emit SomeEvent(returnValue); - return returnValue; + revert(); } - function equalsSideEffect(uint256 possiblyZero) + function stringRevert(string calldata message) external - view - returns (bool) { - if (counter == 0) { - return possiblyZero == 0; - } else { - return false; - } + revert(message); } - function noEffect(uint256) + function doNothing() external pure {} // solhint-disable-line no-empty-blocks - function numberSideEffect() + function returnInteger(uint256 integer) external - view + pure returns (uint256) { - return counter; - } - - function hashSideEffect(uint256 arg1, bytes32 arg2) - external - view - returns (bytes32) - { - if (counter == 0) { - return keccak256(abi.encode(arg1, arg2)); - } else { - return keccak256(hex""); - } + return integer; } } diff --git a/contracts/integrations/test/examples/simple.ts b/contracts/integrations/test/examples/simple.ts deleted file mode 100644 index 23f68f08b4..0000000000 --- a/contracts/integrations/test/examples/simple.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { blockchainTests, expect } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; - -import { artifacts, TestFrameworkContract } from '../../src'; -import { FunctionAssertion, Result } from '../utils/function_assertions'; - -// These tests provide examples for how to use the "FunctionAssertion" class to write -// tests for "payable" and "nonpayable" Solidity functions as well as "pure" and "view" functions. -blockchainTests('TestFramework', env => { - let exampleContract: TestFrameworkContract; - - before(async () => { - exampleContract = await TestFrameworkContract.deployFrom0xArtifactAsync( - artifacts.TestFramework, - env.provider, - env.txDefaults, - artifacts, - ); - }); - - describe('numberSideEffect', () => { - let assertion: FunctionAssertion; - - before(async () => { - const condition = { - before: async () => {}, - after: async (beforeInfo: any, result: Result) => { - // Ensure that the call was successful. - expect(result.success).to.be.true(); - - // Ensure that the correct counter was returned. - const counter = await exampleContract.counter.callAsync(); - expect(result.data).bignumber.to.be.eq(counter); - }, - }; - assertion = new FunctionAssertion(exampleContract.numberSideEffect, condition); - }); - - it('should return the correct counter', async () => { - await assertion.runAsync(); - }); - - it('should return the correct counter', async () => { - await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(2)); - await assertion.runAsync(); - }); - }); - - describe('setCounter', () => { - let assertion: FunctionAssertion; - - before(async () => { - const condition = { - before: async (expectedCounter: BigNumber) => {}, - after: async (beforeInfo: any, result: Result, expectedCounter: BigNumber) => { - // Ensure that the call was successful. - expect(result.success).to.be.true(); - - // Ensure that the counter was updated correctly. - const counter = await exampleContract.counter.callAsync(); - expect(counter).bignumber.to.be.eq(expectedCounter); - }, - }; - assertion = new FunctionAssertion(exampleContract.setCounter, condition); - }); - - it('should correctly set counter to 1', async () => { - await assertion.runAsync(new BigNumber(1)); - }); - - it('should correctly set counter to 1500', async () => { - await assertion.runAsync(new BigNumber(1500)); - }); - }); -}); diff --git a/contracts/integrations/test/framework-unit-tests/function_assertion_test.ts b/contracts/integrations/test/framework-unit-tests/function_assertion_test.ts index 07cc7d32c5..495a95756b 100644 --- a/contracts/integrations/test/framework-unit-tests/function_assertion_test.ts +++ b/contracts/integrations/test/framework-unit-tests/function_assertion_test.ts @@ -6,10 +6,10 @@ import { getRandomInteger, hexRandom, } from '@0x/contracts-test-utils'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, StringRevertError } from '@0x/utils'; import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import { artifacts, TestFrameworkContract, TestFrameworkSomeEventEventArgs, TestFrameworkEvents } from '../../src'; +import { artifacts, TestFrameworkContract, TestFrameworkEventEventArgs, TestFrameworkEvents } from '../../src'; import { FunctionAssertion, Result } from '../utils/function_assertions'; const ZERO = constants.ZERO_AMOUNT; @@ -30,13 +30,12 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { describe('runAsync', () => { it('should call the before function with the provided arguments', async () => { let sideEffectTarget = ZERO; - const assertion = new FunctionAssertion(exampleContract.noEffect, { - before: async (inputValue: BigNumber) => { - sideEffectTarget = inputValue; + const assertion = new FunctionAssertion(exampleContract.returnInteger, { + before: async (input: BigNumber) => { + sideEffectTarget = randomInput; }, - after: async (beforeInfo: any, result: Result, returnValue: BigNumber) => {}, + after: async (beforeInfo: any, result: Result, input: BigNumber) => {}, }); - const randomInput = getRandomInteger(ZERO, MAX_UINT256); await assertion.runAsync(randomInput); expect(sideEffectTarget).bignumber.to.be.eq(randomInput); @@ -44,36 +43,33 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { it('should call the after function with the provided arguments', async () => { let sideEffectTarget = ZERO; - const assertion = new FunctionAssertion(exampleContract.noEffect, { - before: async (inputValue: BigNumber) => {}, - after: async (beforeInfo: any, result: Result, returnValue: BigNumber) => { - sideEffectTarget = returnValue; + const assertion = new FunctionAssertion(exampleContract.returnInteger, { + before: async (input: BigNumber) => {}, + after: async (beforeInfo: any, result: Result, input: BigNumber) => { + sideEffectTarget = input; }, }); - const randomInput = getRandomInteger(ZERO, MAX_UINT256); await assertion.runAsync(randomInput); expect(sideEffectTarget).bignumber.to.be.eq(randomInput); }); it('should not fail immediately if the wrapped function fails', async () => { - await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1)); - const assertion = new FunctionAssertion(exampleContract.revertSideEffect, { - before: async (inputValue: BigNumber) => {}, - after: async (beforeInfo: any, result: Result, returnValue: BigNumber) => {}, + const assertion = new FunctionAssertion(exampleContract.emptyRevert, { + before: async () => {}, + after: async (beforeInfo: any, result: Result) => {}, }); - const randomInput = getRandomInteger(ZERO, MAX_UINT256); - await assertion.runAsync(randomInput); + await assertion.runAsync(); }); - it('should pass the return value from "before" to "after"', async () => { + it('should pass the return value of "before" to "after"', async () => { const randomInput = getRandomInteger(ZERO, MAX_UINT256); let sideEffectTarget = constants.ZERO_AMOUNT; - const assertion = new FunctionAssertion(exampleContract.noEffect, { - before: async (inputValue: BigNumber) => { + const assertion = new FunctionAssertion(exampleContract.returnInteger, { + before: async (input: BigNumber) => { return randomInput; }, - after: async (beforeInfo: any, result: Result, returnValue: BigNumber) => { + after: async (beforeInfo: any, result: Result, input: BigNumber) => { sideEffectTarget = beforeInfo; }, }); @@ -83,9 +79,9 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { it('should pass the result from the function call to "after"', async () => { let sideEffectTarget = constants.ZERO_AMOUNT; - const assertion = new FunctionAssertion(exampleContract.revertSideEffect, { - before: async (inputValue: BigNumber) => {}, - after: async (beforeInfo: any, result: Result, returnValue: BigNumber) => { + const assertion = new FunctionAssertion(exampleContract.returnInteger, { + before: async (input: BigNumber) => {}, + after: async (beforeInfo: any, result: Result, input: BigNumber) => { sideEffectTarget = result.data; }, }); @@ -96,40 +92,43 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { it('should pass the receipt from the function call to "after"', async () => { let sideEffectTarget = {} as TransactionReceiptWithDecodedLogs; - const assertion = new FunctionAssertion(exampleContract.revertSideEffect, { - before: async (inputValue: BigNumber) => {}, - after: async (beforeInfo: any, result: Result, returnValue: BigNumber) => { + const assertion = new FunctionAssertion(exampleContract.emitEvent, { + before: async (input: string) => {}, + after: async (beforeInfo: any, result: Result, input: string) => { if (result.receipt) { sideEffectTarget = result.receipt; - } else { - throw new Error('No receipt received.'); } }, }); - const randomInput = getRandomInteger(ZERO, MAX_UINT256); - await assertion.runAsync(randomInput); + + const input = 'emitted data'; + await assertion.runAsync(input); // Ensure that the correct events were emitted. - const [event] = filterLogsToArguments( + const [event] = filterLogsToArguments( sideEffectTarget.logs, - TestFrameworkEvents.SomeEvent, + TestFrameworkEvents.Event, ); - expect(event).to.be.deep.eq({ someNumber: randomInput }); + expect(event).to.be.deep.eq({ input }); }); it('should pass the error to "after" if the function call fails', async () => { - let sideEffectTarget: Error = new Error(''); - await exampleContract.setCounter.awaitTransactionSuccessAsync(new BigNumber(1)); - const assertion = new FunctionAssertion(exampleContract.revertSideEffect, { - before: async (inputValue: BigNumber) => {}, - after: async (beforeInfo: any, result: Result, returnValue: BigNumber) => { + let sideEffectTarget: Error; + const assertion = new FunctionAssertion(exampleContract.stringRevert, { + before: async string => {}, + after: async (any, result: Result, string) => { sideEffectTarget = result.data; }, }); - const randomInput = getRandomInteger(ZERO, MAX_UINT256); - await assertion.runAsync(randomInput); - const errorMessage = 'VM Exception while processing transaction: revert Revert'; - expect(sideEffectTarget.message).to.be.eq(errorMessage); + const message = 'error message'; + await assertion.runAsync(message); + + const expectedError = new StringRevertError(message); + return expect( + new Promise((resolve, reject) => { + reject(sideEffectTarget); + }), + ).to.revertWith(expectedError); }); }); }); diff --git a/contracts/integrations/test/utils/function_assertions.ts b/contracts/integrations/test/utils/function_assertions.ts index 85652dcf81..05672886ed 100644 --- a/contracts/integrations/test/utils/function_assertions.ts +++ b/contracts/integrations/test/utils/function_assertions.ts @@ -3,7 +3,6 @@ import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; export interface ContractGetterFunction { callAsync: (...args: any[]) => Promise; - getABIEncodedTransactionData: (...args: any[]) => string; } export interface ContractWrapperFunction extends ContractGetterFunction {