diff --git a/src/test/java/GameUIControllerTest.java b/src/test/java/GameUIControllerTest.java new file mode 100644 index 0000000..88774f2 --- /dev/null +++ b/src/test/java/GameUIControllerTest.java @@ -0,0 +1,157 @@ +import GUI.GameUIController; +import GUI.HitoriDialogManager; +import javafx.stage.Stage; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.testfx.framework.junit5.ApplicationExtension; +import org.testfx.framework.junit5.Start; + +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import java.util.Optional; + +@ExtendWith(ApplicationExtension.class) +class GameUIControllerTest { + private GameUIController controller; + private HitoriDialogManager dialogManager; + private Stage stage; + private static final int[][] TEST_BOARD = { + {1, 2, 1}, + {2, 1, 2}, + {1, 2, 1} + }; + + @Start + private void start(Stage stage) { + this.stage = stage; + } + + @BeforeEach + void setUp() { + dialogManager = mock(HitoriDialogManager.class); + controller = new GameUIController(TEST_BOARD, dialogManager); + } + + @Test + void testInitialization() { + assertNotNull(controller); + assertNotNull(controller.getBoardPanel()); + assertNotNull(controller.getControlPanel()); + assertNotNull(controller.getScorePanel()); + assertFalse(controller.isPaused()); + } + + @Test + void testHandleLeftClick() { + controller.handleLeftClick(0, 0); + // Verify the board was updated + assertTrue(controller.getBoardPanel().getChildren().size() > 0); + } + + @Test + void testHandleRightClick() { + controller.handleRightClick(0, 0); + // Verify the board was updated + assertTrue(controller.getBoardPanel().getChildren().size() > 0); + } + + @Test + void testTogglePause() { + assertFalse(controller.isPaused()); + controller.togglePause(); + assertTrue(controller.isPaused()); + controller.togglePause(); + assertFalse(controller.isPaused()); + } + + @Test + void testResetGame() { + // Make some moves first + controller.handleLeftClick(0, 0); + controller.handleRightClick(1, 1); + + controller.resetGame(); + // Verify the board is reset + var boardPanel = controller.getBoardPanel(); + assertEquals(9, boardPanel.getChildren().size()); // 3x3 board + } + + @Test + void testUndoRedo() { + controller.handleLeftClick(0, 0); + controller.undo(); + controller.redo(); + // Verify the board state + assertTrue(controller.getBoardPanel().getChildren().size() > 0); + } + + @Test + void testShowErrors() { + // Create some errors first + controller.handleLeftClick(0, 0); + controller.handleLeftClick(0, 1); + + controller.showErrors(); + verify(dialogManager, times(1)).showAlert(anyString(), anyString()); + } + + @Test + void testSaveGame() { + controller.saveGame(); + verify(dialogManager).showAlert(eq("Game Saved"), anyString()); + } + + @Test + void testDeleteHighScores() { + when(dialogManager.confirmDeleteHighScores()).thenReturn(true); + controller.deleteHighScores(); + verify(dialogManager).showAlert(eq("High Scores Deleted"), anyString()); + } + + @Test + void testHandleWin() { + // Setup mock responses + when(dialogManager.askForPlayerName()).thenReturn(Optional.of("TestPlayer")); + when(dialogManager.confirmNewGame()).thenReturn(false); + + // Make winning moves (this is simplified) + makeWinningMoves(); + + // Verify win handling + verify(dialogManager, times(1)).showAlert(eq("Congratulations!"), anyString()); + } + + @Test + void testConvertErrorsToSet() { + List errors = List.of( + new int[]{0, 0}, + new int[]{1, 1} + ); + var errorSet = controller.convertErrorsToSet(errors); + assertTrue(errorSet.contains("0,0")); + assertTrue(errorSet.contains("1,1")); + } + + @Test + void testCleanup() { + controller.cleanup(); + assertFalse(controller.isPaused()); + } + + // Helper method to simulate winning moves + private void makeWinningMoves() { + // This would need to be implemented according to your winning condition + // For test purposes, we'll just make some moves + controller.handleLeftClick(0, 2); + controller.handleRightClick(0, 0); + controller.handleRightClick(0, 1); + controller.handleRightClick(1, 0); + controller.handleRightClick(1, 1); + controller.handleRightClick(1, 2); + controller.handleRightClick(2, 0); + controller.handleRightClick(2, 1); + controller.handleLeftClick(2, 2); + } +} diff --git a/src/test/java/HitoriBoardPanelTest.java b/src/test/java/HitoriBoardPanelTest.java new file mode 100644 index 0000000..39124f8 --- /dev/null +++ b/src/test/java/HitoriBoardPanelTest.java @@ -0,0 +1,114 @@ +import domain.GameSolver; +import domain.HitoriGameMoves; +import GUI.GameUIController; +import GUI.HitoriBoardPanel; +import javafx.scene.control.Button; +import org.junit.jupiter.api.*; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import org.junit.jupiter.api.extension.ExtendWith; +import org.testfx.framework.junit5.ApplicationExtension; +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(ApplicationExtension.class) +class HitoriBoardPanelTest { + private HitoriBoardPanel boardPanel; + private HitoriGameMoves gameMoves; + private GameSolver gameSolver; + private GameUIController controller; + private static final int[][] TEST_BOARD = { + {1, 2, 1}, + {2, 1, 2}, + {1, 2, 1} + }; + + @BeforeEach + void setUp() { + gameMoves = new HitoriGameMoves(TEST_BOARD); + gameSolver = new GameSolver(TEST_BOARD); + controller = mock(GameUIController.class); + boardPanel = new HitoriBoardPanel(gameMoves, gameSolver, controller); + } + + @Test + void testInitialization() { + assertNotNull(boardPanel); + assertEquals(9, boardPanel.getChildren().size()); // 3x3 board = 9 buttons + } + + @Test + void testCellCreation() { + var children = boardPanel.getChildren(); + var firstButton = (Button) children.get(0); + assertEquals("1", firstButton.getText()); + } + + @Test + void testButtonStyling() { + var children = boardPanel.getChildren(); + var button = (Button) children.get(0); + assertEquals("-fx-background-color: lightgray; -fx-text-fill: black;", button.getStyle()); + } + + @Test + void testUpdateBoard() { + boardPanel.updateBoard(); + assertEquals(9, boardPanel.getChildren().size()); + } + + @Test + void testShowErrors() { + // Mark some cells as black to create errors + gameMoves.markCellAsBlack(0, 0); + gameMoves.markCellAsBlack(0, 1); + + boardPanel.showErrors(); + + // Verify that error cells are marked red + var children = boardPanel.getChildren(); + for (var child : children) { + Button button = (Button) child; + if (button.getStyle().contains("red")) { + assertTrue(true); + return; + } + } + } + + @Test + void testLeftClickHandling() { + when(controller.isPaused()).thenReturn(false); + var button = (Button) boardPanel.getChildren().get(0); + + MouseEvent event = mock(MouseEvent.class); + when(event.getButton()).thenReturn(MouseButton.PRIMARY); + button.fireEvent(event); + + verify(controller, times(0)).handleLeftClick(anyInt(), anyInt()); + } + + @Test + void testRightClickHandling() { + when(controller.isPaused()).thenReturn(false); + var button = (Button) boardPanel.getChildren().get(0); + + MouseEvent event = mock(MouseEvent.class); + when(event.getButton()).thenReturn(MouseButton.SECONDARY); + button.fireEvent(event); + + verify(controller, times(0)).handleRightClick(anyInt(), anyInt()); + } + + @Test + void testPausedState() { + when(controller.isPaused()).thenReturn(true); + var button = (Button) boardPanel.getChildren().get(0); + + MouseEvent event = mock(MouseEvent.class); + when(event.getButton()).thenReturn(MouseButton.PRIMARY); + button.fireEvent(event); + + verify(controller, never()).handleLeftClick(anyInt(), anyInt()); + } +} diff --git a/src/test/java/HitoriControlPanelTest.java b/src/test/java/HitoriControlPanelTest.java new file mode 100644 index 0000000..6b00818 --- /dev/null +++ b/src/test/java/HitoriControlPanelTest.java @@ -0,0 +1,126 @@ +import GUI.GameUIController; +import GUI.HitoriControlPanel; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.testfx.framework.junit5.ApplicationExtension; +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(ApplicationExtension.class) +class HitoriControlPanelTest { + private HitoriControlPanel controlPanel; + private GameUIController controller; + + @BeforeEach + void setUp() { + controller = mock(GameUIController.class); + controlPanel = new HitoriControlPanel(controller); + } + + @Test + void testInitialization() { + assertNotNull(controlPanel); + assertTrue(controlPanel.getChildren().size() > 0); + } + + @Test + void testUpdateTimerLabel() { + controlPanel.updateTimerLabel(42); + var timerLabel = findLabelByText(controlPanel, "Time: 42s"); + assertNotNull(timerLabel); + } + + @Test + void testUpdateMistakeLabel() { + controlPanel.updateMistakeLabel(5); + var mistakeLabel = findLabelByText(controlPanel, "Mistakes: 5"); + assertNotNull(mistakeLabel); + } + + @Test + void testSetPauseButtonText() { + controlPanel.setPauseButtonText("Test"); + var pauseButton = findButtonByText(controlPanel, "Test"); + assertNotNull(pauseButton); + } + + @Test + void testPauseButtonAction() { + var pauseButton = findButtonByText(controlPanel, "Pause"); + assertNotNull(pauseButton); + + pauseButton.fire(); + verify(controller, times(1)).togglePause(); + } + + @Test + void testResetButtonAction() { + var resetButton = findButtonByText(controlPanel, "Reset"); + assertNotNull(resetButton); + + resetButton.fire(); + verify(controller, times(1)).resetGame(); + } + + @Test + void testUndoButtonAction() { + var undoButton = findButtonByText(controlPanel, "Undo"); + assertNotNull(undoButton); + + undoButton.fire(); + verify(controller, times(1)).undo(); + } + + @Test + void testRedoButtonAction() { + var redoButton = findButtonByText(controlPanel, "Redo"); + assertNotNull(redoButton); + + redoButton.fire(); + verify(controller, times(1)).redo(); + } + + @Test + void testCheckSolutionButtonAction() { + var checkButton = findButtonByText(controlPanel, "Check Solution"); + assertNotNull(checkButton); + + checkButton.fire(); + verify(controller, times(1)).checkSolution(); + } + + @Test + void testNewGameButtonAction() { + var newGameButton = findButtonByText(controlPanel, "New Game"); + assertNotNull(newGameButton); + + newGameButton.fire(); + verify(controller, times(1)).newGame(); + } + + @Test + void testShowErrorsButtonAction() { + var showErrorsButton = findButtonByText(controlPanel, "Show Errors"); + assertNotNull(showErrorsButton); + + showErrorsButton.fire(); + verify(controller, times(1)).showErrors(); + } + + private Label findLabelByText(HitoriControlPanel panel, String text) { + return (Label) panel.getChildren().stream() + .filter(node -> node instanceof Label && ((Label) node).getText().equals(text)) + .findFirst() + .orElse(null); + } + + private Button findButtonByText(HitoriControlPanel panel, String text) { + return (Button) panel.getChildren().stream() + .flatMap(node -> node.lookupAll("Button").stream()) + .filter(node -> node instanceof Button && ((Button) node).getText().equals(text)) + .findFirst() + .orElse(null); + } +} diff --git a/src/test/java/HitoriDialogManagerTest.java b/src/test/java/HitoriDialogManagerTest.java new file mode 100644 index 0000000..9a28c3a --- /dev/null +++ b/src/test/java/HitoriDialogManagerTest.java @@ -0,0 +1,78 @@ +import domain.HitoriBoardLoader; +import GUI.HitoriDialogManager; +import javafx.stage.Stage; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.testfx.framework.junit5.ApplicationExtension; +import org.testfx.framework.junit5.Start; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(ApplicationExtension.class) +class HitoriDialogManagerTest { + private HitoriDialogManager dialogManager; + private Stage stage; + private HitoriBoardLoader boardLoader; + + @Start + private void start(Stage stage) { + this.stage = stage; + } + + @BeforeEach + void setUp() { + boardLoader = mock(HitoriBoardLoader.class); + dialogManager = new HitoriDialogManager(stage); + } + + @Test + void testShowAlert() { + // Cannot directly test Alert dialogs in headless mode + assertDoesNotThrow(() -> + dialogManager.showAlert("Test", "Test Message") + ); + } + + @Test + void testConfirmDeleteHighScores() { + // Cannot directly test confirmation dialogs in headless mode + assertDoesNotThrow(() -> + dialogManager.confirmDeleteHighScores() + ); + } + + @Test + void testConfirmNewGame() { + // Cannot directly test confirmation dialogs in headless mode + assertDoesNotThrow(() -> + dialogManager.confirmNewGame() + ); + } + + @Test + void testAskForPlayerName() { + // Cannot directly test input dialogs in headless mode + assertDoesNotThrow(() -> + dialogManager.askForPlayerName() + ); + } + + @Test + void testConfirmLoadSavedGame() { + // Cannot directly test confirmation dialogs in headless mode + assertDoesNotThrow(() -> + dialogManager.confirmLoadSavedGame() + ); + } + + @Test + void testShowBoardSelectionDialog() { + // Cannot directly test choice dialogs in headless mode + when(boardLoader.getAvailableBoardNames()) + .thenReturn(java.util.Arrays.asList("Board1", "Board2")); + + assertDoesNotThrow(() -> + dialogManager.showBoardSelectionDialog(boardLoader) + ); + } +} \ No newline at end of file diff --git a/src/test/java/HitoriGameScoresTest.java b/src/test/java/HitoriGameScoresTest.java new file mode 100644 index 0000000..0e27e9c --- /dev/null +++ b/src/test/java/HitoriGameScoresTest.java @@ -0,0 +1,116 @@ +import domain.HitoriGameScores; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; +import java.io.File; +import java.util.List; + + +class HitoriGameScoresTest { + private HitoriGameScores scores; + + @BeforeEach + void setUp() { + scores = new HitoriGameScores(); + new File("highscores.dat").delete(); // Ensure clean state + } + + @AfterEach + void tearDown() { + new File("highscores.dat").delete(); // Cleanup + } + + @Test + void testAddHighScore() { + scores.addHighScore("TestPlayer", 100, 2); + List highScores = scores.getHighScoresWithAverage(); + + assertFalse(highScores.isEmpty()); + assertTrue(highScores.get(0).contains("TestPlayer")); + assertTrue(highScores.get(0).contains("100s")); + assertTrue(highScores.get(0).contains("2")); + } + + @Test + void testMultipleHighScores() { + scores.addHighScore("Player1", 100, 1); + scores.addHighScore("Player2", 200, 2); + scores.addHighScore("Player3", 150, 3); + + List highScores = scores.getHighScoresWithAverage(); + assertEquals(4, highScores.size()); // 3 scores + average line + + // Should be sorted by time + assertTrue(highScores.get(0).contains("Player1")); + assertTrue(highScores.get(1).contains("Player3")); + assertTrue(highScores.get(2).contains("Player2")); + } + + @Test + void testDeleteHighScores() { + scores.addHighScore("Player1", 100, 1); + scores.addHighScore("Player2", 200, 2); + + scores.deleteHighScores(); + List highScores = scores.getHighScoresWithAverage(); + + assertEquals(1, highScores.size()); // Only average line remains + assertTrue(highScores.get(0).contains("Average Time: 0")); + } + + @Test + void testAverageCalculation() { + scores.addHighScore("Player1", 100, 1); + scores.addHighScore("Player2", 200, 2); + + List highScores = scores.getHighScoresWithAverage(); + String averageLine = highScores.get(highScores.size() - 1); + assertTrue(averageLine.contains("Average Time: 150.0")); + } + + @Test + void testSaveAndLoadHighScores() { + scores.addHighScore("Player1", 100, 1); + scores.addHighScore("Player2", 200, 2); + scores.saveHighScoresToFile(); + + HitoriGameScores newScores = new HitoriGameScores(); + newScores.loadHighScoresFromFile(); + List loadedScores = newScores.getHighScoresWithAverage(); + + assertFalse(loadedScores.isEmpty()); + assertTrue(loadedScores.get(0).contains("Player1")); + assertTrue(loadedScores.get(1).contains("Player2")); + } + + @Test + void testLoadWithNoFile() { + scores.loadHighScoresFromFile(); // No file exists + List highScores = scores.getHighScoresWithAverage(); + + assertEquals(1, highScores.size()); // Only average line + assertTrue(highScores.get(0).contains("Average Time: 0")); + } + + @Test + void testTop10Limit() { + // Add more than 10 scores + for (int i = 0; i < 15; i++) { + scores.addHighScore("Player" + i, 100 + i, i); + } + + List highScores = scores.getHighScoresWithAverage(); + assertEquals(11, highScores.size()); // 10 scores + average line + } + + @Test + void testScoreSorting() { + scores.addHighScore("Fast", 50, 0); + scores.addHighScore("Medium", 100, 1); + scores.addHighScore("Slow", 150, 2); + + List highScores = scores.getHighScoresWithAverage(); + assertTrue(highScores.get(0).contains("Fast")); + assertTrue(highScores.get(1).contains("Medium")); + assertTrue(highScores.get(2).contains("Slow")); + } +} diff --git a/src/test/java/HitoriGameSolverTest.java b/src/test/java/HitoriGameSolverTest.java new file mode 100644 index 0000000..15a0487 --- /dev/null +++ b/src/test/java/HitoriGameSolverTest.java @@ -0,0 +1,127 @@ +import domain.GameSolver; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; +import java.util.List; + +class HitoriGameSolverTest { + private GameSolver game; + private static final int[][] TEST_BOARD = { + {1, 2, 1}, + {2, 1, 2}, + {1, 2, 1} + }; + + @BeforeEach + void setUp() { + game = new GameSolver(TEST_BOARD); + } + + @Test + void testUnsolvedInitialState() { + assertFalse(game.isSolved()); + } + + @Test + void testSolvingPuzzle() { + // Apply known solution + game.markCellAsBlack(0, 2); + game.markCellAsWhite(0, 0); + game.markCellAsWhite(0, 1); + game.markCellAsWhite(1, 0); + game.markCellAsWhite(1, 1); + game.markCellAsWhite(1, 2); + game.markCellAsWhite(2, 0); + game.markCellAsWhite(2, 1); + game.markCellAsBlack(2, 2); + + assertTrue(game.isSolved()); + } + + @Test + void testIncorrectSolution() { + // Mark all cells white + for (int i = 0; i < TEST_BOARD.length; i++) { + for (int j = 0; j < TEST_BOARD[0].length; j++) { + game.markCellAsWhite(i, j); + } + } + + // Should not be solved due to duplicate numbers + assertFalse(game.isSolved()); + } + + @Test + void testDisconnectedWhiteCells() { + // Create a solution with disconnected white cells + game.markCellAsWhite(0, 0); + game.markCellAsBlack(0, 1); + game.markCellAsBlack(1, 0); + game.markCellAsBlack(1, 1); + game.markCellAsWhite(2, 2); + + // Should not be solved due to disconnected white cells + assertFalse(game.isSolved()); + } + + @Test + void testFindIncorrectBlackMarks() { + // Create adjacent black cells + game.markCellAsBlack(0, 0); + game.markCellAsBlack(0, 1); // This creates an invalid situation + + List errors = game.findIncorrectBlackMarks(); + assertFalse(errors.isEmpty()); + assertEquals(2, errors.size()); // Both cells should be reported + + // Verify error coordinates + boolean foundFirst = false; + boolean foundSecond = false; + for (int[] error : errors) { + if (error[0] == 0 && error[1] == 0) foundFirst = true; + if (error[0] == 0 && error[1] == 1) foundSecond = true; + } + assertTrue(foundFirst && foundSecond); + } + + @Test + void testNoIncorrectBlackMarks() { + // Make valid black marks + game.markCellAsBlack(0, 0); + game.markCellAsBlack(2, 2); + + List errors = game.findIncorrectBlackMarks(); + assertTrue(errors.isEmpty()); + } + + @Test + void testUnmarkedCellsNotSolved() { + // Leave some cells unmarked + game.markCellAsWhite(0, 0); + game.markCellAsBlack(0, 1); + // Don't mark other cells + + assertFalse(game.isSolved()); + } + + @Test + void testDuplicateNumbersInRows() { + // Mark cells to create duplicate numbers in a row + game.markCellAsWhite(0, 0); + game.markCellAsWhite(0, 1); + game.markCellAsWhite(0, 2); + // Row now has duplicate numbers + + assertFalse(game.isSolved()); + } + + @Test + void testDuplicateNumbersInColumns() { + // Mark cells to create duplicate numbers in a column + game.markCellAsWhite(0, 0); + game.markCellAsWhite(1, 0); + game.markCellAsWhite(2, 0); + // Column now has duplicate numbers + + assertFalse(game.isSolved()); + } +} diff --git a/src/test/java/HitoriGameTest.java b/src/test/java/HitoriGameTest.java new file mode 100644 index 0000000..d25c7ad --- /dev/null +++ b/src/test/java/HitoriGameTest.java @@ -0,0 +1,151 @@ +import domain.HitoriGameMain; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; +import java.io.File; + +class HitoriGameTest { + private HitoriGameMain game; + private static final int[][] TEST_BOARD = { + {1, 2, 1}, + {2, 1, 2}, + {1, 2, 1} + }; + + @BeforeEach + void setUp() { + game = new HitoriGameMain(TEST_BOARD); + new File("gamestate.dat").delete(); + new File("highscores.dat").delete(); + } + + @AfterEach + void tearDown() { + new File("gamestate.dat").delete(); + new File("highscores.dat").delete(); + } + + @Test + void testGameIntegration() { + // Test timer functionality + game.startTimer(); + try { + Thread.sleep(1100); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + assertTrue(game.getElapsedTimeInSeconds() >= 1); + + // Test game moves + game.markCellAsBlack(0, 2); + assertTrue(game.getBlackCells()[0][2]); + + // Test scoring + game.addHighScore("TestPlayer", 100); + assertFalse(game.getHighScoresWithAverage().isEmpty()); + } + + @Test + void testSaveAndLoadGameState() { + // Make some moves + game.markCellAsWhite(0, 0); + game.markCellAsBlack(1, 1); + game.startTimer(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + // Save game state + game.saveGameState(); + + // Load game state + HitoriGameMain loadedGame = HitoriGameMain.loadGameState(); + assertNotNull(loadedGame); + assertTrue(loadedGame.getWhiteCells()[0][0]); + assertTrue(loadedGame.getBlackCells()[1][1]); + assertTrue(loadedGame.getElapsedTimeInSeconds() > 0); + } + + @Test + void testResetAll() { + // Setup some game state + game.markCellAsBlack(0, 0); + game.startTimer(); + game.addHighScore("TestPlayer", 100); + + // Reset everything + game.reset(); + + // Verify reset + assertFalse(game.getBlackCells()[0][0]); + assertEquals(0, game.getElapsedTimeInSeconds()); + assertEquals(0, game.getMistakeCount()); + } + + @Test + void testCompleteGameFlow() { + // Start game + game.startTimer(); + + // Make some moves towards solution + game.markCellAsBlack(0, 2); + game.markCellAsWhite(0, 0); + game.markCellAsWhite(0, 1); + game.markCellAsWhite(1, 0); + game.markCellAsWhite(1, 1); + game.markCellAsWhite(1, 2); + game.markCellAsWhite(2, 0); + game.markCellAsWhite(2, 1); + game.markCellAsBlack(2, 2); + + // Verify solution + assertTrue(game.isSolved()); + + // Add score + game.stopTimer(); + game.addHighScore("Winner", game.getElapsedTimeInSeconds()); + + // Verify score was recorded + boolean found = false; + for (String score : game.getHighScoresWithAverage()) { + if (score.contains("Winner")) { + found = true; + break; + } + } + assertTrue(found); + } + + @Test + void testTimerPauseResume() { + game.startTimer(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + game.pauseTimer(); + long pausedTime = game.getElapsedTimeInSeconds(); + + try { + Thread.sleep(500); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + // Time should not increase while paused + assertEquals(pausedTime, game.getElapsedTimeInSeconds()); + + game.startTimer(); // Resume + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + // Time should increase after resume + assertTrue(game.getElapsedTimeInSeconds() > pausedTime); + } +} diff --git a/src/test/java/HitoriGameTimerTest.java b/src/test/java/HitoriGameTimerTest.java new file mode 100644 index 0000000..6463f83 --- /dev/null +++ b/src/test/java/HitoriGameTimerTest.java @@ -0,0 +1,131 @@ +import domain.HitoriGameTimer; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +class HitoriGameTimerTest { + private HitoriGameTimer timer; + + @BeforeEach + void setUp() { + timer = new HitoriGameTimer(); + } + + @Test + void testInitialState() { + assertEquals(0, timer.getElapsedTimeInSeconds()); + assertFalse(timer.isPaused()); + } + + @Test + void testStartTimer() { + timer.startTimer(); + try { + Thread.sleep(1100); // Wait a bit more than 1 second + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + assertTrue(timer.getElapsedTimeInSeconds() >= 1); + assertFalse(timer.isPaused()); + } + + @Test + void testPauseTimer() { + timer.startTimer(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + timer.pauseTimer(); + long pausedTime = timer.getElapsedTimeInSeconds(); + assertTrue(timer.isPaused()); + + try { + Thread.sleep(500); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + // Time should not have increased while paused + assertEquals(pausedTime, timer.getElapsedTimeInSeconds()); + } + + @Test + void testResumeTimer() { + timer.startTimer(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + timer.pauseTimer(); + long pausedTime = timer.getElapsedTimeInSeconds(); + + timer.startTimer(); // Resume + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + assertTrue(timer.getElapsedTimeInSeconds() > pausedTime); + } + + @Test + void testStopTimer() { + timer.startTimer(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + timer.stopTimer(); + long stoppedTime = timer.getElapsedTimeInSeconds(); + + try { + Thread.sleep(500); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + assertEquals(stoppedTime, timer.getElapsedTimeInSeconds()); + } + + @Test + void testResetTimer() { + timer.startTimer(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + timer.resetTimer(); + assertEquals(0, timer.getElapsedTimeInSeconds()); + assertFalse(timer.isPaused()); + } + + @Test + void testMultiplePauseResume() { + timer.startTimer(); + try { + Thread.sleep(500); + timer.pauseTimer(); + Thread.sleep(500); + timer.startTimer(); + Thread.sleep(500); + timer.pauseTimer(); + Thread.sleep(500); + timer.startTimer(); + Thread.sleep(500); + } catch (InterruptedException e) { + fail("Timer test interrupted"); + } + + assertTrue(timer.getElapsedTimeInSeconds() >= 1); + } +} diff --git a/src/test/java/HitoriScorePanelTest.java b/src/test/java/HitoriScorePanelTest.java new file mode 100644 index 0000000..4504e85 --- /dev/null +++ b/src/test/java/HitoriScorePanelTest.java @@ -0,0 +1,77 @@ +import GUI.GameUIController; +import GUI.HitoriScorePanel; +import javafx.scene.control.Button; +import javafx.scene.control.TextArea; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.testfx.framework.junit5.ApplicationExtension; +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(ApplicationExtension.class) +class HitoriScorePanelTest { + private HitoriScorePanel scorePanel; + private GameUIController controller; + + @BeforeEach + void setUp() { + controller = mock(GameUIController.class); + scorePanel = new HitoriScorePanel(controller); + } + + @Test + void testInitialization() { + assertNotNull(scorePanel); + assertTrue(scorePanel.getChildren().size() > 0); + } + + @Test + void testUpdateHighScores() { + String testScores = "Player1: 100\nPlayer2: 200"; + scorePanel.updateHighScores(testScores); + + TextArea highScoreArea = findTextArea(scorePanel); + assertNotNull(highScoreArea); + assertEquals(testScores, highScoreArea.getText()); + } + + @Test + void testSaveButtonAction() { + var saveButton = findButtonByText(scorePanel, "Save Game"); + assertNotNull(saveButton); + + saveButton.fire(); + verify(controller, times(1)).saveGame(); + } + + @Test + void testDeleteHighScoresButtonAction() { + var deleteButton = findButtonByText(scorePanel, "Delete High Scores"); + assertNotNull(deleteButton); + + deleteButton.fire(); + verify(controller, times(1)).deleteHighScores(); + } + + @Test + void testHighScoreAreaNotEditable() { + TextArea highScoreArea = findTextArea(scorePanel); + assertNotNull(highScoreArea); + assertFalse(highScoreArea.isEditable()); + } + + private TextArea findTextArea(HitoriScorePanel panel) { + return (TextArea) panel.getChildren().stream() + .filter(node -> node instanceof TextArea) + .findFirst() + .orElse(null); + } + + private Button findButtonByText(HitoriScorePanel panel, String text) { + return (Button) panel.getChildren().stream() + .filter(node -> node instanceof Button && ((Button) node).getText().equals(text)) + .findFirst() + .orElse(null); + } +} +