lib/test: Go external-test packages (<mod>_test); retire decimaltest (#16 PREP-a)

30 lib test files: package <mod> -> <mod>_test, the sanctioned Go-over-Hare
departure (CLAUDE.md rule-9 carve-out; white-box testing deferred, not
forbidden). decimaltest retired per .ai/rob-16-decimaltest-ruling.md: Hare
ships no decimal_test.ha (engine covered transitively); coverage migrated
losslessly into stoftest rows (all-9s carry, nd>19 pure-decimal) + ftostest
f64_roundtrip mirroring ref/hare strconv ftos_test.ha tcsf64; k=0 micro-gap
documented at site. regex_test keeps its white-box internal probes under a
documented rule-7 divergence (rehome = task #9). 922_decimal_run + its 989
byte-id row removed with the fixture.
This commit is contained in:
2026-06-10 12:11:11 +09:00
parent b795c320c9
commit 99e3393048
35 changed files with 77 additions and 306 deletions

View File

@@ -6,7 +6,7 @@
6. ref/hare and ref/plan9front are read-only references — consult before inventing data shapes or syntax
7. No workarounds. If a bug forces a workaround, STOP and report with a precise repro. Document any retained divergence at the site with a pointer to the filed task. Never silent.
8. Comments are WHY-only. Never narrate WHAT the code does — names carry the WHAT. Comment only non-obvious WHY: a constraint, a divergence from a reference, a citation to a filed task.
9. Hare-fidelity over convenience. No ad-hoc extensions, renames, or convenience wrappers in lib/. Cite ref/hare/<module>/<file> for every signature ported. Carve-out: the Hare `_unsafe` suffix convention is dropped wholesale (ww is C/Plan-9-lineage, an unmanaged systems language — no GC, no "safe" baseline to be unsafe relative to). bytes→str is a pure reinterpret (`strings.frombytes`, renamed from Hare's `fromutf8_unsafe`); validation is opt-in via `utf8.validate(b)?` at the IO source, never wrapped per-construction. Rationale: ref/hare/strings/utf8.ha:10,22 — the suffix flags Hare's managed-bytes-safety axis, which ww doesn't have. The honest name (`frombytes`) reserves `fromutf8` for a future true validating helper.
9. Hare-fidelity over convenience. No ad-hoc extensions, renames, or convenience wrappers in lib/. Cite ref/hare/<module>/<file> for every signature ported. Carve-out: the Hare `_unsafe` suffix convention is dropped wholesale (ww is C/Plan-9-lineage, an unmanaged systems language — no GC, no "safe" baseline to be unsafe relative to). bytes→str is a pure reinterpret (`strings.frombytes`, renamed from Hare's `fromutf8_unsafe`); validation is opt-in via `utf8.validate(b)?` at the IO source, never wrapped per-construction. Rationale: ref/hare/strings/utf8.ha:10,22 — the suffix flags Hare's managed-bytes-safety axis, which ww doesn't have. The honest name (`frombytes`) reserves `fromutf8` for a future true validating helper. Carve-out: lib/ tests use Go's external-test-package idiom (`package <mod>_test;` + `import <mod>;`), a sanctioned Go-over-Hare departure — ww hard-rejects self-import (full Go), and Hare's same-package `@test` colocation has no ww analogue yet (in-package white-box testing is deferred pending tasks #5/#8, not forbidden). Rule 5/9 binds lib/ *API* surface, not test-authoring style. Ref: Go `foo_test` convention; task #16.
10. Symmetric stages. cstage and wwstage MUST emit byte-identical asm for the same input. When inference power differs, align the richer side DOWN to the leaner side, not the other way.
11. Split commits when they bundle unrelated concerns. Bisect-cleanliness is the default. Multi-fix commits need a body paragraph explaining why they couldn't split.
12. Simple data, simple algorithms. Sea-of-stars style. Mirror Hare's structural choices over clever alternatives.

View File

@@ -475,7 +475,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
$(BIN)/test_path_run \
$(BIN)/test_letshadow_run \
$(BIN)/test_strglobeq_run \
$(BIN)/test_decimal_run $(BIN)/test_strconv_int_run \
$(BIN)/test_strconv_int_run \
$(BIN)/test_stof_run $(BIN)/test_ftos_run \
$(BIN)/test_memio_run $(BIN)/test_temp_run $(BIN)/test_getopt_run \
$(BIN)/test_errno_run \
@@ -2203,10 +2203,6 @@ $(BIN)/test_nkname_run: test/wcc/905_nkname_run.c $(BIN)/ww $(BIN)/w6c \
$(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/test_decimal_run: test/wcc/922_decimal_run.c $(BIN)/ww $(BIN)/w6c \
$(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/test_strconv_int_run: test/wcc/922_strconv_int_run.c $(BIN)/ww $(BIN)/w6c \
$(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<

View File

@@ -4,7 +4,7 @@
//
// Vectors mirror Hare's @test fn strcasecmp in ref/hare/ascii/string.ha.
package ascii;
package ascii_test;
import ascii;
import os;

View File

@@ -6,7 +6,7 @@
// surface — `let st = memio.fixed(buf); &st.vt` into the scanner/stream
// init, io.read/write/close return size/io.error.
package bufio;
package bufio_test;
import bufio;
import bytes;

View File

@@ -6,7 +6,7 @@
// Vectors mirror Hare's @test fns in ref/hare/bytes/equal.ha,
// ref/hare/bytes/index.ha, ref/hare/bytes/contains.ha.
package bytes;
package bytes_test;
import bytes;
import os;

View File

@@ -33,7 +33,7 @@
// Don't `use io;` here — lib/os and lib/io collide on read/write/
// close (task #17). We need only os.getenv + os.exit.
package dirs;
package dirs_test;
import dirs;
import os;

View File

@@ -1,4 +1,4 @@
package base32;
package base32_test;
import base32;

View File

@@ -9,7 +9,7 @@
// The streaming decoder (newdecoder) is deferred (#247-sibling), so the
// decode side is exercised through decodestr only.
package base64;
package base64_test;
import base64;
import bytes;

View File

@@ -7,7 +7,7 @@
// The streaming decoder (newdecoder) is deferred (#247), so the decode
// side is exercised through decodestr only.
package hex;
package hex_test;
import bytes;
import errors;

View File

@@ -6,7 +6,7 @@
// store gap (task #6). [[errtag]] collapses each named-void variant to
// a small int so the row body is a single integer compare.
package errors;
package errors_test;
import errors;
import os;

View File

@@ -7,7 +7,7 @@
// here threads a different variadic argument-pack into fprint, and the
// variadic shape can't be table-driven within a single fn body.
package fmt;
package fmt_test;
import fmt;
import io;

View File

@@ -13,7 +13,7 @@
// reports `WEXITSTATUS = 11..N` pointing at the failing scenario.
// Same convention as lib/log/logtest.
package fnmatch;
package fnmatch_test;
import fnmatch;

View File

@@ -19,7 +19,7 @@
// per task #15 — but the nested-if shape was the original workaround
// and is preserved here as a regression marker.
package getopt;
package getopt_test;
import getopt;
import io;

View File

@@ -1,4 +1,4 @@
package adler32;
package adler32_test;
import adler32;

View File

@@ -1,4 +1,4 @@
package crc16;
package crc16_test;
import crc16;

View File

@@ -1,4 +1,4 @@
package crc32;
package crc32_test;
import crc32;

View File

@@ -1,4 +1,4 @@
package crc64;
package crc64_test;
import crc64;

View File

@@ -1,4 +1,4 @@
package siphash;
package siphash_test;
import siphash;

View File

@@ -9,7 +9,7 @@
// killing the test driver — left as a TODO until the project grows
// a subprocess fixture.
package log;
package log_test;
import fmt;
import io;

View File

@@ -1,4 +1,4 @@
package random;
package random_test;
import random;

View File

@@ -7,7 +7,7 @@
// value-return surface (`let st = memio.fixed(buf); &st.vt` into the
// io dispatchers; io.read/write/close return size/io.error).
package memio;
package memio_test;
import bytes;
import errors;

View File

@@ -23,7 +23,7 @@
// concat (task #17). os alone is sufficient: getenv + exit are the
// only primitives needed.
package os;
package os_test;
import os;
import rt;

View File

@@ -17,7 +17,7 @@
// + 10` tells the harness which row tripped. Same shape as
// ostest / temptest / shlextest.
package os;
package os_test;
import os;

View File

@@ -13,7 +13,7 @@
// the table holds {segment, expected-string} pairs (stack.ha:36-42 is
// the normalization spec these rows encode).
package path;
package path_test;
import path;
import os;

View File

@@ -27,7 +27,7 @@
// not `regex.inst_charset { … }`): the parser rejects a module-qualified
// name in struct-literal position (#29), and the imported type
// is in scope unqualified.
package regex;
package regex_test;
import regex;
import io;
@@ -167,6 +167,8 @@ fn fail() void = { os.exit(signalled + 10); };
regex.finish(&re);
};
// rule-7 divergence: white-box probes of regex internals; mislabeled _test pending task #9 (in-pkg test harness via #5/-T dir-enum, #8 boundary).
// compile("abc") emits the 5-inst literal program: the leading
// unanchored inst_skip (regex.ha:261-263), one inst_lit per rune, the
// epilogue inst_match(false) (ha:475-477). compile()'s

View File

@@ -20,7 +20,7 @@
// reports `WEXITSTATUS = 11..N` pointing at the failing scenario.
// Same convention as fnmatchtest / logtest.
package shlex;
package shlex_test;
import shlex;
import io;

View File

@@ -1,212 +0,0 @@
// decimaltest — exercises lib/strconv/decimal.ww (Hare decimal.ha port).
// Run with `out/bin/ww run lib/strconv/test/decimaltest.ww`. Same
// signalled-then-fail()-with-+10 pattern as bytestest / hex / utf8.
// Non-zero exit pinpoints the failing scenario.
//
// Hare has no decimal_test.ha (decimal is exercised transitively via
// ftos_test.ha). ww-authored probes per
// feedback_test_match_hare_source ("ww-authored where Hare doesn't
// ship direct tests"). Coverage per Drew design pre-flight:
// trim (RHS-zeros), decimal_shift (k=0/k>0/k<0/|k|>maxshift),
// leftshift (small/edge), rightshift (small/break-out), round (at
// various dp), decimal_round (small + dp>18 + dp<0).
//
// Lives in lib/strconv/test/ (not lib/strconv/) so `import strconv`
// resolves to the lib/strconv DIRECTORY rather than shadowing on
// the strconv.ww FILE — pulls in decimal.ww + stof_data.ww +
// strconv.ww as the unified `package strconv` compilation.
package strconv;
import strconv;
import os;
let signalled: i32 = 0;
fn fail() void = { os.exit(signalled + 10); };
// Seeds `d` with `vals` as the leading digits + `dp` as the decimal
// point, leaving negative/truncated false. Each test starts from a
// known state.
fn seed(d: *decimal, vals: []u8, dp: i32) void = {
let SZ_ONE: size = (1u64: size);
let i: size = (0u64: size);
for (i < (vals.len: size)) {
d.digits[i] = vals[i];
i += SZ_ONE;
};
d.nd = (vals.len: size);
d.dp = dp;
};
// ---- trim -------------------------------------------------------------
// ref/hare/strconv/decimal.ha:29.
@test fn trim_cases() void = {
let d: decimal;
let vals: [5]u8;
vals[0] = 1u8; vals[1] = 2u8; vals[2] = 3u8; vals[3] = 0u8; vals[4] = 0u8;
seed(&d, vals[0:5], 3);
trim(&d);
if (d.nd != (3u64: size)) { fail(); };
if (d.dp != 3) { fail(); };
// all-zero case: nd shrinks to 0.
let zeros: [3]u8;
seed(&d, zeros[0:3], 2);
trim(&d);
if (d.nd != (0u64: size)) { fail(); };
};
// ---- leftshift / leftshift_newdigits ---------------------------------
// ref/hare/strconv/decimal.ha:35,57.
@test fn leftshift_small_cases() void = {
// Shift "5" by 1 → "10" → trim collapses to nd=1 with dp+=1 (Hare
// trims trailing zero of the high-shifted byte).
let d: decimal;
d.digits[0] = 5u8;
d.nd = (1u64: size);
d.dp = 1;
leftshift(&d, 1u32);
if (d.dp != 2) { fail(); };
if (d.digits[0] != 1u8) { fail(); };
// post-trim nd is 1 (trailing 0 stripped).
if (d.nd != (1u64: size)) { fail(); };
// Shift "123" by 1 → "246" (no trim — no trailing zero).
let v3: [3]u8;
v3[0] = 1u8; v3[1] = 2u8; v3[2] = 3u8;
seed(&d, v3[0:3], 3);
leftshift(&d, 1u32);
if (d.nd != (3u64: size)) { fail(); };
if (d.dp != 3) { fail(); };
if (d.digits[0] != 2u8) { fail(); };
if (d.digits[1] != 4u8) { fail(); };
if (d.digits[2] != 6u8) { fail(); };
// nd == 0 no-op (early-return arm of leftshift).
let z: decimal;
leftshift(&z, 1u32);
if (z.nd != (0u64: size)) { fail(); };
};
// ---- rightshift -----------------------------------------------------
// ref/hare/strconv/decimal.ha:93.
@test fn rightshift_small_cases() void = {
// Shift "10" (dp=2) right by 1 → "5" (dp=1).
let d: decimal;
let vals: [2]u8;
vals[0] = 1u8; vals[1] = 0u8;
seed(&d, vals[0:2], 2);
rightshift(&d, 1u32);
if (d.nd != (1u64: size)) { fail(); };
if (d.dp != 1) { fail(); };
if (d.digits[0] != 5u8) { fail(); };
};
// ---- decimal_shift --------------------------------------------------
// ref/hare/strconv/decimal.ha:138.
@test fn decimal_shift_cases() void = {
// k=0 no-op.
let d: decimal;
let v3: [3]u8; v3[0] = 1u8; v3[1] = 2u8; v3[2] = 3u8;
seed(&d, v3[0:3], 3);
decimal_shift(&d, 0);
if (d.nd != (3u64: size)) { fail(); };
if (d.dp != 3) { fail(); };
if (d.digits[0] != 1u8) { fail(); };
// k=2 small positive: 123 << 2 = 492 → digits 4,9,2; dp=3.
seed(&d, v3[0:3], 3);
decimal_shift(&d, 2);
if (d.dp != 3) { fail(); };
if (d.digits[0] != 4u8) { fail(); };
if (d.digits[1] != 9u8) { fail(); };
if (d.digits[2] != 2u8) { fail(); };
// k>maxshift triggers the break-up loop. Exact digits are checked
// transitively by stof in fold-4; verify dp grew.
let v: [3]u8; v[0] = 1u8; v[1] = 0u8; v[2] = 0u8;
seed(&d, v[0:3], 3);
decimal_shift(&d, 70);
if (d.dp <= 3) { fail(); };
};
// ---- should_round_up + round + decimal_round ------------------------
// ref/hare/strconv/decimal.ha:155,162,188.
@test fn round_cases() void = {
// rounddown — "1234" rounded to 2 digits → "12".
let d: decimal;
let v: [4]u8; v[0] = 1u8; v[1] = 2u8; v[2] = 3u8; v[3] = 4u8;
seed(&d, v[0:4], 4);
round(&d, (2u32: uint));
if (d.nd != (2u64: size)) { fail(); };
if (d.digits[0] != 1u8) { fail(); };
if (d.digits[1] != 2u8) { fail(); };
// roundup — "1259" rounded to 2 digits → "13" (digit[2]==5 →
// should_round_up, digit[1]=2 → +1 → digit[1]=3).
let r: [4]u8; r[0] = 1u8; r[1] = 2u8; r[2] = 5u8; r[3] = 9u8;
seed(&d, r[0:4], 4);
round(&d, (2u32: uint));
if (d.nd != (2u64: size)) { fail(); };
if (d.digits[0] != 1u8) { fail(); };
if (d.digits[1] != 3u8) { fail(); };
// roundup with all-9s carry — "999" rounded to 2 digits → "1"
// with dp incremented.
let nines: [3]u8; nines[0] = 9u8; nines[1] = 9u8; nines[2] = 9u8;
seed(&d, nines[0:3], 3);
round(&d, (2u32: uint));
if (d.digits[0] != 1u8) { fail(); };
if (d.nd != (1u64: size)) { fail(); };
if (d.dp != 4) { fail(); };
};
@test fn decimal_round_cases() void = {
// dp<0 → 0.
let d: decimal;
let v: [3]u8; v[0] = 1u8; v[1] = 2u8; v[2] = 3u8;
seed(&d, v[0:3], -1);
if (decimal_round(&d) != 0u64) { fail(); };
// nd==0 → 0.
let z: decimal;
z.dp = 5;
if (decimal_round(&z) != 0u64) { fail(); };
// dp>18 → ~0u64 (all-bits-set).
let big: decimal;
let one: [1]u8; one[0] = 1u8;
seed(&big, one[0:1], 19);
let zero_u: u64 = 0u64;
if (decimal_round(&big) != ~zero_u) { fail(); };
// "123" with dp=3 → 123.
seed(&d, v[0:3], 3);
if (decimal_round(&d) != 123u64) { fail(); };
// "12" with dp=4 → 1200 (multiply by 10 for each missing digit).
let two: [2]u8; two[0] = 1u8; two[1] = 2u8;
seed(&d, two[0:2], 4);
if (decimal_round(&d) != 1200u64) { fail(); };
// "126" with dp=2 → 13 (rounded up via should_round_up at dp=2:
// digit[2]==6 >= 5).
let r: [3]u8; r[0] = 1u8; r[1] = 2u8; r[2] = 6u8;
seed(&d, r[0:3], 2);
if (decimal_round(&d) != 13u64) { fail(); };
};
export fn main() i32 = {
signalled = 1; trim_cases();
signalled = 2; leftshift_small_cases();
signalled = 3; rightshift_small_cases();
signalled = 4; decimal_shift_cases();
signalled = 5; round_cases();
signalled = 6; decimal_round_cases();
return 0;
};

View File

@@ -20,7 +20,7 @@
// DIRECTORY (full package), not the strconv.ww FILE — same rationale as
// stoftest/decimaltest.
package strconv;
package strconv_test;
import strconv;
import os;
@@ -43,6 +43,17 @@ fn chk(n: f64, want: str) bool = {
return streq(f64tos(n), want);
};
// rt64 — bit-exact round-trip: render then parse back must reproduce the
// exact bits. The parse-back re-runs strconv's decimal slow path.
fn rt64(x: f64) bool = {
match (stof64(f64tos(x), base.DEC)) {
case let v: f64 => { return math.f64bits(v) == math.f64bits(x); };
case let e: invalid => { return false; };
case let e: overflow => { return false; };
};
return false;
};
// ftos_test.ha:57-64 (G/void/NONE-equivalent) — fixed-point renders.
@test fn f64tos_fixed() void = {
if (!chk(13.37, "13.37")) { fail(); };
@@ -151,6 +162,21 @@ fn chkf32(n: f32, want: str) bool = {
if (!chkf32(nan, "nan")) { fail(); };
};
// ftos_test.ha:196-204 (tcsf64) — Hare's f64-exclusive extremes, here as a
// bit-exact ROUND-TRIP (f64bits(stof64(f64tos(x)))==f64bits(x)): the parse-
// back re-runs strconv's decimal engine end-to-end, preserving the coverage
// the retired white-box decimaltest.ww gave directly (#16). Extremes built
// via f64frombits (ww math has no F64_MIN_*/MAX_NORMAL const); exact and
// 17-digit-halfway values as literals.
@test fn f64_roundtrip() void = {
if (!rt64(9007199254740991.0)) { fail(); }; // 2^53-1
if (!rt64(90071992547409915.0)) { fail(); }; // 17-digit halfway pair
if (!rt64(90071992547409925.0)) { fail(); };
if (!rt64(math.f64frombits(0x0000000000000001u64))) { fail(); }; // F64_MIN_SUBNORMAL (5e-324)
if (!rt64(math.f64frombits(0x0010000000000000u64))) { fail(); }; // F64_MIN_NORMAL
if (!rt64(math.f64frombits(0x7FEFFFFFFFFFFFFFu64))) { fail(); }; // F64_MAX_NORMAL
};
export fn main() i32 = {
signalled = 1; f64tos_fixed();
signalled = 2; f64tos_scientific();
@@ -159,6 +185,7 @@ export fn main() i32 = {
signalled = 5; f32tos_scientific();
signalled = 6; f32tos_extremes();
signalled = 7; f32tos_special();
signalled = 8; f64_roundtrip();
os.exit(0);
return 0;
};

View File

@@ -19,7 +19,7 @@
// literal form for the expectation side); the original Hare radix form
// is noted inline.
package strconv;
package strconv_test;
import strconv;
import os;

View File

@@ -15,7 +15,7 @@
// DIRECTORY (full package: strconv.ww + decimal.ww + stof_data.ww +
// stof.ww), not the strconv.ww FILE — same rationale as decimaltest.
package strconv;
package strconv_test;
import strconv;
import os;
@@ -123,6 +123,18 @@ fn nan32(s: str) bool = {
if (!chk64("-1e-324", base.DEC, nzero)) { fail(); };
if (!chk64("5e-324", base.DEC, subn)) { fail(); };
// Decimal-engine edge probes migrated here when the white-box
// decimaltest.ww retired (#16): the external-test idiom can't reach
// strconv's unexported decimal fns, so these two black-box rows pin
// the only edges not already guaranteed transitively. C1: all-9s
// round-up carry + decimal_round dp>18 boundary. C2: nd>19 skips
// eisel-lemire, forcing the pure-decimal slow path (extra trim).
// Micro-gap (rule-7, honest): decimal_shift's k=0 early-return no-op
// is a trivial guard, not reached transitively by any slow-path input
// — consciously un-migrated, not silently dropped.
if (!chk64("9999999999999999", base.DEC, 1.0e16)) { fail(); };
if (!chk64("100000000000000000001", base.DEC, 1.0e20)) { fail(); };
if (inv64("") != 0) { fail(); };
if (inv64("0ZO") != 1) { fail(); };
if (inv64("1.23ezz") != 5) { fail(); };

View File

@@ -6,7 +6,11 @@
// Vectors mirror ref/hare/strings/{dup,concat,trim,contains,index,
// suffix,compare}.ha where ww can express them.
package strings;
// `_test` suffix: Go external-test-package idiom (sanctioned Go-over-Hare
// departure for lib/ tests) — self-import is hard-rejected, so the test
// lives in package strings_test and pulls the real package via import.
// See CLAUDE.md rule-5/9 carve-out; task #16.
package strings_test;
import strings;
import encoding.utf8;

View File

@@ -13,7 +13,7 @@
// leave detritus under /tmp. `ls /tmp` before/after each run should
// match.
package temp;
package temp_test;
import os;
import temp;

View File

@@ -3,7 +3,7 @@
// pattern as fmttest / logtest / stattest so a non-zero exit
// pinpoints the offending scenario.
package time;
package time_test;
import os;
import time;

View File

@@ -1,57 +0,0 @@
/*
* 922_decimal_run — execute the lib/strconv/test/decimaltest fixture
* under the C-side `ww run` driver and assert exit 0.
*
* Same thin-wrapper shape as 967_bytes_run / 968_utf8_run / 979_hex_run:
* decimaltest.ww carries its own `export fn main()` that drives the
* @test fns and signals which case failed via the exit code (signalled
* + 10, so cases 1..6 → exit 11..16).
*
* The test fixture lives in lib/strconv/test/ (not lib/strconv/) so
* `import strconv` resolves to the lib/strconv DIRECTORY rather than
* shadowing on the strconv.ww FILE — same-dir resolution would pull
* in only strconv.ww and miss decimal.ww + stof_data.ww. From the
* test/ subdir, the search-path lookup falls through srcd and reaches
* the libdir's directory hit, expanding the full strconv package.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return 1;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
const char *src = "lib/strconv/test/decimaltest.ww";
char path[1024], cmd[2048];
snprintf(path, sizeof path, "%s/%s", cwd, src);
snprintf(cmd, sizeof cmd, "%s/ww run %s", bin, path);
int rc = runwait(cmd);
if (rc != 0) {
fprintf(stderr, "decimal_run FAIL: %s exited %d\n", src, rc);
return 1;
}
printf("decimal_run: %s ok\n", src);
return 0;
}

View File

@@ -85,7 +85,6 @@ static const struct ent ents[] = {
{ .fixture = "lib/memio/memiotest.ww", .mode = M_ID },
{ .fixture = "lib/os/ostest.ww", .mode = M_ID },
{ .fixture = "lib/regex/regex_test.ww", .mode = M_ID },
{ .fixture = "lib/strconv/test/decimaltest.ww", .mode = M_ID },
{ .fixture = "lib/strconv/test/ftostest.ww", .mode = M_ID },
/* graduated from #59.10 DIVERGE by the #62 float-literal fold fix
* (wwstage lexer now folds through strconv.stof64, matching