trackler 2.0.8.19 → 2.0.8.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/phone-number/canonical-data.json +2 -2
  3. data/lib/trackler/version.rb +1 -1
  4. data/tracks/c/config.json +7 -0
  5. data/tracks/c/exercises/react/makefile +16 -0
  6. data/tracks/c/exercises/react/src/example.c +185 -0
  7. data/tracks/c/exercises/react/src/react.h +29 -0
  8. data/tracks/c/exercises/react/test/test_react.c +324 -0
  9. data/tracks/c/exercises/react/test/vendor/unity.c +1300 -0
  10. data/tracks/c/exercises/react/test/vendor/unity.h +274 -0
  11. data/tracks/c/exercises/react/test/vendor/unity_internals.h +701 -0
  12. data/tracks/csharp/.travis.yml +2 -9
  13. data/tracks/csharp/appveyor.yml +3 -3
  14. data/tracks/csharp/build.cake +13 -4
  15. data/tracks/csharp/build.ps1 +56 -164
  16. data/tracks/csharp/build.sh +33 -78
  17. data/tracks/csharp/circle.yml +2 -4
  18. data/tracks/csharp/config.json +2 -1
  19. data/tracks/csharp/exercises/leap/LeapTest.cs +8 -8
  20. data/tracks/csharp/generators/CanonicalData.cs +19 -0
  21. data/tracks/csharp/generators/CanonicalDataCase.cs +24 -0
  22. data/tracks/csharp/generators/CanonicalDataCaseJsonConverter.cs +32 -0
  23. data/tracks/csharp/generators/CanonicalDataCasesJsonConverter.cs +30 -0
  24. data/tracks/csharp/generators/CanonicalDataParser.cs +28 -0
  25. data/tracks/csharp/generators/ExerciseCollection.cs +23 -0
  26. data/tracks/csharp/generators/Exercises/Exercise.cs +14 -0
  27. data/tracks/csharp/generators/Exercises/LeapExercise.cs +35 -0
  28. data/tracks/csharp/generators/Generators.csproj +12 -0
  29. data/tracks/csharp/generators/Generators.csproj.user +6 -0
  30. data/tracks/csharp/generators/Generators.sln +22 -0
  31. data/tracks/csharp/generators/Program.cs +59 -0
  32. data/tracks/csharp/generators/TestClass.cs +13 -0
  33. data/tracks/csharp/generators/TestClassRenderer.cs +36 -0
  34. data/tracks/csharp/generators/TestMethod.cs +9 -0
  35. data/tracks/csharp/generators/TestMethodNameTransformer.cs +11 -0
  36. data/tracks/csharp/generators/TestMethodRenderer.cs +18 -0
  37. data/tracks/csharp/generators/To.cs +7 -0
  38. data/tracks/csharp/generators/generate.ps1 +2 -0
  39. data/tracks/csharp/generators/generate.sh +4 -0
  40. data/tracks/delphi/config.json +8 -0
  41. data/tracks/delphi/exercises/phone-number/uPhoneNumberExample.pas +6 -6
  42. data/tracks/delphi/exercises/phone-number/uPhoneNumberTests.pas +28 -17
  43. data/tracks/delphi/exercises/roman-numerals/RomanNumerals.dpr +60 -0
  44. data/tracks/delphi/exercises/roman-numerals/uRomanNumeralsExample.pas +49 -0
  45. data/tracks/delphi/exercises/roman-numerals/uRomanNumeralsTest.pas +216 -0
  46. data/tracks/elixir/config.json +22 -0
  47. data/tracks/elixir/exercises/poker/example.exs +136 -0
  48. data/tracks/elixir/exercises/poker/poker.exs +34 -0
  49. data/tracks/elixir/exercises/poker/poker_test.exs +217 -0
  50. data/tracks/elixir/exercises/protein-translation/example.exs +62 -0
  51. data/tracks/elixir/exercises/protein-translation/protein_translation.exs +34 -0
  52. data/tracks/elixir/exercises/protein-translation/protein_translation_test.exs +87 -0
  53. data/tracks/elixir/exercises/say/example.exs +139 -0
  54. data/tracks/elixir/exercises/say/say.exs +8 -0
  55. data/tracks/elixir/exercises/say/say_test.exs +85 -0
  56. data/tracks/go/exercises/robot-name/example.go +2 -0
  57. data/tracks/go/exercises/robot-name/robot_name_test.go +9 -1
  58. data/tracks/go/exercises/roman-numerals/roman_numerals_test.go +4 -1
  59. data/tracks/go/exercises/saddle-points/saddle_points_test.go +6 -6
  60. data/tracks/php/config.json +7 -0
  61. data/tracks/php/exercises/grade-school/example.php +35 -0
  62. data/tracks/php/exercises/grade-school/grade-school_test.php +84 -0
  63. metadata +43 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a18e7d1d01de5dac14394d4c662332c16d96702
