ww build: discard exact null outputs

This commit is contained in:
2026-08-20 23:17:23 +09:00
parent 84f5e68709
commit 71a9da2058
7 changed files with 751 additions and 31 deletions

View File

@@ -542,6 +542,16 @@ fn directoryisempty(path: str) bool = {
return true;
};
fn discardedlinkcleaned(marker: str) void = {
let output: str = readfile(marker);
assert(output.len != 0);
assert(!has(output, "/dev/null"));
let slash: i32 = output.len - 1;
for (slash >= 0 && output[slash] != '/') { slash -= 1; };
assert(slash > 0);
assert(!os.exists(strings.sub(output, 0, slash)));
};
fn byteshasat(s: str, off: i32, want: str) bool = {
if (off < 0 || off + want.len > s.len) { return false; };
let i: i32 = 0;
@@ -12990,3 +13000,490 @@ fn runtimepath(relative: str) str = {
assert(!directoryhasnew(parallelwwwork));
clean(root);
};
@test fn exact_null_output_discards_build_products() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/source");
let base: str = strings.concat(source, "/base");
let alpha: str = strings.concat(source, "/alpha");
let beta: str = strings.concat(source, "/beta");
let library: str = strings.concat(source, "/library");
let bad: str = strings.concat(source, "/bad");
let absent: str = strings.concat(source, "/absent");
mkdirall(base); mkdirall(alpha); mkdirall(beta);
mkdirall(library); mkdirall(bad); mkdirall(absent);
writefile(strings.concat(base, "/base.ww"), strings.concat(
"package base;\n",
"export fn value() i32 = { return 4; };\n"));
let alphafile: str = strings.concat(alpha, "/main.ww");
let alphaoriginal: str = strings.concat(
"package main;\nimport base;\n",
"fn main() i32 = { return base.value(); };\n");
let alphachanged: str = strings.concat(
"package main;\nimport base;\n",
"fn main() i32 = { return base.value() + 1; };\n");
let alphafailing: str = strings.concat(
"package main;\nimport base;\n",
"fn main() i32 = { return base.value() + 2; };\n");
writefile(alphafile, alphaoriginal);
writefile(strings.concat(beta, "/main.ww"),
"package main;\nfn main() i32 = { return 6; };\n");
writefile(strings.concat(library, "/library.ww"), strings.concat(
"package odd;\n",
"export fn value() i32 = { return 7; };\n"));
writefile(strings.concat(bad, "/main.ww"), strings.concat(
"package main;\nimport _ missing.pkg;\n",
"fn main() i32 = { return 0; };\n"));
let raw: str = strings.concat(source, "/raw.ww");
writefile(raw, "package main;\nfn main() i32 = { return 9; };\n");
let compilerwrapper: str = strings.concat(root, "/null-w6c.sh");
let assemblerwrapper: str = strings.concat(root, "/null-w6a.sh");
let linkerwrapper: str = strings.concat(root, "/null-w6l.sh");
writeexecutable(compilerwrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_NULL_CTRACE\"\n",
"exec \"$WW_NULL_REAL_C\" \"$@\"\n"));
writeexecutable(assemblerwrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_NULL_ATRACE\"\n",
"exec \"$WW_NULL_REAL_A\" \"$@\"\n"));
writeexecutable(linkerwrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_NULL_LTRACE\"\n",
"out= take=\n",
"for arg do\n",
" if test \"$take\" = yes; then out=$arg; take=; continue; fi\n",
" if test \"$arg\" = -o; then take=yes; fi\n",
"done\n",
"printf '%s' \"$out\" > \"$WW_NULL_LAST_OUTPUT\"\n",
"case \"$WW_NULL_LINK_MODE\" in\n",
" fail) printf 'injected null-output linker failure\\n' >&2; exit 97;;\n",
" signal) kill -TERM \"$$\";;\n",
"esac\n",
"\"$WW_NULL_REAL_L\" \"$@\"\n",
"rc=$?\n",
"if test \"$rc\" -eq 0 && test -n \"$WW_NULL_CAPTURE\"; then\n",
" cp \"$out\" \"$WW_NULL_CAPTURE\" || exit 98\n",
"fi\n",
"exit \"$rc\"\n"));
let nullbefore: os.filestat;
match (os.stat(&nullbefore, "/dev/null")) {
case void => void;
case let e: os.oserror => abort("cannot stat /dev/null");
};
assert(((nullbefore.mode as u32) & 61440u32)
== (os.mode.CHR as u32));
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 tags: []str = ["c", "ww"];
let coldref: str = "";
let changedref: str = "";
let rawref: str = "";
let lookalikeref: str = "";
let faildiagref: str = "";
let signaldiagref: str = "";
let missingdiagref: str = "";
let emptydiagref: str = "";
let rejectdiagref: str = "";
let testcompileref: str = "";
let testoutrefs: []str = ["", "", ""];
let testerrrefs: []str = ["", "", ""];
let baseenv: []str = os.getenvs();
let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
let out: commandout;
let si: i32 = 0;
for (si < stages.len) {
rewritefile(alphafile, alphaoriginal);
let work: str = strings.concat(root, "/work-", tags[si]);
mkdirall(work);
let ctrace: str = strings.concat(root, "/", tags[si], "-c.trace");
let atrace: str = strings.concat(root, "/", tags[si], "-a.trace");
let ltrace: str = strings.concat(root, "/", tags[si], "-l.trace");
let lastout: str = strings.concat(root, "/", tags[si], "-last.out");
let capture: str = strings.concat(root, "/", tags[si], "-capture");
writefile(ctrace, ""); writefile(atrace, "");
writefile(ltrace, ""); writefile(lastout, "");
let env: []str = alloc([], (baseenv.len + 12): 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_NULL_")) {
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_NULL_CTRACE=", ctrace));
append(env, strings.concat("WW_NULL_ATRACE=", atrace));
append(env, strings.concat("WW_NULL_LTRACE=", ltrace));
append(env, strings.concat("WW_NULL_REAL_C=",
driver(compilers[si])));
append(env, strings.concat("WW_NULL_REAL_A=",
driver(assemblers[si])));
append(env, strings.concat("WW_NULL_REAL_L=",
driver(linkers[si])));
let linkmodeindex: i32 = env.len;
append(env, "WW_NULL_LINK_MODE=");
let captureindex: i32 = env.len;
append(env, strings.concat("WW_NULL_CAPTURE=", capture));
append(env, strings.concat("WW_NULL_LAST_OUTPUT=", lastout));
// Exact null is no-install policy. Loading, dependency production,
// assembly, archiving, and the command link still occur normally.
let coldav: []str = [driver(stages[si]), "build", "-w", work,
"-I", source, "-o", "/dev/null", alpha];
runcommandenvdir(root, strings.concat("null-cold-", tags[si]), coldav,
env, root, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(occurrences(readfile(ctrace), "\n") == 2);
assert(occurrences(readfile(atrace), "\n") == 3);
assert(occurrences(readfile(ltrace), "\n") == 1);
assert(has(readfile(ctrace), "/base.unit.new"));
assert(has(readfile(ctrace), "/alpha.unit.new"));
discardedlinkcleaned(lastout);
let coldbytes: str = readfile(capture);
if (si == 0) { coldref = strings.dup(coldbytes); }
else { assert(same(coldref, coldbytes)); };
let runav: []str = [capture];
runcommand(root, strings.concat("null-cold-run-", tags[si]), runav,
time.second, &out);
expectexit(&out, 4);
let originalunit: str = readfile(strings.concat(work,
"/alpha.unit.ww"));
// Unchanged actions are warm-reused, but the command links again into
// fresh private storage because null output is not a result cache.
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, ""); rewritefile(lastout, "");
rewritefile(capture, "");
runcommandenvdir(root, strings.concat("null-warm-", tags[si]), coldav,
env, root, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(readfile(ctrace).len == 0 && readfile(atrace).len == 0);
assert(occurrences(readfile(ltrace), "\n") == 1);
assert(same(coldbytes, readfile(capture)));
discardedlinkcleaned(lastout);
// Source change invalidates the owning action and linked bytes while
// preserving the same action names and persistent representation.
rewritefile(alphafile, alphachanged);
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, ""); rewritefile(lastout, "");
rewritefile(capture, "");
runcommandenvdir(root, strings.concat("null-change-", tags[si]), coldav,
env, root, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(readfile(ctrace), "\n") == 1);
assert(occurrences(readfile(atrace), "\n") == 1);
assert(occurrences(readfile(ltrace), "\n") == 1);
assert(!same(originalunit, readfile(strings.concat(work,
"/alpha.unit.ww"))));
let changedbytes: str = readfile(capture);
assert(!same(coldbytes, changedbytes));
if (si == 0) { changedref = strings.dup(changedbytes); }
else { assert(same(changedref, changedbytes)); };
discardedlinkcleaned(lastout);
let kept: []str = alloc([], suffixes.len: u64)!;
let xi: i32 = 0;
for (xi < suffixes.len) {
append(kept, strings.dup(readfile(strings.concat(work,
"/alpha", suffixes[xi]))));
xi += 1;
};
// A late producer failure and a producer signal cannot publish and
// cannot commit an invalidated persistent generation.
rewritefile(alphafile, alphafailing);
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, ""); rewritefile(lastout, "");
env[linkmodeindex] = "WW_NULL_LINK_MODE=fail";
runcommandenvdir(root, strings.concat("null-fail-", tags[si]), coldav,
env, root, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "injected null-output linker failure\n"));
assert(has(out.stderr, "ww: w6l failed\n"));
assert(occurrences(readfile(ltrace), "\n") == 1);
discardedlinkcleaned(lastout);
xi = 0;
for (xi < suffixes.len) {
assert(same(kept[xi], readfile(strings.concat(work,
"/alpha", suffixes[xi]))));
xi += 1;
};
assert(!directoryhasnew(work));
if (si == 0) { faildiagref = strings.dup(out.stderr); }
else { assert(same(faildiagref, out.stderr)); };
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, ""); rewritefile(lastout, "");
env[linkmodeindex] = "WW_NULL_LINK_MODE=signal";
runcommandenvdir(root, strings.concat("null-signal-", tags[si]), coldav,
env, root, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "ww: w6l failed\n"));
discardedlinkcleaned(lastout);
xi = 0;
for (xi < suffixes.len) {
assert(same(kept[xi], readfile(strings.concat(work,
"/alpha", suffixes[xi]))));
xi += 1;
};
assert(!directoryhasnew(work));
if (si == 0) { signaldiagref = strings.dup(out.stderr); }
else { assert(same(signaldiagref, out.stderr)); };
env[linkmodeindex] = "WW_NULL_LINK_MODE=";
// Import loading and empty-pattern handling precede output planning.
// The exact null exception changes neither diagnostic nor tool order.
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, ""); rewritefile(lastout, "");
let badav: []str = [driver(stages[si]), "build", "-I", source,
"-o", "/dev/null", bad];
runcommandenvdir(root, strings.concat("null-import-", tags[si]), badav,
env, root, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(has(out.stderr, "cannot find package missing.pkg\n"));
assert(readfile(ctrace).len == 0 && readfile(atrace).len == 0
&& readfile(ltrace).len == 0 && readfile(lastout).len == 0);
if (si == 0) { missingdiagref = strings.dup(out.stderr); }
else { assert(same(missingdiagref, out.stderr)); };
let emptyroot: str = strings.concat(source, "/absent/...");
let emptyav: []str = [driver(stages[si]), "build", "-o",
"/dev/null", emptyroot];
runcommandenvdir(root, strings.concat("null-empty-", tags[si]), emptyav,
env, root, time.second, &out);
expectexit(&out, 0);
assert(has(out.stderr, "matched no packages\n"));
assert(readfile(ctrace).len == 0 && readfile(ltrace).len == 0);
if (si == 0) { emptydiagref = strings.dup(out.stderr); }
else { assert(same(emptydiagref, out.stderr)); };
// One discard request may contain commands and a non-main library.
// Every action runs, only commands link, and no basename is published.
rewritefile(alphafile, alphaoriginal);
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, ""); rewritefile(lastout, "");
let multiav: []str = [driver(stages[si]), "build", "-I", source,
"-o", "/dev/null", alpha, beta, library];
runcommandenvdir(root, strings.concat("null-multi-", tags[si]), multiav,
env, root, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(occurrences(readfile(ctrace), "\n") == 4);
assert(occurrences(readfile(atrace), "\n") == 6);
assert(occurrences(readfile(ltrace), "\n") == 2);
assert(!os.exists(strings.concat(root, "/alpha")));
assert(!os.exists(strings.concat(root, "/beta")));
assert(!os.exists(strings.concat(root, "/library")));
assert(!os.exists("/dev/null.new"));
assert(!os.exists("/dev/null.sepwork"));
// Assembly-only keeps the same loading/action exception, has no link,
// and needs no persistent workdir solely to make discarded files visible.
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, ""); rewritefile(lastout, "");
let asmav: []str = [driver(stages[si]), "build", "-S", "-I", source,
"-o", "/dev/null", alpha, beta, library];
runcommandenvdir(root, strings.concat("null-asm-", tags[si]), asmav,
env, root, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(readfile(ctrace), "\n") == 4);
assert(readfile(atrace).len == 0 && readfile(ltrace).len == 0);
// The direct raw-file route links privately too. A wrapper capture proves
// the linked bytes are runnable before the driver's cleanup.
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, ""); rewritefile(lastout, "");
rewritefile(capture, "");
let rawav: []str = [driver(stages[si]), "build", "-o",
"/dev/null", raw];
runcommandenvdir(root, strings.concat("null-raw-", tags[si]), rawav,
env, root, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(readfile(ltrace), "\n") == 1);
discardedlinkcleaned(lastout);
let rawbytes: str = readfile(capture);
if (si == 0) { rawref = strings.dup(rawbytes); }
else { assert(same(rawref, rawbytes)); };
let rawrun: []str = [capture];
runcommand(root, strings.concat("null-raw-run-", tags[si]), rawrun,
time.second, &out);
expectexit(&out, 9);
// Null recognition is exact. A regular lookalike is retained with its
// established adjacent scratch; a multi-root lookalike still rejects.
let lookalike: str = strings.concat(root, "/null-like-", tags[si]);
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, ""); rewritefile(lastout, "");
env[captureindex] = "WW_NULL_CAPTURE=";
let lookav: []str = [driver(stages[si]), "build", "-o",
lookalike, raw];
runcommandenvdir(root, strings.concat("null-look-", tags[si]), lookav,
env, root, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(os.exists(lookalike));
assert(os.exists(strings.concat(lookalike, ".sepwork")));
let lookbytes: str = readfile(lookalike);
if (si == 0) { lookalikeref = strings.dup(lookbytes); }
else { assert(same(lookalikeref, lookbytes)); };
let rejectout: str = strings.concat(root, "/multi-like-", tags[si]);
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, "");
let rejectav: []str = [driver(stages[si]), "build", "-I", source,
"-o", rejectout, alpha, beta];
runcommandenvdir(root, strings.concat("null-reject-", tags[si]),
rejectav, env, root, time.second, &out);
expectexit(&out, 2);
assert(has(out.stderr, "cannot use -o with multiple packages\n"));
assert(readfile(ctrace).len == 0 && readfile(atrace).len == 0
&& readfile(ltrace).len == 0);
if (si == 0) { rejectdiagref = strings.dup(out.stderr); }
else { assert(same(rejectdiagref, out.stderr)); };
env[captureindex] = strings.concat("WW_NULL_CAPTURE=", capture);
// Raw test compilation has the same private-output rule. Running forms
// preserve ordinary success, assertion, and signal outcomes.
let compileav: []str = [driver(stages[si]), "test", "-c", "-o",
"/dev/null", runtimepath("success_test.ww")];
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, ""); rewritefile(lastout, "");
rewritefile(capture, "");
runcommandenvdir(root, strings.concat("null-test-c-", tags[si]),
compileav, env, root,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
assert(occurrences(readfile(ltrace), "\n") == 1);
discardedlinkcleaned(lastout);
let testbytes: str = readfile(capture);
if (si == 0) { testcompileref = strings.dup(testbytes); }
else { assert(same(testcompileref, testbytes)); };
let runtargets: []str = ["success_test.ww", "fail_test.ww",
"signal_test.ww"];
let exitcodes: []i32 = [0, 1, 1];
let needles: []str = ["alpha_pass ... ok\n",
"assertion_failure ... FAIL (exit 1)\n",
"signal_is_not_exit ... FAIL (signal 15)\n"];
let ri: i32 = 0;
for (ri < runtargets.len) {
let testav: []str = [driver(stages[si]), "test"];
append(testav, "-o"); append(testav, "/dev/null");
append(testav, runtimepath(runtargets[ri]));
rewritefile(ctrace, ""); rewritefile(atrace, "");
rewritefile(ltrace, ""); rewritefile(lastout, "");
runcommandenvdir(root, strings.concat("null-test-run-", tags[si],
"-", boundarypkgname(ri)), testav, env, root,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, exitcodes[ri]);
assert(has(out.stdout, needles[ri]));
assert(occurrences(readfile(ltrace), "\n") == 1);
discardedlinkcleaned(lastout);
if (si == 0) {
testoutrefs[ri] = strings.dup(out.stdout);
testerrrefs[ri] = strings.dup(out.stderr);
} else {
assert(same(testoutrefs[ri], out.stdout));
assert(same(testerrrefs[ri], out.stderr));
};
ri += 1;
};
assert(!os.exists("/dev/null.new"));
assert(!os.exists("/dev/null.sepwork"));
si += 1;
};
// Persisted semantic artifacts remain byte-identical across stages. Output
// disposition is request metadata and does not enter these identities.
let actions: []str = ["base", "alpha"];
let ai: i32 = 0;
for (ai < actions.len) {
let xi: i32 = 0;
for (xi < suffixes.len) {
assert(same(readfile(strings.concat(root, "/work-c/",
actions[ai], suffixes[xi])), readfile(strings.concat(root,
"/work-ww/", actions[ai], suffixes[xi]))));
xi += 1;
};
ai += 1;
};
// Independent Cstage and WWstage discard requests can execute together.
// Their private products and persistent generations remain isolated.
let pcwork: str = strings.concat(root, "/parallel-c-work");
let pwwork: str = strings.concat(root, "/parallel-ww-work");
mkdirall(pcwork); mkdirall(pwwork);
let pcav: []str = [driver("ww"), "build", "-w", pcwork,
"-I", source, "-o", "/dev/null", alpha, beta, library];
let pwav: []str = [driver("ww_ww"), "build", "-w", pwwork,
"-I", source, "-o", "/dev/null", alpha, beta, library];
let pc: exec.command;
pc.path = pcav[0]; pc.argv = pcav; pc.env = os.getenvs(); pc.dir = root;
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 = root;
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);
assert(pwp.result.errno == 0 && pwp.result.cleanuperrno == 0);
assert(pcp.result.termination == exec.termination.EXIT
&& pcp.result.code == 0);
assert(pwp.result.termination == exec.termination.EXIT
&& pwp.result.code == 0);
assert(readfile(pc.stdoutpath).len == 0 && readfile(pc.stderrpath).len == 0);
assert(readfile(pw.stdoutpath).len == 0 && readfile(pw.stderrpath).len == 0);
assert(!directoryhasnew(pcwork) && !directoryhasnew(pwwork));
ai = 0;
let parallel: []str = ["base", "alpha", "beta", "library"];
for (ai < parallel.len) {
let xi: i32 = 0;
for (xi < suffixes.len) {
assert(same(readfile(strings.concat(pcwork, "/", parallel[ai],
suffixes[xi])), readfile(strings.concat(pwwork, "/",
parallel[ai], suffixes[xi]))));
xi += 1;
};
ai += 1;
};
let nullafter: os.filestat;
match (os.stat(&nullafter, "/dev/null")) {
case void => void;
case let e: os.oserror => abort("cannot restat /dev/null");
};
assert((nullafter.mode as u32) == (nullbefore.mode as u32));
assert(nullafter.inode == nullbefore.inode);
assert(nullafter.sz == nullbefore.sz);
assert(!os.exists("/dev/null.new"));
assert(!os.exists("/dev/null.sepwork"));
clean(root);
};