diff --git a/pom.xml b/pom.xml
index a9d5cb8..fcdf0a2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,6 +21,31 @@
5.8.1
test
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.9.3
+ test
+
+
+
+ org.powermock
+ powermock-module-junit4
+ 2.0.9
+ test
+
+
+ org.powermock
+ powermock-api-mockito2
+ 2.0.9
+ test
+
+
+ org.powermock
+ powermock-module-junit4-rule
+ 2.0.9
+ test
+
org.apache.maven.plugins
@@ -28,6 +53,14 @@
3.6.0
+
+ org.mockito
+ mockito-core
+ 5.15.2
+ test
+
+
+
diff --git a/src/main/java/de/deversmann/facade/Facade.java b/src/main/java/de/deversmann/facade/Facade.java
index 2fc2428..0c95a1a 100644
--- a/src/main/java/de/deversmann/facade/Facade.java
+++ b/src/main/java/de/deversmann/facade/Facade.java
@@ -78,10 +78,6 @@ public class Facade {
return highscoreManager.getAverageTime(currentPuzzleName);
}
- public String getCurrentPuzzleName() {
- return currentPuzzleName;
- }
-
public void saveCurrentPuzzleHighscoreToFile() throws IOException {
if (currentPuzzleName == null) return;
String base = currentPuzzleName.replaceAll(".*/", "");
diff --git a/src/main/java/de/deversmann/gui/GameView.java b/src/main/java/de/deversmann/gui/GameView.java
index 66a14cd..34f38df 100644
--- a/src/main/java/de/deversmann/gui/GameView.java
+++ b/src/main/java/de/deversmann/gui/GameView.java
@@ -13,16 +13,16 @@ import java.util.Set;
public class GameView extends JFrame {
private final Facade facade;
- private SpielfeldGUI spielfeldGUI;
+ SpielfeldGUI spielfeldGUI;
- private JComboBox cbSpielfelder;
- private JButton btnLoad;
- private JButton btnRandom;
- private JButton btnCheckSolution;
- private JButton btnShowSolution;
- private JButton btnReset;
- private JLabel timeLabel;
- private Timer timer;
+ JComboBox cbSpielfelder;
+ JButton btnLoad;
+ JButton btnRandom;
+ JButton btnCheckSolution;
+ JButton btnShowSolution;
+ JButton btnReset;
+ JLabel timeLabel;
+ Timer timer;
private final String[] spielfelder = {
"4x4.csv",
@@ -98,7 +98,7 @@ public class GameView extends JFrame {
timer.start();
}
- private void ladeSpielfeld(String pfad) {
+ void ladeSpielfeld(String pfad) {
try {
facade.ladeSpielfeld(pfad);
facade.loadCurrentPuzzleHighscoreFromFile();
@@ -117,7 +117,7 @@ public class GameView extends JFrame {
}
}
- private void checkSolution() {
+ void checkSolution() {
var blackCells = spielfeldGUI.getBlackCells();
var solutionCoordinates = facade.getLoesungsKoordinaten();
if (solutionCoordinates == null) {
@@ -201,7 +201,7 @@ public class GameView extends JFrame {
JOptionPane.showMessageDialog(this, sb.toString(), "Ergebnis", JOptionPane.INFORMATION_MESSAGE);
}
- private boolean containsCell(List blackCells, String sol) {
+ boolean containsCell(List blackCells, String sol) {
String[] parts = sol.split(",");
int rr = Integer.parseInt(parts[0]);
int cc = Integer.parseInt(parts[1]);
@@ -213,7 +213,7 @@ public class GameView extends JFrame {
return false;
}
- private void showSolution() {
+ void showSolution() {
var feld = facade.getAktuellesPuzzle();
if (feld == null) return;
spielfeldGUI.updateGrid(feld);
@@ -227,7 +227,7 @@ public class GameView extends JFrame {
spielfeldGUI.setAllNonBlackToWhite();
}
- private void resetField() {
+ void resetField() {
var feld = facade.getAktuellesPuzzle();
if (feld != null) {
spielfeldGUI.updateGrid(feld);
diff --git a/src/test/java/de/deversmann/domain/CSVReaderTest.java b/src/test/java/de/deversmann/domain/CSVReaderTest.java
new file mode 100644
index 0000000..99b2e82
--- /dev/null
+++ b/src/test/java/de/deversmann/domain/CSVReaderTest.java
@@ -0,0 +1,80 @@
+package de.deversmann.domain;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class CSVReaderTest {
+
+ @Test
+ void testReadPuzzleWithSolutionRealData() throws IOException {
+ String csvContent = """
+ 4,5,6,7
+ 8,9,10,11
+ 12,13,14,15
+ 16,17,18,19
+ //Lösung
+ 2,2
+ 3,3
+ """;
+ Path tempFile = Files.createTempFile("realPuzzle", ".csv");
+ Files.writeString(tempFile, csvContent);
+
+ CSVReader reader = new CSVReader();
+ PuzzleData data = reader.readPuzzleWithSolution(tempFile.toString());
+
+ int[][] expectedPuzzle = {
+ {4, 5, 6, 7},
+ {8, 9, 10, 11},
+ {12, 13, 14, 15},
+ {16, 17, 18, 19}
+ };
+ assertArrayEquals(expectedPuzzle, data.getPuzzle());
+ assertEquals(2, data.getSolutionCoordinates().size());
+ assertArrayEquals(new int[]{2, 2}, data.getSolutionCoordinates().get(0));
+ assertArrayEquals(new int[]{3, 3}, data.getSolutionCoordinates().get(1));
+
+ Files.delete(tempFile);
+ }
+
+ @Test
+ void testReadPuzzleWithInvalidData() throws IOException {
+ String csvContent = """
+ 1,2,3
+ 4,5
+ //Lösung
+ a,b
+ """;
+ Path tempFile = Files.createTempFile("invalidPuzzle", ".csv");
+ Files.writeString(tempFile, csvContent);
+
+ CSVReader reader = new CSVReader();
+
+ assertThrows(NumberFormatException.class, () -> reader.readPuzzleWithSolution(tempFile.toString()));
+
+ Files.delete(tempFile);
+ }
+
+ @Test
+ void testReadPuzzleWithoutSolution() throws IOException {
+ String csvContent = """
+ 1,2,3
+ 4,5,6
+ 7,8,9
+ """;
+ Path tempFile = Files.createTempFile("noSolutionPuzzle", ".csv");
+ Files.writeString(tempFile, csvContent);
+
+ CSVReader reader = new CSVReader();
+ PuzzleData data = reader.readPuzzleWithSolution(tempFile.toString());
+
+ assertNotNull(data.getPuzzle());
+ assertTrue(data.getSolutionCoordinates().isEmpty());
+
+ Files.delete(tempFile);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/deversmann/domain/HighscoreManagerTest.java b/src/test/java/de/deversmann/domain/HighscoreManagerTest.java
new file mode 100644
index 0000000..aa9a371
--- /dev/null
+++ b/src/test/java/de/deversmann/domain/HighscoreManagerTest.java
@@ -0,0 +1,63 @@
+package de.deversmann.domain;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class HighscoreManagerTest {
+
+ @Test
+ void testAddAndRetrieveHighscores() {
+ HighscoreManager manager = new HighscoreManager();
+ manager.addHighscore("Puzzle1", "Alice", 120, 2);
+
+ List highscores = manager.getHighscores("Puzzle1");
+
+ assertEquals(1, highscores.size());
+ assertEquals("Alice", highscores.get(0).getPlayerName());
+ assertEquals(120, highscores.get(0).getTimeSeconds());
+ assertEquals(2, highscores.get(0).getErrorCount());
+ }
+
+ @Test
+ void testSaveAndLoadHighscores() throws IOException {
+ HighscoreManager manager = new HighscoreManager();
+ manager.addHighscore("Puzzle1", "Alice", 120, 2);
+
+ Path tempFile = Files.createTempFile("testHighscores", ".txt");
+ manager.saveSinglePuzzle("Puzzle1", tempFile.toString());
+
+ HighscoreManager newManager = new HighscoreManager();
+ newManager.loadSinglePuzzle("Puzzle1", tempFile.toString());
+
+ List highscores = newManager.getHighscores("Puzzle1");
+
+ assertEquals(1, highscores.size());
+ assertEquals("Alice", highscores.get(0).getPlayerName());
+ assertEquals(120, highscores.get(0).getTimeSeconds());
+ assertEquals(2, highscores.get(0).getErrorCount());
+
+ Files.delete(tempFile);
+ }
+
+ @Test
+ void testGetAverageTimeNoEntries() {
+ HighscoreManager manager = new HighscoreManager();
+ double avgTime = manager.getAverageTime("Puzzle1");
+
+ assertEquals(-1, avgTime, "Average time should be -1 for no entries.");
+ }
+
+ @Test
+ void testLoadSinglePuzzleFileNotFound() {
+ HighscoreManager manager = new HighscoreManager();
+
+ assertDoesNotThrow(() -> manager.loadSinglePuzzle("Puzzle1", "nonexistent.txt"));
+ assertTrue(manager.getHighscores("Puzzle1").isEmpty());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/deversmann/domain/PuzzleDataTest.java b/src/test/java/de/deversmann/domain/PuzzleDataTest.java
new file mode 100644
index 0000000..c10c798
--- /dev/null
+++ b/src/test/java/de/deversmann/domain/PuzzleDataTest.java
@@ -0,0 +1,30 @@
+package de.deversmann.domain;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class PuzzleDataTest {
+
+ @Test
+ void testGetPuzzle() {
+ int[][] puzzle = {{1, 2}, {3, 4}};
+ List solution = List.of(new int[]{1, 1}, new int[]{2, 2});
+
+ PuzzleData data = new PuzzleData(puzzle, solution);
+
+ assertArrayEquals(puzzle, data.getPuzzle());
+ }
+
+ @Test
+ void testGetSolutionCoordinates() {
+ int[][] puzzle = {{1, 2}, {3, 4}};
+ List solution = List.of(new int[]{1, 1}, new int[]{2, 2});
+
+ PuzzleData data = new PuzzleData(puzzle, solution);
+
+ assertEquals(solution, data.getSolutionCoordinates());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/deversmann/facade/FacadeTest.java b/src/test/java/de/deversmann/facade/FacadeTest.java
new file mode 100644
index 0000000..741925b
--- /dev/null
+++ b/src/test/java/de/deversmann/facade/FacadeTest.java
@@ -0,0 +1,153 @@
+package de.deversmann.facade;
+
+import de.deversmann.domain.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.powermock.api.mockito.PowerMockito;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+class FacadeTest {
+
+ private CSVReader csvReaderMock;
+ private HighscoreManager highscoreManagerMock;
+ private Zeiterfassung zeiterfassungMock;
+ private Facade facade;
+
+ @BeforeEach
+ void setup() throws Exception {
+ facade = new Facade();
+
+ csvReaderMock = mock(CSVReader.class);
+ highscoreManagerMock = mock(HighscoreManager.class);
+ zeiterfassungMock = mock(Zeiterfassung.class);
+
+ PowerMockito.field(Facade.class, "csvReader").set(facade, csvReaderMock);
+ PowerMockito.field(Facade.class, "highscoreManager").set(facade, highscoreManagerMock);
+ PowerMockito.field(Facade.class, "zeiterfassung").set(facade, zeiterfassungMock);
+ }
+
+ @Test
+ void testLadeSpielfeldMitEchtenDaten() throws IOException {
+ PuzzleData puzzleData = new PuzzleData(new int[][]{{1, 2, 3, 4}}, List.of(new int[]{1, 1}));
+ when(csvReaderMock.readPuzzleWithSolution(anyString())).thenReturn(puzzleData);
+
+ facade.ladeSpielfeld("test.csv");
+
+ assertNotNull(facade.getAktuellesPuzzle());
+ assertEquals(1, facade.getLoesungsKoordinaten().size());
+ }
+
+ @Test
+ void testStopZeiterfassung() {
+ when(zeiterfassungMock.getElapsedTimeInSeconds()).thenReturn(42L);
+
+ long elapsedTime = facade.stopZeiterfassung();
+
+ verify(zeiterfassungMock, times(1)).stop();
+ assertEquals(42L, elapsedTime);
+ }
+
+ @Test
+ void testGetElapsedTimeSoFar() {
+ when(zeiterfassungMock.getElapsedTimeInSeconds()).thenReturn(15L);
+
+ long elapsedTime = facade.getElapsedTimeSoFar();
+
+ verify(zeiterfassungMock, times(1)).getElapsedTimeInSeconds();
+ assertEquals(15L, elapsedTime);
+ }
+
+ @Test
+ void testIncrementErrorCount() {
+ assertEquals(0, facade.getCurrentErrorCount());
+
+ facade.incrementErrorCount();
+
+ assertEquals(1, facade.getCurrentErrorCount());
+ }
+
+ @Test
+ void testAddHighscoreForCurrentPuzzle() throws IOException {
+ facade.ladeSpielfeld("test.csv");
+
+ facade.addHighscoreForCurrentPuzzle("Player1", 100L, 3);
+
+ verify(highscoreManagerMock, times(1))
+ .addHighscore(eq("test.csv"), eq("Player1"), eq(100L), eq(3));
+ }
+
+ @Test
+ void testGetHighscoresForCurrentPuzzle() throws IOException {
+ when(highscoreManagerMock.getHighscores("test.csv"))
+ .thenReturn(List.of(new HighscoreEntry("Player1", 100L, 2)));
+
+ facade.ladeSpielfeld("test.csv");
+ List highscores = facade.getHighscoresForCurrentPuzzle();
+
+ assertEquals(1, highscores.size());
+ assertEquals("Player1", highscores.get(0).getPlayerName());
+ }
+
+ @Test
+ void testGetAverageTimeForCurrentPuzzle() throws IOException {
+ when(highscoreManagerMock.getAverageTime("test.csv")).thenReturn(75.0);
+
+ facade.ladeSpielfeld("test.csv");
+ double avgTime = facade.getAverageTimeForCurrentPuzzle();
+
+ assertEquals(75.0, avgTime, 0.01);
+ }
+
+ @Test
+ void testSaveCurrentPuzzleHighscoreToFile() throws IOException {
+ facade.ladeSpielfeld("test.csv");
+
+ facade.saveCurrentPuzzleHighscoreToFile();
+
+ verify(highscoreManagerMock, times(1))
+ .saveSinglePuzzle(eq("test.csv"), anyString());
+ }
+
+ @Test
+ void testLoadCurrentPuzzleHighscoreFromFile() throws IOException {
+ facade.ladeSpielfeld("test.csv");
+
+ facade.loadCurrentPuzzleHighscoreFromFile();
+
+ verify(highscoreManagerMock, times(1))
+ .loadSinglePuzzle(eq("test.csv"), anyString());
+ }
+
+ @Test
+ void testGetAktuellesPuzzle() throws IOException {
+ PuzzleData puzzleData = new PuzzleData(new int[][]{{1, 2, 3, 4}}, List.of());
+ when(csvReaderMock.readPuzzleWithSolution(anyString())).thenReturn(puzzleData);
+
+ facade.ladeSpielfeld("test.csv");
+
+ int[][] puzzle = facade.getAktuellesPuzzle();
+
+ assertNotNull(puzzle);
+ assertEquals(4, puzzle[0].length);
+ }
+
+ @Test
+ void testGetLoesungsKoordinaten() throws IOException {
+ PuzzleData puzzleData = new PuzzleData(new int[][]{{1, 2}}, List.of(new int[]{1, 1}));
+ when(csvReaderMock.readPuzzleWithSolution(anyString())).thenReturn(puzzleData);
+
+ facade.ladeSpielfeld("test.csv");
+
+ List solutionCoordinates = facade.getLoesungsKoordinaten();
+
+ assertNotNull(solutionCoordinates);
+ assertEquals(1, solutionCoordinates.size());
+ assertArrayEquals(new int[]{1, 1}, solutionCoordinates.get(0));
+ }
+}
\ No newline at end of file