diff --git a/java/src/main/java/org/elections/Candidate.java b/java/src/main/java/org/elections/Candidate.java new file mode 100644 index 0000000..a3b4009 --- /dev/null +++ b/java/src/main/java/org/elections/Candidate.java @@ -0,0 +1,35 @@ +package org.elections; + +public class Candidate { + private final String name; + private final boolean isOfficial; + + public Candidate(String name, boolean isOfficial) { + this.name = name; + this.isOfficial = isOfficial; + } + + public static Candidate official(String name) { + return new Candidate(name, true); + } + + public static Candidate unofficial(String name) { + return new Candidate(name, false); + } + + public String name() { + return this.name; + } + + public boolean isOfficial() { + return this.isOfficial; + } + + public boolean hasName(String candidateName) { + return this.name.equals(candidateName); + } + + public boolean isBlank() { + return this.name.trim().isEmpty(); + } +} diff --git a/java/src/main/java/org/elections/Candidates.java b/java/src/main/java/org/elections/Candidates.java new file mode 100644 index 0000000..9100604 --- /dev/null +++ b/java/src/main/java/org/elections/Candidates.java @@ -0,0 +1,47 @@ +package org.elections; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public class Candidates { + private final List candidates = new ArrayList<>(); + + public void addOfficial(String name) { + candidates.add(Candidate.official(name)); + } + + public void addUnofficial(String name) { + candidates.add(Candidate.unofficial(name)); + } + + public List officialCandidates() { + return candidates.stream() + .filter(Candidate::isOfficial) + .map(Candidate::name) + .collect(Collectors.toUnmodifiableList()); + } + + public long officialCandidatesCount() { + return candidates.stream().filter(Candidate::isOfficial).count(); + } + + public boolean isUnregistered(String candidate) { + return candidates.stream().noneMatch(sameNameAs(candidate)); + } + + private Predicate sameNameAs(String candidate) { + return c -> candidate.equals(c.name()); + } + + public String get(int index) { + return candidates.get(index).name(); + } + + public Candidate findByName(String candidateName) { + return candidates.stream() + .filter(candidate -> candidate.hasName(candidateName)) + .findFirst().orElse(null); + } +} diff --git a/java/src/main/java/org/elections/Elections.java b/java/src/main/java/org/elections/Elections.java index 3d6242f..e85f052 100644 --- a/java/src/main/java/org/elections/Elections.java +++ b/java/src/main/java/org/elections/Elections.java @@ -1,149 +1,48 @@ package org.elections; -import java.text.DecimalFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; public class Elections { - List candidates = new ArrayList<>(); - List officialCandidates = new ArrayList<>(); - ArrayList votesWithoutDistricts = new ArrayList<>(); - Map> votesWithDistricts; - private Map> list; - private boolean withDistrict; + private final Electors electors; + private final Candidates candidates; + private final Votes votes; + private final VotingResultStrategy voting; public Elections(Map> list, boolean withDistrict) { - this.list = list; - this.withDistrict = withDistrict; - - votesWithDistricts = new HashMap<>(); - votesWithDistricts.put("District 1", new ArrayList<>()); - votesWithDistricts.put("District 2", new ArrayList<>()); - votesWithDistricts.put("District 3", new ArrayList<>()); + electors = Electors.fromMapByDistrict(list); + candidates = new Candidates(); + votes = new Votes(); + + List districts = new ArrayList<>(); + districts.add("District 1"); + districts.add("District 2"); + districts.add("District 3"); + + voting = withDistrict + ? new WithDistrictVotingResult(candidates, electors, districts) + :new NoDistrictVotingResult(candidates, electors); } - public void addCandidate(String candidate) { - officialCandidates.add(candidate); - candidates.add(candidate); - votesWithoutDistricts.add(0); - votesWithDistricts.get("District 1").add(0); - votesWithDistricts.get("District 2").add(0); - votesWithDistricts.get("District 3").add(0); + public void addOfficialCandidate(String candidate) { + candidates.addOfficial(candidate); } - public void voteFor(String elector, String candidate, String electorDistrict) { - if (!withDistrict) { - if (candidates.contains(candidate)) { - int index = candidates.indexOf(candidate); - votesWithoutDistricts.set(index, votesWithoutDistricts.get(index) + 1); - } else { - candidates.add(candidate); - votesWithoutDistricts.add(1); - } - } else { - if (votesWithDistricts.containsKey(electorDistrict)) { - ArrayList districtVotes = votesWithDistricts.get(electorDistrict); - if (candidates.contains(candidate)) { - int index = candidates.indexOf(candidate); - districtVotes.set(index, districtVotes.get(index) + 1); - } else { - candidates.add(candidate); - votesWithDistricts.forEach((district, votes) -> { - votes.add(0); - }); - districtVotes.set(candidates.size() - 1, districtVotes.get(candidates.size() - 1) + 1); - } - } + public void voteFor(String electorName, String candidateName, String electorDistrict) { + if (candidates.isUnregistered(candidateName)) { + candidates.addUnofficial(candidateName); } + + votes.registerVote(electorDistrict, + electors.findByName(electorName), + candidates.findByName(candidateName)); } public Map results() { - Map results = new HashMap<>(); - Integer nbVotes = 0; - Integer nullVotes = 0; - Integer blankVotes = 0; - int nbValidVotes = 0; - - if (!withDistrict) { - nbVotes = votesWithoutDistricts.stream().reduce(0, Integer::sum); - for (int i = 0; i < officialCandidates.size(); i++) { - int index = candidates.indexOf(officialCandidates.get(i)); - nbValidVotes += votesWithoutDistricts.get(index); - } - - for (int i = 0; i < votesWithoutDistricts.size(); i++) { - Float candidatResult = ((float)votesWithoutDistricts.get(i) * 100) / nbValidVotes; - String candidate = candidates.get(i); - if (officialCandidates.contains(candidate)) { - results.put(candidate, String.format(Locale.FRENCH, "%.2f%%", candidatResult)); - } else { - if (candidates.get(i).isEmpty()) { - blankVotes += votesWithoutDistricts.get(i); - } else { - nullVotes += votesWithoutDistricts.get(i); - } - } - } - } else { - for (Map.Entry> entry : votesWithDistricts.entrySet()) { - ArrayList districtVotes = entry.getValue(); - nbVotes += districtVotes.stream().reduce(0, Integer::sum); - } - - for (int i = 0; i < officialCandidates.size(); i++) { - int index = candidates.indexOf(officialCandidates.get(i)); - for (Map.Entry> entry : votesWithDistricts.entrySet()) { - ArrayList districtVotes = entry.getValue(); - nbValidVotes += districtVotes.get(index); - } - } - - Map officialCandidatesResult = new HashMap<>(); - for (int i = 0; i < officialCandidates.size(); i++) { - officialCandidatesResult.put(candidates.get(i), 0); - } - for (Map.Entry> entry : votesWithDistricts.entrySet()) { - ArrayList districtResult = new ArrayList<>(); - ArrayList districtVotes = entry.getValue(); - for (int i = 0; i < districtVotes.size(); i++) { - float candidateResult = 0; - if (nbValidVotes != 0) - candidateResult = ((float)districtVotes.get(i) * 100) / nbValidVotes; - String candidate = candidates.get(i); - if (officialCandidates.contains(candidate)) { - districtResult.add(candidateResult); - } else { - if (candidates.get(i).isEmpty()) { - blankVotes += districtVotes.get(i); - } else { - nullVotes += districtVotes.get(i); - } - } - } - int districtWinnerIndex = 0; - for (int i = 1; i < districtResult.size(); i++) { - if (districtResult.get(districtWinnerIndex) < districtResult.get(i)) - districtWinnerIndex = i; - } - officialCandidatesResult.put(candidates.get(districtWinnerIndex), officialCandidatesResult.get(candidates.get(districtWinnerIndex)) + 1); - } - for (int i = 0; i < officialCandidatesResult.size(); i++) { - Float ratioCandidate = ((float) officialCandidatesResult.get(candidates.get(i))) / officialCandidatesResult.size() * 100; - results.put(candidates.get(i), String.format(Locale.FRENCH, "%.2f%%", ratioCandidate)); - } - } - - float blankResult = ((float)blankVotes * 100) / nbVotes; - results.put("Blank", String.format(Locale.FRENCH, "%.2f%%", blankResult)); - - float nullResult = ((float)nullVotes * 100) / nbVotes; - results.put("Null", String.format(Locale.FRENCH, "%.2f%%", nullResult)); - - int nbElectors = list.values().stream().map(List::size).reduce(0, Integer::sum); - DecimalFormat df = new DecimalFormat(); - df.setMaximumFractionDigits(2); - float abstentionResult = 100 - ((float) nbVotes * 100 / nbElectors); - results.put("Abstention", String.format(Locale.FRENCH, "%.2f%%", abstentionResult)); - - return results; + FormattedResult formattedResult = new FormattedResult(Locale.FRENCH, "%.2f%%"); + voting.count(votes).printOn(formattedResult); + return formattedResult.result(); } } diff --git a/java/src/main/java/org/elections/Elector.java b/java/src/main/java/org/elections/Elector.java new file mode 100644 index 0000000..962e54c --- /dev/null +++ b/java/src/main/java/org/elections/Elector.java @@ -0,0 +1,20 @@ +package org.elections; + +public class Elector { + private String district; + private String name; + + public static Elector withDistrict_Name_(String district, String name) { + return new Elector().setDistrict_Name_(district, name); + } + + private Elector setDistrict_Name_(String district, String name) { + this.district = district; + this.name = name; + return this; + } + + public boolean hasName(String electorName) { + return this.name.equals(electorName); + } +} diff --git a/java/src/main/java/org/elections/Electors.java b/java/src/main/java/org/elections/Electors.java new file mode 100644 index 0000000..d283ee8 --- /dev/null +++ b/java/src/main/java/org/elections/Electors.java @@ -0,0 +1,39 @@ +package org.elections; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class Electors { + private final List electors; + + private Electors() { + electors = new ArrayList<>(); + } + + public static Electors fromMapByDistrict(Map> electorsByDistrict) { + Electors instance = new Electors(); + for (Map.Entry> district : electorsByDistrict.entrySet()) { + instance.addAll(district.getValue().stream() + .map(el -> Elector.withDistrict_Name_(district.getKey(), el)) + .collect(Collectors.toList())); + } + return instance; + } + + private void addAll(List electorList) { + electors.addAll(electorList); + } + + public int size() { + return electors.size(); + } + + public Elector findByName(String electorName) { + return electors.stream() + .filter(elector -> elector.hasName(electorName)) + .findAny() + .orElse(null); + } +} diff --git a/java/src/main/java/org/elections/FormattedResult.java b/java/src/main/java/org/elections/FormattedResult.java new file mode 100644 index 0000000..10feace --- /dev/null +++ b/java/src/main/java/org/elections/FormattedResult.java @@ -0,0 +1,41 @@ +package org.elections; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +public class FormattedResult { + private final Locale locale; + private final String percentFormat; + private final Map result; + + public FormattedResult(Locale locale, String percentFormat) { + this.locale = locale; + this.percentFormat = percentFormat; + result = new HashMap<>(); + } + + public void addCandidateResult(String candidate, Fraction candidateResult) { + putFormattedValue(candidate, candidateResult); + } + + private void putFormattedValue(String key, Fraction value) { + result.put(key, String.format(locale, percentFormat, value.asPercent())); + } + + public void addBlankVotes(Fraction blanks) { + putFormattedValue("Blank", blanks); + } + + public void addNullVotes(Fraction nulls) { + putFormattedValue("Null", nulls); + } + + public void addAbstention(Fraction abstentionResult) { + putFormattedValue("Abstention", abstentionResult); + } + + public Map result() { + return new HashMap<>(this.result); + } +} diff --git a/java/src/main/java/org/elections/Fraction.java b/java/src/main/java/org/elections/Fraction.java new file mode 100644 index 0000000..31dee8e --- /dev/null +++ b/java/src/main/java/org/elections/Fraction.java @@ -0,0 +1,22 @@ +package org.elections; + +public class Fraction { + private final long numerator; + private final long denominator; + + public static Fraction withNumeratorDenominator(long numerator, long denominator) { + return new Fraction(numerator, denominator); + } + + private Fraction(long numerator, long denominator) { + this.numerator = numerator; + this.denominator = denominator; + } + + public float asPercent() { + if (this.denominator==0) { + return 0; + } + return (float) this.numerator * 100 / this.denominator; + } +} diff --git a/java/src/main/java/org/elections/NoDistrictVotingResult.java b/java/src/main/java/org/elections/NoDistrictVotingResult.java new file mode 100644 index 0000000..430a111 --- /dev/null +++ b/java/src/main/java/org/elections/NoDistrictVotingResult.java @@ -0,0 +1,18 @@ +package org.elections; + +import java.util.Map; +import java.util.stream.Collectors; + +public class NoDistrictVotingResult extends VotingResultStrategy { + public NoDistrictVotingResult(Candidates candidates, Electors electors) { + super(candidates, electors); + } + + @Override + protected Map calculateResult() { + long validVotes = votes.countValid(); + return votes.resultForNoDistrict().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> Fraction.withNumeratorDenominator(e.getValue(), validVotes))); + } + +} diff --git a/java/src/main/java/org/elections/Vote.java b/java/src/main/java/org/elections/Vote.java new file mode 100644 index 0000000..fc83e6d --- /dev/null +++ b/java/src/main/java/org/elections/Vote.java @@ -0,0 +1,37 @@ +package org.elections; + +public class Vote { + private final Elector elector; + private final Candidate candidate; + private final String district; + + public Vote(Elector elector, Candidate candidate, String district) { + this.elector = elector; + this.candidate = candidate; + this.district = district; + } + + public boolean isBlank() { + return this.candidate.isBlank(); + } + + public boolean hasCandidate() { + return !this.isBlank(); + } + + public boolean isForUnofficialCandidate() { + return !this.candidate.isOfficial(); + } + + public boolean isForOfficialCandidate() { + return this.candidate.isOfficial(); + } + + public boolean isForDistrict(String district) { + return this.district.equals(district); + } + + public String candidateName() { + return this.candidate.name(); + } +} diff --git a/java/src/main/java/org/elections/Votes.java b/java/src/main/java/org/elections/Votes.java new file mode 100644 index 0000000..1ed3131 --- /dev/null +++ b/java/src/main/java/org/elections/Votes.java @@ -0,0 +1,62 @@ +package org.elections; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.counting; +import static java.util.stream.Collectors.groupingBy; + +public class Votes { + private final List votes; + + public Votes() { + votes = new ArrayList<>(); + } + + public void registerVote(String district, Elector elector, Candidate candidate) { + votes.add(new Vote(elector, candidate, district)); + } + + public long countBlanks() { + return errorVotesStream().filter(Vote::isBlank).count(); + } + + public long countNulls() { + return errorVotesStream().filter(Vote::hasCandidate).count(); + } + + private Stream errorVotesStream() { + return votes.stream().filter(Vote::isForUnofficialCandidate); + } + + public long countValid() { + return votes.size() - errorVotesStream().count(); + } + + public long countAllVotes() { + return votes.size(); + } + + public Map resultForNoDistrict() { + return votesForOfficialCandidates().collect(groupingBy(Vote::candidateName, counting())); + } + + private Stream votesForOfficialCandidates() { + return votes.stream().filter(Vote::isForOfficialCandidate); + } + + public String districtWinner(String districtName) { + return resultForDistrict(districtName).entrySet().stream() + .max(Map.Entry.comparingByValue()) + .map(Map.Entry::getKey) + .orElse(null); + } + + private Map resultForDistrict(String districtName) { + return votesForOfficialCandidates() + .filter(vote -> vote.isForDistrict(districtName)) + .collect(groupingBy(Vote::candidateName, counting())); + } +} diff --git a/java/src/main/java/org/elections/VotingResultStrategy.java b/java/src/main/java/org/elections/VotingResultStrategy.java new file mode 100644 index 0000000..353d6db --- /dev/null +++ b/java/src/main/java/org/elections/VotingResultStrategy.java @@ -0,0 +1,36 @@ +package org.elections; + +import java.util.Map; + +public abstract class VotingResultStrategy { + protected final Candidates candidates; + protected final Electors electors; + protected Map result; + protected Votes votes; + + public VotingResultStrategy(Candidates candidates, Electors electors) { + this.candidates = candidates; + this.electors = electors; + } + + public void printOn(FormattedResult formattedResult) { + Fraction zero = Fraction.withNumeratorDenominator(0L, 1L); + long nbVotes = votes.countAllVotes(); + + for (String candidate : candidates.officialCandidates()) { + formattedResult.addCandidateResult(candidate, result.getOrDefault(candidate, zero)); + } + + formattedResult.addBlankVotes(Fraction.withNumeratorDenominator(votes.countBlanks(), nbVotes)); + formattedResult.addNullVotes(Fraction.withNumeratorDenominator(votes.countNulls(), nbVotes)); + formattedResult.addAbstention(Fraction.withNumeratorDenominator(electors.size() - nbVotes, electors.size())); + } + + public VotingResultStrategy count(Votes votes) { + this.votes = votes; + this.result = calculateResult(); + return this; + } + + protected abstract Map calculateResult(); +} diff --git a/java/src/main/java/org/elections/WithDistrictVotingResult.java b/java/src/main/java/org/elections/WithDistrictVotingResult.java new file mode 100644 index 0000000..42b9973 --- /dev/null +++ b/java/src/main/java/org/elections/WithDistrictVotingResult.java @@ -0,0 +1,29 @@ +package org.elections; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class WithDistrictVotingResult extends VotingResultStrategy { + private final List districts; + + public WithDistrictVotingResult(Candidates candidates, Electors electors, List districts) { + super(candidates, electors); + this.districts = districts; + } + + @Override + protected Map calculateResult() { + Map officialCandidatesResult = new HashMap<>(); + for (int i = 0; i < candidates.officialCandidatesCount(); i++) { + officialCandidatesResult.put(candidates.get(i), 0L); + } + for (String district : districts) { + String districtWinner = votes.districtWinner(district); + officialCandidatesResult.put(districtWinner, officialCandidatesResult.get(districtWinner) + 1); + } + return officialCandidatesResult.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> Fraction.withNumeratorDenominator(e.getValue(), districts.size()))); + } +} diff --git a/java/src/test/java/org/elections/ElectionsTest.java b/java/src/test/java/org/elections/ElectionsTest.java index 5c48f71..a650469 100644 --- a/java/src/test/java/org/elections/ElectionsTest.java +++ b/java/src/test/java/org/elections/ElectionsTest.java @@ -1,58 +1,144 @@ package org.elections; +import java.util.stream.IntStream; import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import java.util.Arrays; import java.util.List; import java.util.Map; +@DisplayName("Тесты механизма голосования") class ElectionsTest { + private final Map> electorsByDistrict = Map.of( + "District 1", Arrays.asList("Bob", "Anna", "Jess", "July"), + "District 2", Arrays.asList("Jerry", "Simon"), + "District 3", Arrays.asList("Johnny", "Matt", "Carole") + ); - @Test - void electionWithoutDistricts() { - Map> list = Map.of( - "District 1", Arrays.asList("Bob", "Anna", "Jess", "July"), - "District 2", Arrays.asList("Jerry", "Simon"), - "District 3", Arrays.asList("Johnny", "Matt", "Carole") - ); - Elections elections = new Elections(list, false); - elections.addCandidate("Michel"); - elections.addCandidate("Jerry"); - elections.addCandidate("Johnny"); + @Nested + @DisplayName("Голосование без учета округов") + class NoDistrictsTest { - elections.voteFor("Bob", "Jerry", "District 1"); - elections.voteFor("Jerry", "Jerry", "District 2"); - elections.voteFor("Anna", "Johnny", "District 1"); - elections.voteFor("Johnny", "Johnny", "District 3"); - elections.voteFor("Matt", "Donald", "District 3"); - elections.voteFor("Jess", "Joe", "District 1"); - elections.voteFor("Simon", "", "District 2"); - elections.voteFor("Carole", "", "District 3"); + @Nested + @DisplayName("Список зарегистрированных кандидатов пуст") + class NoCandidatesTest { + @Test + @DisplayName("Голоса за любого кандидата дают 100% испорченных бюллетеней") + void votesForAnyCandidate_shouldShow100PercentNulls() { + Elections elections = new Elections(electorsByDistrict, false); + elections.voteFor("Bob", "Jerry", "District 1"); + elections.voteFor("Anna", "Jerry", "District 1"); - Map results = elections.results(); + Map results = elections.results(); + + Map expectedResults = Map.of( + "Blank", "0,00%", + "Null", "100,00%", + "Abstention", "77,78%"); + Assertions.assertThat(results).isEqualTo(expectedResults); + } + + @Test + @DisplayName("Голос от неизвестного избирателя учитывается и уменьшает неявку") + void oneVoteFromUnknownElector_shouldDecreaseAbstention() { + Elections elections = new Elections(electorsByDistrict, false); + elections.voteFor("Eugene", "Jerry", "District 1"); + + Map results = elections.results(); + + Map expectedResults = Map.of( + "Blank", "0,00%", + "Null", "100,00%", + "Abstention", "88,89%"); + Assertions.assertThat(results).isEqualTo(expectedResults); + } + + @Test + @DisplayName("Повторное голосование доступно и уменьшает неявку") + void multipleVotesFromSameElector_shouldDecreaseAbstention() { + Elections elections = new Elections(electorsByDistrict, false); + IntStream.range(1,10) + .forEach(i -> elections.voteFor("Eugene", "Jerry", "District 1")); + + Map results = elections.results(); + + Map expectedResults = Map.of( + "Blank", "0,00%", + "Null", "100,00%", + "Abstention", "0,00%"); + Assertions.assertThat(results).isEqualTo(expectedResults); + } + + @Test + @DisplayName("Если голосов больше, чем избирателей, неявка отрицательна") + void tooManyVotes_shouldMakeAbstentionNegative() { + Elections elections = new Elections(electorsByDistrict, false); + IntStream.range(1,11) + .forEach(i -> elections.voteFor("Eugene", "Jerry", "District 1")); + + Map results = elections.results(); + + Map expectedResults = Map.of( + "Blank", "0,00%", + "Null", "100,00%", + "Abstention", "-11,11%"); + Assertions.assertThat(results).isEqualTo(expectedResults); + + } + + } + + @Test + @DisplayName("Approval-Test для подсчета голосов") + void electionWithoutDistricts() { + Elections elections = new Elections(electorsByDistrict, false); + elections.addOfficialCandidate("Michel"); + elections.addOfficialCandidate("Jerry"); + elections.addOfficialCandidate("Johnny"); + + elections.voteFor("Bob", "Jerry", "District 1"); + elections.voteFor("Jerry", "Jerry", "District 2"); + elections.voteFor("Anna", "Johnny", "District 1"); + elections.voteFor("Johnny", "Johnny", "District 3"); + elections.voteFor("Matt", "Donald", "District 3"); + elections.voteFor("Jess", "Joe", "District 1"); + elections.voteFor("Simon", "", "District 2"); + elections.voteFor("Carole", "", "District 3"); + + Map results = elections.results(); + + Map expectedResults = Map.of( + "Jerry", "50,00%", + "Johnny", "50,00%", + "Michel", "0,00%", + "Blank", "25,00%", + "Null", "25,00%", + "Abstention", "11,11%"); + Assertions.assertThat(results).isEqualTo(expectedResults); + } - Map expectedResults = Map.of( - "Jerry", "50,00%", - "Johnny", "50,00%", - "Michel", "0,00%", - "Blank", "25,00%", - "Null", "25,00%", - "Abstention", "11,11%"); - Assertions.assertThat(results).isEqualTo(expectedResults); } + + + @Test + void givenNoCandidatesWithDistricts_oneVoteForAnyCandidate_shouldThrow() { + Elections elections = new Elections(electorsByDistrict, true); + elections.voteFor("Bob", "Jerry", "District 1"); + + Assertions.assertThatNullPointerException().isThrownBy(elections::results); + } + + @Test void electionWithDistricts() { - Map> list = Map.of( - "District 1", Arrays.asList("Bob", "Anna", "Jess", "July"), - "District 2", Arrays.asList("Jerry", "Simon"), - "District 3", Arrays.asList("Johnny", "Matt", "Carole") - ); - Elections elections = new Elections(list, true); - elections.addCandidate("Michel"); - elections.addCandidate("Jerry"); - elections.addCandidate("Johnny"); + Elections elections = new Elections(electorsByDistrict, true); + elections.addOfficialCandidate("Michel"); + elections.addOfficialCandidate("Jerry"); + elections.addOfficialCandidate("Johnny"); elections.voteFor("Bob", "Jerry", "District 1"); elections.voteFor("Jerry", "Jerry", "District 2");