forge/
progress.rs
1use alloy_primitives::map::HashMap;
2use indicatif::{MultiProgress, ProgressBar};
3use parking_lot::Mutex;
4use std::{sync::Arc, time::Duration};
5#[derive(Debug)]
11pub struct TestsProgressState {
12 multi: MultiProgress,
14 overall_progress: ProgressBar,
16 suites_progress: HashMap<String, ProgressBar>,
18}
19
20impl TestsProgressState {
21 pub fn new(suites_len: usize, threads_no: usize) -> Self {
23 let multi = MultiProgress::new();
24 let overall_progress = multi.add(ProgressBar::new(suites_len as u64));
25 overall_progress.set_style(
26 indicatif::ProgressStyle::with_template("{bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
27 .unwrap()
28 .progress_chars("##-"),
29 );
30 overall_progress.set_message(format!("completed (with {} threads)", threads_no as u64));
31 Self { multi, overall_progress, suites_progress: HashMap::default() }
32 }
33
34 pub fn start_suite_progress(&mut self, suite_name: &String) {
36 let suite_progress = self.multi.add(ProgressBar::new_spinner());
37 suite_progress.set_style(
38 indicatif::ProgressStyle::with_template("{spinner} {wide_msg:.bold.dim}")
39 .unwrap()
40 .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "),
41 );
42 suite_progress.set_message(format!("{suite_name} "));
43 suite_progress.enable_steady_tick(Duration::from_millis(100));
44 self.suites_progress.insert(suite_name.to_owned(), suite_progress);
45 }
46
47 pub fn end_suite_progress(&mut self, suite_name: &String, result_summary: String) {
49 if let Some(suite_progress) = self.suites_progress.remove(suite_name) {
50 self.multi.suspend(|| {
51 let _ = sh_println!("{suite_name}\n ↪ {result_summary}");
52 });
53 suite_progress.finish_and_clear();
54 self.overall_progress.inc(1);
56 }
57 }
58
59 pub fn start_fuzz_progress(
64 &mut self,
65 suite_name: &str,
66 test_name: &String,
67 runs: u32,
68 ) -> Option<ProgressBar> {
69 if let Some(suite_progress) = self.suites_progress.get(suite_name) {
70 let fuzz_progress =
71 self.multi.insert_after(suite_progress, ProgressBar::new(runs as u64));
72 fuzz_progress.set_style(
73 indicatif::ProgressStyle::with_template(
74 " ↪ {prefix:.bold.dim}: [{pos}/{len}]{msg} Runs",
75 )
76 .unwrap()
77 .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "),
78 );
79 fuzz_progress.set_prefix(test_name.to_string());
80 Some(fuzz_progress)
81 } else {
82 None
83 }
84 }
85
86 pub fn clear(&mut self) {
88 self.multi.clear().unwrap();
89 }
90}
91
92#[derive(Debug, Clone)]
94pub struct TestsProgress {
95 pub inner: Arc<Mutex<TestsProgressState>>,
96}
97
98impl TestsProgress {
99 pub fn new(suites_len: usize, threads_no: usize) -> Self {
100 Self { inner: Arc::new(Mutex::new(TestsProgressState::new(suites_len, threads_no))) }
101 }
102}
103
104pub fn start_fuzz_progress(
106 tests_progress: Option<&TestsProgress>,
107 suite_name: &str,
108 test_name: &String,
109 runs: u32,
110) -> Option<ProgressBar> {
111 if let Some(progress) = tests_progress {
112 progress.inner.lock().start_fuzz_progress(suite_name, test_name, runs)
113 } else {
114 None
115 }
116}