]> git.proxmox.com Git - cargo.git/blob - tests/testsuite/tree.rs
Add `cargo tree` command.
[cargo.git] / tests / testsuite / tree.rs
1 //! Tests for the `cargo tree` command.
2
3 use cargo_test_support::cross_compile::alternate;
4 use cargo_test_support::registry::{Dependency, Package};
5 use cargo_test_support::{basic_manifest, git, project, rustc_host, Project};
6
7 fn make_simple_proj() -> Project {
8 Package::new("c", "1.0.0").publish();
9 Package::new("b", "1.0.0").dep("c", "1.0").publish();
10 Package::new("a", "1.0.0").dep("b", "1.0").publish();
11 Package::new("bdep", "1.0.0").dep("b", "1.0").publish();
12 Package::new("devdep", "1.0.0").dep("b", "1.0.0").publish();
13
14 project()
15 .file(
16 "Cargo.toml",
17 r#"
18 [package]
19 name = "foo"
20 version = "0.1.0"
21
22 [dependencies]
23 a = "1.0"
24 c = "1.0"
25
26 [build-dependencies]
27 bdep = "1.0"
28
29 [dev-dependencies]
30 devdep = "1.0"
31 "#,
32 )
33 .file("src/lib.rs", "")
34 .file("build.rs", "fn main() {}")
35 .build()
36 }
37
38 #[cargo_test]
39 fn simple() {
40 // A simple test with a few different dependencies.
41 let p = make_simple_proj();
42
43 p.cargo("tree")
44 .with_stdout(
45 "\
46 foo v0.1.0 ([..]/foo)
47 ├── a v1.0.0
48 │ └── b v1.0.0
49 │ └── c v1.0.0
50 └── c v1.0.0 (*)
51 [build-dependencies]
52 └── bdep v1.0.0
53 └── b v1.0.0 (*)
54 [dev-dependencies]
55 └── devdep v1.0.0
56 └── b v1.0.0 (*)
57 ",
58 )
59 .run();
60
61 p.cargo("tree -p bdep")
62 .with_stdout(
63 "\
64 bdep v1.0.0
65 └── b v1.0.0
66 └── c v1.0.0
67 ",
68 )
69 .run();
70 }
71
72 #[cargo_test]
73 fn virtual_workspace() {
74 // Multiple packages in a virtual workspace.
75 Package::new("somedep", "1.0.0").publish();
76 let p = project()
77 .file(
78 "Cargo.toml",
79 r#"
80 [workspace]
81 members = ["a", "b", "c"]
82 "#,
83 )
84 .file("a/Cargo.toml", &basic_manifest("a", "1.0.0"))
85 .file("a/src/lib.rs", "")
86 .file(
87 "b/Cargo.toml",
88 r#"
89 [package]
90 name = "b"
91 version = "0.1.0"
92
93 [dependencies]
94 c = { path = "../c" }
95 somedep = "1.0"
96 "#,
97 )
98 .file("b/src/lib.rs", "")
99 .file("c/Cargo.toml", &basic_manifest("c", "1.0.0"))
100 .file("c/src/lib.rs", "")
101 .build();
102
103 p.cargo("tree")
104 .with_stdout(
105 "\
106 a v1.0.0 ([..]/foo/a)
107
108 b v0.1.0 ([..]/foo/b)
109 ├── c v1.0.0 ([..]/foo/c)
110 └── somedep v1.0.0
111
112 c v1.0.0 ([..]/foo/c)
113 ",
114 )
115 .run();
116
117 p.cargo("tree -p a").with_stdout("a v1.0.0 [..]").run();
118
119 p.cargo("tree")
120 .cwd("b")
121 .with_stdout(
122 "\
123 b v0.1.0 ([..]/foo/b)
124 ├── c v1.0.0 ([..]/foo/c)
125 └── somedep v1.0.0
126 ",
127 )
128 .run();
129 }
130
131 #[cargo_test]
132 fn dedupe_edges() {
133 // Works around https://github.com/rust-lang/cargo/issues/7985
134 Package::new("bitflags", "1.0.0").publish();
135 Package::new("manyfeat", "1.0.0")
136 .feature("f1", &[])
137 .feature("f2", &[])
138 .feature("f3", &[])
139 .dep("bitflags", "1.0")
140 .publish();
141 Package::new("a", "1.0.0")
142 .feature_dep("manyfeat", "1.0", &["f1"])
143 .publish();
144 Package::new("b", "1.0.0")
145 .feature_dep("manyfeat", "1.0", &["f2"])
146 .publish();
147 Package::new("c", "1.0.0")
148 .feature_dep("manyfeat", "1.0", &["f3"])
149 .publish();
150
151 let p = project()
152 .file(
153 "Cargo.toml",
154 r#"
155 [package]
156 name = "foo"
157 version = "0.1.0"
158
159 [dependencies]
160 a = "1.0"
161 b = "1.0"
162 c = "1.0"
163 "#,
164 )
165 .file("src/lib.rs", "")
166 .build();
167
168 p.cargo("tree")
169 .with_stdout(
170 "\
171 foo v0.1.0 ([..]/foo)
172 ├── a v1.0.0
173 │ └── manyfeat v1.0.0
174 │ └── bitflags v1.0.0
175 ├── b v1.0.0
176 │ └── manyfeat v1.0.0 (*)
177 └── c v1.0.0
178 └── manyfeat v1.0.0 (*)
179 ",
180 )
181 .run();
182 }
183
184 #[cargo_test]
185 fn renamed_deps() {
186 // Handles renamed dependencies.
187 Package::new("one", "1.0.0").publish();
188 Package::new("two", "1.0.0").publish();
189 Package::new("bar", "1.0.0").dep("one", "1.0").publish();
190 Package::new("bar", "2.0.0").dep("two", "1.0").publish();
191 let p = project()
192 .file(
193 "Cargo.toml",
194 r#"
195 [package]
196 name = "foo"
197 version = "1.0.0"
198
199 [dependencies]
200 bar1 = {version = "1.0", package="bar"}
201 bar2 = {version = "2.0", package="bar"}
202 "#,
203 )
204 .file("src/lib.rs", "")
205 .build();
206
207 p.cargo("tree")
208 .with_stdout(
209 "\
210 foo v1.0.0 ([..]/foo)
211 ├── bar v1.0.0
212 │ └── one v1.0.0
213 └── bar v2.0.0
214 └── two v1.0.0
215 ",
216 )
217 .run();
218 }
219
220 #[cargo_test]
221 fn source_kinds() {
222 // Handles git and path sources.
223 Package::new("regdep", "1.0.0").publish();
224 let git_project = git::new("gitdep", |p| {
225 p.file("Cargo.toml", &basic_manifest("gitdep", "1.0.0"))
226 .file("src/lib.rs", "")
227 });
228 let p = project()
229 .file(
230 "Cargo.toml",
231 &format!(
232 r#"
233 [package]
234 name = "foo"
235 version = "0.1.0"
236
237 [dependencies]
238 regdep = "1.0"
239 pathdep = {{ path = "pathdep" }}
240 gitdep = {{ git = "{}" }}
241 "#,
242 git_project.url()
243 ),
244 )
245 .file("src/lib.rs", "")
246 .file("pathdep/Cargo.toml", &basic_manifest("pathdep", "1.0.0"))
247 .file("pathdep/src/lib.rs", "")
248 .build();
249
250 p.cargo("tree")
251 .with_stdout(
252 "\
253 foo v0.1.0 ([..]/foo)
254 ├── gitdep v1.0.0 (file://[..]/gitdep#[..])
255 ├── pathdep v1.0.0 ([..]/foo/pathdep)
256 └── regdep v1.0.0
257 ",
258 )
259 .run();
260 }
261
262 #[cargo_test]
263 fn features() {
264 // Exercises a variety of feature behaviors.
265 Package::new("optdep_default", "1.0.0").publish();
266 Package::new("optdep", "1.0.0").publish();
267 let p = project()
268 .file(
269 "Cargo.toml",
270 r#"
271 [package]
272 name = "a"
273 version = "0.1.0"
274
275 [dependencies]
276 optdep_default = { version = "1.0", optional = true }
277 optdep = { version = "1.0", optional = true }
278
279 [features]
280 default = ["optdep_default"]
281 "#,
282 )
283 .file("src/lib.rs", "")
284 .build();
285
286 p.cargo("tree")
287 .with_stdout(
288 "\
289 a v0.1.0 ([..]/foo)
290 └── optdep_default v1.0.0
291 ",
292 )
293 .run();
294
295 p.cargo("tree --no-default-features")
296 .with_stdout(
297 "\
298 a v0.1.0 ([..]/foo)
299 ",
300 )
301 .run();
302
303 p.cargo("tree --all-features")
304 .with_stdout(
305 "\
306 a v0.1.0 ([..]/foo)
307 ├── optdep v1.0.0
308 └── optdep_default v1.0.0
309 ",
310 )
311 .run();
312
313 p.cargo("tree --features optdep")
314 .with_stdout(
315 "\
316 a v0.1.0 ([..]/foo)
317 ├── optdep v1.0.0
318 └── optdep_default v1.0.0
319 ",
320 )
321 .run();
322 }
323
324 #[cargo_test]
325 fn filters_target() {
326 // --target flag
327 Package::new("targetdep", "1.0.0").publish();
328 Package::new("hostdep", "1.0.0").publish();
329 Package::new("devdep", "1.0.0").publish();
330 Package::new("build_target_dep", "1.0.0").publish();
331 Package::new("build_host_dep", "1.0.0")
332 .target_dep("targetdep", "1.0", alternate())
333 .target_dep("hostdep", "1.0", &rustc_host())
334 .publish();
335 Package::new("pm_target", "1.0.0")
336 .proc_macro(true)
337 .publish();
338 Package::new("pm_host", "1.0.0").proc_macro(true).publish();
339
340 let p = project()
341 .file(
342 "Cargo.toml",
343 &format!(
344 r#"
345 [package]
346 name = "foo"
347 version = "0.1.0"
348
349 [target.'{alt}'.dependencies]
350 targetdep = "1.0"
351 pm_target = "1.0"
352
353 [target.'{host}'.dependencies]
354 hostdep = "1.0"
355 pm_host = "1.0"
356
357 [target.'{alt}'.dev-dependencies]
358 devdep = "1.0"
359
360 [target.'{alt}'.build-dependencies]
361 build_target_dep = "1.0"
362
363 [target.'{host}'.build-dependencies]
364 build_host_dep = "1.0"
365 "#,
366 alt = alternate(),
367 host = rustc_host()
368 ),
369 )
370 .file("src/lib.rs", "")
371 .file("build.rs", "fn main() {}")
372 .build();
373
374 p.cargo("tree")
375 .with_stdout(
376 "\
377 foo v0.1.0 ([..]/foo)
378 ├── hostdep v1.0.0
379 └── pm_host v1.0.0
380 [build-dependencies]
381 └── build_host_dep v1.0.0
382 └── hostdep v1.0.0 (*)
383 ",
384 )
385 .run();
386
387 p.cargo("tree --target")
388 .arg(alternate())
389 .with_stdout(
390 "\
391 foo v0.1.0 ([..]/foo)
392 ├── pm_target v1.0.0
393 └── targetdep v1.0.0
394 [build-dependencies]
395 └── build_host_dep v1.0.0
396 └── hostdep v1.0.0
397 [dev-dependencies]
398 └── devdep v1.0.0
399 ",
400 )
401 .run();
402
403 p.cargo("tree --target")
404 .arg(rustc_host())
405 .with_stdout(
406 "\
407 foo v0.1.0 ([..]/foo)
408 ├── hostdep v1.0.0
409 └── pm_host v1.0.0
410 [build-dependencies]
411 └── build_host_dep v1.0.0
412 └── hostdep v1.0.0
413 ",
414 )
415 .run();
416
417 p.cargo("tree --no-filter-targets --target")
418 .arg(alternate())
419 .with_status(101)
420 .with_stderr("[ERROR] cannot specify both `--target` and `--no-filter-targets`")
421 .run();
422
423 p.cargo("tree --no-filter-targets")
424 .with_stdout(
425 "\
426 foo v0.1.0 ([..]/foo)
427 ├── hostdep v1.0.0
428 ├── pm_host v1.0.0
429 ├── pm_target v1.0.0
430 └── targetdep v1.0.0
431 [build-dependencies]
432 ├── build_host_dep v1.0.0
433 │ ├── hostdep v1.0.0 (*)
434 │ └── targetdep v1.0.0 (*)
435 └── build_target_dep v1.0.0
436 [dev-dependencies]
437 └── devdep v1.0.0
438 ",
439 )
440 .run();
441 }
442
443 #[cargo_test]
444 fn no_dev_dependencies() {
445 Package::new("devdep", "1.0.0").publish();
446 let p = project()
447 .file(
448 "Cargo.toml",
449 r#"
450 [package]
451 name = "foo"
452 version = "0.1.0"
453
454 [dev-dependencies]
455 devdep = "1.0"
456 "#,
457 )
458 .file("src/lib.rs", "")
459 .build();
460
461 p.cargo("tree")
462 .with_stdout(
463 "\
464 foo v0.1.0 ([..]foo)
465 [dev-dependencies]
466 └── devdep v1.0.0
467 ",
468 )
469 .run();
470
471 p.cargo("tree --no-dev-dependencies")
472 .with_stdout(
473 "\
474 foo v0.1.0 ([..]foo)
475 ",
476 )
477 .run();
478 }
479
480 #[cargo_test]
481 fn cyclic_dev_dep() {
482 // Cyclical dev-dependency and inverse flag.
483 let p = project()
484 .file(
485 "Cargo.toml",
486 r#"
487 [package]
488 name = "foo"
489 version = "0.1.0"
490
491 [dev-dependencies]
492 dev-dep = { path = "dev-dep" }
493 "#,
494 )
495 .file("src/lib.rs", "")
496 .file(
497 "dev-dep/Cargo.toml",
498 r#"
499 [package]
500 name = "dev-dep"
501 version = "0.1.0"
502
503 [dependencies]
504 foo = { path=".." }
505 "#,
506 )
507 .file("dev-dep/src/lib.rs", "")
508 .build();
509
510 p.cargo("tree")
511 .with_stdout(
512 "\
513 foo v0.1.0 ([..]/foo)
514 [dev-dependencies]
515 └── dev-dep v0.1.0 ([..]/foo/dev-dep)
516 └── foo v0.1.0 ([..]/foo) (*)
517 ",
518 )
519 .run();
520
521 p.cargo("tree --invert")
522 .with_stdout(
523 "\
524 foo v0.1.0 ([..]/foo)
525 └── dev-dep v0.1.0 ([..]/foo/dev-dep)
526 [dev-dependencies]
527 └── foo v0.1.0 ([..]/foo) (*)
528 ",
529 )
530 .run();
531 }
532
533 #[cargo_test]
534 fn invert() {
535 Package::new("b1", "1.0.0").dep("c", "1.0").publish();
536 Package::new("b2", "1.0.0").dep("d", "1.0").publish();
537 Package::new("c", "1.0.0").publish();
538 Package::new("d", "1.0.0").publish();
539 let p = project()
540 .file(
541 "Cargo.toml",
542 r#"
543 [package]
544 name = "foo"
545 version = "0.1.0"
546
547 [dependencies]
548 b1 = "1.0"
549 b2 = "1.0"
550 c = "1.0"
551 "#,
552 )
553 .file("src/lib.rs", "")
554 .build();
555
556 p.cargo("tree")
557 .with_stdout(
558 "\
559 foo v0.1.0 ([..]/foo)
560 ├── b1 v1.0.0
561 │ └── c v1.0.0
562 ├── b2 v1.0.0
563 │ └── d v1.0.0
564 └── c v1.0.0 (*)
565 ",
566 )
567 .run();
568
569 p.cargo("tree --invert -p c")
570 .with_stdout(
571 "\
572 c v1.0.0
573 ├── b1 v1.0.0
574 │ └── foo v0.1.0 ([..]/foo)
575 └── foo v0.1.0 ([..]/foo) (*)
576 ",
577 )
578 .run();
579 }
580
581 #[cargo_test]
582 fn invert_with_build_dep() {
583 // -i with -p for a common dependency between normal and build deps.
584 Package::new("common", "1.0.0").publish();
585 Package::new("bdep", "1.0.0").dep("common", "1.0").publish();
586 let p = project()
587 .file(
588 "Cargo.toml",
589 r#"
590 [package]
591 name = "foo"
592 version = "0.1.0"
593
594 [dependencies]
595 common = "1.0"
596
597 [build-dependencies]
598 bdep = "1.0"
599 "#,
600 )
601 .file("src/lib.rs", "")
602 .build();
603
604 p.cargo("tree")
605 .with_stdout(
606 "\
607 foo v0.1.0 ([..]/foo)
608 └── common v1.0.0
609 [build-dependencies]
610 └── bdep v1.0.0
611 └── common v1.0.0 (*)
612 ",
613 )
614 .run();
615
616 p.cargo("tree -i -p common")
617 .with_stdout(
618 "\
619 common v1.0.0
620 ├── bdep v1.0.0
621[build-dependencies]
622 │ └── foo v0.1.0 ([..]/foo)
623 └── foo v0.1.0 ([..]/foo) (*)
624 ",
625 )
626 .run();
627 }
628
629 #[cargo_test]
630 fn no_indent() {
631 let p = make_simple_proj();
632
633 p.cargo("tree --no-indent")
634 .with_stdout(
635 "\
636 foo v0.1.0 ([..]/foo)
637 a v1.0.0
638 b v1.0.0
639 c v1.0.0
640 c v1.0.0 (*)
641 bdep v1.0.0
642 b v1.0.0 (*)
643 devdep v1.0.0
644 b v1.0.0 (*)
645 ",
646 )
647 .run();
648 }
649
650 #[cargo_test]
651 fn prefix_depth() {
652 let p = make_simple_proj();
653
654 p.cargo("tree --prefix-depth")
655 .with_stdout(
656 "\
657 0foo v0.1.0 ([..]/foo)
658 1a v1.0.0
659 2b v1.0.0
660 3c v1.0.0
661 1c v1.0.0 (*)
662 1bdep v1.0.0
663 2b v1.0.0 (*)
664 1devdep v1.0.0
665 2b v1.0.0 (*)
666 ",
667 )
668 .run();
669 }
670
671 #[cargo_test]
672 fn no_dedupe() {
673 let p = make_simple_proj();
674
675 p.cargo("tree --no-dedupe")
676 .with_stdout(
677 "\
678 foo v0.1.0 ([..]/foo)
679 ├── a v1.0.0
680 │ └── b v1.0.0
681 │ └── c v1.0.0
682 └── c v1.0.0
683 [build-dependencies]
684 └── bdep v1.0.0
685 └── b v1.0.0
686 └── c v1.0.0
687 [dev-dependencies]
688 └── devdep v1.0.0
689 └── b v1.0.0
690 └── c v1.0.0
691 ",
692 )
693 .run();
694 }
695
696 #[cargo_test]
697 fn no_dedupe_cycle() {
698 // --no-dedupe with a dependency cycle
699 let p = project()
700 .file(
701 "Cargo.toml",
702 r#"
703 [package]
704 name = "foo"
705 version = "0.1.0"
706
707 [dev-dependencies]
708 bar = {path = "bar"}
709 "#,
710 )
711 .file("src/lib.rs", "")
712 .file(
713 "bar/Cargo.toml",
714 r#"
715 [package]
716 name = "bar"
717 version = "0.1.0"
718
719 [dependencies]
720 foo = {path=".."}
721 "#,
722 )
723 .file("bar/src/lib.rs", "")
724 .build();
725
726 p.cargo("tree")
727 .with_stdout(
728 "\
729 foo v0.1.0 ([..]/foo)
730 [dev-dependencies]
731 └── bar v0.1.0 ([..]/foo/bar)
732 └── foo v0.1.0 ([..]/foo) (*)
733 ",
734 )
735 .run();
736
737 p.cargo("tree --no-dedupe")
738 .with_stdout(
739 "\
740 foo v0.1.0 ([..]/foo)
741 [dev-dependencies]
742 └── bar v0.1.0 ([..]/foo/bar)
743 └── foo v0.1.0 ([..]/foo) (*)
744 ",
745 )
746 .run();
747 }
748
749 #[cargo_test]
750 fn duplicates() {
751 Package::new("dog", "1.0.0").publish();
752 Package::new("dog", "2.0.0").publish();
753 Package::new("cat", "1.0.0").publish();
754 Package::new("cat", "2.0.0").publish();
755 Package::new("dep", "1.0.0")
756 .dep("dog", "1.0")
757 .dep("cat", "1.0")
758 .publish();
759 let p = project()
760 .file(
761 "Cargo.toml",
762 r#"
763 [workspace]
764 members = ["a", "b"]
765 "#,
766 )
767 .file(
768 "a/Cargo.toml",
769 r#"
770 [package]
771 name = "a"
772 version = "0.1.0"
773
774 [dependencies]
775 dog1 = { version = "1.0", package = "dog" }
776 dog2 = { version = "2.0", package = "dog" }
777 "#,
778 )
779 .file("a/src/lib.rs", "")
780 .file(
781 "b/Cargo.toml",
782 r#"
783 [package]
784 name = "b"
785 version = "0.1.0"
786
787 [dependencies]
788 dep = "1.0"
789 cat = "2.0"
790 "#,
791 )
792 .file("b/src/lib.rs", "")
793 .build();
794
795 p.cargo("tree -p a")
796 .with_stdout(
797 "\
798 a v0.1.0 ([..]/foo/a)
799 ├── dog v1.0.0
800 └── dog v2.0.0
801 ",
802 )
803 .run();
804
805 p.cargo("tree -p b")
806 .with_stdout(
807 "\
808 b v0.1.0 ([..]/foo/b)
809 ├── cat v2.0.0
810 └── dep v1.0.0
811 ├── cat v1.0.0
812 └── dog v1.0.0
813 ",
814 )
815 .run();
816
817 p.cargo("tree -p a -d")
818 .with_stdout(
819 "\
820 dog v1.0.0
821 └── a v0.1.0 ([..]/foo/a)
822
823 dog v2.0.0
824 └── a v0.1.0 ([..]/foo/a)
825 ",
826 )
827 .run();
828
829 p.cargo("tree -p b -d")
830 .with_stdout(
831 "\
832 cat v1.0.0
833 └── dep v1.0.0
834 └── b v0.1.0 ([..]/foo/b)
835
836 cat v2.0.0
837 └── b v0.1.0 ([..]/foo/b)
838 ",
839 )
840 .run();
841 }
842
843 #[cargo_test]
844 fn charset() {
845 let p = make_simple_proj();
846 p.cargo("tree --charset ascii")
847 .with_stdout(
848 "\
849 foo v0.1.0 ([..]/foo)
850 |-- a v1.0.0
851 | `-- b v1.0.0
852 | `-- c v1.0.0
853 `-- c v1.0.0 (*)
854 [build-dependencies]
855 `-- bdep v1.0.0
856 `-- b v1.0.0 (*)
857 [dev-dependencies]
858 `-- devdep v1.0.0
859 `-- b v1.0.0 (*)
860 ",
861 )
862 .run();
863 }
864
865 #[cargo_test]
866 fn format() {
867 Package::new("dep", "1.0.0").publish();
868 let p = project()
869 .file(
870 "Cargo.toml",
871 r#"
872 [package]
873 name = "foo"
874 version = "0.1.0"
875 license = "MIT"
876 repository = "https://github.com/rust-lang/cargo"
877
878 [dependencies]
879 dep = {version="1.0", optional=true}
880
881 [features]
882 default = ["foo"]
883 foo = ["bar"]
884 bar = []
885 "#,
886 )
887 .file("src/lib.rs", "")
888 .build();
889
890 p.cargo("tree --format <<<{p}>>>")
891 .with_stdout("<<<foo v0.1.0 ([..]/foo)>>>")
892 .run();
893
894 p.cargo("tree --format {}")
895 .with_stderr(
896 "\
897 [ERROR] tree format `{}` not valid
898
899 Caused by:
900 unsupported pattern ``
901 ",
902 )
903 .with_status(101)
904 .run();
905
906 p.cargo("tree --format")
907 .arg("{p} {l} {r}")
908 .with_stdout("foo v0.1.0 ([..]/foo) MIT https://github.com/rust-lang/cargo")
909 .run();
910
911 p.cargo("tree --format")
912 .arg("{p} {f}")
913 .with_stdout("foo v0.1.0 ([..]/foo) bar,default,foo")
914 .run();
915
916 p.cargo("tree --all-features --format")
917 .arg("{p} [{f}]")
918 .with_stdout(
919 "\
920 foo v0.1.0 ([..]/foo) [bar,default,dep,foo]
921 └── dep v1.0.0 []
922 ",
923 )
924 .run();
925 }
926
927 #[cargo_test]
928 fn dev_dep_feature() {
929 // -Zfeatures=dev_dep with optional dep
930 Package::new("optdep", "1.0.0").publish();
931 Package::new("bar", "1.0.0")
932 .add_dep(Dependency::new("optdep", "1.0").optional(true))
933 .publish();
934 let p = project()
935 .file(
936 "Cargo.toml",
937 r#"
938 [package]
939 name = "foo"
940 version = "0.1.0"
941
942 [dev-dependencies]
943 bar = { version = "1.0", features = ["optdep"] }
944
945 [dependencies]
946 bar = "1.0"
947 "#,
948 )
949 .file("src/lib.rs", "")
950 .build();
951
952 p.cargo("tree")
953 .with_stdout(
954 "\
955 foo v0.1.0 ([..]/foo)
956 └── bar v1.0.0
957 └── optdep v1.0.0
958 [dev-dependencies]
959 └── bar v1.0.0 (*)
960 ",
961 )
962 .run();
963
964 p.cargo("tree --no-dev-dependencies")
965 .with_stdout(
966 "\
967 foo v0.1.0 ([..]/foo)
968 └── bar v1.0.0
969 └── optdep v1.0.0
970 ",
971 )
972 .run();
973
974 p.cargo("tree -Zfeatures=dev_dep")
975 .masquerade_as_nightly_cargo()
976 .with_stdout(
977 "\
978 foo v0.1.0 ([..]/foo)
979 └── bar v1.0.0
980 └── optdep v1.0.0
981 [dev-dependencies]
982 └── bar v1.0.0 (*)
983 ",
984 )
985 .run();
986
987 p.cargo("tree --no-dev-dependencies -Zfeatures=dev_dep")
988 .masquerade_as_nightly_cargo()
989 .with_stdout(
990 "\
991 foo v0.1.0 ([..]/foo)
992 └── bar v1.0.0
993 ",
994 )
995 .run();
996 }
997
998 #[cargo_test]
999 fn host_dep_feature() {
1000 // -Zfeatures=host_dep with optional dep
1001 Package::new("optdep", "1.0.0").publish();
1002 Package::new("bar", "1.0.0")
1003 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1004 .publish();
1005 let p = project()
1006 .file(
1007 "Cargo.toml",
1008 r#"
1009 [package]
1010 name = "foo"
1011 version = "0.1.0"
1012
1013 [build-dependencies]
1014 bar = { version = "1.0", features = ["optdep"] }
1015
1016 [dependencies]
1017 bar = "1.0"
1018 "#,
1019 )
1020 .file("src/lib.rs", "")
1021 .file("build.rs", "fn main() {}")
1022 .build();
1023
1024 p.cargo("tree")
1025 .with_stdout(
1026 "\
1027 foo v0.1.0 ([..]/foo)
1028 └── bar v1.0.0
1029 └── optdep v1.0.0
1030 [build-dependencies]
1031 └── bar v1.0.0 (*)
1032 ",
1033 )
1034 .run();
1035
1036 p.cargo("tree -Zfeatures=host_dep")
1037 .masquerade_as_nightly_cargo()
1038 .with_stdout(
1039 "\
1040 foo v0.1.0 ([..]/foo)
1041 └── bar v1.0.0
1042 [build-dependencies]
1043 └── bar v1.0.0
1044 └── optdep v1.0.0
1045 ",
1046 )
1047 .run();
1048
1049 // -p
1050 p.cargo("tree -p bar")
1051 .with_stdout(
1052 "\
1053 bar v1.0.0
1054 └── optdep v1.0.0
1055 ",
1056 )
1057 .run();
1058
1059 p.cargo("tree -p bar -Zfeatures=host_dep")
1060 .masquerade_as_nightly_cargo()
1061 .with_stdout(
1062 "\
1063 bar v1.0.0
1064
1065 bar v1.0.0
1066 └── optdep v1.0.0
1067 ",
1068 )
1069 .run();
1070
1071 // invert -p
1072 p.cargo("tree -i -p optdep")
1073 .with_stdout(
1074 "\
1075 optdep v1.0.0
1076 └── bar v1.0.0
1077 └── foo v0.1.0 ([..]/foo)
1078 [build-dependencies]
1079 └── foo v0.1.0 ([..]/foo) (*)
1080 ",
1081 )
1082 .run();
1083
1084 p.cargo("tree -i -p optdep -Zfeatures=host_dep")
1085 .masquerade_as_nightly_cargo()
1086 .with_stdout(
1087 "\
1088 optdep v1.0.0
1089 └── bar v1.0.0
1090 [build-dependencies]
1091 └── foo v0.1.0 ([..]/foo)
1092 ",
1093 )
1094 .run();
1095
1096 // Check that -d handles duplicates with features.
1097 p.cargo("tree -d -Zfeatures=host_dep")
1098 .masquerade_as_nightly_cargo()
1099 .with_stdout(
1100 "\
1101 bar v1.0.0
1102 └── foo v0.1.0 ([..]/foo)
1103
1104 bar v1.0.0
1105 [build-dependencies]
1106 └── foo v0.1.0 ([..]/foo)
1107 ",
1108 )
1109 .run();
1110 }
1111
1112 #[cargo_test]
1113 fn proc_macro_features() {
1114 // -Zfeatures=host_dep with a proc-macro
1115 Package::new("optdep", "1.0.0").publish();
1116 Package::new("somedep", "1.0.0")
1117 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1118 .publish();
1119 Package::new("pm", "1.0.0")
1120 .proc_macro(true)
1121 .feature_dep("somedep", "1.0", &["optdep"])
1122 .publish();
1123 let p = project()
1124 .file(
1125 "Cargo.toml",
1126 r#"
1127 [package]
1128 name = "foo"
1129 version = "0.1.0"
1130
1131 [dependencies]
1132 pm = "1.0"
1133 somedep = "1.0"
1134 "#,
1135 )
1136 .file("src/lib.rs", "")
1137 .build();
1138
1139 p.cargo("tree")
1140 .with_stdout(
1141 "\
1142 foo v0.1.0 ([..]/foo)
1143 ├── pm v1.0.0
1144 │ └── somedep v1.0.0
1145 │ └── optdep v1.0.0
1146 └── somedep v1.0.0 (*)
1147 ",
1148 )
1149 .run();
1150
1151 // Note the missing (*)
1152 p.cargo("tree -Zfeatures=host_dep")
1153 .masquerade_as_nightly_cargo()
1154 .with_stdout(
1155 "\
1156 foo v0.1.0 ([..]/foo)
1157 ├── pm v1.0.0
1158 │ └── somedep v1.0.0
1159 │ └── optdep v1.0.0
1160 └── somedep v1.0.0
1161 ",
1162 )
1163 .run();
1164
1165 // -p
1166 p.cargo("tree -p somedep")
1167 .with_stdout(
1168 "\
1169 somedep v1.0.0
1170 └── optdep v1.0.0
1171 ",
1172 )
1173 .run();
1174
1175 p.cargo("tree -p somedep -Zfeatures=host_dep")
1176 .masquerade_as_nightly_cargo()
1177 .with_stdout(
1178 "\
1179 somedep v1.0.0
1180
1181 somedep v1.0.0
1182 └── optdep v1.0.0
1183 ",
1184 )
1185 .run();
1186
1187 // invert -p
1188 p.cargo("tree -i -p somedep")
1189 .with_stdout(
1190 "\
1191 somedep v1.0.0
1192 ├── foo v0.1.0 ([..]/foo)
1193 └── pm v1.0.0
1194 └── foo v0.1.0 ([..]/foo) (*)
1195 ",
1196 )
1197 .run();
1198
1199 p.cargo("tree -i -p somedep -Zfeatures=host_dep")
1200 .masquerade_as_nightly_cargo()
1201 .with_stdout(
1202 "\
1203 somedep v1.0.0
1204 └── foo v0.1.0 ([..]/foo)
1205
1206 somedep v1.0.0
1207 └── pm v1.0.0
1208 └── foo v0.1.0 ([..]/foo)
1209 ",
1210 )
1211 .run();
1212 }
1213
1214 #[cargo_test]
1215 fn itarget_opt_dep() {
1216 // -Zfeatures=itarget with optional dep
1217 Package::new("optdep", "1.0.0").publish();
1218 Package::new("common", "1.0.0")
1219 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1220 .publish();
1221
1222 let p = project()
1223 .file(
1224 "Cargo.toml",
1225 r#"
1226 [package]
1227 name = "foo"
1228 version = "1.0.0"
1229
1230 [dependencies]
1231 common = "1.0"
1232
1233 [target.'cfg(whatever)'.dependencies]
1234 common = { version = "1.0", features = ["optdep"] }
1235
1236 "#,
1237 )
1238 .file("src/lib.rs", "")
1239 .build();
1240
1241 p.cargo("tree")
1242 .with_stdout(
1243 "\
1244 foo v1.0.0 ([..]/foo)
1245 └── common v1.0.0
1246 └── optdep v1.0.0
1247 ",
1248 )
1249 .run();
1250
1251 p.cargo("tree -Zfeatures=itarget")
1252 .with_stdout(
1253 "\
1254 foo v1.0.0 ([..]/foo)
1255 └── common v1.0.0
1256 ",
1257 )
1258 .masquerade_as_nightly_cargo()
1259 .run();
1260 }
1261
1262 #[cargo_test]
1263 fn ambiguous_name() {
1264 // -p that is ambiguous.
1265 Package::new("dep", "1.0.0").publish();
1266 Package::new("dep", "2.0.0").publish();
1267 Package::new("bar", "1.0.0").dep("dep", "2.0").publish();
1268 let p = project()
1269 .file(
1270 "Cargo.toml",
1271 r#"
1272 [package]
1273 name = "foo"
1274 version = "0.1.0"
1275
1276 [dependencies]
1277 dep = "1.0"
1278 bar = "1.0"
1279 "#,
1280 )
1281 .file("src/lib.rs", "")
1282 .build();
1283
1284 p.cargo("tree -p dep")
1285 .with_stderr_contains(
1286 "\
1287 error: There are multiple `dep` packages in your project, and the specification `dep` is ambiguous.
1288 Please re-run this command with `-p <spec>` where `<spec>` is one of the following:
1289 dep:1.0.0
1290 dep:2.0.0
1291 ",
1292 )
1293 .with_status(101)
1294 .run();
1295 }
1296
1297 #[cargo_test]
1298 fn workspace_features_are_local() {
1299 // The features for workspace packages should be the same as `cargo build`
1300 // (i.e., the features selected depend on the "current" package).
1301 Package::new("optdep", "1.0.0").publish();
1302 Package::new("somedep", "1.0.0")
1303 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1304 .publish();
1305 let p = project()
1306 .file(
1307 "Cargo.toml",
1308 r#"
1309 [workspace]
1310 members = ["a", "b"]
1311 "#,
1312 )
1313 .file(
1314 "a/Cargo.toml",
1315 r#"
1316 [package]
1317 name = "a"
1318 version = "0.1.0"
1319
1320 [dependencies]
1321 somedep = {version="1.0", features=["optdep"]}
1322 "#,
1323 )
1324 .file("a/src/lib.rs", "")
1325 .file(
1326 "b/Cargo.toml",
1327 r#"
1328 [package]
1329 name = "b"
1330 version = "0.1.0"
1331
1332 [dependencies]
1333 somedep = "1.0"
1334 "#,
1335 )
1336 .file("b/src/lib.rs", "")
1337 .build();
1338
1339 p.cargo("tree")
1340 .with_stdout(
1341 "\
1342 a v0.1.0 ([..]/foo/a)
1343 └── somedep v1.0.0
1344 └── optdep v1.0.0
1345
1346 b v0.1.0 ([..]/foo/b)
1347 └── somedep v1.0.0
1348 └── optdep v1.0.0
1349 ",
1350 )
1351 .run();
1352
1353 p.cargo("tree -p a")
1354 .with_stdout(
1355 "\
1356 a v0.1.0 ([..]/foo/a)
1357 └── somedep v1.0.0
1358 └── optdep v1.0.0
1359 ",
1360 )
1361 .run();
1362
1363 p.cargo("tree -p b")
1364 .with_stdout(
1365 "\
1366 b v0.1.0 ([..]/foo/b)
1367 └── somedep v1.0.0
1368 ",
1369 )
1370 .run();
1371 }