Store nomination within voting result

This commit is contained in:
2023-07-08 16:46:24 +02:00
parent b94ec58de3
commit 749af572d5
6 changed files with 302 additions and 370 deletions
@@ -3,10 +3,17 @@ package de.twomartens.wahlrecht.model;
import java.util.Collection; import java.util.Collection;
import java.util.Deque; import java.util.Deque;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import lombok.Builder; import lombok.Builder;
@Builder @Builder
public record ElectedResult(Map<Nomination, Collection<ElectedCandidate>> electedCandidates, public record ElectedResult(Map<VotingResult, Collection<ElectedCandidate>> electedCandidates,
Deque<Double> usedElectionNumbers) { Deque<Double> usedElectionNumbers) {
public Map<Nomination, Collection<ElectedCandidate>> electedCandidatesByNomination() {
return electedCandidates.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey().getNomination(), Entry::getValue));
}
} }
@@ -6,9 +6,7 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import lombok.ToString.Include; import lombok.ToString.Include;
@@ -21,9 +19,6 @@ public class Nomination {
@Include @Include
private final String name; private final String name;
private final boolean supportVotesOnNomination; private final boolean supportVotesOnNomination;
@Getter
@Setter
private VotingResult votingResult;
private void addCandidate(Candidate candidate) { private void addCandidate(Candidate candidate) {
candidates.add(candidate); candidates.add(candidate);
@@ -2,10 +2,16 @@ package de.twomartens.wahlrecht.model;
import java.util.Deque; import java.util.Deque;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import lombok.Builder; import lombok.Builder;
@Builder @Builder
public record SeatResult(Map<Nomination, Integer> seatsPerNomination, public record SeatResult(Map<VotingResult, Integer> seatsPerResult,
Deque<Double> usedElectionNumbers) { Deque<Double> usedElectionNumbers) {
public Map<Nomination, Integer> seatsPerNomination() {
return seatsPerResult.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey().getNomination(), Entry::getValue));
}
} }
@@ -10,14 +10,16 @@ public class VotingResult {
private final int votesOnNomination; private final int votesOnNomination;
private final int votesThroughHealing; private final int votesThroughHealing;
private final Map<Integer, Integer> votesPerPosition; private final Map<Integer, Integer> votesPerPosition;
private final Nomination nomination;
private Integer totalVotes = null; private Integer totalVotes = null;
@Builder @Builder
public VotingResult(int votesOnNomination, int votesThroughHealing, public VotingResult(int votesOnNomination, int votesThroughHealing,
Map<Integer, Integer> votesPerPosition) { Map<Integer, Integer> votesPerPosition, Nomination nomination) {
this.votesOnNomination = votesOnNomination; this.votesOnNomination = votesOnNomination;
this.votesThroughHealing = votesThroughHealing; this.votesThroughHealing = votesThroughHealing;
this.votesPerPosition = votesPerPosition; this.votesPerPosition = votesPerPosition;
this.nomination = nomination;
} }
public int getTotalVotes() { public int getTotalVotes() {
@@ -29,39 +29,37 @@ public class CalculationService {
private final Deque<Double> electionNumberHistory = new ArrayDeque<>(); private final Deque<Double> electionNumberHistory = new ArrayDeque<>();
public ElectedResult calculateConstituency(@NonNull Constituency constituency, public ElectedResult calculateConstituency(@NonNull Constituency constituency,
@NonNull Collection<Nomination> nominations) { @NonNull Collection<VotingResult> votingResults) {
electionNumberHistory.clear(); electionNumberHistory.clear();
int totalVotes = nominations.stream() int totalVotes = votingResults.stream()
.map(Nomination::getVotingResult)
.map(VotingResult::getTotalVotes) .map(VotingResult::getTotalVotes)
.reduce(0, Integer::sum); .reduce(0, Integer::sum);
int numberOfSeats = constituency.numberOfSeats(); int numberOfSeats = constituency.numberOfSeats();
double initialElectionNumber = totalVotes / (double) numberOfSeats; double initialElectionNumber = totalVotes / (double) numberOfSeats;
Map<Nomination, Integer> assignedSeatsPerNomination = calculateAssignedSeatsPerNomination( Map<VotingResult, Integer> assignedSeatsPerResult = calculateAssignedSeatsPerResult(
nominations, numberOfSeats, initialElectionNumber); votingResults, numberOfSeats, initialElectionNumber);
return ElectedResult.builder() return ElectedResult.builder()
.electedCandidates(findElectedCandidates(assignedSeatsPerNomination, Collections.emptyMap())) .electedCandidates(findElectedCandidates(assignedSeatsPerResult, Collections.emptyMap()))
.usedElectionNumbers(electionNumberHistory) .usedElectionNumbers(electionNumberHistory)
.build(); .build();
} }
public SeatResult calculateOverallSeatDistribution(@NonNull Election election, public SeatResult calculateOverallSeatDistribution(@NonNull Election election,
@NonNull Collection<Nomination> nominations) { @NonNull Collection<VotingResult> votingResults) {
electionNumberHistory.clear(); electionNumberHistory.clear();
int totalVotes = nominations.stream() int totalVotes = votingResults.stream()
.map(Nomination::getVotingResult)
.map(VotingResult::getTotalVotes) .map(VotingResult::getTotalVotes)
.reduce(0, Integer::sum); .reduce(0, Integer::sum);
List<Nomination> validNominations = new ArrayList<>(); List<VotingResult> validVotingResults = new ArrayList<>();
int totalIgnoredVotes = 0; int totalIgnoredVotes = 0;
for (Nomination nomination : nominations) { for (VotingResult votingResult : votingResults) {
if (passesVotingThreshold(election, totalVotes, nomination)) { if (passesVotingThreshold(election, totalVotes, votingResult)) {
validNominations.add(nomination); validVotingResults.add(votingResult);
} else { } else {
totalIgnoredVotes += nomination.getVotingResult().getTotalVotes(); totalIgnoredVotes += votingResult.getTotalVotes();
} }
} }
totalVotes -= totalIgnoredVotes; totalVotes -= totalIgnoredVotes;
@@ -69,17 +67,17 @@ public class CalculationService {
int numberOfSeats = election.totalNumberOfSeats(); int numberOfSeats = election.totalNumberOfSeats();
double initialElectionNumber = totalVotes / (double) numberOfSeats; double initialElectionNumber = totalVotes / (double) numberOfSeats;
Map<Nomination, Integer> assignedSeatsPerNomination = calculateAssignedSeatsPerNomination( Map<VotingResult, Integer> assignedSeatsPerResult = calculateAssignedSeatsPerResult(
validNominations, numberOfSeats, initialElectionNumber); validVotingResults, numberOfSeats, initialElectionNumber);
return SeatResult.builder() return SeatResult.builder()
.seatsPerNomination(assignedSeatsPerNomination) .seatsPerResult(assignedSeatsPerResult)
.usedElectionNumbers(electionNumberHistory) .usedElectionNumbers(electionNumberHistory)
.build(); .build();
} }
public ElectedResult calculateElectedOverallCandidates(Map<Nomination, Integer> seatsPerNomination, public ElectedResult calculateElectedOverallCandidates(Map<VotingResult, Integer> seatsPerNomination,
Map<Nomination, Collection<ElectedCandidate>> electedCandidates) { Map<VotingResult, Collection<ElectedCandidate>> electedCandidates) {
electionNumberHistory.clear(); electionNumberHistory.clear();
return ElectedResult.builder() return ElectedResult.builder()
@@ -89,30 +87,35 @@ public class CalculationService {
} }
private static boolean passesVotingThreshold(@NonNull Election election, int totalVotes, private static boolean passesVotingThreshold(@NonNull Election election, int totalVotes,
@NonNull Nomination nomination) { @NonNull VotingResult votingResult) {
return totalVotes * election.votingThreshold().getMultiplier() return totalVotes * election.votingThreshold().getMultiplier()
<= nomination.getVotingResult().getTotalVotes(); <= votingResult.getTotalVotes();
} }
@NonNull @NonNull
private Map<Nomination, Collection<ElectedCandidate>> findElectedCandidates( private Map<VotingResult, Collection<ElectedCandidate>> findElectedCandidates(
@NonNull Map<Nomination, Integer> assignedSeatsPerNomination, @NonNull Map<VotingResult, Integer> assignedSeatsPerNomination,
Map<Nomination, Collection<ElectedCandidate>> alreadyElectedCandidates) { Map<VotingResult, Collection<ElectedCandidate>> alreadyElectedCandidates) {
Map<Nomination, Collection<ElectedCandidate>> electedCandidates = new HashMap<>(); Map<VotingResult, Collection<ElectedCandidate>> electedCandidates = new HashMap<>();
assignedSeatsPerNomination.entrySet().stream() for (Entry<VotingResult, Integer> entry : assignedSeatsPerNomination.entrySet()) {
.filter(entry -> entry.getValue() > 0) if (entry.getValue() > 0) {
.forEach(entry -> Collection<ElectedCandidate> candidates = findCandidates(
electedCandidates.put(entry.getKey(), findCandidates(entry.getKey(), entry.getValue(), entry.getKey(),
alreadyElectedCandidates.getOrDefault(entry.getKey(), Collections.emptyList())))); entry.getValue(),
alreadyElectedCandidates.getOrDefault(entry.getKey(), Collections.emptyList())
);
electedCandidates.put(entry.getKey(), candidates);
}
}
return electedCandidates; return electedCandidates;
} }
@NonNull @NonNull
private Collection<ElectedCandidate> findCandidates(@NonNull Nomination nomination, private Collection<ElectedCandidate> findCandidates(@NonNull VotingResult votingResult,
int numberOfSeats, Collection<ElectedCandidate> alreadyElectedCandidates) { int numberOfSeats, Collection<ElectedCandidate> alreadyElectedCandidates) {
List<Integer> individualVotesOrder = nomination.getVotingResult().getVotesPerPosition() List<Integer> individualVotesOrder = votingResult.getVotesPerPosition()
.entrySet().stream() .entrySet().stream()
.sorted(Comparator.comparing(Entry<Integer, Integer>::getValue).reversed()) .sorted(Comparator.comparing(Entry<Integer, Integer>::getValue).reversed())
.map(Entry::getKey) .map(Entry::getKey)
@@ -123,8 +126,9 @@ public class CalculationService {
Map<Candidate, ElectedCandidate> electedCandidateMap = alreadyElectedCandidates.stream() Map<Candidate, ElectedCandidate> electedCandidateMap = alreadyElectedCandidates.stream()
.collect(Collectors.toMap(ElectedCandidate::candidate, Function.identity())); .collect(Collectors.toMap(ElectedCandidate::candidate, Function.identity()));
Nomination nomination = votingResult.getNomination();
if (nomination.supportsVotesOnNomination()) { if (nomination.supportsVotesOnNomination()) {
int seatsByNomination = calculateSeatsByNominationOrder(nomination, numberOfSeats); int seatsByNomination = calculateSeatsByNominationOrder(votingResult, numberOfSeats);
seatsByVoteOrder = numberOfSeats - seatsByNomination; seatsByVoteOrder = numberOfSeats - seatsByNomination;
List<Candidate> candidates = nomination.getCandidates(); List<Candidate> candidates = nomination.getCandidates();
int electedByNominationOrder = 0; int electedByNominationOrder = 0;
@@ -157,72 +161,72 @@ public class CalculationService {
return elected; return elected;
} }
private static int calculateSeatsByNominationOrder(@NonNull Nomination nomination, int numberOfSeats) { private static int calculateSeatsByNominationOrder(@NonNull VotingResult votingResult, int numberOfSeats) {
int votesOnNomination = nomination.getVotingResult().getVotesOnNomination(); int votesOnNomination = votingResult.getVotesOnNomination();
int totalVotes = nomination.getVotingResult().getTotalVotesWithoutHealing(); int totalVotes = votingResult.getTotalVotesWithoutHealing();
return (int) Math.round((numberOfSeats * votesOnNomination) / (double) totalVotes); return (int) Math.round((numberOfSeats * votesOnNomination) / (double) totalVotes);
} }
private Map<Nomination, Integer> calculateAssignedSeatsPerNomination( private Map<VotingResult, Integer> calculateAssignedSeatsPerResult(
@NonNull Collection<Nomination> nominations, @NonNull Collection<VotingResult> votingResults,
int numberOfSeats, Double initialElectionNumber) { int numberOfSeats, Double initialElectionNumber) {
double electionNumber = initialElectionNumber; double electionNumber = initialElectionNumber;
long assignedSeats; long assignedSeats;
Map<Nomination, Integer> assignedSeatsPerNomination; Map<VotingResult, Integer> assignedSeatsPerVotingResult;
do { do {
electionNumberHistory.add(electionNumber); electionNumberHistory.add(electionNumber);
Map<Nomination, Double> seatsPerNomination = new HashMap<>(); Map<VotingResult, Double> seatsPerVotingResult = new HashMap<>();
for (Nomination nomination : nominations) { for (VotingResult votingResult : votingResults) {
double seatNumber = calculateAssignedSeatNumber(electionNumber, double seatNumber = calculateAssignedSeatNumber(electionNumber,
nomination.getVotingResult().getTotalVotes()); votingResult.getTotalVotes());
seatsPerNomination.put(nomination, seatNumber); seatsPerVotingResult.put(votingResult, seatNumber);
} }
assignedSeatsPerNomination = seatsPerNomination.entrySet().stream() assignedSeatsPerVotingResult = seatsPerVotingResult.entrySet().stream()
.map(entry -> Map.entry(entry.getKey(), (int) Math.round(entry.getValue()))) .map(entry -> Map.entry(entry.getKey(), (int) Math.round(entry.getValue())))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue)); .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
assignedSeats = assignedSeatsPerNomination.values().stream().reduce(0, Integer::sum); assignedSeats = assignedSeatsPerVotingResult.values().stream().reduce(0, Integer::sum);
if (assignedSeats < numberOfSeats) { if (assignedSeats < numberOfSeats) {
// election number was too big, decrease // election number was too big, decrease
electionNumber = calculateLowerElectionNumber(initialElectionNumber, seatsPerNomination, electionNumber = calculateLowerElectionNumber(initialElectionNumber, seatsPerVotingResult,
assignedSeatsPerNomination); assignedSeatsPerVotingResult);
} else if (assignedSeats > numberOfSeats) { } else if (assignedSeats > numberOfSeats) {
// election number was too small, increase // election number was too small, increase
electionNumber = calculateHigherElectionNumber(initialElectionNumber, seatsPerNomination, electionNumber = calculateHigherElectionNumber(initialElectionNumber, seatsPerVotingResult,
assignedSeatsPerNomination); assignedSeatsPerVotingResult);
} }
} while (assignedSeats != numberOfSeats); } while (assignedSeats != numberOfSeats);
return assignedSeatsPerNomination; return assignedSeatsPerVotingResult;
} }
private static double calculateHigherElectionNumber(Double initialElectionNumber, private static double calculateHigherElectionNumber(Double initialElectionNumber,
@NonNull Map<Nomination, Double> seatsPerNomination, @NonNull Map<VotingResult, Double> seatsPerVotingResult,
Map<Nomination, Integer> assignedSeatsPerNomination) { Map<VotingResult, Integer> assignedSeatsPerVotingResult) {
double electionNumber; double electionNumber;
electionNumber = seatsPerNomination.entrySet().stream() electionNumber = seatsPerVotingResult.entrySet().stream()
.map(entry -> Map.entry(entry.getKey(), .map(entry -> Map.entry(entry.getKey(),
entry.getValue() - assignedSeatsPerNomination.get(entry.getKey()))) entry.getValue() - assignedSeatsPerVotingResult.get(entry.getKey())))
.min(Comparator.comparing(Entry<Nomination, Double>::getValue)) .min(Comparator.comparing(Entry<VotingResult, Double>::getValue))
.map(entry -> entry.getKey().getVotingResult().getTotalVotes() .map(entry -> entry.getKey().getTotalVotes()
/ (assignedSeatsPerNomination.get(entry.getKey()) - 0.5)) / (assignedSeatsPerVotingResult.get(entry.getKey()) - 0.5))
.orElse(initialElectionNumber); .orElse(initialElectionNumber);
return electionNumber; return electionNumber;
} }
private static double calculateLowerElectionNumber(Double initialElectionNumber, private static double calculateLowerElectionNumber(Double initialElectionNumber,
@NonNull Map<Nomination, Double> seatsPerNomination, @NonNull Map<VotingResult, Double> seatsPerVotingResult,
Map<Nomination, Integer> assignedSeatsPerNomination) { Map<VotingResult, Integer> assignedSeatsPerVotingResult) {
double electionNumber; double electionNumber;
electionNumber = seatsPerNomination.entrySet().stream() electionNumber = seatsPerVotingResult.entrySet().stream()
.map(entry -> Map.entry(entry.getKey(), .map(entry -> Map.entry(entry.getKey(),
entry.getValue() - assignedSeatsPerNomination.get(entry.getKey()))) entry.getValue() - assignedSeatsPerVotingResult.get(entry.getKey())))
.max(Comparator.comparing(Entry<Nomination, Double>::getValue)) .max(Comparator.comparing(Entry<VotingResult, Double>::getValue))
.map(entry -> entry.getKey().getVotingResult().getTotalVotes() .map(entry -> entry.getKey().getTotalVotes()
/ (assignedSeatsPerNomination.get(entry.getKey()) + 0.5)) / (assignedSeatsPerVotingResult.get(entry.getKey()) + 0.5))
.orElse(initialElectionNumber); .orElse(initialElectionNumber);
return electionNumber; return electionNumber;
} }
@@ -14,9 +14,11 @@ import java.time.LocalDate;
import java.time.Month; import java.time.Month;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.assertj.core.api.Assertions; import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@@ -25,28 +27,6 @@ import org.springframework.lang.NonNull;
class CalculationServiceTest { class CalculationServiceTest {
private static final Constituency EIMSBUETTEL_NORD = new Constituency("Eimsbüttel-Nord", 3);
private static final Constituency EIMSBUETTEL_SUED = new Constituency("Eimsbüttel-Süd", 5);
private static final Constituency HARO = new Constituency("Rotherbaum/Harvestehude", 4);
private static final Constituency LOKSTEDT = new Constituency("Lokstedt", 3);
private static final Constituency NIENDORF = new Constituency("Niendorf", 5);
private static final Constituency SCHNELSEN = new Constituency("Schnelsen", 3);
private static final Constituency EIDELSTEDT = new Constituency("Eidelstedt", 4);
private static final Constituency STELLINGEN = new Constituency("Stellingen", 3);
private static final Nomination SPD_NIENDORF = buildNomination("SPD-Niendorf", false);
private static final Nomination CDU_NIENDORF = buildNomination("CDU-Niendorf", false);
private static final Nomination FDP_NIENDORF = buildNomination("FDP-Niendorf", false);
private static final Nomination LINKE_NIENDORF = buildNomination("LINKE-Niendorf", false);
private static final Nomination GRUENE_NIENDORF = buildNomination("GRUENE-Niendorf", false);
private static final Nomination AFD_NIENDORF = buildNomination("AFD-Niendorf", false);
private static final Nomination SPD_BEZIRK = buildNomination("SPD-Bezirk", true);
private static final Nomination CDU_BEZIRK = buildNomination("CDU-Bezirk", true);
private static final Nomination FDP_BEZIRK = buildNomination("FDP-Bezirk", true);
private static final Nomination LINKE_BEZIRK = buildNomination("LINKE-Bezirk", true);
private static final Nomination GRUENE_BEZIRK = buildNomination("GRUENE-Bezirk", true);
private static final Nomination AFD_BEZIRK = buildNomination("AFD-Bezirk", true);
private static final Nomination PIRATEN_BEZIRK = buildNomination("Piraten-Bezirk", true);
public static final String GOTTLIEB_GABOR = "Gottlieb, Gabor"; public static final String GOTTLIEB_GABOR = "Gottlieb, Gabor";
public static final String RIEGEL_ANN_KATHRIN = "Riegel, Ann-Kathrin"; public static final String RIEGEL_ANN_KATHRIN = "Riegel, Ann-Kathrin";
public static final String HOEFLICH_JUTTA = "Höflich, Jutta"; public static final String HOEFLICH_JUTTA = "Höflich, Jutta";
@@ -68,13 +48,191 @@ class CalculationServiceTest {
public static final String ERK_ARAMAK = "Erk, Aramak"; public static final String ERK_ARAMAK = "Erk, Aramak";
public static final String DR_FISCHER_JOST_LEONHARDT = "Dr. Fischer, Jost Leonhardt"; public static final String DR_FISCHER_JOST_LEONHARDT = "Dr. Fischer, Jost Leonhardt";
public static final String KUELL_GABRIELA = "Küll, Gabriela"; public static final String KUELL_GABRIELA = "Küll, Gabriela";
private static final Constituency EIMSBUETTEL_NORD = new Constituency("Eimsbüttel-Nord", 3);
private static final Constituency EIMSBUETTEL_SUED = new Constituency("Eimsbüttel-Süd", 5);
private static final Constituency HARO = new Constituency("Rotherbaum/Harvestehude", 4);
private static final Constituency LOKSTEDT = new Constituency("Lokstedt", 3);
private static final Constituency NIENDORF = new Constituency("Niendorf", 5);
private static final Constituency SCHNELSEN = new Constituency("Schnelsen", 3);
private static final Constituency EIDELSTEDT = new Constituency("Eidelstedt", 4);
private static final Constituency STELLINGEN = new Constituency("Stellingen", 3);
private static final Nomination SPD_NIENDORF = buildNomination("SPD-Niendorf", false);
private static final VotingResult SPD_NIENDORF_RESULT = buildVotingResult(SPD_NIENDORF, 0, 0,
11882, 7617, 1946, 1743, 1363, 762, 895, 1598, 1786, 781);
private static final Nomination CDU_NIENDORF = buildNomination("CDU-Niendorf", false);
public static final VotingResult CDU_NIENDORF_RESULT = buildVotingResult(CDU_NIENDORF, 0, 0, 10733,
4550, 2310, 2333, 2565);
private static final Nomination FDP_NIENDORF = buildNomination("FDP-Niendorf", false);
public static final VotingResult FDP_NIENDORF_RESULT = buildVotingResult(FDP_NIENDORF, 0, 0, 2498,
3200, 992);
private static final Nomination LINKE_NIENDORF = buildNomination("LINKE-Niendorf", false);
public static final VotingResult LINKE_NIENDORF_RESULT = buildVotingResult(LINKE_NIENDORF, 0, 0,
3782, 1584, 1185);
private static final Nomination GRUENE_NIENDORF = buildNomination("GRUENE-Niendorf", false);
public static final VotingResult GRUENE_NIENDORF_RESULT = buildVotingResult(GRUENE_NIENDORF, 0, 0,
14838, 12501);
private static final Nomination AFD_NIENDORF = buildNomination("AFD-Niendorf", false);
public static final VotingResult AFD_NIENDORF_RESULT = buildVotingResult(AFD_NIENDORF, 0, 0, 6616);
private static final Nomination SPD_BEZIRK = buildNomination("SPD-Bezirk", true);
public static final VotingResult SPD_BEZIRK_RESULT = buildVotingResult(SPD_BEZIRK, 84703, 985,
8782, 3318, 3825, 3519, 2036, 3923, 5427, 2131, 566, 895, 1425, 1924, 819,
2590, 2190, 3568, 742, 401, 554, 1133, 1268, 580, 254, 1217, 693, 1359, 481,
650, 230, 1544, 1080, 1879, 400, 353, 525, 469, 196, 759, 872);
private static final Nomination CDU_BEZIRK = buildNomination("CDU-Bezirk", true);
public static final VotingResult CDU_BEZIRK_RESULT = buildVotingResult(CDU_BEZIRK, 66245, 660,
5966, 1982, 1604, 2414, 1322, 2237, 1868, 1872, 1889, 881, 1253, 2921, 598,
2721, 618, 941, 620, 837, 378, 594, 484, 584, 472, 408, 748, 650, 282,
315, 1397, 502);
private static final Nomination FDP_BEZIRK = buildNomination("FDP-Bezirk", true);
public static final VotingResult FDP_BEZIRK_RESULT = buildVotingResult(FDP_BEZIRK, 24435, 240,
3528, 1964, 1633, 897, 1193, 355, 401, 1012, 496, 1242, 643, 300, 311,
998, 505, 2181);
private static final Nomination LINKE_BEZIRK = buildNomination("LINKE-Bezirk", true);
public static final VotingResult LINKE_BEZIRK_RESULT = buildVotingResult(LINKE_BEZIRK, 47452, 330,
4890, 875, 1532, 1293, 2321, 696, 1843, 2212, 1488, 483, 764, 572, 892);
private static final Nomination GRUENE_BEZIRK = buildNomination("GRUENE-Bezirk", true);
public static final VotingResult GRUENE_BEZIRK_RESULT = buildVotingResult(GRUENE_BEZIRK, 150842,
900,
10586, 5629, 12597, 2935, 3378, 735, 5662, 4021, 2065, 2469, 1561, 3557, 2290,
1411, 2445, 1761, 1252, 1628, 652, 3524, 677, 843, 2375, 500, 1674, 3264, 1569,
531, 531, 652, 5358, 2129);
private static final Nomination AFD_BEZIRK = buildNomination("AFD-Bezirk", true);
public static final VotingResult AFD_BEZIRK_RESULT = buildVotingResult(AFD_BEZIRK, 21625, 220,
1226, 1950, 3007, 874, 1032, 780, 535, 221, 283);
private static final Nomination PIRATEN_BEZIRK = buildNomination("Piraten-Bezirk", true);
public static final VotingResult PIRATEN_BEZIRK_RESULT = buildVotingResult(PIRATEN_BEZIRK, 6715,
25,
871, 1907, 987);
private CalculationService service; private CalculationService service;
@BeforeAll @BeforeAll
static void setUpOverall() { static void setUp() {
setUpCandidatesConstituency();
setUpCandidatesOverall(); setUpCandidatesOverall();
setUpResultsOverall(); }
private static void setUpCandidatesConstituency() {
SPD_NIENDORF.addCandidates(new Candidate("Schwarzarius, Ines", ""));
SPD_NIENDORF.addCandidates(new Candidate("Urbanski, Torge", ""));
SPD_NIENDORF.addCandidates(new Candidate("Fischbach-Pyttel, Carola", ""));
SPD_NIENDORF.addCandidates(new Candidate("Bäcker, Guido", ""));
SPD_NIENDORF.addCandidates(new Candidate("Porr, Ulrike", ""));
SPD_NIENDORF.addCandidates(new Candidate("Petersen, Johannes", ""));
SPD_NIENDORF.addCandidates(new Candidate("Kröger, Manuela-Andrea", ""));
SPD_NIENDORF.addCandidates(new Candidate("Steppat, Wolfgang", ""));
SPD_NIENDORF.addCandidates(new Candidate("Canbay, Berfin", ""));
SPD_NIENDORF.addCandidates(new Candidate("Schumacher, Wolfgang", ""));
CDU_NIENDORF.addCandidates(new Candidate("Kuhn, Rüdiger", ""));
CDU_NIENDORF.addCandidates(new Candidate("Ahrens, Mareike", ""));
CDU_NIENDORF.addCandidates(new Candidate("Wysocki, Michael", ""));
CDU_NIENDORF.addCandidates(new Candidate("Dönselmann, Malte", ""));
CDU_NIENDORF.addCandidates(new Candidate("Seehaber, Daniel", ""));
LINKE_NIENDORF.addCandidates(new Candidate("Dr. Khenkhar, Malik", ""));
LINKE_NIENDORF.addCandidates(new Candidate("Radom, Claudia", ""));
LINKE_NIENDORF.addCandidates(new Candidate("Kara, Başak", ""));
FDP_NIENDORF.addCandidates(new Candidate("Häffs, Marvin", ""));
FDP_NIENDORF.addCandidates(new Candidate("Bahmer, Larissa", ""));
FDP_NIENDORF.addCandidates(new Candidate("Patzer, Heinrich-Otto", ""));
GRUENE_NIENDORF.addCandidates(new Candidate("Demirhan, Sina", ""));
GRUENE_NIENDORF.addCandidates(new Candidate("Schmidt, Lutz", "Redakteur"));
AFD_NIENDORF.addCandidates(new Candidate("Hanssen, Wolfgang", ""));
}
private static VotingResult buildVotingResult(Nomination nomination, int votesOnNomination,
int votesThroughHealing,
@NonNull int... votes) {
return VotingResult.builder()
.votesThroughHealing(votesThroughHealing)
.votesOnNomination(votesOnNomination)
.votesPerPosition(buildVotesPerPosition(votes))
.nomination(nomination)
.build();
}
private static void setUpCandidatesOverall() {
SPD_BEZIRK.addCandidates(buildCandidates(
GOTTLIEB_GABOR, "Meding, Sarah", "Harringa, Nils", "Nendza-Ammar, Charlotte",
"Rust, Rüdiger", "Köster-Marjanovic, Hannelore", RIEGEL_ANN_KATHRIN, "Rüter, Monika",
"Heise, Elk", "Fischbach-Pyttel, Carola", "Schirmer, Stephan-Philipp",
"Telljohann, Katharina",
"Röder, Wilfried", "Dr. Matiss, Claudia", "Koßel, Uwe", "Wagner, Saskia", "Bäcker, Guido",
"Tiben-Thörner, Karin", "Ptach, Stephan", "Steinbiß, Emily", "Berisha, Dafina",
"Meyer, Simon", "Porr, Ulrike", "Lange, Frederik", "Oliva, Nora", "Drossinakis, Panagiotis",
"Jacobs, Ruth", "Bernstein, Til", "Kröger, Manuela-Andrea", "Dr. Enzmann, Dirk",
"Schilling, Alexandra", "Abboud, Hussein", "Petersen, Britt", "Petersen, Johannes",
"Petersen, Doris", "Frese, Gabor", "Suh-von Bremen, Sun Won", "Steppat, Wolfgang",
"Hildebrand, Denise"
));
CDU_BEZIRK.addCandidates(buildCandidates(
HOEFLICH_JUTTA, "Könecke, Christian", "Birnbaum, Andreas", "Möller-Fiedler, Sybille",
"Kochmann, Franziska", "von Deutsch, Christiane", "Hoffmann, Bernd", "Holst, Christian",
"Lau, Roman", "Hille, Robert", "Ahrens, Mareike", DR_LANGHEIN_A_W_HEINRICH,
"Wichmann, Norbert", "Lau, Johanna", "Czernotzky, Birgit", "von Sawilski, Marlies",
"Dönselmann, Malte",
"Jarzembowski, Daniel", "Howe, Sönke", "Recknagel, Dennis", "Dieball, Laura",
"Josefowsky, Ernst Günther", "Wysocki, Michael", "Thomsen, Thomas", "Greshake, Sascha",
"Thiesen, Marianne",
"Schüller, Michael", "Jacobs, Jürgen", "Weiler, Johannes", "Howe, Raphaela"
));
LINKE_BEZIRK.addCandidates(buildCandidates(
PAGELS_MANUELA, WIEGMANN_ROLAND, "Peters, Ralf", "Hoyer, Jonas",
KLEINERT_MIKEY, "Schulte, Kolja", "Huwald, Kristin", "Dr. Ritter, Sabine",
"Pirling, David", "Reipschläger, Bernhard", "Arndt, Thomas", "Artus, Holger",
"WLaab, Helene"
));
GRUENE_BEZIRK.addCandidates(buildCandidates(
"Kern, Lisa", "Hadji Mir Agha, Ali", "Dr. Putz, Miriam", KUHLMANN_DIETMAR,
"Dr. Hunter, Lynne", "Schmidt-Tobler, Falk", "Demirhan, Sina", KLEIN_ROBERT,
ERK_ARAMAK, MARTENS_JIM, "Warnecke, Anne Kathrin", DR_FISCHER_JOST_LEONHARDT,
"Kost, Cornelia", "Brandt, Christopher", "Schübel, Nina Joana", "Schmidt, Lutz",
"Wolf, Rita",
"Alam, Leon", "Schwarzwald, Cristina", "Thies, Nico", "Hasselmann, Annette",
"Koriath, Jan", KUELL_GABRIELA, "Köhler, Kevin", "Hericks, Susanne",
BOHNY_CARL_MARIA,
"Fester, Emilia", "Hofmann, Klaus-Dieter", "Neumann, Bernd", "Braasch, Julian",
DORSCH_SEBASTIAN, "Hasselmann, Harald"
));
FDP_BEZIRK.addCandidates(buildCandidates(
KRUEGER_KLAUS, SCHWANKE_BENJAMIN, "Cleven, Martina", "Zielinski, Mathias",
"Thiele, Camilla Joyce", "Krüger, Hannelore", "Welling, Jörg", "Häffs, Marvin",
"Korb, Hendrik", "Bahmer, Larissa", "Langbehn, Marian", "Szrubarski, Sebastian",
"Patzer, Heinrich-Otto", "Sosin, Tatjana", "Damm, Renate", MUELLER_SOENKSEN_BURKHARDT
));
AFD_BEZIRK.addCandidates(buildCandidates(
SCHOEMER_DIRK, ZIMMERMANN_ELKE, PILLATZKE_JOERG, "Pohl, Christian",
"Hanssen, Wolfgang", "Lemke, Martin", "Cremer-Thursby, Marc", "Schultz, Thomas",
"Ziob, Peter"
));
PIRATEN_BEZIRK.addCandidates(buildCandidates(
"Dr. Siebert-Schütz, Martin", "Mewes, Christoph", "Brümmer, Amadeus"
));
}
private static Nomination buildNomination(String name, boolean supportVotesOnNomination) {
return new Nomination(name, supportVotesOnNomination);
}
private static Collection<Candidate> buildCandidates(String... names) {
return Arrays.stream(names).map(name -> new Candidate(name, "")).toList();
}
@NonNull
private static Map<Integer, Integer> buildVotesPerPosition(@NonNull int... votes) {
return IntStream.rangeClosed(1, votes.length)
.boxed()
.collect(Collectors.toMap(Function.identity(), i -> votes[i - 1]));
} }
@BeforeEach @BeforeEach
@@ -84,20 +242,18 @@ class CalculationServiceTest {
@Test @Test
void shouldCalculateConstituencyCorrectly() { void shouldCalculateConstituencyCorrectly() {
Collection<Nomination> nominations = List.of( Collection<VotingResult> votingResults = List.of(
SPD_NIENDORF, SPD_NIENDORF_RESULT,
CDU_NIENDORF, CDU_NIENDORF_RESULT,
LINKE_NIENDORF, LINKE_NIENDORF_RESULT,
FDP_NIENDORF, GRUENE_NIENDORF_RESULT,
GRUENE_NIENDORF, FDP_NIENDORF_RESULT,
AFD_NIENDORF AFD_NIENDORF_RESULT
); );
setUpCandidatesConstituency();
setUpResultsConstituency();
ElectedResult elected = service.calculateConstituency(NIENDORF, nominations); ElectedResult elected = service.calculateConstituency(NIENDORF, votingResults);
Assertions.assertThat(elected.electedCandidates()) Assertions.assertThat(elected.electedCandidatesByNomination())
.containsKey(SPD_NIENDORF) .containsKey(SPD_NIENDORF)
.containsKey(CDU_NIENDORF) .containsKey(CDU_NIENDORF)
.containsKey(GRUENE_NIENDORF) .containsKey(GRUENE_NIENDORF)
@@ -114,16 +270,17 @@ class CalculationServiceTest {
Election election = new Election("Bezirkswahl 2019", Election election = new Election("Bezirkswahl 2019",
LocalDate.of(2019, Month.MAY, 26), VotingThreshold.THREE, LocalDate.of(2019, Month.MAY, 26), VotingThreshold.THREE,
51, constituencies); 51, constituencies);
Collection<Nomination> nominations = List.of( Collection<VotingResult> votingResults = List.of(
SPD_BEZIRK, SPD_BEZIRK_RESULT,
CDU_BEZIRK, CDU_BEZIRK_RESULT,
LINKE_BEZIRK, LINKE_BEZIRK_RESULT,
FDP_BEZIRK, GRUENE_BEZIRK_RESULT,
GRUENE_BEZIRK, FDP_BEZIRK_RESULT,
AFD_BEZIRK AFD_BEZIRK_RESULT,
PIRATEN_BEZIRK_RESULT
); );
SeatResult result = service.calculateOverallSeatDistribution(election, nominations); SeatResult result = service.calculateOverallSeatDistribution(election, votingResults);
Assertions.assertThat(result.seatsPerNomination()) Assertions.assertThat(result.seatsPerNomination())
.containsEntry(SPD_BEZIRK, 12) .containsEntry(SPD_BEZIRK, 12)
@@ -136,19 +293,20 @@ class CalculationServiceTest {
@Test @Test
void shouldCalculateOverallCandidatesCorrectly() { void shouldCalculateOverallCandidatesCorrectly() {
Map<Nomination, Integer> seatsPerNomination = Map.of( Map<VotingResult, Integer> seatsPerVotingResult = Map.of(
SPD_BEZIRK, 2, SPD_BEZIRK_RESULT, 2,
CDU_BEZIRK, 2, CDU_BEZIRK_RESULT, 2,
LINKE_BEZIRK, 3, LINKE_BEZIRK_RESULT, 3,
GRUENE_BEZIRK, 8, GRUENE_BEZIRK_RESULT, 8,
FDP_BEZIRK, 3, FDP_BEZIRK_RESULT, 3,
AFD_BEZIRK, 3 AFD_BEZIRK_RESULT, 3
); );
Map<Nomination, Collection<ElectedCandidate>> electedCandidates = setUpConstituencyResults(); Map<VotingResult, Collection<ElectedCandidate>> electedCandidates = setUpConstituencyResults();
ElectedResult result = service.calculateElectedOverallCandidates(seatsPerNomination, electedCandidates); ElectedResult result = service.calculateElectedOverallCandidates(seatsPerVotingResult,
electedCandidates);
Assertions.assertThat(result.electedCandidates()) Assertions.assertThat(result.electedCandidatesByNomination())
.anySatisfy((nomination, candidates) -> { .anySatisfy((nomination, candidates) -> {
Assertions.assertThat(nomination).isEqualTo(SPD_BEZIRK); Assertions.assertThat(nomination).isEqualTo(SPD_BEZIRK);
Assertions.assertThat(candidates) Assertions.assertThat(candidates)
@@ -217,231 +375,9 @@ class CalculationServiceTest {
}); });
} }
private void setUpCandidatesConstituency() { @NonNull
SPD_NIENDORF.addCandidates(new Candidate("Schwarzarius, Ines", "")); private Map<VotingResult, Collection<ElectedCandidate>> setUpConstituencyResults() {
SPD_NIENDORF.addCandidates(new Candidate("Urbanski, Torge", "")); return Map.of(GRUENE_BEZIRK_RESULT, List.of(
SPD_NIENDORF.addCandidates(new Candidate("Fischbach-Pyttel, Carola", ""));
SPD_NIENDORF.addCandidates(new Candidate("Bäcker, Guido", ""));
SPD_NIENDORF.addCandidates(new Candidate("Porr, Ulrike", ""));
SPD_NIENDORF.addCandidates(new Candidate("Petersen, Johannes", ""));
SPD_NIENDORF.addCandidates(new Candidate("Kröger, Manuela-Andrea", ""));
SPD_NIENDORF.addCandidates(new Candidate("Steppat, Wolfgang", ""));
SPD_NIENDORF.addCandidates(new Candidate("Canbay, Berfin", ""));
SPD_NIENDORF.addCandidates(new Candidate("Schumacher, Wolfgang", ""));
CDU_NIENDORF.addCandidates(new Candidate("Kuhn, Rüdiger", ""));
CDU_NIENDORF.addCandidates(new Candidate("Ahrens, Mareike", ""));
CDU_NIENDORF.addCandidates(new Candidate("Wysocki, Michael", ""));
CDU_NIENDORF.addCandidates(new Candidate("Dönselmann, Malte", ""));
CDU_NIENDORF.addCandidates(new Candidate("Seehaber, Daniel", ""));
LINKE_NIENDORF.addCandidates(new Candidate("Dr. Khenkhar, Malik", ""));
LINKE_NIENDORF.addCandidates(new Candidate("Radom, Claudia", ""));
LINKE_NIENDORF.addCandidates(new Candidate("Kara, Başak", ""));
FDP_NIENDORF.addCandidates(new Candidate("Häffs, Marvin", ""));
FDP_NIENDORF.addCandidates(new Candidate("Bahmer, Larissa", ""));
FDP_NIENDORF.addCandidates(new Candidate("Patzer, Heinrich-Otto", ""));
GRUENE_NIENDORF.addCandidates(new Candidate("Demirhan, Sina", ""));
GRUENE_NIENDORF.addCandidates(new Candidate("Schmidt, Lutz", "Redakteur"));
AFD_NIENDORF.addCandidates(new Candidate("Hanssen, Wolfgang", ""));
}
private void setUpResultsConstituency() {
SPD_NIENDORF.setVotingResult(VotingResult.builder()
.votesOnNomination(0)
.votesPerPosition(Map.of(
1, 11882,
2, 7617,
3, 1946,
4, 1743,
5, 1363,
6, 762,
7, 895,
8, 1598,
9, 1786,
10, 781
))
.build());
CDU_NIENDORF.setVotingResult(VotingResult.builder()
.votesOnNomination(0)
.votesPerPosition(Map.of(
1, 10733,
2, 4550,
3, 2310,
4, 2333,
5, 2565
))
.build());
LINKE_NIENDORF.setVotingResult(VotingResult.builder()
.votesOnNomination(0)
.votesPerPosition(Map.of(
1, 3782,
2, 1584,
3, 1185
))
.build());
FDP_NIENDORF.setVotingResult(VotingResult.builder()
.votesOnNomination(0)
.votesPerPosition(Map.of(
1, 2498,
2, 3200,
3, 992
))
.build());
GRUENE_NIENDORF.setVotingResult(VotingResult.builder()
.votesOnNomination(0)
.votesPerPosition(Map.of(
1, 14838,
2, 12501
))
.build());
AFD_NIENDORF.setVotingResult(VotingResult.builder()
.votesOnNomination(0)
.votesPerPosition(Map.of(
1, 6616
))
.build());
}
private static void setUpCandidatesOverall() {
SPD_BEZIRK.addCandidates(buildCandidates(
GOTTLIEB_GABOR, "Meding, Sarah", "Harringa, Nils", "Nendza-Ammar, Charlotte",
"Rust, Rüdiger", "Köster-Marjanovic, Hannelore", RIEGEL_ANN_KATHRIN, "Rüter, Monika",
"Heise, Elk", "Fischbach-Pyttel, Carola", "Schirmer, Stephan-Philipp", "Telljohann, Katharina",
"Röder, Wilfried", "Dr. Matiss, Claudia", "Koßel, Uwe", "Wagner, Saskia", "Bäcker, Guido",
"Tiben-Thörner, Karin", "Ptach, Stephan", "Steinbiß, Emily", "Berisha, Dafina",
"Meyer, Simon", "Porr, Ulrike", "Lange, Frederik", "Oliva, Nora", "Drossinakis, Panagiotis",
"Jacobs, Ruth", "Bernstein, Til", "Kröger, Manuela-Andrea", "Dr. Enzmann, Dirk",
"Schilling, Alexandra", "Abboud, Hussein", "Petersen, Britt", "Petersen, Johannes",
"Petersen, Doris", "Frese, Gabor", "Suh-von Bremen, Sun Won", "Steppat, Wolfgang",
"Hildebrand, Denise"
));
CDU_BEZIRK.addCandidates(buildCandidates(
HOEFLICH_JUTTA, "Könecke, Christian", "Birnbaum, Andreas", "Möller-Fiedler, Sybille",
"Kochmann, Franziska", "von Deutsch, Christiane", "Hoffmann, Bernd", "Holst, Christian",
"Lau, Roman", "Hille, Robert", "Ahrens, Mareike", DR_LANGHEIN_A_W_HEINRICH,
"Wichmann, Norbert", "Lau, Johanna", "Czernotzky, Birgit", "von Sawilski, Marlies",
"Dönselmann, Malte",
"Jarzembowski, Daniel", "Howe, Sönke", "Recknagel, Dennis", "Dieball, Laura",
"Josefowsky, Ernst Günther", "Wysocki, Michael", "Thomsen, Thomas", "Greshake, Sascha",
"Thiesen, Marianne",
"Schüller, Michael", "Jacobs, Jürgen", "Weiler, Johannes", "Howe, Raphaela"
));
LINKE_BEZIRK.addCandidates(buildCandidates(
PAGELS_MANUELA, WIEGMANN_ROLAND, "Peters, Ralf", "Hoyer, Jonas",
KLEINERT_MIKEY, "Schulte, Kolja", "Huwald, Kristin", "Dr. Ritter, Sabine",
"Pirling, David", "Reipschläger, Bernhard", "Arndt, Thomas", "Artus, Holger",
"WLaab, Helene"
));
GRUENE_BEZIRK.addCandidates(buildCandidates(
"Kern, Lisa", "Hadji Mir Agha, Ali", "Dr. Putz, Miriam", KUHLMANN_DIETMAR,
"Dr. Hunter, Lynne", "Schmidt-Tobler, Falk", "Demirhan, Sina", KLEIN_ROBERT,
ERK_ARAMAK, MARTENS_JIM, "Warnecke, Anne Kathrin", DR_FISCHER_JOST_LEONHARDT,
"Kost, Cornelia", "Brandt, Christopher", "Schübel, Nina Joana", "Schmidt, Lutz",
"Wolf, Rita",
"Alam, Leon", "Schwarzwald, Cristina", "Thies, Nico", "Hasselmann, Annette",
"Koriath, Jan", KUELL_GABRIELA, "Köhler, Kevin", "Hericks, Susanne",
BOHNY_CARL_MARIA,
"Fester, Emilia", "Hofmann, Klaus-Dieter", "Neumann, Bernd", "Braasch, Julian",
DORSCH_SEBASTIAN, "Hasselmann, Harald"
));
FDP_BEZIRK.addCandidates(buildCandidates(
KRUEGER_KLAUS, SCHWANKE_BENJAMIN, "Cleven, Martina", "Zielinski, Mathias",
"Thiele, Camilla Joyce", "Krüger, Hannelore", "Welling, Jörg", "Häffs, Marvin",
"Korb, Hendrik", "Bahmer, Larissa", "Langbehn, Marian", "Szrubarski, Sebastian",
"Patzer, Heinrich-Otto", "Sosin, Tatjana", "Damm, Renate", MUELLER_SOENKSEN_BURKHARDT
));
AFD_BEZIRK.addCandidates(buildCandidates(
SCHOEMER_DIRK, ZIMMERMANN_ELKE, PILLATZKE_JOERG, "Pohl, Christian",
"Hanssen, Wolfgang", "Lemke, Martin", "Cremer-Thursby, Marc", "Schultz, Thomas",
"Ziob, Peter"
));
PIRATEN_BEZIRK.addCandidates(buildCandidates(
"Dr. Siebert-Schütz, Martin", "Mewes, Christoph", "Brümmer, Amadeus"
));
}
private static void setUpResultsOverall() {
SPD_BEZIRK.setVotingResult(VotingResult.builder()
.votesOnNomination(84703)
.votesThroughHealing(985)
.votesPerPosition(buildVotesPerPosition(
8782, 3318, 3825, 3519, 2036, 3923, 5427, 2131, 566, 895, 1425, 1924, 819,
2590, 2190, 3568, 742, 401, 554, 1133, 1268, 580, 254, 1217, 693, 1359, 481,
650, 230, 1544, 1080, 1879, 400, 353, 525, 469, 196, 759, 872
))
.build());
CDU_BEZIRK.setVotingResult(VotingResult.builder()
.votesOnNomination(66245)
.votesThroughHealing(660)
.votesPerPosition(buildVotesPerPosition(
5966, 1982, 1604, 2414, 1322, 2237, 1868, 1872, 1889, 881, 1253, 2921, 598,
2721, 618, 941, 620, 837, 378, 594, 484, 584, 472, 408, 748, 650, 282,
315, 1397, 502
))
.build());
LINKE_BEZIRK.setVotingResult(VotingResult.builder()
.votesOnNomination(47452)
.votesThroughHealing(330)
.votesPerPosition(buildVotesPerPosition(
4890, 875, 1532, 1293, 2321, 696, 1843, 2212, 1488, 483, 764, 572, 892
))
.build());
GRUENE_BEZIRK.setVotingResult(VotingResult.builder()
.votesOnNomination(150842)
.votesThroughHealing(900)
.votesPerPosition(buildVotesPerPosition(
10586, 5629, 12597, 2935, 3378, 735, 5662, 4021, 2065, 2469, 1561, 3557, 2290,
1411, 2445, 1761, 1252, 1628, 652, 3524, 677, 843, 2375, 500, 1674, 3264, 1569,
531, 531, 652, 5358, 2129
))
.build());
FDP_BEZIRK.setVotingResult(VotingResult.builder()
.votesOnNomination(24435)
.votesThroughHealing(240)
.votesPerPosition(buildVotesPerPosition(
3528, 1964, 1633, 897, 1193, 355, 401, 1012, 496, 1242, 643, 300, 311,
998, 505, 2181
))
.build());
AFD_BEZIRK.setVotingResult(VotingResult.builder()
.votesOnNomination(21625)
.votesThroughHealing(220)
.votesPerPosition(buildVotesPerPosition(
1226, 1950, 3007, 874, 1032, 780, 535, 221, 283
))
.build());
PIRATEN_BEZIRK.setVotingResult(VotingResult.builder()
.votesOnNomination(6715)
.votesThroughHealing(25)
.votesPerPosition(buildVotesPerPosition(
871, 1907, 987
))
.build());
}
private Map<Nomination, Collection<ElectedCandidate>> setUpConstituencyResults() {
return Map.of(GRUENE_BEZIRK, List.of(
new ElectedCandidate(GRUENE_BEZIRK.getCandidate(1), Elected.CONSTITUENCY), new ElectedCandidate(GRUENE_BEZIRK.getCandidate(1), Elected.CONSTITUENCY),
new ElectedCandidate(GRUENE_BEZIRK.getCandidate(2), Elected.CONSTITUENCY), new ElectedCandidate(GRUENE_BEZIRK.getCandidate(2), Elected.CONSTITUENCY),
new ElectedCandidate(GRUENE_BEZIRK.getCandidate(3), Elected.CONSTITUENCY), new ElectedCandidate(GRUENE_BEZIRK.getCandidate(3), Elected.CONSTITUENCY),
@@ -455,22 +391,4 @@ class CalculationServiceTest {
new ElectedCandidate(GRUENE_BEZIRK.getCandidate(22), Elected.CONSTITUENCY) new ElectedCandidate(GRUENE_BEZIRK.getCandidate(22), Elected.CONSTITUENCY)
)); ));
} }
private static Nomination buildNomination(String name, boolean supportVotesOnNomination) {
return new Nomination(name, supportVotesOnNomination);
}
private static Collection<Candidate> buildCandidates(String... names) {
return Arrays.stream(names).map(name -> new Candidate(name, "")).toList();
}
@NonNull
private static Map<Integer, Integer> buildVotesPerPosition(@NonNull int... votes) {
Map<Integer, Integer> votesPerPosition = new HashMap<>();
for (int i = 0; i < votes.length; i++) {
int vote = votes[i];
votesPerPosition.put(i + 1, vote);
}
return votesPerPosition;
}
} }