Delete old test helpers.

This commit is contained in:
Nicolás Venturo
2019-01-11 16:02:57 -03:00
parent 5997da9693
commit 3e85ec771c
20 changed files with 4 additions and 954 deletions

View File

@ -1,12 +0,0 @@
const { ethGetBalance } = require('./web3');
async function balanceDifference (account, promiseFunc) {
const balanceBefore = await ethGetBalance(account);
await promiseFunc();
const balanceAfter = await ethGetBalance(account);
return balanceAfter.minus(balanceBefore);
}
module.exports = {
balanceDifference,
};

View File

@ -1,8 +0,0 @@
const BigNumber = web3.BigNumber;
module.exports = {
ZERO_ADDRESS: '0x0000000000000000000000000000000000000000',
MAX_UINT256: new BigNumber(2).pow(256).minus(1),
MAX_INT256: new BigNumber(2).pow(255).minus(1),
MIN_INT256: new BigNumber(2).pow(255).times(-1),
};

View File

@ -1,7 +0,0 @@
function ether (n) {
return new web3.BigNumber(web3.toWei(n, 'ether'));
}
module.exports = {
ether,
};

View File

@ -1,57 +0,0 @@
const { should, BigNumber } = require('./setup');
const SolidityEvent = require('web3/lib/web3/event.js');
const { ethGetTransactionReceipt } = require('./web3');
function inLogs (logs, eventName, eventArgs = {}) {
const event = logs.find(function (e) {
if (e.event === eventName) {
for (const [k, v] of Object.entries(eventArgs)) {
contains(e.args, k, v);
}
return true;
}
});
should.exist(event);
return event;
}
async function inConstruction (contract, eventName, eventArgs = {}) {
return inTransaction(contract.transactionHash, contract.constructor, eventName, eventArgs);
}
async function inTransaction (txHash, emitter, eventName, eventArgs = {}) {
const receipt = await ethGetTransactionReceipt(txHash);
const logs = decodeLogs(receipt.logs, emitter.events);
return inLogs(logs, eventName, eventArgs);
}
function contains (args, key, value) {
if (isBigNumber(args[key])) {
args[key].should.be.bignumber.equal(value);
} else {
args[key].should.be.equal(value);
}
}
function isBigNumber (object) {
return object.isBigNumber ||
object instanceof BigNumber ||
(object.constructor && object.constructor.name === 'BigNumber');
}
function decodeLogs (logs, events) {
return Array.prototype.concat(...logs.map(log =>
log.topics.filter(topic => topic in events).map(topic => {
const event = new SolidityEvent(null, events[topic], 0);
return event.decode(log);
})
));
}
module.exports = {
inLogs,
inConstruction,
inTransaction,
};

View File

@ -1,25 +0,0 @@
const { soliditySha3 } = require('web3-utils');
const INTERFACE_ID_LENGTH = 4;
function makeInterfaceId (interfaces = []) {
const interfaceIdBuffer = interfaces
.map(methodSignature => soliditySha3(methodSignature)) // keccak256
.map(h =>
Buffer
.from(h.substring(2), 'hex')
.slice(0, 4) // bytes4()
)
.reduce((memo, bytes) => {
for (let i = 0; i < INTERFACE_ID_LENGTH; i++) {
memo[i] = memo[i] ^ bytes[i]; // xor
}
return memo;
}, Buffer.alloc(INTERFACE_ID_LENGTH));
return `0x${interfaceIdBuffer.toString('hex')}`;
}
module.exports = {
makeInterfaceId,
};

View File

