diff options
Diffstat (limited to 'tests/test_direct.c')
| -rw-r--r-- | tests/test_direct.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/tests/test_direct.c b/tests/test_direct.c new file mode 100644 index 0000000..7f0e192 --- /dev/null +++ b/tests/test_direct.c @@ -0,0 +1,157 @@ +// Tests for direct.h - computation graph connectivity and updates +#include <stdio.h> +typedef double direct_value_t; +#define DT_IMPLEMENTATION +#include "../include/direct.h" + +#include <math.h> + +#define EPS 1e-9 + +#define ASSERT(cond, msg) \ + do { \ + if (!(cond)) { \ + fprintf(stderr, "FAIL: %s (test_direct.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_direct.c:%d)\n", \ + msg, (double)(a), (double)(b), __LINE__); \ + failures++; \ + } \ + } while (0) + +static int failures = 0; + +void test_connect() { + node_t a = {NULL, 1, 0, &dt_one}; + node_t b = {NULL, 2, 0, &dt_add}; + + ASSERT(dt_connect(&b, &a), "connect returns 1 on success"); + ASSERT(b.edge != NULL, "connect sets edge"); + if (!b.edge) { dt_clear_edges(&b); return; } + ASSERT(b.edge->node == &a, "connect sets correct node"); + + dt_clear_edges(&b); +} + +void test_disconnect() { + node_t a = {NULL, 1, 0, &dt_one}; + node_t b = {NULL, 2, 0, &dt_add}; + + dt_connect(&b, &a); + dt_disconnect(&b, &a); + ASSERT(b.edge == NULL, "disconnect removes edge"); +} + +void test_connect_ok_null() { + node_t a = {NULL, 1, 0, &dt_one}; + node_t b = {NULL, 2, 0, &dt_add}; + + ASSERT(!dt_connect_ok(NULL, &a), "connect_ok NULL to returns 0"); + ASSERT(!dt_connect_ok(&b, NULL), "connect_ok NULL from returns 0"); + ASSERT(!dt_connect_ok(NULL, NULL), "connect_ok both NULL returns 0"); +} + +void test_add() { + node_t a = {NULL, 0, 0, &dt_one}; + node_t b = {NULL, 0, 0, &dt_one}; + node_t sum = {NULL, 0, 0, &dt_add}; + + dt_connect(&sum, &a); + dt_connect(&sum, &b); + dt_update(&sum); + + ASSERT_FLOAT_EQ(a.x, 1, "dt_one sets a to 1"); + ASSERT_FLOAT_EQ(b.x, 1, "dt_one sets b to 1"); + ASSERT_FLOAT_EQ(sum.x, 2, "add sums edges: 0+1+1"); + + dt_clear_edges(&sum); +} + +void test_subtract() { + node_t a = {NULL, 0, 0, &dt_one}; + node_t b = {NULL, 0, 0, &dt_one}; + node_t c = {NULL, 0, 0, &dt_one}; + node_t diff = {NULL, 0, 0, &dt_subtract}; + + dt_connect(&diff, &a); + dt_connect(&diff, &b); + dt_connect(&diff, &c); + dt_update(&diff); + + ASSERT_FLOAT_EQ(diff.x, -3, "subtract: 0 - 1 - 1 - 1"); + + dt_clear_edges(&diff); +} + +void test_multiple_connections() { + node_t a = {NULL, 0, 0, &dt_one}; + node_t b = {NULL, 0, 0, &dt_one}; + node_t c = {NULL, 0, 0, &dt_one}; + node_t sum = {NULL, 5, 0, &dt_add}; + + dt_connect(&sum, &a); + dt_connect(&sum, &b); + dt_connect(&sum, &c); + dt_update(&sum); + + ASSERT_FLOAT_EQ(sum.x, 8, "add: 5 + 1 + 1 + 1"); + + dt_clear_edges(&sum); +} + +void test_chained_addition() { + node_t a = {NULL, 0, 0, &dt_one}; + node_t b = {NULL, 0, 0, &dt_one}; + node_t c = {NULL, 0, 0, &dt_one}; + + node_t ab = {NULL, 0, 0, &dt_add}; + dt_connect(&ab, &a); + dt_connect(&ab, &b); + + node_t abc = {NULL, 10, 0, &dt_add}; + dt_connect(&abc, &ab); + dt_connect(&abc, &c); + + dt_update(&abc); + ASSERT_FLOAT_EQ(ab.x, 2, "ab: 0+1+1=2"); + ASSERT_FLOAT_EQ(abc.x, 13, "abc: 10+2+1=13"); + + dt_clear_edges(&ab); + dt_clear_edges(&abc); +} + +void test_clear_edges() { + node_t a = {NULL, 1, 0, &dt_one}; + node_t b = {NULL, 0, 0, &dt_add}; + + dt_connect(&b, &a); + dt_clear_edges(&b); + ASSERT(b.edge == NULL, "clear_edges sets edge to NULL"); +} + +void test_single_node() { + node_t n = {NULL, 42, 0, &dt_one}; + dt_update(&n); + ASSERT_FLOAT_EQ(n.x, 1, "single node with dt_one"); +} + +int main() { + test_connect(); + test_disconnect(); + test_add(); + test_subtract(); + test_multiple_connections(); + test_chained_addition(); + test_clear_edges(); + test_single_node(); + test_connect_ok_null(); + + printf("test_direct: %d failures\n", failures); + return failures; +} |