From 503b284b740d1ad80d58eb193307b2956008ebc9 Mon Sep 17 00:00:00 2001 From: Jim Martens Date: Sun, 2 Jul 2023 21:33:15 +0200 Subject: [PATCH] Added calculation of overall seat allocation --- .../wahlrecht/model/Nomination.java | 5 + .../wahlrecht/model/SeatResult.java | 11 + .../wahlrecht/model/VotingResult.java | 7 +- ...onService.java => CalculationService.java} | 40 +- .../service/CalculationServiceTest.java | 348 ++++++++++++++++++ .../ConstituencyCalculationServiceTest.java | 152 -------- 6 files changed, 408 insertions(+), 155 deletions(-) create mode 100644 module-server/src/main/java/de/twomartens/wahlrecht/model/SeatResult.java rename module-server/src/main/java/de/twomartens/wahlrecht/service/{ConstituencyCalculationService.java => CalculationService.java} (78%) create mode 100644 module-server/src/test/java/de/twomartens/wahlrecht/service/CalculationServiceTest.java delete mode 100644 module-server/src/test/java/de/twomartens/wahlrecht/service/ConstituencyCalculationServiceTest.java diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/model/Nomination.java b/module-server/src/main/java/de/twomartens/wahlrecht/model/Nomination.java index c9bc36b..e2f069e 100644 --- a/module-server/src/main/java/de/twomartens/wahlrecht/model/Nomination.java +++ b/module-server/src/main/java/de/twomartens/wahlrecht/model/Nomination.java @@ -2,6 +2,7 @@ package de.twomartens.wahlrecht.model; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,6 +36,10 @@ public class Nomination { Arrays.stream(candidates).forEach(this::addCandidate); } + public void addCandidates(Collection candidates) { + candidates.forEach(this::addCandidate); + } + public Candidate getCandidate(int position) { return positionToCandidate.get(position); } diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/model/SeatResult.java b/module-server/src/main/java/de/twomartens/wahlrecht/model/SeatResult.java new file mode 100644 index 0000000..19d0a64 --- /dev/null +++ b/module-server/src/main/java/de/twomartens/wahlrecht/model/SeatResult.java @@ -0,0 +1,11 @@ +package de.twomartens.wahlrecht.model; + +import java.util.Deque; +import java.util.Map; +import lombok.Builder; + +@Builder +public record SeatResult(Map seatsPerNomination, + Deque usedElectionNumbers) { + +} diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/model/VotingResult.java b/module-server/src/main/java/de/twomartens/wahlrecht/model/VotingResult.java index 100f787..94ba941 100644 --- a/module-server/src/main/java/de/twomartens/wahlrecht/model/VotingResult.java +++ b/module-server/src/main/java/de/twomartens/wahlrecht/model/VotingResult.java @@ -8,18 +8,21 @@ import lombok.Getter; public class VotingResult { private final int votesOnNomination; + private final int votesThroughHealing; private final Map votesPerPosition; private Integer totalVotes = null; @Builder - public VotingResult(int votesOnNomination, Map votesPerPosition) { + public VotingResult(int votesOnNomination, int votesThroughHealing, + Map votesPerPosition) { this.votesOnNomination = votesOnNomination; + this.votesThroughHealing = votesThroughHealing; this.votesPerPosition = votesPerPosition; } public int getTotalVotes() { if (totalVotes == null) { - totalVotes = votesOnNomination + votesPerPosition.values().stream() + totalVotes = votesOnNomination + votesThroughHealing + votesPerPosition.values().stream() .reduce(0, Integer::sum); } return totalVotes; diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/service/ConstituencyCalculationService.java b/module-server/src/main/java/de/twomartens/wahlrecht/service/CalculationService.java similarity index 78% rename from module-server/src/main/java/de/twomartens/wahlrecht/service/ConstituencyCalculationService.java rename to module-server/src/main/java/de/twomartens/wahlrecht/service/CalculationService.java index 480bda8..6a177d8 100644 --- a/module-server/src/main/java/de/twomartens/wahlrecht/service/ConstituencyCalculationService.java +++ b/module-server/src/main/java/de/twomartens/wahlrecht/service/CalculationService.java @@ -3,7 +3,9 @@ package de.twomartens.wahlrecht.service; import de.twomartens.wahlrecht.model.Candidate; import de.twomartens.wahlrecht.model.Constituency; import de.twomartens.wahlrecht.model.ElectedResult; +import de.twomartens.wahlrecht.model.Election; import de.twomartens.wahlrecht.model.Nomination; +import de.twomartens.wahlrecht.model.SeatResult; import de.twomartens.wahlrecht.model.VotingResult; import java.util.ArrayDeque; import java.util.ArrayList; @@ -19,7 +21,7 @@ import org.springframework.lang.NonNull; import org.springframework.stereotype.Service; @Service -public class ConstituencyCalculationService { +public class CalculationService { private final Deque electionNumberHistory = new ArrayDeque<>(); public ElectedResult calculateConstituency(@NonNull Constituency constituency, @@ -41,6 +43,42 @@ public class ConstituencyCalculationService { .build(); } + public SeatResult calculateOverallSeatDistribution(@NonNull Election election, + @NonNull Collection nominations) { + electionNumberHistory.clear(); + int totalVotes = nominations.stream() + .map(Nomination::getVotingResult) + .map(VotingResult::getTotalVotes) + .reduce(0, Integer::sum); + + List validNominations = new ArrayList<>(); + int totalIgnoredVotes = 0; + for (Nomination nomination : nominations) { + if (passesVotingThreshold(election, totalVotes, nomination)) { + validNominations.add(nomination); + } else { + totalIgnoredVotes += nomination.getVotingResult().getTotalVotes(); + } + } + totalVotes -= totalIgnoredVotes; + + int numberOfSeats = election.totalNumberOfSeats(); + double initialElectionNumber = totalVotes / (double) numberOfSeats; + + Map assignedSeatsPerNomination = calculateAssignedSeatsPerNomination( + validNominations, numberOfSeats, initialElectionNumber); + + return SeatResult.builder() + .seatsPerNomination(assignedSeatsPerNomination) + .usedElectionNumbers(electionNumberHistory) + .build(); + } + + private static boolean passesVotingThreshold(Election election, int totalVotes, Nomination nomination) { + return totalVotes * election.votingThreshold().getMultiplier() + <= nomination.getVotingResult().getTotalVotes(); + } + @NonNull private Map> findElectedCandidates( @NonNull Map assignedSeatsPerNomination) { diff --git a/module-server/src/test/java/de/twomartens/wahlrecht/service/CalculationServiceTest.java b/module-server/src/test/java/de/twomartens/wahlrecht/service/CalculationServiceTest.java new file mode 100644 index 0000000..253c7f8 --- /dev/null +++ b/module-server/src/test/java/de/twomartens/wahlrecht/service/CalculationServiceTest.java @@ -0,0 +1,348 @@ +package de.twomartens.wahlrecht.service; + +import de.twomartens.wahlrecht.model.Candidate; +import de.twomartens.wahlrecht.model.Constituency; +import de.twomartens.wahlrecht.model.ElectedResult; +import de.twomartens.wahlrecht.model.Election; +import de.twomartens.wahlrecht.model.Nomination; +import de.twomartens.wahlrecht.model.SeatResult; +import de.twomartens.wahlrecht.model.VotingResult; +import de.twomartens.wahlrecht.model.VotingThreshold; +import java.time.LocalDate; +import java.time.Month; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.lang.NonNull; + +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); + + private CalculationService service; + + @BeforeEach + void setService() { + service = new CalculationService(); + } + + @Test + void shouldCalculateConstituencyCorrectly() { + Collection nominations = List.of( + SPD_NIENDORF, + CDU_NIENDORF, + LINKE_NIENDORF, + FDP_NIENDORF, + GRUENE_NIENDORF, + AFD_NIENDORF + ); + setUpCandidatesConstituency(); + setUpResultsConstituency(); + + ElectedResult elected = service.calculateConstituency(NIENDORF, nominations); + + Assertions.assertThat(elected.electedCandidates()) + .containsKey(SPD_NIENDORF) + .containsKey(CDU_NIENDORF) + .containsKey(GRUENE_NIENDORF) + .doesNotContainKey(LINKE_NIENDORF) + .doesNotContainKey(AFD_NIENDORF) + .doesNotContainKey(FDP_NIENDORF); + } + + @Test + void shouldCalculateOverallSeatsCorrectly() { + Collection constituencies = List.of( + EIMSBUETTEL_NORD, EIMSBUETTEL_SUED, HARO, + LOKSTEDT, NIENDORF, SCHNELSEN, EIDELSTEDT, STELLINGEN); + Election election = new Election("Bezirkswahl 2019", + LocalDate.of(2019, Month.MAY, 26), VotingThreshold.THREE, + 51, constituencies); + Collection nominations = List.of( + SPD_BEZIRK, + CDU_BEZIRK, + LINKE_BEZIRK, + FDP_BEZIRK, + GRUENE_BEZIRK, + AFD_BEZIRK + ); + setUpCandidatesOverall(); + setUpResultsOverall(); + + SeatResult result = service.calculateOverallSeatDistribution(election, nominations); + + Assertions.assertThat(result.seatsPerNomination()) + .containsEntry(SPD_BEZIRK, 12L) + .containsEntry(CDU_BEZIRK, 9L) + .containsEntry(LINKE_BEZIRK, 5L) + .containsEntry(FDP_BEZIRK, 3L) + .containsEntry(GRUENE_BEZIRK, 19L) + .containsEntry(AFD_BEZIRK, 3L); + } + + private 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 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 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( + "Höflich, 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", "Küll, 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( + "Krüger, 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", "Müller-Sönksen, Burkhardt" + )); + + AFD_BEZIRK.addCandidates(buildCandidates( + "Schömer, Dirk", "Zimmermann, Elke", "Pillatzke, Jörg", "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 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 static Nomination buildNomination(String name, boolean supportVotesOnNomination) { + return new Nomination(name, supportVotesOnNomination); + } + + private static Collection buildCandidates(String... names) { + return Arrays.stream(names).map(name -> new Candidate(name, "")).toList(); + } + + @NonNull + private static Map buildVotesPerPosition(@NonNull int... votes) { + Map votesPerPosition = new HashMap<>(); + for (int i = 0; i < votes.length; i++) { + int vote = votes[i]; + votesPerPosition.put(i + 1, vote); + } + return votesPerPosition; + } +} \ No newline at end of file diff --git a/module-server/src/test/java/de/twomartens/wahlrecht/service/ConstituencyCalculationServiceTest.java b/module-server/src/test/java/de/twomartens/wahlrecht/service/ConstituencyCalculationServiceTest.java deleted file mode 100644 index 74b02af..0000000 --- a/module-server/src/test/java/de/twomartens/wahlrecht/service/ConstituencyCalculationServiceTest.java +++ /dev/null @@ -1,152 +0,0 @@ -package de.twomartens.wahlrecht.service; - -import de.twomartens.wahlrecht.model.Candidate; -import de.twomartens.wahlrecht.model.Constituency; -import de.twomartens.wahlrecht.model.ElectedResult; -import de.twomartens.wahlrecht.model.Nomination; -import de.twomartens.wahlrecht.model.VotingResult; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class ConstituencyCalculationServiceTest { - private static final Nomination SPD_NIENDORF = buildNomination("SPD-Niendorf"); - private static final Nomination CDU_NIENDORF = buildNomination("CDU-Niendorf"); - private static final Nomination FDP_NIENDORF = buildNomination("FDP-Niendorf"); - private static final Nomination LINKE_NIENDORF = buildNomination("LINKE-Niendorf"); - private static final Nomination GRUENE_NIENDORF = buildNomination("GRUENE-Niendorf"); - private static final Nomination AFD_NIENDORF = buildNomination("AFD-Niendorf"); - - private ConstituencyCalculationService service; - - @BeforeEach - void setService() { - service = new ConstituencyCalculationService(); - } - - @Test - void shouldCalculateConstituencyCorrectly() { - Constituency constituency = new Constituency("Niendorf", 5); - Collection nominations = List.of( - SPD_NIENDORF, - CDU_NIENDORF, - LINKE_NIENDORF, - FDP_NIENDORF, - GRUENE_NIENDORF, - AFD_NIENDORF - ); - setUpCandidates(); - setUpResults(); - - ElectedResult elected = service.calculateConstituency(constituency, nominations); - - Assertions.assertThat(elected.electedCandidates()) - .containsKey(SPD_NIENDORF) - .containsKey(CDU_NIENDORF) - .containsKey(GRUENE_NIENDORF) - .doesNotContainKey(LINKE_NIENDORF) - .doesNotContainKey(AFD_NIENDORF) - .doesNotContainKey(FDP_NIENDORF); - } - - private void setUpCandidates() { - 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 void setUpResults() { - 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 Nomination buildNomination(String name) { - return new Nomination(name, false); - } -} \ No newline at end of file