4
- data.tar.gz: ea97a61252024003df91aed43f471bed17ebd3eb
3
+ metadata.gz: eb72b896068a0db09871303423eb36d77ae12e79
4
+ data.tar.gz: b4f173c7a80ecc1a8dad8b60f163a92085a97a82
5
5
  SHA512:
6
- metadata.gz: fd8893f9ee7a77e3cd946e475be1dd3d598a3749fd167037ac5279ccdeb01e88d3caf2bdedcee4cbceb161be47705ac79d4443be9238e2faf5e39599a16213d8
7
- data.tar.gz: 13dd5a5e0552cb679fce68a2adbccb3fb588aa31ab627420cc81d4855f82fe56ed13138caa90c8965a08e6cca4f62577390117ed40cc58ca69024c0e0d063dda
6
+ metadata.gz: 36f010e19529f3ff4f39e0a8b3aa16ecbba03834b7fbc36a644e1abef9dc9e1d05e3bb17a81c3ffdecc2daeb9ed0d3c08d68387b1559cd8b3154bad7cf52a2bf
7
+ data.tar.gz: 9ebce40e4a533258b9920f11ae1354e29aeb926704bf074eb05733d13364335be3e93a993e6f8b3fd7422c131286c3a4d9d38c244ebbe5e0b4b8e8198d0838dc
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "exercise": "phone-number",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "cases": [
5
5
  {
6
6
  "description": "Cleanup user-entered phone numbers",
@@ -35,7 +35,7 @@
35
35
  "expected": null
36
36
  },
37
37
  {
38
- "description": "invalid when 11 digits",
38
+ "description": "invalid when 11 digits does not start with a 1",
39
39
  "property": "clean",
40
40
  "phrase": "21234567890",
41
41
  "expected": null
@@ -1,3 +1,3 @@
1
1
  module Trackler
2
- VERSION = "2.0.8.19"
2
+ VERSION = "2.0.8.20"
3
3
  end
data/tracks/c/config.json CHANGED
@@ -238,6 +238,13 @@
238
238
  "topics": [
239
239
  "Functions"
240
240
  ]
241
+ }, {
242
+ "difficulty": 10,
243
+ "slug": "react",
244
+ "topics": [
245
+ "memory management",
246
+ "Functions"
247
+ ]
241
248
  }],
