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

@@ -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;
};