nx_mccabe_gate.nx source
↩ module page · 286 lines · 15341 B
1// nx_mccabe_gate.nx -- teeth for the cyclomatic-complexity census.
2//
3// IN-PROCESS: imports nx_mccabe_lib.nx and calls mc_scan_file directly, so it exercises the SAME code the
4// census runs and has no NOT-DEPLOYED failure mode.
5//
6// EVERY v(G) BELOW WAS COMPUTED BY HAND FIRST AND IS WRITTEN INTO THE TOOTH NAME. A complexity organ that is
7// only checked against itself is unfalsifiable; these are six shapes whose answers are known independently.
8//
9// THE TWO TEETH THAT MATTER MOST ARE THE TRAPS. The trivial wrong implementation is a text search for the
10// keywords, and it passes every counting tooth here -- only the COMMENT trap and the STRING trap refute it.
11// Measured on the real corpus before this organ existed: the first `&&` occurrences a naive search finds are
12// all inside comments. A SCANNER THAT DOES NOT SKIP COMMENTS MEASURES THE DOCUMENTATION, NOT THE CODE.
13//
14// Fixtures are planted at runtime under /tmp/mccabe_gate/ and unlinked before creation, so the gate is
15// idempotent and shares nothing with any production beat.
16// license_tier: ORIGINAL expect_exit: 0
17import "nx_mccabe_lib.nx"
18import "nx_gate_verdict.nx"
19
20const MCG_DIR: *u8 = "/tmp/mccabe_gate\x00"
21const MCG_MODE644: i64 = 420
22const MCG_MODE755: i64 = 493
23const MCG_NFIX: i64 = 9 // fixture files planted; binds the denominator so no tooth passes on the empty set
24// CE1 class-join fixtures live in a SEPARATE dir so the nine-fixture walk above stays exact, with a PLANTED table --
25// a gate that read the production conf would track that conf, not the code.
26const MCG_CLSDIR: *u8 = "/tmp/mccabe_gate_cls\x00"
27const MCG_CLSROWS: i64 = 2 // rows in the planted table
28const MCG_CLSFIX: i64 = 5 // class fixtures planted
29const MCG_ROW_BUILDER: i64 = 1 // planted table order: BUILDER first, so a head carrying both markers reads BUILDER
30const MCG_ROW_GENERATED: i64 = 2
31const MCG_CLS_BUILDER_FILES: i64 = 2 // g_builder + g_both (first row wins)
32const MCG_CLS_GEN_FILES: i64 = 1 // g_gen only -- g_late carries the marker BEYOND the head window
33const MCG_CLS_UNMARKED_FILES: i64 = 2 // g_plain + g_late
34const MCG_CLS_GEN_VG: i64 = 2 // g_gen: one if, hand-computed
35
36func mcg_put(path: *u8, data: *u8) -> i64 {
37 sys_unlinkat(path)
38 let fd: i64=sys_openat_wr(path, MCG_MODE644)
39 if fd<0 { return 0-1 }
40 var n: i64=0
41 while data[n]!=(0 as u8) { n=n+1 }
42 if n>0 { sys_write(fd, data, n) }
43 sys_close(fd)
44 return n
45}
46func mcg_path(buf: *u8, name: *u8) -> i64 {
47 var a: i64=mc_cat(buf, 0, MCG_DIR as *u8)
48 a=mc_cat(buf, a, "/" as *u8)
49 a=mc_cat(buf, a, name)
50 buf[a]=0 as u8
51 return a
52}
53func mcg_clspath(buf: *u8, name: *u8) -> i64 {
54 var a: i64=mc_cat(buf, 0, MCG_CLSDIR as *u8)
55 a=mc_cat(buf, a, "/" as *u8)
56 a=mc_cat(buf, a, name)
57 buf[a]=0 as u8
58 return a
59}
60// scan ONE single-function fixture and return that function's v(G); nf[0] receives the function count
61func mcg_vg(path: *u8, nf: *i64) -> i64 {
62 let hist: *i64=sys_mmap(MC_HIST_MAX*8+64) as *i64
63 var z: i64=0
64 while z<MC_HIST_MAX { hist[z]=0; z=z+1 }
65 let c: *i64=sys_mmap(128) as *i64
66 var y: i64=0
67 while y<8 { c[y]=0; y=y+1 }
68 let work: *u8=sys_mmap(65536)
69 let wo: *i64=sys_mmap(16) as *i64
70 wo[0]=0
71 mc_scan_file(path, hist, c, work, wo)
72 nf[0]=c[MC_C_FUNCS]
73 return c[MC_C_MAX]
74}
75
76func main(argc: i64, argv: *i64) -> i64 {
77 gv_head("=== NX-MCCABE-GATE -- does v(G) match a hand-computed answer, and does it ignore prose? ===" as *u8)
78 let ctr: *i64=gv_ctr()
79 sys_mkdir(MCG_DIR as *u8, MCG_MODE755)
80 let pb: *u8=sys_mmap(1024)
81 let nf: *i64=sys_mmap(16) as *i64
82
83 // ---------- plant nine shapes with independently known answers ----------
84 mcg_path(pb, "f1_flat.nx\x00" as *u8)
85 mcg_put(pb, "func t() -> i64 {\n return 0\n}\n" as *u8)
86 mcg_path(pb, "f2_oneif.nx\x00" as *u8)
87 mcg_put(pb, "func t(a: i64) -> i64 {\n if a>0 { return 1 }\n return 0\n}\n" as *u8)
88 mcg_path(pb, "f3_ifelse.nx\x00" as *u8)
89 mcg_put(pb, "func t(a: i64) -> i64 {\n if a>0 { return 1 } else { return 2 }\n}\n" as *u8)
90 mcg_path(pb, "f4_while.nx\x00" as *u8)
91 mcg_put(pb, "func t(a: i64) -> i64 {\n var i: i64=0\n while i<a { i=i+1 }\n return i\n}\n" as *u8)
92 mcg_path(pb, "f5_nested.nx\x00" as *u8)
93 mcg_put(pb, "func t(a: i64) -> i64 {\n if a>0 { if a>5 { return 2 } }\n return 0\n}\n" as *u8)
94 mcg_path(pb, "f6_commenttrap.nx\x00" as *u8)
95 mcg_put(pb, "func t() -> i64 {\n // if while for and if again\n return 0\n}\n" as *u8)
96 mcg_path(pb, "f7_stringtrap.nx\x00" as *u8)
97 mcg_put(pb, "func t() -> i64 {\n let s: *u8 = \x22if while for if\x22 as *u8\n return 0\n}\n" as *u8)
98 mcg_path(pb, "f8_andand.nx\x00" as *u8)
99 mcg_put(pb, "func t(a: i64, b: i64) -> i64 {\n if a>0 { if b>0 { return 1 } }\n return 0\n}\n" as *u8)
100 mcg_path(pb, "f9_deep.nx\x00" as *u8)
101 mcg_put(pb, "func t(a: i64) -> i64 {\n if a>1 { }\n if a>2 { }\n if a>3 { }\n if a>4 { }\n if a>5 { }\n if a>6 { }\n if a>7 { }\n if a>8 { }\n if a>9 { }\n if a>10 { }\n if a>11 { }\n if a>12 { }\n return 0\n}\n" as *u8)
102
103 // ---------- ANTI-VACUITY FIRST: a count-everything implementation dies here ----------
104 mcg_path(pb, "f1_flat.nx\x00" as *u8); let v1: i64=mcg_vg(pb, nf)
105 var ok1: i64=0
106 if v1==1 { if nf[0]==1 { ok1=1 } }
107 gv_check("neg-control-anti-vacuity-a-straight-line-function-is-exactly-vG-1" as *u8, ok1, ctr)
108
109 mcg_path(pb, "f2_oneif.nx\x00" as *u8); let v2: i64=mcg_vg(pb, nf)
110 var ok2: i64=0
111 if v2==2 { ok2=1 }
112 gv_check("one-if-is-vG-2-hand-computed" as *u8, ok2, ctr)
113
114 mcg_path(pb, "f3_ifelse.nx\x00" as *u8); let v3: i64=mcg_vg(pb, nf)
115 var ok3: i64=0
116 if v3==2 { ok3=1 }
117 gv_check("neg-control-else-is-NOT-a-decision-point-if-else-stays-vG-2" as *u8, ok3, ctr)
118
119 mcg_path(pb, "f4_while.nx\x00" as *u8); let v4: i64=mcg_vg(pb, nf)
120 var ok4: i64=0
121 if v4==2 { ok4=1 }
122 gv_check("one-while-is-vG-2-hand-computed" as *u8, ok4, ctr)
123
124 mcg_path(pb, "f5_nested.nx\x00" as *u8); let v5: i64=mcg_vg(pb, nf)
125 var ok5: i64=0
126 if v5==3 { ok5=1 }
127 gv_check("two-nested-ifs-are-vG-3-hand-computed" as *u8, ok5, ctr)
128
129 // ---------- THE TRAPS: the keyword-grep implementation passes everything above and dies here ----------
130 // A TRUE BITE PAIR: BOTH SIGNALS PRESENT AT ONCE. Two tests that each isolate one signal do not prove
131 // discrimination -- the detector under test is "does vG exceed 1", the BAD input is a function with REAL
132 // nested decisions (it must fire) and the GOOD input is a function whose only keywords are PROSE (it must
133 // stay silent). A keyword-grep implementation fires on both and dies here.
134 mcg_path(pb, "f6_commenttrap.nx\x00" as *u8); let v6: i64=mcg_vg(pb, nf)
135 var fires_real: i64=0
136 if v5>1 { fires_real=1 }
137 var fires_prose: i64=0
138 if v6>1 { fires_prose=1 }
139 gv_bite("discriminates-REAL-decisions-from-the-same-keywords-in-a-COMMENT" as *u8, fires_real, fires_prose, ctr)
140 var exact6: i64=0
141 if v6==1 { exact6=1 }
142 gv_check("comment-trap-lands-on-exactly-vG-1-not-merely-lower" as *u8, exact6, ctr)
143
144 mcg_path(pb, "f7_stringtrap.nx\x00" as *u8); let v7: i64=mcg_vg(pb, nf)
145 var fires_lit: i64=0
146 if v7>1 { fires_lit=1 }
147 gv_bite("discriminates-REAL-decisions-from-the-same-keywords-in-a-STRING-LITERAL" as *u8, fires_real, fires_lit, ctr)
148 var exact7: i64=0
149 if v7==1 { exact7=1 }
150 gv_check("string-trap-lands-on-exactly-vG-1-not-merely-lower" as *u8, exact7, ctr)
151
152 mcg_path(pb, "f8_andand.nx\x00" as *u8); let v8: i64=mcg_vg(pb, nf)
153 var ok8: i64=0
154 if v8==3 { ok8=1 }
155 gv_check("two-guards-are-vG-3-hand-computed" as *u8, ok8, ctr)
156
157 // ---------- the cited bar fires, and only where it should ----------
158 mcg_path(pb, "f9_deep.nx\x00" as *u8); let v9: i64=mcg_vg(pb, nf)
159 var badhi: i64=0
160 if v9>MC_LIMIT { badhi=1 }
161 var goodhi: i64=0
162 if v1>MC_LIMIT { goodhi=1 }
163 gv_bite("above-the-cited-limit-of-10-fires-on-a-13-and-is-silent-on-a-1" as *u8, badhi, goodhi, ctr)
164 var ok9: i64=0
165 if v9==13 { ok9=1 }
166 gv_check("twelve-ifs-are-vG-13-hand-computed" as *u8, ok9, ctr)
167
168 // ---------- a whole-directory walk: denominator bound, and the worklist names the offender ----------
169 let hist: *i64=sys_mmap(MC_HIST_MAX*8+64) as *i64
170 var z: i64=0
171 while z<MC_HIST_MAX { hist[z]=0; z=z+1 }
172 let c: *i64=sys_mmap(128) as *i64
173 var y: i64=0
174 while y<8 { c[y]=0; y=y+1 }
175 let work: *u8=sys_mmap(MC_WORKCAP)
176 let wo: *i64=sys_mmap(16) as *i64
177 wo[0]=0
178 let wp: *u8=sys_mmap(MC_PATHCAP)
179 let dn: i64=mc_cat(wp, 0, MCG_DIR as *u8)
180 mc_walk(wp, dn, 0, hist, c, work, wo)
181 var okf: i64=0
182 if c[MC_C_FILES]==MCG_NFIX { if c[MC_C_FUNCS]==MCG_NFIX { okf=1 } }
183 gv_check("the-walk-reached-all-nine-fixtures-and-found-all-nine-functions" as *u8, okf, ctr)
184 var okab: i64=0
185 if c[MC_C_ABOVE]==1 { okab=1 }
186 gv_check("exactly-one-fixture-is-above-the-cited-bar-not-zero-and-not-all" as *u8, okab, ctr)
187 var okwl: i64=0
188 if wo[0]>0 { okwl=1 }
189 gv_check("the-count-carries-its-worklist-the-offender-is-NAMED" as *u8, okwl, ctr)
190 var okp: i64=0
191 let p50: i64=mc_pct(hist, c[MC_C_FUNCS], c[MC_C_OVER], c[MC_C_MAX], 500)
192 if p50>=1 { if p50<=c[MC_C_MAX] { okp=1 } }
193 gv_check("p50-derived-from-the-CDF-lies-inside-the-observed-range" as *u8, okp, ctr)
194
195 // ---------- CE1: the head-marker class join, on planted fixtures in a SEPARATE dir with a PLANTED table ----------
196 sys_mkdir(MCG_CLSDIR as *u8, MCG_MODE755)
197 let cp: *u8=sys_mmap(1024)
198 mcg_clspath(cp, "classes.conf\x00" as *u8)
199 mcg_put(cp, "BUILDER|AUTHORED BY THE NISHI BUILDER\nGENERATED|GENERATED\n" as *u8)
200 mcg_clspath(cp, "g_gen.nx\x00" as *u8)
201 mcg_put(cp, "// GENERATED by a fixture planter\nfunc t(a: i64) -> i64 {\n if a>0 { return 1 }\n return 0\n}\n" as *u8)
202 mcg_clspath(cp, "g_builder.nx\x00" as *u8)
203 mcg_put(cp, "// AUTHORED BY THE NISHI BUILDER (pattern: FIXTURE)\nfunc t() -> i64 {\n return 0\n}\n" as *u8)
204 mcg_clspath(cp, "g_plain.nx\x00" as *u8)
205 mcg_put(cp, "func t() -> i64 {\n return 0\n}\n" as *u8)
206 mcg_clspath(cp, "g_both.nx\x00" as *u8)
207 mcg_put(cp, "// GENERATED but also AUTHORED BY THE NISHI BUILDER -- the FIRST table row wins\nfunc t() -> i64 {\n return 0\n}\n" as *u8)
208 mcg_clspath(cp, "g_late.nx\x00" as *u8)
209 mcg_put(cp, "// filler filler filler filler filler filler filler filler filler filler filler filler filler filler filler\n// filler filler filler filler filler filler filler filler filler filler filler filler filler filler filler\n// filler filler filler filler filler filler filler filler filler filler filler filler filler filler filler\n// filler filler filler filler filler filler filler filler filler filler filler filler filler filler filler\n// GENERATED beyond the head window\nfunc t() -> i64 {\n return 0\n}\n" as *u8)
210 let cc: *i64=sys_mmap(MC_C_SLOTS*8) as *i64
211 var cy: i64=0
212 while cy<MC_C_SLOTS { cc[cy]=0; cy=cy+1 }
213 mcg_clspath(cp, "classes.conf\x00" as *u8)
214 let crows: i64=mc_cls_load_from(cc, cp)
215 var okcr: i64=0
216 if crows==MCG_CLSROWS { okcr=1 }
217 gv_check("class-table-loads-exactly-two-rows-from-the-planted-conf" as *u8, okcr, ctr)
218 let chist: *i64=sys_mmap(MC_HIST_MAX*8+64) as *i64
219 var cz: i64=0
220 while cz<MC_HIST_MAX { chist[cz]=0; cz=cz+1 }
221 let cwork: *u8=sys_mmap(65536)
222 let cwo: *i64=sys_mmap(16) as *i64
223 cwo[0]=0
224 let cwp: *u8=sys_mmap(MC_PATHCAP)
225 let cdn: i64=mc_cat(cwp, 0, MCG_CLSDIR as *u8)
226 mc_walk(cwp, cdn, 0, chist, cc, cwork, cwo)
227 let bU: i64=MC_C_CLSBASE
228 let bB: i64=MC_C_CLSBASE+MCG_ROW_BUILDER*MC_CLS_FIELDS
229 let bG: i64=MC_C_CLSBASE+MCG_ROW_GENERATED*MC_CLS_FIELDS
230 var okwalk: i64=0
231 if cc[MC_C_FILES]==MCG_CLSFIX { okwalk=1 }
232 gv_check("the-class-walk-reached-all-five-class-fixtures" as *u8, okwalk, ctr)
233 var okg: i64=0
234 if cc[bG+MC_CF_FILES]==MCG_CLS_GEN_FILES { if cc[bG+MC_CF_FUNCS]==MCG_CLS_GEN_FILES { if cc[bG+MC_CF_SUMVG]==MCG_CLS_GEN_VG { okg=1 } } }
235 gv_check("generated-head-marker-classifies-into-the-GENERATED-row-carrying-its-hand-computed-vG-2" as *u8, okg, ctr)
236 var okb: i64=0
237 if cc[bB+MC_CF_FILES]==MCG_CLS_BUILDER_FILES { okb=1 }
238 gv_check("neg-control-first-matching-row-wins-a-head-carrying-BOTH-markers-reads-the-FIRST-row-BUILDER" as *u8, okb, ctr)
239 var oku: i64=0
240 if cc[bU+MC_CF_FILES]==MCG_CLS_UNMARKED_FILES { oku=1 }
241 gv_check("neg-control-a-marker-beyond-the-head-window-does-NOT-classify-a-whole-file-grep-dies-here" as *u8, oku, ctr)
242 var cps: i64=0
243 var cpn2: i64=0
244 var ci: i64=0
245 while ci<=crows { let cbi: i64=MC_C_CLSBASE+ci*MC_CLS_FIELDS; cps=cps+cc[cbi+MC_CF_FILES]; cpn2=cpn2+cc[cbi+MC_CF_FUNCS]; ci=ci+1 }
246 var oksum: i64=0
247 if cps==cc[MC_C_FILES] { if cpn2==cc[MC_C_FUNCS] { if cps==MCG_CLSFIX { oksum=1 } } }
248 gv_check("class-partition-sums-files-and-funcs-to-the-walk-and-the-walk-is-not-empty" as *u8, oksum, ctr)
249 // absent table: classification OFF, no class block written, the scan itself unchanged
250 let c2: *i64=sys_mmap(MC_C_SLOTS*8) as *i64
251 var c2y: i64=0
252 while c2y<MC_C_SLOTS { c2[c2y]=0; c2y=c2y+1 }
253 mcg_clspath(cp, "nope.conf\x00" as *u8)
254 let r2: i64=mc_cls_load_from(c2, cp)
255 mcg_clspath(cp, "g_gen.nx\x00" as *u8)
256 mc_scan_file(cp, chist, c2, cwork, cwo)
257 var okab2: i64=0
258 if r2==0 { if c2[MC_C_FILES]==1 { if c2[MC_C_CLSBASE+MC_CF_FILES]==0 { if c2[bG+MC_CF_FILES]==0 { okab2=1 } } } }
259 gv_check("neg-control-an-absent-table-classifies-nothing-and-writes-no-class-block" as *u8, okab2, ctr)
260 gv_puts(" class join: rows=" as *u8); gv_num(crows); gv_puts(" files=" as *u8); gv_num(cc[MC_C_FILES]); gv_puts(" UNMARKED=" as *u8); gv_num(cc[bU+MC_CF_FILES]); gv_puts(" BUILDER=" as *u8); gv_num(cc[bB+MC_CF_FILES]); gv_puts(" GENERATED=" as *u8); gv_num(cc[bG+MC_CF_FILES]); gv_puts(" gen_sumvG=" as *u8); gv_num(cc[bG+MC_CF_SUMVG]); gv_puts("\n" as *u8)
261
262 // ---------- idempotence ----------
263 mcg_path(pb, "f9_deep.nx\x00" as *u8)
264 let again: i64=mcg_vg(pb, nf)
265 var okid: i64=0
266 if again==v9 { okid=1 }
267 gv_check("idempotent-a-second-scan-returns-the-same-vG" as *u8, okid, ctr)
268
269 gv_puts("\n observed vG: flat=" as *u8); gv_num(v1)
270 gv_puts(" oneif=" as *u8); gv_num(v2)
271 gv_puts(" ifelse=" as *u8); gv_num(v3)
272 gv_puts(" while=" as *u8); gv_num(v4)
273 gv_puts(" nested=" as *u8); gv_num(v5)
274 gv_puts(" commenttrap=" as *u8); gv_num(v6)
275 gv_puts(" stringtrap=" as *u8); gv_num(v7)
276 gv_puts(" twoguards=" as *u8); gv_num(v8)
277 gv_puts(" deep=" as *u8); gv_num(v9)
278 gv_puts("\n walk: files=" as *u8); gv_num(c[MC_C_FILES])
279 gv_puts(" funcs=" as *u8); gv_num(c[MC_C_FUNCS])
280 gv_puts(" above10=" as *u8); gv_num(c[MC_C_ABOVE])
281 gv_puts(" max=" as *u8); gv_num(c[MC_C_MAX])
282 gv_puts(" p50=" as *u8); gv_num(p50)
283 gv_puts("\n" as *u8)
284
285 return gv_verdict("mccabe" as *u8, ctr, "every expected vG in the tooth names was hand-computed before the organ was run; fixtures are runtime-planted under /tmp and unlinked before creation" as *u8)
286}