Commit a9f910d3 by Nicolás Venturo Committed by Francisco Giordano

Increase test coverage (#1237)

* Fixed a SplitPayment test

* Deleted unnecessary function.

* Improved PostDeliveryCrowdsale tests.

* Improved RefundableCrowdsale tests.

* Improved MintedCrowdsale tests.

* Improved IncreasingPriceCrowdsale tests.

* Fixed a CappedCrowdsale test.

* Improved TimedCrowdsale tests.

* Improved descriptions of added tests.
parent a466e76d
...@@ -22,8 +22,8 @@ contract IncreasingPriceCrowdsale is TimedCrowdsale { ...@@ -22,8 +22,8 @@ contract IncreasingPriceCrowdsale is TimedCrowdsale {
* @param _finalRate Number of tokens a buyer gets per wei at the end of the crowdsale * @param _finalRate Number of tokens a buyer gets per wei at the end of the crowdsale
*/ */
constructor(uint256 _initialRate, uint256 _finalRate) public { constructor(uint256 _initialRate, uint256 _finalRate) public {
require(_initialRate >= _finalRate);
require(_finalRate > 0); require(_finalRate > 0);
require(_initialRate >= _finalRate);
initialRate = _initialRate; initialRate = _initialRate;
finalRate = _finalRate; finalRate = _finalRate;
} }
......
...@@ -47,7 +47,7 @@ contract Heritable is Ownable { ...@@ -47,7 +47,7 @@ contract Heritable is Ownable {
* before the heir can take ownership. * before the heir can take ownership.
*/ */
constructor(uint256 _heartbeatTimeout) public { constructor(uint256 _heartbeatTimeout) public {
setHeartbeatTimeout(_heartbeatTimeout); heartbeatTimeout_ = _heartbeatTimeout;
} }
function setHeir(address _newHeir) public onlyOwner { function setHeir(address _newHeir) public onlyOwner {
...@@ -113,13 +113,6 @@ contract Heritable is Ownable { ...@@ -113,13 +113,6 @@ contract Heritable is Ownable {
timeOfDeath_ = 0; timeOfDeath_ = 0;
} }
function setHeartbeatTimeout(uint256 _newHeartbeatTimeout)
internal onlyOwner
{
require(ownerLives());
heartbeatTimeout_ = _newHeartbeatTimeout;
}
function ownerLives() internal view returns (bool) { function ownerLives() internal view returns (bool) {
return timeOfDeath_ == 0; return timeOfDeath_ == 0;
} }
......
...@@ -19,17 +19,19 @@ contract('CappedCrowdsale', function ([_, wallet]) { ...@@ -19,17 +19,19 @@ contract('CappedCrowdsale', function ([_, wallet]) {
beforeEach(async function () { beforeEach(async function () {
this.token = await SimpleToken.new(); this.token = await SimpleToken.new();
this.crowdsale = await CappedCrowdsale.new(rate, wallet, this.token.address, cap);
await this.token.transfer(this.crowdsale.address, tokenSupply);
}); });
describe('creating a valid crowdsale', function () { it('rejects a cap of zero', async function () {
it('should fail with zero cap', async function () {
await expectThrow( await expectThrow(
CappedCrowdsale.new(rate, wallet, 0, this.token.address), CappedCrowdsale.new(rate, wallet, this.token.address, 0),
EVMRevert, EVMRevert,
); );
}); });
context('with crowdsale', function () {
beforeEach(async function () {
this.crowdsale = await CappedCrowdsale.new(rate, wallet, this.token.address, cap);
await this.token.transfer(this.crowdsale.address, tokenSupply);
}); });
describe('accepting payments', function () { describe('accepting payments', function () {
...@@ -70,4 +72,5 @@ contract('CappedCrowdsale', function ([_, wallet]) { ...@@ -70,4 +72,5 @@ contract('CappedCrowdsale', function ([_, wallet]) {
(await this.crowdsale.capReached()).should.equal(true); (await this.crowdsale.capReached()).should.equal(true);
}); });
}); });
});
}); });
...@@ -2,6 +2,7 @@ const { ether } = require('../helpers/ether'); ...@@ -2,6 +2,7 @@ const { ether } = require('../helpers/ether');
const { advanceBlock } = require('../helpers/advanceToBlock'); const { advanceBlock } = require('../helpers/advanceToBlock');
const { increaseTimeTo, duration } = require('../helpers/increaseTime'); const { increaseTimeTo, duration } = require('../helpers/increaseTime');
const { latestTime } = require('../helpers/latestTime'); const { latestTime } = require('../helpers/latestTime');
const { assertRevert } = require('../helpers/assertRevert');
const BigNumber = web3.BigNumber; const BigNumber = web3.BigNumber;
...@@ -32,6 +33,22 @@ contract('IncreasingPriceCrowdsale', function ([_, investor, wallet, purchaser]) ...@@ -32,6 +33,22 @@ contract('IncreasingPriceCrowdsale', function ([_, investor, wallet, purchaser])
this.closingTime = this.startTime + duration.weeks(1); this.closingTime = this.startTime + duration.weeks(1);
this.afterClosingTime = this.closingTime + duration.seconds(1); this.afterClosingTime = this.closingTime + duration.seconds(1);
this.token = await SimpleToken.new(); this.token = await SimpleToken.new();
});
it('rejects a final rate larger than the initial rate', async function () {
await assertRevert(IncreasingPriceCrowdsale.new(
this.startTime, this.closingTime, wallet, this.token.address, initialRate, initialRate.plus(1)
));
});
it('rejects a final rate of zero', async function () {
await assertRevert(IncreasingPriceCrowdsale.new(
this.startTime, this.closingTime, wallet, this.token.address, initialRate, 0
));
});
context('with crowdsale', function () {
beforeEach(async function () {
this.crowdsale = await IncreasingPriceCrowdsale.new( this.crowdsale = await IncreasingPriceCrowdsale.new(
this.startTime, this.closingTime, wallet, this.token.address, initialRate, finalRate this.startTime, this.closingTime, wallet, this.token.address, initialRate, finalRate
); );
...@@ -80,4 +97,5 @@ contract('IncreasingPriceCrowdsale', function ([_, investor, wallet, purchaser]) ...@@ -80,4 +97,5 @@ contract('IncreasingPriceCrowdsale', function ([_, investor, wallet, purchaser])
(await this.token.balanceOf(investor)).should.be.bignumber.equal(value.mul(rateAtTime450000)); (await this.token.balanceOf(investor)).should.be.bignumber.equal(value.mul(rateAtTime450000));
}); });
}); });
});
}); });
const { shouldBehaveLikeMintedCrowdsale } = require('./MintedCrowdsale.behavior'); const { shouldBehaveLikeMintedCrowdsale } = require('./MintedCrowdsale.behavior');
const { ether } = require('../helpers/ether'); const { ether } = require('../helpers/ether');
const { assertRevert } = require('../helpers/assertRevert');
const BigNumber = web3.BigNumber; const BigNumber = web3.BigNumber;
const MintedCrowdsale = artifacts.require('MintedCrowdsaleImpl'); const MintedCrowdsale = artifacts.require('MintedCrowdsaleImpl');
const MintableToken = artifacts.require('MintableToken'); const MintableToken = artifacts.require('MintableToken');
const RBACMintableToken = artifacts.require('RBACMintableToken'); const RBACMintableToken = artifacts.require('RBACMintableToken');
const StandardToken = artifacts.require('StandardToken');
contract('MintedCrowdsale', function ([_, investor, wallet, purchaser]) { contract('MintedCrowdsale', function ([_, investor, wallet, purchaser]) {
const rate = new BigNumber(1000); const rate = new BigNumber(1000);
...@@ -40,4 +42,19 @@ contract('MintedCrowdsale', function ([_, investor, wallet, purchaser]) { ...@@ -40,4 +42,19 @@ contract('MintedCrowdsale', function ([_, investor, wallet, purchaser]) {
shouldBehaveLikeMintedCrowdsale([_, investor, wallet, purchaser], rate, value); shouldBehaveLikeMintedCrowdsale([_, investor, wallet, purchaser], rate, value);
}); });
describe('using non-mintable token', function () {
beforeEach(async function () {
this.token = await StandardToken.new();
this.crowdsale = await MintedCrowdsale.new(rate, wallet, this.token.address);
});
it('rejects bare payments', async function () {
await assertRevert(this.crowdsale.send(value));
});
it('rejects token purchases', async function () {
await assertRevert(this.crowdsale.buyTokens(investor, { value: value, from: purchaser }));
});
});
}); });
...@@ -16,7 +16,6 @@ const SimpleToken = artifacts.require('SimpleToken'); ...@@ -16,7 +16,6 @@ const SimpleToken = artifacts.require('SimpleToken');
contract('PostDeliveryCrowdsale', function ([_, investor, wallet, purchaser]) { contract('PostDeliveryCrowdsale', function ([_, investor, wallet, purchaser]) {
const rate = new BigNumber(1); const rate = new BigNumber(1);
const value = ether(42);
const tokenSupply = new BigNumber('1e22'); const tokenSupply = new BigNumber('1e22');
before(async function () { before(async function () {
...@@ -27,7 +26,6 @@ contract('PostDeliveryCrowdsale', function ([_, investor, wallet, purchaser]) { ...@@ -27,7 +26,6 @@ contract('PostDeliveryCrowdsale', function ([_, investor, wallet, purchaser]) {
beforeEach(async function () { beforeEach(async function () {
this.openingTime = (await latestTime()) + duration.weeks(1); this.openingTime = (await latestTime()) + duration.weeks(1);
this.closingTime = this.openingTime + duration.weeks(1); this.closingTime = this.openingTime + duration.weeks(1);
this.beforeEndTime = this.closingTime - duration.hours(1);
this.afterClosingTime = this.closingTime + duration.seconds(1); this.afterClosingTime = this.closingTime + duration.seconds(1);
this.token = await SimpleToken.new(); this.token = await SimpleToken.new();
this.crowdsale = await PostDeliveryCrowdsale.new( this.crowdsale = await PostDeliveryCrowdsale.new(
...@@ -36,30 +34,41 @@ contract('PostDeliveryCrowdsale', function ([_, investor, wallet, purchaser]) { ...@@ -36,30 +34,41 @@ contract('PostDeliveryCrowdsale', function ([_, investor, wallet, purchaser]) {
await this.token.transfer(this.crowdsale.address, tokenSupply); await this.token.transfer(this.crowdsale.address, tokenSupply);
}); });
it('should not immediately assign tokens to beneficiary', async function () { context('after opening time', function () {
beforeEach(async function () {
await increaseTimeTo(this.openingTime); await increaseTimeTo(this.openingTime);
});
context('with bought tokens', function () {
const value = ether(42);
beforeEach(async function () {
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }); await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
});
it('does not immediately assign tokens to beneficiaries', async function () {
(await this.token.balanceOf(investor)).should.be.bignumber.equal(0); (await this.token.balanceOf(investor)).should.be.bignumber.equal(0);
}); });
it('should not allow beneficiaries to withdraw tokens before crowdsale ends', async function () { it('does not allow beneficiaries to withdraw tokens before crowdsale ends', async function () {
await increaseTimeTo(this.beforeEndTime);
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
await expectThrow(this.crowdsale.withdrawTokens({ from: investor }), EVMRevert); await expectThrow(this.crowdsale.withdrawTokens({ from: investor }), EVMRevert);
}); });
it('should allow beneficiaries to withdraw tokens after crowdsale ends', async function () { context('after closing time', function () {
await increaseTimeTo(this.openingTime); beforeEach(async function () {
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
await increaseTimeTo(this.afterClosingTime); await increaseTimeTo(this.afterClosingTime);
await this.crowdsale.withdrawTokens({ from: investor });
}); });
it('should return the amount of tokens bought', async function () { it('allows beneficiaries to withdraw tokens', async function () {
await increaseTimeTo(this.openingTime);
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
await increaseTimeTo(this.afterClosingTime);
await this.crowdsale.withdrawTokens({ from: investor }); await this.crowdsale.withdrawTokens({ from: investor });
(await this.token.balanceOf(investor)).should.be.bignumber.equal(value); (await this.token.balanceOf(investor)).should.be.bignumber.equal(value);
}); });
it('rejects multiple withdrawals', async function () {
await this.crowdsale.withdrawTokens({ from: investor });
await expectThrow(this.crowdsale.withdrawTokens({ from: investor }), EVMRevert);
});
});
});
});
}); });
...@@ -30,16 +30,12 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor, purchaser ...@@ -30,16 +30,12 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor, purchaser
this.openingTime = (await latestTime()) + duration.weeks(1); this.openingTime = (await latestTime()) + duration.weeks(1);
this.closingTime = this.openingTime + duration.weeks(1); this.closingTime = this.openingTime + duration.weeks(1);
this.afterClosingTime = this.closingTime + duration.seconds(1); this.afterClosingTime = this.closingTime + duration.seconds(1);
this.preWalletBalance = await ethGetBalance(wallet);
this.token = await SimpleToken.new(); this.token = await SimpleToken.new();
this.crowdsale = await RefundableCrowdsale.new(
this.openingTime, this.closingTime, rate, wallet, this.token.address, goal, { from: owner }
);
await this.token.transfer(this.crowdsale.address, tokenSupply);
}); });
describe('creating a valid crowdsale', function () { it('rejects a goal of zero', async function () {
it('should fail with zero goal', async function () {
await expectThrow( await expectThrow(
RefundableCrowdsale.new( RefundableCrowdsale.new(
this.openingTime, this.closingTime, rate, wallet, this.token.address, 0, { from: owner } this.openingTime, this.closingTime, rate, wallet, this.token.address, 0, { from: owner }
...@@ -47,39 +43,72 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor, purchaser ...@@ -47,39 +43,72 @@ contract('RefundableCrowdsale', function ([_, owner, wallet, investor, purchaser
EVMRevert, EVMRevert,
); );
}); });
context('with crowdsale', function () {
beforeEach(async function () {
this.crowdsale = await RefundableCrowdsale.new(
this.openingTime, this.closingTime, rate, wallet, this.token.address, goal, { from: owner }
);
await this.token.transfer(this.crowdsale.address, tokenSupply);
}); });
it('should deny refunds before end', async function () { context('before opening time', function () {
await expectThrow(this.crowdsale.claimRefund({ from: investor }), EVMRevert); it('denies refunds', async function () {
await increaseTimeTo(this.openingTime);
await expectThrow(this.crowdsale.claimRefund({ from: investor }), EVMRevert); await expectThrow(this.crowdsale.claimRefund({ from: investor }), EVMRevert);
}); });
});
it('should deny refunds after end if goal was reached', async function () { context('after opening time', function () {
beforeEach(async function () {
await increaseTimeTo(this.openingTime); await increaseTimeTo(this.openingTime);
await this.crowdsale.sendTransaction({ value: goal, from: investor }); });
await increaseTimeTo(this.afterClosingTime);
it('denies refunds', async function () {
await expectThrow(this.crowdsale.claimRefund({ from: investor }), EVMRevert); await expectThrow(this.crowdsale.claimRefund({ from: investor }), EVMRevert);
}); });
it('should allow refunds after end if goal was not reached', async function () { context('with unreached goal', function () {
await increaseTimeTo(this.openingTime); beforeEach(async function () {
await this.crowdsale.sendTransaction({ value: lessThanGoal, from: investor }); await this.crowdsale.sendTransaction({ value: lessThanGoal, from: investor });
});
context('after closing time and finalization', function () {
beforeEach(async function () {
await increaseTimeTo(this.afterClosingTime); await increaseTimeTo(this.afterClosingTime);
await this.crowdsale.finalize({ from: owner }); await this.crowdsale.finalize({ from: owner });
});
it('refunds', async function () {
const pre = await ethGetBalance(investor); const pre = await ethGetBalance(investor);
await this.crowdsale.claimRefund({ from: investor, gasPrice: 0 }); await this.crowdsale.claimRefund({ from: investor, gasPrice: 0 });
const post = await ethGetBalance(investor); const post = await ethGetBalance(investor);
post.minus(pre).should.be.bignumber.equal(lessThanGoal); post.minus(pre).should.be.bignumber.equal(lessThanGoal);
}); });
});
});
it('should forward funds to wallet after end if goal was reached', async function () { context('with reached goal', function () {
await increaseTimeTo(this.openingTime); beforeEach(async function () {
await this.crowdsale.sendTransaction({ value: goal, from: investor }); await this.crowdsale.sendTransaction({ value: goal, from: investor });
});
context('after closing time and finalization', function () {
beforeEach(async function () {
await increaseTimeTo(this.afterClosingTime); await increaseTimeTo(this.afterClosingTime);
const pre = await ethGetBalance(wallet);
await this.crowdsale.finalize({ from: owner }); await this.crowdsale.finalize({ from: owner });
const post = await ethGetBalance(wallet); });
post.minus(pre).should.be.bignumber.equal(goal);
it('denies refunds', async function () {
await expectThrow(this.crowdsale.claimRefund({ from: investor }), EVMRevert);
});
it('forwards funds to wallet', async function () {
const postWalletBalance = await ethGetBalance(wallet);
postWalletBalance.minus(this.preWalletBalance).should.be.bignumber.equal(goal);
});
});
});
});
}); });
}); });
...@@ -29,6 +29,22 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) { ...@@ -29,6 +29,22 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) {
this.closingTime = this.openingTime + duration.weeks(1); this.closingTime = this.openingTime + duration.weeks(1);
this.afterClosingTime = this.closingTime + duration.seconds(1); this.afterClosingTime = this.closingTime + duration.seconds(1);
this.token = await SimpleToken.new(); this.token = await SimpleToken.new();
});
it('rejects an opening time in the past', async function () {
await expectThrow(TimedCrowdsale.new(
(await latestTime()) - duration.days(1), this.closingTime, rate, wallet, this.token.address
), EVMRevert);
});
it('rejects a closing time before the opening time', async function () {
await expectThrow(TimedCrowdsale.new(
this.openingTime, this.openingTime - duration.seconds(1), rate, wallet, this.token.address
), EVMRevert);
});
context('with crowdsale', function () {
beforeEach(async function () {
this.crowdsale = await TimedCrowdsale.new(this.openingTime, this.closingTime, rate, wallet, this.token.address); this.crowdsale = await TimedCrowdsale.new(this.openingTime, this.closingTime, rate, wallet, this.token.address);
await this.token.transfer(this.crowdsale.address, tokenSupply); await this.token.transfer(this.crowdsale.address, tokenSupply);
}); });
...@@ -57,4 +73,5 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) { ...@@ -57,4 +73,5 @@ contract('TimedCrowdsale', function ([_, investor, wallet, purchaser]) {
await expectThrow(this.crowdsale.buyTokens(investor, { value: value, from: purchaser }), EVMRevert); await expectThrow(this.crowdsale.buyTokens(investor, { value: value, from: purchaser }), EVMRevert);
}); });
}); });
});
}); });
...@@ -14,28 +14,28 @@ contract('SplitPayment', function ([_, owner, payee1, payee2, payee3, nonpayee1, ...@@ -14,28 +14,28 @@ contract('SplitPayment', function ([_, owner, payee1, payee2, payee3, nonpayee1,
const amount = web3.toWei(1.0, 'ether'); const amount = web3.toWei(1.0, 'ether');
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
it('cannot be created with no payees', async function () { it('rejects an empty set of payees', async function () {
await expectThrow(SplitPayment.new([], []), EVMRevert); await expectThrow(SplitPayment.new([], []), EVMRevert);
}); });
it('requires shares for each payee', async function () { it('rejects more payees than shares', async function () {
await expectThrow(SplitPayment.new([payee1, payee2, payee3], [20, 30]), EVMRevert); await expectThrow(SplitPayment.new([payee1, payee2, payee3], [20, 30]), EVMRevert);
}); });
it('requires a payee for each share', async function () { it('rejects more shares than payees', async function () {
await expectThrow(SplitPayment.new([payee1, payee2], [20, 30, 40]), EVMRevert); await expectThrow(SplitPayment.new([payee1, payee2], [20, 30, 40]), EVMRevert);
}); });
it('requires non-null payees', async function () { it('rejects null payees', async function () {
await expectThrow(SplitPayment.new([payee1, ZERO_ADDRESS], [20, 30]), EVMRevert); await expectThrow(SplitPayment.new([payee1, ZERO_ADDRESS], [20, 30]), EVMRevert);
}); });
it('requires non-zero shares', async function () { it('rejects zero-valued shares', async function () {
await expectThrow(SplitPayment.new([payee1, payee2], [20, 0]), EVMRevert); await expectThrow(SplitPayment.new([payee1, payee2], [20, 0]), EVMRevert);
}); });
it('rejects repeated payees', async function () { it('rejects repeated payees', async function () {
await expectThrow(SplitPayment.new([payee1, payee1], [20, 0]), EVMRevert); await expectThrow(SplitPayment.new([payee1, payee1], [20, 30]), EVMRevert);
}); });
context('once deployed', function () { context('once deployed', function () {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment