From b00750ccf45672c28439699f4b0f272f03333dfc Mon Sep 17 00:00:00 2001 From: danggg Date: Sun, 23 Nov 2025 15:46:28 +0700 Subject: [PATCH] [nextest-runner] add verbose flag to display test command lines --- nextest-runner/src/reporter/displayer/imp.rs | 98 ++++++++++++++++---- nextest-runner/src/reporter/imp.rs | 1 + 2 files changed, 83 insertions(+), 16 deletions(-) diff --git a/nextest-runner/src/reporter/displayer/imp.rs b/nextest-runner/src/reporter/displayer/imp.rs index fc84ed316e1..437b0a5339d 100644 --- a/nextest-runner/src/reporter/displayer/imp.rs +++ b/nextest-runner/src/reporter/displayer/imp.rs @@ -54,6 +54,7 @@ pub(crate) struct DisplayReporterBuilder { pub(crate) failure_output: Option, pub(crate) should_colorize: bool, pub(crate) no_capture: bool, + pub(crate) verbose: bool, pub(crate) show_progress: ShowProgress, pub(crate) no_output_indent: bool, pub(crate) max_progress_running: MaxProgressRunning, @@ -141,6 +142,7 @@ impl DisplayReporterBuilder { final_status_level: self.status_levels.final_status_level, }, no_capture: self.no_capture, + verbose: self.verbose, no_output_indent: self.no_output_indent, counter_width, styles, @@ -377,6 +379,7 @@ struct DisplayReporterImpl<'a> { default_filter: CompiledDefaultFilter, status_levels: StatusLevels, no_capture: bool, + verbose: bool, no_output_indent: bool, // None if no counter is displayed. If a counter is displayed, this is the // width of the total number of tests to run. @@ -623,6 +626,10 @@ impl<'a> DisplayReporterImpl<'a> { ), )?; } + + if self.verbose { + self.write_test_command_line(test_instance, writer)?; + } } TestEventKind::TestSlow { stress_index, @@ -1312,6 +1319,28 @@ impl<'a> DisplayReporterImpl<'a> { Ok(()) } + fn write_test_command_line( + &self, + test_instance: &TestInstance<'a>, + writer: &mut dyn WriteStr, + ) -> io::Result<()> { + // Display the command line that will be used to run this test. + // Format: binary_path --exact test_name --nocapture [--ignored] + write!( + writer, + "{:>12} {} --exact {} --nocapture", + "COMMAND".style(self.styles.count), + test_instance.suite_info.binary_path, + test_instance.name, + )?; + if test_instance.test_info.ignored { + write!(writer, " --ignored")?; + } + writeln!(writer)?; + + Ok(()) + } + fn write_setup_script_status_line( &self, stress_index: Option, @@ -2360,10 +2389,29 @@ mod tests { use smol_str::SmolStr; use std::{num::NonZero, sync::Arc}; + fn default_builder() -> DisplayReporterBuilder { + DisplayReporterBuilder { + default_filter: CompiledDefaultFilter::for_default_config(), + status_levels: StatusLevels { + status_level: StatusLevel::Fail, + final_status_level: FinalStatusLevel::Fail, + }, + test_count: 5000, + success_output: Some(TestOutputDisplay::Immediate), + failure_output: Some(TestOutputDisplay::Immediate), + should_colorize: false, + no_capture: true, + verbose: false, + show_progress: ShowProgress::Counter, + no_output_indent: false, + max_progress_running: MaxProgressRunning::default(), + } + } + /// Creates a test reporter with default settings and calls the given function with it. /// /// Returns the output written to the reporter. - fn with_reporter<'a, F>(f: F, out: &'a mut String) + fn with_reporter<'a, F>(builder: DisplayReporterBuilder, f: F, out: &'a mut String) where F: FnOnce(DisplayReporter<'a>), { @@ -2379,21 +2427,6 @@ mod tests { ) .unwrap(); - let builder = DisplayReporterBuilder { - default_filter: CompiledDefaultFilter::for_default_config(), - status_levels: StatusLevels { - status_level: StatusLevel::Fail, - final_status_level: FinalStatusLevel::Fail, - }, - test_count: 5000, - success_output: Some(TestOutputDisplay::Immediate), - failure_output: Some(TestOutputDisplay::Immediate), - should_colorize: false, - no_capture: true, - show_progress: ShowProgress::Counter, - no_output_indent: false, - max_progress_running: MaxProgressRunning::default(), - }; let output = ReporterStderr::Buffer(out); let reporter = builder.build(&configs, output); f(reporter); @@ -2452,6 +2485,7 @@ mod tests { let mut out = String::new(); with_reporter( + default_builder(), |mut reporter| { // TODO: write a bunch more outputs here. reporter @@ -2508,6 +2542,7 @@ mod tests { let mut out = String::new(); with_reporter( + default_builder(), |mut reporter| { // Test single run with all passing tests let run_stats_success = RunStats { @@ -2685,6 +2720,7 @@ mod tests { let mut out = String::new(); with_reporter( + default_builder(), |mut reporter| { // Info started event. reporter @@ -3130,6 +3166,7 @@ mod tests { let mut out = String::new(); with_reporter( + default_builder(), |reporter| { assert!(reporter.inner.no_capture, "no_capture is true"); assert_eq!( @@ -3151,6 +3188,35 @@ mod tests { &mut out, ); } + + #[test] + fn test_verbose_flag() { + // Test with verbose = false + let mut out_non_verbose = String::new(); + let builder = default_builder(); + with_reporter( + builder, + |reporter| { + assert!( + !reporter.inner.verbose, + "verbose should be false when not set" + ); + }, + &mut out_non_verbose, + ); + + // Test with verbose = true + let mut out_verbose = String::new(); + let mut builder_verbose = default_builder(); + builder_verbose.verbose = true; + with_reporter( + builder_verbose, + |reporter| { + assert!(reporter.inner.verbose, "verbose should be true when set"); + }, + &mut out_verbose, + ); + } } #[cfg(all(windows, test))] diff --git a/nextest-runner/src/reporter/imp.rs b/nextest-runner/src/reporter/imp.rs index 8bf7e6cafbf..67c1c3a9790 100644 --- a/nextest-runner/src/reporter/imp.rs +++ b/nextest-runner/src/reporter/imp.rs @@ -148,6 +148,7 @@ impl ReporterBuilder { failure_output: self.failure_output, should_colorize: self.should_colorize, no_capture: self.no_capture, + verbose: self.verbose, show_progress: self.show_progress, no_output_indent: self.no_output_indent, max_progress_running: self.max_progress_running,