package attest_test; // The #6 @test DROP/KEEP/LINK emission property, driven by w6c / // w6c_ww DIRECTLY on the import-free test/wcc/data/attest_* fixtures. // Port of the retired native carrier test/wcc/911_attest_drop.c; // every assertion preserved. // // Direct-frontend is the only host that can compare -T and non-T on // the SAME input: `ww test` is always -T, `ww build` always non-T. // A @test fn is spliced out of a non-test build (harec-faithful, // ref/harec/src/check.c:3941 — checked but never emitted) and kept // under -T (the synth entry references it); the -T synth's `test.run` // callee stays an external CALL, so no driver resolution is needed. // // nondrop — attest_nondrop.ww compiled four ways (cs/ww x non-T/-T): // the plain fn's TEXT def is present in both modes; the three @test // TEXT defs are absent non-T and present under -T. The fixture layout // exercises the splice loop's unlink edges (head @test, surviving // plain fn, two consecutive @test). The presence rows run against the // cstage .s; the cs==ww byte-id in BOTH modes (rule 10) carries them // onto the wwstage .s by construction. // // undefbody — a @test body referencing an undefined symbol rejects in // non-T on both frontends: the body is type-checked BEFORE the splice // drops it (harec checks at :3913, drops at :3941). // // linkfail — non-test code CALLs a @test fn: non-T compile+assemble // succeed per stage triple, but the link MUST fail, and the link // stderr must name calldropped_test (non-vacuity: the failure is ON // the dropped @test symbol — a libwwrt path drift failing every link // would otherwise mask the property). import os; import os.exec; import strings; import testenv; import time; fn fail(label: str, why: str) void = { let m: str = strings.concat("attest FAIL: ", label, " -- ", why, "\n"); os.write(2, m.ptr, m.len: u64); assert(false); }; fn tmo() time.duration = { return (60i64 * (time.second: i64)): time.duration; }; fn runcode(dir: str, name: str, argv: []str) i32 = { let co: testenv.commandout; testenv.runcommand(dir, dir, name, argv, tmo(), &co); if (co.termination != exec.termination.EXIT) { return -1; }; return co.code; }; // column-0 anchored TEXT label; the '\n' prepend counts a // file-leading label too. fn hastext(s: str, sym: str) bool = { return testenv.occurrences(strings.concat("\n", s), strings.concat("\nTEXT ", sym, ",")) > 0; }; @test fn nondrop() void = { let td: str = testenv.fresh(); let fixture: str = strings.concat(testenv.repo(), "/test/wcc/data/attest_nondrop.ww"); let comps: []str = ["w6c", "w6c", "w6c_ww", "w6c_ww"]; let testmode: []bool = [false, true, false, true]; let names: []str = ["cp", "ct", "wp", "wt"]; let asms: []str = ["", "", "", ""]; let j: i32 = 0; for (j < 4) { let outf: str = strings.concat(td, "/", names[j], ".s"); let av: []str = alloc([], 5u64)!; append(av, testenv.driver(comps[j])); if (testmode[j]) { append(av, "-T"); }; append(av, fixture); append(av, "-o"); append(av, outf); if (runcode(td, names[j], av) != 0) { fail("nondrop", strings.concat(comps[j], " nondrop compile failed")); }; asms[j] = testenv.readfile(outf); j += 1; }; let syms: []str = ["data.nondrop_keep", "data.nondrop_test_a", "data.nondrop_test_b", "data.nondrop_test_c", "data.nondrop_keep", "data.nondrop_test_a", "data.nondrop_test_b", "data.nondrop_test_c"]; let rowmode: []bool = [false, false, false, false, true, true, true, true]; let present: []bool = [true, false, false, false, true, true, true, true]; let whats: []str = ["plain fn kept non-T", "head @test dropped non-T", "mid @test dropped non-T", "consecutive @test dropped non-T", "plain fn kept under -T", "head @test kept under -T", "mid @test kept under -T", "consecutive @test kept under -T"]; let i: i32 = 0; for (i < syms.len) { let s: str = asms[0]; if (rowmode[i]) { s = asms[1]; }; if (hastext(s, syms[i]) != present[i]) { fail("nondrop", whats[i]); }; i += 1; }; if (!testenv.same(asms[0], asms[2])) { fail("nondrop", "non-T @test-drop asm cs!=ww (rule 10)"); }; if (!testenv.same(asms[1], asms[3])) { fail("nondrop", "-T @test-keep asm cs!=ww (rule 10)"); }; testenv.clean(td); }; @test fn undefbody() void = { let td: str = testenv.fresh(); let fixture: str = strings.concat(testenv.repo(), "/test/wcc/data/attest_undefbody.ww"); let comps: []str = ["w6c", "w6c_ww"]; let c: i32 = 0; for (c < 2) { let av: []str = [testenv.driver(comps[c]), fixture, "-o", "/dev/null"]; if (runcode(td, strings.concat("reject_", comps[c]), av) == 0) { fail("undefbody", strings.concat(comps[c], " (non-T) accepted an undefined symbol in a @test body")); }; c += 1; }; testenv.clean(td); }; @test fn linkfail() void = { let td: str = testenv.fresh(); let fixture: str = strings.concat(testenv.repo(), "/test/wcc/data/attest_calldropped.ww"); let rt: str = strings.concat(testenv.repo(), "/out/lib/libwwrt.a"); let comps: []str = ["w6c", "w6c_ww"]; let asmts: []str = ["w6a", "w6a_ww"]; let linkts: []str = ["w6l", "w6l_ww"]; let s: i32 = 0; for (s < 2) { let asmf: str = strings.concat(td, "/lf.", comps[s], ".s"); let obj: str = strings.concat(td, "/lf.", comps[s], ".o"); let exe: str = strings.concat(td, "/lf.", comps[s], ".exe"); let cav: []str = [testenv.driver(comps[s]), fixture, "-o", asmf]; if (runcode(td, strings.concat("cc_", comps[s]), cav) != 0) { fail("linkfail", strings.concat(comps[s], " non-T calldropped compile failed")); }; let aav: []str = [testenv.driver(asmts[s]), "-o", obj, asmf]; if (runcode(td, strings.concat("as_", asmts[s]), aav) != 0) { fail("linkfail", strings.concat(asmts[s], " calldropped assemble failed")); }; let lo: testenv.commandout; let lav: []str = [testenv.driver(linkts[s]), "-o", exe, obj, rt]; testenv.runcommand(td, td, strings.concat("ld_", linkts[s]), lav, tmo(), &lo); assert(lo.termination == exec.termination.EXIT); if (lo.code == 0) { fail("linkfail", strings.concat(linkts[s], " linked calldropped (expected undefined-reference to ", "the dropped @test sym)")); }; if (!testenv.has(lo.stderr, "calldropped_test")) { fail("linkfail", strings.concat(linkts[s], " link failed but not on the dropped @test sym (masked)")); }; s += 1; }; testenv.clean(td); };