use alloy_primitives::map::HashMap;
use indicatif::{MultiProgress, ProgressBar};
use parking_lot::Mutex;
use std::{sync::Arc, time::Duration};
#[derive(Debug)]
pub struct TestsProgressState {
multi: MultiProgress,
overall_progress: ProgressBar,
suites_progress: HashMap<String, ProgressBar>,
}
impl TestsProgressState {
pub fn new(suites_len: usize, threads_no: usize) -> Self {
let multi = MultiProgress::new();
let overall_progress = multi.add(ProgressBar::new(suites_len as u64));
overall_progress.set_style(
indicatif::ProgressStyle::with_template("{bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
.unwrap()
.progress_chars("##-"),
);
overall_progress.set_message(format!("completed (with {} threads)", threads_no as u64));
Self { multi, overall_progress, suites_progress: HashMap::default() }
}
pub fn start_suite_progress(&mut self, suite_name: &String) {
let suite_progress = self.multi.add(ProgressBar::new_spinner());
suite_progress.set_style(
indicatif::ProgressStyle::with_template("{spinner} {wide_msg:.bold.dim}")
.unwrap()
.tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "),
);
suite_progress.set_message(format!("{suite_name} "));
suite_progress.enable_steady_tick(Duration::from_millis(100));
self.suites_progress.insert(suite_name.to_owned(), suite_progress);
}
pub fn end_suite_progress(&mut self, suite_name: &String, result_summary: String) {
if let Some(suite_progress) = self.suites_progress.remove(suite_name) {
self.multi.suspend(|| {
let _ = sh_println!("{suite_name}\n ↪ {result_summary}");
});
suite_progress.finish_and_clear();
self.overall_progress.inc(1);
}
}
pub fn start_fuzz_progress(
&mut self,
suite_name: &str,
test_name: &String,
runs: u32,
) -> Option<ProgressBar> {
if let Some(suite_progress) = self.suites_progress.get(suite_name) {
let fuzz_progress =
self.multi.insert_after(suite_progress, ProgressBar::new(runs as u64));
fuzz_progress.set_style(
indicatif::ProgressStyle::with_template(
" ↪ {prefix:.bold.dim}: [{pos}/{len}]{msg} Runs",
)
.unwrap()
.tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "),
);
fuzz_progress.set_prefix(test_name.to_string());
Some(fuzz_progress)
} else {
None
}
}
pub fn clear(&mut self) {
self.multi.clear().unwrap();
}
}
#[derive(Debug, Clone)]
pub struct TestsProgress {
pub inner: Arc<Mutex<TestsProgressState>>,
}
impl TestsProgress {
pub fn new(suites_len: usize, threads_no: usize) -> Self {
Self { inner: Arc::new(Mutex::new(TestsProgressState::new(suites_len, threads_no))) }
}
}
pub fn start_fuzz_progress(
tests_progress: Option<&TestsProgress>,
suite_name: &str,
test_name: &String,
runs: u32,
) -> Option<ProgressBar> {
if let Some(progress) = tests_progress {
progress.inner.lock().start_fuzz_progress(suite_name, test_name, runs)
} else {
None
}
}