Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions src/error_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,78 +92,78 @@ mod tests {
// ─── format_user_error tests ─────────────────────────────────────────────

#[test]
fn test_format_user_error_timeout() {
fn format_user_error_timeout() {
let result = format_user_error("timeout waiting for session/new response");
assert!(result.contains("Request Timeout"));
assert!(result.contains("session/new"));
}

#[test]
fn test_format_user_error_connection_closed() {
fn format_user_error_connection_closed() {
let result = format_user_error("connection closed");
assert!(result.contains("Connection Lost"));
}

#[test]
fn test_format_user_error_channel_closed() {
fn format_user_error_channel_closed() {
let result = format_user_error("channel closed");
assert!(result.contains("Connection Lost"));
}

#[test]
fn test_format_user_error_failed_to_spawn() {
fn format_user_error_failed_to_spawn() {
let result = format_user_error("failed to spawn /some/path: No such file");
assert!(result.contains("Agent Not Found"));
assert!(result.contains("the agent")); // generic, no provider name
}

#[test]
fn test_format_user_error_no_such_file() {
fn format_user_error_no_such_file() {
let result = format_user_error("binary /usr/bin/nonexistent: no such file");
assert!(result.contains("Agent Not Found"));
}

#[test]
fn test_format_user_error_pool_exhausted() {
fn format_user_error_pool_exhausted() {
let result = format_user_error("pool exhausted (5 sessions)");
assert!(result.contains("Service Busy"));
}

#[test]
fn test_format_user_error_invalid_api_key() {
fn format_user_error_invalid_api_key() {
let result = format_user_error("invalid api key");
assert!(result.contains("Unauthorized"));
}

#[test]
fn test_format_user_error_unauthorized() {
fn format_user_error_unauthorized() {
let result = format_user_error("unauthorized: token rejected");
assert!(result.contains("Unauthorized"));
}

#[test]
fn test_format_user_error_unknown() {
fn format_user_error_unknown() {
let result = format_user_error("something went wrong");
assert!(result.contains("Error"));
assert!(result.contains("something went wrong"));
}

#[test]
fn test_format_user_error_empty() {
fn format_user_error_empty() {
let result = format_user_error("");
assert!(result.contains("Error"));
assert!(result.contains("unknown"));
}

#[test]
fn test_format_user_error_case_insensitive() {
fn format_user_error_case_insensitive() {
assert!(format_user_error("TIMEOUT WAITING FOR foo").contains("Timeout"));
assert!(format_user_error("CONNECTION CLOSED").contains("Connection"));
assert!(format_user_error("POOL EXHAUSTED").contains("Busy"));
}

#[test]
fn test_format_user_error_mixed_case_timeout() {
fn format_user_error_mixed_case_timeout() {
// Case-insensitive matching should still extract method correctly
let result = format_user_error("Timeout Waiting For custom/method");
assert!(result.contains("Request Timeout"));
Expand All @@ -173,67 +173,67 @@ mod tests {
// ─── format_coded_error tests ───────────────────────────────────────────

#[test]
fn test_format_coded_error_401() {
fn format_coded_error_401() {
let result = format_coded_error(401, "invalid token", None);
assert!(result.contains("Unauthorized"));
assert!(result.contains("401"));
assert!(result.contains("invalid token"));
}

#[test]
fn test_format_coded_error_429() {
fn format_coded_error_429() {
let result = format_coded_error(429, "", None);
assert!(result.contains("Rate Limited"));
assert!(result.contains("429"));
assert!(!result.contains("\n")); // no message, no newline
}

#[test]
fn test_format_coded_error_503() {
fn format_coded_error_503() {
let result = format_coded_error(503, "service unavailable", None);
assert!(result.contains("Service Unavailable"));
assert!(result.contains("503"));
assert!(result.contains("service unavailable"));
}

#[test]
fn test_format_coded_error_json_rpc() {
fn format_coded_error_json_rpc() {
let result = format_coded_error(-32602, "missing required parameter", None);
assert!(result.contains("Invalid Params"));
assert!(result.contains("-32602"));
}

#[test]
fn test_format_coded_error_server_error_range() {
fn format_coded_error_server_error_range() {
let result = format_coded_error(-32050, "internal failure", None);
assert!(result.contains("Server Error"));
assert!(result.contains("-32050"));
}

#[test]
fn test_format_coded_error_connection_error() {
fn format_coded_error_connection_error() {
let result = format_coded_error(-32000, "connection refused", None);
assert!(result.contains("Server Error")); // -32000 falls in -32099..=-32000 range
assert!(result.contains("-32000"));
}

#[test]
fn test_format_coded_error_unknown_code() {
fn format_coded_error_unknown_code() {
let result = format_coded_error(999, "something happened", None);
assert!(result.contains("Error"));
assert!(result.contains("999"));
assert!(result.contains("something happened"));
}

#[test]
fn test_format_coded_error_with_data_message() {
fn format_coded_error_with_data_message() {
let result = format_coded_error(-32603, "Internal error", Some("model not supported"));
assert!(result.contains("Internal Error"));
assert!(result.contains("model not supported"));
}

#[test]
fn test_format_coded_error_data_message_not_duplicated() {
fn format_coded_error_data_message_not_duplicated() {
// If data_message is already in message, don't repeat it
let result = format_coded_error(-32603, "model not supported", Some("model not supported"));
assert_eq!(result.matches("model not supported").count(), 1);
Expand Down
46 changes: 23 additions & 23 deletions src/remind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,83 +211,83 @@ mod tests {
use super::*;

#[test]
fn test_parse_delay_minutes() {
fn parse_delay_minutes() {
assert_eq!(parse_delay("5m").unwrap(), 300);
assert_eq!(parse_delay("1m").unwrap(), 60);
}

#[test]
fn test_parse_delay_hours() {
fn parse_delay_hours() {
assert_eq!(parse_delay("2h").unwrap(), 7200);
}

#[test]
fn test_parse_delay_days() {
fn parse_delay_days() {
assert_eq!(parse_delay("1d").unwrap(), 86400);
assert_eq!(parse_delay("30d").unwrap(), 2_592_000);
}

#[test]
fn test_parse_delay_combined() {
fn parse_delay_combined() {
assert_eq!(parse_delay("1h30m").unwrap(), 5400);
assert_eq!(parse_delay("1d12h").unwrap(), 129_600);
}

#[test]
fn test_parse_delay_bare_number_defaults_to_minutes() {
fn parse_delay_bare_number_defaults_to_minutes() {
assert_eq!(parse_delay("10").unwrap(), 600);
}

#[test]
fn test_parse_delay_too_short() {
fn parse_delay_too_short() {
assert!(parse_delay("0m").is_err());
assert!(parse_delay("0h").is_err());
}

#[test]
fn test_parse_delay_too_long() {
fn parse_delay_too_long() {
assert!(parse_delay("31d").is_err());
}

#[test]
fn test_format_delay() {
fn format_delay_basic() {
assert_eq!(format_delay(3600), "1h");
assert_eq!(format_delay(5400), "1h 30m");
assert_eq!(format_delay(90000), "1d 1h");
}

#[test]
fn test_parse_delay_empty() {
fn parse_delay_empty() {
assert!(parse_delay("").is_err());
assert!(parse_delay(" ").is_err());
}

#[test]
fn test_parse_delay_invalid_unit() {
fn parse_delay_invalid_unit() {
assert!(parse_delay("2x").is_err());
assert!(parse_delay("abc").is_err());
assert!(parse_delay("5s").is_err());
}

#[test]
fn test_parse_delay_case_insensitive() {
fn parse_delay_case_insensitive() {
assert_eq!(parse_delay("2H").unwrap(), 7200);
assert_eq!(parse_delay("1D30M").unwrap(), 88200);
}

#[test]
fn test_parse_delay_whitespace_trimmed() {
fn parse_delay_whitespace_trimmed() {
assert_eq!(parse_delay(" 5m ").unwrap(), 300);
}

#[test]
fn test_parse_delay_bare_number_boundary() {
fn parse_delay_bare_number_boundary() {
assert_eq!(parse_delay("1").unwrap(), 60); // 1 min
assert_eq!(parse_delay("30").unwrap(), 1800); // 30 min
}

#[test]
fn test_parse_delay_exact_boundaries() {
fn parse_delay_exact_boundaries() {
// Exactly 1m (minimum)
assert_eq!(parse_delay("1m").unwrap(), 60);
// Exactly 30d (maximum)
Expand All @@ -297,19 +297,19 @@ mod tests {
}

#[test]
fn test_format_delay_zero() {
fn format_delay_zero() {
assert_eq!(format_delay(0), "< 1m");
}

#[test]
fn test_format_delay_pure_units() {
fn format_delay_pure_units() {
assert_eq!(format_delay(86400), "1d");
assert_eq!(format_delay(120), "2m");
assert_eq!(format_delay(7200), "2h");
}

#[tokio::test]
async fn test_reminder_store_add_remove() {
async fn reminder_store_add_remove() {
let dir = std::env::temp_dir().join(format!("remind_test_{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("reminders.json");
Expand Down Expand Up @@ -341,7 +341,7 @@ mod tests {
}

#[tokio::test]
async fn test_reminder_store_persists_across_reload() {
async fn reminder_store_persists_across_reload() {
let dir = std::env::temp_dir().join(format!("remind_test2_{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("reminders.json");
Expand Down Expand Up @@ -369,31 +369,31 @@ mod tests {
}

#[test]
fn test_sanitize_message_strips_everyone_here() {
fn sanitize_message_strips_everyone_here() {
assert_eq!(sanitize_message("hello @everyone"), "hello @\u{200b}everyone");
assert_eq!(sanitize_message("hey @here check"), "hey @\u{200b}here check");
assert_eq!(sanitize_message("@everyone @here"), "@\u{200b}everyone @\u{200b}here");
}

#[test]
fn test_sanitize_message_no_change() {
fn sanitize_message_no_change() {
assert_eq!(sanitize_message("normal message"), "normal message");
assert_eq!(sanitize_message("<@123> hello"), "<@123> hello");
}

#[test]
fn test_validate_message_ok() {
fn validate_message_ok() {
assert!(validate_message("short message").is_ok());
assert!(validate_message(&"a".repeat(1800)).is_ok());
}

#[test]
fn test_validate_message_too_long() {
fn validate_message_too_long() {
assert!(validate_message(&"a".repeat(1801)).is_err());
}

#[test]
fn test_max_targets_constant() {
fn max_targets_constant() {
assert_eq!(MAX_TARGETS, 10);
}
}
4 changes: 2 additions & 2 deletions src/setup/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ mod tests {
use super::*;

#[test]
fn test_generate_config_contains_sections() {
fn generate_config_contains_sections() {
let config = generate_config(
"my_token",
"claude",
Expand All @@ -148,7 +148,7 @@ mod tests {
}

#[test]
fn test_generate_config_kiro_working_dir() {
fn generate_config_kiro_working_dir() {
let config = generate_config("tok", "kiro", vec!["ch".to_string()], "/home/agent", 10, 24);
assert!(config.contains(r#"working_dir = "/home/agent""#));
assert!(config.contains("acp"));
Expand Down
8 changes: 4 additions & 4 deletions src/setup/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,30 +47,30 @@ mod tests {
use super::*;

#[test]
fn test_validate_bot_token_ok() {
fn validate_bot_token_ok() {
assert!(validate_bot_token("simple_token").is_ok());
assert!(validate_bot_token("token.with-dashes_123").is_ok());
assert!(validate_bot_token("***/efgh").is_ok());
}

#[test]
fn test_validate_bot_token_reject_invalid() {
fn validate_bot_token_reject_invalid() {
assert!(validate_bot_token("").is_err());
assert!(validate_bot_token("token\nnewline").is_err());
assert!(validate_bot_token("token\ttab").is_err());
assert!(validate_bot_token("token with space").is_err());
}

#[test]
fn test_validate_agent_command() {
fn validate_agent_command_known_and_unknown() {
for agent in &["kiro", "claude", "codex", "gemini"] {
assert!(validate_agent_command(agent).is_ok());
}
assert!(validate_agent_command("invalid").is_err());
}

#[test]
fn test_validate_channel_id() {
fn validate_channel_id_accepts_numeric_rejects_invalid() {
assert!(validate_channel_id("1492329565824094370").is_ok());
assert!(validate_channel_id("").is_err());
assert!(validate_channel_id("abc123").is_err());
Expand Down
Loading