]> git.proxmox.com Git - rustc.git/blame - src/tools/cargo/tests/testsuite/features_namespaced.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / src / tools / cargo / tests / testsuite / features_namespaced.rs
CommitLineData
0a29b90c
FG
1//! Tests for namespaced features.
2
3use super::features2::switch_to_resolver_2;
4use cargo_test_support::registry::{Dependency, Package, RegistryBuilder};
5use cargo_test_support::{project, publish};
6
7#[cargo_test]
8fn dependency_with_crate_syntax() {
9 // Registry dependency uses dep: syntax.
10 Package::new("baz", "1.0.0").publish();
11 Package::new("bar", "1.0.0")
12 .add_dep(Dependency::new("baz", "1.0").optional(true))
13 .feature("feat", &["dep:baz"])
14 .publish();
15 let p = project()
16 .file(
17 "Cargo.toml",
18 r#"
19 [package]
20 name = "foo"
21 version = "0.1.0"
22
23 [dependencies]
24 bar = {version="1.0", features=["feat"]}
25 "#,
26 )
27 .file("src/lib.rs", "")
28 .build();
29
30 p.cargo("check")
31 .with_stderr(
32 "\
33[UPDATING] [..]
34[DOWNLOADING] crates ...
35[DOWNLOADED] [..]
36[DOWNLOADED] [..]
37[CHECKING] baz v1.0.0
38[CHECKING] bar v1.0.0
39[CHECKING] foo v0.1.0 [..]
40[FINISHED] [..]
41",
42 )
43 .run();
44}
45
46#[cargo_test]
47fn namespaced_invalid_feature() {
48 // Specifies a feature that doesn't exist.
49 let p = project()
50 .file(
51 "Cargo.toml",
52 r#"
53 [package]
54 name = "foo"
55 version = "0.0.1"
56 authors = []
57
58 [features]
59 bar = ["baz"]
60 "#,
61 )
62 .file("src/main.rs", "")
63 .build();
64
65 p.cargo("check")
66 .with_status(101)
67 .with_stderr(
68 "\
69[ERROR] failed to parse manifest at `[..]`
70
71Caused by:
72 feature `bar` includes `baz` which is neither a dependency nor another feature
73",
74 )
75 .run();
76}
77
78#[cargo_test]
79fn namespaced_invalid_dependency() {
80 // Specifies a dep:name that doesn't exist.
81 let p = project()
82 .file(
83 "Cargo.toml",
84 r#"
85 [package]
86 name = "foo"
87 version = "0.0.1"
88
89 [features]
90 bar = ["dep:baz"]
91 "#,
92 )
93 .file("src/main.rs", "")
94 .build();
95
96 p.cargo("check")
97 .with_status(101)
98 .with_stderr(
99 "\
100[ERROR] failed to parse manifest at `[..]`
101
102Caused by:
103 feature `bar` includes `dep:baz`, but `baz` is not listed as a dependency
104",
105 )
106 .run();
107}
108
109#[cargo_test]
110fn namespaced_non_optional_dependency() {
111 // Specifies a dep:name for a dependency that is not optional.
112 let p = project()
113 .file(
114 "Cargo.toml",
115 r#"
116 [package]
117 name = "foo"
118 version = "0.0.1"
119
120 [features]
121 bar = ["dep:baz"]
122
123 [dependencies]
124 baz = "0.1"
125 "#,
126 )
127 .file("src/main.rs", "")
128 .build();
129
130 p.cargo("check")
131
132 .with_status(101)
133 .with_stderr(
134 "\
135[ERROR] failed to parse manifest at `[..]`
136
137Caused by:
138 feature `bar` includes `dep:baz`, but `baz` is not an optional dependency
139 A non-optional dependency of the same name is defined; consider adding `optional = true` to its definition.
140",
141 )
142 .run();
143}
144
145#[cargo_test]
146fn namespaced_implicit_feature() {
147 // Backwards-compatible with old syntax.
148 Package::new("baz", "0.1.0").publish();
149
150 let p = project()
151 .file(
152 "Cargo.toml",
153 r#"
154 [package]
155 name = "foo"
156 version = "0.0.1"
157
158 [features]
159 bar = ["baz"]
160
161 [dependencies]
162 baz = { version = "0.1", optional = true }
163 "#,
164 )
165 .file("src/main.rs", "fn main() {}")
166 .build();
167
168 p.cargo("check")
169 .with_stderr(
170 "\
171[UPDATING] [..]
172[CHECKING] foo v0.0.1 [..]
173[FINISHED] [..]
174",
175 )
176 .run();
177 p.cargo("check --features baz")
178 .with_stderr(
179 "\
180[DOWNLOADING] crates ...
181[DOWNLOADED] baz v0.1.0 [..]
182[CHECKING] baz v0.1.0
183[CHECKING] foo v0.0.1 [..]
184[FINISHED] [..]
185",
186 )
187 .run();
188}
189
190#[cargo_test]
191fn namespaced_shadowed_dep() {
192 // An optional dependency is not listed in the features table, and its
193 // implicit feature is overridden.
194 let p = project()
195 .file(
196 "Cargo.toml",
197 r#"
198 [package]
199 name = "foo"
200 version = "0.0.1"
201
202 [features]
203 baz = []
204
205 [dependencies]
206 baz = { version = "0.1", optional = true }
207 "#,
208 )
209 .file("src/main.rs", "fn main() {}")
210 .build();
211
212 p.cargo("check")
213 .with_status(101)
214 .with_stderr(
215 "\
216[ERROR] failed to parse manifest at `[..]`
217
218Caused by:
219 optional dependency `baz` is not included in any feature
220 Make sure that `dep:baz` is included in one of features in the [features] table.
221",
222 )
223 .run();
224}
225
226#[cargo_test]
227fn namespaced_shadowed_non_optional() {
228 // Able to specify a feature with the same name as a required dependency.
229 Package::new("baz", "0.1.0").publish();
230 let p = project()
231 .file(
232 "Cargo.toml",
233 r#"
234 [package]
235 name = "foo"
236 version = "0.0.1"
237
238 [features]
239 baz = []
240
241 [dependencies]
242 baz = "0.1"
243 "#,
244 )
245 .file("src/lib.rs", "")
246 .build();
247
248 p.cargo("check").run();
249}
250
251#[cargo_test]
252fn namespaced_implicit_non_optional() {
253 // Includes a non-optional dependency in [features] table.
254 let p = project()
255 .file(
256 "Cargo.toml",
257 r#"
258 [package]
259 name = "foo"
260 version = "0.0.1"
261
262 [features]
263 bar = ["baz"]
264
265 [dependencies]
266 baz = "0.1"
267 "#,
268 )
269 .file("src/main.rs", "fn main() {}")
270 .build();
271
272 p.cargo("check").with_status(101).with_stderr(
273 "\
274[ERROR] failed to parse manifest at `[..]`
275
276Caused by:
277 feature `bar` includes `baz`, but `baz` is not an optional dependency
278 A non-optional dependency of the same name is defined; consider adding `optional = true` to its definition.
279",
280 ).run();
281}
282
283#[cargo_test]
284fn namespaced_same_name() {
285 // Explicitly listing an optional dependency in the [features] table.
286 Package::new("baz", "0.1.0").publish();
287
288 let p = project()
289 .file(
290 "Cargo.toml",
291 r#"
292 [package]
293 name = "foo"
294 version = "0.0.1"
295
296 [features]
297 baz = ["dep:baz"]
298
299 [dependencies]
300 baz = { version = "0.1", optional = true }
301 "#,
302 )
303 .file(
304 "src/main.rs",
305 r#"
306 fn main() {
307 if cfg!(feature="baz") { println!("baz"); }
308 }
309 "#,
310 )
311 .build();
312
313 p.cargo("run")
314 .with_stderr(
315 "\
316[UPDATING] [..]
317[COMPILING] foo v0.0.1 [..]
318[FINISHED] [..]
319[RUNNING] [..]
320",
321 )
322 .with_stdout("")
323 .run();
324
325 p.cargo("run --features baz")
326 .with_stderr(
327 "\
328[DOWNLOADING] crates ...
329[DOWNLOADED] baz v0.1.0 [..]
330[COMPILING] baz v0.1.0
331[COMPILING] foo v0.0.1 [..]
332[FINISHED] [..]
333[RUNNING] [..]
334",
335 )
336 .with_stdout("baz")
337 .run();
338}
339
340#[cargo_test]
341fn no_implicit_feature() {
342 // Using `dep:` will not create an implicit feature.
343 Package::new("regex", "1.0.0").publish();
344 Package::new("lazy_static", "1.0.0").publish();
345
346 let p = project()
347 .file(
348 "Cargo.toml",
349 r#"
350 [package]
351 name = "foo"
352 version = "0.1.0"
353
354 [dependencies]
355 regex = { version = "1.0", optional = true }
356 lazy_static = { version = "1.0", optional = true }
357
358 [features]
359 regex = ["dep:regex", "dep:lazy_static"]
360 "#,
361 )
362 .file(
363 "src/main.rs",
364 r#"
365 fn main() {
366 if cfg!(feature = "regex") { println!("regex"); }
367 if cfg!(feature = "lazy_static") { println!("lazy_static"); }
368 }
369 "#,
370 )
371 .build();
372
373 p.cargo("run")
374 .with_stderr(
375 "\
376[UPDATING] [..]
377[COMPILING] foo v0.1.0 [..]
378[FINISHED] [..]
379[RUNNING] `target/debug/foo[EXE]`
380",
381 )
382 .with_stdout("")
383 .run();
384
385 p.cargo("run --features regex")
386 .with_stderr_unordered(
387 "\
388[DOWNLOADING] crates ...
389[DOWNLOADED] regex v1.0.0 [..]
390[DOWNLOADED] lazy_static v1.0.0 [..]
391[COMPILING] regex v1.0.0
392[COMPILING] lazy_static v1.0.0
393[COMPILING] foo v0.1.0 [..]
394[FINISHED] [..]
395[RUNNING] `target/debug/foo[EXE]`
396",
397 )
398 .with_stdout("regex")
399 .run();
400
401 p.cargo("run --features lazy_static")
402 .with_stderr(
403 "\
404[ERROR] Package `foo v0.1.0 [..]` does not have feature `lazy_static`. \
405It has an optional dependency with that name, but that dependency uses the \"dep:\" \
406syntax in the features table, so it does not have an implicit feature with that name.
407",
408 )
409 .with_status(101)
410 .run();
411}
412
413#[cargo_test]
414fn crate_syntax_bad_name() {
415 // "dep:bar" = []
416 Package::new("bar", "1.0.0").publish();
417 let p = project()
418 .file(
419 "Cargo.toml",
420 r#"
421 [package]
422 name = "foo"
423 version = "0.1.0"
424
425 [dependencies]
426 bar = { version="1.0", optional=true }
427
428 [features]
429 "dep:bar" = []
430 "#,
431 )
432 .file("src/lib.rs", "")
433 .build();
434
435 p.cargo("check --features dep:bar")
436 .with_status(101)
437 .with_stderr(
438 "\
439[ERROR] failed to parse manifest at [..]/foo/Cargo.toml`
440
441Caused by:
4b012472
FG
442 TOML parse error at line 10, column 17
443 |
444 10 | \"dep:bar\" = []
445 | ^^^^^^^^^
0a29b90c
FG
446 feature named `dep:bar` is not allowed to start with `dep:`
447",
448 )
449 .run();
450}
451
452#[cargo_test]
453fn crate_syntax_in_dep() {
454 // features = ["dep:baz"]
455 Package::new("baz", "1.0.0").publish();
456 Package::new("bar", "1.0.0")
457 .add_dep(Dependency::new("baz", "1.0").optional(true))
458 .publish();
459 let p = project()
460 .file(
461 "Cargo.toml",
462 r#"
463 [package]
464 name = "foo"
465 version = "0.1.0"
466
467 [dependencies]
468 bar = { version = "1.0", features = ["dep:baz"] }
469 "#,
470 )
471 .file("src/lib.rs", "")
472 .build();
473
474 p.cargo("check")
475 .with_status(101)
476 .with_stderr(
477 "\
478error: failed to parse manifest at `[CWD]/Cargo.toml`
479
480Caused by:
481 feature `dep:baz` in dependency `bar` is not allowed to use explicit `dep:` syntax
482 If you want to enable [..]
483",
484 )
485 .run();
486}
487
488#[cargo_test]
489fn crate_syntax_cli() {
490 // --features dep:bar
491 Package::new("bar", "1.0.0").publish();
492 let p = project()
493 .file(
494 "Cargo.toml",
495 r#"
496 [package]
497 name = "foo"
498 version = "0.1.0"
499
500 [dependencies]
501 bar = { version = "1.0", optional=true }
502 "#,
503 )
504 .file("src/lib.rs", "")
505 .build();
506
507 p.cargo("check --features dep:bar")
508 .with_status(101)
509 .with_stderr(
510 "\
511[ERROR] feature `dep:bar` is not allowed to use explicit `dep:` syntax
512",
513 )
514 .run();
515
516 switch_to_resolver_2(&p);
517 p.cargo("check --features dep:bar")
518 .with_status(101)
519 .with_stderr(
520 "\
521[ERROR] feature `dep:bar` is not allowed to use explicit `dep:` syntax
522",
523 )
524 .run();
525}
526
527#[cargo_test]
528fn crate_required_features() {
529 // required-features = ["dep:bar"]
530 Package::new("bar", "1.0.0").publish();
531 let p = project()
532 .file(
533 "Cargo.toml",
534 r#"
535 [package]
536 name = "foo"
537 version = "0.1.0"
538
539 [dependencies]
540 bar = { version = "1.0", optional=true }
541
542 [[bin]]
543 name = "foo"
544 required-features = ["dep:bar"]
545 "#,
546 )
547 .file("src/main.rs", "fn main() {}")
548 .build();
549
550 p.cargo("check")
551 .with_status(101)
552 .with_stderr(
553 "\
554[UPDATING] [..]
555[ERROR] invalid feature `dep:bar` in required-features of target `foo`: \
556`dep:` prefixed feature values are not allowed in required-features
557",
558 )
559 .run();
560}
561
562#[cargo_test]
563fn json_exposed() {
564 // Checks that the implicit dep: values are exposed in JSON.
565 Package::new("bar", "1.0.0").publish();
566 let p = project()
567 .file(
568 "Cargo.toml",
569 r#"
570 [package]
571 name = "foo"
572 version = "0.1.0"
573
574 [dependencies]
575 bar = { version = "1.0", optional=true }
576 "#,
577 )
578 .file("src/lib.rs", "")
579 .build();
580
581 p.cargo("metadata --no-deps")
582 .with_json(
583 r#"
584 {
585 "packages": [
586 {
587 "name": "foo",
588 "version": "0.1.0",
589 "id": "foo 0.1.0 [..]",
590 "license": null,
591 "license_file": null,
592 "description": null,
593 "homepage": null,
594 "documentation": null,
595 "source": null,
596 "dependencies": "{...}",
597 "targets": "{...}",
598 "features": {
599 "bar": ["dep:bar"]
600 },
601 "manifest_path": "[..]foo/Cargo.toml",
602 "metadata": null,
603 "publish": null,
604 "authors": [],
605 "categories": [],
606 "default_run": null,
607 "keywords": [],
608 "readme": null,
609 "repository": null,
610 "rust_version": null,
611 "edition": "2015",
612 "links": null
613 }
614 ],
615 "workspace_members": "{...}",
49aad941 616 "workspace_default_members": "{...}",
0a29b90c
FG
617 "resolve": null,
618 "target_directory": "[..]foo/target",
619 "version": 1,
620 "workspace_root": "[..]foo",
621 "metadata": null
622 }
623 "#,
624 )
625 .run();
626}
627
628#[cargo_test]
629fn crate_feature_with_explicit() {
630 // crate_name/feat_name syntax where crate_name already has a feature defined.
631 // NOTE: I don't know if this is actually ideal behavior.
632 Package::new("bar", "1.0.0")
633 .feature("bar_feat", &[])
634 .file(
635 "src/lib.rs",
636 r#"
637 #[cfg(not(feature="bar_feat"))]
638 compile_error!("bar_feat is not enabled");
639 "#,
640 )
641 .publish();
642 let p = project()
643 .file(
644 "Cargo.toml",
645 r#"
646 [package]
647 name = "foo"
648 version = "0.1.0"
649
650 [dependencies]
651 bar = { version="1.0", optional = true }
652
653 [features]
654 f1 = ["bar/bar_feat"]
655 bar = ["dep:bar", "f2"]
656 f2 = []
657 "#,
658 )
659 .file(
660 "src/lib.rs",
661 r#"
662 #[cfg(not(feature="bar"))]
663 compile_error!("bar should be enabled");
664
665 #[cfg(not(feature="f2"))]
666 compile_error!("f2 should be enabled");
667 "#,
668 )
669 .build();
670
671 p.cargo("check --features f1")
672 .with_stderr(
673 "\
674[UPDATING] [..]
675[DOWNLOADING] crates ...
676[DOWNLOADED] bar v1.0.0 [..]
677[CHECKING] bar v1.0.0
678[CHECKING] foo v0.1.0 [..]
679[FINISHED] [..]
680",
681 )
682 .run();
683}
684
685#[cargo_test]
686fn optional_explicit_without_crate() {
687 // "feat" syntax when there is no implicit "feat" feature because it is
688 // explicitly listed elsewhere.
689 Package::new("bar", "1.0.0").publish();
690 let p = project()
691 .file(
692 "Cargo.toml",
693 r#"
694 [package]
695 name = "foo"
696 version = "0.1.0"
697
698 [dependencies]
699 bar = { version = "1.0", optional = true }
700
701 [features]
702 feat1 = ["dep:bar"]
703 feat2 = ["bar"]
704 "#,
705 )
706 .file("src/lib.rs", "")
707 .build();
708
709 p.cargo("check")
710 .with_status(101)
711 .with_stderr(
712 "\
713[ERROR] failed to parse manifest at [..]
714
715Caused by:
716 feature `feat2` includes `bar`, but `bar` is an optional dependency without an implicit feature
717 Use `dep:bar` to enable the dependency.
718",
719 )
720 .run();
721}
722
723#[cargo_test]
724fn tree() {
725 Package::new("baz", "1.0.0").publish();
726 Package::new("bar", "1.0.0")
727 .add_dep(Dependency::new("baz", "1.0").optional(true))
728 .feature("feat1", &["dep:baz"])
729 .feature("feat2", &[])
730 .publish();
731 let p = project()
732 .file(
733 "Cargo.toml",
734 r#"
735 [package]
736 name = "foo"
737 version = "0.1.0"
738
739 [dependencies]
740 bar = { version = "1.0", features = ["feat1"], optional=true }
741
742 [features]
743 a = ["bar/feat2"]
744 bar = ["dep:bar"]
745 "#,
746 )
747 .file("src/lib.rs", "")
748 .build();
749
750 p.cargo("tree -e features")
751 .with_stdout("foo v0.1.0 ([ROOT]/foo)")
752 .run();
753
754 p.cargo("tree -e features --features a")
755 .with_stdout(
756 "\
757foo v0.1.0 ([ROOT]/foo)
758├── bar feature \"default\"
759│ └── bar v1.0.0
760│ └── baz feature \"default\"
761│ └── baz v1.0.0
762└── bar feature \"feat1\"
763 └── bar v1.0.0 (*)
764",
765 )
766 .run();
767
768 p.cargo("tree -e features --features a -i bar")
769 .with_stdout(
770 "\
771bar v1.0.0
772├── bar feature \"default\"
773│ └── foo v0.1.0 ([ROOT]/foo)
774│ ├── foo feature \"a\" (command-line)
775│ ├── foo feature \"bar\"
776│ │ └── foo feature \"a\" (command-line)
777│ └── foo feature \"default\" (command-line)
778├── bar feature \"feat1\"
779│ └── foo v0.1.0 ([ROOT]/foo) (*)
780└── bar feature \"feat2\"
781 └── foo feature \"a\" (command-line)
782",
783 )
784 .run();
785
786 p.cargo("tree -e features --features bar")
787 .with_stdout(
788 "\
789foo v0.1.0 ([ROOT]/foo)
790├── bar feature \"default\"
791│ └── bar v1.0.0
792│ └── baz feature \"default\"
793│ └── baz v1.0.0
794└── bar feature \"feat1\"
795 └── bar v1.0.0 (*)
796",
797 )
798 .run();
799
800 p.cargo("tree -e features --features bar -i bar")
801 .with_stdout(
802 "\
803bar v1.0.0
804├── bar feature \"default\"
805│ └── foo v0.1.0 ([ROOT]/foo)
806│ ├── foo feature \"bar\" (command-line)
807│ └── foo feature \"default\" (command-line)
808└── bar feature \"feat1\"
809 └── foo v0.1.0 ([ROOT]/foo) (*)
810",
811 )
812 .run();
813}
814
815#[cargo_test]
816fn tree_no_implicit() {
817 // tree without an implicit feature
818 Package::new("bar", "1.0.0").publish();
819 let p = project()
820 .file(
821 "Cargo.toml",
822 r#"
823 [package]
824 name = "foo"
825 version = "0.1.0"
826
827 [dependencies]
828 bar = { version = "1.0", optional=true }
829
830 [features]
831 a = ["dep:bar"]
832 "#,
833 )
834 .file("src/lib.rs", "")
835 .build();
836
837 p.cargo("tree -e features")
838 .with_stdout("foo v0.1.0 ([ROOT]/foo)")
839 .run();
840
841 p.cargo("tree -e features --all-features")
842 .with_stdout(
843 "\
844foo v0.1.0 ([ROOT]/foo)
845└── bar feature \"default\"
846 └── bar v1.0.0
847",
848 )
849 .run();
850
851 p.cargo("tree -e features -i bar --all-features")
852 .with_stdout(
853 "\
854bar v1.0.0
855└── bar feature \"default\"
856 └── foo v0.1.0 ([ROOT]/foo)
857 ├── foo feature \"a\" (command-line)
858 └── foo feature \"default\" (command-line)
859",
860 )
861 .run();
862}
863
864#[cargo_test]
865fn publish_no_implicit() {
866 let registry = RegistryBuilder::new().http_api().http_index().build();
867
868 // Does not include implicit features or dep: syntax on publish.
869 Package::new("opt-dep1", "1.0.0").publish();
870 Package::new("opt-dep2", "1.0.0").publish();
871
872 let p = project()
873 .file(
874 "Cargo.toml",
875 r#"
876 [package]
877 name = "foo"
878 version = "0.1.0"
879 description = "foo"
880 license = "MIT"
881 homepage = "https://example.com/"
882
883 [dependencies]
884 opt-dep1 = { version = "1.0", optional = true }
885 opt-dep2 = { version = "1.0", optional = true }
886
887 [features]
888 feat = ["opt-dep1"]
889 "#,
890 )
891 .file("src/lib.rs", "")
892 .build();
893
894 p.cargo("publish --no-verify")
895 .replace_crates_io(registry.index_url())
896 .with_stderr(
897 "\
898[UPDATING] [..]
899[PACKAGING] foo v0.1.0 [..]
900[PACKAGED] [..]
901[UPLOADING] foo v0.1.0 [..]
902[UPLOADED] foo v0.1.0 [..]
903note: Waiting [..]
904You may press ctrl-c [..]
905[PUBLISHED] foo v0.1.0 [..]
906",
907 )
908 .run();
909
910 publish::validate_upload_with_contents(
911 r#"
912 {
913 "authors": [],
914 "badges": {},
915 "categories": [],
916 "deps": [
917 {
918 "default_features": true,
919 "features": [],
920 "kind": "normal",
921 "name": "opt-dep1",
922 "optional": true,
923 "target": null,
924 "version_req": "^1.0"
925 },
926 {
927 "default_features": true,
928 "features": [],
929 "kind": "normal",
930 "name": "opt-dep2",
931 "optional": true,
932 "target": null,
933 "version_req": "^1.0"
934 }
935 ],
936 "description": "foo",
937 "documentation": null,
938 "features": {
939 "feat": ["opt-dep1"]
940 },
941 "homepage": "https://example.com/",
942 "keywords": [],
943 "license": "MIT",
944 "license_file": null,
945 "links": null,
946 "name": "foo",
947 "readme": null,
948 "readme_file": null,
949 "repository": null,
49aad941 950 "rust_version": null,
0a29b90c
FG
951 "vers": "0.1.0"
952 }
953 "#,
954 "foo-0.1.0.crate",
955 &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs"],
956 &[(
957 "Cargo.toml",
958 &format!(
959 r#"{}
960[package]
961name = "foo"
962version = "0.1.0"
963description = "foo"
964homepage = "https://example.com/"
965license = "MIT"
966
967[dependencies.opt-dep1]
968version = "1.0"
969optional = true
970
971[dependencies.opt-dep2]
972version = "1.0"
973optional = true
974
975[features]
976feat = ["opt-dep1"]
977"#,
978 cargo::core::package::MANIFEST_PREAMBLE
979 ),
980 )],
981 );
982}
983
984#[cargo_test]
985fn publish() {
986 let registry = RegistryBuilder::new().http_api().http_index().build();
987
988 // Publish behavior with explicit dep: syntax.
989 Package::new("bar", "1.0.0").publish();
990 let p = project()
991 .file(
992 "Cargo.toml",
993 r#"
994 [package]
995 name = "foo"
996 version = "0.1.0"
997 description = "foo"
998 license = "MIT"
999 homepage = "https://example.com/"
1000
1001 [dependencies]
1002 bar = { version = "1.0", optional = true }
1003
1004 [features]
1005 feat1 = []
1006 feat2 = ["dep:bar"]
1007 feat3 = ["feat2"]
1008 "#,
1009 )
1010 .file("src/lib.rs", "")
1011 .build();
1012
1013 p.cargo("publish")
1014 .replace_crates_io(registry.index_url())
1015 .with_stderr(
1016 "\
1017[UPDATING] [..]
1018[PACKAGING] foo v0.1.0 [..]
1019[VERIFYING] foo v0.1.0 [..]
1020[UPDATING] [..]
1021[COMPILING] foo v0.1.0 [..]
1022[FINISHED] [..]
1023[PACKAGED] [..]
1024[UPLOADING] foo v0.1.0 [..]
1025[UPLOADED] foo v0.1.0 [..]
1026note: Waiting [..]
1027You may press ctrl-c [..]
1028[PUBLISHED] foo v0.1.0 [..]
1029",
1030 )
1031 .run();
1032
1033 publish::validate_upload_with_contents(
1034 r#"
1035 {
1036 "authors": [],
1037 "badges": {},
1038 "categories": [],
1039 "deps": [
1040 {
1041 "default_features": true,
1042 "features": [],
1043 "kind": "normal",
1044 "name": "bar",
1045 "optional": true,
1046 "target": null,
1047 "version_req": "^1.0"
1048 }
1049 ],
1050 "description": "foo",
1051 "documentation": null,
1052 "features": {
1053 "feat1": [],
1054 "feat2": ["dep:bar"],
1055 "feat3": ["feat2"]
1056 },
1057 "homepage": "https://example.com/",
1058 "keywords": [],
1059 "license": "MIT",
1060 "license_file": null,
1061 "links": null,
1062 "name": "foo",
1063 "readme": null,
1064 "readme_file": null,
1065 "repository": null,
49aad941 1066 "rust_version": null,
0a29b90c
FG
1067 "vers": "0.1.0"
1068 }
1069 "#,
1070 "foo-0.1.0.crate",
1071 &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs"],
1072 &[(
1073 "Cargo.toml",
1074 &format!(
1075 r#"{}
1076[package]
1077name = "foo"
1078version = "0.1.0"
1079description = "foo"
1080homepage = "https://example.com/"
1081license = "MIT"
1082
1083[dependencies.bar]
1084version = "1.0"
1085optional = true
1086
1087[features]
1088feat1 = []
1089feat2 = ["dep:bar"]
1090feat3 = ["feat2"]
1091"#,
1092 cargo::core::package::MANIFEST_PREAMBLE
1093 ),
1094 )],
1095 );
1096}
1097
1098#[cargo_test]
1099fn namespaced_feature_together() {
1100 // Check for an error when `dep:` is used with `/`
1101 Package::new("bar", "1.0.0")
1102 .feature("bar-feat", &[])
1103 .publish();
1104
1105 // Non-optional shouldn't have extra err.
1106 let p = project()
1107 .file(
1108 "Cargo.toml",
1109 r#"
1110 [package]
1111 name = "foo"
1112 version = "0.1.0"
1113
1114 [dependencies]
1115 bar = "1.0"
1116
1117 [features]
1118 f1 = ["dep:bar/bar-feat"]
1119 "#,
1120 )
1121 .file("src/lib.rs", "")
1122 .build();
1123 p.cargo("check")
1124 .with_status(101)
1125 .with_stderr(
1126 "\
1127error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
1128
1129Caused by:
1130 feature `f1` includes `dep:bar/bar-feat` with both `dep:` and `/`
1131 To fix this, remove the `dep:` prefix.
1132",
1133 )
1134 .run();
1135
1136 // Weak dependency shouldn't have extra err.
1137 p.change_file(
1138 "Cargo.toml",
1139 r#"
1140 [package]
1141 name = "foo"
1142 version = "0.1.0"
1143
1144 [dependencies]
1145 bar = {version = "1.0", optional = true }
1146
1147 [features]
1148 f1 = ["dep:bar?/bar-feat"]
1149 "#,
1150 );
1151 p.cargo("check")
1152 .with_status(101)
1153 .with_stderr(
1154 "\
1155error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
1156
1157Caused by:
1158 feature `f1` includes `dep:bar?/bar-feat` with both `dep:` and `/`
1159 To fix this, remove the `dep:` prefix.
1160",
1161 )
1162 .run();
1163
1164 // If dep: is already specified, shouldn't have extra err.
1165 p.change_file(
1166 "Cargo.toml",
1167 r#"
1168 [package]
1169 name = "foo"
1170 version = "0.1.0"
1171
1172 [dependencies]
1173 bar = {version = "1.0", optional = true }
1174
1175 [features]
1176 f1 = ["dep:bar", "dep:bar/bar-feat"]
1177 "#,
1178 );
1179 p.cargo("check")
1180 .with_status(101)
1181 .with_stderr(
1182 "\
1183error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
1184
1185Caused by:
1186 feature `f1` includes `dep:bar/bar-feat` with both `dep:` and `/`
1187 To fix this, remove the `dep:` prefix.
1188",
1189 )
1190 .run();
1191
1192 // Only when the other 3 cases aren't true should it give some extra help.
1193 p.change_file(
1194 "Cargo.toml",
1195 r#"
1196 [package]
1197 name = "foo"
1198 version = "0.1.0"
1199
1200 [dependencies]
1201 bar = {version = "1.0", optional = true }
1202
1203 [features]
1204 f1 = ["dep:bar/bar-feat"]
1205 "#,
1206 );
1207 p.cargo("check")
1208 .with_status(101)
1209 .with_stderr(
1210 "\
1211error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
1212
1213Caused by:
1214 feature `f1` includes `dep:bar/bar-feat` with both `dep:` and `/`
1215 To fix this, remove the `dep:` prefix.
1216 If the intent is to avoid creating an implicit feature `bar` for an optional \
1217 dependency, then consider replacing this with two values:
1218 \"dep:bar\", \"bar/bar-feat\"
1219",
1220 )
1221 .run();
1222}
49aad941
FG
1223
1224#[cargo_test]
1225fn dep_feature_when_hidden() {
1226 // Checks for behavior with dep:bar and bar/feat syntax when there is no
1227 // `bar` feature.
1228 let p = project()
1229 .file(
1230 "Cargo.toml",
1231 r#"
1232 [package]
1233 name = "foo"
1234 version = "0.1.0"
1235
1236 [dependencies]
1237 bar = { path = "bar", optional = true }
1238
1239 [features]
1240 f1 = ["dep:bar"]
1241 f2 = ["bar/bar_feat"]
1242 "#,
1243 )
1244 .file("src/lib.rs", "")
1245 .file(
1246 "bar/Cargo.toml",
1247 r#"
1248 [package]
1249 name = "bar"
1250 version = "0.1.0"
1251
1252 [features]
1253 bar_feat = []
1254 "#,
1255 )
1256 .file("bar/src/lib.rs", "")
1257 .build();
1258
1259 p.cargo("tree -f")
1260 .arg("{p} features={f}")
1261 .with_stdout(
1262 "\
1263foo v0.1.0 ([ROOT]/foo) features=",
1264 )
1265 .with_stderr("")
1266 .run();
1267
1268 p.cargo("tree -F f1 -f")
1269 .arg("{p} features={f}")
1270 .with_stdout(
1271 "\
1272foo v0.1.0 ([ROOT]/foo) features=f1
1273└── bar v0.1.0 ([ROOT]/foo/bar) features=
1274",
1275 )
1276 .with_stderr("")
1277 .run();
1278
1279 p.cargo("tree -F f2 -f")
1280 .arg("{p} features={f}")
1281 .with_stdout(
1282 "\
1283foo v0.1.0 ([ROOT]/foo) features=f2
1284└── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat
1285",
1286 )
1287 .with_stderr("")
1288 .run();
1289
1290 p.cargo("tree --all-features -f")
1291 .arg("{p} features={f}")
1292 .with_stdout(
1293 "\
1294foo v0.1.0 ([ROOT]/foo) features=f1,f2
1295└── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat
1296",
1297 )
1298 .with_stderr("")
1299 .run();
1300}