Skip to content

Commit 330f7d3

Browse files
authored
Merge 664236c into ccc6f0f
2 parents ccc6f0f + 664236c commit 330f7d3

File tree

1 file changed

+108
-78
lines changed

1 file changed

+108
-78
lines changed

exercises/react/tests/react.rs

Lines changed: 108 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -99,20 +99,49 @@ fn error_setting_a_compute_cell() {
9999
assert!(reactor.set_value(output, 3).is_err());
100100
}
101101

102+
/// A CallbackRecorder helps tests whether callbacks get called correctly.
103+
/// You'll see it used in tests that deal with callbacks.
104+
/// The names should be descriptive enough so that the tests make sense,
105+
/// so it's not necessary to fully understand the implementation,
106+
/// though you are welcome to.
107+
struct CallbackRecorder {
108+
// Note that this `Cell` is https://doc.rust-lang.org/std/cell/
109+
// a mechanism to allow internal mutability,
110+
// distinct from the cells (input cells, compute cells) in the reactor
111+
value: std::cell::Cell<Option<isize>>,
112+
}
113+
114+
impl CallbackRecorder {
115+
fn new() -> Self {
116+
CallbackRecorder {
117+
value: std::cell::Cell::new(None),
118+
}
119+
}
120+
121+
fn expect_to_have_been_called_with(&self, v: isize) {
122+
assert_ne!(self.value.get(), None, "Callback was not called, but should have been");
123+
assert_eq!(self.value.replace(None), Some(v), "Callback was called with incorrect value");
124+
}
125+
126+
fn expect_not_to_have_been_called(&self) {
127+
assert_eq!(self.value.get(), None, "Callback was called, but should not have been");
128+
}
129+
130+
fn callback_called(&self, v: isize) {
131+
assert_eq!(self.value.replace(Some(v)), None, "Callback was called too many times; can't be called with {}", v);
132+
}
133+
}
134+
102135
#[test]
103136
#[ignore]
104137
fn compute_cells_fire_callbacks() {
105-
// This is a bit awkward, but the closure mutably borrows `values`.
106-
// So we have to end its borrow by taking reactor out of scope.
107-
let mut values = Vec::new();
108-
{
109-
let mut reactor = Reactor::new();
110-
let input = reactor.create_input(1);
111-
let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
112-
assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
113-
assert!(reactor.set_value(input, 3).is_ok());
114-
}
115-
assert_eq!(values, vec![4]);
138+
let cb = CallbackRecorder::new();
139+
let mut reactor = Reactor::new();
140+
let input = reactor.create_input(1);
141+
let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
142+
assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_ok());
143+
assert!(reactor.set_value(input, 3).is_ok());
144+
cb.expect_to_have_been_called_with(4);
116145
}
117146

118147
#[test]
@@ -127,95 +156,96 @@ fn error_adding_callback_to_nonexistent_cell() {
127156
#[test]
128157
#[ignore]
129158
fn callbacks_only_fire_on_change() {
130-
let mut values = Vec::new();
131-
{
132-
let mut reactor = Reactor::new();
133-
let input = reactor.create_input(1);
134-
let output = reactor.create_compute(&[input], |v| if v[0] < 3 { 111 } else { 222 }).unwrap();
135-
assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
136-
assert!(reactor.set_value(input, 2).is_ok());
137-
assert!(reactor.set_value(input, 4).is_ok());
138-
}
139-
assert_eq!(values, vec![222]);
159+
let cb = CallbackRecorder::new();
160+
let mut reactor = Reactor::new();
161+
let input = reactor.create_input(1);
162+
let output = reactor.create_compute(&[input], |v| if v[0] < 3 { 111 } else { 222 }).unwrap();
163+
assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_ok());
164+
165+
assert!(reactor.set_value(input, 2).is_ok());
166+
cb.expect_not_to_have_been_called();
167+
assert!(reactor.set_value(input, 4).is_ok());
168+
cb.expect_to_have_been_called_with(222);
140169
}
141170

142171
#[test]
143172
#[ignore]
144173
fn callbacks_can_be_added_and_removed() {
145-
let mut values1 = Vec::new();
146-
let mut values2 = Vec::new();
147-
let mut values3 = Vec::new();
148-
{
149-
let mut reactor = Reactor::new();
150-
let input = reactor.create_input(11);
151-
let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
152-
let callback = reactor.add_callback(output, |v| values1.push(v)).unwrap();
153-
assert!(reactor.add_callback(output, |v| values2.push(v)).is_ok());
154-
assert!(reactor.set_value(input, 31).is_ok());
155-
assert!(reactor.remove_callback(output, callback).is_ok());
156-
assert!(reactor.add_callback(output, |v| values3.push(v)).is_ok());
157-
assert!(reactor.set_value(input, 41).is_ok());
158-
}
159-
assert_eq!(values1, vec![32]);
160-
assert_eq!(values2, vec![32, 42]);
161-
assert_eq!(values3, vec![42]);
174+
let cb1 = CallbackRecorder::new();
175+
let cb2 = CallbackRecorder::new();
176+
let cb3 = CallbackRecorder::new();
177+
178+
let mut reactor = Reactor::new();
179+
let input = reactor.create_input(11);
180+
let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
181+
182+
let callback = reactor.add_callback(output, |v| cb1.callback_called(v)).unwrap();
183+
assert!(reactor.add_callback(output, |v| cb2.callback_called(v)).is_ok());
184+
185+
assert!(reactor.set_value(input, 31).is_ok());
186+
cb1.expect_to_have_been_called_with(32);
187+
cb2.expect_to_have_been_called_with(32);
188+
189+
assert!(reactor.remove_callback(output, callback).is_ok());
190+
assert!(reactor.add_callback(output, |v| cb3.callback_called(v)).is_ok());
191+
192+
assert!(reactor.set_value(input, 41).is_ok());
193+
cb1.expect_not_to_have_been_called();
194+
cb2.expect_to_have_been_called_with(42);
195+
cb3.expect_to_have_been_called_with(42);
162196
}
163197

