// timetest — exercises lib/time. Run with `out/bin/ww run // lib/time/timetest.ww`. Same `signalled`-then-fail()-with-+10 // pattern as fmttest / logtest / stattest so a non-zero exit // pinpoints the offending scenario. package time; import os; import time; let signalled: i32 = 0; fn fail() void = { os.exit(signalled + 10); }; // ---- constants: load-bearing names + values ---------------------------- // // Without these multipliers every caller would re-derive 1e9 in // place. The values themselves are nailed down by Hare's // ref/hare/time/duration.ha:9-18. @test fn constants() void = { if ((time.nanosecond: i64) != 1i64) { fail(); }; if ((time.microsecond: i64) != 1000i64) { fail(); }; if ((time.millisecond: i64) != 1000000i64) { fail(); }; if ((time.second: i64) != 1000000000i64) { fail(); }; // "Roundtrip" check: derived multiples land on the canonical // nanosecond count. Catches a future re-derivation drift. if (5i64 * (time.second: i64) != 5000000000i64) { fail(); }; if (3i64 * (time.millisecond: i64) != 3000000i64) { fail(); }; if (7i64 * (time.microsecond: i64) != 7000i64) { fail(); }; }; // ---- now(monotonic) is monotonic across two calls ---------------------- @test fn nowmonotonic() void = { let a = time.now(time.clock.monotonic); let b = time.now(time.clock.monotonic); // Two back-to-back calls — b can equal a (same ns tick) but // must never precede it. if (time.compare(a, b) > 0i8) { fail(); }; }; // ---- now(realtime) returns a post-2020 epoch --------------------------- // // Sanity check that the syscall plumbing actually lands real bytes // in the instant. 2020-01-01 UTC = 1577836800 unix seconds; any // past-2020 wall clock satisfies this. (CI / test machines running // pre-2020 would fail here; acceptable trade for catching a // zero-init / wrong-slot regression.) @test fn nowrealtime() void = { let t = time.now(time.clock.realtime); if (t.sec < 1577836800i64) { fail(); }; if (t.nsec < 0i64) { fail(); }; if (t.nsec >= 1000000000i64) { fail(); }; }; // ---- add: zero duration is identity ------------------------------------ @test fn addzero() void = { let a: time.instant; a.sec = 100i64; a.nsec = 500i64; let r = time.add(a, 0i64); if (r.sec != 100i64) { fail(); }; if (r.nsec != 500i64) { fail(); }; }; // ---- add: positive duration, no carry ---------------------------------- @test fn addpos_nocarry() void = { let a: time.instant; a.sec = 10i64; a.nsec = 100i64; let r = time.add(a, 200i64); if (r.sec != 10i64) { fail(); }; if (r.nsec != 300i64) { fail(); }; }; // ---- add: positive duration, carries into next second ------------------ @test fn addpos_carry() void = { let a: time.instant; a.sec = 10i64; a.nsec = 999999900i64; let r = time.add(a, 200i64); if (r.sec != 11i64) { fail(); }; if (r.nsec != 100i64) { fail(); }; }; // ---- add: full-second duration ----------------------------------------- @test fn addpos_fullsecond() void = { let a: time.instant; a.sec = 5i64; a.nsec = 0i64; let r = time.add(a, (time.second: i64) * 3i64); if (r.sec != 8i64) { fail(); }; if (r.nsec != 0i64) { fail(); }; }; // ---- add: negative duration, no borrow --------------------------------- @test fn addneg_noborrow() void = { let a: time.instant; a.sec = 10i64; a.nsec = 500i64; let r = time.add(a, -100i64); if (r.sec != 10i64) { fail(); }; if (r.nsec != 400i64) { fail(); }; }; // ---- add: negative duration, borrows from previous second -------------- @test fn addneg_borrow() void = { let a: time.instant; a.sec = 10i64; a.nsec = 100i64; let r = time.add(a, -200i64); if (r.sec != 9i64) { fail(); }; if (r.nsec != 999999900i64) { fail(); }; }; // ---- diff: simple subtraction ------------------------------------------ @test fn diffsimple() void = { let a: time.instant; a.sec = 10i64; a.nsec = 100i64; let b: time.instant; b.sec = 12i64; b.nsec = 300i64; let d: i64 = time.diff(a, b): i64; // b - a = 2.0000002 sec = 2_000_000_200 ns if (d != 2000000200i64) { fail(); }; }; // ---- diff: reversed sign ----------------------------------------------- @test fn diffneg() void = { let a: time.instant; a.sec = 12i64; a.nsec = 300i64; let b: time.instant; b.sec = 10i64; b.nsec = 100i64; let d: i64 = time.diff(a, b): i64; if (d != -2000000200i64) { fail(); }; }; // ---- compare: -1 / 0 / +1 ladder --------------------------------------- @test fn comparelt() void = { let a: time.instant; a.sec = 1i64; a.nsec = 0i64; let b: time.instant; b.sec = 2i64; b.nsec = 0i64; if (time.compare(a, b) != -1i8) { fail(); }; }; @test fn comparegt() void = { let a: time.instant; a.sec = 2i64; a.nsec = 0i64; let b: time.instant; b.sec = 1i64; b.nsec = 0i64; if (time.compare(a, b) != 1i8) { fail(); }; }; @test fn compareeq() void = { let a: time.instant; a.sec = 5i64; a.nsec = 42i64; let b: time.instant; b.sec = 5i64; b.nsec = 42i64; if (time.compare(a, b) != 0i8) { fail(); }; }; @test fn comparensec_only() void = { let a: time.instant; a.sec = 5i64; a.nsec = 100i64; let b: time.instant; b.sec = 5i64; b.nsec = 200i64; if (time.compare(a, b) != -1i8) { fail(); }; if (time.compare(b, a) != 1i8) { fail(); }; }; export fn main() i32 = { signalled = 1; constants(); signalled = 2; nowmonotonic(); signalled = 3; nowrealtime(); signalled = 4; addzero(); signalled = 5; addpos_nocarry(); signalled = 6; addpos_carry(); signalled = 7; addpos_fullsecond(); signalled = 8; addneg_noborrow(); signalled = 9; addneg_borrow(); signalled = 10; diffsimple(); signalled = 11; diffneg(); signalled = 12; comparelt(); signalled = 13; comparegt(); signalled = 14; compareeq(); signalled = 15; comparensec_only(); return 0; };