use ircbot::{bot, Context, Result};
#[bot]
impl MyBot {
#[command("ping")]
async fn ping(&self, ctx: Context) -> Result {
ctx.reply("pong!")
}
#[command("echo")]
async fn echo(&self, ctx: Context, text: String) -> Result {
ctx.say(text)
}
#[on(message = "hello *")]
async fn greet(&self, ctx: Context, who: String) -> Result {
ctx.say(format!("Hello, {who}!"))
}
#[on(event = "JOIN", target = "#rust")]
async fn welcome(&self, ctx: Context) -> Result {
if let Some(user) = &ctx.sender {
ctx.say(format!("Welcome to #rust, {}!", user.nick))
} else {
Ok(())
}
}
#[on(mention)]
async fn on_mention(&self, ctx: Context, text: String) -> Result {
ctx.reply(format!("You said: {}", text))
}
#[on(mention, target = "#rust")]
async fn on_mention_rust(&self, ctx: Context) -> Result {
ctx.notice("I heard you!").await
}
#[command("secret")]
async fn secret(&self, ctx: Context) -> Result {
ctx.whisper("This is just between us.").await
}
#[on(
cron = "0 0 8-16 * * MON-FRI",
tz = "America/New_York",
target = "#rust"
)]
async fn hourly_reminder(&self, ctx: Context) -> Result {
ctx.say("Reminder: be excellent to each other!")
}
}
#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
println!("basic_bot example compiled successfully.");
println!("To connect for real, uncomment the lines below and point at a live server:");
println!(" let bot = MyBot::new(\"ircbot\", \"irc.libera.chat:6667\", [\"#rust\"]).await?;");
println!(" bot.main_loop().await?;");
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use ircbot::testing::TestContext;
#[tokio::test]
async fn ping_replies_with_nick_prefix_in_channel() {
let bot = MyBot::default();
let mut tc = TestContext::channel("#test", "alice", "!ping");
bot.ping(tc.take_ctx()).await.unwrap();
assert_eq!(
tc.next_reply(),
Some("PRIVMSG #test :alice, pong!\r\n".to_string()),
);
}
#[tokio::test]
async fn ping_replies_without_prefix_in_query() {
let bot = MyBot::default();
let mut tc = TestContext::private("alice", "!ping");
bot.ping(tc.take_ctx()).await.unwrap();
assert_eq!(
tc.next_reply(),
Some("PRIVMSG alice :pong!\r\n".to_string()),
);
}
#[tokio::test]
async fn echo_says_the_provided_text() {
let bot = MyBot::default();
let mut tc = TestContext::channel("#test", "alice", "!echo hello world");
bot.echo(tc.take_ctx(), "hello world".to_string())
.await
.unwrap();
assert_eq!(
tc.next_reply(),
Some("PRIVMSG #test :hello world\r\n".to_string()),
);
}
#[tokio::test]
async fn greet_says_hello_with_captured_name() {
let bot = MyBot::default();
let mut tc = TestContext::channel("#test", "alice", "hello rust");
bot.greet(tc.take_ctx(), "rust".to_string()).await.unwrap();
assert_eq!(
tc.next_reply(),
Some("PRIVMSG #test :Hello, rust!\r\n".to_string()),
);
}
#[tokio::test]
async fn welcome_greets_new_user_in_rust_channel() {
let bot = MyBot::default();
let mut tc = TestContext::builder()
.target("#rust")
.is_channel(true)
.sender_nick("newuser")
.build();
bot.welcome(tc.take_ctx()).await.unwrap();
assert_eq!(
tc.next_reply(),
Some("PRIVMSG #rust :Welcome to #rust, newuser!\r\n".to_string()),
);
}
#[tokio::test]
async fn on_mention_echoes_the_addressed_text() {
let bot = MyBot::default();
let mut tc = TestContext::channel("#test", "alice", "testbot: greetings");
bot.on_mention(tc.take_ctx(), "greetings".to_string())
.await
.unwrap();
assert_eq!(
tc.next_reply(),
Some("PRIVMSG #test :alice, You said: greetings\r\n".to_string()),
);
}
#[tokio::test]
async fn on_mention_rust_sends_notice() {
let bot = MyBot::default();
let mut tc = TestContext::builder()
.target("#rust")
.is_channel(true)
.sender_nick("alice")
.build();
bot.on_mention_rust(tc.take_ctx()).await.unwrap();
assert_eq!(
tc.next_reply(),
Some("NOTICE #rust :I heard you!\r\n".to_string()),
);
}
#[tokio::test]
async fn secret_whispers_to_sender_regardless_of_channel() {
let bot = MyBot::default();
let mut tc = TestContext::channel("#test", "alice", "!secret");
bot.secret(tc.take_ctx()).await.unwrap();
assert_eq!(
tc.next_reply(),
Some("PRIVMSG alice :This is just between us.\r\n".to_string()),
);
}
#[tokio::test]
async fn hourly_reminder_says_to_channel() {
let bot = MyBot::default();
let mut tc = TestContext::builder()
.target("#rust")
.is_channel(true)
.build();
bot.hourly_reminder(tc.take_ctx()).await.unwrap();
assert_eq!(
tc.next_reply(),
Some("PRIVMSG #rust :Reminder: be excellent to each other!\r\n".to_string()),
);
}
}