1 //! Tests for weak-dep-features.
3 use super::features2
::switch_to_resolver_2
;
4 use cargo_test_support
::paths
::CargoPathExt
;
5 use cargo_test_support
::registry
::{Dependency, Package, RegistryBuilder}
;
6 use cargo_test_support
::{project, publish}
;
9 // Helper to create lib.rs files that check features.
10 fn require(enabled_features
: &[&str], disabled_features
: &[&str]) -> String
{
11 let mut s
= String
::new();
12 for feature
in enabled_features
{
13 writeln
!(s
, "#[cfg(not(feature=\"{feature}\"))] compile_error!(\"expected feature {feature} to be enabled\");",
14 feature
=feature
).unwrap();
16 for feature
in disabled_features
{
17 writeln
!(s
, "#[cfg(feature=\"{feature}\")] compile_error!(\"did not expect feature {feature} to be enabled\");",
18 feature
=feature
).unwrap();
25 Package
::new("bar", "1.0.0")
27 .file("src/lib.rs", &require(&["feat"], &[]))
38 bar = { version = "1.0", optional = true }
44 .file("src/lib.rs", &require(&["f1"], &[]))
47 // It's a bit unfortunate that this has to download `bar`, but avoiding
48 // that is extremely difficult.
49 p
.cargo("check --features f1")
53 [DOWNLOADING] crates ...
54 [DOWNLOADED] bar v1.0.0 [..]
55 [CHECKING] foo v0.1.0 [..]
61 p
.cargo("check --features f1,bar")
65 [CHECKING] foo v0.1.0 [..]
74 // A complex chain that requires deferring enabling the feature due to
75 // another dependency getting enabled.
76 Package
::new("bar", "1.0.0")
78 .file("src/lib.rs", &require(&["feat"], &[]))
80 Package
::new("dep", "1.0.0")
81 .add_dep(Dependency
::new("bar", "1.0").optional(true))
82 .feature("feat", &["bar?/feat"])
84 Package
::new("bar_activator", "1.0.0")
85 .feature_dep("dep", "1.0", &["bar"])
96 dep = { version = "1.0", features = ["feat"] }
100 .file("src/lib.rs", "")
107 [DOWNLOADING] crates ...
108 [DOWNLOADED] dep v1.0.0 [..]
109 [DOWNLOADED] bar_activator v1.0.0 [..]
110 [DOWNLOADED] bar v1.0.0 [..]
111 [CHECKING] bar v1.0.0
112 [CHECKING] dep v1.0.0
113 [CHECKING] bar_activator v1.0.0
114 [CHECKING] foo v0.1.0 [..]
122 fn not_optional_dep() {
123 // Attempt to use dep_name?/feat where dep_name is not optional.
124 Package
::new("dep", "1.0.0").feature("feat", &[]).publish();
141 .file("src/lib.rs", "")
147 error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
150 feature `feat` includes `dep?/feat` with a `?`, but `dep` is not an optional dependency
151 A non-optional dependency of the same name is defined; consider removing the `?` or changing the dependency to be optional
157 fn optional_cli_syntax() {
158 // --features bar?/feat
159 Package
::new("bar", "1.0.0")
160 .feature("feat", &[])
161 .file("src/lib.rs", &require(&["feat"], &[]))
173 bar = { version = "1.0", optional = true }
176 .file("src/lib.rs", "")
179 // Does not build bar.
180 p
.cargo("check --features bar?/feat")
184 [DOWNLOADING] crates ...
185 [DOWNLOADED] bar v1.0.0 [..]
186 [CHECKING] foo v0.1.0 [..]
193 p
.cargo("check --features bar?/feat,bar")
196 [CHECKING] bar v1.0.0
197 [CHECKING] foo v0.1.0 [..]
203 eprintln
!("check V2 resolver");
204 switch_to_resolver_2(&p
);
205 p
.build_dir().rm_rf();
206 // Does not build bar.
207 p
.cargo("check --features bar?/feat")
210 [CHECKING] foo v0.1.0 [..]
217 p
.cargo("check --features bar?/feat,bar")
220 [CHECKING] bar v1.0.0
221 [CHECKING] foo v0.1.0 [..]
229 fn required_features() {
230 // required-features doesn't allow ?
231 Package
::new("bar", "1.0.0").feature("feat", &[]).publish();
242 bar = { version = "1.0", optional = true }
246 required-features = ["bar?/feat"]
249 .file("src/main.rs", "fn main() {}")
257 [ERROR] invalid feature `bar?/feat` in required-features of target `foo`: \
258 optional dependency with `?` is not allowed in required-features
265 fn weak_with_host_decouple() {
266 // weak-dep-features with new resolver
270 // └── bar v1.0.0 <-- does not have `feat` enabled
271 // [build-dependencies]
272 // └── bar_activator v1.0.0
274 // └── bar v1.0.0 <-- does have `feat` enabled
275 Package
::new("bar", "1.0.0")
276 .feature("feat", &[])
280 pub fn feat() -> bool {
281 cfg!(feature = "feat")
287 Package
::new("common", "1.0.0")
288 .add_dep(Dependency
::new("bar", "1.0").optional(true))
289 .feature("feat", &["bar?/feat"])
293 #[cfg(feature = "bar")]
294 pub fn feat() -> bool { bar::feat() }
295 #[cfg(not(feature = "bar"))]
296 pub fn feat() -> bool { false }
301 Package
::new("bar_activator", "1.0.0")
302 .feature_dep("common", "1.0", &["bar", "feat"])
306 pub fn feat() -> bool {
323 common = { version = "1.0", features = ["feat"] }
326 bar_activator = "1.0"
333 assert!(!common::feat());
341 assert!(bar_activator::feat());
351 [DOWNLOADING] crates ...
355 [COMPILING] bar v1.0.0
356 [COMPILING] common v1.0.0
357 [COMPILING] bar_activator v1.0.0
358 [COMPILING] foo v0.1.0 [..]
360 [RUNNING] `target/debug/foo[EXE]`
367 fn weak_namespaced() {
368 // Behavior with a dep: dependency.
369 Package
::new("bar", "1.0.0")
370 .feature("feat", &[])
371 .file("src/lib.rs", &require(&["feat"], &[]))
382 bar = { version = "1.0", optional = true }
389 .file("src/lib.rs", &require(&["f1"], &["f2", "bar"]))
392 p
.cargo("check --features f1")
396 [DOWNLOADING] crates ...
397 [DOWNLOADED] bar v1.0.0 [..]
398 [CHECKING] foo v0.1.0 [..]
405 .arg("{p} feats:{f}")
406 .with_stdout("foo v0.1.0 ([ROOT]/foo) feats:")
409 p
.cargo("tree --features f1 -f")
410 .arg("{p} feats:{f}")
411 .with_stdout("foo v0.1.0 ([ROOT]/foo) feats:f1")
414 p
.cargo("tree --features f1,f2 -f")
415 .arg("{p} feats:{f}")
418 foo v0.1.0 ([ROOT]/foo) feats:f1,f2
419 └── bar v1.0.0 feats:feat
424 // "bar" remains not-a-feature
425 p
.change_file("src/lib.rs", &require(&["f1", "f2"], &["bar"]));
427 p
.cargo("check --features f1,f2")
430 [CHECKING] bar v1.0.0
431 [CHECKING] foo v0.1.0 [..]
440 Package
::new("bar", "1.0.0")
441 .feature("feat", &[])
442 .file("src/lib.rs", &require(&["feat"], &[]))
453 bar = { version = "1.0", optional = true }
459 .file("src/lib.rs", &require(&["f1"], &[]))
462 p
.cargo("tree --features f1")
463 .with_stdout("foo v0.1.0 ([ROOT]/foo)")
466 p
.cargo("tree --features f1,bar")
469 foo v0.1.0 ([ROOT]/foo)
475 p
.cargo("tree --features f1,bar -e features")
478 foo v0.1.0 ([ROOT]/foo)
479 └── bar feature \"default\"
485 p
.cargo("tree --features f1,bar -e features -i bar")
489 ├── bar feature \"default\"
490 │ └── foo v0.1.0 ([ROOT]/foo)
491 │ ├── foo feature \"bar\" (command-line)
492 │ ├── foo feature \"default\" (command-line)
493 │ └── foo feature \"f1\" (command-line)
494 └── bar feature \"feat\"
495 └── foo feature \"f1\" (command-line)
500 p
.cargo("tree -e features --features bar?/feat")
501 .with_stdout("foo v0.1.0 ([ROOT]/foo)")
504 // This is a little strange in that it produces no output.
505 // Maybe `cargo tree` should print a note about why?
506 p
.cargo("tree -e features -i bar --features bar?/feat")
510 p
.cargo("tree -e features -i bar --features bar?/feat,bar")
514 ├── bar feature \"default\"
515 │ └── foo v0.1.0 ([ROOT]/foo)
516 │ ├── foo feature \"bar\" (command-line)
517 │ └── foo feature \"default\" (command-line)
518 └── bar feature \"feat\" (command-line)
526 let registry
= RegistryBuilder
::new().http_api().http_index().build();
528 // Publish behavior with /? syntax.
529 Package
::new("bar", "1.0.0").feature("feat", &[]).publish();
539 homepage = "https://example.com/"
542 bar
= { version = "1.0", optional = true }
546 feat2
= ["bar?/feat"]
549 .file("src
/lib
.rs
", "")
553 .replace_crates_io(registry.index_url())
557 [PACKAGING
] foo v0
.1
.0 [..]
558 [VERIFYING
] foo v0
.1
.0 [..]
560 [COMPILING
] foo v0
.1
.0 [..]
563 [UPLOADING
] foo v0
.1
.0 [..]
564 [UPLOADED
] foo v0
.1
.0 to registry `crates
-io`
565 note
: Waiting
for `foo v0
.1
.0` to be available at registry `crates
-io`
.
566 You may press ctrl
-c to skip waiting
; the
crate should be available shortly
.
567 [PUBLISHED
] foo v0
.1
.0 at registry `crates
-io`
572 publish::validate_upload_with_contents(
580 "default_features": true,
586 "version_req": "^1.0"
589 "description": "foo",
590 "documentation": null
,
593 "feat2": ["bar?/feat"]
595 "homepage": "https://example.com/",
598 "license_file": null
,
604 "rust_version": null
,
609 &["Cargo
.toml
", "Cargo
.toml
.orig
", "src
/lib
.rs
"],
618 homepage
= "https://example.com/"
627 feat2
= ["bar?/feat"]
629 cargo::core::package::MANIFEST_PREAMBLE