// Tests for direct.h - computation graph connectivity and updates #include typedef double direct_value_t; #define DT_IMPLEMENTATION #include "../include/direct.h" #include #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; }