Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
array_list_tests.h File Reference
#include <stdio.h>
#include <serene/rt/context.h>
#include <serene/rt/impl/array_list.h>
#include "base.h"
Include dependency graph for array_list_tests.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  al_dummy

Macros

#define AL_TESTS(X)
#define AL_TEST_LOG(...)

Typedefs

typedef struct al_dummy al_dummy

Functions

static void test_al_empty ()
static void test_al_push_less_than_32 ()
static void test_al_push_more_than_32 ()
static void test_al_push_tail_to_trie_boundary ()
static void test_al_get_out_of_bounds ()
static void test_al_update ()
static void test_al_remove ()
static void test_al_remove_out_of_bounds ()
static void test_al_remove_drain_and_push ()

Macro Definition Documentation

◆ AL_TEST_LOG

#define AL_TEST_LOG ( ...)

Definition at line 41 of file array_list_tests.h.

◆ AL_TESTS

#define AL_TESTS ( X)
Value:
X("array_list::empty", test_al_empty), \
X("array_list::push_less_than_32", test_al_push_less_than_32), \
X("array_list::push_more_than_32", test_al_push_more_than_32), \
X("array_list::tail_to_trie_boundary", test_al_push_tail_to_trie_boundary), \
X("array_list::get_out_of_bounds", test_al_get_out_of_bounds), \
X("array_list::update", test_al_update), X("array_list::remove", test_al_remove), \
X("array_list::remove_out_of_bounds", test_al_remove_out_of_bounds), \
X("array_list::remove_drain_and_push", test_al_remove_drain_and_push)
static void test_al_remove()
static void test_al_get_out_of_bounds()
static void test_al_remove_drain_and_push()
static void test_al_push_more_than_32()
static void test_al_push_tail_to_trie_boundary()
static void test_al_remove_out_of_bounds()
static void test_al_update()
static void test_al_empty()
static void test_al_push_less_than_32()

Definition at line 28 of file array_list_tests.h.

28#define AL_TESTS(X) \
29 X("array_list::empty", test_al_empty), \
30 X("array_list::push_less_than_32", test_al_push_less_than_32), \
31 X("array_list::push_more_than_32", test_al_push_more_than_32), \
32 X("array_list::tail_to_trie_boundary", test_al_push_tail_to_trie_boundary), \
33 X("array_list::get_out_of_bounds", test_al_get_out_of_bounds), \
34 X("array_list::update", test_al_update), X("array_list::remove", test_al_remove), \
35 X("array_list::remove_out_of_bounds", test_al_remove_out_of_bounds), \
36 X("array_list::remove_drain_and_push", test_al_remove_drain_and_push)

Typedef Documentation

◆ al_dummy

typedef struct al_dummy al_dummy

Function Documentation

◆ test_al_empty()

void test_al_empty ( )
static

Definition at line 49 of file array_list_tests.h.

49 {
50 MAKE_ENGINE(mm, engine);
51 MAKE_CONTEXT(engine, ctx);
52
53 auto s = array_list_empty(ctx);
54
55 TEST_CHECK(s.len == 0);
56 TEST_CHECK(s.tail_len == 0);
57 TEST_CHECK(s.root == nullptr);
58 TEST_CHECK(s.maybe_error == nullptr);
59
60 RELEASE_CONTEXT(ctx);
61 SHUTDOWN_ENGINE(mm, engine);
62}
#define TEST_CHECK(cond)
Definition acutest.h:95
array_list_t array_list_empty(const srn_context_t *ctx)
Create an empty array list in the given context ctx.
Definition array_list.c:101
#define RELEASE_CONTEXT(x)
Definition base.h:48
#define SHUTDOWN_ENGINE(mm, engine)
Definition base.h:40
#define MAKE_ENGINE(mm, engine)
Definition base.h:34
#define MAKE_CONTEXT(engine, x)
Definition base.h:44
Here is the call graph for this function:

◆ test_al_get_out_of_bounds()

void test_al_get_out_of_bounds ( )
static

Definition at line 204 of file array_list_tests.h.

