package package_test; // Make builds and invokes this one binary; discovery, subprocess ownership, // output interpretation, and assertions remain WW code. import crypto.sha256; import hash; import os; import os.exec; import strings; import temp; import time; type commandout = struct { termination: exec.termination, code: i32, stdout: str, stderr: str, }; fn envrequired(name: str) str = { match (os.getenv(name)) { case let value: str => { assert(value.len != 0); return strings.dup(value); }; case void => abort("missing package-test environment"); }; }; fn repo() str = { return envrequired("WW_PACKAGE_REPO"); }; fn driver(name: str) str = { return strings.concat(repo(), "/out/bin/", name); }; fn readfile(path: str) str = { let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); assert(fd >= 0); let sr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = -1i64; match (sr) { case let v: i64 => n = v; case let e: os.oserror => abort("filesize failed"); }; assert(n >= 0i64); let b: []u8 = alloc([], (n + 1i64): u64)!; b.len = (n + 1i64): i32; let rr: (i64 | os.oserror) = os.readall(fd, b.ptr, n: u64); os.close(fd); let got: i64 = -1i64; match (rr) { case let v: i64 => got = v; case let e: os.oserror => abort("read failed"); }; assert(got == n); let ni: i32 = n: i32; b[ni] = 0u8; let out: str; out.ptr = b.ptr; out.len = n: i32; return out; }; fn writefile(path: str, content: str) void = { let fd: i32 = os.open(path, os.flag.WRONLY | os.flag.CREATE | os.flag.EXCL, 384i32); assert(fd >= 0); match (os.writeall(fd, content.ptr, content.len: u64)) { case let n: i64 => assert(n == content.len: i64); case let e: os.oserror => abort("write failed"); }; assert(os.close(fd) == 0); }; fn rewritefile(path: str, content: str) void = { let fd: i32 = os.open(path, os.flag.WRONLY | os.flag.TRUNC, 384i32); assert(fd >= 0); match (os.writeall(fd, content.ptr, content.len: u64)) { case let n: i64 => assert(n == content.len: i64); case let e: os.oserror => abort("write failed"); }; assert(os.close(fd) == 0); }; fn writeexecutable(path: str, content: str) void = { let fd: i32 = os.open(path, os.flag.WRONLY | os.flag.CREATE | os.flag.EXCL, 448i32); assert(fd >= 0); match (os.writeall(fd, content.ptr, content.len: u64)) { case let n: i64 => assert(n == content.len: i64); case let e: os.oserror => abort("write failed"); }; assert(os.close(fd) == 0); }; fn runcommand(root: str, name: str, argv: []str, lifetime: time.duration, out: *commandout) void = { let c: exec.command; c.path = argv[0]; c.argv = argv; c.env = os.getenvs(); c.dir = repo(); c.stdoutpath = strings.concat(root, "/", name, ".stdout"); c.stderrpath = strings.concat(root, "/", name, ".stderr"); c.deadline = time.add(time.now(time.clock.monotonic), lifetime); c.grace = (100i64 * (time.millisecond: i64)): time.duration; let r: exec.result; exec.run(&c, &r); assert(r.errno == 0 && r.cleanuperrno == 0); out.termination = r.termination; out.code = r.code; out.stdout = readfile(c.stdoutpath); out.stderr = readfile(c.stderrpath); }; fn runcommanddir(root: str, name: str, dir: str, argv: []str, lifetime: time.duration, out: *commandout) void = { let c: exec.command; c.path = argv[0]; c.argv = argv; c.env = os.getenvs(); c.dir = dir; c.stdoutpath = strings.concat(root, "/", name, ".stdout"); c.stderrpath = strings.concat(root, "/", name, ".stderr"); c.deadline = time.add(time.now(time.clock.monotonic), lifetime); c.grace = (100i64 * (time.millisecond: i64)): time.duration; let r: exec.result; exec.run(&c, &r); assert(r.errno == 0 && r.cleanuperrno == 0); out.termination = r.termination; out.code = r.code; out.stdout = readfile(c.stdoutpath); out.stderr = readfile(c.stderrpath); }; fn runcommandenv(root: str, name: str, argv: []str, env: []str, lifetime: time.duration, out: *commandout) void = { let c: exec.command; c.path = argv[0]; c.argv = argv; c.env = env; c.dir = repo(); c.stdoutpath = strings.concat(root, "/", name, ".stdout"); c.stderrpath = strings.concat(root, "/", name, ".stderr"); c.deadline = time.add(time.now(time.clock.monotonic), lifetime); c.grace = (100i64 * (time.millisecond: i64)): time.duration; let r: exec.result; exec.run(&c, &r); assert(r.errno == 0 && r.cleanuperrno == 0); out.termination = r.termination; out.code = r.code; out.stdout = readfile(c.stdoutpath); out.stderr = readfile(c.stderrpath); }; fn runcommandenvdir(root: str, name: str, argv: []str, env: []str, dir: str, lifetime: time.duration, out: *commandout) void = { let c: exec.command; c.path = argv[0]; c.argv = argv; c.env = env; c.dir = dir; c.stdoutpath = strings.concat(root, "/", name, ".stdout"); c.stderrpath = strings.concat(root, "/", name, ".stderr"); c.deadline = time.add(time.now(time.clock.monotonic), lifetime); c.grace = (100i64 * (time.millisecond: i64)): time.duration; let r: exec.result; exec.run(&c, &r); assert(r.errno == 0 && r.cleanuperrno == 0); out.termination = r.termination; out.code = r.code; out.stdout = readfile(c.stdoutpath); out.stderr = readfile(c.stderrpath); }; fn clean(root: str) void = { let av: []str = ["/bin/rm", "-rf", "--", root]; let c: exec.command; c.path = av[0]; c.argv = av; c.env = os.getenvs(); c.dir = "/"; c.stdoutpath = strings.concat(root, ".cleanup.stdout"); c.stderrpath = strings.concat(root, ".cleanup.stderr"); c.deadline = time.add(time.now(time.clock.monotonic), time.second); c.grace = (50i64 * (time.millisecond: i64)): time.duration; let r: exec.result; exec.run(&c, &r); assert(r.termination == exec.termination.EXIT && r.code == 0); assert(os.remove(c.stdoutpath) == 0); assert(os.remove(c.stderrpath) == 0); }; fn fresh() str = { return strings.dup(temp.dir()); }; fn pos(haystack: str, needle: str) i32 = { match (strings.index(haystack, needle)) { case let n: i32 => return n; case void => return -1; }; }; fn has(haystack: str, needle: str) bool = { return pos(haystack, needle) >= 0; }; fn same(a: str, b: str) bool = { if (a.len != b.len) { return false; }; let i: i32 = 0; for (i < a.len) { if (a[i] != b[i]) { return false; }; i += 1; }; return true; }; fn occurrences(haystack: str, needle: str) i32 = { if (needle.len == 0 || haystack.len < needle.len) { return 0; }; let count: i32 = 0; let i: i32 = 0; for (i + needle.len <= haystack.len) { let matches: bool = true; let j: i32 = 0; for (j < needle.len) { if (haystack[i + j] != needle[j]) { matches = false; break; }; j += 1; }; if (matches) { count += 1; i += needle.len; } else { i += 1; }; }; return count; }; fn boundarypkgname(n: i32) str = { assert(n >= 0 && n < 1000); let out: []u8 = alloc([], 4u64)!; append(out, 'p'); append(out, ('0': i32 + (n / 100)): u8); append(out, ('0': i32 + ((n / 10) % 10)): u8); append(out, ('0': i32 + (n % 10)): u8); return strings.frombytes(out); }; fn linecontaining(text: str, needle: str) str = { let start: i32 = 0; let i: i32 = 0; for (i <= text.len) { if (i == text.len || text[i] == '\n': u8) { let line: str; line.ptr = text.ptr + (start: u64); line.len = i - start; if (has(line, needle)) { return line; }; start = i + 1; }; i += 1; }; abort("missing trace line"); }; fn expectexit(out: *commandout, code: i32) void = { assert(out.termination == exec.termination.EXIT); assert(out.code == code); }; fn primarydiagnostic(s: str) str = { let begin: i32 = pos(s, ": error: "); if (begin >= 0) { begin += 9; } else { begin = pos(s, "ww: dependency cycle: "); }; if (begin < 0) { return s; }; let end: i32 = begin; for (end < s.len && s[end] != '\n') { end += 1; }; return strings.sub(s, begin, end); }; fn rejectpackagestable(root: str, label: str, target: str, needle: str) void = { let drivers: []str = ["ww", "ww_ww", "ww", "ww_ww"]; let tags: []str = ["c1", "w1", "c2", "w2"]; let diagnostics: []str = ["", "", "", ""]; let outstem: str = strings.concat(root, "/reject-", label); let i: i32 = 0; for (i < drivers.len) { let av: []str = [driver(drivers[i]), "test", "-c", "-o", outstem, "-I", root, target]; let out: commandout; runcommand(root, strings.concat("reject-", label, "-", tags[i]), av, (60i64 * (time.second: i64)): time.duration, &out); assert(out.termination == exec.termination.EXIT && out.code != 0); assert(has(out.stderr, needle)); diagnostics[i] = strings.dup(primarydiagnostic(out.stderr)); let scratch: str = strings.concat(outstem, ".sepwork"); if (os.exists(scratch)) { clean(scratch); }; if (os.exists(outstem)) { clean(outstem); }; i += 1; }; assert(same(diagnostics[0], diagnostics[2])); assert(same(diagnostics[1], diagnostics[3])); assert(same(diagnostics[0], diagnostics[1])); }; fn packagepath(relative: str) str = { return strings.concat(repo(), "/test/package/", relative); }; fn workescape(s: str) str = { let out: []u8 = alloc([], (s.len * 2 + 1): u64)!; let i: i32 = 0; for (i < s.len) { if (s[i] == '_') { append(out, '_'); append(out, 'u'); } else { if (s[i] == '/') { append(out, '_'); append(out, 's'); } else { append(out, s[i]); }; }; i += 1; }; return strings.frombytes(out); }; fn localidentity(dir: str, declaredname: str) str = { let out: []u8 = alloc([], (dir.len * 4 + 16): u64)!; let prefix: str = "__wwlocal.p"; let i: i32 = 0; for (i < prefix.len) { append(out, prefix[i]); i += 1; }; let hex: str = "0123456789abcdef"; i = 0; for (i < dir.len) { let c: u8 = dir[i]; if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) { append(out, c); } else if (c == '_') { append(out, '_'); append(out, 'u'); } else if (c == '/') { append(out, '_'); append(out, 's'); } else { let high: i32 = (c / 16u8): i32; let low: i32 = (c % 16u8): i32; append(out, '_'); append(out, 'x'); append(out, hex[high]); append(out, hex[low]); }; i += 1; }; return strings.frombytes(out); }; fn digesthex(h: *hash.hash) str = { let digest: [32]u8; hash.sum(h, digest[0:32]); let out: []u8 = alloc([], 65u64)!; let digits: str = "0123456789abcdef"; let i: i32 = 0; for (i < 32) { let high: i32 = (digest[i] / 16u8): i32; let low: i32 = (digest[i] % 16u8): i32; append(out, digits[high]); append(out, digits[low]); i += 1; }; return strings.frombytes(out); }; fn packagestoragekey(path: str, canon: str, variant: i32, role: i32) str = { let state: sha256.state = sha256.sha256(); let h: *hash.hash = (&state): *hash.hash; hash.write(h, strings.toutf8("ww-package-storage-v2:")); let tag: [4]u8; tag[0] = ('0': i32 + variant): u8; tag[1] = ':': u8; tag[2] = ('0': i32 + role): u8; tag[3] = ':': u8; hash.write(h, tag[0:4]); hash.write(h, strings.toutf8(path)); let zero: [1]u8; zero[0] = 0u8; hash.write(h, zero[0:1]); hash.write(h, strings.toutf8(canon)); let out: []u8 = alloc([], 81u64)!; let prefix: str = "__wwpkg.v"; let i: i32 = 0; for (i < prefix.len) { append(out, prefix[i]); i += 1; }; append(out, tag[0]); append(out, '.'); append(out, 'r'); append(out, tag[2]); append(out, '.'); append(out, 'h'); let hex: str = digesthex(h); i = 0; for (i < hex.len) { append(out, hex[i]); i += 1; }; return strings.frombytes(out); }; fn importrelative(path: str) str = { let out: []u8 = alloc([], (path.len + 1): u64)!; let i: i32 = 0; for (i < path.len) { if (path[i] == '.') { append(out, '/'); } else { append(out, path[i]); }; i += 1; }; return strings.frombytes(out); }; fn longidentity(leaf: str) str = { let out: []u8 = alloc([], 384u64)!; let component: str = "segmentabcdefghijklmnop"; let n: i32 = 0; for (n < 13) { let i: i32 = 0; for (i < component.len) { append(out, component[i]); i += 1; }; append(out, '.'); n += 1; }; let i: i32 = 0; for (i < leaf.len) { append(out, leaf[i]); i += 1; }; return strings.frombytes(out); }; fn deeppunctuationpath(root: str, branch: str) str = { let out: str = strings.concat(root, "/outside +% @ _/", branch); let component: str = "/punctuation + percent% at@ under_score"; let n: i32 = 0; for (n < 9) { out = strings.concat(out, component); n += 1; }; return out; }; fn mkdirall(path: str) void = { match (os.mkdirs(path, 448i32)) { case void => void; case let e: os.oserror => abort("mkdirs failed"); }; }; fn normalizedtrace(trace: str, work: str, output: str) str = { let first: str; match (strings.replace(trace, work, "$WORK/")) { case let value: str => first = value; case nomem => abort("trace normalization failed"); }; match (strings.replace(first, output, "$OUTPUT")) { case let value: str => return value; case nomem => abort("trace normalization failed"); }; }; fn hexbytes(value: str) str = { let out: []u8 = alloc([], (value.len * 2 + 1): u64)!; let digits: str = "0123456789abcdef"; let i: i32 = 0; for (i < value.len) { let high: i32 = (value[i] / 16u8): i32; let low: i32 = (value[i] % 16u8): i32; append(out, digits[high]); append(out, digits[low]); i += 1; }; return strings.frombytes(out); }; @test fn deterministic_routing_and_filters() void = { let root: str = fresh(); let target: str = packagepath("routing"); let sourceroot: str = strings.concat(repo(), "/test/package"); let av: []str = [driver("ww"), "test", "-I", sourceroot, "-list", target]; let out: commandout; runcommand(root, "list", av, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let first: i32 = pos(out.stdout, "routing.private_helper_first\n"); let second: i32 = pos(out.stdout, "routing.same_package\n"); let third: i32 = pos(out.stdout, "routing_test.external_package\n"); assert(first >= 0 && first < second && second < third); assert(occurrences(out.stdout, "routing.private_helper_first\n") == 1); assert(occurrences(out.stdout, "routing.same_package\n") == 1); assert(occurrences(out.stdout, "routing_test.external_package\n") == 1); let rav: []str = [driver("ww"), "test", "-I", sourceroot, target]; runcommand(root, "run", rav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "routing.private_helper_first ... ok\n")); assert(has(out.stdout, "routing.same_package ... ok\n")); assert(has(out.stdout, "routing_test.external_package ... ok\n")); assert(has(out.stdout, "2 passed, 0 failed, 0 skipped, 0 harness errors\n")); assert(has(out.stdout, "1 passed, 0 failed, 0 skipped, 0 harness errors\n")); let fav: []str = [driver("ww"), "test", "-run", "routing.private_helper_first", "-filter", "external_package", "-I", sourceroot, target]; runcommand(root, "filters", fav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "routing.private_helper_first ... ok\n")); assert(!has(out.stdout, "routing.same_package ...")); assert(has(out.stdout, "routing_test.external_package ... ok\n")); let nav: []str = [driver("ww"), "test", "-I", sourceroot, "-run", "no-such-*", target]; runcommand(root, "nomatch", nav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(occurrences(out.stdout, "[no matches]\n") == 2); assert(occurrences(out.stdout, "1 discovered, 0 selected, 0 started, 0 completed\n") == 1); assert(occurrences(out.stdout, "2 discovered, 0 selected, 0 started, 0 completed\n") == 1); let lnav: []str = [driver("ww"), "test", "-list", "-run", "no-such-*", "-I", sourceroot, target]; runcommand(root, "list-nomatch", lnav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(occurrences(out.stdout, "[no matches]\n") == 2); clean(root); }; @test fn imported_dependency_tests_do_not_leak() void = { let root: str = fresh(); let base: str = packagepath("dependency"); let av: []str = [driver("ww"), "test", "-I", base, strings.concat(base, "/root")]; let out: commandout; runcommand(root, "dependency", av, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "root.imported_production_only ... ok\n")); assert(!has(out.stdout, "imported_dependency_test_must_not_leak")); assert(has(out.stdout, "1 discovered, 1 selected, 1 started, 1 completed\n")); clean(root); }; // Go's contract: only *_test.ww sources are test sources; a line-leading // @test anywhere else fails classification loudly rather than run or // drop silently. @test fn noncanonical_attest_rejected() void = { let root: str = fresh(); let pkgdir: str = strings.concat(root, "/noncanon"); assert(os.mkdir(pkgdir, 448i32) == 0); writefile(strings.concat(pkgdir, "/noncanon.ww"), strings.concat( "package noncanon;\n", "@test\n/* lexer whitespace is legal here */\n", "fn hidden() void = { assert(false); };\n")); let stages: []str = ["ww", "ww_ww"]; let out: commandout; let i: i32 = 0; for (i < stages.len) { let av: []str = [driver(stages[i]), "test", pkgdir]; runcommand(root, strings.concat("noncanon-", stages[i]), av, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, "@test declaration outside *_test.ww")); assert(!has(out.stdout, "hidden")); i += 1; }; clean(root); }; @test fn empty_and_invalid_package_classes() void = { let root: str = fresh(); let av: []str = [driver("ww"), "test", packagepath("no_tests")]; let out: commandout; runcommand(root, "notests", av, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, " [no tests]\n")); assert(!has(out.stdout, " ... ok")); let bad: []str = [driver("ww"), "test", packagepath("bad_external")]; runcommand(root, "badexternal", bad, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, "test package must match production package or _test")); let empty: str = strings.concat(root, "/empty"); assert(os.mkdir(empty, 448i32) == 0); let emptyav: []str = [driver("ww"), "test", empty]; runcommand(root, "emptydir", emptyav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, "directory contains no WW package sources")); let invalid: str = strings.concat(root, "/invalid-no-tests"); assert(os.mkdir(invalid, 448i32) == 0); writefile(strings.concat(invalid, "/invalid.ww"), "package invalid;\nimport nowhere;\n"); let invalidav: []str = [driver("ww"), "test", invalid]; runcommand(root, "invalid-no-tests", invalidav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, "cannot find package nowhere")); assert(!has(out.stdout, "[no tests]")); // A test file is part of its variant even when it only supplies helpers. // Its imports and package clause must therefore reach the shared loader; // the coordinator cannot use textual @test presence as a source filter. let helperbad: str = strings.concat(root, "/helperbad"); assert(os.mkdir(helperbad, 448i32) == 0); writefile(strings.concat(helperbad, "/helperbad.ww"), "package helperbad;\nexport fn value() i32 = { return 1; };\n"); writefile(strings.concat(helperbad, "/helper_test.ww"), "package helperbad_test;\nimport nowhere;\nfn helper() void = { };\n"); let stages: []str = ["ww", "ww_ww"]; let si: i32 = 0; for (si < stages.len) { let helperav: []str = [driver(stages[si]), "test", helperbad]; runcommand(root, strings.concat("helper-only-", stages[si]), helperav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, "cannot find package nowhere")); si += 1; }; let helperwrong: str = strings.concat(root, "/helperwrong"); assert(os.mkdir(helperwrong, 448i32) == 0); writefile(strings.concat(helperwrong, "/helperwrong.ww"), "package helperwrong;\nfn value() void = { };\n"); writefile(strings.concat(helperwrong, "/wrong_test.ww"), "package unrelated;\nfn helper() void = { };\n"); let wrongav: []str = [driver("ww"), "test", helperwrong]; runcommand(root, "helper-wrong-package", wrongav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, "test package must match production package or _test")); // Package declarations are validation/kind data, not fixed driver storage. // A 256-byte selector must reach both stages intact and run under the same // reversible outside-root identity instead of preserving the old slot cap. let longdir: str = strings.concat(root, "/long-package"); assert(os.mkdir(longdir, 448i32) == 0); let chunk: str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; let longname: str = strings.concat(chunk, chunk, chunk, chunk, chunk, chunk, chunk, chunk); assert(longname.len == 256); writefile(strings.concat(longdir, "/long.ww"), strings.concat("package ", longname, ";\nfn value() void = { };\n")); writefile(strings.concat(longdir, "/long_test.ww"), strings.concat( "package ", longname, ";\n", "@test fn long_package_runs() void = { value(); };\n")); let longc: []str = [driver("ww"), "test", longdir]; let longw: []str = [driver("ww_ww"), "test", longdir]; let outc: commandout; let outw: commandout; runcommand(root, "long-package-c", longc, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "long-package-ww", longw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(outc.stderr.len == 0); assert(has(outc.stdout, strings.concat(longname, ".long_package_runs ... ok\n"))); let multiline: str = strings.concat(root, "/multiline-test"); assert(os.mkdir(multiline, 448i32) == 0); writefile(strings.concat(multiline, "/multiline.ww"), "package multiline;\nfn value() i32 = { return 42; };\n"); writefile(strings.concat(multiline, "/multiline_test.ww"), strings.concat("package multiline;\n@test\n", "/* lexer whitespace between attribute and declaration */\n", "fn actually_runs() void = { assert(value() == 42); };\n")); let multilineav: []str = [driver("ww"), "test", multiline]; runcommand(root, "multiline-test", multilineav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "multiline.actually_runs ... ok\n")); assert(!has(out.stdout, "[no tests]")); let commented: str = strings.concat(root, "/commented-test"); assert(os.mkdir(commented, 448i32) == 0); writefile(strings.concat(commented, "/commented.ww"), "package commented;\nfn value() i32 = { return 1; };\n"); writefile(strings.concat(commented, "/commented_test.ww"), strings.concat( "package commented;\n/*\n", "@test fn phantom() void = { assert(false); };\n", "*/\nfn helper() void = { };\n")); let commentedav: []str = [driver("ww"), "test", commented]; runcommand(root, "commented-test", commentedav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, " [no tests]\n")); assert(!has(out.stdout, "phantom")); clean(root); }; @test fn symlink_package_root_reuses_canonical_directory() void = { let root: str = fresh(); let real: str = deeppunctuationpath(root, "symlink target"); let link: str = strings.concat(root, "/link"); let wrapper: str = strings.concat(root, "/compiler wrapper.sh"); mkdirall(real); writefile(strings.concat(real, "/real.ww"), "package real;\nexport fn value() int = { return 1; };\n"); writefile(strings.concat(real, "/real_test.ww"), "package real;\n@test fn value_is_one() void = { assert(value() == 1); };\n"); let lav: []str = ["/bin/ln", "-s", real, link]; let out: commandout; runcommand(root, "link", lav, time.second, &out); expectexit(&out, 0); writeexecutable(wrapper, strings.concat( "#!/bin/sh\n", "printf 'BEGIN' >> \"$WW_SYMLINK_COMPILER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_SYMLINK_COMPILER_TRACE\"; done\n", "printf '\\n' >> \"$WW_SYMLINK_COMPILER_TRACE\"\n", "exec \"$WW_SYMLINK_REAL_COMPILER\" \"$@\"\n")); let actionid: str = localidentity(real, "real"); assert(actionid.len > 255); let action: str = packagestoragekey(actionid, real, 1, 0); assert(action.len + 9 <= 255); let stages: []str = ["ww", "ww_ww"]; let compilers: []str = ["w6c", "w6c_ww"]; let references: []str = ["", "", ""]; let baseenv: []str = os.getenvs(); let si: i32 = 0; for (si < stages.len) { let work: str = strings.concat(root, "/work-", stages[si]); let trace: str = strings.concat(root, "/trace-", stages[si]); assert(os.mkdir(work, 448i32) == 0); writefile(trace, ""); let env: []str = alloc([], (baseenv.len + 3): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_SYMLINK_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_SYMLINK_REAL_COMPILER=")) { append(env, baseenv[ei]); }; ei += 1; }; append(env, strings.concat("WW_W6C=", wrapper)); append(env, strings.concat("WW_SYMLINK_COMPILER_TRACE=", trace)); append(env, strings.concat("WW_SYMLINK_REAL_COMPILER=", driver(compilers[si]))); let av: []str = [driver(stages[si]), "test", "-w", work, real]; runcommandenv(root, strings.concat("real-cold-", stages[si]), av, env, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "real.value_is_one ... ok\n")); let coldtrace: str = readfile(trace); assert(coldtrace.len > 0); assert(has(coldtrace, strings.concat("<--import><", actionid, "><"))); let key: str = work; assert(os.exists(key)); let suffixes: []str = [".unit.ww", ".wwi", ".a"]; let xi: i32 = 0; for (xi < suffixes.len) { let artifact: str = readfile(strings.concat(key, "/", action, suffixes[xi])); if (xi == 0) { assert(has(artifact, strings.concat("//ww:module-reset ", actionid, "\n"))); } else { if (xi == 1) { assert(strings.hasprefix(artifact, strings.concat("//ww:module ", actionid, "\n"))); }; }; if (si == 0) { references[xi] = strings.dup(artifact); } else { assert(same(references[xi], artifact)); }; xi += 1; }; let linkav: []str = [driver(stages[si]), "test", "-w", work, link]; runcommandenv(root, strings.concat("symlink-warm-", stages[si]), linkav, env, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "real.value_is_one ... ok\n")); assert(same(coldtrace, readfile(trace))); xi = 0; for (xi < suffixes.len) { assert(same(references[xi], readfile(strings.concat(key, "/", action, suffixes[xi])))); xi += 1; }; let relative: str = strings.concat(".", strings.sub(real, root.len, real.len)); let relativeav: []str = [driver(stages[si]), "test", "-w", work, relative]; runcommandenvdir(root, strings.concat("relative-warm-", stages[si]), relativeav, env, root, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "real.value_is_one ... ok\n")); assert(same(coldtrace, readfile(trace))); xi = 0; for (xi < suffixes.len) { assert(same(references[xi], readfile(strings.concat(key, "/", action, suffixes[xi])))); xi += 1; }; si += 1; }; clean(root); }; @test fn pass_skip_and_expected_abort() void = { let root: str = fresh(); let av: []str = [driver("ww"), "test", packagepath("cases/pass")]; let out: commandout; runcommand(root, "pass", av, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "pass_test.alpha_pass ... ok\n")); assert(has(out.stdout, "pass_test.beta_skip ... SKIP: synthetic unavailable feature\n")); assert(has(out.stdout, "pass_test.gamma_expected_abort ... ok\n")); assert(has(out.stdout, "pass_test.delta_pass ... ok\n")); assert(has(out.stdout, "3 passed, 0 failed, 1 skipped, 0 harness errors\n")); assert(has(out.stdout, "4 discovered, 4 selected, 4 started, 4 completed\n")); clean(root); }; @test fn failures_are_distinct_and_clamped() void = { let root: str = fresh(); let out: commandout; let av: []str = [driver("ww"), "test", packagepath("cases/assert_failure")]; runcommand(root, "assert", av, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "assert_failure_test.assertion_failure ... FAIL (exit 1)\n")); assert(!has(out.stderr, "captures:")); let nonzeroav: []str = [driver("ww"), "test", packagepath("cases/nonzero")]; runcommand(root, "nonzero", nonzeroav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "nonzero_test.deliberate_nonzero_exit ... FAIL (exit 7)\n")); let prematureav: []str = [driver("ww"), "test", packagepath("cases/premature")]; runcommand(root, "premature", prematureav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "premature_test.clean_exit_without_completion ... HARNESS (incomplete result)\n")); let signalav: []str = [driver("ww"), "test", packagepath("cases/signal")]; runcommand(root, "signal", signalav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "signal_test.signal_is_not_exit ... FAIL (signal 15)\n")); let multiav: []str = [driver("ww"), "test", packagepath("cases/multi_fail")]; runcommand(root, "multifail", multiav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "1 passed, 2 failed, 0 skipped, 0 harness errors\n")); assert(has(out.stdout, "3 discovered, 3 selected, 3 started, 3 completed\n")); clean(root); }; @test fn timeout_and_descendant_cleanup() void = { let root: str = fresh(); let av: []str = [driver("ww"), "test", "-timeout-ms=100", packagepath("cases/timeout")]; let out: commandout; runcommand(root, "timeout", av, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "timeout_test.timeout_clears_term_resistant_descendant ... FAIL(timeout)\n")); assert(has(out.stdout, "1 discovered, 1 selected, 1 started, 1 completed\n")); let descendantav: []str = [driver("ww"), "test", packagepath("cases/descendant")]; runcommand(root, "descendant", descendantav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "descendant_test.normal_return_clears_descendant ... ok\n")); assert(!has(out.stdout, "HARNESS")); clean(root); }; @test fn cstage_wwstage_behavior_and_assembly_match() void = { let root: str = fresh(); let route: str = strings.concat(root, "/route"); assert(os.mkdir(route, 448i32) == 0); writefile(strings.concat(route, "/route.ww"), "package route;\nexport fn value() int = { return 7; };\n"); writefile(strings.concat(route, "/a_test.ww"), "package route;\n@test fn white() void = { assert(value() == 7); };\n"); writefile(strings.concat(route, "/z_test.ww"), "package route_test;\nimport route;\n@test fn external() void = { assert(route.value() == 7); };\n"); let outc: commandout; let outw: commandout; let listc: []str = [driver("ww"), "test", "-I", root, "-list", route]; let listw: []str = [driver("ww_ww"), "test", "-I", root, "-list", route]; runcommand(root, "list-c", listc, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "list-ww", listw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); let misusec: []str = [driver("ww"), "test", "-run"]; let misusew: []str = [driver("ww_ww"), "test", "-run"]; runcommand(root, "misuse-c", misusec, time.second, &outc); runcommand(root, "misuse-ww", misusew, time.second, &outw); expectexit(&outc, 2); expectexit(&outw, 2); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "ww test: -run needs an argument\n")); let timeoutc: []str = [driver("ww"), "test", "-timeout-ms=4000000", "-I", root, route]; let timeoutw: []str = [driver("ww_ww"), "test", "-timeout-ms=4000000", "-I", root, route]; runcommand(root, "timeout-misuse-c", timeoutc, time.second, &outc); runcommand(root, "timeout-misuse-ww", timeoutw, time.second, &outw); expectexit(&outc, 2); expectexit(&outw, 2); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "usage: wwtest package")); let cc: []str = [driver("ww"), "test", "-c", "-I", root, route]; runcommand(root, "compile-c", cc, (30i64 * (time.second: i64)): time.duration, &outc); expectexit(&outc, 0); assert(has(outc.stdout, strings.concat(" -> ", route, "/route.test\n"))); assert(has(outc.stdout, strings.concat(" -> ", route, "/route_test.test\n"))); let cwhite: str = readfile(strings.concat(route, "/route.test.sepwork/route-internal-test.s")); let cexternal: str = readfile(strings.concat(route, "/route.test.sepwork/route_test-external-test.s")); // The explicit package `-c` outputs are caller-owned artifacts. Release // the shared C-stage tree before asking the WW driver to acquire the same // stem; the driver never deletes a pre-existing `.sepwork` path. clean(strings.concat(route, "/route.test.sepwork")); let wc: []str = [driver("ww_ww"), "test", "-c", "-I", root, route]; runcommand(root, "compile-ww", wc, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(same(cwhite, readfile(strings.concat(route, "/route.test.sepwork/route-internal-test.s")))); assert(same(cexternal, readfile(strings.concat(route, "/route.test.sepwork/route_test-external-test.s")))); clean(root); }; @test fn directory_package_graph_variants() void = { let root: str = fresh(); let implementation: str = strings.concat(root, "/implementation"); let api: str = strings.concat(root, "/api"); let testonly: str = strings.concat(root, "/__same"); let externalonly: str = strings.concat(root, "/__external"); let pkg: str = strings.concat(root, "/pkg"); assert(os.mkdir(implementation, 448i32) == 0); assert(os.mkdir(api, 448i32) == 0); assert(os.mkdir(testonly, 448i32) == 0); assert(os.mkdir(externalonly, 448i32) == 0); assert(os.mkdir(pkg, 448i32) == 0); writefile(strings.concat(implementation, "/implementation.ww"), strings.concat("package implementation;\n", "// IMPLEMENTATION_SOURCE\n", "export fn value() i32 = { return 41; };\n")); writefile(strings.concat(api, "/api.ww"), strings.concat( "package api;\nimport implementation;\n", "// API_SOURCE\n", "export fn value() i32 = { return implementation.value(); };\n")); writefile(strings.concat(api, "/api_test.ww"), strings.concat( "package api;\n", "TEST_DEPENDENCY_MUST_NOT_COMPILE\n")); writefile(strings.concat(testonly, "/source.ww"), strings.concat( "package __same;\n", "export fn value() i32 = { return 1; };\n")); writefile(strings.concat(externalonly, "/source.ww"), strings.concat( "package __external;\n", "export fn value() i32 = { return 1; };\n")); writefile(strings.concat(pkg, "/a.ww"), strings.concat( "package pkg;\nimport api;\n", "// PACKAGE_PRODUCTION_A\n", "export fn value() i32 = { return api.value(); };\n")); writefile(strings.concat(pkg, "/z.ww"), strings.concat( "package pkg;\n", "// PACKAGE_PRODUCTION_Z\n", "fn secret() i32 = { return 6; };\n", "export fn second() i32 = { return 9; };\n")); writefile(strings.concat(pkg, "/same_test.ww"), strings.concat( "package pkg;\nimport __same;\n", "// SAME_TEST_SOURCE\n", "@test fn same_graph() void = {\n", " assert(value() + __same.value() == 42);\n", " assert(secret() == 6);\n};\n")); writefile(strings.concat(pkg, "/external_test.ww"), strings.concat( "package pkg_test;\nimport __external;\nimport pkg;\n", "// EXTERNAL_TEST_SOURCE\n", "@test fn external_graph() void = {\n", " assert(pkg.value() + __external.value() == 42);\n", " assert(pkg.second() == 9);\n};\n")); let prodout: str = strings.concat(root, "/production.a"); let prodav: []str = [driver("ww"), "build", "-I", root, "-o", prodout, pkg]; let out: commandout; runcommand(root, "production-build", prodav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let prodwork: str = strings.concat(prodout, ".sepwork/"); let produnit: str = readfile(strings.concat(prodwork, "pkg.unit.ww")); assert(has(produnit, "//ww:module-reset pkg\n")); assert(!has(produnit, "//ww:module ")); assert(!has(produnit, "IMPLEMENTATION_SOURCE")); assert(!has(produnit, "__same")); assert(!has(produnit, "__external")); assert(!os.exists(strings.concat(prodwork, "__same.unit.ww"))); assert(!os.exists(strings.concat(prodwork, "__external.unit.ww"))); assert(!has(readfile(strings.concat(prodwork, "api.unit.ww")), "TEST_DEPENDENCY_MUST_NOT_COMPILE")); let samebin: str = strings.concat(pkg, "/pkg.test"); let externalbin: str = strings.concat(pkg, "/pkg_test.test"); let sharedworkroot: str = strings.concat(samebin, ".sepwork"); let sharedwork: str = strings.concat(sharedworkroot, "/"); let compilertrace: str = strings.concat(root, "/compiler.trace"); let linkertrace: str = strings.concat(root, "/linker.trace"); let compilerwrapper: str = strings.concat(root, "/trace-w6c.sh"); let linkerwrapper: str = strings.concat(root, "/trace-w6l.sh"); writefile(compilertrace, ""); writefile(linkertrace, ""); writeexecutable(compilerwrapper, strings.concat( "#!/bin/sh\n", "printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_COMPILER_TRACE\"\n", "exec \"$WW_PACKAGE_W6C\" \"$@\"\n")); writeexecutable(linkerwrapper, strings.concat( "#!/bin/sh\n", "printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_LINKER_TRACE\"\n", "exec \"$WW_PACKAGE_W6L\" \"$@\"\n")); let baseenv: []str = os.getenvs(); let traceenv: []str = alloc([], (baseenv.len + 6): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_LINKER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6L=")) { append(traceenv, baseenv[ei]); }; ei += 1; }; append(traceenv, strings.concat("WW_W6C=", compilerwrapper)); append(traceenv, strings.concat("WW_W6L=", linkerwrapper)); append(traceenv, strings.concat("WW_PACKAGE_COMPILER_TRACE=", compilertrace)); append(traceenv, strings.concat("WW_PACKAGE_LINKER_TRACE=", linkertrace)); append(traceenv, strings.concat("WW_PACKAGE_W6C=", driver("w6c"))); append(traceenv, strings.concat("WW_PACKAGE_W6L=", driver("w6l"))); let wwtraceenv: []str = alloc([], (baseenv.len + 6): u64)!; ei = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_LINKER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6L=")) { append(wwtraceenv, baseenv[ei]); }; ei += 1; }; append(wwtraceenv, strings.concat("WW_W6C=", compilerwrapper)); append(wwtraceenv, strings.concat("WW_W6L=", linkerwrapper)); append(wwtraceenv, strings.concat("WW_PACKAGE_COMPILER_TRACE=", compilertrace)); append(wwtraceenv, strings.concat("WW_PACKAGE_LINKER_TRACE=", linkertrace)); append(wwtraceenv, strings.concat("WW_PACKAGE_W6C=", driver("w6c_ww"))); append(wwtraceenv, strings.concat("WW_PACKAGE_W6L=", driver("w6l_ww"))); let drivers: []str = ["ww", "ww", "ww_ww"]; let tags: []str = ["c1", "c2", "ww"]; let referenceout: str = ""; let referenceerr: str = ""; let referencesame: str = ""; let referenceexternal: str = ""; let referencesameunit: str = ""; let referenceexternalunit: str = ""; let referenceproductionunit: str = ""; let packageactions: []str = ["pkg-internal-test", "pkg-internal-test-main", "pkg_test-external-test", "pkg_test-external-test-main"]; let referenceactionexports: []str = ["", "", "", ""]; let referenceactionarchives: []str = ["", "", "", ""]; let i: i32 = 0; for (i < drivers.len) { let av: []str = [driver(drivers[i]), "test", "-c", "-I", root, pkg]; if (i == 0) { runcommandenv(root, strings.concat("variant-build-", tags[i]), av, traceenv, (120i64 * (time.second: i64)): time.duration, &out); } else { runcommand(root, strings.concat("variant-build-", tags[i]), av, (120i64 * (time.second: i64)): time.duration, &out); }; expectexit(&out, 0); let buildstdout: str = strings.dup(out.stdout); let buildstderr: str = strings.dup(out.stderr); let sameunit: str = readfile(strings.concat(sharedwork, "pkg-internal-test.unit.ww")); let externalunit: str = readfile(strings.concat(sharedwork, "pkg_test-external-test.unit.ww")); let externalproduction: str = readfile(strings.concat(sharedwork, "pkg.unit.ww")); let samemainunit: str = readfile(strings.concat(sharedwork, "pkg-internal-test-main.unit.ww")); let externalmainunit: str = readfile(strings.concat(sharedwork, "pkg_test-external-test-main.unit.ww")); assert(!os.exists(strings.concat(sharedwork, "__ww-test-001-external-production.unit.ww"))); assert(!os.exists(strings.concat(externalbin, ".sepwork"))); assert(!has(sameunit, "//ww:module ")); assert(os.exists(strings.concat(sharedwork, "__external.unit.ww"))); assert(has(sameunit, "PACKAGE_PRODUCTION_A")); assert(has(sameunit, "PACKAGE_PRODUCTION_Z")); assert(has(sameunit, "SAME_TEST_SOURCE")); assert(!has(sameunit, "EXTERNAL_TEST_SOURCE")); assert(!has(externalunit, "//ww:module ")); assert(has(externalunit, "EXTERNAL_TEST_SOURCE")); assert(!has(externalunit, "PACKAGE_PRODUCTION_A")); assert(!has(externalunit, "PACKAGE_PRODUCTION_Z")); assert(has(externalproduction, "PACKAGE_PRODUCTION_A")); assert(has(externalproduction, "PACKAGE_PRODUCTION_Z")); assert(!has(externalproduction, "//ww:module ")); assert(!has(externalproduction, "SAME_TEST_SOURCE")); assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE")); assert(strings.hasprefix(samemainunit, strings.concat( "//ww:module-reset __wwtestmain.pkg.internal.main\n", "package main;\nimport pkg;\nimport test;\n"))); assert(strings.hasprefix(externalmainunit, strings.concat( "//ww:module-reset __wwtestmain.pkg_test.external.main\n", "package main;\nimport pkg_test;\nimport test;\n"))); assert(has(samemainunit, "//ww:direct-export pkg ")); assert(has(samemainunit, "//ww:direct-export test ")); assert(has(externalmainunit, "//ww:direct-export pkg_test ")); assert(has(externalmainunit, "//ww:direct-export test ")); assert(!has(samemainunit, "PACKAGE_PRODUCTION")); assert(!has(samemainunit, "SAME_TEST_SOURCE")); assert(!has(externalmainunit, "EXTERNAL_TEST_SOURCE")); assert(!has(readfile(strings.concat(sharedwork, "api.unit.ww")), "TEST_DEPENDENCY_MUST_NOT_COMPILE")); let artifacts: []str = ["implementation", "api", "pkg", "__same", "__external", "test", "pkg-internal-test", "pkg-internal-test-main", "pkg_test-external-test", "pkg_test-external-test-main"]; let ai: i32 = 0; for (ai < artifacts.len) { assert(os.exists(strings.concat(sharedwork, artifacts[ai], ".wwi"))); assert(os.exists(strings.concat(sharedwork, artifacts[ai], ".a"))); ai += 1; }; ai = 0; for (ai < packageactions.len) { let ex: str = readfile(strings.concat(sharedwork, packageactions[ai], ".wwi")); let ar: str = readfile(strings.concat(sharedwork, packageactions[ai], ".a")); if (i == 0) { referenceactionexports[ai] = strings.dup(ex); referenceactionarchives[ai] = strings.dup(ar); } else { assert(same(referenceactionexports[ai], ex)); assert(same(referenceactionarchives[ai], ar)); }; ai += 1; }; assert(os.exists(samebin)); assert(os.exists(externalbin)); if (i == 0) { let ctrace: str = readfile(compilertrace); assert(occurrences(ctrace, "implementation.unit.ww") == 1); assert(occurrences(ctrace, "api.unit.ww") == 1); assert(occurrences(ctrace, "/pkg.unit.ww") == 1); assert(occurrences(ctrace, "/__same.unit.ww") == 1); assert(occurrences(ctrace, "/__external.unit.ww") == 1); assert(occurrences(ctrace, "/test.unit.ww") == 1); assert(occurrences(ctrace, "pkg-internal-test.unit.ww") == 1); assert(occurrences(ctrace, "pkg_test-external-test.unit.ww") == 1); assert(occurrences(ctrace, "pkg-internal-test-main.unit.ww") == 1); assert(occurrences(ctrace, "pkg_test-external-test-main.unit.ww") == 1); assert(occurrences(ctrace, "-T --entry --test-support-module") == 2); assert(occurrences(ctrace, "--test-package") == 2); let samecompile: str = linecontaining(ctrace, "pkg-internal-test.unit.ww"); let externalcompile: str = linecontaining(ctrace, "pkg_test-external-test.unit.ww"); let productioncompile: str = linecontaining(ctrace, "/pkg.unit.ww"); assert(same(samecompile, strings.concat( "--test-package --package-init-symbol ", "__ww..pkg.p.pkg.v1.r0.init -c --import __same ", sharedwork, "__same.wwi --import api ", sharedwork, "api.wwi -I ", sharedwork, "pkg-internal-test.wwi -o ", sharedwork, "pkg-internal-test.s ", sharedwork, "pkg-internal-test.unit.ww"))); assert(same(externalcompile, strings.concat( "--test-package --package-init-symbol ", "__ww..pkg.p.pkg_test.v2.r0.init -c --import __external ", sharedwork, "__external.wwi --import pkg ", sharedwork, "pkg.wwi -I ", sharedwork, "pkg_test-external-test.wwi -o ", sharedwork, "pkg_test-external-test.s ", sharedwork, "pkg_test-external-test.unit.ww"))); let samemaincompile: str = linecontaining(ctrace, "pkg-internal-test-main.unit.ww"); let externalmaincompile: str = linecontaining(ctrace, "pkg_test-external-test-main.unit.ww"); assert(same(samemaincompile, strings.concat( "-T --entry --test-support-module test ", "--test-target-package pkg --package-init-symbol ", "__ww..pkg.p.__wwtestmain.pkg.internal.main.v3.r2.init ", "--init-dispatch-symbol __ww..dispatch -c --import pkg ", sharedwork, "pkg-internal-test.wwi --import test ", sharedwork, "test.wwi -I ", sharedwork, "pkg-internal-test-main.wwi -o ", sharedwork, "pkg-internal-test-main.s ", sharedwork, "pkg-internal-test-main.unit.ww"))); assert(same(externalmaincompile, strings.concat( "-T --entry --test-support-module test ", "--test-target-package pkg_test --package-init-symbol ", "__ww..pkg.p.__wwtestmain.pkg_test.external.main.v3.r2.init ", "--init-dispatch-symbol __ww..dispatch -c --import pkg_test ", sharedwork, "pkg_test-external-test.wwi --import test ", sharedwork, "test.wwi -I ", sharedwork, "pkg_test-external-test-main.wwi -o ", sharedwork, "pkg_test-external-test-main.s ", sharedwork, "pkg_test-external-test-main.unit.ww"))); assert(same(productioncompile, strings.concat( "--package-init-symbol __ww..pkg.p.pkg.v0.r0.init ", "-c --import api ", sharedwork, "api.wwi -I ", sharedwork, "pkg.wwi -o ", sharedwork, "pkg.s ", sharedwork, "pkg.unit.ww"))); let ltrace: str = readfile(linkertrace); assert(occurrences(ltrace, "\n") == 2); let samelink: str = linecontaining(ltrace, strings.concat("-o ", samebin, ".new ")); let externallink: str = linecontaining(ltrace, strings.concat("-o ", externalbin, ".new ")); assert(has(samelink, strings.concat(sharedwork, "api.a"))); assert(has(samelink, strings.concat(sharedwork, "implementation.a"))); assert(has(samelink, strings.concat(sharedwork, "__same.a"))); assert(has(samelink, strings.concat(sharedwork, "pkg-internal-test-main.a"))); assert(has(samelink, strings.concat(sharedwork, "pkg-internal-test.a"))); assert(!has(samelink, strings.concat(sharedwork, "pkg.a"))); assert(!has(samelink, strings.concat(sharedwork, "__external.a"))); assert(has(externallink, strings.concat(sharedwork, "pkg.a"))); assert(has(externallink, strings.concat(sharedwork, "pkg_test-external-test-main.a"))); assert(has(externallink, strings.concat(sharedwork, "pkg_test-external-test.a"))); assert(!has(samelink, ".wwi")); assert(!has(externallink, ".wwi")); assert(has(externallink, strings.concat(sharedwork, "api.a"))); assert(has(externallink, strings.concat(sharedwork, "implementation.a"))); assert(has(externallink, strings.concat(sharedwork, "__external.a"))); assert(!has(externallink, strings.concat(sharedwork, "__same.a"))); }; let runav: []str = [samebin]; runcommand(root, strings.concat("variant-run-same-", tags[i]), runav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "same_graph ... ok\n")); let externalrun: []str = [externalbin]; runcommand(root, strings.concat("variant-run-external-", tags[i]), externalrun, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "external_graph ... ok\n")); if (i == 0) { referenceout = buildstdout; referenceerr = buildstderr; referencesame = readfile(samebin); referenceexternal = readfile(externalbin); referencesameunit = strings.dup(sameunit); referenceexternalunit = strings.dup(externalunit); referenceproductionunit = strings.dup(externalproduction); } else { assert(same(referencesame, readfile(samebin))); assert(same(referenceexternal, readfile(externalbin))); assert(same(referencesameunit, sameunit)); assert(same(referenceexternalunit, externalunit)); assert(same(referenceproductionunit, externalproduction)); assert(same(referenceout, buildstdout)); assert(same(referenceerr, buildstderr)); }; if (i + 1 < drivers.len) { clean(sharedworkroot); clean(samebin); clean(externalbin); }; i += 1; }; // Canonical variant keys stay disjoint from valid packages literally named // __same and __external, including warm reuse. let warmroot: str = strings.concat(root, "/warm"); assert(os.mkdir(warmroot, 448i32) == 0); let warmav: []str = [driver("ww"), "test", "-w", warmroot, "-I", root, pkg]; runcommandenv(root, "variant-warm-cold", warmav, traceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let warmstdout: str = strings.dup(out.stdout); let warmstderr: str = strings.dup(out.stderr); let warmtrace: str = readfile(compilertrace); let warmwork: str = strings.concat(warmroot, "/"); assert(has(readfile(strings.concat(warmwork, "__same.unit.ww")), "package __same;")); assert(has(readfile(strings.concat(warmwork, "pkg-internal-test.unit.ww")), "SAME_TEST_SOURCE")); assert(has(readfile(strings.concat(warmwork, "__external.unit.ww")), "package __external;")); assert(has(readfile(strings.concat(warmwork, "pkg_test-external-test.unit.ww")), "EXTERNAL_TEST_SOURCE")); assert(has(readfile(strings.concat(warmwork, "pkg.unit.ww")), "PACKAGE_PRODUCTION_A")); assert(!os.exists(strings.concat(warmwork, "__ww-test-001-external-production.unit.ww"))); // Equivalent hidden product order is presentation-only. The driver sorts // and interns before compilation, so reversing the descriptors reuses the // same persistent actions and leaves every artifact byte unchanged. let orderwork: str = strings.concat(root, "/order-work"); assert(os.mkdir(orderwork, 448i32) == 0); let orderav: []str = [driver("ww"), "test", "-c", "-w", orderwork, "-I", root, "--ww-package-test", "external", "pkg_test", pkg, externalbin, strings.concat(root, "/order-external.status"), "--ww-package-test", "same", "pkg", pkg, samebin, strings.concat(root, "/order-same.status"), pkg]; let cordertracebefore: str = strings.dup(readfile(compilertrace)); let corderlinkbefore: str = strings.dup(readfile(linkertrace)); runcommandenv(root, "variant-order-reversed", orderav, traceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let cordertraceafter: str = strings.dup(readfile(compilertrace)); let corderlinkafter: str = strings.dup(readfile(linkertrace)); let creversedtrace: str = strings.dup(strings.sub(cordertraceafter, cordertracebefore.len, cordertraceafter.len)); let creversedlink: str = strings.dup(strings.sub(corderlinkafter, corderlinkbefore.len, corderlinkafter.len)); let orderworkdir: str = strings.concat(orderwork, "/"); let orderactions: []str = ["pkg", "pkg-internal-test", "pkg_test-external-test", "pkg-internal-test-main", "pkg_test-external-test-main"]; let oi: i32 = 0; for (oi < orderactions.len) { let suffixes: []str = [".unit.ww", ".wwi", ".a"]; let xi: i32 = 0; for (xi < suffixes.len) { assert(same(readfile(strings.concat(warmwork, orderactions[oi], suffixes[xi])), readfile(strings.concat(orderworkdir, orderactions[oi], suffixes[xi])))); xi += 1; }; oi += 1; }; clean(orderwork); assert(os.mkdir(orderwork, 448i32) == 0); let orderforwardav: []str = [driver("ww"), "test", "-c", "-w", orderwork, "-I", root, "--ww-package-test", "same", "pkg", pkg, samebin, strings.concat(root, "/order-same.status"), "--ww-package-test", "external", "pkg_test", pkg, externalbin, strings.concat(root, "/order-external.status"), pkg]; let cforwardtracebefore: str = strings.dup(readfile(compilertrace)); let cforwardlinkbefore: str = strings.dup(readfile(linkertrace)); runcommandenv(root, "variant-order-forward", orderforwardav, traceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let cforwardtraceafter: str = strings.dup(readfile(compilertrace)); let cforwardlinkafter: str = strings.dup(readfile(linkertrace)); assert(same(creversedtrace, strings.sub(cforwardtraceafter, cforwardtracebefore.len, cforwardtraceafter.len))); assert(same(creversedlink, strings.sub(cforwardlinkafter, cforwardlinkbefore.len, cforwardlinkafter.len))); let ordertrace: str = readfile(compilertrace); let coldcounts: []i32 = [occurrences(ordertrace, "/pkg.unit.new"), occurrences(ordertrace, "/pkg-internal-test.unit.new"), occurrences(ordertrace, "/pkg_test-external-test.unit.new")]; assert(coldcounts[0] == 3 && coldcounts[1] == 3 && coldcounts[2] == 3); let orderwwwork: str = strings.concat(root, "/order-ww-work"); let orderwwsame: str = strings.concat(root, "/order-ww-same.test"); let orderwwexternal: str = strings.concat(root, "/order-ww-external.test"); assert(os.mkdir(orderwwwork, 448i32) == 0); let orderwwav: []str = [driver("ww_ww"), "test", "-c", "-w", orderwwwork, "-I", root, "--ww-package-test", "external", "pkg_test", pkg, orderwwexternal, strings.concat(root, "/order-ww-external.status"), "--ww-package-test", "same", "pkg", pkg, orderwwsame, strings.concat(root, "/order-ww-same.status"), pkg]; let wordertracebefore: str = strings.dup(readfile(compilertrace)); let worderlinkbefore: str = strings.dup(readfile(linkertrace)); runcommandenv(root, "variant-order-reversed-ww", orderwwav, wwtraceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let wordertraceafter: str = strings.dup(readfile(compilertrace)); let worderlinkafter: str = strings.dup(readfile(linkertrace)); let wreversedtrace: str = strings.dup(strings.sub(wordertraceafter, wordertracebefore.len, wordertraceafter.len)); let wreversedlink: str = strings.dup(strings.sub(worderlinkafter, worderlinkbefore.len, worderlinkafter.len)); clean(orderwwwork); assert(os.mkdir(orderwwwork, 448i32) == 0); let orderwwforward: []str = [driver("ww_ww"), "test", "-c", "-w", orderwwwork, "-I", root, "--ww-package-test", "same", "pkg", pkg, orderwwsame, strings.concat(root, "/order-ww-same.status"), "--ww-package-test", "external", "pkg_test", pkg, orderwwexternal, strings.concat(root, "/order-ww-external.status"), pkg]; let wforwardtracebefore: str = strings.dup(readfile(compilertrace)); let wforwardlinkbefore: str = strings.dup(readfile(linkertrace)); runcommandenv(root, "variant-order-forward-ww", orderwwforward, wwtraceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let wforwardtraceafter: str = strings.dup(readfile(compilertrace)); let wforwardlinkafter: str = strings.dup(readfile(linkertrace)); assert(same(wreversedtrace, strings.sub(wforwardtraceafter, wforwardtracebefore.len, wforwardtraceafter.len))); assert(same(wreversedlink, strings.sub(wforwardlinkafter, wforwardlinkbefore.len, wforwardlinkafter.len))); oi = 0; for (oi < orderactions.len) { let suffixes: []str = [".unit.ww", ".wwi", ".a"]; let xi: i32 = 0; for (xi < suffixes.len) { assert(same(readfile(strings.concat(warmwork, orderactions[oi], suffixes[xi])), readfile(strings.concat(orderwwwork, "/", orderactions[oi], suffixes[xi])))); xi += 1; }; oi += 1; }; let tracedorders: str = readfile(compilertrace); coldcounts[0] = occurrences(tracedorders, "/pkg.unit.new"); coldcounts[1] = occurrences(tracedorders, "/pkg-internal-test.unit.new"); coldcounts[2] = occurrences(tracedorders, "/pkg_test-external-test.unit.new"); runcommandenv(root, "variant-warm-reuse", warmav, traceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(warmstdout, out.stdout)); assert(same(warmstderr, out.stderr)); let reusedtrace: str = readfile(compilertrace); assert(occurrences(reusedtrace, "/pkg.unit.new") == coldcounts[0]); assert(occurrences(reusedtrace, "/pkg-internal-test.unit.new") == coldcounts[1]); assert(occurrences(reusedtrace, "/pkg_test-external-test.unit.new") == coldcounts[2]); let aliasunit: str = strings.concat(root, "/alias.unit.ww"); writefile(aliasunit, strings.concat( "//ww:module-reset __wwtest\n", "package test;\nexport fn value() i32 = { return 1; };\n")); let aliasstages: []str = ["w6c", "w6c_ww"]; let aliaserrs: []str = ["", ""]; i = 0; for (i < aliasstages.len) { let asmout: str = strings.concat(root, "/alias-", aliasstages[i], ".s"); let rawav: []str = [driver(aliasstages[i]), "-c", "-o", asmout, aliasunit]; runcommand(root, strings.concat("alias-unowned-", aliasstages[i]), rawav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); assert(os.exists(asmout)); let badav: []str = [driver(aliasstages[i]), "-c", "--test-support-module", "arbitrary", "-o", asmout, aliasunit]; runcommand(root, strings.concat("alias-arbitrary-", aliasstages[i]), badav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 2); assert(has(out.stderr, "invalid --test-support-module")); aliaserrs[i] = strings.dup(out.stderr); i += 1; }; assert(same(aliaserrs[0], aliaserrs[1])); clean(root); }; @test fn multi_directory_shared_package_plan() void = { let root: str = fresh(); let leaf: str = strings.concat(root, "/leaf"); let common: str = strings.concat(root, "/common"); let suite: str = strings.concat(root, "/suite"); let alpha: str = strings.concat(suite, "/alpha"); let beta: str = strings.concat(suite, "/beta"); let gamma: str = strings.concat(suite, "/gamma"); let alphasame: str = strings.concat(alpha, "/_alpha_same"); let alphaexternal: str = strings.concat(alpha, "/_alpha_external"); let betasame: str = strings.concat(beta, "/_beta_same"); let betaexternal: str = strings.concat(beta, "/_beta_external"); let alphashadow: str = strings.concat(root, "/_alpha_same"); let betashadow: str = strings.concat(root, "/_beta_same"); let dirs: []str = [leaf, common, suite, alpha, beta, gamma, alphasame, alphaexternal, betasame, betaexternal, alphashadow, betashadow]; let di: i32 = 0; for (di < dirs.len) { assert(os.mkdir(dirs[di], 448i32) == 0); di += 1; }; writefile(strings.concat(leaf, "/leaf.ww"), strings.concat( "package leaf;\n", "// MULTIDIR_LEAF\n", "export fn value() i32 = { return 40; };\n")); writefile(strings.concat(common, "/common.ww"), strings.concat( "package common;\nimport leaf;\n", "// MULTIDIR_COMMON\n", "export fn value() i32 = { return leaf.value(); };\n")); writefile(strings.concat(common, "/common_test.ww"), strings.concat( "package common;\n", "DEPENDENCY_TEST_FILE_MUST_NOT_COMPILE\n")); writefile(strings.concat(alphasame, "/source.ww"), "package _alpha_same;\nexport fn value() i32 = { return 1; };\n"); writefile(strings.concat(alphaexternal, "/source.ww"), "package _alpha_external;\nexport fn value() i32 = { return 1; };\n"); writefile(strings.concat(betasame, "/source.ww"), "package _beta_same;\nexport fn value() i32 = { return 2; };\n"); writefile(strings.concat(betaexternal, "/source.ww"), "package _beta_external;\nexport fn value() i32 = { return 2; };\n"); // The explicit -I root contains deliberately wrong shadows. Each selected // directory must retain its own first lookup root inside the union plan. writefile(strings.concat(alphashadow, "/source.ww"), "package _alpha_same;\nexport fn value() i32 = { return 99; };\n"); writefile(strings.concat(betashadow, "/source.ww"), "package _beta_same;\nexport fn value() i32 = { return 99; };\n"); writefile(strings.concat(alpha, "/a.ww"), strings.concat( "package alpha;\nimport common;\n", "// MULTIDIR_ALPHA_A\n", "export fn value() i32 = { return common.value(); };\n")); writefile(strings.concat(alpha, "/z.ww"), strings.concat( "package alpha;\n", "// MULTIDIR_ALPHA_Z\n", "fn secret() i32 = { return 1; };\n", "export fn exported() i32 = { return 1; };\n")); writefile(strings.concat(alpha, "/same_test.ww"), strings.concat( "package alpha;\nimport _alpha_same;\n", "// MULTIDIR_ALPHA_SAME\n", "@test fn alpha_same_runs() void = {\n", " assert(value() + secret() + _alpha_same.value() == 42);\n};\n")); writefile(strings.concat(alpha, "/external_test.ww"), strings.concat( "package alpha_test;\nimport alpha;\nimport _alpha_external;\n", "// MULTIDIR_ALPHA_EXTERNAL\n", "@test fn alpha_external_runs() void = {\n", " assert(alpha.value() + alpha.exported()", " + _alpha_external.value() == 42);\n};\n")); // A no-test directory is an ordinary production product. Beta also imports // it, proving that root/dependency discovery shares the same action. writefile(strings.concat(gamma, "/gamma.ww"), strings.concat( "package gamma;\nimport common;\n", "// MULTIDIR_GAMMA\n", "export fn value() i32 = { return common.value(); };\n")); writefile(strings.concat(beta, "/beta.ww"), strings.concat( "package beta;\nimport gamma;\nimport alpha;\n", "// MULTIDIR_BETA\n", "fn secret() i32 = { return 2; };\n", "export fn value() i32 = { return gamma.value(); };\n", "export fn exported() i32 = { return alpha.exported() + 1; };\n")); writefile(strings.concat(beta, "/same_test.ww"), strings.concat( "package beta;\nimport _beta_same;\n", "// MULTIDIR_BETA_SAME\n", "@test fn beta_same_runs() void = {\n", " assert(value() + secret() + _beta_same.value() == 44);\n};\n")); writefile(strings.concat(beta, "/external_test.ww"), strings.concat( "package beta_test;\nimport beta;\nimport _beta_external;\n", "// MULTIDIR_BETA_EXTERNAL\n", "@test fn beta_external_runs() void = {\n", " assert(beta.value() + beta.exported()", " + _beta_external.value() == 44);\n};\n")); let compilertrace: str = strings.concat(root, "/compiler.trace"); let linkertrace: str = strings.concat(root, "/linker.trace"); let compilerwrapper: str = strings.concat(root, "/trace-w6c.sh"); let linkerwrapper: str = strings.concat(root, "/trace-w6l.sh"); writefile(compilertrace, ""); writefile(linkertrace, ""); writeexecutable(compilerwrapper, strings.concat( "#!/bin/sh\n", "printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_COMPILER_TRACE\"\n", "exec \"$WW_PACKAGE_W6C\" \"$@\"\n")); writeexecutable(linkerwrapper, strings.concat( "#!/bin/sh\n", "printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_LINKER_TRACE\"\n", "exec \"$WW_PACKAGE_W6L\" \"$@\"\n")); let baseenv: []str = os.getenvs(); let traceenv: []str = alloc([], (baseenv.len + 6): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_LINKER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6L=")) { append(traceenv, baseenv[ei]); }; ei += 1; }; append(traceenv, strings.concat("WW_W6C=", compilerwrapper)); append(traceenv, strings.concat("WW_W6L=", linkerwrapper)); append(traceenv, strings.concat("WW_PACKAGE_COMPILER_TRACE=", compilertrace)); append(traceenv, strings.concat("WW_PACKAGE_LINKER_TRACE=", linkertrace)); append(traceenv, strings.concat("WW_PACKAGE_W6C=", driver("w6c"))); append(traceenv, strings.concat("WW_PACKAGE_W6L=", driver("w6l"))); // Exercise default sibling discovery independently of the exact-path // override contract covered below: the copied driver sits beside narrow // tracing wrappers for its real compiler and linker actions. let wwtracebin: str = strings.concat(repo(), "/out/package-trace-", workescape(root)); assert(os.mkdir(wwtracebin, 448i32) == 0); let wwtracedriver: str = strings.concat(wwtracebin, "/ww_ww"); let wwcompilertrace: str = strings.concat(root, "/ww-compiler.trace"); let wwlinkertrace: str = strings.concat(root, "/ww-linker.trace"); writefile(wwcompilertrace, ""); writefile(wwlinkertrace, ""); writeexecutable(wwtracedriver, readfile(driver("ww_ww"))); writeexecutable(strings.concat(wwtracebin, "/wwtest"), readfile(driver("wwtest"))); writeexecutable(strings.concat(wwtracebin, "/w6c_ww"), strings.concat( "#!/bin/sh\n", "printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_WW_COMPILER_TRACE\"\n", "exec \"$WW_PACKAGE_W6C_WW\" \"$@\"\n")); writeexecutable(strings.concat(wwtracebin, "/w6a_ww"), strings.concat( "#!/bin/sh\nexec \"$WW_PACKAGE_W6A_WW\" \"$@\"\n")); writeexecutable(strings.concat(wwtracebin, "/w6l_ww"), strings.concat( "#!/bin/sh\n", "printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_WW_LINKER_TRACE\"\n", "exec \"$WW_PACKAGE_W6L_WW\" \"$@\"\n")); let wwtraceenv: []str = alloc([], (baseenv.len + 5): u64)!; ei = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_PACKAGE_WW_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_WW_LINKER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C_WW=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6A_WW=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6L_WW=")) { append(wwtraceenv, baseenv[ei]); }; ei += 1; }; append(wwtraceenv, strings.concat("WW_PACKAGE_WW_COMPILER_TRACE=", wwcompilertrace)); append(wwtraceenv, strings.concat("WW_PACKAGE_WW_LINKER_TRACE=", wwlinkertrace)); append(wwtraceenv, strings.concat("WW_PACKAGE_W6C_WW=", driver("w6c_ww"))); append(wwtraceenv, strings.concat("WW_PACKAGE_W6A_WW=", driver("w6a_ww"))); append(wwtraceenv, strings.concat("WW_PACKAGE_W6L_WW=", driver("w6l_ww"))); let bins: []str = [strings.concat(alpha, "/alpha.test"), strings.concat(alpha, "/alpha_test.test"), strings.concat(beta, "/beta.test"), strings.concat(beta, "/beta_test.test"), strings.concat(gamma, "/gamma.test")]; let rootkeys: []str = ["alpha-internal-test", "alpha_test-external-test", "beta-internal-test", "beta_test-external-test", "gamma"]; let mainkeys: []str = ["alpha-internal-test-main", "alpha_test-external-test-main", "beta-internal-test-main", "beta_test-external-test-main", "gamma-main"]; let alphaartifact: str = "alpha"; let betaartifact: str = "beta"; let expectedtests: []str = ["alpha_same_runs ... ok\n", "alpha_external_runs ... ok\n", "beta_same_runs ... ok\n", "beta_external_runs ... ok\n"]; let sharedworkroot: str = strings.concat(bins[0], ".sepwork"); let sharedwork: str = strings.concat(sharedworkroot, "/"); let referencebins: []str = ["", "", "", "", ""]; let referenceroots: []str = ["", "", "", "", ""]; let referenceout: str = ""; let referenceerr: str = ""; let referencecommonwwi: str = ""; let referencecommona: str = ""; let referencealphaa: str = ""; let stages: []str = ["ww", "ww", "ww_ww"]; let tags: []str = ["c1", "c2", "ww"]; let out: commandout; let si: i32 = 0; for (si < stages.len) { let stagepath: str = driver(stages[si]); if (si == 2) { stagepath = wwtracedriver; }; let av: []str = [stagepath, "test", "-c", "-j", "1", "-I", suite, "-I", root, strings.concat(suite, "/...")]; if (si == 0) { runcommandenv(root, "multidir-c1", av, traceenv, (120i64 * (time.second: i64)): time.duration, &out); } else { if (si == 2) { runcommandenv(root, strings.concat("multidir-", tags[si]), av, wwtraceenv, (120i64 * (time.second: i64)): time.duration, &out); } else { runcommand(root, strings.concat("multidir-", tags[si]), av, (120i64 * (time.second: i64)): time.duration, &out); }; }; expectexit(&out, 0); let buildstdout: str = strings.dup(out.stdout); let buildstderr: str = strings.dup(out.stderr); let commonunit: str = readfile(strings.concat(sharedwork, "common.unit.ww")); let alphaunit: str = readfile(strings.concat(sharedwork, alphaartifact, ".unit.ww")); let betaunit: str = readfile(strings.concat(sharedwork, betaartifact, ".unit.ww")); let gammaunit: str = readfile(strings.concat(sharedwork, "gamma.unit.ww")); assert(has(commonunit, "//ww:module-reset common\n")); assert(!has(commonunit, "//ww:module ")); assert(!has(alphaunit, "//ww:module ")); assert(has(alphaunit, "MULTIDIR_ALPHA_A")); assert(has(alphaunit, "MULTIDIR_ALPHA_Z")); assert(!has(betaunit, "//ww:module ")); assert(has(betaunit, "MULTIDIR_BETA")); assert(!has(gammaunit, "//ww:module ")); assert(has(gammaunit, "MULTIDIR_GAMMA")); assert(!has(gammaunit, "MULTIDIR_COMMON")); assert(!has(commonunit, "DEPENDENCY_TEST_FILE_MUST_NOT_COMPILE")); let roots: []str = [readfile(strings.concat(sharedwork, rootkeys[0], ".unit.ww")), readfile(strings.concat(sharedwork, rootkeys[1], ".unit.ww")), readfile(strings.concat(sharedwork, rootkeys[2], ".unit.ww")), readfile(strings.concat(sharedwork, rootkeys[3], ".unit.ww")), readfile(strings.concat(sharedwork, rootkeys[4], ".unit.ww"))]; assert(!has(roots[0], "//ww:module ")); assert(has(roots[0], "MULTIDIR_ALPHA_A")); assert(has(roots[0], "MULTIDIR_ALPHA_Z")); assert(has(roots[0], "MULTIDIR_ALPHA_SAME")); assert(!has(roots[0], "MULTIDIR_ALPHA_EXTERNAL")); assert(!has(roots[1], "//ww:module ")); assert(has(roots[1], "MULTIDIR_ALPHA_EXTERNAL")); assert(!has(roots[1], "MULTIDIR_ALPHA_A")); assert(!has(roots[2], "//ww:module ")); assert(has(roots[2], "MULTIDIR_BETA")); assert(has(roots[2], "MULTIDIR_BETA_SAME")); assert(!has(roots[3], "//ww:module ")); assert(has(roots[3], "MULTIDIR_BETA_EXTERNAL")); assert(!has(roots[3], "MULTIDIR_BETA_SAME")); assert(has(roots[4], "MULTIDIR_GAMMA")); assert(!has(roots[4], "MULTIDIR_COMMON")); let products: []str = ["leaf", "common", alphaartifact, betaartifact, "gamma", "_alpha_same", "_alpha_external", "_beta_same", "_beta_external", "test", "alpha-internal-test", "alpha_test-external-test", "beta-internal-test", "beta_test-external-test", "alpha-internal-test-main", "alpha_test-external-test-main", "beta-internal-test-main", "beta_test-external-test-main", "gamma-main"]; let pi: i32 = 0; for (pi < products.len) { assert(os.exists(strings.concat(sharedwork, products[pi], ".unit.ww"))); assert(os.exists(strings.concat(sharedwork, products[pi], ".wwi"))); assert(os.exists(strings.concat(sharedwork, products[pi], ".a"))); pi += 1; }; let ri: i32 = 0; for (ri < rootkeys.len) { assert(os.exists(strings.concat(sharedwork, rootkeys[ri], ".o"))); assert(os.exists(strings.concat(sharedwork, rootkeys[ri], ".wwi"))); assert(os.exists(strings.concat(sharedwork, rootkeys[ri], ".a"))); assert(os.exists(strings.concat(sharedwork, mainkeys[ri], ".unit.ww"))); assert(os.exists(strings.concat(sharedwork, mainkeys[ri], ".wwi"))); assert(os.exists(strings.concat(sharedwork, mainkeys[ri], ".a"))); assert(os.exists(bins[ri])); if (ri > 0) { assert(!os.exists(strings.concat(bins[ri], ".sepwork"))); }; let runav: []str = [bins[ri]]; runcommand(root, strings.concat("multidir-run-", tags[si], "-", rootkeys[ri]), runav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); if (ri < expectedtests.len) { assert(has(out.stdout, expectedtests[ri])); } else { assert(out.stdout.len == 0 && out.stderr.len == 0); }; ri += 1; }; if (si == 0) { let ctrace: str = readfile(compilertrace); let once: []str = ["leaf", "common", alphaartifact, betaartifact, "gamma", "_alpha_same", "_alpha_external", "_beta_same", "_beta_external", "test"]; pi = 0; for (pi < once.len) { assert(occurrences(ctrace, strings.concat("/", once[pi], ".unit.ww")) == 1); pi += 1; }; // alpha is both external-test production and a direct dependency of // beta. The canonical production action above is compiled once and no // role-qualified production action exists. assert(occurrences(ctrace, "/alpha.unit.ww") == 1); assert(occurrences(ctrace, "/gamma.unit.ww") == 1); assert(occurrences(ctrace, "external-production") == 0); ri = 0; for (ri < rootkeys.len) { assert(occurrences(ctrace, strings.concat(rootkeys[ri], ".unit.ww")) == 1); assert(occurrences(ctrace, strings.concat(mainkeys[ri], ".unit.ww")) == 1); ri += 1; }; assert(pos(ctrace, "/leaf.unit.ww") < pos(ctrace, "/common.unit.ww")); assert(pos(ctrace, "/common.unit.ww") < pos(ctrace, strings.concat("/", alphaartifact, ".unit.ww"))); assert(pos(ctrace, "/common.unit.ww") < pos(ctrace, strings.concat("/", betaartifact, ".unit.ww"))); let ltrace: str = readfile(linkertrace); assert(occurrences(ltrace, "\n") == 5); ri = 0; for (ri < bins.len) { let link: str = linecontaining(ltrace, strings.concat("-o ", bins[ri], ".new ")); assert(has(link, strings.concat(sharedwork, mainkeys[ri], ".a"))); assert(has(link, strings.concat(sharedwork, rootkeys[ri], ".a"))); assert(!has(link, ".wwi")); assert(has(link, strings.concat(sharedwork, "common.a"))); assert(has(link, strings.concat(sharedwork, "leaf.a"))); assert(has(link, strings.concat(sharedwork, "test.a"))); if (ri >= 2) { assert(has(link, strings.concat(sharedwork, "gamma.a"))); } else { assert(!has(link, strings.concat(sharedwork, "gamma.a"))); }; if (ri == 4) { assert(!has(link, strings.concat(sharedwork, alphaartifact, ".a"))); assert(!has(link, strings.concat(sharedwork, betaartifact, ".a"))); assert(!has(link, strings.concat(sharedwork, "_alpha_same.a"))); assert(!has(link, strings.concat(sharedwork, "_alpha_external.a"))); assert(!has(link, strings.concat(sharedwork, "_beta_same.a"))); assert(!has(link, strings.concat(sharedwork, "_beta_external.a"))); } else { if (ri < 2) { assert(!has(link, strings.concat(sharedwork, betaartifact, ".a"))); assert(!has(link, strings.concat(sharedwork, "_beta_same.a"))); assert(!has(link, strings.concat(sharedwork, "_beta_external.a"))); } else { assert(has(link, strings.concat(sharedwork, alphaartifact, ".a"))); assert(!has(link, strings.concat(sharedwork, "_alpha_same.a"))); assert(!has(link, strings.concat(sharedwork, "_alpha_external.a"))); }; if (ri == 0) { assert(has(link, strings.concat(sharedwork, "_alpha_same.a"))); assert(!has(link, strings.concat(sharedwork, alphaartifact, ".a"))); assert(!has(link, strings.concat(sharedwork, "_alpha_external.a"))); } else { if (ri == 1) { assert(has(link, strings.concat(sharedwork, alphaartifact, ".a"))); assert(has(link, strings.concat(sharedwork, "_alpha_external.a"))); assert(!has(link, strings.concat(sharedwork, "_alpha_same.a"))); } else { if (ri == 2) { assert(has(link, strings.concat(sharedwork, "_beta_same.a"))); assert(!has(link, strings.concat(sharedwork, betaartifact, ".a"))); assert(!has(link, strings.concat(sharedwork, "_beta_external.a"))); } else { assert(has(link, strings.concat(sharedwork, betaartifact, ".a"))); assert(has(link, strings.concat(sharedwork, "_beta_external.a"))); assert(!has(link, strings.concat(sharedwork, "_beta_same.a"))); }; }; }; }; ri += 1; }; referenceout = buildstdout; referenceerr = buildstderr; referencecommonwwi = strings.dup(readfile(strings.concat(sharedwork, "common.wwi"))); referencecommona = strings.dup(readfile(strings.concat(sharedwork, "common.a"))); referencealphaa = strings.dup(readfile(strings.concat(sharedwork, alphaartifact, ".a"))); ri = 0; for (ri < bins.len) { referencebins[ri] = strings.dup(readfile(bins[ri])); referenceroots[ri] = strings.dup(roots[ri]); ri += 1; }; } else { assert(same(referenceout, buildstdout)); assert(same(referenceerr, buildstderr)); assert(same(referencecommonwwi, readfile(strings.concat(sharedwork, "common.wwi")))); assert(same(referencecommona, readfile(strings.concat(sharedwork, "common.a")))); assert(same(referencealphaa, readfile(strings.concat(sharedwork, alphaartifact, ".a")))); ri = 0; for (ri < bins.len) { assert(same(referencebins[ri], readfile(bins[ri]))); assert(same(referenceroots[ri], roots[ri])); ri += 1; }; }; if (si == 2) { let wwtrace: str = readfile(wwcompilertrace); let once: []str = ["leaf", "common", alphaartifact, betaartifact, "gamma", "_alpha_same", "_alpha_external", "_beta_same", "_beta_external", "test"]; pi = 0; for (pi < once.len) { assert(occurrences(wwtrace, strings.concat("/", once[pi], ".unit.ww")) == 1); pi += 1; }; assert(occurrences(wwtrace, "/alpha.unit.ww") == 1); assert(occurrences(wwtrace, "/gamma.unit.ww") == 1); assert(occurrences(wwtrace, "external-production") == 0); ri = 0; for (ri < rootkeys.len) { assert(occurrences(wwtrace, strings.concat(rootkeys[ri], ".unit.ww")) == 1); assert(occurrences(wwtrace, strings.concat(mainkeys[ri], ".unit.ww")) == 1); ri += 1; }; assert(occurrences(readfile(wwlinkertrace), "\n") == 5); }; if (si + 1 < stages.len) { clean(sharedworkroot); ri = 0; for (ri < bins.len) { clean(bins[ri]); ri += 1; }; }; si += 1; }; clean(sharedworkroot); let bi: i32 = 0; for (bi < bins.len) { clean(bins[bi]); bi += 1; }; let warmroot: str = strings.concat(root, "/warm-c"); let warmwwroot: str = strings.concat(root, "/warm-ww"); assert(os.mkdir(warmroot, 448i32) == 0); assert(os.mkdir(warmwwroot, 448i32) == 0); let warmc: []str = [driver("ww"), "test", "-j", "1", "-w", warmroot, "-I", suite, "-I", root, strings.concat(suite, "/...")]; runcommandenv(root, "multidir-warm-cold", warmc, traceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let warmstdout: str = strings.dup(out.stdout); let warmstderr: str = strings.dup(out.stderr); let warmtrace: str = readfile(compilertrace); let warmparallel: []str = [driver("ww"), "test", "-j", "4", "-w", warmroot, "-I", suite, "-I", root, strings.concat(suite, "/...")]; let warmequivalentc: []str = [driver("ww"), "test", "-j", "4", "-w", warmroot, "-I", suite, "-I", root, strings.concat(suite, "/./...")]; runcommandenv(root, "multidir-warm-reuse", warmequivalentc, traceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(warmstderr, out.stderr)); assert(same(warmtrace, readfile(compilertrace))); let warmkey: str = "/"; let warmwork: str = strings.concat(warmroot, warmkey); assert(os.exists(strings.concat(warmwork, "alpha-internal-test.unit.ww"))); assert(os.exists(strings.concat(warmwork, "beta_test-external-test.unit.ww"))); let warmww: []str = [wwtracedriver, "test", "-j", "4", "-w", warmwwroot, "-I", suite, "-I", root, strings.concat(suite, "/...")]; runcommandenv(root, "multidir-warm-ww", warmww, wwtraceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(warmstdout, out.stdout)); assert(same(warmstderr, out.stderr)); let warmwwtrace: str = strings.dup(readfile(wwcompilertrace)); let warmwwequivalent: []str = [wwtracedriver, "test", "-j", "4", "-w", warmwwroot, "-I", suite, "-I", root, strings.concat(suite, "/./...")]; runcommandenv(root, "multidir-warm-ww-reuse", warmwwequivalent, wwtraceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(warmstderr, out.stderr)); assert(same(warmwwtrace, readfile(wwcompilertrace))); let warmwwwork: str = strings.concat(warmwwroot, warmkey); assert(same(readfile(strings.concat(warmwork, "common.wwi")), readfile(strings.concat(warmwwwork, "common.wwi")))); assert(same(readfile(strings.concat(warmwork, "common.a")), readfile(strings.concat(warmwwwork, "common.a")))); assert(same(readfile(strings.concat(warmwork, "alpha-internal-test.unit.ww")), readfile(strings.concat(warmwwwork, "alpha-internal-test.unit.ww")))); // Change one shared dependency's public export in place. Each stage must // rebuild that canonical action and its one direct importer exactly once; // common's unchanged regenerated export stops propagation to gamma/alpha. let oldleafwwi: str = readfile(strings.concat(warmwork, "leaf.wwi")); let oldcommonwwi: str = readfile(strings.concat(warmwork, "common.wwi")); let oldcommona: str = readfile(strings.concat(warmwork, "common.a")); let oldgammaa: str = readfile(strings.concat(warmwork, "gamma.a")); assert(os.remove(strings.concat(leaf, "/leaf.ww")) == 0); writefile(strings.concat(leaf, "/leaf.ww"), strings.concat( "package leaf;\n// MULTIDIR_LEAF\n", "export fn value() i32 = { return 40; };\n", "export fn newly_visible() i32 = { return 2; };\n")); let cbeforechange: str = strings.dup(readfile(compilertrace)); let wbeforechange: str = strings.dup(readfile(wwcompilertrace)); runcommandenv(root, "multidir-warm-c-export-change", warmparallel, traceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(warmstdout, out.stdout)); assert(same(warmstderr, out.stderr)); let cafterchange: str = strings.dup(readfile(compilertrace)); assert(occurrences(cafterchange, "/leaf.unit.new") == occurrences(cbeforechange, "/leaf.unit.new") + 1); assert(occurrences(cafterchange, "/common.unit.new") == occurrences(cbeforechange, "/common.unit.new") + 1); assert(occurrences(cafterchange, "/gamma.unit.new") == occurrences(cbeforechange, "/gamma.unit.new")); assert(occurrences(cafterchange, "/alpha-internal-test.unit.new") == occurrences(cbeforechange, "/alpha-internal-test.unit.new")); assert(!same(oldleafwwi, readfile(strings.concat(warmwork, "leaf.wwi")))); assert(same(oldcommonwwi, readfile(strings.concat(warmwork, "common.wwi")))); assert(same(oldcommona, readfile(strings.concat(warmwork, "common.a")))); assert(same(oldgammaa, readfile(strings.concat(warmwork, "gamma.a")))); let changedleafunit: str = readfile(strings.concat(warmwork, "leaf.unit.ww")); let changedleafwwi: str = readfile(strings.concat(warmwork, "leaf.wwi")); let changedleafa: str = readfile(strings.concat(warmwork, "leaf.a")); let changedcommonunit: str = readfile(strings.concat(warmwork, "common.unit.ww")); runcommandenv(root, "multidir-warm-ww-export-change", warmww, wwtraceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(warmstdout, out.stdout)); assert(same(warmstderr, out.stderr)); let wafterchange: str = strings.dup(readfile(wwcompilertrace)); assert(occurrences(wafterchange, "/leaf.unit.new") == occurrences(wbeforechange, "/leaf.unit.new") + 1); assert(occurrences(wafterchange, "/common.unit.new") == occurrences(wbeforechange, "/common.unit.new") + 1); assert(occurrences(wafterchange, "/gamma.unit.new") == occurrences(wbeforechange, "/gamma.unit.new")); assert(occurrences(wafterchange, "/alpha-internal-test.unit.new") == occurrences(wbeforechange, "/alpha-internal-test.unit.new")); assert(same(changedleafunit, readfile(strings.concat(warmwwwork, "leaf.unit.ww")))); assert(same(changedleafwwi, readfile(strings.concat(warmwwwork, "leaf.wwi")))); assert(same(changedleafa, readfile(strings.concat(warmwwwork, "leaf.a")))); assert(same(changedcommonunit, readfile(strings.concat(warmwwwork, "common.unit.ww")))); assert(same(readfile(strings.concat(warmwork, "common.wwi")), readfile(strings.concat(warmwwwork, "common.wwi")))); assert(same(readfile(strings.concat(warmwork, "common.a")), readfile(strings.concat(warmwwwork, "common.a")))); // A second unchanged request in either stage performs no compilation. runcommandenv(root, "multidir-warm-c-export-reuse", warmparallel, traceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(cafterchange, readfile(compilertrace))); runcommandenv(root, "multidir-warm-ww-export-reuse", warmww, wwtraceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(wafterchange, readfile(wwcompilertrace))); // Exercise the inverse discovery order explicitly. aaroot is selected and // loaded before zimporter, which later imports it; gamma above is first // discovered through beta and only later visited as a selected root. Both // orders must compile one production action, and a root-only build must emit // byte-identical owner unit, export, and archive. let aaroot: str = strings.concat(root, "/aaroot"); let zimporter: str = strings.concat(root, "/zimporter"); assert(os.mkdir(aaroot, 448i32) == 0); assert(os.mkdir(zimporter, 448i32) == 0); writefile(strings.concat(aaroot, "/aaroot.ww"), strings.concat( "package aaroot;\n// ROOT_FIRST_OWNER\n", "export fn value() i32 = { return 42; };\n")); writefile(strings.concat(zimporter, "/zimporter.ww"), strings.concat( "package zimporter;\nimport aaroot;\n", "export fn value() i32 = { return aaroot.value(); };\n")); let rootrefs: []str = ["", "", ""]; let rootstages: []str = ["ww", "ww_ww"]; let rsi: i32 = 0; for (rsi < rootstages.len) { let uniondriver: str = driver(rootstages[rsi]); if (rsi == 1) { uniondriver = wwtracedriver; }; let rootout: str = strings.concat(root, "/root-only-", rootstages[rsi], ".a"); let rootav: []str = [driver(rootstages[rsi]), "build", "-I", root, "-o", rootout, aaroot]; runcommand(root, strings.concat("root-only-", rootstages[rsi]), rootav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let rootwork: str = strings.concat(rootout, ".sepwork/"); let depbin: str = strings.concat(root, "/root-first-", rootstages[rsi], "-dep.test"); let userbin: str = strings.concat(root, "/root-first-", rootstages[rsi], "-user.test"); let unionav: []str = [uniondriver, "test", "-c", "-I", root, "--ww-package-test", "production", "aaroot", aaroot, depbin, strings.concat(root, "/root-first-", rootstages[rsi], "-dep.status"), "--ww-package-test", "production", "zimporter", zimporter, userbin, strings.concat(root, "/root-first-", rootstages[rsi], "-user.status"), aaroot]; let beforetrace: str = ""; if (rsi == 0) { beforetrace = strings.dup(readfile(compilertrace)); } else { beforetrace = strings.dup(readfile(wwcompilertrace)); }; if (rsi == 0) { runcommandenv(root, "root-first-c", unionav, traceenv, (120i64 * (time.second: i64)): time.duration, &out); } else { runcommandenv(root, "root-first-ww", unionav, wwtraceenv, (120i64 * (time.second: i64)): time.duration, &out); }; expectexit(&out, 0); let aftertrace: str = ""; if (rsi == 0) { aftertrace = strings.dup(readfile(compilertrace)); } else { aftertrace = strings.dup(readfile(wwcompilertrace)); }; assert(occurrences(aftertrace, "/aaroot.unit.ww") == occurrences(beforetrace, "/aaroot.unit.ww") + 1); let unionwork: str = strings.concat(depbin, ".sepwork/"); let suffixes: []str = [".unit.ww", ".wwi", ".a"]; let xi: i32 = 0; for (xi < suffixes.len) { let rootbytes: str = readfile(strings.concat(rootwork, "aaroot", suffixes[xi])); assert(same(rootbytes, readfile(strings.concat(unionwork, "aaroot", suffixes[xi])))); if (rsi == 0) { rootrefs[xi] = strings.dup(rootbytes); } else { assert(same(rootrefs[xi], rootbytes)); }; xi += 1; }; rsi += 1; }; clean(wwtracebin); clean(root); }; @test fn shared_package_resolution_context_conflict_is_stable() void = { let root: str = fresh(); let suite: str = strings.concat(root, "/suite"); let a: str = strings.concat(suite, "/a"); let b: str = strings.concat(suite, "/b"); let good: str = strings.concat(suite, "/good"); let aleaf: str = strings.concat(a, "/_leaf"); let bleaf: str = strings.concat(b, "/_leaf"); let common: str = strings.concat(root, "/common"); let dirs: []str = [suite, a, b, good, aleaf, bleaf, common]; let di: i32 = 0; for (di < dirs.len) { assert(os.mkdir(dirs[di], 448i32) == 0); di += 1; }; writefile(strings.concat(aleaf, "/_leaf.ww"), "package _leaf;\nexport fn value() i32 = { return 20; };\n"); writefile(strings.concat(bleaf, "/_leaf.ww"), "package _leaf;\nexport fn value() i32 = { return 21; };\n"); writefile(strings.concat(common, "/common.ww"), strings.concat( "package common;\nimport _leaf;\n", "export fn value() i32 = { return _leaf.value(); };\n")); writefile(strings.concat(a, "/a.ww"), "package a;\nimport common;\nfn value() i32 = { return common.value(); };\n"); writefile(strings.concat(a, "/a_test.ww"), "package a;\n@test fn a_context() void = { assert(value() == 20); };\n"); writefile(strings.concat(b, "/b.ww"), "package b;\nimport common;\nfn value() i32 = { return common.value(); };\n"); writefile(strings.concat(b, "/b_test.ww"), "package b;\n@test fn b_context() void = { assert(value() == 21); };\n"); writefile(strings.concat(good, "/good.ww"), "package good;\nfn value() i32 = { return 42; };\n"); writefile(strings.concat(good, "/good_test.ww"), "package good;\n@test fn unrelated_runs() void = { assert(value() == 42); };\n"); let tooltrace: str = strings.concat(root, "/context-tool.trace"); let compilerwrapper: str = strings.concat(root, "/context-w6c.sh"); let linkerwrapper: str = strings.concat(root, "/context-w6l.sh"); writefile(tooltrace, ""); writeexecutable(compilerwrapper, strings.concat( "#!/bin/sh\nprintf 'compile\\n' >> \"$WW_CONTEXT_TRACE\"\n", "exec \"$WW_CONTEXT_W6C\" \"$@\"\n")); writeexecutable(linkerwrapper, strings.concat( "#!/bin/sh\nprintf 'link\\n' >> \"$WW_CONTEXT_TRACE\"\n", "exec \"$WW_CONTEXT_W6L\" \"$@\"\n")); let baseenv: []str = os.getenvs(); let traceenv: []str = alloc([], (baseenv.len + 5): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_CONTEXT_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_CONTEXT_W6C=") && !strings.hasprefix(baseenv[ei], "WW_CONTEXT_W6L=")) { append(traceenv, baseenv[ei]); }; ei += 1; }; append(traceenv, strings.concat("WW_W6C=", compilerwrapper)); append(traceenv, strings.concat("WW_W6L=", linkerwrapper)); append(traceenv, strings.concat("WW_CONTEXT_TRACE=", tooltrace)); append(traceenv, strings.concat("WW_CONTEXT_W6C=", driver("w6c"))); append(traceenv, strings.concat("WW_CONTEXT_W6L=", driver("w6l"))); let stages: []str = ["ww", "ww_ww"]; let jobs: []str = ["1", "4"]; let diagnostics: []str = ["", ""]; let referenceout: str = ""; let out: commandout; let i: i32 = 0; for (i < stages.len) { let av: []str = [driver(stages[i]), "test", "-j", jobs[i], "-I", root, strings.concat(suite, "/...")]; let stageenv: []str = traceenv; if (i == 1) { let wwenv: []str = alloc([], (baseenv.len + 5): u64)!; stageenv = wwenv; ei = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_CONTEXT_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_CONTEXT_W6C=") && !strings.hasprefix(baseenv[ei], "WW_CONTEXT_W6L=")) { append(stageenv, baseenv[ei]); }; ei += 1; }; append(stageenv, strings.concat("WW_W6C=", compilerwrapper)); append(stageenv, strings.concat("WW_W6L=", linkerwrapper)); append(stageenv, strings.concat("WW_CONTEXT_TRACE=", tooltrace)); append(stageenv, strings.concat("WW_CONTEXT_W6C=", driver("w6c_ww"))); append(stageenv, strings.concat("WW_CONTEXT_W6L=", driver("w6l_ww"))); }; runcommandenv(root, strings.concat("context-conflict-", stages[i]), av, stageenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, strings.concat( "ww: package _leaf resolves to directories ", aleaf, " and ", bleaf, "\n"))); assert(has(out.stderr, strings.concat("FAIL ", a, " [a] (build exit 1)\n"))); assert(has(out.stderr, strings.concat("FAIL ", b, " [b] (build exit 1)\n"))); assert(has(out.stderr, strings.concat("FAIL ", good, " [good] (build exit 1)\n"))); assert(!has(out.stdout, "unrelated_runs")); diagnostics[i] = strings.dup(primarydiagnostic(out.stderr)); if (i == 0) { referenceout = strings.dup(out.stdout); } else { assert(same(referenceout, out.stdout)); }; i += 1; }; assert(same(diagnostics[0], diagnostics[1])); assert(readfile(tooltrace).len == 0); clean(root); }; @test fn mixed_named_test_and_toolchain_test_actions_do_not_collide() void = { let root: str = fresh(); let suite: str = strings.concat(root, "/suite"); let named: str = strings.concat(suite, "/test"); let consumer: str = strings.concat(suite, "/zconsumer"); assert(os.mkdir(suite, 448i32) == 0); assert(os.mkdir(named, 448i32) == 0); assert(os.mkdir(consumer, 448i32) == 0); writefile(strings.concat(named, "/named.ww"), strings.concat( "package test;\n// MIXED_USER_TEST_PRODUCTION\n", "fn hidden() i32 = { return 19; };\n", "export fn value() i32 = { return 42; };\n")); writefile(strings.concat(named, "/same_test.ww"), strings.concat( "package test;\n@test fn named_same_runs() void = {", " assert(hidden() == 19); };\n")); writefile(strings.concat(named, "/external_test.ww"), strings.concat( "package test_test;\nimport test;\n", "@test fn named_external_runs() void = {", " assert(test.value() == 42); };\n")); writefile(strings.concat(consumer, "/consumer.ww"), strings.concat( "package zconsumer;\n", "// MIXED_GENERATED_TOOLCHAIN_TEST_SUPPORT\n", "export fn value() i32 = { return 42; };\n")); writefile(strings.concat(consumer, "/same_test.ww"), strings.concat( "package zconsumer;\n@test fn consumer_same_runs() void = {", " assert(value() == 42); };\n")); writefile(strings.concat(consumer, "/external_test.ww"), strings.concat( "package zconsumer_test;\nimport zconsumer;\n", "@test fn consumer_external_runs() void = {", " assert(zconsumer.value() == 42); };\n")); let linktrace: str = strings.concat(root, "/mixed-link.trace"); let linkwrapper: str = strings.concat(root, "/mixed-w6l.sh"); writefile(linktrace, ""); writeexecutable(linkwrapper, strings.concat( "#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_MIXED_LINK_TRACE\"\n", "exec \"$WW_MIXED_W6L\" \"$@\"\n")); let baseenv: []str = os.getenvs(); let linkenv: []str = alloc([], (baseenv.len + 3): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_MIXED_LINK_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_MIXED_W6L=")) { append(linkenv, baseenv[ei]); }; ei += 1; }; append(linkenv, strings.concat("WW_W6L=", linkwrapper)); append(linkenv, strings.concat("WW_MIXED_LINK_TRACE=", linktrace)); append(linkenv, strings.concat("WW_MIXED_W6L=", driver("w6l"))); let bins: []str = [strings.concat(named, "/test.test"), strings.concat(named, "/test_test.test"), strings.concat(consumer, "/zconsumer.test"), strings.concat(consumer, "/zconsumer_test.test")]; let keys: []str = ["test-internal-test", "test_test-external-test", "zconsumer-internal-test", "zconsumer_test-external-test"]; let expected: []str = ["named_same_runs ... ok\n", "named_external_runs ... ok\n", "consumer_same_runs ... ok\n", "consumer_external_runs ... ok\n"]; let workroot: str = strings.concat(bins[0], ".sepwork"); let work: str = strings.concat(workroot, "/"); let referenceunits: []str = ["", "", "", ""]; let stages: []str = ["ww", "ww_ww"]; let out: commandout; let si: i32 = 0; for (si < stages.len) { let av: []str = [driver(stages[si]), "test", "-c", "-j", "1", "-I", suite, strings.concat(suite, "/...")]; if (si == 0) { runcommandenv(root, "mixed-actions-c", av, linkenv, (120i64 * (time.second: i64)): time.duration, &out); } else { runcommand(root, "mixed-actions-ww", av, (120i64 * (time.second: i64)): time.duration, &out); }; expectexit(&out, 0); let namedprod: str = readfile(strings.concat(work, "test.unit.ww")); let support: str = readfile(strings.concat(work, "__wwtest.unit.ww")); assert(has(namedprod, "MIXED_USER_TEST_PRODUCTION")); assert(has(namedprod, "//ww:module-reset test\n")); assert(has(support, "//ww:module-reset __wwtest\n")); let suffixes: []str = [".unit.ww", ".wwi", ".a"]; let actions: []str = ["test", "__wwtest"]; let ai: i32 = 0; for (ai < actions.len) { let xi: i32 = 0; for (xi < suffixes.len) { assert(os.exists(strings.concat(work, actions[ai], suffixes[xi]))); xi += 1; }; ai += 1; }; let ri: i32 = 0; for (ri < keys.len) { let unit: str = readfile(strings.concat(work, keys[ri], ".unit.ww")); assert(!has(unit, "//ww:module ")); let runav: []str = [bins[ri]]; runcommand(root, strings.concat("mixed-run-", stages[si], "-", keys[ri]), runav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, expected[ri])); if (si == 0) { referenceunits[ri] = strings.dup(unit); } else { assert(same(referenceunits[ri], unit)); }; ri += 1; }; if (si == 0) { let links: str = readfile(linktrace); assert(occurrences(links, "\n") == 4); let namedsame: str = linecontaining(links, strings.concat("-o ", bins[0], ".new ")); let namedexternal: str = linecontaining(links, strings.concat("-o ", bins[1], ".new ")); let consumersame: str = linecontaining(links, strings.concat("-o ", bins[2], ".new ")); let consumerexternal: str = linecontaining(links, strings.concat("-o ", bins[3], ".new ")); assert(has(namedsame, strings.concat(work, "__wwtest.a"))); assert(!has(namedsame, strings.concat(work, "test.a"))); assert(has(namedexternal, strings.concat(work, "test.a"))); assert(has(namedexternal, strings.concat(work, "__wwtest.a"))); assert(has(consumersame, strings.concat(work, "__wwtest.a"))); assert(!has(consumersame, strings.concat(work, "test.a"))); assert(has(consumerexternal, strings.concat(work, "__wwtest.a"))); assert(!has(consumerexternal, strings.concat(work, "test.a"))); }; if (si == 0) { clean(workroot); let bi: i32 = 0; for (bi < bins.len) { clean(bins[bi]); bi += 1; }; }; si += 1; }; clean(root); }; @test fn long_shared_link_closure_is_complete() void = { let root: str = fresh(); let d1: str = strings.concat(root, "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); let d2: str = strings.concat(d1, "/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); let d3: str = strings.concat(d2, "/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"); let target: str = strings.concat(d3, "/target"); let chainroot: str = strings.concat(d3, "/chain"); assert(os.mkdir(d1, 448i32) == 0); assert(os.mkdir(d2, 448i32) == 0); assert(os.mkdir(d3, 448i32) == 0); assert(os.mkdir(target, 448i32) == 0); assert(os.mkdir(chainroot, 448i32) == 0); let packagecount: i32 = 300; let i: i32 = 0; for (i < packagecount) { let name: str = boundarypkgname(i); let dir: str = strings.concat(root, "/", name); assert(os.mkdir(dir, 448i32) == 0); let a: str = ""; if (i + 1 < packagecount) { let next: str = boundarypkgname(i + 1); a = strings.concat("package ", name, ";\nimport ", next, ";\n// OWNER_A_", name, "\nexport fn value() i32 = { return ", next, ".value(); };\n"); } else { a = strings.concat("package ", name, ";\n// OWNER_A_", name, "\nexport fn value() i32 = { return 42; };\n"); }; let z: str = strings.concat("package ", name, ";\n// OWNER_Z_", name, "\nfn private_value() i32 = { return value(); };\n"); writefile(strings.concat(dir, "/a.ww"), a); writefile(strings.concat(dir, "/z.ww"), z); i += 1; }; let roota: str = "package main;\n// ROOT_A\n"; i = 0; for (i < packagecount) { if (i != 150) { roota = strings.concat(roota, "import ", boundarypkgname(i), ";\n"); }; i += 1; }; i = 0; for (i < packagecount) { if (i != 150) { let name: str = boundarypkgname(i); roota = strings.concat(roota, "fn use_", name, "() i32 = { return ", name, ".value(); };\n"); }; i += 1; }; let rootz: str = strings.concat("package main;\nimport p150;\n", "// ROOT_Z\nfn main() i32 = { return p150.value() - 42; };\n"); writefile(strings.concat(target, "/a.ww"), roota); writefile(strings.concat(target, "/z.ww"), rootz); let chainsource: str = strings.concat("package main;\nimport p000;\n", "// CHAIN_ROOT\nfn main() i32 = { return p000.value() - 42; };\n"); writefile(strings.concat(chainroot, "/main.ww"), chainsource); let rootaction: str = "target"; let chainaction: str = "chain"; let compilerwrapper: str = strings.concat(root, "/boundary-w6c.sh"); let assemblerwrapper: str = strings.concat(root, "/boundary-w6a.sh"); let linkerwrapper: str = strings.concat(root, "/boundary-w6l.sh"); writeexecutable(compilerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_BOUNDARY_COMPILER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_BOUNDARY_COMPILER_TRACE\"; done\n", "printf '\\n' >> \"$WW_BOUNDARY_COMPILER_TRACE\"\n", "exec \"$WW_BOUNDARY_W6C\" \"$@\"\n")); writeexecutable(assemblerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_BOUNDARY_ASSEMBLER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_BOUNDARY_ASSEMBLER_TRACE\"; done\n", "printf '\\n' >> \"$WW_BOUNDARY_ASSEMBLER_TRACE\"\n", "exec \"$WW_BOUNDARY_W6A\" \"$@\"\n")); writeexecutable(linkerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_BOUNDARY_LINKER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_BOUNDARY_LINKER_TRACE\"; done\n", "printf '\\n' >> \"$WW_BOUNDARY_LINKER_TRACE\"\n", "exec \"$WW_BOUNDARY_W6L\" \"$@\"\n")); let stages: []str = ["ww", "ww_ww"]; let compilers: []str = ["w6c", "w6c_ww"]; let assemblers: []str = ["w6a", "w6a_ww"]; let linkers: []str = ["w6l", "w6l_ww"]; let works: []str = [strings.concat(root, "/boundary-c-work"), strings.concat(root, "/boundary-ww-work")]; let bins: []str = [strings.concat(root, "/boundary-c-bin"), strings.concat(root, "/boundary-ww-bin")]; let chainbins: []str = [strings.concat(root, "/boundary-c-chain-bin"), strings.concat(root, "/boundary-ww-chain-bin")]; let compilertraces: []str = [strings.concat(root, "/boundary-c-compiler"), strings.concat(root, "/boundary-ww-compiler")]; let assemblertraces: []str = [strings.concat(root, "/boundary-c-assembler"), strings.concat(root, "/boundary-ww-assembler")]; let linkertraces: []str = [strings.concat(root, "/boundary-c-linker"), strings.concat(root, "/boundary-ww-linker")]; let baseenv: []str = os.getenvs(); let environments: [][]str = alloc([], stages.len: u64)!; let out: commandout; let si: i32 = 0; for (si < stages.len) { assert(os.mkdir(works[si], 448i32) == 0); writefile(compilertraces[si], ""); writefile(assemblertraces[si], ""); writefile(linkertraces[si], ""); let env: []str = alloc([], (baseenv.len + 11): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6A=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_BOUNDARY_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_BOUNDARY_ASSEMBLER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_BOUNDARY_LINKER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_BOUNDARY_W6C=") && !strings.hasprefix(baseenv[ei], "WW_BOUNDARY_W6A=") && !strings.hasprefix(baseenv[ei], "WW_BOUNDARY_W6L=") && !strings.hasprefix(baseenv[ei], "WW_LIB=") && !strings.hasprefix(baseenv[ei], "WW_SRCLIB=")) { append(env, baseenv[ei]); }; ei += 1; }; append(env, strings.concat("WW_W6C=", compilerwrapper)); append(env, strings.concat("WW_W6A=", assemblerwrapper)); append(env, strings.concat("WW_W6L=", linkerwrapper)); append(env, strings.concat("WW_BOUNDARY_COMPILER_TRACE=", compilertraces[si])); append(env, strings.concat("WW_BOUNDARY_ASSEMBLER_TRACE=", assemblertraces[si])); append(env, strings.concat("WW_BOUNDARY_LINKER_TRACE=", linkertraces[si])); append(env, strings.concat("WW_BOUNDARY_W6C=", driver(compilers[si]))); append(env, strings.concat("WW_BOUNDARY_W6A=", driver(assemblers[si]))); append(env, strings.concat("WW_BOUNDARY_W6L=", driver(linkers[si]))); append(env, strings.concat("WW_LIB=", repo(), "/out/bin/../lib")); append(env, strings.concat("WW_SRCLIB=", repo(), "/lib")); append(environments, env); let av: []str = [driver(stages[si]), "build", "-w", works[si], "-I", d3, "-I", root, "-o", bins[si], target]; runcommandenv(root, strings.concat("boundary-cold-", stages[si]), av, env, (600i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); let runav: []str = [bins[si]]; runcommand(root, strings.concat("boundary-run-", stages[si]), runav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); let ctrace: str = readfile(compilertraces[si]); let atrace: str = readfile(assemblertraces[si]); let ltrace: str = readfile(linkertraces[si]); assert(occurrences(ctrace, "\n") == packagecount + 1); assert(occurrences(atrace, "\n") == packagecount + 2); assert(occurrences(ltrace, "\n") == 1); let rootline: str = linecontaining(ctrace, strings.concat("/", rootaction, ".unit.new")); assert(occurrences(rootline, "<--import>") == packagecount); let expectedroot: str = strings.concat( "BEGIN<--entry><--package-init-symbol><__ww..pkg.p.", rootaction, ".v0.r0.init><--init-dispatch-symbol>", "<__ww..dispatch><-c>"); i = 0; for (i < packagecount) { let name: str = boundarypkgname(i); expectedroot = strings.concat(expectedroot, "<--import><", name, "><", works[si], "/", name, ".wwi.new>"); assert(occurrences(rootline, strings.concat("<", name, "><", works[si], "/", name, ".wwi.new>")) == 1); i += 1; }; expectedroot = strings.concat(expectedroot, "<-I><", works[si], "/", rootaction, ".wwi.new><-o><", works[si], "/", rootaction, ".s.new><", works[si], "/", rootaction, ".unit.new>"); assert(same(rootline, expectedroot)); i = 0; for (i < packagecount) { let name: str = boundarypkgname(i); let expectedcompile: str = strings.concat( "BEGIN<--package-init-symbol><__ww..pkg.p.", name, ".v0.r0.init><-c>"); if (i + 1 < packagecount) { let next: str = boundarypkgname(i + 1); expectedcompile = strings.concat(expectedcompile, "<--import><", next, "><", works[si], "/", next, ".wwi.new>"); }; expectedcompile = strings.concat(expectedcompile, "<-I><", works[si], "/", name, ".wwi.new><-o><", works[si], "/", name, ".s.new><", works[si], "/", name, ".unit.new>"); assert(same(linecontaining(ctrace, strings.concat("/", name, ".unit.new")), expectedcompile)); let expectedassemble: str = strings.concat("BEGIN<-o><", works[si], "/", name, ".o.new><", works[si], "/", name, ".s.new>"); assert(same(linecontaining(atrace, strings.concat("/", name, ".o.new")), expectedassemble)); assert(occurrences(ltrace, strings.concat("<", works[si], "/", name, ".a.new>")) == 1); assert(os.exists(strings.concat(works[si], "/", name, ".wwi"))); assert(os.exists(strings.concat(works[si], "/", name, ".s"))); assert(os.exists(strings.concat(works[si], "/", name, ".o"))); assert(os.exists(strings.concat(works[si], "/", name, ".a"))); let a: str = ""; if (i + 1 < packagecount) { let next: str = boundarypkgname(i + 1); a = strings.concat("package ", name, ";\nimport ", next, ";\n// OWNER_A_", name, "\nexport fn value() i32 = { return ", next, ".value(); };\n"); } else { a = strings.concat("package ", name, ";\n// OWNER_A_", name, "\nexport fn value() i32 = { return 42; };\n"); }; let z: str = strings.concat("package ", name, ";\n// OWNER_Z_", name, "\nfn private_value() i32 = { return value(); };\n"); let unit: str = readfile(strings.concat(works[si], "/", name, ".unit.ww")); assert(strings.hasprefix(unit, strings.concat("//ww:module-reset ", name, "\n", a, "\n//ww:module-reset ", name, "\n", z, "\n"))); if (i + 1 < packagecount) { assert(has(unit, strings.concat("//ww:direct-export ", boundarypkgname(i + 1), " "))); }; assert(strings.hasprefix(readfile(strings.concat(works[si], "/", name, ".wwi")), strings.concat("//ww:module ", name, "\n"))); i += 1; }; assert(occurrences(ltrace, strings.concat("<", works[si], "/", rootaction, ".a.new>")) == 1); assert(!has(ltrace, ".wwi>")); let expectedlink: str = strings.concat("BEGIN<-o><", bins[si], ".new><", works[si], "/", rootaction, ".a.new>"); i = 0; for (i < packagecount) { expectedlink = strings.concat(expectedlink, "<", works[si], "/", boundarypkgname(i), ".a.new>"); i += 1; }; expectedlink = strings.concat(expectedlink, "<", repo(), "/out/bin/../lib/libwwrt.a>\n"); assert(same(ltrace, expectedlink)); let rootunit: str = readfile(strings.concat(works[si], "/", rootaction, ".unit.ww")); assert(strings.hasprefix(rootunit, strings.concat("//ww:module-reset target\n", roota, "\n//ww:module-reset target\n", rootz, "\n"))); assert(occurrences(rootunit, "//ww:direct-export p") == packagecount); let rootassemble: str = strings.concat("BEGIN<-o><", works[si], "/", rootaction, ".o.new><", works[si], "/", rootaction, ".s.new>"); assert(same(linecontaining(atrace, strings.concat("/", rootaction, ".o.new")), rootassemble)); let dispatchassemble: str = strings.concat("BEGIN<-o><", works[si], "/", rootaction, ".init.o.new><", works[si], "/", rootaction, ".init.s.new>"); assert(same(linecontaining(atrace, strings.concat("/", rootaction, ".init.o.new")), dispatchassemble)); // Repeating the same semantic request in the persistent work root may // relink the requested binary, but must not compile or assemble any action. let cbefore: i32 = ctrace.len; let abefore: i32 = atrace.len; runcommandenv(root, strings.concat("boundary-warm-", stages[si]), av, env, (600i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); assert(readfile(compilertraces[si]).len == cbefore); assert(readfile(assemblertraces[si]).len == abefore); // A second root importing only p000 proves that link closure expansion, // not the wide root's direct import list, reaches every archive beyond 256. let chaincbefore: i32 = readfile(compilertraces[si]).len; let chainabefore: i32 = readfile(assemblertraces[si]).len; let chainlbefore: i32 = readfile(linkertraces[si]).len; let chainav: []str = [driver(stages[si]), "build", "-w", works[si], "-I", d3, "-I", root, "-o", chainbins[si], chainroot]; runcommandenv(root, strings.concat("boundary-chain-", stages[si]), chainav, env, (600i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); let chainctrace: str = readfile(compilertraces[si]); let chainatrace: str = readfile(assemblertraces[si]); let chainltrace: str = readfile(linkertraces[si]); let cdelta: str = strings.sub(chainctrace, chaincbefore, chainctrace.len); let adelta: str = strings.sub(chainatrace, chainabefore, chainatrace.len); let ldelta: str = strings.sub(chainltrace, chainlbefore, chainltrace.len); assert(occurrences(cdelta, "\n") == 1); assert(occurrences(adelta, "\n") == 2); assert(occurrences(ldelta, "\n") == 1); assert(same(cdelta, strings.concat( "BEGIN<--entry><--package-init-symbol><__ww..pkg.p.", chainaction, ".v0.r0.init><--init-dispatch-symbol>", "<__ww..dispatch><-c><--import><", works[si], "/p000.wwi><-I><", works[si], "/", chainaction, ".wwi.new><-o><", works[si], "/", chainaction, ".s.new><", works[si], "/", chainaction, ".unit.new>\n"))); assert(same(adelta, strings.concat("BEGIN<-o><", works[si], "/", chainaction, ".o.new><", works[si], "/", chainaction, ".s.new>\n", "BEGIN<-o><", works[si], "/", chainaction, ".init.o.new><", works[si], "/", chainaction, ".init.s.new>\n"))); let expectedchainlink: str = strings.concat("BEGIN<-o><", chainbins[si], ".new><", works[si], "/", chainaction, ".a.new>"); i = 0; for (i < packagecount) { expectedchainlink = strings.concat(expectedchainlink, "<", works[si], "/", boundarypkgname(i), ".a>"); i += 1; }; expectedchainlink = strings.concat(expectedchainlink, "<", repo(), "/out/bin/../lib/libwwrt.a>\n"); assert(same(ldelta, expectedchainlink)); assert(!has(ldelta, ".wwi>")); let chainunit: str = readfile(strings.concat(works[si], "/", chainaction, ".unit.ww")); assert(strings.hasprefix(chainunit, strings.concat( "//ww:module-reset chain\n", chainsource, "\n"))); assert(has(chainunit, "//ww:direct-export p000 ")); let chainrun: []str = [chainbins[si]]; runcommand(root, strings.concat("boundary-chain-run-", stages[si]), chainrun, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); si += 1; }; let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"]; i = 0; for (i < packagecount) { let name: str = boundarypkgname(i); let xi: i32 = 0; for (xi < suffixes.len) { assert(same(readfile(strings.concat(works[0], "/", name, suffixes[xi])), readfile(strings.concat(works[1], "/", name, suffixes[xi])))); xi += 1; }; i += 1; }; let xi: i32 = 0; for (xi < suffixes.len) { assert(same(readfile(strings.concat(works[0], "/", rootaction, suffixes[xi])), readfile(strings.concat(works[1], "/", rootaction, suffixes[xi])))); xi += 1; }; assert(same(readfile(bins[0]), readfile(bins[1]))); xi = 0; for (xi < suffixes.len) { assert(same(readfile(strings.concat(works[0], "/", chainaction, suffixes[xi])), readfile(strings.concat(works[1], "/", chainaction, suffixes[xi])))); xi += 1; }; assert(same(readfile(chainbins[0]), readfile(chainbins[1]))); // p257 is inserted beyond the former 256-action boundary. A changed // export recompiles that package, its direct importer p256, and the root // (which directly imports every package), then stops at p255 because the // regenerated p256 export is byte-identical. let changed: str = strings.concat(root, "/p257/a.ww"); rewritefile(changed, strings.concat( "package p257;\nimport p258;\n// OWNER_A_p257_CHANGED\n", "export fn value() i32 = { return p258.value(); };\n", "export fn changed() i32 = { return 257; };\n")); si = 0; for (si < stages.len) { let before: str = readfile(compilertraces[si]); let av: []str = [driver(stages[si]), "build", "-w", works[si], "-I", d3, "-I", root, "-o", bins[si], target]; runcommandenv(root, strings.concat("boundary-change-", stages[si]), av, environments[si], (600i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); let after: str = readfile(compilertraces[si]); let delta: str = strings.sub(after, before.len, after.len); assert(occurrences(delta, "\n") == 3); assert(occurrences(delta, "/p257.unit.new") == 1); assert(occurrences(delta, "/p256.unit.new") == 1); assert(occurrences(delta, strings.concat("/", rootaction, ".unit.new")) == 1); assert(!has(delta, "/p255.unit.new")); assert(!has(delta, "/p258.unit.new")); let runav: []str = [bins[si]]; runcommand(root, strings.concat("boundary-change-run-", stages[si]), runav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); si += 1; }; assert(same(readfile(strings.concat(works[0], "/p257.wwi")), readfile(strings.concat(works[1], "/p257.wwi")))); assert(same(readfile(bins[0]), readfile(bins[1]))); // Close the 300-node chain into a cycle. Both graph implementations must // emit the complete deterministic path before compiler, assembler, or linker. rewritefile(strings.concat(root, "/p299/a.ww"), strings.concat( "package p299;\nimport p000;\n// OWNER_A_p299_CYCLE\n", "export fn value() i32 = { return p000.value(); };\n")); let wantcycle: str = "ww: dependency cycle: "; i = 0; for (i < packagecount) { if (i != 0) { wantcycle = strings.concat(wantcycle, " -> "); }; wantcycle = strings.concat(wantcycle, boundarypkgname(i)); i += 1; }; wantcycle = strings.concat(wantcycle, " -> p000\n"); let referencecycle: str = ""; si = 0; for (si < stages.len) { rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let cyclework: str = strings.concat(root, "/cycle-work-", stages[si]); assert(os.mkdir(cyclework, 448i32) == 0); let cyclebin: str = strings.concat(root, "/cycle-bin-", stages[si]); let av: []str = [driver(stages[si]), "build", "-w", cyclework, "-I", d3, "-I", root, "-o", cyclebin, target]; runcommandenv(root, strings.concat("boundary-cycle-", stages[si]), av, environments[si], (600i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(out.stdout.len == 0); assert(same(out.stderr, wantcycle)); assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); if (si == 0) { referencecycle = strings.dup(out.stderr); } else { assert(same(referencecycle, out.stderr)); }; si += 1; }; clean(root); }; @test fn dynamic_package_universe_crosses_former_boundary() void = { let root: str = fresh(); let suite: str = strings.concat(root, "/suite"); assert(os.mkdir(suite, 448i32) == 0); let directorycount: i32 = 52; let aliascount: i32 = 205; let totaldirectorycount: i32 = directorycount + aliascount; let productcount: i32 = directorycount * 2 + aliascount; // Each selected directory contributes production, internal, external, and // two generated-main actions. The shared test support action and its eight // ordinary dependencies are command-global actions too. let directactioncount: i32 = directorycount * 5 + 9; let coordinatoractioncount: i32 = directactioncount + aliascount * 2; let i: i32 = 0; for (i < directorycount) { let name: str = boundarypkgname(i); let dir: str = strings.concat(suite, "/", name); assert(os.mkdir(dir, 448i32) == 0); writefile(strings.concat(dir, "/a.ww"), strings.concat( "package ", name, ";\n// DYNAMIC_PRODUCTION_", name, "\nexport fn value() i32 = { return 42; };\n")); writefile(strings.concat(dir, "/same_test.ww"), strings.concat( "package ", name, ";\n// DYNAMIC_INTERNAL_", name, "\n@test fn same_value() void = { assert(value() == 42); };\n")); writefile(strings.concat(dir, "/external_test.ww"), strings.concat( "package ", name, "_test;\nimport ", name, ";\n// DYNAMIC_EXTERNAL_", name, "\n@test fn external_value() void = { assert(", name, ".value() == 42); };\n")); i += 1; }; // Production-only directories make the recursive coordinator request own // 257 resolution contexts and 309 products. Each contributes a production // action plus its generated production test-main action. for (i < totaldirectorycount) { let name: str = boundarypkgname(i); let dir: str = strings.concat(suite, "/", name); assert(os.mkdir(dir, 448i32) == 0); writefile(strings.concat(dir, "/a.ww"), strings.concat( "package ", name, ";\n// DYNAMIC_PRODUCTION_ONLY_", name, "\nexport fn value() i32 = { return 42; };\n")); i += 1; }; i = 0; for (i < aliascount) { let alias: str = strings.concat(suite, "/alias-", boundarypkgname(i)); assert(os.symlink(strings.concat(suite, "/p000"), alias) == 0); i += 1; }; let compilerwrapper: str = strings.concat(root, "/universe-w6c.sh"); let linkerwrapper: str = strings.concat(root, "/universe-w6l.sh"); writeexecutable(compilerwrapper, strings.concat( "#!/bin/sh\nprintf '%s\\n' \"$*\" >> ", "\"$WW_UNIVERSE_COMPILER_TRACE\"\n", "exec \"$WW_UNIVERSE_W6C\" \"$@\"\n")); writeexecutable(linkerwrapper, strings.concat( "#!/bin/sh\nprintf '%s\\n' \"$*\" >> ", "\"$WW_UNIVERSE_LINKER_TRACE\"\n", "exec \"$WW_UNIVERSE_W6L\" \"$@\"\n")); let coordinatorproxy: str = strings.concat(root, "/universe-coordinator.sh"); let driverwrapper: str = strings.concat(root, "/universe-driver.sh"); writeexecutable(coordinatorproxy, strings.concat( "#!/bin/sh\n", "if [ \"$1\" != package ] || [ \"$2\" != --ww-driver ] || ", "[ \"$#\" -lt 3 ]; then exit 97; fi\n", "shift 3\nexec \"$WW_UNIVERSE_WWTEST\" package --ww-driver ", "\"$WW_UNIVERSE_DRIVER_WRAPPER\" \"$@\"\n")); writeexecutable(driverwrapper, strings.concat( "#!/bin/sh\ncount=0\n", "for arg in \"$@\"; do\n", " if [ \"$arg\" = --ww-package-test ]; then count=$((count + 1)); fi\n", "done\nprintf '%s\\n' \"$count\" >> ", "\"$WW_UNIVERSE_BUILDER_TRACE\"\n", "exec \"$WW_UNIVERSE_DRIVER\" \"$@\"\n")); let stages: []str = ["ww", "ww_ww"]; let compilers: []str = ["w6c", "w6c_ww"]; let assemblers: []str = ["w6a", "w6a_ww"]; let linkers: []str = ["w6l", "w6l_ww"]; let workroots: []str = [strings.concat(root, "/universe-c-workroot"), strings.concat(root, "/universe-ww-workroot")]; let works: []str = [workroots[0], workroots[1]]; let compilertraces: []str = [strings.concat(root, "/universe-c-compiler"), strings.concat(root, "/universe-ww-compiler")]; let linkertraces: []str = [strings.concat(root, "/universe-c-linker"), strings.concat(root, "/universe-ww-linker")]; let buildertraces: []str = [strings.concat(root, "/universe-c-builder"), strings.concat(root, "/universe-ww-builder")]; let baseenv: []str = os.getenvs(); let coordinatoroutputs: []str = ["", ""]; let out: commandout; let si: i32 = 0; for (si < stages.len) { assert(os.mkdir(workroots[si], 448i32) == 0); writefile(compilertraces[si], ""); writefile(linkertraces[si], ""); writefile(buildertraces[si], ""); let env: []str = alloc([], (baseenv.len + 14): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6A=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_LINKER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_W6C=") && !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_W6L=") && !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_WWTEST=") && !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_DRIVER_WRAPPER=") && !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_DRIVER=") && !strings.hasprefix(baseenv[ei], "WW_UNIVERSE_BUILDER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_WWTEST=") && !strings.hasprefix(baseenv[ei], "WW_LIB=") && !strings.hasprefix(baseenv[ei], "WW_SRCLIB=")) { append(env, baseenv[ei]); }; ei += 1; }; append(env, strings.concat("WW_W6C=", compilerwrapper)); append(env, strings.concat("WW_W6A=", driver(assemblers[si]))); append(env, strings.concat("WW_W6L=", linkerwrapper)); append(env, strings.concat("WW_UNIVERSE_COMPILER_TRACE=", compilertraces[si])); append(env, strings.concat("WW_UNIVERSE_LINKER_TRACE=", linkertraces[si])); append(env, strings.concat("WW_UNIVERSE_W6C=", driver(compilers[si]))); append(env, strings.concat("WW_UNIVERSE_W6L=", driver(linkers[si]))); append(env, strings.concat("WW_LIB=", repo(), "/out/bin/../lib")); append(env, strings.concat("WW_SRCLIB=", repo(), "/lib")); append(env, strings.concat("WW_WWTEST=", coordinatorproxy)); append(env, strings.concat("WW_UNIVERSE_WWTEST=", repo(), "/out/bin/wwtest")); append(env, strings.concat("WW_UNIVERSE_DRIVER_WRAPPER=", driverwrapper)); append(env, strings.concat("WW_UNIVERSE_DRIVER=", driver(stages[si]))); append(env, strings.concat("WW_UNIVERSE_BUILDER_TRACE=", buildertraces[si])); let av: []str = alloc([], (8 + productcount * 6): u64)!; append(av, driver(stages[si])); append(av, "test"); append(av, "-c"); append(av, "-w"); append(av, works[si]); append(av, "-I"); append(av, suite); if (si == 0) { i = 0; for (i < directorycount) { let name: str = boundarypkgname(i); let dir: str = strings.concat(suite, "/", name); append(av, "--ww-package-test"); append(av, "same"); append(av, name); append(av, dir); append(av, strings.concat(root, "/c-same-", name)); append(av, strings.concat(root, "/c-same-", name, ".status")); append(av, "--ww-package-test"); append(av, "external"); append(av, strings.concat(name, "_test")); append(av, dir); append(av, strings.concat(root, "/c-external-", name)); append(av, strings.concat(root, "/c-external-", name, ".status")); i += 1; }; i = 0; for (i < aliascount) { let aname: str = boundarypkgname(i); let alias: str = strings.concat(suite, "/alias-", aname); append(av, "--ww-package-test"); append(av, "same"); append(av, "p000"); append(av, alias); append(av, strings.concat(root, "/c-alias-", aname)); append(av, strings.concat(root, "/c-alias-", aname, ".status")); i += 1; }; } else { // Reverse both the product groups and variant order. The driver must // derive the same canonical action universe independent of request order. i = aliascount - 1; for (i >= 0) { let aname: str = boundarypkgname(i); let alias: str = strings.concat(suite, "/alias-", aname); append(av, "--ww-package-test"); append(av, "same"); append(av, "p000"); append(av, alias); append(av, strings.concat(root, "/ww-alias-", aname)); append(av, strings.concat(root, "/ww-alias-", aname, ".status")); i -= 1; }; i = directorycount - 1; for (i >= 0) { let name: str = boundarypkgname(i); let dir: str = strings.concat(suite, "/", name); append(av, "--ww-package-test"); append(av, "external"); append(av, strings.concat(name, "_test")); append(av, dir); append(av, strings.concat(root, "/ww-external-", name)); append(av, strings.concat(root, "/ww-external-", name, ".status")); append(av, "--ww-package-test"); append(av, "same"); append(av, name); append(av, dir); append(av, strings.concat(root, "/ww-same-", name)); append(av, strings.concat(root, "/ww-same-", name, ".status")); i -= 1; }; }; append(av, strings.concat(suite, "/p000")); assert(av.len == 8 + productcount * 6); runcommandenv(root, strings.concat("dynamic-universe-", stages[si]), av, env, (600i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); let ctrace: str = readfile(compilertraces[si]); let ltrace: str = readfile(linkertraces[si]); assert(occurrences(ctrace, "\n") == directactioncount); assert(occurrences(ltrace, "\n") == productcount); assert(!has(ltrace, ".wwi")); assert(occurrences(ctrace, "/test.unit.new") == 1); i = 0; for (i < directorycount) { let name: str = boundarypkgname(i); let internal: str = strings.concat(name, "-internal-test"); let external: str = strings.concat(name, "_test-external-test"); let internalmain: str = strings.concat(internal, "-main"); let externalmain: str = strings.concat(external, "-main"); assert(occurrences(ctrace, strings.concat("/", name, ".unit.new")) == 1); assert(occurrences(ctrace, strings.concat("/", internal, ".unit.new")) == 1); assert(occurrences(ctrace, strings.concat("/", external, ".unit.new")) == 1); assert(occurrences(ctrace, strings.concat("/", internalmain, ".unit.new")) == 1); assert(occurrences(ctrace, strings.concat("/", externalmain, ".unit.new")) == 1); let actions: []str = [name, internal, external, internalmain, externalmain]; let ai: i32 = 0; for (ai < actions.len) { assert(os.exists(strings.concat(works[si], "/", actions[ai], ".unit.ww"))); assert(os.exists(strings.concat(works[si], "/", actions[ai], ".wwi"))); assert(os.exists(strings.concat(works[si], "/", actions[ai], ".s"))); assert(os.exists(strings.concat(works[si], "/", actions[ai], ".o"))); assert(os.exists(strings.concat(works[si], "/", actions[ai], ".a"))); ai += 1; }; let prefix: str = "c"; if (si == 1) { prefix = "ww"; }; assert(os.exists(strings.concat(root, "/", prefix, "-same-", name))); assert(os.exists(strings.concat(root, "/", prefix, "-external-", name))); i += 1; }; i = 0; for (i < aliascount) { let name: str = boundarypkgname(i); let prefix: str = "c"; if (si == 1) { prefix = "ww"; }; assert(os.exists(strings.concat(root, "/", prefix, "-alias-", name))); i += 1; }; let prefix: str = "c"; if (si == 1) { prefix = "ww"; }; let samples: []str = [strings.concat(root, "/", prefix, "-same-p051"), strings.concat(root, "/", prefix, "-external-p051"), strings.concat(root, "/", prefix, "-alias-p204")]; i = 0; for (i < samples.len) { let runav: []str = [samples[i]]; runcommand(root, strings.concat("dynamic-run-", stages[si], "-", boundarypkgname(i)), runav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "_value ... ok\n")); i += 1; }; // Exercise the public coordinator path with the same persistent package // universe. It must construct and pass all 309 descriptors in one argv, // retain the 270 existing actions, and add exactly the 410 actions owned by // the 205 production-only directories. let cbefore: i32 = readfile(compilertraces[si]).len; let lbefore: i32 = readfile(linkertraces[si]).len; let recursive: str = strings.concat(suite, "/..."); let coordinatorav: []str = [driver(stages[si]), "test", "-j", "1", "-w", workroots[si], "-I", suite, recursive]; runcommandenv(root, strings.concat("dynamic-coordinator-", stages[si]), coordinatorav, env, (1200i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stderr.len == 0); coordinatoroutputs[si] = strings.dup(out.stdout); let cafter: str = readfile(compilertraces[si]); let lafter: str = readfile(linkertraces[si]); assert(occurrences(cafter, "\n") == coordinatoractioncount); assert(occurrences(strings.sub(cafter, cbefore, cafter.len), "\n") == aliascount * 2); assert(occurrences(strings.sub(lafter, lbefore, lafter.len), "\n") == productcount); assert(!has(strings.sub(lafter, lbefore, lafter.len), ".wwi")); assert(same(readfile(buildertraces[si]), "309\n")); assert(occurrences(out.stdout, "ok ") == directorycount * 2); assert(occurrences(out.stdout, "? ") == aliascount); i = 0; for (i < directorycount) { let name: str = boundarypkgname(i); assert(has(out.stdout, strings.concat("ok ", suite, "/", name, " [", name, ", same-package]\n"))); assert(has(out.stdout, strings.concat("ok ", suite, "/", name, " [", name, "_test, external]\n"))); i += 1; }; i = directorycount; for (i < totaldirectorycount) { let name: str = boundarypkgname(i); assert(has(out.stdout, strings.concat("? ", suite, "/", name, " [no tests]\n"))); i += 1; }; // Repeating the public request may relink products, but every canonical // action in the >256 universe must be warm. let warmcompilerlen: i32 = cafter.len; runcommandenv(root, strings.concat("dynamic-coordinator-warm-", stages[si]), coordinatorav, env, (1200i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stderr.len == 0); assert(same(out.stdout, coordinatoroutputs[si])); assert(readfile(compilertraces[si]).len == warmcompilerlen); assert(same(readfile(buildertraces[si]), "309\n309\n")); si += 1; }; assert(same(coordinatoroutputs[0], coordinatoroutputs[1])); let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"]; i = 0; for (i < directorycount) { let name: str = boundarypkgname(i); let actions: []str = [name, strings.concat(name, "-internal-test"), strings.concat(name, "_test-external-test"), strings.concat(name, "-internal-test-main"), strings.concat(name, "_test-external-test-main")]; let ai: i32 = 0; for (ai < actions.len) { let xi: i32 = 0; for (xi < suffixes.len) { assert(same(readfile(strings.concat(works[0], "/", actions[ai], suffixes[xi])), readfile(strings.concat(works[1], "/", actions[ai], suffixes[xi])))); xi += 1; }; ai += 1; }; i += 1; }; i = directorycount; for (i < totaldirectorycount) { let name: str = boundarypkgname(i); let actions: []str = [name, strings.concat(name, "-main")]; let ai: i32 = 0; for (ai < actions.len) { let xi: i32 = 0; for (xi < suffixes.len) { assert(same(readfile(strings.concat(works[0], "/", actions[ai], suffixes[xi])), readfile(strings.concat(works[1], "/", actions[ai], suffixes[xi])))); xi += 1; }; ai += 1; }; i += 1; }; let supportactions: []str = ["ascii", "bytes", "encoding.utf8", "fnmatch", "os", "strings", "test", "time", "types"]; let ai: i32 = 0; for (ai < supportactions.len) { i = 0; for (i < suffixes.len) { assert(same(readfile(strings.concat(works[0], "/", supportactions[ai], suffixes[i])), readfile(strings.concat(works[1], "/", supportactions[ai], suffixes[i])))); i += 1; }; ai += 1; }; assert(same(readfile(strings.concat(root, "/c-same-p051")), readfile(strings.concat(root, "/ww-same-p051")))); assert(same(readfile(strings.concat(root, "/c-external-p051")), readfile(strings.concat(root, "/ww-external-p051")))); assert(same(readfile(strings.concat(root, "/c-alias-p204")), readfile(strings.concat(root, "/ww-alias-p204")))); let internalunit: str = readfile(strings.concat(works[0], "/p051-internal-test.unit.ww")); let externalunit: str = readfile(strings.concat(works[0], "/p051_test-external-test.unit.ww")); let productionunit: str = readfile(strings.concat(works[0], "/p051.unit.ww")); assert(has(internalunit, "DYNAMIC_PRODUCTION_p051")); assert(has(internalunit, "DYNAMIC_INTERNAL_p051")); assert(!has(internalunit, "DYNAMIC_EXTERNAL_p051")); assert(has(externalunit, "DYNAMIC_EXTERNAL_p051")); assert(!has(externalunit, "DYNAMIC_PRODUCTION_p051")); assert(has(productionunit, "DYNAMIC_PRODUCTION_p051")); assert(!has(productionunit, "DYNAMIC_INTERNAL_p051")); assert(!has(productionunit, "DYNAMIC_EXTERNAL_p051")); clean(root); }; @test fn multi_directory_test_failures_are_isolated() void = { let root: str = fresh(); let suite: str = strings.concat(root, "/suite"); let alpha: str = strings.concat(suite, "/alpha"); let beta: str = strings.concat(suite, "/beta"); assert(os.mkdir(suite, 448i32) == 0); assert(os.mkdir(alpha, 448i32) == 0); assert(os.mkdir(beta, 448i32) == 0); writefile(strings.concat(alpha, "/alpha.ww"), strings.concat( "package alpha;\n", "fn hidden() i32 = { return 41; };\n", "export fn shown() i32 = { return 41; };\n")); writefile(strings.concat(alpha, "/same_test.ww"), strings.concat( "package alpha;\n", "@test fn alpha_same_survives() void = {", " assert(hidden() == 41); };\n")); writefile(strings.concat(alpha, "/external_test.ww"), strings.concat( "package alpha_test;\nimport alpha;\n", "@test fn alpha_external_fails() void = {", " assert(alpha.hidden() == 41); };\n")); writefile(strings.concat(beta, "/beta.ww"), strings.concat( "package beta;\n", "fn hidden() i32 = { return 42; };\n", "export fn shown() i32 = { return 42; };\n")); writefile(strings.concat(beta, "/same_test.ww"), strings.concat( "package beta;\n", "@test fn beta_same_survives() void = {", " assert(hidden() == 42); };\n")); writefile(strings.concat(beta, "/external_test.ww"), strings.concat( "package beta_test;\nimport beta;\n", "@test fn beta_external_survives() void = {", " assert(beta.shown() == 42); };\n")); let stages: []str = ["ww", "ww_ww"]; let jobs: []str = ["1", "4"]; let diagnostics: []str = ["", ""]; let referenceout: str = ""; let out: commandout; let i: i32 = 0; for (i < stages.len) { let av: []str = [driver(stages[i]), "test", "-j", jobs[i], "-I", root, strings.concat(suite, "/...")]; runcommand(root, strings.concat("multidir-failure-", stages[i]), av, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(out.stdout.len == 0); assert(has(out.stderr, "has no exported declaration 'hidden'")); assert(has(out.stderr, strings.concat("FAIL ", alpha, " [alpha] (build exit 1)\n"))); assert(has(out.stderr, strings.concat("FAIL ", alpha, " [alpha_test] (build exit 1)\n"))); assert(has(out.stderr, strings.concat("FAIL ", beta, " [beta] (build exit 1)\n"))); assert(has(out.stderr, strings.concat("FAIL ", beta, " [beta_test] (build exit 1)\n"))); let alphapos: i32 = pos(out.stderr, strings.concat("FAIL ", alpha, " [alpha] (build exit 1)\n")); let betapos: i32 = pos(out.stderr, strings.concat("FAIL ", beta, " [beta] (build exit 1)\n")); assert(alphapos >= 0 && alphapos < betapos); diagnostics[i] = strings.dup(primarydiagnostic(out.stderr)); if (i == 0) { referenceout = strings.dup(out.stdout); } else { assert(same(referenceout, out.stdout)); }; i += 1; }; assert(same(diagnostics[0], diagnostics[1])); clean(root); }; // Roots remain independently diagnosed and may be staged in parallel, but one // failing product rejects publication and execution of the entire request. @test fn sibling_test_variant_failures_are_isolated() void = { let root: str = fresh(); let badexternal: str = strings.concat(root, "/badexternal"); let badsame: str = strings.concat(root, "/badsame"); assert(os.mkdir(badexternal, 448i32) == 0); assert(os.mkdir(badsame, 448i32) == 0); writefile(strings.concat(badexternal, "/badexternal.ww"), strings.concat( "package badexternal;\n", "fn hidden() i32 = { return 41; };\n", "export fn shown() i32 = { return 41; };\n")); writefile(strings.concat(badexternal, "/same_test.ww"), strings.concat( "package badexternal;\n", "@test fn valid_same_runs() void = { assert(hidden() == 41); };\n")); writefile(strings.concat(badexternal, "/external_test.ww"), strings.concat( "package badexternal_test;\nimport badexternal;\n", "@test fn invalid_external() void = {\n", " assert(badexternal.hidden() == 41);\n};\n")); writefile(strings.concat(badsame, "/badsame.ww"), strings.concat( "package badsame;\n", "export fn shown() i32 = { return 42; };\n")); writefile(strings.concat(badsame, "/same_test.ww"), strings.concat( "package badsame;\n", "@test fn invalid_same() void = { assert(missing() == 0); };\n")); writefile(strings.concat(badsame, "/external_test.ww"), strings.concat( "package badsame_test;\nimport badsame;\n", "@test fn valid_external_runs() void = {\n", " assert(badsame.shown() == 42);\n};\n")); let stages: []str = ["ww", "ww_ww"]; let tags: []str = ["c", "ww"]; let externaldiagnostics: []str = ["", ""]; let samediagnostics: []str = ["", ""]; let out: commandout; let i: i32 = 0; for (i < stages.len) { let externalav: []str = [driver(stages[i]), "test", "-I", root, badexternal]; runcommand(root, strings.concat("isolated-external-", tags[i]), externalav, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(out.stdout.len == 0); assert(has(out.stderr, "has no exported declaration 'hidden'")); assert(has(out.stderr, strings.concat("FAIL ", badexternal, " [badexternal] (build exit 1)\n"))); assert(has(out.stderr, strings.concat("FAIL ", badexternal, " [badexternal_test] (build exit 1)\n"))); externaldiagnostics[i] = strings.dup(primarydiagnostic(out.stderr)); let sameav: []str = [driver(stages[i]), "test", "-I", root, badsame]; runcommand(root, strings.concat("isolated-same-", tags[i]), sameav, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(out.stdout.len == 0); assert(has(out.stderr, "undefined: missing")); assert(has(out.stderr, strings.concat("FAIL ", badsame, " [badsame] (build exit 1)\n"))); assert(has(out.stderr, strings.concat("FAIL ", badsame, " [badsame_test] (build exit 1)\n"))); samediagnostics[i] = strings.dup(primarydiagnostic(out.stderr)); i += 1; }; assert(same(externaldiagnostics[0], externaldiagnostics[1])); assert(same(samediagnostics[0], samediagnostics[1])); // A persistent request is one publication transaction. A rejection leaves // no reusable generation, so every staged action is reconsidered next time. let warmroot: str = strings.concat(root, "/warm-partial"); assert(os.mkdir(warmroot, 448i32) == 0); let trace: str = strings.concat(root, "/warm-partial.trace"); let wrapper: str = strings.concat(root, "/warm-partial-w6c.sh"); writefile(trace, ""); writeexecutable(wrapper, strings.concat( "#!/bin/sh\n", "printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_COMPILER_TRACE\"\n", "exec \"$WW_PACKAGE_W6C\" \"$@\"\n")); let baseenv: []str = os.getenvs(); let traceenv: []str = alloc([], (baseenv.len + 3): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=")) { append(traceenv, baseenv[ei]); }; ei += 1; }; append(traceenv, strings.concat("WW_W6C=", wrapper)); append(traceenv, strings.concat("WW_PACKAGE_COMPILER_TRACE=", trace)); append(traceenv, strings.concat("WW_PACKAGE_W6C=", driver("w6c"))); let warmav: []str = [driver("ww"), "test", "-j", "4", "-w", warmroot, "-I", root, badexternal]; runcommandenv(root, "isolated-warm-first", warmav, traceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let firsttrace: str = readfile(trace); assert(occurrences(firsttrace, "/badexternal-internal-test.unit.new") == 1); assert(occurrences(firsttrace, "/badexternal_test-external-test.unit.new") == 1); runcommandenv(root, "isolated-warm-reuse", warmav, traceenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let secondtrace: str = readfile(trace); assert(occurrences(secondtrace, "/badexternal-internal-test.unit.new") == 2); assert(occurrences(secondtrace, "/badexternal_test-external-test.unit.new") == 2); assert(!os.exists(strings.concat(warmroot, "/badexternal-internal-test.unit.ww"))); assert(!os.exists(strings.concat(warmroot, "/badexternal_test-external-test.unit.ww"))); assert(!os.exists(strings.concat(warmroot, "/.wwtool.stamp"))); let wwtracebin: str = strings.concat(repo(), "/out/partial-trace-", workescape(root)); assert(os.mkdir(wwtracebin, 448i32) == 0); let wwdriver: str = strings.concat(wwtracebin, "/ww_ww"); let wwtrace: str = strings.concat(root, "/warm-partial-ww.trace"); let wwwarmroot: str = strings.concat(root, "/warm-partial-ww"); assert(os.mkdir(wwwarmroot, 448i32) == 0); writefile(wwtrace, ""); writeexecutable(wwdriver, readfile(driver("ww_ww"))); writeexecutable(strings.concat(wwtracebin, "/wwtest"), readfile(driver("wwtest"))); writeexecutable(strings.concat(wwtracebin, "/w6c_ww"), strings.concat( "#!/bin/sh\n", "printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_WW_COMPILER_TRACE\"\n", "exec \"$WW_PACKAGE_W6C_WW\" \"$@\"\n")); writeexecutable(strings.concat(wwtracebin, "/w6a_ww"), readfile(driver("w6a_ww"))); writeexecutable(strings.concat(wwtracebin, "/w6l_ww"), readfile(driver("w6l_ww"))); let wwenv: []str = alloc([], (baseenv.len + 2): u64)!; ei = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_PACKAGE_WW_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C_WW=")) { append(wwenv, baseenv[ei]); }; ei += 1; }; append(wwenv, strings.concat("WW_PACKAGE_WW_COMPILER_TRACE=", wwtrace)); append(wwenv, strings.concat("WW_PACKAGE_W6C_WW=", driver("w6c_ww"))); let wwwarmav: []str = [wwdriver, "test", "-j", "4", "-w", wwwarmroot, "-I", root, badexternal]; runcommandenv(root, "isolated-warm-ww-first", wwwarmav, wwenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let wwfirst: str = readfile(wwtrace); assert(occurrences(wwfirst, "/badexternal-internal-test.unit.new") == 1); assert(occurrences(wwfirst, "/badexternal_test-external-test.unit.new") == 1); runcommandenv(root, "isolated-warm-ww-reuse", wwwarmav, wwenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let wwsecond: str = readfile(wwtrace); assert(occurrences(wwsecond, "/badexternal-internal-test.unit.new") == 2); assert(occurrences(wwsecond, "/badexternal_test-external-test.unit.new") == 2); assert(!os.exists(strings.concat(wwwarmroot, "/badexternal-internal-test.unit.ww"))); assert(!os.exists(strings.concat(wwwarmroot, "/badexternal_test-external-test.unit.ww"))); assert(!os.exists(strings.concat(wwwarmroot, "/.wwtool.stamp"))); clean(wwtracebin); clean(root); }; // The compiler-generated runner uses a reserved graph qualifier rather than // claiming the user-visible import path `test`. A real multi-file production // package named test can therefore be the normal direct dependency of its // external test variant in both bootstrap stages. @test fn production_package_named_test_remains_available() void = { let root: str = fresh(); let pkg: str = strings.concat(root, "/test"); assert(os.mkdir(pkg, 448i32) == 0); writefile(strings.concat(pkg, "/a.ww"), strings.concat( "package test;\n", "// USER_TEST_PACKAGE_A\n", "export fn first() i32 = { return 19; };\n")); writefile(strings.concat(pkg, "/z.ww"), strings.concat( "package test;\n", "// USER_TEST_PACKAGE_Z\n", "export fn second() i32 = { return 23; };\n")); writefile(strings.concat(pkg, "/external_test.ww"), strings.concat( "package test_test;\nimport test;\n", "// USER_TEST_EXTERNAL\n", "@test fn package_name_is_not_reserved() void = {\n", " assert(test.first() + test.second() == 42);\n};\n")); let bin: str = strings.concat(root, "/named-test.bin"); let workroot: str = strings.concat(bin, ".sepwork"); let work: str = strings.concat(workroot, "/"); let stages: []str = ["ww", "ww_ww"]; let referencebin: str = ""; let referenceroot: str = ""; let referenceprod: str = ""; let referencesupport: str = ""; let out: commandout; let i: i32 = 0; for (i < stages.len) { let av: []str = [driver(stages[i]), "test", "-c", "-I", root, "-o", bin, pkg]; runcommand(root, strings.concat("named-test-build-", stages[i]), av, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let rootunit: str = readfile(strings.concat(work, "test_test-external-test.unit.ww")); let produnit: str = readfile(strings.concat(work, "test.unit.ww")); let supportunit: str = readfile(strings.concat(work, "__wwtest.unit.ww")); assert(!has(rootunit, "//ww:module ")); assert(has(rootunit, "USER_TEST_EXTERNAL")); assert(!has(rootunit, "USER_TEST_PACKAGE_A")); assert(!has(rootunit, "USER_TEST_PACKAGE_Z")); assert(has(produnit, "USER_TEST_PACKAGE_A")); assert(has(produnit, "USER_TEST_PACKAGE_Z")); assert(has(supportunit, "//ww:module-reset __wwtest\n")); assert(has(supportunit, "package test;\n")); assert(os.exists(strings.concat(work, "test.wwi"))); assert(os.exists(strings.concat(work, "test.a"))); assert(!os.exists(strings.concat(work, "__ww-test-000-external-production.unit.ww"))); assert(os.exists(strings.concat(work, "__wwtest.wwi"))); assert(os.exists(strings.concat(work, "__wwtest.a"))); let runav: []str = [bin]; runcommand(root, strings.concat("named-test-run-", stages[i]), runav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "package_name_is_not_reserved ... ok\n")); if (i == 0) { referencebin = readfile(bin); referenceroot = strings.dup(rootunit); referenceprod = strings.dup(produnit); referencesupport = strings.dup(supportunit); } else { assert(same(referencebin, readfile(bin))); assert(same(referenceroot, rootunit)); assert(same(referenceprod, produnit)); assert(same(referencesupport, supportunit)); }; if (i + 1 < stages.len) { clean(workroot); clean(bin); }; i += 1; }; clean(root); }; @test fn internal_package_import_visibility() void = { let root: str = fresh(); let source: str = strings.concat(root, "/host/internal/source"); let runtime: str = strings.concat(root, "/runtime"); let tools: str = strings.concat(root, "/tools"); let domain: str = strings.concat(source, "/domain"); let leaf: str = strings.concat(domain, "/leaf"); let secret: str = strings.concat(domain, "/internal/secret"); let client: str = strings.concat(domain, "/client"); let outsider: str = strings.concat(source, "/outsider"); let prefixclient: str = strings.concat(source, "/domainx/client"); let deep: str = strings.concat(domain, "/internal/outer/internal/deep"); let deepclient: str = strings.concat(domain, "/internal/outer/client"); let nestedoutsider: str = strings.concat(domain, "/nestedclient"); let internalx: str = strings.concat(domain, "/internalx/visible"); let internalxclient: str = strings.concat(source, "/internalxclient"); let testclient: str = strings.concat(domain, "/testclient"); let outsame: str = strings.concat(source, "/outsame"); let outexternal: str = strings.concat(source, "/outexternal"); let physical: str = strings.concat(root, "/physical/domain"); let linkedsecret: str = strings.concat(physical, "/internal/secret"); let linkedclient: str = strings.concat(physical, "/client"); let rawallowed: str = strings.concat(source, "/alias/rawclient.ww"); let rawalias: str = strings.concat(domain, "/rawalias.ww"); let rawescape: str = strings.concat(domain, "/rawescape.ww"); let aliasinternal: str = strings.concat(source, "/alias/internal"); let aliasclient: str = strings.concat(source, "/alias/client"); let aliasownedclient: str = strings.concat(source, "/alias/owned-client"); let aliasoutsider: str = strings.concat(source, "/alias/outsider"); let shapedomain: str = strings.concat(source, "/shape/domain"); let shapeinternal: str = strings.concat(shapedomain, "/internal"); let shapeclient: str = strings.concat(shapedomain, "/client"); let shapeoutsider: str = strings.concat(source, "/shape/outsider"); let shapevault: str = strings.concat(root, "/vault"); mkdirall(leaf); mkdirall(secret); mkdirall(client); mkdirall(outsider); mkdirall(prefixclient); mkdirall(deep); mkdirall(deepclient); mkdirall(nestedoutsider); mkdirall(internalx); mkdirall(internalxclient); mkdirall(testclient); mkdirall(outsame); mkdirall(outexternal); mkdirall(linkedsecret); mkdirall(linkedclient); mkdirall(aliasinternal); mkdirall(aliasownedclient); mkdirall(shapeinternal); mkdirall(shapeclient); mkdirall(shapeoutsider); mkdirall(shapevault); mkdirall(runtime); mkdirall(tools); writefile(strings.concat(runtime, "/libwwrt.a"), readfile(strings.concat(repo(), "/out/lib/libwwrt.a"))); let leafbody: str = strings.concat( "package leaf;\n", "export fn value() i32 = { return 20; };\n"); let secreta: str = strings.concat( "package secret;\n", "import domain.leaf;\n", "export fn value() i32 = { return leaf.value() + 22; };\n"); let secretz: str = strings.concat( "package secret;\n", "fn private_value() i32 = { return 99; };\n"); let clientbody: str = strings.concat( "package main;\n", "import domain.internal.secret;\n", "fn main() i32 = { return secret.value(); };\n"); writefile(strings.concat(leaf, "/leaf.ww"), leafbody); writefile(strings.concat(secret, "/a.ww"), secreta); writefile(strings.concat(secret, "/z.ww"), secretz); writefile(strings.concat(client, "/main.ww"), clientbody); writefile(strings.concat(outsider, "/main.ww"), strings.concat( "package main;\nimport domain.internal.secret;\n", "fn main() i32 = { return secret.value(); };\n")); writefile(strings.concat(prefixclient, "/main.ww"), strings.concat( "package main;\nimport domain.internal.secret;\n", "fn main() i32 = { return secret.value(); };\n")); writefile(strings.concat(deep, "/deep.ww"), strings.concat( "package deep;\n", "export fn value() i32 = { return 7; };\n")); writefile(strings.concat(deepclient, "/main.ww"), strings.concat( "package main;\n", "import domain.internal.outer.internal.deep;\n", "fn main() i32 = { return deep.value(); };\n")); writefile(strings.concat(nestedoutsider, "/main.ww"), strings.concat( "package main;\n", "import domain.internal.outer.internal.deep;\n", "fn main() i32 = { return deep.value(); };\n")); writefile(strings.concat(internalx, "/visible.ww"), strings.concat( "package visible;\n", "export fn value() i32 = { return 9; };\n")); writefile(strings.concat(internalxclient, "/main.ww"), strings.concat( "package main;\nimport domain.internalx.visible;\n", "fn main() i32 = { return visible.value(); };\n")); writefile(strings.concat(linkedsecret, "/secret.ww"), strings.concat( "package secret;\n", "export fn value() i32 = { return 31; };\n")); writefile(strings.concat(linkedclient, "/main.ww"), strings.concat( "package main;\nimport alias.internal.secret;\n", "fn main() i32 = { return secret.value(); };\n")); writefile(rawallowed, strings.concat( "package main;\nimport alias.internal.secret;\n", "fn main() i32 = { return secret.value(); };\n")); assert(os.symlink(rawallowed, rawalias) == 0); assert(os.symlink(strings.concat(outsider, "/main.ww"), rawescape) == 0); assert(os.symlink(linkedsecret, strings.concat(aliasinternal, "/secret")) == 0); writefile(strings.concat(aliasownedclient, "/main.ww"), strings.concat( "package main;\nimport alias.internal.secret;\n", "fn main() i32 = { return secret.value(); };\n")); assert(os.symlink(aliasownedclient, aliasclient) == 0); assert(os.symlink(linkedclient, aliasoutsider) == 0); writefile(strings.concat(shapevault, "/secret.ww"), strings.concat( "package secret;\n", "export fn value() i32 = { return 17; };\n")); assert(os.symlink(shapevault, strings.concat(shapeinternal, "/secret")) == 0); writefile(strings.concat(shapeclient, "/main.ww"), strings.concat( "package main;\nimport shape.domain.internal.secret;\n", "fn main() i32 = { return secret.value(); };\n")); writefile(strings.concat(shapeoutsider, "/main.ww"), strings.concat( "package main;\nimport shape.domain.internal.secret;\n", "fn main() i32 = { return secret.value(); };\n")); writefile(strings.concat(testclient, "/testclient.ww"), strings.concat( "package testclient;\n", "export fn value() i32 = { return 1; };\n")); writefile(strings.concat(testclient, "/same_test.ww"), strings.concat( "package testclient;\nimport domain.internal.secret;\n", "@test fn allowed_same() void = {\n", " assert(secret.value() == 42);\n};\n")); writefile(strings.concat(testclient, "/external_test.ww"), strings.concat( "package testclient_test;\nimport domain.internal.secret;\n", "import domain.testclient;\n", "@test fn allowed_external() void = {\n", " assert(secret.value() + testclient.value() == 43);\n};\n")); writefile(strings.concat(outsame, "/outsame.ww"), "package outsame;\nexport fn value() i32 = { return 1; };\n"); writefile(strings.concat(outsame, "/same_test.ww"), strings.concat( "package outsame;\nimport domain.internal.secret;\n", "@test fn forbidden_same() void = { assert(false); };\n")); writefile(strings.concat(outexternal, "/outexternal.ww"), "package outexternal;\nexport fn value() i32 = { return 1; };\n"); writefile(strings.concat(outexternal, "/external_test.ww"), strings.concat( "package outexternal_test;\nimport domain.internal.secret;\n", "@test fn forbidden_external() void = { assert(false); };\n")); let compilerwrapper: str = strings.concat(tools, "/w6c.sh"); let assemblerwrapper: str = strings.concat(tools, "/w6a.sh"); let linkerwrapper: str = strings.concat(tools, "/w6l.sh"); writeexecutable(compilerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_INTERNAL_COMPILER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_INTERNAL_COMPILER_TRACE\"; done\n", "printf '\\n' >> \"$WW_INTERNAL_COMPILER_TRACE\"\n", "exec \"$WW_INTERNAL_REAL_COMPILER\" \"$@\"\n")); writeexecutable(assemblerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_INTERNAL_ASSEMBLER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_INTERNAL_ASSEMBLER_TRACE\"; done\n", "printf '\\n' >> \"$WW_INTERNAL_ASSEMBLER_TRACE\"\n", "exec \"$WW_INTERNAL_REAL_ASSEMBLER\" \"$@\"\n")); writeexecutable(linkerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_INTERNAL_LINKER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_INTERNAL_LINKER_TRACE\"; done\n", "printf '\\n' >> \"$WW_INTERNAL_LINKER_TRACE\"\n", "exec \"$WW_INTERNAL_REAL_LINKER\" \"$@\"\n")); let stages: []str = ["ww", "ww_ww"]; let compilers: []str = ["w6c", "w6c_ww"]; let assemblers: []str = ["w6a", "w6a_ww"]; let linkers: []str = ["w6l", "w6l_ww"]; let labels: []str = ["0", "1", "2", "3", "4"]; let works: []str = [strings.concat(root, "/c-work"), strings.concat(root, "/ww-work")]; let bins: []str = [strings.concat(root, "/c-bin"), strings.concat(root, "/ww-bin")]; let compilertraces: []str = [strings.concat(root, "/c-compiler"), strings.concat(root, "/ww-compiler")]; let assemblertraces: []str = [strings.concat(root, "/c-assembler"), strings.concat(root, "/ww-assembler")]; let linkertraces: []str = [strings.concat(root, "/c-linker"), strings.concat(root, "/ww-linker")]; let artifacts: []str = ["domain.leaf", "domain.internal.secret", "domain.client"]; let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"]; let references: []str = alloc([], (artifacts.len * suffixes.len): u64)!; let ri: i32 = 0; for (ri < artifacts.len * suffixes.len) { append(references, ""); ri += 1; }; let referencebin: str = ""; let referencecompiler: str = ""; let referenceassembler: str = ""; let referencelinker: str = ""; let referencediagnostic: str = ""; let referencetestout: str = ""; let referencetesterr: str = ""; let referencetestartifacts: []str = alloc([], 12u64)!; ri = 0; for (ri < 12) { append(referencetestartifacts, ""); ri += 1; }; let allowedreferences: []str = ["", "", "", ""]; let testrejectreferences: []str = ["", ""]; let orderreference: str = ""; let baseenv: []str = os.getenvs(); let si: i32 = 0; for (si < stages.len) { assert(os.mkdir(works[si], 448i32) == 0); writefile(compilertraces[si], ""); writefile(assemblertraces[si], ""); writefile(linkertraces[si], ""); let env: []str = alloc([], (baseenv.len + 11): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6A=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_INTERNAL_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_INTERNAL_ASSEMBLER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_INTERNAL_LINKER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_INTERNAL_REAL_COMPILER=") && !strings.hasprefix(baseenv[ei], "WW_INTERNAL_REAL_ASSEMBLER=") && !strings.hasprefix(baseenv[ei], "WW_INTERNAL_REAL_LINKER=") && !strings.hasprefix(baseenv[ei], "WW_LIB=")) { append(env, baseenv[ei]); }; ei += 1; }; append(env, strings.concat("WW_W6C=", compilerwrapper)); append(env, strings.concat("WW_W6A=", assemblerwrapper)); append(env, strings.concat("WW_W6L=", linkerwrapper)); append(env, strings.concat("WW_INTERNAL_COMPILER_TRACE=", compilertraces[si])); append(env, strings.concat("WW_INTERNAL_ASSEMBLER_TRACE=", assemblertraces[si])); append(env, strings.concat("WW_INTERNAL_LINKER_TRACE=", linkertraces[si])); append(env, strings.concat("WW_INTERNAL_REAL_COMPILER=", driver(compilers[si]))); append(env, strings.concat("WW_INTERNAL_REAL_ASSEMBLER=", driver(assemblers[si]))); append(env, strings.concat("WW_INTERNAL_REAL_LINKER=", driver(linkers[si]))); append(env, strings.concat("WW_LIB=", runtime)); let av: []str = [driver(stages[si]), "build", "-w", works[si], "-I", source, "-o", bins[si], client]; let out: commandout; runcommandenv(root, strings.concat("internal-cold-", stages[si]), av, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); let wantsecret: str = strings.concat( "//ww:module-reset domain.internal.secret\n", secreta, "\n//ww:module-reset domain.internal.secret\n", secretz, "\n"); let secretunit: str = readfile(strings.concat(works[si], "/domain.internal.secret.unit.ww")); assert(strings.hasprefix(secretunit, wantsecret)); assert(has(secretunit, "//ww:direct-export domain.leaf ")); let ai: i32 = 0; for (ai < artifacts.len) { let xi: i32 = 0; for (xi < suffixes.len) { let bytes: str = readfile(strings.concat(works[si], "/", artifacts[ai], suffixes[xi])); let index: i32 = ai * suffixes.len + xi; if (si == 0) { references[index] = strings.dup(bytes); } else { assert(same(references[index], bytes)); }; xi += 1; }; ai += 1; }; let ctrace: str = readfile(compilertraces[si]); let atrace: str = readfile(assemblertraces[si]); let ltrace: str = readfile(linkertraces[si]); assert(occurrences(ctrace, "\n") == 3); assert(occurrences(atrace, "\n") == 4); assert(occurrences(ltrace, "\n") == 1); let dispatchline: str = strings.concat("BEGIN<-o><", works[si], "/domain.client.init.o.new><", works[si], "/domain.client.init.s.new>"); assert(same(linecontaining(atrace, "/domain.client.init.o.new"), dispatchline)); let secretline: str = linecontaining(ctrace, "domain.internal.secret.unit.new"); assert(occurrences(secretline, "domain.leaf.wwi") == 1); assert(!has(secretline, "domain.client.wwi")); let clientline: str = linecontaining(ctrace, "domain.client.unit.new"); assert(occurrences(clientline, "domain.internal.secret.wwi") == 1); assert(!has(clientline, "domain.leaf.wwi")); assert(occurrences(ltrace, strings.concat(works[si], "/domain.client.a")) == 1); assert(occurrences(ltrace, strings.concat(works[si], "/domain.internal.secret.a")) == 1); assert(occurrences(ltrace, strings.concat(works[si], "/domain.leaf.a")) == 1); assert(!has(ltrace, ".wwi")); let normalizedcompiler: str = normalizedtrace(ctrace, strings.concat(works[si], "/"), bins[si]); let normalizedassembler: str = normalizedtrace(atrace, strings.concat(works[si], "/"), bins[si]); let normalizedlinker: str = normalizedtrace(ltrace, strings.concat(works[si], "/"), bins[si]); if (si == 0) { referencecompiler = strings.dup(normalizedcompiler); referenceassembler = strings.dup(normalizedassembler); referencelinker = strings.dup(normalizedlinker); referencebin = strings.dup(readfile(bins[si])); } else { assert(same(referencecompiler, normalizedcompiler)); assert(same(referenceassembler, normalizedassembler)); assert(same(referencelinker, normalizedlinker)); assert(same(referencebin, readfile(bins[si]))); }; let runav: []str = [bins[si]]; runcommand(root, strings.concat("internal-run-", stages[si]), runav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 42); assert(out.stdout.len == 0 && out.stderr.len == 0); let voucher: str = readfile(strings.concat(works[si], "/domain.internal.secret.unit.ww")); let toolww: str = readfile(strings.concat(works[si], "/.wwtool.ww")); let toolc: str = readfile(strings.concat(works[si], "/.wwtool.w6c")); let toola: str = readfile(strings.concat(works[si], "/.wwtool.w6a")); let toolstamp: str = readfile(strings.concat(works[si], "/.wwtool.stamp")); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); runcommandenv(root, strings.concat("internal-warm-", stages[si]), av, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(occurrences(readfile(linkertraces[si]), "\n") == 1); assert(same(voucher, readfile(strings.concat(works[si], "/domain.internal.secret.unit.ww")))); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let badout: str = strings.concat(root, "/warm-forbidden-", stages[si]); let badav: []str = [driver(stages[si]), "build", "-w", works[si], "-I", source, "-o", badout, outsider]; runcommandenv(root, strings.concat("internal-warm-forbidden-", stages[si]), badav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let wantdiag: str = strings.concat(outsider, "/main.ww:2:1: error: use of internal package ", "domain.internal.secret not allowed\n"); assert(same(out.stderr, wantdiag)); if (si == 0) { referencediagnostic = strings.dup(out.stderr); } else { assert(same(referencediagnostic, out.stderr)); }; assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); assert(!os.exists(badout)); assert(!os.exists(strings.concat(works[si], "/outsider.unit.ww"))); assert(same(voucher, readfile(strings.concat(works[si], "/domain.internal.secret.unit.ww")))); assert(same(toolww, readfile(strings.concat(works[si], "/.wwtool.ww")))); assert(same(toolc, readfile(strings.concat(works[si], "/.wwtool.w6c")))); assert(same(toola, readfile(strings.concat(works[si], "/.wwtool.w6a")))); assert(same(toolstamp, readfile(strings.concat(works[si], "/.wwtool.stamp")))); let coldreject: str = strings.concat(root, "/cold-reject-", stages[si]); assert(os.mkdir(coldreject, 448i32) == 0); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let coldav: []str = [driver(stages[si]), "build", "-w", coldreject, "-I", source, "-o", strings.concat(coldreject, ".bin"), outsider]; runcommandenv(root, strings.concat("internal-cold-forbidden-", stages[si]), coldav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(same(out.stderr, wantdiag)); assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); assert(!os.exists(strings.concat(coldreject, "/.wwtool.ww"))); assert(!os.exists(strings.concat(coldreject, "/.wwtool.w6c"))); assert(!os.exists(strings.concat(coldreject, "/.wwtool.w6a"))); assert(!os.exists(strings.concat(coldreject, "/.wwtool.stamp"))); assert(!os.exists(strings.concat(coldreject, ".bin"))); assert(!os.exists(strings.concat(coldreject, "/domain.internal.secret.unit.ww"))); assert(!os.exists(strings.concat(coldreject, "/domain.internal.secret.a"))); assert(!os.exists(strings.concat(coldreject, "/outsider.unit.ww"))); let allowedtargets: []str = [deepclient, internalxclient, aliasclient, shapeclient]; let allowedcodes: []i32 = [7, 9, 31, 17]; let allowedi: i32 = 0; for (allowedi < allowedtargets.len) { let allowedout: str = strings.concat(root, "/allowed-", stages[si], "-", labels[allowedi]); let allowedav: []str = [driver(stages[si]), "build", "-I", source, "-o", allowedout, allowedtargets[allowedi]]; runcommandenv(root, strings.concat("internal-allowed-", stages[si], "-", labels[allowedi]), allowedav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let allowedrun: []str = [allowedout]; runcommand(root, strings.concat("internal-allowed-run-", stages[si], "-", labels[allowedi]), allowedrun, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, allowedcodes[allowedi]); if (si == 0) { allowedreferences[allowedi] = strings.dup(readfile(allowedout)); } else { assert(same(allowedreferences[allowedi], readfile(allowedout))); }; allowedi += 1; }; let rawout: str = strings.concat(root, "/raw-allowed-", stages[si]); let rawav: []str = [driver(stages[si]), "build", "-I", source, "-o", rawout, rawalias]; runcommandenv(root, strings.concat("internal-raw-allowed-", stages[si]), rawav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let rawrun: []str = [rawout]; runcommand(root, strings.concat("internal-raw-run-", stages[si]), rawrun, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 31); let directout: str = strings.concat(root, "/direct-", stages[si], ".a"); let directav: []str = [driver(stages[si]), "build", "-I", source, "-o", directout, secret]; runcommandenv(root, strings.concat("internal-direct-", stages[si]), directav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(references[1 * suffixes.len + 4], readfile(directout))); assert(same(references[1 * suffixes.len + 1], readfile(strings.concat(directout, ".wwi")))); let rejecttargets: []str = [prefixclient, nestedoutsider, aliasoutsider, rawescape, shapeoutsider]; let rejectimports: []str = ["domain.internal.secret", "domain.internal.outer.internal.deep", "alias.internal.secret", "domain.internal.secret", "shape.domain.internal.secret"]; let rejecti: i32 = 0; for (rejecti < rejecttargets.len) { let rejectwork: str = strings.concat(root, "/reject-", stages[si], "-", labels[rejecti]); assert(os.mkdir(rejectwork, 448i32) == 0); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let rejectav: []str = [driver(stages[si]), "build", "-w", rejectwork, "-I", source, "-o", strings.concat(rejectwork, ".bin"), rejecttargets[rejecti]]; runcommandenv(root, strings.concat("internal-reject-", stages[si], "-", labels[rejecti]), rejectav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let rejectsource: str = strings.concat(rejecttargets[rejecti], "/main.ww"); if (rejecti == 3) { rejectsource = rawescape; }; let rejectdiag: str = strings.concat(rejectsource, ":2:1: error: use of internal package ", rejectimports[rejecti], " not allowed\n"); assert(same(out.stderr, rejectdiag)); assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); assert(!os.exists(strings.concat(rejectwork, "/.wwtool.ww"))); assert(!os.exists(strings.concat(rejectwork, "/.wwtool.w6c"))); assert(!os.exists(strings.concat(rejectwork, "/.wwtool.w6a"))); assert(!os.exists(strings.concat(rejectwork, "/.wwtool.stamp"))); assert(!os.exists(strings.concat(rejectwork, ".bin"))); rejecti += 1; }; let testworkroot: str = strings.concat(root, "/test-work-", stages[si]); assert(os.mkdir(testworkroot, 448i32) == 0); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let testav: []str = [driver(stages[si]), "test", "-w", testworkroot, "-I", source, testclient]; runcommandenv(root, strings.concat("internal-test-allowed-", stages[si]), testav, env, (180i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "allowed_same ... ok\n")); assert(has(out.stdout, "allowed_external ... ok\n")); if (si == 0) { referencetestout = strings.dup(out.stdout); referencetesterr = strings.dup(out.stderr); } else { assert(same(referencetestout, out.stdout)); assert(same(referencetesterr, out.stderr)); }; let testwork: str = strings.concat(testworkroot, "/"); let testactions: []str = ["domain.testclient-internal-test", "domain.testclient_test-external-test", "domain.testclient-internal-test-main", "domain.testclient_test-external-test-main"]; ai = 0; for (ai < testactions.len) { let testsuffixes: []str = [".unit.ww", ".wwi", ".a"]; let xi: i32 = 0; for (xi < testsuffixes.len) { let bytes: str = readfile(strings.concat(testwork, testactions[ai], testsuffixes[xi])); let index: i32 = ai * testsuffixes.len + xi; if (si == 0) { referencetestartifacts[index] = strings.dup(bytes); } else { assert(same(referencetestartifacts[index], bytes)); }; xi += 1; }; ai += 1; }; let testcompiletrace: str = readfile(compilertraces[si]); let sameline: str = linecontaining(testcompiletrace, "domain.testclient-internal-test.unit"); let externalline: str = linecontaining(testcompiletrace, "domain.testclient_test-external-test.unit"); assert(occurrences(sameline, "domain.internal.secret.wwi") == 1); assert(occurrences(externalline, "domain.internal.secret.wwi") == 1); assert(!has(sameline, "domain.leaf.wwi")); assert(!has(externalline, "domain.leaf.wwi")); let samemainline: str = linecontaining(testcompiletrace, "domain.testclient-internal-test-main.unit"); let externalmainline: str = linecontaining(testcompiletrace, "domain.testclient_test-external-test-main.unit"); assert(!has(samemainline, "domain.internal.secret.wwi")); assert(!has(externalmainline, "domain.internal.secret.wwi")); assert(occurrences(testcompiletrace, "--test-package") == 2); assert(occurrences(testcompiletrace, "<-T><--entry><--test-support-module>") == 2); assert(!has(readfile(linkertraces[si]), ".wwi")); let testrejects: []str = [outsame, outexternal]; let testfiles: []str = ["/same_test.ww", "/external_test.ww"]; let tri: i32 = 0; for (tri < testrejects.len) { let tw: str = strings.concat(root, "/test-reject-", stages[si], "-", labels[tri]); assert(os.mkdir(tw, 448i32) == 0); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let tav: []str = [driver(stages[si]), "test", "-w", tw, "-I", source, testrejects[tri]]; runcommandenv(root, strings.concat("internal-test-reject-", stages[si], "-", labels[tri]), tav, env, (180i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let testdiag: str = strings.concat(testrejects[tri], testfiles[tri], ":2:1: error: use of internal package ", "domain.internal.secret not allowed\n"); assert(has(out.stderr, testdiag)); if (si == 0) { testrejectreferences[tri] = strings.dup(out.stderr); } else { assert(same(testrejectreferences[tri], out.stderr)); }; assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); tri += 1; }; let orderwork: str = strings.concat(root, "/order-work-", stages[si]); assert(os.mkdir(orderwork, 448i32) == 0); let orderforward: []str = [driver(stages[si]), "test", "-c", "-w", orderwork, "-I", source, "--ww-package-test", "production", "main", client, strings.concat(root, "/order-client-", stages[si]), strings.concat(root, "/order-client-", stages[si], ".status"), "--ww-package-test", "production", "main", outsider, strings.concat(root, "/order-outsider-", stages[si]), strings.concat(root, "/order-outsider-", stages[si], ".status"), client]; let orderreverse: []str = [driver(stages[si]), "test", "-c", "-w", orderwork, "-I", source, "--ww-package-test", "production", "main", outsider, strings.concat(root, "/order-outsider-", stages[si]), strings.concat(root, "/order-outsider-", stages[si], ".status"), "--ww-package-test", "production", "main", client, strings.concat(root, "/order-client-", stages[si]), strings.concat(root, "/order-client-", stages[si], ".status"), client]; let orderrequests: [][]str = [orderforward, orderreverse]; let orderdiags: []str = ["", ""]; let oi: i32 = 0; for (oi < 2) { rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); runcommandenv(root, strings.concat("internal-order-", stages[si], "-", labels[oi]), orderrequests[oi], env, (180i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); orderdiags[oi] = strings.dup(out.stderr); assert(same(out.stderr, wantdiag)); assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); oi += 1; }; assert(same(orderdiags[0], orderdiags[1])); if (si == 0) { orderreference = strings.dup(orderdiags[0]); } else { assert(same(orderreference, orderdiags[0])); }; si += 1; }; clean(root); }; @test fn exact_package_tool_argv_stage_parity() void = { let root: str = fresh(); let source: str = strings.concat(root, "/source tree"); let runtime: str = strings.concat(root, "/runtime library"); let baseidentity: str = longidentity("paritybase"); let leftidentity: str = longidentity("parityleft"); let rightidentity: str = longidentity("parityright"); let rootidentity: str = longidentity("paritycommand"); assert(baseidentity.len > 255 && rootidentity.len > 255); let base: str = strings.concat(source, "/", importrelative(baseidentity)); let left: str = strings.concat(source, "/", importrelative(leftidentity)); let right: str = strings.concat(source, "/", importrelative(rightidentity)); let target: str = strings.concat(source, "/", importrelative(rootidentity)); let tools: str = strings.concat(root, "/tool wrappers"); assert(os.mkdir(source, 448i32) == 0); assert(os.mkdir(runtime, 448i32) == 0); writefile(strings.concat(runtime, "/libwwrt.a"), readfile(strings.concat(repo(), "/out/lib/libwwrt.a"))); mkdirall(base); mkdirall(left); mkdirall(right); mkdirall(target); assert(os.mkdir(tools, 448i32) == 0); let basea: str = strings.concat( "package paritybase;\n", "export fn value() i32 = { return 20; };\n"); let basez: str = strings.concat( "package paritybase;\n", "fn private_value() i32 = { return 99; };\n"); let leftbody: str = strings.concat( "package parityleft;\n", "import ", baseidentity, ";\n", "export fn value() i32 = { return ", "paritybase.value(); };\n"); let leftz: str = strings.concat( "package parityleft;\n", "import ", baseidentity, ";\n", "export fn repeated_binding() i32 = { return ", "paritybase.value(); };\n"); let rightbody: str = strings.concat( "package parityright;\n", "import ", baseidentity, ";\n", "export fn value() i32 = { return ", "paritybase.value() + 1; };\n"); let rootbody: str = strings.concat( "package main;\n", "import ", rightidentity, ";\n", "import ", leftidentity, ";\n", "fn main() i32 = { return parityleft.value() + ", "parityright.value() + 1; };\n"); writefile(strings.concat(base, "/a.ww"), basea); writefile(strings.concat(base, "/z.ww"), basez); writefile(strings.concat(left, "/a.ww"), leftbody); writefile(strings.concat(left, "/z.ww"), leftz); writefile(strings.concat(right, "/right.ww"), rightbody); writefile(strings.concat(target, "/main.ww"), rootbody); let compilerwrapper: str = strings.concat(tools, "/w6c wrapper.sh"); let assemblerwrapper: str = strings.concat(tools, "/w6a wrapper.sh"); let linkerwrapper: str = strings.concat(tools, "/w6l wrapper.sh"); let failurewrapper: str = strings.concat(tools, "/failing w6c wrapper.sh"); writeexecutable(compilerwrapper, strings.concat( "#!/bin/sh\n", "printf 'BEGIN' >> \"$WW_ARGV_COMPILER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_ARGV_COMPILER_TRACE\"; done\n", "printf '\\n' >> \"$WW_ARGV_COMPILER_TRACE\"\n", "exec \"$WW_ARGV_REAL_COMPILER\" \"$@\"\n")); writeexecutable(assemblerwrapper, strings.concat( "#!/bin/sh\n", "printf 'BEGIN' >> \"$WW_ARGV_ASSEMBLER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_ARGV_ASSEMBLER_TRACE\"; done\n", "printf '\\n' >> \"$WW_ARGV_ASSEMBLER_TRACE\"\n", "exec \"$WW_ARGV_REAL_ASSEMBLER\" \"$@\"\n")); writeexecutable(linkerwrapper, strings.concat( "#!/bin/sh\n", "printf 'BEGIN' >> \"$WW_ARGV_LINKER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_ARGV_LINKER_TRACE\"; done\n", "printf '\\n' >> \"$WW_ARGV_LINKER_TRACE\"\n", "exec \"$WW_ARGV_REAL_LINKER\" \"$@\"\n")); writeexecutable(failurewrapper, strings.concat( "#!/bin/sh\n", "printf 'BEGIN' >> \"$WW_ARGV_FAILURE_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_ARGV_FAILURE_TRACE\"; done\n", "printf '\\n' >> \"$WW_ARGV_FAILURE_TRACE\"\n", "owner=\n", "for arg in \"$@\"; do if [ \"$arg\" = ", "\"$WW_ARGV_MISSING_OWNER\" ]; then owner=1; fi; done\n", "if [ -n \"$owner\" ]; then\n", " mv -- \"$WW_ARGV_MISSING_EXPORT\" ", "\"$WW_ARGV_MISSING_EXPORT.saved\" || exit 24\n", " \"$WW_ARGV_REAL_COMPILER\" \"$@\"\n", " rc=$?\n", " mv -- \"$WW_ARGV_MISSING_EXPORT.saved\" ", "\"$WW_ARGV_MISSING_EXPORT\" || exit 25\n", " exit $rc\n", "fi\n", "exec \"$WW_ARGV_REAL_COMPILER\" \"$@\"\n")); let stages: []str = ["ww", "ww", "ww_ww", "ww_ww"]; let compilers: []str = ["w6c", "w6c", "w6c_ww", "w6c_ww"]; let assemblers: []str = ["w6a", "w6a", "w6a_ww", "w6a_ww"]; let linkers: []str = ["w6l", "w6l", "w6l_ww", "w6l_ww"]; let tags: []str = ["c1", "c2", "ww1", "ww2"]; let bin: str = strings.concat(root, "/published binary"); let workroot: str = strings.concat(bin, ".sepwork"); let work: str = strings.concat(workroot, "/"); let identities: []str = [baseidentity, leftidentity, rightidentity, rootidentity]; let artifacts: []str = [packagestoragekey(baseidentity, base, 0, 0), packagestoragekey(leftidentity, left, 0, 0), packagestoragekey(rightidentity, right, 0, 0), packagestoragekey(rootidentity, target, 0, 0)]; let unitartifacts: []str = artifacts; let aki: i32 = 0; for (aki < artifacts.len) { assert(strings.hasprefix(artifacts[aki], "__wwpkg.v0.r0.h")); assert(artifacts[aki].len <= 246); aki += 1; }; let wantunits: []str = [strings.concat( "//ww:module-reset ", baseidentity, "\n", basea, "\n//ww:module-reset ", baseidentity, "\n", basez, "\n"), strings.concat("//ww:module-reset ", leftidentity, "\n", leftbody, "\n//ww:module-reset ", leftidentity, "\n", leftz, "\n"), strings.concat("//ww:module-reset ", rightidentity, "\n", rightbody, "\n"), strings.concat("//ww:module-reset ", rootidentity, "\n", rootbody, "\n")]; let referenceunits: []str = ["", "", "", ""]; let referenceexports: []str = ["", "", "", ""]; let referencearchives: []str = ["", "", "", ""]; let referencebin: str = ""; let referencecompiler: str = ""; let referenceassembler: str = ""; let referencelinker: str = ""; let referenceout: str = ""; let referenceerr: str = ""; let referencefailure: str = ""; let referencecollision: str = ""; let baseenv: []str = os.getenvs(); let si: i32 = 0; for (si < stages.len) { let compilertrace: str = strings.concat(root, "/", tags[si], " compiler trace"); let assemblertrace: str = strings.concat(root, "/", tags[si], " assembler trace"); let linkertrace: str = strings.concat(root, "/", tags[si], " linker trace"); let failuretrace: str = strings.concat(root, "/", tags[si], " failure trace"); writefile(compilertrace, ""); writefile(assemblertrace, ""); writefile(linkertrace, ""); writefile(failuretrace, ""); let env: []str = alloc([], (baseenv.len + 11): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_SRCLIB=") && !strings.hasprefix(baseenv[ei], "WW_LIB=") && !strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6A=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_ARGV_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_ARGV_ASSEMBLER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_ARGV_LINKER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_ARGV_REAL_COMPILER=") && !strings.hasprefix(baseenv[ei], "WW_ARGV_REAL_ASSEMBLER=") && !strings.hasprefix(baseenv[ei], "WW_ARGV_REAL_LINKER=") && !strings.hasprefix(baseenv[ei], "WW_ARGV_FAILURE_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_ARGV_MISSING_EXPORT=") && !strings.hasprefix(baseenv[ei], "WW_ARGV_MISSING_OWNER=")) { append(env, baseenv[ei]); }; ei += 1; }; append(env, strings.concat("WW_SRCLIB=", source)); append(env, strings.concat("WW_LIB=", runtime)); append(env, strings.concat("WW_W6C=", compilerwrapper)); append(env, strings.concat("WW_W6A=", assemblerwrapper)); append(env, strings.concat("WW_W6L=", linkerwrapper)); append(env, strings.concat("WW_ARGV_COMPILER_TRACE=", compilertrace)); append(env, strings.concat("WW_ARGV_ASSEMBLER_TRACE=", assemblertrace)); append(env, strings.concat("WW_ARGV_LINKER_TRACE=", linkertrace)); append(env, strings.concat("WW_ARGV_REAL_COMPILER=", driver(compilers[si]))); append(env, strings.concat("WW_ARGV_REAL_ASSEMBLER=", driver(assemblers[si]))); append(env, strings.concat("WW_ARGV_REAL_LINKER=", driver(linkers[si]))); let request: str = target; if (si == 1 || si == 3) { request = rootidentity; }; let av: []str = [driver(stages[si]), "build", "-o", bin, request]; let out: commandout; runcommandenv(root, strings.concat("exact-argv-", tags[si]), av, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stderr.len == 0); let ui: i32 = 0; for (ui < unitartifacts.len) { let unit: str = readfile(strings.concat(work, unitartifacts[ui], ".unit.ww")); assert(strings.hasprefix(unit, wantunits[ui])); if (ui == 1 || ui == 2) { assert(has(unit, strings.concat("//ww:direct-export ", baseidentity, " "))); } else { if (ui == 3) { assert(has(unit, strings.concat("//ww:direct-export ", leftidentity, " "))); assert(has(unit, strings.concat("//ww:direct-export ", rightidentity, " "))); }; }; assert(!has(unit, "//ww:module ")); if (si == 0) { referenceunits[ui] = strings.dup(unit); } else { assert(same(referenceunits[ui], unit)); }; ui += 1; }; let ai: i32 = 0; for (ai < artifacts.len) { let exportf: str = readfile(strings.concat(work, artifacts[ai], ".wwi")); let assembly: str = readfile(strings.concat(work, artifacts[ai], ".s")); let archive: str = readfile(strings.concat(work, artifacts[ai], ".a")); assert(strings.hasprefix(exportf, strings.concat("//ww:module ", identities[ai], "\n"))); if (ai < 3) { assert(has(assembly, strings.concat(identities[ai], ".value"))); }; if (ai == 3) { assert(has(exportf, "\npackage main;\n")); assert(!has(exportf, "\npackage paritycommand;\n")); }; if (si == 0) { referenceexports[ai] = strings.dup(exportf); referencearchives[ai] = strings.dup(archive); } else { assert(same(referenceexports[ai], exportf)); assert(same(referencearchives[ai], archive)); }; ai += 1; }; assert(os.exists(bin)); let ctrace: str = readfile(compilertrace); let atrace: str = readfile(assemblertrace); let ltrace: str = readfile(linkertrace); assert(occurrences(ctrace, "\n") == 4); let baseline: str = strings.concat( "BEGIN<--package-init-symbol><__ww..pkg.p.", baseidentity, ".v0.r0.init><-c><-I><", work, artifacts[0], ".wwi><-o><", work, artifacts[0], ".s><", work, artifacts[0], ".unit.ww>"); let leftline: str = strings.concat( "BEGIN<--package-init-symbol><__ww..pkg.p.", leftidentity, ".v0.r0.init><-c><--import>", "<", baseidentity, "><", work, artifacts[0], ".wwi><-I><", work, artifacts[1], ".wwi><-o><", work, artifacts[1], ".s><", work, artifacts[1], ".unit.ww>"); let rightline: str = strings.concat( "BEGIN<--package-init-symbol><__ww..pkg.p.", rightidentity, ".v0.r0.init><-c><--import>", "<", baseidentity, "><", work, artifacts[0], ".wwi><-I><", work, artifacts[2], ".wwi><-o><", work, artifacts[2], ".s><", work, artifacts[2], ".unit.ww>"); let rootline: str = strings.concat( "BEGIN<--entry><--package-init-symbol><__ww..pkg.p.", rootidentity, ".v0.r0.init><--init-dispatch-symbol>", "<__ww..dispatch><-c><--import>", "<", leftidentity, "><", work, artifacts[1], ".wwi><--import>", "<", rightidentity, "><", work, artifacts[2], ".wwi><-I><", work, artifacts[3], ".wwi><-o><", work, artifacts[3], ".s><", work, artifacts[3], ".unit.ww>"); assert(same(linecontaining(ctrace, strings.concat(artifacts[0], ".unit.ww")), baseline)); assert(same(linecontaining(ctrace, strings.concat(artifacts[1], ".unit.ww")), leftline)); assert(same(linecontaining(ctrace, strings.concat(artifacts[2], ".unit.ww")), rightline)); assert(same(linecontaining(ctrace, strings.concat(artifacts[3], ".unit.ww")), rootline)); assert(!has(rootline, strings.concat(artifacts[0], ".wwi"))); // Canonical owner and declared name stay independent even in a raw // package compile. --entry selects link-root code generation; it is not // permission to replace canonical owner with the declared name. let rejectwwi: str = strings.concat(root, "/reject-", tags[si], ".wwi"); let rejectasm: str = strings.concat(root, "/reject-", tags[si], ".s"); let rejectav: []str = [driver(compilers[si]), "-c", "--import", leftidentity, strings.concat(work, artifacts[1], ".wwi"), "--import", rightidentity, strings.concat(work, artifacts[2], ".wwi"), "-I", rejectwwi, "-o", rejectasm, strings.concat(work, artifacts[3], ".unit.ww")]; runcommand(root, strings.concat("command-without-entry-", tags[si]), rejectav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); assert(os.exists(rejectwwi) && os.exists(rejectasm)); let ownerrejectwwi: str = strings.concat(root, "/owner-reject-", tags[si], ".wwi"); let ownerrejectasm: str = strings.concat(root, "/owner-reject-", tags[si], ".s"); let ownerrejectav: []str = [driver(compilers[si]), "-c", "--import", leftidentity, strings.concat(work, artifacts[0], ".wwi"), "-I", ownerrejectwwi, "-o", ownerrejectasm, strings.concat(work, artifacts[1], ".unit.ww")]; runcommand(root, strings.concat("export-owner-reject-", tags[si]), ownerrejectav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(same(out.stderr, strings.concat("w6c: import ", leftidentity, ": export owner mismatch in ", work, artifacts[0], ".wwi\n"))); assert(occurrences(atrace, "\n") == 5); ai = 0; for (ai < artifacts.len) { let assemblerline: str = strings.concat("BEGIN<-o><", work, artifacts[ai], ".o><", work, artifacts[ai], ".s>"); assert(same(linecontaining(atrace, strings.concat(work, artifacts[ai], ".o")), assemblerline)); ai += 1; }; let dispatcherline: str = strings.concat("BEGIN<-o><", work, artifacts[3], ".init.o><", work, artifacts[3], ".init.s>"); assert(same(linecontaining(atrace, strings.concat(work, artifacts[3], ".init.o")), dispatcherline)); assert(occurrences(ltrace, "\n") == 1); assert(has(ltrace, strings.concat("BEGIN<-o><", bin, ".new><", work, artifacts[3], ".a>"))); ai = 0; for (ai < artifacts.len) { assert(occurrences(ltrace, strings.concat("<", work, artifacts[ai], ".a>")) == 1); ai += 1; }; assert(has(ltrace, strings.concat("<", runtime, "/libwwrt.a>"))); assert(!has(ltrace, strings.concat("<", repo(), "/out/lib/libwwrt.a>"))); assert(!has(ltrace, ".wwi>")); let runav: []str = [bin]; runcommand(root, strings.concat("exact-argv-run-", tags[si]), runav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 42); assert(out.stdout.len == 0 && out.stderr.len == 0); if (si == 0) { referencebin = strings.dup(readfile(bin)); referencecompiler = strings.dup(ctrace); referenceassembler = strings.dup(atrace); referencelinker = strings.dup(ltrace); referenceout = strings.dup(out.stdout); referenceerr = strings.dup(out.stderr); } else { assert(same(referencebin, readfile(bin))); assert(same(referencecompiler, ctrace)); assert(same(referenceassembler, atrace)); assert(same(referencelinker, ltrace)); assert(same(referenceout, out.stdout)); assert(same(referenceerr, out.stderr)); }; // Select the same long ordinary directory as both an explicit product // root and the dependency of another product in one command. Then build // it alone through logical and literal spellings. All routes must intern // one production action and emit the dependency-built bytes above. let combinedbase: str = strings.concat(root, "/combined-base-", tags[si]); let combinedleft: str = strings.concat(root, "/combined-left-", tags[si]); let combinedbasestatus: str = strings.concat(combinedbase, ".status"); let combinedleftstatus: str = strings.concat(combinedleft, ".status"); clean(compilertrace); writefile(compilertrace, ""); clean(assemblertrace); writefile(assemblertrace, ""); clean(linkertrace); writefile(linkertrace, ""); let combinedav: []str = [driver(stages[si]), "test", "-c", "-I", source, "--ww-package-test", "production", "paritybase", base, combinedbase, combinedbasestatus, "--ww-package-test", "production", "parityleft", left, combinedleft, combinedleftstatus, left]; runcommandenv(root, strings.concat("long-combined-", tags[si]), combinedav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let combinedtrace: str = readfile(compilertrace); assert(occurrences(combinedtrace, strings.concat(artifacts[0], ".unit.ww>")) == 1); let combinedwork: str = strings.concat(combinedbase, ".sepwork/"); let combinedunit: str = readfile(strings.concat(combinedwork, artifacts[0], ".unit.ww")); let combinedwwi: str = readfile(strings.concat(combinedwork, artifacts[0], ".wwi")); let combinedarchive: str = readfile(strings.concat(combinedwork, artifacts[0], ".a")); assert(same(referenceunits[0], combinedunit)); assert(same(referenceexports[0], combinedwwi)); assert(same(referencearchives[0], combinedarchive)); let rootspellings: []str = [baseidentity, base]; let rootlabels: []str = ["logical", "literal"]; let ri: i32 = 0; for (ri < rootspellings.len) { let rootout: str = strings.concat(root, "/long-root-", rootlabels[ri], "-", tags[si], ".a"); clean(compilertrace); writefile(compilertrace, ""); let rootav: []str = [driver(stages[si]), "build", "-I", source, "-o", rootout, rootspellings[ri]]; runcommandenv(root, strings.concat("long-root-", rootlabels[ri], "-", tags[si]), rootav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(occurrences(readfile(compilertrace), strings.concat( artifacts[0], ".unit.ww>")) == 1); let rootwork: str = strings.concat(rootout, ".sepwork/"); assert(same(combinedunit, readfile(strings.concat(rootwork, artifacts[0], ".unit.ww")))); assert(same(combinedwwi, readfile(strings.concat(rootwork, artifacts[0], ".wwi")))); assert(same(combinedarchive, readfile(strings.concat(rootwork, artifacts[0], ".a")))); clean(strings.concat(rootout, ".sepwork")); clean(rootout); clean(strings.concat(rootout, ".wwi")); ri += 1; }; clean(strings.concat(combinedbase, ".sepwork")); clean(combinedbase); clean(combinedleft); clean(combinedbasestatus); clean(combinedleftstatus); let seedav: []str = [driver(stages[si]), "build", "-w", workroot, "-o", bin, request]; runcommandenv(root, strings.concat("persistent-seed-", tags[si]), seedav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(os.remove(compilertrace) == 0); assert(os.remove(assemblertrace) == 0); writefile(compilertrace, ""); writefile(assemblertrace, ""); let equivalent: str = rootidentity; if (same(request, rootidentity)) { equivalent = target; }; let warmav: []str = [driver(stages[si]), "build", "-w", workroot, "-o", bin, equivalent]; runcommandenv(root, strings.concat("persistent-equivalent-", tags[si]), warmav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(readfile(compilertrace).len == 0); assert(readfile(assemblertrace).len == 0); let baseafile: str = strings.concat(base, "/a.ww"); assert(os.remove(baseafile) == 0); writefile(baseafile, strings.concat(basea, "export fn marker() i32 = { return 7; };\n")); runcommandenv(root, strings.concat("persistent-export-", tags[si]), warmav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let changedtrace: str = readfile(compilertrace); assert(occurrences(changedtrace, "\n") == 3); assert(has(changedtrace, strings.concat(artifacts[0], ".unit.new"))); assert(has(changedtrace, strings.concat(artifacts[1], ".unit.new"))); assert(has(changedtrace, strings.concat(artifacts[2], ".unit.new"))); assert(!has(changedtrace, strings.concat(artifacts[3], ".unit.new"))); let badunit: str = strings.concat(work, artifacts[0], ".unit.ww"); assert(os.remove(badunit) == 0); writefile(badunit, "//ww:module-reset wrong.owner\n"); assert(os.remove(compilertrace) == 0); assert(os.remove(assemblertrace) == 0); assert(os.remove(linkertrace) == 0); writefile(compilertrace, ""); writefile(assemblertrace, ""); writefile(linkertrace, ""); let collisionav: []str = [driver(stages[si]), "build", "-w", workroot, "-o", bin, request]; runcommandenv(root, strings.concat("storage-owner-", tags[si]), collisionav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let collisiondiag: str = strings.concat( "ww: package storage owner mismatch at ", artifacts[0], " for ", baseidentity, "\n"); assert(same(out.stderr, collisiondiag)); assert(readfile(compilertrace).len == 0); assert(readfile(assemblertrace).len == 0); assert(readfile(linkertrace).len == 0); if (si == 0) { referencecollision = strings.dup(out.stderr); } else { assert(same(referencecollision, out.stderr)); }; assert(os.remove(baseafile) == 0); writefile(baseafile, basea); clean(workroot); clean(bin); let failenv: []str = alloc([], (env.len + 4): u64)!; ei = 0; for (ei < env.len) { if (!strings.hasprefix(env[ei], "WW_W6C=") && !strings.hasprefix(env[ei], "WW_ARGV_FAILURE_TRACE=")) { append(failenv, env[ei]); }; ei += 1; }; append(failenv, strings.concat("WW_W6C=", failurewrapper)); append(failenv, strings.concat("WW_ARGV_FAILURE_TRACE=", failuretrace)); append(failenv, strings.concat("WW_ARGV_MISSING_EXPORT=", work, artifacts[0], ".wwi")); append(failenv, strings.concat("WW_ARGV_MISSING_OWNER=", work, artifacts[1], ".unit.ww")); runcommandenv(root, strings.concat("exact-argv-fail-", tags[si]), av, failenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let wantfailure: str = strings.concat( "w6c: import ", baseidentity, ": cannot read ", work, artifacts[0], ".wwi\n", "ww: w6c failed for ", leftidentity, "\n"); assert(same(out.stderr, wantfailure)); assert(has(readfile(failuretrace), strings.concat( "<--import><", baseidentity, "><", work, artifacts[0], ".wwi>"))); if (si == 0) { referencefailure = strings.dup(out.stderr); } else { assert(same(referencefailure, out.stderr)); }; clean(workroot); if (os.exists(bin)) { clean(bin); }; si += 1; }; clean(root); }; @test fn command_package_test_variants_keep_canonical_identity() void = { let root: str = fresh(); let source: str = strings.concat(root, "/source"); let commandid: str = longidentity("cmdtool"); assert(commandid.len > 255); let target: str = strings.concat(source, "/", importrelative(commandid)); let importer: str = strings.concat(source, "/importer"); let wrapper: str = strings.concat(root, "/command-w6c.sh"); assert(os.mkdir(source, 448i32) == 0); mkdirall(target); assert(os.mkdir(importer, 448i32) == 0); writefile(strings.concat(target, "/main.ww"), strings.concat( "package main;\n", "export fn value() i32 = { return 41; };\n", "fn main() i32 = { return 0; };\n")); writefile(strings.concat(target, "/internal_test.ww"), strings.concat( "package main;\n", "@test fn command_internal() void = { assert(value() == 41); };\n")); writefile(strings.concat(target, "/external_test.ww"), strings.concat( "package main_test;\n", "import ", commandid, ";\n", "@test fn command_external() void = { ", "assert(main.value() == 41); };\n")); writefile(strings.concat(importer, "/importer.ww"), strings.concat( "package importer;\n", "import ", commandid, ";\n", "export fn value() i32 = { return main.value(); };\n")); writeexecutable(wrapper, strings.concat( "#!/bin/sh\n", "printf 'BEGIN' >> \"$WW_COMMAND_COMPILER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_COMMAND_COMPILER_TRACE\"; done\n", "printf '\\n' >> \"$WW_COMMAND_COMPILER_TRACE\"\n", "exec \"$WW_COMMAND_REAL_COMPILER\" \"$@\"\n")); let stages: []str = ["ww", "ww_ww"]; let compilers: []str = ["w6c", "w6c_ww"]; let internalid: str = commandid; let externalid: str = strings.concat(commandid, "_test"); let internalmainid: str = strings.concat("__wwtestmain.", commandid, ".internal.main"); let externalmainid: str = strings.concat("__wwtestmain.", externalid, ".external.main"); let actionids: []str = [commandid, internalid, externalid, internalmainid, externalmainid]; let artifacts: []str = [packagestoragekey(commandid, target, 0, 0), packagestoragekey(internalid, target, 1, 0), packagestoragekey(externalid, target, 2, 0), packagestoragekey(internalmainid, strings.concat(target, "#internal-test-main"), 3, 2), packagestoragekey(externalmainid, strings.concat(target, "#external-test-main"), 3, 2)]; let suffixes: []str = [".unit.ww", ".wwi", ".a"]; let reference: []str = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]; let samebin: str = strings.concat(target, "/main.test"); let externalbin: str = strings.concat(target, "/main_test.test"); let baseenv: []str = os.getenvs(); let si: i32 = 0; for (si < stages.len) { let workroot: str = strings.concat(root, "/command-work-", stages[si]); assert(os.mkdir(workroot, 448i32) == 0); let work: str = strings.concat(workroot, "/"); let trace: str = strings.concat(root, "/", stages[si], ".trace"); writefile(trace, ""); let env: []str = alloc([], (baseenv.len + 3): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_COMMAND_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_COMMAND_REAL_COMPILER=")) { append(env, baseenv[ei]); }; ei += 1; }; append(env, strings.concat("WW_W6C=", wrapper)); append(env, strings.concat("WW_COMMAND_COMPILER_TRACE=", trace)); append(env, strings.concat("WW_COMMAND_REAL_COMPILER=", driver(compilers[si]))); let av: []str = [driver(stages[si]), "test", "-w", workroot, "-I", source, target]; let out: commandout; runcommandenv(root, strings.concat("command-variants-", stages[si]), av, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stderr.len == 0); assert(has(out.stdout, "main.command_internal ... ok\n")); assert(has(out.stdout, "main_test.command_external ... ok\n")); let ctrace: str = readfile(trace); let ai: i32 = 0; for (ai < artifacts.len) { let line: str = linecontaining(ctrace, strings.concat(artifacts[ai], ".unit.new")); if (ai < 3) { assert(has(line, "<--command-package>")); } else { assert(has(line, "<-T><--entry>")); }; let sj: i32 = 0; for (sj < suffixes.len) { let body: str = readfile(strings.concat(work, artifacts[ai], suffixes[sj])); if (sj == 0) { assert(has(body, strings.concat("//ww:module-reset ", actionids[ai], "\n"))); } else { if (sj == 1) { assert(strings.hasprefix(body, strings.concat("//ww:module ", actionids[ai], "\n"))); }; }; let ri: i32 = ai * suffixes.len + sj; if (si == 0) { reference[ri] = strings.dup(body); } else { assert(same(reference[ri], body)); }; sj += 1; }; ai += 1; }; let externalline: str = linecontaining(ctrace, strings.concat(artifacts[2], ".unit.new")); assert(has(externalline, strings.concat("<--import><", commandid, "><", work, artifacts[0], ".wwi.new>"))); let internalmainline: str = linecontaining(ctrace, strings.concat(artifacts[3], ".unit.new")); let externalmainline: str = linecontaining(ctrace, strings.concat(artifacts[4], ".unit.new")); assert(has(internalmainline, strings.concat("<--import><", internalid, "><", work, artifacts[1], ".wwi.new>"))); assert(has(internalmainline, strings.concat( "<--test-target-package><", internalid, ">"))); assert(has(externalmainline, strings.concat("<--import><", externalid, "><", work, artifacts[2], ".wwi.new>"))); assert(has(externalmainline, strings.concat( "<--test-target-package><", externalid, ">"))); assert(occurrences(ctrace, strings.concat("<", work, artifacts[0], ".unit.new>")) == 1); assert(has(readfile(strings.concat(work, artifacts[0], ".s")), strings.concat(commandid, ".value"))); assert(has(readfile(strings.concat(work, artifacts[1], ".s")), strings.concat(commandid, ".command_internal"))); assert(has(readfile(strings.concat(work, artifacts[2], ".s")), strings.concat(externalid, ".command_external"))); let warmrefs: []str = alloc([], reference.len: u64)!; warmrefs.len = reference.len; ai = 0; for (ai < artifacts.len) { let sj: i32 = 0; for (sj < suffixes.len) { warmrefs[ai * suffixes.len + sj] = strings.dup(readfile( strings.concat(work, artifacts[ai], suffixes[sj]))); sj += 1; }; ai += 1; }; runcommandenv(root, strings.concat("command-warm-", stages[si]), av, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "main.command_internal ... ok\n")); assert(has(out.stdout, "main_test.command_external ... ok\n")); assert(same(ctrace, readfile(trace))); ai = 0; for (ai < artifacts.len) { let sj: i32 = 0; for (sj < suffixes.len) { assert(same(warmrefs[ai * suffixes.len + sj], readfile( strings.concat(work, artifacts[ai], suffixes[sj])))); sj += 1; }; ai += 1; }; // The same command action is not generally source-importable. It is // classified from its declaration so this Go-like diagnostic is stable, // and graph failure occurs before any compiler invocation. clean(trace); writefile(trace, ""); let importout: str = strings.concat(root, "/importer-", stages[si], ".a"); let importav: []str = [driver(stages[si]), "build", "-I", source, "-o", importout, importer]; runcommandenv(root, strings.concat("command-import-", stages[si]), importav, env, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, strings.concat("package ", commandid, " is a program, not an importable package\n"))); assert(readfile(trace).len == 0); clean(workroot); clean(samebin); clean(externalbin); si += 1; }; clean(root); }; @test fn package_graph_diagnostics_are_stable() void = { let root: str = fresh(); let missing: str = strings.concat(root, "/missing"); let cycle: str = strings.concat(root, "/cycle"); let left: str = strings.concat(root, "/left"); let right: str = strings.concat(root, "/right"); let conflict: str = strings.concat(root, "/conflict"); let privatepkg: str = strings.concat(root, "/privatepkg"); let identityroot: str = strings.concat(root, "/identityroot"); let identityactual: str = strings.concat(root, "/identityactual"); let identityalias: str = strings.concat(root, "/identityalias"); let reserved: str = strings.concat(root, "/reservedprobe"); assert(os.mkdir(missing, 448i32) == 0); assert(os.mkdir(cycle, 448i32) == 0); assert(os.mkdir(left, 448i32) == 0); assert(os.mkdir(right, 448i32) == 0); assert(os.mkdir(conflict, 448i32) == 0); assert(os.mkdir(privatepkg, 448i32) == 0); assert(os.mkdir(identityroot, 448i32) == 0); assert(os.mkdir(identityactual, 448i32) == 0); assert(os.mkdir(reserved, 448i32) == 0); writefile(strings.concat(missing, "/missing.ww"), "package missing;\nfn local() void = { };\n"); writefile(strings.concat(missing, "/missing_test.ww"), strings.concat( "package missing;\nimport nowhere;\n", "@test fn missing_import() void = { };\n")); writefile(strings.concat(cycle, "/cycle.ww"), "package cycle;\nfn local() void = { };\n"); writefile(strings.concat(cycle, "/cycle_test.ww"), strings.concat( "package cycle;\nimport left;\n", "@test fn cycle_import() void = { };\n")); writefile(strings.concat(left, "/left.ww"), "package left;\nimport right;\nexport fn v() i32 = { return right.v(); };\n"); writefile(strings.concat(right, "/right.ww"), "package right;\nimport left;\nexport fn v() i32 = { return left.v(); };\n"); writefile(strings.concat(conflict, "/a.ww"), "package conflict;\nfn a() void = { };\n"); writefile(strings.concat(conflict, "/z.ww"), "package other;\nfn z() void = { };\n"); writefile(strings.concat(conflict, "/conflict_test.ww"), "package conflict;\n@test fn conflict_name() void = { };\n"); writefile(strings.concat(privatepkg, "/a.ww"), strings.concat( "package privatepkg;\n", "export fn shown() i32 = { return 1; };\n")); writefile(strings.concat(privatepkg, "/z.ww"), "package privatepkg;\nfn hidden() i32 = { return 2; };\n"); writefile(strings.concat(privatepkg, "/external_test.ww"), strings.concat( "package privatepkg_test;\nimport privatepkg;\n", "@test fn private_use() void = { assert(privatepkg.hidden() == 2); };\n")); writefile(strings.concat(identityactual, "/identityactual.ww"), "package identityactual;\nexport fn value() i32 = { return 1; };\n"); let linkout: commandout; let linkav: []str = ["/bin/ln", "-s", identityactual, identityalias]; runcommand(root, "identity-alias", linkav, time.second, &linkout); expectexit(&linkout, 0); writefile(strings.concat(identityroot, "/identityroot.ww"), strings.concat( "package identityroot;\nimport identityactual;\n", "import identityalias;\nexport fn value() i32 = { return 1; };\n")); writefile(strings.concat(reserved, "/reservedprobe.ww"), strings.concat( "package reservedprobe;\nimport __wwlocal.fake;\n", "export fn value() i32 = { return 1; };\n")); rejectpackagestable(root, "missing", missing, "cannot find package nowhere"); rejectpackagestable(root, "cycle", cycle, "ww: dependency cycle:"); rejectpackagestable(root, "conflict", conflict, "conflicting package names conflict and other"); rejectpackagestable(root, "private", privatepkg, "package 'privatepkg' has no exported declaration 'hidden'"); let stages: []str = ["ww", "ww_ww"]; let tooltrace: str = strings.concat(root, "/identity-tool.trace"); let compilerwrapper: str = strings.concat(root, "/identity-w6c.sh"); let linkerwrapper: str = strings.concat(root, "/identity-w6l.sh"); writefile(tooltrace, ""); writeexecutable(compilerwrapper, strings.concat( "#!/bin/sh\nprintf 'compile\\n' >> \"$WW_IDENTITY_TRACE\"\n", "exec \"$WW_IDENTITY_W6C\" \"$@\"\n")); writeexecutable(linkerwrapper, strings.concat( "#!/bin/sh\nprintf 'link\\n' >> \"$WW_IDENTITY_TRACE\"\n", "exec \"$WW_IDENTITY_W6L\" \"$@\"\n")); let baseenv: []str = os.getenvs(); let traceenv: []str = alloc([], (baseenv.len + 5): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_IDENTITY_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_IDENTITY_W6C=") && !strings.hasprefix(baseenv[ei], "WW_IDENTITY_W6L=")) { append(traceenv, baseenv[ei]); }; ei += 1; }; append(traceenv, strings.concat("WW_W6C=", compilerwrapper)); append(traceenv, strings.concat("WW_W6L=", linkerwrapper)); append(traceenv, strings.concat("WW_IDENTITY_TRACE=", tooltrace)); append(traceenv, strings.concat("WW_IDENTITY_W6C=", driver("w6c"))); append(traceenv, strings.concat("WW_IDENTITY_W6L=", driver("w6l"))); let out: commandout; let i: i32 = 0; let identitydiagnostics: []str = ["", ""]; i = 0; for (i < stages.len) { let av: []str = [driver(stages[i]), "build", "-I", root, "-o", strings.concat(root, "/bad-identity-", stages[i], ".a"), identityroot]; runcommandenv(root, strings.concat("duplicate-directory-identity-", stages[i]), av, traceenv, (60i64 * (time.second: i64)): time.duration, &out); assert(out.termination == exec.termination.EXIT && out.code != 0); assert(has(out.stderr, strings.concat("ww: package directory ", identityactual, " has import identities identityactual and ", "identityalias\n"))); identitydiagnostics[i] = strings.dup(out.stderr); i += 1; }; assert(same(identitydiagnostics[0], identitydiagnostics[1])); // A canonical directory acquiring two import identities rejects before // compiler or linker invocation. The converse is covered by the shared // multi-context resolution test above. assert(readfile(tooltrace).len == 0); let reserveddiagnostics: []str = ["", ""]; i = 0; for (i < stages.len) { let av: []str = [driver(stages[i]), "build", "-I", root, "-o", strings.concat(root, "/bad-reserved-", stages[i], ".a"), reserved]; runcommandenv(root, strings.concat("reserved-local-import-", stages[i]), av, traceenv, (60i64 * (time.second: i64)): time.duration, &out); assert(out.termination == exec.termination.EXIT && out.code != 0); assert(has(out.stderr, "package path __wwlocal.fake is reserved")); reserveddiagnostics[i] = strings.dup(primarydiagnostic(out.stderr)); i += 1; }; assert(same(reserveddiagnostics[0], reserveddiagnostics[1])); assert(readfile(tooltrace).len == 0); clean(root); }; // Invalid @test attribute shapes reject at build with stable text on // BOTH frontends (the -T synth checker owns them; the fixture corpus // cannot reach -T, so these rows live here). Fragments only — the // stages' error-line prefixes legitimately differ (file:line:col vs // file:). @test fn invalid_test_shapes_reject() void = { let root: str = fresh(); let shapes: []str = [ "@test export fn t() void = { };", "@test fn t() void;", "@test fn t(x: i32) void = { };", "@test fn t() i32 = { return 0; };", "@test @test fn t() void = { };", ]; let frags: []str = [ "@test fn 't' cannot be exported", "@test fn 't' needs a body", "@test fn 't' must be fn() void", "@test fn 't' must be fn() void", "duplicate @test on fn 't'", ]; let digits: []str = ["0", "1", "2", "3", "4"]; let outc: commandout; let outw: commandout; let i: i32 = 0; for (i < shapes.len) { let dir: str = strings.concat(root, "/shape", digits[i]); assert(os.mkdir(dir, 448i32) == 0); let src: str = strings.concat(dir, "/bad_test.ww"); writefile(src, strings.concat("package main;\n", shapes[i], "\n")); let avc: []str = [driver("ww"), "test", src]; let avw: []str = [driver("ww_ww"), "test", src]; runcommand(root, strings.concat("shape-c", digits[i]), avc, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, strings.concat("shape-ww", digits[i]), avw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(has(outc.stderr, frags[i])); assert(has(outw.stderr, frags[i])); i += 1; }; clean(root); }; // Go's local-pattern parity: "..." walks below the prefix preceding its first // occurrence. Dot-, underscore-, and testdata-prefixed trees are excluded; // vendor is traversed but a wildcard cannot consume a non-terminal vendor. // Excluded sentinels fail so a wrong descent turns the whole run red. @test fn recursive_tree_discovery() void = { let root: str = fresh(); let tree: str = strings.concat(root, "/tree"); assert(os.mkdir(tree, 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/alpha"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/beta"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/beta/inner"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/gamma"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/app"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/app/vendor"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/app/vendor/lib"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/app/vendor/lib/math"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/domain"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/domain/app"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/domain/vendor"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/domain/vendor/dep"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/.hidden"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/.hidden/deep"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/_skip"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/testdata"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/testdata/bad"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/vendor"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/vendor/bad"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/vendor/bad/vendor"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/vendor/bad/vendor/deep"), 448i32) == 0); assert(os.mkdir(strings.concat(tree, "/vendorx"), 448i32) == 0); writefile(strings.concat(tree, "/a.ww"), "package rootpkg;\nfn first() i32 = { return 1; };\n"); writefile(strings.concat(tree, "/root_test.ww"), strings.concat( "package rootpkg;\n", "@test fn treeroot() void = { assert(first() + last() == 3); };\n")); writefile(strings.concat(tree, "/z.ww"), "package rootpkg;\nfn last() i32 = { return 2; };\n"); writefile(strings.concat(tree, "/alpha/alpha.ww"), "package alpha;\nexport fn value() int = { return 7; };\n"); writefile(strings.concat(tree, "/alpha/alpha_test.ww"), strings.concat("package alpha_test;\nimport alpha;\n", "@test fn treealpha() void = { assert(alpha.value() == 7);", " assert(alpha.linked() == 11); };\n")); writefile(strings.concat(tree, "/beta/inner/inner_test.ww"), "package inner;\n@test fn treeinner() void = { assert(1 == 1); };\n"); writefile(strings.concat(tree, "/gamma/gamma.ww"), "package gamma;\nexport fn g() int = { return 1; };\n"); writefile(strings.concat(tree, "/app/app.ww"), strings.concat( "package app;\nimport lib.math;\n", "export fn value() int = { return math.value(); };\n")); writefile(strings.concat(tree, "/app/app_test.ww"), strings.concat( "package app;\n@test fn vendored_dependency() void = {", " assert(value() == 17); };\n")); writefile(strings.concat(tree, "/app/vendor/lib/math/math.ww"), "package math;\nexport fn value() int = { return 17; };\n"); writefile(strings.concat(tree, "/domain/app/app.ww"), strings.concat( "package app;\nimport dep;\n", "fn value() int = { return dep.value(); };\n")); writefile(strings.concat(tree, "/domain/app/app_test.ww"), strings.concat( "package app;\n@test fn ancestor_vendor() void = {", " assert(value() == 29); };\n")); writefile(strings.concat(tree, "/domain/vendor/dep/dep.ww"), "package dep;\nexport fn value() int = { return 29; };\n"); writefile(strings.concat(tree, "/gamma/.ignored.ww"), "this hidden source must not make package loading fail\n"); writefile(strings.concat(tree, "/gamma/_ignored.ww"), "this underscore source must not make package loading fail\n"); writefile(strings.concat(tree, "/.hidden/hid_test.ww"), "package hid;\n@test fn hidden_direct() void = { assert(true); };\n"); writefile(strings.concat(tree, "/.hidden/deep/bad.ww"), "this excluded malformed directory must not be selected\n"); writefile(strings.concat(tree, "/_skip/skip_test.ww"), "package _skip;\n@test fn underscore_direct() void = { assert(true); };\n"); writefile(strings.concat(tree, "/testdata/bad/bad_test.ww"), "package bad;\n@test fn testdata_direct() void = { assert(true); };\n"); writefile(strings.concat(tree, "/vendor/vendor.ww"), "package vendor;\nexport fn value() int = { return 1; };\n"); writefile(strings.concat(tree, "/vendor/bad/bad.ww"), "package bad;\nexport fn value() int = { return 2; };\n"); writefile(strings.concat(tree, "/vendor/bad/bad_test.ww"), "package bad;\n@test fn explicit_vendor() void = { assert(value() == 2); };\n"); writefile(strings.concat(tree, "/vendor/bad/vendor/deep/deep_test.ww"), "package deep;\n@test fn nested_vendor_must_not_run() void = { assert(false); };\n"); writefile(strings.concat(tree, "/vendorx/vendorx.ww"), "package vendorx;\nexport fn value() int = { return 3; };\n"); let outside: str = strings.concat(root, "/outside"); let alias: str = strings.concat(root, "/tree-alias"); assert(os.mkdir(outside, 448i32) == 0); writefile(strings.concat(outside, "/outside.ww"), "package outside;\nexport fn value() int = { return 23; };\n"); writefile(strings.concat(outside, "/outside_test.ww"), strings.concat( "package outside;\n@test fn explicit_root_symlink() void = {", " assert(value() == 23); };\n")); let linkout: commandout; let linkedsource: str = strings.concat(root, "/alpha-linked-source"); writefile(linkedsource, "package alpha;\nexport fn linked() int = { return 11; };\n"); let linkedav: []str = ["/bin/ln", "-s", linkedsource, strings.concat(tree, "/alpha/linked.ww")]; runcommand(root, "recursive-source-link", linkedav, time.second, &linkout); expectexit(&linkout, 0); let linkeddirectory: str = strings.concat(root, "/source-directory"); assert(os.mkdir(linkeddirectory, 448i32) == 0); let linkeddirav: []str = ["/bin/ln", "-s", linkeddirectory, strings.concat(tree, "/alpha/directory.ww")]; runcommand(root, "recursive-source-directory-link", linkeddirav, time.second, &linkout); expectexit(&linkout, 0); let aliasav: []str = ["/bin/ln", "-s", tree, alias]; runcommand(root, "recursive-root-alias", aliasav, time.second, &linkout); expectexit(&linkout, 0); let escapeav: []str = ["/bin/ln", "-s", outside, strings.concat(tree, "/escape")]; runcommand(root, "recursive-child-escape", escapeav, time.second, &linkout); expectexit(&linkout, 0); let cycleav: []str = ["/bin/ln", "-s", tree, strings.concat(tree, "/cycle")]; runcommand(root, "recursive-child-cycle", cycleav, time.second, &linkout); expectexit(&linkout, 0); let spec: str = strings.concat(tree, "/..."); let outc: commandout; let outw: commandout; let treec: []str = [driver("ww"), "test", "-I", tree, spec]; let treew: []str = [driver("ww_ww"), "test", "-I", tree, spec]; runcommand(root, "tree-c", treec, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-ww", treew, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); let seq: str = strings.dup(outc.stdout); // A directory -o publishes every selected command by directory basename. // Non-command production roots remain graph roots but have no named output. let commands: str = strings.concat(root, "/commands"); let commandalpha: str = strings.concat(commands, "/cmd-alpha"); let commandzeta: str = strings.concat(commands, "/cmd-zeta"); let commandlib: str = strings.concat(commands, "/library"); assert(os.mkdir(commands, 448i32) == 0); assert(os.mkdir(commandalpha, 448i32) == 0); assert(os.mkdir(commandzeta, 448i32) == 0); assert(os.mkdir(commandlib, 448i32) == 0); writefile(strings.concat(commandalpha, "/main.ww"), strings.concat( "package main;\nimport library;\n", "fn main() i32 = { return library.value(); };\n")); writefile(strings.concat(commandzeta, "/main.ww"), "package main;\nfn main() i32 = { return 0; };\n"); writefile(strings.concat(commandlib, "/library.ww"), "package library;\nexport fn value() i32 = { return 0; };\n"); let commandalias: str = strings.concat(root, "/commands-alias"); let commandaliasav: []str = ["/bin/ln", "-s", commands, commandalias]; runcommand(root, "recursive-command-alias", commandaliasav, time.second, &linkout); expectexit(&linkout, 0); let dashselector: str = "-dash-command"; let dashselectorpath: str = strings.concat(root, "/", dashselector); let dashselectorav: []str = ["/bin/ln", "-s", commandalpha, dashselectorpath]; runcommand(root, "recursive-dash-selector", dashselectorav, time.second, &linkout); expectexit(&linkout, 0); let commandalphaid: str = localidentity(commandalpha, "main"); let commandzetaid: str = localidentity(commandzeta, "main"); let binc: str = strings.concat(root, "/bin-c"); let binw: str = strings.concat(root, "/bin-ww"); let reversebinc: str = strings.concat(root, "/reverse-bin-c"); let reversebinw: str = strings.concat(root, "/reverse-bin-ww"); assert(os.mkdir(binc, 448i32) == 0); assert(os.mkdir(binw, 448i32) == 0); let commandspec: str = strings.concat(commands, "/..."); let commandaliasspec: str = strings.concat(commandalias, "/..."); let commandworks: []str = [strings.concat(root, "/command-work-c"), strings.concat(root, "/command-work-ww")]; let commandreverseworks: []str = [strings.concat(root, "/command-reverse-work-c"), strings.concat(root, "/command-reverse-work-ww")]; let commandbins: []str = [binc, binw]; let commandreversebins: []str = [reversebinc, reversebinw]; let commandreverseoutputs: []str = [strings.concat(reversebinc, "/"), strings.concat(reversebinw, "/")]; let commandcompilertraces: []str = [strings.concat(root, "/command-compiler-c"), strings.concat(root, "/command-compiler-ww")]; let commandassemblertraces: []str = [strings.concat(root, "/command-assembler-c"), strings.concat(root, "/command-assembler-ww")]; let commandlinkertraces: []str = [strings.concat(root, "/command-linker-c"), strings.concat(root, "/command-linker-ww")]; let commandasmworks: []str = [strings.concat(root, "/asm-work-c"), strings.concat(root, "/asm-work-ww")]; let commandtools: str = strings.concat(root, "/command-tools"); assert(os.mkdir(commandtools, 448i32) == 0); let commandcompilerwrapper: str = strings.concat(commandtools, "/w6c.sh"); let commandassemblerwrapper: str = strings.concat(commandtools, "/w6a.sh"); let commandlinkerwrapper: str = strings.concat(commandtools, "/w6l.sh"); writeexecutable(commandcompilerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PATTERN_COMPILER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_PATTERN_COMPILER_TRACE\"; done\n", "printf '\\n' >> \"$WW_PATTERN_COMPILER_TRACE\"\n", "exec \"$WW_PATTERN_REAL_COMPILER\" \"$@\"\n")); writeexecutable(commandassemblerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PATTERN_ASSEMBLER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_PATTERN_ASSEMBLER_TRACE\"; done\n", "printf '\\n' >> \"$WW_PATTERN_ASSEMBLER_TRACE\"\n", "exec \"$WW_PATTERN_REAL_ASSEMBLER\" \"$@\"\n")); writeexecutable(commandlinkerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_PATTERN_LINKER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_PATTERN_LINKER_TRACE\"; done\n", "printf '\\n' >> \"$WW_PATTERN_LINKER_TRACE\"\n", "exec \"$WW_PATTERN_REAL_LINKER\" \"$@\"\n")); let collisions: str = strings.concat(root, "/collisions"); let collisionleft: str = strings.concat(collisions, "/left"); let collisionright: str = strings.concat(collisions, "/right"); let collisionleftcmd: str = strings.concat(collisionleft, "/same"); let collisionrightcmd: str = strings.concat(collisionright, "/same"); assert(os.mkdir(collisions, 448i32) == 0); assert(os.mkdir(collisionleft, 448i32) == 0); assert(os.mkdir(collisionright, 448i32) == 0); assert(os.mkdir(collisionleftcmd, 448i32) == 0); assert(os.mkdir(collisionrightcmd, 448i32) == 0); writefile(strings.concat(collisionleftcmd, "/main.ww"), "package main;\nfn main() i32 = { return 0; };\n"); writefile(strings.concat(collisionrightcmd, "/main.ww"), "package main;\nfn main() i32 = { return 0; };\n"); let collisionspec: str = strings.concat(collisions, "/..."); let collisionout: str = strings.concat(root, "/collision-bin"); assert(os.mkdir(collisionout, 448i32) == 0); let collisionworks: []str = [strings.concat(root, "/collision-work-c"), strings.concat(root, "/collision-work-ww")]; let commandstages: []str = ["ww", "ww_ww"]; let commandcompilers: []str = ["w6c", "w6c_ww"]; let commandassemblers: []str = ["w6a", "w6a_ww"]; let commandlinkers: []str = ["w6l", "w6l_ww"]; let commandbaseenv: []str = os.getenvs(); let referencecommandcompiler: str = ""; let referencecommandassembler: str = ""; let referencecommandlinker: str = ""; let referenceasmcompiler: str = ""; let referenceasmrejectdiag: str = ""; let referencecollisiondiag: str = ""; let referencefanoutpathdiag: str = ""; let referencescratchpathdiag: str = ""; let referenceworkpathdiag: str = ""; // Raw -o/-w spellings still fit the public PATH_MAX contract. The // directory fan-out, cold scratch, and persistent tool-record spellings // derived from them do not, and must be rejected before any producer. let longoutputbytes: []u8 = alloc([], os.PATH_MAX: u64)!; let longpathi: i32 = 0; for (longpathi < root.len) { append(longoutputbytes, root[longpathi]); longpathi += 1; }; append(longoutputbytes, '/': u8); for (longoutputbytes.len < os.PATH_MAX - 2) { append(longoutputbytes, 'o': u8); }; append(longoutputbytes, '/': u8); assert(longoutputbytes.len == os.PATH_MAX - 1); let longoutputdir: str = strings.frombytes(longoutputbytes); let longscratchbytes: []u8 = alloc([], os.PATH_MAX: u64)!; longpathi = 0; for (longpathi < root.len) { append(longscratchbytes, root[longpathi]); longpathi += 1; }; append(longscratchbytes, '/': u8); for (longscratchbytes.len < os.PATH_MAX - 1) { append(longscratchbytes, 's': u8); }; assert(longscratchbytes.len == os.PATH_MAX - 1); let longscratchout: str = strings.frombytes(longscratchbytes); let longworkbytes: []u8 = alloc([], os.PATH_MAX: u64)!; longpathi = 0; for (longpathi < root.len) { append(longworkbytes, root[longpathi]); longpathi += 1; }; for (longworkbytes.len < os.PATH_MAX - 8) { append(longworkbytes, '/': u8); let segmentbytes: i32 = 0; for (segmentbytes < 120 && longworkbytes.len < os.PATH_MAX - 8) { append(longworkbytes, 'w': u8); segmentbytes += 1; }; }; let longworkdir: str = strings.frombytes(longworkbytes); mkdirall(longworkdir); let commandworkpaths: []str = ["", ""]; let commandstage: i32 = 0; for (commandstage < commandstages.len) { writefile(commandcompilertraces[commandstage], ""); writefile(commandassemblertraces[commandstage], ""); writefile(commandlinkertraces[commandstage], ""); let commandenv: []str = alloc([], (commandbaseenv.len + 9): u64)!; let commandei: i32 = 0; for (commandei < commandbaseenv.len) { if (!strings.hasprefix(commandbaseenv[commandei], "WW_W6C=") && !strings.hasprefix(commandbaseenv[commandei], "WW_W6A=") && !strings.hasprefix(commandbaseenv[commandei], "WW_W6L=") && !strings.hasprefix(commandbaseenv[commandei], "WW_PATTERN_COMPILER_TRACE=") && !strings.hasprefix(commandbaseenv[commandei], "WW_PATTERN_ASSEMBLER_TRACE=") && !strings.hasprefix(commandbaseenv[commandei], "WW_PATTERN_LINKER_TRACE=") && !strings.hasprefix(commandbaseenv[commandei], "WW_PATTERN_REAL_COMPILER=") && !strings.hasprefix(commandbaseenv[commandei], "WW_PATTERN_REAL_ASSEMBLER=") && !strings.hasprefix(commandbaseenv[commandei], "WW_PATTERN_REAL_LINKER=")) { append(commandenv, commandbaseenv[commandei]); }; commandei += 1; }; append(commandenv, strings.concat("WW_W6C=", commandcompilerwrapper)); append(commandenv, strings.concat("WW_W6A=", commandassemblerwrapper)); append(commandenv, strings.concat("WW_W6L=", commandlinkerwrapper)); append(commandenv, strings.concat("WW_PATTERN_COMPILER_TRACE=", commandcompilertraces[commandstage])); append(commandenv, strings.concat("WW_PATTERN_ASSEMBLER_TRACE=", commandassemblertraces[commandstage])); append(commandenv, strings.concat("WW_PATTERN_LINKER_TRACE=", commandlinkertraces[commandstage])); append(commandenv, strings.concat("WW_PATTERN_REAL_COMPILER=", driver(commandcompilers[commandstage]))); append(commandenv, strings.concat("WW_PATTERN_REAL_ASSEMBLER=", driver(commandassemblers[commandstage]))); append(commandenv, strings.concat("WW_PATTERN_REAL_LINKER=", driver(commandlinkers[commandstage]))); let commandforward: []str = [driver(commandstages[commandstage]), "build", "-w", commandworks[commandstage], "-I", commands, "-L", strings.concat(repo(), "/out/lib"), "-lwcc", "-o", commandbins[commandstage], commandspec, commandaliasspec, commandspec, commandalpha]; let commandreverse: []str = [driver(commandstages[commandstage]), "build", "-w", commandreverseworks[commandstage], "-I", commands, "-L", strings.concat(repo(), "/out/lib"), "-lwcc", "-o", commandreverseoutputs[commandstage], commandalpha, commandspec, commandaliasspec, commandspec]; if (commandstage == 0) { runcommandenv(root, "tree-command-output-c", commandforward, commandenv, (60i64 * (time.second: i64)): time.duration, &outc); expectexit(&outc, 0); } else { runcommandenv(root, "tree-command-output-ww", commandforward, commandenv, (60i64 * (time.second: i64)): time.duration, &outw); expectexit(&outw, 0); }; let commandstdout: str; let commandstderr: str; if (commandstage == 0) { commandstdout = strings.dup(outc.stdout); commandstderr = strings.dup(outc.stderr); } else { commandstdout = strings.dup(outw.stdout); commandstderr = strings.dup(outw.stderr); }; let commandalphabin: str = strings.dup(readfile(strings.concat( commandbins[commandstage], "/cmd-alpha"))); let commandzetabin: str = strings.dup(readfile(strings.concat( commandbins[commandstage], "/cmd-zeta"))); let commandwork: str = strings.concat(commandworks[commandstage], "/"); commandworkpaths[commandstage] = strings.dup(commandwork); let commandctrace: str = readfile(commandcompilertraces[commandstage]); let commandatrace: str = readfile(commandassemblertraces[commandstage]); let commandltrace: str = readfile(commandlinkertraces[commandstage]); assert(occurrences(commandctrace, "\n") == 3); assert(occurrences(commandatrace, "\n") == 5); assert(occurrences(commandltrace, "\n") == 2); let commandalphacompile: str = linecontaining(commandctrace, strings.concat(commandalphaid, ".unit.new")); assert(occurrences(commandalphacompile, strings.concat( "<--import><", commandwork, "library.wwi.new>")) == 1); assert(!has(commandalphacompile, "cmd-zeta.wwi")); let alphaassembly: str = strings.concat("BEGIN<-o><", commandwork, commandalphaid, ".init.o.new><", commandwork, commandalphaid, ".init.s.new>"); let zetaassembly: str = strings.concat("BEGIN<-o><", commandwork, commandzetaid, ".init.o.new><", commandwork, commandzetaid, ".init.s.new>"); assert(same(linecontaining(commandatrace, strings.concat(commandalphaid, ".init.o.new")), alphaassembly)); assert(same(linecontaining(commandatrace, strings.concat(commandzetaid, ".init.o.new")), zetaassembly)); let commandalphalink: str = linecontaining(commandltrace, strings.concat("<-o><", commandbins[commandstage], "/cmd-alpha.new>")); let commandzetalink: str = linecontaining(commandltrace, strings.concat("<-o><", commandbins[commandstage], "/cmd-zeta.new>")); assert(occurrences(commandalphalink, strings.concat("<", commandwork, commandalphaid, ".a.new>")) == 1); assert(occurrences(commandalphalink, strings.concat("<", commandwork, "library.a.new>")) == 1); assert(!has(commandalphalink, strings.concat(commandzetaid, ".a"))); assert(!has(commandalphalink, ".wwi>")); assert(has(commandalphalink, strings.concat("<-L><", repo(), "/out/lib><-l>"))); assert(has(commandzetalink, strings.concat("<", commandwork, commandzetaid, ".a.new>"))); assert(!has(commandzetalink, "library.a")); assert(!has(commandzetalink, ".wwi>")); let normalizedcommandcompiler: str = normalizedtrace(commandctrace, commandwork, commandbins[commandstage]); let normalizedcommandassembler: str = normalizedtrace(commandatrace, commandwork, commandbins[commandstage]); let normalizedcommandlinker: str = normalizedtrace(commandltrace, commandwork, commandbins[commandstage]); if (commandstage == 0) { referencecommandcompiler = strings.dup(normalizedcommandcompiler); referencecommandassembler = strings.dup(normalizedcommandassembler); referencecommandlinker = strings.dup(normalizedcommandlinker); } else { assert(same(referencecommandcompiler, normalizedcommandcompiler)); assert(same(referencecommandassembler, normalizedcommandassembler)); assert(same(referencecommandlinker, normalizedcommandlinker)); }; // Reverse the identical request multiset into an independent cold // work/output root inside this stage. Canonical product ordering leaves // diagnostics, normalized tool argv, artifacts, and binaries fixed. rewritefile(commandcompilertraces[commandstage], ""); rewritefile(commandassemblertraces[commandstage], ""); rewritefile(commandlinkertraces[commandstage], ""); if (commandstage == 0) { runcommandenv(root, "tree-command-reverse-c", commandreverse, commandenv, (60i64 * (time.second: i64)): time.duration, &outc); expectexit(&outc, 0); assert(same(commandstdout, outc.stdout)); assert(same(commandstderr, outc.stderr)); } else { runcommandenv(root, "tree-command-reverse-ww", commandreverse, commandenv, (60i64 * (time.second: i64)): time.duration, &outw); expectexit(&outw, 0); assert(same(commandstdout, outw.stdout)); assert(same(commandstderr, outw.stderr)); }; let reversework: str = strings.concat( commandreverseworks[commandstage], "/"); let reversectrace: str = readfile(commandcompilertraces[commandstage]); let reverseatrace: str = readfile(commandassemblertraces[commandstage]); let reverseltrace: str = readfile(commandlinkertraces[commandstage]); assert(same(normalizedcommandcompiler, normalizedtrace(reversectrace, reversework, commandreversebins[commandstage]))); assert(same(normalizedcommandassembler, normalizedtrace(reverseatrace, reversework, commandreversebins[commandstage]))); assert(same(normalizedcommandlinker, normalizedtrace(reverseltrace, reversework, commandreversebins[commandstage]))); let reverseactions: []str = [commandalphaid, commandzetaid, "library"]; let reversesuffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"]; let rai: i32 = 0; for (rai < reverseactions.len) { let rsi: i32 = 0; for (rsi < reversesuffixes.len) { assert(same(readfile(strings.concat(commandwork, reverseactions[rai], reversesuffixes[rsi])), readfile(strings.concat(reversework, reverseactions[rai], reversesuffixes[rsi])))); rsi += 1; }; rai += 1; }; assert(same(commandalphabin, readfile(strings.concat( commandreversebins[commandstage], "/cmd-alpha")))); assert(same(commandzetabin, readfile(strings.concat( commandreversebins[commandstage], "/cmd-zeta")))); // Return to the forward store: a warm equivalent request invokes no // compiler or assembler before the direct-form reuse check below. rewritefile(commandcompilertraces[commandstage], ""); rewritefile(commandassemblertraces[commandstage], ""); rewritefile(commandlinkertraces[commandstage], ""); if (commandstage == 0) { runcommandenv(root, "tree-command-warm-c", commandforward, commandenv, (60i64 * (time.second: i64)): time.duration, &outc); expectexit(&outc, 0); } else { runcommandenv(root, "tree-command-warm-ww", commandforward, commandenv, (60i64 * (time.second: i64)): time.duration, &outw); expectexit(&outw, 0); }; assert(readfile(commandcompilertraces[commandstage]).len == 0); assert(readfile(commandassemblertraces[commandstage]).len == 0); let directbin: str = strings.concat(root, "/direct-", commandstages[commandstage]); let directav: []str = [driver(commandstages[commandstage]), "build", "-w", commandworks[commandstage], "-I", commands, "-L", strings.concat(repo(), "/out/lib"), "-lwcc", "-o", directbin, commandalpha]; if (commandstage == 0) { runcommandenv(root, "tree-command-direct-c", directav, commandenv, (60i64 * (time.second: i64)): time.duration, &outc); expectexit(&outc, 0); } else { runcommandenv(root, "tree-command-direct-ww", directav, commandenv, (60i64 * (time.second: i64)): time.duration, &outw); expectexit(&outw, 0); }; assert(readfile(commandcompilertraces[commandstage]).len == 0); assert(readfile(commandassemblertraces[commandstage]).len == 0); assert(same(commandalphabin, readfile(directbin))); rewritefile(commandcompilertraces[commandstage], ""); rewritefile(commandassemblertraces[commandstage], ""); rewritefile(commandlinkertraces[commandstage], ""); let commandasm: []str = [driver(commandstages[commandstage]), "build", "-S", "-w", commandasmworks[commandstage], "-I", commands, commandspec, commandaliasspec, commandalpha]; if (commandstage == 0) { runcommandenv(root, "tree-command-asm-c", commandasm, commandenv, (60i64 * (time.second: i64)): time.duration, &outc); expectexit(&outc, 0); } else { runcommandenv(root, "tree-command-asm-ww", commandasm, commandenv, (60i64 * (time.second: i64)): time.duration, &outw); expectexit(&outw, 0); }; let commandasmwork: str = strings.concat(commandasmworks[commandstage], "/"); let commandasmtrace: str = readfile(commandcompilertraces[commandstage]); assert(occurrences(commandasmtrace, "\n") == 3); assert(readfile(commandassemblertraces[commandstage]).len == 0); assert(readfile(commandlinkertraces[commandstage]).len == 0); assert(os.exists(strings.concat(commandasmwork, commandalphaid, ".s"))); assert(os.exists(strings.concat(commandasmwork, commandzetaid, ".s"))); assert(os.exists(strings.concat(commandasmwork, "library.s"))); let normalizedasmcompiler: str = normalizedtrace(commandasmtrace, commandasmwork, commandbins[commandstage]); if (commandstage == 0) { referenceasmcompiler = strings.dup(normalizedasmcompiler); } else { assert(same(referenceasmcompiler, normalizedasmcompiler)); }; if (commandstage == 0) { runcommandenv(root, "tree-command-asm-warm-c", commandasm, commandenv, (60i64 * (time.second: i64)): time.duration, &outc); expectexit(&outc, 0); } else { runcommandenv(root, "tree-command-asm-warm-ww", commandasm, commandenv, (60i64 * (time.second: i64)): time.duration, &outw); expectexit(&outw, 0); }; assert(same(commandasmtrace, readfile(commandcompilertraces[commandstage]))); rewritefile(commandcompilertraces[commandstage], ""); rewritefile(commandassemblertraces[commandstage], ""); rewritefile(commandlinkertraces[commandstage], ""); let commandasmnowork: []str = [driver(commandstages[commandstage]), "build", "-S", "-I", commands, commandspec]; if (commandstage == 0) { runcommandenv(root, "tree-command-asm-no-work-c", commandasmnowork, commandenv, time.second, &outc); expectexit(&outc, 2); referenceasmrejectdiag = strings.dup(outc.stderr); } else { runcommandenv(root, "tree-command-asm-no-work-ww", commandasmnowork, commandenv, time.second, &outw); expectexit(&outw, 2); assert(same(referenceasmrejectdiag, outw.stderr)); }; assert(has(referenceasmrejectdiag, "wwtest package: recursive -S needs -w\n")); assert(readfile(commandcompilertraces[commandstage]).len == 0); assert(readfile(commandassemblertraces[commandstage]).len == 0); assert(readfile(commandlinkertraces[commandstage]).len == 0); rewritefile(commandcompilertraces[commandstage], ""); rewritefile(commandassemblertraces[commandstage], ""); rewritefile(commandlinkertraces[commandstage], ""); let collisionav: []str = [driver(commandstages[commandstage]), "build", "-w", collisionworks[commandstage], "-o", collisionout, collisionspec]; if (commandstage == 0) { runcommandenv(root, "tree-collision-c", collisionav, commandenv, time.second, &outc); expectexit(&outc, 1); referencecollisiondiag = strings.dup(outc.stderr); } else { runcommandenv(root, "tree-collision-ww", collisionav, commandenv, time.second, &outw); expectexit(&outw, 1); assert(same(referencecollisiondiag, outw.stderr)); }; assert(readfile(commandcompilertraces[commandstage]).len == 0); assert(readfile(commandassemblertraces[commandstage]).len == 0); assert(readfile(commandlinkertraces[commandstage]).len == 0); assert(!os.exists(collisionworks[commandstage])); rewritefile(commandcompilertraces[commandstage], ""); rewritefile(commandassemblertraces[commandstage], ""); rewritefile(commandlinkertraces[commandstage], ""); let fanoutpathav: []str = [driver(commandstages[commandstage]), "build", "-o", longoutputdir, "-I", commands, commandspec]; if (commandstage == 0) { runcommandenv(root, "tree-fanout-path-c", fanoutpathav, commandenv, time.second, &outc); expectexit(&outc, 1); referencefanoutpathdiag = strings.dup(outc.stderr); } else { runcommandenv(root, "tree-fanout-path-ww", fanoutpathav, commandenv, time.second, &outw); expectexit(&outw, 1); assert(same(referencefanoutpathdiag, outw.stderr)); }; assert(has(referencefanoutpathdiag, "ww: command output path is too long\n")); assert(readfile(commandcompilertraces[commandstage]).len == 0); assert(readfile(commandassemblertraces[commandstage]).len == 0); assert(readfile(commandlinkertraces[commandstage]).len == 0); let scratchpathav: []str = [driver(commandstages[commandstage]), "build", "-o", longscratchout, "-I", commands, commandalpha]; if (commandstage == 0) { runcommandenv(root, "tree-scratch-path-c", scratchpathav, commandenv, time.second, &outc); expectexit(&outc, 1); referencescratchpathdiag = strings.dup(outc.stderr); } else { runcommandenv(root, "tree-scratch-path-ww", scratchpathav, commandenv, time.second, &outw); expectexit(&outw, 1); assert(same(referencescratchpathdiag, outw.stderr)); }; assert(has(referencescratchpathdiag, "ww: scratch path is too long\n")); assert(readfile(commandcompilertraces[commandstage]).len == 0); assert(readfile(commandassemblertraces[commandstage]).len == 0); assert(readfile(commandlinkertraces[commandstage]).len == 0); let workpathav: []str = [driver(commandstages[commandstage]), "build", "-w", longworkdir, "-I", commands, commandalpha]; if (commandstage == 0) { runcommandenv(root, "tree-work-path-c", workpathav, commandenv, time.second, &outc); expectexit(&outc, 1); referenceworkpathdiag = strings.dup(outc.stderr); } else { runcommandenv(root, "tree-work-path-ww", workpathav, commandenv, time.second, &outw); expectexit(&outw, 1); assert(same(referenceworkpathdiag, outw.stderr)); }; assert(has(referenceworkpathdiag, "ww: workdir path is too long\n")); assert(readfile(commandcompilertraces[commandstage]).len == 0); assert(readfile(commandassemblertraces[commandstage]).len == 0); assert(readfile(commandlinkertraces[commandstage]).len == 0); commandstage += 1; }; assert(has(referencecollisiondiag, "ww: multiple commands produce output basename \"same\"")); assert(!os.exists(strings.concat(collisionout, "/same"))); let commandactions: []str = [commandalphaid, commandzetaid, "library"]; let commandsuffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"]; let commandaction: i32 = 0; for (commandaction < commandactions.len) { let commandsuffix: i32 = 0; for (commandsuffix < commandsuffixes.len) { assert(same(readfile(strings.concat(commandworkpaths[0], commandactions[commandaction], commandsuffixes[commandsuffix])), readfile(strings.concat(commandworkpaths[1], commandactions[commandaction], commandsuffixes[commandsuffix])))); commandsuffix += 1; }; commandaction += 1; }; assert(os.exists(strings.concat(binc, "/cmd-alpha"))); assert(os.exists(strings.concat(binc, "/cmd-zeta"))); assert(os.exists(strings.concat(binw, "/cmd-alpha"))); assert(os.exists(strings.concat(binw, "/cmd-zeta"))); assert(!os.exists(strings.concat(binc, "/library"))); assert(!os.exists(strings.concat(binw, "/library"))); assert(same(readfile(strings.concat(binc, "/cmd-alpha")), readfile(strings.concat(binw, "/cmd-alpha")))); assert(same(readfile(strings.concat(binc, "/cmd-zeta")), readfile(strings.concat(binw, "/cmd-zeta")))); // `--` ends build option parsing and every following argument remains a // package selector. The coordinator receives and builds that direct root. let dashworks: []str = [strings.concat(root, "/dash-work-c"), strings.concat(root, "/dash-work-ww")]; let dashbins: []str = [strings.concat(root, "/dash-bin-c"), strings.concat(root, "/dash-bin-ww")]; let dashtrailworks: []str = [strings.concat(root, "/dash-trail-work-c"), strings.concat(root, "/dash-trail-work-ww")]; let dashtrailbins: []str = [strings.concat(root, "/dash-trail-bin-c"), strings.concat(root, "/dash-trail-bin-ww")]; let referencedashstdout: str = ""; let referencedashstderr: str = ""; let dashstage: i32 = 0; for (dashstage < commandstages.len) { let dashav: []str = [driver(commandstages[dashstage]), "build", "-w", dashworks[dashstage], "-I", commands, "-o", dashbins[dashstage], "--", dashselector]; if (dashstage == 0) { runcommanddir(root, "tree-dash-c", root, dashav, (30i64 * (time.second: i64)): time.duration, &outc); expectexit(&outc, 0); referencedashstdout = strings.dup(outc.stdout); referencedashstderr = strings.dup(outc.stderr); } else { runcommanddir(root, "tree-dash-ww", root, dashav, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outw, 0); assert(same(referencedashstdout, outw.stdout)); assert(same(referencedashstderr, outw.stderr)); }; assert(os.exists(strings.concat(dashworks[dashstage], "/", commandalphaid, ".unit.ww"))); // Once the first positional has stopped flag parsing, a later `--` is // another package argument, not a second terminator. let dashtrailav: []str = [driver(commandstages[dashstage]), "build", "-w", dashtrailworks[dashstage], "-I", commands, "-o", dashtrailbins[dashstage], commandalpha, "--"]; if (dashstage == 0) { runcommand(root, "tree-dash-trailing-c", dashtrailav, time.second, &outc); expectexit(&outc, 1); assert(has(outc.stderr, "--: cannot canonicalize package directory\n")); } else { runcommand(root, "tree-dash-trailing-ww", dashtrailav, time.second, &outw); expectexit(&outw, 1); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(has(outw.stderr, "--: cannot canonicalize package directory\n")); }; assert(!os.exists(dashtrailworks[dashstage])); assert(!os.exists(dashtrailbins[dashstage])); dashstage += 1; }; assert(same(readfile(dashbins[0]), readfile(dashbins[1]))); let commandrun: []str = [strings.concat(binc, "/cmd-alpha")]; runcommand(root, "tree-command-run", commandrun, time.second, &outc); expectexit(&outc, 0); let nomainpattern: str = strings.concat(commandlib, "/..."); let nomainc: []str = [driver("ww"), "build", "-o", binc, nomainpattern]; let nomainw: []str = [driver("ww_ww"), "build", "-o", binw, nomainpattern]; runcommand(root, "tree-no-main-c", nomainc, time.second, &outc); runcommand(root, "tree-no-main-ww", nomainw, time.second, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "ww: no main packages to build\n")); assert(has(seq, strings.concat("ok ", tree, " [rootpkg, same-package]\n"))); assert(has(seq, strings.concat("ok ", tree, "/alpha [alpha_test, external]\n"))); assert(has(seq, strings.concat("ok ", tree, "/app [app, same-package]\n"))); assert(has(seq, strings.concat("ok ", tree, "/beta/inner [inner, same-package]\n"))); assert(has(seq, strings.concat("ok ", tree, "/domain/app [app, same-package]\n"))); assert(has(seq, strings.concat("? ", tree, "/gamma [no tests]\n"))); assert(has(seq, strings.concat("? ", tree, "/vendor [no tests]\n"))); assert(has(seq, strings.concat("? ", tree, "/vendorx [no tests]\n"))); let rootreport: i32 = pos(seq, strings.concat("ok ", tree, " [rootpkg, same-package]\n")); let alphareport: i32 = pos(seq, strings.concat("ok ", tree, "/alpha [alpha_test, external]\n")); let appreport: i32 = pos(seq, strings.concat("ok ", tree, "/app [app, same-package]\n")); let innerreport: i32 = pos(seq, strings.concat("ok ", tree, "/beta/inner [inner, same-package]\n")); let domainreport: i32 = pos(seq, strings.concat("ok ", tree, "/domain/app [app, same-package]\n")); let gammareport: i32 = pos(seq, strings.concat("? ", tree, "/gamma [no tests]\n")); let vendorreport: i32 = pos(seq, strings.concat("? ", tree, "/vendor [no tests]\n")); let vendorxreport: i32 = pos(seq, strings.concat("? ", tree, "/vendorx [no tests]\n")); assert(rootreport >= 0 && rootreport < alphareport && alphareport < appreport && appreport < innerreport && innerreport < domainreport && domainreport < gammareport && gammareport < vendorreport && vendorreport < vendorxreport); assert(occurrences(seq, strings.concat(tree, " [")) == 1); assert(occurrences(seq, strings.concat("ok ", tree, "/alpha [alpha_test, external]\n")) == 1); assert(occurrences(seq, strings.concat("ok ", tree, "/app [app, same-package]\n")) == 1); assert(occurrences(seq, strings.concat("ok ", tree, "/beta/inner [inner, same-package]\n")) == 1); assert(occurrences(seq, strings.concat("ok ", tree, "/domain/app [app, same-package]\n")) == 1); assert(occurrences(seq, strings.concat("? ", tree, "/gamma [no tests]\n")) == 1); assert(occurrences(seq, strings.concat("? ", tree, "/vendor [no tests]\n")) == 1); assert(occurrences(seq, strings.concat("? ", tree, "/vendorx [no tests]\n")) == 1); assert(!has(seq, ".hidden")); assert(!has(seq, "_skip")); assert(!has(seq, "/testdata")); assert(!has(seq, "/vendor/bad")); assert(!has(seq, "/app/vendor/lib/math")); assert(!has(seq, outside)); let buildworkc: str = strings.concat(root, "/build-work-c"); let buildworkw: str = strings.concat(root, "/build-work-ww"); let buildc: []str = [driver("ww"), "build", "-w", buildworkc, "-I", tree, spec]; let buildw: []str = [driver("ww_ww"), "build", "-w", buildworkw, "-I", tree, spec]; runcommand(root, "tree-build-c", buildc, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-build-ww", buildw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); let buildactions: []str = [localidentity(tree, "rootpkg"), "alpha", "app", "domain.app", "gamma", "vendor", "vendorx"]; let bai: i32 = 0; for (bai < buildactions.len) { let cunit: str = readfile(strings.concat(buildworkc, "/", buildactions[bai], ".unit.ww")); assert(same(cunit, readfile(strings.concat(buildworkw, "/", buildactions[bai], ".unit.ww")))); bai += 1; }; assert(!os.exists(strings.concat(buildworkc, "/beta.inner.unit.ww"))); assert(!os.exists(strings.concat(buildworkw, "/beta.inner.unit.ww"))); assert(!os.exists(strings.concat(buildworkc, "/alpha-internal-test.unit.ww"))); assert(!os.exists(strings.concat(buildworkw, "/alpha-internal-test.unit.ww"))); // Concurrent scheduling must not reorder the emitted byte stream. let j4: []str = [driver("ww"), "test", "-j", "4", "-I", tree, spec]; runcommand(root, "tree-j4", j4, (30i64 * (time.second: i64)): time.duration, &outc); expectexit(&outc, 0); assert(same(outc.stdout, seq)); let j0: []str = [driver("ww"), "test", "-j", "0", spec]; runcommand(root, "tree-j0", j0, time.second, &outc); expectexit(&outc, 2); assert(has(outc.stderr, "usage: wwtest package")); let overlapc: []str = [driver("ww"), "test", "-I", tree, strings.concat(tree, "/alpha"), spec, spec, strings.concat(alias, "/...")]; let overlapcreverse: []str = [driver("ww"), "test", "-I", tree, strings.concat(alias, "/..."), spec, spec, strings.concat(tree, "/alpha")]; let overlapw: []str = [driver("ww_ww"), "test", "-I", tree, strings.concat(alias, "/..."), spec, spec, strings.concat(tree, "/alpha")]; let overlapwreverse: []str = [driver("ww_ww"), "test", "-I", tree, strings.concat(tree, "/alpha"), spec, spec, strings.concat(alias, "/...")]; runcommand(root, "tree-overlap-c", overlapc, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-overlap-ww", overlapw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, seq)); assert(same(outw.stdout, seq)); assert(same(outc.stderr, outw.stderr)); let overlapstderr: str = strings.dup(outc.stderr); runcommand(root, "tree-overlap-reverse-c", overlapcreverse, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-overlap-reverse-ww", overlapwreverse, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, seq)); assert(same(outw.stdout, seq)); assert(same(outc.stderr, overlapstderr)); assert(same(outw.stderr, overlapstderr)); // The first ellipsis need not be a path element. With cwd as the implicit // traversal root, matching uses cleaned relative candidates rather than an // accidental "./" prefix. let middlec: []str = [driver("ww"), "test", "-I", tree, "tr.../alpha"]; let middlew: []str = [driver("ww_ww"), "test", "-I", tree, "tr.../alpha"]; runcommanddir(root, "tree-middle-pattern-c", root, middlec, (30i64 * (time.second: i64)): time.duration, &outc); runcommanddir(root, "tree-middle-pattern-ww", root, middlew, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stdout, strings.concat("ok ", tree, "/alpha [alpha_test, external]\n"))); assert(!has(outc.stdout, strings.concat("ok ", tree, " [rootpkg, same-package]\n"))); // The recursive exclusions are traversal rules, not bans on direct roots. let directc: []str = [driver("ww"), "test", "-I", tree, strings.concat(tree, "/.hidden"), strings.concat(tree, "/_skip"), strings.concat(tree, "/testdata/bad")]; let directw: []str = [driver("ww_ww"), "test", "-I", tree, strings.concat(tree, "/testdata/bad"), strings.concat(tree, "/_skip"), strings.concat(tree, "/.hidden")]; runcommand(root, "tree-direct-exclusions-c", directc, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-direct-exclusions-ww", directw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stdout, strings.concat("ok ", tree, "/.hidden [hid, same-package]\n"))); assert(has(outc.stdout, strings.concat("ok ", tree, "/_skip [_skip, same-package]\n"))); assert(has(outc.stdout, strings.concat("ok ", tree, "/testdata/bad [bad, same-package]\n"))); // A generic wildcard selects a code-bearing terminal vendor directory but // cannot consume it. Rooting the pattern at vendor selects its descendants; // a second non-terminal vendor remains a barrier. let vendorspec: str = strings.concat(tree, "/vendor/..."); let vendorc: []str = [driver("ww"), "test", "-I", tree, vendorspec]; let vendorw: []str = [driver("ww_ww"), "test", "-I", tree, vendorspec]; runcommand(root, "tree-explicit-vendor-c", vendorc, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-explicit-vendor-ww", vendorw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stdout, strings.concat("? ", tree, "/vendor [no tests]\n"))); assert(has(outc.stdout, strings.concat("ok ", tree, "/vendor/bad [bad, same-package]\n"))); assert(!has(outc.stdout, "/vendor/bad/vendor/deep")); let vendordirectc: []str = [driver("ww"), "test", "-I", tree, strings.concat(tree, "/app/vendor/lib/math")]; let vendordirectw: []str = [driver("ww_ww"), "test", "-I", tree, strings.concat(tree, "/app/vendor/lib/math")]; runcommand(root, "tree-direct-below-vendor-c", vendordirectc, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-direct-below-vendor-ww", vendordirectw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stdout, strings.concat("? ", tree, "/app/vendor/lib/math [no tests]\n"))); let vendorroots: []str = [driver("ww"), "test", "-I", tree, strings.concat(tree, "/app/vendor/...")]; runcommand(root, "tree-pattern-below-vendor", vendorroots, (30i64 * (time.second: i64)): time.duration, &outc); expectexit(&outc, 0); assert(has(outc.stdout, strings.concat("? ", tree, "/app/vendor/lib/math [no tests]\n"))); // A child symlink is never traversed. The same symlink is followed when it // is itself the explicit traversal root, then canonical output names it once. let escapec: []str = [driver("ww"), "test", "-I", root, strings.concat(tree, "/escape/...")]; let escapew: []str = [driver("ww_ww"), "test", "-I", root, strings.concat(tree, "/escape/...")]; runcommand(root, "tree-explicit-symlink-root-c", escapec, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-explicit-symlink-root-ww", escapew, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stdout, strings.concat("ok ", outside, " [outside, same-package]\n"))); let oc: []str = [driver("ww"), "test", "-o", strings.concat(root, "/stem"), spec]; let ow: []str = [driver("ww_ww"), "test", "-o", strings.concat(root, "/stem"), spec]; runcommand(root, "tree-o-c", oc, time.second, &outc); runcommand(root, "tree-o-ww", ow, time.second, &outw); expectexit(&outc, 2); expectexit(&outw, 2); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "ww test: -o needs -c for a package target\n")); // -w on a package target forwards to the coordinator: one shared // persistent driver workdir for the complete selected request, // reuse owned by the driver's content-identity contract. The // byte stream must match the plain run, cold and warm. let wdroot: str = strings.concat(root, "/wd"); assert(os.mkdir(wdroot, 448i32) == 0); let wdc: []str = [driver("ww"), "test", "-w", wdroot, "-I", tree, spec]; let wdw: []str = [driver("ww_ww"), "test", "-w", wdroot, "-I", tree, spec]; runcommand(root, "tree-w-c", wdc, (30i64 * (time.second: i64)): time.duration, &outc); let wdkey: str = wdroot; let expandedmath: str = "app.vendor.lib.math"; let expandedancestor: str = "domain.vendor.dep"; assert(os.exists(strings.concat(wdkey, "/", expandedmath, ".unit.ww"))); assert(os.exists(strings.concat(wdkey, "/", expandedancestor, ".unit.ww"))); assert(!os.exists(strings.concat(wdkey, "/math.unit.ww"))); let appunit: str = readfile(strings.concat(wdkey, "/app-internal-test.unit.ww")); assert(has(appunit, strings.concat("//ww:import-map lib.math ", expandedmath, " "))); assert(has(readfile(strings.concat(wdkey, "/", expandedmath, ".unit.ww")), strings.concat("//ww:module-reset ", expandedmath, "\n"))); let ancestorunit: str = readfile(strings.concat(wdkey, "/domain.app-internal-test.unit.ww")); assert(has(ancestorunit, strings.concat("//ww:import-map dep ", expandedancestor, " "))); assert(has(readfile(strings.concat(wdkey, "/", expandedancestor, ".unit.ww")), strings.concat("//ww:module-reset ", expandedancestor, "\n"))); let alphaunit: str = readfile(strings.concat(wdkey, "/alpha.unit.ww")); assert(pos(alphaunit, "export fn value()") < pos(alphaunit, "export fn linked()")); runcommand(root, "tree-w-ww", wdw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stdout, seq)); runcommand(root, "tree-w-warm", wdc, (30i64 * (time.second: i64)): time.duration, &outc); expectexit(&outc, 0); assert(same(outc.stdout, seq)); // -c publishes caller-owned artifacts; a persistent workdir is a // different ownership contract — the coordinator rejects the mix. let wcc: []str = [driver("ww"), "test", "-c", "-w", wdroot, "-I", tree, spec]; let wcw: []str = [driver("ww_ww"), "test", "-c", "-w", wdroot, "-I", tree, spec]; runcommand(root, "tree-wc-c", wcc, time.second, &outc); runcommand(root, "tree-wc-ww", wcw, time.second, &outw); expectexit(&outc, 2); expectexit(&outw, 2); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "wwtest package: -w conflicts with -c\n")); let bare: str = strings.concat(root, "/bare"); let barez: str = strings.concat(root, "/zz-bare"); assert(os.mkdir(bare, 448i32) == 0); assert(os.mkdir(strings.concat(bare, "/sub"), 448i32) == 0); assert(os.mkdir(barez, 448i32) == 0); let barec: []str = [driver("ww"), "test", strings.concat(bare, "/...")]; let barew: []str = [driver("ww_ww"), "test", strings.concat(bare, "/...")]; runcommand(root, "tree-bare-c", barec, (10i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-bare-ww", barew, (10i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, strings.concat("ww: warning: \"", bare, "/...\" matched no packages\n"))); assert(has(outc.stderr, "ww test: no packages to test\n")); let baredirectc: []str = [driver("ww"), "test", bare]; let baredirectw: []str = [driver("ww_ww"), "test", bare]; runcommand(root, "tree-bare-direct-c", baredirectc, time.second, &outc); runcommand(root, "tree-bare-direct-ww", baredirectw, time.second, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "directory contains no WW package sources\n")); let quotedpattern: str = strings.concat(root, "/no\"..."); let quotedc: []str = [driver("ww"), "test", quotedpattern]; let quotedw: []str = [driver("ww_ww"), "test", quotedpattern]; runcommand(root, "tree-quoted-unmatched-c", quotedc, time.second, &outc); runcommand(root, "tree-quoted-unmatched-ww", quotedw, time.second, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, strings.concat("ww: warning: \"", root, "/no\\\"...\" matched no packages\n"))); // strconv.Quote escapes valid but non-printing Unicode, not only malformed // bytes and ASCII controls. U+2028 is a stable discriminator. let nonprintingbytes: []u8 = alloc([], (root.len + 8): u64)!; let qi: i32 = 0; for (qi < root.len) { append(nonprintingbytes, root[qi]); qi += 1; }; append(nonprintingbytes, '/': u8); append(nonprintingbytes, 'n': u8); append(nonprintingbytes, 0xe2u8); append(nonprintingbytes, 0x80u8); append(nonprintingbytes, 0xa8u8); append(nonprintingbytes, '.': u8); append(nonprintingbytes, '.': u8); append(nonprintingbytes, '.': u8); let nonprintingpattern: str = strings.frombytes(nonprintingbytes); let nonprintingc: []str = [driver("ww"), "test", nonprintingpattern]; let nonprintingw: []str = [driver("ww_ww"), "test", nonprintingpattern]; runcommand(root, "tree-nonprinting-unmatched-c", nonprintingc, time.second, &outc); runcommand(root, "tree-nonprinting-unmatched-ww", nonprintingw, time.second, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "\\u2028...\" matched no packages\n")); let mixedc: []str = [driver("ww"), "test", "-I", tree, strings.concat(barez, "/..."), spec, strings.concat(bare, "/...")]; let mixedw: []str = [driver("ww_ww"), "test", "-I", tree, strings.concat(bare, "/..."), spec, strings.concat(barez, "/...")]; runcommand(root, "tree-unmatched-order-c", mixedc, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-unmatched-order-ww", mixedw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, seq)); assert(same(outw.stdout, seq)); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, strings.concat("ww: warning: \"", bare, "/...\" matched no packages\n"))); let barewarning: str = strings.concat("ww: warning: \"", bare, "/...\" matched no packages\n"); let barezwarning: str = strings.concat("ww: warning: \"", barez, "/...\" matched no packages\n"); assert(pos(outc.stderr, barewarning) < pos(outc.stderr, barezwarning)); // Pinned pkgpattern rejects invalid UTF-8 patterns before regexp // construction, so they match nothing and receive the ordinary quoted // warning. Candidate names still use regexp's DecodeRune behavior. let invalidpatternbytes: []u8 = alloc([], (root.len + 6): u64)!; let mpi: i32 = 0; for (mpi < root.len) { append(invalidpatternbytes, root[mpi]); mpi += 1; }; append(invalidpatternbytes, '/': u8); append(invalidpatternbytes, '.': u8); append(invalidpatternbytes, '.': u8); append(invalidpatternbytes, '.': u8); append(invalidpatternbytes, 0xffu8); let invalidpattern: str = strings.frombytes(invalidpatternbytes); let invalidpatternc: []str = [driver("ww"), "test", invalidpattern]; let invalidpatternw: []str = [driver("ww_ww"), "test", invalidpattern]; runcommand(root, "tree-invalid-pattern-c", invalidpatternc, time.second, &outc); runcommand(root, "tree-invalid-pattern-ww", invalidpatternw, time.second, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "...\\xff\" matched no packages\n")); // U+FFFD in a valid pattern matches a malformed candidate filename byte as // regexp does, while the wildcard below does not consume a newline. let utfbase: str = strings.concat(root, "/utf-names"); assert(os.mkdir(utfbase, 448i32) == 0); let invalidnamebytes: []u8 = alloc([], (utfbase.len + 2): u64)!; mpi = 0; for (mpi < utfbase.len) { append(invalidnamebytes, utfbase[mpi]); mpi += 1; }; append(invalidnamebytes, '/': u8); append(invalidnamebytes, 0xffu8); let invalidname: str = strings.frombytes(invalidnamebytes); assert(os.mkdir(invalidname, 448i32) == 0); writefile(strings.concat(invalidname, "/case_test.ww"), strings.concat( "package invalidname;\n@test fn replacement_match() void = {", " assert(true); };\n")); let replacementbytes: []u8 = alloc([], (utfbase.len + 8): u64)!; mpi = 0; for (mpi < utfbase.len) { append(replacementbytes, utfbase[mpi]); mpi += 1; }; append(replacementbytes, '/': u8); append(replacementbytes, 0xefu8); append(replacementbytes, 0xbfu8); append(replacementbytes, 0xbdu8); append(replacementbytes, '.': u8); append(replacementbytes, '.': u8); append(replacementbytes, '.': u8); let replacementpattern: str = strings.frombytes(replacementbytes); let replacementc: []str = [driver("ww"), "test", replacementpattern]; let replacementw: []str = [driver("ww_ww"), "test", replacementpattern]; runcommand(root, "tree-replacement-pattern-c", replacementc, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-replacement-pattern-ww", replacementw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stdout, "invalidname.replacement_match ... ok\n")); let newlinebase: str = strings.concat(root, "/newline-names"); assert(os.mkdir(newlinebase, 448i32) == 0); let newlinedir: str = strings.concat(newlinebase, "/line\nbreak"); assert(os.mkdir(newlinedir, 448i32) == 0); writefile(strings.concat(newlinedir, "/case_test.ww"), "package newline;\n@test fn must_not_match() void = { assert(false); };\n"); let newlinepattern: str = strings.concat(newlinebase, "/line...break"); let newlinec: []str = [driver("ww"), "test", newlinepattern]; let newlinew: []str = [driver("ww_ww"), "test", newlinepattern]; runcommand(root, "tree-newline-pattern-c", newlinec, time.second, &outc); runcommand(root, "tree-newline-pattern-ww", newlinew, time.second, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "line...break\" matched no packages\n")); let barebuildc: []str = [driver("ww"), "build", strings.concat(bare, "/...")]; let barebuildw: []str = [driver("ww_ww"), "build", strings.concat(bare, "/...")]; runcommand(root, "tree-empty-build-c", barebuildc, time.second, &outc); runcommand(root, "tree-empty-build-ww", barebuildw, time.second, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "matched no packages\n")); // A wildcard recognizes a test-only directory, so it is not unmatched; // build then omits it while test keeps its isolated variant. Direct build // remains an explicit unusable-package error. let testonly: str = strings.concat(tree, "/beta/..."); let testonlyc: []str = [driver("ww"), "build", "-I", tree, testonly]; let testonlyw: []str = [driver("ww_ww"), "build", "-I", tree, testonly]; runcommand(root, "tree-test-only-build-c", testonlyc, time.second, &outc); runcommand(root, "tree-test-only-build-ww", testonlyw, time.second, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(outc.stdout.len == 0 && outc.stderr.len == 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); let testdirectc: []str = [driver("ww"), "build", strings.concat(tree, "/beta/inner")]; let testdirectw: []str = [driver("ww_ww"), "build", strings.concat(tree, "/beta/inner")]; runcommand(root, "tree-test-only-direct-c", testdirectc, time.second, &outc); runcommand(root, "tree-test-only-direct-ww", testdirectw, time.second, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "directory contains no WW package sources\n")); let malformed: str = strings.concat(root, "/malformed"); let malformedgood: str = strings.concat(malformed, "/good"); let malformedbad: str = strings.concat(malformed, "/bad"); assert(os.mkdir(malformed, 448i32) == 0); assert(os.mkdir(malformedgood, 448i32) == 0); assert(os.mkdir(malformedbad, 448i32) == 0); writefile(strings.concat(malformedgood, "/good.ww"), "package good;\nexport fn value() int = { return 1; };\n"); let loop: str = strings.concat(root, "/loop"); let loopav: []str = ["/bin/ln", "-s", loop, loop]; runcommand(root, "recursive-root-loop", loopav, time.second, &linkout); expectexit(&linkout, 0); let rejecttrace: str = strings.concat(root, "/pattern-reject.trace"); let rejectcompiler: str = strings.concat(root, "/pattern-reject-w6c.sh"); writefile(rejecttrace, ""); writeexecutable(rejectcompiler, strings.concat( "#!/bin/sh\nprintf 'compiler\\n' >> \"$WW_PATTERN_REJECT_TRACE\"\n", "exit 99\n")); let baseenv: []str = os.getenvs(); let rejectenv: []str = alloc([], (baseenv.len + 2): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_PATTERN_REJECT_TRACE=")) { append(rejectenv, baseenv[ei]); }; ei += 1; }; append(rejectenv, strings.concat("WW_W6C=", rejectcompiler)); append(rejectenv, strings.concat("WW_PATTERN_REJECT_TRACE=", rejecttrace)); let rejectspec: str = strings.concat(malformed, "/..."); let warmworkc: str = strings.concat(root, "/warm-reject-work-c"); let warmworkw: str = strings.concat(root, "/warm-reject-work-ww"); let warmc: []str = [driver("ww"), "build", "-w", warmworkc, "-I", malformed, rejectspec]; let warmw: []str = [driver("ww_ww"), "build", "-w", warmworkw, "-I", malformed, rejectspec]; // Seed genuine committed package, voucher, and tool state before making a // second selected directory malformed. runcommand(root, "tree-malformed-seed-c", warmc, (30i64 * (time.second: i64)): time.duration, &outc); runcommand(root, "tree-malformed-seed-ww", warmw, (30i64 * (time.second: i64)): time.duration, &outw); expectexit(&outc, 0); expectexit(&outw, 0); assert(same(outc.stdout, outw.stdout)); assert(same(outc.stderr, outw.stderr)); let warmsuffixes: []str = ["/good.unit.ww", "/good.wwi", "/good.s", "/good.o", "/good.a", "/.wwtool.stamp", "/.wwtool.ww", "/.wwtool.w6c", "/.wwtool.w6a"]; let warmcstate: []str = alloc([], warmsuffixes.len: u64)!; let warmwstate: []str = alloc([], warmsuffixes.len: u64)!; let wi: i32 = 0; for (wi < warmsuffixes.len) { append(warmcstate, readfile(strings.concat(warmworkc, warmsuffixes[wi]))); append(warmwstate, readfile(strings.concat(warmworkw, warmsuffixes[wi]))); wi += 1; }; writefile(strings.concat(warmworkc, "/marker"), "c-warm\n"); writefile(strings.concat(warmworkw, "/marker"), "ww-warm\n"); writefile(strings.concat(malformedbad, "/bad.ww"), "this selected source has no package clause\n"); let rejectworkc: str = strings.concat(root, "/cold-reject-work-c"); let rejectworkw: str = strings.concat(root, "/cold-reject-work-ww"); let rejectc: []str = [driver("ww"), "build", "-w", rejectworkc, "-I", malformed, rejectspec]; let rejectw: []str = [driver("ww_ww"), "build", "-w", rejectworkw, "-I", malformed, rejectspec]; runcommandenv(root, "tree-malformed-c", rejectc, rejectenv, time.second, &outc); runcommandenv(root, "tree-malformed-ww", rejectw, rejectenv, time.second, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "invalid or missing package clause\n")); assert(readfile(rejecttrace).len == 0); assert(!os.exists(rejectworkc) && !os.exists(rejectworkw)); // Warm rejection preserves all previously committed package, voucher, // tool, and caller-owned marker bytes while still reaching no producer. runcommandenv(root, "tree-malformed-warm-c", warmc, rejectenv, time.second, &outc); runcommandenv(root, "tree-malformed-warm-ww", warmw, rejectenv, time.second, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "invalid or missing package clause\n")); assert(readfile(rejecttrace).len == 0); assert(same(readfile(strings.concat(warmworkc, "/marker")), "c-warm\n")); assert(same(readfile(strings.concat(warmworkw, "/marker")), "ww-warm\n")); wi = 0; for (wi < warmsuffixes.len) { assert(same(warmcstate[wi], readfile(strings.concat(warmworkc, warmsuffixes[wi])))); assert(same(warmwstate[wi], readfile(strings.concat(warmworkw, warmsuffixes[wi])))); wi += 1; }; // A valid package clause that fails during source-import graph loading is // also rejected before private work/output directories are materialized. let graphbad: str = strings.concat(root, "/graph-bad"); let graphapp: str = strings.concat(graphbad, "/app"); assert(os.mkdir(graphbad, 448i32) == 0); assert(os.mkdir(graphapp, 448i32) == 0); writefile(strings.concat(graphapp, "/main.ww"), "package main;\nimport nowhere;\nfn main() void = { };\n"); let graphspec: str = strings.concat(graphbad, "/..."); let graphworkc: str = strings.concat(root, "/graph-work-c"); let graphworkw: str = strings.concat(root, "/graph-work-ww"); let graphoutc: str = strings.concat(root, "/graph-out-c/"); let graphoutw: str = strings.concat(root, "/graph-out-ww/"); let graphc: []str = [driver("ww"), "build", "-w", graphworkc, "-o", graphoutc, "-I", graphbad, graphspec]; let graphw: []str = [driver("ww_ww"), "build", "-w", graphworkw, "-o", graphoutw, "-I", graphbad, graphspec]; runcommandenv(root, "tree-graph-reject-c", graphc, rejectenv, time.second, &outc); runcommandenv(root, "tree-graph-reject-ww", graphw, rejectenv, time.second, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "cannot find package nowhere\n")); assert(readfile(rejecttrace).len == 0); assert(!os.exists(graphworkc) && !os.exists(graphworkw)); assert(!os.exists(graphoutc) && !os.exists(graphoutw)); // If output creation succeeds but a later workdir prefix is unusable, the // driver reclaims only the output prefixes it just minted. Both stages make // the same pre-producer failure and leave the caller tree unchanged. let setupblock: str = strings.concat(root, "/setup-block"); let setupwork: str = strings.concat(setupblock, "/child"); let setupoutroot: str = strings.concat(root, "/setup-output"); let setuppreserved: str = strings.concat(root, "/setup-preserved"); assert(os.mkdir(setuppreserved, 448i32) == 0); let setupout: str = strings.concat(setupoutroot, "/../setup-preserved/nested/"); writefile(setupblock, "not a directory\n"); let setupc: []str = [driver("ww"), "build", "-w", setupwork, "-o", setupout, "-I", commands, commandspec]; let setupw: []str = [driver("ww_ww"), "build", "-w", setupwork, "-o", setupout, "-I", commands, commandspec]; runcommandenv(root, "tree-setup-rollback-c", setupc, rejectenv, time.second, &outc); expectexit(&outc, 1); assert(has(outc.stderr, strings.concat("ww: workdir ", setupwork, " is not a directory\n"))); assert(readfile(rejecttrace).len == 0); assert(!os.exists(setupoutroot)); assert(os.exists(setuppreserved)); assert(!os.exists(strings.concat(setuppreserved, "/nested"))); assert(!os.exists(setupwork)); assert(same(readfile(setupblock), "not a directory\n")); runcommandenv(root, "tree-setup-rollback-ww", setupw, rejectenv, time.second, &outw); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(readfile(rejecttrace).len == 0); assert(!os.exists(setupoutroot)); assert(os.exists(setuppreserved)); assert(!os.exists(strings.concat(setuppreserved, "/nested"))); assert(!os.exists(setupwork)); assert(same(readfile(setupblock), "not a directory\n")); let loopc: []str = [driver("ww"), "test", strings.concat(loop, "/...")]; let loopw: []str = [driver("ww_ww"), "test", strings.concat(loop, "/...")]; runcommandenv(root, "tree-loop-c", loopc, rejectenv, time.second, &outc); runcommandenv(root, "tree-loop-ww", loopw, rejectenv, time.second, &outw); expectexit(&outc, 1); expectexit(&outw, 1); assert(same(outc.stderr, outw.stderr)); assert(has(outc.stderr, "cannot canonicalize package directory\n")); assert(readfile(rejecttrace).len == 0); clean(root); }; @test fn persistent_package_request_workdir_is_stable() void = { let root: str = fresh(); let tree: str = deeppunctuationpath(root, "request tree"); assert(tree.len > 255); let adir: str = strings.concat(tree, "/a"); let bdir: str = strings.concat(tree, "/b"); let a: str = strings.concat(adir, "/foo"); let b: str = strings.concat(bdir, "/foo"); let workc: str = strings.concat(root, "/work-c"); let workww: str = strings.concat(root, "/work-ww"); mkdirall(tree); assert(os.mkdir(adir, 448i32) == 0); assert(os.mkdir(bdir, 448i32) == 0); assert(os.mkdir(a, 448i32) == 0); assert(os.mkdir(b, 448i32) == 0); assert(os.mkdir(workc, 448i32) == 0); assert(os.mkdir(workww, 448i32) == 0); writefile(strings.concat(a, "/foo.ww"), "package foo;\nfn value() i32 = { return 1; };\n"); writefile(strings.concat(a, "/foo_test.ww"), "package foo;\n@test fn first() void = { assert(value() == 1); };\n"); writefile(strings.concat(b, "/foo.ww"), "package foo;\nfn value() i32 = { return 2; };\n"); writefile(strings.concat(b, "/foo_test.ww"), "package foo;\n@test fn second() void = { assert(value() == 2); };\n"); let av: []str = [driver("ww"), "test", "-j", "2", "-w", workc, "-I", tree, strings.concat(tree, "/...")]; let out: commandout; runcommand(root, "workkey-cold", av, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let cold: str = strings.dup(out.stdout); assert(has(cold, strings.concat("ok ", a, " [foo, same-package]\n"))); assert(has(cold, strings.concat("ok ", b, " [foo, same-package]\n"))); let ckey: str = workc; assert(os.exists(ckey)); let aaction: str = "a.foo-internal-test"; let baction: str = "b.foo-internal-test"; assert(os.exists(strings.concat(ckey, "/", aaction, ".unit.ww"))); assert(os.exists(strings.concat(ckey, "/", baction, ".unit.ww"))); let aunit: str = readfile(strings.concat(ckey, "/", aaction, ".unit.ww")); let bunit: str = readfile(strings.concat(ckey, "/", baction, ".unit.ww")); let awwi: str = readfile(strings.concat(ckey, "/", aaction, ".wwi")); let bwwi: str = readfile(strings.concat(ckey, "/", baction, ".wwi")); let aa: str = readfile(strings.concat(ckey, "/", aaction, ".a")); let ba: str = readfile(strings.concat(ckey, "/", baction, ".a")); assert(has(aunit, "return 1") && !has(aunit, "return 2")); assert(has(bunit, "return 2") && !has(bunit, "return 1")); runcommand(root, "workkey-warm", av, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(cold, out.stdout)); let wwav: []str = [driver("ww_ww"), "test", "-j", "1", "-w", workww, "-I", tree, strings.concat(tree, "/...")]; runcommand(root, "workkey-ww", wwav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(cold, out.stdout)); let wwkey: str = workww; assert(same(aunit, readfile(strings.concat(wwkey, "/", aaction, ".unit.ww")))); assert(same(bunit, readfile(strings.concat(wwkey, "/", baction, ".unit.ww")))); assert(same(awwi, readfile(strings.concat(wwkey, "/", aaction, ".wwi")))); assert(same(bwwi, readfile(strings.concat(wwkey, "/", baction, ".wwi")))); assert(same(aa, readfile(strings.concat(wwkey, "/", aaction, ".a")))); assert(same(ba, readfile(strings.concat(wwkey, "/", baction, ".a")))); // The shared semantic-action store and warm action set are unchanged by an // equivalent recursive-root spelling. let equivalentav: []str = [driver("ww_ww"), "test", "-j", "2", "-w", workww, "-I", tree, strings.concat(tree, "/./...")]; runcommand(root, "workkey-equivalent", equivalentav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, strings.concat("ok ", a, " [foo, same-package]\n"))); assert(has(out.stdout, strings.concat("ok ", b, " [foo, same-package]\n"))); assert(os.exists(wwkey)); assert(same(aunit, readfile(strings.concat(wwkey, "/", aaction, ".unit.ww")))); assert(same(bunit, readfile(strings.concat(wwkey, "/", baction, ".unit.ww")))); assert(same(awwi, readfile(strings.concat(wwkey, "/", aaction, ".wwi")))); assert(same(bwwi, readfile(strings.concat(wwkey, "/", baction, ".wwi")))); assert(same(aa, readfile(strings.concat(wwkey, "/", aaction, ".a")))); assert(same(ba, readfile(strings.concat(wwkey, "/", baction, ".a")))); // Outside every active import root, equal declaration leaves remain two // deterministic command-local identities derived from canonical dirs. let localleft: str = deeppunctuationpath(root, "local left"); let localright: str = deeppunctuationpath(root, "local right"); mkdirall(localleft); mkdirall(localright); writefile(strings.concat(localleft, "/foo.ww"), "package foo;\nexport fn value() i32 = { return 11; };\n"); writefile(strings.concat(localright, "/foo.ww"), "package foo;\nexport fn value() i32 = { return 22; };\n"); let localids: []str = [localidentity(localleft, "foo"), localidentity(localright, "foo")]; assert(!same(localids[0], localids[1])); assert(localids[0].len > 255 && localids[1].len > 255); let localstorage: []str = [packagestoragekey(localids[0], localleft, 0, 0), packagestoragekey(localids[1], localright, 0, 0)]; assert(!same(localstorage[0], localstorage[1])); let stages: []str = ["ww", "ww_ww"]; let localrefs: []str = ["", "", "", "", "", ""]; let si: i32 = 0; for (si < stages.len) { let leftout: str = strings.concat(root, "/local-", stages[si], "-left.test"); let rightout: str = strings.concat(root, "/local-", stages[si], "-right.test"); let lav: []str = [driver(stages[si]), "test", "-c", "--ww-package-test", "production", "foo", localleft, leftout, strings.concat(root, "/local-", stages[si], "-left.status"), "--ww-package-test", "production", "foo", localright, rightout, strings.concat(root, "/local-", stages[si], "-right.status"), localleft]; runcommand(root, strings.concat("local-command-union-", stages[si]), lav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let localwork: str = strings.concat(leftout, ".sepwork/"); let li: i32 = 0; for (li < localids.len) { let suffixes: []str = [".unit.ww", ".wwi", ".a"]; let xi: i32 = 0; for (xi < suffixes.len) { let artifact: str = readfile(strings.concat(localwork, localstorage[li], suffixes[xi])); if (xi == 0) { assert(has(artifact, strings.concat("//ww:module-reset ", localids[li], "\n"))); } else { if (xi == 1) { assert(strings.hasprefix(artifact, strings.concat( "//ww:module ", localids[li], "\n"))); }; }; let refi: i32 = li * 3 + xi; if (si == 0) { localrefs[refi] = strings.dup(artifact); } else { assert(same(localrefs[refi], artifact)); }; xi += 1; }; li += 1; }; si += 1; }; clean(root); }; fn runtimepath(relative: str) str = { return strings.concat(repo(), "/test/package/runtime/", relative); }; // The single-FILE `ww test ` route wraps the same in-binary test // runtime as the directory-package route (cases/*), but through the // driver's single-file leg. One row per outcome class keeps that leg's // wiring honest; the runtime-internal classifications themselves are // owned by the cases/* tests above. @test fn singlefile_runtime_outcomes() void = { let root: str = fresh(); let out: commandout; let successav: []str = [driver("ww"), "test", runtimepath("success_test.ww")]; runcommand(root, "sf-success", successav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "alpha_pass ... ok\n")); assert(has(out.stdout, "beta_skip ... SKIP: synthetic unavailable feature\n")); assert(has(out.stdout, "gamma_expected_abort ... ok\n")); assert(has(out.stdout, "delta_pass ... ok\n")); assert(has(out.stdout, "3 passed, 0 failed, 1 skipped, 0 harness errors\n")); assert(has(out.stdout, "4 discovered, 4 selected, 4 started, 4 completed\n")); let failav: []str = [driver("ww"), "test", runtimepath("fail_test.ww")]; runcommand(root, "sf-fail", failav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "assertion_failure ... FAIL (exit 1)\n")); let multiav: []str = [driver("ww"), "test", runtimepath("multiple_fail_test.ww")]; runcommand(root, "sf-multi", multiav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "0 passed, 2 failed, 0 skipped, 0 harness errors\n")); let unmetav: []str = [driver("ww"), "test", runtimepath("expected_abort_return_test.ww")]; runcommand(root, "sf-unmet", unmetav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "expected_abort_must_happen ... FAIL (expected abort)\n")); let premav: []str = [driver("ww"), "test", runtimepath("premature_exit_test.ww")]; runcommand(root, "sf-premature", premav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "clean_exit_without_completion ... HARNESS (incomplete result)\n")); let sigav: []str = [driver("ww"), "test", runtimepath("signal_test.ww")]; runcommand(root, "sf-signal", sigav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "signal_is_not_exit ... FAIL (signal 15)\n")); // Record-and-continue past every fault class: the runner reports // hardware faults with their literal signal numbers and still // reaches the trailing test (retired 911_attest_record). let recav: []str = [driver("ww"), "test", runtimepath("record_continue_test.ww")]; runcommand(root, "sf-record", recav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "rec_pass_a ... ok\n")); assert(has(out.stdout, "rec_assert ... FAIL (exit 1)\n")); assert(has(out.stdout, "rec_segv ... FAIL (signal 11)\n")); assert(has(out.stdout, "rec_div0 ... FAIL (signal 8)\n")); assert(has(out.stdout, "rec_pass_b ... ok\n")); assert(has(out.stdout, "2 passed, 3 failed, 0 skipped, 0 harness errors\n")); assert(has(out.stdout, "5 discovered, 5 selected, 5 started, 5 completed\n")); clean(root); }; // Explicit linker search/library flags are retained by the package builder // and reach both native linkers in their accepted argv forms. This is a // real manifest-free build/run check, not a parser-only simulation. @test fn linker_flag_stage_parity() void = { let root: str = fresh(); let pkg: str = strings.concat(root, "/mainpkg"); let extra: str = strings.concat(root, "/extra"); let linktrace: str = strings.concat(root, "/link.trace"); let cwrapper: str = strings.concat(root, "/trace-w6l.sh"); assert(os.mkdir(pkg, 448i32) == 0); assert(os.mkdir(extra, 448i32) == 0); writefile(linktrace, ""); writeexecutable(cwrapper, strings.concat( "#!/bin/sh\n", "printf '%s\\n' \"$*\" >> \"$WW_LINK_FLAG_TRACE\"\n", "exec \"$WW_LINK_FLAG_W6L\" \"$@\"\n")); writefile(strings.concat(pkg, "/main.ww"), "package main;\nfn main() void = {};\n"); writefile(strings.concat(extra, "/extra.ww"), "package extra;\nexport fn marker() i32 = { return 7; };\n"); let extralib: str = strings.concat(root, "/libextra.a"); let libav: []str = [driver("ww"), "build", "-o", extralib, extra]; let out: commandout; runcommand(root, "link-flags-library", libav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let cbin: str = strings.concat(root, "/c-main"); let wwbin: str = strings.concat(root, "/ww-main"); let cav: []str = [driver("ww"), "build", "-L", root, "-l", "extra", "-o", cbin, pkg]; let baseenv: []str = os.getenvs(); let cenv: []str = alloc([], (baseenv.len + 3): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_LINK_FLAG_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_LINK_FLAG_W6L=")) { append(cenv, baseenv[ei]); }; ei += 1; }; append(cenv, strings.concat("WW_W6L=", cwrapper)); append(cenv, strings.concat("WW_LINK_FLAG_TRACE=", linktrace)); append(cenv, strings.concat("WW_LINK_FLAG_W6L=", driver("w6l"))); runcommandenv(root, "link-flags-c", cav, cenv, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let ctraced: str = readfile(linktrace); assert(has(ctraced, strings.concat(" -L ", root, " -l extra"))); // Keep this row on default sibling discovery: a copied driver beside a // tracing linker and exact compiler/assembler siblings proves WWstage uses // the same separate flag/value linker argv contract as Cstage. let tracedir: str = strings.concat(repo(), "/out/link-flag-trace-", workescape(root)); assert(os.mkdir(tracedir, 448i32) == 0); let tracedriver: str = strings.concat(tracedir, "/ww_ww"); writeexecutable(tracedriver, readfile(driver("ww_ww"))); writeexecutable(strings.concat(tracedir, "/w6c_ww"), readfile(driver("w6c_ww"))); writeexecutable(strings.concat(tracedir, "/w6a_ww"), readfile(driver("w6a_ww"))); writeexecutable(strings.concat(tracedir, "/w6l_ww"), strings.concat( "#!/bin/sh\n", "printf '%s\\n' \"$*\" >> \"$WW_LINK_FLAG_TRACE\"\n", "exec \"$WW_LINK_FLAG_W6L_WW\" \"$@\"\n")); let wenv: []str = alloc([], (baseenv.len + 2): u64)!; ei = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_LINK_FLAG_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_LINK_FLAG_W6L_WW=")) { append(wenv, baseenv[ei]); }; ei += 1; }; append(wenv, strings.concat("WW_LINK_FLAG_TRACE=", linktrace)); append(wenv, strings.concat("WW_LINK_FLAG_W6L_WW=", driver("w6l_ww"))); let twav: []str = [tracedriver, "build", "-L", root, "-l", "extra", "-o", wwbin, pkg]; runcommandenv(root, "link-flags-ww", twav, wenv, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let wtraced: str = readfile(linktrace); let wwdelta: str = strings.sub(wtraced, ctraced.len, wtraced.len); assert(has(wwdelta, strings.concat(" -L ", root, " -l extra"))); assert(!has(wwdelta, strings.concat(" -L", root))); assert(!has(wwdelta, " -lextra")); assert(same(readfile(cbin), readfile(wwbin))); let crun: []str = [cbin]; let wrun: []str = [wwbin]; runcommand(root, "link-flags-c-run", crun, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); runcommand(root, "link-flags-ww-run", wrun, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); clean(tracedir); clean(root); }; // The published test binary's OWN command surface: repeated glob args, // -list (with and without a glob), and -timeout-ms. Only a direct // invocation of the `-c` artifact proves these; every driver route // parses its flags before the binary sees them. @test fn published_binary_cli() void = { let root: str = fresh(); let out: commandout; let stem: str = strings.concat(root, "/rtsuccess"); let cav: []str = [driver("ww"), "test", "-c", "-o", stem, runtimepath("success_test.ww")]; runcommand(root, "publish", cav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let gav: []str = [stem, "alpha*", "delta*"]; runcommand(root, "globs", gav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "alpha_pass ... ok\n")); assert(has(out.stdout, "delta_pass ... ok\n")); assert(has(out.stdout, "2 passed, 0 failed, 0 skipped, 0 harness errors\n")); assert(has(out.stdout, "4 discovered, 2 selected, 2 started, 2 completed\n")); let lav: []str = [stem, "-list"]; runcommand(root, "list", lav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(out.stdout, "alpha_pass\nbeta_skip\ngamma_expected_abort\ndelta_pass\n")); let lgav: []str = [stem, "-list", "gamma*"]; runcommand(root, "list-glob", lgav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(out.stdout, "gamma_expected_abort\n")); let tav: []str = [stem, "-timeout-ms=50", "alpha*"]; runcommand(root, "cli-timeout", tav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "1 passed, 0 failed, 0 skipped, 0 harness errors\n")); clean(root); }; // Direct-binary timeout classification and descendant handling. The // runcommand deadline bounds the no-hang claims: a runner waiting on a // SIGTERM-blocking or process-group-escaped pipe writer would trip it. @test fn direct_binary_timeout_and_descendants() void = { let root: str = fresh(); let out: commandout; let tstem: str = strings.concat(root, "/rttimeout"); let tcav: []str = [driver("ww"), "test", "-c", "-o", tstem, runtimepath("timeout_test.ww")]; runcommand(root, "publish-timeout", tcav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let trun: []str = [tstem, "-timeout-ms=50"]; runcommand(root, "run-timeout", trun, (20i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stdout, "hang_times_out ... FAIL(timeout)\n")); let lstem: str = strings.concat(root, "/rtlinger"); let lcav: []str = [driver("ww"), "test", "-c", "-o", lstem, runtimepath("lingering_descendant_test.ww")]; runcommand(root, "publish-linger", lcav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let lrun: []str = [lstem, "-timeout-ms=250"]; runcommand(root, "run-linger", lrun, (20i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "returning_test_clears_descendant ... ok\n")); let estem: str = strings.concat(root, "/rtescaped"); let ecav: []str = [driver("ww"), "test", "-c", "-o", estem, runtimepath("escaped_descendant_test.ww")]; runcommand(root, "publish-escaped", ecav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let erun: []str = [estem, "-timeout-ms=250"]; runcommand(root, "run-escaped", erun, (20i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "escaped_writer_does_not_hold_runner ... ok\n")); clean(root); }; @test fn vendor_directory_import_resolution() void = { let root: str = fresh(); let source: str = strings.concat(root, "/source"); let runtime: str = strings.concat(root, "/runtime"); let tools: str = strings.concat(root, "/tools"); let leaf: str = strings.concat(source, "/lib/leaf"); let nearest: str = strings.concat(source, "/domain/app/vendor/lib/math"); let outer: str = strings.concat(source, "/domain/vendor/lib/math"); let rootvendor: str = strings.concat(source, "/vendor/lib/math"); let ordinary: str = strings.concat(source, "/lib/math"); let client: str = strings.concat(source, "/domain/app/client"); let one: str = strings.concat(source, "/domain/app/one"); let two: str = strings.concat(source, "/domain/app/two"); let outerclient: str = strings.concat(source, "/domain/other/client"); let rootclient: str = strings.concat(source, "/other/client"); let emptyclient: str = strings.concat(source, "/domain/empty/client"); let testonlyclient: str = strings.concat(source, "/domain/testonly/client"); let bareclient: str = strings.concat(source, "/domain/bare/client"); let outsider: str = strings.concat(source, "/outsider"); let prefixclient: str = strings.concat(source, "/domainx/client"); let directclient: str = strings.concat(source, "/domain/app/direct"); let directhijack: str = strings.concat(directclient, "/vendor/domain/app/vendor/lib/math"); let nested: str = strings.concat(source, "/nested/owner/vendor/outer/vendor/lib/math"); let nestedclient: str = strings.concat(source, "/nested/owner/vendor/outer/client"); let ordinaryclient: str = strings.concat(source, "/ordinaryclient"); let vendorx: str = strings.concat(source, "/vendorx/lib/math"); let terminalvendor: str = strings.concat(source, "/terminal/vendor"); let physicalclient: str = strings.concat(source, "/domain/app/physicalclient"); let aliasclient: str = strings.concat(source, "/aliasclient"); let physicaldirect: str = strings.concat(source, "/domain/app/physicaldirect"); let aliasdirect: str = strings.concat(source, "/aliasdirect"); let escapephysical: str = strings.concat(root, "/escape/client"); let escapeclient: str = strings.concat(source, "/domain/app/escape"); let shapeclient: str = strings.concat(source, "/shape/owner/client"); let shapevendor: str = strings.concat(source, "/shape/owner/vendor/lib/math"); let shapevault: str = strings.concat(root, "/vault/deep/different"); let testclient: str = strings.concat(source, "/domain/app/testclient"); let testbad: str = strings.concat(source, "/testbad"); let supportcase: str = strings.concat(source, "/supportcase"); let toolsource: str = strings.concat(root, "/toolsource"); let toolsupport: str = strings.concat(toolsource, "/test"); let toolvendor: str = strings.concat(toolsource, "/test/vendor/fnmatch"); let vendortest: str = strings.concat(source, "/literal/owner/vendor/lib/math"); let nestedvendortest: str = strings.concat(vendortest, "/vendor/lib/math"); let alpha: str = strings.concat(source, "/alpha/client"); let beta: str = strings.concat(source, "/beta/client"); let alphavendor: str = strings.concat(alpha, "/vendor/lib/math"); let betavendor: str = strings.concat(beta, "/vendor/lib/math"); let pairvault: str = strings.concat(root, "/pair-vault/math"); let boundary: str = strings.concat(root, "/boundary"); let active: str = strings.concat(boundary, "/active"); let boundaryclient: str = strings.concat(active, "/domain/app"); let boundaryordinary: str = strings.concat(active, "/lib/math"); let boundaryabove: str = strings.concat(boundary, "/vendor/lib/math"); let cleanroot: str = strings.concat(root, "/clean"); let cleanclient: str = strings.concat(cleanroot, "/domain/app"); let cleanordinary: str = strings.concat(cleanroot, "/lib/math"); let dirs: []str = [leaf, nearest, outer, rootvendor, ordinary, client, one, two, outerclient, rootclient, emptyclient, strings.concat(emptyclient, "/vendor/lib/math/fake.ww"), testonlyclient, strings.concat(testonlyclient, "/vendor/lib/math"), bareclient, strings.concat(bareclient, "/vendor/lib/math"), outsider, prefixclient, directclient, directhijack, nested, nestedclient, ordinaryclient, vendorx, terminalvendor, physicalclient, physicaldirect, escapephysical, shapeclient, strings.concat(source, "/shape/owner/vendor/lib"), shapevault, testclient, testbad, supportcase, toolsupport, toolvendor, vendortest, nestedvendortest, alpha, beta, strings.concat(alpha, "/vendor/lib"), strings.concat(beta, "/vendor/lib"), pairvault, boundaryclient, boundaryordinary, boundaryabove, cleanclient, cleanordinary, runtime, tools]; let di: i32 = 0; for (di < dirs.len) { mkdirall(dirs[di]); di += 1; }; writefile(strings.concat(runtime, "/libwwrt.a"), readfile(strings.concat(repo(), "/out/lib/libwwrt.a"))); writefile(strings.concat(leaf, "/leaf.ww"), strings.concat( "package leaf;\n", "export fn value() i32 = { return 1; };\n")); let neara: str = strings.concat( "package math;\nimport lib.leaf;\n", "export fn value() i32 = { return leaf.value() + 10; };\n"); let nearz: str = strings.concat( "package math;\n", "fn private_value() i32 = { return 99; };\n"); writefile(strings.concat(nearest, "/a.ww"), neara); writefile(strings.concat(nearest, "/z.ww"), nearz); writefile(strings.concat(outer, "/math.ww"), "package math;\nexport fn value() i32 = { return 22; };\n"); writefile(strings.concat(rootvendor, "/math.ww"), "package math;\nexport fn value() i32 = { return 33; };\n"); writefile(strings.concat(ordinary, "/math.ww"), "package math;\nexport fn value() i32 = { return 44; };\n"); let mainbody: str = strings.concat( "package main;\nimport lib.math;\n", "fn main() i32 = { return math.value(); };\n"); writefile(strings.concat(client, "/main.ww"), mainbody); writefile(strings.concat(one, "/main.ww"), mainbody); writefile(strings.concat(two, "/main.ww"), mainbody); writefile(strings.concat(outerclient, "/main.ww"), mainbody); writefile(strings.concat(rootclient, "/main.ww"), mainbody); writefile(strings.concat(emptyclient, "/main.ww"), mainbody); writefile(strings.concat(testonlyclient, "/main.ww"), mainbody); writefile(strings.concat(testonlyclient, "/vendor/lib/math/only_test.ww"), "package math;\n@test fn only() void = { assert(true); };\n"); writefile(strings.concat(bareclient, "/main.ww"), mainbody); writefile(strings.concat(bareclient, "/vendor/lib/math/.ww"), "package math;\n"); let expanded: str = "domain.app.vendor.lib.math"; let directbody: str = strings.concat( "package main;\nimport ", expanded, ";\n", "fn main() i32 = { return math.value(); };\n"); writefile(strings.concat(outsider, "/main.ww"), directbody); writefile(strings.concat(prefixclient, "/main.ww"), directbody); writefile(strings.concat(directclient, "/main.ww"), directbody); writefile(strings.concat(directhijack, "/math.ww"), "package math;\nexport fn value() i32 = { return 99; };\n"); writefile(strings.concat(nested, "/math.ww"), "package math;\nexport fn value() i32 = { return 77; };\n"); writefile(strings.concat(nestedclient, "/main.ww"), mainbody); writefile(strings.concat(vendorx, "/math.ww"), "package math;\nexport fn value() i32 = { return 4; };\n"); writefile(strings.concat(terminalvendor, "/vendor.ww"), "package vendor;\nexport fn value() i32 = { return 8; };\n"); writefile(strings.concat(ordinaryclient, "/main.ww"), strings.concat( "package main;\nimport vendorx.lib.math;\nimport terminal.vendor;\n", "fn main() i32 = { return math.value() + vendor.value(); };\n")); writefile(strings.concat(physicalclient, "/main.ww"), mainbody); assert(os.symlink(physicalclient, aliasclient) == 0); writefile(strings.concat(physicaldirect, "/main.ww"), directbody); assert(os.symlink(physicaldirect, aliasdirect) == 0); writefile(strings.concat(escapephysical, "/main.ww"), mainbody); assert(os.symlink(escapephysical, escapeclient) == 0); writefile(strings.concat(shapevault, "/math.ww"), "package math;\nexport fn value() i32 = { return 17; };\n"); assert(os.symlink(shapevault, shapevendor) == 0); writefile(strings.concat(shapeclient, "/main.ww"), mainbody); writefile(strings.concat(testclient, "/testclient.ww"), strings.concat( "package testclient;\nimport lib.math;\n", "export fn value() i32 = { return math.value(); };\n")); writefile(strings.concat(testclient, "/same_test.ww"), strings.concat( "package testclient;\nimport lib.math;\n", "@test fn same_vendor() void = { assert(math.value() == 11); };\n")); writefile(strings.concat(testclient, "/external_test.ww"), strings.concat( "package testclient_test;\nimport lib.math;\n", "import domain.app.testclient;\n", "@test fn external_vendor() void = {\n", " assert(math.value() + testclient.value() == 22);\n};\n")); writefile(strings.concat(testbad, "/testbad.ww"), "package testbad;\nexport fn value() i32 = { return 1; };\n"); writefile(strings.concat(testbad, "/same_test.ww"), strings.concat( "package testbad;\nimport ", expanded, ";\n", "@test fn forbidden_vendor() void = { assert(false); };\n")); writefile(strings.concat(supportcase, "/supportcase.ww"), "package supportcase;\nexport fn value() i32 = { return 1; };\n"); writefile(strings.concat(supportcase, "/supportcase_test.ww"), "package supportcase;\n@test fn support_runs() void = { assert(value() == 1); };\n"); writefile(strings.concat(toolsupport, "/run.ww"), readfile(strings.concat(repo(), "/lib/test/run.ww"))); writefile(strings.concat(toolvendor, "/fnmatch.ww"), readfile(strings.concat(repo(), "/lib/fnmatch/fnmatch.ww"))); let tooldeps: []str = ["ascii", "bytes", "encoding", "os", "rt", "strings", "time", "types"]; di = 0; for (di < tooldeps.len) { assert(os.symlink(strings.concat(repo(), "/lib/", tooldeps[di]), strings.concat(toolsource, "/", tooldeps[di])) == 0); di += 1; }; writefile(strings.concat(vendortest, "/math.ww"), "package math;\nexport fn value() i32 = { return 7; };\n"); writefile(strings.concat(vendortest, "/math_test.ww"), strings.concat( "package math_test;\nimport lib.math;\n", "@test fn nested_external_vendor() void = {\n", " assert(math.value() == 9);\n};\n")); writefile(strings.concat(nestedvendortest, "/math.ww"), "package math;\nexport fn value() i32 = { return 9; };\n"); writefile(strings.concat(pairvault, "/math.ww"), "package math;\nexport fn value() i32 = { return 61; };\n"); assert(os.symlink(pairvault, alphavendor) == 0); assert(os.symlink(pairvault, betavendor) == 0); writefile(strings.concat(alpha, "/main.ww"), mainbody); writefile(strings.concat(beta, "/main.ww"), mainbody); writefile(strings.concat(boundaryclient, "/main.ww"), mainbody); writefile(strings.concat(boundaryordinary, "/math.ww"), "package math;\nexport fn value() i32 = { return 55; };\n"); writefile(strings.concat(boundaryabove, "/math.ww"), "package math;\nexport fn value() i32 = { return 66; };\n"); writefile(strings.concat(cleanclient, "/main.ww"), mainbody); writefile(strings.concat(cleanordinary, "/math.ww"), "package math;\nexport fn value() i32 = { return 44; };\n"); let compilerwrapper: str = strings.concat(tools, "/w6c.sh"); let assemblerwrapper: str = strings.concat(tools, "/w6a.sh"); let linkerwrapper: str = strings.concat(tools, "/w6l.sh"); writeexecutable(compilerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_VENDOR_COMPILER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_VENDOR_COMPILER_TRACE\"; done\n", "printf '\\n' >> \"$WW_VENDOR_COMPILER_TRACE\"\n", "exec \"$WW_VENDOR_REAL_COMPILER\" \"$@\"\n")); writeexecutable(assemblerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_VENDOR_ASSEMBLER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_VENDOR_ASSEMBLER_TRACE\"; done\n", "printf '\\n' >> \"$WW_VENDOR_ASSEMBLER_TRACE\"\n", "exec \"$WW_VENDOR_REAL_ASSEMBLER\" \"$@\"\n")); writeexecutable(linkerwrapper, strings.concat( "#!/bin/sh\nprintf 'BEGIN' >> \"$WW_VENDOR_LINKER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_VENDOR_LINKER_TRACE\"; done\n", "printf '\\n' >> \"$WW_VENDOR_LINKER_TRACE\"\n", "exec \"$WW_VENDOR_REAL_LINKER\" \"$@\"\n")); let stages: []str = ["ww", "ww_ww"]; let compilers: []str = ["w6c", "w6c_ww"]; let assemblers: []str = ["w6a", "w6a_ww"]; let linkers: []str = ["w6l", "w6l_ww"]; let works: []str = [strings.concat(root, "/c-work"), strings.concat(root, "/ww-work")]; let bins: []str = [strings.concat(root, "/c-bin"), strings.concat(root, "/ww-bin")]; let compilertraces: []str = [strings.concat(root, "/c-compiler"), strings.concat(root, "/ww-compiler")]; let assemblertraces: []str = [strings.concat(root, "/c-assembler"), strings.concat(root, "/ww-assembler")]; let linkertraces: []str = [strings.concat(root, "/c-linker"), strings.concat(root, "/ww-linker")]; let coreartifacts: []str = ["lib.leaf", expanded, "domain.app.client"]; let coresuffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"]; let references: []str = alloc([], (coreartifacts.len * coresuffixes.len): u64)!; let ri: i32 = 0; for (ri < coreartifacts.len * coresuffixes.len) { append(references, ""); ri += 1; }; let referencebin: str = ""; let referencecompiler: str = ""; let referenceassembler: str = ""; let referencelinker: str = ""; let referencedirectdiag: str = ""; let referenceoutsidediag: str = ""; let combinedrefs: []str = ["", "", "", "", "", ""]; let referencetestout: str = ""; let referencetesterr: str = ""; let testrefs: []str = ["", "", "", "", "", ""]; let referencesupportout: str = ""; let supportrefs: []str = ["", "", ""]; let referenceorderdiag: str = ""; let referenceescapeddiag: str = ""; let referencealiasdirectdiag: str = ""; let referenceprefixdiag: str = ""; let candidate_diag_refs: []str = ["", ""]; let supplementalrefs: []str = ["", "", "", "", "", "", "", "", ""]; let referencevendortestout: str = ""; let referencevendortesterr: str = ""; let referencetestbaddiag: str = ""; let baseenv: []str = os.getenvs(); let si: i32 = 0; for (si < stages.len) { assert(os.mkdir(works[si], 448i32) == 0); writefile(compilertraces[si], ""); writefile(assemblertraces[si], ""); writefile(linkertraces[si], ""); let env: []str = alloc([], (baseenv.len + 11): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6A=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_LIB=") && !strings.hasprefix(baseenv[ei], "WW_SRCLIB=") && !strings.hasprefix(baseenv[ei], "WW_VENDOR_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_VENDOR_ASSEMBLER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_VENDOR_LINKER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_VENDOR_REAL_COMPILER=") && !strings.hasprefix(baseenv[ei], "WW_VENDOR_REAL_ASSEMBLER=") && !strings.hasprefix(baseenv[ei], "WW_VENDOR_REAL_LINKER=")) { append(env, baseenv[ei]); }; ei += 1; }; append(env, strings.concat("WW_W6C=", compilerwrapper)); append(env, strings.concat("WW_W6A=", assemblerwrapper)); append(env, strings.concat("WW_W6L=", linkerwrapper)); append(env, strings.concat("WW_LIB=", runtime)); append(env, strings.concat("WW_VENDOR_COMPILER_TRACE=", compilertraces[si])); append(env, strings.concat("WW_VENDOR_ASSEMBLER_TRACE=", assemblertraces[si])); append(env, strings.concat("WW_VENDOR_LINKER_TRACE=", linkertraces[si])); append(env, strings.concat("WW_VENDOR_REAL_COMPILER=", driver(compilers[si]))); append(env, strings.concat("WW_VENDOR_REAL_ASSEMBLER=", driver(assemblers[si]))); append(env, strings.concat("WW_VENDOR_REAL_LINKER=", driver(linkers[si]))); let av: []str = [driver(stages[si]), "build", "-w", works[si], "-I", source, "-o", bins[si], client]; let out: commandout; runcommandenv(root, strings.concat("vendor-cold-", stages[si]), av, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); let wantnear: str = strings.concat( "//ww:module-reset ", expanded, "\n", neara, "\n", "//ww:module-reset ", expanded, "\n", nearz, "\n", "//ww:vendor-dir ", hexbytes(nearest), "\n"); let nearunit: str = readfile(strings.concat(works[si], "/", expanded, ".unit.ww")); assert(strings.hasprefix(nearunit, wantnear)); assert(has(nearunit, "//ww:direct-export lib.leaf ")); let clientunit: str = readfile(strings.concat(works[si], "/domain.app.client.unit.ww")); assert(has(clientunit, strings.concat("//ww:import-map lib.math ", expanded, " ", hexbytes(nearest), "\n"))); let ai: i32 = 0; for (ai < coreartifacts.len) { let xi: i32 = 0; for (xi < coresuffixes.len) { let bytes: str = readfile(strings.concat(works[si], "/", coreartifacts[ai], coresuffixes[xi])); let index: i32 = ai * coresuffixes.len + xi; if (si == 0) { references[index] = strings.dup(bytes); } else { assert(same(references[index], bytes)); }; xi += 1; }; ai += 1; }; let ctrace: str = readfile(compilertraces[si]); let atrace: str = readfile(assemblertraces[si]); let ltrace: str = readfile(linkertraces[si]); assert(occurrences(ctrace, "\n") == 3); assert(occurrences(atrace, "\n") == 4); assert(occurrences(ltrace, "\n") == 1); assert(has(ltrace, strings.concat("BEGIN<-o><", bins[si], ".new>"))); let dispatchline: str = strings.concat("BEGIN<-o><", works[si], "/domain.app.client.init.o.new><", works[si], "/domain.app.client.init.s.new>"); assert(same(linecontaining(atrace, "/domain.app.client.init.o.new"), dispatchline)); let nearline: str = linecontaining(ctrace, strings.concat(expanded, ".unit.new")); assert(occurrences(nearline, "<--import>") == 1); assert(!has(nearline, "domain.app.client.wwi")); let clientline: str = linecontaining(ctrace, "domain.app.client.unit.new"); assert(occurrences(clientline, strings.concat("<--import><", expanded, "><", works[si], "/", expanded, ".wwi.new>")) == 1); assert(occurrences(clientline, strings.concat( "<--import-map><", expanded, ">")) == 1); assert(!has(clientline, "lib.leaf.wwi")); assert(occurrences(ltrace, strings.concat("<", works[si], "/domain.app.client.a.new>")) == 1); assert(occurrences(ltrace, strings.concat("<", works[si], "/", expanded, ".a.new>")) == 1); assert(occurrences(ltrace, strings.concat("<", works[si], "/lib.leaf.a.new>")) == 1); assert(!has(ltrace, ".wwi>")); let nc: str = normalizedtrace(ctrace, strings.concat(works[si], "/"), bins[si]); let na: str = normalizedtrace(atrace, strings.concat(works[si], "/"), bins[si]); let nl: str = normalizedtrace(ltrace, strings.concat(works[si], "/"), bins[si]); if (si == 0) { referencecompiler = strings.dup(nc); referenceassembler = strings.dup(na); referencelinker = strings.dup(nl); referencebin = strings.dup(readfile(bins[si])); } else { assert(same(referencecompiler, nc)); assert(same(referenceassembler, na)); assert(same(referencelinker, nl)); assert(same(referencebin, readfile(bins[si]))); }; let runav: []str = [bins[si]]; runcommand(root, strings.concat("vendor-run-", stages[si]), runav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 11); let voucher: str = readfile(strings.concat(works[si], "/", expanded, ".unit.ww")); let toolww: str = readfile(strings.concat(works[si], "/.wwtool.ww")); let toolc: str = readfile(strings.concat(works[si], "/.wwtool.w6c")); let toola: str = readfile(strings.concat(works[si], "/.wwtool.w6a")); let stamp: str = readfile(strings.concat(works[si], "/.wwtool.stamp")); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); runcommandenv(root, strings.concat("vendor-warm-", stages[si]), av, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(occurrences(readfile(linkertraces[si]), "\n") == 1); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let badout: str = strings.concat(root, "/warm-bad-", stages[si]); let badav: []str = [driver(stages[si]), "build", "-w", works[si], "-I", source, "-o", badout, outsider]; runcommandenv(root, strings.concat("vendor-warm-bad-", stages[si]), badav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let outsidediag: str = strings.concat(outsider, "/main.ww:2:1: error: use of vendored package not allowed\n"); assert(same(out.stderr, outsidediag)); if (si == 0) { referenceoutsidediag = strings.dup(out.stderr); } else { assert(same(referenceoutsidediag, out.stderr)); }; assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); assert(!os.exists(badout)); assert(same(voucher, readfile(strings.concat(works[si], "/", expanded, ".unit.ww")))); assert(same(toolww, readfile(strings.concat(works[si], "/.wwtool.ww")))); assert(same(toolc, readfile(strings.concat(works[si], "/.wwtool.w6c")))); assert(same(toola, readfile(strings.concat(works[si], "/.wwtool.w6a")))); assert(same(stamp, readfile(strings.concat(works[si], "/.wwtool.stamp")))); ai = 0; for (ai < coreartifacts.len) { let xi: i32 = 0; for (xi < coresuffixes.len) { let index: i32 = ai * coresuffixes.len + xi; assert(same(references[index], readfile(strings.concat( works[si], "/", coreartifacts[ai], coresuffixes[xi])))); xi += 1; }; ai += 1; }; let coldout: str = strings.concat(root, "/cold-bad-", stages[si]); let coldav: []str = [driver(stages[si]), "build", "-I", source, "-o", coldout, outsider]; runcommandenv(root, strings.concat("vendor-cold-bad-", stages[si]), coldav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(same(out.stderr, outsidediag)); assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); assert(!os.exists(coldout)); assert(!os.exists(strings.concat(coldout, ".sepwork"))); let directout: str = strings.concat(root, "/direct-bad-", stages[si]); let directav: []str = [driver(stages[si]), "build", "-I", source, "-o", directout, directclient]; runcommandenv(root, strings.concat("vendor-direct-bad-", stages[si]), directav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let directdiag: str = strings.concat(directclient, "/main.ww:2:1: error: ", expanded, " must be imported as lib.math\n"); assert(same(out.stderr, directdiag)); if (si == 0) { referencedirectdiag = strings.dup(out.stderr); } else { assert(same(referencedirectdiag, out.stderr)); }; assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); assert(!os.exists(directout)); assert(!os.exists(strings.concat(directout, ".sepwork"))); // The lexical importer is outside domain/app, but the symlink target is // physically inside it. Visibility therefore passes and the later // effective-spelling diagnostic proves physical importer containment. let aliasdirectout: str = strings.concat(root, "/alias-direct-bad-", stages[si]); let aliasdirectav: []str = [driver(stages[si]), "build", "-I", source, "-o", aliasdirectout, aliasdirect]; runcommandenv(root, strings.concat("vendor-alias-direct-bad-", stages[si]), aliasdirectav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let aliasdirectdiag: str = strings.concat(aliasdirect, "/main.ww:2:1: error: ", expanded, " must be imported as lib.math\n"); assert(same(out.stderr, aliasdirectdiag)); if (si == 0) { referencealiasdirectdiag = strings.dup(out.stderr); } else { assert(same(referencealiasdirectdiag, out.stderr)); }; assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); assert(!os.exists(aliasdirectout)); assert(!os.exists(strings.concat(aliasdirectout, ".sepwork"))); // Remaining resolution rows reuse the stage workdir, but every output // remains independently executable and compared across stages below. let targets: []str = [outerclient, rootclient, emptyclient, boundaryclient, cleanclient, nestedclient, ordinaryclient, aliasclient, shapeclient]; let roots: []str = [source, source, source, active, cleanroot, source, source, source, source]; let codes: []i32 = [22, 33, 22, 55, 44, 77, 12, 33, 17]; let labels: []str = ["outer", "root", "empty", "boundary", "ordinary", "nested", "names", "alias", "shape"]; let ti: i32 = 0; for (ti < targets.len) { let output: str = strings.concat(root, "/", labels[ti], "-", stages[si]); let tav: []str = [driver(stages[si]), "build", "-w", works[si], "-I", roots[ti], "-o", output, targets[ti]]; runcommandenv(root, strings.concat("vendor-", labels[ti], "-", stages[si]), tav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let rr: []str = [output]; runcommand(root, strings.concat("vendor-run-", labels[ti], "-", stages[si]), rr, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, codes[ti]); if (si == 0) { supplementalrefs[ti] = strings.dup(readfile(output)); } else { assert(same(supplementalrefs[ti], readfile(output))); }; ti += 1; }; let escapedout: str = strings.concat(root, "/escape-bad-", stages[si]); let escapedav: []str = [driver(stages[si]), "build", "-I", source, "-o", escapedout, escapeclient]; runcommandenv(root, strings.concat("vendor-escape-bad-", stages[si]), escapedav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, "use of vendored package not allowed\n")); if (si == 0) { referenceescapeddiag = strings.dup(out.stderr); } else { assert(same(referenceescapeddiag, out.stderr)); }; let prefixout: str = strings.concat(root, "/prefix-bad-", stages[si]); let prefixav: []str = [driver(stages[si]), "build", "-I", source, "-o", prefixout, prefixclient]; runcommandenv(root, strings.concat("vendor-prefix-bad-", stages[si]), prefixav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, "use of vendored package not allowed\n")); if (si == 0) { referenceprefixdiag = strings.dup(out.stderr); } else { assert(same(referenceprefixdiag, out.stderr)); }; let candidateclients: []str = [testonlyclient, bareclient]; let candidatefiles: []str = ["only_test.ww", ".ww"]; let ci: i32 = 0; for (ci < candidateclients.len) { let candidateout: str = strings.concat(root, "/candidate-bad-", stages[si], "-", candidatefiles[ci]); let cav: []str = [driver(stages[si]), "build", "-I", source, "-o", candidateout, candidateclients[ci]]; runcommandenv(root, strings.concat("vendor-candidate-bad-", stages[si], "-", candidatefiles[ci]), cav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, "/vendor/lib/math: directory contains no WW package sources\n")); assert(!os.exists(strings.concat(candidateout, ".sepwork"))); if (si == 0) { candidate_diag_refs[ci] = strings.dup(out.stderr); } else { assert(same(candidate_diag_refs[ci], out.stderr)); }; ci += 1; }; let selected: str = strings.concat(root, "/selected-", stages[si], ".a"); let selectedav: []str = [driver(stages[si]), "build", "-I", source, "-o", selected, nearest]; runcommandenv(root, strings.concat("vendor-selected-", stages[si]), selectedav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(references[1 * coresuffixes.len + 4], readfile(selected))); assert(same(references[1 * coresuffixes.len + 1], readfile(strings.concat(selected, ".wwi")))); // One command-global union shares one vendored action between three // importers, keeps an outer physical copy distinct, and also keeps two // expanded identities distinct when their lexical vendor routes converge // through symlinks on one physical directory. rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let combinedwork: str = strings.concat(root, "/combined-work-", stages[si]); assert(os.mkdir(combinedwork, 448i32) == 0); let combinedtargets: []str = [client, one, two, outerclient, alpha, beta, pairvault]; let combinedpackages: []str = ["main", "main", "main", "main", "main", "main", "math"]; let combinedcodes: []i32 = [0, 0, 0, 0, 0, 0, 0]; let combinedoutputs: []str = [ strings.concat(root, "/combined-client-", stages[si]), strings.concat(root, "/combined-one-", stages[si]), strings.concat(root, "/combined-two-", stages[si]), strings.concat(root, "/combined-outer-", stages[si]), strings.concat(root, "/combined-alpha-", stages[si]), strings.concat(root, "/combined-beta-", stages[si]), strings.concat(root, "/combined-local-", stages[si])]; let combinedstatuses: []str = [ strings.concat(combinedoutputs[0], ".status"), strings.concat(combinedoutputs[1], ".status"), strings.concat(combinedoutputs[2], ".status"), strings.concat(combinedoutputs[3], ".status"), strings.concat(combinedoutputs[4], ".status"), strings.concat(combinedoutputs[5], ".status"), strings.concat(combinedoutputs[6], ".status")]; let combinedav: []str = alloc([], (8 + combinedtargets.len * 6): u64)!; append(combinedav, driver(stages[si])); append(combinedav, "test"); append(combinedav, "-c"); append(combinedav, "-w"); append(combinedav, combinedwork); append(combinedav, "-I"); append(combinedav, source); let ui: i32 = 0; for (ui < combinedtargets.len) { append(combinedav, "--ww-package-test"); append(combinedav, "production"); append(combinedav, combinedpackages[ui]); append(combinedav, combinedtargets[ui]); append(combinedav, combinedoutputs[ui]); append(combinedav, combinedstatuses[ui]); ui += 1; }; append(combinedav, client); runcommandenv(root, strings.concat("vendor-combined-", stages[si]), combinedav, env, (180i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); let combinedtrace: str = readfile(compilertraces[si]); assert(occurrences(combinedtrace, strings.concat("/", expanded, ".unit.new")) == 1); assert(occurrences(combinedtrace, "/domain.vendor.lib.math.unit.new") == 1); assert(occurrences(combinedtrace, "/alpha.client.vendor.lib.math.unit.new") == 1); assert(occurrences(combinedtrace, "/beta.client.vendor.lib.math.unit.new") == 1); assert(has(combinedtrace, localidentity(pairvault, "math"))); assert(occurrences(combinedtrace, "/lib.leaf.unit.new") == 1); let combinedidentities: []str = [expanded, "alpha.client.vendor.lib.math", "beta.client.vendor.lib.math"]; let combinedsuffixes: []str = [".wwi", ".a"]; ui = 0; for (ui < combinedidentities.len) { let xi: i32 = 0; for (xi < combinedsuffixes.len) { let bytes: str = readfile(strings.concat(combinedwork, "/", combinedidentities[ui], combinedsuffixes[xi])); let index: i32 = ui * combinedsuffixes.len + xi; if (si == 0) { combinedrefs[index] = strings.dup(bytes); } else { assert(same(combinedrefs[index], bytes)); }; xi += 1; }; ui += 1; }; assert(os.exists(strings.concat(combinedwork, "/domain.vendor.lib.math.wwi"))); assert(os.exists(strings.concat(combinedwork, "/domain.vendor.lib.math.a"))); ui = 0; for (ui < combinedoutputs.len) { let cav: []str = [combinedoutputs[ui]]; runcommand(root, strings.concat("vendor-combined-run-", stages[si], "-", labels[ui]), cav, (60i64 * (time.second: i64)): time.duration, &out); expectexit(&out, combinedcodes[ui]); ui += 1; }; // A target interned by the allowed product is still checked at the // forbidden source edge. Reversing product descriptors changes neither // the diagnostic nor any status/tool state. let orderwork: str = strings.concat(root, "/vendor-order-work-", stages[si]); assert(os.mkdir(orderwork, 448i32) == 0); let orderallowed: str = strings.concat(root, "/vendor-order-allowed-", stages[si]); let orderforbidden: str = strings.concat(root, "/vendor-order-forbidden-", stages[si]); let orderallowedstatus: str = strings.concat(orderallowed, ".status"); let orderforbiddenstatus: str = strings.concat(orderforbidden, ".status"); writefile(orderallowedstatus, "sentinel-allowed\n"); writefile(orderforbiddenstatus, "sentinel-forbidden\n"); let orderforward: []str = [driver(stages[si]), "test", "-c", "-w", orderwork, "-I", source, "--ww-package-test", "production", "main", client, orderallowed, orderallowedstatus, "--ww-package-test", "production", "main", outsider, orderforbidden, orderforbiddenstatus, client]; let orderreverse: []str = [driver(stages[si]), "test", "-c", "-w", orderwork, "-I", source, "--ww-package-test", "production", "main", outsider, orderforbidden, orderforbiddenstatus, "--ww-package-test", "production", "main", client, orderallowed, orderallowedstatus, client]; let orderrequests: [][]str = [orderforward, orderreverse]; let orderdiags: []str = ["", ""]; let oi: i32 = 0; for (oi < orderrequests.len) { rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); runcommandenv(root, strings.concat("vendor-order-", stages[si], "-", labels[oi]), orderrequests[oi], env, (180i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(same(out.stderr, outsidediag)); orderdiags[oi] = strings.dup(out.stderr); assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); assert(same(readfile(orderallowedstatus), "sentinel-allowed\n")); assert(same(readfile(orderforbiddenstatus), "sentinel-forbidden\n")); assert(!os.exists(strings.concat(orderwork, "/.wwtool.stamp"))); assert(!os.exists(orderallowed) && !os.exists(orderforbidden)); oi += 1; }; assert(same(orderdiags[0], orderdiags[1])); if (si == 0) { referenceorderdiag = strings.dup(orderdiags[0]); } else { assert(same(referenceorderdiag, orderdiags[0])); }; // Production, same-package test, and external test sources all retain // their short spelling while consuming the one expanded direct export. let testworkroot: str = strings.concat(root, "/vendor-test-work-", stages[si]); assert(os.mkdir(testworkroot, 448i32) == 0); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let testav: []str = [driver(stages[si]), "test", "-w", testworkroot, "-I", source, testclient]; runcommandenv(root, strings.concat("vendor-tests-", stages[si]), testav, env, (180i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "same_vendor ... ok\n")); assert(has(out.stdout, "external_vendor ... ok\n")); if (si == 0) { referencetestout = strings.dup(out.stdout); referencetesterr = strings.dup(out.stderr); } else { assert(same(referencetestout, out.stdout)); assert(same(referencetesterr, out.stderr)); }; let testwork: str = strings.concat(testworkroot, "/"); let testactions: []str = ["domain.app.testclient-internal-test", "domain.app.testclient_test-external-test"]; let testsuffixes: []str = [".unit.ww", ".wwi", ".a"]; ui = 0; for (ui < testactions.len) { let xi: i32 = 0; for (xi < testsuffixes.len) { let bytes: str = readfile(strings.concat(testwork, testactions[ui], testsuffixes[xi])); let index: i32 = ui * testsuffixes.len + xi; if (si == 0) { testrefs[index] = strings.dup(bytes); } else { assert(same(testrefs[index], bytes)); }; xi += 1; }; assert(has(readfile(strings.concat(testwork, testactions[ui], ".unit.ww")), strings.concat("//ww:import-map lib.math ", expanded, " ", hexbytes(nearest), "\n"))); ui += 1; }; let testtrace: str = readfile(compilertraces[si]); assert(occurrences(testtrace, strings.concat("/", expanded, ".unit.new")) == 1); let internalline: str = linecontaining(testtrace, "domain.app.testclient-internal-test.unit.new"); let externalline: str = linecontaining(testtrace, "domain.app.testclient_test-external-test.unit.new"); assert(occurrences(internalline, strings.concat("<--import><", expanded, "><", testwork, expanded, ".wwi.new>")) == 1); assert(occurrences(externalline, strings.concat("<--import><", expanded, "><", testwork, expanded, ".wwi.new>")) == 1); assert(occurrences(internalline, strings.concat( "<--import-map><", expanded, ">")) == 1); assert(occurrences(externalline, strings.concat( "<--import-map><", expanded, ">")) == 1); assert(!has(internalline, "lib.leaf.wwi")); assert(!has(externalline, "lib.leaf.wwi")); let internalmainline: str = linecontaining(testtrace, "domain.app.testclient-internal-test-main.unit.new"); let externalmainline: str = linecontaining(testtrace, "domain.app.testclient_test-external-test-main.unit.new"); assert(!has(internalmainline, expanded)); assert(!has(externalmainline, expanded)); assert(!has(readfile(linkertraces[si]), ".wwi>")); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); runcommandenv(root, strings.concat("vendor-tests-warm-", stages[si]), testav, env, (180i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(same(referencetestout, out.stdout)); assert(same(referencetesterr, out.stderr)); assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); // A directly selected vendored test root is legal, and its external // source still performs the ordinary nearest-vendor search first. rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let vendortestav: []str = [driver(stages[si]), "test", "-I", source, vendortest]; runcommandenv(root, strings.concat("vendor-literal-test-", stages[si]), vendortestav, env, (180i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "nested_external_vendor ... ok\n")); if (si == 0) { referencevendortestout = strings.dup(out.stdout); referencevendortesterr = strings.dup(out.stderr); } else { assert(same(referencevendortestout, out.stdout)); assert(same(referencevendortesterr, out.stderr)); }; assert(has(readfile(compilertraces[si]), "literal.owner.vendor.lib.math.vendor.lib.math.unit.ww")); // A cold forbidden public test request is rejected before any // persistent tool or package state is written. let testbadworkroot: str = strings.concat(root, "/vendor-test-bad-work-", stages[si]); assert(os.mkdir(testbadworkroot, 448i32) == 0); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let testbadav: []str = [driver(stages[si]), "test", "-w", testbadworkroot, "-I", source, testbad]; runcommandenv(root, strings.concat("vendor-test-bad-", stages[si]), testbadav, env, (180i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); let testbaddiag: str = strings.concat(testbad, "/same_test.ww:2:1: error: use of vendored package not allowed\n"); assert(has(out.stderr, testbaddiag)); if (si == 0) { referencetestbaddiag = strings.dup(out.stderr); } else { assert(same(referencetestbaddiag, out.stderr)); }; assert(!os.exists(strings.concat(testbadworkroot, "/.wwtool.stamp"))); assert(readfile(compilertraces[si]).len == 0); assert(readfile(assemblertraces[si]).len == 0); assert(readfile(linkertraces[si]).len == 0); // The coordinator's synthetic support/main edges stay synthetic, while // imports written in the real test-support source use this same resolver. let supportenv: []str = alloc([], (env.len + 1): u64)!; ei = 0; for (ei < env.len) { append(supportenv, env[ei]); ei += 1; }; append(supportenv, strings.concat("WW_SRCLIB=", toolsource)); let supportworkroot: str = strings.concat(root, "/vendor-support-work-", stages[si]); assert(os.mkdir(supportworkroot, 448i32) == 0); rewritefile(compilertraces[si], ""); rewritefile(assemblertraces[si], ""); rewritefile(linkertraces[si], ""); let supportav: []str = [driver(stages[si]), "test", "-w", supportworkroot, "-I", source, supportcase]; runcommandenv(root, strings.concat("vendor-support-", stages[si]), supportav, supportenv, (240i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "support_runs ... ok\n")); assert(out.stderr.len == 0); if (si == 0) { referencesupportout = strings.dup(out.stdout); } else { assert(same(referencesupportout, out.stdout)); }; let supportwork: str = strings.concat(supportworkroot, "/"); let supportunit: str = readfile(strings.concat(supportwork, "test.unit.ww")); assert(has(supportunit, strings.concat("//ww:import-map fnmatch ", "test.vendor.fnmatch ", hexbytes(toolvendor), "\n"))); assert(has(readfile(strings.concat(supportwork, "test.vendor.fnmatch.unit.ww")), strings.concat( "//ww:vendor-dir ", hexbytes(toolvendor), "\n"))); let supporttrace: str = readfile(compilertraces[si]); let supportline: str = linecontaining(supporttrace, "/test.unit.new"); assert(occurrences(supportline, "<--import>") == 1); assert(occurrences(supportline, "<--import-map>") == 1); assert(!has(supportline, "/ascii.wwi>")); assert(occurrences(supporttrace, "/test.vendor.fnmatch.unit.new") == 1); let supportmainline: str = linecontaining(supporttrace, "supportcase-internal-test-main.unit.new"); assert(!has(supportmainline, "test.vendor.fnmatch")); assert(!has(readfile(linkertraces[si]), ".wwi>")); let supportsuffixes: []str = [".unit.ww", ".wwi", ".a"]; ui = 0; for (ui < supportsuffixes.len) { let bytes: str = readfile(strings.concat(supportwork, "test.vendor.fnmatch", supportsuffixes[ui])); if (si == 0) { supportrefs[ui] = strings.dup(bytes); } else { assert(same(supportrefs[ui], bytes)); }; ui += 1; }; si += 1; }; clean(root); }; // The package-level -o contract: -c -o names the single package's // artifact in place of the fixed .test stem; -o without -c // has nothing to name (runs execute from the temp root); one name // cannot fan out over multiple packages (Go's `go test -o` rule). @test fn declared_name_identity_and_file_import_scope() void = { let root: str = fresh(); let source: str = strings.concat(root, "/source"); let tools: str = strings.concat(root, "/tools"); let codec: str = strings.concat(source, "/acme/codec"); let bridge: str = strings.concat(source, "/acme/bridge"); let direct: str = strings.concat(source, "/cmd/direct"); let app: str = strings.concat(source, "/cmd/app"); let scopeone: str = strings.concat(source, "/scope/one"); let scopetwo: str = strings.concat(source, "/scope/two"); let scoped: str = strings.concat(source, "/cmd/scoped"); let repeated: str = strings.concat(source, "/cmd/repeated"); let commitcodec: str = strings.concat(source, "/commit/codec"); let commitapp: str = strings.concat(source, "/cmd/commit"); let leafbad: str = strings.concat(source, "/cmd/leafbad"); let leak: str = strings.concat(source, "/cmd/leak"); let duplicate: str = strings.concat(source, "/cmd/duplicate"); let collision: str = strings.concat(source, "/cmd/collision"); let crosscollision: str = strings.concat(source, "/cmd/crosscollision"); let conflict: str = strings.concat(source, "/conflict/pkg"); let leafmain: str = strings.concat(source, "/domain/main"); let program: str = strings.concat(source, "/domain/program"); let leafmainuser: str = strings.concat(source, "/cmd/leafmain"); let programuser: str = strings.concat(source, "/cmd/programuser"); let testcodec: str = strings.concat(source, "/testpkg/codec"); let testhelper: str = strings.concat(source, "/testonly/helper"); let vendored: str = strings.concat(source, "/vend/vendor/short/codec"); let vendorclient: str = strings.concat(source, "/vend/client"); let dirs: []str = [source, tools, codec, bridge, direct, app, scopeone, scopetwo, scoped, repeated, commitcodec, commitapp, leafbad, leak, duplicate, collision, crosscollision, conflict, leafmain, program, leafmainuser, programuser, testcodec, testhelper, vendored, vendorclient]; let di: i32 = 0; for (di < dirs.len) { mkdirall(dirs[di]); di += 1; }; let wirebody: str = strings.concat( "package wire;\n", "export type Thing = i32;\n", "export fn value() i32 = { return 42; };\n"); let cablebody: str = strings.concat( "package cable;\n", "export type Thing = i32;\n", "export fn value() i32 = { return 42; };\n"); let codecfile: str = strings.concat(codec, "/codec.ww"); writefile(codecfile, wirebody); let commitcodecfile: str = strings.concat(commitcodec, "/codec.ww"); let commitappfile: str = strings.concat(commitapp, "/main.ww"); writefile(commitcodecfile, wirebody); writefile(commitappfile, strings.concat( "package main;\nimport commit.codec;\n", "fn main() i32 = { return wire.value(); };\n")); let bridgefile: str = strings.concat(bridge, "/bridge.ww"); let stablebridgebody: str = strings.concat( "package bridge;\nimport stable acme.codec;\n", "export type BridgedThing = stable.Thing;\n", "export fn bridged() i32 = { return stable.value(); };\n"); let steadybridgebody: str = strings.concat( "package bridge;\nimport steady acme.codec;\n", "export type BridgedThing = steady.Thing;\n", "export fn bridged() i32 = { return steady.value(); };\n"); writefile(bridgefile, stablebridgebody); writefile(strings.concat(direct, "/main.ww"), strings.concat( "package main;\nimport acme.codec;\n", "fn main() i32 = { return wire.value(); };\n")); writefile(strings.concat(app, "/main.ww"), strings.concat( "package main;\nimport acme.bridge;\n", "fn main() i32 = { return bridge.bridged(); };\n")); writefile(strings.concat(scopeone, "/one.ww"), "package same;\nexport fn value() i32 = { return 20; };\n"); writefile(strings.concat(scopetwo, "/two.ww"), "package same;\nexport fn value() i32 = { return 22; };\n"); writefile(strings.concat(scoped, "/a.ww"), strings.concat( "package main;\nimport shared scope.one;\n", "fn left() i32 = { return shared.value(); };\n")); writefile(strings.concat(scoped, "/b.ww"), strings.concat( "package main;\nimport shared scope.two;\n", "fn right() i32 = { return shared.value(); };\n")); writefile(strings.concat(scoped, "/main.ww"), "package main;\nfn main() i32 = { return left() + right(); };\n"); writefile(strings.concat(repeated, "/a.ww"), strings.concat( "package main;\nimport stable acme.codec;\n", "fn first() i32 = { return stable.value(); };\n")); writefile(strings.concat(repeated, "/b.ww"), strings.concat( "package main;\nimport acme.codec;\n", "fn second() i32 = { return wire.value(); };\n")); writefile(strings.concat(repeated, "/main.ww"), strings.concat( "package main;\n", "fn main() i32 = { return first() - second(); };\n")); writefile(strings.concat(leafbad, "/main.ww"), strings.concat( "package main;\nimport acme.codec;\n", "fn main() i32 = { return codec.value(); };\n")); writefile(strings.concat(leak, "/a.ww"), strings.concat( "package main;\nimport acme.codec;\n", "fn anchor() i32 = { return 1; };\n")); writefile(strings.concat(leak, "/b.ww"), "package main;\nfn leaked() i32 = { return wire.value(); };\n"); writefile(strings.concat(leak, "/main.ww"), "package main;\nfn main() i32 = { return leaked(); };\n"); writefile(strings.concat(duplicate, "/main.ww"), strings.concat( "package main;\nimport scope.one;\nimport scope.two;\n", "fn main() i32 = { return same.value(); };\n")); writefile(strings.concat(collision, "/main.ww"), strings.concat( "package main;\nimport scope.one;\n", "fn same() i32 = { return 0; };\n", "fn main() i32 = { return same(); };\n")); writefile(strings.concat(crosscollision, "/a.ww"), strings.concat( "package main;\nimport scope.one;\n", "fn fromdep() i32 = { return same.value(); };\n")); writefile(strings.concat(crosscollision, "/b.ww"), strings.concat( "package main;\nfn same() i32 = { return 0; };\n", "fn main() i32 = { return fromdep(); };\n")); writefile(strings.concat(conflict, "/a.ww"), "package first;\nexport fn a() i32 = { return 1; };\n"); writefile(strings.concat(conflict, "/b.ww"), "package second;\nexport fn b() i32 = { return 2; };\n"); writefile(strings.concat(leafmain, "/utility.ww"), "package utility;\nexport fn value() i32 = { return 7; };\n"); writefile(strings.concat(program, "/program.ww"), "package main;\nexport fn value() i32 = { return 9; };\n"); writefile(strings.concat(leafmainuser, "/main.ww"), strings.concat( "package main;\nimport domain.main;\n", "fn main() i32 = { return utility.value(); };\n")); writefile(strings.concat(programuser, "/main.ww"), strings.concat( "package main;\nimport stable domain.program;\n", "fn main() i32 = { return stable.value(); };\n")); writefile(strings.concat(testhelper, "/helper.ww"), "package helper;\nexport fn value() i32 = { return 1; };\n"); writefile(strings.concat(testcodec, "/codec.ww"), wirebody); writefile(strings.concat(testcodec, "/internal_test.ww"), strings.concat( "package wire;\nimport assist testonly.helper;\n", "@test fn internal_name_uses_declaration() void = {\n", " assert(value() + assist.value() == 43);\n};\n")); writefile(strings.concat(testcodec, "/external_test.ww"), strings.concat( "package wire_test;\nimport prod testpkg.codec;\n", "@test fn external_name_uses_declaration() void = {\n", " assert(prod.value() == 42);\n};\n")); writefile(strings.concat(vendored, "/codec.ww"), "package cable;\nexport fn value() i32 = { return 13; };\n"); writefile(strings.concat(vendorclient, "/a.ww"), strings.concat( "package main;\nimport stable short.codec;\n", "fn vendora() i32 = { return stable.value(); };\n")); writefile(strings.concat(vendorclient, "/b.ww"), strings.concat( "package main;\nimport short.codec;\n", "fn vendorb() i32 = { return cable.value(); };\n")); writefile(strings.concat(vendorclient, "/main.ww"), "package main;\nfn main() i32 = { return vendora(); };\n"); let compilerwrapper: str = strings.concat(tools, "/w6c.sh"); writeexecutable(compilerwrapper, strings.concat( "#!/bin/sh\n", "printf 'BEGIN' >> \"$WW_NAME_COMPILER_TRACE\"\n", "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", "\"$WW_NAME_COMPILER_TRACE\"; done\n", "printf '\\n' >> \"$WW_NAME_COMPILER_TRACE\"\n", "exec \"$WW_NAME_REAL_COMPILER\" \"$@\"\n")); let stages: []str = ["ww", "ww_ww"]; let compilers: []str = ["w6c", "w6c_ww"]; let assemblers: []str = ["w6a", "w6a_ww"]; let linkers: []str = ["w6l", "w6l_ww"]; let works: []str = [strings.concat(root, "/c-work"), strings.concat(root, "/ww-work")]; let traces: []str = [strings.concat(root, "/c-compiler"), strings.concat(root, "/ww-compiler")]; let directbins: []str = [strings.concat(root, "/c-direct"), strings.concat(root, "/ww-direct")]; let appbins: []str = [strings.concat(root, "/c-app"), strings.concat(root, "/ww-app")]; let scopedbins: []str = [strings.concat(root, "/c-scoped"), strings.concat(root, "/ww-scoped")]; let repeatedbins: []str = [strings.concat(root, "/c-repeated"), strings.concat(root, "/ww-repeated")]; let commitworks: []str = [strings.concat(root, "/c-commit-work"), strings.concat(root, "/ww-commit-work")]; let commitcoldbins: []str = [strings.concat(root, "/c-commit-cold"), strings.concat(root, "/ww-commit-cold")]; let commitrejectbins: []str = [strings.concat(root, "/c-commit-reject"), strings.concat(root, "/ww-commit-reject")]; let commitfixedbins: []str = [strings.concat(root, "/c-commit-fixed"), strings.concat(root, "/ww-commit-fixed")]; let leafmainbins: []str = [strings.concat(root, "/c-leafmain"), strings.concat(root, "/ww-leafmain")]; let vendorbins: []str = [strings.concat(root, "/c-vendor"), strings.concat(root, "/ww-vendor")]; let actions: []str = ["acme.codec", "acme.bridge", "cmd.direct", "cmd.app", "scope.one", "scope.two", "cmd.scoped", "cmd.repeated", "domain.main", "cmd.leafmain", "vend.vendor.short.codec", "vend.client"]; let suffixes: []str = [".unit.ww", ".wwi", ".a"]; let artifactrefs: []str = alloc([], (actions.len * suffixes.len): u64)!; let ari: i32 = 0; for (ari < actions.len * suffixes.len) { append(artifactrefs, ""); ari += 1; }; let binaryrefs: []str = ["", "", "", "", "", ""]; let diagnosticrefs: []str = ["", "", "", "", "", ""]; let directtraceref: str = ""; let scopedtraceref: str = ""; let repeatedtraceref: str = ""; let changedtraceref: str = ""; let aliastraceref: str = ""; let commitbindingref: str = ""; let commitbinref: str = ""; let initialwwiref: str = ""; let testoutref: str = ""; let baseenv: []str = os.getenvs(); let si: i32 = 0; for (si < stages.len) { rewritefile(codecfile, wirebody); rewritefile(bridgefile, stablebridgebody); rewritefile(commitcodecfile, wirebody); rewritefile(commitappfile, strings.concat( "package main;\nimport commit.codec;\n", "fn main() i32 = { return wire.value(); };\n")); assert(os.mkdir(works[si], 448i32) == 0); assert(os.mkdir(commitworks[si], 448i32) == 0); writefile(traces[si], ""); let env: []str = alloc([], (baseenv.len + 7): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { if (!strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6A=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], "WW_SRCLIB=") && !strings.hasprefix(baseenv[ei], "WW_NAME_COMPILER_TRACE=") && !strings.hasprefix(baseenv[ei], "WW_NAME_REAL_COMPILER=")) { append(env, baseenv[ei]); }; ei += 1; }; append(env, strings.concat("WW_W6C=", compilerwrapper)); append(env, strings.concat("WW_W6A=", driver(assemblers[si]))); append(env, strings.concat("WW_W6L=", driver(linkers[si]))); append(env, strings.concat("WW_SRCLIB=", repo(), "/lib")); append(env, strings.concat("WW_NAME_COMPILER_TRACE=", traces[si])); append(env, strings.concat("WW_NAME_REAL_COMPILER=", driver(compilers[si]))); // A directly selected library keeps canonical action/artifact identity // even though its declaration is unrelated to the path leaf. let out: commandout; let selectav: []str = [driver(stages[si]), "build", "-w", works[si], "-I", source, codec]; runcommandenv(root, strings.concat("name-select-", stages[si]), selectav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); assert(os.exists(strings.concat(works[si], "/acme.codec.wwi"))); assert(!os.exists(strings.concat(works[si], "/wire.wwi"))); let initialwwi: str = readfile(strings.concat(works[si], "/acme.codec.wwi")); assert(has(initialwwi, "//ww:module acme.codec\npackage wire;\n")); if (si == 0) { initialwwiref = strings.dup(initialwwi); } else { assert(same(initialwwiref, initialwwi)); }; rewritefile(traces[si], ""); let directav: []str = [driver(stages[si]), "build", "-w", works[si], "-I", source, "-o", directbins[si], direct]; runcommandenv(root, strings.concat("name-direct-", stages[si]), directav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(out.stdout.len == 0 && out.stderr.len == 0); let directtrace: str = readfile(traces[si]); let directline: str = linecontaining(directtrace, "cmd.direct.unit.new"); assert(occurrences(directline, "<--import>") == 1); assert(!has(directline, "wire.wwi")); let ndirect: str = normalizedtrace(directtrace, strings.concat(works[si], "/"), directbins[si]); if (si == 0) { directtraceref = strings.dup(ndirect); } else { assert(same(directtraceref, ndirect)); }; let runav: []str = [directbins[si]]; runcommand(root, strings.concat("name-direct-run-", stages[si]), runav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 42); // The package and command form one publication transaction. A changed // declared name is visible to the importer through the staged .wwi, but // its resulting semantic rejection must preserve the complete prior // generation and force the next request to reconsider both actions. let commitcoldav: []str = [driver(stages[si]), "build", "-w", commitworks[si], "-I", source, "-o", commitcoldbins[si], commitapp]; runcommandenv(root, strings.concat("name-commit-cold-", stages[si]), commitcoldav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let commitrun: []str = [commitcoldbins[si]]; runcommand(root, strings.concat("name-commit-cold-run-", stages[si]), commitrun, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 42); let commitpaths: []str = ["/.wwtool.ww", "/.wwtool.w6c", "/.wwtool.w6a", "/.wwtool.stamp", "/commit.codec.unit.ww", "/commit.codec.wwi", "/commit.codec.s", "/commit.codec.o", "/commit.codec.a", "/cmd.commit.unit.ww", "/cmd.commit.wwi", "/cmd.commit.s", "/cmd.commit.o", "/cmd.commit.a", "/cmd.commit.init.unit.ww", "/cmd.commit.init.s", "/cmd.commit.init.o"]; let commitsnapshots: []str = alloc([], commitpaths.len: u64)!; let cpi: i32 = 0; for (cpi < commitpaths.len) { append(commitsnapshots, readfile(strings.concat(commitworks[si], commitpaths[cpi]))); cpi += 1; }; let commitcoldbytes: str = readfile(commitcoldbins[si]); rewritefile(commitcodecfile, cablebody); let commitrejectav: []str = [driver(stages[si]), "build", "-w", commitworks[si], "-I", source, "-o", commitrejectbins[si], commitapp]; let partialsuffixes: []str = [".unit.new", ".wwi.new", ".s.new", ".o.new", ".a.new", ".init.unit.new", ".init.s.new", ".init.o.new"]; let rejectedactions: []str = ["commit.codec", "cmd.commit"]; let attemptlabels: []str = ["0", "1"]; let attempt: i32 = 0; for (attempt < 2) { rewritefile(traces[si], ""); runcommandenv(root, strings.concat("name-commit-reject-", stages[si], "-", attemptlabels[attempt]), commitrejectav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, "imported as cable and not used")); assert(has(out.stderr, "undefined: wire")); assert(has(out.stderr, "ww: w6c failed for cmd.commit\n")); let ncommitbinding: str = normalizedtrace(out.stderr, strings.concat(commitworks[si], "/"), commitrejectbins[si]); if (si == 0 && attempt == 0) { commitbindingref = strings.dup(ncommitbinding); } else { assert(same(commitbindingref, ncommitbinding)); }; let rejecttrace: str = readfile(traces[si]); assert(occurrences(rejecttrace, "/commit.codec.unit.new") == 1); assert(occurrences(rejecttrace, "/cmd.commit.unit.new") == 1); cpi = 0; for (cpi < commitpaths.len) { assert(same(commitsnapshots[cpi], readfile(strings.concat( commitworks[si], commitpaths[cpi])))); cpi += 1; }; assert(same(commitcoldbytes, readfile(commitcoldbins[si]))); let rai: i32 = 0; for (rai < rejectedactions.len) { let psi: i32 = 0; for (psi < partialsuffixes.len) { assert(!os.exists(strings.concat(commitworks[si], "/", rejectedactions[rai], partialsuffixes[psi]))); psi += 1; }; rai += 1; }; assert(!os.exists(commitrejectbins[si])); assert(!os.exists(strings.concat(commitrejectbins[si], ".new"))); attempt += 1; }; rewritefile(commitappfile, strings.concat( "package main;\nimport commit.codec;\n", "fn main() i32 = { return cable.value(); };\n")); let commitfixedav: []str = [driver(stages[si]), "build", "-w", commitworks[si], "-I", source, "-o", commitfixedbins[si], commitapp]; runcommandenv(root, strings.concat("name-commit-fixed-", stages[si]), commitfixedav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let commitfixedrun: []str = [commitfixedbins[si]]; runcommand(root, strings.concat("name-commit-fixed-run-", stages[si]), commitfixedrun, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 42); assert(has(readfile(strings.concat(commitworks[si], "/commit.codec.wwi")), "//ww:module commit.codec\npackage cable;\n")); assert(same(commitcoldbytes, readfile(commitcoldbins[si]))); let commitbinbytes: str = readfile(commitfixedbins[si]); if (si == 0) { commitbinref = strings.dup(commitbinbytes); } else { assert(same(commitbinref, commitbinbytes)); }; // The same declared qualifier belongs to each importing source file, // not to the package-wide namespace. rewritefile(traces[si], ""); let scopedav: []str = [driver(stages[si]), "build", "-w", works[si], "-I", source, "-o", scopedbins[si], scoped]; runcommandenv(root, strings.concat("name-scoped-", stages[si]), scopedav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let scopedtrace: str = readfile(traces[si]); let scopedline: str = linecontaining(scopedtrace, "cmd.scoped.unit.new"); assert(occurrences(scopedline, "<--import>") == 1); assert(occurrences(scopedline, "<--import>") == 1); let nscoped: str = normalizedtrace(scopedtrace, strings.concat(works[si], "/"), scopedbins[si]); if (si == 0) { scopedtraceref = strings.dup(nscoped); } else { assert(same(scopedtraceref, nscoped)); }; let scopedrun: []str = [scopedbins[si]]; runcommand(root, strings.concat("name-scoped-run-", stages[si]), scopedrun, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 42); // Two per-file binding records for one canonical package still form // exactly one direct graph edge and one compiler input. rewritefile(traces[si], ""); let repeatedav: []str = [driver(stages[si]), "build", "-w", works[si], "-I", source, "-o", repeatedbins[si], repeated]; runcommandenv(root, strings.concat("name-repeated-", stages[si]), repeatedav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let repeatedunit: str = readfile(strings.concat(works[si], "/cmd.repeated.unit.ww")); assert(occurrences(repeatedunit, "import stable acme.codec;") == 1); assert(occurrences(repeatedunit, "import acme.codec;") == 1); let repeatedtrace: str = readfile(traces[si]); let repeatedline: str = linecontaining(repeatedtrace, "cmd.repeated.unit.new"); assert(occurrences(repeatedline, "<--import>") == 1); assert(occurrences(repeatedtrace, "acme.codec.unit.new") == 0); let nrepeated: str = normalizedtrace(repeatedtrace, strings.concat(works[si], "/"), repeatedbins[si]); if (si == 0) { repeatedtraceref = strings.dup(nrepeated); } else { assert(same(repeatedtraceref, nrepeated)); }; let repeatedrun: []str = [repeatedbins[si]]; runcommand(root, strings.concat("name-repeated-run-", stages[si]), repeatedrun, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); // A path ending in main remains importable when its declaration is not // main. A different path declaring main is rejected by loaded name. let leafmainav: []str = [driver(stages[si]), "build", "-w", works[si], "-I", source, "-o", leafmainbins[si], leafmainuser]; runcommandenv(root, strings.concat("name-leafmain-", stages[si]), leafmainav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let leafmainrun: []str = [leafmainbins[si]]; runcommand(root, strings.concat("name-leafmain-run-", stages[si]), leafmainrun, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 7); // Compiler-owned binding failures are deterministic across stages and // never commit an action voucher/artifact or publish a binary. let rejectwork: str = strings.concat(root, "/reject-work-", stages[si]); assert(os.mkdir(rejectwork, 448i32) == 0); let rejecttargets: []str = [leafbad, leak, duplicate, collision, crosscollision, programuser]; let rejectactions: []str = ["cmd.leafbad", "cmd.leak", "cmd.duplicate", "cmd.collision", "cmd.crosscollision", "cmd.programuser"]; let rejectneedles: []str = ["undefined: codec", "package 'wire' is not directly imported", "same redeclared in this block", "same already declared through import of package same", "same already declared through import of package same", "package domain.program is a program, not an importable package"]; let rj: i32 = 0; for (rj < rejecttargets.len) { let badbin: str = strings.concat(root, "/reject-bin-", stages[si], "-", rejectactions[rj]); let badav: []str = [driver(stages[si]), "build", "-w", rejectwork, "-I", source, "-o", badbin, rejecttargets[rj]]; runcommandenv(root, strings.concat("name-reject-", stages[si], "-", rejectactions[rj]), badav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, rejectneedles[rj])); let normalized: str = normalizedtrace(out.stderr, strings.concat(rejectwork, "/"), badbin); if (rj == 2) { assert(same(normalized, strings.concat( "$WORK/cmd.duplicate.unit.new:4:1: error: same redeclared in this block\n", "\t$WORK/cmd.duplicate.unit.new:3:1: other declaration of same\n", "$WORK/cmd.duplicate.unit.new:4:1: error: \"scope.two\" imported as same and not used\n", "ww: w6c failed for cmd.duplicate\n"))); }; if (rj == 3) { assert(same(normalized, strings.concat( "$WORK/cmd.collision.unit.new:3:1: error: \"scope.one\" imported as same and not used\n", "$WORK/cmd.collision.unit.new:4:1: error: same already declared through import of package same (\"scope.one\")\n", "\t$WORK/cmd.collision.unit.new:3:1: other declaration of same\n", "ww: w6c failed for cmd.collision\n"))); }; if (si == 0) { diagnosticrefs[rj] = strings.dup(normalized); } else { assert(same(diagnosticrefs[rj], normalized)); }; assert(!os.exists(badbin)); let committed: []str = [".unit.ww", ".wwi", ".s", ".o", ".a", ".unit.new", ".wwi.new", ".s.new", ".o.new", ".a.new"]; let ci: i32 = 0; for (ci < committed.len) { assert(!os.exists(strings.concat(rejectwork, "/", rejectactions[rj], committed[ci]))); ci += 1; }; rj += 1; }; let conflictav: []str = [driver(stages[si]), "build", "-w", rejectwork, "-I", source, conflict]; runcommandenv(root, strings.concat("name-conflict-", stages[si]), conflictav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, "conflicting package names")); assert(!os.exists(strings.concat(rejectwork, "/conflict.pkg.unit.ww"))); // Production/internal/external naming uses the declaration, while every // action and generated-main artifact retains canonical variant identity. let testwork: str = strings.concat(root, "/test-work-", stages[si]); assert(os.mkdir(testwork, 448i32) == 0); rewritefile(traces[si], ""); let testav: []str = [driver(stages[si]), "test", "-w", testwork, "-I", source, testcodec]; runcommandenv(root, strings.concat("name-test-", stages[si]), testav, env, (240i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "internal_name_uses_declaration ... ok\n")); assert(has(out.stdout, "external_name_uses_declaration ... ok\n")); assert(out.stderr.len == 0); if (si == 0) { testoutref = strings.dup(out.stdout); } else { assert(same(testoutref, out.stdout)); }; let productionunit: str = readfile(strings.concat(testwork, "/testpkg.codec.unit.ww")); let internalunit: str = readfile(strings.concat(testwork, "/testpkg.codec-internal-test.unit.ww")); let externalunit: str = readfile(strings.concat(testwork, "/testpkg.codec_test-external-test.unit.ww")); assert(!has(productionunit, "testonly.helper")); assert(has(internalunit, "import assist testonly.helper;")); assert(!has(externalunit, "testonly.helper")); assert(has(externalunit, "package wire_test;")); assert(os.exists(strings.concat(testwork, "/testpkg.codec-internal-test-main.a"))); assert(os.exists(strings.concat(testwork, "/testpkg.codec_test-external-test-main.a"))); assert(os.exists(strings.concat(testwork, "/test.a"))); assert(!has(readfile(strings.concat(testwork, "/testpkg.codec-internal-test-main.unit.ww")), "testonly.helper")); assert(!has(readfile(strings.concat(testwork, "/testpkg.codec_test-external-test-main.unit.ww")), "testonly.helper")); let recursivebuildwork: str = strings.concat(root, "/recursive-build-", stages[si]); assert(os.mkdir(recursivebuildwork, 448i32) == 0); let recursivebuildav: []str = [driver(stages[si]), "build", "-w", recursivebuildwork, "-I", source, strings.concat(source, "/testpkg/...")]; runcommandenv(root, strings.concat("name-recursive-build-", stages[si]), recursivebuildav, env, (180i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(os.exists(strings.concat(recursivebuildwork, "/testpkg.codec.wwi"))); let recursivetestwork: str = strings.concat(root, "/recursive-test-", stages[si]); assert(os.mkdir(recursivetestwork, 448i32) == 0); let recursivetestav: []str = [driver(stages[si]), "test", "-w", recursivetestwork, "-I", source, strings.concat(source, "/testpkg/...")]; runcommandenv(root, strings.concat("name-recursive-test-", stages[si]), recursivetestav, env, (240i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "external_name_uses_declaration ... ok\n")); // Vendor expansion owns the action/map identity; the loaded declaration // independently supplies cable as the source-visible qualifier. rewritefile(traces[si], ""); let vendorav: []str = [driver(stages[si]), "build", "-w", works[si], "-I", source, "-o", vendorbins[si], vendorclient]; runcommandenv(root, strings.concat("name-vendor-", stages[si]), vendorav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let vendorunit: str = readfile(strings.concat(works[si], "/vend.client.unit.ww")); assert(occurrences(vendorunit, "import stable short.codec;") == 1); assert(occurrences(vendorunit, "import short.codec;") == 1); assert(has(vendorunit, strings.concat( "//ww:import-map short.codec vend.vendor.short.codec ", hexbytes(vendored), "\n"))); assert(occurrences(vendorunit, "//ww:import-map short.codec vend.vendor.short.codec ") == 1); let vendortrace: str = readfile(traces[si]); let vendorline: str = linecontaining(vendortrace, "vend.client.unit.new"); assert(occurrences(vendorline, "<--import>") == 1); assert(occurrences(vendorline, strings.concat( "<--import-map>")) == 1); let vendorwwi: str = readfile(strings.concat(works[si], "/vend.vendor.short.codec.wwi")); assert(has(vendorwwi, strings.concat( "//ww:module vend.vendor.short.codec\npackage cable;\n"))); assert(!os.exists(strings.concat(works[si], "/short.codec.a"))); let vendorrun: []str = [vendorbins[si]]; runcommand(root, strings.concat("name-vendor-run-", stages[si]), vendorrun, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 13); // A stable explicit alias survives a dependency declared-name change. // Canonicalized exported type references keep the bridge interface // unchanged, so reconsideration stops after the direct importer. rewritefile(traces[si], ""); let appav: []str = [driver(stages[si]), "build", "-w", works[si], "-I", source, "-o", appbins[si], app]; runcommandenv(root, strings.concat("name-app-cold-", stages[si]), appav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let apprun: []str = [appbins[si]]; runcommand(root, strings.concat("name-app-run-", stages[si]), apprun, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 42); let stablebridgewwi: str = readfile(strings.concat(works[si], "/acme.bridge.wwi")); assert(has(stablebridgewwi, "import __wwi_61636d652e636f646563 acme.codec;\n")); assert(has(stablebridgewwi, "export type BridgedThing = __wwi_61636d652e636f646563.Thing;\n")); assert(!has(stablebridgewwi, "stable.Thing")); rewritefile(traces[si], ""); runcommandenv(root, strings.concat("name-app-warm-", stages[si]), appav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(readfile(traces[si]).len == 0); rewritefile(codecfile, cablebody); rewritefile(traces[si], ""); runcommandenv(root, strings.concat("name-app-renamed-", stages[si]), appav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let changedtrace: str = readfile(traces[si]); assert(occurrences(changedtrace, "\n") == 2); assert(occurrences(changedtrace, "/acme.codec.unit.new") == 1); assert(occurrences(changedtrace, "/acme.bridge.unit.new") == 1); assert(!has(changedtrace, "/cmd.app.unit.new")); let nchanged: str = normalizedtrace(changedtrace, strings.concat(works[si], "/"), appbins[si]); if (si == 0) { changedtraceref = strings.dup(nchanged); } else { assert(same(changedtraceref, nchanged)); }; let renamedwwi: str = readfile(strings.concat(works[si], "/acme.codec.wwi")); assert(has(renamedwwi, "//ww:module acme.codec\npackage cable;\n")); assert(!has(renamedwwi, "package wire;")); assert(same(stablebridgewwi, readfile(strings.concat(works[si], "/acme.bridge.wwi")))); runcommand(root, strings.concat("name-app-renamed-run-", stages[si]), apprun, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 42); // Editing only the local alias rebuilds its owning source action. It // cannot rename canonical exports or force the downstream command. rewritefile(bridgefile, steadybridgebody); rewritefile(traces[si], ""); runcommandenv(root, strings.concat("name-app-alias-edit-", stages[si]), appav, env, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let aliastrace: str = readfile(traces[si]); assert(occurrences(aliastrace, "\n") == 1); assert(occurrences(aliastrace, "/acme.bridge.unit.new") == 1); assert(!has(aliastrace, "/acme.codec.unit.new")); assert(!has(aliastrace, "/cmd.app.unit.new")); assert(same(stablebridgewwi, readfile(strings.concat(works[si], "/acme.bridge.wwi")))); let nalias: str = normalizedtrace(aliastrace, strings.concat(works[si], "/"), appbins[si]); if (si == 0) { aliastraceref = strings.dup(nalias); } else { assert(same(aliastraceref, nalias)); }; runcommand(root, strings.concat("name-app-alias-edit-run-", stages[si]), apprun, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 42); // New semantic artifacts and binaries are byte-identical across the // independently cold Cstage and WWstage work roots. ari = 0; for (ari < actions.len) { let xi: i32 = 0; for (xi < suffixes.len) { let index: i32 = ari * suffixes.len + xi; let bytes: str = readfile(strings.concat(works[si], "/", actions[ari], suffixes[xi])); if (si == 0) { artifactrefs[index] = strings.dup(bytes); } else { assert(same(artifactrefs[index], bytes)); }; xi += 1; }; ari += 1; }; let stagebins: []str = [directbins[si], appbins[si], scopedbins[si], repeatedbins[si], leafmainbins[si], vendorbins[si]]; let bini: i32 = 0; for (bini < stagebins.len) { let bytes: str = readfile(stagebins[bini]); if (si == 0) { binaryrefs[bini] = strings.dup(bytes); } else { assert(same(binaryrefs[bini], bytes)); }; bini += 1; }; si += 1; }; clean(root); }; @test fn explicit_import_alias_binding_modes() void = { let root: str = fresh(); let source: str = strings.concat(root, "/source"); let one: str = strings.concat(source, "/pkg/one"); let two: str = strings.concat(source, "/pkg/two"); let positives: []str = ["default", "alias", "reuse", "repeatok", "repeatedfiles", "blankalias", "blankrepeat", "blankdefault", "blankexplicit", "blankfiles"]; let negatives: []str = ["barefn", "baretype", "baredef", "bareconst", "barevar", "aliasbad", "aliasleak", "repeatdup", "aliasdup", "defaultalias", "declcollision", "unusedalias", "blankqual", "blankbare", "blankordinaryunused"]; let dirs: []str = [one, two]; let i: i32 = 0; for (i < positives.len) { append(dirs, strings.concat(source, "/cmd/", positives[i])); i += 1; }; i = 0; for (i < negatives.len) { append(dirs, strings.concat(source, "/cmd/", negatives[i])); i += 1; }; i = 0; for (i < dirs.len) { mkdirall(dirs[i]); i += 1; }; writefile(strings.concat(one, "/one.ww"), strings.concat( "package wire;\n", "export fn value() i32 = { return 11; };\n", "export type Thing = i32;\n", "export def DEFINED: i32 = 13;\n", "export const CONSTANT: i32 = 17;\n", "export let VARIABLE: i32 = 19;\n")); writefile(strings.concat(two, "/two.ww"), "package cable;\nexport fn value() i32 = { return 29; };\n"); let defaultbody: str = strings.concat( "package main;\nimport pkg.one;\n", "fn typed(v: wire.Thing) i32 = { return v: i32; };\n", "fn main() i32 = { return wire.value() + wire.DEFINED + ", "wire.CONSTANT + wire.VARIABLE + typed(23); };\n"); writefile(strings.concat(source, "/cmd/default/main.ww"), defaultbody); writefile(strings.concat(source, "/cmd/alias/main.ww"), strings.concat( "package main;\nimport stable pkg.one;\n", "fn typed(v: stable.Thing) i32 = { return v: i32; };\n", "fn main() i32 = { return stable.value() + stable.DEFINED + ", "stable.CONSTANT + stable.VARIABLE + typed(23); };\n")); writefile(strings.concat(source, "/cmd/reuse/a.ww"), strings.concat( "package main;\nimport shared pkg.one;\n", "fn left() i32 = { return shared.value(); };\n")); writefile(strings.concat(source, "/cmd/reuse/b.ww"), strings.concat( "package main;\nimport shared pkg.two;\n", "fn right() i32 = { return shared.value(); };\n")); writefile(strings.concat(source, "/cmd/reuse/main.ww"), "package main;\nfn main() i32 = { return left() + right(); };\n"); writefile(strings.concat(source, "/cmd/repeatok/main.ww"), strings.concat( "package main;\nimport pkg.one;\nimport first pkg.one;\n", "import second pkg.one;\n", "fn main() i32 = { return wire.value() + first.value() + ", "second.value(); };\n")); writefile(strings.concat(source, "/cmd/repeatedfiles/a.ww"), strings.concat( "package main;\nimport left pkg.one;\n", "fn first() i32 = { return left.value(); };\n")); writefile(strings.concat(source, "/cmd/repeatedfiles/b.ww"), strings.concat( "package main;\nimport right pkg.one;\n", "fn second() i32 = { return right.value(); };\n")); writefile(strings.concat(source, "/cmd/repeatedfiles/main.ww"), "package main;\nfn main() i32 = { return first() + second(); };\n"); writefile(strings.concat(source, "/cmd/blankalias/main.ww"), "package main;\nimport _ pkg.one;\nfn main() i32 = { return 0; };\n"); writefile(strings.concat(source, "/cmd/blankrepeat/main.ww"), strings.concat("package main;\nimport _ pkg.one;\n", "import _ pkg.one;\nfn main() i32 = { return 0; };\n")); writefile(strings.concat(source, "/cmd/blankdefault/main.ww"), strings.concat("package main;\nimport _ pkg.one;\nimport pkg.one;\n", "fn main() i32 = { return wire.value(); };\n")); writefile(strings.concat(source, "/cmd/blankexplicit/main.ww"), strings.concat("package main;\nimport _ pkg.one;\n", "import stable pkg.one;\n", "fn main() i32 = { return stable.value(); };\n")); writefile(strings.concat(source, "/cmd/blankfiles/a.ww"), "package main;\nimport _ pkg.one;\n"); writefile(strings.concat(source, "/cmd/blankfiles/b.ww"), "package main;\nimport _ pkg.one;\n"); writefile(strings.concat(source, "/cmd/blankfiles/main.ww"), "package main;\nfn main() i32 = { return 0; };\n"); let bareexprs: []str = ["value()", "take(7)", "DEFINED", "CONSTANT", "VARIABLE"]; let barenames: []str = ["barefn", "baretype", "baredef", "bareconst", "barevar"]; i = 0; for (i < barenames.len) { let pre: str = ""; if (i == 1) { pre = "fn take(v: Thing) i32 = { return v: i32; };\n"; }; writefile(strings.concat(source, "/cmd/", barenames[i], "/main.ww"), strings.concat("package main;\nimport pkg.one;\n", pre, "fn main() i32 = { return ", bareexprs[i], "; };\n")); i += 1; }; writefile(strings.concat(source, "/cmd/aliasbad/main.ww"), strings.concat( "package main;\nimport stable pkg.one;\n", "fn bad(v: wire.Thing) i32 = { return v: i32; };\n", "fn declared() i32 = { return wire.value(); };\n", "fn leaf() i32 = { return one.value(); };\n", "fn bare() i32 = { return value(); };\n", "fn main() i32 = { return stable.value(); };\n")); writefile(strings.concat(source, "/cmd/aliasleak/a.ww"), strings.concat( "package main;\nimport stable pkg.one;\n", "fn anchor() i32 = { return stable.value(); };\n")); writefile(strings.concat(source, "/cmd/aliasleak/b.ww"), "package main;\nfn leaked() i32 = { return stable.value(); };\n"); writefile(strings.concat(source, "/cmd/aliasleak/main.ww"), "package main;\nfn main() i32 = { return leaked(); };\n"); writefile(strings.concat(source, "/cmd/repeatdup/main.ww"), strings.concat( "package main;\nimport pkg.one;\nimport pkg.one;\n", "fn main() i32 = { return wire.value(); };\n")); writefile(strings.concat(source, "/cmd/aliasdup/main.ww"), strings.concat( "package main;\nimport stable pkg.one;\nimport stable pkg.two;\n", "fn main() i32 = { return stable.value(); };\n")); writefile(strings.concat(source, "/cmd/defaultalias/main.ww"), strings.concat( "package main;\nimport pkg.one;\nimport wire pkg.two;\n", "fn main() i32 = { return wire.value(); };\n")); writefile(strings.concat(source, "/cmd/declcollision/main.ww"), strings.concat( "package main;\nimport stable pkg.one;\n", "fn stable() i32 = { return 0; };\n", "fn main() i32 = { return stable(); };\n")); writefile(strings.concat(source, "/cmd/unusedalias/main.ww"), "package main;\nimport stable pkg.one;\nfn main() i32 = { return 0; };\n"); writefile(strings.concat(source, "/cmd/blankqual/main.ww"), strings.concat("package main;\nimport _ pkg.one;\n", "fn main() i32 = { return wire.value(); };\n")); writefile(strings.concat(source, "/cmd/blankbare/main.ww"), strings.concat("package main;\nimport _ pkg.one;\n", "fn main() i32 = { return value(); };\n")); writefile(strings.concat(source, "/cmd/blankordinaryunused/main.ww"), strings.concat("package main;\nimport _ pkg.one;\nimport pkg.one;\n", "fn main() i32 = { return 0; };\n")); let stages: []str = ["ww", "ww_ww"]; let expected: []i32 = [83, 83, 40, 33, 22, 0, 0, 11, 11, 0]; let binaryrefs: []str = ["", "", "", "", "", "", "", "", "", ""]; let diagrefs: []str = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]; let needles: []str = ["undefined: value", "unknown type 'Thing'", "undefined: DEFINED", "undefined: CONSTANT", "undefined: VARIABLE", "unknown type 'wire.Thing'", "package 'stable' is not directly imported", "wire redeclared in this block", "stable redeclared in this block", "wire redeclared in this block", "stable already declared through import of package stable", "\"pkg.one\" imported as stable and not used", "undefined: wire", "undefined: value", "\"pkg.one\" imported as wire and not used"]; let exactdiags: []str = [ strings.concat( "$WORK/cmd.barefn.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n", "$WORK/cmd.barefn.unit.new:4:26: error: undefined: value\n", "ww: w6c failed for cmd.barefn\n"), strings.concat( "$WORK/cmd.baretype.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n", "$WORK/cmd.baretype.unit.new:4:12: error: unknown type 'Thing'\n", "ww: w6c failed for cmd.baretype\n"), strings.concat( "$WORK/cmd.baredef.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n", "$WORK/cmd.baredef.unit.new:4:26: error: undefined: DEFINED\n", "ww: w6c failed for cmd.baredef\n"), strings.concat( "$WORK/cmd.bareconst.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n", "$WORK/cmd.bareconst.unit.new:4:26: error: undefined: CONSTANT\n", "ww: w6c failed for cmd.bareconst\n"), strings.concat( "$WORK/cmd.barevar.unit.new:3:1: error: \"pkg.one\" imported as wire and not used\n", "$WORK/cmd.barevar.unit.new:4:26: error: undefined: VARIABLE\n", "ww: w6c failed for cmd.barevar\n"), "", "", strings.concat( "$WORK/cmd.repeatdup.unit.new:4:1: error: wire redeclared in this block\n", "\t$WORK/cmd.repeatdup.unit.new:3:1: other declaration of wire\n", "$WORK/cmd.repeatdup.unit.new:4:1: error: \"pkg.one\" imported as wire and not used\n", "ww: w6c failed for cmd.repeatdup\n"), strings.concat( "$WORK/cmd.aliasdup.unit.new:4:1: error: stable redeclared in this block\n", "\t$WORK/cmd.aliasdup.unit.new:3:1: other declaration of stable\n", "$WORK/cmd.aliasdup.unit.new:4:1: error: \"pkg.two\" imported as stable and not used\n", "ww: w6c failed for cmd.aliasdup\n"), strings.concat( "$WORK/cmd.defaultalias.unit.new:4:1: error: wire redeclared in this block\n", "\t$WORK/cmd.defaultalias.unit.new:3:1: other declaration of wire\n", "$WORK/cmd.defaultalias.unit.new:4:1: error: \"pkg.two\" imported as wire and not used\n", "ww: w6c failed for cmd.defaultalias\n"), strings.concat( "$WORK/cmd.declcollision.unit.new:3:1: error: \"pkg.one\" imported as stable and not used\n", "$WORK/cmd.declcollision.unit.new:4:1: error: stable already declared through import of package stable (\"pkg.one\")\n", "\t$WORK/cmd.declcollision.unit.new:3:1: other declaration of stable\n", "ww: w6c failed for cmd.declcollision\n"), strings.concat( "$WORK/cmd.unusedalias.unit.new:3:1: error: \"pkg.one\" imported as stable and not used\n", "ww: w6c failed for cmd.unusedalias\n"), "", "", "", ]; let si: i32 = 0; for (si < stages.len) { let work: str = strings.concat(root, "/work-", stages[si]); let rejectwork: str = strings.concat(root, "/reject-", stages[si]); mkdirall(work); mkdirall(rejectwork); i = 0; for (i < positives.len) { let target: str = strings.concat(source, "/cmd/", positives[i]); let binary: str = strings.concat(root, "/", stages[si], "-", positives[i]); let av: []str = [driver(stages[si]), "build", "-w", work, "-I", source, "-o", binary, target]; let out: commandout; runcommand(root, strings.concat("alias-positive-", stages[si], "-", positives[i]), av, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let runav: []str = [binary]; runcommand(root, strings.concat("alias-positive-run-", stages[si], "-", positives[i]), runav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, expected[i]); let bytes: str = readfile(binary); if (si == 0) { binaryrefs[i] = strings.dup(bytes); } else { assert(same(binaryrefs[i], bytes)); }; i += 1; }; let aliasunit: str = readfile(strings.concat(work, "/cmd.alias.unit.ww")); assert(has(aliasunit, "import stable pkg.one;")); let aliaswwi: str = readfile(strings.concat(work, "/cmd.alias.wwi")); assert(has(aliaswwi, "import __wwi_706b672e6f6e65 pkg.one;")); assert(!has(aliaswwi, "import stable")); assert(os.exists(strings.concat(work, "/pkg.one.a"))); assert(!os.exists(strings.concat(work, "/stable.a"))); let repeatunit: str = readfile(strings.concat(work, "/cmd.repeatok.unit.ww")); assert(occurrences(repeatunit, "pkg.one;") == 3); let repeatedunit: str = readfile(strings.concat(work, "/cmd.repeatedfiles.unit.ww")); assert(occurrences(repeatedunit, "pkg.one;") == 2); let blankunit: str = readfile(strings.concat(work, "/cmd.blankalias.unit.ww")); assert(has(blankunit, "import _ pkg.one;")); let blankwwi: str = readfile(strings.concat(work, "/cmd.blankalias.wwi")); assert(!has(blankwwi, "import _") && !has(blankwwi, "__ww..")); let blankrepeat: str = readfile(strings.concat(work, "/cmd.blankrepeat.unit.ww")); assert(occurrences(blankrepeat, "import _ pkg.one;") == 2); assert(occurrences(blankrepeat, "//ww:direct-export pkg.one ") == 1); let blankfiles: str = readfile(strings.concat(work, "/cmd.blankfiles.unit.ww")); assert(occurrences(blankfiles, "import _ pkg.one;") == 2); assert(occurrences(blankfiles, "//ww:direct-export pkg.one ") == 1); let blankdispatch: str = readfile(strings.concat(work, "/cmd.blankdefault.init.unit.ww")); assert(occurrences(blankdispatch, "//ww:init-call __ww..pkg.p.pkg.one.v0.r0.init") == 1); i = 0; for (i < negatives.len) { let target: str = strings.concat(source, "/cmd/", negatives[i]); let binary: str = strings.concat(root, "/reject-bin-", stages[si], "-", negatives[i]); let av: []str = [driver(stages[si]), "build", "-w", rejectwork, "-I", source, "-o", binary, target]; let out: commandout; runcommand(root, strings.concat("alias-negative-", stages[si], "-", negatives[i]), av, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); assert(has(out.stderr, needles[i])); if (i == 5) { assert(has(out.stderr, "undefined: wire")); assert(has(out.stderr, "undefined: one")); assert(has(out.stderr, "undefined: value")); }; if (i < 5) { let unusedpos: i32 = pos(out.stderr, "\"pkg.one\" imported as wire and not used"); let namepos: i32 = pos(out.stderr, needles[i]); assert(unusedpos >= 0 && namepos > unusedpos); }; if (i == 7 || i == 8 || i == 9) { let redeclared: i32 = pos(out.stderr, "redeclared in this block"); let unused: i32 = pos(out.stderr, "imported as"); assert(redeclared >= 0 && unused > redeclared); }; let normalized: str = normalizedtrace(out.stderr, strings.concat(rejectwork, "/"), binary); if (exactdiags[i].len > 0) { assert(same(normalized, exactdiags[i])); }; if (si == 0) { diagrefs[i] = strings.dup(normalized); } else { assert(same(diagrefs[i], normalized)); }; assert(!os.exists(binary)); let action: str = strings.concat("cmd.", negatives[i]); let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a", ".unit.new", ".wwi.new", ".s.new", ".o.new", ".a.new"]; let j: i32 = 0; for (j < suffixes.len) { assert(!os.exists(strings.concat(rejectwork, "/", action, suffixes[j]))); j += 1; }; i += 1; }; si += 1; }; clean(root); }; @test fn compile_artifact_naming() void = { let root: str = fresh(); let pdir: str = strings.concat(root, "/pkg"); assert(os.mkdir(pdir, 493i32) == 0); writefile(strings.concat(pdir, "/pkg.ww"), "package pkg;\nexport fn v() i32 = { return 7; };\n"); writefile(strings.concat(pdir, "/pkg_test.ww"), strings.concat( "package pkg_test;\nimport pkg;\n", "@test fn seven() void = { assert(pkg.v() == 7); };\n")); let adir: str = strings.concat(root, "/a"); assert(os.mkdir(adir, 493i32) == 0); // '_'-prefixed: the tree walk skips it, so the artifacts and // their .sepwork trees never pollute the multi-package discovery. let outdir: str = strings.concat(root, "/_out"); assert(os.mkdir(outdir, 493i32) == 0); writefile(strings.concat(adir, "/a.ww"), "package a;\nexport fn v() i32 = { return 1; };\n"); writefile(strings.concat(adir, "/a_test.ww"), strings.concat( "package a_test;\nimport a;\n", "@test fn one() void = { assert(a.v() == 1); };\n")); let out: commandout; let drvs: []str = ["ww", "ww_ww"]; let i: i32 = 0; for (i < 2) { let named: str = strings.concat(outdir, "/out_", drvs[i], ".bin"); let coav: []str = [driver(drvs[i]), "test", "-c", "-I", root, "-o", named, pdir]; runcommand(root, strings.concat("nameco_", drvs[i]), coav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); let fi: os.filestat; match (os.stat(&fi, named)) { case void => void; case let e: os.oserror => abort("-c -o artifact missing"); }; match (os.stat(&fi, strings.concat(pdir, "/pkg.test"))) { case void => abort("-c -o still published the fixed stem"); case let e: os.oserror => void; }; let runav: []str = [named]; runcommand(root, strings.concat("namerun_", drvs[i]), runav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 0); assert(has(out.stdout, "seven ... ok")); let nocav: []str = [driver(drvs[i]), "test", "-I", root, "-o", named, pdir]; runcommand(root, strings.concat("noc_", drvs[i]), nocav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 2); assert(has(out.stderr, "-o needs -c for a package target")); let mulav: []str = [driver(drvs[i]), "test", "-c", "-o", named, strings.concat(root, "/...")]; runcommand(root, strings.concat("multi_", drvs[i]), mulav, (30i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 2); assert(has(out.stderr, "cannot use -o with multiple packages")); i += 1; }; clean(root); };