From fc67798699d0e6641bde443695101b9da04a860d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 Aug 2025 16:08:14 +0200 Subject: [PATCH 1/2] Display merged doctests times as expected depending on the format specified --- src/librustdoc/doctest.rs | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 35ace6566381b..7d37668ba0129 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -12,7 +12,7 @@ use std::process::{self, Command, Stdio}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; -use std::{fmt, panic, str}; +use std::{panic, str}; pub(crate) use make::{BuildDocTestBuilder, DocTestBuilder}; pub(crate) use markdown::test as test_markdown; @@ -60,24 +60,15 @@ impl MergedDoctestTimes { self.added_compilation_times += 1; } - fn display_times(&self) { + /// Returns `(total_time, compilation_time)`. + fn times_in_secs(&self) -> Option<(f64, f64)> { // If no merged doctest was compiled, then there is nothing to display since the numbers // displayed by `libtest` for standalone tests are already accurate (they include both // compilation and runtime). - if self.added_compilation_times > 0 { - println!("{self}"); + if self.added_compilation_times == 0 { + return None; } - } -} - -impl fmt::Display for MergedDoctestTimes { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "all doctests ran in {:.2}s; merged doctests compilation took {:.2}s", - self.total_time.elapsed().as_secs_f64(), - self.compilation_time.as_secs_f64(), - ) + Some((self.total_time.elapsed().as_secs_f64(), self.compilation_time.as_secs_f64())) } } @@ -400,15 +391,21 @@ pub(crate) fn run_tests( if ran_edition_tests == 0 || !standalone_tests.is_empty() { standalone_tests.sort_by(|a, b| a.desc.name.as_slice().cmp(b.desc.name.as_slice())); test::test_main_with_exit_callback(&test_args, standalone_tests, None, || { + let times = times.times_in_secs(); // We ensure temp dir destructor is called. std::mem::drop(temp_dir.take()); - times.display_times(); + if let Some((total_time, compilation_time)) = times { + test::print_merged_doctests_times(&test_args, total_time, compilation_time); + } }); } + let times = times.times_in_secs(); + // We ensure temp dir destructor is called. + std::mem::drop(temp_dir); + if let Some((total_time, compilation_time)) = times { + test::print_merged_doctests_times(&test_args, total_time, compilation_time); + } if nb_errors != 0 { - // We ensure temp dir destructor is called. - std::mem::drop(temp_dir); - times.display_times(); // FIXME(GuillaumeGomez): Uncomment the next line once #144297 has been merged. // std::process::exit(test::ERROR_EXIT_CODE); std::process::exit(101); From 51087b2bce448b5f52ac1121138a106b9459cb50 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 Aug 2025 16:59:58 +0200 Subject: [PATCH 2/2] Add regression test for rustdoc output format --- .../rustdoc-doctest-output-format/file.rs | 3 + .../rustdoc-doctest-output-format/rmake.rs | 79 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 tests/run-make/rustdoc-doctest-output-format/file.rs create mode 100644 tests/run-make/rustdoc-doctest-output-format/rmake.rs diff --git a/tests/run-make/rustdoc-doctest-output-format/file.rs b/tests/run-make/rustdoc-doctest-output-format/file.rs new file mode 100644 index 0000000000000..51d17849fd718 --- /dev/null +++ b/tests/run-make/rustdoc-doctest-output-format/file.rs @@ -0,0 +1,3 @@ +//! ``` +//! let x = 12; +//! ``` diff --git a/tests/run-make/rustdoc-doctest-output-format/rmake.rs b/tests/run-make/rustdoc-doctest-output-format/rmake.rs new file mode 100644 index 0000000000000..a54d62114f1e6 --- /dev/null +++ b/tests/run-make/rustdoc-doctest-output-format/rmake.rs @@ -0,0 +1,79 @@ +//! Regression test to ensure that the output format is respected for doctests. +//! +//! Regression test for . + +use run_make_support::{rustdoc, serde_json}; + +fn run_test(edition: &str, format: Option<&str>) -> String { + let mut r = rustdoc(); + r.input("file.rs").edition(edition).arg("--test"); + if let Some(format) = format { + r.args(&["--test-args", "-Zunstable-options"]).args(&[ + "--test-args", + "--format", + "--test-args", + format, + ]); + } + r.run().stdout_utf8() +} + +fn check_json_output(edition: &str, expected_reports: usize) { + let out = run_test(edition, Some("json")); + let mut found_report = 0; + for (line_nb, line) in out.lines().enumerate() { + match serde_json::from_str::(&line) { + Ok(value) => { + if value.get("type") == Some(&serde_json::json!("report")) { + found_report += 1; + } + } + Err(error) => panic!( + "failed for {edition} edition (json format) at line {}: non-JSON value: {error}\n\ + ====== output ======\n{out}", + line_nb + 1, + ), + } + } + if found_report != expected_reports { + panic!( + "failed for {edition} edition (json format): expected {expected_reports} doctest \ + time `report`, found {found_report}\n====== output ======\n{out}", + ); + } +} + +fn check_non_json_output(edition: &str, expected_reports: usize) { + let out = run_test(edition, None); + let mut found_report = 0; + for (line_nb, line) in out.lines().enumerate() { + if line.starts_with('{') && serde_json::from_str::(&line).is_ok() { + panic!( + "failed for {edition} edition: unexpected json at line {}: `{line}`\n\ + ====== output ======\n{out}", + line_nb + 1 + ); + } + if line.starts_with("all doctests ran in") + && line.contains("; merged doctests compilation took ") + { + found_report += 1; + } + } + if found_report != expected_reports { + panic!( + "failed for {edition} edition: expected {expected_reports} doctest time `report`, \ + found {found_report}\n====== output ======\n{out}", + ); + } +} + +fn main() { + // Only the merged doctests generate the "times report". + check_json_output("2021", 0); + check_json_output("2024", 1); + + // Only the merged doctests generate the "times report". + check_non_json_output("2021", 0); + check_non_json_output("2024", 1); +}