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