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 ()
static srn_error_t * fe_all_visitor (array_list_t *al, size_t n, void *data)
static srn_error_t * fe_early_exit_visitor (array_list_t *al, size_t n, void *data)
static void test_al_for_each ()
static void test_al_for_each_early_exit ()
static void test_al_for_each_empty ()

Variables

static size_t g_fe_count
static bool g_fe_order_ok
static size_t g_fe_stop_at

Macro Definition Documentation

◆ AL_TEST_LOG

#define AL_TEST_LOG ( ...)

Definition at line 44 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), \
X("array_list::for_each", test_al_for_each), \
X("array_list::for_each_early_exit", test_al_for_each_early_exit), \
X("array_list::for_each_empty", test_al_for_each_empty)
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_for_each()
static void test_al_push_more_than_32()
static void test_al_for_each_empty()
static void test_al_push_tail_to_trie_boundary()
static void test_al_for_each_early_exit()
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), \
37 X("array_list::for_each", test_al_for_each), \
38 X("array_list::for_each_early_exit", test_al_for_each_early_exit), \
39 X("array_list::for_each_empty", test_al_for_each_empty)

Typedef Documentation

◆ al_dummy

typedef struct al_dummy al_dummy

Function Documentation

◆ fe_all_visitor()

srn_error_t * fe_all_visitor ( array_list_t * al,
size_t n,
void * data )
static

Definition at line 420 of file array_list_tests.h.

420 {
421 UNUSED(al);
422 g_fe_count++;
423
424 if (((al_dummy *)data)->foo != (int)n) {
425 g_fe_order_ok = false;
426 }
427
428 return nullptr;
429}
int n
Definition acutest.h:525
static bool g_fe_order_ok
static size_t g_fe_count
#define UNUSED(x)
Definition utils.h:45
Here is the caller graph for this function:

◆ fe_early_exit_visitor()

srn_error_t * fe_early_exit_visitor ( array_list_t * al,
size_t n,
void * data )
static

Definition at line 431 of file array_list_tests.h.

431 {
432 UNUSED(data);
433 g_fe_count++;
434
435 if (n == g_fe_stop_at) {
436 return ERR(al->ctx, INDEX_OUT_OF_BOUND, "stop");
437 }
438
439 return nullptr;
440}
static size_t g_fe_stop_at
@ INDEX_OUT_OF_BOUND
Definition errors.h:98
#define ERR(ctx, err, msg)
Definition errors.h:223
const srn_context_t * ctx
The context that owns every allocation the array list retains.
Definition array_list.h:183
Here is the caller graph for this function:

◆ test_al_empty()

void test_al_empty ( )
static

Definition at line 52 of file array_list_tests.h.

52 {
53 MAKE_ENGINE(mm, engine);
54 MAKE_CONTEXT(engine, ctx);
55
56 auto s = array_list_empty(ctx);
57
58 TEST_CHECK(s.len == 0);
59 TEST_CHECK(s.tail_len == 0);
60 TEST_CHECK(s.root == nullptr);
61 TEST_CHECK(s.maybe_error == nullptr);
62
63 RELEASE_CONTEXT(ctx);
64 SHUTDOWN_ENGINE(mm, engine);
65}
#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_for_each()

void test_al_for_each ( )
static

Definition at line 444 of file array_list_tests.h.

444 {
445 MAKE_ENGINE(mm, engine);
446 MAKE_CONTEXT(engine, ctx);
447
448 auto s = array_list_empty(ctx);
449
450 for (int i = 0; i < 100; i++) {
451 al_dummy *d = ALLOC(ctx, al_dummy);
452 d->foo = i;
453 d->bar = 3000 - i;
455 }
456
457 g_fe_count = 0;
458 g_fe_order_ok = true;
459
460 auto err = array_list_for_each(&s, fe_all_visitor);
461 ASSERT_NULL(err);
462 TEST_CHECK(g_fe_count == 100);
464
465 RELEASE_CONTEXT(ctx);
466 SHUTDOWN_ENGINE(mm, engine);
467}
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
srn_error_t * array_list_for_each(array_list_t *al, array_list_for_each_f_t f)
Run the give function f for every element in the given array list al.
Definition array_list.c:327
static srn_error_t * fe_all_visitor(array_list_t *al, size_t n, void *data)
#define ASSERT_NULL(x)
Definition base.h:31
#define ALLOC(ctx, T)
Definition context.h:95
Here is the call graph for this function:

◆ test_al_for_each_early_exit()

void test_al_for_each_early_exit ( )
static

Definition at line 471 of file array_list_tests.h.

