diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index e42d4348fd..0e53ea30d1 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2018" [features] -test-support = ["buffer/test-support"] +test-support = ["buffer/test-support", "gpui/test-support"] [dependencies] buffer = { path = "../buffer" } @@ -23,6 +23,7 @@ smol = "1.2" [dev-dependencies] buffer = { path = "../buffer", features = ["test-support"] } +gpui = { path = "../gpui", features = ["test-support"] } rand = "0.8" unindent = "0.1.7" tree-sitter = "0.19" diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index b54b17d2ab..5378e05b4c 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -5,15 +5,15 @@ name = "gpui" version = "0.1.0" [features] -test-support = [] +test-support = ["env_logger"] [dependencies] gpui_macros = { path = "../gpui_macros" } sum_tree = { path = "../sum_tree" } - async-task = "4.0.3" backtrace = "0.3" ctor = "0.1" +env_logger = { version = "0.8", optional = true } etagere = "0.2" image = "0.23" lazy_static = "1.4.0" diff --git a/crates/gpui/src/lib.rs b/crates/gpui/src/lib.rs index 2ea6c32257..49fc74d47b 100644 --- a/crates/gpui/src/lib.rs +++ b/crates/gpui/src/lib.rs @@ -1,8 +1,8 @@ mod app; pub use app::*; mod assets; -#[cfg(test)] -mod test; +#[cfg(any(test, feature = "test-support"))] +pub mod test; pub use assets::*; pub mod elements; pub mod font_cache; diff --git a/crates/gpui/src/test.rs b/crates/gpui/src/test.rs index 4fabec46d7..1d885fd73a 100644 --- a/crates/gpui/src/test.rs +++ b/crates/gpui/src/test.rs @@ -1,8 +1,88 @@ -use ctor::ctor; +use std::{ + panic::{self, RefUnwindSafe}, + rc::Rc, + sync::{ + atomic::{AtomicU64, Ordering::SeqCst}, + Arc, + }, +}; -#[ctor] +use crate::{executor, platform, FontCache, MutableAppContext, Platform, TestAppContext}; + +#[cfg(test)] +#[ctor::ctor] fn init_logger() { env_logger::builder() .filter_level(log::LevelFilter::Info) .init(); } + +pub fn run_sync_test( + mut num_iterations: u64, + mut starting_seed: u64, + max_retries: usize, + test_fn: &mut (dyn RefUnwindSafe + Fn(&mut MutableAppContext, u64)), +) { + let is_randomized = num_iterations > 1; + if is_randomized { + if let Ok(value) = std::env::var("SEED") { + starting_seed = value.parse().expect("invalid SEED variable"); + } + if let Ok(value) = std::env::var("ITERATIONS") { + num_iterations = value.parse().expect("invalid ITERATIONS variable"); + } + } + + let atomic_seed = AtomicU64::new(starting_seed as u64); + let mut retries = 0; + + loop { + let result = panic::catch_unwind(|| { + let foreground_platform = Rc::new(platform::test::foreground_platform()); + let platform = Arc::new(platform::test::platform()); + let font_system = platform.fonts(); + let font_cache = Arc::new(FontCache::new(font_system)); + + loop { + let seed = atomic_seed.load(SeqCst); + if seed >= starting_seed + num_iterations { + break; + } + + if is_randomized { + dbg!(seed); + } + + let (foreground, background) = executor::deterministic(seed); + let mut cx = TestAppContext::new( + foreground_platform.clone(), + platform.clone(), + foreground.clone(), + background.clone(), + font_cache.clone(), + 0, + ); + cx.update(|cx| test_fn(cx, seed)); + + atomic_seed.fetch_add(1, SeqCst); + } + }); + + match result { + Ok(_) => { + break; + } + Err(error) => { + if retries < max_retries { + retries += 1; + println!("retrying: attempt {}", retries); + } else { + if is_randomized { + eprintln!("failing seed: {}", atomic_seed.load(SeqCst)); + } + panic::resume_unwind(error); + } + } + } + } +} diff --git a/crates/gpui_macros/src/lib.rs b/crates/gpui_macros/src/lib.rs index 8f3e55de79..721a6ab452 100644 --- a/crates/gpui_macros/src/lib.rs +++ b/crates/gpui_macros/src/lib.rs @@ -192,70 +192,12 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { fn #outer_fn_name() { #inner_fn - let is_randomized = #num_iterations > 1; - let mut num_iterations = #num_iterations as u64; - let mut starting_seed = #starting_seed as u64; - if is_randomized { - if let Ok(value) = std::env::var("SEED") { - starting_seed = value.parse().expect("invalid SEED variable"); - } - if let Ok(value) = std::env::var("ITERATIONS") { - num_iterations = value.parse().expect("invalid ITERATIONS variable"); - } - } - - let mut atomic_seed = std::sync::atomic::AtomicU64::new(starting_seed as u64); - let mut retries = 0; - - loop { - let result = std::panic::catch_unwind(|| { - let foreground_platform = std::rc::Rc::new(#namespace::platform::test::foreground_platform()); - let platform = std::sync::Arc::new(#namespace::platform::test::platform()); - let font_system = #namespace::Platform::fonts(platform.as_ref()); - let font_cache = std::sync::Arc::new(#namespace::FontCache::new(font_system)); - - loop { - let seed = atomic_seed.load(std::sync::atomic::Ordering::SeqCst); - if seed >= starting_seed + num_iterations { - break; - } - - if is_randomized { - dbg!(seed); - } - - let (foreground, background) = #namespace::executor::deterministic(seed); - let mut cx = #namespace::TestAppContext::new( - foreground_platform.clone(), - platform.clone(), - foreground.clone(), - background.clone(), - font_cache.clone(), - 0, - ); - cx.update(|cx| #inner_fn_name(#inner_fn_args)); - - atomic_seed.fetch_add(1, std::sync::atomic::Ordering::SeqCst); - } - }); - - match result { - Ok(_) => { - break; - } - Err(error) => { - if retries < #max_retries { - retries += 1; - println!("retrying: attempt {}", retries); - } else { - if is_randomized { - eprintln!("failing seed: {}", atomic_seed.load(std::sync::atomic::Ordering::SeqCst)); - } - std::panic::resume_unwind(error); - } - } - } - } + #namespace::test::run_sync_test( + #num_iterations as u64, + #starting_seed as u64, + #max_retries, + &mut |cx, seed| #inner_fn_name(#inner_fn_args) + ); } } };