def test_publish(self) -> None:
        # Arrange
        now = datetime.now(timezone.utc)
        description = ElectionDescription(
            "", ElectionType.unknown, now, now, [], [], [], [], [], []
        )
        context = CiphertextElectionContext(1, 1, ONE_MOD_P, ONE_MOD_Q)
        constants = ElectionConstants()
        devices = []
        coefficients = [CoefficientValidationSet("", [], [])]
        encrypted_ballots = []
        tally = PlaintextTally("", [], [])

        # Act
        publish(
            description,
            context,
            constants,
            devices,
            encrypted_ballots,
            CiphertextTally("", description, context),
            tally,
            coefficients,
        )

        # Assert
        self.assertTrue(path.exists(RESULTS_DIR))

        # Cleanup
        rmtree(RESULTS_DIR)
def election_descriptions(draw: _DrawType,
                          max_num_parties: int = 3,
                          max_num_contests: int = 3):
    """
    Generates an `ElectionDescription` -- the top-level object describing an election.
    :param draw: Hidden argument, used by Hypothesis.
    :param max_num_parties: The largest number of parties that will be generated (default: 3)
    :param max_num_contests: The largest number of contests that will be generated (default: 3)
    """
    assert max_num_parties > 0, "need at least one party"
    assert max_num_contests > 0, "need at least one contest"

    geo_units = [draw(geopolitical_units())]
    num_parties: int = draw(integers(1, max_num_parties))

    # keep this small so tests run faster
    parties: List[Party] = draw(party_lists(num_parties))
    num_contests: int = draw(integers(1, max_num_contests))

    # generate a collection candidates mapped to contest descriptions
    candidate_contests: List[Tuple[List[Candidate], ContestDescription]] = [
        draw(contest_descriptions(i, parties, geo_units))
        for i in range(num_contests)
    ]
    assert len(candidate_contests) > 0

    candidates_ = reduce(
        lambda a, b: a + b,
        [candidate_contest[0] for candidate_contest in candidate_contests],
    )
    contests = [
        candidate_contest[1] for candidate_contest in candidate_contests
    ]

    styles = [draw(ballot_styles(parties, geo_units))]

    # maybe later on we'll do something more complicated with dates
    start_date = draw(datetimes())
    end_date = start_date

    return ElectionDescription(
        election_scope_id=draw(emails()),
        spec_version="v0.95",
        type=ElectionType.general,  # good enough for now
        start_date=start_date,
        end_date=end_date,
        geopolitical_units=geo_units,
        parties=parties,
        candidates=candidates_,
        contests=contests,
        ballot_styles=styles,
        name=draw(internationalized_texts()),
        contact_information=draw(contact_infos()),
    )
    def get_fake_election(self) -> ElectionDescription:
        """
        Get a single Fake Election object that is manually constructed with default values
        """

        fake_ballot_style = BallotStyle("some-ballot-style-id")
        fake_ballot_style.geopolitical_unit_ids = ["some-geopoltical-unit-id"]

        fake_referendum_ballot_selections = [
            # Referendum selections are simply a special case of `candidate` in the object model
            SelectionDescription("some-object-id-affirmative",
                                 "some-candidate-id-1", 0),
            SelectionDescription("some-object-id-negative",
                                 "some-candidate-id-2", 1),
        ]

        sequence_order = 0
        number_elected = 1
        votes_allowed = 1
        fake_referendum_contest = ReferendumContestDescription(
            "some-referendum-contest-object-id",
            "some-geopoltical-unit-id",
            sequence_order,
            VoteVariationType.one_of_m,
            number_elected,
            votes_allowed,
            "some-referendum-contest-name",
            fake_referendum_ballot_selections,
        )

        fake_candidate_ballot_selections = [
            SelectionDescription("some-object-id-candidate-1",
                                 "some-candidate-id-1", 0),
            SelectionDescription("some-object-id-candidate-2",
                                 "some-candidate-id-2", 1),
            SelectionDescription("some-object-id-candidate-3",
                                 "some-candidate-id-3", 2),
        ]

        sequence_order_2 = 1
        number_elected_2 = 2
        votes_allowed_2 = 2
        fake_candidate_contest = CandidateContestDescription(
            "some-candidate-contest-object-id",
            "some-geopoltical-unit-id",
            sequence_order_2,
            VoteVariationType.one_of_m,
            number_elected_2,
            votes_allowed_2,
            "some-candidate-contest-name",
            fake_candidate_ballot_selections,
        )

        fake_election = ElectionDescription(
            election_scope_id="some-scope-id",
            type=ElectionType.unknown,
            start_date=datetime.now(),
            end_date=datetime.now(),
            geopolitical_units=[
                GeopoliticalUnit(
                    "some-geopoltical-unit-id",
                    "some-gp-unit-name",
                    ReportingUnitType.unknown,
                )
            ],
            parties=[Party("some-party-id-1"),
                     Party("some-party-id-2")],
            candidates=[
                Candidate("some-candidate-id-1"),
                Candidate("some-candidate-id-2"),
                Candidate("some-candidate-id-3"),
            ],
            contests=[fake_referendum_contest, fake_candidate_contest],
            ballot_styles=[fake_ballot_style],
        )

        return fake_election
