From 37dedc342c087506e502c78a952b45b1c91602fb Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 1 Nov 2026 18:03:24 +0100 Subject: v4.0.2: port slots, blackjack and crash to structured views --- tests/client_core.rs | 111 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 99 insertions(+), 12 deletions(-) (limited to 'tests/client_core.rs') diff --git a/tests/client_core.rs b/tests/client_core.rs index 695dcb1..0a2cb7b 100644 --- a/tests/client_core.rs +++ b/tests/client_core.rs @@ -12,7 +12,7 @@ use zagan_bet::client::games::response::{ }; use zagan_bet::client::games::roulette::{Cursor, Direction}; use zagan_bet::client::ui::command_names; -use zagan_bet::client::view::{Command, RoulettePhase, View}; +use zagan_bet::client::view::{Command, RoulettePhase, SlotsPhase, View}; use zagan_bet::roulette::BetTarget; use zagan_bet::crash::CrashState; @@ -1209,7 +1209,7 @@ fn the_roulette_view_reflects_the_cursor_and_bets() { let mut h = Harness::new(); h.enter_roulette(); - let View::Roulette(view) = h.core.view() else { + let Some(View::Roulette(view)) = h.core.view() else { panic!("expected a roulette view"); }; assert_eq!(view.cursor, Cursor::Lattice { x: 1, y: 5 }); @@ -1226,7 +1226,7 @@ fn the_roulette_view_reflects_the_cursor_and_bets() { let effects = h.core.command(Command::PlaceBet); h.apply(effects); - let View::Roulette(view) = h.core.view() else { + let Some(View::Roulette(view)) = h.core.view() else { panic!("expected a roulette view"); }; assert_eq!( @@ -1248,7 +1248,7 @@ fn clicking_a_bet_target_does_not_move_the_cursor() { let effects = h.core.command(Command::PlaceBetAt(BetTarget::Split { a: 1, b: 4 })); h.apply(effects); - let View::Roulette(view) = h.core.view() else { + let Some(View::Roulette(view)) = h.core.view() else { panic!("expected a roulette view"); }; assert_eq!(view.bets.amount_on(&BetTarget::Split { a: 1, b: 4 }), 10); @@ -1269,7 +1269,7 @@ fn the_roulette_view_reports_the_result() { let bets = r#"{"chips":[{"target":{"bet":"straight","number":1},"amount":10}]}"#; h.reply(&format!("ROULETTE_RESULT s1 360 10 1350 1 red {bets}")); - let View::Roulette(view) = h.core.view() else { + let Some(View::Roulette(view)) = h.core.view() else { panic!("expected a roulette view"); }; assert_eq!(view.phase, RoulettePhase::Result); @@ -1286,27 +1286,31 @@ fn the_chip_size_is_a_command() { h.enter_roulette(); h.core.command(Command::AdjustChip(10)); - let View::Roulette(view) = h.core.view() else { + let Some(View::Roulette(view)) = h.core.view() else { panic!("expected a roulette view"); }; assert_eq!(view.chip, 20); h.core.command(Command::SetChip(5)); - let View::Roulette(view) = h.core.view() else { + let Some(View::Roulette(view)) = h.core.view() else { panic!("expected a roulette view"); }; assert_eq!(view.chip, 10, "the chip never goes below 10"); } #[test] -fn unported_games_still_reach_the_frontend_as_text() { +fn slots_reach_the_frontend_as_a_structured_view() { let mut h = Harness::new(); h.enter_slots("10"); + h.key(Key::Char(' ')); - match h.core.view() { - View::Text(lines) => assert_eq!(lines.len(), 10), - other => panic!("expected the text bridge, got {other:?}"), - } + let view = h.core.view().expect("a slots view"); + let View::Slots(view) = view else { + panic!("expected a slots view"); + }; + assert_eq!(view.bet, 10); + assert_eq!(view.phase, SlotsPhase::Spinning); + assert_eq!(h.board().len(), 10); } #[test] @@ -1320,3 +1324,86 @@ fn leaving_through_a_command_clears_the_screen() { assert!(!h.core.is_in_game()); assert!(h.screen.lines.iter().any(|line| line == "Game exited.")); } + +#[test] +fn the_slots_view_carries_the_result() { + let mut h = Harness::new(); + h.enter_slots("10"); + h.key(Key::Char(' ')); + h.reply(&format!( + "GAME_RESULT s1 20 10 1010 {WIN3} win 1 0,3,6" + )); + + let Some(View::Slots(view)) = h.core.view() else { + panic!("expected a slots view"); + }; + assert_eq!(view.phase, SlotsPhase::Result); + assert_eq!(view.winnings, Some(20)); + assert_eq!(view.win_type, "win"); + assert_eq!(view.win_lines, vec![1]); + assert_eq!(view.win_cells, vec![0, 3, 6]); + assert_eq!(view.reels.len(), 15); +} + +#[test] +fn the_blackjack_view_carries_the_hand_and_legal_actions() { + let mut h = Harness::new(); + h.enter_blackjack(); + h.key(Key::Char(' ')); + + let player = bj_state( + "bj1", + "player", + &["10S", "6H"], + &["9D", "?"], + 16, + 9, + 10, + 10, + 990, + &["hit", "stand", "double"], + "playing", + 0, + ); + h.reply(&format!( + "BLACKJACK_STATE {}", + serde_json::to_string(&player).unwrap() + )); + + let Some(View::Blackjack(view)) = h.core.view() else { + panic!("expected a blackjack view"); + }; + assert_eq!(view.status, "player"); + assert_eq!(view.bet, 10); + let hand = view.hand.expect("the hand is part of the view"); + assert_eq!(hand.player_total, 16); + assert_eq!(hand.actions, vec!["hit", "stand", "double"]); + assert_eq!(hand.session_id, "bj1"); +} + +#[test] +fn the_crash_view_follows_the_round() { + let mut h = Harness::new(); + h.enter_crash(); + h.key(Key::Char(' ')); + + let running = crash_state("running", 1.0, None, 0, 990); + h.reply(&crash_line("CRASH_START", &running)); + + let Some(View::Crash(view)) = h.core.view() else { + panic!("expected a crash view"); + }; + assert_eq!(view.status, "running"); + assert_eq!(view.bet, 10); + assert_eq!(view.balance, Some(990)); + assert!((view.multiplier - 1.0).abs() < 1e-9); + assert_eq!(view.potential, 10); + assert_eq!(view.crash_point, None); + + h.tick(Duration::from_secs(5)); + let Some(View::Crash(view)) = h.core.view() else { + panic!("expected a crash view"); + }; + assert!((view.multiplier - 2.0).abs() < 1e-6); + assert_eq!(view.potential, 20); +} -- cgit v1.2.3