planetsim/test_viewerstate.cpp
Jonas Reith e24326b735 Add a Main Menu + save browser, replacing auto-generate and the one-slot save
The app used to always generate a world straight from planet.cfg on launch
and F5 always overwrote a single fixed planet.save. Now it opens on a
full-screen Main Menu (Home / Settings / Load World) so every PlanetConfig
field, the seed, starting a new world, and browsing saves are all reachable
without hand-editing planet.cfg, and saves are timestamped so nothing is
silently overwritten. A toolbar button reopens the menu later without
disturbing a running world.

The settings editor is generic (no per-field UI code): configFieldTable()
reuses the existing CONFIG_FIELDS X-macro to build a runtime field table,
grouped into 25 categories via an explicit name->category lookup (a
"first field of each section" boundary scan was tried first and is wrong,
since CONFIG_FIELDS emits all doubles, then all ints, then the seed --
not struct declaration order, so most categories aren't contiguous in that
order). Save v25 adds the viewer's colour-mode/overlay state, kept out of
Planet::writeState/readState's signature so it touches none of the
existing headless tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TMfyZv91tonDnPJqbaTVJE
2026-08-31 19:11:16 +02:00

81 lines
3.6 KiB
C++

// Headless checks for the v25 viewer colour-mode/overlay save block (no window needed).
// Modeled on test_events.cpp.
#include "Viewer.hpp"
#include <cstdio>
#include <fstream>
#include <string>
static int failures = 0;
static void check(bool cond, const char* what) {
std::printf(" [%s] %s\n", cond ? "PASS" : "FAIL", what);
if (!cond) ++failures;
}
int main() {
std::printf("Viewer state: v25 colour-mode/overlay save/load round-trip\n");
Viewer v;
PlanetConfig cfg; cfg.subdivisions = 2; cfg.seed = 777;
v.cfg = cfg;
v.planet.generate(cfg);
// Set every overlay to a value that differs from the Viewer's own defaults, plus a non-default
// colour mode, so a bug that left fields untouched (rather than round-tripped) would show up.
v.mode = ColorMode::Biome;
v.showBorders = false; // default true
v.showDrift = false; // default true
v.showRivers = false; // default true
v.showGrat = true; // default false
v.dayNightOn = false; // default true
v.showTides = true; // default false
v.showCurrents = true; // default false
v.showClouds = false; // default true
v.showVolcanoes = false; // default true
v.showNames = true; // default false
v.showSettlements = false; // default true
v.showDiplomacy = false; // default true
v.showRealms = true; // default false
const char* path = "/tmp/fanworgen_viewerstate_test.save";
v.saveGame(path);
Viewer r;
r.loadGame(path);
check(r.mode == ColorMode::Biome, "v25 save/load restores the colour mode");
check(r.showBorders == false, "v25 restores showBorders");
check(r.showDrift == false, "v25 restores showDrift");
check(r.showRivers == false, "v25 restores showRivers");
check(r.showGrat == true, "v25 restores showGrat");
check(r.dayNightOn == false, "v25 restores dayNightOn");
check(r.showTides == true, "v25 restores showTides");
check(r.showCurrents == true, "v25 restores showCurrents");
check(r.showClouds == false, "v25 restores showClouds");
check(r.showVolcanoes == false, "v25 restores showVolcanoes");
check(r.showNames == true, "v25 restores showNames");
check(r.showSettlements == false, "v25 restores showSettlements");
check(r.showDiplomacy == false, "v25 restores showDiplomacy");
check(r.showRealms == true, "v25 restores showRealms");
check(r.screen == AppScreen::World, "loadGame() switches the app screen to World");
check(r.menuState.worldEverGenerated, "loadGame() marks a world as having been generated");
// Negative test: patch the save's version back to 24 (pre-v25, no mode/overlay block) and load
// into a fresh Viewer whose defaults differ from the saved-but-truncated values above -- must
// not crash, and must leave mode/overlays exactly at the fresh Viewer's own pre-load values.
{
std::fstream fs(path, std::ios::in | std::ios::out | std::ios::binary);
uint32_t oldVer = 24;
fs.seekp(4);
fs.write((char*)&oldVer, 4);
}
Viewer old;
ColorMode preLoadMode = old.mode;
bool preLoadBorders = old.showBorders, preLoadRealms = old.showRealms;
old.loadGame(path);
check(old.mode == preLoadMode, "pre-v25 saves leave the colour mode at its pre-load value");
check(old.showBorders == preLoadBorders, "pre-v25 saves leave showBorders at its pre-load value");
check(old.showRealms == preLoadRealms, "pre-v25 saves leave showRealms at its pre-load value");
std::printf(failures ? "\nFAILURES: %d\n" : "\nALL VIEWER STATE CHECKS PASSED\n", failures);
return failures ? 1 : 0;
}