1use std::{
2 panic::{self, RefUnwindSafe},
3 rc::Rc,
4 sync::{
5 atomic::{AtomicU64, Ordering::SeqCst},
6 Arc,
7 },
8};
9
10use crate::{executor, platform, FontCache, MutableAppContext, Platform, TestAppContext};
11
12#[cfg(test)]
13#[ctor::ctor]
14fn init_logger() {
15 env_logger::builder()
16 .filter_level(log::LevelFilter::Info)
17 .init();
18}
19
20pub fn run_sync_test(
21 mut num_iterations: u64,
22 mut starting_seed: u64,
23 max_retries: usize,
24 test_fn: &mut (dyn RefUnwindSafe + Fn(&mut MutableAppContext, u64)),
25) {
26 let is_randomized = num_iterations > 1;
27 if is_randomized {
28 if let Ok(value) = std::env::var("SEED") {
29 starting_seed = value.parse().expect("invalid SEED variable");
30 }
31 if let Ok(value) = std::env::var("ITERATIONS") {
32 num_iterations = value.parse().expect("invalid ITERATIONS variable");
33 }
34 }
35
36 let atomic_seed = AtomicU64::new(starting_seed as u64);
37 let mut retries = 0;
38
39 loop {
40 let result = panic::catch_unwind(|| {
41 let foreground_platform = Rc::new(platform::test::foreground_platform());
42 let platform = Arc::new(platform::test::platform());
43 let font_system = platform.fonts();
44 let font_cache = Arc::new(FontCache::new(font_system));
45
46 loop {
47 let seed = atomic_seed.load(SeqCst);
48 if seed >= starting_seed + num_iterations {
49 break;
50 }
51
52 if is_randomized {
53 dbg!(seed);
54 }
55
56 let (foreground, background) = executor::deterministic(seed);
57 let mut cx = TestAppContext::new(
58 foreground_platform.clone(),
59 platform.clone(),
60 foreground.clone(),
61 background.clone(),
62 font_cache.clone(),
63 0,
64 );
65 cx.update(|cx| test_fn(cx, seed));
66
67 atomic_seed.fetch_add(1, SeqCst);
68 }
69 });
70
71 match result {
72 Ok(_) => {
73 break;
74 }
75 Err(error) => {
76 if retries < max_retries {
77 retries += 1;
78 println!("retrying: attempt {}", retries);
79 } else {
80 if is_randomized {
81 eprintln!("failing seed: {}", atomic_seed.load(SeqCst));
82 }
83 panic::resume_unwind(error);
84 }
85 }
86 }
87 }
88}