471 {
472 MAKE_ENGINE(mm, engine);
473 MAKE_CONTEXT(engine, ctx);
474
475 auto s = array_list_empty(ctx);
476
477 for (int i = 0; i < 20; i++) {
478 al_dummy *d = ALLOC(ctx, al_dummy);
479 d->foo = i;
481 }
482
483 g_fe_count = 0;
484 g_fe_stop_at = 5;
485
487 ASSERT_NOT_NULL(err);
488 TEST_CHECK(err->tag == INDEX_OUT_OF_BOUND);
489 // The callback ran for indices 0..5 inclusive, so 6 calls total.
491
492 RELEASE_CONTEXT(ctx);
493 SHUTDOWN_ENGINE(mm, engine);
494}
static srn_error_t * fe_early_exit_visitor(array_list_t *al, size_t n, void *data)
#define ASSERT_NOT_NULL(x)
Definition base.h:30
Here is the call graph for this function:

◆ test_al_for_each_empty()

void test_al_for_each_empty ( )
static

Definition at line 497 of file array_list_tests.h.

497 {
498 MAKE_ENGINE(mm, engine);
499 MAKE_CONTEXT(engine, ctx);
500
501 auto s = array_list_empty(ctx);
502
503 g_fe_count = 0;
504
505 auto err = array_list_for_each(&s, fe_all_visitor);
506 ASSERT_NULL(err);
508
509 RELEASE_CONTEXT(ctx);
510 SHUTDOWN_ENGINE(mm, engine);
511}
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 207 of file array_list_tests.h.

207 {
208 MAKE_ENGINE(mm, engine);
209 MAKE_CONTEXT(engine, ctx);
210
211 auto s = array_list_empty(ctx);
212
213 // Empty list: index 0 is already out of bounds.
214 auto empty = array_list_get(&s, 0);
215 ASSERT_NOT_NULL(empty.maybe_error);
216 TEST_CHECK(empty.maybe_error->tag == INDEX_OUT_OF_BOUND);
217 ASSERT_NULL(empty.data);
218
219 for (int i = 0; i < 40; i++) {
220 al_dummy *d = ALLOC(ctx, al_dummy);
221 d->foo = i;
222 d->bar = 3000 - i;
223 auto err = array_list_push(&s, d);
224 ASSERT_NULL(err);
225 }
226
227 // The first invalid index is exactly len.
228 auto at_len = array_list_get(&s, s.len);
229 ASSERT_NOT_NULL(at_len.maybe_error);
230 TEST_CHECK(at_len.maybe_error->tag == INDEX_OUT_OF_BOUND);
231 ASSERT_NULL(at_len.data);
232
233 // A far larger index fails the same way and exercises the message sizing path.
234 auto far = array_list_get(&s, s.len + 1000);
235 ASSERT_NOT_NULL(far.maybe_error);
236 TEST_CHECK(far.maybe_error->tag == INDEX_OUT_OF_BOUND);
237 ASSERT_NULL(far.data);
238
239 // The last valid index still succeeds.
240 auto last = array_list_get(&s, s.len - 1);
241 TEST_NO_ERROR(last);
242 ASSERT_NOT_NULL(last.data);
243 TEST_CHECK(((al_dummy *)last.data)->foo == 39);
244
245 RELEASE_CONTEXT(ctx);
246 SHUTDOWN_ENGINE(mm, engine);
247}
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
#define TEST_NO_ERROR(x)
Definition base.h:32
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 67 of file array_list_tests.h.

67 {
68 MAKE_ENGINE(mm, engine);
69 MAKE_CONTEXT(engine, ctx);
70
71 auto s = array_list_empty(ctx);
72
73 for (size_t i = 0; i < 31; i++) {
74 auto g = ALLOC(ctx, al_dummy);
75 g->bar = (int)i + 1;
76 g->foo = (int)i + 2;
77 auto err = array_list_push(&s, g);
78 ASSERT_NULL(err);
79
80 TEST_CHECK(s.len == i + 1);
81 TEST_CHECK(s.tail_len == i + 1);
82 TEST_CHECK(s.root == nullptr);
83 TEST_CHECK(s.maybe_error == nullptr);
84 }
85
86 for (size_t i = 0; i < 30; i++) {
87 auto res = array_list_get(&s, i);
88 TEST_NO_ERROR(res);
89 ASSERT_NOT_NULL(res.data);
90
91 al_dummy *d = res.data;
92 TEST_CHECK(d->foo == (int)(i + 2));
93 TEST_CHECK(d->bar == (int)(i + 1));
94 }
95
96 RELEASE_CONTEXT(ctx);
97 SHUTDOWN_ENGINE(mm, engine);
98}
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 100 of file array_list_tests.h.

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

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

◆ test_al_remove()

void test_al_remove ( )
static

Definition at line 286 of file array_list_tests.h.

