83 lines
2.7 KiB
Rust
83 lines
2.7 KiB
Rust
use std::collections::BTreeMap;
|
|
use std::path::PathBuf;
|
|
|
|
use rustbot::bot::module::{Action, Command, Module};
|
|
use rustbot::bot::modules::weather::{format_weather, parse_db, to_json, Weather};
|
|
|
|
fn cmd<'a>(sender: &'a str, name: &'a str, args: &'a [&'a str]) -> Command<'a> {
|
|
Command { sender, reply_to: "#chan", name, args, prefix: ">", network: "test" }
|
|
}
|
|
|
|
fn reply(actions: &[Action]) -> &str {
|
|
match actions {
|
|
[Action::Reply(s)] => s,
|
|
_ => panic!("expected exactly one Reply"),
|
|
}
|
|
}
|
|
|
|
fn temp(name: &str) -> PathBuf {
|
|
let p = std::env::temp_dir().join(format!("rubot-test-{name}.json"));
|
|
let _ = std::fs::remove_file(&p);
|
|
p
|
|
}
|
|
|
|
#[test]
|
|
fn json_round_trip_handles_special_chars() {
|
|
let mut m = BTreeMap::new();
|
|
m.insert("alice".to_string(), "73700".to_string());
|
|
m.insert("bob".to_string(), "Saint-Étienne, FR".to_string());
|
|
m.insert("carol".to_string(), "a\"b\\c\nd".to_string());
|
|
let back = parse_db(&to_json(&m));
|
|
assert_eq!(m, back);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_db_tolerates_junk() {
|
|
assert!(parse_db("").is_empty());
|
|
assert!(parse_db("not json").is_empty());
|
|
assert_eq!(parse_db("{}").len(), 0);
|
|
assert_eq!(parse_db("{\"a\":\"b\"}").get("a").map(String::as_str), Some("b"));
|
|
}
|
|
|
|
#[test]
|
|
fn add_saves_and_persists_case_insensitively() {
|
|
let path = temp("weather-add");
|
|
let mut w = Weather::with_path(path.clone());
|
|
let r = reply(&w.on_command(&cmd("Alice", "add", &["73700"]))).to_string();
|
|
assert!(r.contains("73700"), "reply: {r:?}");
|
|
|
|
let w2 = Weather::with_path(path.clone());
|
|
assert_eq!(w2.location_of("alice"), Some("73700"));
|
|
assert_eq!(w2.location_of("ALICE"), Some("73700"));
|
|
let _ = std::fs::remove_file(&path);
|
|
}
|
|
|
|
#[test]
|
|
fn add_without_arg_shows_usage() {
|
|
let mut w = Weather::with_path(temp("weather-usage"));
|
|
let r = reply(&w.on_command(&cmd("alice", "add", &[]))).to_string();
|
|
assert!(r.contains("usage"), "reply: {r:?}");
|
|
}
|
|
|
|
#[test]
|
|
fn w_without_saved_location_hints_to_add() {
|
|
let mut w = Weather::with_path(temp("weather-hint"));
|
|
let r = reply(&w.on_command(&cmd("nobody", "w", &[]))).to_string();
|
|
assert!(r.contains("add"), "reply: {r:?}");
|
|
}
|
|
|
|
#[test]
|
|
fn format_weather_builds_friendly_line() {
|
|
let out = format_weather("73700|☀️ |Sunny|+23°C|+18°C|↘8km/h|45%", "73700");
|
|
assert!(out.contains("☀️"), "{out}");
|
|
assert!(out.contains("73700: Sunny"), "{out}");
|
|
assert!(out.contains("23°C") && !out.contains("+23"), "{out}");
|
|
assert!(out.contains("feels like 18°C"), "{out}");
|
|
assert!(out.contains("45%"), "{out}");
|
|
}
|
|
|
|
#[test]
|
|
fn format_weather_friendly_not_found() {
|
|
let out = format_weather("location not found: upstream error", "zzz");
|
|
assert!(out.contains("couldn't find 'zzz'"), "{out}");
|
|
}
|