]> git.proxmox.com Git - rustc.git/blame_incremental - src/tools/cargo/tests/testsuite/weak_dep_features.rs
bump version to 1.80.1+dfsg1-1~bpo12+pve1
[rustc.git] / src / tools / cargo / tests / testsuite / weak_dep_features.rs
... / ...
CommitLineData
1//! Tests for weak-dep-features.
2
3use super::features2::switch_to_resolver_2;
4use cargo_test_support::paths::CargoPathExt;
5use cargo_test_support::registry::{Dependency, Package, RegistryBuilder};
6use cargo_test_support::{project, publish};
7use std::fmt::Write;
8
9// Helper to create lib.rs files that check features.
10fn require(enabled_features: &[&str], disabled_features: &[&str]) -> String {
11 let mut s = String::new();
12 writeln!(s, "#![allow(unexpected_cfgs)]").unwrap();
13 for feature in enabled_features {
14 writeln!(s, "#[cfg(not(feature=\"{feature}\"))] compile_error!(\"expected feature {feature} to be enabled\");",
15 feature=feature).unwrap();
16 }
17 for feature in disabled_features {
18 writeln!(s, "#[cfg(feature=\"{feature}\")] compile_error!(\"did not expect feature {feature} to be enabled\");",
19 feature=feature).unwrap();
20 }
21 s
22}
23
24#[cargo_test]
25fn simple() {
26 Package::new("bar", "1.0.0")
27 .feature("feat", &[])
28 .file("src/lib.rs", &require(&["feat"], &[]))
29 .publish();
30 let p = project()
31 .file(
32 "Cargo.toml",
33 r#"
34 [package]
35 name = "foo"
36 version = "0.1.0"
37 edition = "2015"
38
39 [dependencies]
40 bar = { version = "1.0", optional = true }
41
42 [features]
43 f1 = ["bar?/feat"]
44 "#,
45 )
46 .file("src/lib.rs", &require(&["f1"], &[]))
47 .build();
48
49 // It's a bit unfortunate that this has to download `bar`, but avoiding
50 // that is extremely difficult.
51 p.cargo("check --features f1")
52 .with_stderr(
53 "\
54[UPDATING] [..]
55[LOCKING] 2 packages to latest compatible versions
56[DOWNLOADING] crates ...
57[DOWNLOADED] bar v1.0.0 [..]
58[CHECKING] foo v0.1.0 [..]
59[FINISHED] [..]
60",
61 )
62 .run();
63
64 p.cargo("check --features f1,bar")
65 .with_stderr(
66 "\
67[CHECKING] bar v1.0.0
68[CHECKING] foo v0.1.0 [..]
69[FINISHED] [..]
70",
71 )
72 .run();
73}
74
75#[cargo_test]
76fn deferred() {
77 // A complex chain that requires deferring enabling the feature due to
78 // another dependency getting enabled.
79 Package::new("bar", "1.0.0")
80 .feature("feat", &[])
81 .file("src/lib.rs", &require(&["feat"], &[]))
82 .publish();
83 Package::new("dep", "1.0.0")
84 .add_dep(Dependency::new("bar", "1.0").optional(true))
85 .feature("feat", &["bar?/feat"])
86 .publish();
87 Package::new("bar_activator", "1.0.0")
88 .feature_dep("dep", "1.0", &["bar"])
89 .publish();
90 let p = project()
91 .file(
92 "Cargo.toml",
93 r#"
94 [package]
95 name = "foo"
96 version = "0.1.0"
97 edition = "2015"
98
99 [dependencies]
100 dep = { version = "1.0", features = ["feat"] }
101 bar_activator = "1.0"
102 "#,
103 )
104 .file("src/lib.rs", "")
105 .build();
106
107 p.cargo("check")
108 .with_stderr(
109 "\
110[UPDATING] [..]
111[LOCKING] 4 packages to latest compatible versions
112[DOWNLOADING] crates ...
113[DOWNLOADED] dep v1.0.0 [..]
114[DOWNLOADED] bar_activator v1.0.0 [..]
115[DOWNLOADED] bar v1.0.0 [..]
116[CHECKING] bar v1.0.0
117[CHECKING] dep v1.0.0
118[CHECKING] bar_activator v1.0.0
119[CHECKING] foo v0.1.0 [..]
120[FINISHED] [..]
121",
122 )
123 .run();
124}
125
126#[cargo_test]
127fn not_optional_dep() {
128 // Attempt to use dep_name?/feat where dep_name is not optional.
129 Package::new("dep", "1.0.0").feature("feat", &[]).publish();
130
131 let p = project()
132 .file(
133 "Cargo.toml",
134 r#"
135 [package]
136 name = "foo"
137 version = "0.1.0"
138 edition = "2015"
139
140 [dependencies]
141 dep = "1.0"
142
143 [features]
144 feat = ["dep?/feat"]
145 "#,
146 )
147 .file("src/lib.rs", "")
148 .build();
149
150 p.cargo("check")
151 .with_status(101)
152 .with_stderr("\
153error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
154
155Caused by:
156 feature `feat` includes `dep?/feat` with a `?`, but `dep` is not an optional dependency
157 A non-optional dependency of the same name is defined; consider removing the `?` or changing the dependency to be optional
158")
159 .run();
160}
161
162#[cargo_test]
163fn optional_cli_syntax() {
164 // --features bar?/feat
165 Package::new("bar", "1.0.0")
166 .feature("feat", &[])
167 .file("src/lib.rs", &require(&["feat"], &[]))
168 .publish();
169
170 let p = project()
171 .file(
172 "Cargo.toml",
173 r#"
174 [package]
175 name = "foo"
176 version = "0.1.0"
177 edition = "2015"
178
179 [dependencies]
180 bar = { version = "1.0", optional = true }
181 "#,
182 )
183 .file("src/lib.rs", "")
184 .build();
185
186 // Does not build bar.
187 p.cargo("check --features bar?/feat")
188 .with_stderr(
189 "\
190[UPDATING] [..]
191[LOCKING] 2 packages to latest compatible versions
192[DOWNLOADING] crates ...
193[DOWNLOADED] bar v1.0.0 [..]
194[CHECKING] foo v0.1.0 [..]
195[FINISHED] [..]
196",
197 )
198 .run();
199
200 // Builds bar.
201 p.cargo("check --features bar?/feat,bar")
202 .with_stderr(
203 "\
204[CHECKING] bar v1.0.0
205[CHECKING] foo v0.1.0 [..]
206[FINISHED] [..]
207",
208 )
209 .run();
210
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(
217 "\
218[CHECKING] foo v0.1.0 [..]
219[FINISHED] [..]
220",
221 )
222 .run();
223
224 // Builds bar.
225 p.cargo("check --features bar?/feat,bar")
226 .with_stderr(
227 "\
228[CHECKING] bar v1.0.0
229[CHECKING] foo v0.1.0 [..]
230[FINISHED] [..]
231",
232 )
233 .run();
234}
235
236#[cargo_test]
237fn required_features() {
238 // required-features doesn't allow ?
239 Package::new("bar", "1.0.0").feature("feat", &[]).publish();
240
241 let p = project()
242 .file(
243 "Cargo.toml",
244 r#"
245 [package]
246 name = "foo"
247 version = "0.1.0"
248 edition = "2015"
249
250 [dependencies]
251 bar = { version = "1.0", optional = true }
252
253 [[bin]]
254 name = "foo"
255 required-features = ["bar?/feat"]
256 "#,
257 )
258 .file("src/main.rs", "fn main() {}")
259 .build();
260
261 p.cargo("check")
262 .with_status(101)
263 .with_stderr(
264 "\
265[UPDATING] [..]
266[LOCKING] 2 packages to latest compatible versions
267[ERROR] invalid feature `bar?/feat` in required-features of target `foo`: \
268optional dependency with `?` is not allowed in required-features
269",
270 )
271 .run();
272}
273
274#[cargo_test]
275fn weak_with_host_decouple() {
276 // weak-dep-features with new resolver
277 //
278 // foo v0.1.0
279 // └── common v1.0.0
280 // └── bar v1.0.0 <-- does not have `feat` enabled
281 // [build-dependencies]
282 // └── bar_activator v1.0.0
283 // └── common v1.0.0
284 // └── bar v1.0.0 <-- does have `feat` enabled
285 Package::new("bar", "1.0.0")
286 .feature("feat", &[])
287 .file(
288 "src/lib.rs",
289 r#"
290 pub fn feat() -> bool {
291 cfg!(feature = "feat")
292 }
293 "#,
294 )
295 .publish();
296
297 Package::new("common", "1.0.0")
298 .add_dep(Dependency::new("bar", "1.0").optional(true))
299 .feature("feat", &["bar?/feat"])
300 .file(
301 "src/lib.rs",
302 r#"
303 #[cfg(feature = "bar")]
304 pub fn feat() -> bool { bar::feat() }
305 #[cfg(not(feature = "bar"))]
306 pub fn feat() -> bool { false }
307 "#,
308 )
309 .publish();
310
311 Package::new("bar_activator", "1.0.0")
312 .feature_dep("common", "1.0", &["bar", "feat"])
313 .file(
314 "src/lib.rs",
315 r#"
316 pub fn feat() -> bool {
317 common::feat()
318 }
319 "#,
320 )
321 .publish();
322
323 let p = project()
324 .file(
325 "Cargo.toml",
326 r#"
327 [package]
328 name = "foo"
329 version = "0.1.0"
330 edition = "2015"
331 resolver = "2"
332
333 [dependencies]
334 common = { version = "1.0", features = ["feat"] }
335
336 [build-dependencies]
337 bar_activator = "1.0"
338 "#,
339 )
340 .file(
341 "src/main.rs",
342 r#"
343 fn main() {
344 assert!(!common::feat());
345 }
346 "#,
347 )
348 .file(
349 "build.rs",
350 r#"
351 fn main() {
352 assert!(bar_activator::feat());
353 }
354 "#,
355 )
356 .build();
357
358 p.cargo("run")
359 .with_stderr(
360 "\
361[UPDATING] [..]
362[LOCKING] 4 packages to latest compatible versions
363[DOWNLOADING] crates ...
364[DOWNLOADED] [..]
365[DOWNLOADED] [..]
366[DOWNLOADED] [..]
367[COMPILING] bar v1.0.0
368[COMPILING] common v1.0.0
369[COMPILING] bar_activator v1.0.0
370[COMPILING] foo v0.1.0 [..]
371[FINISHED] [..]
372[RUNNING] `target/debug/foo[EXE]`
373",
374 )
375 .run();
376}
377
378#[cargo_test]
379fn weak_namespaced() {
380 // Behavior with a dep: dependency.
381 Package::new("bar", "1.0.0")
382 .feature("feat", &[])
383 .file("src/lib.rs", &require(&["feat"], &[]))
384 .publish();
385 let p = project()
386 .file(
387 "Cargo.toml",
388 r#"
389 [package]
390 name = "foo"
391 version = "0.1.0"
392 edition = "2015"
393
394 [dependencies]
395 bar = { version = "1.0", optional = true }
396
397 [features]
398 f1 = ["bar?/feat"]
399 f2 = ["dep:bar"]
400 "#,
401 )
402 .file("src/lib.rs", &require(&["f1"], &["f2", "bar"]))
403 .build();
404
405 p.cargo("check --features f1")
406 .with_stderr(
407 "\
408[UPDATING] [..]
409[LOCKING] 2 packages to latest compatible versions
410[DOWNLOADING] crates ...
411[DOWNLOADED] bar v1.0.0 [..]
412[CHECKING] foo v0.1.0 [..]
413[FINISHED] [..]
414",
415 )
416 .run();
417
418 p.cargo("tree -f")
419 .arg("{p} feats:{f}")
420 .with_stdout("foo v0.1.0 ([ROOT]/foo) feats:")
421 .run();
422
423 p.cargo("tree --features f1 -f")
424 .arg("{p} feats:{f}")
425 .with_stdout("foo v0.1.0 ([ROOT]/foo) feats:f1")
426 .run();
427
428 p.cargo("tree --features f1,f2 -f")
429 .arg("{p} feats:{f}")
430 .with_stdout(
431 "\
432foo v0.1.0 ([ROOT]/foo) feats:f1,f2
433└── bar v1.0.0 feats:feat
434",
435 )
436 .run();
437
438 // "bar" remains not-a-feature
439 p.change_file("src/lib.rs", &require(&["f1", "f2"], &["bar"]));
440
441 p.cargo("check --features f1,f2")
442 .with_stderr(
443 "\
444[CHECKING] bar v1.0.0
445[CHECKING] foo v0.1.0 [..]
446[FINISHED] [..]
447",
448 )
449 .run();
450}
451
452#[cargo_test]
453fn tree() {
454 Package::new("bar", "1.0.0")
455 .feature("feat", &[])
456 .file("src/lib.rs", &require(&["feat"], &[]))
457 .publish();
458 let p = project()
459 .file(
460 "Cargo.toml",
461 r#"
462 [package]
463 name = "foo"
464 version = "0.1.0"
465 edition = "2015"
466
467 [dependencies]
468 bar = { version = "1.0", optional = true }
469
470 [features]
471 f1 = ["bar?/feat"]
472 "#,
473 )
474 .file("src/lib.rs", &require(&["f1"], &[]))
475 .build();
476
477 p.cargo("tree --features f1")
478 .with_stdout("foo v0.1.0 ([ROOT]/foo)")
479 .run();
480
481 p.cargo("tree --features f1,bar")
482 .with_stdout(
483 "\
484foo v0.1.0 ([ROOT]/foo)
485└── bar v1.0.0
486",
487 )
488 .run();
489
490 p.cargo("tree --features f1,bar -e features")
491 .with_stdout(
492 "\
493foo v0.1.0 ([ROOT]/foo)
494└── bar feature \"default\"
495 └── bar v1.0.0
496",
497 )
498 .run();
499
500 p.cargo("tree --features f1,bar -e features -i bar")
501 .with_stdout(
502 "\
503bar v1.0.0
504├── bar feature \"default\"
505│ └── foo v0.1.0 ([ROOT]/foo)
506│ ├── foo feature \"bar\" (command-line)
507│ ├── foo feature \"default\" (command-line)
508│ └── foo feature \"f1\" (command-line)
509└── bar feature \"feat\"
510 └── foo feature \"f1\" (command-line)
511",
512 )
513 .run();
514
515 p.cargo("tree -e features --features bar?/feat")
516 .with_stdout("foo v0.1.0 ([ROOT]/foo)")
517 .run();
518
519 // This is a little strange in that it produces no output.
520 // Maybe `cargo tree` should print a note about why?
521 p.cargo("tree -e features -i bar --features bar?/feat")
522 .with_stdout("")
523 .run();
524
525 p.cargo("tree -e features -i bar --features bar?/feat,bar")
526 .with_stdout(
527 "\
528bar v1.0.0
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)
534",
535 )
536 .run();
537}
538
539#[cargo_test]
540fn publish() {
541 let registry = RegistryBuilder::new().http_api().http_index().build();
542
543 // Publish behavior with /? syntax.
544 Package::new("bar", "1.0.0").feature("feat", &[]).publish();
545 let p = project()
546 .file(
547 "Cargo.toml",
548 r#"
549 [package]
550 name = "foo"
551 version = "0.1.0"
552 edition = "2015"
553 description = "foo"
554 license = "MIT"
555 homepage = "https://example.com/"
556
557 [dependencies]
558 bar = { version = "1.0", optional = true }
559
560 [features]
561 feat1 = []
562 feat2 = ["bar?/feat"]
563 "#,
564 )
565 .file("src/lib.rs", "")
566 .build();
567
568 p.cargo("publish")
569 .replace_crates_io(registry.index_url())
570 .with_stderr(
571 "\
572[UPDATING] [..]
573[PACKAGING] foo v0.1.0 [..]
574[VERIFYING] foo v0.1.0 [..]
575[UPDATING] [..]
576[COMPILING] foo v0.1.0 [..]
577[FINISHED] [..]
578[PACKAGED] [..]
579[UPLOADING] foo v0.1.0 [..]
580[UPLOADED] foo v0.1.0 to registry `crates-io`
581[NOTE] waiting for `foo v0.1.0` to be available at registry `crates-io`.
582You may press ctrl-c to skip waiting; the crate should be available shortly.
583[PUBLISHED] foo v0.1.0 at registry `crates-io`
584",
585 )
586 .run();
587
588 publish::validate_upload_with_contents(
589 r#"
590 {
591 "authors": [],
592 "badges": {},
593 "categories": [],
594 "deps": [
595 {
596 "default_features": true,
597 "features": [],
598 "kind": "normal",
599 "name": "bar",
600 "optional": true,
601 "target": null,
602 "version_req": "^1.0"
603 }
604 ],
605 "description": "foo",
606 "documentation": null,
607 "features": {
608 "feat1": [],
609 "feat2": ["bar?/feat"]
610 },
611 "homepage": "https://example.com/",
612 "keywords": [],
613 "license": "MIT",
614 "license_file": null,
615 "links": null,
616 "name": "foo",
617 "readme": null,
618 "readme_file": null,
619 "repository": null,
620 "rust_version": null,
621 "vers": "0.1.0"
622 }
623 "#,
624 "foo-0.1.0.crate",
625 &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs"],
626 &[(
627 "Cargo.toml",
628 &format!(
629 r#"{}
630[package]
631edition = "2015"
632name = "foo"
633version = "0.1.0"
634build = false
635autobins = false
636autoexamples = false
637autotests = false
638autobenches = false
639description = "foo"
640homepage = "https://example.com/"
641readme = false
642license = "MIT"
643
644[lib]
645name = "foo"
646path = "src/lib.rs"
647
648[dependencies.bar]
649version = "1.0"
650optional = true
651
652[features]
653feat1 = []
654feat2 = ["bar?/feat"]
655"#,
656 cargo::core::manifest::MANIFEST_PREAMBLE
657 ),
658 )],
659 );
660}