package it.polimi.ingsw.gc14.Model; import it.polimi.ingsw.gc14.Model.Cards.Building.EffectType; 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 org.junit.jupiter.api.Test; import java.util.*; import static org.junit.jupiter.api.Assertions.*; class GameTest { private Queue completeSlotChoice(Game game) { 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)); } assertEquals(GameStages.RESOLVING_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, 0)); } } private void resolveAllMandatoryActions(Game game) { int guard = 0; while (game.getCurrentState().getGameStage() == GameStages.RESOLVING_ACTIONS && guard < 50) { guard++; resolveOneMandatoryAction(game); } assertTrue(guard < 50, "Possible infinite loop while resolving mandatory actions."); } 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)); } else if (!game.getLowerListBuilding().isEmpty()) { current.addFood(100); assertTrue(game.DrawLowerBuildingCardByIndex(current, 0)); } else { fail("No valid lower card available."); } } else if (game.getCurrentState().getNUpper() > 0) { int index = firstNonEventIndexOrMinusOne(game.getUpperListTribeCards()); if (index != -1) { assertTrue(game.DrawUpperTribeCardByIndex(current, index)); } else if (!game.getUpperListBuilding().isEmpty()) { current.addFood(100); assertTrue(game.DrawUpperBuildingCardByIndex(current, 0)); } else { fail("No valid upper card available."); } } else { fail("Current player has no remaining draws."); } } private void resolveActionsUntilOptionalCardEffect(Game game) { int guard = 0; while (game.getCurrentState().getGameStage() == GameStages.RESOLVING_ACTIONS && guard < 50) { guard++; resolveOneMandatoryAction(game); } assertTrue(guard < 50, "Possible infinite loop while resolving mandatory actions."); assertEquals(GameStages.OPTIONAL_CARD_EFFECT, game.getCurrentState().getGameStage()); } private void setCurrentStateEra(Game game, int era) { try { java.lang.reflect.Field field = game.getCurrentState().getClass().getDeclaredField("Era"); field.setAccessible(true); field.set(game.getCurrentState(), era); } catch (Exception e) { fail("Failed to set CurrentState era: " + e.getMessage()); } } private static class FinalTestBuildingCard extends BuildingCard { FinalTestBuildingCard() { super(12, 1, 1, 0); } @Override public EffectType getEffectType() { return EffectType.FINAL; } @Override public void applyEffect(Player player) { player.addPrestige(10); } } private int slotIndexById(Game game, char slotId) { it.polimi.ingsw.gc14.Model.GamePackage.Board board = getBoard(game); List slots = board.getSlotList(); for (int i = 0; i < slots.size(); i++) { if (slots.get(i).getSlotId() == slotId) { return i; } } fail("No slot found with id: " + slotId); return -1; } private Player completeSlotChoiceAndAdvanceToPlayerOnSlot(Game game, char slotId) { Player targetPlayer = game.getCurrentState().getCurrentPlayer(); int targetSlotIndex = slotIndexById(game, slotId); assertTrue(game.SlotChoiceByIndex(targetPlayer, targetSlotIndex)); Set usedSlots = new HashSet<>(); usedSlots.add(targetSlotIndex); int nextSlotIndex = 0; while (game.getCurrentState().getGameStage() == GameStages.SLOT_CHOICE) { while (usedSlots.contains(nextSlotIndex)) { nextSlotIndex++; } Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertTrue(game.SlotChoiceByIndex(current, nextSlotIndex)); usedSlots.add(nextSlotIndex); } assertEquals(GameStages.RESOLVING_ACTIONS, game.getCurrentState().getGameStage()); int guard = 0; while (game.getCurrentState().getGameStage() == GameStages.RESOLVING_ACTIONS && !targetPlayer.equals(game.getCurrentState().getCurrentPlayer()) && guard < 20) { guard++; resolveOneMandatoryAction(game); } assertTrue(guard < 20, "Possible infinite loop while reaching target player's slot."); assertEquals(targetPlayer, game.getCurrentState().getCurrentPlayer()); return targetPlayer; } private void resolveOptionalPhaseIfPresent(Game game) { int guard = 0; while (game.getCurrentState().getGameStage() == GameStages.OPTIONAL_CARD_EFFECT && guard < 10) { guard++; Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertTrue(game.NoOptionalCard(current)); } assertTrue(guard < 10, "Possible infinite loop during optional phase."); } private void playOneFullRound(Game game) { assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); completeSlotChoice(game); assertEquals(GameStages.RESOLVING_ACTIONS, game.getCurrentState().getGameStage()); resolveAllMandatoryActions(game); resolveOptionalPhaseIfPresent(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 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 addPlayerShouldRejectDuplicatesAndStartSlotChoiceWhenFull() { 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.SLOT_CHOICE, game.getCurrentState().getGameStage()); assertFalse(game.addPlayer(p4)); } @Test void slotChoiceByIndexShouldRejectInvalidWrongAndOccupiedSlot() { 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(); 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)); Queue players = new LinkedList<>(); for (int i = 0; i < 3; 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)); } temp_player.addFood(100); assertFalse(game.getUpperListBuilding().isEmpty()); index = 0; 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.RESOLVING_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.addFood(100); int foodBefore = current.getFoodValue(); int buildingsBefore = current.buildingCards.size(); assertTrue(game.PickOptionalBuildingCard(current, 0)); assertTrue(current.getFoodValue() < foodBefore); assertEquals(buildingsBefore + 1, current.buildingCards.size()); } @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.OPTIONAL_CARD_EFFECT, 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)); } return players; } private int firstEventIndexOrMinusOne(List cards) { for (int i = 0; i < cards.size(); i++) { if (cards.get(i).IsEventCard()) { return i; } } return -1; } private it.polimi.ingsw.gc14.Model.GamePackage.Board getBoard(Game game) { try { java.lang.reflect.Field field = Game.class.getDeclaredField("board"); field.setAccessible(true); return (it.polimi.ingsw.gc14.Model.GamePackage.Board) field.get(game); } catch (Exception e) { fail("Failed to access board field: " + e.getMessage()); return null; } } private void invokePrivateMethod(Game game, String methodName) { try { java.lang.reflect.Method method = Game.class.getDeclaredMethod(methodName); method.setAccessible(true); method.invoke(game); } catch (Exception e) { fail("Failed to invoke private method " + methodName + ": " + e.getMessage()); } } @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 drawMethodsShouldRejectWrongStateInvalidIndexesAndWrongPlayer() { 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(); assertNotNull(current); assertFalse(game.DrawLowerTribeCardByIndex(current, 0)); assertFalse(game.DrawUpperTribeCardByIndex(current, 0)); assertFalse(game.DrawUpperBuildingCardByIndex(current, 0)); assertFalse(game.DrawLowerBuildingCardByIndex(current, 0)); 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 drawLowerBuildingCardShouldWorkWhenLowerBuildingExists() { Game game = new Game(3); addPlayers(game, 3, "lower_building_"); Player current = completeSlotChoiceAndAdvanceToPlayerOnSlot(game, 'D'); assertNotNull(current); it.polimi.ingsw.gc14.Model.GamePackage.Board board = getBoard(game); assertNotNull(board); board.lowerListBuilding.clear(); board.lowerListBuilding.add(new BuildingCard(12, 1, 1, 0)); current.addFood(100); int foodBefore = current.getFoodValue(); int buildingsBefore = current.buildingCards.size(); assertTrue(game.DrawLowerBuildingCardByIndex(current, 0)); assertTrue(current.getFoodValue() < foodBefore); assertEquals(buildingsBefore + 1, current.buildingCards.size()); assertEquals(1, game.getCurrentState().getNLower()); } @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 void pickOptionalBuildingCardShouldReturnFalseIfPlayerCannotPay() { Game game = new Game(3); List players = addPlayers(game, 3, "optional_no_food_"); giveOptionalEffectToAllPlayers(players.get(0), players.get(1), players.get(2)); completeSlotChoice(game); resolveActionsUntilOptionalCardEffect(game); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); if (!game.getUpperListBuilding().isEmpty()) { assertFalse(game.PickOptionalBuildingCard(current, 0)); } } @Test void eventResolutionShouldDoNothingOutsideResolvingEventStage() { Game game = new Game(3); assertEquals(GameStages.WAITING, game.getCurrentState().getGameStage()); invokePrivateMethod(game, "EventResolution"); assertEquals(GameStages.WAITING, game.getCurrentState().getGameStage()); } @Test void nextRoundShouldIncreaseRound() { Game game = new Game(3); int roundBefore = game.getCurrentState().getRound(); invokePrivateMethod(game, "nextRound"); assertEquals(roundBefore + 1, game.getCurrentState().getRound()); } @Test void addObserverAndNotifyObserversShouldCallObserver() { Game game = new Game(3); final boolean[] notified = {false}; game.addObserver(updatedGame -> { assertSame(game, updatedGame); notified[0] = true; }); invokePrivateMethod(game, "notifyObservers"); assertTrue(notified[0]); } @Test void drawLowerTribeCardShouldReturnFalseWhenNoLowerDrawsAreAvailable() { Game game = new Game(3); addPlayers(game, 3, "no_lower_"); Player current = completeSlotChoiceAndAdvanceToPlayerOnSlot(game, 'C'); assertNotNull(current); int index = firstNonEventIndex(game.getLowerListTribeCards()); assertEquals(0, game.getCurrentState().getNLower()); assertFalse(game.DrawLowerTribeCardByIndex(current, index)); } @Test void drawLowerTribeCardShouldReturnFalseForEventCard() { Game game = new Game(3); addPlayers(game, 3, "lower_event_"); Player current = completeSlotChoiceAndAdvanceToPlayerOnSlot(game, 'B'); assertNotNull(current); it.polimi.ingsw.gc14.Model.GamePackage.Board board = getBoard(game); assertNotNull(board); board.lowerListTribe.add(0, new it.polimi.ingsw.gc14.Model.Cards.TribeCards.Events.Sustenance(1, 3)); assertTrue(board.lowerListTribe.get(0).IsEventCard()); assertFalse(game.DrawLowerTribeCardByIndex(current, 0)); } @Test void drawUpperBuildingCardShouldReturnFalseWhenNoUpperDrawsAreAvailable() { Game game = new Game(3); addPlayers(game, 3, "no_upper_building_"); Player current = completeSlotChoiceAndAdvanceToPlayerOnSlot(game, 'B'); assertNotNull(current); it.polimi.ingsw.gc14.Model.GamePackage.Board board = getBoard(game); assertNotNull(board); board.upperListBuilding.clear(); board.upperListBuilding.add(new BuildingCard(12, 1, 1, 0)); current.addFood(100); assertEquals(0, game.getCurrentState().getNUpper()); assertFalse(game.DrawUpperBuildingCardByIndex(current, 0)); } @Test void drawUpperBuildingCardShouldBuyBuildingAndDecreaseUpperDraws() { Game game = new Game(3); addPlayers(game, 3, "upper_buy_true_"); Player current = completeSlotChoiceAndAdvanceToPlayerOnSlot(game, 'F'); assertNotNull(current); it.polimi.ingsw.gc14.Model.GamePackage.Board board = getBoard(game); assertNotNull(board); board.upperListBuilding.clear(); board.upperListBuilding.add(new BuildingCard(12, 1, 1, 0)); current.addFood(100); int foodBefore = current.getFoodValue(); int buildingsBefore = current.buildingCards.size(); assertTrue(game.DrawUpperBuildingCardByIndex(current, 0)); assertTrue(current.getFoodValue() < foodBefore); assertEquals(buildingsBefore + 1, current.buildingCards.size()); assertEquals(1, game.getCurrentState().getNUpper()); } @Test void nextRoundShouldUpdateEraWhenBoardEraDiffersFromCurrentStateEra() { Game game = new Game(3); setCurrentStateEra(game, 0); assertEquals(0, game.getCurrentState().getEra()); invokePrivateMethod(game, "nextRound"); assertEquals(1, game.getCurrentState().getEra()); } @Test void endGameShouldApplyFinalBuildingEffectsAndSetEndedStage() { Game game = new Game(3); Player player = new Player("final_player"); Player p2 = new Player("p2"); Player p3 = new Player("p3"); assertTrue(game.addPlayer(player)); assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); player.buildingCards.add(new FinalTestBuildingCard()); int prestigeBefore = player.getPrestigeValue(); invokePrivateMethod(game, "endGame"); assertEquals(prestigeBefore + 10, player.getPrestigeValue()); assertEquals(GameStages.ENDED, game.getCurrentState().getGameStage()); } @Test void shouldNotCrashWhenNoPlayerHasOptionalEffect() { Game game = new Game(3); addPlayers(game, 3, "no_optional_"); completeSlotChoice(game); assertDoesNotThrow(() -> resolveAllMandatoryActions(game)); assertNotEquals(GameStages.OPTIONAL_CARD_EFFECT, 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.SLOT_CHOICE, game.getCurrentState().getGameStage()); Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); assertTrue(game.SlotChoiceByIndex(current, 0)); } @Test void fullGameShouldEndAfterTenRoundsForTwoThreeAndFourPlayersUsingOnlyPublicGameFlow() { for (int nPlayers : new int[]{2, 3, 4}) { Game game = new Game(nPlayers); for (int i = 1; i <= nPlayers; i++) { assertTrue(game.addPlayer(new Player("p" + nPlayers + "_" + i))); } assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); assertEquals(1, game.getCurrentState().getRound()); assertNotNull(game.getCurrentState().getCurrentPlayer()); int guard = 0; while (game.getCurrentState().getGameStage() != GameStages.ENDED && guard < 15) { guard++; int roundBefore = game.getCurrentState().getRound(); playOneFullRound(game); if (roundBefore < 10) { assertEquals( GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage(), "After a non-final round, the game must return to SLOT_CHOICE." ); assertEquals( roundBefore + 1, game.getCurrentState().getRound(), "The round number must increase by one after each completed round." ); assertNotNull( game.getCurrentState().getCurrentPlayer(), "At the beginning of the next round there must be a current player." ); } else { assertEquals( GameStages.ENDED, game.getCurrentState().getGameStage(), "After round 10, the game must end." ); assertEquals( 10, game.getCurrentState().getRound(), "The game must end at round 10." ); } } assertTrue( guard < 15, "Possible infinite loop while playing the full game with " + nPlayers + " players." ); assertEquals( GameStages.ENDED, game.getCurrentState().getGameStage(), "The game must end after round 10 with " + nPlayers + " players." ); assertEquals( 10, game.getCurrentState().getRound(), "The game must end at round 10 with " + nPlayers + " players." ); } } @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 void roundShouldAdvanceAfterOnlyOptionalPlayerSkipsOptionalCard() { Game game = new Game(3); List players = addPlayers(game, 3, "single_optional_"); players.get(0).buildingCards.add(new BuildingCard(12, 1, 1, 0)); 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 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 fourPlayerGameShouldAllowPlayingSlotG() { Game game = new Game(4); addPlayers(game, 4, "slot_g_"); Player playerOnG = completeSlotChoiceAndAdvanceToPlayerOnSlot(game, 'G'); assertNotNull(playerOnG); assertEquals(GameStages.RESOLVING_ACTIONS, game.getCurrentState().getGameStage()); assertEquals(playerOnG, game.getCurrentState().getCurrentPlayer()); assertEquals('G', game.getCurrentState().getSlot().getSlotId()); assertEquals(1, game.getCurrentState().getNLower()); assertEquals(2, game.getCurrentState().getNUpper()); resolveOneMandatoryAction(game); assertEquals(0, game.getCurrentState().getNLower()); assertEquals(2, game.getCurrentState().getNUpper()); resolveOneMandatoryAction(game); assertEquals(0, game.getCurrentState().getNLower()); assertEquals(1, game.getCurrentState().getNUpper()); resolveOneMandatoryAction(game); assertFalse( game.getCurrentState().getGameStage() == GameStages.RESOLVING_ACTIONS && playerOnG.equals(game.getCurrentState().getCurrentPlayer()) && game.getCurrentState().getSlot().getSlotId() == 'G', "After resolving all actions of slot G, the game must not still be resolving slot G for the same player." ); } }