1use super::{
9 DisplayConfig, DisplayerKind, FinalStatusLevel, MaxProgressRunning, StatusLevel,
10 TestOutputDisplay,
11 displayer::{DisplayReporter, DisplayReporterBuilder, ShowTerminalProgress},
12};
13use crate::{
14 config::core::EvaluatableProfile,
15 errors::WriteEventError,
16 list::TestList,
17 record::{ShortestRunIdPrefix, StoreSizes},
18 redact::Redactor,
19 reporter::{
20 aggregator::EventAggregator, displayer::ShowProgress, events::*,
21 structured::StructuredReporter,
22 },
23 write_str::WriteStr,
24};
25use std::time::Duration;
26
27#[derive(Clone, Debug, Default)]
29pub struct ReporterStats {
30 pub recording_sizes: Option<StoreSizes>,
33 pub run_finished: Option<RunFinishedInfo>,
35}
36
37#[derive(Clone, Copy, Debug)]
42pub struct RunFinishedInfo {
43 pub stats: RunFinishedStats,
45 pub elapsed: Duration,
47 pub outstanding_not_seen_count: Option<usize>,
53}
54
55pub enum ReporterOutput<'a> {
60 Terminal,
64
65 Writer {
68 writer: &'a mut (dyn WriteStr + Send),
70 use_unicode: bool,
76 },
77}
78
79#[derive(Debug, Default)]
81pub struct ReporterBuilder {
82 no_capture: bool,
83 should_colorize: bool,
84 failure_output: Option<TestOutputDisplay>,
85 success_output: Option<TestOutputDisplay>,
86 status_level: Option<StatusLevel>,
87 final_status_level: Option<FinalStatusLevel>,
88
89 verbose: bool,
90 show_progress: ShowProgress,
91 no_output_indent: bool,
92 max_progress_running: MaxProgressRunning,
93 redactor: Redactor,
94}
95
96impl ReporterBuilder {
97 pub fn set_no_capture(&mut self, no_capture: bool) -> &mut Self {
102 self.no_capture = no_capture;
103 self
104 }
105
106 pub fn set_colorize(&mut self, should_colorize: bool) -> &mut Self {
108 self.should_colorize = should_colorize;
109 self
110 }
111
112 pub fn set_failure_output(&mut self, failure_output: TestOutputDisplay) -> &mut Self {
114 self.failure_output = Some(failure_output);
115 self
116 }
117
118 pub fn set_success_output(&mut self, success_output: TestOutputDisplay) -> &mut Self {
120 self.success_output = Some(success_output);
121 self
122 }
123
124 pub fn set_status_level(&mut self, status_level: StatusLevel) -> &mut Self {
126 self.status_level = Some(status_level);
127 self
128 }
129
130 pub fn set_final_status_level(&mut self, final_status_level: FinalStatusLevel) -> &mut Self {
132 self.final_status_level = Some(final_status_level);
133 self
134 }
135
136 pub fn set_verbose(&mut self, verbose: bool) -> &mut Self {
138 self.verbose = verbose;
139 self
140 }
141
142 pub fn set_show_progress(&mut self, show_progress: ShowProgress) -> &mut Self {
144 self.show_progress = show_progress;
145 self
146 }
147
148 pub fn set_no_output_indent(&mut self, no_output_indent: bool) -> &mut Self {
150 self.no_output_indent = no_output_indent;
151 self
152 }
153
154 pub fn set_max_progress_running(
159 &mut self,
160 max_progress_running: MaxProgressRunning,
161 ) -> &mut Self {
162 self.max_progress_running = max_progress_running;
163 self
164 }
165
166 pub fn set_redactor(&mut self, redactor: Redactor) -> &mut Self {
168 self.redactor = redactor;
169 self
170 }
171}
172
173impl ReporterBuilder {
174 pub fn build<'a>(
176 &self,
177 test_list: &TestList,
178 profile: &EvaluatableProfile<'a>,
179 show_term_progress: ShowTerminalProgress,
180 output: ReporterOutput<'a>,
181 structured_reporter: StructuredReporter<'a>,
182 ) -> Reporter<'a> {
183 let aggregator = EventAggregator::new(test_list.mode(), profile);
184
185 let display_reporter = DisplayReporterBuilder {
186 mode: test_list.mode(),
187 default_filter: profile.default_filter().clone(),
188 display_config: DisplayConfig {
189 show_progress: self.show_progress,
190 no_capture: self.no_capture,
191 status_level: self.status_level,
192 final_status_level: self.final_status_level,
193 profile_status_level: profile.status_level(),
194 profile_final_status_level: profile.final_status_level(),
195 },
196 run_count: test_list.run_count(),
197 success_output: self.success_output,
198 failure_output: self.failure_output,
199 should_colorize: self.should_colorize,
200 verbose: self.verbose,
201 no_output_indent: self.no_output_indent,
202 max_progress_running: self.max_progress_running,
203 show_term_progress,
204 displayer_kind: DisplayerKind::Live,
205 redactor: self.redactor.clone(),
206 }
207 .build(output);
208
209 Reporter {
210 display_reporter,
211 structured_reporter,
212 metadata_reporter: aggregator,
213 run_finished: None,
214 }
215 }
216}
217
218pub struct Reporter<'a> {
221 display_reporter: DisplayReporter<'a>,
223 metadata_reporter: EventAggregator<'a>,
225 structured_reporter: StructuredReporter<'a>,
227 run_finished: Option<RunFinishedInfo>,
229}
230
231impl<'a> Reporter<'a> {
232 pub fn report_event(&mut self, event: ReporterEvent<'a>) -> Result<(), WriteEventError> {
234 match event {
235 ReporterEvent::Tick => {
236 self.tick();
237 Ok(())
238 }
239 ReporterEvent::Test(event) => self.write_event(event),
240 }
241 }
242
243 pub fn finish(mut self) -> ReporterStats {
248 self.display_reporter.finish();
249 let recording_sizes = self.structured_reporter.finish();
250 ReporterStats {
251 recording_sizes,
252 run_finished: self.run_finished,
253 }
254 }
255
256 pub fn set_run_id_unique_prefix(&mut self, prefix: ShortestRunIdPrefix) {
261 self.display_reporter.set_run_id_unique_prefix(prefix);
262 }
263
264 fn tick(&mut self) {
270 self.display_reporter.tick();
271 }
272
273 fn write_event(&mut self, event: Box<TestEvent<'a>>) -> Result<(), WriteEventError> {
275 if let TestEventKind::RunFinished {
277 run_stats,
278 elapsed,
279 outstanding_not_seen,
280 ..
281 } = &event.kind
282 {
283 self.run_finished = Some(RunFinishedInfo {
284 stats: *run_stats,
285 elapsed: *elapsed,
286 outstanding_not_seen_count: outstanding_not_seen.as_ref().map(|t| t.total_not_seen),
287 });
288 }
289
290 self.display_reporter.write_event(&event)?;
292 self.structured_reporter.write_event(&event)?;
293 self.metadata_reporter.write_event(event)?;
294 Ok(())
295 }
296}