diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-01 17:58:03 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-01 17:58:03 +0100 |
| commit | 46202ee2e398ffd49febe6684f5c6a8648da600d (patch) | |
| tree | 00631532b6b4805ddc8a728246787651dd7185f2 /tests | |
| parent | docs: document DOWNLOAD_URL and the XDG reset path (diff) | |
| download | zagan-bet-46202ee2e398ffd49febe6684f5c6a8648da600d.tar.gz zagan-bet-46202ee2e398ffd49febe6684f5c6a8648da600d.zip | |
v4.0.1: introduce Command/View and port roulette to the shared boundary
Diffstat (limited to '')
| -rw-r--r-- | tests/client_core.rs | 130 |
1 files changed, 126 insertions, 4 deletions
diff --git a/tests/client_core.rs b/tests/client_core.rs index b0bba6f..695dcb1 100644 --- a/tests/client_core.rs +++ b/tests/client_core.rs | |||
| @@ -10,7 +10,10 @@ use zagan_bet::client::core::{ClientCore, Effect, InteractiveCommand, Key}; | |||
| 10 | use zagan_bet::client::games::response::{ | 10 | use zagan_bet::client::games::response::{ |
| 11 | parse_blackjack_response, parse_crash_response, parse_spin_response, | 11 | parse_blackjack_response, parse_crash_response, parse_spin_response, |
| 12 | }; | 12 | }; |
| 13 | use zagan_bet::client::games::roulette::{Cursor, Direction}; | ||
| 13 | use zagan_bet::client::ui::command_names; | 14 | use zagan_bet::client::ui::command_names; |
| 15 | use zagan_bet::client::view::{Command, RoulettePhase, View}; | ||
| 16 | use zagan_bet::roulette::BetTarget; | ||
| 14 | use zagan_bet::crash::CrashState; | 17 | use zagan_bet::crash::CrashState; |
| 15 | 18 | ||
| 16 | const WIN3: &str = "CCCCLLCLODGSDGS"; | 19 | const WIN3: &str = "CCCCLLCLODGSDGS"; |
| @@ -36,7 +39,8 @@ impl Screen { | |||
| 36 | for effect in effects { | 39 | for effect in effects { |
| 37 | match effect { | 40 | match effect { |
| 38 | Effect::Print(lines) => self.lines.extend(lines.iter().cloned()), | 41 | Effect::Print(lines) => self.lines.extend(lines.iter().cloned()), |
| 39 | Effect::ReplaceRegion(lines) => { | 42 | Effect::Render(view) => { |
| 43 | let lines = zagan_bet::client::tui::render_view(view); | ||
| 40 | if let Some(start) = self.region_start { | 44 | if let Some(start) = self.region_start { |
| 41 | self.lines.truncate(start); | 45 | self.lines.truncate(start); |
| 42 | } else { | 46 | } else { |
| @@ -52,14 +56,15 @@ impl Screen { | |||
| 52 | self.region_start = None; | 56 | self.region_start = None; |
| 53 | self.region_len = 0; | 57 | self.region_len = 0; |
| 54 | } | 58 | } |
| 55 | Effect::AnimateRoulette { final_lines, .. } => { | 59 | Effect::AnimateRoulette { view, .. } => { |
| 60 | let lines = zagan_bet::client::tui::render_view(view); | ||
| 56 | if let Some(start) = self.region_start { | 61 | if let Some(start) = self.region_start { |
| 57 | self.lines.truncate(start); | 62 | self.lines.truncate(start); |
| 58 | } else { | 63 | } else { |
| 59 | self.region_start = Some(self.lines.len()); | 64 | self.region_start = Some(self.lines.len()); |
| 60 | } | 65 | } |
| 61 | self.lines.extend(final_lines.iter().cloned()); | 66 | self.lines.extend(lines.iter().cloned()); |
| 62 | self.region_len = final_lines.len(); | 67 | self.region_len = lines.len(); |
| 63 | } | 68 | } |
| 64 | Effect::SetPrompt { text, cursor_col } => { | 69 | Effect::SetPrompt { text, cursor_col } => { |
| 65 | self.prompt = text.clone(); | 70 | self.prompt = text.clone(); |
| @@ -1198,3 +1203,120 @@ fn history_rejects_a_bad_count_without_sending() { | |||
| 1198 | .iter() | 1203 | .iter() |
| 1199 | .any(|line| line.contains("Usage: history [1-50]"))); | 1204 | .any(|line| line.contains("Usage: history [1-50]"))); |
| 1200 | } | 1205 | } |
| 1206 | |||
| 1207 | #[test] | ||
| 1208 | fn the_roulette_view_reflects_the_cursor_and_bets() { | ||
| 1209 | let mut h = Harness::new(); | ||
| 1210 | h.enter_roulette(); | ||
| 1211 | |||
| 1212 | let View::Roulette(view) = h.core.view() else { | ||
| 1213 | panic!("expected a roulette view"); | ||
| 1214 | }; | ||
| 1215 | assert_eq!(view.cursor, Cursor::Lattice { x: 1, y: 5 }); | ||
| 1216 | assert_eq!( | ||
| 1217 | view.cursor.target(), | ||
| 1218 | Some(BetTarget::Straight { number: 1 }) | ||
| 1219 | ); | ||
| 1220 | assert!(view.bets.is_empty()); | ||
| 1221 | assert_eq!(view.chip, 10); | ||
| 1222 | assert_eq!(view.phase, RoulettePhase::Placing); | ||
| 1223 | |||
| 1224 | h.core.command(Command::MoveCursor(Direction::Up)); | ||
| 1225 | h.core.command(Command::MoveCursor(Direction::Up)); | ||
| 1226 | let effects = h.core.command(Command::PlaceBet); | ||
| 1227 | h.apply(effects); | ||
| 1228 | |||
| 1229 | let View::Roulette(view) = h.core.view() else { | ||
| 1230 | panic!("expected a roulette view"); | ||
| 1231 | }; | ||
| 1232 | assert_eq!( | ||
| 1233 | view.cursor.target(), | ||
| 1234 | Some(BetTarget::Straight { number: 2 }) | ||
| 1235 | ); | ||
| 1236 | assert_eq!(view.bets.total(), 10); | ||
| 1237 | assert_eq!( | ||
| 1238 | view.bets.amount_on(&BetTarget::Straight { number: 2 }), | ||
| 1239 | 10 | ||
| 1240 | ); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | #[test] | ||
| 1244 | fn clicking_a_bet_target_does_not_move_the_cursor() { | ||
| 1245 | let mut h = Harness::new(); | ||
| 1246 | h.enter_roulette(); | ||
| 1247 | |||
| 1248 | let effects = h.core.command(Command::PlaceBetAt(BetTarget::Split { a: 1, b: 4 })); | ||
| 1249 | h.apply(effects); | ||
| 1250 | |||
| 1251 | let View::Roulette(view) = h.core.view() else { | ||
| 1252 | panic!("expected a roulette view"); | ||
| 1253 | }; | ||
| 1254 | assert_eq!(view.bets.amount_on(&BetTarget::Split { a: 1, b: 4 }), 10); | ||
| 1255 | assert_eq!( | ||
| 1256 | view.cursor.target(), | ||
| 1257 | Some(BetTarget::Straight { number: 1 }), | ||
| 1258 | "a click places a chip without dragging the keyboard cursor" | ||
| 1259 | ); | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | #[test] | ||
| 1263 | fn the_roulette_view_reports_the_result() { | ||
| 1264 | let mut h = Harness::new(); | ||
| 1265 | h.enter_roulette(); | ||
| 1266 | h.core.command(Command::PlaceBet); | ||
| 1267 | |||
| 1268 | h.key(Key::Char(' ')); | ||
| 1269 | let bets = r#"{"chips":[{"target":{"bet":"straight","number":1},"amount":10}]}"#; | ||
| 1270 | h.reply(&format!("ROULETTE_RESULT s1 360 10 1350 1 red {bets}")); | ||
| 1271 | |||
| 1272 | let View::Roulette(view) = h.core.view() else { | ||
| 1273 | panic!("expected a roulette view"); | ||
| 1274 | }; | ||
| 1275 | assert_eq!(view.phase, RoulettePhase::Result); | ||
| 1276 | assert_eq!(view.number, Some(1)); | ||
| 1277 | assert_eq!(view.color.as_deref(), Some("red")); | ||
| 1278 | assert_eq!(view.winnings, Some(360)); | ||
| 1279 | assert_eq!(view.balance, Some(1350)); | ||
| 1280 | assert!(view.error.is_none()); | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | #[test] | ||
| 1284 | fn the_chip_size_is_a_command() { | ||
| 1285 | let mut h = Harness::new(); | ||
| 1286 | h.enter_roulette(); | ||
| 1287 | |||
| 1288 | h.core.command(Command::AdjustChip(10)); | ||
| 1289 | let View::Roulette(view) = h.core.view() else { | ||
| 1290 | panic!("expected a roulette view"); | ||
| 1291 | }; | ||
| 1292 | assert_eq!(view.chip, 20); | ||
| 1293 | |||
| 1294 | h.core.command(Command::SetChip(5)); | ||
| 1295 | let View::Roulette(view) = h.core.view() else { | ||
| 1296 | panic!("expected a roulette view"); | ||
| 1297 | }; | ||
| 1298 | assert_eq!(view.chip, 10, "the chip never goes below 10"); | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | #[test] | ||
| 1302 | fn unported_games_still_reach_the_frontend_as_text() { | ||
| 1303 | let mut h = Harness::new(); | ||
| 1304 | h.enter_slots("10"); | ||
| 1305 | |||
| 1306 | match h.core.view() { | ||
| 1307 | View::Text(lines) => assert_eq!(lines.len(), 10), | ||
| 1308 | other => panic!("expected the text bridge, got {other:?}"), | ||
| 1309 | } | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | #[test] | ||
| 1313 | fn leaving_through_a_command_clears_the_screen() { | ||
| 1314 | let mut h = Harness::new(); | ||
| 1315 | h.enter_roulette(); | ||
| 1316 | |||
| 1317 | let effects = h.core.command(Command::Leave); | ||
| 1318 | h.apply(effects); | ||
| 1319 | |||
| 1320 | assert!(!h.core.is_in_game()); | ||
| 1321 | assert!(h.screen.lines.iter().any(|line| line == "Game exited.")); | ||
| 1322 | } | ||
