From b3a1bce00944258f172e573ec20d7d9e567a1e11 Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Sun, 21 Sep 2025 18:55:26 +0800 Subject: [PATCH] Add tests for iter --- ds/map/test.ha | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/ds/map/test.ha b/ds/map/test.ha index 5789d1c04581ae4b021eef3aba1f250078bc06d4..e6b023db8861d9c8a0ad4855b2fb0205029bcb19 100644 --- a/ds/map/test.ha +++ b/ds/map/test.ha @@ -8,6 +8,14 @@ dst[i] = ((x >> (8u64 * (i: u64))) & 0xFFu64): u8; }; }; +fn get_le64(src: []u8) u64 = { + let x: u64 = 0u64; + for (let i = 0z; i < 8z; i += 1) { + x |= (src[i]: u64) << (8u64 * (i: u64)); + }; + return x; +}; + type oracle = []nullable *opaque; fn must_set(m: *map, key: []u8, v: *opaque) void = { @@ -19,6 +27,47 @@ }; fn must_get(m: *map, key: []u8) (*opaque | void) = get(m, key); fn must_del(m: *map, key: []u8) (*opaque | void) = del(m, key); +fn verify_iter_matches_oracle(m: *map, exp: oracle) void = { + let seen: []bool = alloc([false...], len(exp))!; + + let it: *iterator = match (iter(m)) { + case let p: *iterator => yield p; + case nomem => abort("iter: out of memory"); + }; + + for (true) { + match (next(it)) { + case let kv: ([]u8, *opaque) => + let k = kv.0; + let v = kv.1; + + assert(len(k) >= 8z, "iter: key too short"); + let idx = (get_le64(k[..8]): size); + assert(idx < len(exp), "iter: decoded index out of range"); + + match (exp[idx]) { + case null => + abort("iter: found element which should not exist"); + case let p: *opaque => + assert(v == p, "iter: value pointer mismatch"); + }; + + assert(!seen[idx], "iter: duplicate key encountered"); + seen[idx] = true; + case done => + break; + }; + }; + + for (let i = 0z; i < len(exp); i += 1) { + match (exp[i]) { + case null => void; + case *opaque => + assert(seen[i], "iter: missing expected key"); + }; + }; +}; + export fn stress_test(m: *map, key_space: size) void = { let empty: [KEY_LEN]u8 = [0...]; let keybufs: [][KEY_LEN]u8 = alloc([empty...], key_space)!; @@ -47,6 +96,9 @@ case void => abort("phase1: get void after set"); }; }; + // Verify contents via iterator after initial inserts. + verify_iter_matches_oracle(m, exp); + // Forward read sweep (all should be present) for (let i = 0z; i < key_space; i += 1) { match (must_get(m, keys[i])) { @@ -132,6 +184,9 @@ exp[i] = vp; }; }; + // Verify contents via iterator after mixed updates. + verify_iter_matches_oracle(m, exp); + // Reading in reverse order for (let r = key_space; r > 0z; r -= 1) { let i = r - 1z; @@ -177,5 +232,15 @@ match (must_del(m, keys[i])) { case void => void; case *opaque => abort("final: del returned value after full clear"); }; + }; + + // Iterator should also report empty + let it_empty: *iterator = match (iter(m)) { + case let p: *iterator => yield p; + case nomem => abort("iter(empty): out of memory"); + }; + match (next(it_empty)) { + case done => void; + case ([]u8, *opaque) => abort("final: iterator produced elements after clear"); }; }; -- 2.48.1