correlate 0.3.0

correlate is a standalone server that listens for Stripe webhook events and sends notification emails about successful orders.
#[cfg(test)]
mod my_tests {

    use crate::stripe::{
        charge::{StripeCharge, StripeChargeStatus},
        checkout::{
            StripeCheckoutSession, StripeMode, StripeObjectType, StripePaymentStatus,
            StripeSessionStatus,
        },
        customer::StripeCustomerDetails,
        date::StripeDate,
        StripeCurrency,
    };
    use chrono::Local;
    use pretty_assertions::assert_eq;

    #[test]
    fn test_checkout_session_successful() {
        let session = StripeCheckoutSession {
            id: "cs_test_123".to_string(),
            object_type: StripeObjectType::CheckoutSession,
            amount_subtotal: 1000,
            amount_total: 1000,
            created: StripeDate::new(1234567890),
            currency: StripeCurrency::USD,
            mode: StripeMode::Payment,
            payment_status: StripePaymentStatus::Paid,
            status: StripeSessionStatus::Complete,
            customer_details: Some(StripeCustomerDetails {
                email: "mail@address.com".to_string(),
                name: "Email Client".to_string(),
            }),
            url: "https://example.com".to_string(),
        };

        assert!(session.is_successful());
        assert!(session.has_valid_object_type());
    }

    #[test]
    fn test_checkout_session_formatted_amount() {
        let mut session = StripeCheckoutSession {
            id: "cs_test_123".to_string(),
            object_type: StripeObjectType::CheckoutSession,
            amount_subtotal: 1000,
            amount_total: 1000,
            created: StripeDate::new(1234567890),
            currency: StripeCurrency::USD,
            mode: StripeMode::Payment,
            payment_status: StripePaymentStatus::Paid,
            status: StripeSessionStatus::Complete,
            customer_details: Some(StripeCustomerDetails {
                email: "mail@address.com".to_string(),
                name: "Email Client".to_string(),
            }),
            url: "https://example.com".to_string(),
        };

        assert_eq!(session.formatted_amount_total(), "$10.00");

        session.currency = StripeCurrency::EUR;
        assert_eq!(session.formatted_amount_total(), "€10.00");

        session.currency = StripeCurrency::CAD;
        assert_eq!(session.formatted_amount_total(), "CA$\u{a0}10.00");

        session.amount_total = 1250;
        assert_eq!(session.formatted_amount_total(), "CA$\u{a0}12.50");

        session.amount_total = 5;
        assert_eq!(session.formatted_amount_total(), "CA$\u{a0}0.05");
    }

    #[test]
    fn test_charge_successful() {
        let charge = StripeCharge {
            id: "ch_123456",
            created: StripeDate::new(1620000000),
            currency: StripeCurrency::USD,
            paid: true,
            status: StripeChargeStatus::Succeeded,
            amount: 1000,
            billing_details: StripeCustomerDetails {
                email: "mail@address.com".to_string(),
                name: "Email Client".to_string(),
            },
            calculated_statement_descriptor: Some("Test Store"),
            receipt_url: Some("https://receipt.stripe.com/test"),
        };

        assert!(charge.is_successful());
    }

    #[test]
    fn test_charge_unsuccessful() {
        let failed_charge = StripeCharge {
            id: "ch_123456",
            created: StripeDate::new(1620000000),
            currency: StripeCurrency::USD,
            paid: true,
            // change to failing status
            status: StripeChargeStatus::Failed,
            amount: 1000,
            billing_details: StripeCustomerDetails {
                email: "mail@address.com".to_string(),
                name: "Email Client".to_string(),
            },
            calculated_statement_descriptor: Some("Test Store"),
            receipt_url: Some("https://receipt.stripe.com/test"),
        };

        assert!(!failed_charge.is_successful());

        let unpaid_charge = &StripeCharge {
            paid: false,
            status: StripeChargeStatus::Succeeded,
            ..failed_charge
        };

        assert!(!unpaid_charge.is_successful());
    }

    #[test]
    fn test_charge_formatted_amount() {
        let mut charge = StripeCharge {
            id: "ch_123456",
            created: StripeDate::new(1620000000),
            currency: StripeCurrency::USD,
            paid: true,
            status: StripeChargeStatus::Succeeded,
            amount: 1000,
            billing_details: StripeCustomerDetails {
                email: "mail@address.com".to_string(),
                name: "Email Client".to_string(),
            },
            calculated_statement_descriptor: Some("Test Store"),
            receipt_url: Some("https://receipt.stripe.com/test"),
        };

        assert_eq!(charge.formatted_amount(), "$10.00");

        charge.currency = StripeCurrency::EUR;
        assert_eq!(charge.formatted_amount(), "€10.00");

        charge.currency = StripeCurrency::CAD;
        assert_eq!(charge.formatted_amount(), "CA$\u{a0}10.00");

        charge.amount = 1250;
        assert_eq!(charge.formatted_amount(), "CA$\u{a0}12.50");

        charge.amount = 5;
        assert_eq!(charge.formatted_amount(), "CA$\u{a0}0.05");
    }

    #[test]
    fn test_stripe_date_localtime() {
        let timestamp = 1234567890;
        let date = StripeDate::new(timestamp);

        // Test conversion to string
        let formatted = date.to_string();
        assert!(!formatted.is_empty());

        // Test conversion to DateTime<Local>
        let datetime = date.into_inner();
        assert_eq!(datetime.timestamp(), timestamp);
    }

    #[test]
    fn test_stripe_date_relative_time() {
        let now = Local::now().timestamp();
        let date = StripeDate::new(now - 3600); // 1 hour ago

        let relative = date.relative_time();
        assert!(relative.contains("hour"));
    }

    #[test]
    fn test_currency_display() {
        assert_eq!(StripeCurrency::CAD.to_string(), "CA$\u{a0}");
        assert_eq!(StripeCurrency::EUR.to_string(), "");
        assert_eq!(StripeCurrency::GBP.to_string(), "£");
        assert_eq!(StripeCurrency::USD.to_string(), "$");
    }
}