mod common;

use milter::*;
use std::net::{Ipv4Addr, SocketAddr};

#[test]
fn all_stages() {
    let test_name = common::test_name(file!());
    let miltertest = common::spawn_miltertest_runner(file!());

    Milter::new("inet:3334@localhost")
        .name(test_name.to_str().unwrap())
        .on_connect(connect_callback)
        .on_helo(helo_callback)
        .on_mail(mail_callback)
        .on_rcpt(rcpt_callback)
        .on_data(data_callback)
        .on_header(header_callback)
        .on_eoh(eoh_callback)
        .on_body(body_callback)
        .on_eom(eom_callback)
        .on_close(close_callback)
        .run()
        .expect("milter execution failed");

    let exit_code = miltertest.join().expect("panic in miltertest runner");
    assert!(exit_code.success(), "miltertest returned error exit code");
}

#[on_connect(connect_callback)]
fn handle_connect(_: Context<()>, hostname: &str, socket_address: Option<SocketAddr>) -> Status {
    assert_eq!(hostname, "client.example.com");

    assert!(socket_address.is_some());
    assert_eq!(socket_address.unwrap().ip(), Ipv4Addr::new(123, 123, 123, 123));

    Status::Continue
}

#[on_helo(helo_callback)]
fn handle_helo(_: Context<()>, helo_host: &str) -> Status {
    assert_eq!(helo_host, "mail.example.com");

    Status::Continue
}

#[on_mail(mail_callback)]
fn handle_mail(_: Context<()>, smtp_args: Vec<&str>) -> Status {
    assert_eq!(smtp_args[0], "from@example.com");

    Status::Continue
}

#[on_rcpt(rcpt_callback)]
fn handle_rcpt(_: Context<()>, smtp_args: Vec<&str>) -> Status {
    assert_eq!(smtp_args[0], "to@example.com");

    Status::Continue
}

#[on_data(data_callback)]
fn handle_data(_: Context<()>) -> Status {
    Status::Continue
}

#[on_header(header_callback)]
fn handle_header(_: Context<()>, name: &str, value: &str) -> Status {
    assert_eq!(name, "Test-Name");
    assert_eq!(value, "Test-Value");

    Status::Continue
}

#[on_eoh(eoh_callback)]
fn handle_eoh(_: Context<()>) -> Status {
    Status::Continue
}

#[on_body(body_callback)]
fn handle_body(_: Context<()>, content: &[u8]) -> Status {
    assert_eq!(content, b"body");

    Status::Continue
}

#[on_eom(eom_callback)]
fn handle_eom(_: Context<()>) -> Status {
    Status::Continue
}

#[on_close(close_callback)]
fn handle_close(_: Context<()>) -> Status {
    Status::Continue
}
