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}