refactor(core): derive draw_mode/is_won/move_count/is_auto_completable from session

Remove the draw_mode, move_count, is_won, and is_auto_completable fields
from GameState; they are now &self methods deriving from the underlying
card_game session (draw_mode from session config, move_count from history
length, is_won/is_auto_completable from check_win/check_auto_complete).

Tests previously fabricated these via direct field writes, which is no
longer possible. Add gated test-support overrides on TestPileState
(won/auto_completable/move_count) plus setters set_test_won,
set_test_auto_completable, set_test_move_count, and set_test_draw_mode
(re-deals the seed). All compiled out in production builds.

Fix the field->method ripple across solitaire_data, solitaire_wasm, and
solitaire_engine. Add a test-support dev-dependency to solitaire_data for
the won-game storage test.

cargo test --workspace and cargo clippy --workspace -- -D warnings pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
funman300
2026-06-10 09:24:03 -07:00
parent 1438fd6265
commit 056459619b
20 changed files with 187 additions and 120 deletions
+5 -5
View File
@@ -85,13 +85,13 @@ pub fn game_state_file_path() -> Option<PathBuf> {
pub fn load_game_state_from(path: &Path) -> Option<GameState> {
let data = fs::read(path).ok()?;
let gs: GameState = serde_json::from_slice(&data).ok()?;
if gs.is_won { None } else { Some(gs) }
if gs.is_won() { None } else { Some(gs) }
}
/// Save an in-progress `GameState` atomically. Skips the write if `gs.is_won`
/// because a completed game should not be resumed.
pub fn save_game_state_to(path: &Path, gs: &GameState) -> io::Result<()> {
if gs.is_won {
if gs.is_won() {
return Ok(());
}
if let Some(parent) = path.parent() {
@@ -386,8 +386,8 @@ mod tests {
let loaded = load_game_state_from(&path).expect("load");
assert_eq!(loaded.seed, gs.seed);
assert_eq!(loaded.draw_mode, gs.draw_mode);
assert!(!loaded.is_won);
assert_eq!(loaded.draw_mode(), gs.draw_mode());
assert!(!loaded.is_won());
}
#[test]
@@ -411,7 +411,7 @@ mod tests {
let _ = fs::remove_file(&path);
let mut gs = GameState::new(99, DrawMode::DrawOne);
gs.is_won = true;
gs.set_test_won(true);
save_game_state_to(&path, &gs).expect("save should be no-op, not error");
assert!(
!path.exists(),