lib: migrate every test file to the canonical *_test.ww name
25 renames (git mv, content untouched). _test.ww is what the package coordinator's test detection and the sep loader's canonical exclusion key on; the old *test.ww spellings survived only through the line-leading-@test compatibility scan. Consumers updated in place: LIBRARY_TESTS, the libbyteid roster, the 901/974/975/976 carriers that copy or invoke these files, and the check.c/check.ww + path/ftos comments that cite them. Closes the open-driver-work migration bullet.
This commit is contained in:
240
lib/log/log_test.ww
Normal file
240
lib/log/log_test.ww
Normal file
@@ -0,0 +1,240 @@
|
||||
// logtest — exercises lib/log. Run with `out/bin/ww run lib/log/logtest.ww`.
|
||||
//
|
||||
// One scenario per @test fn (the ww-stdlib idiom): each scenario
|
||||
// constructs a stdlogger over a memio.stream and asserts the bytes
|
||||
// the logger produced. The test surface mirrors what drew called out
|
||||
// in the design read: lprintln-to-memio, silent-writes-nothing, and
|
||||
// setlogger-swap. The process-terminating arm ([[log.fatal]] /
|
||||
// [[log.lfatal]]) needs a subprocess to verify exit(255) without
|
||||
// killing the test driver — left as a TODO until the project grows
|
||||
// a subprocess fixture.
|
||||
|
||||
package log_test;
|
||||
|
||||
import fmt;
|
||||
import io;
|
||||
import log;
|
||||
import memio;
|
||||
|
||||
fn streq(a: str, b: str) bool = {
|
||||
if (a.len != b.len) { return false; };
|
||||
let i: i32 = 0;
|
||||
for (i < a.len) {
|
||||
if (a[i] != b[i]) { return false; };
|
||||
i += 1;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
// ---- default points at global after init (must run first) ------------
|
||||
|
||||
// log.default writes to stderr through the private stderrsink — we
|
||||
// can't easily capture stderr from inside the test, so this scenario
|
||||
// verifies the initial wiring only: after lazy [[ensureinit]] runs,
|
||||
// [[log.default]] / [[log.silent]] are non-nil and [[log.global]]
|
||||
// equals [[log.default]]. The check is order-sensitive: any later
|
||||
// scenario that calls [[log.setlogger]] mutates the global, so this
|
||||
// scenario must run before [[setloggerswap]].
|
||||
@test fn defaultwiredtoglobal() void = {
|
||||
let buf: [4]u8;
|
||||
let mem = memio.fixed(buf[0:4]);
|
||||
let s = &mem.vt;
|
||||
let sl = log.new(s); // triggers ensureinit
|
||||
|
||||
assert(!(log.silent == nil));
|
||||
assert(!(log.default == nil));
|
||||
assert(!(log.global == nil));
|
||||
assert(!(log.global != log.default));
|
||||
};
|
||||
|
||||
// ---- lprintln to a memio sink: exact-byte assertion -------------------
|
||||
|
||||
@test fn lprintlnbasic() void = {
|
||||
let buf: [32]u8;
|
||||
let mem = memio.fixed(buf[0:32]);
|
||||
let s = &mem.vt;
|
||||
|
||||
let sl = log.new(s);
|
||||
|
||||
log.lprintln(&sl.logger, "hello", 42i64);
|
||||
|
||||
assert(!(!streq(memio.string(&mem), "hello 42\n")));
|
||||
};
|
||||
|
||||
// ---- lprintln single-arg: no leading space, just trailing newline -----
|
||||
|
||||
@test fn lprintlnsingle() void = {
|
||||
let buf: [16]u8;
|
||||
let mem = memio.fixed(buf[0:16]);
|
||||
let s = &mem.vt;
|
||||
|
||||
let sl = log.new(s);
|
||||
|
||||
log.lprintln(&sl.logger, "only");
|
||||
|
||||
assert(!(!streq(memio.string(&mem), "only\n")));
|
||||
};
|
||||
|
||||
// ---- lprintln zero args: bare newline ---------------------------------
|
||||
|
||||
@test fn lprintlnempty() void = {
|
||||
let buf: [4]u8;
|
||||
let mem = memio.fixed(buf[0:4]);
|
||||
let s = &mem.vt;
|
||||
|
||||
let sl = log.new(s);
|
||||
|
||||
log.lprintln(&sl.logger);
|
||||
|
||||
assert(!(!streq(memio.string(&mem), "\n")));
|
||||
};
|
||||
|
||||
// ---- silent: lprintln through log.silent writes no bytes --------------
|
||||
|
||||
// The silent logger's callback discards args without touching fmt or
|
||||
// any sink. Verified indirectly: we wire a memio.stream and never
|
||||
// pass it to log.silent — but the @test fn calling log.new first
|
||||
// triggers [[log.ensureinit]] so log.silent is non-nil here. Then
|
||||
// lprintln(silent, ...) must not crash and the memio sink must stay
|
||||
// empty (silent has no path to it anyway).
|
||||
@test fn silentwritesnothing() void = {
|
||||
let buf: [16]u8;
|
||||
let mem = memio.fixed(buf[0:16]);
|
||||
let s = &mem.vt;
|
||||
|
||||
let sl = log.new(s); // triggers log.ensureinit; populates log.silent
|
||||
|
||||
assert(!(log.silent == nil));
|
||||
|
||||
log.lprintln(log.silent, "ignored", 1i64, true);
|
||||
|
||||
assert(!(mem.pos != 0));
|
||||
};
|
||||
|
||||
// ---- setlogger swap: global redirects to a new sink, then to silent --
|
||||
|
||||
// Three-phase: install sl1 as global, println writes there; swap to
|
||||
// sl2, println writes there only; swap to silent, println discards.
|
||||
// Each memio sink starts empty and is asserted at each phase to pin
|
||||
// the swap semantics.
|
||||
@test fn setloggerswap() void = {
|
||||
let buf1: [32]u8;
|
||||
let mem1 = memio.fixed(buf1[0:32]);
|
||||
let s1 = &mem1.vt;
|
||||
let sl1 = log.new(s1);
|
||||
|
||||
let buf2: [32]u8;
|
||||
let mem2 = memio.fixed(buf2[0:32]);
|
||||
let s2 = &mem2.vt;
|
||||
let sl2 = log.new(s2);
|
||||
|
||||
log.setlogger(&sl1.logger);
|
||||
log.println("first");
|
||||
assert(!(!streq(memio.string(&mem1), "first\n")));
|
||||
assert(!(mem2.pos != 0));
|
||||
|
||||
log.setlogger(&sl2.logger);
|
||||
log.println("second");
|
||||
assert(!(!streq(memio.string(&mem2), "second\n")));
|
||||
// mem1 must be unchanged.
|
||||
assert(!(!streq(memio.string(&mem1), "first\n")));
|
||||
|
||||
log.setlogger(log.silent);
|
||||
log.println("dropped");
|
||||
// Both sinks unchanged.
|
||||
assert(!(!streq(memio.string(&mem1), "first\n")));
|
||||
assert(!(!streq(memio.string(&mem2), "second\n")));
|
||||
};
|
||||
|
||||
// ---- lprintfln: {n}-placeholder render into a memio sink -------------
|
||||
|
||||
@test fn lprintflnbasic() void = {
|
||||
let buf: [32]u8;
|
||||
let mem = memio.fixed(buf[0:32]);
|
||||
let s = &mem.vt;
|
||||
|
||||
let sl = log.new(s);
|
||||
|
||||
log.lprintfln(&sl.logger, "x={} y={}", 42i64, "hi");
|
||||
|
||||
assert(!(!streq(memio.string(&mem), "x=42 y=hi\n")));
|
||||
};
|
||||
|
||||
// ---- printfln through global: setlogger then dispatch ---------------
|
||||
|
||||
// Mirrors [[setloggerswap]] but exercises the format-string path:
|
||||
// install sl1 as global, printfln writes there; mem2 stays empty.
|
||||
@test fn printflnglobal() void = {
|
||||
let buf1: [32]u8;
|
||||
let mem1 = memio.fixed(buf1[0:32]);
|
||||
let s1 = &mem1.vt;
|
||||
let sl1 = log.new(s1);
|
||||
|
||||
let buf2: [32]u8;
|
||||
let mem2 = memio.fixed(buf2[0:32]);
|
||||
let s2 = &mem2.vt;
|
||||
let sl2 = log.new(s2);
|
||||
|
||||
log.setlogger(&sl1.logger);
|
||||
log.printfln("v={}", 7i64);
|
||||
assert(!(!streq(memio.string(&mem1), "v=7\n")));
|
||||
assert(!(mem2.pos != 0));
|
||||
};
|
||||
|
||||
// ---- silent.printfln writes nothing ---------------------------------
|
||||
|
||||
// The silent logger's printfln callback discards args without touching
|
||||
// fmt or any sink. Same pattern as [[silentwritesnothing]] for the
|
||||
// bare-args path.
|
||||
@test fn silentignoresprintfln() void = {
|
||||
let buf: [16]u8;
|
||||
let mem = memio.fixed(buf[0:16]);
|
||||
let s = &mem.vt;
|
||||
|
||||
let sl = log.new(s); // triggers log.ensureinit; populates log.silent
|
||||
|
||||
assert(!(log.silent == nil));
|
||||
|
||||
log.lprintfln(log.silent, "ignored={}", 1i64);
|
||||
|
||||
assert(!(mem.pos != 0));
|
||||
};
|
||||
|
||||
// ---- lprintfln: indexed {N} placeholder across log → fmt seam -------
|
||||
|
||||
// The fmt parser proper is covered in fmttest; this pins that log's
|
||||
// variadic forwarding propagates argv order so indexed placeholders
|
||||
// resolve correctly.
|
||||
@test fn lprintflnindexed() void = {
|
||||
let buf: [16]u8;
|
||||
let mem = memio.fixed(buf[0:16]);
|
||||
let s = &mem.vt;
|
||||
|
||||
let sl = log.new(s);
|
||||
|
||||
log.lprintfln(&sl.logger, "{1} {0}", "a", "b");
|
||||
|
||||
assert(!(!streq(memio.string(&mem), "b a\n")));
|
||||
};
|
||||
|
||||
// ---- lprintfln: {:mods} modifier across log → fmt seam --------------
|
||||
|
||||
// Pins that mod-bearing placeholders flow through log's forwarding
|
||||
// intact (parser proper covered in fmttest).
|
||||
@test fn lprintflnmods() void = {
|
||||
let buf: [16]u8;
|
||||
let mem = memio.fixed(buf[0:16]);
|
||||
let s = &mem.vt;
|
||||
|
||||
let sl = log.new(s);
|
||||
|
||||
log.lprintfln(&sl.logger, "{:5}", 42i64);
|
||||
|
||||
assert(!(!streq(memio.string(&mem), " 42\n")));
|
||||
};
|
||||
|
||||
// TODO subprocess: log.fatal / log.lfatal / log.fatalf / log.lfatalf
|
||||
// exit(255). Verifying them needs a fork+wait fixture so the parent
|
||||
// can assert WEXITSTATUS == 255 without the test process itself
|
||||
// terminating. lib/os doesn't ship process spawning yet; revisit
|
||||
// when that lands.
|
||||
Reference in New Issue
Block a user