Store nomination within voting result
This commit is contained in:
@@ -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() {
|
||||||
|
|||||||
+68
-64
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
+216
-298
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user