From 828470137cb4e806c31a26fa741d5d67c64f98c2 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 28 Oct 2026 22:31:18 +0100 Subject: v0.2.4: fix command UX, completion wrapping and auth prompt cancellation --- tests/client_core.rs | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) (limited to 'tests/client_core.rs') diff --git a/tests/client_core.rs b/tests/client_core.rs index 3dbbfe5..79b3dd8 100644 --- a/tests/client_core.rs +++ b/tests/client_core.rs @@ -5,6 +5,7 @@ //! player would see, not about ANSI sequences. use zagan_bet::client::core::{ClientCore, Effect, InteractiveCommand, Key}; +use zagan_bet::client::ui::command_names; #[derive(Default)] struct Screen { @@ -12,6 +13,7 @@ struct Screen { region_start: Option, region_len: usize, prompt: String, + prompt_cursor: u16, } impl Screen { @@ -40,7 +42,10 @@ impl Screen { self.region_start = None; self.region_len = 0; } - Effect::SetPrompt { text, .. } => self.prompt = text.clone(), + Effect::SetPrompt { text, cursor_col } => { + self.prompt = text.clone(); + self.prompt_cursor = *cursor_col; + } Effect::SendLine(line) => sent.push(line.clone()), Effect::Interactive(command) => interactive.push(command.clone()), Effect::Quit @@ -214,3 +219,170 @@ fn an_empty_reply_is_an_error_not_a_silent_spin() { assert_eq!(h.board().len(), 7); assert!(h.board()[4].contains("No response from server")); } + +#[test] +fn empty_enter_does_not_print_help() { + let mut h = Harness::new(); + h.line("games"); + let lines_before = h.screen.lines.clone(); + + h.key(Key::Enter); + + assert_eq!(h.screen.lines, lines_before); + assert_eq!(h.screen.prompt, ""); +} + +#[test] +fn history_does_not_duplicate_consecutive_commands() { + let mut h = Harness::new(); + h.line("games"); + h.line("games"); + + h.key(Key::Up); + assert_eq!(h.screen.prompt, "games"); + h.key(Key::Up); + assert_eq!(h.screen.prompt, "games"); +} + +#[test] +fn history_recalls_previous_commands() { + let mut h = Harness::new(); + h.line("games"); + h.line("help"); + + h.key(Key::Up); + assert_eq!(h.screen.prompt, "help"); + h.key(Key::Up); + assert_eq!(h.screen.prompt, "games"); +} + +#[test] +fn tab_completes_a_unique_command() { + let mut h = Harness::new(); + for c in "con".chars() { + h.key(Key::Char(c)); + } + + h.key(Key::Tab); + + assert_eq!(h.screen.prompt, "connect"); + assert_eq!(h.screen.prompt_cursor, 9); +} + +#[test] +fn tab_completion_list_wraps() { + let mut h = Harness::new(); + + h.key(Key::Tab); + + assert!(h + .screen + .lines + .iter() + .any(|line| line == "Possible completions:")); + for line in h + .screen + .lines + .iter() + .skip_while(|line| line.as_str() != "Possible completions:") + .skip(1) + { + assert!( + line.len() <= 76, + "completion line is too wide ({}): {line:?}", + line.len() + ); + } + assert_eq!(h.screen.prompt, ""); +} + +#[test] +fn play_without_a_bet_uses_the_default() { + let mut h = Harness::new(); + h.line("play slots"); + + assert_eq!(h.board().len(), 7); + assert!(h.board()[1].contains("Bet: 10 PLN")); +} + +#[test] +fn an_invalid_bet_does_not_start_a_game() { + let mut h = Harness::new(); + h.line("play slots 5"); + + assert!(h.board().is_empty()); + assert!(h + .screen + .lines + .iter() + .any(|line| line.contains("Bet must be at least 10 PLN"))); +} + +#[test] +fn help_lists_every_command() { + let mut h = Harness::new(); + h.line("help"); + + let transcript = h.screen.lines.join("\n"); + for command in command_names() { + assert!( + transcript.contains(command), + "help is missing '{command}'" + ); + } +} + +#[test] +fn send_keeps_the_whole_message() { + let mut h = Harness::new(); + h.line("send hello world"); + + assert_eq!(h.sent.last().map(String::as_str), Some("hello world")); +} + +#[test] +fn play_requires_a_connection_and_a_login() { + let mut h = Harness::new(); + h.core.set_connected(false); + h.line("play slots"); + assert!(h + .screen + .lines + .iter() + .any(|line| line.contains("Not connected"))); + + let mut h = Harness::new(); + h.core.set_logged_in(None); + h.line("play slots"); + assert!(h + .screen + .lines + .iter() + .any(|line| line.contains("Not logged in"))); +} + +#[test] +fn ctrl_c_quits_from_the_prompt() { + let mut core = ClientCore::new(); + assert_eq!(core.handle_key(Key::CtrlC), vec![Effect::Quit]); +} + +#[test] +fn ctrl_c_quits_from_a_game() { + let mut h = Harness::new(); + h.enter_slots("50"); + + assert_eq!(h.core.handle_key(Key::CtrlC), vec![Effect::Quit]); +} + +#[test] +fn prompt_cursor_tracks_the_input() { + let mut h = Harness::new(); + h.key(Key::Char('a')); + assert_eq!(h.screen.prompt, "a"); + assert_eq!(h.screen.prompt_cursor, 3); + + h.key(Key::Backspace); + assert_eq!(h.screen.prompt, ""); + assert_eq!(h.screen.prompt_cursor, 2); +} -- cgit v1.2.3