missive 0.7.0

Compose, deliver, preview, and test emails in Rust - pluggable providers with zero configuration code
Documentation
//! Email struct tests.
//!
//! Ported from Swoosh's email_test.exs

use missive::{Address, Email};
use serde_json::json;

// ============================================================================
// Constructor Tests
// ============================================================================

#[test]
fn new_creates_empty_email() {
    let email = Email::new();
    assert!(email.from_address().is_none());
    assert!(email.to_addresses().is_empty());
    assert!(email.subject_line().is_empty());
    assert!(email.html_body_content().is_none());
    assert!(email.text_body_content().is_none());
}

// ============================================================================
// From Tests
// ============================================================================

#[test]
fn from_sets_sender_from_string() {
    let email = Email::new().from("tony.stark@example.com");
    let from = email.from_address().unwrap();
    assert_eq!(from.email(), "tony.stark@example.com");
    assert!(from.display_name().is_none());
}

#[test]
fn from_sets_sender_from_tuple() {
    let email = Email::new().from(("Steve Rogers", "steve.rogers@example.com"));
    let from = email.from_address().unwrap();
    assert_eq!(from.email(), "steve.rogers@example.com");
    assert_eq!(from.display_name(), Some("Steve Rogers"));
}

#[test]
fn from_replaces_previous_sender() {
    let email = Email::new()
        .from("tony.stark@example.com")
        .from(("Steve Rogers", "steve.rogers@example.com"));
    let from = email.from_address().unwrap();
    assert_eq!(from.email(), "steve.rogers@example.com");
}

// ============================================================================
// Subject Tests
// ============================================================================

#[test]
fn subject_sets_subject() {
    let email = Email::new().subject("Hello, Avengers!");
    assert_eq!(email.subject_line(), "Hello, Avengers!");
}

#[test]
fn subject_replaces_previous_subject() {
    let email = Email::new()
        .subject("Hello, Avengers!")
        .subject("Welcome, I am Jarvis");
    assert_eq!(email.subject_line(), "Welcome, I am Jarvis");
}

// ============================================================================
// Body Tests
// ============================================================================

#[test]
fn html_body_sets_html_body() {
    let email = Email::new().html_body("<h1>Hello, Avengers!</h1>");
    assert_eq!(email.html_body_content(), Some("<h1>Hello, Avengers!</h1>"));
}

#[test]
fn html_body_replaces_previous_html_body() {
    let email = Email::new()
        .html_body("<h1>Hello, Avengers!</h1>")
        .html_body("<h1>Welcome, I am Jarvis</h1>");
    assert_eq!(
        email.html_body_content(),
        Some("<h1>Welcome, I am Jarvis</h1>")
    );
}

#[test]
fn text_body_sets_text_body() {
    let email = Email::new().text_body("Hello, Avengers!");
    assert_eq!(email.text_body_content(), Some("Hello, Avengers!"));
}

#[test]
fn text_body_replaces_previous_text_body() {
    let email = Email::new()
        .text_body("Hello, Avengers!")
        .text_body("Welcome, I am Jarvis");
    assert_eq!(email.text_body_content(), Some("Welcome, I am Jarvis"));
}

// ============================================================================
// Reply-To Tests
// ============================================================================

#[test]
fn reply_to_sets_reply_to_from_string() {
    let email = Email::new().reply_to("welcome.avengers@example.com");
    assert_eq!(email.reply_to_addresses().len(), 1);
    assert_eq!(
        email.reply_to_addresses()[0].email(),
        "welcome.avengers@example.com"
    );
}

#[test]
fn reply_to_sets_reply_to_from_tuple() {
    let email = Email::new().reply_to(("Jarvis Assist", "help.jarvis@example.com"));
    assert_eq!(email.reply_to_addresses().len(), 1);
    assert_eq!(
        email.reply_to_addresses()[0].email(),
        "help.jarvis@example.com"
    );
    assert_eq!(
        email.reply_to_addresses()[0].display_name(),
        Some("Jarvis Assist")
    );
}

// ============================================================================
// To Tests
// ============================================================================

#[test]
fn to_adds_recipient() {
    let email = Email::new().to("tony.stark@example.com");
    assert_eq!(email.to_addresses().len(), 1);
    assert_eq!(email.to_addresses()[0].email(), "tony.stark@example.com");
}

#[test]
fn to_adds_multiple_recipients() {
    let email = Email::new()
        .to("tony.stark@example.com")
        .to(("Steve Rogers", "steve.rogers@example.com"));

    assert_eq!(email.to_addresses().len(), 2);
    assert_eq!(email.to_addresses()[0].email(), "tony.stark@example.com");
    assert_eq!(email.to_addresses()[1].email(), "steve.rogers@example.com");
    assert_eq!(email.to_addresses()[1].display_name(), Some("Steve Rogers"));
}

#[test]
fn to_adds_recipient_with_name() {
    let email = Email::new().to(("Thor Odinson", "thor.odinson@example.com"));
    assert_eq!(email.to_addresses()[0].email(), "thor.odinson@example.com");
    assert_eq!(email.to_addresses()[0].display_name(), Some("Thor Odinson"));
}

// ============================================================================
// CC Tests
// ============================================================================

#[test]
fn cc_adds_recipient() {
    let email = Email::new().cc("natasha.romanoff@example.com");
    assert_eq!(email.cc_addresses().len(), 1);
    assert_eq!(
        email.cc_addresses()[0].email(),
        "natasha.romanoff@example.com"
    );
}

