lib/os+dirs tests: hand-main plumbing -> assert (@test conversion B6)
WW_TEST_* env arrangement logic untouched; only the fail/exit plumbing converts.
This commit is contained in:
@@ -26,21 +26,18 @@
|
||||
// asserts immediately. Don't call two dirs.* fns and compare across
|
||||
// — the second clobbers the first's view.
|
||||
//
|
||||
// `signalled` global bumps before each test so a failing exit code
|
||||
// pinpoints the offending row (WEXITSTATUS = signalled + 10). Same
|
||||
// shape as temptest / shlextest / fnmatchtest / ostest.
|
||||
// A failing row aborts via the assert/abort builtin (task #5 @test
|
||||
// conversion).
|
||||
//
|
||||
// Don't `use io;` here — lib/os and lib/io collide on read/write/
|
||||
// close (task #17). We need only os.getenv + os.exit.
|
||||
// close (task #17). We need only os.getenv.
|
||||
|
||||
package dirs_test;
|
||||
|
||||
import dirs;
|
||||
import os;
|
||||
|
||||
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; };
|
||||
@@ -87,7 +84,7 @@ fn gettmpdir() str = {
|
||||
match (os.getenv("WW_TEST_TMPDIR")) {
|
||||
case let s: str => return s;
|
||||
case void => {
|
||||
fail();
|
||||
abort();
|
||||
let empty: str;
|
||||
return empty;
|
||||
};
|
||||
@@ -100,7 +97,7 @@ fn gettmpdir() str = {
|
||||
let tmpl = gettmpdir();
|
||||
let exp = expected(tmpl, "cfg", "myapp");
|
||||
let got = dirs.config("myapp");
|
||||
if (!streq(got, exp)) { fail(); };
|
||||
assert(!(!streq(got, exp)));
|
||||
};
|
||||
|
||||
// ---- 2: XDG_CACHE_HOME="relative/path" → fallback to $HOME/.cache --
|
||||
@@ -112,7 +109,7 @@ fn gettmpdir() str = {
|
||||
let tmpl = gettmpdir();
|
||||
let exp = expected(tmpl, ".cache", "myapp");
|
||||
let got = dirs.cache("myapp");
|
||||
if (!streq(got, exp)) { fail(); };
|
||||
assert(!(!streq(got, exp)));
|
||||
};
|
||||
|
||||
// ---- 3: XDG_DATA_HOME unset → fallback to $HOME/.local/share -------
|
||||
@@ -121,7 +118,7 @@ fn gettmpdir() str = {
|
||||
let tmpl = gettmpdir();
|
||||
let exp = expected(tmpl, ".local/share", "myapp");
|
||||
let got = dirs.data("myapp");
|
||||
if (!streq(got, exp)) { fail(); };
|
||||
assert(!(!streq(got, exp)));
|
||||
};
|
||||
|
||||
// ---- 4: XDG_STATE_HOME unset → fallback to $HOME/.local/state ------
|
||||
@@ -130,13 +127,13 @@ fn gettmpdir() str = {
|
||||
let tmpl = gettmpdir();
|
||||
let exp = expected(tmpl, ".local/state", "myapp");
|
||||
let got = dirs.state("myapp");
|
||||
if (!streq(got, exp)) { fail(); };
|
||||
assert(!(!streq(got, exp)));
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
signalled = 1; test_config_xdg_set();
|
||||
signalled = 2; test_cache_xdg_relative_fallback();
|
||||
signalled = 3; test_data_unset_fallback();
|
||||
signalled = 4; test_state_unset_fallback();
|
||||
test_config_xdg_set();
|
||||
test_cache_xdg_relative_fallback();
|
||||
test_data_unset_fallback();
|
||||
test_state_unset_fallback();
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
// cover alloc/free; the direct row here pins the FFI shape under
|
||||
// lib/os itself so future bindings refactors can't quietly drift.
|
||||
//
|
||||
// Convention follows the stdlib `_run` test fixtures: hand-rolled
|
||||
// @test fns dispatched from `main()` in numeric order, with a
|
||||
// `signalled` global the main fn bumps so a failing case exits with
|
||||
// `WEXITSTATUS = signalled + 10` — the harness then knows which
|
||||
// scenario tripped. Same shape as temptest / shlextest / fnmatchtest.
|
||||
// Hand-rolled @test fns dispatched from `main()` in source order; a
|
||||
// failing case aborts via the assert/abort builtin (task #5 @test
|
||||
// conversion).
|
||||
//
|
||||
// Pre-arranged env state (set by 974_getenv_run.c via setenv/unsetenv
|
||||
// before exec'ing `ww run lib/os/ostest.ww`):
|
||||
@@ -20,17 +18,15 @@
|
||||
//
|
||||
// Don't `use io;` here — lib/os and lib/io both export read/write/
|
||||
// close as C symbols that collide under the driver's flat-scope
|
||||
// concat (task #17). os alone is sufficient: getenv + exit are the
|
||||
// only primitives needed.
|
||||
// concat (task #17). os alone is sufficient: getenv + alloc/free are
|
||||
// the only primitives needed.
|
||||
|
||||
package os_test;
|
||||
|
||||
import os;
|
||||
import rt;
|
||||
|
||||
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; };
|
||||
@@ -47,9 +43,9 @@ fn streq(a: str, b: str) bool = {
|
||||
@test fn test_getenv_set() void = {
|
||||
let r = os.getenv("WW_TEST_GETENV");
|
||||
match (r) {
|
||||
case void => fail();
|
||||
case void => abort();
|
||||
case let s: str => {
|
||||
if (!streq(s, "hello-world")) { fail(); };
|
||||
assert(!(!streq(s, "hello-world")));
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -63,9 +59,9 @@ fn streq(a: str, b: str) bool = {
|
||||
@test fn test_getenv_empty() void = {
|
||||
let r = os.getenv("WW_TEST_EMPTY");
|
||||
match (r) {
|
||||
case void => fail();
|
||||
case void => abort();
|
||||
case let s: str => {
|
||||
if (s.len != 0) { fail(); };
|
||||
assert(!(s.len != 0));
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -76,7 +72,7 @@ fn streq(a: str, b: str) bool = {
|
||||
let r = os.getenv("WW_TEST_NOT_SET");
|
||||
match (r) {
|
||||
case void => {};
|
||||
case let s: str => fail();
|
||||
case let s: str => abort();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -91,7 +87,7 @@ fn streq(a: str, b: str) bool = {
|
||||
let r = os.getenv("WW_TEST_GETEN");
|
||||
match (r) {
|
||||
case void => {};
|
||||
case let s: str => fail();
|
||||
case let s: str => abort();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -106,16 +102,16 @@ fn streq(a: str, b: str) bool = {
|
||||
p.len = 4096;
|
||||
p[0] = 90u8; // 0x5a
|
||||
p[4095] = 165u8; // 0xa5
|
||||
if (p[0] != 90u8) { fail(); };
|
||||
if (p[4095] != 165u8) { fail(); };
|
||||
assert(!(p[0] != 90u8));
|
||||
assert(!(p[4095] != 165u8));
|
||||
os.free(p.ptr: *void, 4096u64);
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
signalled = 1; test_getenv_set();
|
||||
signalled = 2; test_getenv_empty();
|
||||
signalled = 3; test_getenv_unset();
|
||||
signalled = 4; test_getenv_prefix_no_match();
|
||||
signalled = 5; test_alloc_free_roundtrip();
|
||||
test_getenv_set();
|
||||
test_getenv_empty();
|
||||
test_getenv_unset();
|
||||
test_getenv_prefix_no_match();
|
||||
test_alloc_free_roundtrip();
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -12,24 +12,20 @@
|
||||
// WW_TEST_STAT_SUBDIR = "<tmp>/subdir" directory, 0700
|
||||
// WW_TEST_STAT_NOENT = "<tmp>/does-not-exist"
|
||||
//
|
||||
// Test exit code follows the stdlib `_run` convention: a `signalled`
|
||||
// global the main fn bumps before each row, so `WEXITSTATUS = signalled
|
||||
// + 10` tells the harness which row tripped. Same shape as
|
||||
// ostest / temptest / shlextest.
|
||||
// A failing row aborts via the assert/abort builtin (task #5 @test
|
||||
// conversion).
|
||||
|
||||
package os_test;
|
||||
|
||||
import os;
|
||||
|
||||
let signalled: i32 = 0;
|
||||
|
||||
fn fail() void = { os.exit(signalled + 10); };
|
||||
|
||||
// envpath — fetch an env var or abort; we want a clean signal if
|
||||
// 976_stat_run.c didn't prime the env state.
|
||||
fn envpath(name: str) str = {
|
||||
match (os.getenv(name)) {
|
||||
case void => { fail(); return "": str; };
|
||||
case void => { abort(); return "": str; };
|
||||
case let s: str => return s;
|
||||
};
|
||||
};
|
||||
@@ -59,27 +55,27 @@ fn istype(m: os.mode, t: os.mode) bool = {
|
||||
| os.stat_mask.ATIME | os.stat_mask.MTIME
|
||||
| os.stat_mask.CTIME) as u32;
|
||||
match (os.stat(&fi, p)) {
|
||||
case let e: os.oserror => fail();
|
||||
case let e: os.oserror => abort();
|
||||
case void => {
|
||||
if ((fi.mask as u32) != wantmask) { fail(); };
|
||||
if (!istype(fi.mode, os.mode.REG)) { fail(); };
|
||||
if (fi.sz != 11u64) { fail(); };
|
||||
if (fi.inode == 0u64) { fail(); };
|
||||
assert(!((fi.mask as u32) != wantmask));
|
||||
assert(!(!istype(fi.mode, os.mode.REG)));
|
||||
assert(!(fi.sz != 11u64));
|
||||
assert(!(fi.inode == 0u64));
|
||||
// Permission-bit smoke test — 976_stat_run.c open(2)s with
|
||||
// mode 0644 so USER_R survives any reasonable umask. Catches
|
||||
// a struct-field-offset miscompile on `fi.mode` that the
|
||||
// type-bit istype() check could miss if perm bits aliased a
|
||||
// neighbouring u32 (uid/gid).
|
||||
if (((fi.mode as u32) & (os.mode.USER_R as u32)) == 0u32) {
|
||||
fail();
|
||||
abort();
|
||||
};
|
||||
// atime/mtime/ctime — kernel-set at create time, all
|
||||
// post-epoch (>0). Three distinct kstat offsets (72/88/104)
|
||||
// so a fillfilestat field-copy miscompile or a filestat
|
||||
// time.instant offset bug surfaces here, not silently.
|
||||
if (fi.atime.sec <= 0i64) { fail(); };
|
||||
if (fi.mtime.sec <= 0i64) { fail(); };
|
||||
if (fi.ctime.sec <= 0i64) { fail(); };
|
||||
assert(!(fi.atime.sec <= 0i64));
|
||||
assert(!(fi.mtime.sec <= 0i64));
|
||||
assert(!(fi.ctime.sec <= 0i64));
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -90,9 +86,9 @@ fn istype(m: os.mode, t: os.mode) bool = {
|
||||
let p = envpath("WW_TEST_STAT_SUBDIR");
|
||||
let fi: os.filestat;
|
||||
match (os.stat(&fi, p)) {
|
||||
case let e: os.oserror => fail();
|
||||
case let e: os.oserror => abort();
|
||||
case void => {
|
||||
if (!istype(fi.mode, os.mode.DIR)) { fail(); };
|
||||
assert(!(!istype(fi.mode, os.mode.DIR)));
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -103,10 +99,10 @@ fn istype(m: os.mode, t: os.mode) bool = {
|
||||
let p = envpath("WW_TEST_STAT_NOENT");
|
||||
let fi: os.filestat;
|
||||
match (os.stat(&fi, p)) {
|
||||
case void => fail();
|
||||
case void => abort();
|
||||
case let e: os.oserror => {
|
||||
// ENOENT = 2 → raw errno is -2.
|
||||
if ((e: i64) != -2i64) { fail(); };
|
||||
assert(!((e: i64) != -2i64));
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -120,10 +116,10 @@ fn istype(m: os.mode, t: os.mode) bool = {
|
||||
let p = envpath("WW_TEST_STAT_SYMLINK");
|
||||
let fi: os.filestat;
|
||||
match (os.stat(&fi, p)) {
|
||||
case let e: os.oserror => fail();
|
||||
case let e: os.oserror => abort();
|
||||
case void => {
|
||||
if (!istype(fi.mode, os.mode.REG)) { fail(); };
|
||||
if (fi.sz != 11u64) { fail(); };
|
||||
assert(!(!istype(fi.mode, os.mode.REG)));
|
||||
assert(!(fi.sz != 11u64));
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -132,9 +128,9 @@ fn istype(m: os.mode, t: os.mode) bool = {
|
||||
let p = envpath("WW_TEST_STAT_SYMLINK");
|
||||
let fi: os.filestat;
|
||||
match (os.lstat(&fi, p)) {
|
||||
case let e: os.oserror => fail();
|
||||
case let e: os.oserror => abort();
|
||||
case void => {
|
||||
if (!istype(fi.mode, os.mode.LINK)) { fail(); };
|
||||
assert(!(!istype(fi.mode, os.mode.LINK)));
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -144,13 +140,13 @@ fn istype(m: os.mode, t: os.mode) bool = {
|
||||
@test fn test_fstat_regfile() void = {
|
||||
let p = envpath("WW_TEST_STAT_REGFILE");
|
||||
let fd: i32 = os.open(p, os.flag.RDONLY, 0i32);
|
||||
if (fd < 0) { fail(); };
|
||||
assert(!(fd < 0));
|
||||
let fi: os.filestat;
|
||||
match (os.fstat(&fi, fd)) {
|
||||
case let e: os.oserror => { os.close(fd); fail(); };
|
||||
case let e: os.oserror => { os.close(fd); abort(); };
|
||||
case void => {
|
||||
if (!istype(fi.mode, os.mode.REG)) { os.close(fd); fail(); };
|
||||
if (fi.sz != 11u64) { os.close(fd); fail(); };
|
||||
if (!istype(fi.mode, os.mode.REG)) { os.close(fd); abort(); };
|
||||
if (fi.sz != 11u64) { os.close(fd); abort(); };
|
||||
};
|
||||
};
|
||||
os.close(fd);
|
||||
@@ -160,17 +156,17 @@ fn istype(m: os.mode, t: os.mode) bool = {
|
||||
|
||||
@test fn test_exists_regfile() void = {
|
||||
let p = envpath("WW_TEST_STAT_REGFILE");
|
||||
if (!os.exists(p)) { fail(); };
|
||||
assert(!(!os.exists(p)));
|
||||
};
|
||||
|
||||
@test fn test_exists_subdir() void = {
|
||||
let p = envpath("WW_TEST_STAT_SUBDIR");
|
||||
if (!os.exists(p)) { fail(); };
|
||||
assert(!(!os.exists(p)));
|
||||
};
|
||||
|
||||
@test fn test_exists_noent() void = {
|
||||
let p = envpath("WW_TEST_STAT_NOENT");
|
||||
if (os.exists(p)) { fail(); };
|
||||
assert(!(os.exists(p)));
|
||||
};
|
||||
|
||||
// ---- ENAMETOOLONG: kpath rejects paths >= PATH_MAX -------------------
|
||||
@@ -197,29 +193,29 @@ fn makebig(n: i32) str = {
|
||||
let bp = makebig(os.PATH_MAX);
|
||||
let fi: os.filestat;
|
||||
match (os.stat(&fi, bp)) {
|
||||
case void => fail();
|
||||
case void => abort();
|
||||
case let e: os.oserror => {
|
||||
if ((e: i64) != -36i64) { fail(); }; // ENAMETOOLONG
|
||||
assert(!((e: i64) != -36i64)); // ENAMETOOLONG
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@test fn test_exists_toolong() void = {
|
||||
let bp = makebig(os.PATH_MAX);
|
||||
if (os.exists(bp)) { fail(); };
|
||||
assert(!(os.exists(bp)));
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
signalled = 1; test_stat_regfile();
|
||||
signalled = 2; test_stat_subdir();
|
||||
signalled = 3; test_stat_noent();
|
||||
signalled = 4; test_stat_symlink_follow();
|
||||
signalled = 5; test_lstat_symlink_nofollow();
|
||||
signalled = 6; test_fstat_regfile();
|
||||
signalled = 7; test_exists_regfile();
|
||||
signalled = 8; test_exists_subdir();
|
||||
signalled = 9; test_exists_noent();
|
||||
signalled = 10; test_stat_toolong();
|
||||
signalled = 11; test_exists_toolong();
|
||||
test_stat_regfile();
|
||||
test_stat_subdir();
|
||||
test_stat_noent();
|
||||
test_stat_symlink_follow();
|
||||
test_lstat_symlink_nofollow();
|
||||
test_fstat_regfile();
|
||||
test_exists_regfile();
|
||||
test_exists_subdir();
|
||||
test_exists_noent();
|
||||
test_stat_toolong();
|
||||
test_exists_toolong();
|
||||
return 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user