const { expect } = require("chai"); const { ethers } = require("hardhat"); describe("Contrat Voting", function () { let voting; let owner; let voter1; let voter2; let voter3; let nonVoter; beforeEach(async function () { // Déploiement d'un nouveau contrat pour chaque test [owner, voter1, voter2, voter3, nonVoter] = await ethers.getSigners(); const Voting = await ethers.getContractFactory("Voting"); voting = await Voting.deploy(); await voting.deployed(); }); describe("Enregistrement des électeurs", function () { it("devrait permettre au propriétaire d'enregistrer un électeur", async function () { await expect(voting.registerVoter(voter1.address)) .to.emit(voting, "VoterRegistered") .withArgs(voter1.address); }); it("ne devrait pas permettre à un non-propriétaire d'enregistrer un électeur", async function () { await expect(voting.connect(voter1).registerVoter(voter2.address)) .to.be.revertedWith("Ownable: caller is not the owner"); }); it("ne devrait pas permettre d'enregistrer un électeur déjà enregistré", async function () { await voting.registerVoter(voter1.address); await expect(voting.registerVoter(voter1.address)) .to.be.revertedWith("L'electeur est deja enregistre"); }); }); describe("Enregistrement des propositions", function () { beforeEach(async function () { // Enregistrement des électeurs await voting.registerVoter(voter1.address); await voting.registerVoter(voter2.address); }); it("devrait permettre au propriétaire de démarrer la session d'enregistrement des propositions", async function () { await expect(voting.startProposalsRegistration(60)) .to.emit(voting, "WorkflowStatusChange") .withArgs(0, 1); // RegisteringVoters -> ProposalsRegistrationStarted }); it("devrait permettre aux électeurs enregistrés de soumettre des propositions", async function () { await voting.startProposalsRegistration(60); await expect(voting.connect(voter1).registerProposal("Proposition 1")) .to.emit(voting, "ProposalRegistered") .withArgs(1); // Index 1 car la proposition genesis est à l'index 0 }); it("ne devrait pas permettre aux non-électeurs de soumettre des propositions", async function () { await voting.startProposalsRegistration(60); await expect(voting.connect(nonVoter).registerProposal("Proposition illégitime")) .to.be.revertedWith("Vous n'etes pas un electeur enregistre"); }); it("ne devrait pas permettre de soumettre des propositions après la fin de la session", async function () { await voting.startProposalsRegistration(60); await voting.endProposalsRegistration(); await expect(voting.connect(voter1).registerProposal("Proposition tardive")) .to.be.revertedWith("La session d'enregistrement des propositions n'est pas active"); }); }); describe("Session de vote", function () { beforeEach(async function () { // Configuration du scénario de test await voting.registerVoter(voter1.address); await voting.registerVoter(voter2.address); await voting.registerVoter(voter3.address); await voting.startProposalsRegistration(60); await voting.connect(voter1).registerProposal("Proposition 1"); await voting.connect(voter2).registerProposal("Proposition 2"); await voting.endProposalsRegistration(); }); it("devrait permettre au propriétaire de démarrer la session de vote", async function () { await expect(voting.startVotingSession(60)) .to.emit(voting, "WorkflowStatusChange") .withArgs(2, 3); // ProposalsRegistrationEnded -> VotingSessionStarted }); it("devrait permettre aux électeurs enregistrés de voter", async function () { await voting.startVotingSession(60); await expect(voting.connect(voter1).vote(1)) // Vote pour la proposition 1 .to.emit(voting, "Voted") .withArgs(voter1.address, 1); }); it("ne devrait pas permettre de voter deux fois", async function () { await voting.startVotingSession(60); await voting.connect(voter1).vote(1); await expect(voting.connect(voter1).vote(2)) .to.be.revertedWith("Vous avez deja vote"); }); it("ne devrait pas permettre de voter pour une proposition inexistante", async function () { await voting.startVotingSession(60); await expect(voting.connect(voter1).vote(999)) .to.be.revertedWith("La proposition n'existe pas"); }); }); describe("Délégation de vote (fonctionnalité supplémentaire)", function () { beforeEach(async function () { // Configuration du scénario de test pour la délégation await voting.registerVoter(voter1.address); await voting.registerVoter(voter2.address); await voting.registerVoter(voter3.address); await voting.startProposalsRegistration(60); await voting.connect(voter1).registerProposal("Proposition 1"); await voting.connect(voter2).registerProposal("Proposition 2"); await voting.endProposalsRegistration(); await voting.startVotingSession(60); }); it("devrait permettre à un électeur de déléguer son vote", async function () { await voting.connect(voter1).delegateVoteTo(voter2.address); const delegation = await voting.connect(voter1).getDelegation(voter1.address); expect(delegation).to.equal(voter2.address); }); it("devrait automatiquement voter si le délégué a déjà voté", async function () { await voting.connect(voter2).vote(2); // Voter2 vote pour la proposition 2 await voting.connect(voter1).delegateVoteTo(voter2.address); // Voter1 délègue à voter2 // Vérification que voter1 a effectivement voté pour la même proposition que voter2 const [, hasVoted, votedProposalId] = await voting.connect(voter1).getVoter(voter1.address); expect(hasVoted).to.be.true; expect(votedProposalId).to.equal(2); }); it("ne devrait pas permettre les boucles de délégation", async function () { await voting.connect(voter1).delegateVoteTo(voter2.address); await voting.connect(voter2).delegateVoteTo(voter3.address); await expect(voting.connect(voter3).delegateVoteTo(voter1.address)) .to.be.revertedWith("Boucle de delegation detectee"); }); }); describe("Délais automatiques (fonctionnalité supplémentaire)", function () { it("devrait mettre à jour le statut lorsque le délai est passé", async function () { // Ce test est difficile à implémenter en pratique car il faudrait manipuler le temps // Dans un environnement de test réel, on utiliserait des outils comme evm_increaseTime // Ici, on se contente de vérifier que la fonction existe et peut être appelée await voting.registerVoter(voter1.address); await voting.startProposalsRegistration(0); // Délai de 0 minute pour le test await expect(voting.checkAndUpdateStatus()).to.not.be.reverted; }); }); describe("Comptage et résultats", function () { beforeEach(async function () { // Préparation d'un scénario de vote complet await voting.registerVoter(voter1.address); await voting.registerVoter(voter2.address); await voting.registerVoter(voter3.address); await voting.startProposalsRegistration(60); await voting.connect(voter1).registerProposal("Proposition 1"); await voting.connect(voter2).registerProposal("Proposition 2"); await voting.endProposalsRegistration(); await voting.startVotingSession(60); // Voter1 et voter3 votent pour la proposition 1, voter2 pour la proposition 2 await voting.connect(voter1).vote(1); await voting.connect(voter2).vote(2); await voting.connect(voter3).vote(1); await voting.endVotingSession(); }); it("devrait permettre au propriétaire de comptabiliser les votes", async function () { await expect(voting.tallyVotes()) .to.emit(voting, "WorkflowStatusChange") .withArgs(4, 5); // VotingSessionEnded -> VotesTallied }); it("devrait déterminer correctement la proposition gagnante", async function () { await voting.tallyVotes(); const [winningProposalId, description, voteCount] = await voting.getWinner(); // Vérification que la proposition 1 a gagné avec 2 votes expect(winningProposalId).to.equal(1); expect(description).to.equal("Proposition 1"); expect(voteCount).to.equal(2); }); it("ne devrait pas permettre d'accéder au gagnant avant le comptage", async function () { await voting.endVotingSession(); // Sans appeler tallyVotes() await expect(voting.getWinner()) .to.be.revertedWith("Les votes n'ont pas encore ete comptabilises"); }); }); });