]> git.proxmox.com Git - cargo.git/commitdiff
Run rustdoc doctests relative to the workspace
authorArpad Borsos <arpad.borsos@googlemail.com>
Mon, 22 Feb 2021 19:06:03 +0000 (20:06 +0100)
committerArpad Borsos <arpad.borsos@googlemail.com>
Mon, 22 Feb 2021 19:33:31 +0000 (20:33 +0100)
By doing so, rustdoc will also emit workspace-relative filenames for the doctests.

This was first landed in #8954 but later backed out in #8996 because it changed the CWD of rustdoc test invocations.

The second try relies on the new `--test-run-directory` rustdoc option which was added in https://github.com/rust-lang/rust/pull/81264 to explicitly control the rustdoc test cwd.

fixes #8993

12 files changed:
src/cargo/core/compiler/fingerprint.rs
src/cargo/core/compiler/mod.rs
src/cargo/core/features.rs
src/cargo/ops/cargo_test.rs
src/cargo/util/mod.rs
src/cargo/util/workspace.rs
tests/testsuite/build_script.rs
tests/testsuite/cross_compile.rs
tests/testsuite/doc.rs
tests/testsuite/lto.rs
tests/testsuite/rename_deps.rs
tests/testsuite/test.rs

index 76f1a3b02fda62441fc063694b4b22751089d7a6..9c776d09fc7bd241592135cdad22e3fb5e7745e7 100644 (file)
@@ -334,7 +334,7 @@ use crate::util;
 use crate::util::errors::{CargoResult, CargoResultExt};
 use crate::util::interning::InternedString;
 use crate::util::paths;
-use crate::util::{internal, profile, ProcessBuilder};
+use crate::util::{internal, path_args, profile, ProcessBuilder};
 
 use super::custom_build::BuildDeps;
 use super::job::{Job, Work};
@@ -1324,7 +1324,7 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Finger
         profile: profile_hash,
         // Note that .0 is hashed here, not .1 which is the cwd. That doesn't
         // actually affect the output artifact so there's no need to hash it.
-        path: util::hash_u64(super::path_args(cx.bcx, unit).0),
+        path: util::hash_u64(path_args(cx.bcx.ws, unit).0),
         features: format!("{:?}", unit.features),
         deps,
         local: Mutex::new(local),
