use zagan_bet::client::ui::{ command_names, completion_lines, display_width, first_contact_lines, format_pong, help_lines, host_lines, input_cursor_column, lines_to_move_up, parse_bet_arg, record_history, }; use std::time::Duration; #[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}'" ); } } #[test] fn display_width_counts_terminal_columns_not_bytes() { assert_eq!(display_width("abc"), 3); assert_eq!(display_width("ąćęłńóśźż"), 9); assert_eq!(display_width("中"), 2); assert_eq!(display_width("🎉"), 2); assert_eq!(display_width("e\u{0301}"), 1); } #[test] fn cursor_column_uses_display_width() { assert_eq!(input_cursor_column(2, display_width("ąć")), 4); assert_eq!(input_cursor_column(2, display_width("中")), 4); } #[test] fn first_contact_message_stays_within_80_columns() { let fingerprint = "a4d6f80784154c2cb739a1df61ab3e9038ed731ee2e05c7611457ac741b3834c"; let lines = first_contact_lines("127.0.0.1:11525", fingerprint); assert!(lines.iter().any(|line| line.contains("127.0.0.1:11525"))); assert!(lines.iter().any(|line| line.contains(fingerprint))); for line in lines { assert!( line.len() <= 80, "first-contact line is too wide ({}): {line:?}", line.len() ); } } #[test] fn pong_is_formatted_to_one_decimal() { assert_eq!(format_pong(Duration::from_micros(144)), "Pong (0.1ms)"); assert_eq!(format_pong(Duration::from_millis(41)), "Pong (41.0ms)"); } #[test] fn host_lines_fit_an_80_column_terminal() { let fingerprint = "a4d6f80784154c2cb739a1df61ab3e9038ed731ee2e05c7611457ac741b3834c"; let lines = host_lines(&[ ( "127.0.0.1:11525".to_string(), Some(fingerprint.to_string()), ), ("unknown.example:443".to_string(), None), ]); assert!(lines.iter().any(|line| line.contains("127.0.0.1:11525"))); assert!(lines.iter().any(|line| line.contains(fingerprint))); assert!(lines.iter().any(|line| line.contains("no fingerprint"))); for line in lines { assert!( line.len() <= 80, "host line is too wide ({}): {line:?}", line.len() ); } }