game/axl_memory_test.c

212 lines
5.2 KiB
C

/*
* axl_memory_tests.c — Comprehensive unit tests for axl_memory.h
*/
#include "axl_memory.h"
#include "axl_koan.h"
#include <string.h>
/* ------------------------------------------------------------------ */
/* Basic allocation & initialization */
/* ------------------------------------------------------------------ */
KOAN(init_called)
{
void* p = axl_malloc(1);
ASSERT_NOT_NULL(p);
axl_free(p);
}
KOAN(malloc_returns_different_pointers)
{
void* a = axl_malloc(16);
void* b = axl_malloc(32);
ASSERT_NOT_NULL(a);
ASSERT_NOT_NULL(b);
ASSERT_TRUE(a != b);
axl_free(a);
axl_free(b);
}
KOAN(malloc_exhaustion_returns_null)
{
void* p = axl_malloc(AXL_HEAP_SIZE + 4096); /* definitely too big */
ASSERT_NULL(p);
}
/* ------------------------------------------------------------------ */
/* Realloc behavior (strictly per C standard) */
/* ------------------------------------------------------------------ */
KOAN(realloc_null_acts_like_malloc)
{
void* p = axl_realloc(NULL, 64);
ASSERT_NOT_NULL(p);
axl_memset(p, 0x55, 64);
axl_free(p);
}
KOAN(realloc_zero_size_frees_and_returns_null_or_valid)
{
void* p = axl_malloc(100);
ASSERT_NOT_NULL(p);
void* q = axl_realloc(p, 0);
if (q != NULL) axl_free(q);
/* Original p is freed regardless */
}
KOAN(realloc_enlarge_preserves_content)
{
void* p = axl_malloc(32);
axl_memset(p, 0xCD, 32);
void* q = axl_realloc(p, 128);
ASSERT_NOT_NULL(q);
for (int i = 0; i < 32; i++)
ASSERT_INT_EQ(0xCD, ((u8*)q)[i]);
axl_free(q);
}
KOAN(realloc_shrink_preserves_prefix)
{
void* p = axl_malloc(256);
axl_memset(p, 0xAB, 256);
void* q = axl_realloc(p, 64);
ASSERT_NOT_NULL(q);
for (int i = 0; i < 64; i++)
ASSERT_INT_EQ(0xAB, ((u8*)q)[i]);
axl_free(q);
}
KOAN(realloc_same_size_returns_same_or_equivalent)
{
void* p = axl_malloc(100);
p = axl_realloc(p, 100);
ASSERT_NOT_NULL(p);
/* May return same or different pointer */
axl_free(p);
}
/* ------------------------------------------------------------------ */
/* Memory operations */
/* ------------------------------------------------------------------ */
KOAN(memset_fills_correctly)
{
void* p = axl_malloc(64);
axl_memset(p, 0x55, 64);
for (int i = 0; i < 64; i++)
ASSERT_INT_EQ(0x55, ((u8*)p)[i]);
axl_free(p);
}
KOAN(memset_zero_bytes_is_nop)
{
void* p = axl_malloc(16);
axl_memset(p, 0xFF, 16);
axl_memset(p, 0x00, 0); /* should not change anything */
for (int i = 0; i < 16; i++)
ASSERT_INT_EQ(0xFF, ((u8*)p)[i]);
axl_free(p);
}
KOAN(memcpy_copies_exact_bytes)
{
u8 src[32];
for (int i = 0; i < 32; i++) src[i] = (u8)i;
void* dst = axl_malloc(32);
axl_memcpy(dst, src, 32);
ASSERT_INT_EQ(0, memcmp(dst, src, 32));
axl_free(dst);
}
KOAN(memcpy_zero_bytes_is_nop)
{
u8 data[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
void* p = axl_malloc(16);
axl_memcpy(p, data, 16);
axl_memcpy(p, "junk", 0); /* must not modify */
ASSERT_INT_EQ(0, memcmp(p, data, 16));
axl_free(p);
}
KOAN(memcmp_returns_correct_sign)
{
u8 a[] = {0, 0, 0, 0};
u8 b[] = {0, 0, 0, 1};
u8 c[] = {0, 0, 1, 0};
ASSERT_INT_EQ(0, axl_memcmp(a, a, 4));
ASSERT_TRUE(axl_memcmp(a, b, 4) < 0);
ASSERT_TRUE(axl_memcmp(b, a, 4) > 0);
ASSERT_TRUE(axl_memcmp(a, c, 3) < 0 );
ASSERT_TRUE(axl_memcmp(a, b, 2) == 0);
ASSERT_TRUE(axl_memcmp(a, c, 2) == 0);
ASSERT_TRUE(axl_memcmp(c, b, 2) == 0);
ASSERT_TRUE(axl_memcmp(a, c, 4) < 0);
}
KOAN(memcmp_zero_length_returns_zero)
{
u8 x = 0xFF, y = 0x00;
ASSERT_INT_EQ(0, axl_memcmp(&x, &y, 0));
}
/* ------------------------------------------------------------------ */
/* Double-free and use-after-free detection (indirect) */
/* ------------------------------------------------------------------ */
KOAN(double_free_does_not_crash)
{
void* p = axl_malloc(64);
ASSERT_NOT_NULL(p);
axl_free(p);
axl_free(p); /* should be ignored or handled safely */
}
/* ------------------------------------------------------------------ */
/* Large and boundary allocations */
/* ------------------------------------------------------------------ */
KOAN(large_allocation_near_heap_limit)
{
/* Allocate almost entire heap */
void* p = axl_malloc(AXL_HEAP_SIZE - 1024);
ASSERT_NOT_NULL(p); /* may pass if overhead is small */
if (p) axl_free(p);
}
KOAN(allocation_of_max_size_fails)
{
void* p = axl_malloc(AXL_HEAP_SIZE);
ASSERT_NULL(p);
}
/* ------------------------------------------------------------------ */
/* Stress: many small allocations */
/* ------------------------------------------------------------------ */
KOAN(many_small_allocations)
{
#define N 1000
void* ptrs[N];
for (int i = 0; i < N; i++) {
ptrs[i] = axl_malloc(16);
ASSERT_NOT_NULL(ptrs[i]);
*(u32*)ptrs[i] = 0xDEADBEEF;
}
for (int i = 0; i < N; i++) {
ASSERT_INT_EQ(0xDEADBEEF, *(u32*)ptrs[i]);
axl_free(ptrs[i]);
}
}
/* ------------------------------------------------------------------ */
/* Main */
/* ------------------------------------------------------------------ */
int main(void)
{
axl_init();
return koan_run_all();
}