Skip to content

Commit

Permalink
Conditionally mark the test cfg as a well known cfg (#15007)
Browse files Browse the repository at this point in the history
### What does this PR try to resolve?

This PR conditionally mark the `test` cfg as a well known cfg depending
on the target unit "test" field (ie `lib.test = false`, `[[bin]] test =
false` and others).

This is related to rust-lang/rust#117778 and
https://users.rust-lang.org/t/cargo-what-is-the-purpose-of-lib-test-false/102361.

When defining `lib.test = false` (and others), any use of `cfg(test)`
will trigger the `unexpected_cfgs` lint.
```toml
[lib]
test = false  # will now warn on cfg(test)
```

### How should we test and review this PR?

Best reviewed commit by commit. Second commit removes the `test` cfg
from the `--check-cfg` args.

### Additional information

T-compiler
[MCP#785](rust-lang/compiler-team#785) and
#14963 were of preparatory work.

r? @epage
  • Loading branch information
epage authored Jan 28, 2025
2 parents 730d997 + b757af9 commit 26ce027
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 8 deletions.
19 changes: 14 additions & 5 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1391,17 +1391,26 @@ fn check_cfg_args(unit: &Unit) -> Vec<OsString> {
}
arg_feature.push("))");

// In addition to the package features, we also include the `test` cfg (since
// compiler-team#785, as to be able to someday apply yt conditionaly), as well
// the `docsrs` cfg from the docs.rs service.
// In addition to the package features, we also conditionaly include the `test` cfg
// based on the unit target "test" field (ie `lib.test = false`, `[[bin]] test = false` and
// others).
//
// We include `docsrs` here (in Cargo) instead of rustc, since there is a much closer
// We also include `docsrs` here (in Cargo) instead of rustc, since there is a much closer
// relationship between Cargo and docs.rs than rustc and docs.rs. In particular, all
// users of docs.rs use Cargo, but not all users of rustc (like Rust-for-Linux) use docs.rs.
let arg_extra = if unit.target.tested()
// Benchmarks default to `test = false` but most of them still use the test crate
// and the `#[test]` attribute, so for now always mark `test` as well known for them.
|| unit.target.is_bench()
{
OsString::from("cfg(docsrs,test)")
} else {
OsString::from("cfg(docsrs)")
};

vec![
OsString::from("--check-cfg"),
OsString::from("cfg(docsrs,test)"),
arg_extra,
OsString::from("--check-cfg"),
arg_feature,
]
Expand Down
5 changes: 4 additions & 1 deletion src/doc/src/reference/cargo-targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,10 @@ the target name.
### The `test` field

The `test` field indicates whether or not the target is tested by default by
[`cargo test`]. The default is `true` for lib, bins, and tests.
[`cargo test`], and whenever the target is expected to have tests. Warnings
may be reported when tests are unexpected (i.e., `test = false`).

The default is `true` for lib, bins, and tests.

> **Note**: Examples are built by [`cargo test`] by default to ensure they
> continue to compile, but they are not *tested* by default. Setting `test =
Expand Down
187 changes: 187 additions & 0 deletions tests/testsuite/check_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,193 @@ fn well_known_names_values_doctest() {
.run();
}

#[cargo_test(nightly, reason = "warning currently only on nightly")]
fn test_false_lib() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[lib]
test = false
"#,
)
.file("src/lib.rs", "#[cfg(test)] mod tests {}")
.build();

p.cargo("check -v")
.with_stderr_does_not_contain(x!("rustc" => "cfg" of "docsrs,test"))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.with_stderr_data(str![[r#"
...
[WARNING] unexpected `cfg` condition name: `test`
...
[WARNING] `foo` (lib) generated 1 warning
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
"#]])
.run();

p.cargo("clean").run();
p.cargo("test -v")
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.with_stderr_data(str![[r#"
...
[WARNING] unexpected `cfg` condition name: `test`
...
[WARNING] `foo` (lib) generated 1 warning
[FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[DOCTEST] foo
[RUNNING] [..]
"#]])
.run();

p.cargo("clean").run();
p.cargo("test --lib -v")
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.with_stderr_data(str![[r#"
...
[WARNING] unexpected `cfg` condition name: `test`
--> src/lib.rs:1:7
...
[WARNING] `foo` (lib test) generated 1 warning
[FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[RUNNING] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]`
"#]])
.run();
}

#[cargo_test(nightly, reason = "warning currently only on nightly")]
fn test_false_bins() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[[bin]]
name = "daemon"
test = false
path = "src/deamon.rs"
"#,
)
.file("src/main.rs", "fn main() {}\n#[cfg(test)] mod tests {}")
.file("src/deamon.rs", "fn main() {}\n#[cfg(test)] mod tests {}")
.build();

