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
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, )