summaryrefslogtreecommitdiffstats
path: root/tests/test_stack.c
diff options
context:
space:
mode:
authorEthan Werner <mail@ethanwerner.com>2026-09-19 06:09:54 +0000
committerEthan Werner <mail@ethanwerner.com>2026-09-19 06:09:54 +0000
commitbf19b9938508f70011395f4dc283ca758ec6a8d3 (patch)
tree46dc4c442ed8d8d43040433c6a4794e76f8e618a /tests/test_stack.c
parent96ecf29e8be977f51f351308ef2c7c492bb829aa (diff)
llm toolingHEADmaster
Diffstat (limited to 'tests/test_stack.c')
-rw-r--r--tests/test_stack.c234
1 files changed, 234 insertions, 0 deletions
diff --git a/tests/test_stack.c b/tests/test_stack.c
new file mode 100644
index 0000000..8fc19a3
--- /dev/null
+++ b/tests/test_stack.c
@@ -0,0 +1,234 @@
+// Tests for stack.h - stack push, pop, peek, and resizing operations
+#include <math.h>
+#include <stdio.h>
+
+typedef double stack_value_t;
+
+#define STACK_IMPLEMENTATION
+#include "../include/stack.h"
+
+#define EPS 1e-9
+
+#define ASSERT(cond, msg) \
+ do { \
+ if (!(cond)) { \
+ fprintf(stderr, "FAIL: %s (test_stack.c:%d)\n", msg, __LINE__); \
+ failures++; \
+ } \
+ } while (0)
+
+#define ASSERT_FLOAT_EQ(a, b, msg) \
+ do { \
+ if (fabs((a) - (b)) > EPS) { \
+ fprintf(stderr, "FAIL: %s (got %f, expected %f) (test_stack.c:%d)\n", \
+ msg, (double)(a), (double)(b), __LINE__); \
+ failures++; \
+ } \
+ } while (0)
+
+static int failures = 0;
+
+void test_init_and_free() {
+ stack_t s = {.capacity = 10};
+ stack_init(&s);
+ ASSERT(s.size == 0, "init size should be 0");
+ ASSERT(s.capacity == 10, "init capacity should be 10");
+ ASSERT(s.data != NULL, "init data should not be NULL");
+ stack_free(&s);
+}
+
+void test_default_capacity() {
+ stack_t s = {0};
+ stack_init(&s);
+ ASSERT(s.capacity == 16, "default capacity should be 16");
+ stack_free(&s);
+}
+
+void test_push_pop() {
+ stack_t s = {0};
+ stack_init(&s);
+
+ for (int i = 0; i < 5; i++) {
+ stack_push(&s, (stack_value_t)(i * 10));
+ }
+
+ ASSERT(s.size == 5, "size after 5 pushes");
+ ASSERT_FLOAT_EQ(stack_pop(&s), 40, "pop last pushed");
+ ASSERT_FLOAT_EQ(stack_pop(&s), 30, "pop second last");
+ ASSERT(s.size == 3, "size after 2 pops");
+
+ stack_free(&s);
+}
+
+void test_peek() {
+ stack_t s = {0};
+ stack_init(&s);
+ stack_push(&s, 42);
+
+ ASSERT_FLOAT_EQ(stack_peek(&s), 42, "peek returns top");
+ ASSERT(s.size == 1, "peek does not change size");
+
+ stack_free(&s);
+}
+
+void test_peek_empty() {
+ stack_t s = {0};
+ stack_init(&s);
+ ASSERT_FLOAT_EQ(stack_peek(&s), 0, "peek empty returns ZERO");
+ stack_free(&s);
+}
+
+void test_pop_empty() {
+ stack_t s = {0};
+ stack_init(&s);
+ ASSERT_FLOAT_EQ(stack_pop(&s), 0, "pop empty returns ZERO");
+ stack_free(&s);
+}
+
+void test_grow() {
+ stack_t s = {.capacity = 2};
+ stack_init(&s);
+
+ for (int i = 0; i < 10; i++) {
+ stack_push(&s, (stack_value_t)i);
+ }
+
+ ASSERT(s.size == 10, "size after growing");
+ ASSERT(s.capacity >= 10, "capacity grew");
+
+ for (int i = 9; i >= 0; i--) {
+ ASSERT_FLOAT_EQ(stack_pop(&s), (stack_value_t)i, "values preserved after grow");
+ }
+
+ stack_free(&s);
+}
+
+void test_clear() {
+ stack_t s = {0};
+ stack_init(&s);
+ stack_push(&s, 1);
+ stack_push(&s, 2);
+ stack_push(&s, 3);
+
+ stack_clear(&s);
+ ASSERT_FLOAT_EQ(s.data[0], 0, "clear zeroed data[0]");
+ ASSERT_FLOAT_EQ(s.data[1], 0, "clear zeroed data[1]");
+ ASSERT_FLOAT_EQ(s.data[2], 0, "clear zeroed data[2]");
+
+ stack_free(&s);
+}
+
+void test_from_array() {
+ stack_value_t arr[] = {1, 2, 3, 4, 5};
+ stack_t s = {0};
+ stack_from_array(&s, arr, 5);
+
+ ASSERT(s.size == 5, "from_array size");
+ ASSERT(s.capacity == 5, "from_array capacity");
+
+ for (int i = 4; i >= 0; i--) {
+ ASSERT_FLOAT_EQ(stack_pop(&s), (stack_value_t)(i + 1), "from_array values");
+ }
+
+ stack_free(&s);
+}
+
+void test_empty() {
+ stack_t s = {0};
+ stack_init(&s);
+ ASSERT(stack_empty(&s) == 1, "empty stack returns true");
+ stack_push(&s, 42);
+ ASSERT(stack_empty(&s) == 0, "non-empty stack returns false");
+ stack_free(&s);
+}
+
+void test_from_array_single() {
+ stack_value_t arr[] = {42};
+ stack_t s = {0};
+ stack_from_array(&s, arr, 1);
+
+ ASSERT(s.size == 1, "from_array single size");
+ ASSERT(s.capacity == 1, "from_array single capacity");
+ ASSERT_FLOAT_EQ(stack_pop(&s), 42, "from_array single value");
+
+ stack_free(&s);
+}
+
+void test_multiple_free() {
+ stack_t s = {0};
+ stack_init(&s);
+ stack_free(&s);
+ ASSERT(s.data == NULL, "data is NULL after free");
+ ASSERT(s.size == 0, "size is 0 after free");
+ ASSERT(s.capacity == 0, "capacity is 0 after free");
+ stack_free(&s);
+ ASSERT(s.data == NULL, "second free is safe");
+}
+
+void test_pop_ok() {
+ stack_t s = {0};
+ stack_init(&s);
+
+ stack_value_t out = 0;
+ ASSERT(!stack_pop_ok(&s, &out), "pop_ok on empty returns 0");
+
+ stack_push(&s, 42);
+ ASSERT(stack_pop_ok(&s, &out), "pop_ok on non-empty returns 1");
+ ASSERT_FLOAT_EQ(out, 42, "pop_ok value");
+ ASSERT(s.size == 0, "pop_ok decrements size");
+
+ stack_free(&s);
+}
+
+void test_peek_ok() {
+ stack_t s = {0};
+ stack_init(&s);
+
+ stack_value_t out = 0;
+ ASSERT(!stack_peek_ok(&s, &out), "peek_ok on empty returns 0");
+
+ stack_push(&s, 99);
+ ASSERT(stack_peek_ok(&s, &out), "peek_ok on non-empty returns 1");
+ ASSERT_FLOAT_EQ(out, 99, "peek_ok value");
+ ASSERT(s.size == 1, "peek_ok does not change size");
+
+ stack_free(&s);
+}
+
+void test_pop_ok_null_out() {
+ stack_t s = {0};
+ stack_init(&s);
+ stack_push(&s, 1);
+ ASSERT(!stack_pop_ok(&s, NULL), "pop_ok with NULL out returns 0");
+ stack_free(&s);
+}
+
+void test_peek_ok_null_out() {
+ stack_t s = {0};
+ stack_init(&s);
+ stack_push(&s, 1);
+ ASSERT(!stack_peek_ok(&s, NULL), "peek_ok with NULL out returns 0");
+ stack_free(&s);
+}
+
+int main() {
+ test_init_and_free();
+ test_default_capacity();
+ test_push_pop();
+ test_peek();
+ test_peek_empty();
+ test_pop_empty();
+ test_pop_ok();
+ test_peek_ok();
+ test_pop_ok_null_out();
+ test_peek_ok_null_out();
+ test_grow();
+ test_clear();
+ test_from_array();
+ test_from_array_single();
+ test_empty();
+ test_multiple_free();
+
+ printf("test_stack: %d failures\n", failures);
+ return failures;
+}