Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test for issue 4866 #5007

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 291 additions & 0 deletions tests/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1236,3 +1236,294 @@ fn many_cli_features_comma_and_space_delimited() {
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
", dir = p.url())));
}

#[test]
fn features_not_unified() {
// FIXME: https://github.com/rust-lang/cargo/issues/4866
//
// We need three crates for this:
// * foo: a library with a feature enabled by default
// * bar: a library with a dependency on foo with foo
// features enabled implicitly by default
// * baz:
// * a library with a dependency on foo without features
// * that has a dev-dependency on bar
//
// When building baz (not its test, just baz) the default
// feature of foo should not be enabled.

let p = project("root")
.file("foo/Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []

[features]
default = [ "meow" ]
meow = []
"#)
.file("foo/src/lib.rs", r#"
pub fn foo() {}
"#);

// First, we test that default features are not enabled if
// baz does not add a dependency on bar:
{
let mut p = p.clone();
let p = p.file("Cargo.toml", r#"
[package]
name = "baz"
version = "0.0.1"
authors = []

[features]
default = []
meow = [ "foo/meow" ]

# Dependency on foo without features
[dependencies.foo]
path = "foo"
default-features = false
"#)
.file("src/lib.rs", r#"
extern crate foo;
pub use foo::foo;
"#)
.build();

assert_that(p.cargo("build").arg("--verbose"),
execs().with_status(0)
.with_stderr_contains("[COMPILING] foo v0.0.1 ([..])")
.with_stderr_contains(
"[RUNNING] `rustc --crate-name foo foo/src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=[..] -C extra-filename=[..] --out-dir [..] -L dependency=[..]`")
.with_stderr_contains("[COMPILING] baz v0.0.1 ([..])")
.with_stderr_contains("[RUNNING] `rustc --crate-name baz src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 --cfg 'feature=\"default\"' -C metadata=[..] -C extra-filename=[..] --out-dir [..] -L dependency=[..] --extern foo=[..]`")
.with_stderr_contains("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]"));
}

// Then we add bar, the crate with a dependency on foo that implicitly
// enables all features:
let p = p.clone()
.file("bar/Cargo.toml", r#"
[package]
name = "bar"
version = "0.0.1"
authors = []

[dependencies.foo]
path = "../foo"
"#)
.file("bar/src/lib.rs", r#"
extern crate foo;
pub use foo::foo;
"#);

// Now we add a dev-dependency to bar which shouldn't influence how baz is
// built:
{
let mut p = p.clone();
let p = p.file("Cargo.toml", r#"
[package]
name = "baz"
version = "0.0.1"
authors = []

[features]
default = []
meow = [ "foo/meow" ]

# Dependency on foo without features
[dependencies.foo]
path = "foo"
default-features = false

# Dev dependency on bar, this shouldn't
# influence how baz is built:
[dev-dependencies]
bar = { path = "bar" }
"#)
.file("src/lib.rs", r#"
extern crate foo;
pub use foo::foo;
"#)
.build();

assert_that(p.cargo("build").arg("--verbose"),
execs().with_status(0)
.with_stderr_contains("[COMPILING] foo v0.0.1 ([..])")
/* FIXME
.with_stderr_contains("[RUNNING] `rustc --crate-name foo foo/src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=[..] -C extra-filename=[..] --out-dir [..] -L dependency=[..]`")
*/
.with_stderr_contains("[COMPILING] baz v0.0.1 ([..])")
.with_stderr_contains("[RUNNING] `rustc --crate-name baz src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 --cfg 'feature=\"default\"' -C metadata=[..] -C extra-filename=[..] --out-dir [..] -L dependency=[..] --extern foo=[..]`")
.with_stderr_contains("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]")
);
}

// Now we add an impossible target target-specific dependency that shouldn't
// influence how baz is built:
{
let mut p = p.clone();
let p = p.file("Cargo.toml", r#"
[package]
name = "baz"
version = "0.0.1"
authors = []

[features]
default = []
meow = [ "foo/meow" ]

# Dependency on foo without features
[dependencies.foo]
path = "foo"
default-features = false

# Impossible target-specific dependency shouldn't
# influence how baz is built:
[target.'cfg(all(target_os = "windows", target_os = "macos"))'.dependencies]
bar = { path = "bar" }
"#)
.file("src/lib.rs", r#"
extern crate foo;
pub use foo::foo;
"#)
.build();

assert_that(p.cargo("build").arg("--verbose"),
execs().with_status(0)
.with_stderr_contains("[COMPILING] foo v0.0.1 ([..])")
/* FIXME
.with_stderr_contains("[RUNNING] `rustc --crate-name foo foo/src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=[..] -C extra-filename=[..] --out-dir [..] -L dependency=[..]`")
*/
.with_stderr_contains("[COMPILING] baz v0.0.1 ([..])")
.with_stderr_contains("[RUNNING] `rustc --crate-name baz src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 --cfg 'feature=\"default\"' -C metadata=[..] -C extra-filename=[..] --out-dir [..] -L dependency=[..] --extern foo=[..]`")
.with_stderr_contains("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]")
);
}

// Now we add both an impossible target target-specific dependency and a
// dev-dependency that shouldn't
// influence how baz is built:
{
let mut p = p.clone();
let p = p.file("Cargo.toml", r#"
[package]
name = "baz"
version = "0.0.1"
authors = []

[features]
default = []
meow = [ "foo/meow" ]

# Dependency on foo without features
[dependencies.foo]
path = "foo"
default-features = false

# Impossible target-specific dependency shouldn't
# influence how baz is built:
[target.'cfg(all(target_os = "windows", target_os = "macos"))'.dependencies]
bar = { path = "bar" }

# Dev dependency on bar, this shouldn't
# influence how baz is built:
[dev-dependencies]
bar = { path = "bar" }
"#)
.file("src/lib.rs", r#"
extern crate foo;
pub use foo::foo;
"#)
.build();

assert_that(p.cargo("build").arg("--verbose"),
execs().with_status(0)
.with_stderr_contains("[COMPILING] foo v0.0.1 ([..])")
/* FIXME:
.with_stderr_contains("[RUNNING] `rustc --crate-name foo foo/src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=[..] -C extra-filename=[..] --out-dir [..] -L dependency=[..]`
")
*/
.with_stderr_contains("[COMPILING] baz v0.0.1 ([..])")
.with_stderr_contains("[RUNNING] `rustc --crate-name baz src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 --cfg 'feature=\"default\"' -C metadata=[..] -C extra-filename=[..] --out-dir [..] -L dependency=[..] --extern foo=[..]`
")
.with_stderr_contains("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]")
);
}

// Finally we add to those dependencies a platform-specific dependency that
// is included in all targets and propagates a feature from an other_foo
// crate
{
let mut p = p.clone();
let p = p
.file("other_foo/Cargo.toml", r#"
[project]
name = "other_foo"
version = "0.0.1"
authors = []

[features]
default = [ "other_meow" ]
other_meow = []
"#)
.file("other_foo/src/lib.rs", r#"
pub fn other_foo() {}
"#)
.file("Cargo.toml", r#"
[package]
name = "baz"
version = "0.0.1"
authors = []

[features]
default = []
meow = [ "foo/meow" ]

# Dependency on foo without features
[dependencies.foo]
path = "foo"
default-features = false

# Impossible target-specific dependency shouldn't
# influence how baz is built:
[target.'cfg(all(target_os = "windows", target_os = "macos"))'.dependencies]
bar = { path = "bar" }

# Dev dependency on bar, this shouldn't
# influence how baz is built:
[dev-dependencies]
bar = { path = "bar" }

# This platform-specific dependency is always enabled for all targets:
[target.'cfg(all())'.dependencies]
other_foo = { path = "other_foo" }
"#)
.file("src/lib.rs", r#"
extern crate foo;
extern crate other_foo;
pub use foo::foo;
pub use other_foo::other_foo;
"#)
.build();

// FIXME:
assert_that(p.cargo("build").arg("--verbose").arg("-j").arg("1"),
execs().with_status(0)
.with_stderr_contains("[COMPILING] other_foo v0.0.1 ([..])")
.with_stderr_contains("[RUNNING] `rustc --crate-name other_foo other_foo/src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 --cfg 'feature=\"default\"' --cfg 'feature=\"other_meow\"' -C metadata=[..] -C extra-filename=[..] --out-dir [..] -L dependency=[..]`
")
.with_stderr_contains("[COMPILING] foo v0.0.1 ([..])")
/* FIXME:
.with_stderr_contains("[RUNNING] `rustc --crate-name foo foo/src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 -C metadata=[..] -C extra-filename=[..] --out-dir [..] -L dependency=[..]`
")
*/
.with_stderr_contains("[COMPILING] baz v0.0.1 ([..])")
.with_stderr_contains("[RUNNING] `rustc --crate-name baz src/lib.rs --crate-type lib --emit=dep-info,link -C debuginfo=2 --cfg 'feature=\"default\"' -C metadata=[..] -C extra-filename=[..] --out-dir [..] -L dependency=[..] --extern foo=[..]`
")
.with_stderr_contains("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]")
);
}
}