use ircbot::handler::HandlerEntry;
use ircbot::testing::TestContext;
use ircbot::{bot, Context, Result, Trigger, User};
#[bot]
impl MacroBot {
#[command("ping")]
async fn ping(&self, ctx: Context) -> Result {
ctx.say("pong")
}
#[command("hi", target = "#rust")]
async fn hi_rust(&self, ctx: Context) -> Result {
ctx.say("hi")
}
#[on(message = "hello *")]
async fn greet(&self, ctx: Context, who: String) -> Result {
ctx.say(format!("hi {who}"))
}
#[on(event = "JOIN", regex = "(.+)")]
async fn on_join(&self, ctx: Context) -> Result {
ctx.say("joined")
}
#[on(mention)]
async fn on_mention(&self, ctx: Context) -> Result {
ctx.say("mentioned")
}
#[on(cron = "0 0 * * * *", tz = "UTC")]
async fn on_cron(&self, ctx: Context) -> Result {
ctx.say("cron")
}
#[on(
message = "winner",
command = "loser",
event = "ALSO_LOSER",
mention,
cron = "0 0 * * * *"
)]
async fn precedence(&self, ctx: Context) -> Result {
ctx.say("p")
}
#[on(event = "PRIVMSG", regex = r"(\w+) (\w+)")]
async fn two_args(&self, ctx: Context, a: String, b: String) -> Result {
ctx.say(format!("{a}-{b}"))
}
#[command("whoami")]
async fn whoami(&self, ctx: Context, user: User) -> Result {
ctx.say(user.nick)
}
fn helper(&self) -> u32 {
42
}
}
fn handlers() -> Vec<HandlerEntry<MacroBot>> {
MacroBot::__handlers()
}
async fn invoke(entry: &HandlerEntry<MacroBot>, mut tc: TestContext) -> Option<String> {
let bot = std::sync::Arc::new(MacroBot::default());
(entry.handler)(bot, tc.take_ctx()).await.unwrap();
tc.next_reply()
}
#[test]
fn command_attr_yields_command_trigger() {
match &handlers()[0].trigger {
Trigger::Command { name, target } => {
assert_eq!(name, "ping");
assert_eq!(target.as_deref(), None);
}
other => panic!("expected Command, got {other:?}"),
}
}
#[test]
fn command_target_propagates() {
match &handlers()[1].trigger {
Trigger::Command { name, target } => {
assert_eq!(name, "hi");
assert_eq!(target.as_deref(), Some("#rust"));
}
other => panic!("expected Command, got {other:?}"),
}
}
#[test]
fn on_message_yields_message_trigger() {
match &handlers()[2].trigger {
Trigger::Message { pattern, .. } => assert_eq!(pattern, "hello *"),
other => panic!("expected Message, got {other:?}"),
}
}
#[test]
fn on_event_with_regex_yields_event_trigger() {
match &handlers()[3].trigger {
Trigger::Event {
event,
target,
regex,
} => {
assert_eq!(event, "JOIN");
assert_eq!(target.as_deref(), None);
assert_eq!(regex.as_deref(), Some("(.+)"));
}
other => panic!("expected Event, got {other:?}"),
}
}
#[test]
fn on_mention_yields_mention_trigger() {
assert!(matches!(
&handlers()[4].trigger,
Trigger::Mention { target: None }
));
}
#[test]
fn on_cron_yields_cron_trigger() {
match &handlers()[5].trigger {
Trigger::Cron { schedule, tz, .. } => {
assert_eq!(schedule, "0 0 * * * *");
assert_eq!(tz, "UTC");
}
other => panic!("expected Cron, got {other:?}"),
}
}
#[test]
fn message_wins_trigger_precedence() {
match &handlers()[6].trigger {
Trigger::Message { pattern, .. } => assert_eq!(pattern, "winner"),
other => panic!("expected Message (precedence), got {other:?}"),
}
}
#[test]
fn only_annotated_methods_produce_handler_entries() {
assert_eq!(handlers().len(), 9);
}
#[test]
fn plain_method_remains_callable() {
assert_eq!(MacroBot::default().helper(), 42);
}
#[tokio::test]
async fn string_arg_filled_from_captures_when_present() {
let entry = &handlers()[2]; let tc = TestContext::builder()
.target("#test")
.captures(vec!["world".to_string()])
.build();
assert_eq!(
invoke(entry, tc).await,
Some("PRIVMSG #test :hi world\r\n".to_string())
);
}
#[tokio::test]
async fn string_arg_falls_back_to_message_text_when_no_captures() {
let entry = &handlers()[2]; let tc = TestContext::builder()
.target("#test")
.text("raw body")
.build();
assert_eq!(
invoke(entry, tc).await,
Some("PRIVMSG #test :hi raw body\r\n".to_string())
);
}
#[tokio::test]
async fn two_string_args_pull_successive_captures() {
let entry = &handlers()[7]; let tc = TestContext::builder()
.target("#test")
.captures(vec!["foo".to_string(), "bar".to_string()])
.build();
assert_eq!(
invoke(entry, tc).await,
Some("PRIVMSG #test :foo-bar\r\n".to_string())
);
}
#[tokio::test]
async fn user_arg_filled_from_sender() {
let entry = &handlers()[8]; let tc = TestContext::builder()
.target("#test")
.sender_nick("zaphod")
.build();
assert_eq!(
invoke(entry, tc).await,
Some("PRIVMSG #test :zaphod\r\n".to_string())
);
}