use std::fs::File; use std::io::prelude::*; use cargotest::support::paths::CargoPathExt; use cargotest::support::{project, execs}; use hamcrest::assert_that; #[test] fn invalid1() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] [features] bar = ["baz"] "#) .file("src/main.rs", "") .build(); assert_that(p.cargo("build"), execs().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 ")); } #[test] fn invalid2() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] [features] bar = ["baz"] [dependencies.bar] path = "foo" "#) .file("src/main.rs", "") .build(); assert_that(p.cargo("build"), execs().with_status(101).with_stderr("\ [ERROR] failed to parse manifest at `[..]` Caused by: Features and dependencies cannot have the same name: `bar` ")); } #[test] fn invalid3() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] [features] bar = ["baz"] [dependencies.baz] path = "foo" "#) .file("src/main.rs", "") .build(); assert_that(p.cargo("build"), execs().with_status(101).with_stderr("\ [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 ")); } #[test] fn invalid4() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] path = "bar" features = ["bar"] "#) .file("src/main.rs", "") .file("bar/Cargo.toml", r#" [project] name = "bar" version = "0.0.1" authors = [] "#) .file("bar/src/lib.rs", "") .build(); assert_that(p.cargo("build"), execs().with_status(101).with_stderr("\ [ERROR] Package `bar v0.0.1 ([..])` does not have these features: `bar` ")); p.change_file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] "#); assert_that(p.cargo("build").arg("--features").arg("test"), execs().with_status(101).with_stderr("\ [ERROR] Package `foo v0.0.1 ([..])` does not have these features: `test` ")); } #[test] fn invalid5() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] [dev-dependencies.bar] path = "bar" optional = true "#) .file("src/main.rs", "") .build(); assert_that(p.cargo("build"), execs().with_status(101).with_stderr("\ [ERROR] failed to parse manifest at `[..]` Caused by: Dev-dependencies are not allowed to be optional: `bar` ")); } #[test] fn invalid6() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] [features] foo = ["bar/baz"] "#) .file("src/main.rs", "") .build(); assert_that(p.cargo("build").arg("--features").arg("foo"), execs().with_status(101).with_stderr("\ [ERROR] failed to parse manifest at `[..]` Caused by: Feature `foo` requires a feature of `bar` which is not a dependency ")); } #[test] fn invalid7() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] [features] foo = ["bar/baz"] bar = [] "#) .file("src/main.rs", "") .build(); assert_that(p.cargo("build").arg("--features").arg("foo"), execs().with_status(101).with_stderr("\ [ERROR] failed to parse manifest at `[..]` Caused by: Feature `foo` requires a feature of `bar` which is not a dependency ")); } #[test] fn invalid8() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] path = "bar" features = ["foo/bar"] "#) .file("src/main.rs", "") .file("bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" authors = [] "#) .file("bar/src/lib.rs", "") .build(); assert_that(p.cargo("build").arg("--features").arg("foo"), execs().with_status(101).with_stderr("\ [ERROR] feature names may not contain slashes: `foo/bar` ")); } #[test] fn invalid9() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] path = "bar" "#) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" authors = [] "#) .file("bar/src/lib.rs", "") .build(); assert_that(p.cargo("build").arg("--features").arg("bar"), execs().with_status(0).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 ([..]) Finished dev [unoptimized + debuginfo] target(s) in [..] secs ")); } #[test] fn invalid10() { let p = project("foo") .file("Cargo.toml", r#" [project] 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", r#" [package] name = "baz" version = "0.0.1" authors = [] "#) .file("bar/baz/src/lib.rs", "") .build(); assert_that(p.cargo("build"), execs().with_status(0).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 ([..]) Finished dev [unoptimized + debuginfo] target(s) in [..] secs ")); } #[test] fn no_transitive_dep_feature_requirement() { let p = project("foo") .file("Cargo.toml", r#" [project] 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", r#" 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(); assert_that(p.cargo("build"), execs().with_status(101).with_stderr("\ [ERROR] feature names may not contain slashes: `bar/qux` ")); } #[test] fn no_feature_doesnt_build() { let p = project("foo") .file("Cargo.toml", r#" [project] 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", r#" [package] name = "bar" version = "0.0.1" authors = [] "#) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); assert_that(p.cargo("build"), execs().with_status(0).with_stderr(format!("\ [COMPILING] foo v0.0.1 ({dir}) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ", dir = p.url()))); assert_that(p.process(&p.bin("foo")), execs().with_status(0).with_stdout("")); assert_that(p.cargo("build").arg("--features").arg("bar"), execs().with_status(0).with_stderr(format!("\ [COMPILING] bar v0.0.1 ({dir}/bar) [COMPILING] foo v0.0.1 ({dir}) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ", dir = p.url()))); assert_that(p.process(&p.bin("foo")), execs().with_status(0).with_stdout("bar\n")); } #[test] fn default_feature_pulled_in() { let p = project("foo") .file("Cargo.toml", r#" [project] 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", r#" [package] name = "bar" version = "0.0.1" authors = [] "#) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); assert_that(p.cargo("build"), execs().with_status(0).with_stderr(format!("\ [COMPILING] bar v0.0.1 ({dir}/bar) [COMPILING] foo v0.0.1 ({dir}) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ", dir = p.url()))); assert_that(p.process(&p.bin("foo")), execs().with_status(0).with_stdout("bar\n")); assert_that(p.cargo("build").arg("--no-default-features"), execs().with_status(0).with_stderr(format!("\ [COMPILING] foo v0.0.1 ({dir}) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ", dir = p.url()))); assert_that(p.process(&p.bin("foo")), execs().with_status(0).with_stdout("")); } #[test] fn cyclic_feature() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] [features] default = ["default"] "#) .file("src/main.rs", "") .build(); assert_that(p.cargo("build"), execs().with_status(101).with_stderr("\ [ERROR] Cyclic feature dependency: feature `default` depends on itself ")); } #[test] fn cyclic_feature2() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] [features] foo = ["bar"] bar = ["foo"] "#) .file("src/main.rs", "fn main() {}") .build(); assert_that(p.cargo("build"), execs().with_status(0).with_stdout("")); } #[test] fn groups_on_groups_on_groups() { let p = project("foo") .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 "#) .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", r#" [package] name = "bar" version = "0.0.1" authors = [] "#) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", r#" [package] name = "baz" version = "0.0.1" authors = [] "#) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); assert_that(p.cargo("build"), execs().with_status(0).with_stderr(format!("\ [COMPILING] ba[..] v0.0.1 ({dir}/ba[..]) [COMPILING] ba[..] v0.0.1 ({dir}/ba[..]) [COMPILING] foo v0.0.1 ({dir}) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ", dir = p.url()))); } #[test] fn many_cli_features() { let p = project("foo") .file("Cargo.toml", r#" [project] 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", r#" [package] name = "bar" version = "0.0.1" authors = [] "#) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", r#" [package] name = "baz" version = "0.0.1" authors = [] "#) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); assert_that(p.cargo("build").arg("--features").arg("bar baz"), execs().with_status(0).with_stderr(format!("\ [COMPILING] ba[..] v0.0.1 ({dir}/ba[..]) [COMPILING] ba[..] v0.0.1 ({dir}/ba[..]) [COMPILING] foo v0.0.1 ({dir}) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ", dir = p.url()))); } #[test] fn union_features() { let p = project("foo") .file("Cargo.toml", r#" [project] 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(); assert_that(p.cargo("build"), execs().with_status(0).with_stderr(format!("\ [COMPILING] d2 v0.0.1 ({dir}/d2) [COMPILING] d1 v0.0.1 ({dir}/d1) [COMPILING] foo v0.0.1 ({dir}) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ", dir = p.url()))); } #[test] fn many_features_no_rebuilds() { let p = project("foo") .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(); assert_that(p.cargo("build"), execs().with_status(0).with_stderr(format!("\ [COMPILING] a v0.1.0 ({dir}/a) [COMPILING] b v0.1.0 ({dir}) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ", dir = p.url()))); p.root().move_into_the_past(); assert_that(p.cargo("build").arg("-v"), execs().with_status(0).with_stderr("\ [FRESH] a v0.1.0 ([..]/a) [FRESH] b v0.1.0 ([..]) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ")); } // Tests that all cmd lines work with `--features ""` #[test] fn empty_features() { let p = project("foo") .file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] "#) .file("src/main.rs", "fn main() {}") .build(); assert_that(p.cargo("build").arg("--features").arg(""), execs().with_status(0)); } // Tests that all cmd lines work with `--features ""` #[test] fn transitive_features() { let p = project("foo") .file("Cargo.toml", r#" [project] 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(); assert_that(p.cargo("build").arg("--features").arg("foo"), execs().with_status(0)); } #[test] fn everything_in_the_lockfile() { let p = project("foo") .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 "#) .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", r#" [package] name = "d2" version = "0.0.2" authors = [] "#) .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(); assert_that(p.cargo("fetch"), execs().with_status(0)); let loc = p.root().join("Cargo.lock"); let mut lockfile = String::new(); t!(t!(File::open(&loc)).read_to_string(&mut 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); } #[test] fn no_rebuild_when_frobbing_default_feature() { let p = project("foo") .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(); assert_that(p.cargo("build"), execs().with_status(0)); assert_that(p.cargo("build"), execs().with_status(0).with_stdout("")); assert_that(p.cargo("build"), execs().with_status(0).with_stdout("")); } #[test] fn unions_work_with_no_default_features() { let p = project("foo") .file("Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [dependencies] a = { path = "a" } b = { path = "b" } "#) .file("src/lib.rs", r#" 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(); assert_that(p.cargo("build"), execs().with_status(0)); assert_that(p.cargo("build"), execs().with_status(0).with_stdout("")); assert_that(p.cargo("build"), execs().with_status(0).with_stdout("")); } #[test] fn optional_and_dev_dep() { let p = project("foo") .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", r#" [package] name = "foo" version = "0.1.0" authors = [] "#) .file("foo/src/lib.rs", "") .build(); assert_that(p.cargo("build"), execs().with_status(0).with_stderr("\ [COMPILING] test v0.1.0 ([..]) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ")); } #[test] fn activating_feature_activates_dep() { let p = project("foo") .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(); assert_that(p.cargo("build").arg("--features").arg("a").arg("-v"), execs().with_status(0)); } #[test] fn dep_feature_in_cmd_line() { let p = project("foo") .file("Cargo.toml", r#" [project] 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", r#" 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: assert_that(p.cargo("build"), execs().with_status(101)); // 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: assert_that(p.cargo("build").arg("--features").arg("derived/derived-feat"), execs().with_status(0)); // Trying to enable features of transitive dependencies is an error assert_that(p.cargo("build").arg("--features").arg("bar/some-feat"), execs().with_status(101).with_stderr("\ [ERROR] Package `foo v0.0.1 ([..])` does not have these features: `bar` ")); // Hierarchical feature specification should still be disallowed assert_that(p.cargo("build").arg("--features").arg("derived/bar/some-feat"), execs().with_status(101).with_stderr("\ [ERROR] feature names may not contain slashes: `bar/some-feat` ")); } #[test] fn all_features_flag_enables_all_features() { let p = project("foo") .file("Cargo.toml", r#" [project] 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", r#" [package] name = "baz" version = "0.0.1" authors = [] "#) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); assert_that(p.cargo("build").arg("--all-features"), execs().with_status(0)); } #[test] fn many_cli_features_comma_delimited() { let p = project("foo") .file("Cargo.toml", r#" [project] 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", r#" [package] name = "bar" version = "0.0.1" authors = [] "#) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", r#" [package] name = "baz" version = "0.0.1" authors = [] "#) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); assert_that(p.cargo("build").arg("--features").arg("bar,baz"), execs().with_status(0).with_stderr(format!("\ [COMPILING] ba[..] v0.0.1 ({dir}/ba[..]) [COMPILING] ba[..] v0.0.1 ({dir}/ba[..]) [COMPILING] foo v0.0.1 ({dir}) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ", dir = p.url()))); } #[test] fn many_cli_features_comma_and_space_delimited() { let p = project("foo") .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 "#) .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", r#" [package] name = "bar" version = "0.0.1" authors = [] "#) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", r#" [package] name = "baz" version = "0.0.1" authors = [] "#) .file("baz/src/lib.rs", "pub fn baz() {}") .file("bam/Cargo.toml", r#" [package] name = "bam" version = "0.0.1" authors = [] "#) .file("bam/src/lib.rs", "pub fn bam() {}") .file("bap/Cargo.toml", r#" [package] name = "bap" version = "0.0.1" authors = [] "#) .file("bap/src/lib.rs", "pub fn bap() {}") .build(); assert_that(p.cargo("build").arg("--features").arg("bar,baz bam bap"), execs().with_status(0).with_stderr(format!("\ [COMPILING] ba[..] v0.0.1 ({dir}/ba[..]) [COMPILING] ba[..] v0.0.1 ({dir}/ba[..]) [COMPILING] ba[..] v0.0.1 ({dir}/ba[..]) [COMPILING] ba[..] v0.0.1 ({dir}/ba[..]) [COMPILING] foo v0.0.1 ({dir}) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ", dir = p.url()))); }