use crate::command::chat::constants::*;
use crate::command::chat::error::ChatError;
use crate::command::chat::tools::tool_names;
#[test]
fn error_to_retry_policy_chain() {
let retryable: Vec<ChatError> = vec![
ChatError::NetworkTimeout("t".into()),
ChatError::NetworkError("e".into()),
ChatError::StreamInterrupted("s".into()),
ChatError::StreamDeserialize("d".into()),
ChatError::ApiServerError {
status: 500,
message: "err".into(),
},
ChatError::ApiServerError {
status: 503,
message: "err".into(),
},
ChatError::ApiRateLimit {
message: "msg".into(),
retry_after_secs: None,
},
ChatError::AbnormalFinish("network_error".into()),
];
for err in &retryable {
let msg = err.display_message();
assert!(
!msg.is_empty(),
"retryable error {err:?} 的 display_message 不应为空"
);
}
let non_retryable: Vec<ChatError> = vec![
ChatError::ApiAuth("key".into()),
ChatError::ApiBadRequest("param".into()),
ChatError::HookAborted,
ChatError::RuntimeFailed("err".into()),
];
for err in &non_retryable {
let msg = err.display_message();
assert!(
!msg.is_empty(),
"non-retryable error {err:?} 的 display_message 不应为空"
);
}
}
#[test]
fn key_tool_names_are_non_empty() {
assert!(!tool_names::BASH.is_empty(), "BASH 工具名不应为空");
assert!(!tool_names::READ.is_empty(), "READ 工具名不应为空");
assert!(!tool_names::EDIT.is_empty(), "EDIT 工具名不应为空");
assert!(!tool_names::WRITE.is_empty(), "WRITE 工具名不应为空");
assert!(!tool_names::GREP.is_empty(), "GREP 工具名不应为空");
assert!(!tool_names::GLOB.is_empty(), "GLOB 工具名不应为空");
}
#[test]
fn tool_names_are_consistent_format() {
for name in [
tool_names::BASH,
tool_names::READ,
tool_names::EDIT,
tool_names::WRITE,
tool_names::GREP,
tool_names::GLOB,
] {
assert!(!name.is_empty(), "工具名不应为空");
assert!(!name.contains(' '), "工具名 '{name}' 不应包含空格");
}
}
#[test]
fn constants_reasonable_ranges() {
assert!(
SHELL_DEFAULT_TIMEOUT_SECS <= SHELL_MAX_TIMEOUT_SECS,
"Shell 默认超时 ({SHELL_DEFAULT_TIMEOUT_SECS}s) 不应超过最大 ({SHELL_MAX_TIMEOUT_SECS}s)"
);
assert!(SHELL_MAX_TIMEOUT_SECS > 0, "Shell 最大超时应为正数");
assert!(WEB_RESPONSE_MAX_BYTES > 0, "Web 响应最大字节数应为正数");
assert!(
WEB_SEARCH_DEFAULT_COUNT <= WEB_SEARCH_MAX_COUNT,
"Web 搜索默认数量 ({WEB_SEARCH_DEFAULT_COUNT}) 不应超过上限 ({WEB_SEARCH_MAX_COUNT})"
);
assert!(
MICRO_COMPACT_BYTES_THRESHOLD > 0,
"Micro compact 字节阈值应为正数"
);
assert!(COMPACT_KEEP_RECENT > 0, "Compact keep_recent 应为正数");
assert!(DEFAULT_MAX_TOOL_ROUNDS > 0, "默认最大工具轮数应为正数");
assert!(
DEFAULT_MAX_HISTORY_MESSAGES > 0,
"默认最大历史消息数应为正数"
);
let quota_sum = WINDOW_QUOTA_USER + WINDOW_QUOTA_ASST_TEXT + WINDOW_QUOTA_TOOL_GROUP;
assert!(
(quota_sum - 1.0).abs() < 0.01,
"Window 配额总和应为 1.0,实际为 {quota_sum}"
);
assert!(HOOK_DEFAULT_TIMEOUT_SECS > 0, "Hook 默认超时应为正数");
assert!(
HOOK_DEFAULT_LLM_TIMEOUT_SECS > HOOK_DEFAULT_TIMEOUT_SECS,
"LLM hook 超时应大于 shell hook 超时"
);
assert!(
BG_TASK_DEFAULT_TIMEOUT_MS <= BG_TASK_MAX_TIMEOUT_MS,
"后台任务默认超时不应超过最大超时"
);
assert!(WORKTREE_NAME_MAX_LEN > 0, "Worktree 名称最大长度应为正数");
assert!(INPUT_BUFFER_MAX_LEN > 0, "输入缓冲区最大长度应为正数");
}
#[test]
fn constants_positive_values() {
let positive_constants = [
("TOOL_OUTPUT_SUMMARY_MAX_LEN", TOOL_OUTPUT_SUMMARY_MAX_LEN),
("MESSAGE_PREVIEW_MAX_LEN", MESSAGE_PREVIEW_MAX_LEN),
("PAGE_SCROLL_LINES", PAGE_SCROLL_LINES),
(
"COMPACT_SUMMARY_MAX_TOKENS",
COMPACT_SUMMARY_MAX_TOKENS as usize,
),
("TEAM_MAX_MEMBERS", TEAM_MAX_MEMBERS),
("ARCHIVE_NAME_MAX_LEN", ARCHIVE_NAME_MAX_LEN),
];
for (name, value) in positive_constants {
assert!(value > 0, "{name} ({value}) 应为正数");
}
}