From 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 14:41:41 +0200 Subject: Merging upstream version 1.70.0+dfsg2. Signed-off-by: Daniel Baumann --- .../cargo/tests/testsuite/package_features.rs | 704 +++++++++++++++++++++ 1 file changed, 704 insertions(+) create mode 100644 src/tools/cargo/tests/testsuite/package_features.rs (limited to 'src/tools/cargo/tests/testsuite/package_features.rs') diff --git a/src/tools/cargo/tests/testsuite/package_features.rs b/src/tools/cargo/tests/testsuite/package_features.rs new file mode 100644 index 000000000..15f726be5 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/package_features.rs @@ -0,0 +1,704 @@ +//! Tests for feature selection on the command-line. + +use super::features2::switch_to_resolver_2; +use cargo_test_support::registry::{Dependency, Package}; +use cargo_test_support::{basic_manifest, project}; +use std::fmt::Write; + +#[cargo_test] +fn virtual_no_default_features() { + // --no-default-features in root of virtual workspace. + Package::new("dep1", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["a", "b"] + "#, + ) + .file( + "a/Cargo.toml", + r#" + [package] + name = "a" + version = "0.1.0" + + [dependencies] + dep1 = {version = "1.0", optional = true} + + [features] + default = ["dep1"] + "#, + ) + .file("a/src/lib.rs", "") + .file( + "b/Cargo.toml", + r#" + [package] + name = "b" + version = "0.1.0" + + [features] + default = ["f1"] + f1 = [] + "#, + ) + .file( + "b/src/lib.rs", + r#" + #[cfg(feature = "f1")] + compile_error!{"expected f1 off"} + "#, + ) + .build(); + + p.cargo("check --no-default-features") + .with_stderr_unordered( + "\ +[UPDATING] [..] +[CHECKING] a v0.1.0 [..] +[CHECKING] b v0.1.0 [..] +[FINISHED] [..] +", + ) + .run(); + + p.cargo("check --features foo") + .with_status(101) + .with_stderr( + "[ERROR] none of the selected packages contains these features: foo, did you mean: f1?", + ) + .run(); + + p.cargo("check --features a/dep1,b/f1,b/f2,f2") + .with_status(101) + .with_stderr("[ERROR] none of the selected packages contains these features: b/f2, f2, did you mean: f1?") + .run(); + + p.cargo("check --features a/dep,b/f1,b/f2,f2") + .with_status(101) + .with_stderr("[ERROR] none of the selected packages contains these features: a/dep, b/f2, f2, did you mean: a/dep1, f1?") + .run(); + + p.cargo("check --features a/dep,a/dep1") + .with_status(101) + .with_stderr("[ERROR] none of the selected packages contains these features: a/dep, did you mean: b/f1?") + .run(); +} + +#[cargo_test] +fn virtual_typo_member_feature() { + project() + .file( + "Cargo.toml", + r#" + [package] + name = "a" + version = "0.1.0" + resolver = "2" + + [features] + deny-warnings = [] + "#, + ) + .file("src/lib.rs", "") + .build() + .cargo("check --features a/deny-warning") + .with_status(101) + .with_stderr( + "[ERROR] none of the selected packages contains these features: a/deny-warning, did you mean: a/deny-warnings?", + ) + .run(); +} + +#[cargo_test] +fn virtual_features() { + // --features in root of virtual workspace. + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["a", "b"] + "#, + ) + .file( + "a/Cargo.toml", + r#" + [package] + name = "a" + version = "0.1.0" + + [features] + f1 = [] + "#, + ) + .file( + "a/src/lib.rs", + r#" + #[cfg(not(feature = "f1"))] + compile_error!{"f1 is missing"} + "#, + ) + .file("b/Cargo.toml", &basic_manifest("b", "0.1.0")) + .file("b/src/lib.rs", "") + .build(); + + p.cargo("check --features f1") + .with_stderr_unordered( + "\ +[CHECKING] a [..] +[CHECKING] b [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn virtual_with_specific() { + // -p flags with --features in root of virtual. + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["a", "b"] + "#, + ) + .file( + "a/Cargo.toml", + r#" + [package] + name = "a" + version = "0.1.0" + + [features] + f1 = [] + f2 = [] + "#, + ) + .file( + "a/src/lib.rs", + r#" + #[cfg(not_feature = "f1")] + compile_error!{"f1 is missing"} + #[cfg(not_feature = "f2")] + compile_error!{"f2 is missing"} + "#, + ) + .file( + "b/Cargo.toml", + r#" + [package] + name = "b" + version = "0.1.0" + + [features] + f2 = [] + f3 = [] + "#, + ) + .file( + "b/src/lib.rs", + r#" + #[cfg(not_feature = "f2")] + compile_error!{"f2 is missing"} + #[cfg(not_feature = "f3")] + compile_error!{"f3 is missing"} + "#, + ) + .build(); + + p.cargo("check -p a -p b --features f1,f2,f3") + .with_stderr_unordered( + "\ +[CHECKING] a [..] +[CHECKING] b [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn other_member_from_current() { + // -p for another member while in the current directory. + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["bar"] + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = { path="bar", features=["f3"] } + + [features] + f1 = ["bar/f4"] + "#, + ) + .file("src/lib.rs", "") + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.1.0" + + [features] + f1 = [] + f2 = [] + f3 = [] + f4 = [] + "#, + ) + .file("bar/src/lib.rs", "") + .file( + "bar/src/main.rs", + r#" + fn main() { + if cfg!(feature = "f1") { + print!("f1"); + } + if cfg!(feature = "f2") { + print!("f2"); + } + if cfg!(feature = "f3") { + print!("f3"); + } + if cfg!(feature = "f4") { + print!("f4"); + } + println!(); + } + "#, + ) + .build(); + + // Old behavior. + p.cargo("run -p bar --features f1") + .with_stdout("f3f4") + .run(); + + p.cargo("run -p bar --features f1,f2") + .with_status(101) + .with_stderr("[ERROR] Package `foo[..]` does not have the feature `f2`") + .run(); + + p.cargo("run -p bar --features bar/f1") + .with_stdout("f1f3") + .run(); + + // New behavior. + switch_to_resolver_2(&p); + p.cargo("run -p bar --features f1").with_stdout("f1").run(); + + p.cargo("run -p bar --features f1,f2") + .with_stdout("f1f2") + .run(); + + p.cargo("run -p bar --features bar/f1") + .with_stdout("f1") + .run(); +} + +#[cargo_test] +fn feature_default_resolver() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "a" + version = "0.1.0" + + [features] + test = [] + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { + if cfg!(feature = "test") { + println!("feature set"); + } + } + "#, + ) + .build(); + + p.cargo("check --features testt") + .with_status(101) + .with_stderr("[ERROR] Package `a[..]` does not have the feature `testt`") + .run(); + + p.cargo("run --features test") + .with_status(0) + .with_stdout("feature set") + .run(); + + p.cargo("run --features a/test") + .with_status(101) + .with_stderr("[ERROR] package `a[..]` does not have a dependency named `a`") + .run(); +} + +#[cargo_test] +fn virtual_member_slash() { + // member slash feature syntax + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["a"] + "#, + ) + .file( + "a/Cargo.toml", + r#" + [package] + name = "a" + version = "0.1.0" + + [dependencies] + b = {path="../b", optional=true} + + [features] + default = ["f1"] + f1 = [] + f2 = [] + "#, + ) + .file( + "a/src/lib.rs", + r#" + #[cfg(feature = "f1")] + compile_error!{"f1 is set"} + + #[cfg(feature = "f2")] + compile_error!{"f2 is set"} + + #[cfg(feature = "b")] + compile_error!{"b is set"} + "#, + ) + .file( + "b/Cargo.toml", + r#" + [package] + name = "b" + version = "0.1.0" + + [features] + bfeat = [] + "#, + ) + .file( + "b/src/lib.rs", + r#" + #[cfg(feature = "bfeat")] + compile_error!{"bfeat is set"} + "#, + ) + .build(); + + p.cargo("check -p a") + .with_status(101) + .with_stderr_contains("[..]f1 is set[..]") + .with_stderr_does_not_contain("[..]f2 is set[..]") + .with_stderr_does_not_contain("[..]b is set[..]") + .run(); + + p.cargo("check -p a --features a/f1") + .with_status(101) + .with_stderr_contains("[..]f1 is set[..]") + .with_stderr_does_not_contain("[..]f2 is set[..]") + .with_stderr_does_not_contain("[..]b is set[..]") + .run(); + + p.cargo("check -p a --features a/f2") + .with_status(101) + .with_stderr_contains("[..]f1 is set[..]") + .with_stderr_contains("[..]f2 is set[..]") + .with_stderr_does_not_contain("[..]b is set[..]") + .run(); + + p.cargo("check -p a --features b/bfeat") + .with_status(101) + .with_stderr_contains("[..]bfeat is set[..]") + .run(); + + p.cargo("check -p a --no-default-features").run(); + + p.cargo("check -p a --no-default-features --features b") + .with_status(101) + .with_stderr_contains("[..]b is set[..]") + .run(); +} + +#[cargo_test] +fn non_member() { + // -p for a non-member + Package::new("dep", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + resolver = "2" + + [dependencies] + dep = "1.0" + + [features] + f1 = [] + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check -p dep --features f1") + .with_status(101) + .with_stderr("[ERROR] cannot specify features for packages outside of workspace") + .run(); + + p.cargo("check -p dep --all-features") + .with_status(101) + .with_stderr("[ERROR] cannot specify features for packages outside of workspace") + .run(); + + p.cargo("check -p dep --no-default-features") + .with_status(101) + .with_stderr("[ERROR] cannot specify features for packages outside of workspace") + .run(); + + p.cargo("check -p dep") + .with_stderr( + "\ +[UPDATING] [..] +[DOWNLOADING] [..] +[DOWNLOADED] [..] +[CHECKING] dep [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn resolver1_member_features() { + // --features member-name/feature-name with resolver="1" + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["member1", "member2"] + "#, + ) + .file( + "member1/Cargo.toml", + r#" + [package] + name = "member1" + version = "0.1.0" + + [features] + m1-feature = [] + "#, + ) + .file( + "member1/src/main.rs", + r#" + fn main() { + if cfg!(feature = "m1-feature") { + println!("m1-feature set"); + } + } + "#, + ) + .file("member2/Cargo.toml", &basic_manifest("member2", "0.1.0")) + .file("member2/src/lib.rs", "") + .build(); + + p.cargo("run -p member1 --features member1/m1-feature") + .cwd("member2") + .with_stdout("m1-feature set") + .run(); + + p.cargo("check -p member1 --features member1/m2-feature") + .cwd("member2") + .with_status(101) + .with_stderr("[ERROR] Package `member1[..]` does not have the feature `m2-feature`") + .run(); +} + +#[cargo_test] +fn non_member_feature() { + // --features for a non-member + Package::new("jazz", "1.0.0").publish(); + Package::new("bar", "1.0.0") + .add_dep(Dependency::new("jazz", "1.0").optional(true)) + .publish(); + let make_toml = |resolver, optional| { + let mut s = String::new(); + write!( + s, + r#" + [package] + name = "foo" + version = "0.1.0" + resolver = "{}" + + [dependencies] + "#, + resolver + ) + .unwrap(); + if optional { + s.push_str(r#"bar = { version = "1.0", optional = true } "#); + } else { + s.push_str(r#"bar = "1.0""#) + } + s.push('\n'); + s + }; + let p = project() + .file("Cargo.toml", &make_toml("1", false)) + .file("src/lib.rs", "") + .build(); + p.cargo("fetch").run(); + ///////////////////////// V1 non-optional + eprintln!("V1 non-optional"); + p.cargo("check -p bar") + .with_stderr( + "\ +[CHECKING] bar v1.0.0 +[FINISHED] [..] +", + ) + .run(); + // TODO: This should not be allowed (future warning?) + p.cargo("check --features bar/jazz") + .with_stderr( + "\ +[DOWNLOADING] crates ... +[DOWNLOADED] jazz v1.0.0 [..] +[CHECKING] jazz v1.0.0 +[CHECKING] bar v1.0.0 +[CHECKING] foo v0.1.0 [..] +[FINISHED] [..] +", + ) + .run(); + // TODO: This should not be allowed (future warning?) + p.cargo("check -p bar --features bar/jazz -v") + .with_stderr( + "\ +[FRESH] jazz v1.0.0 +[FRESH] bar v1.0.0 +[FINISHED] [..] +", + ) + .run(); + + ///////////////////////// V1 optional + eprintln!("V1 optional"); + p.change_file("Cargo.toml", &make_toml("1", true)); + + // This error isn't great, but is probably unlikely to be common in + // practice, so I'm not going to put much effort into improving it. + p.cargo("check -p bar") + .with_status(101) + .with_stderr( + "\ +error: package ID specification `bar` did not match any packages + +Did you mean `foo`? +", + ) + .run(); + + p.cargo("check -p bar --features bar -v") + .with_stderr( + "\ +[FRESH] bar v1.0.0 +[FINISHED] [..] +", + ) + .run(); + + // TODO: This should not be allowed (future warning?) + p.cargo("check -p bar --features bar/jazz -v") + .with_stderr( + "\ +[FRESH] jazz v1.0.0 +[FRESH] bar v1.0.0 +[FINISHED] [..] +", + ) + .run(); + + ///////////////////////// V2 non-optional + eprintln!("V2 non-optional"); + p.change_file("Cargo.toml", &make_toml("2", false)); + // TODO: This should not be allowed (future warning?) + p.cargo("check --features bar/jazz -v") + .with_stderr( + "\ +[FRESH] jazz v1.0.0 +[FRESH] bar v1.0.0 +[FRESH] foo v0.1.0 [..] +[FINISHED] [..] +", + ) + .run(); + p.cargo("check -p bar -v") + .with_stderr( + "\ +[FRESH] bar v1.0.0 +[FINISHED] [..] +", + ) + .run(); + p.cargo("check -p bar --features bar/jazz") + .with_status(101) + .with_stderr("error: cannot specify features for packages outside of workspace") + .run(); + + ///////////////////////// V2 optional + eprintln!("V2 optional"); + p.change_file("Cargo.toml", &make_toml("2", true)); + p.cargo("check -p bar") + .with_status(101) + .with_stderr( + "\ +error: package ID specification `bar` did not match any packages + +Did you mean `foo`? +", + ) + .run(); + // New --features behavior does not look at cwd. + p.cargo("check -p bar --features bar") + .with_status(101) + .with_stderr("error: cannot specify features for packages outside of workspace") + .run(); + p.cargo("check -p bar --features bar/jazz") + .with_status(101) + .with_stderr("error: cannot specify features for packages outside of workspace") + .run(); + p.cargo("check -p bar --features foo/bar") + .with_status(101) + .with_stderr("error: cannot specify features for packages outside of workspace") + .run(); +} -- cgit v1.2.3