aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei-Chieh, Hsia <passion804222@gmail.com>2018-11-28 18:11:25 +0800
committerChenWei <catsass19@hotmail.com>2018-11-28 18:11:25 +0800
commita5efb275c943a160d40175d65afaa91b435cfc81 (patch)
treeacbfdc5670aae39965251b3a973873f39333a0b8
parent7ddcdd82e3d5d008b420e0fb2a8c2874485106b7 (diff)
downloaddexon-lottery-a5efb275c943a160d40175d65afaa91b435cfc81.tar
dexon-lottery-a5efb275c943a160d40175d65afaa91b435cfc81.tar.gz
dexon-lottery-a5efb275c943a160d40175d65afaa91b435cfc81.tar.bz2
dexon-lottery-a5efb275c943a160d40175d65afaa91b435cfc81.tar.lz
dexon-lottery-a5efb275c943a160d40175d65afaa91b435cfc81.tar.xz
dexon-lottery-a5efb275c943a160d40175d65afaa91b435cfc81.tar.zst
dexon-lottery-a5efb275c943a160d40175d65afaa91b435cfc81.zip
Complete test (#2)
* complete test * update readme
-rw-r--r--README.md13
-rw-r--r--contracts/Election.sol34
-rw-r--r--package.json8
-rw-r--r--test/TestElection.js137
4 files changed, 148 insertions, 44 deletions
diff --git a/README.md b/README.md
index 262fb38..7628e82 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,16 @@
-# Hello DEXON
-**Hello DEXON** is a simple smart contract utilizing DEXON's unbiased randomness.
+# Dexon DApp Workshop 12/01
+**Simple Election DApp**
-## Installation
-1. `git clone https://github.com/dexon-foundation/hello-dexon.git`
-2. `cd hello-dexon`
+## Install
3. `npm install`
## Compile
1. `npm run compile`
+## Testing
+1. `npm run test`
+
## Deploy contract (on DEXON testnet)
1. Copy `secret.js.sample` to `secret.js`.
2. Set the `mnemonic` in `secret.js`.
-3. `truffle migrate --network=testnet`
+3. `npm run deploy`
diff --git a/contracts/Election.sol b/contracts/Election.sol
index da1ba1f..e4e749f 100644
--- a/contracts/Election.sol
+++ b/contracts/Election.sol
@@ -34,8 +34,11 @@ contract Election {
// Announce the elected person and restart election
function resetElection() public onlyOwner {
- refundDeposit();
- announceElectedPerson();
+ if (round > 0) {
+ refundDeposit();
+ announceElectedPerson();
+ }
+
totalVote = 0;
round += 1;
isVoting = false;
@@ -88,26 +91,25 @@ contract Election {
}
function announceElectedPerson() private {
- if (round > 0) {
- uint numOfCandidates = candiatesList.length;
- uint maxVote = 0;
- address highestCandidate;
- for (uint x = 0; x < numOfCandidates; x++) {
- address currentAddr = candiatesList[x];
- Candidate storage currentCandidate = candidateData[round][currentAddr];
- if (currentCandidate.vote > maxVote) {
- highestCandidate = currentAddr;
- }
+ uint numOfCandidates = candiatesList.length;
+ uint maxVote = 0;
+ address highestCandidate;
+ for (uint x = 0; x < numOfCandidates; x++) {
+ address currentAddr = candiatesList[x];
+ Candidate storage currentCandidate = candidateData[round][currentAddr];
+ if (currentCandidate.vote > maxVote) {
+ highestCandidate = currentAddr;
+ maxVote = currentCandidate.vote;
}
- Candidate storage electedPerson = candidateData[round][highestCandidate];
- emit elected(round, highestCandidate, electedPerson.name, electedPerson.vote);
- delete candiatesList;
}
+ Candidate storage electedPerson = candidateData[round][highestCandidate];
+ emit elected(round, highestCandidate, electedPerson.name, electedPerson.vote);
+ delete candiatesList;
}
function sponsor(address candidateAddr) public onlyInRegister payable {
Candidate storage candidate = candidateData[round][candidateAddr];
- require(candidate.isRegistered == true, "candidate not found");
+ require(candidate.isRegistered == true, "Candidate not exists");
candidateAddr.transfer(msg.value);
emit sponsorCandidate(round, candidateAddr, candidate.name, msg.sender, msg.value);
}
diff --git a/package.json b/package.json
index d5a7f77..5d67f01 100644
--- a/package.json
+++ b/package.json
@@ -1,17 +1,17 @@
{
- "name": "hello-dexon",
+ "name": "Simple Election DApp",
"version": "0.0.1",
- "author": "Jimmy Hu",
"license": "MIT",
- "description": "A simple smart contract utilizing DEXON's unbiased randomness.",
+ "description": "A simple election DApp",
"homepage": "https://dexon.org",
"repository": {
"type": "git",
- "url": "https://github.com/dexon-foundation/hello-dexon.git"
+ "url": "https://github.com/cobinhood/dapp-workshop-1201.git"
},
"scripts": {
"postinstall": "rm -rf node_modules/truffle/node_modules/solc && cp -r node_modules/solc node_modules/truffle/node_modules/; touch secret.js",
"compile": "node_modules/.bin/truffle compile",
+ "test": "node_modules/.bin/truffle test",
"deploy": "node_modules/.bin/truffle migrate --network=testnet"
},
"dependencies": {
diff --git a/test/TestElection.js b/test/TestElection.js
index 6e1e7a4..8aae1dd 100644
--- a/test/TestElection.js
+++ b/test/TestElection.js
@@ -14,29 +14,30 @@ async function tryCatch(promise, reason) {
contract('Election', (accounts) => {
let election;
-
+
+ const register = (name, account, value = 1e+18) => election.register(name, { from: account, value });
+
beforeEach('setup contract for each test', async () => {
election = await Election.new();
});
describe('startVoting()', () => {
it('should work correctly', async () => {
- const { logs } = await election.startVoting();
-
- const eventIndex = logs.findIndex(log => log.event === 'voteStart');
+ await election.startVoting();
+
const isVoting = await election.isVoting();
assert.equal(isVoting, true);
- assert.notEqual(eventIndex, -1);
- assert.equal(logs[eventIndex].args.round.toNumber(), 1);
+ });
+
+ it('should revert if it is not called by owner', async () => {
+ tryCatch(election.startVoting({ from: accounts[1] }), 'Only owner is allowed');
});
});
describe('register()', () => {
- const register = (fee) => election.register('william', { from: accounts[1], value: fee });
-
it('should work correctly', async () => {
- const { logs } = await register(1e+18);
+ const { logs } = await register('william', accounts[1]);
const eventIndex = logs.findIndex(log => log.event === 'registered');
const candidateList = await election.getCandidatesList();
@@ -54,16 +55,16 @@ contract('Election', (accounts) => {
it('should revert if is in voting peroid', async () => {
await election.startVoting();
- await tryCatch(register(1e+18), 'Only allowed before voting period');
+ await tryCatch(register('william', accounts[1]), 'Only allowed before voting period');
});
it('should revert if balance is not enough', async () => {
- await tryCatch(register(0.5+18), 'Insufficient deposit');
+ await tryCatch(register('william', accounts[1], 0.5e+18), 'Insufficient deposit');
});
it('should revert if user is already registered', async () => {
- await register(1e+18);
- await tryCatch(register(1e+18), 'Already registered');
+ await register('william', accounts[1])
+ await tryCatch(register('william', accounts[1]), 'Already registered');
});
});
@@ -77,11 +78,9 @@ contract('Election', (accounts) => {
const vote = (targetCandidate, voter = accounts[1]) => election.vote(targetCandidate, { from: voter });
beforeEach('setup candidate', async () => {
- const register = (name, account) => election.register(name, { from: account, value: 1e+18 });
- election = await Election.new();
- register('wayne', accounts[0]);
- register('wei chao', accounts[1]);
- register('william', accounts[2]);
+ await register('wayne', accounts[0]);
+ await register('wei chao', accounts[1]);
+ await register('william', accounts[2]);
});
it('should work correctly', async () => {
@@ -128,4 +127,106 @@ contract('Election', (accounts) => {
await tryCatch(vote(accounts[3]), 'Candidate not exists');
});
});
+
+ describe('resetElection()', () => {
+ it('should work correclty at zero round', async () => {
+ await election.resetElection();
+ const round = (await election.round()).toNumber();
+ const isVoting = await election.isVoting();
+ const totalVote = (await election.totalVote()).toNumber();
+ const candidateList = await election.getCandidatesList();
+
+ assert.equal(totalVote, 0);
+ assert.equal(round, 2);
+ assert.equal(isVoting, false);
+ assert.equal(candidateList.length, 0);
+ });
+
+ it('should work correclty at first round', async () => {
+ // Bad smells(bad pratice) here. Please extract private functions to library to test it if you want to test those private functions.
+ const vote = (targetCandidate, voter = accounts[1]) => election.vote(targetCandidate, { from: voter });
+
+ await register('wayne', accounts[0]);
+ await register('wei chao', accounts[1]);
+ await register('william', accounts[2]);
+
+ await election.startVoting();
+
+ await vote(accounts[0], accounts[0]);
+ await vote(accounts[0], accounts[1]);
+ await vote(accounts[0], accounts[2]);
+ await vote(accounts[1], accounts[3]);
+ await vote(accounts[1], accounts[4]);
+ await vote(accounts[2], accounts[5]);
+
+ const { logs } = await election.resetElection();
+ const electedEventIndex = logs.findIndex(log => log.event === 'elected');
+ const refundEvents = logs.reduce((acc, log) => {
+ if (log.event === 'refund') {
+ acc.push(log);
+ }
+
+ return acc;
+ }, []);
+
+ const wayneRefundEvent = refundEvents.find(event => event.args.candidate === accounts[0]);
+ const weiChaoRefundEvent = refundEvents.find(event => event.args.candidate === accounts[1]);
+ const guaranteedDeposit = (await election.guaranteedDeposit()).toNumber();
+
+ const candidateList = await election.getCandidatesList();
+ const round = (await election.round()).toNumber();
+ const isVoting = await election.isVoting();
+ const totalVote = (await election.totalVote()).toNumber();
+
+ assert.equal(totalVote, 0);
+ assert.equal(round, 2);
+ assert.equal(isVoting, false);
+ assert.equal(candidateList.length, 0);
+
+ assert.equal(refundEvents.length, 2);
+ assert.equal(wayneRefundEvent.args.amount, guaranteedDeposit);
+ assert.equal(weiChaoRefundEvent.args.amount, guaranteedDeposit);
+ assert.equal(logs[electedEventIndex].args.round.toNumber(), 1);
+ assert.equal(logs[electedEventIndex].args.candidate, accounts[0]);
+ assert.equal(logs[electedEventIndex].args.name, 'wayne');
+ assert.equal(logs[electedEventIndex].args.vote.toNumber(), 3);
+ });
+
+ it('should revert if it is not called by owner', async () => {
+ tryCatch(election.resetElection({ from: accounts[1] }), 'Only owner is allowed');
+ });
+ });
+
+ describe('getCandidatesList()', () => {
+ it('should return list correctly', async () => {
+ const candidateList = await election.getCandidatesList();
+
+ assert(candidateList instanceof Array);
+ });
+ });
+
+ describe('sponsor()', () => {
+ it('should work correctly', async () => {
+ await register('william', accounts[1]);
+
+ const prevBalance = (await web3.eth.getBalance(accounts[1])).toNumber();
+
+ await election.sponsor(accounts[1], { from: accounts[0], value: 1e+18 });
+
+ const earn = (await web3.eth.getBalance(accounts[1])).toNumber() - prevBalance;
+
+ assert.equal(earn, 1e+18);
+ });
+
+ it('should revert if is in voting period', async () => {
+ await register('william', accounts[1]);
+ await election.startVoting();
+
+ tryCatch(election.sponsor(accounts[1], { from: accounts[0], value: 1e+18 }), 'Only allowed before voting period');
+ });
+
+ it('should revert if is in voting period', async () => {
+ tryCatch(election.sponsor(accounts[1], { from: accounts[0], value: 1e+18 }), 'Candidate not exists');
+ });
+ });
});