From 10a5864fdf291525d3c8b40f0f3928425a2970f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 10 Oct 2018 20:55:10 -0300 Subject: [PATCH] First test helpers tests (#1369) * Removed unused advanceToBlock. * Added advanceBlock tests. * Fixed advanceToBlock tests. * Added single argument tests. * Finished inLogs tests. * Fixed linter errors. * Fixed linter errors. (cherry picked from commit 9f822906b8e8e052bae7947d4c362fbabdd2c3ba) --- contracts/mocks/EventEmitter.sol | 62 ++++++ test/helpers/advanceToBlock.js | 12 -- test/helpers/test/advanceToBlock.test.js | 19 ++ test/helpers/test/expectEvent.test.js | 232 +++++++++++++++++++++++ 4 files changed, 313 insertions(+), 12 deletions(-) create mode 100644 contracts/mocks/EventEmitter.sol create mode 100644 test/helpers/test/advanceToBlock.test.js create mode 100644 test/helpers/test/expectEvent.test.js diff --git a/contracts/mocks/EventEmitter.sol b/contracts/mocks/EventEmitter.sol new file mode 100644 index 000000000..71582d9f5 --- /dev/null +++ b/contracts/mocks/EventEmitter.sol @@ -0,0 +1,62 @@ +pragma solidity ^0.4.24; + +contract EventEmitter { + event Argumentless(); + event ShortUint(uint8 value); + event ShortInt(int8 value); + event LongUint(uint256 value); + event LongInt(int256 value); + event Address(address value); + event Boolean(bool value); + event String(string value); + event LongUintBooleanString( + uint256 uintValue, + bool booleanValue, + string stringValue + ); + + function emitArgumentless() public { + emit Argumentless(); + } + + function emitShortUint(uint8 value) public { + emit ShortUint(value); + } + + function emitShortInt(int8 value) public { + emit ShortInt(value); + } + + function emitLongUint(uint256 value) public { + emit LongUint(value); + } + + function emitLongInt(int256 value) public { + emit LongInt(value); + } + + function emitAddress(address value) public { + emit Address(value); + } + + function emitBoolean(bool value) public { + emit Boolean(value); + } + + function emitString(string value) public { + emit String(value); + } + + function emitLongUintBooleanString( + uint256 uintValue, + bool booleanValue, + string stringValue) + public { + emit LongUintBooleanString(uintValue, booleanValue, stringValue); + } + + function emitLongUintAndBoolean(uint256 uintValue, bool boolValue) public { + emit LongUint(uintValue); + emit Boolean(boolValue); + } +} diff --git a/test/helpers/advanceToBlock.js b/test/helpers/advanceToBlock.js index 22e5467cc..225502022 100644 --- a/test/helpers/advanceToBlock.js +++ b/test/helpers/advanceToBlock.js @@ -10,18 +10,6 @@ function advanceBlock () { }); } -// Advances the block number so that the last mined block is `number`. -async function advanceToBlock (number) { - if (web3.eth.blockNumber > number) { - throw Error(`block number ${number} is in the past (current is ${web3.eth.blockNumber})`); - } - - while (web3.eth.blockNumber < number) { - await advanceBlock(); - } -} - module.exports = { advanceBlock, - advanceToBlock, }; diff --git a/test/helpers/test/advanceToBlock.test.js b/test/helpers/test/advanceToBlock.test.js new file mode 100644 index 000000000..cd8f1c352 --- /dev/null +++ b/test/helpers/test/advanceToBlock.test.js @@ -0,0 +1,19 @@ +const advanceToBlock = require('../advanceToBlock'); + +const BigNumber = web3.BigNumber; +require('chai') + .use(require('chai-bignumber')(BigNumber)) + .should(); + +describe('advanceToBlock', function () { + beforeEach(function () { + this.startingBlock = web3.eth.blockNumber; + }); + + describe('advanceBlock', function () { + it('increases the block number by one', async function () { + await advanceToBlock.advanceBlock(); + web3.eth.blockNumber.should.be.bignumber.equal(this.startingBlock + 1); + }); + }); +}); diff --git a/test/helpers/test/expectEvent.test.js b/test/helpers/test/expectEvent.test.js new file mode 100644 index 000000000..158a9f374 --- /dev/null +++ b/test/helpers/test/expectEvent.test.js @@ -0,0 +1,232 @@ +const expectEvent = require('../expectEvent'); +const EventEmitter = artifacts.require('EventEmitter'); + +const BigNumber = web3.BigNumber; +const should = require('chai') + .use(require('chai-bignumber')(BigNumber)) + .should(); + +describe('expectEvent', function () { + beforeEach(async function () { + this.emitter = await EventEmitter.new(); + }); + + describe('inLogs', function () { + describe('with no arguments', function () { + beforeEach(async function () { + ({ logs: this.logs } = await this.emitter.emitArgumentless()); + }); + + it('accepts emitted events', function () { + expectEvent.inLogs(this.logs, 'Argumentless'); + }); + + it('throws if an unemitted event is requested', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'UnemittedEvent')); + }); + }); + + describe('with single argument', function () { + context('short uint value', function () { + beforeEach(async function () { + this.value = 42; + ({ logs: this.logs } = await this.emitter.emitShortUint(this.value)); + }); + + it('accepts emitted events with correct JavaScript number', function () { + expectEvent.inLogs(this.logs, 'ShortUint', { value: this.value }); + }); + + it('accepts emitted events with correct BigNumber', function () { + expectEvent.inLogs(this.logs, 'ShortUint', { value: new BigNumber(this.value) }); + }); + + it('throws if an unemitted event is requested', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'UnemittedEvent', { value: this.value })); + }); + + it('throws if an incorrect value is passed', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'ShortUint', { value: 23 })); + }); + }); + + context('short int value', function () { + beforeEach(async function () { + this.value = -42; + ({ logs: this.logs } = await this.emitter.emitShortInt(this.value)); + }); + + it('accepts emitted events with correct JavaScript number', function () { + expectEvent.inLogs(this.logs, 'ShortInt', { value: this.value }); + }); + + it('accepts emitted events with correct BigNumber', function () { + expectEvent.inLogs(this.logs, 'ShortInt', { value: new BigNumber(this.value) }); + }); + + it('throws if an unemitted event is requested', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'UnemittedEvent', { value: this.value })); + }); + + it('throws if an incorrect value is passed', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'ShortInt', { value: -23 })); + }); + }); + + context('long uint value', function () { + beforeEach(async function () { + this.bigNumValue = new BigNumber('123456789012345678901234567890'); + ({ logs: this.logs } = await this.emitter.emitLongUint(this.bigNumValue)); + }); + + it('accepts emitted events with correct BigNumber', function () { + expectEvent.inLogs(this.logs, 'LongUint', { value: this.bigNumValue }); + }); + + it('throws if an unemitted event is requested', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'UnemittedEvent', { value: this.bigNumValue })); + }); + + it('throws if an incorrect value is passed', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'LongUint', { value: 2300 })); + }); + }); + + context('long int value', function () { + beforeEach(async function () { + this.bigNumValue = new BigNumber('-123456789012345678901234567890'); + ({ logs: this.logs } = await this.emitter.emitLongInt(this.bigNumValue)); + }); + + it('accepts emitted events with correct BigNumber', function () { + expectEvent.inLogs(this.logs, 'LongInt', { value: this.bigNumValue }); + }); + + it('throws if an unemitted event is requested', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'UnemittedEvent', { value: this.bigNumValue })); + }); + + it('throws if an incorrect value is passed', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'LongInt', { value: -2300 })); + }); + }); + + context('address value', function () { + beforeEach(async function () { + this.value = '0x811412068e9fbf25dc300a29e5e316f7122b282c'; + ({ logs: this.logs } = await this.emitter.emitAddress(this.value)); + }); + + it('accepts emitted events with correct address', function () { + expectEvent.inLogs(this.logs, 'Address', { value: this.value }); + }); + + it('throws if an unemitted event is requested', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'UnemittedEvent', { value: this.value })); + }); + + it('throws if an incorrect value is passed', function () { + should.Throw(() => + expectEvent.inLogs(this.logs, 'Address', { value: '0x21d04e022e0b52b5d5bcf90b7f1aabf406be002d' }) + ); + }); + }); + + context('boolean value', function () { + beforeEach(async function () { + this.value = true; + ({ logs: this.logs } = await this.emitter.emitBoolean(this.value)); + }); + + it('accepts emitted events with correct address', function () { + expectEvent.inLogs(this.logs, 'Boolean', { value: this.value }); + }); + + it('throws if an unemitted event is requested', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'UnemittedEvent', { value: this.value })); + }); + + it('throws if an incorrect value is passed', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'Boolean', { value: false })); + }); + }); + + context('string value', function () { + beforeEach(async function () { + this.value = 'OpenZeppelin'; + ({ logs: this.logs } = await this.emitter.emitString(this.value)); + }); + + it('accepts emitted events with correct string', function () { + expectEvent.inLogs(this.logs, 'String', { value: this.value }); + }); + + it('throws if an unemitted event is requested', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'UnemittedEvent', { value: this.value })); + }); + + it('throws if an incorrect value is passed', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'String', { value: 'ClosedZeppelin' })); + }); + }); + }); + + describe('with multiple arguments', function () { + beforeEach(async function () { + this.uintValue = new BigNumber('123456789012345678901234567890'); + this.booleanValue = true; + this.stringValue = 'OpenZeppelin'; + ({ logs: this.logs } = + await this.emitter.emitLongUintBooleanString(this.uintValue, this.booleanValue, this.stringValue)); + }); + + it('accepts correct values', function () { + expectEvent.inLogs(this.logs, 'LongUintBooleanString', { + uintValue: this.uintValue, booleanValue: this.booleanValue, stringValue: this.stringValue, + }); + }); + + it('throws with correct values assigned to wrong arguments', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'LongUintBooleanString', { + uintValue: this.booleanValue, booleanValue: this.uintValue, stringValue: this.stringValue, + })); + }); + + it('throws when any of the values is incorrect', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'LongUintBooleanString', { + uintValue: 23, booleanValue: this.booleanValue, stringValue: this.stringValue, + })); + + should.Throw(() => expectEvent.inLogs(this.logs, 'LongUintBooleanString', { + uintValue: this.uintValue, booleanValue: false, stringValue: this.stringValue, + })); + + should.Throw(() => expectEvent.inLogs(this.logs, 'LongUintBooleanString', { + uintValue: this.uintValue, booleanValue: this.booleanValue, stringValue: 'ClosedZeppelin', + })); + }); + }); + + describe('with multiple events', function () { + beforeEach(async function () { + this.uintValue = 42; + this.booleanValue = true; + ({ logs: this.logs } = await this.emitter.emitLongUintAndBoolean(this.uintValue, this.booleanValue)); + }); + + it('accepts all emitted events with correct values', function () { + expectEvent.inLogs(this.logs, 'LongUint', { value: this.uintValue }); + expectEvent.inLogs(this.logs, 'Boolean', { value: this.booleanValue }); + }); + + it('throws if an unemitted event is requested', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'UnemittedEvent', { value: this.uintValue })); + }); + + it('throws if incorrect values are passed', function () { + should.Throw(() => expectEvent.inLogs(this.logs, 'LongUint', { value: 23 })); + should.Throw(() => expectEvent.inLogs(this.logs, 'Boolean', { value: false })); + }); + }); + }); +});