nx_queries_merge_gate.nx source
↩ module page · 76 lines · 4658 B
1// nx_queries_merge_gate.nx -- the referee for nx_queries_merge_lib: a three-file union is row-aligned and space-joined,
2// CRLF inputs merge without their CR, a mismatched id is REFUSED naming the row and input, a row-count mismatch is
3// REFUSED naming the input, and a killed run leaves no half file (the write is tmp + rename). Fixtures live in
4// /tmp/nx_queries_merge_gate/ (fixture-ratchet law), truncate-written at setup so the gate is idempotent.
5// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
6import "nx_queries_merge_lib.nx"
7import "nx_gate_verdict.nx"
8
9const QG_DIR: *u8 = "/tmp/nx_queries_merge_gate" as *u8
10const QG_A: *u8 = "/tmp/nx_queries_merge_gate/a.tsv" as *u8
11const QG_B: *u8 = "/tmp/nx_queries_merge_gate/b.tsv" as *u8
12const QG_C: *u8 = "/tmp/nx_queries_merge_gate/c.tsv" as *u8
13const QG_D: *u8 = "/tmp/nx_queries_merge_gate/d.tsv" as *u8
14const QG_E: *u8 = "/tmp/nx_queries_merge_gate/e.tsv" as *u8
15const QG_OUT: *u8 = "/tmp/nx_queries_merge_gate/out.tsv" as *u8
16const QG_OUT2: *u8 = "/tmp/nx_queries_merge_gate/out2.tsv" as *u8
17const QG_MODE_DIR: i64 = 493
18const QG_IN3: i64 = 3
19const QG_IN2: i64 = 2
20
21func qg_write(p: *u8, s: *u8) -> i64 { let fd: i64 = sys_openat_wr(p, QM_FILE_MODE); if fd < 0 { return 0 - 1 } qm_write_all(fd, s, qm_slen(s)); sys_close(fd); return 0 }
22func qg_exists(p: *u8) -> i64 { let fd: i64 = sys_openat_rd(p); if fd < 0 { return 0 } sys_close(fd); return 1 }
23func qg_read_eq(p: *u8, want: *u8) -> i64 {
24 let ln: *i64 = sys_mmap(16) as *i64
25 let b: *u8 = sys_read_file(p, ln)
26 if (b as i64) == 0 { return 0 }
27 if ln[0] != qm_slen(want) { return 0 }
28 var i: i64 = 0
29 while i < ln[0] { if b[i] != want[i] { return 0 } i = i + 1 }
30 return 1
31}
32
33func main(argc: i64, argv: *i64) -> i64 {
34 let ctr: *i64 = gv_ctr()
35 gv_head("nx_queries_merge_gate -- row-aligned union of query files, refusals named" as *u8)
36 sys_mkdir(QG_DIR, QG_MODE_DIR)
37 qg_write(QG_A, "q1\tA one\nq2\tA two\n" as *u8)
38 // b carries CRLF line ends: the merge must drop the CR
39 let bcr: *u8 = sys_mmap(64)
40 var bo: i64 = qm_cat(bcr, 0, "q1\tB one" as *u8); bcr[bo] = QM_CR as u8; bo = bo + 1; bcr[bo] = QM_NL as u8; bo = bo + 1
41 bo = qm_cat(bcr, bo, "q2\tB two" as *u8); bcr[bo] = QM_CR as u8; bo = bo + 1; bcr[bo] = QM_NL as u8; bo = bo + 1
42 bcr[bo] = 0 as u8
43 qg_write(QG_B, bcr)
44 qg_write(QG_C, "q1\tC one\nq2\tC two" as *u8) // no trailing newline: still two rows
45 qg_write(QG_D, "q1\tD one\nq3\tD three\n" as *u8)
46 qg_write(QG_E, "q1\tE one\n" as *u8)
47 sys_unlinkat(QG_OUT); sys_unlinkat(QG_OUT2)
48 let st: *i64 = sys_mmap(QM_ST_SLOTS * QM_I64) as *i64
49 let ins: *i64 = sys_mmap(QG_IN3 * QM_I64) as *i64
50 ins[0] = QG_A as i64; ins[1] = QG_B as i64; ins[2] = QG_C as i64
51 let rc: i64 = qm_merge(QG_OUT, ins, QG_IN3, st)
52 gv_check_eq("T1 three aligned files merge (exit 0)" as *u8, rc, QM_EXIT_OK, ctr)
53 gv_check_eq("T1a two rows" as *u8, st[0], 2, ctr)
54 gv_check("T1b the union is id TAB text1 SPACE text2 SPACE text3 per row, CR dropped, trailing newline added" as *u8, qg_read_eq(QG_OUT, "q1\tA one B one C one\nq2\tA two B two C two\n" as *u8), ctr)
55 gv_check("T1c no tmp file left behind" as *u8, (qg_exists("/tmp/nx_queries_merge_gate/out.tsv.tmp" as *u8) == 0) as i64, ctr)
56 let mb: i64 = st[1] // banked before the refusal teeth reuse st
57 // ---- refusals ----
58 let ins2: *i64 = sys_mmap(QG_IN2 * QM_I64) as *i64
59 ins2[0] = QG_A as i64; ins2[1] = QG_D as i64
60 let rc2: i64 = qm_merge(QG_OUT2, ins2, QG_IN2, st)
61 gv_check_eq("T2 neg-control a mismatched id is REFUSED" as *u8, rc2, QM_EXIT_REFUSED, ctr)
62 gv_check_eq("T2a ... naming the row (2)" as *u8, st[2], 2, ctr)
63 gv_check_eq("T2b ... and the input (1)" as *u8, st[3], 1, ctr)
64 gv_check("T2c a refused merge writes NO output" as *u8, (qg_exists(QG_OUT2) == 0) as i64, ctr)
65 ins2[1] = QG_E as i64
66 let rc3: i64 = qm_merge(QG_OUT2, ins2, QG_IN2, st)
67 gv_check_eq("T3 neg-control a row-count mismatch is REFUSED" as *u8, rc3, QM_EXIT_REFUSED, ctr)
68 gv_check_eq("T3a ... naming the input (1) with its rows (1)" as *u8, st[3] * 10 + st[4], 11, ctr)
69 gv_check_eq("T3b ... and the reference row count (2)" as *u8, st[0], 2, ctr)
70 ins2[1] = "/tmp/nx_queries_merge_gate/absent.tsv" as i64
71 gv_check_eq("T4 neg-control a missing input is IO, not a merge" as *u8, qm_merge(QG_OUT2, ins2, QG_IN2, st), QM_EXIT_IO, ctr)
72 gv_kv("merged_bytes" as *u8, mb)
73 let rcv: i64 = gv_verdict("QUERIES-MERGE-GATE" as *u8, ctr, "the union is row-aligned and every misalignment is refused by name" as *u8)
74 sys_exit(rcv)
75 return rcv
76}