Files
ww/internal/wwfixture/command.ww
Hojun-Cho aa0f77b891 wwfixture: declarative fixture runner
Discovers test/wcc/data, hard-pins corpus identity (1,224 fixtures,
314 error / 12 compile / 136 run / 762 run-exit, sha256 name hash),
schedules both frontend cells per fixture through os.exec with
per-cell capture dirs, and emits the strict wwfix TSV result stream.
integration.sh is the black-box owner of the CLI/protocol boundary.
2026-08-07 23:21:04 +09:00

151 lines
3.6 KiB
Plaintext

package wwfixture;
import fmt;
import os;
import strings;
type options = struct {
root: str,
patterns: []str,
jobs: i32,
list: bool,
keep: bool,
timeoutms: i64,
input: str,
};
fn usage() void = {
fmt.errorln("usage: wwfixture [-root path] [-run glob]... [-list] [-j N] [-keep] [-timeout-ms N]");
fmt.errorln(" wwfixture validate [-root path] [-run glob]... STREAM");
};
fn positive(s: str, limit: i64, out: *i64) bool = {
if (s.len == 0) { return false; };
let n: i64 = 0i64;
let i: i32 = 0;
for (i < s.len) {
let c: u8 = s[i];
if (c < '0': u8 || c > '9': u8) { return false; };
let digit: i64 = (c - '0': u8): i64;
if (n > (limit - digit) / 10i64) { return false; };
n = n * 10i64 + digit;
i += 1;
};
if (n == 0i64) { return false; };
*out = n;
return true;
};
fn initoptions(out: *options) void = {
out.root = "";
let patterns: []str = alloc([], 16u64)!;
out.patterns = patterns;
out.jobs = 4;
out.list = false;
out.keep = false;
out.timeoutms = 30000i64;
out.input = "";
};
fn parseoptions(args: []str, start: i32, validate: bool,
out: *options) bool = {
initoptions(out);
let i: i32 = start;
for (i < args.len) {
let a: str = args[i];
if (a == "-root" || a == "-run") {
if (i + 1 >= args.len) { return false; };
if (a == "-root") {
if (out.root.len != 0) { return false; };
out.root = args[i + 1];
} else { append(out.patterns, args[i + 1]); };
i += 2;
continue;
};
if (!validate && a == "-list") {
if (out.list) { return false; };
out.list = true; i += 1; continue;
};
if (!validate && a == "-keep") {
if (out.keep) { return false; };
out.keep = true; i += 1; continue;
};
if (!validate && (a == "-j" || a == "-timeout-ms")) {
if (i + 1 >= args.len) { return false; };
let n: i64 = 0i64;
let limit: i64 = 64i64;
if (a == "-timeout-ms") { limit = 3600000i64; };
if (!positive(args[i + 1], limit, &n)) { return false; };
if (a == "-j") { out.jobs = n: i32; }
else { out.timeoutms = n; };
i += 2;
continue;
};
if (validate && a.len > 0 && a[0] != '-': u8 && out.input.len == 0) {
out.input = a; i += 1; continue;
};
return false;
};
if (validate && out.input.len == 0) { return false; };
return true;
};
fn listfixtures(c: *corpus, ids: []identity) bool = {
let i: i32 = 0;
for (i < ids.len) {
let f: *fixture = &c.fixtures[ids[i].fixtureindex];
let line: str = strings.concat(f.id, "\t", stageword(ids[i].stage), "\n");
if (!writeall(os.STDOUT_FILENO, line)) { return false; };
i += 1;
};
return true;
};
fn validatecommand(opts: *options) int = {
let c: corpus;
if (!loadcorpus(opts.root, &c)) {
fmt.errorln("wwfixture validate: ", error());
return 1;
};
let ids: []identity;
selectidentities(&c, opts.patterns, &ids);
let data: str;
if (!readfile(opts.input, &data)) {
fmt.errorln("wwfixture validate: ", error());
return 1;
};
if (!validatestream(data, &c, ids)) {
fmt.errorln("wwfixture validate: ", protocolerror());
return 1;
};
return 0;
};
export fn command(args: []str) int = {
if (args.len < 1) { usage(); return 2; };
let validate: bool = args.len > 1 && args[1] == "validate";
let start: i32 = 1;
if (validate) { start = 2; };
let opts: options;
if (!parseoptions(args, start, validate, &opts)) {
usage();
return 2;
};
if (validate) { return validatecommand(&opts); };
let c: corpus;
if (!loadcorpus(opts.root, &c)) {
fmt.errorln("wwfixture: ", error());
return 1;
};
let ids: []identity;
selectidentities(&c, opts.patterns, &ids);
if (opts.list) {
if (!listfixtures(&c, ids)) {
fmt.errorln("wwfixture: result output failed");
return 1;
};
return 0;
};
return runfixtures(&opts, &c, ids);
};