cc_audit/reporter/
progress.rs1use indicatif::{ProgressBar, ProgressStyle};
6
7const MIN_FILES_FOR_PROGRESS: usize = 10;
9
10pub struct ScanProgress {
12 bar: Option<ProgressBar>,
13}
14
15impl ScanProgress {
16 pub fn new(total_files: usize, is_tty: bool, is_ci: bool) -> Self {
23 let bar = if should_show_progress(total_files, is_tty, is_ci) {
24 Some(create_progress_bar(total_files))
25 } else {
26 None
27 };
28
29 Self { bar }
30 }
31
32 pub fn inc(&self) {
34 if let Some(bar) = &self.bar {
35 bar.inc(1);
36 }
37 }
38
39 pub fn finish(&self) {
41 if let Some(bar) = &self.bar {
42 bar.finish_and_clear();
43 }
44 }
45}
46
47fn should_show_progress(total_files: usize, is_tty: bool, is_ci: bool) -> bool {
49 total_files >= MIN_FILES_FOR_PROGRESS && is_tty && !is_ci
50}
51
52fn create_progress_bar(total: usize) -> ProgressBar {
54 let pb = ProgressBar::new(total as u64);
55 pb.set_style(
56 ProgressStyle::with_template(
57 "Scanning {bar:40} {pos:>4}/{len:4} files ({percent:>3}%) [{elapsed_precise} < {eta_precise}]",
58 )
59 .expect("Invalid progress bar template")
60 .progress_chars("⣿⣀ "), );
62 pb
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn test_should_show_progress_below_threshold() {
71 assert!(!should_show_progress(9, true, false));
73 }
74
75 #[test]
76 fn test_should_show_progress_at_threshold() {
77 assert!(should_show_progress(10, true, false));
79 }
80
81 #[test]
82 fn test_should_show_progress_above_threshold() {
83 assert!(should_show_progress(100, true, false));
85 }
86
87 #[test]
88 fn test_should_not_show_in_non_tty() {
89 assert!(!should_show_progress(100, false, false));
91 }
92
93 #[test]
94 fn test_should_not_show_in_ci() {
95 assert!(!should_show_progress(100, true, true));
97 }
98
99 #[test]
100 fn test_should_not_show_non_tty_and_ci() {
101 assert!(!should_show_progress(100, false, true));
103 }
104
105 #[test]
106 fn test_new_creates_bar_when_conditions_met() {
107 let progress = ScanProgress::new(10, true, false);
108 assert!(progress.bar.is_some());
109 }
110
111 #[test]
112 fn test_new_no_bar_when_below_threshold() {
113 let progress = ScanProgress::new(9, true, false);
114 assert!(progress.bar.is_none());
115 }
116
117 #[test]
118 fn test_new_no_bar_when_non_tty() {
119 let progress = ScanProgress::new(100, false, false);
120 assert!(progress.bar.is_none());
121 }
122
123 #[test]
124 fn test_new_no_bar_when_ci() {
125 let progress = ScanProgress::new(100, true, true);
126 assert!(progress.bar.is_none());
127 }
128
129 #[test]
130 fn test_inc_with_bar() {
131 let progress = ScanProgress::new(10, true, false);
132 progress.inc();
134 }
135
136 #[test]
137 fn test_inc_without_bar() {
138 let progress = ScanProgress::new(5, true, false);
139 progress.inc();
141 }
142
143 #[test]
144 fn test_finish_with_bar() {
145 let progress = ScanProgress::new(10, true, false);
146 progress.finish();
148 }
149
150 #[test]
151 fn test_finish_without_bar() {
152 let progress = ScanProgress::new(5, true, false);
153 progress.finish();
155 }
156
157 #[test]
158 fn test_create_progress_bar() {
159 let pb = create_progress_bar(100);
161 assert_eq!(pb.length(), Some(100));
162 }
163}