//! Tests for namespaced features. use super::features2::switch_to_resolver_2; use cargo_test_support::registry::{Dependency, Package, RegistryBuilder}; use cargo_test_support::{project, publish}; #[cargo_test] fn dependency_with_crate_syntax() { // Registry dependency uses dep: syntax. Package::new("baz", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep(Dependency::new("baz", "1.0").optional(true)) .feature("feat", &["dep:baz"]) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = {version="1.0", features=["feat"]} "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr( "\ [UPDATING] [..] [DOWNLOADING] crates ... [DOWNLOADED] [..] [DOWNLOADED] [..] [CHECKING] baz v1.0.0 [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 [..] [FINISHED] [..] ", ) .run(); } #[cargo_test] fn namespaced_invalid_feature() { // Specifies a feature that doesn't exist. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [features] bar = ["baz"] "#, ) .file("src/main.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr( "\ [ERROR] failed to parse manifest at `[..]` Caused by: feature `bar` includes `baz` which is neither a dependency nor another feature ", ) .run(); } #[cargo_test] fn namespaced_invalid_dependency() { // Specifies a dep:name that doesn't exist. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" [features] bar = ["dep:baz"] "#, ) .file("src/main.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr( "\ [ERROR] failed to parse manifest at `[..]` Caused by: feature `bar` includes `dep:baz`, but `baz` is not listed as a dependency ", ) .run(); } #[cargo_test] fn namespaced_non_optional_dependency() { // Specifies a dep:name for a dependency that is not optional. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" [features] bar = ["dep:baz"] [dependencies] baz = "0.1" "#, ) .file("src/main.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr( "\ [ERROR] failed to parse manifest at `[..]` Caused by: feature `bar` includes `dep:baz`, but `baz` is not an optional dependency A non-optional dependency of the same name is defined; consider adding `optional = true` to its definition. ", ) .run(); } #[cargo_test] fn namespaced_implicit_feature() { // Backwards-compatible with old syntax. Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" [features] bar = ["baz"] [dependencies] baz = { version = "0.1", optional = true } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr( "\ [UPDATING] [..] [CHECKING] foo v0.0.1 [..] [FINISHED] [..] ", ) .run(); p.cargo("check --features baz") .with_stderr( "\ [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.0 [..] [CHECKING] baz v0.1.0 [CHECKING] foo v0.0.1 [..] [FINISHED] [..] ", ) .run(); } #[cargo_test] fn namespaced_shadowed_dep() { // An optional dependency is not listed in the features table, and its // implicit feature is overridden. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" [features] baz = [] [dependencies] baz = { version = "0.1", optional = true } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr( "\ [ERROR] failed to parse manifest at `[..]` Caused by: optional dependency `baz` is not included in any feature Make sure that `dep:baz` is included in one of features in the [features] table. ", ) .run(); } #[cargo_test] fn namespaced_shadowed_non_optional() { // Able to specify a feature with the same name as a required dependency. Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" [features] baz = [] [dependencies] baz = "0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); } #[cargo_test] fn namespaced_implicit_non_optional() { // Includes a non-optional dependency in [features] table. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" [features] bar = ["baz"] [dependencies] baz = "0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").with_status(101).with_stderr( "\ [ERROR] failed to parse manifest at `[..]` Caused by: feature `bar` includes `baz`, but `baz` is not an optional dependency A non-optional dependency of the same name is defined; consider adding `optional = true` to its definition. ", ).run(); } #[cargo_test] fn namespaced_same_name() { // Explicitly listing an optional dependency in the [features] table. Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" [features] baz = ["dep:baz"] [dependencies] baz = { version = "0.1", optional = true } "#, ) .file( "src/main.rs", r#" fn main() { if cfg!(feature="baz") { println!("baz"); } } "#, ) .build(); p.cargo("run") .with_stderr( "\ [UPDATING] [..] [COMPILING] foo v0.0.1 [..] [FINISHED] [..] [RUNNING] [..] ", ) .with_stdout("") .run(); p.cargo("run --features baz") .with_stderr( "\ [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.0 [..] [COMPILING] baz v0.1.0 [COMPILING] foo v0.0.1 [..] [FINISHED] [..] [RUNNING] [..] ", ) .with_stdout("baz") .run(); } #[cargo_test] fn no_implicit_feature() { // Using `dep:` will not create an implicit feature. Package::new("regex", "1.0.0").publish(); Package::new("lazy_static", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] regex = { version = "1.0", optional = true } lazy_static = { version = "1.0", optional = true } [features] regex = ["dep:regex", "dep:lazy_static"] "#, ) .file( "src/main.rs", r#" fn main() { if cfg!(feature = "regex") { println!("regex"); } if cfg!(feature = "lazy_static") { println!("lazy_static"); } } "#, ) .build(); p.cargo("run") .with_stderr( "\ [UPDATING] [..] [COMPILING] foo v0.1.0 [..] [FINISHED] [..] [RUNNING] `target/debug/foo[EXE]` ", ) .with_stdout("") .run(); p.cargo("run --features regex") .with_stderr_unordered( "\ [DOWNLOADING] crates ... [DOWNLOADED] regex v1.0.0 [..] [DOWNLOADED] lazy_static v1.0.0 [..] [COMPILING] regex v1.0.0 [COMPILING] lazy_static v1.0.0 [COMPILING] foo v0.1.0 [..] [FINISHED] [..] [RUNNING] `target/debug/foo[EXE]` ", ) .with_stdout("regex") .run(); p.cargo("run --features lazy_static") .with_stderr( "\ [ERROR] Package `foo v0.1.0 [..]` does not have feature `lazy_static`. \ It has an optional dependency with that name, but that dependency uses the \"dep:\" \ syntax in the features table, so it does not have an implicit feature with that name. ", ) .with_status(101) .run(); } #[cargo_test] fn crate_syntax_bad_name() { // "dep:bar" = [] Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = { version="1.0", optional=true } [features] "dep:bar" = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check --features dep:bar") .with_status(101) .with_stderr( "\ [ERROR] failed to parse manifest at [..]/foo/Cargo.toml` Caused by: TOML parse error at line 10, column 17 | 10 | \"dep:bar\" = [] | ^^^^^^^^^ feature named `dep:bar` is not allowed to start with `dep:` ", ) .run(); } #[cargo_test] fn crate_syntax_in_dep() { // features = ["dep:baz"] Package::new("baz", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep(Dependency::new("baz", "1.0").optional(true)) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = { version = "1.0", features = ["dep:baz"] } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr( "\ error: failed to parse manifest at `[CWD]/Cargo.toml` Caused by: feature `dep:baz` in dependency `bar` is not allowed to use explicit `dep:` syntax If you want to enable [..] ", ) .run(); } #[cargo_test] fn crate_syntax_cli() { // --features dep:bar Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = { version = "1.0", optional=true } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check --features dep:bar") .with_status(101) .with_stderr( "\ [ERROR] feature `dep:bar` is not allowed to use explicit `dep:` syntax ", ) .run(); switch_to_resolver_2(&p); p.cargo("check --features dep:bar") .with_status(101) .with_stderr( "\ [ERROR] feature `dep:bar` is not allowed to use explicit `dep:` syntax ", ) .run(); } #[cargo_test] fn crate_required_features() { // required-features = ["dep:bar"] Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = { version = "1.0", optional=true } [[bin]] name = "foo" required-features = ["dep:bar"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr( "\ [UPDATING] [..] [ERROR] invalid feature `dep:bar` in required-features of target `foo`: \ `dep:` prefixed feature values are not allowed in required-features ", ) .run(); } #[cargo_test] fn json_exposed() { // Checks that the implicit dep: values are exposed in JSON. Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = { version = "1.0", optional=true } "#, ) .file("src/lib.rs", "") .build(); p.cargo("metadata --no-deps") .with_json( r#" { "packages": [ { "name": "foo", "version": "0.1.0", "id": "foo 0.1.0 [..]", "license": null, "license_file": null, "description": null, "homepage": null, "documentation": null, "source": null, "dependencies": "{...}", "targets": "{...}", "features": { "bar": ["dep:bar"] }, "manifest_path": "[..]foo/Cargo.toml", "metadata": null, "publish": null, "authors": [], "categories": [], "default_run": null, "keywords": [], "readme": null, "repository": null, "rust_version": null, "edition": "2015", "links": null } ], "workspace_members": "{...}", "workspace_default_members": "{...}", "resolve": null, "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]foo", "metadata": null } "#, ) .run(); } #[cargo_test] fn crate_feature_with_explicit() { // crate_name/feat_name syntax where crate_name already has a feature defined. // NOTE: I don't know if this is actually ideal behavior. Package::new("bar", "1.0.0") .feature("bar_feat", &[]) .file( "src/lib.rs", r#" #[cfg(not(feature="bar_feat"))] compile_error!("bar_feat is not enabled"); "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = { version="1.0", optional = true } [features] f1 = ["bar/bar_feat"] bar = ["dep:bar", "f2"] f2 = [] "#, ) .file( "src/lib.rs", r#" #[cfg(not(feature="bar"))] compile_error!("bar should be enabled"); #[cfg(not(feature="f2"))] compile_error!("f2 should be enabled"); "#, ) .build(); p.cargo("check --features f1") .with_stderr( "\ [UPDATING] [..] [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 [..] [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 [..] [FINISHED] [..] ", ) .run(); } #[cargo_test] fn optional_explicit_without_crate() { // "feat" syntax when there is no implicit "feat" feature because it is // explicitly listed elsewhere. Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = { version = "1.0", optional = true } [features] feat1 = ["dep:bar"] feat2 = ["bar"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr( "\ [ERROR] failed to parse manifest at [..] Caused by: feature `feat2` includes `bar`, but `bar` is an optional dependency without an implicit feature Use `dep:bar` to enable the dependency. ", ) .run(); } #[cargo_test] fn tree() { Package::new("baz", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep(Dependency::new("baz", "1.0").optional(true)) .feature("feat1", &["dep:baz"]) .feature("feat2", &[]) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = { version = "1.0", features = ["feat1"], optional=true } [features] a = ["bar/feat2"] bar = ["dep:bar"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout("foo v0.1.0 ([ROOT]/foo)") .run(); p.cargo("tree -e features --features a") .with_stdout( "\ foo v0.1.0 ([ROOT]/foo) ├── bar feature \"default\" │ └── bar v1.0.0 │ └── baz feature \"default\" │ └── baz v1.0.0 └── bar feature \"feat1\" └── bar v1.0.0 (*) ", ) .run(); p.cargo("tree -e features --features a -i bar") .with_stdout( "\ bar v1.0.0 ├── bar feature \"default\" │ └── foo v0.1.0 ([ROOT]/foo) │ ├── foo feature \"a\" (command-line) │ ├── foo feature \"bar\" │ │ └── foo feature \"a\" (command-line) │ └── foo feature \"default\" (command-line) ├── bar feature \"feat1\" │ └── foo v0.1.0 ([ROOT]/foo) (*) └── bar feature \"feat2\" └── foo feature \"a\" (command-line) ", ) .run(); p.cargo("tree -e features --features bar") .with_stdout( "\ foo v0.1.0 ([ROOT]/foo) ├── bar feature \"default\" │ └── bar v1.0.0 │ └── baz feature \"default\" │ └── baz v1.0.0 └── bar feature \"feat1\" └── bar v1.0.0 (*) ", ) .run(); p.cargo("tree -e features --features bar -i bar") .with_stdout( "\ bar v1.0.0 ├── bar feature \"default\" │ └── foo v0.1.0 ([ROOT]/foo) │ ├── foo feature \"bar\" (command-line) │ └── foo feature \"default\" (command-line) └── bar feature \"feat1\" └── foo v0.1.0 ([ROOT]/foo) (*) ", ) .run(); } #[cargo_test] fn tree_no_implicit() { // tree without an implicit feature Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = { version = "1.0", optional=true } [features] a = ["dep:bar"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout("foo v0.1.0 ([ROOT]/foo)") .run(); p.cargo("tree -e features --all-features") .with_stdout( "\ foo v0.1.0 ([ROOT]/foo) └── bar feature \"default\" └── bar v1.0.0 ", ) .run(); p.cargo("tree -e features -i bar --all-features") .with_stdout( "\ bar v1.0.0 └── bar feature \"default\" └── foo v0.1.0 ([ROOT]/foo) ├── foo feature \"a\" (command-line) └── foo feature \"default\" (command-line) ", ) .run(); } #[cargo_test] fn publish_no_implicit() { let registry = RegistryBuilder::new().http_api().http_index().build(); // Does not include implicit features or dep: syntax on publish. Package::new("opt-dep1", "1.0.0").publish(); Package::new("opt-dep2", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" description = "foo" license = "MIT" homepage = "https://example.com/" [dependencies] opt-dep1 = { version = "1.0", optional = true } opt-dep2 = { version = "1.0", optional = true } [features] feat = ["opt-dep1"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_stderr( "\ [UPDATING] [..] [PACKAGING] foo v0.1.0 [..] [PACKAGED] [..] [UPLOADING] foo v0.1.0 [..] [UPLOADED] foo v0.1.0 [..] note: Waiting [..] You may press ctrl-c [..] [PUBLISHED] foo v0.1.0 [..] ", ) .run(); publish::validate_upload_with_contents( r#" { "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [], "kind": "normal", "name": "opt-dep1", "optional": true, "target": null, "version_req": "^1.0" }, { "default_features": true, "features": [], "kind": "normal", "name": "opt-dep2", "optional": true, "target": null, "version_req": "^1.0" } ], "description": "foo", "documentation": null, "features": { "feat": ["opt-dep1"] }, "homepage": "https://example.com/", "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": null, "rust_version": null, "vers": "0.1.0" } "#, "foo-0.1.0.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs"], &[( "Cargo.toml", &format!( r#"{} [package] name = "foo" version = "0.1.0" description = "foo" homepage = "https://example.com/" license = "MIT" [dependencies.opt-dep1] version = "1.0" optional = true [dependencies.opt-dep2] version = "1.0" optional = true [features] feat = ["opt-dep1"] "#, cargo::core::package::MANIFEST_PREAMBLE ), )], ); } #[cargo_test] fn publish() { let registry = RegistryBuilder::new().http_api().http_index().build(); // Publish behavior with explicit dep: syntax. Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" description = "foo" license = "MIT" homepage = "https://example.com/" [dependencies] bar = { version = "1.0", optional = true } [features] feat1 = [] feat2 = ["dep:bar"] feat3 = ["feat2"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_stderr( "\ [UPDATING] [..] [PACKAGING] foo v0.1.0 [..] [VERIFYING] foo v0.1.0 [..] [UPDATING] [..] [COMPILING] foo v0.1.0 [..] [FINISHED] [..] [PACKAGED] [..] [UPLOADING] foo v0.1.0 [..] [UPLOADED] foo v0.1.0 [..] note: Waiting [..] You may press ctrl-c [..] [PUBLISHED] foo v0.1.0 [..] ", ) .run(); publish::validate_upload_with_contents( r#" { "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [], "kind": "normal", "name": "bar", "optional": true, "target": null, "version_req": "^1.0" } ], "description": "foo", "documentation": null, "features": { "feat1": [], "feat2": ["dep:bar"], "feat3": ["feat2"] }, "homepage": "https://example.com/", "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": null, "rust_version": null, "vers": "0.1.0" } "#, "foo-0.1.0.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs"], &[( "Cargo.toml", &format!( r#"{} [package] name = "foo" version = "0.1.0" description = "foo" homepage = "https://example.com/" license = "MIT" [dependencies.bar] version = "1.0" optional = true [features] feat1 = [] feat2 = ["dep:bar"] feat3 = ["feat2"] "#, cargo::core::package::MANIFEST_PREAMBLE ), )], ); } #[cargo_test] fn namespaced_feature_together() { // Check for an error when `dep:` is used with `/` Package::new("bar", "1.0.0") .feature("bar-feat", &[]) .publish(); // Non-optional shouldn't have extra err. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "1.0" [features] f1 = ["dep:bar/bar-feat"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr( "\ error: failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `f1` includes `dep:bar/bar-feat` with both `dep:` and `/` To fix this, remove the `dep:` prefix. ", ) .run(); // Weak dependency shouldn't have extra err. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = {version = "1.0", optional = true } [features] f1 = ["dep:bar?/bar-feat"] "#, ); p.cargo("check") .with_status(101) .with_stderr( "\ error: failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `f1` includes `dep:bar?/bar-feat` with both `dep:` and `/` To fix this, remove the `dep:` prefix. ", ) .run(); // If dep: is already specified, shouldn't have extra err. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = {version = "1.0", optional = true } [features] f1 = ["dep:bar", "dep:bar/bar-feat"] "#, ); p.cargo("check") .with_status(101) .with_stderr( "\ error: failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `f1` includes `dep:bar/bar-feat` with both `dep:` and `/` To fix this, remove the `dep:` prefix. ", ) .run(); // Only when the other 3 cases aren't true should it give some extra help. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = {version = "1.0", optional = true } [features] f1 = ["dep:bar/bar-feat"] "#, ); p.cargo("check") .with_status(101) .with_stderr( "\ error: failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `f1` includes `dep:bar/bar-feat` with both `dep:` and `/` To fix this, remove the `dep:` prefix. If the intent is to avoid creating an implicit feature `bar` for an optional \ dependency, then consider replacing this with two values: \"dep:bar\", \"bar/bar-feat\" ", ) .run(); } #[cargo_test] fn dep_feature_when_hidden() { // Checks for behavior with dep:bar and bar/feat syntax when there is no // `bar` feature. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = { path = "bar", optional = true } [features] f1 = ["dep:bar"] f2 = ["bar/bar_feat"] "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" [features] bar_feat = [] "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("tree -f") .arg("{p} features={f}") .with_stdout( "\ foo v0.1.0 ([ROOT]/foo) features=", ) .with_stderr("") .run(); p.cargo("tree -F f1 -f") .arg("{p} features={f}") .with_stdout( "\ foo v0.1.0 ([ROOT]/foo) features=f1 └── bar v0.1.0 ([ROOT]/foo/bar) features= ", ) .with_stderr("") .run(); p.cargo("tree -F f2 -f") .arg("{p} features={f}") .with_stdout( "\ foo v0.1.0 ([ROOT]/foo) features=f2 └── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat ", ) .with_stderr("") .run(); p.cargo("tree --all-features -f") .arg("{p} features={f}") .with_stdout( "\ foo v0.1.0 ([ROOT]/foo) features=f1,f2 └── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat ", ) .with_stderr("") .run(); }