nx_circadian_test.nx source
↩ module page · 96 lines · 4064 B
1// nx_circadian_test.nx -- smoke for nx_circadian.
2
3import "nx_syscalls.nx"
4import "nx_circadian.nx"
5
6func main() -> i64 {
7 let now: nx_size = 1000000000 // 1000 sec base
8
9 // 1: enum validity
10 if nx_cd_rhythm_is_valid(NX_CD_RHYTHM_SUBSTRATE_HEARTBEAT) != 1 { return 1 }
11 if nx_cd_rhythm_is_valid(NX_CD_RHYTHM_SEASONAL) != 1 { return 2 }
12 if nx_cd_rhythm_is_valid(-1) != 0 { return 3 }
13 if nx_cd_rhythm_is_valid(6) != 0 { return 4 }
14 if NX_CD_RHYTHM_N != 6 { return 5 }
15
16 if nx_cd_drift_is_valid(NX_CD_DRIFT_OK) != 1 { return 6 }
17 if nx_cd_drift_is_valid(NX_CD_DRIFT_MAJOR) != 1 { return 7 }
18 if nx_cd_drift_is_valid(NX_CD_DRIFT_INVALID) != 0 { return 8 }
19
20 if nx_cd_v_is_valid(NX_CD_V_OK) != 1 { return 9 }
21 if nx_cd_v_is_valid(-1) != 0 { return 10 }
22
23 // 2: canonical period
24 if nx_cd_rhythm_canonical_period_ms(NX_CD_RHYTHM_SUBSTRATE_HEARTBEAT) != 30000 { return 11 }
25 if nx_cd_rhythm_canonical_period_ms(NX_CD_RHYTHM_DAILY) != 86400000 { return 12 }
26 if nx_cd_rhythm_canonical_period_ms(NX_CD_RHYTHM_WEEKLY) != 604800000 { return 13 }
27
28 // 3: rhythm construction
29 let c: *NxCircadianRhythm = nx_cd_rhythm_new(NX_CD_RHYTHM_SUBSTRATE_HEARTBEAT, now)
30 if c.rhythm != NX_CD_RHYTHM_SUBSTRATE_HEARTBEAT { return 14 }
31 if c.period_ms != 30000 { return 15 }
32 if c.last_tick_at_us != now { return 16 }
33 if c.tick_count != 0 { return 17 }
34 if c.accumulated_drift_us != 0 { return 18 }
35
36 // 4: invalid rhythm returns null
37 let c_bad: *NxCircadianRhythm = nx_cd_rhythm_new(99, now)
38 if c_bad != (0 as *NxCircadianRhythm) { return 19 }
39
40 // 5: due_for_tick -- false right after creation
41 if nx_cd_due_for_tick(c, now) != 0 { return 20 }
42
43 // 6: due_for_tick -- true after period (30 sec = 30M us)
44 if nx_cd_due_for_tick(c, now + 30000000) != 1 { return 21 }
45
46 // 7: due_for_tick -- false just before period
47 if nx_cd_due_for_tick(c, now + 29000000) != 0 { return 22 }
48
49 // 8: tick within tolerance accumulates small drift
50 let v: nx_int = nx_cd_tick(c, now + 30000000) // exact period
51 if v != NX_CD_V_OK { return 23 }
52 if c.tick_count != 1 { return 24 }
53 if c.accumulated_drift_us != 0 { return 25 } // exact
54
55 // 9: tick with drift
56 let v2: nx_int = nx_cd_tick(c, now + 60000000 + 100000) // +100ms late
57 if v2 != NX_CD_V_OK { return 26 }
58 if c.tick_count != 2 { return 27 }
59 if c.accumulated_drift_us != 100000 { return 28 } // 100ms in us
60
61 // 10: drift classification
62 let d_ok: nx_int = nx_cd_drift_classify(c)
63 // 100ms drift on 30sec period -> 100000us / 30000000us = ~0.33% -> OK
64 if d_ok != NX_CD_DRIFT_OK { return 29 }
65
66 // 11: accumulate more drift -> MINOR
67 nx_cd_tick(c, now + 90000000 + 500000) // +500ms drift accumulated
68 // Total now 600ms = 0.6M us; on 30sec period 30M us
69 // minor threshold = period/100 = 300K us; major = period/10 = 3M us
70 // 600K us > 300K -> MINOR
71 let d_minor: nx_int = nx_cd_drift_classify(c)
72 if d_minor != NX_CD_DRIFT_MINOR { return 30 }
73
74 // 12: re-sync clears drift
75 let r: nx_int = nx_cd_resync(c, now + 200000000)
76 if r != NX_CD_V_OK { return 31 }
77 if c.accumulated_drift_us != 0 { return 32 }
78 let d_post: nx_int = nx_cd_drift_classify(c)
79 if d_post != NX_CD_DRIFT_OK { return 33 }
80
81 // 13: major drift threshold (>10% of period = >3M us)
82 let c2: *NxCircadianRhythm = nx_cd_rhythm_new(NX_CD_RHYTHM_SUBSTRATE_HEARTBEAT, now)
83 // Single tick 35 sec late -> 5 sec drift = 5M us on 30sec period = 16.7%
84 nx_cd_tick(c2, now + 35000000)
85 let d_major: nx_int = nx_cd_drift_classify(c2)
86 if d_major != NX_CD_DRIFT_MAJOR { return 34 }
87
88 // 14: null handling
89 let null_c: *NxCircadianRhythm = (0 as i64) as *NxCircadianRhythm
90 if nx_cd_tick(null_c, now) != NX_CD_V_ERR_NULL_INPUT { return 35 }
91 if nx_cd_drift_classify(null_c) != NX_CD_DRIFT_INVALID { return 36 }
92 if nx_cd_resync(null_c, now) != NX_CD_V_ERR_NULL_INPUT { return 37 }
93 if nx_cd_due_for_tick(null_c, now) != 0 { return 38 }
94
95 return 0
96}