diff --git a/crates/gpui/examples/testing.rs b/crates/gpui/examples/testing.rs index 8df7d72b180c25a5b99baae01bb2e5ab7e9a8e95..41f7dad7632a6da9397ba9003b885ae067475915 100644 --- a/crates/gpui/examples/testing.rs +++ b/crates/gpui/examples/testing.rs @@ -311,6 +311,12 @@ mod tests { /// GPUI also provides support for property testing, via the iterations flag #[gpui::test(iterations = 10)] fn test_counter_random_operations(cx: &mut TestAppContext, mut rng: StdRng) { + let window = cx.update(|cx| { + cx.open_window(Default::default(), |_, cx| cx.new(|cx| Counter::new(cx))) + .unwrap() + }); + let mut cx = VisualTestContext::from_window(window.into(), cx); + let counter = cx.new(|cx| Counter::new(cx)); // Perform random increments/decrements @@ -318,14 +324,18 @@ mod tests { for _ in 0..100 { if rng.random_bool(0.5) { expected += 1; - counter.update(cx, |counter, _| counter.count += 1); + counter.update_in(&mut cx, |counter, window, cx| { + counter.increment(&Increment, window, cx) + }); } else { expected -= 1; - counter.update(cx, |counter, _| counter.count -= 1); + counter.update_in(&mut cx, |counter, window, cx| { + counter.decrement(&Decrement, window, cx) + }); } } - let actual = counter.read_with(cx, |counter, _| counter.count); + let actual = counter.read_with(&cx, |counter, _| counter.count); assert_eq!( actual, expected, "Counter should match expected after random ops" @@ -337,30 +347,40 @@ mod tests { mod distributed_systems { use std::sync::{Arc, Mutex}; - /// A mock network that delivers messages between two peers. - struct MockNetwork { + /// The state of the mock network. + struct MockNetworkState { + ordering: Vec, a_to_b: Vec, b_to_a: Vec, } + /// A mock network that delivers messages between two peers. + #[derive(Clone)] + struct MockNetwork { + state: Arc>, + } + impl MockNetwork { - fn new() -> Arc> { - Arc::new(Mutex::new(Self { - a_to_b: Vec::new(), - b_to_a: Vec::new(), - })) + fn new() -> Self { + Self { + state: Arc::new(Mutex::new(MockNetworkState { + ordering: Vec::new(), + a_to_b: Vec::new(), + b_to_a: Vec::new(), + })), + } } - fn a_client(network: &Arc>) -> NetworkClient { + fn a_client(&self) -> NetworkClient { NetworkClient { - network: network.clone(), + network: self.clone(), is_a: true, } } - fn b_client(network: &Arc>) -> NetworkClient { + fn b_client(&self) -> NetworkClient { NetworkClient { - network: network.clone(), + network: self.clone(), is_a: false, } } @@ -369,13 +389,15 @@ mod tests { /// A client handle for sending/receiving messages over the mock network. #[derive(Clone)] struct NetworkClient { - network: Arc>, + network: MockNetwork, is_a: bool, } + // See, networking is easy! impl NetworkClient { fn send(&self, value: i32) { - let mut network = self.network.lock().unwrap(); + let mut network = self.network.state.lock().unwrap(); + network.ordering.push(value); if self.is_a { network.b_to_a.push(value); } else { @@ -384,7 +406,7 @@ mod tests { } fn receive_all(&self) -> Vec { - let mut network = self.network.lock().unwrap(); + let mut network = self.network.state.lock().unwrap(); if self.is_a { network.a_to_b.drain(..).collect() } else { @@ -425,25 +447,6 @@ mod tests { self.count += delta; } } - - /// Like increment, but tracks when the background send executes. - fn increment_tracked( - &mut self, - delta: i32, - cx: &mut Context, - order: Arc>>, - ) { - self.count += delta; - - cx.background_spawn({ - let client = self.client.clone(); - async move { - order.lock().unwrap().push(delta); - client.send(delta); - } - }) - .detach(); - } } use super::*; @@ -454,8 +457,8 @@ mod tests { fn test_app_sync(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) { let network = MockNetwork::new(); - let a = cx_a.new(|_| NetworkedCounter::new(MockNetwork::a_client(&network))); - let b = cx_b.new(|_| NetworkedCounter::new(MockNetwork::b_client(&network))); + let a = cx_a.new(|_| NetworkedCounter::new(network.a_client())); + let b = cx_b.new(|_| NetworkedCounter::new(network.b_client())); // B increments locally and broadcasts the delta b.update(cx_b, |b, cx| b.increment(42, cx)); @@ -482,7 +485,6 @@ mod tests { let network = MockNetwork::new(); // Track execution order - let actual_order = Arc::new(Mutex::new(Vec::new())); let mut original_order = Vec::new(); let a = cx_a.new(|_| NetworkedCounter::new(MockNetwork::a_client(&network))); let b = cx_b.new(|_| NetworkedCounter::new(MockNetwork::b_client(&network))); @@ -490,18 +492,14 @@ mod tests { let num_operations: usize = rng.random_range(3..8); for i in 0..num_operations { - let id = i as i32; + let i = i as i32; let which = rng.random_bool(0.5); - original_order.push(id); + original_order.push(i); if which { - b.update(cx_b, |b, cx| { - b.increment_tracked(id, cx, actual_order.clone()) - }); + b.update(cx_b, |b, cx| b.increment(i, cx)); } else { - a.update(cx_a, |a, cx| { - a.increment_tracked(id, cx, actual_order.clone()) - }); + a.update(cx_a, |a, cx| a.increment(i, cx)); } } @@ -518,7 +516,7 @@ mod tests { // Nicely format the execution order output. // Run this test with `-- --nocapture` to see it! - let actual = actual_order.lock().unwrap(); + let actual = network.state.lock().unwrap().ordering.clone(); let spawned: Vec<_> = original_order.iter().map(|n| format!("{}", n)).collect(); let ran: Vec<_> = actual.iter().map(|n| format!("{}", n)).collect(); let diff: Vec<_> = original_order