|
|
|
|
@@ -854,6 +854,452 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|
|
|
|
clean(root);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// A source file has one contiguous import section immediately after its
|
|
|
|
|
// package clause. The parser may continue after a late import for recovery,
|
|
|
|
|
// but the imports-only loader and the full compiler parser both reject it.
|
|
|
|
|
// This observer keeps that source rule separate from dotted import identity.
|
|
|
|
|
@test fn imports_precede_other_top_level_declarations() void = {
|
|
|
|
|
let root: str = fresh();
|
|
|
|
|
let tree: str = strings.concat(root, "/tree");
|
|
|
|
|
let base: str = strings.concat(tree, "/domain/base");
|
|
|
|
|
let dep: str = strings.concat(tree, "/domain/dep");
|
|
|
|
|
let app: str = strings.concat(tree, "/domain/app");
|
|
|
|
|
let missinglate: str = strings.concat(tree, "/domain/missinglate");
|
|
|
|
|
let prodtest: str = strings.concat(tree, "/domain/prodtest");
|
|
|
|
|
let internaltest: str = strings.concat(tree, "/domain/internaltest");
|
|
|
|
|
let externaltest: str = strings.concat(tree, "/domain/externaltest");
|
|
|
|
|
let testonly: str = strings.concat(tree, "/domain/testonly");
|
|
|
|
|
let validtest: str = strings.concat(tree, "/domain/validtest");
|
|
|
|
|
mkdirall(base); mkdirall(dep); mkdirall(app); mkdirall(missinglate);
|
|
|
|
|
mkdirall(prodtest); mkdirall(internaltest); mkdirall(externaltest);
|
|
|
|
|
mkdirall(testonly); mkdirall(validtest);
|
|
|
|
|
|
|
|
|
|
writefile(strings.concat(base, "/base.ww"),
|
|
|
|
|
"package base;\nexport fn value() i32 = { return 40; };\n");
|
|
|
|
|
let depfile: str = strings.concat(dep, "/dep.ww");
|
|
|
|
|
let depvalid: str = strings.concat(
|
|
|
|
|
"package renamed;\nimport domain.base;\n",
|
|
|
|
|
"fn delta() i32 = { return 1; };\n",
|
|
|
|
|
"export fn value() i32 = { return base.value() + delta(); };\n");
|
|
|
|
|
let deplate: str = strings.concat(
|
|
|
|
|
"package renamed;\nfn delta() i32 = { return 1; };\n",
|
|
|
|
|
"import domain.base;\n",
|
|
|
|
|
"export fn value() i32 = { return base.value() + delta(); };\n");
|
|
|
|
|
writefile(depfile, depvalid);
|
|
|
|
|
let appfile: str = strings.concat(app, "/main.ww");
|
|
|
|
|
let appvalid: str = strings.concat(
|
|
|
|
|
"package main;\nimport domain.dep;\n",
|
|
|
|
|
"fn local() i32 = { return 1; };\n",
|
|
|
|
|
"fn main() i32 = { return renamed.value() + local(); };\n");
|
|
|
|
|
let applate: str = strings.concat(
|
|
|
|
|
"package main;\nfn local() i32 = { return 1; };\n",
|
|
|
|
|
"import domain.dep;\n",
|
|
|
|
|
"fn main() i32 = { return renamed.value() + local(); };\n");
|
|
|
|
|
writefile(appfile, appvalid);
|
|
|
|
|
// Platform exclusion precedes package/import parsing. Neither the wrong
|
|
|
|
|
// declared name nor this late missing import may affect linux/amd64.
|
|
|
|
|
writefile(strings.concat(app, "/ignored_windows.ww"), strings.concat(
|
|
|
|
|
"package wrong;\nfn ignored() void = {};\n",
|
|
|
|
|
"import missing.platform;\n"));
|
|
|
|
|
writefile(strings.concat(missinglate, "/main.ww"), strings.concat(
|
|
|
|
|
"package main;\nfn before() i32 = { return 0; };\n",
|
|
|
|
|
"import missing.pkg;\nfn main() i32 = { return before(); };\n"));
|
|
|
|
|
|
|
|
|
|
// Production, same-package test, external-test, and test-only sources all
|
|
|
|
|
// pass through the same per-source ordering rule before product actions.
|
|
|
|
|
writefile(strings.concat(prodtest, "/pkg.ww"), strings.concat(
|
|
|
|
|
"package prodtest;\nfn local() i32 = { return 1; };\n",
|
|
|
|
|
"import domain.dep;\n",
|
|
|
|
|
"export fn value() i32 = { return local() + renamed.value(); };\n"));
|
|
|
|
|
writefile(strings.concat(prodtest, "/pkg_test.ww"),
|
|
|
|
|
"package prodtest;\n@test fn must_not_run() void = { abort(\"ran\"); };\n");
|
|
|
|
|
writefile(strings.concat(internaltest, "/pkg.ww"),
|
|
|
|
|
"package internaltest;\nfn local() i32 = { return 1; };\n");
|
|
|
|
|
writefile(strings.concat(internaltest, "/pkg_test.ww"), strings.concat(
|
|
|
|
|
"package internaltest;\nfn testlocal() i32 = { return 1; };\n",
|
|
|
|
|
"import domain.dep;\n",
|
|
|
|
|
"@test fn must_not_run() void = { abort(\"ran\"); };\n"));
|
|
|
|
|
writefile(strings.concat(externaltest, "/pkg.ww"),
|
|
|
|
|
"package externaltest;\nexport fn local() i32 = { return 1; };\n");
|
|
|
|
|
writefile(strings.concat(externaltest, "/pkg_test.ww"), strings.concat(
|
|
|
|
|
"package externaltest_test;\nfn testlocal() i32 = { return 1; };\n",
|
|
|
|
|
"import domain.dep;\n",
|
|
|
|
|
"@test fn must_not_run() void = { abort(\"ran\"); };\n"));
|
|
|
|
|
writefile(strings.concat(testonly, "/only_test.ww"), strings.concat(
|
|
|
|
|
"package testonly;\nfn testlocal() i32 = { return 1; };\n",
|
|
|
|
|
"import domain.dep;\n",
|
|
|
|
|
"@test fn must_not_run() void = { abort(\"ran\"); };\n"));
|
|
|
|
|
|
|
|
|
|
writefile(strings.concat(validtest, "/pkg.ww"), strings.concat(
|
|
|
|
|
"package validtest;\nimport domain.dep;\n",
|
|
|
|
|
"fn local() i32 = { return renamed.value(); };\n"));
|
|
|
|
|
writefile(strings.concat(validtest, "/pkg_test.ww"), strings.concat(
|
|
|
|
|
"package validtest;\nimport domain.base;\n",
|
|
|
|
|
"@test fn import_first_runs() void = {",
|
|
|
|
|
" assert(local() + base.value() == 81); };\n"));
|
|
|
|
|
writefile(strings.concat(validtest, "/ignored_windows_test.ww"),
|
|
|
|
|
strings.concat("package wrong;\nfn ignored() void = {};\n",
|
|
|
|
|
"import missing.platform;\n"));
|
|
|
|
|
|
|
|
|
|
let expected: str = "imports must appear before other declarations";
|
|
|
|
|
let sections: str = strings.concat(root, "/sections.ww");
|
|
|
|
|
writefile(sections, strings.concat(
|
|
|
|
|
"package sections;\nfn first() void = {};\n",
|
|
|
|
|
"import one;\nimport two;\n",
|
|
|
|
|
"fn second() void = {};\nimport three;\n"));
|
|
|
|
|
let compilers: []str = ["w6c", "w6c_ww"];
|
|
|
|
|
let directdiag: str = "";
|
|
|
|
|
let out: commandout;
|
|
|
|
|
let i: i32 = 0;
|
|
|
|
|
for (i < compilers.len) {
|
|
|
|
|
let asmout: str = strings.concat(root, "/direct-", compilers[i], ".s");
|
|
|
|
|
let av: []str = [driver(compilers[i]), "-o", asmout, sections];
|
|
|
|
|
runcommand(root, strings.concat("import-order-direct-", compilers[i]),
|
|
|
|
|
av, (30i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
assert(out.stdout.len == 0 && !os.exists(asmout));
|
|
|
|
|
assert(occurrences(out.stderr, expected) == 2);
|
|
|
|
|
assert(same(primarydiagnostic(out.stderr), expected));
|
|
|
|
|
if (i == 0) { directdiag = strings.dup(out.stderr); }
|
|
|
|
|
else { assert(same(directdiag, out.stderr)); };
|
|
|
|
|
i += 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let compilerwrapper: str = strings.concat(root, "/import-w6c.sh");
|
|
|
|
|
let assemblerwrapper: str = strings.concat(root, "/import-w6a.sh");
|
|
|
|
|
let linkerwrapper: str = strings.concat(root, "/import-w6l.sh");
|
|
|
|
|
writeexecutable(compilerwrapper, strings.concat(
|
|
|
|
|
"#!/bin/sh\nprintf 'compile\\n' >> \"$WW_IMPORT_CTRACE\"\n",
|
|
|
|
|
"exec \"$WW_IMPORT_REAL_C\" \"$@\"\n"));
|
|
|
|
|
writeexecutable(assemblerwrapper, strings.concat(
|
|
|
|
|
"#!/bin/sh\nprintf 'assemble\\n' >> \"$WW_IMPORT_ATRACE\"\n",
|
|
|
|
|
"exec \"$WW_IMPORT_REAL_A\" \"$@\"\n"));
|
|
|
|
|
writeexecutable(linkerwrapper, strings.concat(
|
|
|
|
|
"#!/bin/sh\nprintf 'link\\n' >> \"$WW_IMPORT_LTRACE\"\n",
|
|
|
|
|
"exec \"$WW_IMPORT_REAL_L\" \"$@\"\n"));
|
|
|
|
|
|
|
|
|
|
let stages: []str = ["ww", "ww_ww"];
|
|
|
|
|
let assemblers: []str = ["w6a", "w6a_ww"];
|
|
|
|
|
let linkers: []str = ["w6l", "w6l_ww"];
|
|
|
|
|
let tags: []str = ["c", "ww"];
|
|
|
|
|
let works: []str = [strings.concat(root, "/work-c"),
|
|
|
|
|
strings.concat(root, "/work-ww")];
|
|
|
|
|
let outputs: []str = [strings.concat(root, "/app-c"),
|
|
|
|
|
strings.concat(root, "/app-ww")];
|
|
|
|
|
let testworks: []str = [strings.concat(root, "/test-work-c"),
|
|
|
|
|
strings.concat(root, "/test-work-ww")];
|
|
|
|
|
let testbins: []str = [strings.concat(root, "/valid-c.test"),
|
|
|
|
|
strings.concat(root, "/valid-ww.test")];
|
|
|
|
|
let baseenv: []str = os.getenvs();
|
|
|
|
|
let appdiag: str = "";
|
|
|
|
|
let depdiag: str = "";
|
|
|
|
|
let missingdiag: str = "";
|
|
|
|
|
let validtestout: str = "";
|
|
|
|
|
let testdiags: []str = ["", "", "", ""];
|
|
|
|
|
let artifactrefs: []str = alloc([], 64u64)!;
|
|
|
|
|
let testartifactrefs: []str = alloc([], 64u64)!;
|
|
|
|
|
let appbinref: str = "";
|
|
|
|
|
let testbinref: str = "";
|
|
|
|
|
let actions: []str = ["domain.base", "domain.dep", "domain.app"];
|
|
|
|
|
let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
|
|
|
|
|
let initsuffixes: []str = [".init.unit.ww", ".init.s", ".init.o"];
|
|
|
|
|
let testactions: []str = ["domain.base", "domain.dep",
|
|
|
|
|
"domain.validtest-internal-test", "domain.validtest-test-main"];
|
|
|
|
|
let testtargets: []str = ["domain.prodtest", "domain.internaltest",
|
|
|
|
|
"domain.externaltest", "domain.testonly"];
|
|
|
|
|
i = 0;
|
|
|
|
|
for (i < stages.len) {
|
|
|
|
|
mkdirall(works[i]); mkdirall(testworks[i]);
|
|
|
|
|
let ctrace: str = strings.concat(root, "/compile-", tags[i]);
|
|
|
|
|
let atrace: str = strings.concat(root, "/assemble-", tags[i]);
|
|
|
|
|
let ltrace: str = strings.concat(root, "/link-", tags[i]);
|
|
|
|
|
writefile(ctrace, ""); writefile(atrace, ""); writefile(ltrace, "");
|
|
|
|
|
let env: []str = alloc([], (baseenv.len + 10): 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_IMPORT_")) {
|
|
|
|
|
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_IMPORT_CTRACE=", ctrace));
|
|
|
|
|
append(env, strings.concat("WW_IMPORT_ATRACE=", atrace));
|
|
|
|
|
append(env, strings.concat("WW_IMPORT_LTRACE=", ltrace));
|
|
|
|
|
append(env, strings.concat("WW_IMPORT_REAL_C=", driver(compilers[i])));
|
|
|
|
|
append(env, strings.concat("WW_IMPORT_REAL_A=", driver(assemblers[i])));
|
|
|
|
|
append(env, strings.concat("WW_IMPORT_REAL_L=", driver(linkers[i])));
|
|
|
|
|
|
|
|
|
|
let buildav: []str = [driver(stages[i]), "build", "-I", tree,
|
|
|
|
|
"-w", works[i], "-o", outputs[i], "domain.app"];
|
|
|
|
|
runcommandenv(root, strings.concat("import-order-cold-", tags[i]),
|
|
|
|
|
buildav, env, (90i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
|
|
|
|
assert(readfile(ctrace).len != 0 && readfile(atrace).len != 0
|
|
|
|
|
&& readfile(ltrace).len != 0);
|
|
|
|
|
let built: str = strings.dup(readfile(outputs[i]));
|
|
|
|
|
if (i == 0) { appbinref = strings.dup(built); }
|
|
|
|
|
else { assert(same(appbinref, built)); };
|
|
|
|
|
let runav: []str = [outputs[i]];
|
|
|
|
|
runcommand(root, strings.concat("import-order-run-", tags[i]), runav,
|
|
|
|
|
time.second, &out);
|
|
|
|
|
expectexit(&out, 42);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
|
|
|
|
assert(has(readfile(strings.concat(works[i],
|
|
|
|
|
"/domain.dep.unit.ww")),
|
|
|
|
|
"//ww:module-reset domain.dep\npackage renamed;"));
|
|
|
|
|
|
|
|
|
|
// Save and compare every valid semantic output affected by this graph.
|
|
|
|
|
let before: []str = alloc([], 32u64)!;
|
|
|
|
|
let refi: i32 = 0;
|
|
|
|
|
let ai: i32 = 0;
|
|
|
|
|
for (ai < actions.len) {
|
|
|
|
|
let si: i32 = 0;
|
|
|
|
|
for (si < suffixes.len) {
|
|
|
|
|
let bytes: str = strings.dup(readfile(strings.concat(works[i],
|
|
|
|
|
"/", actions[ai], suffixes[si])));
|
|
|
|
|
append(before, bytes);
|
|
|
|
|
if (i == 0) { append(artifactrefs, strings.dup(bytes)); }
|
|
|
|
|
else { assert(same(artifactrefs[refi], bytes)); };
|
|
|
|
|
refi += 1; si += 1;
|
|
|
|
|
};
|
|
|
|
|
ai += 1;
|
|
|
|
|
};
|
|
|
|
|
let ii: i32 = 0;
|
|
|
|
|
for (ii < initsuffixes.len) {
|
|
|
|
|
let bytes: str = strings.dup(readfile(strings.concat(works[i],
|
|
|
|
|
"/domain.app", initsuffixes[ii])));
|
|
|
|
|
append(before, bytes);
|
|
|
|
|
if (i == 0) { append(artifactrefs, strings.dup(bytes)); }
|
|
|
|
|
else { assert(same(artifactrefs[refi], bytes)); };
|
|
|
|
|
refi += 1; ii += 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// A selected source becoming late rejects before every producer and
|
|
|
|
|
// preserves the complete committed generation and public executable.
|
|
|
|
|
rewritefile(appfile, applate);
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("import-order-app-late-", tags[i]),
|
|
|
|
|
buildav, env, (90i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
assert(out.stdout.len == 0 && same(primarydiagnostic(out.stderr), expected));
|
|
|
|
|
assert(readfile(ctrace).len == 0 && readfile(atrace).len == 0
|
|
|
|
|
&& readfile(ltrace).len == 0 && same(built, readfile(outputs[i])));
|
|
|
|
|
if (i == 0) { appdiag = strings.dup(out.stderr); }
|
|
|
|
|
else { assert(same(appdiag, out.stderr)); };
|
|
|
|
|
refi = 0; ai = 0;
|
|
|
|
|
for (ai < actions.len) {
|
|
|
|
|
let si: i32 = 0;
|
|
|
|
|
for (si < suffixes.len) {
|
|
|
|
|
assert(same(before[refi], readfile(strings.concat(works[i],
|
|
|
|
|
"/", actions[ai], suffixes[si]))));
|
|
|
|
|
refi += 1; si += 1;
|
|
|
|
|
};
|
|
|
|
|
ai += 1;
|
|
|
|
|
};
|
|
|
|
|
ii = 0;
|
|
|
|
|
for (ii < initsuffixes.len) {
|
|
|
|
|
assert(same(before[refi], readfile(strings.concat(works[i],
|
|
|
|
|
"/domain.app", initsuffixes[ii]))));
|
|
|
|
|
refi += 1; ii += 1;
|
|
|
|
|
};
|
|
|
|
|
assert(!directoryhasnew(works[i])
|
|
|
|
|
&& !os.exists(strings.concat(outputs[i], ".new"))
|
|
|
|
|
&& !os.exists(strings.concat(outputs[i], ".install"))
|
|
|
|
|
&& !directoryhasfragment(works[i], ".wwtxn."));
|
|
|
|
|
|
|
|
|
|
// Exact restoration reuses the committed producer bytes.
|
|
|
|
|
rewritefile(appfile, appvalid);
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("import-order-app-restored-", tags[i]),
|
|
|
|
|
buildav, env, (90i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& readfile(ctrace).len == 0 && readfile(atrace).len == 0
|
|
|
|
|
&& same(built, readfile(outputs[i])));
|
|
|
|
|
|
|
|
|
|
// The same rule applies while loading an imported package; the root's
|
|
|
|
|
// prior bytes and all graph identities remain unchanged.
|
|
|
|
|
rewritefile(depfile, deplate);
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("import-order-dep-late-", tags[i]),
|
|
|
|
|
buildav, env, (90i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
assert(out.stdout.len == 0 && same(primarydiagnostic(out.stderr), expected)
|
|
|
|
|
&& has(out.stderr, "/domain/dep/dep.ww:"));
|
|
|
|
|
assert(readfile(ctrace).len == 0 && readfile(atrace).len == 0
|
|
|
|
|
&& readfile(ltrace).len == 0 && same(built, readfile(outputs[i])));
|
|
|
|
|
if (i == 0) { depdiag = strings.dup(out.stderr); }
|
|
|
|
|
else { assert(same(depdiag, out.stderr)); };
|
|
|
|
|
rewritefile(depfile, depvalid);
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("import-order-dep-restored-", tags[i]),
|
|
|
|
|
buildav, env, (90i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& readfile(ctrace).len == 0 && readfile(atrace).len == 0
|
|
|
|
|
&& same(built, readfile(outputs[i])));
|
|
|
|
|
|
|
|
|
|
// Syntax ordering precedes import resolution, output creation, and cold
|
|
|
|
|
// scratch even when the late import target does not exist.
|
|
|
|
|
let misswork: str = strings.concat(root, "/missing-work-", tags[i]);
|
|
|
|
|
let missout: str = strings.concat(root, "/missing-output-", tags[i]);
|
|
|
|
|
mkdirall(misswork);
|
|
|
|
|
let missav: []str = [driver(stages[i]), "build", "-I", tree,
|
|
|
|
|
"-w", misswork, "-o", missout, "domain.missinglate"];
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("import-order-missing-", tags[i]),
|
|
|
|
|
missav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
assert(out.stdout.len == 0 && same(primarydiagnostic(out.stderr), expected)
|
|
|
|
|
&& !has(out.stderr, "cannot find package"));
|
|
|
|
|
assert(readfile(ctrace).len == 0 && readfile(atrace).len == 0
|
|
|
|
|
&& readfile(ltrace).len == 0 && directoryisempty(misswork)
|
|
|
|
|
&& !os.exists(missout) && !os.exists(strings.concat(missout, ".new"))
|
|
|
|
|
&& !os.exists(strings.concat(missout, ".sepwork")));
|
|
|
|
|
if (i == 0) { missingdiag = strings.dup(out.stderr); }
|
|
|
|
|
else { assert(same(missingdiag, out.stderr)); };
|
|
|
|
|
|
|
|
|
|
let ti: i32 = 0;
|
|
|
|
|
for (ti < testtargets.len) {
|
|
|
|
|
let twork: str = strings.concat(root, "/invalid-test-work-",
|
|
|
|
|
tags[i], "-", boundarypkgname(ti));
|
|
|
|
|
let tbin: str = strings.concat(root, "/invalid-test-bin-",
|
|
|
|
|
tags[i], "-", boundarypkgname(ti));
|
|
|
|
|
mkdirall(twork);
|
|
|
|
|
let tav: []str = [driver(stages[i]), "test", "-I", tree,
|
|
|
|
|
"-w", twork, "-o", tbin, testtargets[ti]];
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, "");
|
|
|
|
|
rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("import-order-test-", tags[i],
|
|
|
|
|
"-", boundarypkgname(ti)), tav, env,
|
|
|
|
|
(90i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
assert(same(out.stdout, "FAIL\n")
|
|
|
|
|
&& same(primarydiagnostic(out.stderr), expected));
|
|
|
|
|
assert(!has(out.stdout, "must_not_run")
|
|
|
|
|
&& !has(out.stdout, " discovered,")
|
|
|
|
|
&& !has(out.stderr, "ok "));
|
|
|
|
|
assert(readfile(ctrace).len == 0 && readfile(atrace).len == 0
|
|
|
|
|
&& readfile(ltrace).len == 0 && directoryisempty(twork));
|
|
|
|
|
assert(!os.exists(tbin) && !os.exists(strings.concat(tbin, ".new"))
|
|
|
|
|
&& !os.exists(strings.concat(tbin, ".install"))
|
|
|
|
|
&& !os.exists(strings.concat(tbin, ".sepwork")));
|
|
|
|
|
if (i == 0) { testdiags[ti] = strings.dup(out.stderr); }
|
|
|
|
|
else { assert(same(testdiags[ti], out.stderr)); };
|
|
|
|
|
ti += 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// A valid import-first test still compiles to the same retained binary
|
|
|
|
|
// and runs with the same bytes on both stages. Its excluded wrong-target
|
|
|
|
|
// late import remains completely absent from loading.
|
|
|
|
|
let validav: []str = [driver(stages[i]), "test", "-c", "-I", tree,
|
|
|
|
|
"-w", testworks[i], "-o", testbins[i], "domain.validtest"];
|
|
|
|
|
runcommandenv(root, strings.concat("import-order-valid-test-", tags[i]),
|
|
|
|
|
validav, env, (120i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
|
|
|
|
let testbytes: str = strings.dup(readfile(testbins[i]));
|
|
|
|
|
if (i == 0) { testbinref = strings.dup(testbytes); }
|
|
|
|
|
else { assert(same(testbinref, testbytes)); };
|
|
|
|
|
let testrunav: []str = [testbins[i]];
|
|
|
|
|
runcommand(root, strings.concat("import-order-valid-test-run-", tags[i]),
|
|
|
|
|
testrunav, (30i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stderr.len == 0
|
|
|
|
|
&& has(out.stdout, "import_first_runs ... ok\n"));
|
|
|
|
|
if (i == 0) { validtestout = strings.dup(out.stdout); }
|
|
|
|
|
else { assert(same(validtestout, out.stdout)); };
|
|
|
|
|
refi = 0; ai = 0;
|
|
|
|
|
for (ai < testactions.len) {
|
|
|
|
|
let si: i32 = 0;
|
|
|
|
|
for (si < suffixes.len) {
|
|
|
|
|
let bytes: str = readfile(strings.concat(testworks[i], "/",
|
|
|
|
|
testactions[ai], suffixes[si]));
|
|
|
|
|
if (i == 0) { append(testartifactrefs, strings.dup(bytes)); }
|
|
|
|
|
else { assert(same(testartifactrefs[refi], bytes)); };
|
|
|
|
|
refi += 1; si += 1;
|
|
|
|
|
};
|
|
|
|
|
ai += 1;
|
|
|
|
|
};
|
|
|
|
|
ii = 0;
|
|
|
|
|
for (ii < initsuffixes.len) {
|
|
|
|
|
let bytes: str = readfile(strings.concat(testworks[i],
|
|
|
|
|
"/domain.validtest-test-main", initsuffixes[ii]));
|
|
|
|
|
if (i == 0) { append(testartifactrefs, strings.dup(bytes)); }
|
|
|
|
|
else { assert(same(testartifactrefs[refi], bytes)); };
|
|
|
|
|
refi += 1; ii += 1;
|
|
|
|
|
};
|
|
|
|
|
assert(!directoryhasnew(works[i]) && !directoryhasnew(testworks[i])
|
|
|
|
|
&& !directoryhasfragment(works[i], ".wwtxn.")
|
|
|
|
|
&& !directoryhasfragment(testworks[i], ".wwtxn."));
|
|
|
|
|
i += 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Parser state is request-local. A valid Cstage build and an invalid
|
|
|
|
|
// WWstage build can overlap without changing either result or residue.
|
|
|
|
|
let pcwork: str = strings.concat(root, "/parallel-c-work");
|
|
|
|
|
let pwwork: str = strings.concat(root, "/parallel-ww-work");
|
|
|
|
|
let pcout: str = strings.concat(root, "/parallel-c-output");
|
|
|
|
|
let pwout: str = strings.concat(root, "/parallel-ww-output");
|
|
|
|
|
mkdirall(pcwork); mkdirall(pwwork);
|
|
|
|
|
let pcav: []str = [driver("ww"), "build", "-I", tree, "-w", pcwork,
|
|
|
|
|
"-o", pcout, "domain.app"];
|
|
|
|
|
let pwav: []str = [driver("ww_ww"), "build", "-I", tree, "-w", pwwork,
|
|
|
|
|
"-o", pwout, "domain.missinglate"];
|
|
|
|
|
let pc: exec.command;
|
|
|
|
|
pc.path = pcav[0]; pc.argv = pcav; pc.env = os.getenvs(); pc.dir = repo();
|
|
|
|
|
pc.stdoutpath = strings.concat(root, "/parallel-c.stdout");
|
|
|
|
|
pc.stderrpath = strings.concat(root, "/parallel-c.stderr");
|
|
|
|
|
pc.deadline = time.add(time.now(time.clock.monotonic),
|
|
|
|
|
(120i64 * (time.second: i64)): time.duration);
|
|
|
|
|
pc.grace = (100i64 * (time.millisecond: i64)): time.duration;
|
|
|
|
|
let pw: exec.command;
|
|
|
|
|
pw.path = pwav[0]; pw.argv = pwav; pw.env = os.getenvs(); pw.dir = repo();
|
|
|
|
|
pw.stdoutpath = strings.concat(root, "/parallel-ww.stdout");
|
|
|
|
|
pw.stderrpath = strings.concat(root, "/parallel-ww.stderr");
|
|
|
|
|
pw.deadline = time.add(time.now(time.clock.monotonic),
|
|
|
|
|
(120i64 * (time.second: i64)): time.duration);
|
|
|
|
|
pw.grace = (100i64 * (time.millisecond: i64)): time.duration;
|
|
|
|
|
let pcp: exec.process;
|
|
|
|
|
let pwp: exec.process;
|
|
|
|
|
exec.start(&pcp, &pc); exec.start(&pwp, &pw);
|
|
|
|
|
let pcdone: bool = false;
|
|
|
|
|
let pwdone: bool = false;
|
|
|
|
|
for (!pcdone || !pwdone) {
|
|
|
|
|
if (!pcdone) { pcdone = exec.poll(&pcp); };
|
|
|
|
|
if (!pwdone) { pwdone = exec.poll(&pwp); };
|
|
|
|
|
if (!pcdone || !pwdone) {
|
|
|
|
|
time.sleep(time.millisecond, time.clock.monotonic);
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
assert(pcp.result.errno == 0 && pcp.result.cleanuperrno == 0
|
|
|
|
|
&& pcp.result.termination == exec.termination.EXIT
|
|
|
|
|
&& pcp.result.code == 0);
|
|
|
|
|
assert(pwp.result.errno == 0 && pwp.result.cleanuperrno == 0
|
|
|
|
|
&& pwp.result.termination == exec.termination.EXIT
|
|
|
|
|
&& pwp.result.code == 1);
|
|
|
|
|
assert(readfile(pc.stdoutpath).len == 0 && readfile(pc.stderrpath).len == 0);
|
|
|
|
|
assert(readfile(pw.stdoutpath).len == 0
|
|
|
|
|
&& same(primarydiagnostic(readfile(pw.stderrpath)), expected));
|
|
|
|
|
assert(same(appbinref, readfile(pcout)) && !os.exists(pwout)
|
|
|
|
|
&& directoryisempty(pwwork) && !directoryhasnew(pcwork)
|
|
|
|
|
&& !directoryhasfragment(pcwork, ".wwtxn."));
|
|
|
|
|
let pcrun: []str = [pcout];
|
|
|
|
|
runcommand(root, "import-order-parallel-run", pcrun, time.second, &out);
|
|
|
|
|
expectexit(&out, 42);
|
|
|
|
|
assert(!directoryhasfragment(root, ".wwtxn.")
|
|
|
|
|
&& !directoryhasfragment(root, ".install")
|
|
|
|
|
&& !directoryhasnew(root));
|
|
|
|
|
clean(root);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@test fn list_mode_with_no_matches_emits_no_sentinel() void = {
|
|
|
|
|
let root: str = fresh();
|
|
|
|
|
let alpha: str = strings.concat(root, "/alpha");
|
|
|
|
|
|