midiserde 0.1.1

When mini isn't enough and serde is too much
Documentation
//! Tests for chrono `with` modules (rfc3339, timestamp, time_delta).
//!
//! Run: `cargo test -p midiserde --features chrono chrono`
//! Or: `cargo test -p midiserde chrono` (with default includes macros)

#[cfg(not(feature = "chrono"))]
#[test]
fn chrono_feature_disabled() {
    // Stub when chrono is off — file must compile.
}

#[cfg(feature = "chrono")]
mod tests {
    use chrono::TimeZone;
    use midiserde::{json, Deserialize, Serialize};

    #[derive(Debug, PartialEq, Deserialize, Serialize)]
    struct WithRfc3339 {
        name: String,
        #[mini(with = "midiserde::with::rfc3339")]
        created_at: chrono::DateTime<chrono::Utc>,
    }

    #[derive(Debug, PartialEq, Deserialize, Serialize)]
    struct WithTimestamp {
        name: String,
        #[mini(with = "midiserde::with::timestamp")]
        created_at: chrono::DateTime<chrono::Utc>,
    }

    #[derive(Debug, PartialEq, Deserialize, Serialize)]
    struct WithTimeDelta {
        name: String,
        #[mini(with = "midiserde::with::time_delta")]
        timeout: chrono::TimeDelta,
    }

    #[test]
    fn rfc3339_roundtrip() {
        let dt = chrono::Utc.with_ymd_and_hms(2024, 2, 21, 14, 30, 0).unwrap();
        let v = WithRfc3339 {
            name: "event".into(),
            created_at: dt,
        };
        let j = json::to_string(&v);
        let parsed: WithRfc3339 = json::from_str(&j).unwrap();
        assert_eq!(v, parsed);
    }

    #[test]
    fn timestamp_roundtrip() {
        let dt = chrono::Utc.with_ymd_and_hms(2024, 2, 21, 14, 30, 0).unwrap();
        let v = WithTimestamp {
            name: "event".into(),
            created_at: dt,
        };
        let j = json::to_string(&v);
        let ts_str = dt.timestamp().to_string();
        assert!(j.contains(&format!(r#""created_at":{}"#, ts_str)));
        let parsed: WithTimestamp = json::from_str(&j).unwrap();
        assert_eq!(v, parsed);
    }

    #[test]
    fn time_delta_roundtrip() {
        let td = chrono::TimeDelta::try_seconds(30).unwrap();
        let v = WithTimeDelta {
            name: "config".into(),
            timeout: td,
        };
        let j = json::to_string(&v);
        assert!(j.contains(r#""timeout":[30,0]"#));
        let parsed: WithTimeDelta = json::from_str(&j).unwrap();
        assert_eq!(v, parsed);
    }

    #[test]
    fn rfc3339_from_string() {
        let j = r#"{"name": "event", "created_at": "2024-02-21T14:30:00Z"}"#;
        let result: Result<WithRfc3339, _> = json::from_str(j);
        assert!(result.is_ok());
        let v = result.unwrap();
        assert_eq!(v.name, "event");
        assert_eq!(
            v.created_at,
            chrono::Utc.with_ymd_and_hms(2024, 2, 21, 14, 30, 0).unwrap()
        );
    }

    #[test]
    fn rfc3339_invalid_string() {
        let j = r#"{"name": "event", "created_at": "not-a-date"}"#;
        let result: Result<WithRfc3339, _> = json::from_str(j);
        assert!(result.is_err());
    }

    #[test]
    fn timestamp_invalid_string() {
        let j = r#"{"name": "event", "created_at": "not-a-number"}"#;
        let result: Result<WithTimestamp, _> = json::from_str(j);
        assert!(result.is_err());
    }

    #[test]
    fn time_delta_invalid() {
        let j = r#"{"name": "config", "timeout": "30"}"#;
        let result: Result<WithTimeDelta, _> = json::from_str(j);
        assert!(result.is_err());
    }
}