lib/io tests: hand-main plumbing -> assert (@test conversion B5)

This commit is contained in:
2026-06-10 18:52:53 +09:00
parent 612e6d149c
commit e8096e68e1
5 changed files with 492 additions and 531 deletions

View File

@@ -14,20 +14,6 @@ import encoding.utf8;
import io;
import memio;
// Direct exit(2) binding rather than `use os;` — os exports
// read/write/close, which collide with io.read/write/close under
// the driver's flat-scope concat.
@symbol("rt_syscall") fn syscall1ww(num: i64, a: i64) i64;
fn doexit(code: i32) void = {
syscall1ww(60i64, code: i64);
};
// signalled — bumped by main before each test so a failing exit code
// pinpoints the offending case.
let signalled: i32 = 0;
fn fail() void = { doexit(signalled + 10); };
// putstr — copy the bytes of `s` into `into` starting at `off`,
// returning the new offset.
fn putstr(s: str, into: []u8, off: i32) i32 = {
@@ -83,11 +69,11 @@ fn errsource() io.stream = {
let r: (u8 | io.eof | io.error) = bufio.scanbyte(&sc);
match (r) {
case let b: u8 => {
if (weof[i] != 0) { fail(); };
if (b != want[i]) { fail(); };
assert(!(weof[i] != 0));
assert(!(b != want[i]));
};
case io.eof => { if (weof[i] == 0) { fail(); }; };
case let e: io.error => fail();
case io.eof => { assert(!(weof[i] == 0)); };
case let e: io.error => abort();
};
i += 1;
};
@@ -122,14 +108,14 @@ fn errsource() io.stream = {
let r: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc);
match (r) {
case let v: str => {
if (weof[i] != 0) { fail(); };
if (wovr[i] != 0) { fail(); };
if (v.len != wl[i]) { fail(); };
if (v.len > 0 && v[0] != wf[i]) { fail(); };
assert(!(weof[i] != 0));
assert(!(wovr[i] != 0));
assert(!(v.len != wl[i]));
assert(!(v.len > 0 && v[0] != wf[i]));
};
case io.eof => { if (weof[i] == 0) { fail(); }; };
case let e: io.error => fail();
case bufio.overflow => { if (wovr[i] == 0) { fail(); }; };
case io.eof => { assert(!(weof[i] == 0)); };
case let e: io.error => abort();
case bufio.overflow => { assert(!(wovr[i] == 0)); };
};
i += 1;
};
@@ -152,9 +138,9 @@ fn errsource() io.stream = {
let r: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc);
match (r) {
case let v: str => fail();
case io.eof => fail();
case let e: io.error => fail();
case let v: str => abort();
case io.eof => abort();
case let e: io.error => abort();
case bufio.overflow => { };
};
@@ -188,13 +174,13 @@ fn errsource() io.stream = {
let r: ([]u8 | io.eof | io.error | bufio.overflow) = bufio.scanbytes(&sc, 44u8); // ','
match (r) {
case let v: []u8 => {
if (weof[i] != 0) { fail(); };
if (v.len != wl[i]) { fail(); };
if (v.len > 0 && v[0] != wf[i]) { fail(); };
assert(!(weof[i] != 0));
assert(!(v.len != wl[i]));
assert(!(v.len > 0 && v[0] != wf[i]));
};
case io.eof => { if (weof[i] == 0) { fail(); }; };
case let e: io.error => fail();
case bufio.overflow => fail();
case io.eof => { assert(!(weof[i] == 0)); };
case let e: io.error => abort();
case bufio.overflow => abort();
};
i += 1;
};
@@ -213,25 +199,25 @@ fn errsource() io.stream = {
let r1: (u8 | io.eof | io.error) = bufio.scanbyte(&sc);
match (r1) {
case let b: u8 => fail();
case let b: u8 => abort();
case io.eof => { };
case let e: io.error => fail();
case let e: io.error => abort();
};
let r2: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc);
match (r2) {
case let v: str => fail();
case let v: str => abort();
case io.eof => { };
case let e: io.error => fail();
case bufio.overflow => fail();
case let e: io.error => abort();
case bufio.overflow => abort();
};
let r3: ([]u8 | io.eof | io.error | bufio.overflow) = bufio.scanbytes(&sc, 10u8);
match (r3) {
case let v: []u8 => fail();
case let v: []u8 => abort();
case io.eof => { };
case let e: io.error => fail();
case bufio.overflow => fail();
case let e: io.error => abort();
case bufio.overflow => abort();
};
bufio.finish(&sc);
@@ -246,25 +232,25 @@ fn errsource() io.stream = {
let r1: (u8 | io.eof | io.error) = bufio.scanbyte(&sc);
match (r1) {
case let b: u8 => fail();
case io.eof => fail();
case let b: u8 => abort();
case io.eof => abort();
case let e: io.error => { };
};
let r2: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc);
match (r2) {
case let v: str => fail();
case io.eof => fail();
case let v: str => abort();
case io.eof => abort();
case let e: io.error => { };
case bufio.overflow => fail();
case bufio.overflow => abort();
};
let r3: ([]u8 | io.eof | io.error | bufio.overflow) = bufio.scanbytes(&sc, 32u8);
match (r3) {
case let v: []u8 => fail();
case io.eof => fail();
case let v: []u8 => abort();
case io.eof => abort();
case let e: io.error => { };
case bufio.overflow => fail();
case bufio.overflow => abort();
};
bufio.finish(&sc);
@@ -283,20 +269,20 @@ fn errsource() io.stream = {
let r1: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc1);
match (r1) {
case let v: str => { if (v.len != 0) { fail(); }; };
case io.eof => fail();
case let e: io.error => fail();
case bufio.overflow => fail();
case let v: str => { assert(!(v.len != 0)); };
case io.eof => abort();
case let e: io.error => abort();
case bufio.overflow => abort();
};
let r2: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc1);
match (r2) {
case let v: str => {
if (v.len != 3) { fail(); };
if (v[0] != 102u8) { fail(); }; // 'f'
assert(!(v.len != 3));
assert(!(v[0] != 102u8)); // 'f'
};
case io.eof => fail();
case let e: io.error => fail();
case bufio.overflow => fail();
case io.eof => abort();
case let e: io.error => abort();
case bufio.overflow => abort();
};
bufio.finish(&sc1);
@@ -310,17 +296,17 @@ fn errsource() io.stream = {
let t1: ([]u8 | io.eof | io.error | bufio.overflow) = bufio.scanbytes(&sc2, 44u8);
match (t1) {
case let v: []u8 => fail();
case let v: []u8 => abort();
case io.eof => { };
case let e: io.error => fail();
case bufio.overflow => fail();
case let e: io.error => abort();
case bufio.overflow => abort();
};
let t2: ([]u8 | io.eof | io.error | bufio.overflow) = bufio.scanbytes(&sc2, 44u8);
match (t2) {
case let v: []u8 => fail();
case let v: []u8 => abort();
case io.eof => { };
case let e: io.error => fail();
case bufio.overflow => fail();
case let e: io.error => abort();
case bufio.overflow => abort();
};
bufio.finish(&sc2);
};
@@ -349,13 +335,13 @@ fn errsource() io.stream = {
let r: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc);
match (r) {
case let v: str => {
if (weof[i] != 0) { fail(); };
if (v.len != wl[i]) { fail(); };
if (v.len > 0 && v[0] != wf[i]) { fail(); };
assert(!(weof[i] != 0));
assert(!(v.len != wl[i]));
assert(!(v.len > 0 && v[0] != wf[i]));
};
case io.eof => { if (weof[i] == 0) { fail(); }; };
case let e: io.error => fail();
case bufio.overflow => fail();
case io.eof => { assert(!(weof[i] == 0)); };
case let e: io.error => abort();
case bufio.overflow => abort();
};
i += 1;
};
@@ -380,19 +366,19 @@ fn errsource() io.stream = {
let p: io.stream = &b.vt;
let r: (size | io.error) = io.write(p, buf[0:5]);
match (r) {
case let n: size => { if (n: i32 != 5) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); };
case let e: io.error => abort();
};
if (mem.pos != 0) { fail(); };
assert(!(mem.pos != 0));
let fr: (void | io.error) = bufio.flush(&b);
match (fr) {
case void => { };
case let e: io.error => fail();
case let e: io.error => abort();
};
if (mem.pos != 5) { fail(); };
if (raw[0] != 104u8) { fail(); };
if (raw[4] != 111u8) { fail(); };
assert(!(mem.pos != 5));
assert(!(raw[0] != 104u8));
assert(!(raw[4] != 111u8));
};
// ---- write larger than wbuf → auto-flush -----------------------------
@@ -412,20 +398,20 @@ fn errsource() io.stream = {
let p: io.stream = &b.vt;
let r: (size | io.error) = io.write(p, buf[0:10]);
match (r) {
case let n: size => { if (n: i32 != 10) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != 10)); };
case let e: io.error => abort();
};
// Two full flushes happened (8B); 2B still pending.
if (mem.pos != 8) { fail(); };
assert(!(mem.pos != 8));
let fr: (void | io.error) = bufio.flush(&b);
match (fr) {
case void => { };
case let e: io.error => fail();
case let e: io.error => abort();
};
if (mem.pos != 10) { fail(); };
if (raw[0] != 97u8) { fail(); }; // 'a'
if (raw[9] != 106u8) { fail(); }; // 'j'
assert(!(mem.pos != 10));
assert(!(raw[0] != 97u8)); // 'a'
assert(!(raw[9] != 106u8)); // 'j'
};
// ---- default flush byte-set: '\n' in payload triggers flush ---------
@@ -446,22 +432,22 @@ fn errsource() io.stream = {
let zh: i32 = putstr("hello", h[0:5], 0);
let r1: (size | io.error) = io.write(p, h[0:5]);
match (r1) {
case let n: size => { if (n: i32 != 5) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); };
case let e: io.error => abort();
};
if (mem.pos != 0) { fail(); };
assert(!(mem.pos != 0));
// Second write: '\n' present, triggers flush of everything (6B).
let nl: [1]u8;
nl[0] = 10u8;
let r2: (size | io.error) = io.write(p, nl[0:1]);
match (r2) {
case let n: size => { if (n: i32 != 1) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != 1)); };
case let e: io.error => abort();
};
if (mem.pos != 6) { fail(); };
if (raw[0] != 104u8) { fail(); };
if (raw[5] != 10u8) { fail(); };
assert(!(mem.pos != 6));
assert(!(raw[0] != 104u8));
assert(!(raw[5] != 10u8));
};
// ---- explicit-flush-per-write: caller drives the drain ---------------
@@ -482,29 +468,29 @@ fn errsource() io.stream = {
h[0] = 65u8; h[1] = 66u8; // "AB"
let r1: (size | io.error) = io.write(p, h[0:2]);
match (r1) {
case let n: size => { if (n: i32 != 2) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != 2)); };
case let e: io.error => abort();
};
let f1: (void | io.error) = bufio.flush(&b);
match (f1) {
case void => { };
case let e: io.error => fail();
case let e: io.error => abort();
};
if (mem.pos != 2) { fail(); };
if (raw[0] != 65u8) { fail(); };
assert(!(mem.pos != 2));
assert(!(raw[0] != 65u8));
let r2: (size | io.error) = io.write(p, h[0:1]);
match (r2) {
case let n: size => { if (n: i32 != 1) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != 1)); };
case let e: io.error => abort();
};
let f2: (void | io.error) = bufio.flush(&b);
match (f2) {
case void => { };
case let e: io.error => fail();
case let e: io.error => abort();
};
if (mem.pos != 3) { fail(); };
if (raw[2] != 65u8) { fail(); };
assert(!(mem.pos != 3));
assert(!(raw[2] != 65u8));
};
// ---- isbuffered: stream → true, plain memio → false -----------------
@@ -518,8 +504,8 @@ fn errsource() io.stream = {
let wb: [4]u8;
let b: bufio.stream = bufio.init(m, rb[0:4], wb[0:4]);
if (!bufio.isbuffered(&b.vt)) { fail(); };
if (bufio.isbuffered(m)) { fail(); };
assert(!(!bufio.isbuffered(&b.vt)));
assert(!(bufio.isbuffered(m)));
};
// ---- bread + unread: pushed-back bytes come out first ----------------
@@ -541,12 +527,12 @@ fn errsource() io.stream = {
let out: [4]u8;
let r1: (size | io.eof | io.error) = io.read(p, out[0:3]);
match (r1) {
case let z: size => { if (z: i32 != 3) { fail(); }; };
case io.eof => fail();
case let e: io.error => fail();
case let z: size => { assert(!(z: i32 != 3)); };
case io.eof => abort();
case let e: io.error => abort();
};
if (out[0] != 65u8) { fail(); }; // 'A'
if (out[2] != 67u8) { fail(); }; // 'C'
assert(!(out[0] != 65u8)); // 'A'
assert(!(out[2] != 67u8)); // 'C'
// Push back 2 bytes; next read returns them first.
let push: [2]u8;
@@ -555,22 +541,22 @@ fn errsource() io.stream = {
let r2: (size | io.eof | io.error) = io.read(p, out[0:2]);
match (r2) {
case let z: size => { if (z: i32 != 2) { fail(); }; };
case io.eof => fail();
case let e: io.error => fail();
case let z: size => { assert(!(z: i32 != 2)); };
case io.eof => abort();
case let e: io.error => abort();
};
if (out[0] != 88u8) { fail(); }; // 'X'
if (out[1] != 89u8) { fail(); }; // 'Y'
assert(!(out[0] != 88u8)); // 'X'
assert(!(out[1] != 89u8)); // 'Y'
// Subsequent read returns the original tail.
let r3: (size | io.eof | io.error) = io.read(p, out[0:4]);
match (r3) {
case let z: size => { if (z: i32 != 4) { fail(); }; };
case io.eof => fail();
case let e: io.error => fail();
case let z: size => { assert(!(z: i32 != 4)); };
case io.eof => abort();
case let e: io.error => abort();
};
if (out[0] != 68u8) { fail(); }; // 'D'
if (out[3] != 71u8) { fail(); }; // 'G'
assert(!(out[0] != 68u8)); // 'D'
assert(!(out[3] != 71u8)); // 'G'
};
// ---- scanner over a stream-wrapped src: pre-read unread + scanline --
@@ -597,13 +583,13 @@ fn errsource() io.stream = {
let lr: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc);
match (lr) {
case let v: str => {
if (v.len != 8) { fail(); }; // "XYZhello"
if (v[0] != 88u8) { fail(); }; // 'X'
if (v[7] != 111u8) { fail(); }; // 'o'
assert(!(v.len != 8)); // "XYZhello"
assert(!(v[0] != 88u8)); // 'X'
assert(!(v[7] != 111u8)); // 'o'
};
case io.eof => fail();
case let e: io.error => fail();
case bufio.overflow => fail();
case io.eof => abort();
case let e: io.error => abort();
case bufio.overflow => abort();
};
bufio.finish(&sc);
};
@@ -622,9 +608,9 @@ fn errsource() io.stream = {
let r: (void | io.error) = bufio.flush(&b);
match (r) {
case void => { };
case let e: io.error => fail();
case let e: io.error => abort();
};
if (mem.pos != 0) { fail(); };
assert(!(mem.pos != 0));
};
// ---- bclose drains pending wbuf then forwards close to src ----------
@@ -645,19 +631,19 @@ fn errsource() io.stream = {
h[0] = 80u8; h[1] = 81u8; // "PQ"
let r: (size | io.error) = io.write(p, h[0:2]);
match (r) {
case let n: size => { if (n: i32 != 2) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != 2)); };
case let e: io.error => abort();
};
if (mem.pos != 0) { fail(); }; // still buffered
assert(!(mem.pos != 0)); // still buffered
let cr: (void | io.error) = io.close(p);
match (cr) {
case void => { };
case let e: io.error => fail();
case let e: io.error => abort();
};
if (mem.pos != 2) { fail(); };
if (raw[0] != 80u8) { fail(); };
if (raw[1] != 81u8) { fail(); };
assert(!(mem.pos != 2));
assert(!(raw[0] != 80u8));
assert(!(raw[1] != 81u8));
};
// ---- setflush with a custom non-empty byte-set -----------------------
@@ -679,13 +665,13 @@ fn errsource() io.stream = {
let z: i32 = putstr("ab cd", buf[0:5], 0);
let r: (size | io.error) = io.write(p, buf[0:5]);
match (r) {
case let n: size => { if (n: i32 != 5) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); };
case let e: io.error => abort();
};
// Space at index 2 triggers post-copy flush of all 5 bytes.
if (mem.pos != 5) { fail(); };
if (raw[2] != 32u8) { fail(); };
if (raw[4] != 100u8) { fail(); }; // 'd'
assert(!(mem.pos != 5));
assert(!(raw[2] != 32u8));
assert(!(raw[4] != 100u8)); // 'd'
};
// ---- scanrune: ASCII + 2/3/4-byte UTF-8 + idempotent EOF --------------
@@ -720,12 +706,12 @@ fn errsource() io.stream = {
let r: (rune | io.eof | io.error | utf8.invalid) = bufio.scanrune(&sc);
match (r) {
case let rn: rune => {
if (weof[i] != 0) { fail(); };
if (rn: u32 != want[i]) { fail(); };
assert(!(weof[i] != 0));
assert(!(rn: u32 != want[i]));
};
case io.eof => { if (weof[i] == 0) { fail(); }; };
case let e: io.error => fail();
case utf8.invalid => fail();
case io.eof => { assert(!(weof[i] == 0)); };
case let e: io.error => abort();
case utf8.invalid => abort();
};
i += 1;
};
@@ -745,9 +731,9 @@ fn errsource() io.stream = {
let sc1: bufio.scanner = bufio.newscannerbuf(m1, b1[0:8]);
let r1: (rune | io.eof | io.error | utf8.invalid) = bufio.scanrune(&sc1);
match (r1) {
case let rn: rune => fail();
case io.eof => fail();
case let e: io.error => fail();
case let rn: rune => abort();
case io.eof => abort();
case let e: io.error => abort();
case utf8.invalid => { };
};
bufio.finish(&sc1);
@@ -762,9 +748,9 @@ fn errsource() io.stream = {
let sc2: bufio.scanner = bufio.newscannerbuf(m2, b2[0:8]);
let r2: (rune | io.eof | io.error | utf8.invalid) = bufio.scanrune(&sc2);
match (r2) {
case let rn: rune => fail();
case io.eof => fail();
case let e: io.error => fail();
case let rn: rune => abort();
case io.eof => abort();
case let e: io.error => abort();
case utf8.invalid => { };
};
bufio.finish(&sc2);
@@ -779,9 +765,9 @@ fn errsource() io.stream = {
let sc3: bufio.scanner = bufio.newscannerbuf(m3, b3[0:8]);
let r3: (rune | io.eof | io.error | utf8.invalid) = bufio.scanrune(&sc3);
match (r3) {
case let rn: rune => fail();
case io.eof => fail();
case let e: io.error => fail();
case let rn: rune => abort();
case io.eof => abort();
case let e: io.error => abort();
case utf8.invalid => { };
};
bufio.finish(&sc3);
@@ -811,13 +797,13 @@ fn errsource() io.stream = {
let r: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc);
match (r) {
case let v: str => {
if (weof[i] != 0) { fail(); };
if (v.len != wl[i]) { fail(); };
if (v.len > 0 && v[0] != wf[i]) { fail(); };
assert(!(weof[i] != 0));
assert(!(v.len != wl[i]));
assert(!(v.len > 0 && v[0] != wf[i]));
};
case io.eof => { if (weof[i] == 0) { fail(); }; };
case let e: io.error => fail();
case bufio.overflow => fail();
case io.eof => { assert(!(weof[i] == 0)); };
case let e: io.error => abort();
case bufio.overflow => abort();
};
i += 1;
};
@@ -842,12 +828,12 @@ fn errsource() io.stream = {
let r: (rune | io.eof | io.error | utf8.invalid) = bufio.scanrune(&sc2);
match (r) {
case let rn: rune => {
if (weof2[i] != 0) { fail(); };
if (rn: u32 != want[i]) { fail(); };
assert(!(weof2[i] != 0));
assert(!(rn: u32 != want[i]));
};
case io.eof => { if (weof2[i] == 0) { fail(); }; };
case let e: io.error => fail();
case utf8.invalid => fail();
case io.eof => { assert(!(weof2[i] == 0)); };
case let e: io.error => abort();
case utf8.invalid => abort();
};
i += 1;
};
@@ -866,36 +852,36 @@ fn errsource() io.stream = {
let r: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc);
match (r) {
case let v: str => fail();
case io.eof => fail();
case let e: io.error => fail();
case let v: str => abort();
case io.eof => abort();
case let e: io.error => abort();
case bufio.overflow => { };
};
bufio.finish(&sc);
};
export fn main() i32 = {
signalled = 1; scanbytecases();
signalled = 2; scanlinecases();
signalled = 3; scanlineoverflow();
signalled = 4; scanbytescases();
signalled = 5; emptystream();
signalled = 6; errorsource();
signalled = 7; boundarycases();
signalled = 8; multifill();
signalled = 9; streamsmallwrite();
signalled = 10; streamautoflush();
signalled = 11; streamlineflush();
signalled = 12; streamflushonwrite();
signalled = 13; streamisbuffered();
signalled = 14; streamunread();
signalled = 15; streamscannerunread();
signalled = 16; streamflushempty();
signalled = 17; streamcloseflushes();
signalled = 18; streamsetflushcustom();
signalled = 19; scanrunecases();
signalled = 20; scanruneinvalid();
signalled = 21; newscannergrow();
signalled = 22; newscanneroverflow();
scanbytecases();
scanlinecases();
scanlineoverflow();
scanbytescases();
emptystream();
errorsource();
boundarycases();
multifill();
streamsmallwrite();
streamautoflush();
streamlineflush();
streamflushonwrite();
streamisbuffered();
streamunread();
streamscannerunread();
streamflushempty();
streamcloseflushes();
streamsetflushcustom();
scanrunecases();
scanruneinvalid();
newscannergrow();
newscanneroverflow();
return 0;
};

View File

@@ -11,11 +11,6 @@ package errors_test;
import errors;
import os;
// signalled — bumped by main before each test so a failing exit code
// pinpoints the offending case.
let signalled: i32 = 0;
fn fail() void = { os.exit(signalled + 10); };
fn streq(a: str, b: str) bool = {
if (a.len != b.len) { return false; };
let i: i32 = 0;
@@ -85,7 +80,7 @@ fn errtag(e: errors.error) int = {
// regardless — it is how errno is actually used (cf
// lib/io/stream.ww:53, and Hare's errors/rt.ha callers).
let er: errors.error = errors.errno(ins[i]);
if (errtag(er) != exp[i]) { fail(); };
assert(!(errtag(er) != exp[i]));
i += 1;
};
};
@@ -94,25 +89,25 @@ fn errtag(e: errors.error) int = {
@test fn opaquetail() void = {
// EIO (5) is outside the mapped set, so it wraps opaque_.
let e: errors.error = errors.errno(5);
if (errtag(e) != 99) { fail(); };
assert(!(errtag(e) != 99));
match (e) {
case let o: errors.opaque_ =>
if (!streq((*o.strerror)(&o.data), "Unknown error")) { fail(); };
assert(!(!streq((*o.strerror)(&o.data), "Unknown error")));
case =>
fail();
abort();
};
};
// ---- os.strerror mapped path --------------------------------------
@test fn strerrortext() void = {
if (!streq(os.strerror(os.ENOENT), "No such file or directory")) { fail(); };
if (!streq(os.strerror(os.EINVAL), "Invalid argument")) { fail(); };
if (!streq(os.strerror(5), "Unknown error")) { fail(); };
assert(!(!streq(os.strerror(os.ENOENT), "No such file or directory")));
assert(!(!streq(os.strerror(os.EINVAL), "Invalid argument")));
assert(!(!streq(os.strerror(5), "Unknown error")));
};
export fn main() i32 = {
signalled = 1; mapping();
signalled = 2; opaquetail();
signalled = 3; strerrortext();
mapping();
opaquetail();
strerrortext();
return 0;
};

View File

@@ -14,12 +14,6 @@ import io;
import memio;
import os;
// signalled — bumped before each scenario so a failing exit code
// pinpoints the offending case.
let signalled: i32 = 0;
fn fail() void = { os.exit(signalled + 10); };
fn streq(a: str, b: str) bool = {
if (a.len != b.len) { return false; };
let i: i32 = 0;
@@ -56,13 +50,13 @@ fn errsource() io.stream = {
let r: (size | io.error) = fmt.fprint(s, "hello");
match (r) {
case let n: size => { if (n: i32 != 5) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "hello")) { fail(); };
assert(!(!streq(memio.string(&mem), "hello")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// ---- fprint: int + str mix, space-separated ----------------------------
@@ -73,13 +67,13 @@ fn errsource() io.stream = {
let r: (size | io.error) = fmt.fprint(s, 42i64, "x");
match (r) {
case let n: size => { if (n: i32 != 4) { fail(); }; }; // "42 x"
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 4)); }; // "42 x"
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "42 x")) { fail(); };
assert(!(!streq(memio.string(&mem), "42 x")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// ---- fprint: bool + rune renders as "true A" --------------------------
@@ -90,13 +84,13 @@ fn errsource() io.stream = {
let r: (size | io.error) = fmt.fprint(s, true, 'A': rune);
match (r) {
case let n: size => { if (n: i32 != 6) { fail(); }; }; // "true A"
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 6)); }; // "true A"
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "true A")) { fail(); };
assert(!(!streq(memio.string(&mem), "true A")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// ---- fprint: zero args returns 0, no bytes written --------------------
@@ -107,13 +101,13 @@ fn errsource() io.stream = {
let r: (size | io.error) = fmt.fprint(s);
match (r) {
case let n: size => { if (n: i32 != 0) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 0)); };
case let eioe: io.error => abort();
};
if (memio.string(&mem).len != 0) { fail(); };
assert(!(memio.string(&mem).len != 0));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// ---- fprintln: multi-arg, trailing '\n' --------------------------------
@@ -124,13 +118,13 @@ fn errsource() io.stream = {
let r: (size | io.error) = fmt.fprintln(s, "a", 1i64, false);
match (r) {
case let n: size => { if (n: i32 != 10) { fail(); }; }; // "a 1 false\n"
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 10)); }; // "a 1 false\n"
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "a 1 false\n")) { fail(); };
assert(!(!streq(memio.string(&mem), "a 1 false\n")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// ---- fprintln: zero args writes just the newline ----------------------
@@ -141,13 +135,13 @@ fn errsource() io.stream = {
let r: (size | io.error) = fmt.fprintln(s);
match (r) {
case let n: size => { if (n: i32 != 1) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 1)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "\n")) { fail(); };
assert(!(!streq(memio.string(&mem), "\n")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// ---- fprint over a fixed stream: short writes return partial count ----
@@ -163,13 +157,13 @@ fn errsource() io.stream = {
let r: (size | io.error) = fmt.fprint(s, "hello");
match (r) {
case let n: size => { if (n: i32 != 3) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 3)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "hel")) { fail(); };
assert(!(!streq(memio.string(&mem), "hel")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// ---- fprint over a closed stream surfaces io.error -------------------
@@ -183,7 +177,7 @@ fn errsource() io.stream = {
let r: (size | io.error) = fmt.fprint(s, "x");
match (r) {
case let n: size => fail();
case let n: size => abort();
case let eioe: io.error => {};
};
};
@@ -198,12 +192,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "hello {} {}", "world", 42i64);
match (r) {
case let n: size => { if (n: i32 != 14) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 14)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "hello world 42")) { fail(); };
assert(!(!streq(memio.string(&mem), "hello world 42")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_indexed() void = {
@@ -211,12 +205,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{1} {0} {1}", "hello", "world");
match (r) {
case let n: size => { if (n: i32 != 17) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 17)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "world hello world")) { fail(); };
assert(!(!streq(memio.string(&mem), "world hello world")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_literal_braces() void = {
@@ -224,12 +218,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{{ {} }}", 1i64);
match (r) {
case let n: size => { if (n: i32 != 5) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "{ 1 }")) { fail(); };
assert(!(!streq(memio.string(&mem), "{ 1 }")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_width_right() void = {
@@ -237,12 +231,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{:5}", 42i64);
match (r) {
case let n: size => { if (n: i32 != 5) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), " 42")) { fail(); };
assert(!(!streq(memio.string(&mem), " 42")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_width_left() void = {
@@ -250,12 +244,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{:-5}", 42i64);
match (r) {
case let n: size => { if (n: i32 != 5) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "42 ")) { fail(); };
assert(!(!streq(memio.string(&mem), "42 ")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_width_center() void = {
@@ -263,12 +257,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{:=5}", "hi");
match (r) {
case let n: size => { if (n: i32 != 5) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), " hi ")) { fail(); };
assert(!(!streq(memio.string(&mem), " hi ")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_pad_underscore() void = {
@@ -276,12 +270,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{:_05}", "hi");
match (r) {
case let n: size => { if (n: i32 != 5) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "000hi")) { fail(); };
assert(!(!streq(memio.string(&mem), "000hi")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_base_hex() void = {
@@ -289,12 +283,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{:x} {:X}", 48879i64, 61453i64);
match (r) {
case let n: size => { if (n: i32 != 9) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 9)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "beef F00D")) { fail(); };
assert(!(!streq(memio.string(&mem), "beef F00D")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_base_oct_bin() void = {
@@ -302,12 +296,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{:o} {:b}", 493i64, 27i64);
match (r) {
case let n: size => { if (n: i32 != 9) { fail(); }; }; // "755 11011"
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 9)); }; // "755 11011"
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "755 11011")) { fail(); };
assert(!(!streq(memio.string(&mem), "755 11011")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_prec_int() void = {
@@ -315,12 +309,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{:.5}", 42i64);
match (r) {
case let n: size => { if (n: i32 != 5) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "00042")) { fail(); };
assert(!(!streq(memio.string(&mem), "00042")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_prec_str_trunc() void = {
@@ -328,12 +322,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{:.3}", "hello");
match (r) {
case let n: size => { if (n: i32 != 3) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 3)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "hel")) { fail(); };
assert(!(!streq(memio.string(&mem), "hel")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_sign_neg() void = {
@@ -341,12 +335,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{} {:+} {: }", -7i64, 7i64, 7i64);
match (r) {
case let n: size => { if (n: i32 != 8) { fail(); }; }; // "-7 +7 7"
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 8)); }; // "-7 +7 7"
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "-7 +7 7")) { fail(); };
assert(!(!streq(memio.string(&mem), "-7 +7 7")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintfln_basic() void = {
@@ -354,19 +348,19 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintfln(s, "x={}", 9i64);
match (r) {
case let n: size => { if (n: i32 != 4) { fail(); }; }; // "x=9\n"
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 4)); }; // "x=9\n"
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "x=9\n")) { fail(); };
assert(!(!streq(memio.string(&mem), "x=9\n")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_closed() void = {
let s: io.stream = errsource();
let r: (size | io.error) = fmt.fprintf(s, "hello {}", 1i64);
match (r) {
case let n: size => fail();
case let n: size => abort();
case let eioe: io.error => {};
};
};
@@ -375,8 +369,8 @@ fn errsource() io.stream = {
let buf: [16]u8;
let r: (str | io.error) = fmt.bsprintf(buf[0:16], "{} {}", "hi", 42i64);
match (r) {
case let s: str => { if (!streq(s, "hi 42")) { fail(); }; };
case let eioe: io.error => fail();
case let s: str => { assert(!(!streq(s, "hi 42"))); };
case let eioe: io.error => abort();
};
};
@@ -390,12 +384,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{} {}", true, 'A': rune);
match (r) {
case let n: size => { if (n: i32 != 6) { fail(); }; }; // "true A"
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 6)); }; // "true A"
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "true A")) { fail(); };
assert(!(!streq(memio.string(&mem), "true A")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// Verifies bsprintf's documented truncation contract — short writes
@@ -406,8 +400,8 @@ fn errsource() io.stream = {
let buf: [3]u8;
let r: (str | io.error) = fmt.bsprintf(buf[0:3], "{} {}", "hi", 42i64);
match (r) {
case let s: str => { if (!streq(s, "hi ")) { fail(); }; };
case let eioe: io.error => fail();
case let s: str => { assert(!(!streq(s, "hi "))); };
case let eioe: io.error => abort();
};
};
@@ -420,8 +414,8 @@ fn errsource() io.stream = {
let buf: [3]u8;
let r: (str | io.error) = fmt.bsprintf(buf[0:3], "{:5}", 42i64);
match (r) {
case let s: str => { if (!streq(s, " ")) { fail(); }; };
case let eioe: io.error => fail();
case let s: str => { assert(!(!streq(s, " "))); };
case let eioe: io.error => abort();
};
};
@@ -430,7 +424,7 @@ fn errsource() io.stream = {
@test fn asprintf_basic() void = {
let r: str = fmt.asprintf("{} {}", "hi", 42i64);
if (!streq(r, "hi 42")) { fail(); };
assert(!(!streq(r, "hi 42")));
os.free(r.ptr: *void, r.len: u64);
};
@@ -438,7 +432,7 @@ fn errsource() io.stream = {
// double-and-copy grow path; 34B target traverses 8→16→32→64.
@test fn asprintf_growth() void = {
let r: str = fmt.asprintf("hello {} world {} value {}", "alpha", "beta", "gamma");
if (!streq(r, "hello alpha world beta value gamma")) { fail(); };
assert(!(!streq(r, "hello alpha world beta value gamma")));
os.free(r.ptr: *void, r.len: u64);
};
@@ -448,7 +442,7 @@ fn errsource() io.stream = {
// strings.dup empty-input contract.
@test fn asprintf_empty() void = {
let r: str = fmt.asprintf("");
if (r.len != 0) { fail(); };
assert(!(r.len != 0));
};
// Indexed placeholder + modifier through asprintf — confirms the full
@@ -456,7 +450,7 @@ fn errsource() io.stream = {
// the memio.fixed (bsprintf) and memio.dynamic-via-fprintf paths.
@test fn asprintf_indexed_mods() void = {
let r: str = fmt.asprintf("{1:_05}", "zzz", 42i64);
if (!streq(r, "00042")) { fail(); };
assert(!(!streq(r, "00042")));
os.free(r.ptr: *void, r.len: u64);
};
@@ -476,12 +470,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{}", 1.5);
match (r) {
case let n: size => { if (n: i32 != 3) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 3)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "1.5")) { fail(); };
assert(!(!streq(memio.string(&mem), "1.5")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_f64_int_valued() void = {
@@ -489,12 +483,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{}", 1.0);
match (r) {
case let n: size => { if (n: i32 != 1) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 1)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "1")) { fail(); };
assert(!(!streq(memio.string(&mem), "1")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_f64_neg() void = {
@@ -502,12 +496,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{}", -2.5);
match (r) {
case let n: size => { if (n: i32 != 4) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 4)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "-2.5")) { fail(); };
assert(!(!streq(memio.string(&mem), "-2.5")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_f64_zero() void = {
@@ -515,12 +509,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{}", 0.0);
match (r) {
case let n: size => { if (n: i32 != 1) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 1)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "0")) { fail(); };
assert(!(!streq(memio.string(&mem), "0")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_f64_small_frac() void = {
@@ -528,12 +522,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{}", 0.05);
match (r) {
case let n: size => { if (n: i32 != 4) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 4)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "0.05")) { fail(); };
assert(!(!streq(memio.string(&mem), "0.05")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// Pins a large magnitude through the fmt dispatch — post-Ryū-graduation
@@ -544,12 +538,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{}", 9.5e18);
match (r) {
case let n: size => { if (n: i32 != 6) { fail(); }; }; // "9.5e18"
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 6)); }; // "9.5e18"
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "9.5e18")) { fail(); };
assert(!(!streq(memio.string(&mem), "9.5e18")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// Sign-mod fold: '+' on positive, '-' still wins on negative (the
@@ -559,12 +553,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{:+} {:+}", 1.5, -1.5);
match (r) {
case let n: size => { if (n: i32 != 9) { fail(); }; }; // "+1.5 -1.5"
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 9)); }; // "+1.5 -1.5"
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "+1.5 -1.5")) { fail(); };
assert(!(!streq(memio.string(&mem), "+1.5 -1.5")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_f64_sign_space() void = {
@@ -572,12 +566,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{: }", 1.5);
match (r) {
case let n: size => { if (n: i32 != 4) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 4)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), " 1.5")) { fail(); };
assert(!(!streq(memio.string(&mem), " 1.5")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// Width + alignment round-trip through rawlenf64 (sign-aware len count).
@@ -586,12 +580,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{:8}", 1.5);
match (r) {
case let n: size => { if (n: i32 != 8) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 8)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), " 1.5")) { fail(); };
assert(!(!streq(memio.string(&mem), " 1.5")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn fprintf_f64_width_left() void = {
@@ -599,12 +593,12 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprintf(s, "{:-8}", 1.5);
match (r) {
case let n: size => { if (n: i32 != 8) { fail(); }; };
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 8)); };
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "1.5 ")) { fail(); };
assert(!(!streq(memio.string(&mem), "1.5 ")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
// Legacy fprint variadic — covers the non-printf surface arm (where
@@ -614,73 +608,73 @@ fn errsource() io.stream = {
let s: io.stream = &mem.vt;
let r: (size | io.error) = fmt.fprint(s, 1.5, "x");
match (r) {
case let n: size => { if (n: i32 != 5) { fail(); }; }; // "1.5 x"
case let eioe: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); }; // "1.5 x"
case let eioe: io.error => abort();
};
if (!streq(memio.string(&mem), "1.5 x")) { fail(); };
assert(!(!streq(memio.string(&mem), "1.5 x")));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let eioe: io.error => fail(); };
match (c) { case void => {}; case let eioe: io.error => abort(); };
};
@test fn bsprintf_f64() void = {
let buf: [16]u8;
let r: (str | io.error) = fmt.bsprintf(buf[0:16], "x={}", 1.5);
match (r) {
case let s: str => { if (!streq(s, "x=1.5")) { fail(); }; };
case let eioe: io.error => fail();
case let s: str => { assert(!(!streq(s, "x=1.5"))); };
case let eioe: io.error => abort();
};
};
// Heap sink + both signs.
@test fn asprintf_f64() void = {
let r: str = fmt.asprintf("{} {}", 1.5, -2.5);
if (!streq(r, "1.5 -2.5")) { fail(); };
assert(!(!streq(r, "1.5 -2.5")));
os.free(r.ptr: *void, r.len: u64);
};
export fn main() i32 = {
signalled = 1; fprintbarestr();
signalled = 2; fprintintstr();
signalled = 3; fprintboolrune();
signalled = 4; fprintempty();
signalled = 5; fprintlnmulti();
signalled = 6; fprintlnempty();
signalled = 7; fprintfixedshort();
signalled = 8; fprintclosed();
signalled = 9; fprintf_implicit();
signalled = 10; fprintf_indexed();
signalled = 11; fprintf_literal_braces();
signalled = 12; fprintf_width_right();
signalled = 13; fprintf_width_left();
signalled = 14; fprintf_width_center();
signalled = 15; fprintf_pad_underscore();
signalled = 16; fprintf_base_hex();
signalled = 17; fprintf_base_oct_bin();
signalled = 18; fprintf_prec_int();
signalled = 19; fprintf_prec_str_trunc();
signalled = 20; fprintf_sign_neg();
signalled = 21; fprintfln_basic();
signalled = 22; fprintf_closed();
signalled = 23; bsprintf_basic();
signalled = 24; fprintf_bool_rune();
signalled = 25; bsprintf_trunc();
signalled = 26; bsprintf_width_trunc();
signalled = 27; asprintf_basic();
signalled = 28; asprintf_growth();
signalled = 29; asprintf_empty();
signalled = 30; asprintf_indexed_mods();
signalled = 31; fprintf_f64_basic();
signalled = 32; fprintf_f64_int_valued();
signalled = 33; fprintf_f64_neg();
signalled = 34; fprintf_f64_zero();
signalled = 35; fprintf_f64_small_frac();
signalled = 36; fprintf_f64_huge();
signalled = 37; fprintf_f64_sign_plus();
signalled = 38; fprintf_f64_sign_space();
signalled = 39; fprintf_f64_width_right();
signalled = 40; fprintf_f64_width_left();
signalled = 41; fprint_f64_variadic();
signalled = 42; bsprintf_f64();
signalled = 43; asprintf_f64();
fprintbarestr();
fprintintstr();
fprintboolrune();
fprintempty();
fprintlnmulti();
fprintlnempty();
fprintfixedshort();
fprintclosed();
fprintf_implicit();
fprintf_indexed();
fprintf_literal_braces();
fprintf_width_right();
fprintf_width_left();
fprintf_width_center();
fprintf_pad_underscore();
fprintf_base_hex();
fprintf_base_oct_bin();
fprintf_prec_int();
fprintf_prec_str_trunc();
fprintf_sign_neg();
fprintfln_basic();
fprintf_closed();
bsprintf_basic();
fprintf_bool_rune();
bsprintf_trunc();
bsprintf_width_trunc();
asprintf_basic();
asprintf_growth();
asprintf_empty();
asprintf_indexed_mods();
fprintf_f64_basic();
fprintf_f64_int_valued();
fprintf_f64_neg();
fprintf_f64_zero();
fprintf_f64_small_frac();
fprintf_f64_huge();
fprintf_f64_sign_plus();
fprintf_f64_sign_space();
fprintf_f64_width_right();
fprintf_f64_width_left();
fprint_f64_variadic();
bsprintf_f64();
asprintf_f64();
return 0;
};

View File

@@ -15,13 +15,6 @@ import fmt;
import io;
import log;
import memio;
import os;
// signalled — bumped before each scenario so a failing exit code
// pinpoints the offending case.
let signalled: i32 = 0;
fn fail() void = { os.exit(signalled + 10); };
fn streq(a: str, b: str) bool = {
if (a.len != b.len) { return false; };
@@ -48,10 +41,10 @@ fn streq(a: str, b: str) bool = {
let s = &mem.vt;
let sl = log.new(s); // triggers ensureinit
if (log.silent == nil) { fail(); };
if (log.default == nil) { fail(); };
if (log.global == nil) { fail(); };
if (log.global != log.default) { fail(); };
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 -------------------
@@ -65,7 +58,7 @@ fn streq(a: str, b: str) bool = {
log.lprintln(&sl.logger, "hello", 42i64);
if (!streq(memio.string(&mem), "hello 42\n")) { fail(); };
assert(!(!streq(memio.string(&mem), "hello 42\n")));
};
// ---- lprintln single-arg: no leading space, just trailing newline -----
@@ -79,7 +72,7 @@ fn streq(a: str, b: str) bool = {
log.lprintln(&sl.logger, "only");
if (!streq(memio.string(&mem), "only\n")) { fail(); };
assert(!(!streq(memio.string(&mem), "only\n")));
};
// ---- lprintln zero args: bare newline ---------------------------------
@@ -93,7 +86,7 @@ fn streq(a: str, b: str) bool = {
log.lprintln(&sl.logger);
if (!streq(memio.string(&mem), "\n")) { fail(); };
assert(!(!streq(memio.string(&mem), "\n")));
};
// ---- silent: lprintln through log.silent writes no bytes --------------
@@ -111,11 +104,11 @@ fn streq(a: str, b: str) bool = {
let sl = log.new(s); // triggers log.ensureinit; populates log.silent
if (log.silent == nil) { fail(); };
assert(!(log.silent == nil));
log.lprintln(log.silent, "ignored", 1i64, true);
if (mem.pos != 0) { fail(); };
assert(!(mem.pos != 0));
};
// ---- setlogger swap: global redirects to a new sink, then to silent --
@@ -137,20 +130,20 @@ fn streq(a: str, b: str) bool = {
log.setlogger(&sl1.logger);
log.println("first");
if (!streq(memio.string(&mem1), "first\n")) { fail(); };
if (mem2.pos != 0) { fail(); };
assert(!(!streq(memio.string(&mem1), "first\n")));
assert(!(mem2.pos != 0));
log.setlogger(&sl2.logger);
log.println("second");
if (!streq(memio.string(&mem2), "second\n")) { fail(); };
assert(!(!streq(memio.string(&mem2), "second\n")));
// mem1 must be unchanged.
if (!streq(memio.string(&mem1), "first\n")) { fail(); };
assert(!(!streq(memio.string(&mem1), "first\n")));
log.setlogger(log.silent);
log.println("dropped");
// Both sinks unchanged.
if (!streq(memio.string(&mem1), "first\n")) { fail(); };
if (!streq(memio.string(&mem2), "second\n")) { fail(); };
assert(!(!streq(memio.string(&mem1), "first\n")));
assert(!(!streq(memio.string(&mem2), "second\n")));
};
// ---- lprintfln: {n}-placeholder render into a memio sink -------------
@@ -164,7 +157,7 @@ fn streq(a: str, b: str) bool = {
log.lprintfln(&sl.logger, "x={} y={}", 42i64, "hi");
if (!streq(memio.string(&mem), "x=42 y=hi\n")) { fail(); };
assert(!(!streq(memio.string(&mem), "x=42 y=hi\n")));
};
// ---- printfln through global: setlogger then dispatch ---------------
@@ -184,8 +177,8 @@ fn streq(a: str, b: str) bool = {
log.setlogger(&sl1.logger);
log.printfln("v={}", 7i64);
if (!streq(memio.string(&mem1), "v=7\n")) { fail(); };
if (mem2.pos != 0) { fail(); };
assert(!(!streq(memio.string(&mem1), "v=7\n")));
assert(!(mem2.pos != 0));
};
// ---- silent.printfln writes nothing ---------------------------------
@@ -200,11 +193,11 @@ fn streq(a: str, b: str) bool = {
let sl = log.new(s); // triggers log.ensureinit; populates log.silent
if (log.silent == nil) { fail(); };
assert(!(log.silent == nil));
log.lprintfln(log.silent, "ignored={}", 1i64);
if (mem.pos != 0) { fail(); };
assert(!(mem.pos != 0));
};
// ---- lprintfln: indexed {N} placeholder across log → fmt seam -------
@@ -221,7 +214,7 @@ fn streq(a: str, b: str) bool = {
log.lprintfln(&sl.logger, "{1} {0}", "a", "b");
if (!streq(memio.string(&mem), "b a\n")) { fail(); };
assert(!(!streq(memio.string(&mem), "b a\n")));
};
// ---- lprintfln: {:mods} modifier across log → fmt seam --------------
@@ -237,7 +230,7 @@ fn streq(a: str, b: str) bool = {
log.lprintfln(&sl.logger, "{:5}", 42i64);
if (!streq(memio.string(&mem), " 42\n")) { fail(); };
assert(!(!streq(memio.string(&mem), " 42\n")));
};
// TODO subprocess: log.fatal / log.lfatal / log.fatalf / log.lfatalf
@@ -247,16 +240,16 @@ fn streq(a: str, b: str) bool = {
// when that lands.
export fn main() i32 = {
signalled = 1; defaultwiredtoglobal();
signalled = 2; lprintlnbasic();
signalled = 3; lprintlnsingle();
signalled = 4; lprintlnempty();
signalled = 5; silentwritesnothing();
signalled = 6; setloggerswap();
signalled = 7; lprintflnbasic();
signalled = 8; printflnglobal();
signalled = 9; silentignoresprintfln();
signalled = 10; lprintflnindexed();
signalled = 11; lprintflnmods();
defaultwiredtoglobal();
lprintlnbasic();
lprintlnsingle();
lprintlnempty();
silentwritesnothing();
setloggerswap();
lprintflnbasic();
printflnglobal();
silentignoresprintfln();
lprintflnindexed();
lprintflnmods();
return 0;
};

View File

@@ -13,13 +13,6 @@ import bytes;
import errors;
import io;
import memio;
import os;
// signalled — bumped by main before each test so a failing exit code
// pinpoints the offending case.
let signalled: i32 = 0;
fn fail() void = { os.exit(signalled + 10); };
fn putstr(s: str, into: []u8, off: i32) i32 = {
let i: i32 = 0;
@@ -64,20 +57,20 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
match (r) {
case let nz: size => {
let n: i32 = nz: i32;
if (weof[i] != 0) { fail(); };
if (n != wantn[i]) { fail(); };
if (n > 0 && out[0] != wantf[i]) { fail(); };
if (n > 0 && out[n - 1] != wantl[i]) { fail(); };
assert(!(weof[i] != 0));
assert(!(n != wantn[i]));
assert(!(n > 0 && out[0] != wantf[i]));
assert(!(n > 0 && out[n - 1] != wantl[i]));
};
case io.eof => { if (weof[i] == 0) { fail(); }; };
case let e: io.error => fail();
case io.eof => { assert(!(weof[i] == 0)); };
case let e: io.error => abort();
};
i += 1;
};
// fixed stream has no closer → io.close returns void.
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let e: io.error => fail(); };
match (c) { case void => {}; case let e: io.error => abort(); };
};
// ---- fixedwritecases: full-fit / exact-fill / partial / overflow -------------
@@ -108,25 +101,25 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
let hi: i32 = lo + ln[i];
let r: (size | io.error) = io.write(s, src[lo:hi]);
match (r) {
case let n: size => { if (n: i32 != wantn[i]) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != wantn[i])); };
case let e: io.error => abort();
};
i += 1;
};
let want: [16]u8;
let _: i32 = putstr("hello world!!XXX", want[0:16], 0);
if (!bytes.equal(dst[0:16], want[0:16])) { fail(); };
assert(!(!bytes.equal(dst[0:16], want[0:16])));
// 0-byte write is always 0 with no side effects.
let r0: (size | io.error) = io.write(s, src[0:0]);
match (r0) {
case let n: size => { if (n != 0: size) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n != 0: size)); };
case let e: io.error => abort();
};
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let e: io.error => fail(); };
match (c) { case void => {}; case let e: io.error => abort(); };
};
// ---- dynamicgrowcases: every cap doubling exercised ---------------------
@@ -157,18 +150,18 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
let hi: i32 = lo + chunk[i];
let r: (size | io.error) = io.write(s, src[lo:hi]);
match (r) {
case let n: size => { if (n: i32 != chunk[i]) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != chunk[i])); };
case let e: io.error => abort();
};
if (memio.buffer(&st).len != total[i]) { fail(); };
assert(!(memio.buffer(&st).len != total[i]));
off += chunk[i];
i += 1;
};
if (!bytes.equal(memio.buffer(&st), src[0:26])) { fail(); };
assert(!(!bytes.equal(memio.buffer(&st), src[0:26])));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let e: io.error => fail(); };
match (c) { case void => {}; case let e: io.error => abort(); };
};
// ---- dynamicreset: write / reset / write cycles -------------------------
@@ -204,19 +197,19 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
let hi: i32 = lo + ln[i];
let r: (size | io.error) = io.write(s, src[lo:hi]);
match (r) {
case let n: size => { if (n: i32 != ln[i]) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != ln[i])); };
case let e: io.error => abort();
};
off += ln[i];
};
if (memio.buffer(&st).len != want[i]) { fail(); };
assert(!(memio.buffer(&st).len != want[i]));
i += 1;
};
if (!bytes.equal(memio.buffer(&st), src[0:8])) { fail(); };
assert(!(!bytes.equal(memio.buffer(&st), src[0:8])));
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let e: io.error => fail(); };
match (c) { case void => {}; case let e: io.error => abort(); };
};
// ---- borrowedread: under / exact / over / 0-byte ------------------------
@@ -242,12 +235,12 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
let r: ([]u8 | io.eof) = memio.borrowedread(&st, amt[i]);
match (r) {
case let v: []u8 => {
if (weof[i] != 0) { fail(); };
if (v.len != amt[i]) { fail(); };
if (v.len > 0 && v[0] != wf[i]) { fail(); };
if (v.len > 0 && v[v.len - 1] != wl[i]) { fail(); };
assert(!(weof[i] != 0));
assert(!(v.len != amt[i]));
assert(!(v.len > 0 && v[0] != wf[i]));
assert(!(v.len > 0 && v[v.len - 1] != wl[i]));
};
case io.eof => { if (weof[i] == 0) { fail(); }; };
case io.eof => { assert(!(weof[i] == 0)); };
};
i += 1;
};
@@ -259,7 +252,7 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
let st: memio.stream = memio.dynamic();
let s: io.stream = &st.vt;
if (memio.string(&st).len != 0) { fail(); };
assert(!(memio.string(&st).len != 0));
let src: [32]u8;
let _: i32 = putstr("hello world!!", src[0:32], 0);
@@ -279,16 +272,16 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
let lo: i32 = off[i];
let hi: i32 = lo + ln[i];
let r: (size | io.error) = io.write(s, src[lo:hi]);
match (r) { case let n: size => {}; case let e: io.error => fail(); };
match (r) { case let n: size => {}; case let e: io.error => abort(); };
let v: str = memio.string(&st);
if (v.len != want[i]) { fail(); };
if (v[0] != wf[i]) { fail(); };
if (v[v.len - 1] != wl[i]) { fail(); };
assert(!(v.len != want[i]));
assert(!(v[0] != wf[i]));
assert(!(v[v.len - 1] != wl[i]));
i += 1;
};
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let e: io.error => fail(); };
match (c) { case void => {}; case let e: io.error => abort(); };
};
// ---- dynamicfromseed: ownership-transferred seed, read then write -------
@@ -321,12 +314,12 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
match (r) {
case let nz: size => {
let n: i32 = nz: i32;
if (weof[i] != 0) { fail(); };
if (n != rn[i]) { fail(); };
if (out[0] != want[i]) { fail(); };
assert(!(weof[i] != 0));
assert(!(n != rn[i]));
assert(!(out[0] != want[i]));
};
case io.eof => { if (weof[i] == 0) { fail(); }; };
case let e: io.error => fail();
case io.eof => { assert(!(weof[i] == 0)); };
case let e: io.error => abort();
};
i += 1;
};
@@ -337,12 +330,12 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
extra[0]=200u8; extra[1]=201u8; extra[2]=202u8; extra[3]=203u8;
let w: (size | io.error) = io.write(s, extra[0:4]);
match (w) {
case let n: size => { if (n: i32 != 4) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != 4)); };
case let e: io.error => abort();
};
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let e: io.error => fail(); };
match (c) { case void => {}; case let e: io.error => abort(); };
};
// ---- seekcases: SET/CUR/END × in-bounds/OOB over one fixed stream --------
@@ -385,22 +378,22 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
let r: (io.off | io.error) = io.seek(s, off[i], w);
match (r) {
case let o: io.off => {
if (want[i] < 0) { fail(); };
if ((o: i64) != want[i]) { fail(); };
assert(!(want[i] < 0));
assert(!((o: i64) != want[i]));
pos = o: i64;
};
case let e: io.error => {
if (want[i] >= 0) { fail(); };
assert(!(want[i] >= 0));
match (e) {
case errors.invalid => {};
case => fail();
case => abort();
};
};
};
let t: (io.off | io.error) = io.tell(s);
match (t) {
case let o: io.off => { if ((o: i64) != pos) { fail(); }; };
case let e: io.error => fail();
case let o: io.off => { assert(!((o: i64) != pos)); };
case let e: io.error => abort();
};
i += 1;
};
@@ -409,25 +402,25 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
// drains bytes 5..7, then eof.
let r: (io.off | io.error) = io.seek(s, 5, io.whence.SET);
match (r) {
case let o: io.off => { if ((o: i64) != 5) { fail(); }; };
case let e: io.error => fail();
case let o: io.off => { assert(!((o: i64) != 5)); };
case let e: io.error => abort();
};
let out: [8]u8;
let rd: (size | io.eof | io.error) = io.read(s, out[0:8]);
match (rd) {
case let nz: size => {
if (nz: i32 != 3) { fail(); };
if (out[0] != 15u8) { fail(); };
if (out[2] != 17u8) { fail(); };
assert(!(nz: i32 != 3));
assert(!(out[0] != 15u8));
assert(!(out[2] != 17u8));
};
case io.eof => fail();
case let e: io.error => fail();
case io.eof => abort();
case let e: io.error => abort();
};
let rd2: (size | io.eof | io.error) = io.read(s, out[0:8]);
match (rd2) {
case io.eof => {};
case let nz: size => fail();
case let e: io.error => fail();
case let nz: size => abort();
case let e: io.error => abort();
};
};
@@ -454,14 +447,14 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
let r: (io.off | io.error) = io.seek(s, off[i], w);
match (r) {
case let o: io.off => {
if (want[i] < 0) { fail(); };
if ((o: i64) != want[i]) { fail(); };
assert(!(want[i] < 0));
assert(!((o: i64) != want[i]));
};
case let e: io.error => {
if (want[i] >= 0) { fail(); };
assert(!(want[i] >= 0));
match (e) {
case errors.invalid => {};
case => fail();
case => abort();
};
};
};
@@ -482,24 +475,24 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
src[0]=30u8; src[1]=31u8; src[2]=32u8; src[3]=33u8; src[4]=34u8;
let wr: (size | io.error) = io.write(s, src[0:5]);
match (wr) {
case let n: size => { if (n: i32 != 5) { fail(); }; };
case let e: io.error => fail();
case let n: size => { assert(!(n: i32 != 5)); };
case let e: io.error => abort();
};
// END 0 → 5 (logical length); cap is 8 post-grow, so END 1 must
// still be invalid even though capacity would fit it.
let r: (io.off | io.error) = io.seek(s, 0, io.whence.END);
match (r) {
case let o: io.off => { if ((o: i64) != 5) { fail(); }; };
case let e: io.error => fail();
case let o: io.off => { assert(!((o: i64) != 5)); };
case let e: io.error => abort();
};
let r1: (io.off | io.error) = io.seek(s, 1, io.whence.END);
match (r1) {
case let o: io.off => fail();
case let o: io.off => abort();
case let e: io.error => {
match (e) {
case errors.invalid => {};
case => fail();
case => abort();
};
};
};
@@ -507,41 +500,41 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
// CUR -2 → 3; read drains 33,34 then eof.
let r2: (io.off | io.error) = io.seek(s, -2, io.whence.CUR);
match (r2) {
case let o: io.off => { if ((o: i64) != 3) { fail(); }; };
case let e: io.error => fail();
case let o: io.off => { assert(!((o: i64) != 3)); };
case let e: io.error => abort();
};
let out: [4]u8;
let rd: (size | io.eof | io.error) = io.read(s, out[0:4]);
match (rd) {
case let nz: size => {
if (nz: i32 != 2) { fail(); };
if (out[0] != 33u8) { fail(); };
if (out[1] != 34u8) { fail(); };
assert(!(nz: i32 != 2));
assert(!(out[0] != 33u8));
assert(!(out[1] != 34u8));
};
case io.eof => fail();
case let e: io.error => fail();
case io.eof => abort();
case let e: io.error => abort();
};
let rd2: (size | io.eof | io.error) = io.read(s, out[0:4]);
match (rd2) {
case io.eof => {};
case let nz: size => fail();
case let e: io.error => fail();
case let nz: size => abort();
case let e: io.error => abort();
};
let c: (void | io.error) = io.close(s);
match (c) { case void => {}; case let e: io.error => fail(); };
match (c) { case void => {}; case let e: io.error => abort(); };
};
export fn main() i32 = {
signalled = 1; fixedread();
signalled = 2; fixedwritecases();
signalled = 3; dynamicgrowcases();
signalled = 4; dynamicreset();
signalled = 5; borrowedreadcases();
signalled = 6; stringview();
signalled = 7; dynamicfromseed();
signalled = 8; seekcases();
signalled = 9; emptyseek();
signalled = 10; dynamicseek();
fixedread();
fixedwritecases();
dynamicgrowcases();
dynamicreset();
borrowedreadcases();
stringview();
dynamicfromseed();
seekcases();
emptyseek();
dynamicseek();
return 0;
};