1use super::{
9 FinalStatusLevel, MaxProgressRunning, StatusLevel, TestOutputDisplay,
10 displayer::{DisplayReporter, DisplayReporterBuilder, ShowTerminalProgress, StatusLevels},
11};
12use crate::{
13 config::core::EvaluatableProfile,
14 errors::WriteEventError,
15 list::TestList,
16 record::{ShortestRunIdPrefix, StoreSizes},
17 reporter::{
18 aggregator::EventAggregator, displayer::ShowProgress, events::*,
19 structured::StructuredReporter,
20 },
21 write_str::WriteStr,
22};
23use std::time::Duration;
24
25#[derive(Clone, Debug, Default)]
27pub struct ReporterStats {
28 pub recording_sizes: Option<StoreSizes>,
31 pub run_finished: Option<RunFinishedInfo>,
33}
34
35#[derive(Clone, Copy, Debug)]
40pub struct RunFinishedInfo {
41 pub stats: RunFinishedStats,
43 pub elapsed: Duration,
45 pub outstanding_not_seen_count: Option<usize>,
51}
52
53pub enum ReporterOutput<'a> {
58 Terminal,
62
63 Writer {
66 writer: &'a mut (dyn WriteStr + Send),
68 use_unicode: bool,
74 },
75}
76
77#[derive(Debug, Default)]
79pub struct ReporterBuilder {
80 no_capture: bool,
81 should_colorize: bool,
82 failure_output: Option<TestOutputDisplay>,
83 success_output: Option<TestOutputDisplay>,
84 status_level: Option<StatusLevel>,
85 final_status_level: Option<FinalStatusLevel>,
86
87 verbose: bool,
88 show_progress: ShowProgress,
89 no_output_indent: bool,
90 max_progress_running: MaxProgressRunning,
91}
92
93impl ReporterBuilder {
94 pub fn set_no_capture(&mut self, no_capture: bool) -> &mut Self {
99 self.no_capture = no_capture;
100 self
101 }
102
103 pub fn set_colorize(&mut self, should_colorize: bool) -> &mut Self {
105 self.should_colorize = should_colorize;
106 self
107 }
108
109 pub fn set_failure_output(&mut self, failure_output: TestOutputDisplay) -> &mut Self {
111 self.failure_output = Some(failure_output);
112 self
113 }
114
115 pub fn set_success_output(&mut self, success_output: TestOutputDisplay) -> &mut Self {
117 self.success_output = Some(success_output);
118 self
119 }
120
121 pub fn set_status_level(&mut self, status_level: StatusLevel) -> &mut Self {
123 self.status_level = Some(status_level);
124 self
125 }
126
127 pub fn set_final_status_level(&mut self, final_status_level: FinalStatusLevel) -> &mut Self {
129 self.final_status_level = Some(final_status_level);
130 self
131 }
132
133 pub fn set_verbose(&mut self, verbose: bool) -> &mut Self {
135 self.verbose = verbose;
136 self
137 }
138
139 pub fn set_show_progress(&mut self, show_progress: ShowProgress) -> &mut Self {
141 self.show_progress = show_progress;
142 self
143 }
144
145 pub fn set_no_output_indent(&mut self, no_output_indent: bool) -> &mut Self {
147 self.no_output_indent = no_output_indent;
148 self
149 }
150
151 pub fn set_max_progress_running(
156 &mut self,
157 max_progress_running: MaxProgressRunning,
158 ) -> &mut Self {
159 self.max_progress_running = max_progress_running;
160 self
161 }
162}
163
164impl ReporterBuilder {
165 pub fn build<'a>(
167 &self,
168 test_list: &TestList,
169 profile: &EvaluatableProfile<'a>,
170 show_term_progress: ShowTerminalProgress,
171 output: ReporterOutput<'a>,
172 structured_reporter: StructuredReporter<'a>,
173 ) -> Reporter<'a> {
174 let aggregator = EventAggregator::new(test_list.mode(), profile);
175
176 let status_level = self.status_level.unwrap_or_else(|| profile.status_level());
177 let final_status_level = self
178 .final_status_level
179 .unwrap_or_else(|| profile.final_status_level());
180
181 let display_reporter = DisplayReporterBuilder {
182 mode: test_list.mode(),
183 default_filter: profile.default_filter().clone(),
184 status_levels: StatusLevels {
185 status_level,
186 final_status_level,
187 },
188 test_count: test_list.test_count(),
189 success_output: self.success_output,
190 failure_output: self.failure_output,
191 should_colorize: self.should_colorize,
192 no_capture: self.no_capture,
193 verbose: self.verbose,
194 show_progress: self.show_progress,
195 no_output_indent: self.no_output_indent,
196 max_progress_running: self.max_progress_running,
197 show_term_progress,
198 }
199 .build(output);
200
201 Reporter {
202 display_reporter,
203 structured_reporter,
204 metadata_reporter: aggregator,
205 run_finished: None,
206 }
207 }
208}
209
210pub struct Reporter<'a> {
213 display_reporter: DisplayReporter<'a>,
215 metadata_reporter: EventAggregator<'a>,
217 structured_reporter: StructuredReporter<'a>,
219 run_finished: Option<RunFinishedInfo>,
221}
222
223impl<'a> Reporter<'a> {
224 pub fn report_event(&mut self, event: ReporterEvent<'a>) -> Result<(), WriteEventError> {
226 match event {
227 ReporterEvent::Tick => {
228 self.tick();
229 Ok(())
230 }
231 ReporterEvent::Test(event) => self.write_event(event),
232 }
233 }
234
235 pub fn finish(mut self) -> ReporterStats {
240 self.display_reporter.finish();
241 let recording_sizes = self.structured_reporter.finish();
242 ReporterStats {
243 recording_sizes,
244 run_finished: self.run_finished,
245 }
246 }
247
248 pub fn set_run_id_unique_prefix(&mut self, prefix: ShortestRunIdPrefix) {
253 self.display_reporter.set_run_id_unique_prefix(prefix);
254 }
255
256 fn tick(&mut self) {
262 self.display_reporter.tick();
263 }
264
265 fn write_event(&mut self, event: Box<TestEvent<'a>>) -> Result<(), WriteEventError> {
267 if let TestEventKind::RunFinished {
269 run_stats,
270 elapsed,
271 outstanding_not_seen,
272 ..
273 } = &event.kind
274 {
275 self.run_finished = Some(RunFinishedInfo {
276 stats: *run_stats,
277 elapsed: *elapsed,
278 outstanding_not_seen_count: outstanding_not_seen.as_ref().map(|t| t.total_not_seen),
279 });
280 }
281
282 self.display_reporter.write_event(&event)?;
284 self.structured_reporter.write_event(&event)?;
285 self.metadata_reporter.write_event(event)?;
286 Ok(())
287 }
288}