@ -1,26 +0,0 @@
const ethjsABI = require('ethjs-abi');
const { ethSendTransaction } = require('./web3');
function findMethod (abi, name, args) {
for (let i = 0; i < abi.length; i++) {
const methodArgs = abi[i].inputs.map(input => input.type).join(',');
if ((abi[i].name === name) && (methodArgs === args)) {
return abi[i];
}
}
}
async function transaction (target, name, argsTypes, argsValues, opts) {
const abiMethod = findMethod(target.abi, name, argsTypes);
const encodedData = ethjsABI.encodeMethod(abiMethod, argsValues);
return target.sendTransaction(Object.assign({ data: encodedData }, opts));
}
function ether (from, to, value) {
return ethSendTransaction({ from, to, value, gasPrice: 0 });
}
module.exports = {
ether,
transaction,
};

View File

@ -1,9 +0,0 @@
const chai = require('chai');
const BigNumber = web3.BigNumber;
const should = chai.use(require('chai-bignumber')(BigNumber)).should();
module.exports = {
BigNumber,
should,
};

View File

@ -1,36 +0,0 @@
const { should } = require('./setup');
async function shouldFailWithMessage (promise, message) {
try {
await promise;
} catch (error) {
if (message) {
error.message.should.include(message, `Wrong failure type, expected '${message}'`);
}
return;
}
should.fail('Expected failure not received');
}
async function reverting (promise) {
await shouldFailWithMessage(promise, 'revert');
}
async function throwing (promise) {
await shouldFailWithMessage(promise, 'invalid opcode');
}
async function outOfGas (promise) {
await shouldFailWithMessage(promise, 'out of gas');
}
async function shouldFail (promise) {
await shouldFailWithMessage(promise);
}
shouldFail.reverting = reverting;
shouldFail.throwing = throwing;
shouldFail.outOfGas = outOfGas;
module.exports = shouldFail;

View File

