diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index 2e4016e24bc3f..c8af369a9695e 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -417,3 +417,10 @@ This flag is **deprecated** and **has no effect**. Rustdoc only supports Rust source code and Markdown input formats. If the file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file. Otherwise, it assumes that the input file is Rust. + +## `--nocapture` + +When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be +captured by rustdoc. Instead, the output will be directed to your terminal, +as if you had run the test executable manually. This is especially useful +for debugging your tests! diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 4cf647a81ae4b..adbdde0d92cd6 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -156,6 +156,8 @@ crate struct Options { crate run_check: bool, /// Whether doctests should emit unused externs crate json_unused_externs: bool, + /// Whether to skip capturing stdout and stderr of tests. + crate nocapture: bool, } impl fmt::Debug for Options { @@ -199,6 +201,7 @@ impl fmt::Debug for Options { .field("enable-per-target-ignores", &self.enable_per_target_ignores) .field("run_check", &self.run_check) .field("no_run", &self.no_run) + .field("nocapture", &self.nocapture) .finish() } } @@ -627,6 +630,7 @@ impl Options { let run_check = matches.opt_present("check"); let generate_redirect_map = matches.opt_present("generate-redirect-map"); let show_type_layout = matches.opt_present("show-type-layout"); + let nocapture = matches.opt_present("nocapture"); let (lint_opts, describe_lints, lint_cap, _) = get_cmd_lint_options(matches, error_format, &debugging_opts); @@ -665,6 +669,7 @@ impl Options { test_builder, run_check, no_run, + nocapture, render_options: RenderOptions { output, external_html, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index c5ca396e72029..5ce7c49278d23 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -107,6 +107,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { let mut test_args = options.test_args.clone(); let display_warnings = options.display_warnings; + let nocapture = options.nocapture; let externs = options.externs.clone(); let json_unused_externs = options.json_unused_externs; @@ -166,6 +167,9 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { }; test_args.insert(0, "rustdoctest".to_string()); + if nocapture { + test_args.push("--nocapture".to_string()); + } test::test_main(&test_args, tests, Some(test::Options::new().display_output(display_warnings))); @@ -456,7 +460,16 @@ fn run_test( cmd.current_dir(run_directory); } - match cmd.output() { + let result = if options.nocapture { + cmd.status().map(|status| process::Output { + status, + stdout: Vec::new(), + stderr: Vec::new(), + }) + } else { + cmd.output() + }; + match result { Err(e) => return Err(TestFailure::ExecutionError(e)), Ok(out) => { if should_panic && out.status.success() { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d4d87819c0d7a..19deaa11388d8 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -604,6 +604,9 @@ fn opts() -> Vec { unstable("show-type-layout", |o| { o.optflagmulti("", "show-type-layout", "Include the memory layout of types in the docs") }), + unstable("nocapture", |o| { + o.optflag("", "nocapture", "Don't capture stdout and stderr of tests") + }), ] } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 45966c0058df4..6c8b95c04c9e4 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -136,6 +136,9 @@ crate fn test(mut options: Options) -> Result<(), String> { find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None); options.test_args.insert(0, "rustdoctest".to_string()); + if options.nocapture { + options.test_args.push("--nocapture".to_string()); + } test::test_main( &options.test_args, collector.tests, diff --git a/src/test/rustdoc-ui/nocapture-fail.rs b/src/test/rustdoc-ui/nocapture-fail.rs new file mode 100644 index 0000000000000..7706bd1f3e39c --- /dev/null +++ b/src/test/rustdoc-ui/nocapture-fail.rs @@ -0,0 +1,12 @@ +// check-pass +// compile-flags:--test -Zunstable-options --nocapture +// normalize-stderr-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ```compile_fail +/// fn foo() { +/// Input: 123 +/// } +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/nocapture-fail.stderr b/src/test/rustdoc-ui/nocapture-fail.stderr new file mode 100644 index 0000000000000..16a5ac47cd257 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture-fail.stderr @@ -0,0 +1,18 @@ +error: struct literal body without path + --> $DIR/nocapture-fail.rs:8:10 + | +LL | fn foo() { + | __________^ +LL | | Input: 123 +LL | | } + | |_^ + | +help: you might have forgotten to add the struct literal inside the block + | +LL | fn foo() { SomeStruct { +LL | Input: 123 +LL | } } + | + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/nocapture-fail.stdout b/src/test/rustdoc-ui/nocapture-fail.stdout new file mode 100644 index 0000000000000..754f77db53ca3 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture-fail.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/nocapture-fail.rs - Foo (line 7) - compile fail ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/nocapture.rs b/src/test/rustdoc-ui/nocapture.rs new file mode 100644 index 0000000000000..321f5ca08eded --- /dev/null +++ b/src/test/rustdoc-ui/nocapture.rs @@ -0,0 +1,10 @@ +// check-pass +// compile-flags:--test -Zunstable-options --nocapture +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ``` +/// println!("hello!"); +/// eprintln!("stderr"); +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/nocapture.stderr b/src/test/rustdoc-ui/nocapture.stderr new file mode 100644 index 0000000000000..af6415db3c724 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture.stderr @@ -0,0 +1 @@ +stderr diff --git a/src/test/rustdoc-ui/nocapture.stdout b/src/test/rustdoc-ui/nocapture.stdout new file mode 100644 index 0000000000000..4880e75da7062 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture.stdout @@ -0,0 +1,7 @@ + +running 1 test +hello! +test $DIR/nocapture.rs - Foo (line 6) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +