cmd: build local package graphs
This commit is contained in:
502
test/sep/localbuild_test.ww
Normal file
502
test/sep/localbuild_test.ww
Normal file
@@ -0,0 +1,502 @@
|
||||
package localbuild_test;
|
||||
|
||||
// End-to-end local package builds through both production drivers. Fixtures
|
||||
// are created at runtime so there is no manifest or hidden graph input: every
|
||||
// edge below comes from an ordinary WW import declaration.
|
||||
|
||||
import os;
|
||||
import os.exec;
|
||||
import strings;
|
||||
import testenv;
|
||||
import time;
|
||||
|
||||
fn fail(label: str, why: str) void = {
|
||||
let m: str = strings.concat("localbuild FAIL: ", label, " -- ", why,
|
||||
"\n");
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
assert(false);
|
||||
};
|
||||
|
||||
fn tmo() time.duration = {
|
||||
return (240i64 * (time.second: i64)): time.duration;
|
||||
};
|
||||
|
||||
fn mkdir(path: str) void = { assert(os.mkdir(path, 493) == 0); };
|
||||
|
||||
fn command(dir: str, name: str, argv: []str,
|
||||
out: *testenv.commandout) void = {
|
||||
testenv.runcommand(dir, dir, name, argv, tmo(), out);
|
||||
};
|
||||
|
||||
fn code(dir: str, name: str, argv: []str) i32 = {
|
||||
let co: testenv.commandout;
|
||||
command(dir, name, argv, &co);
|
||||
if (co.termination != exec.termination.EXIT) { return -1; };
|
||||
return co.code;
|
||||
};
|
||||
|
||||
fn build(dir: str, driver: str, tag: str, target: str, out: str) i32 = {
|
||||
let av: []str = [testenv.driver(driver), "build", "-I", dir,
|
||||
"-o", out, target];
|
||||
return code(dir, strings.concat("build_", tag), av);
|
||||
};
|
||||
|
||||
fn rejectstable(dir: 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 errors: []str = ["", "", "", ""];
|
||||
let cwork: str = strings.concat(dir, "/work-", label, "-c");
|
||||
let wwork: str = strings.concat(dir, "/work-", label, "-w");
|
||||
mkdir(cwork); mkdir(wwork);
|
||||
let i: i32 = 0;
|
||||
for (i < drivers.len) {
|
||||
let out: str = strings.concat(dir, "/reject-", label, "-", tags[i]);
|
||||
let work: str = cwork;
|
||||
if (i == 1 || i == 3) { work = wwork; };
|
||||
let av: []str = [testenv.driver(drivers[i]), "build", "-I", dir,
|
||||
"-w", work, "-o", out, target];
|
||||
let co: testenv.commandout;
|
||||
command(dir, strings.concat("reject_", label, "_", tags[i]), av,
|
||||
&co);
|
||||
if (co.termination != exec.termination.EXIT || co.code == 0) {
|
||||
fail(label, strings.concat(drivers[i], " accepted invalid graph"));
|
||||
};
|
||||
if (!testenv.has(co.stderr, needle)) {
|
||||
fail(label, strings.concat(drivers[i], " diagnostic missing '",
|
||||
needle, "': ", co.stderr));
|
||||
};
|
||||
errors[i] = co.stderr;
|
||||
i += 1;
|
||||
};
|
||||
if (!testenv.same(errors[0], errors[2])) {
|
||||
fail(label, "C diagnostic changed across repeated builds");
|
||||
};
|
||||
if (!testenv.same(errors[1], errors[3])) {
|
||||
fail(label, "WW diagnostic changed across repeated builds");
|
||||
};
|
||||
};
|
||||
|
||||
@test fn standalone_and_package_artifact() void = {
|
||||
let td: str = testenv.fresh();
|
||||
let app: str = strings.concat(td, "/app");
|
||||
mkdir(app);
|
||||
testenv.writefile(strings.concat(app, "/main.ww"), strings.concat(
|
||||
"package main;\n",
|
||||
"fn main() i32 = { return 23; };\n"));
|
||||
// Ordinary builds must not accidentally select test-only sources.
|
||||
testenv.writefile(strings.concat(app, "/broken_test.ww"),
|
||||
"package other;\nthis is deliberately invalid\n");
|
||||
let c1: str = strings.concat(td, "/standalone-c1");
|
||||
let c2: str = strings.concat(td, "/standalone-c2");
|
||||
let ww: str = strings.concat(td, "/standalone-ww");
|
||||
if (build(td, "ww", "standalone_c1", app, c1) != 0
|
||||
|| build(td, "ww", "standalone_c2", app, c2) != 0
|
||||
|| build(td, "ww_ww", "standalone_ww", app, ww) != 0) {
|
||||
fail("standalone", "manifest-free directory build failed");
|
||||
};
|
||||
let av1: []str = [c1];
|
||||
let av2: []str = [ww];
|
||||
if (code(td, "run_standalone_c", av1) != 23
|
||||
|| code(td, "run_standalone_ww", av2) != 23) {
|
||||
fail("standalone", "built executable returned the wrong value");
|
||||
};
|
||||
if (!testenv.same(testenv.readfile(c1), testenv.readfile(c2))) {
|
||||
fail("standalone", "two clean builds were not byte-identical");
|
||||
};
|
||||
|
||||
let lib: str = strings.concat(td, "/libonly");
|
||||
mkdir(lib);
|
||||
testenv.writefile(strings.concat(lib, "/lib.ww"), strings.concat(
|
||||
"package libonly;\n",
|
||||
"export fn shown() i32 = { return 7; };\n",
|
||||
"fn hidden() i32 = { return 99; };\n"));
|
||||
let ca: str = strings.concat(td, "/libonly-c.a");
|
||||
let wa: str = strings.concat(td, "/libonly-w.a");
|
||||
let cav: []str = [testenv.driver("ww"), "build", "-p", "-I", td,
|
||||
"-o", ca, lib];
|
||||
let wav: []str = [testenv.driver("ww_ww"), "build", "-p", "-I", td,
|
||||
"-o", wa, lib];
|
||||
if (code(td, "build_package_c", cav) != 0
|
||||
|| code(td, "build_package_w", wav) != 0) {
|
||||
fail("package-artifact", "non-main package build failed");
|
||||
};
|
||||
if (!testenv.exists(strings.concat(ca, ".wwi"))
|
||||
|| !testenv.exists(strings.concat(wa, ".wwi"))) {
|
||||
fail("package-artifact", "missing compiler export sidecar");
|
||||
};
|
||||
if (!testenv.same(testenv.readfile(ca), testenv.readfile(wa))
|
||||
|| !testenv.same(testenv.readfile(strings.concat(ca, ".wwi")),
|
||||
testenv.readfile(strings.concat(wa, ".wwi")))) {
|
||||
fail("package-artifact", "C/WW package products differ");
|
||||
};
|
||||
let iface: str = testenv.readfile(strings.concat(ca, ".wwi"));
|
||||
if (!testenv.has(iface, "shown") || testenv.has(iface, "hidden")) {
|
||||
fail("package-artifact", "export interface crossed the private boundary");
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
fn writediamond(td: str, reverse: bool) str = {
|
||||
let shared: str = strings.concat(td, "/shared");
|
||||
let left: str = strings.concat(td, "/left");
|
||||
let right: str = strings.concat(td, "/right");
|
||||
let main: str = strings.concat(td, "/main");
|
||||
if (reverse) { mkdir(left); mkdir(main); mkdir(shared); mkdir(right); }
|
||||
else { mkdir(right); mkdir(shared); mkdir(main); mkdir(left); };
|
||||
let zsrc: str = strings.concat(
|
||||
"package shared;\n",
|
||||
"fn hidden() i32 = { return 91; };\n");
|
||||
let asrc: str = strings.concat(
|
||||
"package shared;\n",
|
||||
"export type token = struct { value: i32, };\n",
|
||||
"export fn base() i32 = { return 3; };\n");
|
||||
if (reverse) {
|
||||
testenv.writefile(strings.concat(shared, "/a.ww"), asrc);
|
||||
testenv.writefile(strings.concat(shared, "/z.ww"), zsrc);
|
||||
} else {
|
||||
testenv.writefile(strings.concat(shared, "/z.ww"), zsrc);
|
||||
testenv.writefile(strings.concat(shared, "/a.ww"), asrc);
|
||||
};
|
||||
testenv.writefile(strings.concat(left, "/left.ww"), strings.concat(
|
||||
"package left;\nimport shared;\nimport shared;\n",
|
||||
"export fn value() i32 = { return shared.base() + 1; };\n"));
|
||||
testenv.writefile(strings.concat(right, "/right.ww"), strings.concat(
|
||||
"package right;\nimport shared;\n",
|
||||
"export fn value() i32 = { return shared.base() + 2; };\n"));
|
||||
testenv.writefile(strings.concat(main, "/main.ww"), strings.concat(
|
||||
"package main;\nimport right;\nimport left;\n",
|
||||
"fn main() i32 = { return left.value() + right.value(); };\n"));
|
||||
return main;
|
||||
};
|
||||
|
||||
@test fn direct_and_diamond() void = {
|
||||
let td: str = testenv.fresh();
|
||||
let treea: str = strings.concat(td, "/tree-a"); mkdir(treea);
|
||||
let treeb: str = strings.concat(td, "/tree-b"); mkdir(treeb);
|
||||
let main: str = writediamond(treea, false);
|
||||
let shuffled: str = writediamond(treeb, true);
|
||||
let drivers: []str = ["ww", "ww_ww"];
|
||||
let tags: []str = ["c", "w"];
|
||||
let i: i32 = 0;
|
||||
for (i < drivers.len) {
|
||||
let out: str = strings.concat(td, "/diamond-", tags[i]);
|
||||
if (build(treea, drivers[i], strings.concat("diamond_", tags[i]),
|
||||
main, out) != 0) {
|
||||
fail("diamond", strings.concat(drivers[i], " build failed"));
|
||||
};
|
||||
let av: []str = [out];
|
||||
if (code(td, strings.concat("run_diamond_", tags[i]), av) != 9) {
|
||||
fail("diamond", "linked program returned the wrong value");
|
||||
};
|
||||
let scratch: str = strings.concat(out, ".sepwork/");
|
||||
if (!testenv.exists(strings.concat(scratch, "shared.a"))
|
||||
|| testenv.exists(strings.concat(scratch, "shared.shared.a"))) {
|
||||
fail("diamond", "shared package was not interned exactly once");
|
||||
};
|
||||
let unit: str = testenv.readfile(strings.concat(scratch,
|
||||
"__root.unit.ww"));
|
||||
let lp: i32 = testenv.pos(unit, "//ww:module left\n");
|
||||
let rp: i32 = testenv.pos(unit, "//ww:module right\n");
|
||||
if (lp < 0 || rp < 0 || lp >= rp) {
|
||||
fail("diamond", "dependency traversal did not byte-sort imports");
|
||||
};
|
||||
let sharedunit: str = testenv.readfile(strings.concat(scratch,
|
||||
"shared.unit.ww"));
|
||||
let ap: i32 = testenv.pos(sharedunit, "export type token");
|
||||
let zp: i32 = testenv.pos(sharedunit, "fn hidden");
|
||||
if (ap < 0 || zp < 0 || ap >= zp) {
|
||||
fail("diamond", "package sources were not byte-sorted");
|
||||
};
|
||||
let leftiface: str = testenv.readfile(strings.concat(scratch,
|
||||
"left.wwi"));
|
||||
if (testenv.occurrences(leftiface, "import shared;") != 1) {
|
||||
fail("diamond", "duplicate import escaped into export data");
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
let shuffledout: str = strings.concat(td, "/diamond-c-shuffled");
|
||||
if (build(treeb, "ww", "diamond_c_shuffled", shuffled,
|
||||
shuffledout) != 0) {
|
||||
fail("diamond", "shuffled directory build failed");
|
||||
};
|
||||
let firstout: str = strings.concat(td, "/diamond-c");
|
||||
if (!testenv.same(testenv.readfile(firstout),
|
||||
testenv.readfile(shuffledout))) {
|
||||
fail("diamond", "shuffled directory enumeration changed output");
|
||||
};
|
||||
let firstscratch: str = strings.concat(firstout, ".sepwork/");
|
||||
let shuffledscratch: str = strings.concat(shuffledout, ".sepwork/");
|
||||
if (!testenv.same(testenv.readfile(strings.concat(firstscratch,
|
||||
"__root.unit.ww")), testenv.readfile(strings.concat(shuffledscratch,
|
||||
"__root.unit.ww"))) || !testenv.same(testenv.readfile(strings.concat(
|
||||
firstscratch, "shared.unit.ww")), testenv.readfile(strings.concat(
|
||||
shuffledscratch, "shared.unit.ww")))) {
|
||||
fail("diamond", "shuffled enumeration changed package units");
|
||||
};
|
||||
|
||||
// Count actual compiler actions, rather than inferring interning from
|
||||
// artifact names. The wrapper is selected through the production
|
||||
// driver's existing tool override and records one row per w6c process.
|
||||
let trace: str = strings.concat(td, "/compiler.trace");
|
||||
let wrapper: str = strings.concat(td, "/trace-w6c.sh");
|
||||
testenv.writefile(trace, "");
|
||||
testenv.writefile(wrapper, strings.concat(
|
||||
"printf '%s\\n' \"$*\" >> \"$WW_LOCALBUILD_TRACE\"\n",
|
||||
"exec \"$WW_LOCALBUILD_W6C\" \"$@\"\n"));
|
||||
let baseenv: []str = os.getenvs();
|
||||
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_LOCALBUILD_TRACE=")
|
||||
&& !strings.hasprefix(baseenv[ei], "WW_LOCALBUILD_W6C=")) {
|
||||
append(env, baseenv[ei]);
|
||||
};
|
||||
ei += 1;
|
||||
};
|
||||
append(env, strings.concat("WW_W6C=/bin/sh ", wrapper));
|
||||
append(env, strings.concat("WW_LOCALBUILD_TRACE=", trace));
|
||||
append(env, strings.concat("WW_LOCALBUILD_W6C=",
|
||||
testenv.driver("w6c")));
|
||||
let countedout: str = strings.concat(td, "/diamond-counted");
|
||||
let countedav: []str = [testenv.driver("ww"), "build", "-I", treea,
|
||||
"-o", countedout, main];
|
||||
let counted: testenv.commandout;
|
||||
testenv.runcommandenv(td, td, "diamond_compile_count", countedav,
|
||||
env, tmo(), &counted);
|
||||
if (counted.termination != exec.termination.EXIT || counted.code != 0) {
|
||||
fail("diamond", "instrumented build failed");
|
||||
};
|
||||
if (testenv.occurrences(testenv.readfile(trace), "shared.unit.ww") != 1) {
|
||||
fail("diamond", "shared package was not compiled exactly once");
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
@test fn builtin_type_precedence() void = {
|
||||
let td: str = testenv.fresh();
|
||||
let dep: str = strings.concat(td, "/builtinshadow"); mkdir(dep);
|
||||
let main: str = strings.concat(td, "/main"); mkdir(main);
|
||||
testenv.writefile(strings.concat(dep, "/dep.ww"), strings.concat(
|
||||
"package builtinshadow;\n",
|
||||
"export type i32 = i8;\n",
|
||||
"export fn width() i32 = { return size(i32): i32; };\n"));
|
||||
testenv.writefile(strings.concat(main, "/main.ww"), strings.concat(
|
||||
"package main;\nimport builtinshadow;\n",
|
||||
"fn main() i32 = { return builtinshadow.width(); };\n"));
|
||||
let drivers: []str = ["ww", "ww_ww"];
|
||||
let tags: []str = ["c", "w"];
|
||||
let outputs: []str = ["", ""];
|
||||
let i: i32 = 0;
|
||||
for (i < drivers.len) {
|
||||
outputs[i] = strings.concat(td, "/builtin-", tags[i]);
|
||||
if (build(td, drivers[i], strings.concat("builtin_", tags[i]),
|
||||
main, outputs[i]) != 0) {
|
||||
fail("builtin-type", strings.concat(drivers[i], " build failed"));
|
||||
};
|
||||
let av: []str = [outputs[i]];
|
||||
if (code(td, strings.concat("run_builtin_", tags[i]), av) != 4) {
|
||||
fail("builtin-type", strings.concat(drivers[i],
|
||||
" let an imported type shadow intrinsic i32"));
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
if (!testenv.same(testenv.readfile(outputs[0]),
|
||||
testenv.readfile(outputs[1]))) {
|
||||
fail("builtin-type", "C/WW products differ");
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
@test fn export_visibility() void = {
|
||||
let td: str = testenv.fresh();
|
||||
let main: str = writediamond(td, false);
|
||||
// The successful diamond already proves a direct exported declaration.
|
||||
testenv.writefile(strings.concat(td, "/private.ww"), strings.concat(
|
||||
"package main;\nimport shared;\n",
|
||||
"fn main() i32 = { return shared.hidden(); };\n"));
|
||||
rejectstable(td, "private", strings.concat(td, "/private.ww"),
|
||||
"has no exported declaration 'hidden'");
|
||||
testenv.writefile(strings.concat(td, "/transitive.ww"), strings.concat(
|
||||
"package main;\nimport left;\n",
|
||||
"fn main() i32 = { return shared.base(); };\n"));
|
||||
rejectstable(td, "transitive", strings.concat(td, "/transitive.ww"),
|
||||
"package 'shared' is not directly imported");
|
||||
testenv.writefile(strings.concat(td, "/transitive-bare-value.ww"),
|
||||
strings.concat("package main;\nimport left;\n",
|
||||
"fn main() i32 = { return base(); };\n"));
|
||||
rejectstable(td, "transitive-bare-value",
|
||||
strings.concat(td, "/transitive-bare-value.ww"), "undefined: base");
|
||||
testenv.writefile(strings.concat(td, "/transitive-bare-type.ww"),
|
||||
strings.concat("package main;\nimport left;\n",
|
||||
"fn main() i32 = { let x: token; return 0; };\n"));
|
||||
rejectstable(td, "transitive-bare-type",
|
||||
strings.concat(td, "/transitive-bare-type.ww"),
|
||||
"unknown type 'token'");
|
||||
// Keep the helper's main directory live so the graph also has a normal
|
||||
// successful consumer in this fixture tree.
|
||||
assert(testenv.exists(main));
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
@test fn import_diagnostics() void = {
|
||||
let td: str = testenv.fresh();
|
||||
let missing: str = strings.concat(td, "/missing"); mkdir(missing);
|
||||
testenv.writefile(strings.concat(missing, "/main.ww"), strings.concat(
|
||||
"package main;\nimport nowhere;\n",
|
||||
"fn main() i32 = { return 0; };\n"));
|
||||
rejectstable(td, "missing", missing, "cannot find package nowhere");
|
||||
|
||||
let self: str = strings.concat(td, "/self"); mkdir(self);
|
||||
testenv.writefile(strings.concat(self, "/main.ww"), strings.concat(
|
||||
"package main;\nimport self;\n",
|
||||
"fn main() i32 = { return 0; };\n"));
|
||||
rejectstable(td, "self", self, "self-import");
|
||||
|
||||
let malformed: str = strings.concat(td, "/malformed"); mkdir(malformed);
|
||||
testenv.writefile(strings.concat(malformed, "/main.ww"), strings.concat(
|
||||
"package main;\nimport ;\n",
|
||||
"fn main() i32 = { return 0; };\n"));
|
||||
rejectstable(td, "malformed", malformed,
|
||||
"main.ww:2:8: error: expected identifier");
|
||||
|
||||
let attributed: str = strings.concat(td, "/attributed"); mkdir(attributed);
|
||||
testenv.writefile(strings.concat(attributed, "/main.ww"), strings.concat(
|
||||
"package main;\n@trace import nowhere;\n",
|
||||
"fn main() i32 = { return 0; };\n"));
|
||||
rejectstable(td, "attributed", attributed,
|
||||
"import cannot be exported or attributed");
|
||||
|
||||
let exported: str = strings.concat(td, "/exported"); mkdir(exported);
|
||||
testenv.writefile(strings.concat(exported, "/main.ww"), strings.concat(
|
||||
"package main;\nexport import nowhere;\n",
|
||||
"fn main() i32 = { return 0; };\n"));
|
||||
rejectstable(td, "exported", exported,
|
||||
"main.ww:2:8: error: import cannot be exported or attributed");
|
||||
|
||||
let conflict: str = strings.concat(td, "/conflict"); mkdir(conflict);
|
||||
testenv.writefile(strings.concat(conflict, "/a.ww"),
|
||||
"package main;\nfn main() i32 = { return 0; };\n");
|
||||
testenv.writefile(strings.concat(conflict, "/z.ww"),
|
||||
"package other;\nfn spare() void = { };\n");
|
||||
rejectstable(td, "conflict", conflict, "conflicting package names");
|
||||
|
||||
let real: str = strings.concat(td, "/real"); mkdir(real);
|
||||
testenv.writefile(strings.concat(real, "/real.ww"), strings.concat(
|
||||
"package real;\n",
|
||||
"export fn value() i32 = { return 1; };\n"));
|
||||
let alias: str = strings.concat(td, "/alias");
|
||||
assert(os.symlink(real, alias) == 0);
|
||||
let aliasmain: str = strings.concat(td, "/alias-main"); mkdir(aliasmain);
|
||||
testenv.writefile(strings.concat(aliasmain, "/main.ww"), strings.concat(
|
||||
"package main;\nimport real;\nimport alias;\n",
|
||||
"fn main() i32 = { return 0; };\n"));
|
||||
rejectstable(td, "identity-alias", aliasmain, "identities");
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
@test fn package_artifact_identity_and_flag_contract() void = {
|
||||
let td: str = testenv.fresh();
|
||||
let root: str = strings.concat(td, "/root"); mkdir(root);
|
||||
let foo: str = strings.concat(root, "/foo"); mkdir(foo);
|
||||
let bar: str = strings.concat(foo, "/bar"); mkdir(bar);
|
||||
testenv.writefile(strings.concat(bar, "/bar.ww"), strings.concat(
|
||||
"package bar;\n",
|
||||
"export fn nestedvalue() i32 = { return 41; };\n"));
|
||||
let ca: str = strings.concat(td, "/nested-c.a");
|
||||
let wa: str = strings.concat(td, "/nested-w.a");
|
||||
let cav: []str = [testenv.driver("ww"), "build", "-p", "-I", root,
|
||||
"-o", ca, "foo.bar"];
|
||||
let wav: []str = [testenv.driver("ww_ww"), "build", "-p", "-I", root,
|
||||
"-o", wa, "foo.bar"];
|
||||
if (code(td, "nested_package_c", cav) != 0
|
||||
|| code(td, "nested_package_w", wav) != 0) {
|
||||
fail("package-identity", "nested logical package build failed");
|
||||
};
|
||||
if (!testenv.same(testenv.readfile(ca), testenv.readfile(wa))
|
||||
|| !testenv.same(testenv.readfile(strings.concat(ca, ".wwi")),
|
||||
testenv.readfile(strings.concat(wa, ".wwi")))) {
|
||||
fail("package-identity", "nested C/WW package products differ");
|
||||
};
|
||||
let nestedasm: str = testenv.readfile(strings.concat(ca,
|
||||
".sepwork/foo.bar.s"));
|
||||
if (!testenv.has(nestedasm, "foo.bar.nestedvalue")) {
|
||||
fail("package-identity", "archive lost the full logical import path");
|
||||
};
|
||||
|
||||
let drivers: []str = ["ww", "ww_ww"];
|
||||
let i: i32 = 0;
|
||||
for (i < drivers.len) {
|
||||
let badout: str = strings.concat(td, "/bad-flags-", drivers[i]);
|
||||
let av: []str = [testenv.driver(drivers[i]), "build", "-p", "-S",
|
||||
"-I", root, "-o", badout, "foo.bar"];
|
||||
let co: testenv.commandout;
|
||||
command(td, strings.concat("package_flag_contract_", drivers[i]),
|
||||
av, &co);
|
||||
if (co.termination != exec.termination.EXIT || co.code == 0
|
||||
|| !testenv.has(co.stderr,
|
||||
"ww build: -p and -S cannot be combined")) {
|
||||
fail("package-flags", strings.concat(drivers[i],
|
||||
" accepted -p -S"));
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
@test fn generated_test_hook_is_not_a_user_exemption() void = {
|
||||
let td: str = testenv.fresh();
|
||||
let src: str = strings.concat(td, "/case.ww");
|
||||
testenv.writefile(src, strings.concat(
|
||||
"package probe;\nimport test;\n",
|
||||
"fn bad() void = { test.run(); };\n",
|
||||
"@test fn one() void = {};\n"));
|
||||
let compilers: []str = ["w6c", "w6c_ww"];
|
||||
let i: i32 = 0;
|
||||
for (i < compilers.len) {
|
||||
let asm: str = strings.concat(td, "/case-", compilers[i], ".s");
|
||||
let av: []str = [testenv.driver(compilers[i]), "-T", "-c", "-o",
|
||||
asm, src];
|
||||
let co: testenv.commandout;
|
||||
command(td, strings.concat("test_hook_", compilers[i]), av, &co);
|
||||
if (co.termination != exec.termination.EXIT || co.code == 0
|
||||
|| !testenv.has(co.stderr,
|
||||
"package 'test' has no exported declaration 'run'")) {
|
||||
fail("test-hook", strings.concat(compilers[i],
|
||||
" exempted a user-authored test.run"));
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
testenv.clean(td);
|
||||
};
|
||||
|
||||
fn writecyclepkg(td: str, name: str, next: str) void = {
|
||||
let dir: str = strings.concat(td, "/", name); mkdir(dir);
|
||||
testenv.writefile(strings.concat(dir, "/p.ww"), strings.concat(
|
||||
"package ", name, ";\nimport ", next, ";\n",
|
||||
"export fn value() i32 = { return 1; };\n"));
|
||||
};
|
||||
|
||||
@test fn cycle_diagnostics() void = {
|
||||
let td: str = testenv.fresh();
|
||||
let two: str = strings.concat(td, "/two-main"); mkdir(two);
|
||||
testenv.writefile(strings.concat(two, "/main.ww"),
|
||||
"package main;\nimport aa;\nfn main() i32 = { return 0; };\n");
|
||||
writecyclepkg(td, "aa", "bb");
|
||||
writecyclepkg(td, "bb", "aa");
|
||||
rejectstable(td, "cycle-two", two,
|
||||
"dependency cycle: aa -> bb -> aa");
|
||||
rejectstable(td, "cycle-root", strings.concat(td, "/aa"),
|
||||
"dependency cycle: aa -> bb -> aa");
|
||||
|
||||
// A second isolated root set avoids reusing the two-package graph.
|
||||
let longroot: str = strings.concat(td, "/long-main"); mkdir(longroot);
|
||||
testenv.writefile(strings.concat(longroot, "/main.ww"),
|
||||
"package main;\nimport ca;\nfn main() i32 = { return 0; };\n");
|
||||
writecyclepkg(td, "ca", "cb");
|
||||
writecyclepkg(td, "cb", "cc");
|
||||
writecyclepkg(td, "cc", "ca");
|
||||
rejectstable(td, "cycle-long", longroot,
|
||||
"dependency cycle: ca -> cb -> cc -> ca");
|
||||
testenv.clean(td);
|
||||
};
|
||||
Reference in New Issue
Block a user