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 reporter::{
19 aggregator::EventAggregator, displayer::ShowProgress, events::*,
20 structured::StructuredReporter,
21 },
22 write_str::WriteStr,
23};
24use std::time::Duration;
25
26#[derive(Clone, Debug, Default)]
28pub struct ReporterStats {
29 pub recording_sizes: Option<StoreSizes>,
32 pub run_finished: Option<RunFinishedInfo>,
34}
35
36#[derive(Clone, Copy, Debug)]
41pub struct RunFinishedInfo {
42 pub stats: RunFinishedStats,
44 pub elapsed: Duration,
46 pub outstanding_not_seen_count: Option<usize>,
52}
53
54pub enum ReporterOutput<'a> {
59 Terminal,
63
64 Writer {
67 writer: &'a mut (dyn WriteStr + Send),
69 use_unicode: bool,
75 },
76}
77
78#[derive(Debug, Default)]
80pub struct ReporterBuilder {
81 no_capture: bool,
82 should_colorize: bool,
83 failure_output: Option<TestOutputDisplay>,
84 success_output: Option<TestOutputDisplay>,
85 status_level: Option<StatusLevel>,
86 final_status_level: Option<FinalStatusLevel>,
87
88 verbose: bool,
89 show_progress: ShowProgress,
90 no_output_indent: bool,
91 max_progress_running: MaxProgressRunning,
92}
93
94impl ReporterBuilder {
95 pub fn set_no_capture(&mut self, no_capture: bool) -> &mut Self {
100 self.no_capture = no_capture;
101 self
102 }
103
104 pub fn set_colorize(&mut self, should_colorize: bool) -> &mut Self {
106 self.should_colorize = should_colorize;
107 self
108 }
109
110 pub fn set_failure_output(&mut self, failure_output: TestOutputDisplay) -> &mut Self {
112 self.failure_output = Some(failure_output);
113 self
114 }
115
116 pub fn set_success_output(&mut self, success_output: TestOutputDisplay) -> &mut Self {
118 self.success_output = Some(success_output);
119 self
120 }
121
122 pub fn set_status_level(&mut self, status_level: StatusLevel) -> &mut Self {
124 self.status_level = Some(status_level);
125 self
126 }
127
128 pub fn set_final_status_level(&mut self, final_status_level: FinalStatusLevel) -> &mut Self {
130 self.final_status_level = Some(final_status_level);
131 self
132 }
133
134 pub fn set_verbose(&mut self, verbose: bool) -> &mut Self {
136 self.verbose = verbose;
137 self
138 }
139
140 pub fn set_show_progress(&mut self, show_progress: ShowProgress) -> &mut Self {
142 self.show_progress = show_progress;
143 self
144 }
145
146 pub fn set_no_output_indent(&mut self, no_output_indent: bool) -> &mut Self {
148 self.no_output_indent = no_output_indent;
149 self
150 }
151
152 pub fn set_max_progress_running(
157 &mut self,
158 max_progress_running: MaxProgressRunning,
159 ) -> &mut Self {
160 self.max_progress_running = max_progress_running;
161 self
162 }
163}
164
165impl ReporterBuilder {
166 pub fn build<'a>(
168 &self,
169 test_list: &TestList,
170 profile: &EvaluatableProfile<'a>,
171 show_term_progress: ShowTerminalProgress,
172 output: ReporterOutput<'a>,
173 structured_reporter: StructuredReporter<'a>,
174 ) -> Reporter<'a> {
175 let aggregator = EventAggregator::new(test_list.mode(), profile);
176
177 let display_reporter = DisplayReporterBuilder {
178 mode: test_list.mode(),
179 default_filter: profile.default_filter().clone(),
180 display_config: DisplayConfig {
181 show_progress: self.show_progress,
182 no_capture: self.no_capture,
183 status_level: self.status_level,
184 final_status_level: self.final_status_level,
185 profile_status_level: profile.status_level(),
186 profile_final_status_level: profile.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 verbose: self.verbose,
193 no_output_indent: self.no_output_indent,
194 max_progress_running: self.max_progress_running,
195 show_term_progress,
196 displayer_kind: DisplayerKind::Live,
197 }
198 .build(output);
199
200 Reporter {
201 display_reporter,
202 structured_reporter,
203 metadata_reporter: aggregator,
204 run_finished: None,
205 }
206 }
207}
208
209pub struct Reporter<'a> {
212 display_reporter: DisplayReporter<'a>,
214 metadata_reporter: EventAggregator<'a>,
216 structured_reporter: StructuredReporter<'a>,
218 run_finished: Option<RunFinishedInfo>,
220}
221
222impl<'a> Reporter<'a> {
223 pub fn report_event(&mut self, event: ReporterEvent<'a>) -> Result<(), WriteEventError> {
225 match event {
226 ReporterEvent::Tick => {
227 self.tick();
228 Ok(())
229 }
230 ReporterEvent::Test(event) => self.write_event(event),
231 }
232 }
233
234 pub fn finish(mut self) -> ReporterStats {
239 self.display_reporter.finish();
240 let recording_sizes = self.structured_reporter.finish();
241 ReporterStats {
242 recording_sizes,
243 run_finished: self.run_finished,
244 }
245 }
246
247 pub fn set_run_id_unique_prefix(&mut self, prefix: ShortestRunIdPrefix) {
252 self.display_reporter.set_run_id_unique_prefix(prefix);
253 }
254
255 fn tick(&mut self) {
261 self.display_reporter.tick();
262 }
263
264 fn write_event(&mut self, event: Box<TestEvent<'a>>) -> Result<(), WriteEventError> {
266 if let TestEventKind::RunFinished {
268 run_stats,
269 elapsed,
270 outstanding_not_seen,
271 ..
272 } = &event.kind
273 {
274 self.run_finished = Some(RunFinishedInfo {
275 stats: *run_stats,
276 elapsed: *elapsed,
277 outstanding_not_seen_count: outstanding_not_seen.as_ref().map(|t| t.total_not_seen),
278 });
279 }
280
281 self.display_reporter.write_event(&event)?;
283 self.structured_reporter.write_event(&event)?;
284 self.metadata_reporter.write_event(event)?;
285 Ok(())
286 }
287}