164198
#[test]
165199
#[ignore]
166200
fn removing_a_callback_multiple_times_doesnt_interfere_with_other_callbacks() {
167-
let mut values1 = Vec::new();
168-
let mut values2 = Vec::new();
169-
{
170-
let mut reactor = Reactor::new();
171-
let input = reactor.create_input(1);
172-
let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
173-
let callback = reactor.add_callback(output, |v| values1.push(v)).unwrap();
174-
assert!(reactor.add_callback(output, |v| values2.push(v)).is_ok());
175-
// We want the first remove to be Ok, but we don't care about the others.
176-
assert!(reactor.remove_callback(output, callback).is_ok());
177-
for _ in 1..5 {
178-
assert!(reactor.remove_callback(output, callback).is_err());
179-
}
180-
assert!(reactor.set_value(input, 2).is_ok());
201+
let cb1 = CallbackRecorder::new();
202+
let cb2 = CallbackRecorder::new();
203+
204+
let mut reactor = Reactor::new();
205+
let input = reactor.create_input(1);
206+
let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
207+
let callback = reactor.add_callback(output, |v| cb1.callback_called(v)).unwrap();
208+
assert!(reactor.add_callback(output, |v| cb2.callback_called(v)).is_ok());
209+
// We want the first remove to be Ok, but we don't care about the others.
210+
assert!(reactor.remove_callback(output, callback).is_ok());
211+
for _ in 1..5 {
212+
assert!(reactor.remove_callback(output, callback).is_err());
181213
}
182-
assert_eq!(values1, Vec::new());
183-
assert_eq!(values2, vec![3]);
214+
215+
assert!(reactor.set_value(input, 2).is_ok());
216+
cb1.expect_not_to_have_been_called();
217+
cb2.expect_to_have_been_called_with(3);
184218
}
185219

186220
#[test]
187221
#[ignore]
188222
fn callbacks_should_only_be_called_once_even_if_multiple_dependencies_change() {
189-
let mut values = Vec::new();
190-
{
191-
let mut reactor = Reactor::new();
192-
let input = reactor.create_input(1);
193-
let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
194-
let minus_one1 = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
195-
let minus_one2 = reactor.create_compute(&[minus_one1], |v| v[0] - 1).unwrap();
196-
let output = reactor.create_compute(&[plus_one, minus_one2], |v| v[0] * v[1]).unwrap();
197-
assert!(reactor.add_callback(output, |v| values.push(v)).is_ok());
198-
assert!(reactor.set_value(input, 4).is_ok());
199-
}
200-
assert_eq!(values, vec![10]);
223+
let cb = CallbackRecorder::new();
224+
let mut reactor = Reactor::new();
225+
let input = reactor.create_input(1);
226+
let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
227+
let minus_one1 = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
228+
let minus_one2 = reactor.create_compute(&[minus_one1], |v| v[0] - 1).unwrap();
229+
let output = reactor.create_compute(&[plus_one, minus_one2], |v| v[0] * v[1]).unwrap();
230+
assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_ok());
231+
assert!(reactor.set_value(input, 4).is_ok());
232+
cb.expect_to_have_been_called_with(10);
201233
}
202234

203235
#[test]
204236
#[ignore]
205237
fn callbacks_should_not_be_called_if_dependencies_change_but_output_value_doesnt_change() {
206-
let mut values = Vec::new();
207-
{
208-
let mut reactor = Reactor::new();
209-
let input = reactor.create_input(1);
210-
let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
211-
let minus_one = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
212-
let always_two = reactor.create_compute(&[plus_one, minus_one], |v| v[0] - v[1]).unwrap();
213-
assert!(reactor.add_callback(always_two, |v| values.push(v)).is_ok());
214-
for i in 2..5 {
215-
assert!(reactor.set_value(input, i).is_ok());
216-
}
238+
let cb = CallbackRecorder::new();
239+
let mut reactor = Reactor::new();
240+
let input = reactor.create_input(1);
241+
let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
242+
let minus_one = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
243+
let always_two = reactor.create_compute(&[plus_one, minus_one], |v| v[0] - v[1]).unwrap();
244+
assert!(reactor.add_callback(always_two, |v| cb.callback_called(v)).is_ok());
245+
for i in 2..5 {
246+
assert!(reactor.set_value(input, i).is_ok());
247+
cb.expect_not_to_have_been_called();
217248
}
218-
assert_eq!(values, Vec::new());
219249
}
220250

221251
#[test]

0 commit comments

Comments
 (0)