summaryrefslogtreecommitdiffstats
path: root/src/tools/cargo/tests/testsuite/features.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/cargo/tests/testsuite/features.rs')
-rw-r--r--src/tools/cargo/tests/testsuite/features.rs2084
1 files changed, 2084 insertions, 0 deletions
diff --git a/src/tools/cargo/tests/testsuite/features.rs b/src/tools/cargo/tests/testsuite/features.rs
new file mode 100644
index 000000000..848e05677
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/features.rs
@@ -0,0 +1,2084 @@
+//! Tests for `[features]` table.
+
+use cargo_test_support::paths::CargoPathExt;
+use cargo_test_support::registry::{Dependency, Package};
+use cargo_test_support::{basic_manifest, project};
+
+#[cargo_test]
+fn invalid1() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ bar = ["baz"]
+ "#,
+ )
+ .file("src/main.rs", "")
+ .build();
+
+ p.cargo("check")
+ .with_status(101)
+ .with_stderr(
+ "\
+[ERROR] failed to parse manifest at `[..]`
+
+Caused by:
+ feature `bar` includes `baz` which is neither a dependency nor another feature
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn same_name() {
+ // Feature with the same name as a dependency.
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ bar = ["baz"]
+ baz = []
+
+ [dependencies.bar]
+ path = "bar"
+ "#,
+ )
+ .file("src/main.rs", "")
+ .file("bar/Cargo.toml", &basic_manifest("bar", "1.0.0"))
+ .file("bar/src/lib.rs", "")
+ .build();
+
+ p.cargo("tree -f")
+ .arg("{p} [{f}]")
+ .with_stderr("")
+ .with_stdout(
+ "\
+foo v0.0.1 ([..]) []
+└── bar v1.0.0 ([..]) []
+",
+ )
+ .run();
+
+ p.cargo("tree --features bar -f")
+ .arg("{p} [{f}]")
+ .with_stderr("")
+ .with_stdout(
+ "\
+foo v0.0.1 ([..]) [bar,baz]
+└── bar v1.0.0 ([..]) []
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn invalid3() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ bar = ["baz"]
+
+ [dependencies.baz]
+ path = "foo"
+ "#,
+ )
+ .file("src/main.rs", "")
+ .build();
+
+ p.cargo("check")
+ .with_status(101)
+ .with_stderr(
+ "\
+[ERROR] failed to parse manifest at `[..]`
+
+Caused by:
+ feature `bar` includes `baz`, but `baz` is not an optional dependency
+ A non-optional dependency of the same name is defined; consider adding `optional = true` to its definition.
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn invalid4() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "bar"
+ features = ["bar"]
+ "#,
+ )
+ .file("src/main.rs", "")
+ .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("bar/src/lib.rs", "")
+ .build();
+
+ p.cargo("check")
+ .with_status(101)
+ .with_stderr(
+ "\
+error: failed to select a version for `bar`.
+ ... required by package `foo v0.0.1 ([..])`
+versions that meet the requirements `*` are: 0.0.1
+
+the package `foo` depends on `bar`, with features: `bar` but `bar` does not have these features.
+
+
+failed to select a version for `bar` which could resolve this conflict",
+ )
+ .run();
+
+ p.change_file("Cargo.toml", &basic_manifest("foo", "0.0.1"));
+
+ p.cargo("check --features test")
+ .with_status(101)
+ .with_stderr("error: Package `foo v0.0.1 ([..])` does not have the feature `test`")
+ .run();
+}
+
+#[cargo_test]
+fn invalid5() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dev-dependencies.bar]
+ path = "bar"
+ optional = true
+ "#,
+ )
+ .file("src/main.rs", "")
+ .build();
+
+ p.cargo("check")
+ .with_status(101)
+ .with_stderr(
+ "\
+[ERROR] failed to parse manifest at `[..]`
+
+Caused by:
+ dev-dependencies are not allowed to be optional: `bar`
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn invalid6() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ foo = ["bar/baz"]
+ "#,
+ )
+ .file("src/main.rs", "")
+ .build();
+
+ p.cargo("check --features foo")
+ .with_status(101)
+ .with_stderr(
+ "\
+[ERROR] failed to parse manifest at `[..]`
+
+Caused by:
+ feature `foo` includes `bar/baz`, but `bar` is not a dependency
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn invalid7() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ foo = ["bar/baz"]
+ bar = []
+ "#,
+ )
+ .file("src/main.rs", "")
+ .build();
+
+ p.cargo("check --features foo")
+ .with_status(101)
+ .with_stderr(
+ "\
+[ERROR] failed to parse manifest at `[..]`
+
+Caused by:
+ feature `foo` includes `bar/baz`, but `bar` is not a dependency
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn invalid8() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "bar"
+ features = ["foo/bar"]
+ "#,
+ )
+ .file("src/main.rs", "")
+ .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("bar/src/lib.rs", "")
+ .build();
+
+ p.cargo("check --features foo")
+ .with_status(101)
+ .with_stderr(
+ "\
+error: failed to parse manifest at `[CWD]/Cargo.toml`
+
+Caused by:
+ feature `foo/bar` in dependency `bar` is not allowed to contain slashes
+ If you want to enable features [..]
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn invalid9() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "bar"
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("bar/src/lib.rs", "")
+ .build();
+
+ p.cargo("check --features bar")
+ .with_stderr(
+ "\
+error: Package `foo v0.0.1 ([..])` does not have feature `bar`. It has a required dependency with that name, but only optional dependencies can be used as features.
+",
+ ).with_status(101).run();
+}
+
+#[cargo_test]
+fn invalid10() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "bar"
+ features = ["baz"]
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .file(
+ "bar/Cargo.toml",
+ r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.baz]
+ path = "baz"
+ "#,
+ )
+ .file("bar/src/lib.rs", "")
+ .file("bar/baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
+ .file("bar/baz/src/lib.rs", "")
+ .build();
+
+ p.cargo("check").with_stderr("\
+error: failed to select a version for `bar`.
+ ... required by package `foo v0.0.1 ([..])`
+versions that meet the requirements `*` are: 0.0.1
+
+the package `foo` depends on `bar`, with features: `baz` but `bar` does not have these features.
+ It has a required dependency with that name, but only optional dependencies can be used as features.
+
+
+failed to select a version for `bar` which could resolve this conflict
+").with_status(101)
+ .run();
+}
+
+#[cargo_test]
+fn no_transitive_dep_feature_requirement() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.derived]
+ path = "derived"
+
+ [features]
+ default = ["derived/bar/qux"]
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ extern crate derived;
+ fn main() { derived::test(); }
+ "#,
+ )
+ .file(
+ "derived/Cargo.toml",
+ r#"
+ [package]
+ name = "derived"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "../bar"
+ "#,
+ )
+ .file("derived/src/lib.rs", "extern crate bar; pub use bar::test;")
+ .file(
+ "bar/Cargo.toml",
+ r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ qux = []
+ "#,
+ )
+ .file(
+ "bar/src/lib.rs",
+ r#"
+ #[cfg(feature = "qux")]
+ pub fn test() { print!("test"); }
+ "#,
+ )
+ .build();
+ p.cargo("check")
+ .with_status(101)
+ .with_stderr(
+ "\
+error: failed to parse manifest at `[CWD]/Cargo.toml`
+
+Caused by:
+ multiple slashes in feature `derived/bar/qux` (included by feature `default`) are not allowed
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn no_feature_doesnt_build() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "bar"
+ optional = true
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[cfg(feature = "bar")]
+ extern crate bar;
+ #[cfg(feature = "bar")]
+ fn main() { bar::bar(); println!("bar") }
+ #[cfg(not(feature = "bar"))]
+ fn main() {}
+ "#,
+ )
+ .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("bar/src/lib.rs", "pub fn bar() {}")
+ .build();
+
+ p.cargo("build")
+ .with_stderr(
+ "\
+[COMPILING] foo v0.0.1 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+ p.process(&p.bin("foo")).with_stdout("").run();
+
+ p.cargo("build --features bar -v")
+ .with_stderr(
+ "\
+[COMPILING] bar v0.0.1 ([CWD]/bar)
+[RUNNING] `rustc --crate-name bar [..]
+[DIRTY-MSVC] foo v0.0.1 ([CWD]): the list of features changed
+[COMPILING] foo v0.0.1 ([CWD])
+[RUNNING] `rustc --crate-name foo [..]
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+ p.process(&p.bin("foo")).with_stdout("bar\n").run();
+}
+
+#[cargo_test]
+fn default_feature_pulled_in() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ default = ["bar"]
+
+ [dependencies.bar]
+ path = "bar"
+ optional = true
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[cfg(feature = "bar")]
+ extern crate bar;
+ #[cfg(feature = "bar")]
+ fn main() { bar::bar(); println!("bar") }
+ #[cfg(not(feature = "bar"))]
+ fn main() {}
+ "#,
+ )
+ .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("bar/src/lib.rs", "pub fn bar() {}")
+ .build();
+
+ p.cargo("build")
+ .with_stderr(
+ "\
+[COMPILING] bar v0.0.1 ([CWD]/bar)
+[COMPILING] foo v0.0.1 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+ p.process(&p.bin("foo")).with_stdout("bar\n").run();
+
+ p.cargo("build --no-default-features -v")
+ .with_stderr(
+ "\
+[DIRTY-MSVC] foo v0.0.1 ([CWD]): the list of features changed
+[COMPILING] foo v0.0.1 ([CWD])
+[RUNNING] `rustc --crate-name foo [..]
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+ p.process(&p.bin("foo")).with_stdout("").run();
+}
+
+#[cargo_test]
+fn cyclic_feature() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ default = ["default"]
+ "#,
+ )
+ .file("src/main.rs", "")
+ .build();
+
+ p.cargo("check")
+ .with_status(101)
+ .with_stderr("[ERROR] cyclic feature dependency: feature `default` depends on itself")
+ .run();
+}
+
+#[cargo_test]
+fn cyclic_feature2() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ foo = ["bar"]
+ bar = ["foo"]
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .build();
+
+ p.cargo("check").with_stdout("").run();
+}
+
+#[cargo_test]
+fn groups_on_groups_on_groups() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ default = ["f1"]
+ f1 = ["f2", "bar"]
+ f2 = ["f3", "f4"]
+ f3 = ["f5", "f6", "baz"]
+ f4 = ["f5", "f7"]
+ f5 = ["f6"]
+ f6 = ["f7"]
+ f7 = ["bar"]
+
+ [dependencies.bar]
+ path = "bar"
+ optional = true
+
+ [dependencies.baz]
+ path = "baz"
+ optional = true
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[allow(unused_extern_crates)]
+ extern crate bar;
+ #[allow(unused_extern_crates)]
+ extern crate baz;
+ fn main() {}
+ "#,
+ )
+ .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("check")
+ .with_stderr(
+ "\
+[CHECKING] ba[..] v0.0.1 ([CWD]/ba[..])
+[CHECKING] ba[..] v0.0.1 ([CWD]/ba[..])
+[CHECKING] foo v0.0.1 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn many_cli_features() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "bar"
+ optional = true
+
+ [dependencies.baz]
+ path = "baz"
+ optional = true
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[allow(unused_extern_crates)]
+ extern crate bar;
+ #[allow(unused_extern_crates)]
+ extern crate baz;
+ fn main() {}
+ "#,
+ )
+ .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("check --features")
+ .arg("bar baz")
+ .with_stderr(
+ "\
+[CHECKING] ba[..] v0.0.1 ([CWD]/ba[..])
+[CHECKING] ba[..] v0.0.1 ([CWD]/ba[..])
+[CHECKING] foo v0.0.1 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn union_features() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.d1]
+ path = "d1"
+ features = ["f1"]
+ [dependencies.d2]
+ path = "d2"
+ features = ["f2"]
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[allow(unused_extern_crates)]
+ extern crate d1;
+ extern crate d2;
+ fn main() {
+ d2::f1();
+ d2::f2();
+ }
+ "#,
+ )
+ .file(
+ "d1/Cargo.toml",
+ r#"
+ [package]
+ name = "d1"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ f1 = ["d2"]
+
+ [dependencies.d2]
+ path = "../d2"
+ features = ["f1"]
+ optional = true
+ "#,
+ )
+ .file("d1/src/lib.rs", "")
+ .file(
+ "d2/Cargo.toml",
+ r#"
+ [package]
+ name = "d2"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ f1 = []
+ f2 = []
+ "#,
+ )
+ .file(
+ "d2/src/lib.rs",
+ r#"
+ #[cfg(feature = "f1")] pub fn f1() {}
+ #[cfg(feature = "f2")] pub fn f2() {}
+ "#,
+ )
+ .build();
+
+ p.cargo("check")
+ .with_stderr(
+ "\
+[CHECKING] d2 v0.0.1 ([CWD]/d2)
+[CHECKING] d1 v0.0.1 ([CWD]/d1)
+[CHECKING] foo v0.0.1 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn many_features_no_rebuilds() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "b"
+ version = "0.1.0"
+ authors = []
+
+ [dependencies.a]
+ path = "a"
+ features = ["fall"]
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .file(
+ "a/Cargo.toml",
+ r#"
+ [package]
+ name = "a"
+ version = "0.1.0"
+ authors = []
+
+ [features]
+ ftest = []
+ ftest2 = []
+ fall = ["ftest", "ftest2"]
+ "#,
+ )
+ .file("a/src/lib.rs", "")
+ .build();
+
+ p.cargo("check")
+ .with_stderr(
+ "\
+[CHECKING] a v0.1.0 ([CWD]/a)
+[CHECKING] b v0.1.0 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+ p.root().move_into_the_past();
+
+ p.cargo("check -v")
+ .with_stderr(
+ "\
+[FRESH] a v0.1.0 ([..]/a)
+[FRESH] b v0.1.0 ([..])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+}
+
+// Tests that all cmd lines work with `--features ""`
+#[cargo_test]
+fn empty_features() {
+ let p = project().file("src/main.rs", "fn main() {}").build();
+
+ p.cargo("check --features").arg("").run();
+}
+
+// Tests that all cmd lines work with `--features ""`
+#[cargo_test]
+fn transitive_features() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ foo = ["bar/baz"]
+
+ [dependencies.bar]
+ path = "bar"
+ "#,
+ )
+ .file("src/main.rs", "extern crate bar; fn main() { bar::baz(); }")
+ .file(
+ "bar/Cargo.toml",
+ r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ baz = []
+ "#,
+ )
+ .file(
+ "bar/src/lib.rs",
+ r#"#[cfg(feature = "baz")] pub fn baz() {}"#,
+ )
+ .build();
+
+ p.cargo("check --features foo").run();
+}
+
+#[cargo_test]
+fn everything_in_the_lockfile() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ f1 = ["d1/f1"]
+ f2 = ["d2"]
+
+ [dependencies.d1]
+ path = "d1"
+ [dependencies.d2]
+ path = "d2"
+ optional = true
+ [dependencies.d3]
+ path = "d3"
+ optional = true
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .file(
+ "d1/Cargo.toml",
+ r#"
+ [package]
+ name = "d1"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ f1 = []
+ "#,
+ )
+ .file("d1/src/lib.rs", "")
+ .file("d2/Cargo.toml", &basic_manifest("d2", "0.0.2"))
+ .file("d2/src/lib.rs", "")
+ .file(
+ "d3/Cargo.toml",
+ r#"
+ [package]
+ name = "d3"
+ version = "0.0.3"
+ authors = []
+
+ [features]
+ f3 = []
+ "#,
+ )
+ .file("d3/src/lib.rs", "")
+ .build();
+
+ p.cargo("fetch").run();
+ let lockfile = p.read_lockfile();
+ assert!(
+ lockfile.contains(r#"name = "d1""#),
+ "d1 not found\n{}",
+ lockfile
+ );
+ assert!(
+ lockfile.contains(r#"name = "d2""#),
+ "d2 not found\n{}",
+ lockfile
+ );
+ assert!(
+ lockfile.contains(r#"name = "d3""#),
+ "d3 not found\n{}",
+ lockfile
+ );
+}
+
+#[cargo_test]
+fn no_rebuild_when_frobbing_default_feature() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+ authors = []
+
+ [dependencies]
+ a = { path = "a" }
+ b = { path = "b" }
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file(
+ "b/Cargo.toml",
+ r#"
+ [package]
+ name = "b"
+ version = "0.1.0"
+ authors = []
+
+ [dependencies]
+ a = { path = "../a", features = ["f1"], default-features = false }
+ "#,
+ )
+ .file("b/src/lib.rs", "")
+ .file(
+ "a/Cargo.toml",
+ r#"
+ [package]
+ name = "a"
+ version = "0.1.0"
+ authors = []
+
+ [features]
+ default = ["f1"]
+ f1 = []
+ "#,
+ )
+ .file("a/src/lib.rs", "")
+ .build();
+
+ p.cargo("check").run();
+ p.cargo("check").with_stdout("").run();
+ p.cargo("check").with_stdout("").run();
+}
+
+#[cargo_test]
+fn unions_work_with_no_default_features() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+ authors = []
+
+ [dependencies]
+ a = { path = "a" }
+ b = { path = "b" }
+ "#,
+ )
+ .file("src/lib.rs", "extern crate a; pub fn foo() { a::a(); }")
+ .file(
+ "b/Cargo.toml",
+ r#"
+ [package]
+ name = "b"
+ version = "0.1.0"
+ authors = []
+
+ [dependencies]
+ a = { path = "../a", features = [], default-features = false }
+ "#,
+ )
+ .file("b/src/lib.rs", "")
+ .file(
+ "a/Cargo.toml",
+ r#"
+ [package]
+ name = "a"
+ version = "0.1.0"
+ authors = []
+
+ [features]
+ default = ["f1"]
+ f1 = []
+ "#,
+ )
+ .file("a/src/lib.rs", r#"#[cfg(feature = "f1")] pub fn a() {}"#)
+ .build();
+
+ p.cargo("check").run();
+ p.cargo("check").with_stdout("").run();
+ p.cargo("check").with_stdout("").run();
+}
+
+#[cargo_test]
+fn optional_and_dev_dep() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "test"
+ version = "0.1.0"
+ authors = []
+
+ [dependencies]
+ foo = { path = "foo", optional = true }
+ [dev-dependencies]
+ foo = { path = "foo" }
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
+ .file("foo/src/lib.rs", "")
+ .build();
+
+ p.cargo("check")
+ .with_stderr(
+ "\
+[CHECKING] test v0.1.0 ([..])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn activating_feature_activates_dep() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "test"
+ version = "0.1.0"
+ authors = []
+
+ [dependencies]
+ foo = { path = "foo", optional = true }
+
+ [features]
+ a = ["foo/a"]
+ "#,
+ )
+ .file(
+ "src/lib.rs",
+ "extern crate foo; pub fn bar() { foo::bar(); }",
+ )
+ .file(
+ "foo/Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+ authors = []
+
+ [features]
+ a = []
+ "#,
+ )
+ .file("foo/src/lib.rs", r#"#[cfg(feature = "a")] pub fn bar() {}"#)
+ .build();
+
+ p.cargo("check --features a -v").run();
+}
+
+#[cargo_test]
+fn dep_feature_in_cmd_line() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.derived]
+ path = "derived"
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ extern crate derived;
+ fn main() { derived::test(); }
+ "#,
+ )
+ .file(
+ "derived/Cargo.toml",
+ r#"
+ [package]
+ name = "derived"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "../bar"
+
+ [features]
+ default = []
+ derived-feat = ["bar/some-feat"]
+ "#,
+ )
+ .file("derived/src/lib.rs", "extern crate bar; pub use bar::test;")
+ .file(
+ "bar/Cargo.toml",
+ r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ some-feat = []
+ "#,
+ )
+ .file(
+ "bar/src/lib.rs",
+ r#"
+ #[cfg(feature = "some-feat")]
+ pub fn test() { print!("test"); }
+ "#,
+ )
+ .build();
+
+ // The foo project requires that feature "some-feat" in "bar" is enabled.
+ // Building without any features enabled should fail:
+ p.cargo("check")
+ .with_status(101)
+ .with_stderr_contains("[..]unresolved import `bar::test`")
+ .run();
+
+ // We should be able to enable the feature "derived-feat", which enables "some-feat",
+ // on the command line. The feature is enabled, thus building should be successful:
+ p.cargo("check --features derived/derived-feat").run();
+
+ // Trying to enable features of transitive dependencies is an error
+ p.cargo("check --features bar/some-feat")
+ .with_status(101)
+ .with_stderr("error: package `foo v0.0.1 ([..])` does not have a dependency named `bar`")
+ .run();
+
+ // Hierarchical feature specification should still be disallowed
+ p.cargo("check --features derived/bar/some-feat")
+ .with_status(101)
+ .with_stderr("[ERROR] multiple slashes in feature `derived/bar/some-feat` is not allowed")
+ .run();
+}
+
+#[cargo_test]
+fn all_features_flag_enables_all_features() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ foo = []
+ bar = []
+
+ [dependencies.baz]
+ path = "baz"
+ optional = true
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[cfg(feature = "foo")]
+ pub fn foo() {}
+
+ #[cfg(feature = "bar")]
+ pub fn bar() {
+ extern crate baz;
+ baz::baz();
+ }
+
+ fn main() {
+ foo();
+ bar();
+ }
+ "#,
+ )
+ .file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
+ .file("baz/src/lib.rs", "pub fn baz() {}")
+ .build();
+
+ p.cargo("check --all-features").run();
+}
+
+#[cargo_test]
+fn many_cli_features_comma_delimited() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "bar"
+ optional = true
+
+ [dependencies.baz]
+ path = "baz"
+ optional = true
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[allow(unused_extern_crates)]
+ extern crate bar;
+ #[allow(unused_extern_crates)]
+ extern crate baz;
+ fn main() {}
+ "#,
+ )
+ .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("check --features bar,baz")
+ .with_stderr(
+ "\
+[CHECKING] ba[..] v0.0.1 ([CWD]/ba[..])
+[CHECKING] ba[..] v0.0.1 ([CWD]/ba[..])
+[CHECKING] foo v0.0.1 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn many_cli_features_comma_and_space_delimited() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "bar"
+ optional = true
+
+ [dependencies.baz]
+ path = "baz"
+ optional = true
+
+ [dependencies.bam]
+ path = "bam"
+ optional = true
+
+ [dependencies.bap]
+ path = "bap"
+ optional = true
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[allow(unused_extern_crates)]
+ extern crate bar;
+ #[allow(unused_extern_crates)]
+ extern crate baz;
+ #[allow(unused_extern_crates)]
+ extern crate bam;
+ #[allow(unused_extern_crates)]
+ extern crate bap;
+ fn main() {}
+ "#,
+ )
+ .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() {}")
+ .file("bam/Cargo.toml", &basic_manifest("bam", "0.0.1"))
+ .file("bam/src/lib.rs", "pub fn bam() {}")
+ .file("bap/Cargo.toml", &basic_manifest("bap", "0.0.1"))
+ .file("bap/src/lib.rs", "pub fn bap() {}")
+ .build();
+
+ p.cargo("check --features")
+ .arg("bar,baz bam bap")
+ .with_stderr(
+ "\
+[CHECKING] ba[..] v0.0.1 ([CWD]/ba[..])
+[CHECKING] ba[..] v0.0.1 ([CWD]/ba[..])
+[CHECKING] ba[..] v0.0.1 ([CWD]/ba[..])
+[CHECKING] ba[..] v0.0.1 ([CWD]/ba[..])
+[CHECKING] foo v0.0.1 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn only_dep_is_optional() {
+ Package::new("bar", "0.1.0").publish();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ foo = ['bar']
+
+ [dependencies]
+ bar = { version = "0.1", optional = true }
+
+ [dev-dependencies]
+ bar = "0.1"
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .build();
+
+ p.cargo("check").run();
+}
+
+#[cargo_test]
+fn all_features_all_crates() {
+ Package::new("bar", "0.1.0").publish();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [workspace]
+ members = ['bar']
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .file(
+ "bar/Cargo.toml",
+ r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ foo = []
+ "#,
+ )
+ .file("bar/src/main.rs", "#[cfg(feature = \"foo\")] fn main() {}")
+ .build();
+
+ p.cargo("check --all-features --workspace").run();
+}
+
+#[cargo_test]
+fn feature_off_dylib() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [workspace]
+ members = ["bar"]
+
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [lib]
+ crate-type = ["dylib"]
+
+ [features]
+ f1 = []
+ "#,
+ )
+ .file(
+ "src/lib.rs",
+ r#"
+ pub fn hello() -> &'static str {
+ if cfg!(feature = "f1") {
+ "f1"
+ } else {
+ "no f1"
+ }
+ }
+ "#,
+ )
+ .file(
+ "bar/Cargo.toml",
+ r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+
+ [dependencies]
+ foo = { path = ".." }
+ "#,
+ )
+ .file(
+ "bar/src/main.rs",
+ r#"
+ extern crate foo;
+
+ fn main() {
+ assert_eq!(foo::hello(), "no f1");
+ }
+ "#,
+ )
+ .build();
+
+ // Build the dylib with `f1` feature.
+ p.cargo("check --features f1").run();
+ // Check that building without `f1` uses a dylib without `f1`.
+ p.cargo("run -p bar").run();
+}
+
+#[cargo_test]
+fn warn_if_default_features() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies.bar]
+ path = "bar"
+ optional = true
+
+ [features]
+ default-features = ["bar"]
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("bar/src/lib.rs", "pub fn bar() {}")
+ .build();
+
+ p.cargo("check")
+ .with_stderr(
+ r#"
+[WARNING] `default-features = [".."]` was found in [features]. Did you mean to use `default = [".."]`?
+[CHECKING] foo v0.0.1 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+ "#.trim(),
+ ).run();
+}
+
+#[cargo_test]
+fn no_feature_for_non_optional_dep() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies]
+ bar = { path = "bar" }
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[cfg(not(feature = "bar"))]
+ fn main() {
+ }
+ "#,
+ )
+ .file(
+ "bar/Cargo.toml",
+ r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ a = []
+ "#,
+ )
+ .file("bar/src/lib.rs", "pub fn bar() {}")
+ .build();
+
+ p.cargo("check --features bar/a").run();
+}
+
+#[cargo_test]
+fn features_option_given_twice() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ a = []
+ b = []
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[cfg(all(feature = "a", feature = "b"))]
+ fn main() {}
+ "#,
+ )
+ .build();
+
+ p.cargo("check --features a --features b").run();
+}
+
+#[cargo_test]
+fn multi_multi_features() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ a = []
+ b = []
+ c = []
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[cfg(all(feature = "a", feature = "b", feature = "c"))]
+ fn main() {}
+ "#,
+ )
+ .build();
+
+ p.cargo("check --features a --features").arg("b c").run();
+}
+
+#[cargo_test]
+fn cli_parse_ok() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ a = []
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ #[cfg(feature = "a")]
+ fn main() {
+ assert_eq!(std::env::args().nth(1).unwrap(), "b");
+ }
+ "#,
+ )
+ .build();
+
+ p.cargo("run --features a b").run();
+}
+
+#[cargo_test]
+fn all_features_virtual_ws() {
+ // What happens with `--all-features` in the root of a virtual workspace.
+ // Some of this behavior is a little strange (member dependencies also
+ // have all features enabled, one might expect `f4` to be disabled).
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [workspace]
+ members = ["a", "b"]
+ "#,
+ )
+ .file(
+ "a/Cargo.toml",
+ r#"
+ [package]
+ name = "a"
+ version = "0.1.0"
+ edition = "2018"
+
+ [dependencies]
+ b = {path="../b", optional=true}
+
+ [features]
+ default = ["f1"]
+ f1 = []
+ f2 = []
+ "#,
+ )
+ .file(
+ "a/src/main.rs",
+ r#"
+ fn main() {
+ if cfg!(feature="f1") {
+ println!("f1");
+ }
+ if cfg!(feature="f2") {
+ println!("f2");
+ }
+ #[cfg(feature="b")]
+ b::f();
+ }
+ "#,
+ )
+ .file(
+ "b/Cargo.toml",
+ r#"
+ [package]
+ name = "b"
+ version = "0.1.0"
+
+ [features]
+ default = ["f3"]
+ f3 = []
+ f4 = []
+ "#,
+ )
+ .file(
+ "b/src/lib.rs",
+ r#"
+ pub fn f() {
+ if cfg!(feature="f3") {
+ println!("f3");
+ }
+ if cfg!(feature="f4") {
+ println!("f4");
+ }
+ }
+ "#,
+ )
+ .build();
+
+ p.cargo("run").with_stdout("f1\n").run();
+ p.cargo("run --all-features")
+ .with_stdout("f1\nf2\nf3\nf4\n")
+ .run();
+ // In `a`, it behaves differently. :(
+ p.cargo("run --all-features")
+ .cwd("a")
+ .with_stdout("f1\nf2\nf3\n")
+ .run();
+}
+
+#[cargo_test]
+fn slash_optional_enables() {
+ // --features dep/feat will enable `dep` and set its feature.
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+
+ [dependencies]
+ dep = {path="dep", optional=true}
+ "#,
+ )
+ .file(
+ "src/lib.rs",
+ r#"
+ #[cfg(not(feature="dep"))]
+ compile_error!("dep not set");
+ "#,
+ )
+ .file(
+ "dep/Cargo.toml",
+ r#"
+ [package]
+ name = "dep"
+ version = "0.1.0"
+
+ [features]
+ feat = []
+ "#,
+ )
+ .file(
+ "dep/src/lib.rs",
+ r#"
+ #[cfg(not(feature="feat"))]
+ compile_error!("feat not set");
+ "#,
+ )
+ .build();
+
+ p.cargo("check")
+ .with_status(101)
+ .with_stderr_contains("[..]dep not set[..]")
+ .run();
+
+ p.cargo("check --features dep/feat").run();
+}
+
+#[cargo_test]
+fn registry_summary_order_doesnt_matter() {
+ // Checks for an issue where the resolver depended on the order of entries
+ // in the registry summary. If there was a non-optional dev-dependency
+ // that appeared before an optional normal dependency, then the resolver
+ // would not activate the optional dependency with a pkg/featname feature
+ // syntax.
+ Package::new("dep", "0.1.0")
+ .feature("feat1", &[])
+ .file(
+ "src/lib.rs",
+ r#"
+ #[cfg(feature="feat1")]
+ pub fn work() {
+ println!("it works");
+ }
+ "#,
+ )
+ .publish();
+ Package::new("bar", "0.1.0")
+ .feature("bar_feat", &["dep/feat1"])
+ .add_dep(Dependency::new("dep", "0.1.0").dev())
+ .add_dep(Dependency::new("dep", "0.1.0").optional(true))
+ .file(
+ "src/lib.rs",
+ r#"
+ // This will fail to compile without `dep` optional dep activated.
+ extern crate dep;
+
+ pub fn doit() {
+ dep::work();
+ }
+ "#,
+ )
+ .publish();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+ edition = "2018"
+
+ [dependencies]
+ bar = { version="0.1", features = ["bar_feat"] }
+ "#,
+ )
+ .file(
+ "src/main.rs",
+ r#"
+ fn main() {
+ bar::doit();
+ }
+ "#,
+ )
+ .build();
+
+ p.cargo("run")
+ .with_stderr(
+ "\
+[UPDATING] [..]
+[DOWNLOADING] crates ...
+[DOWNLOADED] [..]
+[DOWNLOADED] [..]
+[COMPILING] dep v0.1.0
+[COMPILING] bar v0.1.0
+[COMPILING] foo v0.1.0 [..]
+[FINISHED] [..]
+[RUNNING] `target/debug/foo[EXE]`
+",
+ )
+ .with_stdout("it works")
+ .run();
+}
+
+#[cargo_test]
+fn nonexistent_required_features() {
+ Package::new("required_dependency", "0.1.0")
+ .feature("simple", &[])
+ .publish();
+ Package::new("optional_dependency", "0.2.0")
+ .feature("optional", &[])
+ .publish();
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+ [features]
+ existing = []
+ fancy = ["optional_dependency"]
+ [dependencies]
+ required_dependency = { version = "0.1", optional = false}
+ optional_dependency = { version = "0.2", optional = true}
+ [[example]]
+ name = "ololo"
+ required-features = ["not_present",
+ "existing",
+ "fancy",
+ "required_dependency/not_existing",
+ "required_dependency/simple",
+ "optional_dependency/optional",
+ "not_specified_dependency/some_feature"]
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .file("examples/ololo.rs", "fn main() {}")
+ .build();
+
+ p.cargo("check --examples")
+ .with_stderr_contains(
+ "\
+[WARNING] invalid feature `not_present` in required-features of target `ololo`: \
+ `not_present` is not present in [features] section
+[WARNING] invalid feature `required_dependency/not_existing` in required-features \
+ of target `ololo`: feature `not_existing` does not exist in package \
+ `required_dependency v0.1.0`
+[WARNING] invalid feature `not_specified_dependency/some_feature` in required-features \
+ of target `ololo`: dependency `not_specified_dependency` does not exist
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn invalid_feature_names_warning() {
+ // Warnings for more restricted feature syntax.
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+
+ [features]
+ # Some valid, but unusual names, shouldn't warn.
+ "c++17" = []
+ "128bit" = []
+ "_foo" = []
+ "feat-name" = []
+ "feat_name" = []
+ "foo.bar" = []
+
+ # Invalid names.
+ "+foo" = []
+ "-foo" = []
+ ".foo" = []
+ "foo:bar" = []
+ "foo?" = []
+ "?foo" = []
+ "ⒶⒷⒸ" = []
+ "a¼" = []
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ // Unfortunately the warnings are duplicated due to the Summary being
+ // loaded twice (once in the Workspace, and once in PackageRegistry) and
+ // Cargo does not have a de-duplication system. This should probably be
+ // OK, since I'm not expecting this to affect anyone.
+ p.cargo("check")
+ .with_stderr("\
+[WARNING] invalid character `+` in feature `+foo` in package foo v0.1.0 ([ROOT]/foo), the first character must be a Unicode XID start character or digit (most letters or `_` or `0` to `9`)
+This was previously accepted but is being phased out; it will become a hard error in a future release.
+For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
+[WARNING] invalid character `-` in feature `-foo` in package foo v0.1.0 ([ROOT]/foo), the first character must be a Unicode XID start character or digit (most letters or `_` or `0` to `9`)
+This was previously accepted but is being phased out; it will become a hard error in a future release.
+For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
+[WARNING] invalid character `.` in feature `.foo` in package foo v0.1.0 ([ROOT]/foo), the first character must be a Unicode XID start character or digit (most letters or `_` or `0` to `9`)
+This was previously accepted but is being phased out; it will become a hard error in a future release.
+For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
+[WARNING] invalid character `?` in feature `?foo` in package foo v0.1.0 ([ROOT]/foo), the first character must be a Unicode XID start character or digit (most letters or `_` or `0` to `9`)
+This was previously accepted but is being phased out; it will become a hard error in a future release.
+For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
+[WARNING] invalid character `¼` in feature `a¼` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
+This was previously accepted but is being phased out; it will become a hard error in a future release.
+For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
+[WARNING] invalid character `:` in feature `foo:bar` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
+This was previously accepted but is being phased out; it will become a hard error in a future release.
+For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
+[WARNING] invalid character `?` in feature `foo?` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
+This was previously accepted but is being phased out; it will become a hard error in a future release.
+For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
+[WARNING] invalid character `Ⓐ` in feature `ⒶⒷⒸ` in package foo v0.1.0 ([ROOT]/foo), the first character must be a Unicode XID start character or digit (most letters or `_` or `0` to `9`)
+This was previously accepted but is being phased out; it will become a hard error in a future release.
+For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
+[WARNING] invalid character `Ⓑ` in feature `ⒶⒷⒸ` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
+This was previously accepted but is being phased out; it will become a hard error in a future release.
+For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
+[WARNING] invalid character `Ⓒ` in feature `ⒶⒷⒸ` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
+This was previously accepted but is being phased out; it will become a hard error in a future release.
+For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
+[CHECKING] foo v0.1.0 [..]
+[FINISHED] [..]
+")
+ .run();
+}
+
+#[cargo_test]
+fn invalid_feature_names_error() {
+ // Errors for more restricted feature syntax.
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+
+ [features]
+ "foo/bar" = []
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("check")
+ .with_status(101)
+ .with_stderr(
+ "\
+error: failed to parse manifest at `[CWD]/Cargo.toml`
+
+Caused by:
+ feature named `foo/bar` is not allowed to contain slashes
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn default_features_conflicting_warning() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+ authors = []
+
+ [dependencies]
+ a = { path = "a", features = ["f1"], default-features = false, default_features = false }
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file(
+ "a/Cargo.toml",
+ r#"
+ [package]
+ name = "a"
+ version = "0.1.0"
+ authors = []
+
+ [features]
+ default = ["f1"]
+ f1 = []
+ "#,
+ )
+ .file("a/src/lib.rs", "")
+ .build();
+
+ p.cargo("check")
+ .with_stderr_contains(
+"[WARNING] conflicting between `default-features` and `default_features` in the `a` dependency.\n
+ `default_features` is ignored and not recommended for use in the future"
+ )
+ .run();
+}