package it.polimi.ingsw.gc14.Model; import it.polimi.ingsw.gc14.Model.Cards.BuildingCard; import it.polimi.ingsw.gc14.Model.Cards.TribeCard; import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Character; import it.polimi.ingsw.gc14.Model.Cards.TribeCards.CharacterType; import it.polimi.ingsw.gc14.Model.GamePackage.GameStages; import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.Builder; import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.Inventor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import java.util.*; import java.util.stream.Stream; import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.*; @Timeout(value = 10, unit = TimeUnit.SECONDS) class GameTest { private void completeTotemChoice(Game game) { assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); while (game.getCurrentState().getGameStage() == GameStages.TOTEM_CHOICE) { Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); List availableTotems = game.getAvailableTotems(); assertFalse(availableTotems.isEmpty()); Totems selectedTotem = availableTotems.get(0); assertTrue(game.TotemChoice(current, selectedTotem)); assertEquals(selectedTotem, current.totem); } assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); assertNotNull(game.getCurrentState().getCurrentPlayer()); } private Queue completeSlotChoice(Game game) { if (game.getCurrentState().getGameStage() == GameStages.TOTEM_CHOICE) { completeTotemChoice(game); } assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); Queue order = new LinkedList<>(); for (int i = 0; i < game.getNPlayers(); i++) { Player current = game.getCurrentState().getCurrentPlayer(); order.add(current); assertTrue(game.SlotChoiceByIndex(current, i)); assertTrue( game.getSlotMap().values().stream() .anyMatch(player -> player != null && player.getUserName().equals(current.getUserName())), "The selected player should be present in the slot map." ); } assertEquals(GameStages.RES_ACTIONS, game.getCurrentState().getGameStage()); return order; } private int firstNonEventIndex(List cards) { for (int i = 0; i < cards.size(); i++) { if (!cards.get(i).IsEventCard()) { return i; } } fail("No non-event tribe card available."); return -1; } private int firstNonEventIndexOrMinusOne(List cards) { for (int i = 0; i < cards.size(); i++) { if (!cards.get(i).IsEventCard()) { return i; } } return -1; } private void giveOptionalEffectToAllPlayers(Player... players) { for (Player player : players) { player.buildingCards.add(new BuildingCard(12, 1, 1, 1)); } } private void resolveAllMandatoryActions(Game game) { while (game.getCurrentState().getGameStage() == GameStages.RES_ACTIONS) { resolveOneMandatoryAction(game); } } private void resolveOneMandatoryAction(Game game) { Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); if (game.getCurrentState().getNLower() > 0) { int index = firstNonEventIndexOrMinusOne(game.getLowerListTribeCards()); if (index != -1) { assertTrue(game.DrawLowerTribeCardByIndex(current, index)); return; } if (!game.getLowerListBuilding().isEmpty() && game.DrawLowerBuildingCardByIndex(current, 0)) { return; } if(game.getCurrentState().getNUpper() == 0 || game.getUpperListTribeCards().stream().allMatch(TribeCard::IsEventCard)) { assertTrue(game.SkipNoDrawable(current)); return; } } if (game.getCurrentState().getNUpper() > 0) { int index = firstNonEventIndexOrMinusOne(game.getUpperListTribeCards()); if (index != -1) { assertTrue(game.DrawUpperTribeCardByIndex(current, index)); return; } if (!game.getUpperListBuilding().isEmpty() && game.DrawUpperBuildingCardByIndex(current, 0)) { return; } if(game.getCurrentState().getNLower() == 0 || game.getLowerListTribeCards().stream().allMatch(TribeCard::IsEventCard)) { assertTrue(game.SkipNoDrawable(current)); return; } } fail( "Current player has no remaining draw actions.\n" + "Current player: " + current + "\n" + "Round: " + game.getCurrentState().getRound() + "\n" + "Stage: " + game.getCurrentState().getGameStage() + "\n" + "Slot: " + (game.getCurrentState().getSlot() == null ? "null" : game.getCurrentState().getSlot().getSlotId()) + "\n" + "NLower: " + game.getCurrentState().getNLower() + "\n" + "NUpper: " + game.getCurrentState().getNUpper() + "\n" + "Lower tribe size: " + game.getLowerListTribeCards().size() + "\n" + "Upper tribe size: " + game.getUpperListTribeCards().size() + "\n" + "Lower building size: " + game.getLowerListBuilding().size() + "\n" + "Upper building size: " + game.getUpperListBuilding().size() + "\n" + "First lower non-event: " + firstNonEventIndexOrMinusOne(game.getLowerListTribeCards()) + "\n" + "First upper non-event: " + firstNonEventIndexOrMinusOne(game.getUpperListTribeCards()) ); } private void resolveActionsUntilOptionalCardEffect(Game game) { while (game.getCurrentState().getGameStage() == GameStages.RES_ACTIONS) { resolveOneMandatoryAction(game); } assertEquals(GameStages.OPT_CARD_E, game.getCurrentState().getGameStage()); } private void resolveOptionalPhaseIfPresent(Game game) { while (game.getCurrentState().getGameStage() == GameStages.OPT_CARD_E) { Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertTrue(game.NoOptionalCard(current)); } } private void playOneFullRound(Game game) { assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); completeSlotChoice(game); assertEquals(GameStages.RES_ACTIONS, game.getCurrentState().getGameStage()); resolveAllMandatoryActions(game); resolveOptionalPhaseIfPresent(game); } private void resolveCurrentPlayerCompletely(Game game, Player expectedPlayer) { assertEquals(expectedPlayer, game.getCurrentState().getCurrentPlayer()); while (game.getCurrentState().getGameStage() == GameStages.RES_ACTIONS && expectedPlayer.equals(game.getCurrentState().getCurrentPlayer())) { resolveOneMandatoryAction(game); } } @Test void constructorShouldInitializeGameCorrectly() { int nPlayers = 3; Game game = new Game(nPlayers); assertEquals(nPlayers, game.getNPlayers()); assertEquals(GameStages.WAITING, game.getCurrentState().getGameStage()); assertThrows(IllegalArgumentException.class, () -> new Game(6)); assertThrows(IllegalArgumentException.class, () -> new Game(-1)); game = new Game(); assertFalse(game.addPlayer(new Player("p1"))); assertTrue(game.setNPlayer(nPlayers)); assertTrue(game.addPlayer(new Player("p1"))); assertEquals(nPlayers, game.getNPlayers()); assertEquals(GameStages.WAITING, game.getCurrentState().getGameStage()); } @Test void getUpperListTribeCards() { int nPlayers = 3; Game game = new Game(nPlayers); assertEquals(nPlayers + 4, game.getUpperListTribeCards().size()); } @Test void getUpperListBuildingCards() { int nPlayers = 3; Game game = new Game(nPlayers); assertEquals(2, game.getUpperListBuilding().size()); } @Test void getLowerListBuildingCards() { int nPlayers = 3; Game game = new Game(nPlayers); assertEquals(0, game.getLowerListBuilding().size()); } @Test void getLowerListTribeCards() { int nPlayers = 3; Game game = new Game(nPlayers); assertEquals(nPlayers + 1, game.getLowerListTribeCards().size()); } @Test void getBoardShouldReturnBoard() { Game game = new Game(3); assertNotNull(game.getBoard()); } @Test void getPlayerByUsernameShouldReturnPlayerOrNull() { Game game = new Game(3); Player p1 = new Player("p1"); assertTrue(game.addPlayer(p1)); assertEquals(p1, game.getPlayerByUsername("p1")); assertNull(game.getPlayerByUsername("ghost")); } @Test void setNPlayerShouldWorkOnlyIfGameWasCreatedWithZeroPlayers() { Game game = new Game(); assertTrue(game.setNPlayer(3)); assertEquals(3, game.getNPlayers()); assertFalse(game.setNPlayer(4)); } @Test void addPlayerShouldRejectDuplicatesAndStartTotemChoiceWhenFull() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); Player p4 = new Player("p4"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertFalse(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); assertNotNull(game.getCurrentState().getCurrentPlayer()); assertFalse(game.addPlayer(p4)); } @Test void gameShouldEnterTotemChoiceWhenAllPlayersAreAdded() { Game game = new Game(3); assertTrue(game.addPlayer(new Player("p1"))); assertTrue(game.addPlayer(new Player("p2"))); assertTrue(game.addPlayer(new Player("p3"))); assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); assertNotNull(game.getCurrentState().getCurrentPlayer()); } @Test void totemChoiceShouldAssignDistinctTotemsAndStartSlotChoice() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); completeTotemChoice(game); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); assertNotNull(p1.totem); assertNotNull(p2.totem); assertNotNull(p3.totem); assertEquals( 3, Stream.of(p1.totem, p2.totem, p3.totem).distinct().count() ); } @Test void totemChoiceShouldRejectAlreadyChosenTotem() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); Player firstPlayer = game.getCurrentState().getCurrentPlayer(); Totems chosenTotem = game.getAvailableTotems().get(0); assertTrue(game.TotemChoice(firstPlayer, chosenTotem)); Player secondPlayer = game.getCurrentState().getCurrentPlayer(); assertNotNull(secondPlayer); assertFalse(game.TotemChoice(secondPlayer, chosenTotem)); } @Test void totemChoiceShouldRejectWrongPlayer() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); Player current = game.getCurrentState().getCurrentPlayer(); Player wrongPlayer = current.equals(p1) ? p2 : p1; Totems availableTotem = game.getAvailableTotems().get(0); assertFalse(game.TotemChoice(wrongPlayer, availableTotem)); } @Test void getAvailableTotemsShouldExcludeChosenTotems() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); int initialAvailableTotems = game.getAvailableTotems().size(); Player current = game.getCurrentState().getCurrentPlayer(); Totems chosenTotem = game.getAvailableTotems().get(0); assertTrue(game.TotemChoice(current, chosenTotem)); assertEquals(initialAvailableTotems - 1, game.getAvailableTotems().size()); assertFalse(game.getAvailableTotems().contains(chosenTotem)); } @Test void shouldRejectInvalidSlotChoices() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); completeTotemChoice(game); Player current = game.getCurrentState().getCurrentPlayer(); assertFalse(game.SlotChoiceByIndex(current, -1)); assertFalse(game.SlotChoiceByIndex(current, 999)); Player wrongPlayer = current.equals(p1) ? p2 : p1; assertFalse(game.SlotChoiceByIndex(wrongPlayer, 0)); assertTrue(game.SlotChoiceByIndex(current, 0)); Player next = game.getCurrentState().getCurrentPlayer(); assertFalse(game.SlotChoiceByIndex(next, 0)); } @Test void drawingByIndex() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertFalse(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); completeTotemChoice(game); Queue players = new LinkedList<>(); for (int i = 0; i < game.getNPlayers(); i++) { players.add(game.getCurrentState().getCurrentPlayer()); assertTrue(game.SlotChoiceByIndex(game.getCurrentState().getCurrentPlayer(), i)); } Player temp_player; temp_player = players.poll(); assertEquals(temp_player, game.getCurrentState().getCurrentPlayer()); int index; List cards = game.getLowerListTribeCards(); index = firstNonEventIndex(cards); assertTrue(game.DrawLowerTribeCardByIndex(temp_player, index)); temp_player = players.poll(); assertEquals(temp_player, game.getCurrentState().getCurrentPlayer()); int nCards = game.getUpperListTribeCards().size(); int countCards = 0; HashMap nCardsByType = new HashMap(); Arrays.stream(CharacterType.values()).forEach(type -> nCardsByType.put(type, 0)); while (game.getCurrentState().getNUpper() > 1) { cards = game.getUpperListTribeCards(); index = firstNonEventIndexOrMinusOne(cards); if (index == -1) { break; } TribeCard temp_card = cards.get(index); assertEquals(nCards - countCards, game.getUpperListTribeCards().size()); assertTrue(game.DrawUpperTribeCardByIndex(temp_player, index)); drawTribeTest(nCardsByType, temp_card, temp_player); countCards++; } cards = game.getUpperListTribeCards(); int eventIndex = firstEventIndexOrMinusOne(cards); if (eventIndex != -1) { assertFalse(game.DrawUpperTribeCardByIndex(temp_player, eventIndex)); } assertFalse(game.getUpperListBuilding().isEmpty()); temp_player.builders.clear(); index = 0; BuildingCard selectedBuilding = game.getUpperListBuilding().get(index); temp_player.addFood(selectedBuilding.getPrice()); assertTrue(game.DrawUpperBuildingCardByIndex(temp_player, index)); int remainingTribeIndex = firstNonEventIndexOrMinusOne(game.getUpperListTribeCards()); if (remainingTribeIndex != -1) { assertFalse(game.DrawUpperTribeCardByIndex(temp_player, remainingTribeIndex)); } Player thirdPlayer = players.poll(); assertNotNull(thirdPlayer); assertEquals(thirdPlayer, game.getCurrentState().getCurrentPlayer()); while (game.getCurrentState().getGameStage() == GameStages.RES_ACTIONS && thirdPlayer.equals(game.getCurrentState().getCurrentPlayer())) { resolveOneMandatoryAction(game); } assertNotEquals(thirdPlayer, game.getCurrentState().getCurrentPlayer()); } private void drawTribeTest(HashMap nCardsByType, TribeCard temp_card, Player temp_player) { switch (((Character) temp_card).getType()) { case ARTIST: assertEquals(nCardsByType.get(((Character) temp_card).getType()) + 1, temp_player.artists.size()); nCardsByType.merge(((Character) temp_card).getType(), 1, Integer::sum); break; case INVENTOR: assertEquals(nCardsByType.get(((Character) temp_card).getType()) + 1, temp_player.inventors.size()); nCardsByType.merge(((Character) temp_card).getType(), 1, Integer::sum); break; case HUNTER: assertEquals(nCardsByType.get(((Character) temp_card).getType()) + 1, temp_player.hunters.size()); nCardsByType.merge(((Character) temp_card).getType(), 1, Integer::sum); break; case SHAMAN: assertEquals(nCardsByType.get(((Character) temp_card).getType()) + 1, temp_player.shamans.size()); nCardsByType.merge(((Character) temp_card).getType(), 1, Integer::sum); break; case BUILDER: assertEquals(nCardsByType.get(((Character) temp_card).getType()) + 1, temp_player.builders.size()); nCardsByType.merge(((Character) temp_card).getType(), 1, Integer::sum); break; case GATHERER: assertEquals(nCardsByType.get(((Character) temp_card).getType()) + 1, temp_player.gatherers.size()); nCardsByType.merge(((Character) temp_card).getType(), 1, Integer::sum); break; } } @Test void pickOptionalTribeCard() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); giveOptionalEffectToAllPlayers(p1, p2, p3); completeSlotChoice(game); resolveActionsUntilOptionalCardEffect(game); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); int index = firstNonEventIndex(game.getUpperListTribeCards()); int charactersBefore = current.getTotCharacters(); assertTrue(game.PickOptionalTribeCardByIndex(current, index)); assertEquals(charactersBefore + 1, current.getTotCharacters()); } @Test void pickOptionalBuildingCard() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); giveOptionalEffectToAllPlayers(p1, p2, p3); completeSlotChoice(game); resolveActionsUntilOptionalCardEffect(game); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertFalse(game.getUpperListBuilding().isEmpty()); current.builders.clear(); BuildingCard selectedBuilding = game.getUpperListBuilding().get(0); int expectedCost = selectedBuilding.getPrice(); current.addFood(expectedCost); int buildingsBefore = current.buildingCards.size(); int upperBuildingsBefore = game.getUpperListBuilding().size(); int foodBefore = current.getFoodValue(); assertTrue(game.PickOptionalBuildingCard(current, 0)); assertEquals(buildingsBefore + 1, current.buildingCards.size()); assertEquals(upperBuildingsBefore - 1, game.getUpperListBuilding().size()); assertTrue(current.buildingCards.stream() .anyMatch(building -> building.getPrice() == selectedBuilding.getPrice() && building.getPrestigeValue() == selectedBuilding.getPrestigeValue() && building.getEffectId() == selectedBuilding.getEffectId() )); assertEquals(foodBefore - expectedCost, current.getFoodValue()); } @Test void noOptionalCard() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); giveOptionalEffectToAllPlayers(p1, p2, p3); completeSlotChoice(game); resolveActionsUntilOptionalCardEffect(game); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertTrue(game.NoOptionalCard(current)); assertEquals(GameStages.OPT_CARD_E, game.getCurrentState().getGameStage()); assertNotEquals(current, game.getCurrentState().getCurrentPlayer()); } private List addPlayers(Game game, int nPlayers, String prefix) { List players = new ArrayList<>(); for (int i = 1; i <= nPlayers; i++) { Player player = new Player(prefix + i); players.add(player); assertTrue(game.addPlayer(player)); } if (game.getCurrentState().getGameStage() == GameStages.TOTEM_CHOICE) { completeTotemChoice(game); } return players; } private int firstEventIndexOrMinusOne(List cards) { for (int i = 0; i < cards.size(); i++) { if (cards.get(i).IsEventCard()) { return i; } } return -1; } @Test void getCurrentPlayerNumberShouldTrackAddedPlayers() { Game game = new Game(3); assertEquals(0, game.getCurrentPlayerNumber()); assertTrue(game.addPlayer(new Player("a"))); assertEquals(1, game.getCurrentPlayerNumber()); assertTrue(game.addPlayer(new Player("b"))); assertEquals(2, game.getCurrentPlayerNumber()); assertTrue(game.addPlayer(new Player("c"))); assertEquals(3, game.getCurrentPlayerNumber()); } @Test void slotChoiceByIndexShouldReturnFalseOutsideSlotChoiceStage() { Game game = new Game(3); addPlayers(game, 3, "slot_out_"); completeSlotChoice(game); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertFalse(game.SlotChoiceByIndex(current, 0)); } @Test void shouldRejectInvalidDrawRequests() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); /* * The game is currently in TOTEM_CHOICE: * draw requests must be rejected because the game is not in RES_ACTIONS. */ Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertFalse(game.DrawLowerTribeCardByIndex(current, 0)); assertFalse(game.DrawUpperTribeCardByIndex(current, 0)); assertFalse(game.DrawUpperBuildingCardByIndex(current, 0)); assertFalse(game.DrawLowerBuildingCardByIndex(current, 0)); /* * The totem choice phase and the slot choice phase are completed, * so the game enters RES_ACTIONS. */ completeSlotChoice(game); current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); Player wrongPlayer = current.equals(p1) ? p2 : p1; assertFalse(game.DrawLowerTribeCardByIndex(current, -1)); assertFalse(game.DrawLowerTribeCardByIndex(current, 999)); assertFalse(game.DrawUpperTribeCardByIndex(current, -1)); assertFalse(game.DrawUpperTribeCardByIndex(current, 999)); assertFalse(game.DrawUpperBuildingCardByIndex(current, -1)); assertFalse(game.DrawUpperBuildingCardByIndex(current, 999)); assertFalse(game.DrawLowerBuildingCardByIndex(current, -1)); assertFalse(game.DrawLowerBuildingCardByIndex(current, 999)); int lowerIndex = firstNonEventIndexOrMinusOne(game.getLowerListTribeCards()); if (lowerIndex != -1) { assertFalse(game.DrawLowerTribeCardByIndex(wrongPlayer, lowerIndex)); } int upperIndex = firstNonEventIndexOrMinusOne(game.getUpperListTribeCards()); if (upperIndex != -1) { assertFalse(game.DrawUpperTribeCardByIndex(wrongPlayer, upperIndex)); } if (!game.getUpperListBuilding().isEmpty()) { assertFalse(game.DrawUpperBuildingCardByIndex(wrongPlayer, 0)); } } @Test void optionalMethodsShouldReturnFalseOutsideOptionalState() { Game game = new Game(3); addPlayers(game, 3, "optional_out_"); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertFalse(game.PickOptionalTribeCardByIndex(current, 0)); assertFalse(game.PickOptionalBuildingCard(current, 0)); assertFalse(game.NoOptionalCard(current)); } @Test void optionalMethodsShouldRejectWrongPlayerAndInvalidIndexes() { Game game = new Game(3); List players = addPlayers(game, 3, "optional_invalid_"); giveOptionalEffectToAllPlayers(players.get(0), players.get(1), players.get(2)); completeSlotChoice(game); resolveActionsUntilOptionalCardEffect(game); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); Player wrongPlayer = current.equals(players.get(0)) ? players.get(1) : players.get(0); assertFalse(game.PickOptionalTribeCardByIndex(wrongPlayer, 0)); assertFalse(game.PickOptionalBuildingCard(wrongPlayer, 0)); assertFalse(game.NoOptionalCard(wrongPlayer)); assertFalse(game.PickOptionalTribeCardByIndex(current, -1)); assertFalse(game.PickOptionalTribeCardByIndex(current, 999)); assertFalse(game.PickOptionalBuildingCard(current, -1)); assertFalse(game.PickOptionalBuildingCard(current, 999)); } @Test @Timeout(value = 2, unit = TimeUnit.SECONDS) void shouldNotCrashWhenNoPlayerHasOptionalEffect() { Game game = new Game(3); addPlayers(game, 3, "no_optional_"); completeSlotChoice(game); assertDoesNotThrow(() -> resolveAllMandatoryActions(game)); assertNotEquals(GameStages.OPT_CARD_E, game.getCurrentState().getGameStage()); } @Test void constructorShouldRejectOnePlayerGame() { assertThrows(IllegalArgumentException.class, () -> new Game(1)); } @Test void setNPlayerShouldAllowCompleteGameSetup() { Game game = new Game(); assertTrue(game.setNPlayer(3)); assertTrue(game.addPlayer(new Player("p1"))); assertTrue(game.addPlayer(new Player("p2"))); assertTrue(game.addPlayer(new Player("p3"))); assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); completeTotemChoice(game); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertTrue(game.SlotChoiceByIndex(current, 0)); } @Test @Timeout(value = 20, unit = TimeUnit.SECONDS) void shouldCompleteFullGameThroughRealFlow() { for (int nPlayers : new int[]{2, 3, 4, 5}) { Game game = new Game(nPlayers); for (int i = 1; i <= nPlayers; i++) { assertTrue(game.addPlayer(new Player("p" + nPlayers + "_" + i))); } completeTotemChoice(game); assertEquals(nPlayers, game.getCurrentPlayerNumber()); assertEquals(nPlayers, game.getPlayers().size()); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); assertEquals(1, game.getCurrentState().getRound()); assertNotNull(game.getCurrentState().getCurrentPlayer()); for (int expectedRound = 1; expectedRound < 10; expectedRound++) { assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); assertEquals(expectedRound, game.getCurrentState().getRound()); assertEquals(nPlayers, game.getCurrentPlayerNumber()); playOneFullRound(game); assertEquals( GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage(), "After round " + expectedRound + ", the game should return to SLOT_CHOICE." ); assertEquals( expectedRound + 1, game.getCurrentState().getRound(), "The round should increase after completing round " + expectedRound + "." ); assertEquals(nPlayers, game.getCurrentPlayerNumber()); assertNotNull(game.getCurrentState().getCurrentPlayer()); } assertEquals(10, game.getCurrentState().getRound()); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); playOneFullRound(game); assertEquals( GameStages.ENDED, game.getCurrentState().getGameStage(), "The game should end after completing round 10 with " + nPlayers + " players." ); assertEquals(10, game.getCurrentState().getRound()); assertEquals(nPlayers, game.getPlayers().size()); } } @Test void setNPlayerShouldRejectInvalidPlayerCounts() { assertFalse(new Game().setNPlayer(-1)); assertFalse(new Game().setNPlayer(1)); assertFalse(new Game().setNPlayer(6)); } @Test void addPlayerShouldRejectDifferentPlayerWithSameUsername() { Game game = new Game(3); assertTrue(game.addPlayer(new Player("same_name"))); assertFalse(game.addPlayer(new Player("same_name"))); } @Test @Timeout(value = 2, unit = TimeUnit.SECONDS) void roundShouldAdvanceAfterOnlyOptionalPlayerSkipsOptionalCard() { Game game = new Game(3); List players = addPlayers(game, 3, "single_optional_"); players.get(0).buildingCards.add(new BuildingCard(12, 1, 1, 1)); int roundBefore = game.getCurrentState().getRound(); completeSlotChoice(game); resolveActionsUntilOptionalCardEffect(game); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertTrue(game.NoOptionalCard(current)); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); assertEquals(roundBefore + 1, game.getCurrentState().getRound()); assertNotNull(game.getCurrentState().getCurrentPlayer()); } @Test @Timeout(value = 2, unit = TimeUnit.SECONDS) void roundShouldAdvanceAfterAllOptionalPlayersSkipOptionalCard() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); giveOptionalEffectToAllPlayers(p1, p2, p3); int roundBefore = game.getCurrentState().getRound(); completeSlotChoice(game); resolveActionsUntilOptionalCardEffect(game); resolveOptionalPhaseIfPresent(game); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); assertEquals(roundBefore + 1, game.getCurrentState().getRound()); assertNotNull(game.getCurrentState().getCurrentPlayer()); } @Test void pickOptionalBuildingCardShouldReturnFalseIfPlayerCannotPay() { Game game = new Game(3); List players = addPlayers(game, 3, "no_food_"); giveOptionalEffectToAllPlayers(players.get(0), players.get(1), players.get(2)); completeSlotChoice(game); resolveActionsUntilOptionalCardEffect(game); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); while (current.getFoodValue() > 0) { assertTrue(current.removeFood(1)); } current.builders.clear(); assertEquals(0, current.getFoodValue()); assertFalse( game.getUpperListBuilding().isEmpty(), "There must be at least one upper building card to test that the player cannot buy it." ); assertFalse(game.PickOptionalBuildingCard(current, 0)); } @Test @Timeout(value = 5, unit = TimeUnit.SECONDS) void shouldDrawLowerBuildingWhenAvailableAndPlayerCanPay() { Game game = new Game(3); addPlayers(game, 3, "lower_building_"); for (int safety = 0; safety < 300; safety++) { if (game.getCurrentState().getGameStage() == GameStages.SLOT_CHOICE) { completeSlotChoice(game); } if (game.getCurrentState().getGameStage() == GameStages.RES_ACTIONS) { Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); if (game.getCurrentState().getNLower() > 0 && !game.getLowerListBuilding().isEmpty()) { current.builders.clear(); BuildingCard selectedBuilding = game.getLowerListBuilding().get(0); int expectedCost = selectedBuilding.getPrice(); current.addFood(expectedCost); int buildingsBefore = current.buildingCards.size(); int lowerBuildingsBefore = game.getLowerListBuilding().size(); int foodBefore = current.getFoodValue(); assertTrue( game.DrawLowerBuildingCardByIndex(current, 0), "DrawLowerBuildingCardByIndex should return true when lower building exists, player can draw lower, and player has food." ); assertEquals(buildingsBefore + 1, current.buildingCards.size()); assertEquals(lowerBuildingsBefore - 1, game.getLowerListBuilding().size()); assertTrue(current.buildingCards.stream() .anyMatch(building -> building.getPrice() == selectedBuilding.getPrice() && building.getPrestigeValue() == selectedBuilding.getPrestigeValue() && building.getEffectId() == selectedBuilding.getEffectId() )); assertTrue( current.getFoodValue() >= foodBefore - expectedCost, "After buying the building, food should not be lower than the price paid because later effects may add food." ); return; } resolveOneMandatoryAction(game); } if (game.getCurrentState().getGameStage() == GameStages.OPT_CARD_E) { resolveOptionalPhaseIfPresent(game); } if (game.getCurrentState().getGameStage() == GameStages.ENDED) { break; } } fail("The test never reached a state with NLower > 0 and at least one lower building."); } @Test @Timeout(value = 5, unit = TimeUnit.SECONDS) void drawBuildingShouldReturnFalseIfPlayerCannotPay() { Game game = new Game(3); addPlayers(game, 3, "no_food_upper_building_"); for (int safety = 0; safety < 300; safety++) { if (game.getCurrentState().getGameStage() == GameStages.SLOT_CHOICE) { completeSlotChoice(game); } if (game.getCurrentState().getGameStage() == GameStages.RES_ACTIONS) { Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); if (game.getCurrentState().getNUpper() > 0 && !game.getUpperListBuilding().isEmpty()) { BuildingCard selectedBuilding = game.getUpperListBuilding().get(0); if (selectedBuilding.getPrice() <= 0) { resolveOneMandatoryAction(game); continue; } while (current.getFoodValue() > 0) { assertTrue(current.removeFood(1)); } current.builders.clear(); assertEquals(0, current.getFoodValue()); int buildingsBefore = current.buildingCards.size(); int upperBuildingsBefore = game.getUpperListBuilding().size(); assertFalse(game.DrawUpperBuildingCardByIndex(current, 0)); assertEquals(buildingsBefore, current.buildingCards.size()); assertEquals(upperBuildingsBefore, game.getUpperListBuilding().size()); assertEquals(0, current.getFoodValue()); return; } resolveOneMandatoryAction(game); } if (game.getCurrentState().getGameStage() == GameStages.OPT_CARD_E) { resolveOptionalPhaseIfPresent(game); } if (game.getCurrentState().getGameStage() == GameStages.ENDED) { break; } } fail("The test never reached a state with NUpper > 0 and at least one payable upper building."); } @Test void shouldResolvePlayersAccordingToSlotOrder() { Game game = new Game(3); addPlayers(game, 3, "slot_order_"); Player firstChooser = game.getCurrentState().getCurrentPlayer(); assertTrue(game.SlotChoiceByIndex(firstChooser, 2)); Player secondChooser = game.getCurrentState().getCurrentPlayer(); assertTrue(game.SlotChoiceByIndex(secondChooser, 0)); Player thirdChooser = game.getCurrentState().getCurrentPlayer(); assertTrue(game.SlotChoiceByIndex(thirdChooser, 1)); assertEquals(GameStages.RES_ACTIONS, game.getCurrentState().getGameStage()); assertEquals(secondChooser, game.getCurrentState().getCurrentPlayer()); resolveCurrentPlayerCompletely(game, secondChooser); assertEquals(thirdChooser, game.getCurrentState().getCurrentPlayer()); resolveCurrentPlayerCompletely(game, thirdChooser); assertEquals(firstChooser, game.getCurrentState().getCurrentPlayer()); } @Test @Timeout(value = 20, unit = TimeUnit.SECONDS) void endGameShouldNotCrashWhenTriggeredAfterRoundTen() { Game game = new Game(3); List players = addPlayers(game, 3, "end_game_"); giveOptionalEffectToAllPlayers(players.get(0), players.get(1), players.get(2)); while (game.getCurrentState().getRound() < 10) { playOneFullRound(game); } assertEquals(10, game.getCurrentState().getRound()); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); completeSlotChoice(game); resolveAllMandatoryActions(game); assertEquals(GameStages.OPT_CARD_E, game.getCurrentState().getGameStage()); assertDoesNotThrow(() -> resolveOptionalPhaseIfPresent(game)); assertEquals(GameStages.ENDED, game.getCurrentState().getGameStage()); } private void preparePlayerForComparableFinalScoring(Player player) { player.buildingCards.clear(); player.builders.clear(); player.inventors.clear(); player.artists.clear(); player.hunters.clear(); player.shamans.clear(); player.gatherers.clear(); while (player.getFoodValue() > 0) { assertTrue(player.removeFood(1)); } /* * Keeps the optional effect, but with zero final prestige. * This preserves the OPT_CARD_E phase while keeping the comparison controlled. */ player.buildingCards.add(new BuildingCard(12, 1, 1, 0)); } @Test void skipDrawingShouldRejectWrongPlayer() { Game game = new Game(3); List players = addPlayers(game, 3, "skip_wrong_"); completeSlotChoice(game); Player current = game.getCurrentState().getCurrentPlayer(); Player wrongPlayer = players.stream() .filter(p -> !p.equals(current)) .findFirst() .orElseThrow(); assertFalse(game.SkipNoDrawable(wrongPlayer)); } @Test void skipDrawingShouldReturnFalseWhenDrawableCardsExist() { Game game = new Game(3); addPlayers(game, 3, "skip_drawable_"); completeSlotChoice(game); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); boolean hasDrawableLowerTribe = game.getCurrentState().getNLower() > 0 && firstNonEventIndexOrMinusOne(game.getLowerListTribeCards()) != -1; boolean hasDrawableUpperTribe = game.getCurrentState().getNUpper() > 0 && firstNonEventIndexOrMinusOne(game.getUpperListTribeCards()) != -1; assertTrue( hasDrawableLowerTribe || hasDrawableUpperTribe, "The test requires at least one drawable tribe card." ); assertFalse(game.SkipNoDrawable(current)); } @Test @Timeout(value = 20, unit = TimeUnit.SECONDS) void pickOptionalTribeCardShouldRejectEventCardIfPresent() { Game game = new Game(3); List players = addPlayers(game, 3, "optional_event_"); giveOptionalEffectToAllPlayers(players.get(0), players.get(1), players.get(2)); while (game.getCurrentState().getGameStage() != GameStages.ENDED) { assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); completeSlotChoice(game); resolveActionsUntilOptionalCardEffect(game); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); int eventIndex = firstEventIndexOrMinusOne(game.getUpperListTribeCards()); if (eventIndex != -1) { int charactersBefore = current.getTotCharacters(); int upperSizeBefore = game.getUpperListTribeCards().size(); assertFalse(game.PickOptionalTribeCardByIndex(current, eventIndex)); assertEquals(GameStages.OPT_CARD_E, game.getCurrentState().getGameStage()); assertEquals(current, game.getCurrentState().getCurrentPlayer()); assertEquals(charactersBefore, current.getTotCharacters()); assertEquals(upperSizeBefore, game.getUpperListTribeCards().size()); return; } resolveOptionalPhaseIfPresent(game); } org.junit.jupiter.api.Assumptions.assumeTrue( false, "No optional phase with an event card in the upper tribe list was reached." ); } @Test void cardListsShouldReturnCopiesOfLists() { Game game = new Game(3); int upperTribeSize = game.getUpperListTribeCards().size(); int lowerTribeSize = game.getLowerListTribeCards().size(); int upperBuildingSize = game.getUpperListBuilding().size(); int lowerBuildingSize = game.getLowerListBuilding().size(); List upperTribe = game.getUpperListTribeCards(); List lowerTribe = game.getLowerListTribeCards(); List upperBuilding = game.getUpperListBuilding(); List lowerBuilding = game.getLowerListBuilding(); upperTribe.clear(); lowerTribe.clear(); upperBuilding.clear(); lowerBuilding.clear(); assertEquals(upperTribeSize, game.getUpperListTribeCards().size()); assertEquals(lowerTribeSize, game.getLowerListTribeCards().size()); assertEquals(upperBuildingSize, game.getUpperListBuilding().size()); assertEquals(lowerBuildingSize, game.getLowerListBuilding().size()); } @Test void getPlayersShouldReturnAddedPlayers() { Game game = new Game(3); Player p1 = new Player("gp1"); Player p2 = new Player("gp2"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertEquals(2, game.getPlayers().size()); assertTrue(game.getPlayers().contains(p1)); assertTrue(game.getPlayers().contains(p2)); } @Test void skipDrawingShouldRejectOutsideResolvingActions() { Game game = new Game(3); addPlayers(game, 3, "skip_out_"); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); assertFalse(game.SkipNoDrawable(current)); } @Test void disconnectedCurrentPlayerDuringSlotChoiceShouldAdvanceTurn() { Game game = new Game(3); addPlayers(game, 3, "disconnect_slot_"); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertTrue(game.DisconnectedPlayer(current)); assertTrue(game.disconnetedPlayers.containsKey(current)); assertTrue(game.disconnetedPlayers.get(current)); assertNotEquals(current, game.getCurrentState().getCurrentPlayer()); } @Test void disconnectedPlayerShouldReturnFalseIfAlreadyDisconnected() { Game game = new Game(3); addPlayers(game, 3, "disconnect_twice_"); Player current = game.getCurrentState().getCurrentPlayer(); assertTrue(game.DisconnectedPlayer(current)); assertFalse(game.DisconnectedPlayer(current)); } @Test void reconnectPlayerShouldRemovePlayerFromDisconnectedMapDuringSlotChoice() { Game game = new Game(3); addPlayers(game, 3, "reconnect_"); Player current = game.getCurrentState().getCurrentPlayer(); assertTrue(game.DisconnectedPlayer(current)); assertTrue(game.disconnetedPlayers.containsKey(current)); assertTrue(game.ReconnectPlayer(current)); assertFalse(game.disconnetedPlayers.containsKey(current)); } @Test void clearDisconnectedShouldEmptyDisconnectedPlayersMap() { Game game = new Game(3); addPlayers(game, 3, "clear_disconnect_"); Player current = game.getCurrentState().getCurrentPlayer(); assertTrue(game.DisconnectedPlayer(current)); assertFalse(game.disconnetedPlayers.isEmpty()); game.ClearDisconnected(); assertTrue(game.disconnetedPlayers.isEmpty()); } @Test @Timeout(value = 5, unit = TimeUnit.SECONDS) void drawLowerBuildingShouldReturnFalseIfPlayerCannotPay() { Game game = new Game(3); addPlayers(game, 3, "no_food_lower_building_"); for (int safety = 0; safety < 300; safety++) { if (game.getCurrentState().getGameStage() == GameStages.SLOT_CHOICE) { completeSlotChoice(game); } if (game.getCurrentState().getGameStage() == GameStages.RES_ACTIONS) { Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); if (game.getCurrentState().getNLower() > 0 && !game.getLowerListBuilding().isEmpty()) { BuildingCard selectedBuilding = game.getLowerListBuilding().get(0); if (selectedBuilding.getPrice() <= 0) { resolveOneMandatoryAction(game); continue; } while (current.getFoodValue() > 0) { assertTrue(current.removeFood(1)); } current.builders.clear(); assertEquals(0, current.getFoodValue()); int buildingsBefore = current.buildingCards.size(); int lowerBuildingsBefore = game.getLowerListBuilding().size(); assertFalse(game.DrawLowerBuildingCardByIndex(current, 0)); assertEquals(buildingsBefore, current.buildingCards.size()); assertEquals(lowerBuildingsBefore, game.getLowerListBuilding().size()); assertEquals(0, current.getFoodValue()); return; } resolveOneMandatoryAction(game); } if (game.getCurrentState().getGameStage() == GameStages.OPT_CARD_E) { resolveOptionalPhaseIfPresent(game); } if (game.getCurrentState().getGameStage() == GameStages.ENDED) { break; } } fail("The test never reached a state with NLower > 0 and at least one payable lower building."); } @Test @Timeout(value = 5, unit = TimeUnit.SECONDS) void drawLowerBuildingShouldRejectWrongPlayer() { Game game = new Game(3); List players = addPlayers(game, 3, "wrong_lower_building_"); for (int safety = 0; safety < 300; safety++) { if (game.getCurrentState().getGameStage() == GameStages.SLOT_CHOICE) { completeSlotChoice(game); } if (game.getCurrentState().getGameStage() == GameStages.RES_ACTIONS) { Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); if (game.getCurrentState().getNLower() > 0 && !game.getLowerListBuilding().isEmpty()) { Player wrongPlayer = players.stream() .filter(p -> !p.equals(current)) .findFirst() .orElseThrow(); wrongPlayer.addFood(game.getLowerListBuilding().get(0).getPrice()); assertFalse(game.DrawLowerBuildingCardByIndex(wrongPlayer, 0)); return; } resolveOneMandatoryAction(game); } if (game.getCurrentState().getGameStage() == GameStages.OPT_CARD_E) { resolveOptionalPhaseIfPresent(game); } if (game.getCurrentState().getGameStage() == GameStages.ENDED) { break; } } fail("The test never reached a lower building draw state."); } @Test void cardListsShouldReturnClonedCards() { Game game = new Game(3); List firstUpperTribeCall = game.getUpperListTribeCards(); List secondUpperTribeCall = game.getUpperListTribeCards(); assertFalse(firstUpperTribeCall.isEmpty()); assertFalse(secondUpperTribeCall.isEmpty()); assertNotSame(firstUpperTribeCall.get(0), secondUpperTribeCall.get(0)); List firstLowerTribeCall = game.getLowerListTribeCards(); List secondLowerTribeCall = game.getLowerListTribeCards(); assertFalse(firstLowerTribeCall.isEmpty()); assertFalse(secondLowerTribeCall.isEmpty()); assertNotSame(firstLowerTribeCall.get(0), secondLowerTribeCall.get(0)); List firstUpperBuildingCall = game.getUpperListBuilding(); List secondUpperBuildingCall = game.getUpperListBuilding(); assertFalse(firstUpperBuildingCall.isEmpty()); assertFalse(secondUpperBuildingCall.isEmpty()); assertNotSame(firstUpperBuildingCall.get(0), secondUpperBuildingCall.get(0)); } @Test void initShouldAssignInitialFoodAccordingToOrderPosition() { Game game = new Game(5); Player p1 = new Player("p1"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); Player p4 = new Player("p4"); Player p5 = new Player("p5"); assertTrue(game.addPlayer(p1)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); assertTrue(game.addPlayer(p4)); assertTrue(game.addPlayer(p5)); assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); List foodValues = game.getPlayers().stream() .map(Player::getFoodValue) .sorted() .toList(); assertEquals(List.of(2, 3, 3, 4, 4), foodValues); } @Test void slotChoiceShouldAddFoodWhenChoosingSlotAInFivePlayerGame() { Game game = new Game(5); addPlayers(game, 5, "slot_a_"); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); int foodBefore = current.getFoodValue(); assertTrue(game.SlotChoiceByIndex(current, 0)); assertEquals(foodBefore + 3, current.getFoodValue()); } @Test void slotChoiceShouldNotAddFoodWhenChoosingNonASlot() { Game game = new Game(5); addPlayers(game, 5, "slot_non_a_"); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); int foodBefore = current.getFoodValue(); assertTrue(game.SlotChoiceByIndex(current, 1)); assertEquals(foodBefore, current.getFoodValue()); } @Test @Timeout(value = 20, unit = TimeUnit.SECONDS) void endGameShouldAddExactBuildingPrestigeValues() { Game game = new Game(3); List players = addPlayers(game, 3, "final_building_scoring_"); giveOptionalEffectToAllPlayers(players.get(0), players.get(1), players.get(2)); while (game.getCurrentState().getRound() < 10) { playOneFullRound(game); } assertEquals(10, game.getCurrentState().getRound()); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); completeSlotChoice(game); resolveAllMandatoryActions(game); assertEquals(GameStages.OPT_CARD_E, game.getCurrentState().getGameStage()); Player controlPlayer = players.get(0); Player testedPlayer = players.get(1); assertNotNull(controlPlayer); assertNotNull(testedPlayer); /* * The two players are made equivalent with respect to events and final scoring. * The game has still reached round 10 through the real flow. */ preparePlayerForComparableFinalScoring(controlPlayer); preparePlayerForComparableFinalScoring(testedPlayer); preparePlayerForComparableFinalScoring(players.get(2)); BuildingCard firstBuilding = new BuildingCard(12, 1, 1, 7); BuildingCard secondBuilding = new BuildingCard(12, 1, 1, 5); testedPlayer.buildingCards.add(firstBuilding); testedPlayer.buildingCards.add(secondBuilding); int prestigeDifferenceBefore = testedPlayer.getPrestigeValue() - controlPlayer.getPrestigeValue(); int expectedExtraIncrease = firstBuilding.getPrestigeValue() + secondBuilding.getPrestigeValue(); resolveOptionalPhaseIfPresent(game); assertEquals(GameStages.ENDED, game.getCurrentState().getGameStage()); int prestigeDifferenceAfter = testedPlayer.getPrestigeValue() - controlPlayer.getPrestigeValue(); assertEquals( expectedExtraIncrease, prestigeDifferenceAfter - prestigeDifferenceBefore, "Final scoring should add exactly the printed prestige values of the added buildings." ); } @Test @Timeout(value = 20, unit = TimeUnit.SECONDS) void endGameShouldAddExactBuilderPrestigeValues() { Game game = new Game(3); List players = addPlayers(game, 3, "final_builder_scoring_"); giveOptionalEffectToAllPlayers(players.get(0), players.get(1), players.get(2)); while (game.getCurrentState().getRound() < 10) { playOneFullRound(game); } assertEquals(10, game.getCurrentState().getRound()); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); completeSlotChoice(game); resolveAllMandatoryActions(game); assertEquals(GameStages.OPT_CARD_E, game.getCurrentState().getGameStage()); Player controlPlayer = players.get(0); Player testedPlayer = players.get(1); assertNotNull(controlPlayer); assertNotNull(testedPlayer); preparePlayerForComparableFinalScoring(controlPlayer); preparePlayerForComparableFinalScoring(testedPlayer); preparePlayerForComparableFinalScoring(players.get(2)); controlPlayer.builders.add(new Builder(1, 0, 0)); controlPlayer.builders.add(new Builder(1, 0, 0)); testedPlayer.builders.add(new Builder(1, 0, 4)); testedPlayer.builders.add(new Builder(1, 0, 3)); int prestigeDifferenceBefore = testedPlayer.getPrestigeValue() - controlPlayer.getPrestigeValue(); int expectedExtraIncrease = 4 + 3; resolveOptionalPhaseIfPresent(game); assertEquals(GameStages.ENDED, game.getCurrentState().getGameStage()); int prestigeDifferenceAfter = testedPlayer.getPrestigeValue() - controlPlayer.getPrestigeValue(); assertEquals( expectedExtraIncrease, prestigeDifferenceAfter - prestigeDifferenceBefore, "Final scoring should add exactly the prestige values of the builders." ); } @Test @Timeout(value = 20, unit = TimeUnit.SECONDS) void endGameShouldAddExactInventorPrestigeValues() { Game game = new Game(3); List players = addPlayers(game, 3, "final_inventor_scoring_"); giveOptionalEffectToAllPlayers(players.get(0), players.get(1), players.get(2)); while (game.getCurrentState().getRound() < 10) { playOneFullRound(game); } assertEquals(10, game.getCurrentState().getRound()); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); completeSlotChoice(game); resolveAllMandatoryActions(game); assertEquals(GameStages.OPT_CARD_E, game.getCurrentState().getGameStage()); Player controlPlayer = players.get(0); Player testedPlayer = players.get(1); assertNotNull(controlPlayer); assertNotNull(testedPlayer); preparePlayerForComparableFinalScoring(controlPlayer); preparePlayerForComparableFinalScoring(testedPlayer); preparePlayerForComparableFinalScoring(players.get(2)); controlPlayer.builders.add(new Builder(1, 0, 0)); controlPlayer.builders.add(new Builder(1, 0, 0)); controlPlayer.builders.add(new Builder(1, 0, 0)); testedPlayer.inventors.add(new Inventor(1, 0)); testedPlayer.inventors.add(new Inventor(1, 1)); testedPlayer.inventors.add(new Inventor(1, 1)); int prestigeDifferenceBefore = testedPlayer.getPrestigeValue() - controlPlayer.getPrestigeValue(); int expectedExtraIncrease = 3 * 2; resolveOptionalPhaseIfPresent(game); assertEquals(GameStages.ENDED, game.getCurrentState().getGameStage()); int prestigeDifferenceAfter = testedPlayer.getPrestigeValue() - controlPlayer.getPrestigeValue(); assertEquals( expectedExtraIncrease, prestigeDifferenceAfter - prestigeDifferenceBefore, "Final scoring should add exactly inventors times different invention icons." ); } }