Skip to content

Commit 17bf914

Browse files
authored
Create test_dao.py
1 parent b6d7add commit 17bf914

File tree

1 file changed

+203
-0
lines changed

1 file changed

+203
-0
lines changed

tests/test_dao.py

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import pytest
2+
from web3 import Web3
3+
from solcx import compile_source
4+
5+
# Sample Solidity code for the DAO contract
6+
DAO_CONTRACT_SOURCE = '''
7+
// SPDX-License-Identifier: MIT
8+
pragma solidity ^0.8.0;
9+
10+
contract DAO {
11+
struct Proposal {
12+
string description;
13+
uint256 voteCount;
14+
mapping(address => bool) voters;
15+
bool executed;
16+
}
17+
18+
address public admin;
19+
Proposal[] public proposals;
20+
uint256 public proposalCount;
21+
uint256 public votingPeriod;
22+
uint256 public quorum;
23+
24+
event ProposalCreated(uint256 proposalId, string description);
25+
event Voted(uint256 proposalId, address voter);
26+
event ProposalExecuted(uint256 proposalId);
27+
28+
modifier onlyAdmin() {
29+
require(msg.sender == admin, "Only admin can call this function");
30+
_;
31+
}
32+
33+
modifier proposalExists(uint256 _proposalId) {
34+
require(_proposalId < proposalCount, "Proposal does not exist");
35+
_;
36+
}
37+
38+
modifier notVoted(uint256 _proposalId) {
39+
require(!proposals[_proposalId].voters[msg.sender], "You have already voted");
40+
_;
41+
}
42+
43+
modifier notExecuted(uint256 _proposalId) {
44+
require(!proposals[_proposalId].executed, "Proposal already executed");
45+
_;
46+
}
47+
48+
constructor(uint256 _votingPeriod, uint256 _quorum) {
49+
admin = msg.sender;
50+
votingPeriod = _votingPeriod;
51+
quorum = _quorum;
52+
}
53+
54+
function createProposal(string memory _description) public onlyAdmin {
55+
Proposal storage newProposal = proposals.push();
56+
newProposal.description = _description;
57+
newProposal.voteCount = 0;
58+
newProposal.executed = false;
59+
proposalCount++;
60+
61+
emit ProposalCreated(proposalCount - 1, _description);
62+
}
63+
64+
function vote(uint256 _proposalId) public
65+
proposalExists(_proposalId)
66+
notVoted(_proposalId)
67+
notExecuted(_proposalId)
68+
{
69+
Proposal storage proposal = proposals[_proposalId];
70+
proposal.voters[msg.sender] = true;
71+
proposal.voteCount++;
72+
73+
emit Voted(_proposalId, msg.sender);
74+
}
75+
76+
function executeProposal(uint256 _proposalId) public
77+
proposalExists(_proposalId)
78+
notExecuted(_proposalId)
79+
{
80+
Proposal storage proposal = proposals[_proposalId];
81+
require(proposal.voteCount >= quorum, "Not enough votes to execute proposal");
82+
83+
proposal.executed = true;
84+
85+
emit ProposalExecuted(_proposalId);
86+
}
87+
88+
function getProposal(uint256 _proposalId) public view
89+
proposalExists(_proposalId)
90+
returns (string memory, uint256, bool)
91+
{
92+
Proposal storage proposal = proposals[_proposalId];
93+
return (proposal.description, proposal.voteCount, proposal.executed);
94+
}
95+
96+
function getProposalCount() public view returns (uint256) {
97+
return proposalCount;
98+
}
99+
}
100+
'''
101+
102+
@pytest.fixture
103+
def dao_contract(web3):
104+
# Compile the contract
105+
compiled_sol = compile_source(DAO_CONTRACT_SOURCE)
106+
contract_interface = compiled_sol['<stdin>:DAO']
107+
108+
# Deploy the contract
109+
DAOContract = web3.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin'])
110+
tx_hash = DAOContract.constructor(7 days, 2).transact({'from': web3.eth.accounts[0]})
111+
tx_receipt = web3.eth.waitForTransactionReceipt(tx_hash)
112+
113+
return web3.eth.contract(address=tx_receipt.contractAddress, abi=contract_interface['abi'])
114+
115+
def test_create_proposal(dao_contract):
116+
# Arrange
117+
admin = dao_contract.functions.admin().call()
118+
proposal_description = "Proposal 1"
119+
120+
# Act
121+
tx_hash = dao_contract.functions.createProposal(proposal_description).transact({'from': admin})
122+
web3.eth.waitForTransactionReceipt(tx_hash)
123+
124+
# Assert
125+
proposal_count = dao_contract.functions.getProposalCount().call()
126+
assert proposal_count == 1
127+
128+
description, vote_count, executed = dao_contract.functions.getProposal(0).call()
129+
assert description == proposal_description
130+
assert vote_count == 0
131+
assert not executed
132+
133+
def test_vote(dao_contract):
134+
# Arrange
135+
admin = dao_contract.functions.admin().call()
136+
proposal_description = "Proposal 2"
137+
dao_contract.functions.createProposal(proposal_description).transact({'from': admin})
138+
139+
# Act
140+
tx_hash = dao_contract.functions.vote(0).transact({'from': web3.eth.accounts[1]})
141+
web3.eth.waitForTransactionReceipt(tx_hash)
142+
143+
# Assert
144+
description, vote_count, executed = dao_contract.functions.getProposal(0).call()
145+
assert vote_count == 1
146+
147+
def test_execute_proposal(dao_contract):
148+
# Arrange
149+
admin = dao_contract.functions.admin().call()
150+
proposal_description = "Proposal 3"
151+
dao_contract.functions.createProposal(proposal_description).transact({'from': admin})
152+
dao_contract.functions.vote(0).transact({'from': web3.eth.accounts[1]})
153+
154+
# Act
155+
tx_hash = dao_contract.functions.executeProposal(0).transact({'from': admin})
156+
web3.eth.waitForTransactionReceipt(tx_hash)
157+
158+
# Assert
159+
description, vote_count, executed = dao_contract.functions.getProposal(0).call()
160+
assert executed is True
161+
162+
def test_double_vote(dao_contract):
163+
# Arrange
164+
admin = dao_contract.functions.admin().call()
165+
proposal_description = "Proposal 4"
166+
dao_contract.functions.createProposal(proposal_description).transact({'from': admin})
167+
168+
# Act
169+
dao_contract.functions.vote(0).transact({'from': web3.eth.accounts[1]})
170+
171+
# Assert that voting again fails
172+
with pytest.raises(Exception):
173+
dao_contract.functions.vote(0).transact({'from': web3 .eth.accounts[1]})
174+
175+
def test_execute_nonexistent_proposal(dao_contract):
176+
# Arrange
177+
admin = dao_contract.functions.admin().call()
178+
179+
# Act & Assert
180+
with pytest.raises(Exception):
181+
dao_contract.functions.executeProposal(999).transact({'from': admin})
182+
183+
def test_execute_proposal_without_quorum(dao_contract):
184+
# Arrange
185+
admin = dao_contract.functions.admin().call()
186+
proposal_description = "Proposal 5"
187+
dao_contract.functions.createProposal(proposal_description).transact({'from': admin})
188+
189+
# Act & Assert
190+
with pytest.raises(Exception):
191+
dao_contract.functions.executeProposal(0).transact({'from': admin})
192+
193+
def test_get_proposal_count(dao_contract):
194+
# Arrange
195+
admin = dao_contract.functions.admin().call()
196+
dao_contract.functions.createProposal("Proposal 6").transact({'from': admin})
197+
dao_contract.functions.createProposal("Proposal 7").transact({'from': admin})
198+
199+
# Act
200+
proposal_count = dao_contract.functions.getProposalCount().call()
201+
202+
# Assert
203+
assert proposal_count == 2

0 commit comments

Comments
 (0)