cargo/tests/testsuite/metabuild.rs
Alex Crichton 6514c289d2 Improve git error messages a bit
This commit is targeted at further improving the error messages
generated from git errors. For authentication errors the actual URL
fetched is now printed out as well if it's different from the original
URL. This should help handle `insteadOf` logic where SSH urls are used
instead of HTTPS urls and users can know to track that down.

Otherwise the logic about recommending `net.git-fetch-with-cli` was
tweaked a bit and moved to the same location as the rest of our error
reporting.

Note that a change piggy-backed here as well is that `Caused by:` errors
are now automatically all tabbed over a bit instead of only having the
first line tabbed over. This required a good number of tests to be
updated, but it's just an updated in renderings.
2020-06-25 08:47:15 -07:00

760 lines
18 KiB
Rust

//! Tests for the metabuild feature (declarative build scripts).
use cargo_test_support::{
basic_lib_manifest, basic_manifest, is_coarse_mtime, project, registry::Package, rustc_host,
Project,
};
use std::str;
#[cargo_test]
fn metabuild_gated() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
metabuild = ["mb"]
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("build")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr_contains(
"\
error: failed to parse manifest at `[..]`
Caused by:
feature `metabuild` is required
consider adding `cargo-features = [\"metabuild\"]` to the manifest
",
)
.run();
}
fn basic_project() -> Project {
project()
.file(
"Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "foo"
version = "0.0.1"
metabuild = ["mb", "mb-other"]
[build-dependencies]
mb = {path="mb"}
mb-other = {path="mb-other"}
"#,
)
.file("src/lib.rs", "")
.file("mb/Cargo.toml", &basic_lib_manifest("mb"))
.file(
"mb/src/lib.rs",
r#"pub fn metabuild() { println!("Hello mb"); }"#,
)
.file(
"mb-other/Cargo.toml",
r#"
[package]
name = "mb-other"
version = "0.0.1"
"#,
)
.file(
"mb-other/src/lib.rs",
r#"pub fn metabuild() { println!("Hello mb-other"); }"#,
)
.build()
}
#[cargo_test]
fn metabuild_basic() {
let p = basic_project();
p.cargo("build -vv")
.masquerade_as_nightly_cargo()
.with_stdout_contains("[foo 0.0.1] Hello mb")
.with_stdout_contains("[foo 0.0.1] Hello mb-other")
.run();
}
#[cargo_test]
fn metabuild_error_both() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "foo"
version = "0.0.1"
metabuild = "mb"
[build-dependencies]
mb = {path="mb"}
"#,
)
.file("src/lib.rs", "")
.file("build.rs", r#"fn main() {}"#)
.file("mb/Cargo.toml", &basic_lib_manifest("mb"))
.file(
"mb/src/lib.rs",
r#"pub fn metabuild() { println!("Hello mb"); }"#,
)
.build();
p.cargo("build -vv")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr_contains(
"\
error: failed to parse manifest at [..]
Caused by:
cannot specify both `metabuild` and `build`
",
)
.run();
}
#[cargo_test]
fn metabuild_missing_dep() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "foo"
version = "0.0.1"
metabuild = "mb"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("build -vv")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr_contains(
"\
error: failed to parse manifest at [..]
Caused by:
metabuild package `mb` must be specified in `build-dependencies`",
)
.run();
}
#[cargo_test]
fn metabuild_optional_dep() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "foo"
version = "0.0.1"
metabuild = "mb"
[build-dependencies]
mb = {path="mb", optional=true}
"#,
)
.file("src/lib.rs", "")
.file("mb/Cargo.toml", &basic_lib_manifest("mb"))
.file(
"mb/src/lib.rs",
r#"pub fn metabuild() { println!("Hello mb"); }"#,
)
.build();
p.cargo("build -vv")
.masquerade_as_nightly_cargo()
.with_stdout_does_not_contain("[foo 0.0.1] Hello mb")
.run();
p.cargo("build -vv --features mb")
.masquerade_as_nightly_cargo()
.with_stdout_contains("[foo 0.0.1] Hello mb")
.run();
}
#[cargo_test]
fn metabuild_lib_name() {
// Test when setting `name` on [lib].
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "foo"
version = "0.0.1"
metabuild = "mb"
[build-dependencies]
mb = {path="mb"}
"#,
)
.file("src/lib.rs", "")
.file(
"mb/Cargo.toml",
r#"
[package]
name = "mb"
version = "0.0.1"
[lib]
name = "other"
"#,
)
.file(
"mb/src/lib.rs",
r#"pub fn metabuild() { println!("Hello mb"); }"#,
)
.build();
p.cargo("build -vv")
.masquerade_as_nightly_cargo()
.with_stdout_contains("[foo 0.0.1] Hello mb")
.run();
}
#[cargo_test]
fn metabuild_fresh() {
if is_coarse_mtime() {
// This test doesn't work on coarse mtimes very well. Because the
// metabuild script is created at build time, its mtime is almost
// always equal to the mtime of the output. The second call to `build`
// will then think it needs to be rebuilt when it should be fresh.
return;
}
// Check that rebuild is fresh.
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "foo"
version = "0.0.1"
metabuild = "mb"
[build-dependencies]
mb = {path="mb"}
"#,
)
.file("src/lib.rs", "")
.file("mb/Cargo.toml", &basic_lib_manifest("mb"))
.file(
"mb/src/lib.rs",
r#"pub fn metabuild() { println!("Hello mb"); }"#,
)
.build();
p.cargo("build -vv")
.masquerade_as_nightly_cargo()
.with_stdout_contains("[foo 0.0.1] Hello mb")
.run();
p.cargo("build -vv")
.masquerade_as_nightly_cargo()
.with_stdout_does_not_contain("[foo 0.0.1] Hello mb")
.with_stderr(
"\
[FRESH] mb [..]
[FRESH] foo [..]
[FINISHED] dev [..]
",
)
.run();
}
#[cargo_test]
fn metabuild_links() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "foo"
version = "0.0.1"
links = "cat"
metabuild = "mb"
[build-dependencies]
mb = {path="mb"}
"#,
)
.file("src/lib.rs", "")
.file("mb/Cargo.toml", &basic_lib_manifest("mb"))
.file(
"mb/src/lib.rs",
r#"pub fn metabuild() {
assert_eq!(std::env::var("CARGO_MANIFEST_LINKS"),
Ok("cat".to_string()));
println!("Hello mb");
}"#,
)
.build();
p.cargo("build -vv")
.masquerade_as_nightly_cargo()
.with_stdout_contains("[foo 0.0.1] Hello mb")
.run();
}
#[cargo_test]
fn metabuild_override() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "foo"
version = "0.0.1"
links = "cat"
metabuild = "mb"
[build-dependencies]
mb = {path="mb"}
"#,
)
.file("src/lib.rs", "")
.file("mb/Cargo.toml", &basic_lib_manifest("mb"))
.file(
"mb/src/lib.rs",
r#"pub fn metabuild() { panic!("should not run"); }"#,
)
.file(
".cargo/config",
&format!(
r#"
[target.{}.cat]
rustc-link-lib = ["a"]
"#,
rustc_host()
),
)
.build();
p.cargo("build -vv").masquerade_as_nightly_cargo().run();
}
#[cargo_test]
fn metabuild_workspace() {
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["member1", "member2"]
"#,
)
.file(
"member1/Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "member1"
version = "0.0.1"
metabuild = ["mb1", "mb2"]
[build-dependencies]
mb1 = {path="../../mb1"}
mb2 = {path="../../mb2"}
"#,
)
.file("member1/src/lib.rs", "")
.file(
"member2/Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "member2"
version = "0.0.1"
metabuild = ["mb1"]
[build-dependencies]
mb1 = {path="../../mb1"}
"#,
)
.file("member2/src/lib.rs", "")
.build();
project()
.at("mb1")
.file("Cargo.toml", &basic_lib_manifest("mb1"))
.file(
"src/lib.rs",
r#"pub fn metabuild() { println!("Hello mb1 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#,
)
.build();
project()
.at("mb2")
.file("Cargo.toml", &basic_lib_manifest("mb2"))
.file(
"src/lib.rs",
r#"pub fn metabuild() { println!("Hello mb2 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#,
)
.build();
p.cargo("build -vv --workspace")
.masquerade_as_nightly_cargo()
.with_stdout_contains("[member1 0.0.1] Hello mb1 [..]member1")
.with_stdout_contains("[member1 0.0.1] Hello mb2 [..]member1")
.with_stdout_contains("[member2 0.0.1] Hello mb1 [..]member2")
.with_stdout_does_not_contain("[member2 0.0.1] Hello mb2 [..]member2")
.run();
}
#[cargo_test]
fn metabuild_metadata() {
// The metabuild Target is filtered out of the `metadata` results.
let p = basic_project();
let output = p
.cargo("metadata --format-version=1")
.masquerade_as_nightly_cargo()
.exec_with_output()
.expect("cargo metadata failed");
let stdout = str::from_utf8(&output.stdout).unwrap();
let meta: serde_json::Value = serde_json::from_str(stdout).expect("failed to parse json");
let mb_info: Vec<&str> = meta["packages"]
.as_array()
.unwrap()
.iter()
.find(|p| p["name"].as_str().unwrap() == "foo")
.unwrap()["metabuild"]
.as_array()
.unwrap()
.iter()
.map(|s| s.as_str().unwrap())
.collect();
assert_eq!(mb_info, ["mb", "mb-other"]);
}
#[cargo_test]
fn metabuild_build_plan() {
let p = basic_project();
p.cargo("build --build-plan -Zunstable-options")
.masquerade_as_nightly_cargo()
.with_json(
r#"
{
"invocations": [
{
"package_name": "mb",
"package_version": "0.5.0",
"target_kind": ["lib"],
"compile_mode": "build",
"kind": null,
"deps": [],
"outputs": [
"[..]/target/debug/deps/libmb-[..].rlib",
"[..]/target/debug/deps/libmb-[..].rmeta"
],
"links": {},
"program": "rustc",
"args": "{...}",
"env": "{...}",
"cwd": "[..]"
},
{
"package_name": "mb-other",
"package_version": "0.0.1",
"target_kind": ["lib"],
"compile_mode": "build",
"kind": null,
"deps": [],
"outputs": [
"[..]/target/debug/deps/libmb_other-[..].rlib",
"[..]/target/debug/deps/libmb_other-[..].rmeta"
],
"links": {},
"program": "rustc",
"args": "{...}",
"env": "{...}",
"cwd": "[..]"
},
{
"package_name": "foo",
"package_version": "0.0.1",
"target_kind": ["custom-build"],
"compile_mode": "build",
"kind": null,
"deps": [0, 1],
"outputs": "{...}",
"links": "{...}",
"program": "rustc",
"args": "{...}",
"env": "{...}",
"cwd": "[..]"
},
{
"package_name": "foo",
"package_version": "0.0.1",
"target_kind": ["custom-build"],
"compile_mode": "run-custom-build",
"kind": null,
"deps": [2],
"outputs": [],
"links": {},
"program": "[..]/foo/target/debug/build/foo-[..]/metabuild-foo",
"args": [],
"env": "{...}",
"cwd": "[..]"
},
{
"package_name": "foo",
"package_version": "0.0.1",
"target_kind": ["lib"],
"compile_mode": "build",
"kind": null,
"deps": [3],
"outputs": [
"[..]/foo/target/debug/deps/libfoo-[..].rlib",
"[..]/foo/target/debug/deps/libfoo-[..].rmeta"
],
"links": "{...}",
"program": "rustc",
"args": "{...}",
"env": "{...}",
"cwd": "[..]"
}
],
"inputs": [
"[..]/foo/Cargo.toml",
"[..]/foo/mb/Cargo.toml",
"[..]/foo/mb-other/Cargo.toml"
]
}
"#,
)
.run();
assert_eq!(p.glob("target/.metabuild/metabuild-foo-*.rs").count(), 1);
}
#[cargo_test]
fn metabuild_two_versions() {
// Two versions of a metabuild dep with the same name.
let p = project()
.at("ws")
.file(
"Cargo.toml",
r#"
[workspace]
members = ["member1", "member2"]
"#,
)
.file(
"member1/Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "member1"
version = "0.0.1"
metabuild = ["mb"]
[build-dependencies]
mb = {path="../../mb1"}
"#,
)
.file("member1/src/lib.rs", "")
.file(
"member2/Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "member2"
version = "0.0.1"
metabuild = ["mb"]
[build-dependencies]
mb = {path="../../mb2"}
"#,
)
.file("member2/src/lib.rs", "")
.build();
project().at("mb1")
.file("Cargo.toml", r#"
[package]
name = "mb"
version = "0.0.1"
"#)
.file(
"src/lib.rs",
r#"pub fn metabuild() { println!("Hello mb1 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#,
)
.build();
project().at("mb2")
.file("Cargo.toml", r#"
[package]
name = "mb"
version = "0.0.2"
"#)
.file(
"src/lib.rs",
r#"pub fn metabuild() { println!("Hello mb2 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#,
)
.build();
p.cargo("build -vv --workspace")
.masquerade_as_nightly_cargo()
.with_stdout_contains("[member1 0.0.1] Hello mb1 [..]member1")
.with_stdout_contains("[member2 0.0.1] Hello mb2 [..]member2")
.run();
assert_eq!(
p.glob("target/.metabuild/metabuild-member?-*.rs").count(),
2
);
}
#[cargo_test]
fn metabuild_external_dependency() {
Package::new("mb", "1.0.0")
.file("Cargo.toml", &basic_manifest("mb", "1.0.0"))
.file(
"src/lib.rs",
r#"pub fn metabuild() { println!("Hello mb"); }"#,
)
.publish();
Package::new("dep", "1.0.0")
.file(
"Cargo.toml",
r#"
cargo-features = ["metabuild"]
[package]
name = "dep"
version = "1.0.0"
metabuild = ["mb"]
[build-dependencies]
mb = "1.0"
"#,
)
.file("src/lib.rs", "")
.build_dep("mb", "1.0.0")
.publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
[dependencies]
dep = "1.0"
"#,
)
.file("src/lib.rs", "extern crate dep;")
.build();
p.cargo("build -vv")
.masquerade_as_nightly_cargo()
.with_stdout_contains("[dep 1.0.0] Hello mb")
.run();
assert_eq!(p.glob("target/.metabuild/metabuild-dep-*.rs").count(), 1);
}
#[cargo_test]
fn metabuild_json_artifact() {
let p = basic_project();
p.cargo("build --message-format=json")
.masquerade_as_nightly_cargo()
.with_json_contains_unordered(
r#"
{
"executable": null,
"features": [],
"filenames": "{...}",
"fresh": false,
"package_id": "foo [..]",
"profile": "{...}",
"reason": "compiler-artifact",
"target": {
"crate_types": [
"bin"
],
"doctest": false,
"edition": "2018",
"kind": [
"custom-build"
],
"name": "metabuild-foo",
"src_path": "[..]/foo/target/.metabuild/metabuild-foo-[..].rs"
}
}
{
"cfgs": [],
"env": [],
"linked_libs": [],
"linked_paths": [],
"package_id": "foo [..]",
"out_dir": "[..]",
"reason": "build-script-executed"
}
"#,
)
.run();
}
#[cargo_test]
fn metabuild_failed_build_json() {
let p = basic_project();
// Modify the metabuild dep so that it fails to compile.
p.change_file("mb/src/lib.rs", "");
p.cargo("build --message-format=json")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_json_contains_unordered(
r#"
{
"message": {
"children": "{...}",
"code": "{...}",
"level": "error",
"message": "cannot find function `metabuild` in [..] `mb`",
"rendered": "[..]",
"spans": "{...}"
},
"package_id": "foo [..]",
"reason": "compiler-message",
"target": {
"crate_types": [
"bin"
],
"doctest": false,
"edition": "2018",
"kind": [
"custom-build"
],
"name": "metabuild-foo",
"src_path": null
}
}
"#,
)
.run();
}