1+ // SPDX-License-Identifier: MIT
2+ pragma solidity ^ 0.8.26 ;
3+
4+ import {Test, console} from "forge-std/Test.sol " ;
5+ import {Voting} from "../src/token/Voting.sol " ;
6+ import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol " ;
7+
8+ contract VotingTest is Test {
9+ Voting public voting;
10+ address public owner;
11+ address public alice;
12+ address public bob;
13+
14+ function setUp () public {
15+ owner = address (this );
16+ alice = makeAddr ("alice " );
17+ bob = makeAddr ("bob " );
18+
19+ voting = new Voting ();
20+
21+ // Fund test accounts
22+ vm.deal (alice, 10 ether);
23+ vm.deal (bob, 10 ether);
24+ }
25+
26+ function testOwnership () public view {
27+ assertEq (voting.owner (), owner);
28+ }
29+
30+ function testAllocateVotes () public {
31+ // Allocate 5 votes to Alice
32+ voting.allocateVotes (alice, 5 );
33+
34+ // Check allocation
35+ (uint256 voteCount , uint256 expiryTimestamp ) = voting.voteAllocations (alice);
36+ assertEq (voteCount, 5 , "Alice's vote count should be 5 " );
37+
38+ // Check timestamp (roughly)
39+ uint256 expectedExpiry = block .timestamp + 7 days ;
40+ assertApproxEqAbs (expiryTimestamp, expectedExpiry, 1 , "Expiry should be about a week from now " );
41+ }
42+
43+ function testAllocateVotesRequiresOwner () public {
44+ // Try to allocate votes as Alice (not owner)
45+ vm.prank (alice);
46+ vm.expectRevert (abi.encodeWithSelector (Ownable.OwnableUnauthorizedAccount.selector , alice));
47+ voting.allocateVotes (bob, 5 );
48+ }
49+
50+ function testVoting () public {
51+ // Allocate 3 votes to Alice
52+ voting.allocateVotes (alice, 3 );
53+
54+ // Alice votes
55+ vm.prank (alice);
56+ bool success = voting.vote ();
57+ assertTrue (success, "Vote should succeed " );
58+
59+ // Check remaining votes
60+ (uint256 voteCount , ) = voting.voteAllocations (alice);
61+ assertEq (voteCount, 2 , "Alice should have 2 votes remaining " );
62+
63+ // Vote again
64+ vm.prank (alice);
65+ success = voting.vote ();
66+ assertTrue (success, "Second vote should succeed " );
67+
68+ // Check remaining votes again
69+ (voteCount, ) = voting.voteAllocations (alice);
70+ assertEq (voteCount, 1 , "Alice should have 1 vote remaining " );
71+ }
72+
73+ function testCannotVoteWithoutAllocation () public {
74+ // Bob tries to vote without allocation
75+ vm.prank (bob);
76+ // For an address with no allocation, the expiryTimestamp is 0, so it's actually expired
77+ vm.expectRevert ("Votes expired " );
78+ voting.vote ();
79+ }
80+
81+ function testCannotVoteAfterDepleted () public {
82+ // Allocate 1 vote to Alice
83+ voting.allocateVotes (alice, 1 );
84+
85+ // Alice votes once
86+ vm.prank (alice);
87+ voting.vote ();
88+
89+ // Try to vote again
90+ vm.prank (alice);
91+ vm.expectRevert ("No votes available " );
92+ voting.vote ();
93+ }
94+
95+ function testVoteExpiration () public {
96+ // Allocate 5 votes to Alice
97+ voting.allocateVotes (alice, 5 );
98+
99+ // Move time forward one week + 1 second
100+ vm.warp (block .timestamp + 7 days + 1 seconds);
101+
102+ // Alice tries to vote after expiration
103+ vm.prank (alice);
104+ vm.expectRevert ("Votes expired " );
105+ voting.vote ();
106+ }
107+
108+ function testHasVotes () public {
109+ // Allocate 3 votes to Alice
110+ voting.allocateVotes (alice, 3 );
111+
112+ // Check if Alice has votes
113+ bool hasVotes = voting.hasVotes (alice);
114+ assertTrue (hasVotes, "Alice should have votes " );
115+
116+ // Bob should not have votes
117+ hasVotes = voting.hasVotes (bob);
118+ assertFalse (hasVotes, "Bob should not have votes " );
119+
120+ // Alice votes all 3 times
121+ vm.startPrank (alice);
122+ voting.vote ();
123+ voting.vote ();
124+ voting.vote ();
125+ vm.stopPrank ();
126+
127+ // Alice should not have votes anymore
128+ hasVotes = voting.hasVotes (alice);
129+ assertFalse (hasVotes, "Alice should not have votes after using all " );
130+ }
131+
132+ function testGetRemainingVotes () public {
133+ // Allocate 5 votes to Alice
134+ voting.allocateVotes (alice, 5 );
135+
136+ // Check remaining votes
137+ uint256 remaining = voting.getRemainingVotes (alice);
138+ assertEq (remaining, 5 , "Alice should have 5 votes " );
139+
140+ // Alice votes twice
141+ vm.startPrank (alice);
142+ voting.vote ();
143+ voting.vote ();
144+ vm.stopPrank ();
145+
146+ // Check remaining votes again
147+ remaining = voting.getRemainingVotes (alice);
148+ assertEq (remaining, 3 , "Alice should have 3 votes remaining " );
149+
150+ // Move time forward past expiration
151+ vm.warp (block .timestamp + 7 days + 1 seconds);
152+
153+ // Check remaining votes after expiration
154+ remaining = voting.getRemainingVotes (alice);
155+ assertEq (remaining, 0 , "Expired votes should return 0 " );
156+ }
157+
158+ function testReallocation () public {
159+ // Allocate 3 votes to Alice
160+ voting.allocateVotes (alice, 3 );
161+
162+ // Alice uses 1 vote
163+ vm.prank (alice);
164+ voting.vote ();
165+
166+ // Check remaining
167+ uint256 remaining = voting.getRemainingVotes (alice);
168+ assertEq (remaining, 2 , "Alice should have 2 votes remaining " );
169+
170+ // Reallocate 5 votes to Alice
171+ voting.allocateVotes (alice, 5 );
172+
173+ // Check new allocation
174+ remaining = voting.getRemainingVotes (alice);
175+ assertEq (remaining, 5 , "Alice should have 5 votes after reallocation " );
176+ }
177+
178+ function testMultipleUsers () public {
179+ // Allocate votes to Alice and Bob
180+ voting.allocateVotes (alice, 3 );
181+ voting.allocateVotes (bob, 2 );
182+
183+ // Both vote
184+ vm.prank (alice);
185+ voting.vote ();
186+
187+ vm.prank (bob);
188+ voting.vote ();
189+
190+ // Check remaining
191+ uint256 aliceVotes = voting.getRemainingVotes (alice);
192+ uint256 bobVotes = voting.getRemainingVotes (bob);
193+
194+ assertEq (aliceVotes, 2 , "Alice should have 2 votes remaining " );
195+ assertEq (bobVotes, 1 , "Bob should have 1 vote remaining " );
196+ }
197+ }
0 commit comments