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_ui.rs | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 tests/client_ui.rs (limited to 'tests/client_ui.rs') diff --git a/tests/client_ui.rs b/tests/client_ui.rs new file mode 100644 index 0000000..78faed0 --- /dev/null +++ b/tests/client_ui.rs @@ -0,0 +1,131 @@ +use zagan_bet::client::ui::{ + command_names, completion_lines, help_lines, input_cursor_column, lines_to_move_up, + parse_bet_arg, record_history, +}; + +#[test] +fn help_has_no_source_indentation() { + for line in help_lines() { + assert!( + !line.starts_with(" "), + "help line kept its source indentation: {line:?}" + ); + } +} + +#[test] +fn help_documents_every_command() { + let help = help_lines().join("\n"); + for command in command_names() { + assert!(help.contains(command), "help text is missing '{command}'"); + } +} + +#[test] +fn completion_knows_every_command() { + let commands = command_names(); + for expected in [ + "connect", + "games", + "play", + "hosts", + "send", + "logout", + "quit", + ] { + assert!( + commands.contains(&expected), + "tab completion is missing '{expected}'" + ); + } +} + +#[test] +fn history_records_a_command_once() { + let mut history = Vec::new(); + record_history(&mut history, "info"); + record_history(&mut history, "info"); + + assert_eq!(history, vec!["info"]); +} + +#[test] +fn history_keeps_distinct_commands_in_order() { + let mut history = Vec::new(); + record_history(&mut history, "info"); + record_history(&mut history, "ping"); + record_history(&mut history, "info"); + + assert_eq!(history, vec!["info", "ping", "info"]); +} + +#[test] +fn blank_commands_are_not_recorded() { + let mut history = Vec::new(); + record_history(&mut history, ""); + record_history(&mut history, " "); + + assert!(history.is_empty()); +} + +#[test] +fn bet_accepts_ten_or_more() { + assert_eq!(parse_bet_arg("10"), Ok(10)); + assert_eq!(parse_bet_arg("50"), Ok(50)); + assert_eq!(parse_bet_arg(" 250 "), Ok(250)); +} + +#[test] +fn bet_rejects_less_than_ten() { + assert!(parse_bet_arg("9").is_err()); + assert!(parse_bet_arg("0").is_err()); +} + +#[test] +fn bet_rejects_non_numbers() { + assert!(parse_bet_arg("abc").is_err()); + assert!(parse_bet_arg("-50").is_err()); + assert!(parse_bet_arg("").is_err()); +} + +#[test] +fn redraw_moves_up_by_line_count_minus_one() { + assert_eq!(lines_to_move_up(0), 0); + assert_eq!(lines_to_move_up(1), 0); + assert_eq!(lines_to_move_up(7), 6); + assert_eq!(lines_to_move_up(70_000), u16::MAX); +} + +#[test] +fn input_cursor_is_after_the_removed_character() { + assert_eq!(input_cursor_column(10, 8), 18); + assert_eq!(input_cursor_column(10, 0), 10); + assert_eq!(input_cursor_column(2, 5), 7); + assert_eq!(input_cursor_column(70_000, 70_000), u16::MAX); +} + +#[test] +fn completions_wrap_within_the_requested_width() { + let commands = command_names(); + let lines = completion_lines(&commands, 40); + + assert_eq!(lines.first().map(String::as_str), Some("Possible completions:")); + for line in &lines[1..] { + assert!( + line.len() <= 40, + "completion line is too wide ({} > 40): {line:?}", + line.len() + ); + } + + let listed: Vec<&str> = lines[1..] + .iter() + .flat_map(|line| line.split_whitespace()) + .collect(); + for command in commands { + assert!( + listed.contains(&command), + "completion list is missing '{command}'" + ); + } +} -- cgit v1.2.3