114 lines
3.9 KiB
Rust
114 lines
3.9 KiB
Rust
|
|
//! Handler for the `help` command.
|
||
|
|
|
||
|
|
use super::{commands, CommandContext};
|
||
|
|
|
||
|
|
pub(super) fn handle_help(ctx: &CommandContext) -> Option<String> {
|
||
|
|
let mut output = format!("**{} Commands**\n\n", ctx.bot_name);
|
||
|
|
let mut sorted: Vec<_> = commands().iter().collect();
|
||
|
|
sorted.sort_by_key(|c| c.name);
|
||
|
|
for cmd in sorted {
|
||
|
|
output.push_str(&format!("- **{}** — {}\n", cmd.name, cmd.description));
|
||
|
|
}
|
||
|
|
Some(output)
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(test)]
|
||
|
|
mod tests {
|
||
|
|
use super::super::tests::{try_cmd_addressed, commands};
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn help_command_matches() {
|
||
|
|
let result = try_cmd_addressed("Timmy", "@timmy:homeserver.local", "@timmy help");
|
||
|
|
assert!(result.is_some(), "help command should match");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn help_command_case_insensitive() {
|
||
|
|
let result = try_cmd_addressed("Timmy", "@timmy:homeserver.local", "@timmy HELP");
|
||
|
|
assert!(result.is_some(), "HELP should match case-insensitively");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn help_output_contains_all_commands() {
|
||
|
|
let result = try_cmd_addressed("Timmy", "@timmy:homeserver.local", "@timmy help");
|
||
|
|
let output = result.unwrap();
|
||
|
|
for cmd in commands() {
|
||
|
|
assert!(
|
||
|
|
output.contains(cmd.name),
|
||
|
|
"help output must include command '{}'",
|
||
|
|
cmd.name
|
||
|
|
);
|
||
|
|
assert!(
|
||
|
|
output.contains(cmd.description),
|
||
|
|
"help output must include description for '{}'",
|
||
|
|
cmd.name
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn help_output_uses_bot_name() {
|
||
|
|
let result = try_cmd_addressed("HAL", "@hal:example.com", "@hal help");
|
||
|
|
let output = result.unwrap();
|
||
|
|
assert!(
|
||
|
|
output.contains("HAL Commands"),
|
||
|
|
"help output should use bot name: {output}"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn help_output_formatted_as_markdown() {
|
||
|
|
let result = try_cmd_addressed("Timmy", "@timmy:homeserver.local", "@timmy help");
|
||
|
|
let output = result.unwrap();
|
||
|
|
assert!(
|
||
|
|
output.contains("**help**"),
|
||
|
|
"command name should be bold: {output}"
|
||
|
|
);
|
||
|
|
assert!(
|
||
|
|
output.contains("- **"),
|
||
|
|
"commands should be in a list: {output}"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn help_output_includes_status() {
|
||
|
|
let result = try_cmd_addressed("Timmy", "@timmy:homeserver.local", "@timmy help");
|
||
|
|
let output = result.unwrap();
|
||
|
|
assert!(output.contains("status"), "help should list status command: {output}");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn help_output_is_alphabetical() {
|
||
|
|
let result = try_cmd_addressed("Timmy", "@timmy:homeserver.local", "@timmy help");
|
||
|
|
let output = result.unwrap();
|
||
|
|
// Search for **name** (bold markdown) to avoid substring matches in descriptions.
|
||
|
|
let mut positions: Vec<(usize, &str)> = commands()
|
||
|
|
.iter()
|
||
|
|
.map(|c| {
|
||
|
|
let marker = format!("**{}**", c.name);
|
||
|
|
let pos = output.find(&marker).expect("command must appear in help as **name**");
|
||
|
|
(pos, c.name)
|
||
|
|
})
|
||
|
|
.collect();
|
||
|
|
positions.sort_by_key(|(pos, _)| *pos);
|
||
|
|
let names_in_order: Vec<&str> = positions.iter().map(|(_, n)| *n).collect();
|
||
|
|
let mut sorted = names_in_order.clone();
|
||
|
|
sorted.sort();
|
||
|
|
assert_eq!(names_in_order, sorted, "commands must appear in alphabetical order");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn help_output_includes_ambient() {
|
||
|
|
let result = try_cmd_addressed("Timmy", "@timmy:homeserver.local", "@timmy help");
|
||
|
|
let output = result.unwrap();
|
||
|
|
assert!(output.contains("ambient"), "help should list ambient command: {output}");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn help_output_includes_htop() {
|
||
|
|
let result = try_cmd_addressed("Timmy", "@timmy:homeserver.local", "@timmy help");
|
||
|
|
let output = result.unwrap();
|
||
|
|
assert!(output.contains("htop"), "help should list htop command: {output}");
|
||
|
|
}
|
||
|
|
}
|