#[test]
fn a_value_is_written_as_its_spelling_where_a_person_reads_the_format() {
use serde::{Deserialize, Serialize};
use serde_json::{from_str, to_string};
use t2t_core::{Timedelta, Timestamp};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Job {
start: Timestamp,
every: Timedelta,
}
let job: Job = from_str(r#"{"start":"2026-09-16T07:45:00Z","every":"1m30s"}"#).expect("a job");
assert_eq!(job.every, Timedelta::from_secs(90), "a span, from its spelling");
let written = to_string(&job).expect("a timestamp and a span always serialize");
let expected = r#"{"start":"2026-09-16T07:45:00.000000000Z","every":"1m30s"}"#;
assert_eq!(written, expected, "and written back as the spellings `Display` writes");
}
#[test]
fn a_format_no_person_reads_takes_the_count() {
use serde_test::{Configure as _, Token, assert_tokens};
use t2t_core::{TickRate, Timedelta, Timestamp};
let span = Timedelta::from_secs(90);
assert_tokens(&span.readable(), &[Token::Str("1m30s")]);
assert_tokens(&span.compact(), &[Token::I64(90_000_000_000)]);
assert_tokens(&Timestamp::UNIX_EPOCH.compact(), &[Token::I64(0)]);
let rate = TickRate::from_hertz(24_000_000).expect("a rate above zero");
assert_tokens(&rate.compact(), &[Token::U64(24_000_000)]);
}
#[test]
fn a_count_in_a_named_unit_takes_a_module() {
use serde::{Deserialize, Serialize};
use serde_json::{from_str, to_string};
use t2t_core::serde::{timedelta, timestamp};
use t2t_core::{Timedelta, Timestamp};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Job {
#[serde(with = "timestamp::millis")]
received: Timestamp,
#[serde(with = "timestamp::nanos")]
started: Timestamp,
#[serde(with = "timedelta::secs::option")]
timeout: Option<Timedelta>,
}
let sent = r#"{"received":1789544735123,"started":"1789544735123456789","timeout":"30"}"#;
let job: Job = from_str(sent).expect("a job");
assert_eq!(job.received, Timestamp::from_millis(1_789_544_735_123), "a number");
assert_eq!(job.timeout, Some(Timedelta::from_secs(30)), "or a decimal string");
let written = to_string(&job).expect("each field serializes as a number or a string");
let expected = r#"{"received":1789544735123,"started":"1789544735123456789","timeout":30}"#;
assert_eq!(written, expected, "nanoseconds since the epoch in a string, the rest as numbers");
}
#[test]
fn a_count_past_the_range_is_refused_and_a_finer_one_rounded_down() {
use serde::{Deserialize, Serialize};
use serde_json::{from_str, to_string};
use t2t_core::Timestamp;
use t2t_core::serde::timestamp;
#[derive(Debug, Serialize, Deserialize)]
struct Stamp {
#[serde(with = "timestamp::secs")]
published: Timestamp,
}
let refused = from_str::<Stamp>(r#"{"published":253402300799}"#).expect_err("the year 9999");
let reason = refused.to_string();
assert!(reason.starts_with("out of range error"), "past 2262: {reason}");
let stamp = Stamp { published: Timestamp::from_millis(1_789_544_735_999) };
let written = to_string(&stamp).expect("a count of seconds always serializes");
assert_eq!(written, r#"{"published":1789544735}"#, "the second the moment falls in");
}