@@ -392,9 +392,8 @@ contract TokenVotingTest is TestBase {
392392 // It reverts if the total token supply is 0
393393 address [] memory holders = new address [](1 );
394394 holders[0 ] = alice;
395- uint256 [] memory balances = new uint256 [](1 );
396395
397- (dao, plugin,,) = new SimpleBuilder ().withNewToken (holders, balances ).build ();
396+ (dao, plugin,,) = new SimpleBuilder ().withNewToken (holders, 0 ).build ();
398397 dao.grant (address (plugin), alice, plugin.CREATE_PROPOSAL_PERMISSION_ID ());
399398
400399 vm.expectRevert (TokenVoting.NoVotingPower.selector );
@@ -541,65 +540,190 @@ contract TokenVotingTest is TestBase {
541540 }
542541
543542 modifier givenInTheStandardVotingMode () {
543+ address [] memory holders = new address [](10 );
544+ for (uint256 i = 0 ; i < 10 ; i++ ) {
545+ holders[i] = vm.addr (100 + i);
546+ }
547+ uint256 balance = 10 ether ;
548+
549+ (dao, plugin, token,) = new SimpleBuilder ().withSupportThreshold (500_000 ).withMinParticipation (250_000 )
550+ .withNewToken (holders, balance).build ();
551+
552+ dao.grant (address (plugin), address (this ), plugin.CREATE_PROPOSAL_PERMISSION_ID ());
553+ dao.grant (address (plugin), vm.addr (100 ), plugin.CREATE_PROPOSAL_PERMISSION_ID ());
554+ dao.grant (address (plugin), address (this ), plugin.EXECUTE_PROPOSAL_PERMISSION_ID ());
555+
544556 _;
545557 }
546558
547- function test_WhenInteractingWithANonexistentProposal () external givenInTheStandardVotingMode {
559+ function test_revert_WhenInteractingWithANonexistentProposal () external givenInTheStandardVotingMode {
548560 // It reverts if proposal does not exist
549- vm.skip (true );
561+ vm.expectRevert (abi.encodeWithSelector (MajorityVotingBase.NonexistentProposal.selector , 999 ));
562+ plugin.canExecute (999 );
550563 }
551564
552- function test_WhenVotingBeforeTheProposalHasStarted () external givenInTheStandardVotingMode {
565+ function test_revert_WhenVotingBeforeTheProposalHasStarted () external givenInTheStandardVotingMode {
553566 // It does not allow voting, when the vote has not started yet
554- vm.skip (true );
567+ uint64 futureDate = uint64 (block .timestamp + 1 days);
568+ uint256 proposalId =
569+ plugin.createProposal ("0x " , new Action [](0 ), 0 , futureDate, 0 , IMajorityVoting.VoteOption.None, false );
570+
571+ vm.expectRevert (
572+ abi.encodeWithSelector (
573+ MajorityVotingBase.VoteCastForbidden.selector , proposalId, vm.addr (100 ), IMajorityVoting.VoteOption.Yes
574+ )
575+ );
576+ vm.prank (vm.addr (100 ));
577+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Yes, false );
555578 }
556579
557- function test_WhenAUserWith0TokensTriesToVote () external givenInTheStandardVotingMode {
580+ function test_revert_WhenAUserWith0TokensTriesToVote () external givenInTheStandardVotingMode {
558581 // It should not be able to vote if user has 0 token
559- vm.skip (true );
582+ uint256 proposalId = _createDummyProposal (vm.addr (100 ));
583+
584+ vm.expectRevert (
585+ abi.encodeWithSelector (
586+ MajorityVotingBase.VoteCastForbidden.selector , proposalId, david, IMajorityVoting.VoteOption.Yes
587+ )
588+ );
589+ vm.prank (david); // David has 0 tokens
590+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Yes, false );
560591 }
561592
562593 function test_WhenMultipleUsersVoteYesNoAndAbstain () external givenInTheStandardVotingMode {
563594 // It increases the yes, no, and abstain count and emits correct events
564- vm.skip (true );
595+ uint256 proposalId = _createDummyProposal (vm.addr (100 ));
596+ uint256 bal = 10 ether ;
597+
598+ vm.expectEmit (true , true , true , true );
599+ emit IMajorityVoting.VoteCast (proposalId, vm.addr (101 ), IMajorityVoting.VoteOption.Yes, bal);
600+ vm.prank (vm.addr (101 ));
601+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Yes, false );
602+
603+ vm.expectEmit (true , true , true , true );
604+ emit IMajorityVoting.VoteCast (proposalId, vm.addr (102 ), IMajorityVoting.VoteOption.No, bal);
605+ vm.prank (vm.addr (102 ));
606+ plugin.vote (proposalId, IMajorityVoting.VoteOption.No, false );
607+
608+ vm.expectEmit (true , true , true , true );
609+ emit IMajorityVoting.VoteCast (proposalId, vm.addr (103 ), IMajorityVoting.VoteOption.Abstain, bal);
610+ vm.prank (vm.addr (103 ));
611+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Abstain, false );
612+
613+ (,,, MajorityVotingBase.Tally memory tally ,,,) = plugin.getProposal (proposalId);
614+ assertEq (tally.yes, bal);
615+ assertEq (tally.no, bal);
616+ assertEq (tally.abstain, bal);
565617 }
566618
567- function test_WhenAUserTriesToVoteWithVoteOptionNone () external givenInTheStandardVotingMode {
619+ function test_revert_WhenAUserTriesToVoteWithVoteOptionNone () external givenInTheStandardVotingMode {
568620 // It reverts on voting None
569- vm.skip (true );
621+ uint256 proposalId = _createDummyProposal (vm.addr (100 ));
622+ vm.prank (vm.addr (101 ));
623+ vm.expectRevert (
624+ abi.encodeWithSelector (
625+ MajorityVotingBase.VoteCastForbidden.selector , proposalId, vm.addr (101 ), IMajorityVoting.VoteOption.None
626+ )
627+ );
628+ plugin.vote (proposalId, IMajorityVoting.VoteOption.None, false );
570629 }
571630
572- function test_WhenAUserTriesToReplaceTheirExistingVote () external givenInTheStandardVotingMode {
631+ function test_revert_WhenAUserTriesToReplaceTheirExistingVote () external givenInTheStandardVotingMode {
573632 // It reverts on vote replacement
574- vm.skip (true );
633+ uint256 proposalId = _createDummyProposal (vm.addr (100 ));
634+ vm.prank (vm.addr (101 ));
635+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Yes, false );
636+
637+ vm.prank (vm.addr (101 ));
638+ vm.expectRevert (
639+ abi.encodeWithSelector (
640+ MajorityVotingBase.VoteCastForbidden.selector , proposalId, vm.addr (101 ), IMajorityVoting.VoteOption.No
641+ )
642+ );
643+ plugin.vote (proposalId, IMajorityVoting.VoteOption.No, false );
575644 }
576645
577646 function test_WhenAProposalMeetsExecutionCriteriaBeforeTheEndDate () external givenInTheStandardVotingMode {
578647 // It cannot early execute
579- vm.skip (true );
648+ uint256 proposalId = _createDummyProposal (vm.addr (100 ));
649+ for (uint256 i = 1 ; i <= 6 ; i++ ) {
650+ vm.prank (vm.addr (100 + i));
651+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Yes, false );
652+ }
653+ // Support and Participation are high enough, but it's Standard mode
654+ assertTrue (plugin.isSupportThresholdReachedEarly (proposalId));
655+ assertTrue (plugin.isMinParticipationReached (proposalId));
656+ assertFalse (plugin.canExecute (proposalId));
580657 }
581658
582659 function test_WhenAProposalMeetsParticipationAndSupportThresholdsAfterTheEndDate ()
583660 external
584661 givenInTheStandardVotingMode
585662 {
586663 // It can execute normally if participation and support are met
587- vm.skip (true );
664+ uint256 proposalId = _createDummyProposal (vm.addr (100 ));
665+ // 2 yes (20), 1 no (10) -> 3 voters, 30 total votes -> 30% participation, >50% support
666+ vm.prank (vm.addr (101 ));
667+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Yes, false );
668+ vm.prank (vm.addr (102 ));
669+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Yes, false );
670+ vm.prank (vm.addr (103 ));
671+ plugin.vote (proposalId, IMajorityVoting.VoteOption.No, false );
672+
673+ (,, MajorityVotingBase.ProposalParameters memory params ,,,,) = plugin.getProposal (proposalId);
674+ vm.warp (params.endDate);
675+
676+ assertTrue (plugin.canExecute (proposalId));
677+ plugin.execute (proposalId);
678+ (bool open , bool executed ,,,,,) = plugin.getProposal (proposalId);
679+ assertFalse (open);
680+ assertTrue (executed);
588681 }
589682
590683 function test_WhenVotingWithTheTryEarlyExecutionOption () external givenInTheStandardVotingMode {
591684 // It does not execute early when voting with the `tryEarlyExecution` option
592- vm.skip (true );
685+ uint256 proposalId = _createDummyProposal (vm.addr (100 ));
686+ for (uint256 i = 1 ; i < 7 ; i++ ) {
687+ vm.prank (vm.addr (100 + i));
688+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Yes, false );
689+ }
690+
691+ vm.prank (vm.addr (107 ));
692+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Yes, true ); // try early exec
693+
694+ (, bool executed ,,,,,) = plugin.getProposal (proposalId);
695+ assertFalse (executed);
593696 }
594697
595- function test_WhenTryingToExecuteAProposalThatIsNotYetDecided () external givenInTheStandardVotingMode {
698+ function test_revert_WhenTryingToExecuteAProposalThatIsNotYetDecided () external givenInTheStandardVotingMode {
596699 // It reverts if vote is not decided yet
597- vm.skip (true );
700+ uint256 proposalId = _createDummyProposal (vm.addr (100 ));
701+ vm.expectRevert (abi.encodeWithSelector (MajorityVotingBase.ProposalExecutionForbidden.selector , proposalId));
702+ plugin.execute (proposalId);
598703 }
599704
600- function test_WhenTheCallerDoesNotHaveEXECUTEPROPOSALPERMISSIONID () external givenInTheStandardVotingMode {
705+ function test_revert_WhenTheCallerDoesNotHaveEXECUTEPROPOSALPERMISSIONID () external givenInTheStandardVotingMode {
601706 // It can not execute even if participation and support are met when caller does not have permission
602- vm.skip (true );
707+ uint256 proposalId = _createDummyProposal (vm.addr (100 ));
708+ vm.prank (vm.addr (101 ));
709+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Yes, false );
710+ vm.prank (vm.addr (102 ));
711+ plugin.vote (proposalId, IMajorityVoting.VoteOption.Yes, false );
712+ vm.prank (vm.addr (103 ));
713+ plugin.vote (proposalId, IMajorityVoting.VoteOption.No, false );
714+
715+ (,, MajorityVotingBase.ProposalParameters memory params ,,,,) = plugin.getProposal (proposalId);
716+ vm.warp (params.endDate);
717+
718+ dao.revoke (address (dao), address (plugin), dao.EXECUTE_PERMISSION_ID ());
719+
720+ vm.expectRevert (
721+ abi.encodeWithSelector (
722+ DaoUnauthorized.selector , address (dao), address (plugin), bob, plugin.EXECUTE_PROPOSAL_PERMISSION_ID ()
723+ )
724+ );
725+ vm.prank (bob); // Bob has no permission
726+ plugin.execute (proposalId);
603727 }
604728
605729 modifier givenInTheEarlyExecutionVotingMode () {
0 commit comments