index 238deaab8a15a291e30a954c078e6977d5662f9e..3c47cef8adfd3fa0858c287bd686aaa2f096fc26 100644 (file)
@@ -57,7 +57,7 @@ use crate::util::errors::{self, CargoResult, CargoResultExt, ProcessError, Verbo
 use crate::util::interning::InternedString;
 use crate::util::machine_message::Message;
 use crate::util::{self, machine_message, ProcessBuilder};
-use crate::util::{internal, join_paths, paths, profile};
+use crate::util::{add_path_args, internal, join_paths, paths, profile};
 
 const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version";
 
@@ -582,7 +582,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
     let mut rustdoc = cx.compilation.rustdoc_process(unit, None)?;
     rustdoc.inherit_jobserver(&cx.jobserver);
     rustdoc.arg("--crate-name").arg(&unit.target.crate_name());
-    add_path_args(bcx, unit, &mut rustdoc);
+    add_path_args(bcx.ws, unit, &mut rustdoc);
     add_cap_lints(bcx, unit, &mut rustdoc);
 
     if let CompileKind::Target(target) = unit.kind {
@@ -662,41 +662,6 @@ fn append_crate_version_flag(unit: &Unit, rustdoc: &mut ProcessBuilder) {
         .arg(unit.pkg.version().to_string());
 }
 
-// The path that we pass to rustc is actually fairly important because it will
-// show up in error messages (important for readability), debug information
-// (important for caching), etc. As a result we need to be pretty careful how we
-// actually invoke rustc.
-//
-// In general users don't expect `cargo build` to cause rebuilds if you change
-// directories. That could be if you just change directories in the package or
-// if you literally move the whole package wholesale to a new directory. As a
-// result we mostly don't factor in `cwd` to this calculation. Instead we try to
-// track the workspace as much as possible and we update the current directory
-// of rustc/rustdoc where appropriate.
-//
-// The first returned value here is the argument to pass to rustc, and the
-// second is the cwd that rustc should operate in.
-fn path_args(bcx: &BuildContext<'_, '_>, unit: &Unit) -> (PathBuf, PathBuf) {
-    let ws_root = bcx.ws.root();
-    let src = match unit.target.src_path() {
-        TargetSourcePath::Path(path) => path.to_path_buf(),
-        TargetSourcePath::Metabuild => unit.pkg.manifest().metabuild_path(bcx.ws.target_dir()),
-    };
-    assert!(src.is_absolute());
-    if unit.pkg.package_id().source_id().is_path() {
-        if let Ok(path) = src.strip_prefix(ws_root) {
-            return (path.to_path_buf(), ws_root.to_path_buf());
-        }
-    }
-    (src, unit.pkg.root().to_path_buf())
-}
-
-fn add_path_args(bcx: &BuildContext<'_, '_>, unit: &Unit, cmd: &mut ProcessBuilder) {
-    let (arg, cwd) = path_args(bcx, unit);
-    cmd.arg(arg);
-    cmd.cwd(cwd);
-}
-
 fn add_cap_lints(bcx: &BuildContext<'_, '_>, unit: &Unit, cmd: &mut ProcessBuilder) {
     // If this is an upstream dep we don't want warnings from, turn off all
     // lints.
@@ -786,7 +751,7 @@ fn build_base_args(
         cmd.arg(format!("--edition={}", edition));
     }
 
-    add_path_args(bcx, unit, cmd);
+    add_path_args(bcx.ws, unit, cmd);
     add_error_format_and_color(cx, cmd, cx.rmeta_required(unit));
 
     if !test {
index 494e3399300d67103388241738477b18eb81ff73..3256f687f883be9d2988d17ffa65605b5565d307 100644 (file)
@@ -433,6 +433,7 @@ pub struct CliUnstable {
     pub build_std_features: Option<Vec<String>>,
     pub timings: Option<Vec<String>>,
     pub doctest_xcompile: bool,
+    pub doctest_in_workspace: bool,
     pub panic_abort_tests: bool,
     pub jobserver_per_rustc: bool,
     pub features: Option<Vec<String>>,
@@ -596,6 +597,7 @@ impl CliUnstable {
             "build-std-features" => self.build_std_features = Some(parse_features(v)),
             "timings" => self.timings = Some(parse_timings(v)),
             "doctest-xcompile" => self.doctest_xcompile = parse_empty(k, v)?,
+            "doctest-in-workspace" => self.doctest_in_workspace = parse_empty(k, v)?,
             "panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?,
             "jobserver-per-rustc" => self.jobserver_per_rustc = parse_empty(k, v)?,
             "features" => {
index a9f50168ca42aedece0fd25b94f9d61b48410ac0..c0bc2106671ba0fe6657b243c3306b48c445b1ac 100644 (file)
@@ -5,7 +5,7 @@ use crate::core::shell::Verbosity;
 use crate::core::Workspace;
 use crate::ops;
 use crate::util::errors::CargoResult;
-use crate::util::{CargoTestError, Config, ProcessError, Test};
+use crate::util::{add_path_args, CargoTestError, Config, ProcessError, Test};
 
 pub struct TestOptions {
     pub compile_opts: ops::CompileOptions,
@@ -30,7 +30,7 @@ pub fn run_tests(
         return Ok(Some(CargoTestError::new(test, errors)));
     }
 
-    let (doctest, docerrors) = run_doc_tests(ws.config(), options, test_args, &compilation)?;
+    let (doctest, docerrors) = run_doc_tests(ws, options, test_args, &compilation)?;
     let test = if docerrors.is_empty() { test } else { doctest };
     errors.extend(docerrors);
     if errors.is_empty() {
@@ -136,13 +136,15 @@ fn run_unit_tests(
 }
 
 fn run_doc_tests(
-    config: &Config,
+    ws: &Workspace<'_>,
     options: &TestOptions,
     test_args: &[&str],
     compilation: &Compilation<'_>,
 ) -> CargoResult<(Test, Vec<ProcessError>)> {
+    let config = ws.config();
     let mut errors = Vec::new();
     let doctest_xcompile = config.cli_unstable().doctest_xcompile;
+    let doctest_in_workspace = config.cli_unstable().doctest_in_workspace;
 
     for doctest_info in &compilation.to_doc_test {
         let Doctest {
@@ -167,10 +169,18 @@ fn run_doc_tests(
 
         config.shell().status("Doc-tests", unit.target.name())?;
         let mut p = compilation.rustdoc_process(unit, *script_meta)?;
-        p.arg("--test")
-            .arg(unit.target.src_path().path().unwrap())
-            .arg("--crate-name")
-            .arg(&unit.target.crate_name());
+        p.arg("--crate-name").arg(&unit.target.crate_name());
+        p.arg("--test");
+
+        if doctest_in_workspace {
+            add_path_args(ws, unit, &mut p);
+            // FIXME(swatinem): remove the `unstable-options` once rustdoc stabilizes the `test-run-directory` option
+            p.arg("-Z").arg("unstable-options");
+            p.arg("--test-run-directory")
+                .arg(unit.pkg.root().to_path_buf());
+        } else {
+            p.arg(unit.target.src_path().path().unwrap());
+        }
 
         if doctest_xcompile {
             if let CompileKind::Target(target) = unit.kind {
index f0408d2a920d0fdb937fd778ad82c00e8097b738..42b243bf917f8a732fd4a329d084539ba1c5b46e 100644 (file)
@@ -27,8 +27,8 @@ pub use self::sha256::Sha256;
 pub use self::to_semver::ToSemver;
 pub use self::vcs::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo};
 pub use self::workspace::{
-    print_available_benches, print_available_binaries, print_available_examples,
-    print_available_packages, print_available_tests,
+    add_path_args, path_args, print_available_benches, print_available_binaries,
+    print_available_examples, print_available_packages, print_available_tests,
 };
 
 mod canonical_url;
index d261717dc10cf4945ab3c1597d5105c09d75faa2..0cac29f677f321a4f2031b02c0a9e96765e92494 100644 (file)
@@ -1,8 +1,12 @@
+use super::ProcessBuilder;
+use crate::core::compiler::Unit;
+use crate::core::manifest::TargetSourcePath;
 use crate::core::{Target, Workspace};
 use crate::ops::CompileOptions;
 use crate::util::CargoResult;
 use anyhow::bail;
 use std::fmt::Write;
+use std::path::PathBuf;
 
 fn get_available_targets<'a>(
     filter_fn: fn(&Target) -> bool,
@@ -89,3 +93,38 @@ pub fn print_available_benches(ws: &Workspace<'_>, options: &CompileOptions) ->
 pub fn print_available_tests(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
     print_available_targets(Target::is_test, ws, options, "--test", "tests")
 }
+
+/// The path that we pass to rustc is actually fairly important because it will
+/// show up in error messages (important for readability), debug information
+/// (important for caching), etc. As a result we need to be pretty careful how we
+/// actually invoke rustc.
+///
+/// In general users don't expect `cargo build` to cause rebuilds if you change
+/// directories. That could be if you just change directories in the package or
+/// if you literally move the whole package wholesale to a new directory. As a
+/// result we mostly don't factor in `cwd` to this calculation. Instead we try to
+/// track the workspace as much as possible and we update the current directory
+/// of rustc/rustdoc where appropriate.
+///
+/// The first returned value here is the argument to pass to rustc, and the
+/// second is the cwd that rustc should operate in.
+pub fn path_args(ws: &Workspace<'_>, unit: &Unit) -> (PathBuf, PathBuf) {
+    let ws_root = ws.root();
+    let src = match unit.target.src_path() {
+        TargetSourcePath::Path(path) => path.to_path_buf(),
+        TargetSourcePath::Metabuild => unit.pkg.manifest().metabuild_path(ws.target_dir()),
+    };
+    assert!(src.is_absolute());
+    if unit.pkg.package_id().source_id().is_path() {
+        if let Ok(path) = src.strip_prefix(ws_root) {
+            return (path.to_path_buf(), ws_root.to_path_buf());
+        }
+    }
+    (src, unit.pkg.root().to_path_buf())
+}
+
+pub fn add_path_args(ws: &Workspace<'_>, unit: &Unit, cmd: &mut ProcessBuilder) {
+    let (arg, cwd) = path_args(ws, unit);
+    cmd.arg(arg);
+    cmd.cwd(cwd);
+}
index 2965ba98e262dbb7dc6d5c01823bd0f685119d2f..89b38810aeb6a7c9813a64c92c2a00142c7f61d3 100644 (file)
@@ -2753,7 +2753,7 @@ fn doctest_receives_build_link_args() {
 
     p.cargo("test -v")
         .with_stderr_contains(
-            "[RUNNING] `rustdoc [..]--test [..] --crate-name foo [..]-L native=bar[..]`",
+            "[RUNNING] `rustdoc [..]--crate-name foo --test [..]-L native=bar[..]`",
         )
         .run();
 }
index a45124cf3b721f1ddbf71999aa3cdf00e66cd236..42c6e2260e4ec2f99ce2f0f91bf66fc2f3a137ce 100644 (file)
@@ -1109,7 +1109,7 @@ fn doctest_xcompile_linker() {
         .masquerade_as_nightly_cargo()
         .with_stderr_contains(&format!(
             "\
-[RUNNING] `rustdoc --crate-type lib --test [..]\
+[RUNNING] `rustdoc --crate-type lib --crate-name foo --test [..]\
     --target {target} [..] -C linker=my-linker-tool[..]
 ",
             target = target,
index 19a720a8d5b83309d099ba692d157fce6880760b..4878c649875ba0ab2562e38dcae6a72abbe34327 100644 (file)
@@ -1640,6 +1640,82 @@ fn crate_versions_flag_is_overridden() {
     asserts(output_documentation());
 }
 
+#[cargo_test]
+fn doc_test_in_workspace() {
+    if !is_nightly() {
+        // -Zdoctest-in-workspace is unstable
+        return;
+    }
+
+    let p = project()
+        .file(
+            "Cargo.toml",
+            r#"
+                [workspace]
+                members = [
+                    "crate-a",
+                    "crate-b",
+                ]
+            "#,
+        )
+        .file(
+            "crate-a/Cargo.toml",
+            r#"
+                [project]
+                name = "crate-a"
+                version = "0.1.0"
+            "#,
+        )
+        .file(
+            "crate-a/src/lib.rs",
+            "\
+                //! ```
+                //! assert_eq!(1, 1);
+                //! ```
+            ",
+        )
+        .file(
+            "crate-b/Cargo.toml",
+            r#"
+                [project]
+                name = "crate-b"
+                version = "0.1.0"
+            "#,
+        )
+        .file(
+            "crate-b/src/lib.rs",
+            "\
+                //! ```
+                //! assert_eq!(1, 1);
+                //! ```
+            ",
+        )
+        .build();
+    p.cargo("test -Zdoctest-in-workspace --doc -vv")
+        .masquerade_as_nightly_cargo()
+        .with_stderr_contains("[DOCTEST] crate-a")
+        .with_stdout_contains(
+            "
+running 1 test
+test crate-a/src/lib.rs - (line 1) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out[..]
+
+",
+        )
+        .with_stderr_contains("[DOCTEST] crate-b")
+        .with_stdout_contains(
+            "
+running 1 test
+test crate-b/src/lib.rs - (line 1) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out[..]
+
+",
+        )
+        .run();
+}
+
 #[cargo_test]
 fn doc_fingerprint_is_versioning_consistent() {
     // Random rustc verbose version
index f3bfe8e829f8b0fc5e424fb21986d0811786a583..a6d0534a168207df0fdb8fae39809a61c1bd5009 100644 (file)
@@ -526,7 +526,7 @@ fn cdylib_and_rlib() {
 [RUNNING] [..]target/release/deps/bar-[..]
 [RUNNING] [..]target/release/deps/b-[..]
 [DOCTEST] bar
-[RUNNING] `rustdoc --crate-type cdylib --crate-type rlib --test [..]-C embed-bitcode=no[..]
+[RUNNING] `rustdoc --crate-type cdylib --crate-type rlib --crate-name bar --test [..]-C embed-bitcode=no[..]
 ",
         )
         .run();
index fc3d11d2737c7051a198088d82f0bdb52ee7a61f..cc0b71736231c306ee24c3aef15d0fa1b1b6a707 100644 (file)
@@ -266,7 +266,7 @@ fn can_run_doc_tests() {
         .with_stderr_contains(
             "\
 [DOCTEST] foo
-[RUNNING] `rustdoc [..]--test [CWD]/src/lib.rs \
+[RUNNING] `rustdoc [..]--test [..]src/lib.rs \
         [..] \
         --extern bar=[CWD]/target/debug/deps/libbar-[..].rlib \
         --extern baz=[CWD]/target/debug/deps/libbar-[..].rlib \
index 620c5d2202df8717d4733e565fc9237847fe7de9..3e86428c338ceb7c2b9a333175a62248599bf0cb 100644 (file)
@@ -4256,6 +4256,7 @@ fn test_workspaces_cwd() {
             r#"
                 //! ```
                 //! assert_eq!("{expected}", std::fs::read_to_string("file.txt").unwrap());
+                //! assert_eq!("{expected}", include_str!("../file.txt"));
                 //! assert_eq!(
                 //!     std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR")),
                 //!     std::env::current_dir().unwrap(),
@@ -4265,6 +4266,7 @@ fn test_workspaces_cwd() {
                 #[test]
                 fn test_unit_{expected}_cwd() {{
                     assert_eq!("{expected}", std::fs::read_to_string("file.txt").unwrap());
+                    assert_eq!("{expected}", include_str!("../file.txt"));
                     assert_eq!(
                         std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR")),
                         std::env::current_dir().unwrap(),
@@ -4280,6 +4282,7 @@ fn test_workspaces_cwd() {
                 #[test]
                 fn test_integration_{expected}_cwd() {{
                     assert_eq!("{expected}", std::fs::read_to_string("file.txt").unwrap());
+                    assert_eq!("{expected}", include_str!("../file.txt"));
                     assert_eq!(
                         std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR")),
                         std::env::current_dir().unwrap(),