#ifndef SAND_UNIT_ALLOCATOR_UTILS_H #define SAND_UNIT_ALLOCATOR_UTILS_H // This module defines some tests for running against allocators. #include "../core/allocator.h" #include "greatest.h" inline TEST test_allocator_basic_usage(SandAllocator *a) { size_t count = 100; int *ptr = sand_allocate(a, sizeof(int) * count); ASSERT_NEQm("Small allocation should not fail", ptr, NULL); // Unit tests are run under address sanitizer, so this should catch when // returned memory isn't actually writable. for (size_t i = 0; i < count; ++i) { ptr[i] = 123; } // FIXME: I don't really know how to test this. sand_deallocate(a, ptr, sizeof(int) * count); PASS(); } inline TEST test_allocator_reallocation(SandAllocator *a) { size_t count = 50; int *ptr = sand_allocate(a, sizeof(int) * count); ASSERT_NEQm("Small allocation should not fail", ptr, NULL); for (size_t i = 0; i < count; ++i) { ptr[i] = 123; } size_t new_count = 100; int *new_ptr = sand_reallocate(a, ptr, sizeof(int) * count, sizeof(int) * new_count); ASSERT_NEQm("Small reallocation should not fail", new_ptr, NULL); for (size_t i = 0; i < count; ++i) { ASSERT_EQm("Reallocated memory is copied over", new_ptr[i], 123); } // Just like `test_std_allocator_basic_usage` this should // ensure newly allocated memory is reallocated. for (size_t i = count; i < new_count; ++i) { new_ptr[i] = 456; } sand_deallocate(a, new_ptr, sizeof(int) * new_count); PASS(); } inline TEST test_allocator_weird_alignments(SandAllocator *a) { size_t alignments[] = {2,4,8,16,32,64,128,256,1024}; for (unsigned i = 0; i < sizeof(alignments)/sizeof((alignments)[0]); ++i) { int *allocation = sand_allocate_aligned(a, sizeof(*allocation), alignments[i]); *allocation = 123; // ASAN will crash us if invalid memory is returned. sand_deallocate(a, allocation, sizeof(*allocation)); } PASS(); } inline TEST test_allocator_unreasonably_large_allocation_fails_gracefully(SandAllocator *a) { #if defined(__has_feature) # if __has_feature(address_sanitizer) SKIPm("Test does not work under address_sanitizer"); # endif #endif // Compute a request size which is very unlikely to be available. // kibi mebi gibi tebi -byte size_t size = (size_t)1024 * 1024 * 1024 * 1024; void *result = sand_allocate(a, size); ASSERT_EQm("Allocation should fail", result, NULL); PASS(); } #define RUN_ALLOCATOR_TESTS(DO) \ DO(test_allocator_basic_usage) \ DO(test_allocator_reallocation) \ DO(test_allocator_weird_alignments) \ DO(test_allocator_unreasonably_large_allocation_fails_gracefully) #endif