blob: 341db1281c6f32549e0659ec1156bbbd7c2a3080 [file] [log] [blame]
//! Tests for the -Zrustdoc-map feature.
use cargo_test_support::prelude::*;
use cargo_test_support::registry::{self, Package};
use cargo_test_support::{paths, project, str, Project};
fn basic_project() -> Project {
Package::new("bar", "1.0.0")
.file("src/lib.rs", "pub struct Straw;")
.publish();
project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[dependencies]
bar = "1.0"
"#,
)
.file(
"src/lib.rs",
r#"
pub fn myfun() -> Option<bar::Straw> {
None
}
"#,
)
.build()
}
#[expect(deprecated)]
#[cargo_test]
fn ignores_on_stable() {
// Requires -Zrustdoc-map to use.
let p = basic_project();
p.cargo("doc -v --no-deps")
.with_stderr_does_not_contain("[..]--extern-html-root-url[..]")
.run();
}
#[cargo_test(nightly, reason = "--extern-html-root-url is unstable")]
fn simple() {
// Basic test that it works with crates.io.
let p = basic_project();
p.cargo("doc -v --no-deps -Zrustdoc-map")
.masquerade_as_nightly_cargo(&["rustdoc-map"])
.with_stderr_data(str![[r#"
...
[RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]bar=https://docs.rs/bar/1.0.0/[..]`
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[GENERATED] [ROOT]/foo/target/doc/foo/index.html
"#]])
.run();
let myfun = p.read_file("target/doc/foo/fn.myfun.html");
assert!(myfun.contains(r#"href="https://docs.rs/bar/1.0.0/bar/struct.Straw.html""#));
}
#[expect(deprecated)]
#[ignore = "Broken, temporarily disabled until https://github.com/rust-lang/rust/pull/82776 is resolved."]
#[cargo_test]
// #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")]
fn std_docs() {
// Mapping std docs somewhere else.
// For local developers, skip this test if docs aren't installed.
let docs = std::path::Path::new(&paths::sysroot()).join("share/doc/rust/html");
if !docs.exists() {
if cargo_util::is_ci() {
panic!("std docs are not installed, check that the rust-docs component is installed");
} else {
eprintln!(
"documentation not found at {}, \
skipping test (run `rustdoc component add rust-docs` to install",
docs.display()
);
return;
}
}
let p = basic_project();
p.change_file(
".cargo/config.toml",
r#"
[doc.extern-map]
std = "local"
"#,
);
p.cargo("doc -v --no-deps -Zrustdoc-map")
.masquerade_as_nightly_cargo(&["rustdoc-map"])
.with_stderr_contains("[RUNNING] `rustdoc [..]--crate-name foo [..]std=file://[..]")
.run();
let myfun = p.read_file("target/doc/foo/fn.myfun.html");
assert!(myfun.contains(r#"share/doc/rust/html/core/option/enum.Option.html""#));
p.change_file(
".cargo/config.toml",
r#"
[doc.extern-map]
std = "https://example.com/rust/"
"#,
);
p.cargo("doc -v --no-deps -Zrustdoc-map")
.masquerade_as_nightly_cargo(&["rustdoc-map"])
.with_stderr_contains(
"[RUNNING] `rustdoc [..]--crate-name foo [..]std=https://example.com/rust/[..]",
)
.run();
let myfun = p.read_file("target/doc/foo/fn.myfun.html");
assert!(myfun.contains(r#"href="https://example.com/rust/core/option/enum.Option.html""#));
}
#[cargo_test(nightly, reason = "--extern-html-root-url is unstable")]
fn renamed_dep() {
// Handles renamed dependencies.
Package::new("bar", "1.0.0")
.file("src/lib.rs", "pub struct Straw;")
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[dependencies]
groovy = { version = "1.0", package = "bar" }
"#,
)
.file(
"src/lib.rs",
r#"
pub fn myfun() -> Option<groovy::Straw> {
None
}
"#,
)
.build();
p.cargo("doc -v --no-deps -Zrustdoc-map")
.masquerade_as_nightly_cargo(&["rustdoc-map"])
.with_stderr_data(str![[r#"
...
[RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]bar=https://docs.rs/bar/1.0.0/[..]`
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[GENERATED] [ROOT]/foo/target/doc/foo/index.html
"#]])
.run();
let myfun = p.read_file("target/doc/foo/fn.myfun.html");
assert!(myfun.contains(r#"href="https://docs.rs/bar/1.0.0/bar/struct.Straw.html""#));
}
#[cargo_test(nightly, reason = "--extern-html-root-url is unstable")]
fn lib_name() {
// Handles lib name != package name.
Package::new("bar", "1.0.0")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "1.0.0"
[lib]
name = "rumpelstiltskin"
"#,
)
.file("src/lib.rs", "pub struct Straw;")
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies]
bar = "1.0"
"#,
)
.file(
"src/lib.rs",
r#"
pub fn myfun() -> Option<rumpelstiltskin::Straw> {
None
}
"#,
)
.build();
p.cargo("doc -v --no-deps -Zrustdoc-map")
.masquerade_as_nightly_cargo(&["rustdoc-map"])
.with_stderr_data(str![[r#"
...
[RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]rumpelstiltskin=https://docs.rs/bar/1.0.0/[..]`
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[GENERATED] [ROOT]/foo/target/doc/foo/index.html
"#]])
.run();
let myfun = p.read_file("target/doc/foo/fn.myfun.html");
assert!(myfun.contains(r#"href="https://docs.rs/bar/1.0.0/rumpelstiltskin/struct.Straw.html""#));
}
#[cargo_test(nightly, reason = "--extern-html-root-url is unstable")]
fn alt_registry() {
// Supports other registry names.
registry::alt_init();
Package::new("bar", "1.0.0")
.alternative(true)
.file(
"src/lib.rs",
r#"
extern crate baz;
pub struct Queen;
pub use baz::King;
"#,
)
.registry_dep("baz", "1.0")
.publish();
Package::new("baz", "1.0.0")
.alternative(true)
.file("src/lib.rs", "pub struct King;")
.publish();
Package::new("grimm", "1.0.0")
.file("src/lib.rs", "pub struct Gold;")
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[dependencies]
bar = { version = "1.0", registry="alternative" }
grimm = "1.0"
"#,
)
.file(
"src/lib.rs",
r#"
pub fn queen() -> bar::Queen { bar::Queen }
pub fn king() -> bar::King { bar::King }
pub fn gold() -> grimm::Gold { grimm::Gold }
"#,
)
.file(
".cargo/config.toml",
r#"
[doc.extern-map.registries]
alternative = "https://example.com/{pkg_name}/{version}/"
crates-io = "https://docs.rs/"
"#,
)
.build();
p.cargo("doc -v --no-deps -Zrustdoc-map")
.masquerade_as_nightly_cargo(&["rustdoc-map"])
.with_stderr_data(str![[r#"
...
[RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]bar=https://example.com/bar/1.0.0/[..] --extern-html-root-url [..]baz=https://example.com/baz/1.0.0/[..] --extern-html-root-url [..]grimm=https://docs.rs/grimm/1.0.0/[..]`
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[GENERATED] [ROOT]/foo/target/doc/foo/index.html
"#]])
.run();
let queen = p.read_file("target/doc/foo/fn.queen.html");
assert!(queen.contains(r#"href="https://example.com/bar/1.0.0/bar/struct.Queen.html""#));
let king = p.read_file("target/doc/foo/fn.king.html");
assert!(king.contains(r#"href="https://example.com/baz/1.0.0/baz/struct.King.html""#));
let gold = p.read_file("target/doc/foo/fn.gold.html");
assert!(gold.contains(r#"href="https://docs.rs/grimm/1.0.0/grimm/struct.Gold.html""#));
}
#[cargo_test(nightly, reason = "--extern-html-root-url is unstable")]
fn multiple_versions() {
// What happens when there are multiple versions.
// NOTE: This is currently broken behavior. Rustdoc does not provide a way
// to match renamed dependencies.
Package::new("bar", "1.0.0")
.file("src/lib.rs", "pub struct Spin;")
.publish();
Package::new("bar", "2.0.0")
.file("src/lib.rs", "pub struct Straw;")
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[dependencies]
bar = "1.0"
bar2 = {version="2.0", package="bar"}
"#,
)
.file(
"src/lib.rs",
"
pub fn fn1() -> bar::Spin {bar::Spin}
pub fn fn2() -> bar2::Straw {bar2::Straw}
",
)
.build();
p.cargo("doc -v --no-deps -Zrustdoc-map")
.masquerade_as_nightly_cargo(&["rustdoc-map"])
.with_stderr_data(str![[r#"
...
[RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]bar=https://docs.rs/bar/1.0.0/[..] --extern-html-root-url [..]bar=https://docs.rs/bar/2.0.0/[..]`
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[GENERATED] [ROOT]/foo/target/doc/foo/index.html
"#]])
.run();
let fn1 = p.read_file("target/doc/foo/fn.fn1.html");
// This should be 1.0.0, rustdoc seems to use the last entry when there
// are duplicates.
assert!(fn1.contains(r#"href="https://docs.rs/bar/2.0.0/bar/struct.Spin.html""#));
let fn2 = p.read_file("target/doc/foo/fn.fn2.html");
assert!(fn2.contains(r#"href="https://docs.rs/bar/2.0.0/bar/struct.Straw.html""#));
}
#[cargo_test(nightly, reason = "--extern-html-root-url is unstable")]
fn rebuilds_when_changing() {
// Make sure it rebuilds if the map changes.
let p = basic_project();
p.cargo("doc -v --no-deps -Zrustdoc-map")
.masquerade_as_nightly_cargo(&["rustdoc-map"])
.with_stderr_data(str![[r#"
...
[RUNNING] `rustdoc [..]--extern-html-root-url[..]`
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[GENERATED] [ROOT]/foo/target/doc/foo/index.html
"#]])
.run();
// This also tests that the map for docs.rs can be overridden.
p.change_file(
".cargo/config.toml",
r#"
[doc.extern-map.registries]
crates-io = "https://example.com/"
"#,
);
p.cargo("doc -v --no-deps -Zrustdoc-map")
.masquerade_as_nightly_cargo(&["rustdoc-map"])
.with_stderr_data(str![[r#"
...
[RUNNING] `rustdoc [..]--extern-html-root-url [..]bar=https://example.com/bar/1.0.0/[..]`
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[GENERATED] [ROOT]/foo/target/doc/foo/index.html
"#]])
.run();
}
#[cargo_test(nightly, reason = "--extern-html-root-url is unstable")]
fn alt_sparse_registry() {
// Supports other registry names.
registry::init();
let _registry = registry::RegistryBuilder::new()
.http_index()
.alternative()
.build();
Package::new("bar", "1.0.0")
.alternative(true)
.file(
"src/lib.rs",
r#"
extern crate baz;
pub struct Queen;
pub use baz::King;
"#,
)
.registry_dep("baz", "1.0")
.publish();
Package::new("baz", "1.0.0")
.alternative(true)
.file("src/lib.rs", "pub struct King;")
.publish();
Package::new("grimm", "1.0.0")
.file("src/lib.rs", "pub struct Gold;")
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[dependencies]
bar = { version = "1.0", registry="alternative" }
grimm = "1.0"
"#,
)
.file(
"src/lib.rs",
r#"
pub fn queen() -> bar::Queen { bar::Queen }
pub fn king() -> bar::King { bar::King }
pub fn gold() -> grimm::Gold { grimm::Gold }
"#,
)
.file(
".cargo/config.toml",
r#"
[doc.extern-map.registries]
alternative = "https://example.com/{pkg_name}/{version}/"
crates-io = "https://docs.rs/"
"#,
)
.build();
p.cargo("doc -v --no-deps -Zrustdoc-map")
.masquerade_as_nightly_cargo(&["rustdoc-map"])
.with_stderr_data(str![[r#"
...
[RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]bar=https://example.com/bar/1.0.0/[..] --extern-html-root-url [..]baz=https://example.com/baz/1.0.0/[..] --extern-html-root-url [..]grimm=https://docs.rs/grimm/1.0.0/[..]`
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[GENERATED] [ROOT]/foo/target/doc/foo/index.html
"#]])
.run();
let queen = p.read_file("target/doc/foo/fn.queen.html");
assert!(queen.contains(r#"href="https://example.com/bar/1.0.0/bar/struct.Queen.html""#));
let king = p.read_file("target/doc/foo/fn.king.html");
assert!(king.contains(r#"href="https://example.com/baz/1.0.0/baz/struct.King.html""#));
let gold = p.read_file("target/doc/foo/fn.gold.html");
assert!(gold.contains(r#"href="https://docs.rs/grimm/1.0.0/grimm/struct.Gold.html""#));
}
#[expect(deprecated)]
#[cargo_test(nightly, reason = "--extern-html-root-url is unstable")]
fn same_deps_multi_occurrence_in_dep_tree() {
// rust-lang/cargo#13543
Package::new("baz", "1.0.0")
.file("src/lib.rs", "")
.publish();
Package::new("bar", "1.0.0")
.file("src/lib.rs", "")
.dep("baz", "1.0")
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
edition = "2018"
[dependencies]
bar = "1.0"
baz = "1.0"
"#,
)
.file("src/lib.rs", "")
.file(
".cargo/config.toml",
r#"
[doc.extern-map.registries]
crates-io = "https://docs.rs/"
"#,
)
.build();
p.cargo("doc -v --no-deps -Zrustdoc-map")
.masquerade_as_nightly_cargo(&["rustdoc-map"])
.with_stderr_does_not_contain(
"[..]--extern-html-root-url[..]bar=https://docs.rs\
[..]--extern-html-root-url[..]baz=https://docs.rs\
[..]--extern-html-root-url[..]baz=https://docs.rs[..]",
)
.with_stderr_contains(
"[..]--extern-html-root-url[..]bar=https://docs.rs\
[..]--extern-html-root-url[..]baz=https://docs.rs[..]",
)
.run();
}