127 lines
4 KiB
Rust
127 lines
4 KiB
Rust
use rustbot::bot::module::{Action, Command, Module};
|
|
use rustbot::bot::modules::crypto::format_coins;
|
|
use rustbot::bot::modules::dict::parse_definition;
|
|
use rustbot::bot::modules::fun::Fun;
|
|
use rustbot::bot::modules::funweb::{
|
|
format_advice, format_catfact, format_fact, format_joke, format_worldtime,
|
|
};
|
|
use rustbot::bot::modules::weather::format_forecast;
|
|
|
|
fn cmd<'a>(name: &'a str, args: &'a [&'a str]) -> Command<'a> {
|
|
Command {
|
|
sender: "u",
|
|
reply_to: "#c",
|
|
name,
|
|
args,
|
|
prefix: ">",
|
|
network: "t",
|
|
}
|
|
}
|
|
|
|
// ---- funweb formatters ----
|
|
|
|
#[test]
|
|
fn joke_single_and_twopart() {
|
|
assert_eq!(
|
|
format_joke(r#"{"type":"single","joke":"UDP joke."}"#),
|
|
"UDP joke."
|
|
);
|
|
assert_eq!(
|
|
format_joke(r#"{"type":"twopart","setup":"knock knock","delivery":"who?"}"#),
|
|
"knock knock … who?"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn fact_catfact_advice() {
|
|
assert_eq!(
|
|
format_fact(r#"{"text":"the moon is dry"}"#),
|
|
"the moon is dry"
|
|
);
|
|
assert_eq!(format_catfact(r#"{"fact":"cats purr"}"#), "🐱 cats purr");
|
|
assert_eq!(
|
|
format_advice(r#"{"slip":{"id":1,"advice":"drink water"}}"#),
|
|
"💡 drink water"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn worldtime_formats_time_and_day() {
|
|
let out = format_worldtime(
|
|
"Europe/Paris",
|
|
r#"{"time":"04:21","dayOfWeek":"Thursday","timeZone":"Europe/Paris"}"#,
|
|
);
|
|
assert!(out.contains("Europe/Paris"), "{out}");
|
|
assert!(out.contains("04:21") && out.contains("Thursday"), "{out}");
|
|
}
|
|
|
|
// ---- crypto: coins ----
|
|
|
|
#[test]
|
|
fn coins_lists_symbols_and_prices() {
|
|
let out = format_coins(
|
|
r#"[{"symbol":"btc","current_price":64183},{"symbol":"eth","current_price":3200},{"symbol":"xrp","current_price":0.5123}]"#,
|
|
);
|
|
assert!(out.starts_with("top coins:"), "{out}");
|
|
assert!(out.contains("BTC $64183"), "{out}");
|
|
assert!(out.contains("ETH $3200"), "{out}");
|
|
assert!(out.contains("XRP $0.5123"), "{out}"); // sub-$1 keeps 4 decimals
|
|
}
|
|
|
|
// ---- weather: forecast ----
|
|
|
|
#[test]
|
|
fn forecast_summarizes_days() {
|
|
let body = r#"{"weather":[{"date":"2026-07-30","maxtempC":"34","mintempC":"22","hourly":[{},{},{},{},{"weatherDesc":[{"value":"Sunny"}]}]}]}"#;
|
|
let out = format_forecast(body, "Paris");
|
|
assert!(out.starts_with("Paris:"), "{out}");
|
|
assert!(out.contains("07-30"), "{out}");
|
|
assert!(out.contains("Sunny") && out.contains("34/22"), "{out}");
|
|
}
|
|
|
|
// ---- dict: RFC 2229 parsing ----
|
|
|
|
#[test]
|
|
fn dict_parses_first_definition() {
|
|
let resp = "220 banner\r\n150 1 definitions retrieved\r\n151 \"cat\" wn \"WordNet\"\r\ncat\r\n n 1: feline mammal [syn: {cat}, {true cat}]\r\n.\r\n250 ok\r\n";
|
|
let def = parse_definition(resp).expect("a definition");
|
|
assert!(def.contains("feline mammal"), "{def}");
|
|
assert!(!def.contains('{'), "braces should be stripped: {def}");
|
|
}
|
|
|
|
#[test]
|
|
fn dict_no_match_and_no_header_are_none() {
|
|
assert!(parse_definition("220 banner\r\n552 no match\r\n250 ok\r\n").is_none());
|
|
assert!(parse_definition("220 banner\r\n250 ok\r\n").is_none());
|
|
}
|
|
|
|
// ---- fun (local) smoke tests ----
|
|
|
|
fn one_reply(actions: Vec<Action>) -> String {
|
|
match actions.as_slice() {
|
|
[Action::Reply(s)] => s.clone(),
|
|
_ => panic!("expected one reply"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn fun_basics() {
|
|
let mut f = Fun::new();
|
|
assert!(one_reply(f.on_command(&cmd("8ball", &["will it work?"]))).contains("🎱"));
|
|
assert!(one_reply(f.on_command(&cmd("drinks", &[]))).contains("coffee"));
|
|
assert!(one_reply(f.on_command(&cmd("catgif", &[]))).contains("cataas"));
|
|
let rps = one_reply(f.on_command(&cmd("rock", &[])));
|
|
assert!(rps.contains("you:") && rps.contains("me:"), "{rps}");
|
|
}
|
|
|
|
#[test]
|
|
fn coffee_is_a_ctcp_action() {
|
|
let mut f = Fun::new();
|
|
match f.on_command(&cmd("coffee", &["alice"])).as_slice() {
|
|
[Action::Raw(line)] => {
|
|
assert!(line.starts_with("PRIVMSG #c :\u{1}ACTION "), "{line}");
|
|
assert!(line.contains("alice") && line.contains("coffee"), "{line}");
|
|
}
|
|
_ => panic!("expected a raw ACTION"),
|
|
}
|
|
}
|