test: cover directory package test graphs
This commit is contained in:
@@ -91,6 +91,26 @@ fn runcommand(root: str, name: str, argv: []str,
|
||||
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 clean(root: str) void = {
|
||||
let av: []str = ["/bin/rm", "-rf", "--", root];
|
||||
let c: exec.command;
|
||||
@@ -154,10 +174,62 @@ fn expectexit(out: *commandout, code: i32) void = {
|
||||
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);
|
||||
};
|
||||
|
||||
@test fn deterministic_routing_and_filters() void = {
|
||||
let root: str = fresh();
|
||||
let target: str = packagepath("routing");
|
||||
@@ -240,14 +312,20 @@ fn packagepath(relative: str) str = {
|
||||
assert(os.mkdir(pkgdir, 448i32) == 0);
|
||||
writefile(strings.concat(pkgdir, "/noncanon.ww"), strings.concat(
|
||||
"package noncanon;\n",
|
||||
"@test fn hidden() void = { assert(false); };\n"));
|
||||
let av: []str = [driver("ww"), "test", pkgdir];
|
||||
"@test\n/* lexer whitespace is legal here */\n",
|
||||
"fn hidden() void = { assert(false); };\n"));
|
||||
let stages: []str = ["ww", "ww_ww"];
|
||||
let out: commandout;
|
||||
runcommand(root, "noncanon", 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"));
|
||||
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);
|
||||
};
|
||||
|
||||
@@ -275,6 +353,105 @@ fn packagepath(relative: str) str = {
|
||||
(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 <package>_test"));
|
||||
|
||||
// The bootstrap drivers store package identities in the same 256-byte
|
||||
// slot. Reject an overlong coordinator selector before either stage can
|
||||
// truncate it into a different package graph.
|
||||
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"));
|
||||
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, 1);
|
||||
expectexit(&outw, 1);
|
||||
assert(same(outc.stdout, outw.stdout));
|
||||
assert(same(outc.stderr, outw.stderr));
|
||||
assert(has(outc.stderr, "invalid --ww-package-test variant"));
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
@@ -462,6 +639,403 @@ fn packagepath(relative: str) str = {
|
||||
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, "/testonly");
|
||||
let externalonly: str = strings.concat(root, "/externalonly");
|
||||
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, "/testonly.ww"), strings.concat(
|
||||
"package testonly;\n",
|
||||
"export fn value() i32 = { return 1; };\n"));
|
||||
writefile(strings.concat(externalonly, "/externalonly.ww"), strings.concat(
|
||||
"package externalonly;\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 testonly;\n",
|
||||
"// SAME_TEST_SOURCE\n",
|
||||
"@test fn same_graph() void = {\n",
|
||||
" assert(value() + testonly.value() == 42);\n",
|
||||
" assert(secret() == 6);\n};\n"));
|
||||
writefile(strings.concat(pkg, "/external_test.ww"), strings.concat(
|
||||
"package pkg_test;\nimport externalonly;\nimport pkg;\n",
|
||||
"// EXTERNAL_TEST_SOURCE\n",
|
||||
"@test fn external_graph() void = {\n",
|
||||
" assert(pkg.value() + externalonly.value() == 42);\n",
|
||||
" assert(pkg.second() == 9);\n};\n"));
|
||||
|
||||
let prodout: str = strings.concat(root, "/production.a");
|
||||
let prodav: []str = [driver("ww"), "build", "-p", "-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 api\n"));
|
||||
assert(!has(produnit, "//ww:module implementation\n"));
|
||||
assert(!has(produnit, "testonly"));
|
||||
assert(!has(produnit, "externalonly"));
|
||||
assert(!os.exists(strings.concat(prodwork, "testonly.unit.ww")));
|
||||
assert(!os.exists(strings.concat(prodwork, "externalonly.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 sameworkroot: str = strings.concat(samebin, ".sepwork");
|
||||
let externalworkroot: str = strings.concat(externalbin, ".sepwork");
|
||||
let samework: str = strings.concat(sameworkroot, "/");
|
||||
let externalwork: str = strings.concat(externalworkroot, "/");
|
||||
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 i: i32 = 0;
|
||||
for (i < drivers.len) {
|
||||
let av: []str = [driver(drivers[i]), "test", "-c", "-I", root,
|
||||
pkg];
|
||||
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(samework,
|
||||
"__root.unit.ww"));
|
||||
let externalunit: str = readfile(strings.concat(externalwork,
|
||||
"__root.unit.ww"));
|
||||
let externalproduction: str = readfile(strings.concat(externalwork,
|
||||
"pkg.unit.ww"));
|
||||
assert(has(sameunit, "//ww:module api\n"));
|
||||
assert(has(sameunit, "//ww:module testonly\n"));
|
||||
assert(has(sameunit, "//ww:module test\n"));
|
||||
assert(!has(sameunit, "//ww:module implementation\n"));
|
||||
assert(!has(sameunit, "//ww:module externalonly\n"));
|
||||
assert(!os.exists(strings.concat(samework,
|
||||
"externalonly.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 pkg\n"));
|
||||
assert(has(externalunit, "//ww:module externalonly\n"));
|
||||
assert(has(externalunit, "//ww:module test\n"));
|
||||
assert(!has(externalunit, "//ww:module api\n"));
|
||||
assert(!has(externalunit, "//ww:module implementation\n"));
|
||||
assert(!has(externalunit, "//ww:module testonly\n"));
|
||||
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 api\n"));
|
||||
assert(!has(externalproduction, "//ww:module implementation\n"));
|
||||
assert(!has(externalproduction, "SAME_TEST_SOURCE"));
|
||||
assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE"));
|
||||
assert(!has(readfile(strings.concat(externalwork, "api.unit.ww")),
|
||||
"TEST_DEPENDENCY_MUST_NOT_COMPILE"));
|
||||
assert(os.exists(strings.concat(samework, "implementation.a")));
|
||||
assert(os.exists(strings.concat(externalwork, "implementation.a")));
|
||||
assert(os.exists(strings.concat(externalwork, "api.a")));
|
||||
assert(os.exists(strings.concat(externalwork, "pkg.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(sameworkroot); clean(externalworkroot);
|
||||
clean(samebin); clean(externalbin);
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
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);
|
||||
assert(out.termination == exec.termination.EXIT && out.code != 0);
|
||||
assert(has(out.stderr, "package")
|
||||
&& has(out.stderr, "does not match import path"));
|
||||
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);
|
||||
};
|
||||
|
||||
// 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", "-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, "__root.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 test\n"));
|
||||
assert(has(rootunit, "//ww:module __wwtest\n"));
|
||||
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, "__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 diamond_test_dependency_compiles_once() void = {
|
||||
let root: str = fresh();
|
||||
let shared: str = strings.concat(root, "/shared");
|
||||
let left: str = strings.concat(root, "/left");
|
||||
let right: str = strings.concat(root, "/right");
|
||||
let target: str = strings.concat(root, "/diamond");
|
||||
assert(os.mkdir(shared, 448i32) == 0);
|
||||
assert(os.mkdir(left, 448i32) == 0);
|
||||
assert(os.mkdir(right, 448i32) == 0);
|
||||
assert(os.mkdir(target, 448i32) == 0);
|
||||
writefile(strings.concat(shared, "/shared.ww"),
|
||||
"package shared;\nexport fn value() i32 = { return 20; };\n");
|
||||
writefile(strings.concat(left, "/left.ww"), strings.concat(
|
||||
"package left;\nimport shared;\n",
|
||||
"export fn value() i32 = { return shared.value(); };\n"));
|
||||
writefile(strings.concat(right, "/right.ww"), strings.concat(
|
||||
"package right;\nimport shared;\n",
|
||||
"export fn value() i32 = { return shared.value() + 1; };\n"));
|
||||
writefile(strings.concat(target, "/diamond.ww"),
|
||||
"package diamond;\nfn local() i32 = { return 1; };\n");
|
||||
writefile(strings.concat(target, "/diamond_test.ww"), strings.concat(
|
||||
"package diamond;\nimport left;\nimport right;\n",
|
||||
"@test fn one_shared_compile() void = {\n",
|
||||
" assert(left.value() + right.value() + local() == 42);\n};\n"));
|
||||
let trace: str = strings.concat(root, "/compiler.trace");
|
||||
let wrapper: str = strings.concat(root, "/trace-w6c.sh");
|
||||
writefile(trace, "");
|
||||
writefile(wrapper, strings.concat(
|
||||
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_TRACE\"\n",
|
||||
"exec \"$WW_PACKAGE_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_PACKAGE_TRACE=")
|
||||
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=")) {
|
||||
append(env, baseenv[ei]);
|
||||
};
|
||||
ei += 1;
|
||||
};
|
||||
append(env, strings.concat("WW_W6C=/bin/sh ", wrapper));
|
||||
append(env, strings.concat("WW_PACKAGE_TRACE=", trace));
|
||||
append(env, strings.concat("WW_PACKAGE_W6C=", driver("w6c")));
|
||||
let bin: str = strings.concat(root, "/diamond.test");
|
||||
let av: []str = [driver("ww"), "test", "-c", "-o", bin,
|
||||
"-I", root, target];
|
||||
let out: commandout;
|
||||
runcommandenv(root, "diamond-build", av, env,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(occurrences(readfile(trace), "shared.unit.ww") == 1);
|
||||
let work: str = strings.concat(bin, ".sepwork/");
|
||||
let unit: str = readfile(strings.concat(work, "__root.unit.ww"));
|
||||
assert(has(unit, "//ww:module left\n"));
|
||||
assert(has(unit, "//ww:module right\n"));
|
||||
assert(!has(unit, "//ww:module shared\n"));
|
||||
assert(has(readfile(strings.concat(work, "left.unit.ww")),
|
||||
"//ww:module shared\n"));
|
||||
assert(has(readfile(strings.concat(work, "right.unit.ww")),
|
||||
"//ww:module shared\n"));
|
||||
assert(os.exists(strings.concat(work, "shared.a")));
|
||||
let runav: []str = [bin];
|
||||
runcommand(root, "diamond-run", runav,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(has(out.stdout, "one_shared_compile ... ok\n"));
|
||||
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");
|
||||
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);
|
||||
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"));
|
||||
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'");
|
||||
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
|
||||
@@ -522,6 +1096,13 @@ fn packagepath(relative: str) str = {
|
||||
assert(os.mkdir(strings.concat(tree, "/gamma"), 448i32) == 0);
|
||||
assert(os.mkdir(strings.concat(tree, "/.hidden"), 448i32) == 0);
|
||||
assert(os.mkdir(strings.concat(tree, "/_skip"), 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"),
|
||||
@@ -548,12 +1129,25 @@ fn packagepath(relative: str) str = {
|
||||
expectexit(&outw, 0);
|
||||
assert(same(outc.stdout, outw.stdout));
|
||||
assert(same(outc.stderr, outw.stderr));
|
||||
assert(has(outc.stdout, strings.concat("ok ", tree,
|
||||
" [rootpkg, same-package]\n")));
|
||||
assert(has(outc.stdout, strings.concat("ok ", tree,
|
||||
"/alpha [alpha_test, external]\n")));
|
||||
assert(has(outc.stdout, strings.concat("ok ", tree,
|
||||
"/beta/inner [inner, same-package]\n")));
|
||||
assert(has(outc.stdout, strings.concat("? ", tree,
|
||||
"/gamma [no tests]\n")));
|
||||
let rootreport: i32 = pos(outc.stdout, strings.concat("ok ", tree,
|
||||
" [rootpkg, same-package]\n"));
|
||||
let alphareport: i32 = pos(outc.stdout, strings.concat("ok ", tree,
|
||||
"/alpha [alpha_test, external]\n"));
|
||||
let innerreport: i32 = pos(outc.stdout, strings.concat("ok ", tree,
|
||||
"/beta/inner [inner, same-package]\n"));
|
||||
let gammareport: i32 = pos(outc.stdout, strings.concat("? ", tree,
|
||||
"/gamma [no tests]\n"));
|
||||
assert(rootreport >= 0 && rootreport < alphareport
|
||||
&& alphareport < innerreport && innerreport < gammareport);
|
||||
assert(occurrences(outc.stdout, strings.concat(tree, " [")) == 1);
|
||||
assert(!has(outc.stdout, ".hidden"));
|
||||
assert(!has(outc.stdout, "_skip"));
|
||||
|
||||
@@ -640,6 +1234,48 @@ fn packagepath(relative: str) str = {
|
||||
clean(root);
|
||||
};
|
||||
|
||||
@test fn persistent_package_workdirs_do_not_collide() void = {
|
||||
let root: str = fresh();
|
||||
let tree: str = strings.concat(root, "/tree");
|
||||
let a: str = strings.concat(tree, "/a");
|
||||
let ab: str = strings.concat(tree, "/a_b");
|
||||
let work: str = strings.concat(root, "/work");
|
||||
assert(os.mkdir(tree, 448i32) == 0);
|
||||
assert(os.mkdir(a, 448i32) == 0);
|
||||
assert(os.mkdir(ab, 448i32) == 0);
|
||||
assert(os.mkdir(work, 448i32) == 0);
|
||||
writefile(strings.concat(a, "/a.ww"),
|
||||
"package b_c;\nfn value() i32 = { return 1; };\n");
|
||||
writefile(strings.concat(a, "/a_test.ww"),
|
||||
"package b_c;\n@test fn first() void = { assert(value() == 1); };\n");
|
||||
writefile(strings.concat(ab, "/ab.ww"),
|
||||
"package c;\nfn value() i32 = { return 2; };\n");
|
||||
writefile(strings.concat(ab, "/ab_test.ww"),
|
||||
"package c;\n@test fn second() void = { assert(value() == 2); };\n");
|
||||
let av: []str = [driver("ww"), "test", "-j", "2", "-w", work,
|
||||
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,
|
||||
" [b_c, same-package]\n")));
|
||||
assert(has(cold, strings.concat("ok ", ab,
|
||||
" [c, same-package]\n")));
|
||||
let akey: str = strings.concat(work, "/d_", workescape(a), "_p_",
|
||||
workescape("b_c"));
|
||||
let abkey: str = strings.concat(work, "/d_", workescape(ab), "_p_",
|
||||
workescape("c"));
|
||||
assert(!same(akey, abkey));
|
||||
assert(os.exists(akey) && os.exists(abkey));
|
||||
runcommand(root, "workkey-warm", av,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(same(cold, out.stdout));
|
||||
clean(root);
|
||||
};
|
||||
|
||||
fn runtimepath(relative: str) str = {
|
||||
return strings.concat(repo(), "/test/package/runtime/", relative);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user