App.run ended its menu loop on Quit and just returned. The console exits then,
but in the GUI run() is on a daemon worker while the Swing JFrame stays
displayable on the EDT, keeping the JVM alive — and the dismissed menu overlay
just revealed the running game underneath ("back into the game"). EXIT_ON_CLOSE
only fires for the native window X, not a programmatic quit.
Add a GameIO.shutdown() teardown hook (default no-op) and call it after the menu
loop ends. SwingIO overrides it to stop music, dispose the window, and exit the
JVM, mirroring EXIT_ON_CLOSE; console keeps the no-op. Extract an injectable
App.run overload and add AppQuitTest asserting the Quit path invokes shutdown().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
53 lines
1.7 KiB
Java
53 lines
1.7 KiB
Java
package thb.jeanluc.adventure;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.api.io.TempDir;
|
|
import thb.jeanluc.adventure.io.TestIO;
|
|
import thb.jeanluc.adventure.save.SaveService;
|
|
import thb.jeanluc.adventure.save.SettingsStore;
|
|
|
|
import java.nio.file.Path;
|
|
import java.util.List;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
|
|
/**
|
|
* Regression test for the main-menu Quit: choosing Quit must end the menu loop
|
|
* AND tell the frontend to tear down. Previously {@code run} just returned,
|
|
* which exits the console but left the Swing window open (the menu overlay
|
|
* closed and the game reappeared underneath). We assert the frontend-agnostic
|
|
* contract: the Quit path invokes {@link thb.jeanluc.adventure.io.GameIO#shutdown()}.
|
|
*/
|
|
class AppQuitTest {
|
|
|
|
/** Fake IO that always picks the last menu option (Quit) and records shutdown. */
|
|
private static final class QuitIO extends TestIO {
|
|
boolean shutdownCalled;
|
|
int chooseCalls;
|
|
|
|
@Override
|
|
public int choose(String title, List<String> options) {
|
|
chooseCalls++;
|
|
return options.size() - 1; // Quit is the last main-menu option
|
|
}
|
|
|
|
@Override
|
|
public void shutdown() {
|
|
shutdownCalled = true;
|
|
}
|
|
}
|
|
|
|
@Test
|
|
void choosingQuit_tearsDownTheFrontend(@TempDir Path tmp) {
|
|
QuitIO io = new QuitIO();
|
|
SaveService saves = new SaveService(tmp.resolve("saves"));
|
|
SettingsStore settings = new SettingsStore(tmp.resolve("settings.json"));
|
|
|
|
App.run(io, saves, settings);
|
|
|
|
assertThat(io.shutdownCalled).isTrue();
|
|
assertThat(io.chooseCalls).isEqualTo(1); // straight to Quit, no game started
|
|
assertThat(io.allOutput()).contains("Farewell.");
|
|
}
|
|
}
|