@ -3,7 +3,6 @@ const PADDED_SIGNATURE_SIZE = 2 * 96; // 96 bytes in hexadecimal string length
const DUMMY_SIGNATURE = `0x${web3.utils.padLeft('', REAL_SIGNATURE_SIZE)}`;
// messageHex = '0xdeadbeef'
function toEthSignedMessageHash (messageHex) {
const messageBuffer = Buffer.from(messageHex.substring(2), 'hex');
const prefix = Buffer.from(`\u0019Ethereum Signed Message:\n${messageBuffer.length}`);
@ -11,26 +10,13 @@ function toEthSignedMessageHash (messageHex) {
}
// signs message in node (ganache auto-applies "Ethereum Signed Message" prefix)
// messageHex = '0xdeadbeef'
const signMessage = (signer, messageHex = '0x') => {
return web3.eth.sign(messageHex, signer); // actually personal_sign
};
// @TODO - remove this when we migrate to web3-1.0.0
const transformToFullName = function (json) {
if (json.name.indexOf('(') !== -1) {
return json.name;
}
const typeName = json.inputs.map(function (i) { return i.type; }).join();
return json.name + '(' + typeName + ')';
return web3.eth.sign(messageHex, signer);
};
/**
* Create a signer between a contract and a signer for a voucher of method, args, and redeemer
* Note that `method` is the web3 method, not the truffle-contract method
* Well truffle is terrible, but luckily (?) so is web3 < 1.0, so we get to make our own method id
* fetcher because the method on the contract isn't actually the SolidityFunction object ಠ_ಠ
* @param contract TruffleContract
* @param signer address
* @param redeemer address
@ -47,16 +33,12 @@ const getSignFor = (contract, signer) => (redeemer, methodName, methodArgs = [])
if (methodName) {
if (methodArgs.length > 0) {
parts.push(
contract.contract[methodName].getData(...methodArgs.concat([DUMMY_SIGNATURE])).slice(
0,
-1 * PADDED_SIGNATURE_SIZE
)
contract.contract.methods[methodName](...methodArgs.concat([DUMMY_SIGNATURE])).encodeABI()
.slice(0, -1 * PADDED_SIGNATURE_SIZE)
);
} else {
const abi = contract.abi.find(abi => abi.name === methodName);
const name = transformToFullName(abi);
const signature = web3.utils.sha3(name).slice(0, 10);
parts.push(signature);
parts.push(abi.signature);
}
}

View File

@ -1,22 +0,0 @@
const { balanceDifference } = require('../balanceDifference');
const send = require('../send');
const { ether } = require('../ether');
const BigNumber = web3.BigNumber;
require('chai')
.use(require('chai-bignumber')(BigNumber))
.should();
contract('balanceDifference', function ([sender, receiver]) {
it('returns balance increments', async function () {
(await balanceDifference(receiver, () =>
send.ether(sender, receiver, ether(1)))
).should.be.bignumber.equal(ether(1));
});
it('returns balance decrements', async function () {
(await balanceDifference(sender, () =>
send.ether(sender, receiver, ether(1)))
).should.be.bignumber.equal(ether(-1));
});
});

View File

@ -1,16 +0,0 @@
const { ether } = require('../ether');
const BigNumber = web3.BigNumber;
require('chai')
.use(require('chai-bignumber')(BigNumber))
.should();
describe('ether', function () {
it('returns a BigNumber', function () {
ether(1, 'ether').should.be.bignumber.equal(new BigNumber(1000000000000000000));
});
it('works with negative amounts', function () {
ether(-1, 'ether').should.be.bignumber.equal(new BigNumber(-1000000000000000000));
});
});

View File

@ -1,375 +0,0 @@
const expectEvent = require('../expectEvent');
const shouldFail = require('../shouldFail');
const EventEmitter = artifacts.require('EventEmitter');
const IndirectEventEmitter = artifacts.require('IndirectEventEmitter');
const { should, BigNumber } = require('../../helpers/setup');
describe('expectEvent', function () {
beforeEach(async function () {
this.constructionValues = {
uint: 42,
boolean: true,
string: 'OpenZeppelin',
};
this.emitter = await EventEmitter.new(
this.constructionValues.uint,
this.constructionValues.boolean,
this.constructionValues.string
);
});
describe('inConstructor', function () {
context('short uint value', function () {
it('accepts emitted events with correct number', async function () {
await expectEvent.inConstruction(this.emitter, 'ShortUint',
{ value: this.constructionValues.uint }
);
});
it('throws if an incorrect value is passed', async function () {
await shouldFail(expectEvent.inConstruction(this.emitter, 'ShortUint', { value: 23 }));
});
});
context('boolean value', function () {
it('accepts emitted events with correct value', async function () {
await expectEvent.inConstruction(this.emitter, 'Boolean', { value: this.constructionValues.boolean });
});
it('throws if an incorrect value is passed', async function () {
await shouldFail(expectEvent.inConstruction(this.emitter, 'Boolean',
{ value: !this.constructionValues.boolean }
));
});
});
context('string value', function () {
it('accepts emitted events with correct string', async function () {
await expectEvent.inConstruction(this.emitter, 'String', { value: this.constructionValues.string });
});
it('throws if an incorrect string is passed', async function () {
await shouldFail(expectEvent.inConstruction(this.emitter, 'String', { value: 'ClosedZeppelin' }));
});
});
it('throws if an unemitted event is requested', async function () {
await shouldFail(expectEvent.inConstruction(this.emitter, 'UnemittedEvent'));
});
});
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 }));
});
});
describe('with events emitted by an indirectly called contract', function () {
beforeEach(async function () {
this.secondEmitter = await IndirectEventEmitter.new();
this.value = 'OpenZeppelin';
({ logs: this.logs } = await this.emitter.emitStringAndEmitIndirectly(this.value, this.secondEmitter.address));
});
it('accepts events emitted by the directly called contract', function () {
expectEvent.inLogs(this.logs, 'String', { value: this.value });
});
it('throws when passing events emitted by the indirectly called contract', function () {
should.Throw(() => expectEvent.inLogs(this.logs, 'IndirectString', { value: this.value }));
});
});
});
describe('inTransaction', function () {
describe('when emitting from called contract and indirect calls', function () {
context('string value', function () {
beforeEach(async function () {
this.secondEmitter = await IndirectEventEmitter.new();
this.value = 'OpenZeppelin';
const receipt = await this.emitter.emitStringAndEmitIndirectly(this.value, this.secondEmitter.address);
this.txHash = receipt.tx;
});
context('with directly called contract', function () {
it('accepts emitted events with correct string', async function () {
await expectEvent.inTransaction(this.txHash, EventEmitter, 'String', { value: this.value });
});
it('throws if an unemitted event is requested', async function () {
await shouldFail(expectEvent.inTransaction(this.txHash, EventEmitter, 'UnemittedEvent',
{ value: this.value }
));
});
it('throws if an incorrect string is passed', async function () {
await shouldFail(expectEvent.inTransaction(this.txHash, EventEmitter, 'String',
{ value: 'ClosedZeppelin' }
));
});
it('throws if an event emitted from other contract is passed', async function () {
await shouldFail(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString',
{ value: this.value }
));
});
it('throws if an incorrect emitter is passed', async function () {
await shouldFail(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String',
{ value: this.value }
));
});
});
context('with indirectly called contract', function () {
it('accepts events emitted from other contracts', async function () {
await expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'IndirectString',
{ value: this.value }
);
});
it('throws if an unemitted event is requested', async function () {
await shouldFail(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'UnemittedEvent',
{ value: this.value }
));
});
it('throws if an incorrect string is passed', async function () {
await shouldFail(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'IndirectString',
{ value: 'ClosedZeppelin' }
));
});
it('throws if an event emitted from other contract is passed', async function () {
await shouldFail(expectEvent.inTransaction(this.txHash, IndirectEventEmitter, 'String',
{ value: this.value }
));
});
it('throws if an incorrect emitter is passed', async function () {
await shouldFail(expectEvent.inTransaction(this.txHash, EventEmitter, 'IndirectString',
{ value: this.value }
));
});
});
});
});
});
});

View File

@ -1,20 +0,0 @@
const { makeInterfaceId } = require('../makeInterfaceId');
const OwnableInterfaceId = artifacts.require('OwnableInterfaceId');
require('chai')
.should();
describe('makeInterfaceId', function () {
it('calculates the EIP165 interface id from function signatures', async function () {
const calculator = await OwnableInterfaceId.new();
const ownableId = await calculator.getInterfaceId();
makeInterfaceId([
'owner()',
'isOwner()',
'renounceOwnership()',
'transferOwnership(address)',
]).should.equal(ownableId);
});
});

View File

@ -1,70 +0,0 @@
const send = require('../send');
const shouldFail = require('../shouldFail');
const expectEvent = require('../expectEvent');
const { ether } = require('../ether');
const { ethGetBalance } = require('../web3');
const Acknowledger = artifacts.require('Acknowledger');
const BigNumber = web3.BigNumber;
require('chai')
.use(require('chai-bignumber')(BigNumber))
.should();
contract('send', function ([sender, receiver]) {
describe('ether', function () {
it('sends ether with no gas cost', async function () {
const value = ether(1);
const initialSenderBalance = await ethGetBalance(sender);
const initialReceiverBalance = await ethGetBalance(receiver);
await send.ether(sender, receiver, value);
const finalSenderBalance = await ethGetBalance(sender);
const finalReceiverBalance = await ethGetBalance(receiver);
finalSenderBalance.sub(initialSenderBalance).should.be.bignumber.equal(-value);
finalReceiverBalance.sub(initialReceiverBalance).should.be.bignumber.equal(value);
});
it('throws if the sender balance is insufficient', async function () {
const value = (await ethGetBalance(sender)).plus(1);
await shouldFail(send.ether(sender, receiver, value));
});
});
describe('transaction', function () {
beforeEach(async function () {
this.acknowledger = await Acknowledger.new();
});
it('calls a function from its signature ', async function () {
const { logs } = await send.transaction(this.acknowledger, 'foo', 'uint256', [3]);
expectEvent.inLogs(logs, 'AcknowledgeFoo', { a: 3 });
});
it('calls overloaded functions with less arguments', async function () {
const { logs } = await send.transaction(this.acknowledger, 'bar', 'uint256', [3]);
expectEvent.inLogs(logs, 'AcknowledgeBarSingle', { a: 3 });
});
it('calls overloaded functions with more arguments', async function () {
const { logs } = await send.transaction(this.acknowledger, 'bar', 'uint256,uint256', [3, 5]);
expectEvent.inLogs(logs, 'AcknowledgeBarDouble', { a: 3, b: 5 });
});
it('throws if the number of arguments does not match', async function () {
await shouldFail(send.transaction(this.acknowledger, 'foo', 'uint256, uint256', [3, 5]));
});
it('throws if the method does not exist', async function () {
await shouldFail(send.transaction(this.acknowledger, 'baz', 'uint256', [3]));
});
it('throws if there is a mismatch in the number of types and values', async function () {
await shouldFail(send.transaction(this.acknowledger, 'foo', 'uint256', [3, 3]));
});
});
});

View File

@ -1,95 +0,0 @@
const shouldFail = require('../shouldFail');
const BigNumber = web3.BigNumber;
const should = require('chai')
.use(require('chai-bignumber')(BigNumber))
.should();
const Failer = artifacts.require('Failer');
async function assertFailure (promise) {
try {
await promise;
} catch (error) {
return;
}
should.fail();
}
describe('shouldFail', function () {
beforeEach(async function () {
this.failer = await Failer.new();
});
describe('shouldFail', function () {
it('rejects if no failure occurs', async function () {
await assertFailure(shouldFail(this.failer.dontFail()));
});
it('accepts a revert', async function () {
await shouldFail(this.failer.failWithRevert());
});
it('accepts a throw', async function () {
await shouldFail(this.failer.failWithThrow());
});
it('accepts an out of gas', async function () {
await shouldFail(this.failer.failWithOutOfGas({ gas: 2000000 }));
});
});
describe('reverting', function () {
it('rejects if no failure occurs', async function () {
await assertFailure(shouldFail.reverting(this.failer.dontFail()));
});
it('accepts a revert', async function () {
await shouldFail.reverting(this.failer.failWithRevert());
});
it('rejects a throw', async function () {
await assertFailure(shouldFail.reverting(this.failer.failWithThrow()));
});
it('rejects an outOfGas', async function () {
await assertFailure(shouldFail.reverting(this.failer.failWithOutOfGas({ gas: 2000000 })));
});
});
describe('throwing', function () {
it('rejects if no failure occurs', async function () {
await assertFailure(shouldFail.throwing(this.failer.dontFail()));
});
it('accepts a throw', async function () {
await shouldFail.throwing(this.failer.failWithThrow());
});
it('rejects a throw', async function () {
await assertFailure(shouldFail.throwing(this.failer.failWithRevert()));
});
it('rejects an outOfGas', async function () {
await assertFailure(shouldFail.throwing(this.failer.failWithOutOfGas({ gas: 2000000 })));
});
});
describe('outOfGas', function () {
it('rejects if no failure occurs', async function () {
await assertFailure(shouldFail.outOfGas(this.failer.dontFail()));
});
it('accepts an out of gas', async function () {
await shouldFail.outOfGas(this.failer.failWithOutOfGas({ gas: 2000000 }));
});
it('rejects a revert', async function () {
await assertFailure(shouldFail.outOfGas(this.failer.failWithRevert()));
});
it('rejects a throw', async function () {
await assertFailure(shouldFail.outOfGas(this.failer.failWithThrow()));
});
});
});

View File

@ -1,77 +0,0 @@
const time = require('../time');
const shouldFail = require('../shouldFail');
const BigNumber = web3.BigNumber;
require('chai')
.use(require('chai-bignumber')(BigNumber))
.should();
describe('time', function () {
const TOLERANCE_SECONDS = 1;
describe('duration', function () {
it('converts seconds to seconds', function () {
time.duration.seconds(1).should.equal(1);
});
it('converts minutes to seconds', function () {
time.duration.minutes(1).should.equal(60);
});
it('converts hours to seconds', function () {
time.duration.hours(1).should.equal(60 * 60);
});
it('converts days to seconds', function () {
time.duration.days(1).should.equal(60 * 60 * 24);
});
it('converts weeks to seconds', function () {
time.duration.weeks(1).should.equal(60 * 60 * 24 * 7);
});
it('converts years to seconds', function () {
time.duration.years(1).should.equal(60 * 60 * 24 * 365);
});
});
describe('advanceBlock', function () {
it('increases the block number by one', async function () {
const startingBlock = web3.eth.blockNumber;
await time.advanceBlock();
web3.eth.blockNumber.should.be.bignumber.equal(startingBlock + 1);
});
});
context('with starting time', function () {
beforeEach(async function () {
await time.advanceBlock();
this.start = await time.latest();
});
describe('increase', function () {
it('increases time by a duration', async function () {
await time.increase(time.duration.hours(1));
const end = this.start + time.duration.hours(1);
(await time.latest()).should.be.closeTo(end, TOLERANCE_SECONDS);
});
it('throws with negative durations', async function () {
await shouldFail(time.increase(-1));
});
});
describe('increaseTo', function () {
it('increases time to a time in the future', async function () {
const end = this.start + time.duration.hours(1);
await time.increaseTo(end);
(await time.latest()).should.be.closeTo(end, TOLERANCE_SECONDS);
});
it('throws with a time in the past', async function () {
await shouldFail(time.increaseTo(this.start - 30));
});
});
});
});

View File

@ -1,60 +0,0 @@
const { ethGetBlock } = require('./web3');
const pify = require('pify');
function advanceBlock () {
return pify(web3.currentProvider.sendAsync)({
jsonrpc: '2.0',
method: 'evm_mine',
});
}
// Returns the time of the last mined block in seconds
async function latest () {
const block = await ethGetBlock('latest');
return block.timestamp;
}
// Increases ganache time by the passed duration in seconds
async function increase (duration) {
if (duration < 0) throw Error(`Cannot increase time by a negative amount (${duration})`);
await pify(web3.currentProvider.sendAsync)({
jsonrpc: '2.0',
method: 'evm_increaseTime',
params: [duration],
});
await advanceBlock();
}
/**
* Beware that due to the need of calling two separate ganache methods and rpc calls overhead
* it's hard to increase time precisely to a target point so design your test to tolerate
* small fluctuations from time to time.
*
* @param target time in seconds
*/
async function increaseTo (target) {
const now = (await latest());
if (target < now) throw Error(`Cannot increase current time (${now}) to a moment in the past (${target})`);
const diff = target - now;
return increase(diff);
}
const duration = {
seconds: function (val) { return val; },
minutes: function (val) { return val * this.seconds(60); },
hours: function (val) { return val * this.minutes(60); },
days: function (val) { return val * this.hours(24); },
weeks: function (val) { return val * this.days(7); },
years: function (val) { return val * this.days(365); },
};
module.exports = {
advanceBlock,
latest,
increase,
increaseTo,
duration,
};

View File

@ -1,10 +0,0 @@
const pify = require('pify');
const ethAsync = pify(web3.eth);
module.exports = {
ethGetBalance: ethAsync.getBalance,
ethGetBlock: ethAsync.getBlock,
ethGetTransactionReceipt: ethAsync.getTransactionReceipt,
ethSendTransaction: ethAsync.sendTransaction,
};