cargo/tests/testsuite/check_cfg.rs
2024-07-11 09:38:57 +08:00

948 lines
24 KiB
Rust

//! Tests for Cargo usage of rustc `--check-cfg`.
use cargo_test_support::prelude::*;
use cargo_test_support::{basic_manifest, project, str};
macro_rules! x {
($tool:tt => $what:tt $(of $who:tt)?) => {{
#[cfg(windows)]
{
concat!("[RUNNING] [..]", $tool, "[..] --check-cfg ",
$what, '(', $($who,)* ')', "[..]")
}
#[cfg(not(windows))]
{
concat!("[RUNNING] [..]", $tool, "[..] --check-cfg '",
$what, '(', $($who,)* ')', "'", "[..]")
}
}};
($tool:tt => $what:tt of $who:tt with $($first_value:tt $($other_values:tt)*)?) => {{
#[cfg(windows)]
{
concat!("[RUNNING] [..]", $tool, "[..] --check-cfg \"",
$what, '(', $who, ", values(", $("/\"", $first_value, "/\"", $(", ", "/\"", $other_values, "/\"",)*)* "))", '"', "[..]")
}
#[cfg(not(windows))]
{
concat!("[RUNNING] [..]", $tool, "[..] --check-cfg '",
$what, '(', $who, ", values(", $("\"", $first_value, "\"", $(", ", "\"", $other_values, "\"",)*)* "))", "'", "[..]")
}
}};
}
#[allow(deprecated)]
#[cargo_test]
fn features() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[features]
f_a = []
f_b = []
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn features_with_deps() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[dependencies]
bar = { path = "bar/" }
[features]
f_a = []
f_b = []
"#,
)
.file("src/main.rs", "fn main() {}")
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}")
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn features_with_opt_deps() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[dependencies]
bar = { path = "bar/", optional = true }
[features]
default = ["bar"]
f_a = []
f_b = []
"#,
)
.file("src/main.rs", "fn main() {}")
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}")
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "bar" "default" "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn features_with_namespaced_features() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[dependencies]
bar = { path = "bar/", optional = true }
[features]
f_a = ["dep:bar"]
f_b = []
"#,
)
.file("src/main.rs", "fn main() {}")
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}")
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn features_fingerprint() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[features]
f_a = []
f_b = []
"#,
)
.file("src/lib.rs", "#[cfg(feature = \"f_b\")] fn entry() {}")
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.with_stderr_does_not_contain("[..]unexpected_cfgs[..]")
.run();
p.cargo("check -v")
.with_stderr_does_not_contain("[..]rustc[..]")
.run();
// checking that re-ordering the features does not invalid the fingerprint
p.change_file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[features]
f_b = []
f_a = []
"#,
);
p.cargo("check -v")
.with_stderr_does_not_contain("[..]rustc[..]")
.run();
p.change_file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[features]
f_a = []
"#,
);
p.cargo("check -v")
// we check that the fingerprint is indeed dirty
// that is cause rustc to be called again with the new check-cfg args
// and that we indeed found a new warning from the unexpected_cfgs lint
.with_stderr_data(format!(
"\
[DIRTY] foo v0.1.0 ([ROOT]/foo): the list of declared features changed
[CHECKING] foo v0.1.0 ([ROOT]/foo)
{running_rustc}
[WARNING] unexpected `cfg` condition value: `f_b`
...
",
running_rustc = x!("rustc" => "cfg" of "feature" with "f_a")
))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn well_known_names_values() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn features_test() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[features]
f_a = []
f_b = []
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("test -v")
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn features_doctest() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[features]
default = ["f_a"]
f_a = []
f_b = []
"#,
)
.file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
.build();
p.cargo("test -v --doc")
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "default" "f_a" "f_b"))
.with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with "default" "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.with_stderr_contains(x!("rustdoc" => "cfg" of "docsrs"))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn well_known_names_values_test() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("test -v")
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn well_known_names_values_doctest() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
.build();
p.cargo("test -v --doc")
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with))
.with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.with_stderr_contains(x!("rustdoc" => "cfg" of "docsrs"))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn features_doc() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[features]
default = ["f_a"]
f_a = []
f_b = []
"#,
)
.file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
.build();
p.cargo("doc -v")
.with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with "default" "f_a" "f_b"))
.with_stderr_contains(x!("rustdoc" => "cfg" of "docsrs"))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn build_script_feedback() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
build = "build.rs"
"#,
)
.file("src/main.rs", "fn main() {}")
.file(
"build.rs",
r#"fn main() { println!("cargo::rustc-check-cfg=cfg(foo)"); }"#,
)
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "foo"))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn build_script_doc() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
build = "build.rs"
"#,
)
.file("src/main.rs", "fn main() {}")
.file(
"build.rs",
r#"fn main() { println!("cargo::rustc-check-cfg=cfg(foo)"); }"#,
)
.build();
p.cargo("doc -v")
.with_stderr_does_not_contain("rustc [..] --check-cfg [..]")
.with_stderr_data(format!(
"\
[COMPILING] foo v0.0.1 ([ROOT]/foo)
[RUNNING] `rustc [..] build.rs [..]`
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build`
[DOCUMENTING] foo v0.0.1 ([ROOT]/foo)
{running_rustdoc}
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[GENERATED] [ROOT]/foo/target/doc/foo/index.html
",
running_rustdoc = x!("rustdoc" => "cfg" of "foo")
))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn build_script_override() {
let target = cargo_test_support::rustc_host();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.5.0"
edition = "2015"
authors = []
links = "a"
build = "build.rs"
"#,
)
.file("src/main.rs", "fn main() {}")
.file("build.rs", "")
.file(
".cargo/config.toml",
&format!(
r#"
[target.{}.a]
rustc-check-cfg = ["cfg(foo)"]
"#,
target
),
)
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "foo"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.run();
}
#[cargo_test]
fn build_script_test() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2015"
authors = []
build = "build.rs"
"#,
)
.file(
"build.rs",
r#"fn main() {
println!("cargo::rustc-check-cfg=cfg(foo)");
println!("cargo::rustc-cfg=foo");
}"#,
)
.file(
"src/lib.rs",
r#"
///
/// ```
/// extern crate foo;
///
/// fn main() {
/// foo::foo()
/// }
/// ```
///
#[cfg(foo)]
pub fn foo() {}
#[cfg(foo)]
#[test]
fn test_foo() {
foo()
}
"#,
)
.file("tests/test.rs", "#[cfg(foo)] #[test] fn test_bar() {}")
.build();
p.cargo("test -v")
.with_stderr_data(
format!(
"\
{running_rustc}
{running_rustdoc}
...
",
running_rustc = x!("rustc" => "cfg" of "foo"),
running_rustdoc = x!("rustdoc" => "cfg" of "foo")
)
.unordered(),
)
.with_stdout_data(
str![[r#"
test test_foo ... ok
test test_bar ... ok
test [..] ... ok
...
"#]]
.unordered(),
)
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn config_simple() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)", "cfg(has_bar, values(\"yes\", \"no\"))"] }
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "has_foo"))
.with_stderr_contains(x!("rustc" => "cfg" of "has_bar" with "yes" "no"))
.with_stderr_does_not_contain("[..]unused manifest key[..]")
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn config_workspace() {
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["foo/"]
[workspace.lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)"] }
"#,
)
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[lints]
workspace = true
"#,
)
.file("foo/src/main.rs", "fn main() {}")
.build();
p.cargo("check -v")
.with_stderr_data(format!(
"\
...
{running_rustc}
...
",
running_rustc = x!("rustc" => "cfg" of "has_foo")
))
.with_stderr_does_not_contain("unexpected_cfgs")
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn config_workspace_not_inherited() {
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["foo/"]
[workspace.lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)"] }
"#,
)
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
"#,
)
.file("foo/src/main.rs", "fn main() {}")
.build();
p.cargo("check -v")
.with_stderr_does_not_contain(x!("rustc" => "cfg" of "has_foo"))
.with_stderr_does_not_contain("unexpected_cfgs")
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn config_invalid_position() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[lints.rust]
use_bracket = { level = "warn", check-cfg = ["cfg(has_foo)"] }
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v")
.with_stderr_data(str![[r#"
[WARNING] unused manifest key: `lints.rust.use_bracket.check-cfg`
...
"#]])
.with_stderr_does_not_contain(x!("rustc" => "cfg" of "has_foo"))
.run();
}
#[cargo_test]
fn config_invalid_empty() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[lints.rust]
unexpected_cfgs = { }
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] missing field `level`
...
"#]])
.run();
}
#[cargo_test]
fn config_invalid_not_list() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = "cfg()" }
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] `lints.rust.unexpected_cfgs.check-cfg` must be a list of string
...
"#]])
.run();
}
#[cargo_test]
fn config_invalid_not_list_string() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [12] }
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] `lints.rust.unexpected_cfgs.check-cfg` must be a list of string
...
"#]])
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn config_and_features() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[features]
my_feature = []
alloc = []
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)", "cfg(has_bar, values(\"yes\", \"no\"))"] }
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "has_foo"))
.with_stderr_contains(x!("rustc" => "cfg" of "has_bar" with "yes" "no"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "alloc" "my_feature"))
.run();
}
#[cargo_test]
fn config_with_cargo_doc() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)"] }
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("doc -v")
.with_stderr_data(format!(
"\
...
{running_rustdoc}
...
",
running_rustdoc = x!("rustdoc" => "cfg" of "has_foo")
))
.run();
}
#[cargo_test]
fn config_with_cargo_test() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)"] }
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("test -v")
.with_stderr_data(format!(
"\
...
{running_rustc}
...
",
running_rustc = x!("rustc" => "cfg" of "has_foo")
))
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn config_and_build_script() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2021"
build = "build.rs"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(bar)"] }
"#,
)
.file("src/main.rs", "fn main() {}")
.file(
"build.rs",
r#"fn main() { println!("cargo::rustc-check-cfg=cfg(foo)"); }"#,
)
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "foo")) // from build.rs
.with_stderr_contains(x!("rustc" => "cfg" of "bar")) // from config
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn config_features_and_build_script() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
edition = "2021"
build = "build.rs"
[features]
serde = []
json = []
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(bar)"] }
"#,
)
.file("src/main.rs", "fn main() {}")
.file(
"build.rs",
r#"fn main() { println!("cargo::rustc-check-cfg=cfg(foo)"); }"#,
)
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "foo")) // from build.rs
.with_stderr_contains(x!("rustc" => "cfg" of "bar")) // from config
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "json" "serde")) // features
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs")) // Cargo well known
.run();
}
#[allow(deprecated)]
#[cargo_test]
fn config_fingerprint() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(bar)"] }
"#,
)
.file("src/lib.rs", "fn entry() {}")
.build();
p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "bar"))
.run();
p.cargo("check -v")
.with_stderr_does_not_contain("[..]rustc[..]")
.run();
// checking that changing the `check-cfg` config does invalid the fingerprint
p.change_file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(bar)", "cfg(foo)"] }
"#,
);
p.cargo("check -v")
// we check that the fingerprint is indeed dirty
.with_stderr_contains("[..]Dirty[..]the profile configuration changed")
// that cause rustc to be called again with the new check-cfg args
.with_stderr_contains(x!("rustc" => "cfg" of "bar"))
.with_stderr_contains(x!("rustc" => "cfg" of "foo"))
.run();
}