cargo/tests/testsuite/features.rs

1672 lines
39 KiB
Rust
Raw Normal View History

use std::fs::File;
use std::io::prelude::*;
use support::paths::CargoPathExt;
use support::registry::Package;
2018-08-28 20:38:26 +00:00
use support::{basic_manifest, project};
#[test]
fn invalid1() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[features]
bar = ["baz"]
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "")
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
Feature `bar` includes `baz` which is neither a dependency nor another feature
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn invalid2() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[features]
bar = ["baz"]
[dependencies.bar]
path = "foo"
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "")
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
Features and dependencies cannot have the same name: `bar`
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn invalid3() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[features]
bar = ["baz"]
[dependencies.baz]
path = "foo"
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "")
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
Feature `bar` depends on `baz` which is not an optional dependency.
Consider adding `optional = true` to the dependency
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn invalid4() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
features = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "")
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "")
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
error: failed to select a version for `bar`.
... required by package `foo v0.0.1 ([..])`
versions that meet the requirements `*` are: 0.0.1
2018-03-01 18:12:27 +00:00
the package `foo` depends on `bar`, with features: `bar` but `bar` does not have these features.
2018-03-14 15:17:44 +00:00
failed to select a version for `bar` which could resolve this conflict",
).run();
2018-07-24 22:35:01 +00:00
p.change_file("Cargo.toml", &basic_manifest("foo", "0.0.1"));
2018-03-14 15:17:44 +00:00
p.cargo("build --features test")
.with_status(101)
.with_stderr("error: Package `foo v0.0.1 ([..])` does not have these features: `test`")
.run();
}
#[test]
fn invalid5() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dev-dependencies.bar]
path = "bar"
optional = true
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "")
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
Dev-dependencies are not allowed to be optional: `bar`
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn invalid6() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[features]
foo = ["bar/baz"]
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "")
.build();
p.cargo("build --features foo")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
2017-08-05 04:27:26 +00:00
Feature `foo` requires a feature of `bar` which is not a dependency
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn invalid7() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[features]
foo = ["bar/baz"]
bar = []
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "")
.build();
p.cargo("build --features foo")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
2017-08-05 04:27:26 +00:00
Feature `foo` requires a feature of `bar` which is not a dependency
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn invalid8() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
features = ["foo/bar"]
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "")
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "")
.build();
p.cargo("build --features foo")
.with_status(101)
.with_stderr("[ERROR] feature names may not contain slashes: `foo/bar`")
.run();
Disallow specifying features of transitive deps Before this commit, it was possible to activate a feature in a transtive dependency, using a Cargo.toml like the following one: ... [features] # this will enable feature fast in package bar, which is a # dependency of foo default = [ foo/bar/fast ] This is a bug, and was never intended, and it is checked in other places already. The behavior was possible because `build_features::add_feature` treats the specification "foo/bar/fast" as just another feature. So when we require the feature "foo/bar/fast", add_feature for foo will generate a dependency on "foo" requiring that feature "bar/fast" is enabled. Then, when resolving foo, add_feature will find that "bar/fast" is a required feature, so it'll happily add "fast" as the required feature for the dependency "foo". The fix for this is to make sure that the `add_feature` function does not treat `a/b` specifications as just another feature. Instead, it now handles that case without recursion directly when it encounters it. We can see how this resolves the above problem: when resolving foo, add_feature for the required feature "bar/fast" will be called. Because add_feature no longer treats such specifciations differently at the top level, it will try to enable a feature with the exact name "bar/fast", and Context::resolve_features will later find that no such feature exists for package foo. To give a friendlier error message, we also check in Context::resolve_features that we never ever require a feature with a slash in a name from a dependency.
2016-07-01 20:36:05 +00:00
}
#[test]
fn invalid9() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "fn main() {}")
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "")
.build();
p.cargo("build --features bar").with_stderr("\
warning: 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. [..]
Compiling bar v0.0.1 ([..])
Compiling foo v0.0.1 ([..])
2018-05-02 12:52:40 +00:00
Finished dev [unoptimized + debuginfo] target(s) in [..]s
").run();
}
#[test]
fn invalid10() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
features = ["baz"]
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies.baz]
path = "baz"
2018-03-14 15:17:44 +00:00
"#,
).file("bar/src/lib.rs", "")
2018-07-24 22:35:01 +00:00
.file("bar/baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
.file("bar/baz/src/lib.rs", "")
.build();
p.cargo("build").with_stderr("\
warning: Package `bar v0.0.1 ([..])` does not have feature `baz`. It has a required dependency with \
that name, but only optional dependencies can be used as features. [..]
Compiling baz v0.0.1 ([..])
Compiling bar v0.0.1 ([..])
Compiling foo v0.0.1 ([..])
2018-05-02 12:52:40 +00:00
Finished dev [unoptimized + debuginfo] target(s) in [..]s
").run();
}
Disallow specifying features of transitive deps Before this commit, it was possible to activate a feature in a transtive dependency, using a Cargo.toml like the following one: ... [features] # this will enable feature fast in package bar, which is a # dependency of foo default = [ foo/bar/fast ] This is a bug, and was never intended, and it is checked in other places already. The behavior was possible because `build_features::add_feature` treats the specification "foo/bar/fast" as just another feature. So when we require the feature "foo/bar/fast", add_feature for foo will generate a dependency on "foo" requiring that feature "bar/fast" is enabled. Then, when resolving foo, add_feature will find that "bar/fast" is a required feature, so it'll happily add "fast" as the required feature for the dependency "foo". The fix for this is to make sure that the `add_feature` function does not treat `a/b` specifications as just another feature. Instead, it now handles that case without recursion directly when it encounters it. We can see how this resolves the above problem: when resolving foo, add_feature for the required feature "bar/fast" will be called. Because add_feature no longer treats such specifciations differently at the top level, it will try to enable a feature with the exact name "bar/fast", and Context::resolve_features will later find that no such feature exists for package foo. To give a friendlier error message, we also check in Context::resolve_features that we never ever require a feature with a slash in a name from a dependency.
2016-07-01 20:36:05 +00:00
#[test]
fn no_transitive_dep_feature_requirement() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
Disallow specifying features of transitive deps Before this commit, it was possible to activate a feature in a transtive dependency, using a Cargo.toml like the following one: ... [features] # this will enable feature fast in package bar, which is a # dependency of foo default = [ foo/bar/fast ] This is a bug, and was never intended, and it is checked in other places already. The behavior was possible because `build_features::add_feature` treats the specification "foo/bar/fast" as just another feature. So when we require the feature "foo/bar/fast", add_feature for foo will generate a dependency on "foo" requiring that feature "bar/fast" is enabled. Then, when resolving foo, add_feature will find that "bar/fast" is a required feature, so it'll happily add "fast" as the required feature for the dependency "foo". The fix for this is to make sure that the `add_feature` function does not treat `a/b` specifications as just another feature. Instead, it now handles that case without recursion directly when it encounters it. We can see how this resolves the above problem: when resolving foo, add_feature for the required feature "bar/fast" will be called. Because add_feature no longer treats such specifciations differently at the top level, it will try to enable a feature with the exact name "bar/fast", and Context::resolve_features will later find that no such feature exists for package foo. To give a friendlier error message, we also check in Context::resolve_features that we never ever require a feature with a slash in a name from a dependency.
2016-07-01 20:36:05 +00:00
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.derived]
path = "derived"
[features]
default = ["derived/bar/qux"]
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"src/main.rs",
r#"
Disallow specifying features of transitive deps Before this commit, it was possible to activate a feature in a transtive dependency, using a Cargo.toml like the following one: ... [features] # this will enable feature fast in package bar, which is a # dependency of foo default = [ foo/bar/fast ] This is a bug, and was never intended, and it is checked in other places already. The behavior was possible because `build_features::add_feature` treats the specification "foo/bar/fast" as just another feature. So when we require the feature "foo/bar/fast", add_feature for foo will generate a dependency on "foo" requiring that feature "bar/fast" is enabled. Then, when resolving foo, add_feature will find that "bar/fast" is a required feature, so it'll happily add "fast" as the required feature for the dependency "foo". The fix for this is to make sure that the `add_feature` function does not treat `a/b` specifications as just another feature. Instead, it now handles that case without recursion directly when it encounters it. We can see how this resolves the above problem: when resolving foo, add_feature for the required feature "bar/fast" will be called. Because add_feature no longer treats such specifciations differently at the top level, it will try to enable a feature with the exact name "bar/fast", and Context::resolve_features will later find that no such feature exists for package foo. To give a friendlier error message, we also check in Context::resolve_features that we never ever require a feature with a slash in a name from a dependency.
2016-07-01 20:36:05 +00:00
extern crate derived;
fn main() { derived::test(); }
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"derived/Cargo.toml",
r#"
Disallow specifying features of transitive deps Before this commit, it was possible to activate a feature in a transtive dependency, using a Cargo.toml like the following one: ... [features] # this will enable feature fast in package bar, which is a # dependency of foo default = [ foo/bar/fast ] This is a bug, and was never intended, and it is checked in other places already. The behavior was possible because `build_features::add_feature` treats the specification "foo/bar/fast" as just another feature. So when we require the feature "foo/bar/fast", add_feature for foo will generate a dependency on "foo" requiring that feature "bar/fast" is enabled. Then, when resolving foo, add_feature will find that "bar/fast" is a required feature, so it'll happily add "fast" as the required feature for the dependency "foo". The fix for this is to make sure that the `add_feature` function does not treat `a/b` specifications as just another feature. Instead, it now handles that case without recursion directly when it encounters it. We can see how this resolves the above problem: when resolving foo, add_feature for the required feature "bar/fast" will be called. Because add_feature no longer treats such specifciations differently at the top level, it will try to enable a feature with the exact name "bar/fast", and Context::resolve_features will later find that no such feature exists for package foo. To give a friendlier error message, we also check in Context::resolve_features that we never ever require a feature with a slash in a name from a dependency.
2016-07-01 20:36:05 +00:00
[package]
name = "derived"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "../bar"
2018-03-14 15:17:44 +00:00
"#,
).file("derived/src/lib.rs", "extern crate bar; pub use bar::test;")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
Disallow specifying features of transitive deps Before this commit, it was possible to activate a feature in a transtive dependency, using a Cargo.toml like the following one: ... [features] # this will enable feature fast in package bar, which is a # dependency of foo default = [ foo/bar/fast ] This is a bug, and was never intended, and it is checked in other places already. The behavior was possible because `build_features::add_feature` treats the specification "foo/bar/fast" as just another feature. So when we require the feature "foo/bar/fast", add_feature for foo will generate a dependency on "foo" requiring that feature "bar/fast" is enabled. Then, when resolving foo, add_feature will find that "bar/fast" is a required feature, so it'll happily add "fast" as the required feature for the dependency "foo". The fix for this is to make sure that the `add_feature` function does not treat `a/b` specifications as just another feature. Instead, it now handles that case without recursion directly when it encounters it. We can see how this resolves the above problem: when resolving foo, add_feature for the required feature "bar/fast" will be called. Because add_feature no longer treats such specifciations differently at the top level, it will try to enable a feature with the exact name "bar/fast", and Context::resolve_features will later find that no such feature exists for package foo. To give a friendlier error message, we also check in Context::resolve_features that we never ever require a feature with a slash in a name from a dependency.
2016-07-01 20:36:05 +00:00
[package]
name = "bar"
version = "0.0.1"
authors = []
[features]
qux = []
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"bar/src/lib.rs",
r#"
Disallow specifying features of transitive deps Before this commit, it was possible to activate a feature in a transtive dependency, using a Cargo.toml like the following one: ... [features] # this will enable feature fast in package bar, which is a # dependency of foo default = [ foo/bar/fast ] This is a bug, and was never intended, and it is checked in other places already. The behavior was possible because `build_features::add_feature` treats the specification "foo/bar/fast" as just another feature. So when we require the feature "foo/bar/fast", add_feature for foo will generate a dependency on "foo" requiring that feature "bar/fast" is enabled. Then, when resolving foo, add_feature will find that "bar/fast" is a required feature, so it'll happily add "fast" as the required feature for the dependency "foo". The fix for this is to make sure that the `add_feature` function does not treat `a/b` specifications as just another feature. Instead, it now handles that case without recursion directly when it encounters it. We can see how this resolves the above problem: when resolving foo, add_feature for the required feature "bar/fast" will be called. Because add_feature no longer treats such specifciations differently at the top level, it will try to enable a feature with the exact name "bar/fast", and Context::resolve_features will later find that no such feature exists for package foo. To give a friendlier error message, we also check in Context::resolve_features that we never ever require a feature with a slash in a name from a dependency.
2016-07-01 20:36:05 +00:00
#[cfg(feature = "qux")]
pub fn test() { print!("test"); }
2018-03-14 15:17:44 +00:00
"#,
).build();
p.cargo("build")
.with_status(101)
.with_stderr("[ERROR] feature names may not contain slashes: `bar/qux`")
.run();
}
#[test]
fn no_feature_doesnt_build() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
optional = true
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"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() {}
2018-03-14 15:17:44 +00:00
"#,
).file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "pub fn bar() {}")
.build();
p.cargo("build")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] foo v0.0.1 (CWD)
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
2018-08-28 20:38:26 +00:00
p.process(&p.bin("foo")).with_stdout("").run();
2018-03-14 15:17:44 +00:00
p.cargo("build --features bar")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] bar v0.0.1 (CWD/bar)
[COMPILING] foo v0.0.1 (CWD)
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
2018-08-28 20:38:26 +00:00
p.process(&p.bin("foo")).with_stdout("bar\n").run();
}
#[test]
fn default_feature_pulled_in() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[features]
default = ["bar"]
[dependencies.bar]
path = "bar"
optional = true
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"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() {}
2018-03-14 15:17:44 +00:00
"#,
).file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "pub fn bar() {}")
.build();
p.cargo("build")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] bar v0.0.1 (CWD/bar)
[COMPILING] foo v0.0.1 (CWD)
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
2018-08-28 20:38:26 +00:00
p.process(&p.bin("foo")).with_stdout("bar\n").run();
2018-03-14 15:17:44 +00:00
p.cargo("build --no-default-features")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] foo v0.0.1 (CWD)
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
2018-08-28 20:38:26 +00:00
p.process(&p.bin("foo")).with_stdout("").run();
}
#[test]
fn cyclic_feature() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[features]
default = ["default"]
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "")
.build();
p.cargo("build")
.with_status(101)
.with_stderr("[ERROR] Cyclic feature dependency: feature `default` depends on itself")
.run();
}
#[test]
fn cyclic_feature2() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[features]
foo = ["bar"]
bar = ["foo"]
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "fn main() {}")
.build();
p.cargo("build").with_stdout("").run();
}
#[test]
fn groups_on_groups_on_groups() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
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
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"src/main.rs",
r#"
2017-08-27 07:31:16 +00:00
#[allow(unused_extern_crates)]
extern crate bar;
2017-08-27 07:31:16 +00:00
#[allow(unused_extern_crates)]
extern crate baz;
fn main() {}
2018-03-14 15:17:44 +00:00
"#,
).file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "pub fn bar() {}")
2018-07-24 22:35:01 +00:00
.file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
.file("baz/src/lib.rs", "pub fn baz() {}")
.build();
p.cargo("build")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] ba[..] v0.0.1 (CWD/ba[..])
[COMPILING] ba[..] v0.0.1 (CWD/ba[..])
[COMPILING] foo v0.0.1 (CWD)
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn many_cli_features() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
optional = true
[dependencies.baz]
path = "baz"
optional = true
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"src/main.rs",
r#"
2017-08-27 07:31:16 +00:00
#[allow(unused_extern_crates)]
extern crate bar;
2017-08-27 07:31:16 +00:00
#[allow(unused_extern_crates)]
extern crate baz;
fn main() {}
2018-03-14 15:17:44 +00:00
"#,
).file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "pub fn bar() {}")
2018-07-24 22:35:01 +00:00
.file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
.file("baz/src/lib.rs", "pub fn baz() {}")
.build();
p.cargo("build --features")
.arg("bar baz")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] ba[..] v0.0.1 (CWD/ba[..])
[COMPILING] ba[..] v0.0.1 (CWD/ba[..])
[COMPILING] foo v0.0.1 (CWD)
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn union_features() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.d1]
path = "d1"
features = ["f1"]
[dependencies.d2]
path = "d2"
features = ["f2"]
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"src/main.rs",
r#"
2017-08-27 07:31:16 +00:00
#[allow(unused_extern_crates)]
extern crate d1;
extern crate d2;
fn main() {
d2::f1();
d2::f2();
}
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"d1/Cargo.toml",
r#"
[package]
name = "d1"
version = "0.0.1"
authors = []
[features]
f1 = ["d2"]
[dependencies.d2]
path = "../d2"
features = ["f1"]
optional = true
2018-03-14 15:17:44 +00:00
"#,
).file("d1/src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"d2/Cargo.toml",
r#"
[package]
name = "d2"
version = "0.0.1"
authors = []
[features]
f1 = []
f2 = []
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"d2/src/lib.rs",
r#"
#[cfg(feature = "f1")] pub fn f1() {}
#[cfg(feature = "f2")] pub fn f2() {}
2018-03-14 15:17:44 +00:00
"#,
).build();
p.cargo("build")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] d2 v0.0.1 (CWD/d2)
[COMPILING] d1 v0.0.1 (CWD/d1)
[COMPILING] foo v0.0.1 (CWD)
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn many_features_no_rebuilds() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "b"
version = "0.1.0"
authors = []
[dependencies.a]
path = "a"
features = ["fall"]
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"a/Cargo.toml",
r#"
[package]
name = "a"
version = "0.1.0"
authors = []
[features]
ftest = []
ftest2 = []
fall = ["ftest", "ftest2"]
2018-03-14 15:17:44 +00:00
"#,
).file("a/src/lib.rs", "")
.build();
p.cargo("build")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] a v0.1.0 (CWD/a)
[COMPILING] b v0.1.0 (CWD)
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
p.root().move_into_the_past();
p.cargo("build -v")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[FRESH] a v0.1.0 ([..]/a)
[FRESH] b v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
}
// Tests that all cmd lines work with `--features ""`
#[test]
fn empty_features() {
let p = project().file("src/main.rs", "fn main() {}").build();
p.cargo("build --features").arg("").run();
}
// Tests that all cmd lines work with `--features ""`
#[test]
fn transitive_features() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[features]
foo = ["bar/baz"]
[dependencies.bar]
path = "bar"
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "extern crate bar; fn main() { bar::baz(); }")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[features]
baz = []
2018-03-14 15:17:44 +00:00
"#,
).file(
"bar/src/lib.rs",
r#"#[cfg(feature = "baz")] pub fn baz() {}"#,
).build();
p.cargo("build --features foo").run();
}
#[test]
fn everything_in_the_lockfile() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
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
2018-03-14 15:17:44 +00:00
"#,
).file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"d1/Cargo.toml",
r#"
[package]
name = "d1"
version = "0.0.1"
authors = []
[features]
f1 = []
2018-03-14 15:17:44 +00:00
"#,
).file("d1/src/lib.rs", "")
2018-07-24 22:35:01 +00:00
.file("d2/Cargo.toml", &basic_manifest("d2", "0.0.2"))
.file("d2/src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"d3/Cargo.toml",
r#"
[package]
name = "d3"
version = "0.0.3"
authors = []
[features]
f3 = []
2018-03-14 15:17:44 +00:00
"#,
).file("d3/src/lib.rs", "")
.build();
p.cargo("fetch").run();
let loc = p.root().join("Cargo.lock");
let mut lockfile = String::new();
t!(t!(File::open(&loc)).read_to_string(&mut lockfile));
2018-03-14 15:17:44 +00:00
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
);
}
#[test]
fn no_rebuild_when_frobbing_default_feature() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
a = { path = "a" }
b = { path = "b" }
2018-03-14 15:17:44 +00:00
"#,
).file("src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"b/Cargo.toml",
r#"
[package]
name = "b"
version = "0.1.0"
authors = []
[dependencies]
a = { path = "../a", features = ["f1"], default-features = false }
2018-03-14 15:17:44 +00:00
"#,
).file("b/src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"a/Cargo.toml",
r#"
[package]
name = "a"
version = "0.1.0"
authors = []
[features]
default = ["f1"]
f1 = []
2018-03-14 15:17:44 +00:00
"#,
).file("a/src/lib.rs", "")
.build();
p.cargo("build").run();
p.cargo("build").with_stdout("").run();
p.cargo("build").with_stdout("").run();
}
#[test]
fn unions_work_with_no_default_features() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
a = { path = "a" }
b = { path = "b" }
2018-03-14 15:17:44 +00:00
"#,
).file("src/lib.rs", "extern crate a; pub fn foo() { a::a(); }")
2018-03-14 15:17:44 +00:00
.file(
"b/Cargo.toml",
r#"
[package]
name = "b"
version = "0.1.0"
authors = []
[dependencies]
a = { path = "../a", features = [], default-features = false }
2018-03-14 15:17:44 +00:00
"#,
).file("b/src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"a/Cargo.toml",
r#"
[package]
name = "a"
version = "0.1.0"
authors = []
[features]
default = ["f1"]
f1 = []
2018-03-14 15:17:44 +00:00
"#,
).file("a/src/lib.rs", r#"#[cfg(feature = "f1")] pub fn a() {}"#)
.build();
p.cargo("build").run();
p.cargo("build").with_stdout("").run();
p.cargo("build").with_stdout("").run();
}
#[test]
fn optional_and_dev_dep() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "test"
version = "0.1.0"
authors = []
[dependencies]
foo = { path = "foo", optional = true }
[dev-dependencies]
foo = { path = "foo" }
2018-03-14 15:17:44 +00:00
"#,
).file("src/lib.rs", "")
2018-07-24 22:35:01 +00:00
.file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("foo/src/lib.rs", "")
.build();
p.cargo("build")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] test v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn activating_feature_activates_dep() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "test"
version = "0.1.0"
authors = []
[dependencies]
foo = { path = "foo", optional = true }
[features]
a = ["foo/a"]
2018-03-14 15:17:44 +00:00
"#,
).file(
"src/lib.rs",
"extern crate foo; pub fn bar() { foo::bar(); }",
).file(
2018-03-14 15:17:44 +00:00
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
[features]
a = []
2018-03-14 15:17:44 +00:00
"#,
).file("foo/src/lib.rs", r#"#[cfg(feature = "a")] pub fn bar() {}"#)
.build();
p.cargo("build --features a -v").run();
}
#[test]
fn dep_feature_in_cmd_line() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.derived]
path = "derived"
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"src/main.rs",
r#"
extern crate derived;
fn main() { derived::test(); }
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"derived/Cargo.toml",
r#"
[package]
name = "derived"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "../bar"
[features]
default = []
derived-feat = ["bar/some-feat"]
2018-03-14 15:17:44 +00:00
"#,
).file("derived/src/lib.rs", "extern crate bar; pub use bar::test;")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[features]
some-feat = []
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"bar/src/lib.rs",
r#"
#[cfg(feature = "some-feat")]
pub fn test() { print!("test"); }
2018-03-14 15:17:44 +00:00
"#,
).build();
// The foo project requires that feature "some-feat" in "bar" is enabled.
// Building without any features enabled should fail:
p.cargo("build").with_status(101).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("build --features derived/derived-feat").run();
// Trying to enable features of transitive dependencies is an error
p.cargo("build --features bar/some-feat")
.with_status(101)
.with_stderr("error: Package `foo v0.0.1 ([..])` does not have these features: `bar`")
.run();
// Hierarchical feature specification should still be disallowed
p.cargo("build --features derived/bar/some-feat")
.with_status(101)
.with_stderr("[ERROR] feature names may not contain slashes: `bar/some-feat`")
.run();
}
2016-08-31 17:03:26 +00:00
#[test]
fn all_features_flag_enables_all_features() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2016-08-31 17:03:26 +00:00
[project]
name = "foo"
version = "0.0.1"
authors = []
[features]
foo = []
bar = []
[dependencies.baz]
path = "baz"
optional = true
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"src/main.rs",
r#"
2016-08-31 17:03:26 +00:00
#[cfg(feature = "foo")]
pub fn foo() {}
#[cfg(feature = "bar")]
pub fn bar() {
extern crate baz;
baz::baz();
}
fn main() {
foo();
bar();
}
2018-03-14 15:17:44 +00:00
"#,
).file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
.file("baz/src/lib.rs", "pub fn baz() {}")
.build();
2016-08-31 17:03:26 +00:00
p.cargo("build --all-features").run();
2016-08-31 17:03:26 +00:00
}
#[test]
fn many_cli_features_comma_delimited() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
optional = true
[dependencies.baz]
path = "baz"
optional = true
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"src/main.rs",
r#"
2017-08-27 07:31:16 +00:00
#[allow(unused_extern_crates)]
extern crate bar;
2017-08-27 07:31:16 +00:00
#[allow(unused_extern_crates)]
extern crate baz;
fn main() {}
2018-03-14 15:17:44 +00:00
"#,
).file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "pub fn bar() {}")
2018-07-24 22:35:01 +00:00
.file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
.file("baz/src/lib.rs", "pub fn baz() {}")
.build();
p.cargo("build --features bar,baz")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] ba[..] v0.0.1 (CWD/ba[..])
[COMPILING] ba[..] v0.0.1 (CWD/ba[..])
[COMPILING] foo v0.0.1 (CWD)
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn many_cli_features_comma_and_space_delimited() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
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
2018-03-14 15:17:44 +00:00
"#,
).file(
2018-03-14 15:17:44 +00:00
"src/main.rs",
r#"
2017-08-27 07:31:16 +00:00
#[allow(unused_extern_crates)]
extern crate bar;
2017-08-27 07:31:16 +00:00
#[allow(unused_extern_crates)]
extern crate baz;
2017-08-27 07:31:16 +00:00
#[allow(unused_extern_crates)]
extern crate bam;
2017-08-27 07:31:16 +00:00
#[allow(unused_extern_crates)]
extern crate bap;
fn main() {}
2018-03-14 15:17:44 +00:00
"#,
).file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "pub fn bar() {}")
2018-07-24 22:35:01 +00:00
.file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
.file("baz/src/lib.rs", "pub fn baz() {}")
2018-07-24 22:35:01 +00:00
.file("bam/Cargo.toml", &basic_manifest("bam", "0.0.1"))
.file("bam/src/lib.rs", "pub fn bam() {}")
2018-07-24 22:35:01 +00:00
.file("bap/Cargo.toml", &basic_manifest("bap", "0.0.1"))
.file("bap/src/lib.rs", "pub fn bap() {}")
.build();
p.cargo("build --features")
.arg("bar,baz bam bap")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] ba[..] v0.0.1 (CWD/ba[..])
[COMPILING] ba[..] v0.0.1 (CWD/ba[..])
[COMPILING] ba[..] v0.0.1 (CWD/ba[..])
[COMPILING] ba[..] v0.0.1 (CWD/ba[..])
[COMPILING] foo v0.0.1 (CWD)
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
).run();
}
#[test]
fn combining_features_and_package() {
Package::new("dep", "1.0.0").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[workspace]
members = ["bar"]
[dependencies]
dep = "1"
"#,
).file("src/lib.rs", "")
.file(
"bar/Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[features]
main = []
"#,
).file(
"bar/src/main.rs",
2018-04-13 17:59:55 +00:00
r#"
#[cfg(feature = "main")]
fn main() {}
2018-04-13 17:59:55 +00:00
"#,
).build();
p.cargo("build -Z package-features --all --features main")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr_contains(
"\
[ERROR] cannot specify features for more than one package",
).run();
p.cargo("build -Z package-features --package dep --features main")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr_contains(
"\
[ERROR] cannot specify features for packages outside of workspace",
).run();
p.cargo("build -Z package-features --package dep --all-features")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr_contains(
"\
[ERROR] cannot specify features for packages outside of workspace",
).run();
p.cargo("build -Z package-features --package dep --no-default-features")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr_contains(
"\
[ERROR] cannot specify features for packages outside of workspace",
).run();
p.cargo("build -Z package-features --all --all-features")
.masquerade_as_nightly_cargo()
.run();
p.cargo("run -Z package-features --package bar --features main")
.masquerade_as_nightly_cargo()
.run();
}
2018-04-18 10:12:43 +00:00
#[test]
fn namespaced_invalid_feature() {
let p = project()
2018-04-18 10:12:43 +00:00
.file(
"Cargo.toml",
r#"
cargo-features = ["namespaced-features"]
2018-04-18 10:12:43 +00:00
[project]
name = "foo"
version = "0.0.1"
authors = []
namespaced-features = true
[features]
bar = ["baz"]
"#,
).file("src/main.rs", "")
2018-04-18 10:12:43 +00:00
.build();
p.cargo("build")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr(
2018-04-18 10:12:43 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
Feature `bar` includes `baz` which is not defined as a feature
",
).run();
2018-04-18 10:12:43 +00:00
}
#[test]
fn namespaced_invalid_dependency() {
let p = project()
2018-04-18 10:12:43 +00:00
.file(
"Cargo.toml",
r#"
cargo-features = ["namespaced-features"]
2018-04-18 10:12:43 +00:00
[project]
name = "foo"
version = "0.0.1"
authors = []
namespaced-features = true
[features]
bar = ["crate:baz"]
"#,
).file("src/main.rs", "")
2018-04-18 10:12:43 +00:00
.build();
p.cargo("build")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr(
2018-04-18 10:12:43 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
Feature `bar` includes `crate:baz` which is not a known dependency
",
).run();
2018-04-18 10:12:43 +00:00
}
#[test]
fn namespaced_non_optional_dependency() {
let p = project()
2018-04-18 10:12:43 +00:00
.file(
"Cargo.toml",
r#"
cargo-features = ["namespaced-features"]
2018-04-18 10:12:43 +00:00
[project]
name = "foo"
version = "0.0.1"
authors = []
namespaced-features = true
[features]
bar = ["crate:baz"]
[dependencies]
baz = "0.1"
"#,
).file("src/main.rs", "")
2018-04-18 10:12:43 +00:00
.build();
p.cargo("build")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr(
2018-04-18 10:12:43 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
Feature `bar` includes `crate:baz` which is not an optional dependency.
Consider adding `optional = true` to the dependency
",
).run();
2018-04-18 10:12:43 +00:00
}
#[test]
fn namespaced_implicit_feature() {
let p = project()
2018-04-18 10:12:43 +00:00
.file(
"Cargo.toml",
r#"
cargo-features = ["namespaced-features"]
2018-04-18 10:12:43 +00:00
[project]
name = "foo"
version = "0.0.1"
authors = []
namespaced-features = true
[features]
bar = ["baz"]
[dependencies]
baz = { version = "0.1", optional = true }
"#,
).file("src/main.rs", "fn main() {}")
2018-04-18 10:12:43 +00:00
.build();
p.cargo("build").masquerade_as_nightly_cargo().run();
2018-04-18 10:12:43 +00:00
}
#[test]
fn namespaced_shadowed_dep() {
let p = project()
2018-04-18 10:12:43 +00:00
.file(
"Cargo.toml",
r#"
cargo-features = ["namespaced-features"]
2018-04-18 10:12:43 +00:00
[project]
name = "foo"
version = "0.0.1"
authors = []
namespaced-features = true
[features]
baz = []
[dependencies]
baz = { version = "0.1", optional = true }
"#,
).file("src/main.rs", "fn main() {}")
2018-04-18 10:12:43 +00:00
.build();
p.cargo("build").masquerade_as_nightly_cargo().with_status(101).with_stderr(
2018-04-18 10:12:43 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
Feature `baz` includes the optional dependency of the same name, but this is left implicit in the features included by this feature.
Consider adding `crate:baz` to this feature's requirements.
",
)
.run();
2018-04-18 10:12:43 +00:00
}
#[test]
fn namespaced_shadowed_non_optional() {
let p = project()
2018-04-18 10:12:43 +00:00
.file(
"Cargo.toml",
r#"
cargo-features = ["namespaced-features"]
2018-04-18 10:12:43 +00:00
[project]
name = "foo"
version = "0.0.1"
authors = []
namespaced-features = true
[features]
baz = []
[dependencies]
baz = "0.1"
"#,
).file("src/main.rs", "fn main() {}")
2018-04-18 10:12:43 +00:00
.build();
p.cargo("build").masquerade_as_nightly_cargo().with_status(101).with_stderr(
2018-04-18 10:12:43 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
Feature `baz` includes the dependency of the same name, but this is left implicit in the features included by this feature.
Additionally, the dependency must be marked as optional to be included in the feature definition.
Consider adding `crate:baz` to this feature's requirements and marking the dependency as `optional = true`
",
)
.run();
2018-04-18 10:12:43 +00:00
}
#[test]
fn namespaced_implicit_non_optional() {
let p = project()
2018-04-18 10:12:43 +00:00
.file(
"Cargo.toml",
r#"
cargo-features = ["namespaced-features"]
2018-04-18 10:12:43 +00:00
[project]
name = "foo"
version = "0.0.1"
authors = []
namespaced-features = true
[features]
bar = ["baz"]
[dependencies]
baz = "0.1"
"#,
).file("src/main.rs", "fn main() {}")
2018-04-18 10:12:43 +00:00
.build();
p.cargo("build").masquerade_as_nightly_cargo().with_status(101).with_stderr(
2018-04-18 10:12:43 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
Feature `bar` includes `baz` which is not defined as a feature.
A non-optional dependency of the same name is defined; consider adding `optional = true` to its definition
",
).run(
2018-04-18 10:12:43 +00:00
);
}
#[test]
fn namespaced_same_name() {
let p = project()
2018-04-18 10:12:43 +00:00
.file(
"Cargo.toml",
r#"
cargo-features = ["namespaced-features"]
2018-04-18 10:12:43 +00:00
[project]
name = "foo"
version = "0.0.1"
authors = []
namespaced-features = true
[features]
baz = ["crate:baz"]
[dependencies]
baz = { version = "0.1", optional = true }
"#,
).file("src/main.rs", "fn main() {}")
2018-04-18 10:12:43 +00:00
.build();
p.cargo("build").masquerade_as_nightly_cargo().run();
2018-04-18 10:12:43 +00:00
}
#[test]
fn only_dep_is_optional() {
Package::new("bar", "0.1.0").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[project]
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("build").run();
}
#[test]
fn all_features_all_crates() {
Package::new("bar", "0.1.0").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[workspace]
members = ['bar']
"#,
).file("src/main.rs", "fn main() {}")
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.0.1"
authors = []
[features]
foo = []
"#,
).file("bar/src/main.rs", "#[cfg(feature = \"foo\")] fn main() {}")
.build();
p.cargo("build --all-features --all").run();
}