From cec382ef8a035311665ccdf608c44af6d1f39f76 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sat, 8 Aug 2026 16:34:16 +0900 Subject: [PATCH] lib: split time_test into duration/instant/arithm tests per ref/hare/time Mirror ref/hare/time's impl layout in the test siblings: constants -> duration_test.ww (ref/hare/time/duration.ha:9-18 owns the constants); now/sleep rows -> instant_test.ww (instant is the subject type, ref/hare/time/instant.ha; now/sleep bodies live in ref/hare/time/+linux/functions.ha, a platform split ww does not have); add/diff/compare rows -> arithm_test.ww (ref/hare/time/arithm.ha). Pure move: every @test block is byte-identical; only the section banner lines are deleted (the file names now carry them). The stale file header naming the retired `ww run lib/time/timetest.ww` entry point is dropped, not relocated (rule 8: it described a WHAT that no longer exists). Consumers: Makefile LIBRARY_TESTS entry replaced in place; test/byteid roster 44->46 (+2). --- Makefile | 3 +- lib/time/arithm_test.ww | 91 ++++++++++++++++++ lib/time/duration_test.ww | 20 ++++ lib/time/instant_test.ww | 33 +++++++ lib/time/time_test.ww | 168 ---------------------------------- test/byteid/libbyteid_test.ww | 8 +- 6 files changed, 151 insertions(+), 172 deletions(-) create mode 100644 lib/time/arithm_test.ww create mode 100644 lib/time/duration_test.ww create mode 100644 lib/time/instant_test.ww delete mode 100644 lib/time/time_test.ww diff --git a/Makefile b/Makefile index 1f1835cc..f2d2eadc 100644 --- a/Makefile +++ b/Makefile @@ -489,7 +489,8 @@ LIBRARY_TESTS = lib/errors/errno_test.ww lib/ascii/ascii_test.ww \ lib/bufio/bufio_test.ww lib/math/random/random_test.ww \ lib/math/checked/checked_test.ww lib/fmt/fmt_test.ww \ lib/log/log_test.ww lib/log/silent_test.ww lib/fnmatch/fnmatch_test.ww \ - lib/shlex/shlex_test.ww lib/time/time_test.ww \ + lib/shlex/shlex_test.ww lib/time/arithm_test.ww \ + lib/time/duration_test.ww lib/time/instant_test.ww \ lib/encoding/hex/hex_test.ww lib/memio/memio_test.ww \ lib/temp/temp_test.ww lib/getopt/getopt_test.ww \ lib/encoding/base32/base32_test.ww \ diff --git a/lib/time/arithm_test.ww b/lib/time/arithm_test.ww new file mode 100644 index 00000000..66bc5968 --- /dev/null +++ b/lib/time/arithm_test.ww @@ -0,0 +1,91 @@ +package time_test; + +import time; + +@test fn addzero() void = { + let a: time.instant; + a.sec = 100i64; a.nsec = 500i64; + let r = time.add(a, 0i64); + assert(!(r.sec != 100i64)); + assert(!(r.nsec != 500i64)); +}; + +@test fn addpos_nocarry() void = { + let a: time.instant; + a.sec = 10i64; a.nsec = 100i64; + let r = time.add(a, 200i64); + assert(!(r.sec != 10i64)); + assert(!(r.nsec != 300i64)); +}; + +@test fn addpos_carry() void = { + let a: time.instant; + a.sec = 10i64; a.nsec = 999999900i64; + let r = time.add(a, 200i64); + assert(!(r.sec != 11i64)); + assert(!(r.nsec != 100i64)); +}; + +@test fn addpos_fullsecond() void = { + let a: time.instant; + a.sec = 5i64; a.nsec = 0i64; + let r = time.add(a, (time.second: i64) * 3i64); + assert(!(r.sec != 8i64)); + assert(!(r.nsec != 0i64)); +}; + +@test fn addneg_noborrow() void = { + let a: time.instant; + a.sec = 10i64; a.nsec = 500i64; + let r = time.add(a, -100i64); + assert(!(r.sec != 10i64)); + assert(!(r.nsec != 400i64)); +}; + +@test fn addneg_borrow() void = { + let a: time.instant; + a.sec = 10i64; a.nsec = 100i64; + let r = time.add(a, -200i64); + assert(!(r.sec != 9i64)); + assert(!(r.nsec != 999999900i64)); +}; + +@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 + assert(!(d != 2000000200i64)); +}; + +@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; + assert(!(d != -2000000200i64)); +}; + +@test fn comparelt() void = { + let a: time.instant; a.sec = 1i64; a.nsec = 0i64; + let b: time.instant; b.sec = 2i64; b.nsec = 0i64; + assert(!(time.compare(a, b) != -1i8)); +}; + +@test fn comparegt() void = { + let a: time.instant; a.sec = 2i64; a.nsec = 0i64; + let b: time.instant; b.sec = 1i64; b.nsec = 0i64; + assert(!(time.compare(a, b) != 1i8)); +}; + +@test fn compareeq() void = { + let a: time.instant; a.sec = 5i64; a.nsec = 42i64; + let b: time.instant; b.sec = 5i64; b.nsec = 42i64; + assert(!(time.compare(a, b) != 0i8)); +}; + +@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; + assert(!(time.compare(a, b) != -1i8)); + assert(!(time.compare(b, a) != 1i8)); +}; diff --git a/lib/time/duration_test.ww b/lib/time/duration_test.ww new file mode 100644 index 00000000..a528ccc1 --- /dev/null +++ b/lib/time/duration_test.ww @@ -0,0 +1,20 @@ +package time_test; + +import time; + +// 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 = { + assert(!((time.nanosecond: i64) != 1i64)); + assert(!((time.microsecond: i64) != 1000i64)); + assert(!((time.millisecond: i64) != 1000000i64)); + assert(!((time.second: i64) != 1000000000i64)); + + // "Roundtrip" check: derived multiples land on the canonical + // nanosecond count. Catches a future re-derivation drift. + assert(!(5i64 * (time.second: i64) != 5000000000i64)); + assert(!(3i64 * (time.millisecond: i64) != 3000000i64)); + assert(!(7i64 * (time.microsecond: i64) != 7000i64)); +}; diff --git a/lib/time/instant_test.ww b/lib/time/instant_test.ww new file mode 100644 index 00000000..37affb85 --- /dev/null +++ b/lib/time/instant_test.ww @@ -0,0 +1,33 @@ +package time_test; + +import time; + +@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. + assert(!(time.compare(a, b) > 0i8)); +}; + +// 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); + assert(!(t.sec < 1577836800i64)); + assert(!(t.nsec < 0i64)); + assert(!(t.nsec >= 1000000000i64)); +}; + +@test fn sleepmonotonic() void = { + let before: time.instant = time.now(time.clock.monotonic); + time.sleep((5i64 * (time.millisecond: i64)): time.duration, + time.clock.monotonic); + let after: time.instant = time.now(time.clock.monotonic); + let elapsed: i64 = time.diff(before, after): i64; + assert(!(elapsed < 5i64 * (time.millisecond: i64))); +}; diff --git a/lib/time/time_test.ww b/lib/time/time_test.ww deleted file mode 100644 index bd8d971e..00000000 --- a/lib/time/time_test.ww +++ /dev/null @@ -1,168 +0,0 @@ -// timetest — exercises lib/time. Run with `out/bin/ww run -// lib/time/timetest.ww`. A failing row aborts via the assert/abort -// builtin (task #5 @test conversion). - -package time_test; - -import time; - - - -// ---- 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 = { - assert(!((time.nanosecond: i64) != 1i64)); - assert(!((time.microsecond: i64) != 1000i64)); - assert(!((time.millisecond: i64) != 1000000i64)); - assert(!((time.second: i64) != 1000000000i64)); - - // "Roundtrip" check: derived multiples land on the canonical - // nanosecond count. Catches a future re-derivation drift. - assert(!(5i64 * (time.second: i64) != 5000000000i64)); - assert(!(3i64 * (time.millisecond: i64) != 3000000i64)); - assert(!(7i64 * (time.microsecond: i64) != 7000i64)); -}; - -// ---- 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. - assert(!(time.compare(a, b) > 0i8)); -}; - -// ---- 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); - assert(!(t.sec < 1577836800i64)); - assert(!(t.nsec < 0i64)); - assert(!(t.nsec >= 1000000000i64)); -}; - -// ---- 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); - assert(!(r.sec != 100i64)); - assert(!(r.nsec != 500i64)); -}; - -// ---- 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); - assert(!(r.sec != 10i64)); - assert(!(r.nsec != 300i64)); -}; - -// ---- 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); - assert(!(r.sec != 11i64)); - assert(!(r.nsec != 100i64)); -}; - -// ---- 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); - assert(!(r.sec != 8i64)); - assert(!(r.nsec != 0i64)); -}; - -// ---- 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); - assert(!(r.sec != 10i64)); - assert(!(r.nsec != 400i64)); -}; - -// ---- 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); - assert(!(r.sec != 9i64)); - assert(!(r.nsec != 999999900i64)); -}; - -// ---- 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 - assert(!(d != 2000000200i64)); -}; - -// ---- 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; - assert(!(d != -2000000200i64)); -}; - -// ---- 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; - assert(!(time.compare(a, b) != -1i8)); -}; - -@test fn comparegt() void = { - let a: time.instant; a.sec = 2i64; a.nsec = 0i64; - let b: time.instant; b.sec = 1i64; b.nsec = 0i64; - assert(!(time.compare(a, b) != 1i8)); -}; - -@test fn compareeq() void = { - let a: time.instant; a.sec = 5i64; a.nsec = 42i64; - let b: time.instant; b.sec = 5i64; b.nsec = 42i64; - assert(!(time.compare(a, b) != 0i8)); -}; - -@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; - assert(!(time.compare(a, b) != -1i8)); - assert(!(time.compare(b, a) != 1i8)); -}; - -@test fn sleepmonotonic() void = { - let before: time.instant = time.now(time.clock.monotonic); - time.sleep((5i64 * (time.millisecond: i64)): time.duration, - time.clock.monotonic); - let after: time.instant = time.now(time.clock.monotonic); - let elapsed: i64 = time.diff(before, after): i64; - assert(!(elapsed < 5i64 * (time.millisecond: i64))); -}; diff --git a/test/byteid/libbyteid_test.ww b/test/byteid/libbyteid_test.ww index 8941fc11..6ae73ab9 100644 --- a/test/byteid/libbyteid_test.ww +++ b/test/byteid/libbyteid_test.ww @@ -43,7 +43,7 @@ import time; def MID: i32 = 0; def MDIVERGE: i32 = 1; def MWWREJECT: i32 = 2; -def NENTEXPECT: i32 = 45; +def NENTEXPECT: i32 = 47; type ent = struct { fixture: str, // repo-relative .ww; "" -> probe entry @@ -83,7 +83,7 @@ fn pri(p: str, inc: str, sentinel: str, moddir: str) ent = { return e; }; -// The 44-unit roster. Graduation history lives in git (the retired C +// The 46-unit roster. Graduation history lives in git (the retired C // carrier's table comments); cites are kept only where a non-ID pin // would need them. fn corpus() []ent = { @@ -111,7 +111,9 @@ fn corpus() []ent = { append(es, fx("lib/strconv/test/int_test.ww")); append(es, fx("lib/strings/strings_test.ww")); append(es, fx("lib/temp/temp_test.ww")); - append(es, fx("lib/time/time_test.ww")); + append(es, fx("lib/time/arithm_test.ww")); + append(es, fx("lib/time/duration_test.ww")); + append(es, fx("lib/time/instant_test.ww")); append(es, fx("lib/bufio/bufio_test.ww")); append(es, fx("lib/fmt/fmt_test.ww")); append(es, pr("package main;\nimport sort;\nfn main() i32 = { return 0; };\n",