From 03a8526cf0258f89bfcec970c4827412626b49f1 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 15 Feb 2026 14:54:31 +0100 Subject: [PATCH] Add tests Add tests for `core:container/xar` and `core:container/handle_map` (static + dynamic). --- core/container/small_array/small_array.odin | 10 +- .../core/container/test_core_handle_map.odin | 141 ++++++++++++++++++ .../{queue.odin => test_core_queue.odin} | 0 tests/core/container/test_core_xar.odin | 39 +++++ 4 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 tests/core/container/test_core_handle_map.odin rename tests/core/container/{queue.odin => test_core_queue.odin} (100%) create mode 100644 tests/core/container/test_core_xar.odin diff --git a/core/container/small_array/small_array.odin b/core/container/small_array/small_array.odin index b1674566d..8498da852 100644 --- a/core/container/small_array/small_array.odin +++ b/core/container/small_array/small_array.odin @@ -386,7 +386,7 @@ Attempts to add the given element at the beginning. This operation assumes that the small-array is not empty. Note: Performing this operation will cause pointers obtained -through get_ptr(_save) to reference incorrect elements. +through get_ptr(_safe) to reference incorrect elements. **Inputs** - `a`: A pointer to the small-array @@ -466,7 +466,7 @@ Removes and returns the first element of the small-array. This operation assumes that the small-array is not empty. Note: Performing this operation will cause pointers obtained -through get_ptr(_save) to reference incorrect elements. +through get_ptr(_safe) to reference incorrect elements. **Inputs** - `a`: A pointer to the small-array @@ -542,7 +542,7 @@ Attempts to remove and return the first element of the small array. Unlike `pop_front`, it does not assume that the array is non-empty. Note: Performing this operation will cause pointers obtained -through get_ptr(_save) to reference incorrect elements. +through get_ptr(_safe) to reference incorrect elements. **Inputs** - `a`: A pointer to the small-array @@ -616,7 +616,7 @@ consume :: proc "odin" (a: ^$A/Small_Array($N, $T), count: int, loc := #caller_l Removes the element at the specified index while retaining order. Note: Performing this operation will cause pointers obtained -through get_ptr(_save) to reference incorrect elements. +through get_ptr(_safe) to reference incorrect elements. **Inputs** - `a`: A pointer to the small-array @@ -754,7 +754,7 @@ push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) - Tries to insert an element at the specified position. Note: Performing this operation will cause pointers obtained -through get_ptr(_save) to reference incorrect elements. +through get_ptr(_safe) to reference incorrect elements. **Inputs** - `a`: A pointer to the small-array diff --git a/tests/core/container/test_core_handle_map.odin b/tests/core/container/test_core_handle_map.odin new file mode 100644 index 000000000..1753ee91b --- /dev/null +++ b/tests/core/container/test_core_handle_map.odin @@ -0,0 +1,141 @@ +package test_core_container + +import hm "core:container/handle_map" +import "core:container/xar" +import "core:testing" + +Item :: struct { + v: int, + p: ^Item, + handle: hm.Handle32, + my_idx: u16, +} + +@test +test_dynamic_handle_map :: proc(t: ^testing.T) { + dhm: hm.Dynamic_Handle_Map(Item, hm.Handle32) + hm.dynamic_init(&dhm, context.allocator) + defer hm.dynamic_destroy(&dhm) + + items: [dynamic]Item + defer delete(items) + + N :: 512 + for i in 1..=N { + h, add_err := hm.dynamic_add(&dhm, Item{v = i * 10 + 1}) + assert(add_err == nil) + + item := hm.dynamic_get(&dhm, h) + item.handle = h + item.p = item + item.my_idx = h.idx + + append(&items, item^) + } + + testing.expect(t, hm.dynamic_len(dhm) == N) + testing.expect(t, hm.dynamic_cap(dhm) >= N) + + for v in items { + item := hm.dynamic_get(&dhm, v.handle) + assert(item^ == v) + + // Remove half of the items + if item.handle.idx & 1 == 0 { + found, found_err := hm.dynamic_remove(&dhm, v.handle) + assert(found && found_err == nil) + + // These removed handles should no longer be valid + assert(!hm.dynamic_is_valid(&dhm, v.handle)) + } else { + // Non-removed handles should still be valid + assert(hm.dynamic_is_valid(&dhm, v.handle)) + } + } + + testing.expect(t, hm.dynamic_len(dhm) == N / 2) + testing.expect(t, hm.dynamic_cap(dhm) >= N / 2) + testing.expect(t, xar.len(dhm.unused_items) == N / 2) + + it := hm.dynamic_iterator_make(&dhm) + for v, handle in hm.iterate(&it) { + assert(v.handle.idx & 1 == 1) + assert(hm.dynamic_is_valid(&dhm, handle)) + + item := hm.dynamic_get(&dhm, handle) + assert(item.my_idx == v.handle.idx) + } + + for i in 1..=N / 2 { + h, add_err := hm.dynamic_add(&dhm, Item{v = i * 10 + 1}) + assert(add_err == nil) + assert(h.gen == 2) + } + + hm.dynamic_clear(&dhm) + testing.expect(t, hm.dynamic_len(dhm) == 0) + testing.expect(t, hm.dynamic_cap(dhm) >= N) +} + +test_static_handle_map :: proc(t: ^testing.T) { + N :: 512 + + shm: hm.Static_Handle_Map(N, Item, hm.Handle32) + + items: [dynamic]Item + defer delete(items) + + + for i in 1..=N { + h, add_ok := hm.static_add(&shm, Item{v = i * 10 + 1}) + assert(add_ok) + + item := hm.static_get(&shm, h) + item.handle = h + item.p = item + item.my_idx = h.idx + + append(&items, item^) + } + + testing.expect(t, hm.static_len(shm) == N) + testing.expect(t, hm.static_cap(shm) >= N) + + for v in items { + item := hm.static_get(&shm, v.handle) + assert(item^ == v) + + // Remove half of the items + if item.handle.idx & 1 == 0 { + assert(hm.static_remove(&shm, v.handle)) + + // These removed handles should no longer be valid + assert(!hm.static_is_valid(shm, v.handle)) + } else { + // Non-removed handles should still be valid + assert(hm.static_is_valid(shm, v.handle)) + } + } + + testing.expect(t, hm.static_len(shm) == N / 2) + testing.expect(t, hm.static_cap(shm) >= N / 2) + + it := hm.static_iterator_make(&shm) + for v, handle in hm.iterate(&it) { + assert(v.handle.idx & 1 == 1) + assert(hm.static_is_valid(shm, handle)) + + item := hm.static_get(&shm, handle) + assert(item.my_idx == v.handle.idx) + } + + for i in 1..=N / 2 { + h, add_ok := hm.static_add(&shm, Item{v = i * 10 + 1}) + assert(add_ok) + assert(h.gen == 2) + } + + hm.static_clear(&shm) + testing.expect(t, hm.static_len(shm) == 0) + testing.expect(t, hm.static_cap(shm) == N) +} \ No newline at end of file diff --git a/tests/core/container/queue.odin b/tests/core/container/test_core_queue.odin similarity index 100% rename from tests/core/container/queue.odin rename to tests/core/container/test_core_queue.odin diff --git a/tests/core/container/test_core_xar.odin b/tests/core/container/test_core_xar.odin new file mode 100644 index 000000000..a58b369df --- /dev/null +++ b/tests/core/container/test_core_xar.odin @@ -0,0 +1,39 @@ +package test_core_container + +import "core:container/xar" +import "core:testing" + +Value :: struct { + v: int, + p: ^int, +} + +@test +test_xar_pointer_stability :: proc(t: ^testing.T) { + x: xar.Array(int, 4) + defer xar.destroy(&x) + + values: [dynamic]Value + defer delete(values) + + N :: 512 + for i in 1..=N { + v := i * 10 + 1 + xar.push_back(&x, v) + ptr := xar.get_ptr(&x, i - 1) + append(&values, Value{v = v, p = ptr}) + } + + assert(xar.len(x) == N) + assert(xar.cap(x) >= N) + + for value, i in values { + ptr := xar.get_ptr(&x, i) + assert(ptr == value.p) + assert(ptr^ == value.v) + } + + xar.clear(&x) + assert(xar.len(x) == 0) + assert(xar.cap(x) >= N) +} \ No newline at end of file