Uncomment project2 tests (#3200)

This commit is contained in:
Conrad Irwin
2023-11-01 20:27:53 +00:00
committed by GitHub
11 changed files with 3876 additions and 3745 deletions
+1 -1
View File
@@ -376,7 +376,7 @@ impl AppContext {
self.observers.remove(&entity_id);
self.event_listeners.remove(&entity_id);
for mut release_callback in self.release_listeners.remove(&entity_id) {
release_callback(&mut entity, self);
release_callback(entity.as_mut(), self);
}
}
}
+74 -8
View File
@@ -106,7 +106,12 @@ impl EntityMap {
dropped_entity_ids
.into_iter()
.map(|entity_id| {
ref_counts.counts.remove(entity_id);
let count = ref_counts.counts.remove(entity_id).unwrap();
debug_assert_eq!(
count.load(SeqCst),
0,
"dropped an entity that was referenced"
);
(entity_id, self.entities.remove(entity_id).unwrap())
})
.collect()
@@ -211,7 +216,7 @@ impl Drop for AnyModel {
let count = entity_map
.counts
.get(self.entity_id)
.expect("Detected over-release of a model.");
.expect("detected over-release of a handle.");
let prev_count = count.fetch_sub(1, SeqCst);
assert_ne!(prev_count, 0, "Detected over-release of a model.");
if prev_count == 1 {
@@ -395,12 +400,16 @@ impl AnyWeakModel {
}
pub fn upgrade(&self) -> Option<AnyModel> {
let entity_map = self.entity_ref_counts.upgrade()?;
entity_map
.read()
.counts
.get(self.entity_id)?
.fetch_add(1, SeqCst);
let ref_counts = &self.entity_ref_counts.upgrade()?;
let ref_counts = ref_counts.read();
let ref_count = ref_counts.counts.get(self.entity_id)?;
// entity_id is in dropped_entity_ids
if ref_count.load(SeqCst) == 0 {
return None;
}
ref_count.fetch_add(1, SeqCst);
Some(AnyModel {
entity_id: self.entity_id,
entity_type: self.entity_type,
@@ -499,3 +508,60 @@ impl<T> PartialEq<Model<T>> for WeakModel<T> {
self.entity_id() == other.any_model.entity_id()
}
}
#[cfg(test)]
mod test {
use crate::EntityMap;
struct TestEntity {
pub i: i32,
}
#[test]
fn test_entity_map_slot_assignment_before_cleanup() {
// Tests that slots are not re-used before take_dropped.
let mut entity_map = EntityMap::new();
let slot = entity_map.reserve::<TestEntity>();
entity_map.insert(slot, TestEntity { i: 1 });
let slot = entity_map.reserve::<TestEntity>();
entity_map.insert(slot, TestEntity { i: 2 });
let dropped = entity_map.take_dropped();
assert_eq!(dropped.len(), 2);
assert_eq!(
dropped
.into_iter()
.map(|(_, entity)| entity.downcast::<TestEntity>().unwrap().i)
.collect::<Vec<i32>>(),
vec![1, 2],
);
}
#[test]
fn test_entity_map_weak_upgrade_before_cleanup() {
// Tests that weak handles are not upgraded before take_dropped
let mut entity_map = EntityMap::new();
let slot = entity_map.reserve::<TestEntity>();
let handle = entity_map.insert(slot, TestEntity { i: 1 });
let weak = handle.downgrade();
drop(handle);
let strong = weak.upgrade();
assert_eq!(strong, None);
let dropped = entity_map.take_dropped();
assert_eq!(dropped.len(), 1);
assert_eq!(
dropped
.into_iter()
.map(|(_, entity)| entity.downcast::<TestEntity>().unwrap().i)
.collect::<Vec<i32>>(),
vec![1],
);
}
}
+23 -4
View File
@@ -1,7 +1,8 @@
use crate::{
AnyWindowHandle, AppContext, AsyncAppContext, Context, Executor, MainThread, Model,
ModelContext, Result, Task, TestDispatcher, TestPlatform, WindowContext,
AnyWindowHandle, AppContext, AsyncAppContext, Context, EventEmitter, Executor, MainThread,
Model, ModelContext, Result, Task, TestDispatcher, TestPlatform, WindowContext,
};
use futures::SinkExt;
use parking_lot::Mutex;
use std::{future::Future, sync::Arc};
@@ -63,8 +64,8 @@ impl TestAppContext {
}
pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> R {
let mut lock = self.app.lock();
f(&mut *lock)
let mut cx = self.app.lock();
cx.update(f)
}
pub fn read_window<R>(
@@ -149,4 +150,22 @@ impl TestAppContext {
executor: self.executor.clone(),
}
}
pub fn subscribe<T: 'static + EventEmitter + Send>(
&mut self,
entity: &Model<T>,
) -> futures::channel::mpsc::UnboundedReceiver<T::Event>
where
T::Event: 'static + Send + Clone,
{
let (mut tx, rx) = futures::channel::mpsc::unbounded();
entity
.update(self, |_, cx: &mut ModelContext<T>| {
cx.subscribe(entity, move |_, _, event, cx| {
cx.executor().block(tx.send(event.clone())).unwrap();
})
})
.detach();
rx
}
}
+28 -5
View File
@@ -6,7 +6,10 @@ use std::{
marker::PhantomData,
mem,
pin::Pin,
sync::Arc,
sync::{
atomic::{AtomicBool, Ordering::SeqCst},
Arc,
},
task::{Context, Poll},
time::Duration,
};
@@ -136,7 +139,11 @@ impl Executor {
pub fn block<R>(&self, future: impl Future<Output = R>) -> R {
pin_mut!(future);
let (parker, unparker) = parking::pair();
let awoken = Arc::new(AtomicBool::new(false));
let awoken2 = awoken.clone();
let waker = waker_fn(move || {
awoken2.store(true, SeqCst);
unparker.unpark();
});
let mut cx = std::task::Context::from_waker(&waker);
@@ -146,9 +153,20 @@ impl Executor {
Poll::Ready(result) => return result,
Poll::Pending => {
if !self.dispatcher.poll() {
if awoken.swap(false, SeqCst) {
continue;
}
#[cfg(any(test, feature = "test-support"))]
if let Some(_) = self.dispatcher.as_test() {
panic!("blocked with nothing left to run")
if let Some(test) = self.dispatcher.as_test() {
if !test.parking_allowed() {
let mut backtrace_message = String::new();
if let Some(backtrace) = test.waiting_backtrace() {
backtrace_message =
format!("\nbacktrace of waiting future:\n{:?}", backtrace);
}
panic!("parked with nothing left to run\n{:?}", backtrace_message)
}
}
parker.park();
}
@@ -206,12 +224,12 @@ impl Executor {
#[cfg(any(test, feature = "test-support"))]
pub fn start_waiting(&self) {
todo!("start_waiting")
self.dispatcher.as_test().unwrap().start_waiting();
}
#[cfg(any(test, feature = "test-support"))]
pub fn finish_waiting(&self) {
todo!("finish_waiting")
self.dispatcher.as_test().unwrap().finish_waiting();
}
#[cfg(any(test, feature = "test-support"))]
@@ -229,6 +247,11 @@ impl Executor {
self.dispatcher.as_test().unwrap().run_until_parked()
}
#[cfg(any(test, feature = "test-support"))]
pub fn allow_parking(&self) {
self.dispatcher.as_test().unwrap().allow_parking();
}
pub fn num_cpus(&self) -> usize {
num_cpus::get()
}
+29 -1
View File
@@ -1,5 +1,6 @@
use crate::PlatformDispatcher;
use async_task::Runnable;
use backtrace::Backtrace;
use collections::{HashMap, VecDeque};
use parking_lot::Mutex;
use rand::prelude::*;
@@ -28,6 +29,8 @@ struct TestDispatcherState {
time: Duration,
is_main_thread: bool,
next_id: TestDispatcherId,
allow_parking: bool,
waiting_backtrace: Option<Backtrace>,
}
impl TestDispatcher {
@@ -40,6 +43,8 @@ impl TestDispatcher {
time: Duration::ZERO,
is_main_thread: true,
next_id: TestDispatcherId(1),
allow_parking: false,
waiting_backtrace: None,
};
TestDispatcher {
@@ -66,7 +71,7 @@ impl TestDispatcher {
self.state.lock().time = new_now;
}
pub fn simulate_random_delay(&self) -> impl Future<Output = ()> {
pub fn simulate_random_delay(&self) -> impl 'static + Send + Future<Output = ()> {
pub struct YieldNow {
count: usize,
}
@@ -93,6 +98,29 @@ impl TestDispatcher {
pub fn run_until_parked(&self) {
while self.poll() {}
}
pub fn parking_allowed(&self) -> bool {
self.state.lock().allow_parking
}
pub fn allow_parking(&self) {
self.state.lock().allow_parking = true
}
pub fn start_waiting(&self) {
self.state.lock().waiting_backtrace = Some(Backtrace::new_unresolved());
}
pub fn finish_waiting(&self) {
self.state.lock().waiting_backtrace.take();
}
pub fn waiting_backtrace(&self) -> Option<Backtrace> {
self.state.lock().waiting_backtrace.take().map(|mut b| {
b.resolve();
b
})
}
}
impl Clone for TestDispatcher {