governance_test.rs (663 lines)
β
ββ Phase 1: PROPOSAL LIFECYCLE (12 tests)
β ββ 1.1 Creation (4 tests)
β β ββ Basic proposal creation with defaults
β β ββ Custom parameters
β β ββ Multiple proposals
β β ββ Invalid parameters
β β
β ββ 1.2 Retrieval (2 tests)
β ββ Existing proposal
β ββ Non-existent proposal
β
ββ Phase 2: VOTING MECHANICS (15 tests)
β ββ 2.1 Vote Casting (5 tests)
β β ββ Single For vote
β β ββ For/Against/Abstain votes
β β ββ Multiple voters
β β ββ Voting power validation
β β ββ Voting after period ends
β β
β ββ 2.2 Duplicate Prevention (2 tests)
β β ββ Same voter cannot vote twice
β β ββ Different voters OK
β β
β ββ 2.3 Threshold Determination (5 tests)
β ββ Threshold met β Passed
β ββ Threshold not met β stays Active
β ββ Exact boundary
β ββ With Against/Abstain votes
β ββ High threshold (90%+)
β
ββ Phase 3: TIMELOCK & EXECUTION (10 tests)
β ββ 3.1 Voting Period (3 tests)
β β ββ Cannot vote after voting_end
β β ββ Can vote before voting_end
β β ββ Finalize after voting ends
β β
β ββ 3.2 Execution Timelock (3 tests)
β β ββ Cannot execute before timelock
β β ββ Can execute after timelock
β β ββ Execute at boundary
β β
β ββ 3.3 Execution (4 tests)
β ββ Successful execution
β ββ Cannot re-execute
β ββ Cannot execute Failed
β ββ Cannot execute Expired
β
ββ Phase 4: MULTISIG OPERATIONS (15 tests)
β ββ 4.1 Admin Management (4 tests)
β β ββ Initialize with default threshold (1)
β β ββ Set multisig admins
β β ββ Set multisig threshold
β β ββ Prevent impossible thresholds
β β
β ββ 4.2 Approvals (5 tests)
β β ββ Admin approves
β β ββ Same admin cannot approve twice
β β ββ Different admins accumulate
β β ββ Non-admin blocked
β β ββ Get approvals
β β
β ββ 4.3 Execution (6 tests)
β ββ Execute when threshold met
β ββ Cannot execute below threshold
β ββ Execute at boundary
β ββ Only admin can execute
β ββ Specialized proposals
β ββ Full multisig workflow
β
ββ Phase 5: ERROR HANDLING (8 tests)
β ββ 5.1 Authorization (2 tests)
β β ββ Unauthorized proposal creation
β β ββ Multisig auth checks
β β
β ββ 5.2 Invalid Operations (3 tests)
β β ββ Vote on non-existent
β β ββ Execute non-existent
β β ββ Invalid vote value
β β
β ββ 5.3 State Validation (3 tests)
β ββ State consistency
β ββ Voting power consistency
β ββ Timestamp ordering
β
ββ Phase 6: EVENT VALIDATION (4 tests)
β ββ proposal_created event
β ββ vote_cast event
β ββ proposal_executed event
β ββ proposal_failed event
β
ββ Phase 7: INTEGRATION SCENARIOS (6 tests)
ββ Complete proposal lifecycle
ββ Proposal fails voting
ββ Multisig with 3 admins (threshold 2)
ββ Multisig with all approvals (threshold 3)
ββ Mixed voting (For/Against/Abstain)
ββ High-threshold proposal (90%)
Total: 70 tests across 7 phases
stateDiagram-v2
[*] --> Active: create_proposal()
Active --> Passed: vote() reaches threshold
Active --> Expired: timestamp > voting_end
Active --> Failed: mark_proposal_failed()
Passed --> Executed: execute_proposal() (after timelock)
Failed --> [*]
Expired --> [*]
Executed --> [*]
note right of Active
Can receive votes
voting_end timer active
end note
note right of Passed
Votes met threshold
Waiting for timelock
end note
note right of Executed
Proposal applied
Terminal state
end note
Total Voting Power = 100
Vote Distribution:
- 55 For β (exceeds 50% threshold)
- 30 Against
- 15 Abstain
Result: PASSED
Threshold: 50 (basis points 5000)
Actual: 55 (votes_for) >= 50 (required)
100% = 10,000 basis points
90% = 9,000 basis points
75% = 7,500 basis points
50% = 5,000 basis points
25% = 2,500 basis points
1% = 100 basis points
Timeline (timestamps in seconds from now)
t=0 t=voting_period t=voting_period+execution_timelock
β β β
ββ Active ββ Passed ββ Can Execute
β (votes) β (threshold met) β
β β β
βββββββββββββ΄ββββββββββββββββββββββββ
Phase 1: VOTING PHASE (0 to voting_period)
- Voters can vote
- Proposal actively accruing votes
- Status: Active β Passed (if threshold met)
Phase 2: GRACE PERIOD / TIMELOCK (voting_period to voting_period+execution_timelock)
- No more votes allowed
- Cannot execute yet
- Status: Passed
- Purpose: Time for stakeholders to review/dispute
Phase 3: EXECUTION WINDOW (after voting_period+execution_timelock)
- Anyone can execute
- Status: Passed β Executed
- Finalized on-chain
test_propose_basic_creates_active_proposal()
test_vote_for_increments_votes_for_count()
test_threshold_met_transitions_to_passed()
test_multiple_voters_accumulate_votes()
test_execute_after_timelock_succeeds()
test_multisig_admin_approves_successfully()test_vote_duplicate_returns_already_voted_error()
test_execute_before_timelock_returns_not_ready_error()
test_non_admin_approve_returns_unauthorized_error()
test_invalid_threshold_returns_invalid_proposal_error()
test_vote_zero_power_returns_invalid_error()
test_re_execute_returns_already_executed_error()test_threshold_exactly_met_passes_proposal()
test_execute_at_timelock_boundary_succeeds()
test_abort(), high_threshold_9000_basis_points_only_9_of_10()
test_proposal_counter_increment_uniqueness()/// Standard test setup function
fn setup_test_env() -> (Env, Address, Address, u64) {
let env = Env::default();
env.mock_all_auths();
let admin = Address::generate(&env);
let proposal_id = initialize_governance(&env, admin.clone()).unwrap();
(env, admin, proposal_id, /* other data */)
}
/// Test with advance time
#[test]
fn test_with_time_advance() {
let env = Env::default();
env.mock_all_auths();
// Initial time
let initial_timestamp = env.ledger().timestamp();
// Advance time
let new_timestamp = initial_timestamp + 3600; // +1 hour
env.ledger().set(LedgerInfo {
timestamp: new_timestamp,
sequence_number: env.ledger().sequence() + 1,
..env.ledger()
});
// Tests with new timestamp
assert_eq!(env.ledger().timestamp(), new_timestamp);
}| Component | Tests | Coverage Goal | Notes |
|---|---|---|---|
| create_proposal | 4 | 100% | All code paths |
| vote | 7 | 100% | All vote types + errors |
| execute_proposal | 8 | 100% | All states + timelocks |
| mark_proposal_failed | 2 | 100% | Success + errors |
| get_proposal | 2 | 100% | Hit + miss cases |
| get_vote | 2 | 100% | Hit + miss cases |
| set_multisig_admins | 3 | 100% | Valid + errors |
| set_multisig_threshold | 3 | 100% | Valid + errors |
| approve_proposal | 5 | 100% | All paths |
| execute_multisig_proposal | 6 | 100% | Threshold logic |
| Events | 4 | 100% | All event types |
| Integration | 6 | 100% | Full workflows |
| Error Handling | 8 | 100% | All errors |
| TOTAL | 70 | 95%+ | Comprehensive |
1. Create proposal (default params)
2. Voter1 votes For (50 power)
3. Voter2 votes For (50 power)
4. Threshold reached (100 >= 50%) β Passed
5. Wait for timelock (skip time 2 days)
6. Execute proposal β Executed
1. Init 3 admins, threshold=2
2. Create proposal
3. Admin1 approves (1/2)
4. Admin2 approves (2/2) β Threshold met
5. Admin3 approves (3/2, allowed but not needed)
6. Execute proposal β Executed
1. Create proposal (50% threshold)
2. Voter1 votes For (30 power)
3. Voter2 votes Against (30 power)
4. Time expires (voting_end passed)
5. Vote For (30) < Threshold (50) β Failed
6. Cannot execute Failed proposal
1. Create proposal (90% threshold)
2. 10 voters, each 10 power
3. 9 vote For (90 power)
4. 1 votes Against (10 power)
5. For votes (90) >= Threshold (90) β PASSED
6. Execute after timelock
pub enum GovernanceError {
Unauthorized = 1, // Not authorized for operation
ProposalNotFound = 2, // Proposal ID doesn't exist
ProposalAlreadyExecuted = 3, // Already executed once
ProposalAlreadyFailed = 4, // Proposal failed voting
ProposalNotReady = 5, // Timelock not expired
ThresholdNotMet = 6, // For votes < threshold
InvalidProposal = 7, // Bad parameters
InvalidVote = 8, // Bad vote data
AlreadyVoted = 9, // Voter voted twice
VotingPeriodEnded = 10, // Voting window closed
ExecutionFailed = 11, // Execution failed
InvalidMultisigConfig = 12, // Bad multisig setup
InsufficientApprovals = 13, // Not enough approvals
ProposalExpired = 14, // Too old to vote
}Each error must have dedicated test case(s)
for each test:
β Setup environment (Env, addresses)
β Perform action
β Assert expected result
β Verify no side effects
β Document assumptions
β Add NatSpec comment
β Name describes exact scenario
β Single responsibility (one thing per test)
Every governance test must include:
/// Tests that [specific behavior] occurs when [specific condition].
///
/// # Setup
/// - [what's initialized]
/// - [addresses created]
/// - [initial state]
///
/// # Test
/// 1. [First action]
/// 2. [Second action]
/// 3. [Expected result]
///
/// # Validation
/// - [What's verified]
/// - [What shouldn't change]
/// - [Error cases handled]
///
/// # Security Note
/// - [Any auth checks]
/// - [State assumptions]
#[test]
fn test_xxx() { ... }- β 70+ tests implemented
- β 95%+ code coverage
- β 0 compiler warnings
- β All tests passing
- β All error cases covered
- β All state transitions tested
- β Integration scenarios complete
- β Documentation comprehensive
- β Security assumptions validated
- β Ready for production
Next Steps:
- Open governance_test.rs
- Uncomment existing test helpers
- Start implementing Phase 1 tests
- Follow the timeline: 48 hours
- Commit with comprehensive message
Reference: GOVERNANCE_TEST_IMPLEMENTATION_PLAN.md