Added ability to calculate election result
This commit is contained in:
+58
@@ -0,0 +1,58 @@
|
|||||||
|
package de.twomartens.wahlrecht.controller.v1;
|
||||||
|
|
||||||
|
import de.twomartens.wahlrecht.mapper.v1.ElectedCandidatesMapper;
|
||||||
|
import de.twomartens.wahlrecht.mapper.v1.ElectionResultMapper;
|
||||||
|
import de.twomartens.wahlrecht.model.dto.v1.ElectedCandidates;
|
||||||
|
import de.twomartens.wahlrecht.model.dto.v1.ElectionResult;
|
||||||
|
import de.twomartens.wahlrecht.service.CalculationService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping(value = "/wahlrecht/v1")
|
||||||
|
@Tag(name = "Calculations", description = "all requests relating to calculations")
|
||||||
|
public class CalculationController {
|
||||||
|
|
||||||
|
private final ElectedCandidatesMapper electedCandidatesMapper = Mappers.getMapper(
|
||||||
|
ElectedCandidatesMapper.class);
|
||||||
|
private final ElectionResultMapper electionResultMapper = Mappers.getMapper(
|
||||||
|
ElectionResultMapper.class);
|
||||||
|
private final CalculationService service;
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Calculates a provided election result",
|
||||||
|
description = "This request does not store any result and is idempotent.",
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(responseCode = "200",
|
||||||
|
description = "Returns all elected candidates",
|
||||||
|
content = {@Content(
|
||||||
|
mediaType = "application/json",
|
||||||
|
schema = @Schema(implementation = ElectedCandidates.class))}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@PostMapping(value = "/calculate", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<ElectedCandidates> calculateResult(
|
||||||
|
@RequestBody ElectionResult electionResult
|
||||||
|
) {
|
||||||
|
ElectedCandidates result = electedCandidatesMapper.mapToExternal(
|
||||||
|
service.determineElectedCandidates(electionResultMapper.mapToInternal(electionResult)));
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.body(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
package de.twomartens.wahlrecht.mapper.v1;
|
||||||
|
|
||||||
|
import de.twomartens.wahlrecht.model.internal.ElectedCandidate;
|
||||||
|
import de.twomartens.wahlrecht.model.internal.ElectedCandidates;
|
||||||
|
import de.twomartens.wahlrecht.model.internal.VotingResult;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.mapstruct.CollectionMappingStrategy;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.NullValueCheckStrategy;
|
||||||
|
import org.mapstruct.ReportingPolicy;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
|
||||||
|
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
||||||
|
unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||||
|
public interface ElectedCandidatesMapper {
|
||||||
|
|
||||||
|
ElectedResultMapper ELECTED_RESULT_MAPPER = Mappers.getMapper(ElectedResultMapper.class);
|
||||||
|
|
||||||
|
|
||||||
|
de.twomartens.wahlrecht.model.dto.v1.ElectedCandidates mapToExternal(ElectedCandidates candidate);
|
||||||
|
|
||||||
|
default Map<String, Collection<de.twomartens.wahlrecht.model.dto.v1.ElectedCandidate>> mapToExternal(
|
||||||
|
Map<VotingResult, Collection<ElectedCandidate>> value) {
|
||||||
|
return ELECTED_RESULT_MAPPER.mapToExternal(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-5
@@ -1,7 +1,6 @@
|
|||||||
package de.twomartens.wahlrecht.mapper.v1;
|
package de.twomartens.wahlrecht.mapper.v1;
|
||||||
|
|
||||||
import de.twomartens.wahlrecht.model.dto.v1.ElectedCandidate;
|
import de.twomartens.wahlrecht.model.dto.v1.ElectedCandidate;
|
||||||
import de.twomartens.wahlrecht.model.dto.v1.NominationId;
|
|
||||||
import de.twomartens.wahlrecht.model.internal.ElectedResult;
|
import de.twomartens.wahlrecht.model.internal.ElectedResult;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -11,6 +10,7 @@ import org.mapstruct.CollectionMappingStrategy;
|
|||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.NullValueCheckStrategy;
|
import org.mapstruct.NullValueCheckStrategy;
|
||||||
import org.mapstruct.ReportingPolicy;
|
import org.mapstruct.ReportingPolicy;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
|
@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
|
||||||
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
||||||
@@ -19,16 +19,21 @@ public interface ElectedResultMapper {
|
|||||||
|
|
||||||
de.twomartens.wahlrecht.model.dto.v1.ElectedResult mapToExternal(ElectedResult result);
|
de.twomartens.wahlrecht.model.dto.v1.ElectedResult mapToExternal(ElectedResult result);
|
||||||
|
|
||||||
Map<NominationId, Collection<ElectedCandidate>> mapToExternal(
|
default Map<String, Collection<ElectedCandidate>> mapToExternal(
|
||||||
Map<de.twomartens.wahlrecht.model.internal.NominationId,
|
@NonNull Map<de.twomartens.wahlrecht.model.internal.VotingResult,
|
||||||
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate>> value);
|
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate>> value) {
|
||||||
|
return value.entrySet().stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
entry -> entry.getKey().getNominationId().partyAbbreviation(),
|
||||||
|
entry -> mapToExternal(entry.getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
Collection<ElectedCandidate> mapToExternal(
|
Collection<ElectedCandidate> mapToExternal(
|
||||||
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate> value);
|
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate> value);
|
||||||
|
|
||||||
default Map<de.twomartens.wahlrecht.model.internal.NominationId,
|
default Map<de.twomartens.wahlrecht.model.internal.NominationId,
|
||||||
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate>> map(
|
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate>> map(
|
||||||
Map<de.twomartens.wahlrecht.model.internal.VotingResult,
|
@NonNull Map<de.twomartens.wahlrecht.model.internal.VotingResult,
|
||||||
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate>> value) {
|
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate>> value) {
|
||||||
return value.entrySet().stream()
|
return value.entrySet().stream()
|
||||||
.collect(Collectors.toMap(entry -> entry.getKey().getNominationId(), Entry::getValue));
|
.collect(Collectors.toMap(entry -> entry.getKey().getNominationId(), Entry::getValue));
|
||||||
|
|||||||
+9
-1
@@ -9,13 +9,17 @@ import org.mapstruct.Mapper;
|
|||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.NullValueCheckStrategy;
|
import org.mapstruct.NullValueCheckStrategy;
|
||||||
import org.mapstruct.ReportingPolicy;
|
import org.mapstruct.ReportingPolicy;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
|
@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
|
||||||
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
||||||
unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||||
public interface ElectionResultMapper {
|
public interface ElectionResultMapper {
|
||||||
|
|
||||||
de.twomartens.wahlrecht.model.dto.v1.ElectionResult mapToExternal(de.twomartens.wahlrecht.model.db.ElectionResult result);
|
VotingResultMapper VOTING_RESULT_MAPPER = Mappers.getMapper(VotingResultMapper.class);
|
||||||
|
|
||||||
|
de.twomartens.wahlrecht.model.dto.v1.ElectionResult mapToExternal(
|
||||||
|
de.twomartens.wahlrecht.model.db.ElectionResult result);
|
||||||
|
|
||||||
Collection<de.twomartens.wahlrecht.model.dto.v1.VotingResult> mapToExternal(
|
Collection<de.twomartens.wahlrecht.model.dto.v1.VotingResult> mapToExternal(
|
||||||
Collection<de.twomartens.wahlrecht.model.db.VotingResult> results);
|
Collection<de.twomartens.wahlrecht.model.db.VotingResult> results);
|
||||||
@@ -36,6 +40,10 @@ public interface ElectionResultMapper {
|
|||||||
|
|
||||||
ElectionResult mapToInternal(de.twomartens.wahlrecht.model.dto.v1.ElectionResult result);
|
ElectionResult mapToInternal(de.twomartens.wahlrecht.model.dto.v1.ElectionResult result);
|
||||||
|
|
||||||
|
default VotingResult mapToInternal(de.twomartens.wahlrecht.model.dto.v1.VotingResult result) {
|
||||||
|
return VOTING_RESULT_MAPPER.mapToInternal(result);
|
||||||
|
}
|
||||||
|
|
||||||
Collection<VotingResult> mapToInternal(
|
Collection<VotingResult> mapToInternal(
|
||||||
Collection<de.twomartens.wahlrecht.model.dto.v1.VotingResult> results);
|
Collection<de.twomartens.wahlrecht.model.dto.v1.VotingResult> results);
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -6,13 +6,14 @@ import org.mapstruct.CollectionMappingStrategy;
|
|||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.NullValueCheckStrategy;
|
import org.mapstruct.NullValueCheckStrategy;
|
||||||
import org.mapstruct.ReportingPolicy;
|
import org.mapstruct.ReportingPolicy;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
|
@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
|
||||||
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
||||||
unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||||
public interface VotingResultMapper {
|
public interface VotingResultMapper {
|
||||||
|
|
||||||
default de.twomartens.wahlrecht.model.dto.v1.VotingResult mapToExternal(VotingResult result) {
|
default de.twomartens.wahlrecht.model.dto.v1.VotingResult mapToExternal(@NonNull VotingResult result) {
|
||||||
return new de.twomartens.wahlrecht.model.dto.v1.VotingResult(
|
return new de.twomartens.wahlrecht.model.dto.v1.VotingResult(
|
||||||
result.getNominationId().electionName(),
|
result.getNominationId().electionName(),
|
||||||
result.getNominationId().partyAbbreviation(),
|
result.getNominationId().partyAbbreviation(),
|
||||||
@@ -23,7 +24,7 @@ public interface VotingResultMapper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
default VotingResult mapToInternal(de.twomartens.wahlrecht.model.dto.v1.VotingResult result) {
|
default VotingResult mapToInternal(@NonNull de.twomartens.wahlrecht.model.dto.v1.VotingResult result) {
|
||||||
return new VotingResult(
|
return new VotingResult(
|
||||||
new NominationId(result.electionName(), result.partyAbbreviation(),
|
new NominationId(result.electionName(), result.partyAbbreviation(),
|
||||||
result.nominationName()),
|
result.nominationName()),
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
package de.twomartens.wahlrecht.model.dto.v1;
|
package de.twomartens.wahlrecht.model.dto.v1;
|
||||||
|
|
||||||
public record ElectedCandidate(Candidate candidate, Elected elected) {
|
public record ElectedCandidate(Candidate candidate, Elected elected) {
|
||||||
|
|
||||||
public String name() {
|
|
||||||
return candidate.name();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String profession() {
|
|
||||||
return candidate.profession();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package de.twomartens.wahlrecht.model.dto.v1;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public record ElectedCandidates(ElectedResult overallResult,
|
||||||
|
Map<Integer, ElectedResult> constituencyResults,
|
||||||
|
LinkedList<Double> electionNumbersForSeatAllocation) {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
package de.twomartens.wahlrecht.model.dto.v1;
|
package de.twomartens.wahlrecht.model.dto.v1;
|
||||||
|
|
||||||
import de.twomartens.wahlrecht.model.internal.NominationId;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
|
|
||||||
@Builder
|
@Builder
|
||||||
public record ElectedResult(Map<NominationId, Collection<ElectedCandidate>> electedCandidates,
|
public record ElectedResult(Map<String, Collection<ElectedCandidate>> electedCandidates,
|
||||||
LinkedList<Double> usedElectionNumbers) {
|
LinkedList<Double> usedElectionNumbers) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package de.twomartens.wahlrecht.model.internal;
|
||||||
|
|
||||||
|
public record ConstituencyId(String electionName, Integer number) {
|
||||||
|
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package de.twomartens.wahlrecht.model.internal;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.Builder;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
public record ElectedCandidates(ElectedResult overallResult,
|
||||||
|
Map<Integer, ElectedResult> constituencyResults,
|
||||||
|
LinkedList<Double> electionNumbersForSeatAllocation) {
|
||||||
|
|
||||||
|
}
|
||||||
+97
-20
@@ -4,8 +4,10 @@ import de.twomartens.wahlrecht.model.internal.Candidate;
|
|||||||
import de.twomartens.wahlrecht.model.internal.Constituency;
|
import de.twomartens.wahlrecht.model.internal.Constituency;
|
||||||
import de.twomartens.wahlrecht.model.internal.Elected;
|
import de.twomartens.wahlrecht.model.internal.Elected;
|
||||||
import de.twomartens.wahlrecht.model.internal.ElectedCandidate;
|
import de.twomartens.wahlrecht.model.internal.ElectedCandidate;
|
||||||
|
import de.twomartens.wahlrecht.model.internal.ElectedCandidates;
|
||||||
import de.twomartens.wahlrecht.model.internal.ElectedResult;
|
import de.twomartens.wahlrecht.model.internal.ElectedResult;
|
||||||
import de.twomartens.wahlrecht.model.internal.Election;
|
import de.twomartens.wahlrecht.model.internal.Election;
|
||||||
|
import de.twomartens.wahlrecht.model.internal.ElectionResult;
|
||||||
import de.twomartens.wahlrecht.model.internal.Nomination;
|
import de.twomartens.wahlrecht.model.internal.Nomination;
|
||||||
import de.twomartens.wahlrecht.model.internal.NominationId;
|
import de.twomartens.wahlrecht.model.internal.NominationId;
|
||||||
import de.twomartens.wahlrecht.model.internal.SeatResult;
|
import de.twomartens.wahlrecht.model.internal.SeatResult;
|
||||||
@@ -22,22 +24,69 @@ import java.util.Map.Entry;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StopWatch;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service
|
@Service
|
||||||
|
@Slf4j
|
||||||
public class CalculationService {
|
public class CalculationService {
|
||||||
|
|
||||||
private final NominationService nominationService;
|
private final NominationService nominationService;
|
||||||
|
private final ElectionService electionService;
|
||||||
private final LinkedList<Double> electionNumberHistory = new LinkedList<>();
|
private final LinkedList<Double> electionNumberHistory = new LinkedList<>();
|
||||||
|
private StopWatch stopWatch;
|
||||||
|
|
||||||
|
public ElectedCandidates determineElectedCandidates(@NonNull ElectionResult electionResult) {
|
||||||
|
log.info("Calculate election result for election {}", electionResult.electionName());
|
||||||
|
stopWatch = new StopWatch();
|
||||||
|
stopWatch.start("determineElectedCandidates");
|
||||||
|
Election election = electionService.getElectionInternal(electionResult.electionName());
|
||||||
|
SeatResult seatResult = calculateOverallSeatDistribution(election,
|
||||||
|
electionResult.overallResults());
|
||||||
|
Map<Integer, ElectedResult> constituencyResults = new HashMap<>();
|
||||||
|
|
||||||
|
for (Constituency constituency : election.constituencies()) {
|
||||||
|
ElectedResult electedResult = calculateConstituency(constituency,
|
||||||
|
electionResult.constituencyResults().get(constituency.number()));
|
||||||
|
constituencyResults.put(constituency.number(), electedResult);
|
||||||
|
}
|
||||||
|
Map<String, Collection<ElectedCandidate>> electedCandidatesMap = constituencyResults
|
||||||
|
.entrySet().stream()
|
||||||
|
.flatMap(entry -> entry.getValue().electedCandidates().entrySet().stream())
|
||||||
|
.collect(Collectors.groupingBy(entry -> entry.getKey().getNominationId().partyAbbreviation(),
|
||||||
|
Collectors.flatMapping(entry -> entry.getValue().stream(),
|
||||||
|
Collectors.toCollection(ArrayList::new))));
|
||||||
|
|
||||||
|
Map<VotingResult, Integer> remainingSeatsPerParty = seatResult.seatsPerResult()
|
||||||
|
.entrySet().stream()
|
||||||
|
.map(entry -> Map.entry(entry.getKey(),
|
||||||
|
entry.getValue() - electedCandidatesMap.getOrDefault(
|
||||||
|
entry.getKey().getNominationId().partyAbbreviation(),
|
||||||
|
Collections.emptyList()).size()))
|
||||||
|
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
|
||||||
|
|
||||||
|
ElectedResult overallElectedCandidates = calculateElectedOverallCandidates(
|
||||||
|
remainingSeatsPerParty,
|
||||||
|
electedCandidatesMap
|
||||||
|
);
|
||||||
|
|
||||||
|
stopWatch.stop();
|
||||||
|
log.debug("determineCandidates took {} seconds", stopWatch.getTotalTimeSeconds());
|
||||||
|
|
||||||
|
return ElectedCandidates.builder()
|
||||||
|
.overallResult(overallElectedCandidates)
|
||||||
|
.constituencyResults(constituencyResults)
|
||||||
|
.electionNumbersForSeatAllocation(seatResult.usedElectionNumbers())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
public ElectedResult calculateConstituency(@NonNull Constituency constituency,
|
public ElectedResult calculateConstituency(@NonNull Constituency constituency,
|
||||||
@NonNull Collection<VotingResult> votingResults) {
|
@NonNull Collection<VotingResult> votingResults) {
|
||||||
electionNumberHistory.clear();
|
electionNumberHistory.clear();
|
||||||
|
log.info("Calculate constituency {}", constituency.name());
|
||||||
int totalVotes = votingResults.stream()
|
int totalVotes = votingResults.stream()
|
||||||
.map(VotingResult::getTotalVotes)
|
.map(VotingResult::getTotalVotes)
|
||||||
.reduce(0, Integer::sum);
|
.reduce(0, Integer::sum);
|
||||||
@@ -49,12 +98,13 @@ public class CalculationService {
|
|||||||
|
|
||||||
return ElectedResult.builder()
|
return ElectedResult.builder()
|
||||||
.electedCandidates(findElectedCandidates(assignedSeatsPerResult, Collections.emptyMap()))
|
.electedCandidates(findElectedCandidates(assignedSeatsPerResult, Collections.emptyMap()))
|
||||||
.usedElectionNumbers(electionNumberHistory)
|
.usedElectionNumbers(new LinkedList<>(electionNumberHistory))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SeatResult calculateOverallSeatDistribution(@NonNull Election election,
|
public SeatResult calculateOverallSeatDistribution(@NonNull Election election,
|
||||||
@NonNull Collection<VotingResult> votingResults) {
|
@NonNull Collection<VotingResult> votingResults) {
|
||||||
|
log.info("Calculate overall seat distribution for election {}", election.name());
|
||||||
electionNumberHistory.clear();
|
electionNumberHistory.clear();
|
||||||
int totalVotes = votingResults.stream()
|
int totalVotes = votingResults.stream()
|
||||||
.map(VotingResult::getTotalVotes)
|
.map(VotingResult::getTotalVotes)
|
||||||
@@ -64,8 +114,12 @@ public class CalculationService {
|
|||||||
int totalIgnoredVotes = 0;
|
int totalIgnoredVotes = 0;
|
||||||
for (VotingResult votingResult : votingResults) {
|
for (VotingResult votingResult : votingResults) {
|
||||||
if (passesVotingThreshold(election, totalVotes, votingResult)) {
|
if (passesVotingThreshold(election, totalVotes, votingResult)) {
|
||||||
|
log.info("Party passes voting threshold: {}",
|
||||||
|
votingResult.getNominationId().partyAbbreviation());
|
||||||
validVotingResults.add(votingResult);
|
validVotingResults.add(votingResult);
|
||||||
} else {
|
} else {
|
||||||
|
log.info("Party fails voting threshold: {}",
|
||||||
|
votingResult.getNominationId().partyAbbreviation());
|
||||||
totalIgnoredVotes += votingResult.getTotalVotes();
|
totalIgnoredVotes += votingResult.getTotalVotes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,18 +133,25 @@ public class CalculationService {
|
|||||||
|
|
||||||
return SeatResult.builder()
|
return SeatResult.builder()
|
||||||
.seatsPerResult(assignedSeatsPerResult)
|
.seatsPerResult(assignedSeatsPerResult)
|
||||||
.usedElectionNumbers(electionNumberHistory)
|
.usedElectionNumbers(new LinkedList<>(electionNumberHistory))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all elected candidates for given voting results
|
||||||
|
*
|
||||||
|
* @param seatsPerNomination Seats to allocate per voting result
|
||||||
|
* @param electedCandidates Already elected candidates per party
|
||||||
|
*/
|
||||||
public ElectedResult calculateElectedOverallCandidates(
|
public ElectedResult calculateElectedOverallCandidates(
|
||||||
Map<VotingResult, Integer> seatsPerNomination,
|
Map<VotingResult, Integer> seatsPerNomination,
|
||||||
Map<VotingResult, Collection<ElectedCandidate>> electedCandidates) {
|
Map<String, Collection<ElectedCandidate>> electedCandidates) {
|
||||||
|
log.info("Calculate overall elected candidates");
|
||||||
electionNumberHistory.clear();
|
electionNumberHistory.clear();
|
||||||
|
|
||||||
return ElectedResult.builder()
|
return ElectedResult.builder()
|
||||||
.electedCandidates(findElectedCandidates(seatsPerNomination, electedCandidates))
|
.electedCandidates(findElectedCandidates(seatsPerNomination, electedCandidates))
|
||||||
.usedElectionNumbers(electionNumberHistory)
|
.usedElectionNumbers(new LinkedList<>(electionNumberHistory))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,10 +161,16 @@ public class CalculationService {
|
|||||||
<= votingResult.getTotalVotes();
|
<= votingResult.getTotalVotes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all elected candidates for given voting results.
|
||||||
|
*
|
||||||
|
* @param assignedSeatsPerNomination Map of seats to allocate for a voting result
|
||||||
|
* @param alreadyElectedCandidates Map of already elected candidates per party
|
||||||
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private Map<VotingResult, Collection<ElectedCandidate>> findElectedCandidates(
|
private Map<VotingResult, Collection<ElectedCandidate>> findElectedCandidates(
|
||||||
@NonNull Map<VotingResult, Integer> assignedSeatsPerNomination,
|
@NonNull Map<VotingResult, Integer> assignedSeatsPerNomination,
|
||||||
Map<VotingResult, Collection<ElectedCandidate>> alreadyElectedCandidates) {
|
Map<String, Collection<ElectedCandidate>> alreadyElectedCandidates) {
|
||||||
|
|
||||||
Map<VotingResult, Collection<ElectedCandidate>> electedCandidates = new HashMap<>();
|
Map<VotingResult, Collection<ElectedCandidate>> electedCandidates = new HashMap<>();
|
||||||
for (Entry<VotingResult, Integer> entry : assignedSeatsPerNomination.entrySet()) {
|
for (Entry<VotingResult, Integer> entry : assignedSeatsPerNomination.entrySet()) {
|
||||||
@@ -111,7 +178,9 @@ public class CalculationService {
|
|||||||
Collection<ElectedCandidate> candidates = findCandidates(
|
Collection<ElectedCandidate> candidates = findCandidates(
|
||||||
entry.getKey(),
|
entry.getKey(),
|
||||||
entry.getValue(),
|
entry.getValue(),
|
||||||
alreadyElectedCandidates.getOrDefault(entry.getKey(), Collections.emptyList())
|
alreadyElectedCandidates.getOrDefault(
|
||||||
|
entry.getKey().getNominationId().partyAbbreviation(),
|
||||||
|
Collections.emptyList())
|
||||||
);
|
);
|
||||||
electedCandidates.put(entry.getKey(), candidates);
|
electedCandidates.put(entry.getKey(), candidates);
|
||||||
}
|
}
|
||||||
@@ -120,9 +189,18 @@ public class CalculationService {
|
|||||||
return electedCandidates;
|
return electedCandidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds elected candidates for given voting result.
|
||||||
|
*
|
||||||
|
* @param votingResult Result to search candidates for
|
||||||
|
* @param numberOfSeats Number of seats to allocate
|
||||||
|
* @param alreadyElectedCandidates Candidates already elected previously
|
||||||
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private Collection<ElectedCandidate> findCandidates(@NonNull VotingResult votingResult,
|
private Collection<ElectedCandidate> findCandidates(@NonNull VotingResult votingResult,
|
||||||
int numberOfSeats, Collection<ElectedCandidate> alreadyElectedCandidates) {
|
int numberOfSeats, @NonNull Collection<ElectedCandidate> alreadyElectedCandidates) {
|
||||||
|
log.info("Find elected candidates on nomination: {}",
|
||||||
|
votingResult.getNominationId().name());
|
||||||
List<Integer> individualVotesOrder = votingResult.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())
|
||||||
@@ -184,6 +262,7 @@ public class CalculationService {
|
|||||||
double electionNumber = initialElectionNumber;
|
double electionNumber = initialElectionNumber;
|
||||||
long assignedSeats;
|
long assignedSeats;
|
||||||
Map<VotingResult, Integer> assignedSeatsPerVotingResult;
|
Map<VotingResult, Integer> assignedSeatsPerVotingResult;
|
||||||
|
log.debug("Calculate assigned seats with initial election number {}", electionNumber);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
electionNumberHistory.add(electionNumber);
|
electionNumberHistory.add(electionNumber);
|
||||||
@@ -202,10 +281,12 @@ public class CalculationService {
|
|||||||
// election number was too big, decrease
|
// election number was too big, decrease
|
||||||
electionNumber = calculateLowerElectionNumber(initialElectionNumber, seatsPerVotingResult,
|
electionNumber = calculateLowerElectionNumber(initialElectionNumber, seatsPerVotingResult,
|
||||||
assignedSeatsPerVotingResult);
|
assignedSeatsPerVotingResult);
|
||||||
|
log.debug("Calculated lower election number {}", electionNumber);
|
||||||
} else if (assignedSeats > numberOfSeats) {
|
} else if (assignedSeats > numberOfSeats) {
|
||||||
// election number was too small, increase
|
// election number was too small, increase
|
||||||
electionNumber = calculateHigherElectionNumber(initialElectionNumber, seatsPerVotingResult,
|
electionNumber = calculateHigherElectionNumber(initialElectionNumber, seatsPerVotingResult,
|
||||||
assignedSeatsPerVotingResult);
|
assignedSeatsPerVotingResult);
|
||||||
|
log.debug("Calculated higher election number {}", electionNumber);
|
||||||
}
|
}
|
||||||
} while (assignedSeats != numberOfSeats);
|
} while (assignedSeats != numberOfSeats);
|
||||||
|
|
||||||
@@ -216,12 +297,10 @@ public class CalculationService {
|
|||||||
@NonNull Map<VotingResult, Double> seatsPerVotingResult,
|
@NonNull Map<VotingResult, Double> seatsPerVotingResult,
|
||||||
Map<VotingResult, Integer> assignedSeatsPerVotingResult) {
|
Map<VotingResult, Integer> assignedSeatsPerVotingResult) {
|
||||||
double electionNumber;
|
double electionNumber;
|
||||||
electionNumber = seatsPerVotingResult.entrySet().stream()
|
electionNumber = seatsPerVotingResult.keySet().stream()
|
||||||
.map(entry -> Map.entry(entry.getKey(),
|
.map(votingResult -> votingResult.getTotalVotes()
|
||||||
entry.getValue() - assignedSeatsPerVotingResult.get(entry.getKey())))
|
/ (assignedSeatsPerVotingResult.get(votingResult) - 0.5))
|
||||||
.min(Comparator.comparing(Entry<VotingResult, Double>::getValue))
|
.min(Comparator.comparing(Double::doubleValue))
|
||||||
.map(entry -> entry.getKey().getTotalVotes()
|
|
||||||
/ (assignedSeatsPerVotingResult.get(entry.getKey()) - 0.5))
|
|
||||||
.orElse(initialElectionNumber);
|
.orElse(initialElectionNumber);
|
||||||
return electionNumber;
|
return electionNumber;
|
||||||
}
|
}
|
||||||
@@ -230,12 +309,10 @@ public class CalculationService {
|
|||||||
@NonNull Map<VotingResult, Double> seatsPerVotingResult,
|
@NonNull Map<VotingResult, Double> seatsPerVotingResult,
|
||||||
Map<VotingResult, Integer> assignedSeatsPerVotingResult) {
|
Map<VotingResult, Integer> assignedSeatsPerVotingResult) {
|
||||||
double electionNumber;
|
double electionNumber;
|
||||||
electionNumber = seatsPerVotingResult.entrySet().stream()
|
electionNumber = seatsPerVotingResult.keySet().stream()
|
||||||
.map(entry -> Map.entry(entry.getKey(),
|
.map(votingResult -> votingResult.getTotalVotes()
|
||||||
entry.getValue() - assignedSeatsPerVotingResult.get(entry.getKey())))
|
/ (assignedSeatsPerVotingResult.get(votingResult) + 0.5))
|
||||||
.max(Comparator.comparing(Entry<VotingResult, Double>::getValue))
|
.max(Comparator.comparing(Double::doubleValue))
|
||||||
.map(entry -> entry.getKey().getTotalVotes()
|
|
||||||
/ (assignedSeatsPerVotingResult.get(entry.getKey()) + 0.5))
|
|
||||||
.orElse(initialElectionNumber);
|
.orElse(initialElectionNumber);
|
||||||
return electionNumber;
|
return electionNumber;
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-10
@@ -1,10 +1,15 @@
|
|||||||
package de.twomartens.wahlrecht.service;
|
package de.twomartens.wahlrecht.service;
|
||||||
|
|
||||||
|
import de.twomartens.wahlrecht.mapper.v1.ConstituencyMapper;
|
||||||
import de.twomartens.wahlrecht.model.db.Constituency;
|
import de.twomartens.wahlrecht.model.db.Constituency;
|
||||||
|
import de.twomartens.wahlrecht.model.internal.ConstituencyId;
|
||||||
import de.twomartens.wahlrecht.repository.ConstituencyRepository;
|
import de.twomartens.wahlrecht.repository.ConstituencyRepository;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Optional;
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -13,21 +18,52 @@ import org.springframework.stereotype.Service;
|
|||||||
public class ConstituencyService {
|
public class ConstituencyService {
|
||||||
|
|
||||||
private final ConstituencyRepository repository;
|
private final ConstituencyRepository repository;
|
||||||
|
private final ConstituencyMapper mapper = Mappers.getMapper(ConstituencyMapper.class);
|
||||||
|
|
||||||
|
private Map<ConstituencyId, Constituency> constituencies;
|
||||||
|
|
||||||
public Collection<Constituency> getConstituencies() {
|
public Collection<Constituency> getConstituencies() {
|
||||||
return repository.findAll();
|
return repository.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Constituency storeConstituency(@NonNull Constituency constituency) {
|
public Constituency getConstituency(ConstituencyId constituencyId) {
|
||||||
Optional<Constituency> foundOptional = repository
|
return constituencies.get(constituencyId);
|
||||||
.findByElectionNameAndNumber(constituency.getElectionName(), constituency.getNumber());
|
}
|
||||||
|
|
||||||
if (foundOptional.isPresent()) {
|
public de.twomartens.wahlrecht.model.internal.Constituency getConstituencyInternal(
|
||||||
Constituency found = foundOptional.get();
|
ConstituencyId constituencyId) {
|
||||||
found.setNumberOfSeats(constituency.getNumberOfSeats());
|
return mapper.mapToInternal(getConstituency(constituencyId));
|
||||||
found.setName(constituency.getName());
|
}
|
||||||
constituency = found;
|
|
||||||
|
public Constituency storeConstituency(@NonNull Constituency constituency) {
|
||||||
|
if (constituencies == null) {
|
||||||
|
fetchConstituencies();
|
||||||
}
|
}
|
||||||
return repository.save(constituency);
|
|
||||||
|
ConstituencyId constituencyId = new ConstituencyId(constituency.getElectionName(),
|
||||||
|
constituency.getNumber());
|
||||||
|
Constituency existing = constituencies.get(constituencyId);
|
||||||
|
|
||||||
|
if (constituency.equals(existing)) {
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing != null) {
|
||||||
|
existing.setNumberOfSeats(constituency.getNumberOfSeats());
|
||||||
|
existing.setName(constituency.getName());
|
||||||
|
constituency = existing;
|
||||||
|
}
|
||||||
|
Constituency stored = repository.save(constituency);
|
||||||
|
constituencies.put(constituencyId, stored);
|
||||||
|
|
||||||
|
return stored;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchConstituencies() {
|
||||||
|
constituencies = repository.findAll().stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
constituency -> new ConstituencyId(constituency.getElectionName(),
|
||||||
|
constituency.getNumber()),
|
||||||
|
Function.identity()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
package de.twomartens.wahlrecht.service;
|
package de.twomartens.wahlrecht.service;
|
||||||
|
|
||||||
|
import de.twomartens.wahlrecht.mapper.v1.ElectionMapper;
|
||||||
import de.twomartens.wahlrecht.model.db.Constituency;
|
import de.twomartens.wahlrecht.model.db.Constituency;
|
||||||
import de.twomartens.wahlrecht.model.db.Election;
|
import de.twomartens.wahlrecht.model.db.Election;
|
||||||
import de.twomartens.wahlrecht.repository.ElectionRepository;
|
import de.twomartens.wahlrecht.repository.ElectionRepository;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Optional;
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -16,22 +20,43 @@ public class ElectionService {
|
|||||||
|
|
||||||
private final ElectionRepository electionRepository;
|
private final ElectionRepository electionRepository;
|
||||||
private final ConstituencyService constituencyService;
|
private final ConstituencyService constituencyService;
|
||||||
|
private final ElectionMapper electionMapper = Mappers.getMapper(ElectionMapper.class);
|
||||||
|
|
||||||
|
private Map<String, Election> elections;
|
||||||
|
|
||||||
public Collection<Election> getElections() {
|
public Collection<Election> getElections() {
|
||||||
return electionRepository.findAll();
|
return electionRepository.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Election getElection(String electionName) {
|
||||||
|
if (elections == null) {
|
||||||
|
fetchElections();
|
||||||
|
}
|
||||||
|
return elections.get(electionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public de.twomartens.wahlrecht.model.internal.Election getElectionInternal(String electionName) {
|
||||||
|
return electionMapper.mapToInternal(getElection(electionName));
|
||||||
|
}
|
||||||
|
|
||||||
public boolean storeElection(@NonNull Election election) {
|
public boolean storeElection(@NonNull Election election) {
|
||||||
|
if (elections == null) {
|
||||||
|
fetchElections();
|
||||||
|
}
|
||||||
boolean createdNew = true;
|
boolean createdNew = true;
|
||||||
String electionName = election.getName();
|
String electionName = election.getName();
|
||||||
Optional<Election> existingElectionOptional = electionRepository.findByName(electionName);
|
Election existing = elections.get(electionName);
|
||||||
|
|
||||||
|
if (election.equals(existing)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Collection<Constituency> constituencies = new ArrayList<>();
|
Collection<Constituency> constituencies = new ArrayList<>();
|
||||||
election.getConstituencies()
|
election.getConstituencies()
|
||||||
.forEach(constituency -> constituencies.add(
|
.forEach(constituency -> constituencies.add(
|
||||||
constituencyService.storeConstituency(constituency)));
|
constituencyService.storeConstituency(constituency)));
|
||||||
|
|
||||||
if (existingElectionOptional.isPresent()) {
|
if (existing != null) {
|
||||||
Election existing = existingElectionOptional.get();
|
|
||||||
existing.setDay(election.getDay());
|
existing.setDay(election.getDay());
|
||||||
existing.setTotalNumberOfSeats(election.getTotalNumberOfSeats());
|
existing.setTotalNumberOfSeats(election.getTotalNumberOfSeats());
|
||||||
existing.setVotingThreshold(election.getVotingThreshold());
|
existing.setVotingThreshold(election.getVotingThreshold());
|
||||||
@@ -40,8 +65,14 @@ public class ElectionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
election.setConstituencies(constituencies);
|
election.setConstituencies(constituencies);
|
||||||
electionRepository.save(election);
|
Election stored = electionRepository.save(election);
|
||||||
|
elections.put(electionName, stored);
|
||||||
|
|
||||||
return createdNew;
|
return createdNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fetchElections() {
|
||||||
|
elections = electionRepository.findAll().stream()
|
||||||
|
.collect(Collectors.toMap(Election::getName, Function.identity()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ 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 java.util.Optional;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -35,13 +34,16 @@ public class PartyService {
|
|||||||
|
|
||||||
public PartyInElection getPartyByElectionNameAndAbbreviation(String electionName,
|
public PartyInElection getPartyByElectionNameAndAbbreviation(String electionName,
|
||||||
String abbreviation) {
|
String abbreviation) {
|
||||||
Optional<PartyInElection> optionalParty = partyRepository.findByAbbreviationAndElectionName(
|
if (parties == null) {
|
||||||
abbreviation, electionName);
|
fetchParties();
|
||||||
if (optionalParty.isEmpty()) {
|
}
|
||||||
|
PartyId partyId = new PartyId(electionName, abbreviation);
|
||||||
|
PartyInElection party = parties.get(partyId);
|
||||||
|
if (party == null) {
|
||||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND,
|
throw new ResponseStatusException(HttpStatus.NOT_FOUND,
|
||||||
"no party found for %s and %s".formatted(electionName, abbreviation));
|
"no party found for %s and %s".formatted(electionName, abbreviation));
|
||||||
}
|
}
|
||||||
return optionalParty.get();
|
return party;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean storeParty(PartyInElection partyInElection) {
|
public boolean storeParty(PartyInElection partyInElection) {
|
||||||
|
|||||||
+7
-4
@@ -116,6 +116,9 @@ class CalculationServiceTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private NominationService nominationService;
|
private NominationService nominationService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ElectionService electionService;
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
static void setUp() {
|
static void setUp() {
|
||||||
setUpCandidatesConstituency();
|
setUpCandidatesConstituency();
|
||||||
@@ -250,7 +253,7 @@ class CalculationServiceTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setService() {
|
void setService() {
|
||||||
service = new CalculationService(nominationService);
|
service = new CalculationService(nominationService, electionService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -316,7 +319,7 @@ class CalculationServiceTest {
|
|||||||
FDP_BEZIRK_RESULT, 3,
|
FDP_BEZIRK_RESULT, 3,
|
||||||
AFD_BEZIRK_RESULT, 3
|
AFD_BEZIRK_RESULT, 3
|
||||||
);
|
);
|
||||||
Map<VotingResult, Collection<ElectedCandidate>> electedCandidates = setUpConstituencyResults();
|
Map<String, Collection<ElectedCandidate>> electedCandidates = setUpConstituencyResults();
|
||||||
when(nominationService.getNominationInternal(SPD_BEZIRK.getId())).thenReturn(SPD_BEZIRK);
|
when(nominationService.getNominationInternal(SPD_BEZIRK.getId())).thenReturn(SPD_BEZIRK);
|
||||||
when(nominationService.getNominationInternal(CDU_BEZIRK.getId())).thenReturn(CDU_BEZIRK);
|
when(nominationService.getNominationInternal(CDU_BEZIRK.getId())).thenReturn(CDU_BEZIRK);
|
||||||
when(nominationService.getNominationInternal(FDP_BEZIRK.getId())).thenReturn(FDP_BEZIRK);
|
when(nominationService.getNominationInternal(FDP_BEZIRK.getId())).thenReturn(FDP_BEZIRK);
|
||||||
@@ -397,8 +400,8 @@ class CalculationServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Map<VotingResult, Collection<ElectedCandidate>> setUpConstituencyResults() {
|
private Map<String, Collection<ElectedCandidate>> setUpConstituencyResults() {
|
||||||
return Map.of(GRUENE_BEZIRK_RESULT, List.of(
|
return Map.of(GRUENE_BEZIRK_RESULT.getNominationId().partyAbbreviation(), 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),
|
||||||
|
|||||||
Reference in New Issue
Block a user