nextest_runner/reporter/
imp.rs

1// Copyright (c) The nextest Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Prints out and aggregates test execution statuses.
5//!
6//! The main structure in this module is [`TestReporter`].
7
8use super::{
9    FinalStatusLevel, StatusLevel, TestOutputDisplay,
10    displayer::{DisplayReporter, DisplayReporterBuilder, StatusLevels},
11};
12use crate::{
13    config::EvaluatableProfile,
14    errors::WriteEventError,
15    list::TestList,
16    reporter::{aggregator::EventAggregator, events::*, structured::StructuredReporter},
17};
18
19/// Standard error destination for the reporter.
20///
21/// This is usually a terminal, but can be an in-memory buffer for tests.
22pub enum ReporterStderr<'a> {
23    /// Produce output on the (possibly piped) terminal.
24    ///
25    /// If the terminal isn't piped, produce output to a progress bar.
26    Terminal,
27
28    /// Write output to a buffer.
29    Buffer(&'a mut Vec<u8>),
30}
31
32/// Test reporter builder.
33#[derive(Debug, Default)]
34pub struct ReporterBuilder {
35    no_capture: bool,
36    should_colorize: bool,
37    failure_output: Option<TestOutputDisplay>,
38    success_output: Option<TestOutputDisplay>,
39    status_level: Option<StatusLevel>,
40    final_status_level: Option<FinalStatusLevel>,
41
42    verbose: bool,
43    hide_progress_bar: bool,
44    no_output_indent: bool,
45}
46
47impl ReporterBuilder {
48    /// Sets no-capture mode.
49    ///
50    /// In this mode, `failure_output` and `success_output` will be ignored, and `status_level`
51    /// will be at least [`StatusLevel::Pass`].
52    pub fn set_no_capture(&mut self, no_capture: bool) -> &mut Self {
53        self.no_capture = no_capture;
54        self
55    }
56
57    /// Set to true if the reporter should colorize output.
58    pub fn set_colorize(&mut self, should_colorize: bool) -> &mut Self {
59        self.should_colorize = should_colorize;
60        self
61    }
62
63    /// Sets the conditions under which test failures are output.
64    pub fn set_failure_output(&mut self, failure_output: TestOutputDisplay) -> &mut Self {
65        self.failure_output = Some(failure_output);
66        self
67    }
68
69    /// Sets the conditions under which test successes are output.
70    pub fn set_success_output(&mut self, success_output: TestOutputDisplay) -> &mut Self {
71        self.success_output = Some(success_output);
72        self
73    }
74
75    /// Sets the kinds of statuses to output.
76    pub fn set_status_level(&mut self, status_level: StatusLevel) -> &mut Self {
77        self.status_level = Some(status_level);
78        self
79    }
80
81    /// Sets the kinds of statuses to output at the end of the run.
82    pub fn set_final_status_level(&mut self, final_status_level: FinalStatusLevel) -> &mut Self {
83        self.final_status_level = Some(final_status_level);
84        self
85    }
86
87    /// Sets verbose output.
88    pub fn set_verbose(&mut self, verbose: bool) -> &mut Self {
89        self.verbose = verbose;
90        self
91    }
92
93    /// Sets visibility of the progress bar.
94    /// The progress bar is also hidden if `no_capture` is set.
95    pub fn set_hide_progress_bar(&mut self, hide_progress_bar: bool) -> &mut Self {
96        self.hide_progress_bar = hide_progress_bar;
97        self
98    }
99
100    /// Set to true to disable indentation of captured test output.
101    pub fn set_no_output_indent(&mut self, no_output_indent: bool) -> &mut Self {
102        self.no_output_indent = no_output_indent;
103        self
104    }
105}
106
107impl ReporterBuilder {
108    /// Creates a new test reporter.
109    pub fn build<'a>(
110        &self,
111        test_list: &TestList,
112        profile: &EvaluatableProfile<'a>,
113        output: ReporterStderr<'a>,
114        structured_reporter: StructuredReporter<'a>,
115    ) -> Reporter<'a> {
116        let aggregator = EventAggregator::new(profile);
117
118        let status_level = self.status_level.unwrap_or_else(|| profile.status_level());
119        let final_status_level = self
120            .final_status_level
121            .unwrap_or_else(|| profile.final_status_level());
122
123        let display_reporter = DisplayReporterBuilder {
124            default_filter: profile.default_filter().clone(),
125            status_levels: StatusLevels {
126                status_level,
127                final_status_level,
128            },
129            test_count: test_list.test_count(),
130            success_output: self.success_output,
131            failure_output: self.failure_output,
132            should_colorize: self.should_colorize,
133            no_capture: self.no_capture,
134            hide_progress_bar: self.hide_progress_bar,
135            no_output_indent: self.no_output_indent,
136        }
137        .build(output);
138
139        Reporter {
140            display_reporter,
141            structured_reporter,
142            metadata_reporter: aggregator,
143        }
144    }
145}
146
147/// Functionality to report test results to stderr, JUnit, and/or structured,
148/// machine-readable results to stdout.
149pub struct Reporter<'a> {
150    /// Used to display results to standard error.
151    display_reporter: DisplayReporter<'a>,
152    /// Used to aggregate events for JUnit reports written to disk
153    metadata_reporter: EventAggregator<'a>,
154    /// Used to emit test events in machine-readable format(s) to stdout
155    structured_reporter: StructuredReporter<'a>,
156}
157
158impl<'a> Reporter<'a> {
159    /// Report a test event.
160    pub fn report_event(&mut self, event: TestEvent<'a>) -> Result<(), WriteEventError> {
161        self.write_event(event)
162    }
163
164    /// Mark the reporter done.
165    pub fn finish(&mut self) {
166        self.display_reporter.finish();
167    }
168
169    // ---
170    // Helper methods
171    // ---
172
173    /// Report this test event to the given writer.
174    fn write_event(&mut self, event: TestEvent<'a>) -> Result<(), WriteEventError> {
175        // TODO: write to all of these even if one of them fails?
176        self.display_reporter.write_event(&event)?;
177        self.structured_reporter.write_event(&event)?;
178        self.metadata_reporter.write_event(event)?;
179        Ok(())
180    }
181}