nx_chem_report_csv_test.nx source
↩ module page · 172 lines · 8642 B
1// nx_chem_report_csv_test.nx -- C6.1 KAT.
2//
3// expect_exit: 0
4// license_tier: ORIGINAL
5
6import "nx_chem.nx"
7import "nx_chem_molecule.nx"
8import "nx_chem_smiles.nx"
9import "nx_chem_periodic.nx"
10import "nx_chem_valence.nx"
11import "nx_chem_mass.nx"
12import "nx_chem_isotope_pattern.nx"
13import "nx_chem_adulterant_db.nx"
14import "nx_chem_peak_list.nx"
15import "nx_chem_report_json.nx"
16import "nx_chem_report_csv.nx"
17
18// =================================================================
19// A -- emit_csv_field: bare ASCII (no commas/quotes) -> no quoting
20// =================================================================
21func a_csv_field_bare() -> nx_int {
22 let buf: *u8 = sys_mmap(64)
23 let n: nx_int = nx_chem_emit_csv_field(buf, 0, "sibutramine" as *u8)
24 if n != 11 { return 11 }
25 if buf[0] as nx_int != 0x73 { return 12 } // 's'
26 if buf[10] as nx_int != 0x65 { return 13 } // 'e'
27 return 0
28}
29
30// =================================================================
31// B -- emit_csv_field: with comma -> wrap in quotes
32// "DMAA (1,3-dimethylamylamine)" -> "DMAA (1,3-dimethylamylamine)"
33// (12 + 2 quotes = 14? No, original is 28 chars + 2 quotes = 30)
34// =================================================================
35func b_csv_field_with_comma() -> nx_int {
36 let buf: *u8 = sys_mmap(128)
37 let n: nx_int = nx_chem_emit_csv_field(buf, 0, "DMAA (1,3-dimethylamylamine)" as *u8)
38 if n != 30 { return 21 }
39 if buf[0] as nx_int != 0x22 { return 22 } // opening "
40 if buf[n - 1] as nx_int != 0x22 { return 23 } // closing "
41 return 0
42}
43
44// =================================================================
45// C -- emit_csv_field: with quote -> double the quote inside
46// 'say "hi"' -> '"say ""hi"""'
47// =================================================================
48func c_csv_field_with_quote() -> nx_int {
49 let buf: *u8 = sys_mmap(128)
50 let src: *u8 = sys_mmap(32)
51 src[0] = 0x73; src[1] = 0x61; src[2] = 0x79; src[3] = 0x20
52 src[4] = 0x22 // "
53 src[5] = 0x68; src[6] = 0x69
54 src[7] = 0x22 // "
55 src[8] = 0
56 let n: nx_int = nx_chem_emit_csv_field(buf, 0, src)
57 // Expected: "say ""hi""" = " s a y SP " " h i " " " = 12 bytes
58 if n != 12 { return 31 }
59 if buf[0] as nx_int != 0x22 { return 32 } // opening "
60 if buf[4] as nx_int != 0x20 { return 33 } // space
61 if buf[5] as nx_int != 0x22 { return 34 } // first " of ""
62 if buf[6] as nx_int != 0x22 { return 35 } // second " of ""
63 return 0
64}
65
66// =================================================================
67// D -- emit_csv_header has all expected column names
68// =================================================================
69func d_csv_header() -> nx_int {
70 let buf: *u8 = sys_mmap(256)
71 let n: nx_int = nx_chem_emit_csv_header(buf, 0)
72 if buf[n - 1] as nx_int != 0x0A { return 41 } // ends with newline
73 if nx_chem_buf_find(buf, n, "sample_id" as *u8) < 0 { return 42 }
74 if nx_chem_buf_find(buf, n, "peak_mz" as *u8) < 0 { return 43 }
75 if nx_chem_buf_find(buf, n, "regulatory" as *u8) < 0 { return 44 }
76 if nx_chem_buf_find(buf, n, "citation" as *u8) < 0 { return 45 }
77 return 0
78}
79
80// =================================================================
81// E -- emit_report_csv full report: header + 2 matches
82// =================================================================
83func e_full_report() -> nx_int {
84 let db: *AdulterantDB = nx_chem_adulterant_db_seed()
85 let e_sib: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry
86 let e_caf: *AdulterantEntry = ((db.entries as nx_int) + (5 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry
87 let pl: *PeakList = nx_chem_peak_list_new(8)
88 let _a1: nx_int = nx_chem_peak_list_add(pl, e_sib.mh_plus_q4, 1000000000, 742000)
89 let _a2: nx_int = nx_chem_peak_list_add(pl, e_caf.mh_plus_q4, 1500000000, 234000)
90 let buf: *u8 = sys_mmap(4096)
91 let n: nx_int = nx_chem_emit_report_csv(buf, pl, db, "TEST-001" as *u8, 5)
92 // Verify content
93 if nx_chem_buf_find(buf, n, "sample_id" as *u8) < 0 { return 51 } // header
94 if nx_chem_buf_find(buf, n, "TEST-001" as *u8) < 0 { return 52 }
95 if nx_chem_buf_find(buf, n, "sibutramine" as *u8) < 0 { return 53 }
96 if nx_chem_buf_find(buf, n, "BANNED" as *u8) < 0 { return 54 }
97 if nx_chem_buf_find(buf, n, "caffeine" as *u8) < 0 { return 55 }
98 if nx_chem_buf_find(buf, n, "APPROVED" as *u8) < 0 { return 56 }
99 // FDA citation has a colon but no comma -- should NOT be quoted
100 // 21 CFR citation has no special chars -- should NOT be quoted
101 if nx_chem_buf_find(buf, n, "21 CFR" as *u8) < 0 { return 57 }
102 return 0
103}
104
105// =================================================================
106// END-TO-END DEMO: emit a CSV report to stdout
107// =================================================================
108func run_csv_demo() -> nx_int {
109 println("" as *u8)
110 println("==================================================================" as *u8)
111 println(" CSV REPORT (Excel-ready output for lab analysts)" as *u8)
112 println("==================================================================" as *u8)
113 let db: *AdulterantDB = nx_chem_adulterant_db_seed()
114 let pl: *PeakList = nx_chem_peak_list_new(8)
115 let e_sib: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry
116 let e_dmaa: *AdulterantEntry = ((db.entries as nx_int) + (1 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry
117 let e_caf: *AdulterantEntry = ((db.entries as nx_int) + (5 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry
118 let e_eph: *AdulterantEntry = ((db.entries as nx_int) + (0 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry
119 let _a1: nx_int = nx_chem_peak_list_add(pl, e_sib.mh_plus_q4, 995230000, 742300)
120 let _a2: nx_int = nx_chem_peak_list_add(pl, e_dmaa.mh_plus_q4, 874310000, 45200)
121 let _a3: nx_int = nx_chem_peak_list_add(pl, e_caf.mh_plus_q4, 1500000000, 234100)
122 let _a4: nx_int = nx_chem_peak_list_add(pl, e_eph.mh_plus_q4, 321000000, 89500)
123 let buf: *u8 = sys_mmap(8192)
124 let n: nx_int = nx_chem_emit_report_csv(buf, pl, db, "SUSPECT-2026-001" as *u8, 5)
125 let _w: i64 = sys_write(1, buf, n as i64)
126 println("==================================================================" as *u8)
127 let _l1: i64 = print(" CSV size: " as *u8)
128 let _l2: i64 = print_i64(n as i64)
129 let _l3: i64 = println(" bytes (header + 4 rows)" as *u8)
130 println(" Open in Excel/Calc: comma-separated, RFC 4180 escaping," as *u8)
131 println(" citation field quoted only if it contains a comma" as *u8)
132 println("==================================================================" as *u8)
133 return 0
134}
135
136func main() -> nx_exit {
137 println("=== nx_chem_report_csv -- C6.1 KAT: CSV output ===" as *u8)
138
139 let ra: nx_int = a_csv_field_bare()
140 if ra != 0 { println("A csv_field_bare FAIL" as *u8); return ra }
141 println("A csv_field_bare PASS bare ASCII not quoted" as *u8)
142
143 let rb: nx_int = b_csv_field_with_comma()
144 if rb != 0 { println("B csv_field_with_comma FAIL" as *u8); return rb }
145 println("B csv_field_comma PASS comma triggers RFC 4180 quoting" as *u8)
146
147 let rc: nx_int = c_csv_field_with_quote()
148 if rc != 0 { println("C csv_field_quote FAIL" as *u8); return rc }
149 println("C csv_field_quote PASS internal \" doubled (RFC 4180)" as *u8)
150
151 let rd: nx_int = d_csv_header()
152 if rd != 0 { println("D csv_header FAIL" as *u8); return rd }
153 println("D csv_header PASS header has all 9 expected columns" as *u8)
154
155 let re: nx_int = e_full_report()
156 if re != 0 { println("E full_report FAIL" as *u8); return re }
157 println("E full_report PASS header + 2 matches with names + citations" as *u8)
158
159 let _demo: nx_int = run_csv_demo()
160
161 println("" as *u8)
162 println("=== C6.1 substrate milestone PASS ===" as *u8)
163 println(" emit_csv_field: RFC 4180 escaping (comma/quote/newline)" as *u8)
164 println(" emit_csv_header: 9-column header line" as *u8)
165 println(" emit_csv_row: per-match row with sample/peak/match/citation" as *u8)
166 println(" emit_report_csv: full report (header + N rows)" as *u8)
167 println(" emit_report_csv_rows_only: append rows without header" as *u8)
168 println(" (used in batch mode -- 1 header total)" as *u8)
169 println(" Excel-ready: lab analysts open CSV directly, sort/filter by" as *u8)
170 println(" regulatory column, hand to QA reviewer." as *u8)
171 return 0
172}