286 {
287 MAKE_ENGINE(mm, engine);
288 MAKE_CONTEXT(engine, ctx);
289
290 auto s = array_list_empty(ctx);
291
292 // foo carries the logical index so a shift is visible after removal.
293 for (int i = 0; i < 100; i++) {
294 al_dummy *d = ALLOC(ctx, al_dummy);
295 d->foo = i;
296 d->bar = 3000 - i;
298 }
299
300 auto err = array_list_remove(&s, 50);
301 ASSERT_NULL(err);
302 TEST_CHECK(s.len == 99);
303
304 // Elements before the hole are untouched, everything after slid down one.
305 for (int i = 0; i < 99; i++) {
306 auto res = array_list_get(&s, (size_t)i);
307 TEST_NO_ERROR(res);
308 ASSERT_NOT_NULL(res.data);
309 int expected = i < 50 ? i : i + 1;
310 TEST_CHECK(((al_dummy *)res.data)->foo == expected);
311 }
312
313 // The old last index is now out of bounds.
314 auto gone = array_list_get(&s, 99);
315 ASSERT_NOT_NULL(gone.maybe_error);
316 TEST_CHECK(gone.maybe_error->tag == INDEX_OUT_OF_BOUND);
317
318 // Removing the final element is the pop case: no shift, just a shrink.
319 ASSERT_NULL(array_list_remove(&s, s.len - 1));
320 TEST_CHECK(s.len == 98);
321 auto last = array_list_get(&s, s.len - 1);
322 TEST_NO_ERROR(last);
323 // Index 97 held foo 98 after the first removal, and dropping the final
324 // element does not disturb it.
325 TEST_CHECK(((al_dummy *)last.data)->foo == 98);
326
327 RELEASE_CONTEXT(ctx);
328 SHUTDOWN_ENGINE(mm, engine);
329}
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 362 of file array_list_tests.h.

362 {
363 MAKE_ENGINE(mm, engine);
364 MAKE_CONTEXT(engine, ctx);
365
366 auto s = array_list_empty(ctx);
367
368 for (int i = 0; i < 2000; i++) {
369 al_dummy *d = ALLOC(ctx, al_dummy);
370 d->foo = i;
372 }
373
374 // Drop the front 1990 times; the survivors are the original 1990..1999.
375 for (int i = 0; i < 1990; i++) {
377 }
378 TEST_CHECK(s.len == 10);
379
380 for (int i = 0; i < 10; i++) {
381 auto res = array_list_get(&s, (size_t)i);
382 TEST_NO_ERROR(res);
383 ASSERT_NOT_NULL(res.data);
384 TEST_CHECK(((al_dummy *)res.data)->foo == 1990 + i);
385 }
386
387 // Push a fresh batch into the shrunken trie.
388 for (int i = 0; i < 2000; i++) {
389 al_dummy *d = ALLOC(ctx, al_dummy);
390 d->foo = 10000 + i;
392 }
393 TEST_CHECK(s.len == 2010);
394
395 // The ten survivors are still first, the new batch follows in order.
396 for (int i = 0; i < 10; i++) {
397 auto res = array_list_get(&s, (size_t)i);
398 TEST_NO_ERROR(res);
399 TEST_CHECK(((al_dummy *)res.data)->foo == 1990 + i);
400 }
401 for (int i = 0; i < 2000; i++) {
402 auto res = array_list_get(&s, (size_t)(10 + i));
403 TEST_NO_ERROR(res);
404 TEST_CHECK(((al_dummy *)res.data)->foo == 10000 + i);
405 }
406
407 RELEASE_CONTEXT(ctx);
408 SHUTDOWN_ENGINE(mm, engine);
409}
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 333 of file array_list_tests.h.

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

◆ test_al_update()

void test_al_update ( )
static

Definition at line 249 of file array_list_tests.h.

249 {
250 MAKE_ENGINE(mm, engine);
251 MAKE_CONTEXT(engine, ctx);
252
253 auto s = array_list_empty(ctx);
254
255 al_dummy *a = ALLOC(ctx, al_dummy);
256 a->foo = 1;
257 a->bar = 1;
259
260 al_dummy *b = ALLOC(ctx, al_dummy);
261 b->foo = 2;
262 b->bar = 2;
263
264 // a and b are distinct allocations, so distinct pointers.
265 TEST_CHECK(a != b);
266
267 // Precondition: slot 0 holds `a`.
268 auto before = array_list_get(&s, 0);
269 TEST_NO_ERROR(before);
270 TEST_CHECK(before.data == a);
271
272 // Update slot 0 to point at `b`.
274
275 // Postcondition: a fresh fetch must now yield `b`, not `a`.
276 auto after = array_list_get(&s, 0);
277 TEST_NO_ERROR(after);
278 TEST_CHECK(after.data == b);
279
280 RELEASE_CONTEXT(ctx);
281 SHUTDOWN_ENGINE(mm, engine);
282}
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:

Variable Documentation

◆ g_fe_count

size_t g_fe_count
static

Definition at line 416 of file array_list_tests.h.

◆ g_fe_order_ok

bool g_fe_order_ok
static

Definition at line 417 of file array_list_tests.h.

◆ g_fe_stop_at

size_t g_fe_stop_at
static

Definition at line 418 of file array_list_tests.h.