diff options
Diffstat (limited to 'memstack/test/memstack_test.c')
-rw-r--r-- | memstack/test/memstack_test.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/memstack/test/memstack_test.c b/memstack/test/memstack_test.c new file mode 100644 index 0000000..5308be3 --- /dev/null +++ b/memstack/test/memstack_test.c | |||
@@ -0,0 +1,165 @@ | |||
1 | #include "memstack.h" | ||
2 | |||
3 | #include "test.h" | ||
4 | |||
5 | #define NUM_INTS 10 | ||
6 | #define CAPACITY (NUM_INTS * sizeof(int)) | ||
7 | |||
8 | // Create and destroy a statically-backed stack. | ||
9 | TEST_CASE(memstack_create) { | ||
10 | int memory[CAPACITY]; | ||
11 | |||
12 | memstack stack = {0}; | ||
13 | memstack_make(&stack, CAPACITY, memory); | ||
14 | memstack_del(&stack); | ||
15 | } | ||
16 | |||
17 | // Create and destroy a dynamically-backed stack. | ||
18 | TEST_CASE(mem_create_dyn) { | ||
19 | memstack stack = {0}; | ||
20 | memstack_make(&stack, CAPACITY, nullptr); | ||
21 | memstack_del(&stack); | ||
22 | } | ||
23 | |||
24 | // Allocate all N ints. | ||
25 | TEST_CASE(memstack_allocate_until_full) { | ||
26 | memstack stack = {0}; | ||
27 | memstack_make(&stack, CAPACITY, nullptr); | ||
28 | |||
29 | for (int i = 0; i < NUM_INTS; ++i) { | ||
30 | const int* block = memstack_alloc(&stack, sizeof(int)); | ||
31 | TEST_TRUE(block != nullptr); | ||
32 | } | ||
33 | |||
34 | TEST_TRUE(memstack_size(&stack) == CAPACITY); | ||
35 | |||
36 | memstack_del(&stack); | ||
37 | } | ||
38 | |||
39 | // Allocate all N ints, then free them. | ||
40 | TEST_CASE(memstack_fill_then_free) { | ||
41 | memstack stack = {0}; | ||
42 | memstack_make(&stack, CAPACITY, nullptr); | ||
43 | |||
44 | int* blocks[NUM_INTS] = {nullptr}; | ||
45 | for (int i = 0; i < NUM_INTS; ++i) { | ||
46 | blocks[i] = memstack_alloc(&stack, sizeof(int)); | ||
47 | TEST_TRUE(blocks[i] != nullptr); | ||
48 | } | ||
49 | |||
50 | memstack_clear(&stack); | ||
51 | |||
52 | TEST_EQUAL(memstack_size(&stack), 0); | ||
53 | |||
54 | memstack_del(&stack); | ||
55 | } | ||
56 | |||
57 | // Attempt to allocate blocks past the maximum stack size. | ||
58 | // The stack should handle the failed allocations gracefully. | ||
59 | TEST_CASE(memstack_allocate_beyond_max_size) { | ||
60 | memstack stack = {0}; | ||
61 | memstack_make(&stack, CAPACITY, nullptr); | ||
62 | memstack_enable_traps(&stack, false); | ||
63 | |||
64 | // Fully allocate the stack. | ||
65 | for (int i = 0; i < NUM_INTS; ++i) { | ||
66 | TEST_TRUE(memstack_alloc(&stack, sizeof(int)) != nullptr); | ||
67 | } | ||
68 | |||
69 | // Past the end. | ||
70 | for (int i = 0; i < NUM_INTS; ++i) { | ||
71 | TEST_EQUAL(memstack_alloc(&stack, sizeof(int)), nullptr); | ||
72 | } | ||
73 | |||
74 | TEST_TRUE(memstack_size(&stack) == CAPACITY); | ||
75 | |||
76 | memstack_del(&stack); | ||
77 | } | ||
78 | |||
79 | // Free blocks should always remain zeroed out. | ||
80 | // This tests the invariant right after creating the stack. | ||
81 | TEST_CASE(memstack_zero_free_blocks_after_creation) { | ||
82 | memstack stack = {0}; | ||
83 | memstack_make(&stack, CAPACITY, nullptr); | ||
84 | |||
85 | for (int i = 0; i < NUM_INTS; ++i) { | ||
86 | const int* block = memstack_alloc(&stack, sizeof(int)); | ||
87 | TEST_TRUE(block != nullptr); | ||
88 | TEST_EQUAL(*block, 0); | ||
89 | } | ||
90 | |||
91 | memstack_del(&stack); | ||
92 | } | ||
93 | |||
94 | // Free blocks should always remain zeroed out. | ||
95 | // This tests the invariant after clearing the stack and allocating a new block. | ||
96 | TEST_CASE(memstack_zero_free_block_after_free) { | ||
97 | memstack stack = {0}; | ||
98 | memstack_make(&stack, CAPACITY, nullptr); | ||
99 | |||
100 | for (int i = 0; i < NUM_INTS; ++i) { | ||
101 | const int* block = memstack_alloc(&stack, sizeof(int)); | ||
102 | TEST_TRUE(block != nullptr); | ||
103 | TEST_EQUAL(*block, 0); | ||
104 | } | ||
105 | |||
106 | memstack_clear(&stack); | ||
107 | |||
108 | for (int i = 0; i < NUM_INTS; ++i) { | ||
109 | const int* block = memstack_alloc(&stack, sizeof(int)); | ||
110 | TEST_TRUE(block != nullptr); | ||
111 | TEST_EQUAL(*block, 0); | ||
112 | } | ||
113 | |||
114 | memstack_del(&stack); | ||
115 | } | ||
116 | |||
117 | // Aligned allocations should be properly aligned. | ||
118 | TEST_CASE(memstack_alloc_aligned) { | ||
119 | memstack stack = {0}; | ||
120 | memstack_make(&stack, CAPACITY, nullptr); | ||
121 | |||
122 | // -1 because the base address of the memory storage might be unaligned. | ||
123 | for (int i = 0; i < NUM_INTS - 1; ++i) { | ||
124 | const int* block = | ||
125 | memstack_alloc_aligned(&stack, sizeof(int), alignof(int)); | ||
126 | TEST_TRUE(block != nullptr); | ||
127 | TEST_EQUAL(*block, 0); | ||
128 | TEST_EQUAL((uintptr_t)block % alignof(int), 0); | ||
129 | } | ||
130 | |||
131 | memstack_del(&stack); | ||
132 | } | ||
133 | |||
134 | // Get and set the watermark. | ||
135 | TEST_CASE(memstack_watermark) { | ||
136 | memstack stack = {0}; | ||
137 | memstack_make(&stack, CAPACITY, nullptr); | ||
138 | |||
139 | // Allocate N/2 ints. | ||
140 | for (int i = 0; i < NUM_INTS / 2; ++i) { | ||
141 | const int* block = memstack_alloc(&stack, sizeof(int)); | ||
142 | TEST_TRUE(block != nullptr); | ||
143 | } | ||
144 | |||
145 | const size_t watermark = memstack_watermark(&stack); | ||
146 | |||
147 | // Allocate the remaining N/2 ints. | ||
148 | for (int i = 0; i < NUM_INTS / 2; ++i) { | ||
149 | const int* block = memstack_alloc(&stack, sizeof(int)); | ||
150 | TEST_TRUE(block != nullptr); | ||
151 | } | ||
152 | |||
153 | // Now reset the watermark halfway through. | ||
154 | memstack_set_watermark(&stack, watermark); | ||
155 | |||
156 | // Allocate the remaining N/2 ints (again). | ||
157 | for (int i = 0; i < NUM_INTS / 2; ++i) { | ||
158 | const int* block = memstack_alloc(&stack, sizeof(int)); | ||
159 | TEST_TRUE(block != nullptr); | ||
160 | } | ||
161 | |||
162 | memstack_del(&stack); | ||
163 | } | ||
164 | |||
165 | int main() { return 0; } | ||