"""Ballots: every vote is a signed statement bound to a proposal (Articles 5 & 8).""" from __future__ import annotations import pytest from tests.helpers import ballot_ok, cast_ballot, get_field, json_text, set_field PROPOSAL_TITLE = "Ballot unit-test proposal" @pytest.fixture() def proposal_id(repo, citizens): from tests.helpers import create_proposal, proposal_id_of prop = create_proposal( repo, proposer_id=citizens[0]["id"], title=PROPOSAL_TITLE, changes={"constitution/userland/ballot-test-module.yaml": "id: ballot-test\ntitle: Ballot test\n"}, ) return proposal_id_of(prop) def test_cast_and_verify(repo, citizens, proposal_id): voter = citizens[0] ballot = cast_ballot(voter, proposal_id, "yes", repo=repo) assert ballot_ok(ballot, voter["public_key"], proposal_id) def test_ballot_records_choice_and_citizen(repo, citizens, proposal_id): voter = citizens[1] ballot = cast_ballot(voter, proposal_id, "no", repo=repo) text = json_text(ballot) assert voter["id"] in text assert "no" in text def test_tampered_choice_invalidates_signature(repo, citizens, proposal_id): voter = citizens[2] ballot = cast_ballot(voter, proposal_id, "yes", repo=repo) choice_field = None for name in ("choice", "vote", "decision"): if get_field(ballot, name, default=None) is not None: choice_field = name break assert choice_field is not None, "ballot exposes no choice-like field" forged = set_field(ballot, choice_field, "no") assert not ballot_ok(forged, voter["public_key"], proposal_id) def test_ballot_does_not_verify_under_someone_elses_key(repo, citizens, proposal_id): voter, other = citizens[0], citizens[3] ballot = cast_ballot(voter, proposal_id, "yes", repo=repo) assert not ballot_ok(ballot, other["public_key"], proposal_id) def test_invalid_choice_is_rejected(repo, citizens, proposal_id): voter = citizens[4] with pytest.raises(Exception): cast_ballot(voter, proposal_id, "maybe", repo=repo) def test_abstain_is_a_valid_choice(repo, citizens, proposal_id): voter = citizens[5] ballot = cast_ballot(voter, proposal_id, "abstain", repo=repo) assert ballot_ok(ballot, voter["public_key"], proposal_id)