Skip to content

Commit 8d0d9d6

Browse files
author
Arun Prasaad
committed
Add test for end of custom level
1 parent dd045da commit 8d0d9d6

File tree

4 files changed

+80
-9
lines changed

4 files changed

+80
-9
lines changed

.cascade

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ strict_mode = true
88
# Don't create getter methods unless they're actually needed
99
avoid_unnecessary_getters = true
1010
# Method ordering: helper methods after their callers
11+
# Test names should be propositional (e.g., "returns_true_when_condition_met")
12+
propositional_test_names = true
1113
helper_methods_after_caller = true
1214

1315
[editing]
@@ -16,6 +18,8 @@ helper_methods_after_caller = true
1618
make_minimal_changes = true
1719
# Code formatting
1820
no_trailing_spaces = true
21+
# Avoid comments that state the obvious or repeat the code
22+
avoid_superfluous_comments = true
1923

2024
[communication]
2125
# Be direct and to the point

src/main/java/ihm/SokobanWindow.java

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
package ihm;
22

3-
import java.awt.Dimension;
3+
import java.awt.*;
44

5-
import java.awt.Image;
65
import java.awt.event.KeyEvent;
76
import java.awt.event.KeyListener;
87
import java.awt.image.BufferedImage;
98
import java.util.ArrayList;
109
import java.util.List;
11-
import javax.swing.ImageIcon;
12-
import javax.swing.JFrame;
13-
import javax.swing.JOptionPane;
10+
import javax.swing.*;
11+
12+
import com.google.common.annotations.VisibleForTesting;
1413
import logic.Controller;
1514
import logic.Direction;
1615
import logic.GameAction;
@@ -20,6 +19,7 @@
2019
public class SokobanWindow extends JFrame implements KeyListener{
2120

2221
public static final int IMAGE_SIZE = 32;
22+
private final JButton okButton;
2323

2424
public Controller getController() {
2525
return controller;
@@ -49,6 +49,7 @@ public SokobanWindow(Controller controller) {
4949
this.pack();
5050
this.setLocationRelativeTo( null );
5151
this.setVisible( true );
52+
okButton = new JButton("OK");
5253
}
5354

5455
@Override
@@ -98,16 +99,36 @@ else if (input == GameAction.STOP) {
9899
}
99100
}
100101

101-
private void handleEndOfLevel() {
102+
private void handleEndOfLevel() {
102103
if (controller.isOnCustomLevel()) {
103-
JOptionPane.showMessageDialog(this, "Congratulations, you've completed the level!");
104-
exitGame();
104+
105+
JDialog dialog = new JDialog(this, "Level Complete!", true);
106+
okButton.addActionListener(_ -> dialog.dispose());
107+
108+
JOptionPane.showOptionDialog(
109+
dialog,
110+
"Congratulations! You've completed the level!",
111+
"Level Complete!",
112+
JOptionPane.DEFAULT_OPTION,
113+
JOptionPane.INFORMATION_MESSAGE,
114+
null,
115+
new Object[]{okButton},
116+
okButton
117+
);
118+
119+
dispose();
120+
new HomeWindow();
105121
}
106122
else {
107123
handleNextLevel();
108124
}
109125
}
110126

127+
@VisibleForTesting
128+
void clickOkButton() {
129+
okButton.doClick();
130+
}
131+
111132
private void handleNextLevel() {
112133
Object[] options = {"Next level", "Quit"};
113134
Image image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);

src/test/java/ihm/SokobanWindowTest.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import org.junit.jupiter.params.ParameterizedTest;
99
import org.junit.jupiter.params.provider.Arguments;
1010
import org.junit.jupiter.params.provider.MethodSource;
11+
12+
import java.awt.*;
1113
import java.util.stream.Stream;
1214

1315
import javax.swing.*;
@@ -16,6 +18,8 @@
1618

1719
import static org.assertj.core.api.BDDAssertions.then;
1820

21+
import java.util.Arrays;
22+
1923
@NullMarked
2024
class SokobanWindowTest {
2125

@@ -32,7 +36,11 @@ void setUp() {
3236

3337
@AfterEach
3438
void tearDown() {
35-
window.dispose();
39+
40+
// Clean up windows
41+
Arrays.stream(java.awt.Window.getWindows())
42+
.filter(java.awt.Window::isDisplayable)
43+
.forEach(java.awt.Window::dispose);
3644
}
3745

3846
/**
@@ -247,4 +255,35 @@ void handles_restart_action() {
247255
then(controller.getWorker().getColumn()).isNotEqualTo(columnAfterMove);
248256
then(controller.getWorker().getColumn()).isEqualTo(initialColumn);
249257
}
258+
259+
@Test
260+
void completing_a_custom_level_disposes_window_and_shows_home_window() {
261+
// given - create a test window with the simplified level that only needs one push
262+
window = createTestWindow("src/test/resources/levels/test_level_end.txt");
263+
264+
// Simulate the user clicking OK to close the level completion dialog.
265+
// This has to be done before the move to push the box to the target
266+
// because the dialog will wait for user input
267+
Timer timer = new Timer(10, _ -> window.clickOkButton());
268+
timer.setRepeats(false);
269+
SwingUtilities.invokeLater(timer::start);
270+
271+
// When:
272+
// Single move to push the box to the target
273+
KeyEvent rightKey = new KeyEvent(window,
274+
KeyEvent.KEY_PRESSED,
275+
System.currentTimeMillis(),
276+
0,
277+
KeyEvent.VK_RIGHT,
278+
KeyEvent.CHAR_UNDEFINED);
279+
window.keyPressed(rightKey);
280+
281+
then(window.isShowing())
282+
.as("Window is disposed after level completion and OK click")
283+
.isFalse();
284+
285+
then(Window.getWindows())
286+
.as("Contains a visible HomeWindow")
287+
.anyMatch(w -> w instanceof HomeWindow && w.isShowing());
288+
}
250289
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
MMMMMMM
2+
M#####M
3+
M#####M
4+
M#GCT#M
5+
M#####M
6+
M#####M
7+
MMMMMMM

0 commit comments

Comments
 (0)