| //! Tests for workspace feature unification. |
| |
| use crate::prelude::*; |
| use crate::utils::cargo_process; |
| use cargo_test_support::{ |
| basic_manifest, |
| compare::assert_e2e, |
| project, |
| registry::{Dependency, Package}, |
| str, |
| }; |
| |
| #[cargo_test] |
| fn workspace_feature_unification() { |
| let p = project() |
| .file( |
| ".cargo/config.toml", |
| r#" |
| [resolver] |
| feature-unification = "workspace" |
| "#, |
| ) |
| .file( |
| "Cargo.toml", |
| r#" |
| [workspace] |
| resolver = "2" |
| members = ["common", "a", "b"] |
| "#, |
| ) |
| .file( |
| "common/Cargo.toml", |
| r#" |
| [package] |
| name = "common" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [features] |
| a = [] |
| b = [] |
| "#, |
| ) |
| .file( |
| "common/src/lib.rs", |
| r#" |
| #[cfg(not(all(feature = "a", feature = "b")))] |
| compile_error!("features were not unified"); |
| "#, |
| ) |
| .file( |
| "a/Cargo.toml", |
| r#" |
| [package] |
| name = "a" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common", features = ["a"] } |
| "#, |
| ) |
| .file("a/src/lib.rs", "") |
| .file( |
| "b/Cargo.toml", |
| r#" |
| [package] |
| name = "b" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common", features = ["b"] } |
| "#, |
| ) |
| .file("b/src/lib.rs", "") |
| .build(); |
| |
| p.cargo("check -p common") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data(str![[r#" |
| [CHECKING] common v0.1.0 ([ROOT]/foo/common) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| p.cargo("check -p a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data(str![[r#" |
| [CHECKING] a v0.1.0 ([ROOT]/foo/a) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| p.cargo("check -p b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data(str![[r#" |
| [CHECKING] b v0.1.0 ([ROOT]/foo/b) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| p.cargo("check") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data(str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn package_feature_unification() { |
| Package::new("outside", "0.1.0") |
| .feature("a", &[]) |
| .feature("b", &[]) |
| .file( |
| "src/lib.rs", |
| r#" |
| #[cfg(all(feature = "a", feature = "b"))] |
| compile_error!("features were unified"); |
| #[cfg(feature = "a")] |
| pub fn a() {} |
| #[cfg(feature = "b")] |
| pub fn b() {} |
| "#, |
| ) |
| .publish(); |
| |
| let p = project() |
| .file( |
| ".cargo/config.toml", |
| r#" |
| [resolver] |
| feature-unification = "package" |
| "#, |
| ) |
| .file( |
| "Cargo.toml", |
| r#" |
| [workspace] |
| resolver = "2" |
| members = ["common", "a", "b"] |
| "#, |
| ) |
| .file( |
| "common/Cargo.toml", |
| r#" |
| [package] |
| name = "common" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [features] |
| a = [] |
| b = [] |
| "#, |
| ) |
| .file( |
| "common/src/lib.rs", |
| r#" |
| #[cfg(all(feature = "a", feature = "b"))] |
| compile_error!("features were unified"); |
| #[cfg(feature = "a")] |
| pub fn a() {} |
| #[cfg(feature = "b")] |
| pub fn b() {} |
| "#, |
| ) |
| .file( |
| "a/Cargo.toml", |
| r#" |
| [package] |
| name = "a" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common", features = ["a"] } |
| outside = { version = "0.1.0", features = ["a"] } |
| "#, |
| ) |
| .file("a/src/lib.rs", "pub use common::a;") |
| .file( |
| "b/Cargo.toml", |
| r#" |
| [package] |
| name = "b" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common", features = ["b"] } |
| outside = { version = "0.1.0", features = ["b"] } |
| "#, |
| ) |
| .file("b/src/lib.rs", "pub use common::b;") |
| .build(); |
| |
| p.cargo("check -p common") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data(str![[r#" |
| [UPDATING] `dummy-registry` index |
| [LOCKING] 1 package to latest compatible version |
| [CHECKING] common v0.1.0 ([ROOT]/foo/common) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| p.cargo("check -p a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data( |
| str![[r#" |
| [DOWNLOADING] crates ... |
| [DOWNLOADED] outside v0.1.0 (registry `dummy-registry`) |
| [CHECKING] outside v0.1.0 |
| [CHECKING] common v0.1.0 ([ROOT]/foo/common) |
| [CHECKING] a v0.1.0 ([ROOT]/foo/a) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| p.cargo("check -p b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data( |
| str![[r#" |
| [CHECKING] outside v0.1.0 |
| [CHECKING] common v0.1.0 ([ROOT]/foo/common) |
| [CHECKING] b v0.1.0 ([ROOT]/foo/b) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| p.cargo("check -p a -p b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data( |
| str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| p.cargo("check") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data(str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| // Sanity check that compilation without package feature unification does not work |
| p.cargo("check -p a -p b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "selected") |
| .with_status(101) |
| .with_stderr_contains("[ERROR] features were unified") |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn package_feature_unification_default_features() { |
| let p = project() |
| .file( |
| ".cargo/config.toml", |
| r#" |
| [resolver] |
| feature-unification = "package" |
| "#, |
| ) |
| .file( |
| "Cargo.toml", |
| r#" |
| [workspace] |
| resolver = "2" |
| members = ["common", "a", "b"] |
| "#, |
| ) |
| .file( |
| "common/Cargo.toml", |
| r#" |
| [package] |
| name = "common" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [features] |
| default = ["a"] |
| a = [] |
| b = [] |
| "#, |
| ) |
| .file( |
| "common/src/lib.rs", |
| r#" |
| #[cfg(all(feature = "a", feature = "b"))] |
| compile_error!("features were unified"); |
| #[cfg(feature = "a")] |
| pub fn a() {} |
| #[cfg(feature = "b")] |
| pub fn b() {} |
| "#, |
| ) |
| .file( |
| "a/Cargo.toml", |
| r#" |
| [package] |
| name = "a" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common" } |
| "#, |
| ) |
| .file("a/src/lib.rs", "pub use common::a;") |
| .file( |
| "b/Cargo.toml", |
| r#" |
| [package] |
| name = "b" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common", features = ["b"], default-features = false } |
| "#, |
| ) |
| .file("b/src/lib.rs", "pub use common::b;") |
| .build(); |
| |
| p.cargo("check -p common") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data(str![[r#" |
| [CHECKING] common v0.1.0 ([ROOT]/foo/common) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| p.cargo("check -p a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data(str![[r#" |
| [CHECKING] a v0.1.0 ([ROOT]/foo/a) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| p.cargo("check -p b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data(str![[r#" |
| [CHECKING] common v0.1.0 ([ROOT]/foo/common) |
| [CHECKING] b v0.1.0 ([ROOT]/foo/b) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| p.cargo("check") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data( |
| str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn package_feature_unification_cli_features() { |
| Package::new("outside", "0.1.0") |
| .feature("a", &[]) |
| .feature("b", &[]) |
| .file( |
| "src/lib.rs", |
| r#" |
| #[cfg(all(feature = "a", feature = "b"))] |
| compile_error!("features were unified"); |
| #[cfg(feature = "a")] |
| pub fn a() {} |
| #[cfg(feature = "b")] |
| pub fn b() {} |
| "#, |
| ) |
| .publish(); |
| |
| let p = project() |
| .file( |
| ".cargo/config.toml", |
| r#" |
| [resolver] |
| feature-unification = "package" |
| "#, |
| ) |
| .file( |
| "Cargo.toml", |
| r#" |
| [workspace] |
| resolver = "2" |
| members = ["common", "a", "b"] |
| "#, |
| ) |
| .file( |
| "common/Cargo.toml", |
| r#" |
| [package] |
| name = "common" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [features] |
| a = [] |
| b = [] |
| "#, |
| ) |
| .file( |
| "common/src/lib.rs", |
| r#" |
| #[cfg(all(feature = "a", feature = "b"))] |
| compile_error!("features were unified"); |
| #[cfg(feature = "a")] |
| pub fn a() {} |
| #[cfg(feature = "b")] |
| pub fn b() {} |
| "#, |
| ) |
| .file( |
| "a/Cargo.toml", |
| r#" |
| [package] |
| name = "a" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common" } |
| outside = "0.1.0" |
| |
| [features] |
| a = ["common/a", "outside/a"] |
| "#, |
| ) |
| .file("a/src/lib.rs", "pub use common::a;") |
| .file( |
| "b/Cargo.toml", |
| r#" |
| [package] |
| name = "b" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common", features = ["b"] } |
| outside = "0.1.0" |
| |
| [features] |
| b = ["common/b", "outside/b"] |
| "#, |
| ) |
| .file("b/src/lib.rs", "pub use common::b;") |
| .build(); |
| |
| p.cargo("check -p a -p b -F a,b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data( |
| str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| [CHECKING] common v0.1.0 ([ROOT]/foo/common) |
| [UPDATING] `dummy-registry` index |
| [LOCKING] 1 package to latest compatible version |
| [DOWNLOADING] crates ... |
| [DOWNLOADED] outside v0.1.0 (registry `dummy-registry`) |
| [CHECKING] outside v0.1.0 |
| [CHECKING] b v0.1.0 ([ROOT]/foo/b) |
| [CHECKING] a v0.1.0 ([ROOT]/foo/a) |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| p.cargo("check --workspace --exclude common -F a,b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data( |
| str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| |
| p.cargo("check -p a -p b -F a/a,b/b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data( |
| str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| p.cargo("check -p a -p b -F a,b,c") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [ERROR] none of the selected packages contains this feature: c |
| selected packages: a, b |
| |
| "#]]) |
| .run(); |
| p.cargo("check -p a -F b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [ERROR] the package 'a' does not contain this feature: b |
| [HELP] packages with the missing feature: common, b |
| |
| "#]]) |
| .run(); |
| p.cargo("check -p a -F a/a,common/b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_status(101) |
| .with_stderr_contains("[ERROR] features were unified") |
| .run(); |
| |
| p.cargo("check -p a -F a/a,outside/b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_status(101) |
| .with_stderr_contains("[ERROR] features were unified") |
| .run(); |
| |
| // Sanity check that compilation without package feature unification does not work |
| p.cargo("check -p a -p b -F a,b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "selected") |
| .with_status(101) |
| .with_stderr_contains("[ERROR] features were unified") |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn package_feature_unification_weak_dependencies() { |
| let p = project() |
| .file( |
| ".cargo/config.toml", |
| r#" |
| [resolver] |
| feature-unification = "package" |
| "#, |
| ) |
| .file( |
| "Cargo.toml", |
| r#" |
| [workspace] |
| resolver = "2" |
| members = ["common", "a", "b"] |
| "#, |
| ) |
| .file( |
| "common/Cargo.toml", |
| r#" |
| [package] |
| name = "common" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [features] |
| a = [] |
| b = [] |
| "#, |
| ) |
| .file( |
| "common/src/lib.rs", |
| r#" |
| #[cfg(all(feature = "a", feature = "b"))] |
| compile_error!("features were unified"); |
| #[cfg(feature = "a")] |
| pub fn a() {} |
| #[cfg(feature = "b")] |
| pub fn b() {} |
| "#, |
| ) |
| .file( |
| "a/Cargo.toml", |
| r#" |
| [package] |
| name = "a" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common", optional = true } |
| |
| [features] |
| default = ["dep:common", "common?/a"] |
| "#, |
| ) |
| .file("a/src/lib.rs", "pub use common::a;") |
| .file( |
| "b/Cargo.toml", |
| r#" |
| [package] |
| name = "b" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common", optional = true } |
| |
| [features] |
| default = ["dep:common", "common?/b"] |
| "#, |
| ) |
| .file("b/src/lib.rs", "pub use common::b;") |
| .build(); |
| |
| p.cargo("check -p a -p b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data( |
| str![[r#" |
| [CHECKING] common v0.1.0 ([ROOT]/foo/common) |
| [CHECKING] a v0.1.0 ([ROOT]/foo/a) |
| [CHECKING] b v0.1.0 ([ROOT]/foo/b) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| p.cargo("check") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data(str![[r#" |
| [CHECKING] common v0.1.0 ([ROOT]/foo/common) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| // Sanity check that compilation without package feature unification does not work |
| p.cargo("check -p a -p b") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "selected") |
| .with_status(101) |
| .with_stderr_contains("[ERROR] features were unified") |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn feature_unification_cargo_tree() { |
| Package::new("outside", "0.1.0") |
| .feature("a", &[]) |
| .feature("b", &[]) |
| .file( |
| "src/lib.rs", |
| r#" |
| #[cfg(all(feature = "a", feature = "b"))] |
| compile_error!("features were unified"); |
| #[cfg(feature = "a")] |
| pub fn a() {} |
| #[cfg(feature = "b")] |
| pub fn b() {} |
| "#, |
| ) |
| .publish(); |
| |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [workspace] |
| resolver = "2" |
| members = ["common", "a", "b"] |
| "#, |
| ) |
| .file( |
| "common/Cargo.toml", |
| r#" |
| [package] |
| name = "common" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [features] |
| a = [] |
| b = [] |
| "#, |
| ) |
| .file( |
| "common/src/lib.rs", |
| r#" |
| #[cfg(all(feature = "a", feature = "b"))] |
| compile_error!("features were unified"); |
| #[cfg(feature = "a")] |
| pub fn a() {} |
| #[cfg(feature = "b")] |
| pub fn b() {} |
| "#, |
| ) |
| .file( |
| "a/Cargo.toml", |
| r#" |
| [package] |
| name = "a" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common", features = ["a"] } |
| outside = { version = "0.1.0", features = ["a"] } |
| "#, |
| ) |
| .file("a/src/lib.rs", "pub use common::a;") |
| .file( |
| "b/Cargo.toml", |
| r#" |
| [package] |
| name = "b" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common", features = ["b"] } |
| outside = { version = "0.1.0", features = ["b"] } |
| "#, |
| ) |
| .file("b/src/lib.rs", "pub use common::b;") |
| .build(); |
| |
| p.cargo("tree -e features") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "selected") |
| .with_stdout_data(str![[r#" |
| a v0.1.0 ([ROOT]/foo/a) |
| ├── common feature "a" |
| │ └── common v0.1.0 ([ROOT]/foo/common) |
| ├── common feature "default" (command-line) |
| │ └── common v0.1.0 ([ROOT]/foo/common) |
| ├── outside feature "a" |
| │ └── outside v0.1.0 |
| └── outside feature "default" |
| └── outside v0.1.0 |
| |
| b v0.1.0 ([ROOT]/foo/b) |
| ├── common feature "b" |
| │ └── common v0.1.0 ([ROOT]/foo/common) |
| ├── common feature "default" (command-line) (*) |
| ├── outside feature "b" |
| │ └── outside v0.1.0 |
| └── outside feature "default" (*) |
| |
| common v0.1.0 ([ROOT]/foo/common) |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("tree -e features") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "workspace") |
| .with_stdout_data(str![[r#" |
| a v0.1.0 ([ROOT]/foo/a) |
| ├── common feature "a" |
| │ └── common v0.1.0 ([ROOT]/foo/common) |
| ├── common feature "default" (command-line) |
| │ └── common v0.1.0 ([ROOT]/foo/common) |
| ├── outside feature "a" |
| │ └── outside v0.1.0 |
| └── outside feature "default" |
| └── outside v0.1.0 |
| |
| b v0.1.0 ([ROOT]/foo/b) |
| ├── common feature "b" |
| │ └── common v0.1.0 ([ROOT]/foo/common) |
| ├── common feature "default" (command-line) (*) |
| ├── outside feature "b" |
| │ └── outside v0.1.0 |
| └── outside feature "default" (*) |
| |
| common v0.1.0 ([ROOT]/foo/common) |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("tree -e features") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "package") |
| .with_stdout_data(str![[r#" |
| common v0.1.0 ([ROOT]/foo/common) |
| a v0.1.0 ([ROOT]/foo/a) |
| ├── common feature "a" |
| │ └── common v0.1.0 ([ROOT]/foo/common) |
| ├── common feature "default" |
| │ └── common v0.1.0 ([ROOT]/foo/common) |
| ├── outside feature "a" |
| │ └── outside v0.1.0 |
| └── outside feature "default" |
| └── outside v0.1.0 |
| b v0.1.0 ([ROOT]/foo/b) |
| ├── common feature "b" |
| │ └── common v0.1.0 ([ROOT]/foo/common) |
| ├── common feature "default" |
| │ └── common v0.1.0 ([ROOT]/foo/common) |
| ├── outside feature "b" |
| │ └── outside v0.1.0 |
| └── outside feature "default" |
| └── outside v0.1.0 |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn cargo_install_ignores_config() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [package] |
| name = "a" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "common", features = ["a"] } |
| |
| [workspace] |
| members = ["common", "b"] |
| "#, |
| ) |
| .file("src/main.rs", "fn main() {}") |
| .file( |
| "common/Cargo.toml", |
| r#" |
| [package] |
| name = "common" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [features] |
| a = [] |
| b = [] |
| "#, |
| ) |
| .file( |
| "common/src/lib.rs", |
| r#" |
| #[cfg(all(feature = "a", feature = "b"))] |
| compile_error!("features should not be unified"); |
| "#, |
| ) |
| .file( |
| "b/Cargo.toml", |
| r#" |
| [package] |
| name = "b" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| common = { path = "../common", features = ["b"] } |
| "#, |
| ) |
| .file("b/src/lib.rs", "") |
| .build(); |
| |
| cargo_process("install --path") |
| .arg(p.root()) |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "workspace") |
| .with_stderr_data(str![[r#" |
| [INSTALLING] a v0.1.0 ([ROOT]/foo) |
| [COMPILING] common v0.1.0 ([ROOT]/foo/common) |
| [COMPILING] a v0.1.0 ([ROOT]/foo) |
| [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s |
| [INSTALLING] [ROOT]/home/.cargo/bin/a[EXE] |
| [INSTALLED] package `a v0.1.0 ([ROOT]/foo)` (executable `a[EXE]`) |
| [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries |
| |
| "#]]) |
| .run(); |
| cargo_process("install --path") |
| .arg(p.root()) |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "package") |
| .with_stderr_data(str![[r#" |
| [INSTALLING] a v0.1.0 ([ROOT]/foo) |
| [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s |
| [REPLACING] [ROOT]/home/.cargo/bin/a[EXE] |
| [REPLACED] package `a v0.1.0 ([ROOT]/foo)` with `a v0.1.0 ([ROOT]/foo)` (executable `a[EXE]`) |
| [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn unstable_config_on_stable() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [workspace] |
| resolver = "2" |
| members = ["bar"] |
| "#, |
| ) |
| .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) |
| .file("bar/src/lib.rs", "") |
| .build(); |
| |
| p.cargo("check") |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "workspace") |
| .with_stderr_data(str![[r#" |
| [WARNING] ignoring `resolver.feature-unification` without `-Zfeature-unification` |
| [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn cargo_fix_works() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| # Before project |
| [ project ] # After project header |
| # After project header line |
| name = "foo" |
| edition = "2021" |
| # After project table |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .build(); |
| |
| p.cargo("fix --edition --allow-no-vcs") |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "package") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_stderr_data(str![[r#" |
| [MIGRATING] Cargo.toml from 2021 edition to 2024 |
| [FIXED] Cargo.toml (1 fix) |
| [CHECKING] foo v0.0.0 ([ROOT]/foo) |
| [MIGRATING] src/lib.rs from 2021 edition to 2024 |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| assert_e2e().eq( |
| p.read_file("Cargo.toml"), |
| str![[r#" |
| |
| # Before project |
| [ package ] # After project header |
| # After project header line |
| name = "foo" |
| edition = "2021" |
| # After project table |
| |
| "#]], |
| ); |
| } |
| |
| #[cargo_test] |
| fn edition_v2_resolver_report() { |
| // Show a report if the V2 resolver shows differences. |
| Package::new("common", "1.0.0") |
| .feature("f1", &[]) |
| .feature("dev-feat", &[]) |
| .add_dep(Dependency::new("opt_dep", "1.0").optional(true)) |
| .publish(); |
| Package::new("opt_dep", "1.0.0").publish(); |
| |
| Package::new("bar", "1.0.0") |
| .add_dep( |
| Dependency::new("common", "1.0") |
| .target("cfg(whatever)") |
| .enable_features(&["f1"]), |
| ) |
| .publish(); |
| |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [workspace] |
| members = ["bar"] |
| |
| [package] |
| name = "foo" |
| version = "0.1.0" |
| edition = "2018" |
| |
| [dependencies] |
| common = "1.0" |
| bar = "1.0" |
| |
| [build-dependencies] |
| common = { version = "1.0", features = ["opt_dep"] } |
| |
| [dev-dependencies] |
| common = { version="1.0", features=["dev-feat"] } |
| "#, |
| ) |
| .file("src/lib.rs", "") |
| .file( |
| "bar/Cargo.toml", |
| r#" |
| [package] |
| name = "bar" |
| version = "0.1.0" |
| edition = "2018" |
| "#, |
| ) |
| .file("bar/src/lib.rs", "") |
| .build(); |
| |
| p.cargo("fix --edition --allow-no-vcs --workspace") |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "package") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .with_status(101) |
| .with_stderr_data( |
| str![[r#" |
| [MIGRATING] Cargo.toml from 2018 edition to 2021 |
| [UPDATING] `dummy-registry` index |
| [LOCKING] 3 packages to latest compatible versions |
| [DOWNLOADING] crates ... |
| [DOWNLOADED] common v1.0.0 (registry `dummy-registry`) |
| [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) |
| [DOWNLOADED] opt_dep v1.0.0 (registry `dummy-registry`) |
| [MIGRATING] bar/Cargo.toml from 2018 edition to 2021 |
| [ERROR] cannot fix edition when using `feature-unification = "package"`. |
| |
| "#]] |
| .unordered(), |
| ) |
| .run(); |
| } |
| |
| #[cargo_test] |
| fn feature_unification_of_cli_features_within_workspace() { |
| let p = project() |
| .file( |
| "Cargo.toml", |
| r#" |
| [workspace] |
| resolver = "2" |
| members = ["parent", "child", "grandchild"] |
| "#, |
| ) |
| .file( |
| "grandchild/Cargo.toml", |
| r#" |
| [package] |
| name = "grandchild" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [features] |
| a = [] |
| "#, |
| ) |
| .file( |
| "grandchild/src/lib.rs", |
| r#" |
| #[cfg(feature = "a")] |
| pub fn a() {} |
| "#, |
| ) |
| .file( |
| "child/Cargo.toml", |
| r#" |
| [package] |
| name = "child" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| grandchild = { path = "../grandchild" } |
| "#, |
| ) |
| .file("child/src/lib.rs", "pub use grandchild::*;") |
| .file( |
| "parent/Cargo.toml", |
| r#" |
| [package] |
| name = "parent" |
| version = "0.1.0" |
| edition = "2021" |
| |
| [dependencies] |
| child = { path = "../child" } |
| "#, |
| ) |
| .file("parent/src/lib.rs", "pub use child::a;") |
| .build(); |
| |
| p.cargo("check -p parent -F grandchild/a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "package") |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [ERROR] the package 'parent' does not contain this feature: grandchild/a |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -p parent -F grandchild/a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "workspace") |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [ERROR] the package 'parent' does not contain this feature: grandchild/a |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -p parent -F grandchild/a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "selected") |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [ERROR] the package 'parent' does not contain this feature: grandchild/a |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -p child -F grandchild/a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "package") |
| .with_stderr_data(str![[r#" |
| [CHECKING] grandchild v0.1.0 ([ROOT]/foo/grandchild) |
| [CHECKING] child v0.1.0 ([ROOT]/foo/child) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -p child -F grandchild/a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "workspace") |
| .with_stderr_data(str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -p child -F grandchild/a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "selected") |
| .with_stderr_data(str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -F grandchild/a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "package") |
| .with_stderr_data(str![[r#" |
| [CHECKING] parent v0.1.0 ([ROOT]/foo/parent) |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -F grandchild/a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "workspace") |
| .with_stderr_data(str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -F grandchild/a") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "selected") |
| .with_stderr_data(str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -F grandchild/a --workspace --exclude grandchild") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "package") |
| .with_stderr_data(str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -F grandchild/a --workspace --exclude grandchild") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "workspace") |
| .with_stderr_data(str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -F grandchild/a --workspace --exclude grandchild") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "selected") |
| .with_stderr_data(str![[r#" |
| [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -F grandchild/a --workspace --exclude grandchild --exclude child") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "package") |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [ERROR] the package 'parent' does not contain this feature: grandchild/a |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -F grandchild/a --workspace --exclude grandchild --exclude child") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "workspace") |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [ERROR] the package 'parent' does not contain this feature: grandchild/a |
| |
| "#]]) |
| .run(); |
| |
| p.cargo("check -F grandchild/a --workspace --exclude grandchild --exclude child") |
| .arg("-Zfeature-unification") |
| .masquerade_as_nightly_cargo(&["feature-unification"]) |
| .env("CARGO_RESOLVER_FEATURE_UNIFICATION", "selected") |
| .with_status(101) |
| .with_stderr_data(str![[r#" |
| [ERROR] the package 'parent' does not contain this feature: grandchild/a |
| |
| "#]]) |
| .run(); |
| } |