204 {
205 MAKE_ENGINE(mm, engine);
206 MAKE_CONTEXT(engine, ctx);
207
208 auto s = array_list_empty(ctx);
209
210 // Empty list: index 0 is already out of bounds.
211 auto empty = array_list_get(&s, 0);
212 ASSERT_NOT_NULL(empty.maybe_error);
213 TEST_CHECK(empty.maybe_error->tag == INDEX_OUT_OF_BOUND);
214 ASSERT_NULL(empty.data);
215
216 for (int i = 0; i < 40; i++) {
217 al_dummy *d = ALLOC(ctx, al_dummy);
218 d->foo = i;
219 d->bar = 3000 - i;
220 auto err = array_list_push(&s, d);
221 ASSERT_NULL(err);
222 }
223
224 // The first invalid index is exactly len.
225 auto at_len = array_list_get(&s, s.len);
226 ASSERT_NOT_NULL(at_len.maybe_error);
227 TEST_CHECK(at_len.maybe_error->tag == INDEX_OUT_OF_BOUND);
228 ASSERT_NULL(at_len.data);
229
230 // A far larger index fails the same way and exercises the message sizing path.
231 auto far = array_list_get(&s, s.len + 1000);
232 ASSERT_NOT_NULL(far.maybe_error);
233 TEST_CHECK(far.maybe_error->tag == INDEX_OUT_OF_BOUND);
234 ASSERT_NULL(far.data);
235
236 // The last valid index still succeeds.
237 auto last = array_list_get(&s, s.len - 1);
238 TEST_NO_ERROR(last);
239 ASSERT_NOT_NULL(last.data);
240 TEST_CHECK(((al_dummy *)last.data)->foo == 39);
241
242 RELEASE_CONTEXT(ctx);
243 SHUTDOWN_ENGINE(mm, engine);
244}
array_list_maybe_element_t array_list_get(const array_list_t *al, array_list_index_t n)
Negative index is not supported.
Definition array_list.c:235
srn_error_t * array_list_push(array_list_t *al, array_list_elem_t x)
Push the given element x to the end of array_list al.
Definition array_list.c:114
#define ASSERT_NOT_NULL(x)
Definition base.h:30
#define TEST_NO_ERROR(x)
Definition base.h:32
#define ASSERT_NULL(x)
Definition base.h:31
#define ALLOC(ctx, T)
Definition context.h:84
@ INDEX_OUT_OF_BOUND
Definition errors.h:91
Here is the call graph for this function:

◆ test_al_push_less_than_32()

void test_al_push_less_than_32 ( )
static

Definition at line 64 of file array_list_tests.h.

64 {
65 MAKE_ENGINE(mm, engine);
66 MAKE_CONTEXT(engine, ctx);
67
68 auto s = array_list_empty(ctx);
69
70 for (size_t i = 0; i < 31; i++) {
71 auto g = ALLOC(ctx, al_dummy);
72 g->bar = (int)i + 1;
73 g->foo = (int)i + 2;
74 auto err = array_list_push(&s, g);
75 ASSERT_NULL(err);
76
77 TEST_CHECK(s.len == i + 1);
78 TEST_CHECK(s.tail_len == i + 1);
79 TEST_CHECK(s.root == nullptr);
80 TEST_CHECK(s.maybe_error == nullptr);
81 }
82
83 for (size_t i = 0; i < 30; i++) {
84 auto res = array_list_get(&s, i);
85 TEST_NO_ERROR(res);
86 ASSERT_NOT_NULL(res.data);
87
88 al_dummy *d = res.data;
89 TEST_CHECK(d->foo == (int)(i + 2));
90 TEST_CHECK(d->bar == (int)(i + 1));
91 }
92
93 RELEASE_CONTEXT(ctx);
94 SHUTDOWN_ENGINE(mm, engine);
95}
Here is the call graph for this function:

◆ test_al_push_more_than_32()

void test_al_push_more_than_32 ( )
static

Definition at line 97 of file array_list_tests.h.

97 {
98 MAKE_ENGINE(mm, engine);
99 MAKE_CONTEXT(engine, ctx);
100
101 auto s = array_list_empty(ctx);
102
103 for (int i = 0; i < 2000; i++) {
104
105 al_dummy *d = ALLOC(ctx, al_dummy);
107 d->foo = i;
108 d->bar = 3000 - i;
109 auto err = array_list_push(&s, d);
110 ASSERT_NULL(err);
111 }
112
113 TEST_CHECK(s.len == 2000);
114 TEST_CHECK(s.tail_len == 16);
115 TEST_CHECK(s.root != nullptr);
116 TEST_CHECK(s.maybe_error == nullptr);
117
118 al_dummy *d1 = (al_dummy *)s.tail[0];
119
120 ASSERT_NOT_NULL(d1);
121 TEST_CHECK(d1->foo == 1984);
122 TEST_CHECK(d1->bar == 3000 - d1->foo);
123
124 al_dummy *d2 = (al_dummy *)s.tail[s.tail_len - 1];
125 ASSERT_NOT_NULL(d2);
126 TEST_CHECK(d2->foo == 1999);
127 TEST_CHECK(d2->bar == 3000 - d2->foo);
128
129 for (int i = 0; i < 2000; i++) {
130 auto res = array_list_get(&s, (size_t)i);
131 TEST_NO_ERROR(res);
132 ASSERT_NOT_NULL(res.data);
133
134 al_dummy *d = res.data;
135
136 // AL_TEST_LOG("%d %d %d", i, d->foo, d->bar);
137 TEST_CHECK(d->foo == i);
138 TEST_CHECK(d->bar == 3000 - i);
139 };
140
141 RELEASE_CONTEXT(ctx);
142 SHUTDOWN_ENGINE(mm, engine);
143}
Here is the call graph for this function:

◆ test_al_push_tail_to_trie_boundary()

void test_al_push_tail_to_trie_boundary ( )
static

Definition at line 148 of file array_list_tests.h.

148 {
149 MAKE_ENGINE(mm, engine);
150 MAKE_CONTEXT(engine, ctx);
151
152 auto s = array_list_empty(ctx);
153
154 // Fill the tail exactly to AL_BR. Everything still lives in the tail.
155 for (int i = 0; i < 32; i++) {
156 al_dummy *d = ALLOC(ctx, al_dummy);
157 d->foo = i;
158 d->bar = 3000 - i;
159 auto err = array_list_push(&s, d);
160 ASSERT_NULL(err);
161 }
162
163 TEST_CHECK(s.len == 32);
164 TEST_CHECK(s.tail_len == 32);
165 TEST_CHECK(s.root == nullptr);
166 TEST_CHECK(s.maybe_error == nullptr);
167
168 // One more push moves the full tail into the trie and starts a fresh tail.
169 al_dummy *d = ALLOC(ctx, al_dummy);
170 d->foo = 32;
171 d->bar = 3000 - 32;
172 auto err = array_list_push(&s, d);
173 ASSERT_NULL(err);
174
175 TEST_CHECK(s.len == 33);
176 TEST_CHECK(s.tail_len == 1);
177 TEST_CHECK(s.root != nullptr);
178 TEST_CHECK(s.depth == 0);
179 TEST_CHECK(s.maybe_error == nullptr);
180
181 // The last element of the old tail now lives in the trie, the new one in the
182 // fresh tail, and the first element is still reachable.
183 auto first = array_list_get(&s, 0);
184 TEST_NO_ERROR(first);
185 ASSERT_NOT_NULL(first.data);
186 TEST_CHECK(((al_dummy *)first.data)->foo == 0);
187
188 auto last_moved = array_list_get(&s, 31);
189 TEST_NO_ERROR(last_moved);
190 ASSERT_NOT_NULL(last_moved.data);
191 TEST_CHECK(((al_dummy *)last_moved.data)->foo == 31);
192
193 auto in_tail = array_list_get(&s, 32);
194 TEST_NO_ERROR(in_tail);
195 ASSERT_NOT_NULL(in_tail.data);
196 TEST_CHECK(((al_dummy *)in_tail.data)->foo == 32);
197
198 RELEASE_CONTEXT(ctx);
199 SHUTDOWN_ENGINE(mm, engine);
200}
Here is the call graph for this function:

◆ test_al_remove()

void test_al_remove ( )
static

Definition at line 283 of file array_list_tests.h.

283 {
284 MAKE_ENGINE(mm, engine);
285 MAKE_CONTEXT(engine, ctx);
286
287 auto s = array_list_empty(ctx);
288
289 // foo carries the logical index so a shift is visible after removal.
290 for (int i = 0; i < 100; i++) {
291 al_dummy *d = ALLOC(ctx, al_dummy);
292 d->foo = i;
293 d->bar = 3000 - i;
295 }
296
297 auto err = array_list_remove(&s, 50);
298 ASSERT_NULL(err);
299 TEST_CHECK(s.len == 99);
300
301 // Elements before the hole are untouched, everything after slid down one.
302 for (int i = 0; i < 99; i++) {
303 auto res = array_list_get(&s, (size_t)i);
304 TEST_NO_ERROR(res);
305 ASSERT_NOT_NULL(res.data);
306 int expected = i < 50 ? i : i + 1;
307 TEST_CHECK(((al_dummy *)res.data)->foo == expected);
308 }
309
310 // The old last index is now out of bounds.
311 auto gone = array_list_get(&s, 99);
312 ASSERT_NOT_NULL(gone.maybe_error);
313 TEST_CHECK(gone.maybe_error->tag == INDEX_OUT_OF_BOUND);
314
315 // Removing the final element is the pop case: no shift, just a shrink.
316 ASSERT_NULL(array_list_remove(&s, s.len - 1));
317 TEST_CHECK(s.len == 98);
318 auto last = array_list_get(&s, s.len - 1);
319 TEST_NO_ERROR(last);
320 // Index 97 held foo 98 after the first removal, and dropping the final
321 // element does not disturb it.
322 TEST_CHECK(((al_dummy *)last.data)->foo == 98);
323
324 RELEASE_CONTEXT(ctx);
325 SHUTDOWN_ENGINE(mm, engine);
326}
srn_error_t * array_list_remove(array_list_t *al, array_list_index_t n)
Remove the element at the given index n from the array list al, shifting every later element down one...
Definition array_list.c:301
Here is the call graph for this function:

◆ test_al_remove_drain_and_push()

void test_al_remove_drain_and_push ( )
static

Definition at line 359 of file array_list_tests.h.

359 {
360 MAKE_ENGINE(mm, engine);
361 MAKE_CONTEXT(engine, ctx);
362
363 auto s = array_list_empty(ctx);
364
365 for (int i = 0; i < 2000; i++) {
366 al_dummy *d = ALLOC(ctx, al_dummy);
367 d->foo = i;
369 }
370
371 // Drop the front 1990 times; the survivors are the original 1990..1999.
372 for (int i = 0; i < 1990; i++) {
374 }
375 TEST_CHECK(s.len == 10);
376
377 for (int i = 0; i < 10; i++) {
378 auto res = array_list_get(&s, (size_t)i);
379 TEST_NO_ERROR(res);
380 ASSERT_NOT_NULL(res.data);
381 TEST_CHECK(((al_dummy *)res.data)->foo == 1990 + i);
382 }
383
384 // Push a fresh batch into the shrunken trie.
385 for (int i = 0; i < 2000; i++) {
386 al_dummy *d = ALLOC(ctx, al_dummy);
387 d->foo = 10000 + i;
389 }
390 TEST_CHECK(s.len == 2010);
391
392 // The ten survivors are still first, the new batch follows in order.
393 for (int i = 0; i < 10; i++) {
394 auto res = array_list_get(&s, (size_t)i);
395 TEST_NO_ERROR(res);
396 TEST_CHECK(((al_dummy *)res.data)->foo == 1990 + i);
397 }
398 for (int i = 0; i < 2000; i++) {
399 auto res = array_list_get(&s, (size_t)(10 + i));
400 TEST_NO_ERROR(res);
401 TEST_CHECK(((al_dummy *)res.data)->foo == 10000 + i);
402 }
403
404 RELEASE_CONTEXT(ctx);
405 SHUTDOWN_ENGINE(mm, engine);
406}
Here is the call graph for this function:

◆ test_al_remove_out_of_bounds()

void test_al_remove_out_of_bounds ( )
static

Definition at line 330 of file array_list_tests.h.

330 {
331 MAKE_ENGINE(mm, engine);
332 MAKE_CONTEXT(engine, ctx);
333
334 auto s = array_list_empty(ctx);
335
336 auto empty = array_list_remove(&s, 0);
337 ASSERT_NOT_NULL(empty);
338 TEST_CHECK(empty->tag == INDEX_OUT_OF_BOUND);
339 TEST_CHECK(s.len == 0);
340
341 for (int i = 0; i < 40; i++) {
342 al_dummy *d = ALLOC(ctx, al_dummy);
343 d->foo = i;
345 }
346
347 auto at_len = array_list_remove(&s, s.len);
348 ASSERT_NOT_NULL(at_len);
349 TEST_CHECK(at_len->tag == INDEX_OUT_OF_BOUND);
350 TEST_CHECK(s.len == 40);
351
352 RELEASE_CONTEXT(ctx);
353 SHUTDOWN_ENGINE(mm, engine);
354}
Here is the call graph for this function:

◆ test_al_update()

void test_al_update ( )
static

Definition at line 246 of file array_list_tests.h.

246 {
247 MAKE_ENGINE(mm, engine);
248 MAKE_CONTEXT(engine, ctx);
249
250 auto s = array_list_empty(ctx);
251
252 al_dummy *a = ALLOC(ctx, al_dummy);
253 a->foo = 1;
254 a->bar = 1;
256
257 al_dummy *b = ALLOC(ctx, al_dummy);
258 b->foo = 2;
259 b->bar = 2;
260
261 // a and b are distinct allocations, so distinct pointers.
262 TEST_CHECK(a != b);
263
264 // Precondition: slot 0 holds `a`.
265 auto before = array_list_get(&s, 0);
266 TEST_NO_ERROR(before);
267 TEST_CHECK(before.data == a);
268
269 // Update slot 0 to point at `b`.
271
272 // Postcondition: a fresh fetch must now yield `b`, not `a`.
273 auto after = array_list_get(&s, 0);
274 TEST_NO_ERROR(after);
275 TEST_CHECK(after.data == b);
276
277 RELEASE_CONTEXT(ctx);
278 SHUTDOWN_ENGINE(mm, engine);
279}
srn_error_t * array_list_update(array_list_t *al, array_list_index_t n, array_list_elem_t x)
Update the given index n of the array list al with the new element x.
Definition array_list.c:246
Here is the call graph for this function: