@@ -39,6 +39,7 @@ impl DocTestRunner {
39
39
doctest : & DocTestBuilder ,
40
40
scraped_test : & ScrapedDocTest ,
41
41
target_str : & str ,
42
+ opts : & RustdocOptions ,
42
43
) {
43
44
let ignore = match scraped_test. langstr . ignore {
44
45
Ignore :: All => true ,
@@ -62,6 +63,7 @@ impl DocTestRunner {
62
63
self . nb_tests,
63
64
& mut self . output,
64
65
& mut self . output_merged_tests,
66
+ opts,
65
67
) ,
66
68
) ) ;
67
69
self . supports_color &= doctest. supports_color ;
@@ -127,20 +129,30 @@ mod __doctest_mod {{
127
129
128
130
pub static BINARY_PATH: OnceLock<PathBuf> = OnceLock::new();
129
131
pub const RUN_OPTION: &str = \" RUSTDOC_DOCTEST_RUN_NB_TEST\" ;
132
+ pub const SHOULD_PANIC_DISABLED: bool = (
133
+ cfg!(target_family = \" wasm\" ) || cfg!(target_os = \" zkvm\" )
134
+ ) && !cfg!(target_os = \" emscripten\" );
130
135
131
136
#[allow(unused)]
132
137
pub fn doctest_path() -> Option<&'static PathBuf> {{
133
138
self::BINARY_PATH.get()
134
139
}}
135
140
136
141
#[allow(unused)]
137
- pub fn doctest_runner(bin: &std::path::Path, test_nb: usize) -> ExitCode {{
142
+ pub fn doctest_runner(bin: &std::path::Path, test_nb: usize, should_panic: bool ) -> ExitCode {{
138
143
let out = std::process::Command::new(bin)
139
144
.env(self::RUN_OPTION, test_nb.to_string())
140
145
.args(std::env::args().skip(1).collect::<Vec<_>>())
141
146
.output()
142
147
.expect(\" failed to run command\" );
143
- if !out.status.success() {{
148
+ if should_panic {{
149
+ if out.status.code() != Some(test::ERROR_EXIT_CODE) {{
150
+ eprintln!(\" Test didn't panic, but it's marked `should_panic`.\" );
151
+ ExitCode::FAILURE
152
+ }} else {{
153
+ ExitCode::SUCCESS
154
+ }}
155
+ }} else if !out.status.success() {{
144
156
if let Some(code) = out.status.code() {{
145
157
eprintln!(\" Test executable failed (exit status: {{code}}).\" );
146
158
}} else {{
@@ -223,6 +235,7 @@ fn generate_mergeable_doctest(
223
235
id : usize ,
224
236
output : & mut String ,
225
237
output_merged_tests : & mut String ,
238
+ opts : & RustdocOptions ,
226
239
) -> String {
227
240
let test_id = format ! ( "__doctest_{id}" ) ;
228
241
@@ -256,31 +269,33 @@ fn main() {returns_result} {{
256
269
)
257
270
. unwrap ( ) ;
258
271
}
259
- let not_running = ignore || scraped_test. langstr . no_run ;
272
+ let should_panic = scraped_test. langstr . should_panic ;
273
+ let not_running = ignore || scraped_test. no_run ( opts) ;
260
274
writeln ! (
261
275
output_merged_tests,
262
276
"
263
277
mod {test_id} {{
264
278
pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest(
265
- {test_name:?}, {ignore}, {file:?}, {line}, {no_run}, {should_panic} ,
279
+ {test_name:?}, {ignore} || ({should_panic} && crate::__doctest_mod::SHOULD_PANIC_DISABLED) , {file:?}, {line}, {no_run}, false ,
266
280
test::StaticTestFn(
267
281
|| {{{runner}}},
268
282
));
269
283
}}" ,
270
284
test_name = scraped_test. name,
271
285
file = scraped_test. path( ) ,
272
286
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,
287
+ no_run = scraped_test. no_run( opts) ,
275
288
// Setting `no_run` to `true` in `TestDesc` still makes the test run, so we simply
276
289
// don't give it the function to run.
277
290
runner = if not_running {
278
291
"test::assert_test_result(Ok::<(), String>(()))" . to_string( )
279
292
} else {
280
293
format!(
281
294
"
282
- if let Some(bin_path) = crate::__doctest_mod::doctest_path() {{
283
- test::assert_test_result(crate::__doctest_mod::doctest_runner(bin_path, {id}))
295
+ if {should_panic} && crate::__doctest_mod::SHOULD_PANIC_DISABLED {{
296
+ test::assert_test_result(Ok::<(), String>(()))
297
+ }} else if let Some(bin_path) = crate::__doctest_mod::doctest_path() {{
298
+ test::assert_test_result(crate::__doctest_mod::doctest_runner(bin_path, {id}, {should_panic}))
284
299
}} else {{
285
300
test::assert_test_result(doctest_bundle::{test_id}::__main_fn())
286
301
}}
0 commit comments