Skip to content

Commit 0721cd7

Browse files
committed
Auto merge of #143900 - GuillaumeGomez:fix-no-run, r=lolbinarycat,fmease
[rustdoc] Correctly handle `should_panic` doctest attribute and fix `--no-run` test flag on the 2024 edition Fixes #143009. Fixes #143858. Since it includes fixes from #143453, it's taking it over (commits 2, 3 and 4 are from #143453). For `--no-run`, we forgot to check the "global" options in the 2024 edition, fixed in the first commit. For `should_panic` fix, the exit code check has been fixed. cc `@TroyKomodo` (thanks so much for providing such a complete test, made my life a lot easier!) r? `@notriddle`
2 parents 5b9564a + 7b8015c commit 0721cd7

File tree

11 files changed

+163
-18
lines changed

11 files changed

+163
-18
lines changed

library/std/src/error.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ use crate::fmt::{self, Write};
123123
/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned
124124
/// from `main`.
125125
///
126-
/// ```should_panic
126+
/// ```
127127
/// #![feature(error_reporter)]
128128
/// use std::error::Report;
129129
/// # use std::error::Error;
@@ -154,10 +154,14 @@ use crate::fmt::{self, Write};
154154
/// # Err(SuperError { source: SuperErrorSideKick })
155155
/// # }
156156
///
157-
/// fn main() -> Result<(), Report<SuperError>> {
157+
/// fn run() -> Result<(), Report<SuperError>> {
158158
/// get_super_error()?;
159159
/// Ok(())
160160
/// }
161+
///
162+
/// fn main() {
163+
/// assert!(run().is_err());
164+
/// }
161165
/// ```
162166
///
163167
/// This example produces the following output:
@@ -170,7 +174,7 @@ use crate::fmt::{self, Write};
170174
/// output format. If you want to make sure your `Report`s are pretty printed and include backtrace
171175
/// you will need to manually convert and enable those flags.
172176
///
173-
/// ```should_panic
177+
/// ```
174178
/// #![feature(error_reporter)]
175179
/// use std::error::Report;
176180
/// # use std::error::Error;
@@ -201,12 +205,16 @@ use crate::fmt::{self, Write};
201205
/// # Err(SuperError { source: SuperErrorSideKick })
202206
/// # }
203207
///
204-
/// fn main() -> Result<(), Report<SuperError>> {
208+
/// fn run() -> Result<(), Report<SuperError>> {
205209
/// get_super_error()
206210
/// .map_err(Report::from)
207211
/// .map_err(|r| r.pretty(true).show_backtrace(true))?;
208212
/// Ok(())
209213
/// }
214+
///
215+
/// fn main() {
216+
/// assert!(run().is_err());
217+
/// }
210218
/// ```
211219
///
212220
/// This example produces the following output:

src/librustdoc/doctest.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ pub(crate) fn run_tests(
358358
);
359359

360360
for (doctest, scraped_test) in &doctests {
361-
tests_runner.add_test(doctest, scraped_test, &target_str);
361+
tests_runner.add_test(doctest, scraped_test, &target_str, rustdoc_options);
362362
}
363363
let (duration, ret) = tests_runner.run_merged_tests(
364364
rustdoc_test_options,
@@ -828,7 +828,8 @@ fn run_test(
828828
match result {
829829
Err(e) => return (duration, Err(TestFailure::ExecutionError(e))),
830830
Ok(out) => {
831-
if langstr.should_panic && out.status.success() {
831+
// FIXME: use test::ERROR_EXIT_CODE once public
832+
if langstr.should_panic && out.status.code() != Some(101) {
832833
return (duration, Err(TestFailure::UnexpectedRunPass));
833834
} else if !langstr.should_panic && !out.status.success() {
834835
return (duration, Err(TestFailure::ExecutionFailure(out)));
@@ -1138,7 +1139,7 @@ fn doctest_run_fn(
11381139
eprint!("Test compiled successfully, but it's marked `compile_fail`.");
11391140
}
11401141
TestFailure::UnexpectedRunPass => {
1141-
eprint!("Test executable succeeded, but it's marked `should_panic`.");
1142+
eprint!("Test didn't panic, but it's marked `should_panic`.");
11421143
}
11431144
TestFailure::MissingErrorCodes(codes) => {
11441145
eprint!("Some expected error codes were not found: {codes:?}");

src/librustdoc/doctest/runner.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ impl DocTestRunner {
3939
doctest: &DocTestBuilder,
4040
scraped_test: &ScrapedDocTest,
4141
target_str: &str,
42+
opts: &RustdocOptions,
4243
) {
4344
let ignore = match scraped_test.langstr.ignore {
4445
Ignore::All => true,
@@ -62,6 +63,7 @@ impl DocTestRunner {
6263
self.nb_tests,
6364
&mut self.output,
6465
&mut self.output_merged_tests,
66+
opts,
6567
),
6668
));
6769
self.supports_color &= doctest.supports_color;
@@ -134,13 +136,21 @@ mod __doctest_mod {{
134136
}}
135137
136138
#[allow(unused)]
137-
pub fn doctest_runner(bin: &std::path::Path, test_nb: usize) -> ExitCode {{
139+
pub fn doctest_runner(bin: &std::path::Path, test_nb: usize, should_panic: bool) -> ExitCode {{
138140
let out = std::process::Command::new(bin)
139141
.env(self::RUN_OPTION, test_nb.to_string())
140142
.args(std::env::args().skip(1).collect::<Vec<_>>())
141143
.output()
142144
.expect(\"failed to run command\");
143-
if !out.status.success() {{
145+
if should_panic {{
146+
// FIXME: use test::ERROR_EXIT_CODE once public
147+
if out.status.code() != Some(101) {{
148+
eprintln!(\"Test didn't panic, but it's marked `should_panic`.\");
149+
ExitCode::FAILURE
150+
}} else {{
151+
ExitCode::SUCCESS
152+
}}
153+
}} else if !out.status.success() {{
144154
if let Some(code) = out.status.code() {{
145155
eprintln!(\"Test executable failed (exit status: {{code}}).\");
146156
}} else {{
@@ -223,6 +233,7 @@ fn generate_mergeable_doctest(
223233
id: usize,
224234
output: &mut String,
225235
output_merged_tests: &mut String,
236+
opts: &RustdocOptions,
226237
) -> String {
227238
let test_id = format!("__doctest_{id}");
228239

@@ -256,22 +267,21 @@ fn main() {returns_result} {{
256267
)
257268
.unwrap();
258269
}
259-
let not_running = ignore || scraped_test.langstr.no_run;
270+
let not_running = ignore || scraped_test.no_run(opts);
260271
writeln!(
261272
output_merged_tests,
262273
"
263274
mod {test_id} {{
264275
pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest(
265-
{test_name:?}, {ignore}, {file:?}, {line}, {no_run}, {should_panic},
276+
{test_name:?}, {ignore}, {file:?}, {line}, {no_run}, false,
266277
test::StaticTestFn(
267278
|| {{{runner}}},
268279
));
269280
}}",
270281
test_name = scraped_test.name,
271282
file = scraped_test.path(),
272283
line = scraped_test.line,
273-
no_run = scraped_test.langstr.no_run,
274-
should_panic = !scraped_test.langstr.no_run && scraped_test.langstr.should_panic,
284+
no_run = scraped_test.no_run(opts),
275285
// Setting `no_run` to `true` in `TestDesc` still makes the test run, so we simply
276286
// don't give it the function to run.
277287
runner = if not_running {
@@ -280,11 +290,12 @@ test::StaticTestFn(
280290
format!(
281291
"
282292
if let Some(bin_path) = crate::__doctest_mod::doctest_path() {{
283-
test::assert_test_result(crate::__doctest_mod::doctest_runner(bin_path, {id}))
293+
test::assert_test_result(crate::__doctest_mod::doctest_runner(bin_path, {id}, {should_panic}))
284294
}} else {{
285295
test::assert_test_result(doctest_bundle::{test_id}::__main_fn())
286296
}}
287297
",
298+
should_panic = scraped_test.langstr.should_panic,
288299
)
289300
},
290301
)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Ensure that `should_panic` doctests only succeed if the test actually panicked.
2+
// Regression test for <https://github.com/rust-lang/rust/issues/143009>.
3+
4+
//@ needs-target-std
5+
6+
use run_make_support::rustdoc;
7+
8+
fn check_output(output: String, edition: &str) {
9+
let should_contain = &[
10+
"test test.rs - bad_exit_code (line 1) ... FAILED",
11+
"test test.rs - did_not_panic (line 6) ... FAILED",
12+
"test test.rs - did_panic (line 11) ... ok",
13+
"---- test.rs - bad_exit_code (line 1) stdout ----
14+
Test executable failed (exit status: 1).",
15+
"---- test.rs - did_not_panic (line 6) stdout ----
16+
Test didn't panic, but it's marked `should_panic`.",
17+
"test result: FAILED. 1 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out;",
18+
];
19+
for text in should_contain {
20+
assert!(
21+
output.contains(text),
22+
"output (edition: {edition}) doesn't contain {:?}\nfull output: {output}",
23+
text
24+
);
25+
}
26+
}
27+
28+
fn main() {
29+
check_output(rustdoc().input("test.rs").arg("--test").run_fail().stdout_utf8(), "2015");
30+
31+
// Same check with the merged doctest feature (enabled with the 2024 edition).
32+
check_output(
33+
rustdoc().input("test.rs").arg("--test").edition("2024").run_fail().stdout_utf8(),
34+
"2024",
35+
);
36+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// ```
2+
/// std::process::exit(1);
3+
/// ```
4+
fn bad_exit_code() {}
5+
6+
/// ```should_panic
7+
/// std::process::exit(1);
8+
/// ```
9+
fn did_not_panic() {}
10+
11+
/// ```should_panic
12+
/// panic!("yeay");
13+
/// ```
14+
fn did_panic() {}

tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.stdout

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ test $DIR/failed-doctest-should-panic-2021.rs - Foo (line 10) ... FAILED
55
failures:
66

77
---- $DIR/failed-doctest-should-panic-2021.rs - Foo (line 10) stdout ----
8-
Test executable succeeded, but it's marked `should_panic`.
8+
Test didn't panic, but it's marked `should_panic`.
99

1010
failures:
1111
$DIR/failed-doctest-should-panic-2021.rs - Foo (line 10)

tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11

22
running 1 test
3-
test $DIR/failed-doctest-should-panic.rs - Foo (line 12) - should panic ... FAILED
3+
test $DIR/failed-doctest-should-panic.rs - Foo (line 12) ... FAILED
44

55
failures:
66

77
---- $DIR/failed-doctest-should-panic.rs - Foo (line 12) stdout ----
8-
note: test did not panic as expected at $DIR/failed-doctest-should-panic.rs:12:0
8+
Test didn't panic, but it's marked `should_panic`.
9+
910

1011
failures:
1112
$DIR/failed-doctest-should-panic.rs - Foo (line 12)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
running 7 tests
3+
test $DIR/no-run.rs - f (line 14) - compile ... ok
4+
test $DIR/no-run.rs - f (line 17) - compile ... ok
5+
test $DIR/no-run.rs - f (line 20) ... ignored
6+
test $DIR/no-run.rs - f (line 23) - compile ... ok
7+
test $DIR/no-run.rs - f (line 29) - compile fail ... ok
8+
test $DIR/no-run.rs - f (line 34) - compile ... ok
9+
test $DIR/no-run.rs - f (line 38) - compile ... ok
10+
11+
test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
12+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
running 5 tests
3+
test $DIR/no-run.rs - f (line 14) - compile ... ok
4+
test $DIR/no-run.rs - f (line 17) - compile ... ok
5+
test $DIR/no-run.rs - f (line 23) - compile ... ok
6+
test $DIR/no-run.rs - f (line 34) - compile ... ok
7+
test $DIR/no-run.rs - f (line 38) - compile ... ok
8+
9+
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
10+
11+
12+
running 2 tests
13+
test $DIR/no-run.rs - f (line 20) ... ignored
14+
test $DIR/no-run.rs - f (line 29) - compile fail ... ok
15+
16+
test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
17+
18+
all doctests ran in $TIME; merged doctests compilation took $TIME

tests/rustdoc-ui/doctest/no-run.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// This test ensures that the `--no-run` flag works the same between normal and merged doctests.
2+
// Regression test for <https://github.com/rust-lang/rust/issues/143858>.
3+
4+
//@ check-pass
5+
//@ revisions: edition2021 edition2024
6+
//@ [edition2021]edition:2021
7+
//@ [edition2024]edition:2024
8+
//@ compile-flags:-Z unstable-options --test --no-run --test-args=--test-threads=1
9+
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
10+
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
11+
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
12+
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
13+
14+
/// ```
15+
/// let a = true;
16+
/// ```
17+
/// ```should_panic
18+
/// panic!()
19+
/// ```
20+
/// ```ignore (incomplete-code)
21+
/// fn foo() {
22+
/// ```
23+
/// ```no_run
24+
/// loop {
25+
/// println!("Hello, world");
26+
/// }
27+
/// ```
28+
/// fails to compile
29+
/// ```compile_fail
30+
/// let x = 5;
31+
/// x += 2; // shouldn't compile!
32+
/// ```
33+
/// Ok the test does not run
34+
/// ```
35+
/// panic!()
36+
/// ```
37+
/// Ok the test does not run
38+
/// ```should_panic
39+
/// loop {
40+
/// println!("Hello, world");
41+
/// panic!()
42+
/// }
43+
/// ```
44+
pub fn f() {}

0 commit comments

Comments
 (0)