1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
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;
}
|