p.cargo("check -v")
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) // for foo
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs")) // for deamon
.with_stderr_data(str![[r#"
...
[WARNING] unexpected `cfg` condition name: `test`
...
[WARNING] `foo` (bin "daemon") generated 1 warning
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
"#]])
.run();
}

#[cargo_test(nightly, reason = "warning currently only on nightly")]
fn test_false_examples() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[lib]
test = false
[[example]]
name = "daemon"
test = false
path = "src/deamon.rs"
"#,
)
.file("src/lib.rs", "#[cfg(test)] mod tests {}")
.file("src/deamon.rs", "fn main() {}\n#[cfg(test)] mod tests {}")
.build();

p.cargo("check --examples -v")
.with_stderr_does_not_contain(x!("rustc" => "cfg" of "docsrs,test"))
.with_stderr_contains(x!("rustc" => "cfg" of "docsrs"))
.with_stderr_data(str![[r#"
...
[WARNING] unexpected `cfg` condition name: `test`
...
[WARNING] `foo` (lib) generated 1 warning
...
[WARNING] unexpected `cfg` condition name: `test`
...
[WARNING] `foo` (example "daemon") generated 1 warning
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
"#]])
.run();
}

#[cargo_test(
nightly,
reason = "bench is nightly & warning currently only on nightly"
)]
fn test_false_benches() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.0"
edition = "2018"
[[bench]]
name = "ben1"
test = false
path = "benches/ben1.rs"
"#,
)
.file("src/lib.rs", "")
.file(
"benches/ben1.rs",
r#"
#![feature(test)]
extern crate test;
#[bench] fn run1(_ben: &mut test::Bencher) { }
"#,
)
.build();

// Benches always require the `test` cfg, there should be no warning.
p.cargo("bench --bench ben1")
.with_stderr_data(str![[r#"
[COMPILING] foo v0.0.0 ([ROOT]/foo)
[FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s
[RUNNING] benches/ben1.rs (target/release/deps/ben1-[HASH][EXE])
"#]])
.run();
}

#[cargo_test]
fn features_doc() {
let p = project()
Expand Down
19 changes: 17 additions & 2 deletions tests/testsuite/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4191,7 +4191,19 @@ fn test_hint_workspace_virtual() {
.file("a/src/lib.rs", "#[test] fn t1() {}")
.file("b/Cargo.toml", &basic_manifest("b", "0.1.0"))
.file("b/src/lib.rs", "#[test] fn t1() {assert!(false)}")
.file("c/Cargo.toml", &basic_manifest("c", "0.1.0"))
.file(
"c/Cargo.toml",
r#"
[package]
name = "c"
version = "0.1.0"
edition = "2015"
[[example]]
name = "ex1"
test = true
"#,
)
.file(
"c/src/lib.rs",
r#"
Expand Down Expand Up @@ -4275,14 +4287,17 @@ fn test_hint_workspace_virtual() {
[ERROR] test failed, to rerun pass `-p c --bin c`
[RUNNING] tests/t1.rs (target/debug/deps/t1-[HASH][EXE])
[ERROR] test failed, to rerun pass `-p c --test t1`
[RUNNING] unittests examples/ex1.rs (target/debug/examples/ex1-[HASH][EXE])
[ERROR] test failed, to rerun pass `-p c --example ex1`
[DOCTEST] a
[DOCTEST] b
[DOCTEST] c
[ERROR] doctest failed, to rerun pass `-p c --doc`
[ERROR] 4 targets failed:
[ERROR] 5 targets failed:
`-p b --lib`
`-p c --bin c`
`-p c --test t1`
`-p c --example ex1`
`-p c --doc`
"#]])
Expand Down

0 comments on commit 26ce027

Please sign in to comment.