From 9b1d27d440d58edcb4c673798c60181c03c084c1 Mon Sep 17 00:00:00 2001
From: Arpad Borsos <arpad.borsos@googlemail.com>
Date: Fri, 22 Jan 2021 10:54:53 +0100
Subject: [PATCH] Add option to control doctest run directory

This option will allow splitting the compile-time from the run-time
directory of doctest invocations and is one step to solve
https://github.com/rust-lang/cargo/issues/8993#issuecomment-760088944
---
 src/librustdoc/config.rs                      |  5 ++++
 src/librustdoc/doctest.rs                     |  3 +++
 src/librustdoc/lib.rs                         |  8 +++++++
 .../rustdoc-ui/run-directory.correct.stdout   |  6 +++++
 .../rustdoc-ui/run-directory.incorrect.stdout |  6 +++++
 src/test/rustdoc-ui/run-directory.rs          | 23 +++++++++++++++++++
 6 files changed, 51 insertions(+)
 create mode 100644 src/test/rustdoc-ui/run-directory.correct.stdout
 create mode 100644 src/test/rustdoc-ui/run-directory.incorrect.stdout
 create mode 100644 src/test/rustdoc-ui/run-directory.rs

diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index e43ea965c0423..508bed072e61d 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -103,6 +103,8 @@ crate struct Options {
     crate should_test: bool,
     /// List of arguments to pass to the test harness, if running tests.
     crate test_args: Vec<String>,
+    /// The working directory in which to run tests.
+    crate test_run_directory: Option<PathBuf>,
     /// Optional path to persist the doctest executables to, defaults to a
     /// temporary directory if not set.
     crate persist_doctests: Option<PathBuf>,
@@ -175,6 +177,7 @@ impl fmt::Debug for Options {
             .field("lint_cap", &self.lint_cap)
             .field("should_test", &self.should_test)
             .field("test_args", &self.test_args)
+            .field("test_run_directory", &self.test_run_directory)
             .field("persist_doctests", &self.persist_doctests)
             .field("default_passes", &self.default_passes)
             .field("manual_passes", &self.manual_passes)
@@ -572,6 +575,7 @@ impl Options {
         let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some();
         let static_root_path = matches.opt_str("static-root-path");
         let generate_search_filter = !matches.opt_present("disable-per-crate-search");
+        let test_run_directory = matches.opt_str("test-run-directory").map(PathBuf::from);
         let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from);
         let test_builder = matches.opt_str("test-builder").map(PathBuf::from);
         let codegen_options_strs = matches.opt_strs("C");
@@ -613,6 +617,7 @@ impl Options {
             display_warnings,
             show_coverage,
             crate_version,
+            test_run_directory,
             persist_doctests,
             runtool,
             runtool_args,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index c87ab833f7a5e..09cbd94e4ac3f 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -365,6 +365,9 @@ fn run_test(
     } else {
         cmd = Command::new(output_file);
     }
+    if let Some(run_directory) = options.test_run_directory {
+        cmd.current_dir(run_directory);
+    }
 
     match cmd.output() {
         Err(e) => return Err(TestFailure::ExecutionError(e)),
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 719aca612f50d..d823f789013ff 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -167,6 +167,14 @@ fn opts() -> Vec<RustcOptGroup> {
         stable("test-args", |o| {
             o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")
         }),
+        unstable("test-run-directory", |o| {
+            o.optopt(
+                "",
+                "test-run-directory",
+                "The working directory in which to run tests",
+                "PATH",
+            )
+        }),
         stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")),
         stable("markdown-css", |o| {
             o.optmulti(
diff --git a/src/test/rustdoc-ui/run-directory.correct.stdout b/src/test/rustdoc-ui/run-directory.correct.stdout
new file mode 100644
index 0000000000000..e9b2754794a78
--- /dev/null
+++ b/src/test/rustdoc-ui/run-directory.correct.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/run-directory.rs - foo (line 10) ... 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/run-directory.incorrect.stdout b/src/test/rustdoc-ui/run-directory.incorrect.stdout
new file mode 100644
index 0000000000000..97a5dbc5c0cd1
--- /dev/null
+++ b/src/test/rustdoc-ui/run-directory.incorrect.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/run-directory.rs - foo (line 19) ... 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/run-directory.rs b/src/test/rustdoc-ui/run-directory.rs
new file mode 100644
index 0000000000000..78431c0e80b59
--- /dev/null
+++ b/src/test/rustdoc-ui/run-directory.rs
@@ -0,0 +1,23 @@
+// this test asserts that the cwd of doctest invocations is set correctly.
+
+// revisions: correct incorrect
+// check-pass
+// [correct]compile-flags:--test --test-run-directory={{src-base}}
+// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```
+/// assert_eq!(
+///     std::fs::read_to_string("run-directory.rs").unwrap(),
+///     include_str!("run-directory.rs"),
+/// );
+/// ```
+#[cfg(correct)]
+pub fn foo() {}
+
+/// ```
+/// assert!(std::fs::read_to_string("run-directory.rs").is_err());
+/// ```
+#[cfg(incorrect)]
+pub fn foo() {}