#include "memstack.h" #include "test.h" #define NUM_INTS 10 #define CAPACITY (NUM_INTS * sizeof(int)) // Create and destroy a statically-backed stack. TEST_CASE(memstack_create) { int memory[CAPACITY]; memstack stack = {0}; memstack_make(&stack, CAPACITY, memory); memstack_del(&stack); } // Create and destroy a dynamically-backed stack. TEST_CASE(mem_create_dyn) { memstack stack = {0}; memstack_make(&stack, CAPACITY, nullptr); memstack_del(&stack); } // Allocate all N ints. TEST_CASE(memstack_allocate_until_full) { memstack stack = {0}; memstack_make(&stack, CAPACITY, nullptr); for (int i = 0; i < NUM_INTS; ++i) { const int* block = memstack_alloc(&stack, sizeof(int)); TEST_TRUE(block != nullptr); } TEST_TRUE(memstack_size(&stack) == CAPACITY); } // Allocate all N ints, then free them. TEST_CASE(memstack_fill_then_free) { memstack stack = {0}; memstack_make(&stack, CAPACITY, nullptr); int* blocks[NUM_INTS] = {nullptr}; for (int i = 0; i < NUM_INTS; ++i) { blocks[i] = memstack_alloc(&stack, sizeof(int)); TEST_TRUE(blocks[i] != nullptr); } memstack_clear(&stack); TEST_EQUAL(memstack_size(&stack), 0); } // Attempt to allocate blocks past the maximum stack size. // The stack should handle the failed allocations gracefully. TEST_CASE(memstack_allocate_beyond_max_size) { memstack stack = {0}; memstack_make(&stack, CAPACITY, nullptr); memstack_enable_traps(&stack, false); // Fully allocate the stack. for (int i = 0; i < NUM_INTS; ++i) { TEST_TRUE(memstack_alloc(&stack, sizeof(int)) != nullptr); } // Past the end. for (int i = 0; i < NUM_INTS; ++i) { TEST_EQUAL(memstack_alloc(&stack, sizeof(int)), nullptr); } TEST_TRUE(memstack_size(&stack) == CAPACITY); } // Free blocks should always remain zeroed out. // This tests the invariant right after creating the stack. TEST_CASE(memstack_zero_free_blocks_after_creation) { memstack stack = {0}; memstack_make(&stack, CAPACITY, nullptr); for (int i = 0; i < NUM_INTS; ++i) { const int* block = memstack_alloc(&stack, sizeof(int)); TEST_TRUE(block != nullptr); TEST_EQUAL(*block, 0); } } // Free blocks should always remain zeroed out. // This tests the invariant after clearing the stack and allocating a new block. TEST_CASE(memstack_zero_free_block_after_free) { memstack stack = {0}; memstack_make(&stack, CAPACITY, nullptr); for (int i = 0; i < NUM_INTS; ++i) { const int* block = memstack_alloc(&stack, sizeof(int)); TEST_TRUE(block != nullptr); TEST_EQUAL(*block, 0); } memstack_clear(&stack); for (int i = 0; i < NUM_INTS; ++i) { const int* block = memstack_alloc(&stack, sizeof(int)); TEST_TRUE(block != nullptr); TEST_EQUAL(*block, 0); } } int main() { return 0; }