diff --git a/src/main/java/org/rulez/demokracia/pdengine/CanCalculateWinners.java b/src/main/java/org/rulez/demokracia/pdengine/CanCalculateWinners.java new file mode 100644 index 00000000..0014e4e2 --- /dev/null +++ b/src/main/java/org/rulez/demokracia/pdengine/CanCalculateWinners.java @@ -0,0 +1,8 @@ +package org.rulez.demokracia.pdengine; + +import java.util.List; + +public interface CanCalculateWinners { + + List calculateWinners(List ignoredChoices); +} diff --git a/src/main/java/org/rulez/demokracia/pdengine/ComputedVote.java b/src/main/java/org/rulez/demokracia/pdengine/ComputedVote.java index fcf05c26..1c52af4c 100644 --- a/src/main/java/org/rulez/demokracia/pdengine/ComputedVote.java +++ b/src/main/java/org/rulez/demokracia/pdengine/ComputedVote.java @@ -2,18 +2,27 @@ import java.io.Serializable; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; -public class ComputedVote implements ComputedVoteInterface, Serializable { +import org.rulez.demokracia.pdengine.dataobjects.Pair; + +import jersey.repackaged.com.google.common.collect.Sets; +import jersey.repackaged.com.google.common.collect.Sets.SetView; + +public class ComputedVote implements CanCalculateWinners, ComputedVoteInterface, Serializable { private static final long serialVersionUID = 1L; private BeatTable beatTable; private final Vote vote; private BeatTable beatPathTable; + private transient WinnerCalculator winnerCalculator; + public ComputedVote(final Vote vote) { this.vote = vote; + winnerCalculator = new WinnerCalculatorImpl(); } @Override @@ -31,6 +40,12 @@ public void computeVote() { beatPathTable.computeTransitiveClosure(); } + @Override + public List calculateWinners(final List ignoredChoices) { + BeatTable filteredBeatTable = ignoreChoices(ignoredChoices); + return winnerCalculator.calculateWinners(filteredBeatTable); + } + public BeatTable getBeatTable() { return beatTable; } @@ -38,4 +53,22 @@ public BeatTable getBeatTable() { public BeatTable getBeatPathTable() { return beatPathTable; } + + public void setWinnerCalculator(final WinnerCalculatorImpl winnerCalculator) { + this.winnerCalculator = winnerCalculator; + } + + private BeatTable ignoreChoices(final List ignoredChoices) { + SetView activeChoices = Sets.difference(Sets.newHashSet(beatPathTable.getKeyCollection()), + Sets.newHashSet(ignoredChoices)); + BeatTable filteredBeatTable = new BeatTable(activeChoices); + for (String key1 : activeChoices) { + for (String key2 : activeChoices) { + Pair source = beatTable.getElement(key1, key2); + if (Objects.nonNull(source)) + filteredBeatTable.setElement(key1, key2, source); + } + } + return filteredBeatTable; + } } diff --git a/src/main/java/org/rulez/demokracia/pdengine/WinnerCalculator.java b/src/main/java/org/rulez/demokracia/pdengine/WinnerCalculator.java new file mode 100644 index 00000000..785acc16 --- /dev/null +++ b/src/main/java/org/rulez/demokracia/pdengine/WinnerCalculator.java @@ -0,0 +1,8 @@ +package org.rulez.demokracia.pdengine; + +import java.util.List; + +public interface WinnerCalculator { + + List calculateWinners(final BeatTable beatTable); +} diff --git a/src/main/java/org/rulez/demokracia/pdengine/WinnerCalculatorImpl.java b/src/main/java/org/rulez/demokracia/pdengine/WinnerCalculatorImpl.java new file mode 100644 index 00000000..dcccd18d --- /dev/null +++ b/src/main/java/org/rulez/demokracia/pdengine/WinnerCalculatorImpl.java @@ -0,0 +1,12 @@ +package org.rulez.demokracia.pdengine; + +import java.util.List; + +public class WinnerCalculatorImpl implements WinnerCalculator { + + @Override + public List calculateWinners(final BeatTable beatTable) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/test/java/org/rulez/demokracia/pdengine/CalculateWinnersTest.java b/src/test/java/org/rulez/demokracia/pdengine/CalculateWinnersTest.java new file mode 100644 index 00000000..e2587369 --- /dev/null +++ b/src/test/java/org/rulez/demokracia/pdengine/CalculateWinnersTest.java @@ -0,0 +1,66 @@ +package org.rulez.demokracia.pdengine; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.stubbing.Answer; +import org.rulez.demokracia.pdengine.annotations.TestedBehaviour; +import org.rulez.demokracia.pdengine.annotations.TestedFeature; +import org.rulez.demokracia.pdengine.annotations.TestedOperation; +import org.rulez.demokracia.pdengine.testhelpers.CreatedDefaultCastVoteWithRankedChoices; + +@TestedFeature("Vote") +@TestedOperation("calculate winners") +public class CalculateWinnersTest extends CreatedDefaultCastVoteWithRankedChoices { + + private final Answer answerKeyCollection = (invocation) -> { + BeatTable beatTable = (BeatTable) invocation.getArguments()[0]; + return beatTable.getKeyCollection().stream().collect(Collectors.toList()); + }; + + private ComputedVote computedVote; + private final ArgumentCaptor captor = ArgumentCaptor.forClass(BeatTable.class); + + @Override + @Before + public void setUp() { + super.setUp(); + getTheVote().votesCast = castVote; + WinnerCalculatorImpl winnerCalculator = mock(WinnerCalculatorImpl.class); + when(winnerCalculator.calculateWinners(captor.capture())).thenAnswer(answerKeyCollection); + + computedVote = new ComputedVote(getTheVote()); + computedVote.computeVote(); + computedVote.setWinnerCalculator(winnerCalculator); + } + + @TestedBehaviour("only choices not in ignoredChoices are considered") + @Test + public void calculate_winners_returns_none_of_the_ignored_choices() { + List winners = computedVote.calculateWinners(Arrays.asList("A")); + assertFalse(winners.contains("A")); + + } + + @TestedBehaviour("only choices not in ignoredChoices are considered") + @Test + public void calculate_winners_returns_not_ignored_winner() { + List winners = computedVote.calculateWinners(Arrays.asList("C")); + assertBeatTableContainChoice(winners, "A"); + } + + private void assertBeatTableContainChoice(final List winners, final String choice) { + assertTrue(winners.contains(choice)); + BeatTable capturedBeatTable = captor.getValue(); + assertNotNull(capturedBeatTable.getElement(choice, "B")); + } + + +} diff --git a/src/test/java/org/rulez/demokracia/pdengine/UnimplementedTests.java b/src/test/java/org/rulez/demokracia/pdengine/UnimplementedTests.java index 0e0ab92a..19b12115 100644 --- a/src/test/java/org/rulez/demokracia/pdengine/UnimplementedTests.java +++ b/src/test/java/org/rulez/demokracia/pdengine/UnimplementedTests.java @@ -16,4 +16,9 @@ public class UnimplementedTests extends ThrowableTester { public void the_getAssurances_method_is_not_implemented_yet() { assertUnimplemented(() -> new CastVote("proxyId", new ArrayList<>()).getAssurances()); } + + @Test + public void the_calculateWinners_method_is_not_implemented_yet() { + assertUnimplemented(() -> new WinnerCalculatorImpl().calculateWinners(null)); + } }