280 lines
12 KiB
EmacsLisp
280 lines
12 KiB
EmacsLisp
// tests/suite/test_time.el — comprehensive tests for runtime/time.el
|
|
//
|
|
// Covers time_now, now_millis, unix_timestamp, now_ns, time_format, time_to_parts,
|
|
// time_add, time_diff, duration helpers, and uuid_new.
|
|
|
|
// ── time_now / now_millis / unix_timestamp_ms ─────────────────────────────────
|
|
|
|
fn test_time_now_basic(_: String) -> String {
|
|
let t: Int = time_now()
|
|
// Milliseconds since epoch: must be well past year 2020 (1577836800000)
|
|
assert_true(t > 1577836800000, "time_now is past 2020-01-01")
|
|
// Must be before year 2100 (4102444800000)
|
|
assert_true(t < 4102444800000, "time_now is before 2100-01-01")
|
|
return ""
|
|
}
|
|
|
|
fn test_now_millis_basic(_: String) -> String {
|
|
let t: Int = now_millis()
|
|
assert_true(t > 1577836800000, "now_millis is past 2020-01-01")
|
|
assert_true(t < 4102444800000, "now_millis is before 2100-01-01")
|
|
return ""
|
|
}
|
|
|
|
fn test_unix_timestamp_ms_basic(_: String) -> String {
|
|
let t: Int = unix_timestamp_ms()
|
|
assert_true(t > 1577836800000, "unix_timestamp_ms is past 2020-01-01")
|
|
assert_true(t < 4102444800000, "unix_timestamp_ms is before 2100-01-01")
|
|
return ""
|
|
}
|
|
|
|
fn test_time_now_ms_alias(_: String) -> String {
|
|
let t: Int = time_now_ms()
|
|
assert_true(t > 1577836800000, "time_now_ms is past 2020-01-01")
|
|
assert_true(t < 4102444800000, "time_now_ms is before 2100-01-01")
|
|
return ""
|
|
}
|
|
|
|
// ── monotonicity ──────────────────────────────────────────────────────────────
|
|
|
|
fn test_time_monotonic_now_millis(_: String) -> String {
|
|
let t1: Int = now_millis()
|
|
let t2: Int = now_millis()
|
|
assert_true(t2 >= t1, "second call >= first call (monotonic)")
|
|
return ""
|
|
}
|
|
|
|
fn test_time_monotonic_time_now(_: String) -> String {
|
|
let t1: Int = time_now()
|
|
let t2: Int = time_now()
|
|
assert_true(t2 >= t1, "time_now is monotonic across calls")
|
|
return ""
|
|
}
|
|
|
|
fn test_time_monotonic_now_ns(_: String) -> String {
|
|
let t1: Int = now_ns()
|
|
let t2: Int = now_ns()
|
|
assert_true(t2 >= t1, "now_ns is monotonic across calls")
|
|
// ns should be much larger than ms (9 digits difference)
|
|
assert_true(t1 > 1000000000000000000, "now_ns is in nanosecond scale")
|
|
return ""
|
|
}
|
|
|
|
// ── unix_timestamp (seconds) ─────────────────────────────────────────────────
|
|
|
|
fn test_unix_timestamp_basic(_: String) -> String {
|
|
let secs: Int = unix_timestamp()
|
|
// Must be past 2020-01-01 in seconds (1577836800)
|
|
assert_true(secs > 1577836800, "unix_timestamp is past 2020-01-01")
|
|
// Must be before 2100-01-01 in seconds (4102444800)
|
|
assert_true(secs < 4102444800, "unix_timestamp is before 2100-01-01")
|
|
// seconds are about 1000x smaller than millis
|
|
let ms: Int = time_now()
|
|
assert_true(ms > secs, "milliseconds > seconds")
|
|
return ""
|
|
}
|
|
|
|
// ── time_to_parts ─────────────────────────────────────────────────────────────
|
|
|
|
fn test_time_to_parts_basic(_: String) -> String {
|
|
// Known timestamp: 2024-01-15 12:30:45.123 UTC
|
|
// 2024-01-15 00:00:00 UTC = epoch + (54 * 365 + 14 leaps) days approximately
|
|
// Use a precisely known value: 2024-01-15T12:30:45.123Z
|
|
// epoch_ms = 1705320645123
|
|
let ts: Int = 1705320645123
|
|
let parts: String = time_to_parts(ts)
|
|
assert_eq(json_get(parts, "year"), "2024", "year is 2024")
|
|
assert_eq(json_get(parts, "month"), "1", "month is 1 (January)")
|
|
assert_eq(json_get(parts, "day"), "15", "day is 15")
|
|
assert_eq(json_get(parts, "hour"), "12", "hour is 12")
|
|
assert_eq(json_get(parts, "minute"), "30", "minute is 30")
|
|
assert_eq(json_get(parts, "second"), "45", "second is 45")
|
|
assert_eq(json_get(parts, "ms"), "123", "milliseconds is 123")
|
|
return ""
|
|
}
|
|
|
|
fn test_time_to_parts_epoch(_: String) -> String {
|
|
// Unix epoch: 1970-01-01T00:00:00.000Z = timestamp 0
|
|
let parts: String = time_to_parts(0)
|
|
assert_eq(json_get(parts, "year"), "1970", "epoch year is 1970")
|
|
assert_eq(json_get(parts, "month"), "1", "epoch month is 1")
|
|
assert_eq(json_get(parts, "day"), "1", "epoch day is 1")
|
|
assert_eq(json_get(parts, "hour"), "0", "epoch hour is 0")
|
|
assert_eq(json_get(parts, "minute"), "0", "epoch minute is 0")
|
|
assert_eq(json_get(parts, "second"), "0", "epoch second is 0")
|
|
return ""
|
|
}
|
|
|
|
fn test_time_to_parts_current(_: String) -> String {
|
|
let ts: Int = time_now()
|
|
let parts: String = time_to_parts(ts)
|
|
let year: Int = str_to_int(json_get(parts, "year"))
|
|
let month: Int = str_to_int(json_get(parts, "month"))
|
|
let day: Int = str_to_int(json_get(parts, "day"))
|
|
let hour: Int = str_to_int(json_get(parts, "hour"))
|
|
let minute: Int = str_to_int(json_get(parts, "minute"))
|
|
let second: Int = str_to_int(json_get(parts, "second"))
|
|
assert_true(year >= 2024, "current year >= 2024")
|
|
assert_true(year < 2100, "current year < 2100")
|
|
assert_true(month >= 1, "month >= 1")
|
|
assert_true(month <= 12, "month <= 12")
|
|
assert_true(day >= 1, "day >= 1")
|
|
assert_true(day <= 31, "day <= 31")
|
|
assert_true(hour >= 0, "hour >= 0")
|
|
assert_true(hour <= 23, "hour <= 23")
|
|
assert_true(minute >= 0, "minute >= 0")
|
|
assert_true(minute <= 59, "minute <= 59")
|
|
assert_true(second >= 0, "second >= 0")
|
|
assert_true(second <= 59, "second <= 59")
|
|
return ""
|
|
}
|
|
|
|
// ── time_format ───────────────────────────────────────────────────────────────
|
|
|
|
fn test_time_format_iso(_: String) -> String {
|
|
let ts: Int = 1705320645123
|
|
let iso: String = time_format(ts, "ISO")
|
|
assert_starts_with(iso, "2024-01-15", "ISO format starts with correct date")
|
|
assert_contains(iso, "T12:30:45", "ISO format has correct time")
|
|
assert_ends_with(iso, "Z", "ISO format ends with Z")
|
|
assert_contains(iso, "123", "ISO format includes milliseconds")
|
|
return ""
|
|
}
|
|
|
|
fn test_time_format_empty(_: String) -> String {
|
|
let ts: Int = 1705320645123
|
|
let iso: String = time_format(ts, "")
|
|
assert_starts_with(iso, "2024-01-15", "empty fmt gives ISO format")
|
|
assert_ends_with(iso, "Z", "empty fmt gives ISO format ending in Z")
|
|
return ""
|
|
}
|
|
|
|
fn test_time_format_strftime(_: String) -> String {
|
|
let ts: Int = 1705320645123
|
|
let formatted: String = time_format(ts, "%Y-%m-%d")
|
|
assert_eq(formatted, "2024-01-15", "strftime %Y-%m-%d")
|
|
let formatted2: String = time_format(ts, "%H:%M:%S")
|
|
assert_eq(formatted2, "12:30:45", "strftime %H:%M:%S")
|
|
return ""
|
|
}
|
|
|
|
// ── time_add ──────────────────────────────────────────────────────────────────
|
|
|
|
fn test_time_add_basic(_: String) -> String {
|
|
let base: Int = 1000000000000
|
|
assert_int_eq(time_add(base, 1000, "ms"), base + 1000, "add milliseconds")
|
|
assert_int_eq(time_add(base, 1, "sec"), base + 1000, "add 1 second")
|
|
assert_int_eq(time_add(base, 1, "min"), base + 60000, "add 1 minute")
|
|
assert_int_eq(time_add(base, 1, "hour"), base + 3600000, "add 1 hour")
|
|
assert_int_eq(time_add(base, 1, "day"), base + 86400000, "add 1 day")
|
|
return ""
|
|
}
|
|
|
|
fn test_time_add_multiple(_: String) -> String {
|
|
let base: Int = 1000000000000
|
|
assert_int_eq(time_add(base, 60, "sec"), base + 60000, "add 60 seconds")
|
|
assert_int_eq(time_add(base, 24, "hour"), base + 86400000, "add 24 hours = 1 day")
|
|
assert_int_eq(time_add(base, 0, "sec"), base, "add 0 seconds")
|
|
assert_int_eq(time_add(base, -1, "sec"), base - 1000, "add negative seconds")
|
|
return ""
|
|
}
|
|
|
|
// ── time_diff ─────────────────────────────────────────────────────────────────
|
|
|
|
fn test_time_diff_basic(_: String) -> String {
|
|
let t1: Int = 1000000000000
|
|
let t2: Int = t1 + 5000
|
|
assert_int_eq(time_diff(t1, t2, "ms"), 5000, "diff in ms")
|
|
assert_int_eq(time_diff(t1, t2, "sec"), 5, "diff in seconds")
|
|
return ""
|
|
}
|
|
|
|
fn test_time_diff_larger(_: String) -> String {
|
|
let t1: Int = 1000000000000
|
|
let t2: Int = t1 + 3600000
|
|
assert_int_eq(time_diff(t1, t2, "min"), 60, "diff of 1 hour in minutes")
|
|
assert_int_eq(time_diff(t1, t2, "hour"), 1, "diff of 1 hour in hours")
|
|
assert_int_eq(time_diff(t1, t2, "ms"), 3600000, "diff of 1 hour in ms")
|
|
return ""
|
|
}
|
|
|
|
fn test_time_diff_zero(_: String) -> String {
|
|
let t: Int = 1000000000000
|
|
assert_int_eq(time_diff(t, t, "ms"), 0, "same timestamp: diff is 0")
|
|
assert_int_eq(time_diff(t, t, "sec"), 0, "same timestamp: diff in sec is 0")
|
|
return ""
|
|
}
|
|
|
|
// ── Duration helpers ──────────────────────────────────────────────────────────
|
|
|
|
fn test_duration_helpers_basic(_: String) -> String {
|
|
assert_int_eq(duration_seconds(1), 1000000000, "1 second = 1e9 ns")
|
|
assert_int_eq(duration_millis(1), 1000000, "1 ms = 1e6 ns")
|
|
assert_int_eq(duration_nanos(42), 42, "nanos identity")
|
|
assert_int_eq(duration_to_seconds(1000000000), 1, "1e9 ns = 1 second")
|
|
assert_int_eq(duration_to_millis(1000000), 1, "1e6 ns = 1 ms")
|
|
assert_int_eq(duration_to_nanos(42), 42, "nanos identity roundtrip")
|
|
return ""
|
|
}
|
|
|
|
fn test_instant_helpers_basic(_: String) -> String {
|
|
let i: Int = unix_seconds(1000)
|
|
assert_int_eq(i, 1000000000000, "unix_seconds(1000) = 1e12 ns")
|
|
|
|
let ms_i: Int = unix_millis(5000)
|
|
assert_int_eq(ms_i, 5000000000, "unix_millis(5000) = 5e9 ns")
|
|
|
|
assert_int_eq(instant_to_unix_seconds(1000000000000), 1000, "instant to seconds")
|
|
assert_int_eq(instant_to_unix_millis(5000000000), 5000, "instant to millis")
|
|
return ""
|
|
}
|
|
|
|
// ── uuid_new / uuid_v4 ────────────────────────────────────────────────────────
|
|
|
|
fn test_uuid_new_basic(_: String) -> String {
|
|
let u: String = uuid_new()
|
|
assert_int_eq(str_len(u), 36, "UUID has 36 characters")
|
|
assert_eq(str_char_at(u, 8), "-", "UUID has dash at position 8")
|
|
assert_eq(str_char_at(u, 13), "-", "UUID has dash at position 13")
|
|
assert_eq(str_char_at(u, 18), "-", "UUID has dash at position 18")
|
|
assert_eq(str_char_at(u, 23), "-", "UUID has dash at position 23")
|
|
return ""
|
|
}
|
|
|
|
fn test_uuid_uniqueness(_: String) -> String {
|
|
let u1: String = uuid_new()
|
|
let u2: String = uuid_new()
|
|
let u3: String = uuid_v4()
|
|
assert_false(str_eq(u1, u2), "consecutive UUIDs are different")
|
|
assert_false(str_eq(u1, u3), "uuid_new and uuid_v4 produce different values")
|
|
assert_false(str_eq(u2, u3), "three consecutive UUIDs are all different")
|
|
assert_int_eq(str_len(u3), 36, "uuid_v4 also produces 36-char UUID")
|
|
return ""
|
|
}
|
|
|
|
// ── time_from_parts ───────────────────────────────────────────────────────────
|
|
|
|
fn test_time_from_parts_basic(_: String) -> String {
|
|
// time_from_parts(secs, ns, tz) = secs * 1000 + ns / 1000000
|
|
let ts: Int = time_from_parts(1000, 0, "UTC")
|
|
assert_int_eq(ts, 1000000, "1000 secs = 1000000 ms")
|
|
|
|
let ts2: Int = time_from_parts(0, 500000000, "UTC")
|
|
assert_int_eq(ts2, 500, "500ms in nanoseconds -> 500ms")
|
|
|
|
let ts3: Int = time_from_parts(1705320645, 123000000, "UTC")
|
|
assert_int_eq(ts3, 1705320645123, "known timestamp with ms component")
|
|
return ""
|
|
}
|
|
|
|
// ── instant_to_iso8601 ────────────────────────────────────────────────────────
|
|
|
|
fn test_instant_to_iso8601_basic(_: String) -> String {
|
|
let ts_ms: Int = 1705320645123
|
|
let ts_ns: Int = ts_ms * 1000000
|
|
let iso: String = instant_to_iso8601(ts_ns)
|
|
assert_starts_with(iso, "2024-01-15", "instant_to_iso8601 correct date")
|
|
assert_ends_with(iso, "Z", "instant_to_iso8601 ends with Z")
|
|
return ""
|
|
}
|