Exemple #4
0
    def _to_election_description_common(
        self,
        date: Optional[datetime] = None
    ) -> Tuple[ElectionDescription, Dict[str, str], Dict[
            str, ContestDescription], Dict[str, BallotStyle],
               BallotPlaintextFactory, ]:
        # ballotstyle_map: Dict[str, BallotStyle],
        if date is None:
            date = datetime.now()

        party_uids = UidMaker("party")
        party_map = {
            p: Party(
                object_id=party_uids.next(),
                ballot_name=_str_to_internationalized_text_en(p),
            )
            for p in self.metadata.all_parties
        }

        # A ballot style is a subset of all of the contests on the ballot. Luckily, we have a column
        # in the data ("ballot type"), which is exactly what we need.

        # "Geopolitical units" are meant to be their own thing (cities, counties, precincts, etc.),
        # but we don't have any data at all about them in the Dominion CVR file. Our current hack
        # is that we're making them one-to-one with contests.

        contest_uids = UidMaker("contest")
        gp_uids = UidMaker("gpunit")

        contest_map: Dict[str, ContestDescription] = {}
        all_candidates: List[Candidate] = []
        all_gps: List[GeopoliticalUnit] = []

        all_candidate_ids_to_columns: Dict[str, str] = {}

        for name in self.metadata.contest_map.keys():
            (
                contest_description,
                candidates,
                gp,
                candidate_id_to_column,
            ) = self._contest_name_to_description(
                name=name,
                contest_uid_maker=contest_uids,
                gp_uid_maker=gp_uids,
            )
            contest_map[name] = contest_description
            all_candidates = all_candidates + candidates
            all_gps.append(gp)
            for c in candidate_id_to_column.keys():
                all_candidate_ids_to_columns[c] = candidate_id_to_column[c]

        # ballotstyle_uids = UidMaker("ballotstyle")

        ballotstyle_map: Dict[str, BallotStyle] = {
            bt: self._ballot_style_from_id(bt, party_map, contest_map)
            for bt in self.metadata.ballot_types.keys()
        }

        bpf = BallotPlaintextFactory(
            self.metadata.style_map,
            contest_map,
            ballotstyle_map,
            all_candidate_ids_to_columns,
        )

        return (
            ElectionDescription(
                name=_str_to_internationalized_text_en(
                    self.metadata.election_name),
                election_scope_id=self.metadata.election_name,
                type=ElectionType.unknown,
                start_date=date,
                end_date=date,
                geopolitical_units=all_gps,
                parties=list(party_map.values()),
                candidates=all_candidates,
                contests=list(contest_map.values()),
                ballot_styles=list(ballotstyle_map.values()),
            ),
            all_candidate_ids_to_columns,
            contest_map,
            ballotstyle_map,
            bpf,
        )