//! Tests for the `cargo tree` command with -e features option. use cargo_test_support::project; use cargo_test_support::registry::{Dependency, Package}; #[cargo_test] fn dep_feature_various() { // Checks different ways of setting features via dependencies. Package::new("optdep", "1.0.0") .feature("default", &["cat"]) .feature("cat", &[]) .publish(); Package::new("defaultdep", "1.0.0") .feature("default", &["f1"]) .feature("f1", &["optdep"]) .add_dep(Dependency::new("optdep", "1.0").optional(true)) .publish(); Package::new("nodefaultdep", "1.0.0") .feature("default", &["f1"]) .feature("f1", &[]) .publish(); Package::new("nameddep", "1.0.0") .add_dep(Dependency::new("serde", "1.0").optional(true)) .feature("default", &["serde-stuff"]) .feature("serde-stuff", &["serde/derive"]) .feature("vehicle", &["car"]) .feature("car", &[]) .publish(); Package::new("serde_derive", "1.0.0").publish(); Package::new("serde", "1.0.0") .feature("derive", &["serde_derive"]) .add_dep(Dependency::new("serde_derive", "1.0").optional(true)) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] defaultdep = "1.0" nodefaultdep = {version="1.0", default-features = false} nameddep = {version="1.0", features = ["vehicle", "serde"]} "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout( "\ foo v0.1.0 ([..]/foo) ├── nodefaultdep v1.0.0 ├── defaultdep feature \"default\" │ ├── defaultdep v1.0.0 │ │ └── optdep feature \"default\" │ │ ├── optdep v1.0.0 │ │ └── optdep feature \"cat\" │ │ └── optdep v1.0.0 │ └── defaultdep feature \"f1\" │ ├── defaultdep v1.0.0 (*) │ └── defaultdep feature \"optdep\" │ └── defaultdep v1.0.0 (*) ├── nameddep feature \"default\" │ ├── nameddep v1.0.0 │ │ └── serde feature \"default\" │ │ └── serde v1.0.0 │ │ └── serde_derive feature \"default\" │ │ └── serde_derive v1.0.0 │ └── nameddep feature \"serde-stuff\" │ ├── nameddep v1.0.0 (*) │ ├── nameddep feature \"serde\" │ │ └── nameddep v1.0.0 (*) │ └── serde feature \"derive\" │ ├── serde v1.0.0 (*) │ └── serde feature \"serde_derive\" │ └── serde v1.0.0 (*) ├── nameddep feature \"serde\" (*) └── nameddep feature \"vehicle\" ├── nameddep v1.0.0 (*) └── nameddep feature \"car\" └── nameddep v1.0.0 (*) ", ) .run(); } #[cargo_test] fn graph_features_ws_interdependent() { // A workspace with interdependent crates. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" [dependencies] b = {path="../b", features=["feat2"]} [features] default = ["a1"] a1 = [] a2 = [] "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" [features] default = ["feat1"] feat1 = [] feat2 = [] "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout( "\ a v0.1.0 ([..]/foo/a) ├── b feature \"default\" (command-line) │ ├── b v0.1.0 ([..]/foo/b) │ └── b feature \"feat1\" │ └── b v0.1.0 ([..]/foo/b) └── b feature \"feat2\" └── b v0.1.0 ([..]/foo/b) b v0.1.0 ([..]/foo/b) ", ) .run(); p.cargo("tree -e features -i a -i b") .with_stdout( "\ a v0.1.0 ([..]/foo/a) ├── a feature \"a1\" │ └── a feature \"default\" (command-line) └── a feature \"default\" (command-line) b v0.1.0 ([..]/foo/b) ├── b feature \"default\" (command-line) │ └── a v0.1.0 ([..]/foo/a) (*) ├── b feature \"feat1\" │ └── b feature \"default\" (command-line) (*) └── b feature \"feat2\" └── a v0.1.0 ([..]/foo/a) (*) ", ) .run(); } #[cargo_test] fn slash_feature_name() { // dep_name/feat_name syntax Package::new("opt", "1.0.0").feature("feat1", &[]).publish(); Package::new("notopt", "1.0.0") .feature("cat", &[]) .feature("animal", &["cat"]) .publish(); Package::new("opt2", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] opt = {version = "1.0", optional=true} opt2 = {version = "1.0", optional=true} notopt = "1.0" [features] f1 = ["opt/feat1", "notopt/animal"] f2 = ["f1"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e features --features f1") .with_stdout( "\ foo v0.1.0 ([..]/foo) ├── notopt feature \"default\" │ └── notopt v1.0.0 └── opt feature \"default\" └── opt v1.0.0 ", ) .run(); p.cargo("tree -e features --features f1 -i foo") .with_stdout( "\ foo v0.1.0 ([..]/foo) ├── foo feature \"default\" (command-line) ├── foo feature \"f1\" (command-line) └── foo feature \"opt\" └── foo feature \"f1\" (command-line) ", ) .run(); p.cargo("tree -e features --features f1 -i notopt") .with_stdout( "\ notopt v1.0.0 ├── notopt feature \"animal\" │ └── foo feature \"f1\" (command-line) ├── notopt feature \"cat\" │ └── notopt feature \"animal\" (*) └── notopt feature \"default\" └── foo v0.1.0 ([..]/foo) ├── foo feature \"default\" (command-line) ├── foo feature \"f1\" (command-line) └── foo feature \"opt\" └── foo feature \"f1\" (command-line) ", ) .run(); p.cargo("tree -e features --features notopt/animal -i notopt") .with_stdout( "\ notopt v1.0.0 ├── notopt feature \"animal\" (command-line) ├── notopt feature \"cat\" │ └── notopt feature \"animal\" (command-line) └── notopt feature \"default\" └── foo v0.1.0 ([..]/foo) └── foo feature \"default\" (command-line) ", ) .run(); p.cargo("tree -e features --all-features") .with_stdout( "\ foo v0.1.0 ([..]/foo) ├── notopt feature \"default\" │ └── notopt v1.0.0 ├── opt feature \"default\" │ └── opt v1.0.0 └── opt2 feature \"default\" └── opt2 v1.0.0 ", ) .run(); p.cargo("tree -e features --all-features -i opt2") .with_stdout( "\ opt2 v1.0.0 └── opt2 feature \"default\" └── foo v0.1.0 ([..]/foo) ├── foo feature \"default\" (command-line) ├── foo feature \"f1\" (command-line) │ └── foo feature \"f2\" (command-line) ├── foo feature \"f2\" (command-line) ├── foo feature \"opt\" (command-line) │ └── foo feature \"f1\" (command-line) (*) └── foo feature \"opt2\" (command-line) ", ) .run(); } #[cargo_test] fn features_enables_inactive_target() { // Features that enable things on targets that are not enabled. Package::new("optdep", "1.0.0") .feature("feat1", &[]) .publish(); Package::new("dep1", "1.0.0") .feature("somefeat", &[]) .publish(); Package::new("dep2", "1.0.0") .add_dep( Dependency::new("optdep", "1.0.0") .optional(true) .target("cfg(whatever)"), ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [target.'cfg(whatever)'.dependencies] optdep = {version="1.0", optional=true} dep1 = "1.0" [dependencies] dep2 = "1.0" [features] f1 = ["optdep"] f2 = ["optdep/feat1"] f3 = ["dep1/somefeat"] f4 = ["dep2/optdep"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout( "\ foo v0.1.0 ([..]/foo) └── dep2 feature \"default\" └── dep2 v1.0.0 ", ) .run(); p.cargo("tree -e features --all-features") .with_stdout( "\ foo v0.1.0 ([..]/foo) └── dep2 feature \"default\" └── dep2 v1.0.0 ", ) .run(); p.cargo("tree -e features --all-features --target=all") .with_stdout( "\ foo v0.1.0 ([..]/foo) ├── dep1 feature \"default\" │ └── dep1 v1.0.0 ├── dep2 feature \"default\" │ └── dep2 v1.0.0 │ └── optdep feature \"default\" │ └── optdep v1.0.0 └── optdep feature \"default\" (*) ", ) .run(); }