Skip to content

Instantly share code, notes, and snippets.

@leok7v
Created November 29, 2025 07:42
Show Gist options
  • Select an option

  • Save leok7v/25ad567d49e6a6ceeeee4aa8dfdb2d9f to your computer and use it in GitHub Desktop.

Select an option

Save leok7v/25ad567d49e6a6ceeeee4aa8dfdb2d9f to your computer and use it in GitHub Desktop.
map_test.c (see map.h/map.c)
#include "map.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
#define TEST_INT_PAIR(name, T, v1, v2) \
static void map_test_##name(void) { \
struct name map_of(T, T); \
struct name m = {}; \
bool ok = map_alloc(&m, 0); assert(ok); \
ok = map_put(&m, (T)(v1), (T)(v2)); assert(ok); \
T* r = map_get(&m, (T)(v1)); assert(r && *r == (T)(v2)); \
ok = map_remove(&m, (T)(v1)); assert(ok); \
assert(!map_has(&m, (T)(v1))); \
ok = map_put(&m, (T)(v1), (T)(v2)); assert(ok); \
r = map_get(&m, (T)(v1)); assert(r && *r == (T)(v2)); \
map_free(&m); \
}
#define TEST_FOREACH_NUM(name, T) \
static void map_test_foreach_##name(void) { \
struct fe_##name map_of(T, T); \
struct fe_##name m = {}; \
bool ok = map_alloc(&m, 0); assert(ok); \
int count = 0; \
map_foreach(&m, k, v, { count++; (void)k; (void)v; }); \
assert(count == 0); \
for (int i = 1; i <= 5; i++) { \
ok = map_put(&m, (T)i, (T)(i*i)); assert(ok); \
} \
count = 0; \
map_foreach(&m, k, v, { count++; assert(v == k*k); }); \
assert(count == 5); \
ok = map_remove(&m, (T)3); assert(ok); \
count = 0; \
map_foreach(&m, k, v, { count++; (void)k; (void)v; }); \
assert(count == 4); \
map_free(&m); \
}
#define TEST_CLEAR_NUM(name, T) \
static void map_test_clear_##name(void) { \
struct cl_##name map_of(T, T); \
struct cl_##name m = {}; \
bool ok = map_alloc(&m, 16); assert(ok); \
for (int i = 0; i < 5; i++) { \
ok = map_put(&m, (T)i, (T)(i*10)); assert(ok); \
} \
map_clear(&m); \
assert(m.count == 0); \
ok = map_put(&m, (T)99, (T)999); assert(ok); \
assert(!map_has(&m, (T)0)); \
assert(*map_get(&m, (T)99) == (T)999); \
map_free(&m); \
}
#define TEST_GROW_SHRINK_NUM(name, T) \
static void map_test_grow_shrink_##name(void) { \
struct gs_##name map_of(T, T); \
struct gs_##name m = {}; \
bool ok = map_alloc(&m, 8); assert(ok); \
for (int i = 0; i < 5; i++) { \
ok = map_put(&m, (T)i, (T)(i*i)); assert(ok); \
} \
ok = map_grow(&m, 128); assert(ok); \
for (int i = 0; i < 5; i++) { \
assert(*map_get(&m, (T)i) == (T)(i*i)); \
} \
ok = map_shrink(&m, 16); assert(ok); \
for (int i = 0; i < 5; i++) { \
assert(*map_get(&m, (T)i) == (T)(i*i)); \
} \
map_free(&m); \
}
TEST_INT_PAIR(i8, int8_t, -128, 127)
TEST_INT_PAIR(u8, uint8_t, 0, 255)
TEST_INT_PAIR(i16, int16_t, -32768, 32767)
TEST_INT_PAIR(u16, uint16_t, 0, 65535)
TEST_INT_PAIR(i32, int32_t, -2147483647-1, 2147483647)
TEST_INT_PAIR(u32, uint32_t, 0, 0xFFFFFFFFu)
TEST_INT_PAIR(i64, int64_t, -9223372036854775807LL-1, 9223372036854775807LL)
TEST_INT_PAIR(u64, uint64_t, 0, 0xFFFFFFFFFFFFFFFFULL)
TEST_INT_PAIR(sc, signed char, -128, 127)
TEST_INT_PAIR(uc, unsigned char, 0, 255)
TEST_INT_PAIR(sh, short, -32768, 32767)
TEST_INT_PAIR(us, unsigned short, 0, 65535)
TEST_INT_PAIR(lg, long, -1000000, 1000000)
TEST_INT_PAIR(ul, unsigned long, 0, 999999999)
TEST_INT_PAIR(ll, long long, -9000000000LL, 9000000000LL)
TEST_INT_PAIR(ull, unsigned long long, 0, 0xFFFFFFFFFFFFFFFFULL)
TEST_FOREACH_NUM(i32, int32_t)
TEST_FOREACH_NUM(f32, float)
TEST_FOREACH_NUM(f64, double)
TEST_CLEAR_NUM(i32, int32_t)
TEST_CLEAR_NUM(f32, float)
TEST_CLEAR_NUM(f64, double)
TEST_GROW_SHRINK_NUM(i32, int32_t)
TEST_GROW_SHRINK_NUM(f64, double)
static void map_test_s2s(void) {
struct s2s map_of(const char*, const char*);
struct s2s m = {};
bool ok = map_alloc(&m, 1); assert(ok);
ok = map_put(&m, "hello", "world"); assert(ok);
ok = map_put(&m, "foo", "bar"); assert(ok);
assert(strcmp(*map_get(&m, "hello"), "world") == 0);
ok = map_put(&m, "hello", "WORLD"); assert(ok);
assert(strcmp(*map_get(&m, "hello"), "WORLD") == 0);
ok = map_remove(&m, "foo"); assert(ok);
assert(!map_has(&m, "foo"));
ok = map_put(&m, "foo", "baz"); assert(ok);
for (int i = 0; i < 50; i++) {
char key[32], val[32];
snprintf(key, sizeof(key), "k%d", i);
snprintf(val, sizeof(val), "v%d", i);
ok = map_put(&m, key, val); assert(ok);
}
map_free(&m);
}
static void map_test_foreach_s2s(void) {
struct fes2s map_of(const char*, const char*);
struct fes2s m = {};
bool ok = map_alloc(&m, 0); assert(ok);
ok = map_put(&m, "a", "A"); assert(ok);
ok = map_put(&m, "b", "B"); assert(ok);
int count = 0;
map_foreach(&m, k, v, { count++; assert(k && v); });
assert(count == 2);
map_free(&m);
}
static void map_test_clear_s2s(void) {
struct cls2s map_of(const char*, const char*);
struct cls2s m = {};
bool ok = map_alloc(&m, 0); assert(ok);
ok = map_put(&m, "x", "y"); assert(ok);
map_clear(&m);
assert(m.count == 0);
ok = map_put(&m, "a", "b"); assert(ok);
assert(!map_has(&m, "x"));
map_free(&m);
}
static void map_test_grow_s2s(void) {
struct grs2s map_of(const char*, const char*);
struct grs2s m = {};
bool ok = map_alloc(&m, 8); assert(ok);
ok = map_put(&m, "one", "1"); assert(ok);
ok = map_put(&m, "two", "2"); assert(ok);
ok = map_grow(&m, 64); assert(ok);
assert(strcmp(*map_get(&m, "one"), "1") == 0);
assert(strcmp(*map_get(&m, "two"), "2") == 0);
ok = map_shrink(&m, 16); assert(ok);
assert(strcmp(*map_get(&m, "one"), "1") == 0);
map_free(&m);
}
static void map_test_s2i(void) {
struct s2i map_of(const char*, int32_t);
struct s2i m = {};
bool ok = map_alloc(&m, 0); assert(ok);
ok = map_put(&m, "one", 1); assert(ok);
ok = map_put(&m, "neg", -999); assert(ok);
assert(*map_get(&m, "one") == 1);
ok = map_put(&m, "one", 111); assert(ok);
assert(*map_get(&m, "one") == 111);
ok = map_remove(&m, "neg"); assert(ok);
map_free(&m);
}
static void map_test_i2s(void) {
struct i2s map_of(int32_t, const char*);
struct i2s m = {};
bool ok = map_alloc(&m, 0); assert(ok);
ok = map_put(&m, 1, "one"); assert(ok);
ok = map_put(&m, -1, "neg"); assert(ok);
assert(strcmp(*map_get(&m, 1), "one") == 0);
ok = map_put(&m, 1, "ONE"); assert(ok);
assert(strcmp(*map_get(&m, 1), "ONE") == 0);
ok = map_remove(&m, -1); assert(ok);
map_free(&m);
}
static void map_test_d2s(void) {
struct d2s map_of(double, const char*);
struct d2s m = {};
bool ok = map_alloc(&m, 0); assert(ok);
ok = map_put(&m, 3.14, "pi"); assert(ok);
assert(strcmp(*map_get(&m, 3.14), "pi") == 0);
ok = map_put(&m, 3.14, "PI"); assert(ok);
assert(strcmp(*map_get(&m, 3.14), "PI") == 0);
ok = map_remove(&m, 3.14); assert(ok);
ok = map_put(&m, 3.14, "pi2"); assert(ok);
map_free(&m);
}
static void map_test_f2s(void) {
struct f2s map_of(float, const char*);
struct f2s m = {};
bool ok = map_alloc(&m, 0); assert(ok);
ok = map_put(&m, 2.71f, "e"); assert(ok);
assert(strcmp(*map_get(&m, 2.71f), "e") == 0);
ok = map_remove(&m, 2.71f); assert(ok);
ok = map_put(&m, 2.71f, "E"); assert(ok);
map_free(&m);
}
static void map_test_zero_normalization(void) {
struct zf map_of(float, int);
struct zf mf = {};
bool ok = map_alloc(&mf, 0); assert(ok);
ok = map_put(&mf, -0.0f, 42); assert(ok);
assert(map_has(&mf, 0.0f) && map_has(&mf, -0.0f));
assert(*map_get(&mf, 0.0f) == 42);
ok = map_put(&mf, 0.0f, 99); assert(ok);
assert(*map_get(&mf, -0.0f) == 99 && mf.count == 1);
map_free(&mf);
struct zd map_of(double, int);
struct zd md = {};
ok = map_alloc(&md, 0); assert(ok);
ok = map_put(&md, -0.0, 123); assert(ok);
assert(map_has(&md, 0.0) && *map_get(&md, 0.0) == 123);
ok = map_put(&md, 0.0, 456); assert(ok);
assert(*map_get(&md, -0.0) == 456 && md.count == 1);
map_free(&md);
}
static void map_test_empty_ops(void) {
struct eo map_of(int, int);
struct eo m = {};
bool ok = map_alloc(&m, 0); assert(ok);
assert(!map_has(&m, 42));
assert(map_get(&m, 42) == NULL);
assert(!map_remove(&m, 42));
assert(m.count == 0 && m.capacity == 0);
map_clear(&m);
map_free(&m);
}
static void map_test_alloc_default(void) {
struct ad map_of(int, int);
struct ad m = {};
bool ok = map_alloc(&m); assert(ok);
assert(m.capacity == 16);
ok = map_put(&m, 1, 10); assert(ok);
assert(*map_get(&m, 1) == 10);
map_free(&m);
}
static void map_test_tombstone_chain(void) {
struct tc map_of(int, int);
struct tc m = {};
bool ok = map_alloc(&m, 8); assert(ok);
for (int i = 0; i < 6; i++) {
ok = map_put(&m, i, i * 10); assert(ok);
}
ok = map_remove(&m, 1); assert(ok);
ok = map_remove(&m, 3); assert(ok);
assert(map_has(&m, 0) && !map_has(&m, 1) && map_has(&m, 2));
ok = map_put(&m, 100, 1000); assert(ok);
assert(*map_get(&m, 100) == 1000);
map_free(&m);
}
static void map_test_shrink_auto(void) {
struct sa map_of(int, int);
struct sa m = {};
bool ok = map_alloc(&m, 128); assert(ok);
int32_t initial_cap = m.capacity;
for (int i = 0; i < 20; i++) {
ok = map_put(&m, i, i); assert(ok);
}
assert(m.capacity == initial_cap);
for (int i = 0; i < 18; i++) {
ok = map_remove(&m, i); assert(ok);
}
assert(m.count == 2);
assert(m.capacity < initial_cap);
assert(*map_get(&m, 18) == 18);
assert(*map_get(&m, 19) == 19);
map_free(&m);
}
static void map_test_heavy_collision(void) {
struct hc map_of(int, int);
struct hc m = {};
bool ok = map_alloc(&m, 8); assert(ok);
for (int i = 0; i < 100; i++) {
ok = map_put(&m, i, i * i); assert(ok);
}
for (int i = 0; i < 100; i++) {
int* r = map_get(&m, i);
assert(r && *r == i * i);
}
for (int i = 0; i < 100; i += 2) {
ok = map_remove(&m, i); assert(ok);
}
for (int i = 1; i < 100; i += 2) {
int* r = map_get(&m, i);
assert(r && *r == i * i);
}
for (int i = 0; i < 100; i += 2) {
ok = map_put(&m, i, i + 1000); assert(ok);
}
for (int i = 0; i < 100; i += 2) {
int* r = map_get(&m, i);
assert(r && *r == i + 1000);
}
map_free(&m);
}
static void map_test_string_variations(void) {
struct sv map_of(const char*, int);
struct sv m = {};
bool ok = map_alloc(&m, 0); assert(ok);
ok = map_put(&m, "", 0); assert(ok);
assert(map_has(&m, "") && *map_get(&m, "") == 0);
const char* lng = "this is a very long string key for testing";
ok = map_put(&m, lng, 999); assert(ok);
assert(*map_get(&m, lng) == 999);
ok = map_put(&m, "a\nb", 1); assert(ok);
assert(map_has(&m, "a\nb"));
map_free(&m);
}
static void map_test_repeated_ops(void) {
struct rp map_of(int, int);
struct rp m = {};
bool ok = map_alloc(&m, 0); assert(ok);
for (int r = 0; r < 10; r++) {
ok = map_put(&m, 42, r); assert(ok);
assert(*map_get(&m, 42) == r);
ok = map_remove(&m, 42); assert(ok);
}
assert(m.count == 0);
map_free(&m);
}
void map_test(void) {
map_test_i8(); map_test_u8();
map_test_i16(); map_test_u16();
map_test_i32(); map_test_u32();
map_test_i64(); map_test_u64();
map_test_sc(); map_test_uc();
map_test_sh(); map_test_us();
map_test_lg(); map_test_ul();
map_test_ll(); map_test_ull();
map_test_foreach_i32();
map_test_foreach_f32();
map_test_foreach_f64();
map_test_foreach_s2s();
map_test_clear_i32();
map_test_clear_f32();
map_test_clear_f64();
map_test_clear_s2s();
map_test_grow_shrink_i32();
map_test_grow_shrink_f64();
map_test_grow_s2s();
map_test_s2s();
map_test_s2i();
map_test_i2s();
map_test_d2s();
map_test_f2s();
map_test_zero_normalization();
map_test_empty_ops();
map_test_alloc_default();
map_test_tombstone_chain();
map_test_shrink_auto();
map_test_heavy_collision();
map_test_string_variations();
map_test_repeated_ops();
}
void map_test_memory_pressure(void) {
const int N = 1000 * 1000;
for (int i = 0; i < N; i++) {
map_test();
}
}
@leok7v
Copy link
Author

leok7v commented Nov 29, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment