mirror of
https://github.com/rust-lang/cargo
synced 2024-10-14 03:32:39 +00:00
727baf0db1
Previously, rustdoc would warn about linking to items in a binary, even though cargo unconditionally documents private items in a binary. This changes cargo to silence the warning, since it's only relevant in cases where the private items might not be documented.
2791 lines
71 KiB
Rust
2791 lines
71 KiB
Rust
//! Tests for the `cargo doc` command.
|
|
|
|
use cargo::core::compiler::RustDocFingerprint;
|
|
use cargo_test_support::paths::CargoPathExt;
|
|
use cargo_test_support::registry::Package;
|
|
use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project};
|
|
use cargo_test_support::{is_nightly, rustc_host, symlink_supported, tools};
|
|
use std::fs;
|
|
use std::str;
|
|
|
|
#[cargo_test]
|
|
fn simple() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
build = "build.rs"
|
|
"#,
|
|
)
|
|
.file("build.rs", "fn main() {}")
|
|
.file("src/lib.rs", "pub fn foo() {}")
|
|
.build();
|
|
|
|
p.cargo("doc")
|
|
.with_stderr(
|
|
"\
|
|
[..] foo v0.0.1 ([CWD])
|
|
[..] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
assert!(p.root().join("target/doc").is_dir());
|
|
assert!(p.root().join("target/doc/foo/index.html").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_no_libs() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[[bin]]
|
|
name = "foo"
|
|
doc = false
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "bad code")
|
|
.build();
|
|
|
|
p.cargo("doc").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_twice() {
|
|
let p = project().file("src/lib.rs", "pub fn foo() {}").build();
|
|
|
|
p.cargo("doc")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
p.cargo("doc").with_stdout("").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_deps() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dependencies.bar]
|
|
path = "bar"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "extern crate bar; pub fn foo() {}")
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
|
|
.file("bar/src/lib.rs", "pub fn bar() {}")
|
|
.build();
|
|
|
|
p.cargo("doc")
|
|
.with_stderr(
|
|
"\
|
|
[..] bar v0.0.1 ([CWD]/bar)
|
|
[..] bar v0.0.1 ([CWD]/bar)
|
|
[DOCUMENTING] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
assert!(p.root().join("target/doc").is_dir());
|
|
assert!(p.root().join("target/doc/foo/index.html").is_file());
|
|
assert!(p.root().join("target/doc/bar/index.html").is_file());
|
|
|
|
// Verify that it only emits rmeta for the dependency.
|
|
assert_eq!(p.glob("target/debug/**/*.rlib").count(), 0);
|
|
assert_eq!(p.glob("target/debug/deps/libbar-*.rmeta").count(), 1);
|
|
|
|
p.cargo("doc")
|
|
.env("CARGO_LOG", "cargo::ops::cargo_rustc::fingerprint")
|
|
.with_stdout("")
|
|
.run();
|
|
|
|
assert!(p.root().join("target/doc").is_dir());
|
|
assert!(p.root().join("target/doc/foo/index.html").is_file());
|
|
assert!(p.root().join("target/doc/bar/index.html").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_no_deps() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dependencies.bar]
|
|
path = "bar"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "extern crate bar; pub fn foo() {}")
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
|
|
.file("bar/src/lib.rs", "pub fn bar() {}")
|
|
.build();
|
|
|
|
p.cargo("doc --no-deps")
|
|
.with_stderr(
|
|
"\
|
|
[CHECKING] bar v0.0.1 ([CWD]/bar)
|
|
[DOCUMENTING] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
assert!(p.root().join("target/doc").is_dir());
|
|
assert!(p.root().join("target/doc/foo/index.html").is_file());
|
|
assert!(!p.root().join("target/doc/bar/index.html").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_only_bin() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dependencies.bar]
|
|
path = "bar"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "extern crate bar; pub fn foo() {}")
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
|
|
.file("bar/src/lib.rs", "pub fn bar() {}")
|
|
.build();
|
|
|
|
p.cargo("doc -v").run();
|
|
|
|
assert!(p.root().join("target/doc").is_dir());
|
|
assert!(p.root().join("target/doc/bar/index.html").is_file());
|
|
assert!(p.root().join("target/doc/foo/index.html").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_multiple_targets_same_name_lib() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["foo", "bar"]
|
|
"#,
|
|
)
|
|
.file(
|
|
"foo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
[lib]
|
|
name = "foo_lib"
|
|
"#,
|
|
)
|
|
.file("foo/src/lib.rs", "")
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
[lib]
|
|
name = "foo_lib"
|
|
"#,
|
|
)
|
|
.file("bar/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc --workspace")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
error: document output filename collision
|
|
The lib `foo_lib` in package `foo v0.1.0 ([ROOT]/foo/foo)` has the same name as \
|
|
the lib `foo_lib` in package `bar v0.1.0 ([ROOT]/foo/bar)`.
|
|
Only one may be documented at once since they output to the same path.
|
|
Consider documenting only one, renaming one, or marking one with `doc = false` in Cargo.toml.
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_multiple_targets_same_name() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["foo", "bar"]
|
|
"#,
|
|
)
|
|
.file(
|
|
"foo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
[[bin]]
|
|
name = "foo_lib"
|
|
path = "src/foo_lib.rs"
|
|
"#,
|
|
)
|
|
.file("foo/src/foo_lib.rs", "")
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
[lib]
|
|
name = "foo_lib"
|
|
"#,
|
|
)
|
|
.file("bar/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc --workspace")
|
|
.with_stderr_unordered(
|
|
"\
|
|
warning: output filename collision.
|
|
The bin target `foo_lib` in package `foo v0.1.0 ([ROOT]/foo/foo)` \
|
|
has the same output filename as the lib target `foo_lib` in package \
|
|
`bar v0.1.0 ([ROOT]/foo/bar)`.
|
|
Colliding filename is: [ROOT]/foo/target/doc/foo_lib/index.html
|
|
The targets should have unique names.
|
|
This is a known bug where multiple crates with the same name use
|
|
the same path; see <https://github.com/rust-lang/cargo/issues/6313>.
|
|
[DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar)
|
|
[DOCUMENTING] foo v0.1.0 ([ROOT]/foo/foo)
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_multiple_targets_same_name_bin() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["foo", "bar"]
|
|
"#,
|
|
)
|
|
.file(
|
|
"foo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("foo/src/bin/foo-cli.rs", "")
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("bar/src/bin/foo-cli.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc --workspace")
|
|
.with_status(101)
|
|
.with_stderr(
|
|
"\
|
|
error: document output filename collision
|
|
The bin `foo-cli` in package `foo v0.1.0 ([ROOT]/foo/foo)` has the same name as \
|
|
the bin `foo-cli` in package `bar v0.1.0 ([ROOT]/foo/bar)`.
|
|
Only one may be documented at once since they output to the same path.
|
|
Consider documenting only one, renaming one, or marking one with `doc = false` in Cargo.toml.
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_multiple_targets_same_name_undoced() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["foo", "bar"]
|
|
"#,
|
|
)
|
|
.file(
|
|
"foo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
[[bin]]
|
|
name = "foo-cli"
|
|
"#,
|
|
)
|
|
.file("foo/src/foo-cli.rs", "")
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
[[bin]]
|
|
name = "foo-cli"
|
|
doc = false
|
|
"#,
|
|
)
|
|
.file("bar/src/foo-cli.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc --workspace").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_lib_bin_same_name_documents_lib() {
|
|
let p = project()
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
//! Binary documentation
|
|
extern crate foo;
|
|
fn main() {
|
|
foo::foo();
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
//! Library documentation
|
|
pub fn foo() {}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
let doc_html = p.read_file("target/doc/foo/index.html");
|
|
assert!(doc_html.contains("Library"));
|
|
assert!(!doc_html.contains("Binary"));
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_lib_bin_same_name_documents_lib_when_requested() {
|
|
let p = project()
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
//! Binary documentation
|
|
extern crate foo;
|
|
fn main() {
|
|
foo::foo();
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
//! Library documentation
|
|
pub fn foo() {}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc --lib")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
let doc_html = p.read_file("target/doc/foo/index.html");
|
|
assert!(doc_html.contains("Library"));
|
|
assert!(!doc_html.contains("Binary"));
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_lib_bin_same_name_documents_named_bin_when_requested() {
|
|
let p = project()
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
//! Binary documentation
|
|
extern crate foo;
|
|
fn main() {
|
|
foo::foo();
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
//! Library documentation
|
|
pub fn foo() {}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc --bin foo")
|
|
// The checking/documenting lines are sometimes swapped since they run
|
|
// concurrently.
|
|
.with_stderr_unordered(
|
|
"\
|
|
warning: output filename collision.
|
|
The bin target `foo` in package `foo v0.0.1 ([ROOT]/foo)` \
|
|
has the same output filename as the lib target `foo` in package `foo v0.0.1 ([ROOT]/foo)`.
|
|
Colliding filename is: [ROOT]/foo/target/doc/foo/index.html
|
|
The targets should have unique names.
|
|
This is a known bug where multiple crates with the same name use
|
|
the same path; see <https://github.com/rust-lang/cargo/issues/6313>.
|
|
[CHECKING] foo v0.0.1 ([CWD])
|
|
[DOCUMENTING] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
let doc_html = p.read_file("target/doc/foo/index.html");
|
|
assert!(!doc_html.contains("Library"));
|
|
assert!(doc_html.contains("Binary"));
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_lib_bin_same_name_documents_bins_when_requested() {
|
|
let p = project()
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
//! Binary documentation
|
|
extern crate foo;
|
|
fn main() {
|
|
foo::foo();
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
//! Library documentation
|
|
pub fn foo() {}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc --bins")
|
|
// The checking/documenting lines are sometimes swapped since they run
|
|
// concurrently.
|
|
.with_stderr_unordered(
|
|
"\
|
|
warning: output filename collision.
|
|
The bin target `foo` in package `foo v0.0.1 ([ROOT]/foo)` \
|
|
has the same output filename as the lib target `foo` in package `foo v0.0.1 ([ROOT]/foo)`.
|
|
Colliding filename is: [ROOT]/foo/target/doc/foo/index.html
|
|
The targets should have unique names.
|
|
This is a known bug where multiple crates with the same name use
|
|
the same path; see <https://github.com/rust-lang/cargo/issues/6313>.
|
|
[CHECKING] foo v0.0.1 ([CWD])
|
|
[DOCUMENTING] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
let doc_html = p.read_file("target/doc/foo/index.html");
|
|
assert!(!doc_html.contains("Library"));
|
|
assert!(doc_html.contains("Binary"));
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_lib_bin_example_same_name_documents_named_example_when_requested() {
|
|
let p = project()
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
//! Binary documentation
|
|
extern crate foo;
|
|
fn main() {
|
|
foo::foo();
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
//! Library documentation
|
|
pub fn foo() {}
|
|
"#,
|
|
)
|
|
.file(
|
|
"examples/ex1.rs",
|
|
r#"
|
|
//! Example1 documentation
|
|
pub fn x() { f(); }
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc --example ex1")
|
|
// The checking/documenting lines are sometimes swapped since they run
|
|
// concurrently.
|
|
.with_stderr_unordered(
|
|
"\
|
|
[CHECKING] foo v0.0.1 ([CWD])
|
|
[DOCUMENTING] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
|
|
)
|
|
.run();
|
|
|
|
let doc_html = p.read_file("target/doc/ex1/index.html");
|
|
assert!(!doc_html.contains("Library"));
|
|
assert!(!doc_html.contains("Binary"));
|
|
assert!(doc_html.contains("Example1"));
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_lib_bin_example_same_name_documents_examples_when_requested() {
|
|
let p = project()
|
|
.file(
|
|
"src/main.rs",
|
|
r#"
|
|
//! Binary documentation
|
|
extern crate foo;
|
|
fn main() {
|
|
foo::foo();
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
//! Library documentation
|
|
pub fn foo() {}
|
|
"#,
|
|
)
|
|
.file(
|
|
"examples/ex1.rs",
|
|
r#"
|
|
//! Example1 documentation
|
|
pub fn example1() { f(); }
|
|
"#,
|
|
)
|
|
.file(
|
|
"examples/ex2.rs",
|
|
r#"
|
|
//! Example2 documentation
|
|
pub fn example2() { f(); }
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc --examples")
|
|
// The checking/documenting lines are sometimes swapped since they run
|
|
// concurrently.
|
|
.with_stderr_unordered(
|
|
"\
|
|
[CHECKING] foo v0.0.1 ([CWD])
|
|
[DOCUMENTING] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
|
|
)
|
|
.run();
|
|
|
|
let example_doc_html_1 = p.read_file("target/doc/ex1/index.html");
|
|
let example_doc_html_2 = p.read_file("target/doc/ex2/index.html");
|
|
|
|
assert!(!example_doc_html_1.contains("Library"));
|
|
assert!(!example_doc_html_1.contains("Binary"));
|
|
|
|
assert!(!example_doc_html_2.contains("Library"));
|
|
assert!(!example_doc_html_2.contains("Binary"));
|
|
|
|
assert!(example_doc_html_1.contains("Example1"));
|
|
assert!(example_doc_html_2.contains("Example2"));
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_dash_p() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dependencies.a]
|
|
path = "a"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "extern crate a;")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dependencies.b]
|
|
path = "../b"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "extern crate b;")
|
|
.file("b/Cargo.toml", &basic_manifest("b", "0.0.1"))
|
|
.file("b/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc -p a")
|
|
.with_stderr(
|
|
"\
|
|
[..] b v0.0.1 ([CWD]/b)
|
|
[..] b v0.0.1 ([CWD]/b)
|
|
[DOCUMENTING] a v0.0.1 ([CWD]/a)
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_all_exclude() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["bar", "baz"]
|
|
"#,
|
|
)
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("bar/src/lib.rs", "pub fn bar() {}")
|
|
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
|
|
.file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }")
|
|
.build();
|
|
|
|
p.cargo("doc --workspace --exclude baz")
|
|
.with_stderr_does_not_contain("[DOCUMENTING] baz v0.1.0 [..]")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] bar v0.1.0 ([..])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_all_exclude_glob() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["bar", "baz"]
|
|
"#,
|
|
)
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("bar/src/lib.rs", "pub fn bar() {}")
|
|
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
|
|
.file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }")
|
|
.build();
|
|
|
|
p.cargo("doc --workspace --exclude '*z'")
|
|
.with_stderr_does_not_contain("[DOCUMENTING] baz v0.1.0 [..]")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] bar v0.1.0 ([..])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_same_name() {
|
|
let p = project()
|
|
.file("src/lib.rs", "")
|
|
.file("src/bin/main.rs", "fn main() {}")
|
|
.file("examples/main.rs", "fn main() {}")
|
|
.file("tests/main.rs", "fn main() {}")
|
|
.build();
|
|
|
|
p.cargo("doc").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_target() {
|
|
if !is_nightly() {
|
|
// no_core, lang_items requires nightly.
|
|
return;
|
|
}
|
|
const TARGET: &str = "arm-unknown-linux-gnueabihf";
|
|
|
|
let p = project()
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
#![feature(no_core, lang_items)]
|
|
#![no_core]
|
|
|
|
#[lang = "sized"]
|
|
trait Sized {}
|
|
|
|
extern {
|
|
pub static A: u32;
|
|
}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc --verbose --target").arg(TARGET).run();
|
|
assert!(p.root().join(&format!("target/{}/doc", TARGET)).is_dir());
|
|
assert!(p
|
|
.root()
|
|
.join(&format!("target/{}/doc/foo/index.html", TARGET))
|
|
.is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn target_specific_not_documented() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[target.foo.dependencies]
|
|
a = { path = "a" }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("a/Cargo.toml", &basic_manifest("a", "0.0.1"))
|
|
.file("a/src/lib.rs", "not rust")
|
|
.build();
|
|
|
|
p.cargo("doc").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn output_not_captured() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
a = { path = "a" }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("a/Cargo.toml", &basic_manifest("a", "0.0.1"))
|
|
.file(
|
|
"a/src/lib.rs",
|
|
"
|
|
/// ```
|
|
/// `
|
|
/// ```
|
|
pub fn foo() {}
|
|
",
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc")
|
|
.with_stderr_contains("[..]unknown start of token: `")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn target_specific_documented() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[target.foo.dependencies]
|
|
a = {{ path = "a" }}
|
|
[target.{}.dependencies]
|
|
a = {{ path = "a" }}
|
|
"#,
|
|
rustc_host()
|
|
),
|
|
)
|
|
.file(
|
|
"src/lib.rs",
|
|
"
|
|
extern crate a;
|
|
|
|
/// test
|
|
pub fn foo() {}
|
|
",
|
|
)
|
|
.file("a/Cargo.toml", &basic_manifest("a", "0.0.1"))
|
|
.file(
|
|
"a/src/lib.rs",
|
|
"
|
|
/// test
|
|
pub fn foo() {}
|
|
",
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn no_document_build_deps() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[build-dependencies]
|
|
a = { path = "a" }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "pub fn foo() {}")
|
|
.file("a/Cargo.toml", &basic_manifest("a", "0.0.1"))
|
|
.file(
|
|
"a/src/lib.rs",
|
|
"
|
|
/// ```
|
|
/// ☃
|
|
/// ```
|
|
pub fn foo() {}
|
|
",
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_release() {
|
|
let p = project().file("src/lib.rs", "").build();
|
|
|
|
p.cargo("build --release").run();
|
|
p.cargo("doc --release -v")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] foo v0.0.1 ([..])
|
|
[RUNNING] `rustdoc [..] src/lib.rs [..]`
|
|
[FINISHED] release [optimized] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_multiple_deps() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dependencies.bar]
|
|
path = "bar"
|
|
|
|
[dependencies.baz]
|
|
path = "baz"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "extern crate bar; pub fn foo() {}")
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
|
|
.file("bar/src/lib.rs", "pub fn bar() {}")
|
|
.file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
|
|
.file("baz/src/lib.rs", "pub fn baz() {}")
|
|
.build();
|
|
|
|
p.cargo("doc -p bar -p baz -v").run();
|
|
|
|
assert!(p.root().join("target/doc").is_dir());
|
|
assert!(p.root().join("target/doc/bar/index.html").is_file());
|
|
assert!(p.root().join("target/doc/baz/index.html").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn features() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dependencies.bar]
|
|
path = "bar"
|
|
|
|
[features]
|
|
foo = ["bar/bar"]
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", r#"#[cfg(feature = "foo")] pub fn foo() {}"#)
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[features]
|
|
bar = []
|
|
"#,
|
|
)
|
|
.file(
|
|
"bar/build.rs",
|
|
r#"
|
|
fn main() {
|
|
println!("cargo:rustc-cfg=bar");
|
|
}
|
|
"#,
|
|
)
|
|
.file(
|
|
"bar/src/lib.rs",
|
|
r#"#[cfg(feature = "bar")] pub fn bar() {}"#,
|
|
)
|
|
.build();
|
|
p.cargo("doc --features foo")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] bar v0.0.1 [..]
|
|
[DOCUMENTING] bar v0.0.1 [..]
|
|
[DOCUMENTING] foo v0.0.1 [..]
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
assert!(p.root().join("target/doc").is_dir());
|
|
assert!(p.root().join("target/doc/foo/fn.foo.html").is_file());
|
|
assert!(p.root().join("target/doc/bar/fn.bar.html").is_file());
|
|
// Check that turning the feature off will remove the files.
|
|
p.cargo("doc")
|
|
.with_stderr(
|
|
"\
|
|
[COMPILING] bar v0.0.1 [..]
|
|
[DOCUMENTING] bar v0.0.1 [..]
|
|
[DOCUMENTING] foo v0.0.1 [..]
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
assert!(!p.root().join("target/doc/foo/fn.foo.html").is_file());
|
|
assert!(!p.root().join("target/doc/bar/fn.bar.html").is_file());
|
|
// And switching back will rebuild and bring them back.
|
|
p.cargo("doc --features foo")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] bar v0.0.1 [..]
|
|
[DOCUMENTING] foo v0.0.1 [..]
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
assert!(p.root().join("target/doc/foo/fn.foo.html").is_file());
|
|
assert!(p.root().join("target/doc/bar/fn.bar.html").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn rerun_when_dir_removed() {
|
|
let p = project()
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
/// dox
|
|
pub fn foo() {}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc").run();
|
|
assert!(p.root().join("target/doc/foo/index.html").is_file());
|
|
|
|
fs::remove_dir_all(p.root().join("target/doc/foo")).unwrap();
|
|
|
|
p.cargo("doc").run();
|
|
assert!(p.root().join("target/doc/foo/index.html").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn document_only_lib() {
|
|
let p = project()
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
/// dox
|
|
pub fn foo() {}
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/bin/bar.rs",
|
|
r#"
|
|
/// ```
|
|
/// ☃
|
|
/// ```
|
|
pub fn foo() {}
|
|
fn main() { foo(); }
|
|
"#,
|
|
)
|
|
.build();
|
|
p.cargo("doc --lib").run();
|
|
assert!(p.root().join("target/doc/foo/index.html").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn plugins_no_use_target() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[lib]
|
|
proc-macro = true
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
p.cargo("doc --target=x86_64-unknown-openbsd -v").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_all_workspace() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[project]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
bar = { path = "bar" }
|
|
|
|
[workspace]
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("bar/src/lib.rs", "pub fn bar() {}")
|
|
.build();
|
|
|
|
// The order in which bar is compiled or documented is not deterministic
|
|
p.cargo("doc --workspace")
|
|
.with_stderr_contains("[..] Documenting bar v0.1.0 ([..])")
|
|
.with_stderr_contains("[..] Checking bar v0.1.0 ([..])")
|
|
.with_stderr_contains("[..] Documenting foo v0.1.0 ([..])")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_all_virtual_manifest() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["bar", "baz"]
|
|
"#,
|
|
)
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("bar/src/lib.rs", "pub fn bar() {}")
|
|
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
|
|
.file("baz/src/lib.rs", "pub fn baz() {}")
|
|
.build();
|
|
|
|
// The order in which bar and baz are documented is not guaranteed
|
|
p.cargo("doc --workspace")
|
|
.with_stderr_contains("[..] Documenting baz v0.1.0 ([..])")
|
|
.with_stderr_contains("[..] Documenting bar v0.1.0 ([..])")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_virtual_manifest_all_implied() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["bar", "baz"]
|
|
"#,
|
|
)
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("bar/src/lib.rs", "pub fn bar() {}")
|
|
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
|
|
.file("baz/src/lib.rs", "pub fn baz() {}")
|
|
.build();
|
|
|
|
// The order in which bar and baz are documented is not guaranteed
|
|
p.cargo("doc")
|
|
.with_stderr_contains("[..] Documenting baz v0.1.0 ([..])")
|
|
.with_stderr_contains("[..] Documenting bar v0.1.0 ([..])")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_virtual_manifest_one_project() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["bar", "baz"]
|
|
"#,
|
|
)
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("bar/src/lib.rs", "pub fn bar() {}")
|
|
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
|
|
.file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }")
|
|
.build();
|
|
|
|
p.cargo("doc -p bar")
|
|
.with_stderr_does_not_contain("[DOCUMENTING] baz v0.1.0 [..]")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] bar v0.1.0 ([..])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_virtual_manifest_glob() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["bar", "baz"]
|
|
"#,
|
|
)
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("bar/src/lib.rs", "pub fn bar() { break_the_build(); }")
|
|
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
|
|
.file("baz/src/lib.rs", "pub fn baz() {}")
|
|
.build();
|
|
|
|
p.cargo("doc -p '*z'")
|
|
.with_stderr_does_not_contain("[DOCUMENTING] bar v0.1.0 [..]")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] baz v0.1.0 ([..])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_all_member_dependency_same_name() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["bar"]
|
|
"#,
|
|
)
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[project]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("bar/src/lib.rs", "pub fn bar() {}")
|
|
.build();
|
|
|
|
Package::new("bar", "0.1.0").publish();
|
|
|
|
p.cargo("doc --workspace")
|
|
.with_stderr_unordered(
|
|
"\
|
|
[UPDATING] [..]
|
|
[DOWNLOADING] crates ...
|
|
[DOWNLOADED] bar v0.1.0 (registry `dummy-registry`)
|
|
warning: output filename collision.
|
|
The lib target `bar` in package `bar v0.1.0` has the same output filename as \
|
|
the lib target `bar` in package `bar v0.1.0 ([ROOT]/foo/bar)`.
|
|
Colliding filename is: [ROOT]/foo/target/doc/bar/index.html
|
|
The targets should have unique names.
|
|
This is a known bug where multiple crates with the same name use
|
|
the same path; see <https://github.com/rust-lang/cargo/issues/6313>.
|
|
[DOCUMENTING] bar v0.1.0
|
|
[CHECKING] bar v0.1.0
|
|
[DOCUMENTING] bar v0.1.0 [..]
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_workspace_open_help_message() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["foo", "bar"]
|
|
"#,
|
|
)
|
|
.file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
|
|
.file("foo/src/lib.rs", "")
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("bar/src/lib.rs", "")
|
|
.build();
|
|
|
|
// The order in which bar is compiled or documented is not deterministic
|
|
p.cargo("doc --workspace --open")
|
|
.env("BROWSER", tools::echo())
|
|
.with_stderr_contains("[..] Documenting bar v0.1.0 ([..])")
|
|
.with_stderr_contains("[..] Documenting foo v0.1.0 ([..])")
|
|
.with_stderr_contains("[..] Opening [..]/bar/index.html")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_extern_map_local() {
|
|
if !is_nightly() {
|
|
// -Zextern-html-root-url is unstable
|
|
return;
|
|
}
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(".cargo/config.toml", "doc.extern-map.std = 'local'")
|
|
.build();
|
|
|
|
p.cargo("doc -v --no-deps -Zrustdoc-map --open")
|
|
.env("BROWSER", tools::echo())
|
|
.masquerade_as_nightly_cargo()
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] foo v0.1.0 [..]
|
|
[RUNNING] `rustdoc --crate-type lib --crate-name foo src/lib.rs [..]--crate-version 0.1.0`
|
|
[FINISHED] [..]
|
|
Opening [CWD]/target/doc/foo/index.html
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn open_no_doc_crate() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[lib]
|
|
doc = false
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "#[cfg(feature)] pub fn f();")
|
|
.build();
|
|
|
|
p.cargo("doc --open")
|
|
.env("BROWSER", "do_not_run_me")
|
|
.with_status(101)
|
|
.with_stderr_contains("error: no crates with documentation")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_workspace_open_different_library_and_package_names() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["foo"]
|
|
"#,
|
|
)
|
|
.file(
|
|
"foo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
[lib]
|
|
name = "foolib"
|
|
"#,
|
|
)
|
|
.file("foo/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc --open")
|
|
.env("BROWSER", tools::echo())
|
|
.with_stderr_contains("[..] Documenting foo v0.1.0 ([..])")
|
|
.with_stderr_contains("[..] [CWD]/target/doc/foolib/index.html")
|
|
.with_stdout_contains("[CWD]/target/doc/foolib/index.html")
|
|
.run();
|
|
|
|
p.change_file(
|
|
".cargo/config.toml",
|
|
&format!(
|
|
r#"
|
|
[doc]
|
|
browser = ["{}", "a"]
|
|
"#,
|
|
tools::echo().display().to_string().replace('\\', "\\\\")
|
|
),
|
|
);
|
|
|
|
// check that the cargo config overrides the browser env var
|
|
p.cargo("doc --open")
|
|
.env("BROWSER", "do_not_run_me")
|
|
.with_stdout_contains("a [CWD]/target/doc/foolib/index.html")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_workspace_open_binary() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["foo"]
|
|
"#,
|
|
)
|
|
.file(
|
|
"foo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
[[bin]]
|
|
name = "foobin"
|
|
path = "src/main.rs"
|
|
"#,
|
|
)
|
|
.file("foo/src/main.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc --open")
|
|
.env("BROWSER", tools::echo())
|
|
.with_stderr_contains("[..] Documenting foo v0.1.0 ([..])")
|
|
.with_stderr_contains("[..] Opening [CWD]/target/doc/foobin/index.html")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_workspace_open_binary_and_library() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["foo"]
|
|
"#,
|
|
)
|
|
.file(
|
|
"foo/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
[lib]
|
|
name = "foolib"
|
|
[[bin]]
|
|
name = "foobin"
|
|
path = "src/main.rs"
|
|
"#,
|
|
)
|
|
.file("foo/src/lib.rs", "")
|
|
.file("foo/src/main.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc --open")
|
|
.env("BROWSER", tools::echo())
|
|
.with_stderr_contains("[..] Documenting foo v0.1.0 ([..])")
|
|
.with_stderr_contains("[..] Opening [CWD]/target/doc/foolib/index.html")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_edition() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
edition = "2018"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc -v")
|
|
.with_stderr_contains("[RUNNING] `rustdoc [..]--edition=2018[..]")
|
|
.run();
|
|
|
|
p.cargo("test -v")
|
|
.with_stderr_contains("[RUNNING] `rustdoc [..]--edition=2018[..]")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_target_edition() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[lib]
|
|
edition = "2018"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc -v")
|
|
.with_stderr_contains("[RUNNING] `rustdoc [..]--edition=2018[..]")
|
|
.run();
|
|
|
|
p.cargo("test -v")
|
|
.with_stderr_contains("[RUNNING] `rustdoc [..]--edition=2018[..]")
|
|
.run();
|
|
}
|
|
|
|
// Tests an issue where depending on different versions of the same crate depending on `cfg`s
|
|
// caused `cargo doc` to fail.
|
|
#[cargo_test]
|
|
fn issue_5345() {
|
|
let foo = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[target.'cfg(all(windows, target_arch = "x86"))'.dependencies]
|
|
bar = "0.1"
|
|
|
|
[target.'cfg(not(all(windows, target_arch = "x86")))'.dependencies]
|
|
bar = "0.2"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "extern crate bar;")
|
|
.build();
|
|
Package::new("bar", "0.1.0").publish();
|
|
Package::new("bar", "0.2.0").publish();
|
|
|
|
foo.cargo("build").run();
|
|
foo.cargo("doc").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_private_items() {
|
|
let foo = project()
|
|
.file("src/lib.rs", "mod private { fn private_item() {} }")
|
|
.build();
|
|
foo.cargo("doc --document-private-items").run();
|
|
|
|
assert!(foo.root().join("target/doc").is_dir());
|
|
assert!(foo
|
|
.root()
|
|
.join("target/doc/foo/private/index.html")
|
|
.is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_private_ws() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[workspace]
|
|
members = ["a", "b"]
|
|
"#,
|
|
)
|
|
.file("a/Cargo.toml", &basic_manifest("a", "0.0.1"))
|
|
.file("a/src/lib.rs", "fn p() {}")
|
|
.file("b/Cargo.toml", &basic_manifest("b", "0.0.1"))
|
|
.file("b/src/lib.rs", "fn p2() {}")
|
|
.file("b/src/bin/b-cli.rs", "fn main() {}")
|
|
.build();
|
|
p.cargo("doc --workspace --bins --lib --document-private-items -v")
|
|
.with_stderr_contains(
|
|
"[RUNNING] `rustdoc [..] a/src/lib.rs [..]--document-private-items[..]",
|
|
)
|
|
.with_stderr_contains(
|
|
"[RUNNING] `rustdoc [..] b/src/lib.rs [..]--document-private-items[..]",
|
|
)
|
|
.with_stderr_contains(
|
|
"[RUNNING] `rustdoc [..] b/src/bin/b-cli.rs [..]--document-private-items[..]",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
const BAD_INTRA_LINK_LIB: &str = r#"
|
|
#![deny(broken_intra_doc_links)]
|
|
|
|
/// [bad_link]
|
|
pub fn foo() {}
|
|
"#;
|
|
|
|
#[cargo_test]
|
|
fn doc_cap_lints() {
|
|
let a = git::new("a", |p| {
|
|
p.file("Cargo.toml", &basic_lib_manifest("a"))
|
|
.file("src/lib.rs", BAD_INTRA_LINK_LIB)
|
|
});
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
a = {{ git = '{}' }}
|
|
"#,
|
|
a.url()
|
|
),
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc")
|
|
.with_stderr_unordered(
|
|
"\
|
|
[UPDATING] git repository `[..]`
|
|
[DOCUMENTING] a v0.5.0 ([..])
|
|
[CHECKING] a v0.5.0 ([..])
|
|
[DOCUMENTING] foo v0.0.1 ([..])
|
|
[FINISHED] dev [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
p.root().join("target").rm_rf();
|
|
|
|
p.cargo("doc -vv")
|
|
.with_stderr_contains("[WARNING] [..]`bad_link`[..]")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_message_format() {
|
|
let p = project().file("src/lib.rs", BAD_INTRA_LINK_LIB).build();
|
|
|
|
p.cargo("doc --message-format=json")
|
|
.with_status(101)
|
|
.with_json_contains_unordered(
|
|
r#"
|
|
{
|
|
"message": {
|
|
"children": "{...}",
|
|
"code": "{...}",
|
|
"level": "error",
|
|
"message": "{...}",
|
|
"rendered": "{...}",
|
|
"spans": "{...}"
|
|
},
|
|
"package_id": "foo [..]",
|
|
"manifest_path": "[..]",
|
|
"reason": "compiler-message",
|
|
"target": "{...}"
|
|
}
|
|
"#,
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_json_artifacts() {
|
|
// Checks the output of json artifact messages.
|
|
let p = project()
|
|
.file("src/lib.rs", "")
|
|
.file("src/bin/somebin.rs", "fn main() {}")
|
|
.build();
|
|
|
|
p.cargo("doc --message-format=json")
|
|
.with_json_contains_unordered(
|
|
r#"
|
|
{
|
|
"reason": "compiler-artifact",
|
|
"package_id": "foo 0.0.1 [..]",
|
|
"manifest_path": "[ROOT]/foo/Cargo.toml",
|
|
"target":
|
|
{
|
|
"kind": ["lib"],
|
|
"crate_types": ["lib"],
|
|
"name": "foo",
|
|
"src_path": "[ROOT]/foo/src/lib.rs",
|
|
"edition": "2015",
|
|
"doc": true,
|
|
"doctest": true,
|
|
"test": true
|
|
},
|
|
"profile": "{...}",
|
|
"features": [],
|
|
"filenames": ["[ROOT]/foo/target/debug/deps/libfoo-[..].rmeta"],
|
|
"executable": null,
|
|
"fresh": false
|
|
}
|
|
|
|
{
|
|
"reason": "compiler-artifact",
|
|
"package_id": "foo 0.0.1 [..]",
|
|
"manifest_path": "[ROOT]/foo/Cargo.toml",
|
|
"target":
|
|
{
|
|
"kind": ["lib"],
|
|
"crate_types": ["lib"],
|
|
"name": "foo",
|
|
"src_path": "[ROOT]/foo/src/lib.rs",
|
|
"edition": "2015",
|
|
"doc": true,
|
|
"doctest": true,
|
|
"test": true
|
|
},
|
|
"profile": "{...}",
|
|
"features": [],
|
|
"filenames": ["[ROOT]/foo/target/doc/foo/index.html"],
|
|
"executable": null,
|
|
"fresh": false
|
|
}
|
|
|
|
{
|
|
"reason": "compiler-artifact",
|
|
"package_id": "foo 0.0.1 [..]",
|
|
"manifest_path": "[ROOT]/foo/Cargo.toml",
|
|
"target":
|
|
{
|
|
"kind": ["bin"],
|
|
"crate_types": ["bin"],
|
|
"name": "somebin",
|
|
"src_path": "[ROOT]/foo/src/bin/somebin.rs",
|
|
"edition": "2015",
|
|
"doc": true,
|
|
"doctest": false,
|
|
"test": true
|
|
},
|
|
"profile": "{...}",
|
|
"features": [],
|
|
"filenames": ["[ROOT]/foo/target/doc/somebin/index.html"],
|
|
"executable": null,
|
|
"fresh": false
|
|
}
|
|
|
|
{"reason":"build-finished","success":true}
|
|
"#,
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn short_message_format() {
|
|
let p = project().file("src/lib.rs", BAD_INTRA_LINK_LIB).build();
|
|
p.cargo("doc --message-format=short")
|
|
.with_status(101)
|
|
.with_stderr_contains("src/lib.rs:4:6: error: [..]`bad_link`[..]")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_example() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
edition = "2018"
|
|
|
|
[[example]]
|
|
crate-type = ["lib"]
|
|
name = "ex1"
|
|
doc = true
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "pub fn f() {}")
|
|
.file(
|
|
"examples/ex1.rs",
|
|
r#"
|
|
use foo::f;
|
|
|
|
/// Example
|
|
pub fn x() { f(); }
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc").run();
|
|
assert!(p
|
|
.build_dir()
|
|
.join("doc")
|
|
.join("ex1")
|
|
.join("fn.x.html")
|
|
.exists());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_example_with_deps() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
edition = "2018"
|
|
|
|
[[example]]
|
|
crate-type = ["lib"]
|
|
name = "ex"
|
|
doc = true
|
|
|
|
[dev-dependencies]
|
|
a = {path = "a"}
|
|
b = {path = "b"}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"examples/ex.rs",
|
|
r#"
|
|
use a::fun;
|
|
|
|
/// Example
|
|
pub fn x() { fun(); }
|
|
"#,
|
|
)
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.0.1"
|
|
|
|
[dependencies]
|
|
b = {path = "../b"}
|
|
"#,
|
|
)
|
|
.file("a/src/fun.rs", "pub fn fun() {}")
|
|
.file("a/src/lib.rs", "pub mod fun;")
|
|
.file(
|
|
"b/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "b"
|
|
version = "0.0.1"
|
|
"#,
|
|
)
|
|
.file("b/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc --examples").run();
|
|
assert!(p
|
|
.build_dir()
|
|
.join("doc")
|
|
.join("ex")
|
|
.join("fn.x.html")
|
|
.exists());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn bin_private_items() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
"
|
|
pub fn foo_pub() {}
|
|
fn foo_priv() {}
|
|
struct FooStruct;
|
|
enum FooEnum {}
|
|
trait FooTrait {}
|
|
type FooType = u32;
|
|
mod foo_mod {}
|
|
|
|
",
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
assert!(p.root().join("target/doc/foo/index.html").is_file());
|
|
assert!(p.root().join("target/doc/foo/fn.foo_pub.html").is_file());
|
|
assert!(p.root().join("target/doc/foo/fn.foo_priv.html").is_file());
|
|
assert!(p
|
|
.root()
|
|
.join("target/doc/foo/struct.FooStruct.html")
|
|
.is_file());
|
|
assert!(p.root().join("target/doc/foo/enum.FooEnum.html").is_file());
|
|
assert!(p
|
|
.root()
|
|
.join("target/doc/foo/trait.FooTrait.html")
|
|
.is_file());
|
|
assert!(p.root().join("target/doc/foo/type.FooType.html").is_file());
|
|
assert!(p.root().join("target/doc/foo/foo_mod/index.html").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn bin_private_items_deps() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dependencies.bar]
|
|
path = "bar"
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/main.rs",
|
|
"
|
|
fn foo_priv() {}
|
|
pub fn foo_pub() {}
|
|
",
|
|
)
|
|
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
|
|
.file(
|
|
"bar/src/lib.rs",
|
|
"
|
|
#[allow(dead_code)]
|
|
fn bar_priv() {}
|
|
pub fn bar_pub() {}
|
|
",
|
|
)
|
|
.build();
|
|
|
|
p.cargo("doc")
|
|
.with_stderr_unordered(
|
|
"\
|
|
[DOCUMENTING] bar v0.0.1 ([..])
|
|
[CHECKING] bar v0.0.1 ([..])
|
|
[DOCUMENTING] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
assert!(p.root().join("target/doc/foo/index.html").is_file());
|
|
assert!(p.root().join("target/doc/foo/fn.foo_pub.html").is_file());
|
|
assert!(p.root().join("target/doc/foo/fn.foo_priv.html").is_file());
|
|
|
|
assert!(p.root().join("target/doc/bar/index.html").is_file());
|
|
assert!(p.root().join("target/doc/bar/fn.bar_pub.html").is_file());
|
|
assert!(!p.root().join("target/doc/bar/fn.bar_priv.html").exists());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn crate_versions() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "1.2.4"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc -v")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] foo v1.2.4 [..]
|
|
[RUNNING] `rustdoc --crate-type lib --crate-name foo src/lib.rs [..]--crate-version 1.2.4`
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
let output_path = p.root().join("target/doc/foo/index.html");
|
|
let output_documentation = fs::read_to_string(&output_path).unwrap();
|
|
|
|
assert!(output_documentation.contains("Version 1.2.4"));
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn crate_versions_flag_is_overridden() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "1.2.4"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
let output_documentation = || {
|
|
let output_path = p.root().join("target/doc/foo/index.html");
|
|
fs::read_to_string(&output_path).unwrap()
|
|
};
|
|
let asserts = |html: String| {
|
|
assert!(!html.contains("1.2.4"));
|
|
assert!(html.contains("Version 2.0.3"));
|
|
};
|
|
|
|
p.cargo("doc")
|
|
.env("RUSTDOCFLAGS", "--crate-version 2.0.3")
|
|
.run();
|
|
asserts(output_documentation());
|
|
|
|
p.build_dir().rm_rf();
|
|
|
|
p.cargo("rustdoc -- --crate-version 2.0.3").run();
|
|
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
|
|
let old_rustc_verbose_version = format!(
|
|
"\
|
|
rustc 1.41.1 (f3e1a954d 2020-02-24)
|
|
binary: rustc
|
|
commit-hash: f3e1a954d2ead4e2fc197c7da7d71e6c61bad196
|
|
commit-date: 2020-02-24
|
|
host: {}
|
|
release: 1.41.1
|
|
LLVM version: 9.0
|
|
",
|
|
rustc_host()
|
|
);
|
|
|
|
// Create the dummy project.
|
|
let dummy_project = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "1.2.4"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "//! These are the docs!")
|
|
.build();
|
|
|
|
dummy_project.cargo("doc").run();
|
|
|
|
let fingerprint: RustDocFingerprint =
|
|
serde_json::from_str(&dummy_project.read_file("target/.rustdoc_fingerprint.json"))
|
|
.expect("JSON Serde fail");
|
|
|
|
// Check that the fingerprint contains the actual rustc version
|
|
// which has been used to compile the docs.
|
|
let output = std::process::Command::new("rustc")
|
|
.arg("-vV")
|
|
.output()
|
|
.expect("Failed to get actual rustc verbose version");
|
|
assert_eq!(
|
|
fingerprint.rustc_vv,
|
|
(String::from_utf8_lossy(&output.stdout).as_ref())
|
|
);
|
|
|
|
// As the test shows above. Now we have generated the `doc/` folder and inside
|
|
// the rustdoc fingerprint file is located with the correct rustc version.
|
|
// So we will remove it and create a new fingerprint with an old rustc version
|
|
// inside it. We will also place a bogus file inside of the `doc/` folder to ensure
|
|
// it gets removed as we expect on the next doc compilation.
|
|
dummy_project.change_file(
|
|
"target/.rustdoc_fingerprint.json",
|
|
&old_rustc_verbose_version,
|
|
);
|
|
|
|
fs::write(
|
|
dummy_project.build_dir().join("doc/bogus_file"),
|
|
String::from("This is a bogus file and should be removed!"),
|
|
)
|
|
.expect("Error writing test bogus file");
|
|
|
|
// Now if we trigger another compilation, since the fingerprint contains an old version
|
|
// of rustc, cargo should remove the entire `/doc` folder (including the fingerprint)
|
|
// and generating another one with the actual version.
|
|
// It should also remove the bogus file we created above.
|
|
dummy_project.cargo("doc").run();
|
|
|
|
assert!(!dummy_project.build_dir().join("doc/bogus_file").exists());
|
|
|
|
let fingerprint: RustDocFingerprint =
|
|
serde_json::from_str(&dummy_project.read_file("target/.rustdoc_fingerprint.json"))
|
|
.expect("JSON Serde fail");
|
|
|
|
// Check that the fingerprint contains the actual rustc version
|
|
// which has been used to compile the docs.
|
|
assert_eq!(
|
|
fingerprint.rustc_vv,
|
|
(String::from_utf8_lossy(&output.stdout).as_ref())
|
|
);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_fingerprint_respects_target_paths() {
|
|
// Random rustc verbose version
|
|
let old_rustc_verbose_version = format!(
|
|
"\
|
|
rustc 1.41.1 (f3e1a954d 2020-02-24)
|
|
binary: rustc
|
|
commit-hash: f3e1a954d2ead4e2fc197c7da7d71e6c61bad196
|
|
commit-date: 2020-02-24
|
|
host: {}
|
|
release: 1.41.1
|
|
LLVM version: 9.0
|
|
",
|
|
rustc_host()
|
|
);
|
|
|
|
// Create the dummy project.
|
|
let dummy_project = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "1.2.4"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "//! These are the docs!")
|
|
.build();
|
|
|
|
dummy_project.cargo("doc --target").arg(rustc_host()).run();
|
|
|
|
let fingerprint: RustDocFingerprint =
|
|
serde_json::from_str(&dummy_project.read_file("target/.rustdoc_fingerprint.json"))
|
|
.expect("JSON Serde fail");
|
|
|
|
// Check that the fingerprint contains the actual rustc version
|
|
// which has been used to compile the docs.
|
|
let output = std::process::Command::new("rustc")
|
|
.arg("-vV")
|
|
.output()
|
|
.expect("Failed to get actual rustc verbose version");
|
|
assert_eq!(
|
|
fingerprint.rustc_vv,
|
|
(String::from_utf8_lossy(&output.stdout).as_ref())
|
|
);
|
|
|
|
// As the test shows above. Now we have generated the `doc/` folder and inside
|
|
// the rustdoc fingerprint file is located with the correct rustc version.
|
|
// So we will remove it and create a new fingerprint with an old rustc version
|
|
// inside it. We will also place a bogus file inside of the `doc/` folder to ensure
|
|
// it gets removed as we expect on the next doc compilation.
|
|
dummy_project.change_file(
|
|
"target/.rustdoc_fingerprint.json",
|
|
&old_rustc_verbose_version,
|
|
);
|
|
|
|
fs::write(
|
|
dummy_project
|
|
.build_dir()
|
|
.join(rustc_host())
|
|
.join("doc/bogus_file"),
|
|
String::from("This is a bogus file and should be removed!"),
|
|
)
|
|
.expect("Error writing test bogus file");
|
|
|
|
// Now if we trigger another compilation, since the fingerprint contains an old version
|
|
// of rustc, cargo should remove the entire `/doc` folder (including the fingerprint)
|
|
// and generating another one with the actual version.
|
|
// It should also remove the bogus file we created above.
|
|
dummy_project.cargo("doc --target").arg(rustc_host()).run();
|
|
|
|
assert!(!dummy_project
|
|
.build_dir()
|
|
.join(rustc_host())
|
|
.join("doc/bogus_file")
|
|
.exists());
|
|
|
|
let fingerprint: RustDocFingerprint =
|
|
serde_json::from_str(&dummy_project.read_file("target/.rustdoc_fingerprint.json"))
|
|
.expect("JSON Serde fail");
|
|
|
|
// Check that the fingerprint contains the actual rustc version
|
|
// which has been used to compile the docs.
|
|
assert_eq!(
|
|
fingerprint.rustc_vv,
|
|
(String::from_utf8_lossy(&output.stdout).as_ref())
|
|
);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_fingerprint_unusual_behavior() {
|
|
// Checks for some unusual circumstances with clearing the doc directory.
|
|
if !symlink_supported() {
|
|
return;
|
|
}
|
|
let p = project().file("src/lib.rs", "").build();
|
|
p.build_dir().mkdir_p();
|
|
let real_doc = p.root().join("doc");
|
|
real_doc.mkdir_p();
|
|
let build_doc = p.build_dir().join("doc");
|
|
p.symlink(&real_doc, &build_doc);
|
|
fs::write(real_doc.join("somefile"), "test").unwrap();
|
|
fs::write(real_doc.join(".hidden"), "test").unwrap();
|
|
p.cargo("doc").run();
|
|
// Make sure for the first run, it does not delete any files and does not
|
|
// break the symlink.
|
|
assert!(build_doc.join("somefile").exists());
|
|
assert!(real_doc.join("somefile").exists());
|
|
assert!(real_doc.join(".hidden").exists());
|
|
assert!(real_doc.join("foo/index.html").exists());
|
|
// Pretend that the last build was generated by an older version.
|
|
p.change_file(
|
|
"target/.rustdoc_fingerprint.json",
|
|
"{\"rustc_vv\": \"I am old\"}",
|
|
);
|
|
// Change file to trigger a new build.
|
|
p.change_file("src/lib.rs", "// changed");
|
|
p.cargo("doc")
|
|
.with_stderr(
|
|
"[DOCUMENTING] foo [..]\n\
|
|
[FINISHED] [..]",
|
|
)
|
|
.run();
|
|
// This will delete somefile, but not .hidden.
|
|
assert!(!real_doc.join("somefile").exists());
|
|
assert!(real_doc.join(".hidden").exists());
|
|
assert!(real_doc.join("foo/index.html").exists());
|
|
// And also check the -Z flag behavior.
|
|
p.change_file(
|
|
"target/.rustdoc_fingerprint.json",
|
|
"{\"rustc_vv\": \"I am old\"}",
|
|
);
|
|
// Change file to trigger a new build.
|
|
p.change_file("src/lib.rs", "// changed2");
|
|
fs::write(real_doc.join("somefile"), "test").unwrap();
|
|
p.cargo("doc -Z skip-rustdoc-fingerprint")
|
|
.masquerade_as_nightly_cargo()
|
|
.with_stderr(
|
|
"[DOCUMENTING] foo [..]\n\
|
|
[FINISHED] [..]",
|
|
)
|
|
.run();
|
|
// Should not have deleted anything.
|
|
assert!(build_doc.join("somefile").exists());
|
|
assert!(real_doc.join("somefile").exists());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn scrape_examples_basic() {
|
|
if !is_nightly() {
|
|
// -Z rustdoc-scrape-examples is unstable
|
|
return;
|
|
}
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file("examples/ex.rs", "fn main() { foo::foo(); }")
|
|
.file("src/lib.rs", "pub fn foo() {}\npub fn bar() { foo(); }")
|
|
.build();
|
|
|
|
p.cargo("doc -Zunstable-options -Z rustdoc-scrape-examples=all")
|
|
.masquerade_as_nightly_cargo()
|
|
.with_stderr(
|
|
"\
|
|
[..] foo v0.0.1 ([CWD])
|
|
[..] foo v0.0.1 ([CWD])
|
|
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
let doc_html = p.read_file("target/doc/foo/fn.foo.html");
|
|
assert!(doc_html.contains("Examples found in repository"));
|
|
assert!(doc_html.contains("More examples"));
|
|
|
|
// Ensure that the reverse-dependency has its sources generated
|
|
assert!(p.build_dir().join("doc/src/ex/ex.rs.html").exists());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn scrape_examples_avoid_build_script_cycle() {
|
|
if !is_nightly() {
|
|
// -Z rustdoc-scrape-examples is unstable
|
|
return;
|
|
}
|
|
|
|
let p = project()
|
|
// package with build dependency
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
links = "foo"
|
|
|
|
[workspace]
|
|
members = ["bar"]
|
|
|
|
[build-dependencies]
|
|
bar = {path = "bar"}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("build.rs", "fn main(){}")
|
|
// dependency
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.0.1"
|
|
authors = []
|
|
links = "bar"
|
|
"#,
|
|
)
|
|
.file("bar/src/lib.rs", "")
|
|
.file("bar/build.rs", "fn main(){}")
|
|
.build();
|
|
|
|
p.cargo("doc --all -Zunstable-options -Z rustdoc-scrape-examples=all")
|
|
.masquerade_as_nightly_cargo()
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn scrape_examples_complex_reverse_dependencies() {
|
|
if !is_nightly() {
|
|
// -Z rustdoc-scrape-examples is unstable
|
|
return;
|
|
}
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[dev-dependencies]
|
|
a = {path = "a", features = ["feature"]}
|
|
b = {path = "b"}
|
|
|
|
[workspace]
|
|
members = ["b"]
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("examples/ex.rs", "fn main() { a::f(); }")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[lib]
|
|
proc-macro = true
|
|
|
|
[dependencies]
|
|
b = {path = "../b"}
|
|
|
|
[features]
|
|
feature = []
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "#[cfg(feature)] pub fn f();")
|
|
.file(
|
|
"b/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "b"
|
|
version = "0.0.1"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file("b/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc -Zunstable-options -Z rustdoc-scrape-examples=all")
|
|
.masquerade_as_nightly_cargo()
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn scrape_examples_crate_with_dash() {
|
|
if !is_nightly() {
|
|
// -Z rustdoc-scrape-examples is unstable
|
|
return;
|
|
}
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "da-sh"
|
|
version = "0.0.1"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "pub fn foo() {}")
|
|
.file("examples/a.rs", "fn main() { da_sh::foo(); }")
|
|
.build();
|
|
|
|
p.cargo("doc -Zunstable-options -Z rustdoc-scrape-examples=all")
|
|
.masquerade_as_nightly_cargo()
|
|
.run();
|
|
|
|
let doc_html = p.read_file("target/doc/da_sh/fn.foo.html");
|
|
assert!(doc_html.contains("Examples found in repository"));
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn scrape_examples_missing_flag() {
|
|
if !is_nightly() {
|
|
return;
|
|
}
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "1.2.4"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "//! These are the docs!")
|
|
.build();
|
|
p.cargo("doc -Zrustdoc-scrape-examples")
|
|
.masquerade_as_nightly_cargo()
|
|
.with_status(101)
|
|
.with_stderr("error: -Z rustdoc-scrape-examples must take [..] an argument")
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn scrape_examples_configure_profile() {
|
|
if !is_nightly() {
|
|
// -Z rustdoc-scrape-examples is unstable
|
|
return;
|
|
}
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
authors = []
|
|
|
|
[profile.dev]
|
|
panic = "abort"
|
|
"#,
|
|
)
|
|
.file("examples/ex.rs", "fn main() { foo::foo(); }")
|
|
.file("src/lib.rs", "pub fn foo() {}\npub fn bar() { foo(); }")
|
|
.build();
|
|
|
|
p.cargo("doc -Zunstable-options -Z rustdoc-scrape-examples=all")
|
|
.masquerade_as_nightly_cargo()
|
|
.run();
|
|
|
|
let doc_html = p.read_file("target/doc/foo/fn.foo.html");
|
|
assert!(doc_html.contains("Examples found in repository"));
|
|
assert!(doc_html.contains("More examples"));
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn lib_before_bin() {
|
|
// Checks that the library is documented before the binary.
|
|
// Previously they were built concurrently, which can cause issues
|
|
// if the bin has intra-doc links to the lib.
|
|
let p = project()
|
|
.file(
|
|
"src/lib.rs",
|
|
r#"
|
|
/// Hi
|
|
pub fn abc() {}
|
|
"#,
|
|
)
|
|
.file(
|
|
"src/bin/somebin.rs",
|
|
r#"
|
|
//! See [`foo::abc`]
|
|
fn main() {}
|
|
"#,
|
|
)
|
|
.build();
|
|
|
|
// Run check first. This just helps ensure that the test clearly shows the
|
|
// order of the rustdoc commands.
|
|
p.cargo("check").run();
|
|
|
|
// The order of output here should be deterministic.
|
|
p.cargo("doc -v")
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] foo [..]
|
|
[RUNNING] `rustdoc --crate-type lib --crate-name foo src/lib.rs [..]
|
|
[RUNNING] `rustdoc --crate-type bin --crate-name somebin src/bin/somebin.rs [..]
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
// And the link should exist.
|
|
let bin_html = p.read_file("target/doc/somebin/index.html");
|
|
assert!(bin_html.contains("../foo/fn.abc.html"));
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_lib_false() {
|
|
// doc = false for a library
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[lib]
|
|
doc = false
|
|
|
|
[dependencies]
|
|
bar = {path = "bar"}
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "extern crate bar;")
|
|
.file("src/bin/some-bin.rs", "fn main() {}")
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
|
|
[lib]
|
|
doc = false
|
|
"#,
|
|
)
|
|
.file("bar/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc")
|
|
.with_stderr(
|
|
"\
|
|
[CHECKING] bar v0.1.0 [..]
|
|
[CHECKING] foo v0.1.0 [..]
|
|
[DOCUMENTING] foo v0.1.0 [..]
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
assert!(!p.build_dir().join("doc/foo").exists());
|
|
assert!(!p.build_dir().join("doc/bar").exists());
|
|
assert!(p.build_dir().join("doc/some_bin").exists());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn doc_lib_false_dep() {
|
|
// doc = false for a dependency
|
|
// Ensures that the rmeta gets produced
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[dependencies]
|
|
bar = { path = "bar" }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "extern crate bar;")
|
|
.file(
|
|
"bar/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
|
|
[lib]
|
|
doc = false
|
|
"#,
|
|
)
|
|
.file("bar/src/lib.rs", "")
|
|
.build();
|
|
|
|
p.cargo("doc")
|
|
.with_stderr(
|
|
"\
|
|
[CHECKING] bar v0.1.0 [..]
|
|
[DOCUMENTING] foo v0.1.0 [..]
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
|
|
assert!(p.build_dir().join("doc/foo").exists());
|
|
assert!(!p.build_dir().join("doc/bar").exists());
|
|
}
|
|
|
|
#[cfg_attr(windows, ignore)] // weird normalization issue with windows and cargo-test-support
|
|
#[cargo_test]
|
|
fn doc_check_cfg_features() {
|
|
if !is_nightly() {
|
|
// --check-cfg is a nightly only rustdoc command line
|
|
return;
|
|
}
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[project]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
|
|
[features]
|
|
default = ["f_a"]
|
|
f_a = []
|
|
f_b = []
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
|
|
.build();
|
|
|
|
p.cargo("doc -v -Z check-cfg-features")
|
|
.masquerade_as_nightly_cargo()
|
|
.with_stderr(
|
|
"\
|
|
[DOCUMENTING] foo v0.1.0 [..]
|
|
[RUNNING] `rustdoc [..] --check-cfg 'values(feature, \"default\", \"f_a\", \"f_b\")' [..]
|
|
[FINISHED] [..]
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn link_to_private_item() {
|
|
let main = r#"
|
|
//! [bar]
|
|
#[allow(dead_code)]
|
|
fn bar() {}
|
|
"#;
|
|
let p = project().file("src/lib.rs", main).build();
|
|
p.cargo("doc")
|
|
.with_stderr_contains("[..] documentation for `foo` links to private item `bar`")
|
|
.run();
|
|
// Check that binaries don't emit a private_intra_doc_links warning.
|
|
fs::rename(p.root().join("src/lib.rs"), p.root().join("src/main.rs")).unwrap();
|
|
p.cargo("doc")
|
|
.with_stderr(
|
|
"[DOCUMENTING] foo [..]\n\
|
|
[FINISHED] [..]",
|
|
)
|
|
.run();
|
|
}
|