1 //! Tests for weak-dep-features.
5 use cargo_test_support
::paths
::CargoPathExt
;
6 use cargo_test_support
::prelude
::*;
7 use cargo_test_support
::registry
::{Dependency, Package, RegistryBuilder}
;
8 use cargo_test_support
::str;
9 use cargo_test_support
::{project, publish}
;
11 use super::features2
::switch_to_resolver_2
;
13 // Helper to create lib.rs files that check features.
14 fn require(enabled_features
: &[&str], disabled_features
: &[&str]) -> String
{
15 let mut s
= String
::new();
16 writeln
!(s
, "#![allow(unexpected_cfgs)]").unwrap();
17 for feature
in enabled_features
{
18 writeln
!(s
, "#[cfg(not(feature=\"{feature}\"))] compile_error!(\"expected feature {feature} to be enabled\");",
19 feature
=feature
).unwrap();
21 for feature
in disabled_features
{
22 writeln
!(s
, "#[cfg(feature=\"{feature}\")] compile_error!(\"did not expect feature {feature} to be enabled\");",
23 feature
=feature
).unwrap();
30 Package
::new("bar", "1.0.0")
32 .file("src/lib.rs", &require(&["feat"], &[]))
44 bar = { version = "1.0", optional = true }
50 .file("src/lib.rs", &require(&["f1"], &[]))
53 // It's a bit unfortunate that this has to download `bar`, but avoiding
54 // that is extremely difficult.
55 p
.cargo("check --features f1")
56 .with_stderr_data(str![[r
#"
57 [UPDATING] `dummy-registry` index
58 [LOCKING] 2 packages to latest compatible versions
59 [DOWNLOADING] crates ...
60 [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`)
61 [CHECKING] foo v0.1.0 ([ROOT]/foo)
62 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
67 p
.cargo("check --features f1,bar")
68 .with_stderr_data(str![[r
#"
70 [CHECKING] foo v0.1.0 ([ROOT]/foo)
71 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
79 // A complex chain that requires deferring enabling the feature due to
80 // another dependency getting enabled.
81 Package
::new("bar", "1.0.0")
83 .file("src/lib.rs", &require(&["feat"], &[]))
85 Package
::new("dep", "1.0.0")
86 .add_dep(Dependency
::new("bar", "1.0").optional(true))
87 .feature("feat", &["bar?/feat"])
89 Package
::new("bar_activator", "1.0.0")
90 .feature_dep("dep", "1.0", &["bar"])
102 dep = { version = "1.0", features = ["feat"] }
103 bar_activator = "1.0"
106 .file("src/lib.rs", "")
110 .with_stderr_data(str![[r
#"
111 [UPDATING] `dummy-registry` index
112 [LOCKING] 4 packages to latest compatible versions
113 [DOWNLOADING] crates ...
114 [DOWNLOADED] dep v1.0.0 (registry `dummy-registry`)
115 [DOWNLOADED] bar_activator v1.0.0 (registry `dummy-registry`)
116 [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`)
117 [CHECKING] bar v1.0.0
118 [CHECKING] dep v1.0.0
119 [CHECKING] bar_activator v1.0.0
120 [CHECKING] foo v0.1.0 ([ROOT]/foo)
121 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
128 fn not_optional_dep() {
129 // Attempt to use dep_name?/feat where dep_name is not optional.
130 Package
::new("dep", "1.0.0").feature("feat", &[]).publish();
148 .file("src/lib.rs", "")
153 .with_stderr_data(str![[r
#"
154 [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml`
157 feature `feat` includes `dep?/feat` with a `?`, but `dep` is not an optional dependency
158 A non-optional dependency of the same name is defined; consider removing the `?` or changing the dependency to be optional
165 fn optional_cli_syntax() {
166 // --features bar?/feat
167 Package
::new("bar", "1.0.0")
168 .feature("feat", &[])
169 .file("src/lib.rs", &require(&["feat"], &[]))
182 bar = { version = "1.0", optional = true }
185 .file("src/lib.rs", "")
188 // Does not build bar.
189 p
.cargo("check --features bar?/feat")
190 .with_stderr_data(str![[r
#"
191 [UPDATING] `dummy-registry` index
192 [LOCKING] 2 packages to latest compatible versions
193 [DOWNLOADING] crates ...
194 [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`)
195 [CHECKING] foo v0.1.0 ([ROOT]/foo)
196 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
202 p
.cargo("check --features bar?/feat,bar")
203 .with_stderr_data(str![[r
#"
204 [CHECKING] bar v1.0.0
205 [CHECKING] foo v0.1.0 ([ROOT]/foo)
206 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
211 eprintln
!("check V2 resolver");
212 switch_to_resolver_2(&p
);
213 p
.build_dir().rm_rf();
214 // Does not build bar.
215 p
.cargo("check --features bar?/feat")
216 .with_stderr_data(str![[r
#"
217 [CHECKING] foo v0.1.0 ([ROOT]/foo)
218 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
224 p
.cargo("check --features bar?/feat,bar")
225 .with_stderr_data(str![[r
#"
226 [CHECKING] bar v1.0.0
227 [CHECKING] foo v0.1.0 ([ROOT]/foo)
228 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
235 fn required_features() {
236 // required-features doesn't allow ?
237 Package
::new("bar", "1.0.0").feature("feat", &[]).publish();
249 bar = { version = "1.0", optional = true }
253 required-features = ["bar?/feat"]
256 .file("src/main.rs", "fn main() {}")
261 .with_stderr_data(str![[r
#"
262 [UPDATING] `dummy-registry` index
263 [LOCKING] 2 packages to latest compatible versions
264 [ERROR] invalid feature `bar?/feat` in required-features of target `foo`: optional dependency with `?` is not allowed in required-features
271 fn weak_with_host_decouple() {
272 // weak-dep-features with new resolver
276 // └── bar v1.0.0 <-- does not have `feat` enabled
277 // [build-dependencies]
278 // └── bar_activator v1.0.0
280 // └── bar v1.0.0 <-- does have `feat` enabled
281 Package
::new("bar", "1.0.0")
282 .feature("feat", &[])
286 pub fn feat() -> bool {
287 cfg!(feature = "feat")
293 Package
::new("common", "1.0.0")
294 .add_dep(Dependency
::new("bar", "1.0").optional(true))
295 .feature("feat", &["bar?/feat"])
299 #[cfg(feature = "bar")]
300 pub fn feat() -> bool { bar::feat() }
301 #[cfg(not(feature = "bar"))]
302 pub fn feat() -> bool { false }
307 Package
::new("bar_activator", "1.0.0")
308 .feature_dep("common", "1.0", &["bar", "feat"])
312 pub fn feat() -> bool {
330 common = { version = "1.0", features = ["feat"] }
333 bar_activator = "1.0"
340 assert!(!common::feat());
348 assert!(bar_activator::feat());
355 .with_stderr_data(str![[r
#"
356 [UPDATING] `dummy-registry` index
357 [LOCKING] 4 packages to latest compatible versions
358 [DOWNLOADING] crates ...
359 [DOWNLOADED] common v1.0.0 (registry `dummy-registry`)
360 [DOWNLOADED] bar_activator v1.0.0 (registry `dummy-registry`)
361 [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`)
362 [COMPILING] bar v1.0.0
363 [COMPILING] common v1.0.0
364 [COMPILING] bar_activator v1.0.0
365 [COMPILING] foo v0.1.0 ([ROOT]/foo)
366 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
367 [RUNNING] `target/debug/foo[EXE]`
374 fn weak_namespaced() {
375 // Behavior with a dep: dependency.
376 Package
::new("bar", "1.0.0")
377 .feature("feat", &[])
378 .file("src/lib.rs", &require(&["feat"], &[]))
390 bar = { version = "1.0", optional = true }
397 .file("src/lib.rs", &require(&["f1"], &["f2", "bar"]))
400 p
.cargo("check --features f1")
401 .with_stderr_data(str![[r
#"
402 [UPDATING] `dummy-registry` index
403 [LOCKING] 2 packages to latest compatible versions
404 [DOWNLOADING] crates ...
405 [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`)
406 [CHECKING] foo v0.1.0 ([ROOT]/foo)
407 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
413 .arg("{p} feats:{f}")
414 .with_stdout_data(str![[r
#"
415 foo v0.1.0 ([ROOT]/foo) feats:
420 p
.cargo("tree --features f1 -f")
421 .arg("{p} feats:{f}")
422 .with_stdout_data(str![[r
#"
423 foo v0.1.0 ([ROOT]/foo) feats:f1
428 p
.cargo("tree --features f1,f2 -f")
429 .arg("{p} feats:{f}")
430 .with_stdout_data(str![[r
#"
431 foo v0.1.0 ([ROOT]/foo) feats:f1,f2
432 └── bar v1.0.0 feats:feat
437 // "bar" remains not-a-feature
438 p
.change_file("src/lib.rs", &require(&["f1", "f2"], &["bar"]));
440 p
.cargo("check --features f1,f2")
441 .with_stderr_data(str![[r
#"
442 [CHECKING] bar v1.0.0
443 [CHECKING] foo v0.1.0 ([ROOT]/foo)
444 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
452 Package
::new("bar", "1.0.0")
453 .feature("feat", &[])
454 .file("src/lib.rs", &require(&["feat"], &[]))
466 bar = { version = "1.0", optional = true }
472 .file("src/lib.rs", &require(&["f1"], &[]))
475 p
.cargo("tree --features f1")
476 .with_stdout_data(str![[r
#"
477 foo v0.1.0 ([ROOT]/foo)
482 p
.cargo("tree --features f1,bar")
483 .with_stdout_data(str![[r
#"
484 foo v0.1.0 ([ROOT]/foo)
490 p
.cargo("tree --features f1,bar -e features")
491 .with_stdout_data(str![[r
#"
492 foo v0.1.0 ([ROOT]/foo)
493 └── bar feature "default"
499 p
.cargo("tree --features f1,bar -e features -i bar")
500 .with_stdout_data(str![[r
#"
502 ├── bar feature "default"
503 │ └── foo v0.1.0 ([ROOT]/foo)
504 │ ├── foo feature "bar" (command-line)
505 │ ├── foo feature "default" (command-line)
506 │ └── foo feature "f1" (command-line)
507 └── bar feature "feat"
508 └── foo feature "f1" (command-line)
513 p
.cargo("tree -e features --features bar?/feat")
514 .with_stdout_data(str![[r
#"
515 foo v0.1.0 ([ROOT]/foo)
520 // This is a little strange in that it produces no output.
521 // Maybe `cargo tree` should print a note about why?
522 p
.cargo("tree -e features -i bar --features bar?/feat")
523 .with_stdout_data("")
526 p
.cargo("tree -e features -i bar --features bar?/feat,bar")
527 .with_stdout_data(str![[r
#"
529 ├── bar feature "default"
530 │ └── foo v0.1.0 ([ROOT]/foo)
531 │ ├── foo feature "bar" (command-line)
532 │ └── foo feature "default" (command-line)
533 └── bar feature "feat" (command-line)
541 let registry
= RegistryBuilder
::new().http_api().http_index().build();
543 // Publish behavior with /? syntax.
544 Package
::new("bar", "1.0.0").feature("feat", &[]).publish();
555 homepage = "https://example.com/"
558 bar
= { version = "1.0", optional = true }
562 feat2
= ["bar?/feat"]
565 .file("src
/lib
.rs
", "")
569 .replace_crates_io(registry.index_url())
570 .with_stderr_data(str![[r#"
571 [UPDATING
] crates
.io index
572 [PACKAGING
] foo v0
.1
.0 ([ROOT
]/foo
)
573 [PACKAGED
] 3 files
, [FILE_SIZE
]B ([FILE_SIZE
]B compressed
)
574 [VERIFYING
] foo v0
.1
.0 ([ROOT
]/foo
)
575 [UPDATING
] crates
.io index
576 [COMPILING
] foo v0
.1
.0 ([ROOT
]/foo
/target
/package
/foo
-0.1.0)
577 [FINISHED
] `dev` profile
[unoptimized
+ debuginfo
] target(s
) in [ELAPSED
]s
578 [UPLOADING
] foo v0
.1
.0 ([ROOT
]/foo
)
579 [UPLOADED
] foo v0
.1
.0 to registry `crates
-io`
580 [NOTE
] waiting
for `foo v0
.1
.0` to be available at registry `crates
-io`
.
581 You may press ctrl
-c to skip waiting
; the
crate should be available shortly
.
582 [PUBLISHED
] foo v0
.1
.0 at registry `crates
-io`
587 publish::validate_upload_with_contents(
595 "default_features": true,
601 "version_req": "^1.0"
604 "description": "foo",
605 "documentation": null
,
608 "feat2": ["bar?/feat"]
610 "homepage": "https://example.com/",
613 "license_file": null
,
619 "rust_version": null
,
624 &["Cargo
.toml
", "Cargo
.toml
.orig
", "src
/lib
.rs
"],
639 homepage
= "https://example.com/"
653 feat2
= ["bar?/feat"]
655 cargo::core::manifest::MANIFEST_PREAMBLE