| //! 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(); |
| } |