242
249
  "deprecated": [
243
250
 
@@ -0,0 +1,16 @@
1
+ CFLAGS = -std=c99
2
+ CFLAGS += -Wall
3
+ CFLAGS += -Wextra
4
+ CFLAGS += -pedantic
5
+ CFLAGS += -Werror
6
+
7
+
8
+ test: tests.out
9
+ @./tests.out
10
+
11
+ clean:
12
+ rm -f *.o *.out
13
+
14
+ tests.out: test/test_react.c src/react.c src/react.h
15
+ @echo Compiling $@
16
+ @cc $(CFLAGS) src/react.c test/vendor/unity.c test/test_react.c -o tests.out
@@ -0,0 +1,185 @@
1
+ #include <stdlib.h>
2
+ #include "react.h"
3
+
4
+ enum cell_kind {
5
+ kind_input,
6
+ kind_compute1,
7
+ kind_compute2,
8
+ };
9
+
10
+ struct child {
11
+ struct cell *cell;
12
+ struct child *next;
13
+ };
14
+
15
+ struct cb {
16
+ callback_id id;
17
+ callback f;
18
+ void *obj;
19
+ struct cb *next;
20
+ };
21
+
22
+ struct reactor {
23
+ struct child *first;
24
+ struct child *last;
25
+ };
26
+
27
+ struct cell {
28
+ struct reactor *reactor;
29
+ int value;
30
+ enum cell_kind kind;
31
+ struct cell *input1;
32
+ struct cell *input2;
33
+ compute1 compute1;
34
+ compute2 compute2;
35
+ struct cb *cb;
36
+ int callbacks_issued;
37
+ };
38
+
39
+ struct reactor *create_reactor()
40
+ {
41
+ return calloc(1, sizeof(struct reactor));
42
+ }
43
+
44
+ void destroy_reactor(struct reactor *r)
45
+ {
46
+ struct child *child = r->first;
47
+ while (child) {
48
+ struct cb *cb = child->cell->cb;
49
+ while (cb) {
50
+ struct cb *next_cb = cb->next;
51
+ free(cb);
52
+ cb = next_cb;
53
+ }
54
+ free(child->cell);
55
+
56
+ struct child *next = child->next;
57
+ free(child);
58
+ child = next;
59
+ }
60
+ free(r);
61
+ }
62
+
63
+ static void add_child(struct reactor *r, struct cell *cell)
64
+ {
65
+ struct child *child = calloc(1, sizeof(struct child));
66
+ child->cell = cell;
67
+ if (!r->first) {
68
+ r->first = child;
69
+ } else {
70
+ r->last->next = child;
71
+ }
72
+ r->last = child;
73
+ }
74
+
75
+ struct cell *create_input_cell(struct reactor *r, int initial_value)
76
+ {
77
+ struct cell *c = calloc(1, sizeof(struct cell));
78
+ add_child(r, c);
79
+ c->reactor = r;
80
+ c->kind = kind_input;
81
+ c->value = initial_value;
82
+ return c;
83
+ }
84
+
85
+ struct cell *create_compute1_cell(struct reactor *r, struct cell *input,
86
+ compute1 compute)
87
+ {
88
+ struct cell *c = calloc(1, sizeof(struct cell));
89
+ add_child(r, c);
90
+ c->reactor = r;
91
+ c->kind = kind_compute1;
92
+ c->input1 = input;
93
+ c->compute1 = compute;
94
+ c->value = compute(get_cell_value(input));
95
+ return c;
96
+ }
97
+
98
+ struct cell *create_compute2_cell(struct reactor *r, struct cell *input1,
99
+ struct cell *input2, compute2 compute)
100
+ {
101
+ struct cell *c = calloc(1, sizeof(struct cell));
102
+ add_child(r, c);
103
+ c->reactor = r;
104
+ c->kind = kind_compute2;
105
+ c->input1 = input1;
106
+ c->input2 = input2;
107
+ c->compute2 = compute;
108
+ c->value = compute(get_cell_value(input1), get_cell_value(input2));
109
+ return c;
110
+ }
111
+
112
+ int get_cell_value(struct cell *c)
113
+ {
114
+ return c->value;
115
+ }
116
+
117
+ static void propagate(struct cell *c)
118
+ {
119
+ int new_value;
120
+ switch (c->kind) {
121
+ case kind_compute1:
122
+ new_value = c->compute1(get_cell_value(c->input1));
123
+ break;
124
+ case kind_compute2:
125
+ new_value =
126
+ c->compute2(get_cell_value(c->input1), get_cell_value(c->input2));
127
+ break;
128
+ default:
129
+ return;
130
+ }
131
+
132
+ if (new_value != c->value) {
133
+ c->value = new_value;
134
+ for (struct cb * cb = c->cb; cb; cb = cb->next) {
135
+ cb->f(cb->obj, new_value);
136
+ }
137
+ }
138
+
139
+ }
140
+
141
+ void set_cell_value(struct cell *c, int new_value)
142
+ {
143
+ c->value = new_value;
144
+ struct reactor *r = c->reactor;
145
+
146
+ // We take the very naive route of updating all cells.
147
+ // Traversing the tree and only updating the cells dependent on the just-changed cell is possible,
148
+ // but requires much more memory management to make each cell aware of its dependents.
149
+ for (struct child * child = r->first; child; child = child->next) {
150
+ propagate(child->cell);
151
+ }
152
+ }
153
+
154
+ callback_id add_callback(struct cell *c, void *obj, callback f)
155
+ {
156
+ struct cb *cb = calloc(1, sizeof(struct cb));
157
+ cb->id = c->callbacks_issued++;
158
+ cb->next = c->cb;
159
+ cb->obj = obj;
160
+ cb->f = f;
161
+ c->cb = cb;
162
+ return cb->id;
163
+ }
164
+
165
+ void remove_callback(struct cell *c, callback_id to_remove)
166
+ {
167
+ if (!c->cb) {
168
+ return;
169
+ }
170
+ // this dummy starting node reduces code duplication,
171
+ // in case the ID to remove is at the head of the list.
172
+ struct cb dummy;
173
+ dummy.next = c->cb;
174
+ for (struct cb * prev = &dummy, *cb = c->cb; cb;
175
+ prev = prev->next, cb = cb->next) {
176
+ if (cb->id == to_remove) {
177
+ if (cb == c->cb) {
178
+ c->cb = cb->next;
179
+ }
180
+ prev->next = cb->next;
181
+ free(cb);
182
+ return;
183
+ }
184
+ }
185
+ }
@@ -0,0 +1,29 @@
1
+ #ifndef REACT_H
2
+ #define REACT_H
3
+
4
+ struct reactor;
5
+ struct cell;
6
+
7
+ typedef int (*compute1) (int);
8
+ typedef int (*compute2) (int, int);
9
+
10
+ struct reactor *create_reactor();
11
+ // destroy_reactor should free all cells created under that reactor.
12
+ void destroy_reactor(struct reactor *);
13
+
14
+ struct cell *create_input_cell(struct reactor *, int initial_value);
15
+ struct cell *create_compute1_cell(struct reactor *, struct cell *, compute1);
16
+ struct cell *create_compute2_cell(struct reactor *, struct cell *,
17
+ struct cell *, compute2);
18
+
19
+ int get_cell_value(struct cell *);
20
+ void set_cell_value(struct cell *, int new_value);
21
+
22
+ typedef void (*callback) (void *, int);
23
+ typedef int callback_id;
24
+
25
+ // The callback should be called with the same void * given in add_callback.
26
+ callback_id add_callback(struct cell *, void *, callback);
27
+ void remove_callback(struct cell *, callback_id);
28
+
29
+ #endif
@@ -0,0 +1,324 @@
1
+ #include <stddef.h>
2
+ #include <stdio.h>
3
+ #include "vendor/unity.h"
4
+ #include "../src/react.h"
5
+
6
+ void test_input_cells_have_value(void)
7
+ {
8
+ struct reactor *r = create_reactor();
9
+ struct cell *input = create_input_cell(r, 2);
10
+
11
+ TEST_ASSERT_EQUAL_INT(2, get_cell_value(input));
12
+
13
+ destroy_reactor(r);
14
+ }
15
+
16
+ void test_input_cells_value_can_be_set(void)
17
+ {
18
+ struct reactor *r = create_reactor();
19
+ struct cell *input = create_input_cell(r, 4);
20
+
21
+ set_cell_value(input, 20);
22
+ TEST_ASSERT_EQUAL_INT(20, get_cell_value(input));
23
+
24
+ destroy_reactor(r);
25
+ }
26
+
27
+ static int plus1(int x)
28
+ {
29
+ return x + 1;
30
+ }
31
+
32
+ void test_compute_cells_calculate_initial_value(void)
33
+ {
34
+ struct reactor *r = create_reactor();
35
+ struct cell *input = create_input_cell(r, 1);
36
+ struct cell *output = create_compute1_cell(r, input, plus1);
37
+
38
+ TEST_ASSERT_EQUAL_INT(2, get_cell_value(output));
39
+
40
+ destroy_reactor(r);
41
+ }
42
+
43
+ static int concat_digits(int a, int b)
44
+ {
45
+ return b * 10 + a;
46
+ }
47
+
48
+ void test_compute_cells_take_inputs_in_the_right_order(void)
49
+ {
50
+ struct reactor *r = create_reactor();
51
+ struct cell *one = create_input_cell(r, 1);
52
+ struct cell *two = create_input_cell(r, 2);
53
+ struct cell *output = create_compute2_cell(r, one, two, concat_digits);
54
+
55
+ TEST_ASSERT_EQUAL_INT(21, get_cell_value(output));
56
+
57
+ destroy_reactor(r);
58
+ }
59
+
60
+ void test_compute_cells_update_value_when_dependencies_are_changed(void)
61
+ {
62
+ struct reactor *r = create_reactor();
63
+ struct cell *input = create_input_cell(r, 1);
64
+ struct cell *output = create_compute1_cell(r, input, plus1);
65
+
66
+ set_cell_value(input, 3);
67
+ TEST_ASSERT_EQUAL_INT(4, get_cell_value(output));
68
+
69
+ destroy_reactor(r);
70
+ }
71
+
72
+ static int times2(int x)
73
+ {
74
+ return x * 2;
75
+ }
76
+
77
+ static int times30(int x)
78
+ {
79
+ return x * 30;
80
+ }
81
+
82
+ static int plus(int x, int y)
83
+ {
84
+ return x + y;
85
+ }
86
+
87
+ void test_compute_cells_can_depend_on_other_compute_cells(void)
88
+ {
89
+ struct reactor *r = create_reactor();
90
+ struct cell *input = create_input_cell(r, 1);
91
+ struct cell *times_two = create_compute1_cell(r, input, times2);
92
+ struct cell *times_thirty = create_compute1_cell(r, input, times30);
93
+ struct cell *output = create_compute2_cell(r, times_two, times_thirty, plus);
94
+
95
+ TEST_ASSERT_EQUAL_INT(32, get_cell_value(output));
96
+ set_cell_value(input, 3);
97
+ TEST_ASSERT_EQUAL_INT(96, get_cell_value(output));
98
+
99
+ destroy_reactor(r);
100
+ }
101
+
102
+ struct cbinfo {
103
+ int last_value;
104
+ int times_called;
105
+ };
106
+
107
+ static void cb_spy(void *obj, int v)
108
+ {
109
+ struct cbinfo *cbinfo = (struct cbinfo *)obj;
110
+ cbinfo->last_value = v;
111
+ ++cbinfo->times_called;
112
+ }
113
+
114
+ void test_compute_cells_fire_callbacks(void)
115
+ {
116
+ struct reactor *r = create_reactor();
117
+ struct cell *input = create_input_cell(r, 1);
118
+ struct cell *output = create_compute1_cell(r, input, plus1);
119
+
120
+ struct cbinfo cbinfo = { -1, 0 };
121
+ add_callback(output, &cbinfo, cb_spy);
122
+
123
+ set_cell_value(input, 3);
124
+ TEST_ASSERT_EQUAL_INT(1, cbinfo.times_called);
125
+ TEST_ASSERT_EQUAL_INT(4, cbinfo.last_value);
126
+
127
+ destroy_reactor(r);
128
+ }
129
+
130
+ static void cb_noop(void *obj, int v)
131
+ {
132
+ (void)obj;
133
+ (void)v;
134
+ }
135
+
136
+ void test_compute_cells_dont_access_callback_obj(void)
137
+ {
138
+ struct reactor *r = create_reactor();
139
+ struct cell *input = create_input_cell(r, 1);
140
+ struct cell *output = create_compute1_cell(r, input, plus1);
141
+
142
+ add_callback(output, NULL, cb_noop);
143
+
144
+ set_cell_value(input, 3);
145
+
146
+ destroy_reactor(r);
147
+ }
148
+
149
+ static int big_if_three(int x)
150
+ {
151
+ return x < 3 ? 111 : 222;
152
+ }
153
+
154
+ void test_callbacks_only_fire_on_change(void)
155
+ {
156
+ struct reactor *r = create_reactor();
157
+ struct cell *input = create_input_cell(r, 1);
158
+ struct cell *output = create_compute1_cell(r, input, big_if_three);
159
+
160
+ struct cbinfo cbinfo = { -1, 0 };
161
+ add_callback(output, &cbinfo, cb_spy);
162
+
163
+ set_cell_value(input, 2);
164
+ TEST_ASSERT_EQUAL_INT(0, cbinfo.times_called);
165
+
166
+ set_cell_value(input, 4);
167
+ TEST_ASSERT_EQUAL_INT(1, cbinfo.times_called);
168
+ TEST_ASSERT_EQUAL_INT(222, cbinfo.last_value);
169
+
170
+ destroy_reactor(r);
171
+ }
172
+
173
+ void test_callbacks_can_be_added_and_removed(void)
174
+ {
175
+ struct reactor *r = create_reactor();
176
+ struct cell *input = create_input_cell(r, 11);
177
+ struct cell *output = create_compute1_cell(r, input, plus1);
178
+
179
+ struct cbinfo cbinfo1 = { -1, 0 };
180
+ callback_id cb1 = add_callback(output, &cbinfo1, cb_spy);
181
+ struct cbinfo cbinfo2 = { -1, 0 };
182
+ add_callback(output, &cbinfo2, cb_spy);
183
+
184
+ set_cell_value(input, 31);
185
+
186
+ remove_callback(output, cb1);
187
+ struct cbinfo cbinfo3 = { -1, 0 };
188
+ add_callback(output, &cbinfo3, cb_spy);
189
+
190
+ set_cell_value(input, 41);
191
+
192
+ TEST_ASSERT_EQUAL_INT(1, cbinfo1.times_called);
193
+ TEST_ASSERT_EQUAL_INT(32, cbinfo1.last_value);
194
+ TEST_ASSERT_EQUAL_INT(2, cbinfo2.times_called);
195
+ TEST_ASSERT_EQUAL_INT(42, cbinfo2.last_value);
196
+ TEST_ASSERT_EQUAL_INT(1, cbinfo3.times_called);
197
+ TEST_ASSERT_EQUAL_INT(42, cbinfo3.last_value);
198
+
199
+ destroy_reactor(r);
200
+ }
201
+
202
+ void test_removing_most_recent_callback(void)
203
+ {
204
+ struct reactor *r = create_reactor();
205
+ struct cell *input = create_input_cell(r, 11);
206
+ struct cell *output = create_compute1_cell(r, input, plus1);
207
+
208
+ struct cbinfo cbinfo1 = { -1, 0 };
209
+ add_callback(output, &cbinfo1, cb_spy);
210
+ struct cbinfo cbinfo2 = { -1, 0 };
211
+ callback_id cb2 = add_callback(output, &cbinfo2, cb_spy);
212
+ remove_callback(output, cb2);
213
+
214
+ set_cell_value(input, 31);
215
+
216
+ TEST_ASSERT_EQUAL_INT(1, cbinfo1.times_called);
217
+ TEST_ASSERT_EQUAL_INT(32, cbinfo1.last_value);
218
+ TEST_ASSERT_EQUAL_INT(0, cbinfo2.times_called);
219
+
220
+ destroy_reactor(r);
221
+ }
222
+
223
+ void test_removing_a_callback_multiple_times(void)
224
+ {
225
+ struct reactor *r = create_reactor();
226
+ struct cell *input = create_input_cell(r, 11);
227
+ struct cell *output = create_compute1_cell(r, input, plus1);
228
+
229
+ struct cbinfo cbinfo1 = { -1, 0 };
230
+ callback_id cb1 = add_callback(output, &cbinfo1, cb_spy);
231
+ struct cbinfo cbinfo2 = { -1, 0 };
232
+ add_callback(output, &cbinfo2, cb_spy);
233
+ for (int i = 0; i < 10; ++i) {
234
+ remove_callback(output, cb1);
235
+ }
236
+
237
+ set_cell_value(input, 2);
238
+
239
+ TEST_ASSERT_EQUAL_INT(0, cbinfo1.times_called);
240
+ TEST_ASSERT_EQUAL_INT(1, cbinfo2.times_called);
241
+ TEST_ASSERT_EQUAL_INT(3, cbinfo2.last_value);
242
+
243
+ destroy_reactor(r);
244
+ }
245
+
246
+ static int minus1(int x)
247
+ {
248
+ return x - 1;
249
+ }
250
+
251
+ static int times(int x, int y)
252
+ {
253
+ return x * y;
254
+ }
255
+
256
+ void test_callbacks_only_called_once_even_if_multiple_inputs_change(void)
257
+ {
258
+ struct reactor *r = create_reactor();
259
+ struct cell *input = create_input_cell(r, 1);
260
+ struct cell *plus_one = create_compute1_cell(r, input, plus1);
261
+ struct cell *minus_one1 = create_compute1_cell(r, input, minus1);
262
+ struct cell *minus_one2 = create_compute1_cell(r, minus_one1, minus1);
263
+ struct cell *output = create_compute2_cell(r, plus_one, minus_one2, times);
264
+
265
+ struct cbinfo cbinfo = { -1, 0 };
266
+ add_callback(output, &cbinfo, cb_spy);
267
+
268
+ set_cell_value(input, 4);
269
+
270
+ TEST_ASSERT_EQUAL_INT(1, cbinfo.times_called);
271
+ TEST_ASSERT_EQUAL_INT(10, cbinfo.last_value);
272
+
273
+ destroy_reactor(r);
274
+ }
275
+
276
+ static int minus(int x, int y)
277
+ {
278
+ return x - y;
279
+ }
280
+
281
+ void test_callbacks_not_called_if_inputs_change_but_output_doesnt(void)
282
+ {
283
+ struct reactor *r = create_reactor();
284
+ struct cell *input = create_input_cell(r, 1);
285
+ struct cell *plus_one = create_compute1_cell(r, input, plus1);
286
+ struct cell *minus_one = create_compute1_cell(r, input, minus1);
287
+ struct cell *always_two =
288
+ create_compute2_cell(r, plus_one, minus_one, minus);
289
+
290
+ struct cbinfo cbinfo = { -1, 0 };
291
+ add_callback(always_two, &cbinfo, cb_spy);
292
+
293
+ for (int i = 0; i < 10; ++i) {
294
+ set_cell_value(input, i);
295
+ }
296
+
297
+ TEST_ASSERT_EQUAL_INT(0, cbinfo.times_called);
298
+
299
+ destroy_reactor(r);
300
+ }
301
+
302
+ int main(void)
303
+ {
304
+ UnityBegin("test/test_react.c");
305
+
306
+ RUN_TEST(test_input_cells_have_value);
307
+ RUN_TEST(test_input_cells_value_can_be_set);
308
+ RUN_TEST(test_compute_cells_calculate_initial_value);
309
+ RUN_TEST(test_compute_cells_take_inputs_in_the_right_order);
310
+ RUN_TEST(test_compute_cells_update_value_when_dependencies_are_changed);
311
+ RUN_TEST(test_compute_cells_can_depend_on_other_compute_cells);
312
+ RUN_TEST(test_compute_cells_fire_callbacks);
313
+ RUN_TEST(test_compute_cells_dont_access_callback_obj);
314
+ RUN_TEST(test_callbacks_only_fire_on_change);
315
+ RUN_TEST(test_callbacks_can_be_added_and_removed);
316
+ RUN_TEST(test_removing_most_recent_callback);
317
+ RUN_TEST(test_removing_a_callback_multiple_times);
318
+ RUN_TEST(test_callbacks_only_called_once_even_if_multiple_inputs_change);
319
+ RUN_TEST(test_callbacks_not_called_if_inputs_change_but_output_doesnt);
320
+
321
+ UnityEnd();
322
+
323
+ return 0;
324
+ }