code wiki / _hdl_build / nx_galx_sortindex_gate.nx
nx_galx_sortindex_gate.nx source
↩ module page · 72 lines · 3967 B
1// nx_galx_sortindex_gate.nx -- fixture gate for the sort-index builder. Proves: correct ASCENDING order,
2// STABLE on equal keys (preserves id order), accurate count, freshness stamp = size of the fresh file, and
3// idempotent rebuild. Pure-local fixtures in /tmp -> no NAS / no live gallery needed (the daemon's :18090
4// backend is gateway-walled, so the builder is verified here as a standalone unit). license_tier: ORIGINAL
5import "nx_syscalls.nx"
6import "nx_galx_sortindex.nx"
7
8func g_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
9func g_n(v: i64) -> i64 {
10 let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
11 let t: *u8 = sys_mmap(28); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 }
12 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
13 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, bb, k); return 0
14}
15func g_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
16func g_writefile(path: *u8, data: *u8) -> i64 {
17 let fd: i64 = sys_openat_wr(path, 0x1a4); if fd < 0 { return 0 - 1 }
18 sys_write(fd, data, g_strlen(data)); sys_close(fd); return 0
19}
20func g_eq(label: *u8, got: i64, want: i64, pass: *i64, fail: *i64) -> i64 {
21 if got == want { pass[0] = pass[0] + 1 }
22 else { fail[0] = fail[0] + 1; g_p(" FAIL " as *u8); g_p(label); g_p(" got="); g_n(got); g_p(" want="); g_n(want); g_p("\n" as *u8) }
23 return 0
24}
25
26func main(argc: i64, argv: *i64) -> i64 {
27 let pass: *i64 = sys_mmap(16) as *i64; pass[0] = 0
28 let fail: *i64 = sys_mmap(16) as *i64; fail[0] = 0
29 let kf: *u8 = "/tmp/si_keys.txt" as *u8
30 let of: *u8 = "/tmp/si_out.bin" as *u8
31 let ff: *u8 = "/tmp/si_fresh.txt" as *u8
32
33 // 5 recordings; durations 300,100,200,100,50 -> ascending stable order of ids: 4,1,3,2,0
34 // (50=id4, then the two 100s keep id order 1 before 3, then 200=id2, then 300=id0).
35 g_writefile(kf, "dur_ms=300\ndur_ms=100\ndur_ms=200\ndur_ms=100\ndur_ms=50\n" as *u8)
36 g_writefile(ff, "abcdefghij" as *u8) // 10 bytes -> stamp must be 10
37
38 let N: i64 = si_build_index(kf, of, ff)
39 g_eq("build-count" as *u8, N, 5, pass, fail)
40
41 let szp: *i64 = sys_mmap(16) as *i64
42 let ob: *u8 = sys_read_file(of, szp)
43 if (ob as i64) != 0 {
44 g_eq("stamp" as *u8, si_rb64(ob, 0), 10, pass, fail)
45 g_eq("count" as *u8, si_rb64(ob, 8), 5, pass, fail)
46 g_eq("order0" as *u8, si_rb64(ob, 16), 4, pass, fail)
47 g_eq("order1-stable" as *u8, si_rb64(ob, 24), 1, pass, fail)
48 g_eq("order2-stable" as *u8, si_rb64(ob, 32), 3, pass, fail)
49 g_eq("order3" as *u8, si_rb64(ob, 40), 2, pass, fail)
50 g_eq("order4" as *u8, si_rb64(ob, 48), 0, pass, fail)
51 g_eq("filesize" as *u8, szp[0], 16 + 8 * 5, pass, fail)
52 } else { fail[0] = fail[0] + 1; g_p(" FAIL read-out\n" as *u8) }
53
54 // idempotent rebuild -> identical first id
55 let N2: i64 = si_build_index(kf, of, ff)
56 g_eq("idem-count" as *u8, N2, 5, pass, fail)
57 let ob2: *u8 = sys_read_file(of, szp)
58 if (ob2 as i64) != 0 { g_eq("idem-order0" as *u8, si_rb64(ob2, 16), 4, pass, fail) }
59 else { fail[0] = fail[0] + 1; g_p(" FAIL idem-read\n" as *u8) }
60
61 // single-record edge (N=1) + empty/keyless line tolerance (key 0 sorts first, keeps id alignment)
62 g_writefile(kf, "dur_ms=42\n" as *u8)
63 let N3: i64 = si_build_index(kf, of, ff)
64 g_eq("single-count" as *u8, N3, 1, pass, fail)
65 let ob3: *u8 = sys_read_file(of, szp)
66 if (ob3 as i64) != 0 { g_eq("single-order0" as *u8, si_rb64(ob3, 16), 0, pass, fail) }
67 else { fail[0] = fail[0] + 1; g_p(" FAIL single-read\n" as *u8) }
68
69 g_p("\nsortindex gate pass=" as *u8); g_n(pass[0]); g_p(" fail=" as *u8); g_n(fail[0]); g_p("\n" as *u8)
70 if fail[0] == 0 { g_p("GREEN\n" as *u8); sys_exit(0) } else { g_p("RED\n" as *u8); sys_exit(1) }
71 return 0
72}