#[test]
fn cc_adds_multiple_recipients() {
    let email = Email::new()
        .cc("natasha.romanoff@example.com")
        .cc(("Steve Rogers", "steve.rogers@example.com"));

    assert_eq!(email.cc_addresses().len(), 2);
    assert_eq!(
        email.cc_addresses()[0].email(),
        "natasha.romanoff@example.com"
    );
    assert_eq!(email.cc_addresses()[1].email(), "steve.rogers@example.com");
}

// ============================================================================
// BCC Tests
// ============================================================================

#[test]
fn bcc_adds_recipient() {
    let email = Email::new().bcc("loki.odinson@example.com");
    assert_eq!(email.bcc_addresses().len(), 1);
    assert_eq!(email.bcc_addresses()[0].email(), "loki.odinson@example.com");
}

#[test]
fn bcc_adds_multiple_recipients() {
    let email = Email::new()
        .bcc("loki.odinson@example.com")
        .bcc(("Bruce Banner", "hulk.smash@example.com"));

    assert_eq!(email.bcc_addresses().len(), 2);
    assert_eq!(email.bcc_addresses()[0].email(), "loki.odinson@example.com");
    assert_eq!(email.bcc_addresses()[1].email(), "hulk.smash@example.com");
}

// ============================================================================
// Header Tests
// ============================================================================

#[test]
fn header_adds_header() {
    let email = Email::new().header("X-Accept-Language", "en");
    assert_eq!(
        email.headers().get("X-Accept-Language"),
        Some(&"en".to_string())
    );
}

#[test]
fn header_adds_multiple_headers() {
    let email = Email::new()
        .header("X-Accept-Language", "en")
        .header("X-Mailer", "missive");

    assert_eq!(
        email.headers().get("X-Accept-Language"),
        Some(&"en".to_string())
    );
    assert_eq!(
        email.headers().get("X-Mailer"),
        Some(&"missive".to_string())
    );
}

#[test]
fn header_replaces_existing_header() {
    let email = Email::new()
        .header("X-Mailer", "old-mailer")
        .header("X-Mailer", "missive");

    assert_eq!(
        email.headers().get("X-Mailer"),
        Some(&"missive".to_string())
    );
}

// ============================================================================
// Private Data Tests
// ============================================================================

#[test]
fn put_private_adds_private_data() {
    let email = Email::new().put_private("phoenix_layout", json!(false));
    assert_eq!(email.private().get("phoenix_layout"), Some(&json!(false)));
}

#[test]
fn put_private_adds_multiple_private_data() {
    let email = Email::new()
        .put_private("key1", json!("value1"))
        .put_private("key2", json!(42));

    assert_eq!(email.private().get("key1"), Some(&json!("value1")));
    assert_eq!(email.private().get("key2"), Some(&json!(42)));
}

// ============================================================================
// Provider Options Tests
// ============================================================================

#[test]
fn provider_option_adds_option() {
    let email = Email::new().provider_option("tag", "welcome");
    assert_eq!(email.provider_options().get("tag"), Some(&json!("welcome")));
}

#[test]
fn provider_option_adds_complex_option() {
    let email = Email::new().provider_option(
        "tags",
        json!([{"name": "category", "value": "confirm_email"}]),
    );
    assert_eq!(
        email.provider_options().get("tags"),
        Some(&json!([{"name": "category", "value": "confirm_email"}]))
    );
}

// ============================================================================
// Assign Tests
// ============================================================================

#[test]
fn assign_adds_template_variable() {
    let email = Email::new()
        .assign("name", "Tony Stark")
        .assign("team", "Avengers");

    assert_eq!(email.assigns().get("name"), Some(&json!("Tony Stark")));
    assert_eq!(email.assigns().get("team"), Some(&json!("Avengers")));
}

// ============================================================================
// Validation Tests
// ============================================================================

#[test]
fn is_valid_returns_true_for_complete_email() {
    let email = Email::new()
        .from("tony.stark@example.com")
        .to("steve.rogers@example.com")
        .subject("Hello")
        .text_body("Hi there");

    assert!(email.is_valid());
}

#[test]
fn is_valid_returns_false_without_from() {
    let email = Email::new()
        .to("steve.rogers@example.com")
        .subject("Hello")
        .text_body("Hi there");

    assert!(!email.is_valid());
}

#[test]
fn is_valid_returns_false_without_to() {
    let email = Email::new()
        .from("tony.stark@example.com")
        .subject("Hello")
        .text_body("Hi there");

    assert!(!email.is_valid());
}

// ============================================================================
// Address Formatting Tests
// ============================================================================

#[test]
fn address_formatted_without_name() {
    let addr = Address::new("tony.stark@example.com");
    assert_eq!(addr.formatted(), "tony.stark@example.com");
}

#[test]
fn address_formatted_with_name() {
    let addr = Address::with_name("Tony Stark", "tony.stark@example.com");
    assert_eq!(addr.formatted(), "Tony Stark <tony.stark@example.com>");
}

#[test]
fn address_formatted_rfc5322_escapes_special_chars() {
    let addr = Address::with_name("Stark, Tony", "tony.stark@example.com");
    assert_eq!(
        addr.formatted_rfc5322(),
        "\"Stark, Tony\" <tony.stark@example.com>"
    );
}