]> git.proxmox.com Git - cargo.git/blob - tests/testsuite/tree.rs
test(carog-tree): new `--prune` option
[cargo.git] / tests / testsuite / tree.rs
1 //! Tests for the `cargo tree` command.
2
3 use super::features2::switch_to_resolver_2;
4 use cargo_test_support::cross_compile::{self, alternate};
5 use cargo_test_support::registry::{Dependency, Package};
6 use cargo_test_support::{basic_manifest, git, project, rustc_host, Project};
7
8 fn make_simple_proj() -> Project {
9 Package::new("c", "1.0.0").publish();
10 Package::new("b", "1.0.0").dep("c", "1.0").publish();
11 Package::new("a", "1.0.0").dep("b", "1.0").publish();
12 Package::new("bdep", "1.0.0").dep("b", "1.0").publish();
13 Package::new("devdep", "1.0.0").dep("b", "1.0.0").publish();
14
15 project()
16 .file(
17 "Cargo.toml",
18 r#"
19 [package]
20 name = "foo"
21 version = "0.1.0"
22
23 [dependencies]
24 a = "1.0"
25 c = "1.0"
26
27 [build-dependencies]
28 bdep = "1.0"
29
30 [dev-dependencies]
31 devdep = "1.0"
32 "#,
33 )
34 .file("src/lib.rs", "")
35 .file("build.rs", "fn main() {}")
36 .build()
37 }
38
39 #[cargo_test]
40 fn simple() {
41 // A simple test with a few different dependencies.
42 let p = make_simple_proj();
43
44 p.cargo("tree")
45 .with_stdout(
46 "\
47 foo v0.1.0 ([..]/foo)
48 ├── a v1.0.0
49 │ └── b v1.0.0
50 │ └── c v1.0.0
51 └── c v1.0.0
52 [build-dependencies]
53 └── bdep v1.0.0
54 └── b v1.0.0 (*)
55 [dev-dependencies]
56 └── devdep v1.0.0
57 └── b v1.0.0 (*)
58 ",
59 )
60 .run();
61
62 p.cargo("tree -p bdep")
63 .with_stdout(
64 "\
65 bdep v1.0.0
66 └── b v1.0.0
67 └── c v1.0.0
68 ",
69 )
70 .run();
71 }
72
73 #[cargo_test]
74 fn virtual_workspace() {
75 // Multiple packages in a virtual workspace.
76 Package::new("somedep", "1.0.0").publish();
77 let p = project()
78 .file(
79 "Cargo.toml",
80 r#"
81 [workspace]
82 members = ["a", "baz", "c"]
83 "#,
84 )
85 .file("a/Cargo.toml", &basic_manifest("a", "1.0.0"))
86 .file("a/src/lib.rs", "")
87 .file(
88 "baz/Cargo.toml",
89 r#"
90 [package]
91 name = "baz"
92 version = "0.1.0"
93
94 [dependencies]
95 c = { path = "../c" }
96 somedep = "1.0"
97 "#,
98 )
99 .file("baz/src/lib.rs", "")
100 .file("c/Cargo.toml", &basic_manifest("c", "1.0.0"))
101 .file("c/src/lib.rs", "")
102 .build();
103
104 p.cargo("tree")
105 .with_stdout(
106 "\
107 a v1.0.0 ([..]/foo/a)
108
109 baz v0.1.0 ([..]/foo/baz)
110 ├── c v1.0.0 ([..]/foo/c)
111 └── somedep v1.0.0
112
113 c v1.0.0 ([..]/foo/c)
114 ",
115 )
116 .run();
117
118 p.cargo("tree -p a").with_stdout("a v1.0.0 [..]").run();
119
120 p.cargo("tree")
121 .cwd("baz")
122 .with_stdout(
123 "\
124 baz v0.1.0 ([..]/foo/baz)
125 ├── c v1.0.0 ([..]/foo/c)
126 └── somedep v1.0.0
127 ",
128 )
129 .run();
130
131 // exclude baz
132 p.cargo("tree --workspace --exclude baz")
133 .with_stdout(
134 "\
135 a v1.0.0 ([..]/foo/a)
136
137 c v1.0.0 ([..]/foo/c)
138 ",
139 )
140 .run();
141
142 // exclude glob '*z'
143 p.cargo("tree --workspace --exclude '*z'")
144 .with_stdout(
145 "\
146 a v1.0.0 ([..]/foo/a)
147
148 c v1.0.0 ([..]/foo/c)
149 ",
150 )
151 .run();
152
153 // include glob '*z'
154 p.cargo("tree -p '*z'")
155 .with_stdout(
156 "\
157 baz v0.1.0 ([..]/foo/baz)
158 ├── c v1.0.0 ([..]/foo/c)
159 └── somedep v1.0.0
160 ",
161 )
162 .run();
163 }
164
165 #[cargo_test]
166 fn dedupe_edges() {
167 // Works around https://github.com/rust-lang/cargo/issues/7985
168 Package::new("bitflags", "1.0.0").publish();
169 Package::new("manyfeat", "1.0.0")
170 .feature("f1", &[])
171 .feature("f2", &[])
172 .feature("f3", &[])
173 .dep("bitflags", "1.0")
174 .publish();
175 Package::new("a", "1.0.0")
176 .feature_dep("manyfeat", "1.0", &["f1"])
177 .publish();
178 Package::new("b", "1.0.0")
179 .feature_dep("manyfeat", "1.0", &["f2"])
180 .publish();
181 Package::new("c", "1.0.0")
182 .feature_dep("manyfeat", "1.0", &["f3"])
183 .publish();
184
185 let p = project()
186 .file(
187 "Cargo.toml",
188 r#"
189 [package]
190 name = "foo"
191 version = "0.1.0"
192
193 [dependencies]
194 a = "1.0"
195 b = "1.0"
196 c = "1.0"
197 "#,
198 )
199 .file("src/lib.rs", "")
200 .build();
201
202 p.cargo("tree")
203 .with_stdout(
204 "\
205 foo v0.1.0 ([..]/foo)
206 ├── a v1.0.0
207 │ └── manyfeat v1.0.0
208 │ └── bitflags v1.0.0
209 ├── b v1.0.0
210 │ └── manyfeat v1.0.0 (*)
211 └── c v1.0.0
212 └── manyfeat v1.0.0 (*)
213 ",
214 )
215 .run();
216 }
217
218 #[cargo_test]
219 fn renamed_deps() {
220 // Handles renamed dependencies.
221 Package::new("one", "1.0.0").publish();
222 Package::new("two", "1.0.0").publish();
223 Package::new("bar", "1.0.0").dep("one", "1.0").publish();
224 Package::new("bar", "2.0.0").dep("two", "1.0").publish();
225 let p = project()
226 .file(
227 "Cargo.toml",
228 r#"
229 [package]
230 name = "foo"
231 version = "1.0.0"
232
233 [dependencies]
234 bar1 = {version = "1.0", package="bar"}
235 bar2 = {version = "2.0", package="bar"}
236 "#,
237 )
238 .file("src/lib.rs", "")
239 .build();
240
241 p.cargo("tree")
242 .with_stdout(
243 "\
244 foo v1.0.0 ([..]/foo)
245 ├── bar v1.0.0
246 │ └── one v1.0.0
247 └── bar v2.0.0
248 └── two v1.0.0
249 ",
250 )
251 .run();
252 }
253
254 #[cargo_test]
255 fn source_kinds() {
256 // Handles git and path sources.
257 Package::new("regdep", "1.0.0").publish();
258 let git_project = git::new("gitdep", |p| {
259 p.file("Cargo.toml", &basic_manifest("gitdep", "1.0.0"))
260 .file("src/lib.rs", "")
261 });
262 let p = project()
263 .file(
264 "Cargo.toml",
265 &format!(
266 r#"
267 [package]
268 name = "foo"
269 version = "0.1.0"
270
271 [dependencies]
272 regdep = "1.0"
273 pathdep = {{ path = "pathdep" }}
274 gitdep = {{ git = "{}" }}
275 "#,
276 git_project.url()
277 ),
278 )
279 .file("src/lib.rs", "")
280 .file("pathdep/Cargo.toml", &basic_manifest("pathdep", "1.0.0"))
281 .file("pathdep/src/lib.rs", "")
282 .build();
283
284 p.cargo("tree")
285 .with_stdout(
286 "\
287 foo v0.1.0 ([..]/foo)
288 ├── gitdep v1.0.0 (file://[..]/gitdep#[..])
289 ├── pathdep v1.0.0 ([..]/foo/pathdep)
290 └── regdep v1.0.0
291 ",
292 )
293 .run();
294 }
295
296 #[cargo_test]
297 fn features() {
298 // Exercises a variety of feature behaviors.
299 Package::new("optdep_default", "1.0.0").publish();
300 Package::new("optdep", "1.0.0").publish();
301 let p = project()
302 .file(
303 "Cargo.toml",
304 r#"
305 [package]
306 name = "a"
307 version = "0.1.0"
308
309 [dependencies]
310 optdep_default = { version = "1.0", optional = true }
311 optdep = { version = "1.0", optional = true }
312
313 [features]
314 default = ["optdep_default"]
315 "#,
316 )
317 .file("src/lib.rs", "")
318 .build();
319
320 p.cargo("tree")
321 .with_stdout(
322 "\
323 a v0.1.0 ([..]/foo)
324 └── optdep_default v1.0.0
325 ",
326 )
327 .run();
328
329 p.cargo("tree --no-default-features")
330 .with_stdout(
331 "\
332 a v0.1.0 ([..]/foo)
333 ",
334 )
335 .run();
336
337 p.cargo("tree --all-features")
338 .with_stdout(
339 "\
340 a v0.1.0 ([..]/foo)
341 ├── optdep v1.0.0
342 └── optdep_default v1.0.0
343 ",
344 )
345 .run();
346
347 p.cargo("tree --features optdep")
348 .with_stdout(
349 "\
350 a v0.1.0 ([..]/foo)
351 ├── optdep v1.0.0
352 └── optdep_default v1.0.0
353 ",
354 )
355 .run();
356 }
357
358 #[cargo_test]
359 fn filters_target() {
360 // --target flag
361 if cross_compile::disabled() {
362 return;
363 }
364 Package::new("targetdep", "1.0.0").publish();
365 Package::new("hostdep", "1.0.0").publish();
366 Package::new("devdep", "1.0.0").publish();
367 Package::new("build_target_dep", "1.0.0").publish();
368 Package::new("build_host_dep", "1.0.0")
369 .target_dep("targetdep", "1.0", alternate())
370 .target_dep("hostdep", "1.0", rustc_host())
371 .publish();
372 Package::new("pm_target", "1.0.0")
373 .proc_macro(true)
374 .publish();
375 Package::new("pm_host", "1.0.0").proc_macro(true).publish();
376
377 let p = project()
378 .file(
379 "Cargo.toml",
380 &format!(
381 r#"
382 [package]
383 name = "foo"
384 version = "0.1.0"
385
386 [target.'{alt}'.dependencies]
387 targetdep = "1.0"
388 pm_target = "1.0"
389
390 [target.'{host}'.dependencies]
391 hostdep = "1.0"
392 pm_host = "1.0"
393
394 [target.'{alt}'.dev-dependencies]
395 devdep = "1.0"
396
397 [target.'{alt}'.build-dependencies]
398 build_target_dep = "1.0"
399
400 [target.'{host}'.build-dependencies]
401 build_host_dep = "1.0"
402 "#,
403 alt = alternate(),
404 host = rustc_host()
405 ),
406 )
407 .file("src/lib.rs", "")
408 .file("build.rs", "fn main() {}")
409 .build();
410
411 p.cargo("tree")
412 .with_stdout(
413 "\
414 foo v0.1.0 ([..]/foo)
415 ├── hostdep v1.0.0
416 └── pm_host v1.0.0 (proc-macro)
417 [build-dependencies]
418 └── build_host_dep v1.0.0
419 └── hostdep v1.0.0
420 ",
421 )
422 .run();
423
424 p.cargo("tree --target")
425 .arg(alternate())
426 .with_stdout(
427 "\
428 foo v0.1.0 ([..]/foo)
429 ├── pm_target v1.0.0 (proc-macro)
430 └── targetdep v1.0.0
431 [build-dependencies]
432 └── build_host_dep v1.0.0
433 └── hostdep v1.0.0
434 [dev-dependencies]
435 └── devdep v1.0.0
436 ",
437 )
438 .run();
439
440 p.cargo("tree --target")
441 .arg(rustc_host())
442 .with_stdout(
443 "\
444 foo v0.1.0 ([..]/foo)
445 ├── hostdep v1.0.0
446 └── pm_host v1.0.0 (proc-macro)
447 [build-dependencies]
448 └── build_host_dep v1.0.0
449 └── hostdep v1.0.0
450 ",
451 )
452 .run();
453
454 p.cargo("tree --target=all")
455 .with_stdout(
456 "\
457 foo v0.1.0 ([..]/foo)
458 ├── hostdep v1.0.0
459 ├── pm_host v1.0.0 (proc-macro)
460 ├── pm_target v1.0.0 (proc-macro)
461 └── targetdep v1.0.0
462 [build-dependencies]
463 ├── build_host_dep v1.0.0
464 │ ├── hostdep v1.0.0
465 │ └── targetdep v1.0.0
466 └── build_target_dep v1.0.0
467 [dev-dependencies]
468 └── devdep v1.0.0
469 ",
470 )
471 .run();
472
473 // no-proc-macro
474 p.cargo("tree --target=all -e no-proc-macro")
475 .with_stdout(
476 "\
477 foo v0.1.0 ([..]/foo)
478 ├── hostdep v1.0.0
479 └── targetdep v1.0.0
480 [build-dependencies]
481 ├── build_host_dep v1.0.0
482 │ ├── hostdep v1.0.0
483 │ └── targetdep v1.0.0
484 └── build_target_dep v1.0.0
485 [dev-dependencies]
486 └── devdep v1.0.0
487 ",
488 )
489 .run();
490 }
491
492 #[cargo_test]
493 fn dep_kinds() {
494 Package::new("inner-devdep", "1.0.0").publish();
495 Package::new("inner-builddep", "1.0.0").publish();
496 Package::new("inner-normal", "1.0.0").publish();
497 Package::new("inner-pm", "1.0.0").proc_macro(true).publish();
498 Package::new("inner-buildpm", "1.0.0")
499 .proc_macro(true)
500 .publish();
501 Package::new("normaldep", "1.0.0")
502 .dep("inner-normal", "1.0")
503 .dev_dep("inner-devdep", "1.0")
504 .build_dep("inner-builddep", "1.0")
505 .publish();
506 Package::new("devdep", "1.0.0")
507 .dep("inner-normal", "1.0")
508 .dep("inner-pm", "1.0")
509 .dev_dep("inner-devdep", "1.0")
510 .build_dep("inner-builddep", "1.0")
511 .build_dep("inner-buildpm", "1.0")
512 .publish();
513 Package::new("builddep", "1.0.0")
514 .dep("inner-normal", "1.0")
515 .dev_dep("inner-devdep", "1.0")
516 .build_dep("inner-builddep", "1.0")
517 .publish();
518 let p = project()
519 .file(
520 "Cargo.toml",
521 r#"
522 [package]
523 name = "foo"
524 version = "0.1.0"
525
526 [dependencies]
527 normaldep = "1.0"
528
529 [dev-dependencies]
530 devdep = "1.0"
531
532 [build-dependencies]
533 builddep = "1.0"
534 "#,
535 )
536 .file("src/lib.rs", "")
537 .build();
538
539 p.cargo("tree")
540 .with_stdout(
541 "\
542 foo v0.1.0 ([..]/foo)
543 └── normaldep v1.0.0
544 └── inner-normal v1.0.0
545 [build-dependencies]
546 └── inner-builddep v1.0.0
547 [build-dependencies]
548 └── builddep v1.0.0
549 └── inner-normal v1.0.0
550 [build-dependencies]
551 └── inner-builddep v1.0.0
552 [dev-dependencies]
553 └── devdep v1.0.0
554 ├── inner-normal v1.0.0
555 └── inner-pm v1.0.0 (proc-macro)
556 [build-dependencies]
557 ├── inner-builddep v1.0.0
558 └── inner-buildpm v1.0.0 (proc-macro)
559 ",
560 )
561 .run();
562
563 p.cargo("tree -e no-dev")
564 .with_stdout(
565 "\
566 foo v0.1.0 ([..]/foo)
567 └── normaldep v1.0.0
568 └── inner-normal v1.0.0
569 [build-dependencies]
570 └── inner-builddep v1.0.0
571 [build-dependencies]
572 └── builddep v1.0.0
573 └── inner-normal v1.0.0
574 [build-dependencies]
575 └── inner-builddep v1.0.0
576 ",
577 )
578 .run();
579
580 p.cargo("tree -e normal")
581 .with_stdout(
582 "\
583 foo v0.1.0 ([..]/foo)
584 └── normaldep v1.0.0
585 └── inner-normal v1.0.0
586 ",
587 )
588 .run();
589
590 p.cargo("tree -e dev,build")
591 .with_stdout(
592 "\
593 foo v0.1.0 ([..]/foo)
594 [build-dependencies]
595 └── builddep v1.0.0
596 [build-dependencies]
597 └── inner-builddep v1.0.0
598 [dev-dependencies]
599 └── devdep v1.0.0
600 [build-dependencies]
601 ├── inner-builddep v1.0.0
602 └── inner-buildpm v1.0.0 (proc-macro)
603 ",
604 )
605 .run();
606
607 p.cargo("tree -e dev,build,no-proc-macro")
608 .with_stdout(
609 "\
610 foo v0.1.0 ([..]/foo)
611 [build-dependencies]
612 └── builddep v1.0.0
613 [build-dependencies]
614 └── inner-builddep v1.0.0
615 [dev-dependencies]
616 └── devdep v1.0.0
617 [build-dependencies]
618 └── inner-builddep v1.0.0
619 ",
620 )
621 .run();
622 }
623
624 #[cargo_test]
625 fn cyclic_dev_dep() {
626 // Cyclical dev-dependency and inverse flag.
627 let p = project()
628 .file(
629 "Cargo.toml",
630 r#"
631 [package]
632 name = "foo"
633 version = "0.1.0"
634
635 [dev-dependencies]
636 dev-dep = { path = "dev-dep" }
637 "#,
638 )
639 .file("src/lib.rs", "")
640 .file(
641 "dev-dep/Cargo.toml",
642 r#"
643 [package]
644 name = "dev-dep"
645 version = "0.1.0"
646
647 [dependencies]
648 foo = { path=".." }
649 "#,
650 )
651 .file("dev-dep/src/lib.rs", "")
652 .build();
653
654 p.cargo("tree")
655 .with_stdout(
656 "\
657 foo v0.1.0 ([..]/foo)
658 [dev-dependencies]
659 └── dev-dep v0.1.0 ([..]/foo/dev-dep)
660 └── foo v0.1.0 ([..]/foo) (*)
661 ",
662 )
663 .run();
664
665 p.cargo("tree --invert foo")
666 .with_stdout(
667 "\
668 foo v0.1.0 ([..]/foo)
669 └── dev-dep v0.1.0 ([..]/foo/dev-dep)
670 [dev-dependencies]
671 └── foo v0.1.0 ([..]/foo) (*)
672 ",
673 )
674 .run();
675 }
676
677 #[cargo_test]
678 fn invert() {
679 Package::new("b1", "1.0.0").dep("c", "1.0").publish();
680 Package::new("b2", "1.0.0").dep("d", "1.0").publish();
681 Package::new("c", "1.0.0").publish();
682 Package::new("d", "1.0.0").publish();
683 let p = project()
684 .file(
685 "Cargo.toml",
686 r#"
687 [package]
688 name = "foo"
689 version = "0.1.0"
690
691 [dependencies]
692 b1 = "1.0"
693 b2 = "1.0"
694 c = "1.0"
695 "#,
696 )
697 .file("src/lib.rs", "")
698 .build();
699
700 p.cargo("tree")
701 .with_stdout(
702 "\
703 foo v0.1.0 ([..]/foo)
704 ├── b1 v1.0.0
705 │ └── c v1.0.0
706 ├── b2 v1.0.0
707 │ └── d v1.0.0
708 └── c v1.0.0
709 ",
710 )
711 .run();
712
713 p.cargo("tree --invert c")
714 .with_stdout(
715 "\
716 c v1.0.0
717 ├── b1 v1.0.0
718 │ └── foo v0.1.0 ([..]/foo)
719 └── foo v0.1.0 ([..]/foo)
720 ",
721 )
722 .run();
723 }
724
725 #[cargo_test]
726 fn invert_with_build_dep() {
727 // -i for a common dependency between normal and build deps.
728 Package::new("common", "1.0.0").publish();
729 Package::new("bdep", "1.0.0").dep("common", "1.0").publish();
730 let p = project()
731 .file(
732 "Cargo.toml",
733 r#"
734 [package]
735 name = "foo"
736 version = "0.1.0"
737
738 [dependencies]
739 common = "1.0"
740
741 [build-dependencies]
742 bdep = "1.0"
743 "#,
744 )
745 .file("src/lib.rs", "")
746 .build();
747
748 p.cargo("tree")
749 .with_stdout(
750 "\
751 foo v0.1.0 ([..]/foo)
752 └── common v1.0.0
753 [build-dependencies]
754 └── bdep v1.0.0
755 └── common v1.0.0
756 ",
757 )
758 .run();
759
760 p.cargo("tree -i common")
761 .with_stdout(
762 "\
763 common v1.0.0
764 ├── bdep v1.0.0
765[build-dependencies]
766 │ └── foo v0.1.0 ([..]/foo)
767 └── foo v0.1.0 ([..]/foo)
768 ",
769 )
770 .run();
771 }
772
773 #[cargo_test]
774 fn no_indent() {
775 let p = make_simple_proj();
776
777 p.cargo("tree --prefix=none")
778 .with_stdout(
779 "\
780 foo v0.1.0 ([..]/foo)
781 a v1.0.0
782 b v1.0.0
783 c v1.0.0
784 c v1.0.0
785 bdep v1.0.0
786 b v1.0.0 (*)
787 devdep v1.0.0
788 b v1.0.0 (*)
789 ",
790 )
791 .run();
792 }
793
794 #[cargo_test]
795 fn prefix_depth() {
796 let p = make_simple_proj();
797
798 p.cargo("tree --prefix=depth")
799 .with_stdout(
800 "\
801 0foo v0.1.0 ([..]/foo)
802 1a v1.0.0
803 2b v1.0.0
804 3c v1.0.0
805 1c v1.0.0
806 1bdep v1.0.0
807 2b v1.0.0 (*)
808 1devdep v1.0.0
809 2b v1.0.0 (*)
810 ",
811 )
812 .run();
813 }
814
815 #[cargo_test]
816 fn no_dedupe() {
817 let p = make_simple_proj();
818
819 p.cargo("tree --no-dedupe")
820 .with_stdout(
821 "\
822 foo v0.1.0 ([..]/foo)
823 ├── a v1.0.0
824 │ └── b v1.0.0
825 │ └── c v1.0.0
826 └── c v1.0.0
827 [build-dependencies]
828 └── bdep v1.0.0
829 └── b v1.0.0
830 └── c v1.0.0
831 [dev-dependencies]
832 └── devdep v1.0.0
833 └── b v1.0.0
834 └── c v1.0.0
835 ",
836 )
837 .run();
838 }
839
840 #[cargo_test]
841 fn no_dedupe_cycle() {
842 // --no-dedupe with a dependency cycle
843 let p = project()
844 .file(
845 "Cargo.toml",
846 r#"
847 [package]
848 name = "foo"
849 version = "0.1.0"
850
851 [dev-dependencies]
852 bar = {path = "bar"}
853 "#,
854 )
855 .file("src/lib.rs", "")
856 .file(
857 "bar/Cargo.toml",
858 r#"
859 [package]
860 name = "bar"
861 version = "0.1.0"
862
863 [dependencies]
864 foo = {path=".."}
865 "#,
866 )
867 .file("bar/src/lib.rs", "")
868 .build();
869
870 p.cargo("tree")
871 .with_stdout(
872 "\
873 foo v0.1.0 ([..]/foo)
874 [dev-dependencies]
875 └── bar v0.1.0 ([..]/foo/bar)
876 └── foo v0.1.0 ([..]/foo) (*)
877 ",
878 )
879 .run();
880
881 p.cargo("tree --no-dedupe")
882 .with_stdout(
883 "\
884 foo v0.1.0 ([..]/foo)
885 [dev-dependencies]
886 └── bar v0.1.0 ([..]/foo/bar)
887 └── foo v0.1.0 ([..]/foo) (*)
888 ",
889 )
890 .run();
891 }
892
893 #[cargo_test]
894 fn duplicates() {
895 Package::new("dog", "1.0.0").publish();
896 Package::new("dog", "2.0.0").publish();
897 Package::new("cat", "1.0.0").publish();
898 Package::new("cat", "2.0.0").publish();
899 Package::new("dep", "1.0.0")
900 .dep("dog", "1.0")
901 .dep("cat", "1.0")
902 .publish();
903 let p = project()
904 .file(
905 "Cargo.toml",
906 r#"
907 [workspace]
908 members = ["a", "b"]
909 "#,
910 )
911 .file(
912 "a/Cargo.toml",
913 r#"
914 [package]
915 name = "a"
916 version = "0.1.0"
917
918 [dependencies]
919 dog1 = { version = "1.0", package = "dog" }
920 dog2 = { version = "2.0", package = "dog" }
921 "#,
922 )
923 .file("a/src/lib.rs", "")
924 .file(
925 "b/Cargo.toml",
926 r#"
927 [package]
928 name = "b"
929 version = "0.1.0"
930
931 [dependencies]
932 dep = "1.0"
933 cat = "2.0"
934 "#,
935 )
936 .file("b/src/lib.rs", "")
937 .build();
938
939 p.cargo("tree -p a")
940 .with_stdout(
941 "\
942 a v0.1.0 ([..]/foo/a)
943 ├── dog v1.0.0
944 └── dog v2.0.0
945 ",
946 )
947 .run();
948
949 p.cargo("tree -p b")
950 .with_stdout(
951 "\
952 b v0.1.0 ([..]/foo/b)
953 ├── cat v2.0.0
954 └── dep v1.0.0
955 ├── cat v1.0.0
956 └── dog v1.0.0
957 ",
958 )
959 .run();
960
961 p.cargo("tree -p a -d")
962 .with_stdout(
963 "\
964 dog v1.0.0
965 └── a v0.1.0 ([..]/foo/a)
966
967 dog v2.0.0
968 └── a v0.1.0 ([..]/foo/a)
969 ",
970 )
971 .run();
972
973 p.cargo("tree -p b -d")
974 .with_stdout(
975 "\
976 cat v1.0.0
977 └── dep v1.0.0
978 └── b v0.1.0 ([..]/foo/b)
979
980 cat v2.0.0
981 └── b v0.1.0 ([..]/foo/b)
982 ",
983 )
984 .run();
985 }
986
987 #[cargo_test]
988 fn charset() {
989 let p = make_simple_proj();
990 p.cargo("tree --charset ascii")
991 .with_stdout(
992 "\
993 foo v0.1.0 ([..]/foo)
994 |-- a v1.0.0
995 | `-- b v1.0.0
996 | `-- c v1.0.0
997 `-- c v1.0.0
998 [build-dependencies]
999 `-- bdep v1.0.0
1000 `-- b v1.0.0 (*)
1001 [dev-dependencies]
1002 `-- devdep v1.0.0
1003 `-- b v1.0.0 (*)
1004 ",
1005 )
1006 .run();
1007 }
1008
1009 #[cargo_test]
1010 fn format() {
1011 Package::new("dep", "1.0.0").publish();
1012 let p = project()
1013 .file(
1014 "Cargo.toml",
1015 r#"
1016 [package]
1017 name = "foo"
1018 version = "0.1.0"
1019 license = "MIT"
1020 repository = "https://github.com/rust-lang/cargo"
1021
1022 [dependencies]
1023 dep = {version="1.0", optional=true}
1024
1025 [features]
1026 default = ["foo"]
1027 foo = ["bar"]
1028 bar = []
1029 "#,
1030 )
1031 .file("src/lib.rs", "")
1032 .build();
1033
1034 p.cargo("tree --format <<<{p}>>>")
1035 .with_stdout("<<<foo v0.1.0 ([..]/foo)>>>")
1036 .run();
1037
1038 p.cargo("tree --format {}")
1039 .with_stderr(
1040 "\
1041 [ERROR] tree format `{}` not valid
1042
1043 Caused by:
1044 unsupported pattern ``
1045 ",
1046 )
1047 .with_status(101)
1048 .run();
1049
1050 p.cargo("tree --format {p}-{{hello}}")
1051 .with_stdout("foo v0.1.0 ([..]/foo)-{hello}")
1052 .run();
1053
1054 p.cargo("tree --format")
1055 .arg("{p} {l} {r}")
1056 .with_stdout("foo v0.1.0 ([..]/foo) MIT https://github.com/rust-lang/cargo")
1057 .run();
1058
1059 p.cargo("tree --format")
1060 .arg("{p} {f}")
1061 .with_stdout("foo v0.1.0 ([..]/foo) bar,default,foo")
1062 .run();
1063
1064 p.cargo("tree --all-features --format")
1065 .arg("{p} [{f}]")
1066 .with_stdout(
1067 "\
1068 foo v0.1.0 ([..]/foo) [bar,default,dep,foo]
1069 └── dep v1.0.0 []
1070 ",
1071 )
1072 .run();
1073 }
1074
1075 #[cargo_test]
1076 fn dev_dep_feature() {
1077 // New feature resolver with optional dep
1078 Package::new("optdep", "1.0.0").publish();
1079 Package::new("bar", "1.0.0")
1080 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1081 .publish();
1082 let p = project()
1083 .file(
1084 "Cargo.toml",
1085 r#"
1086 [package]
1087 name = "foo"
1088 version = "0.1.0"
1089
1090 [dev-dependencies]
1091 bar = { version = "1.0", features = ["optdep"] }
1092
1093 [dependencies]
1094 bar = "1.0"
1095 "#,
1096 )
1097 .file("src/lib.rs", "")
1098 .build();
1099
1100 // Old behavior.
1101 p.cargo("tree")
1102 .with_stdout(
1103 "\
1104 foo v0.1.0 ([..]/foo)
1105 └── bar v1.0.0
1106 └── optdep v1.0.0
1107 [dev-dependencies]
1108 └── bar v1.0.0 (*)
1109 ",
1110 )
1111 .run();
1112
1113 p.cargo("tree -e normal")
1114 .with_stdout(
1115 "\
1116 foo v0.1.0 ([..]/foo)
1117 └── bar v1.0.0
1118 └── optdep v1.0.0
1119 ",
1120 )
1121 .run();
1122
1123 // New behavior.
1124 switch_to_resolver_2(&p);
1125
1126 p.cargo("tree")
1127 .with_stdout(
1128 "\
1129 foo v0.1.0 ([..]/foo)
1130 └── bar v1.0.0
1131 └── optdep v1.0.0
1132 [dev-dependencies]
1133 └── bar v1.0.0 (*)
1134 ",
1135 )
1136 .run();
1137
1138 p.cargo("tree -e normal")
1139 .with_stdout(
1140 "\
1141 foo v0.1.0 ([..]/foo)
1142 └── bar v1.0.0
1143 ",
1144 )
1145 .run();
1146 }
1147
1148 #[cargo_test]
1149 fn host_dep_feature() {
1150 // New feature resolver with optional build dep
1151 Package::new("optdep", "1.0.0").publish();
1152 Package::new("bar", "1.0.0")
1153 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1154 .publish();
1155 let p = project()
1156 .file(
1157 "Cargo.toml",
1158 r#"
1159 [package]
1160 name = "foo"
1161 version = "0.1.0"
1162
1163 [build-dependencies]
1164 bar = { version = "1.0", features = ["optdep"] }
1165
1166 [dependencies]
1167 bar = "1.0"
1168 "#,
1169 )
1170 .file("src/lib.rs", "")
1171 .file("build.rs", "fn main() {}")
1172 .build();
1173
1174 // Old behavior
1175 p.cargo("tree")
1176 .with_stdout(
1177 "\
1178 foo v0.1.0 ([..]/foo)
1179 └── bar v1.0.0
1180 └── optdep v1.0.0
1181 [build-dependencies]
1182 └── bar v1.0.0 (*)
1183 ",
1184 )
1185 .run();
1186
1187 // -p
1188 p.cargo("tree -p bar")
1189 .with_stdout(
1190 "\
1191 bar v1.0.0
1192 └── optdep v1.0.0
1193 ",
1194 )
1195 .run();
1196
1197 // invert
1198 p.cargo("tree -i optdep")
1199 .with_stdout(
1200 "\
1201 optdep v1.0.0
1202 └── bar v1.0.0
1203 └── foo v0.1.0 ([..]/foo)
1204 [build-dependencies]
1205 └── foo v0.1.0 ([..]/foo)
1206 ",
1207 )
1208 .run();
1209
1210 // New behavior.
1211 switch_to_resolver_2(&p);
1212
1213 p.cargo("tree")
1214 .with_stdout(
1215 "\
1216 foo v0.1.0 ([..]/foo)
1217 └── bar v1.0.0
1218 [build-dependencies]
1219 └── bar v1.0.0
1220 └── optdep v1.0.0
1221 ",
1222 )
1223 .run();
1224
1225 p.cargo("tree -p bar")
1226 .with_stdout(
1227 "\
1228 bar v1.0.0
1229
1230 bar v1.0.0
1231 └── optdep v1.0.0
1232 ",
1233 )
1234 .run();
1235
1236 p.cargo("tree -i optdep")
1237 .with_stdout(
1238 "\
1239 optdep v1.0.0
1240 └── bar v1.0.0
1241 [build-dependencies]
1242 └── foo v0.1.0 ([..]/foo)
1243 ",
1244 )
1245 .run();
1246
1247 // Check that -d handles duplicates with features.
1248 p.cargo("tree -d")
1249 .with_stdout(
1250 "\
1251 bar v1.0.0
1252 └── foo v0.1.0 ([..]/foo)
1253
1254 bar v1.0.0
1255 [build-dependencies]
1256 └── foo v0.1.0 ([..]/foo)
1257 ",
1258 )
1259 .run();
1260 }
1261
1262 #[cargo_test]
1263 fn proc_macro_features() {
1264 // New feature resolver with a proc-macro
1265 Package::new("optdep", "1.0.0").publish();
1266 Package::new("somedep", "1.0.0")
1267 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1268 .publish();
1269 Package::new("pm", "1.0.0")
1270 .proc_macro(true)
1271 .feature_dep("somedep", "1.0", &["optdep"])
1272 .publish();
1273 let p = project()
1274 .file(
1275 "Cargo.toml",
1276 r#"
1277 [package]
1278 name = "foo"
1279 version = "0.1.0"
1280
1281 [dependencies]
1282 pm = "1.0"
1283 somedep = "1.0"
1284 "#,
1285 )
1286 .file("src/lib.rs", "")
1287 .build();
1288
1289 // Old behavior
1290 p.cargo("tree")
1291 .with_stdout(
1292 "\
1293 foo v0.1.0 ([..]/foo)
1294 ├── pm v1.0.0 (proc-macro)
1295 │ └── somedep v1.0.0
1296 │ └── optdep v1.0.0
1297 └── somedep v1.0.0 (*)
1298 ",
1299 )
1300 .run();
1301
1302 // Old behavior + no-proc-macro
1303 p.cargo("tree -e no-proc-macro")
1304 .with_stdout(
1305 "\
1306 foo v0.1.0 ([..]/foo)
1307 └── somedep v1.0.0
1308 └── optdep v1.0.0
1309 ",
1310 )
1311 .run();
1312
1313 // -p
1314 p.cargo("tree -p somedep")
1315 .with_stdout(
1316 "\
1317 somedep v1.0.0
1318 └── optdep v1.0.0
1319 ",
1320 )
1321 .run();
1322
1323 // -p -e no-proc-macro
1324 p.cargo("tree -p somedep -e no-proc-macro")
1325 .with_stdout(
1326 "\
1327 somedep v1.0.0
1328 └── optdep v1.0.0
1329 ",
1330 )
1331 .run();
1332
1333 // invert
1334 p.cargo("tree -i somedep")
1335 .with_stdout(
1336 "\
1337 somedep v1.0.0
1338 ├── foo v0.1.0 ([..]/foo)
1339 └── pm v1.0.0 (proc-macro)
1340 └── foo v0.1.0 ([..]/foo)
1341 ",
1342 )
1343 .run();
1344
1345 // invert + no-proc-macro
1346 p.cargo("tree -i somedep -e no-proc-macro")
1347 .with_stdout(
1348 "\
1349 somedep v1.0.0
1350 └── foo v0.1.0 ([..]/foo)
1351 ",
1352 )
1353 .run();
1354
1355 // New behavior.
1356 switch_to_resolver_2(&p);
1357
1358 // Note the missing (*)
1359 p.cargo("tree")
1360 .with_stdout(
1361 "\
1362 foo v0.1.0 ([..]/foo)
1363 ├── pm v1.0.0 (proc-macro)
1364 │ └── somedep v1.0.0
1365 │ └── optdep v1.0.0
1366 └── somedep v1.0.0
1367 ",
1368 )
1369 .run();
1370
1371 p.cargo("tree -e no-proc-macro")
1372 .with_stdout(
1373 "\
1374 foo v0.1.0 ([..]/foo)
1375 └── somedep v1.0.0
1376 ",
1377 )
1378 .run();
1379
1380 p.cargo("tree -p somedep")
1381 .with_stdout(
1382 "\
1383 somedep v1.0.0
1384
1385 somedep v1.0.0
1386 └── optdep v1.0.0
1387 ",
1388 )
1389 .run();
1390
1391 p.cargo("tree -i somedep")
1392 .with_stdout(
1393 "\
1394 somedep v1.0.0
1395 └── foo v0.1.0 ([..]/foo)
1396
1397 somedep v1.0.0
1398 └── pm v1.0.0 (proc-macro)
1399 └── foo v0.1.0 ([..]/foo)
1400 ",
1401 )
1402 .run();
1403
1404 p.cargo("tree -i somedep -e no-proc-macro")
1405 .with_stdout(
1406 "\
1407 somedep v1.0.0
1408 └── foo v0.1.0 ([..]/foo)
1409
1410 somedep v1.0.0
1411 ",
1412 )
1413 .run();
1414 }
1415
1416 #[cargo_test]
1417 fn itarget_opt_dep() {
1418 // New feature resolver with optional target dep
1419 Package::new("optdep", "1.0.0").publish();
1420 Package::new("common", "1.0.0")
1421 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1422 .publish();
1423
1424 let p = project()
1425 .file(
1426 "Cargo.toml",
1427 r#"
1428 [package]
1429 name = "foo"
1430 version = "1.0.0"
1431
1432 [dependencies]
1433 common = "1.0"
1434
1435 [target.'cfg(whatever)'.dependencies]
1436 common = { version = "1.0", features = ["optdep"] }
1437
1438 "#,
1439 )
1440 .file("src/lib.rs", "")
1441 .build();
1442
1443 // Old behavior
1444 p.cargo("tree")
1445 .with_stdout(
1446 "\
1447 foo v1.0.0 ([..]/foo)
1448 └── common v1.0.0
1449 └── optdep v1.0.0
1450 ",
1451 )
1452 .run();
1453
1454 // New behavior.
1455 switch_to_resolver_2(&p);
1456
1457 p.cargo("tree")
1458 .with_stdout(
1459 "\
1460 foo v1.0.0 ([..]/foo)
1461 └── common v1.0.0
1462 ",
1463 )
1464 .run();
1465 }
1466
1467 #[cargo_test]
1468 fn ambiguous_name() {
1469 // -p that is ambiguous.
1470 Package::new("dep", "1.0.0").publish();
1471 Package::new("dep", "2.0.0").publish();
1472 Package::new("bar", "1.0.0").dep("dep", "2.0").publish();
1473 let p = project()
1474 .file(
1475 "Cargo.toml",
1476 r#"
1477 [package]
1478 name = "foo"
1479 version = "0.1.0"
1480
1481 [dependencies]
1482 dep = "1.0"
1483 bar = "1.0"
1484 "#,
1485 )
1486 .file("src/lib.rs", "")
1487 .build();
1488
1489 p.cargo("tree -p dep")
1490 .with_stderr_contains(
1491 "\
1492 error: There are multiple `dep` packages in your project, and the specification `dep` is ambiguous.
1493 Please re-run this command with `-p <spec>` where `<spec>` is one of the following:
1494 dep:1.0.0
1495 dep:2.0.0
1496 ",
1497 )
1498 .with_status(101)
1499 .run();
1500 }
1501
1502 #[cargo_test]
1503 fn workspace_features_are_local() {
1504 // The features for workspace packages should be the same as `cargo build`
1505 // (i.e., the features selected depend on the "current" package).
1506 Package::new("optdep", "1.0.0").publish();
1507 Package::new("somedep", "1.0.0")
1508 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1509 .publish();
1510 let p = project()
1511 .file(
1512 "Cargo.toml",
1513 r#"
1514 [workspace]
1515 members = ["a", "b"]
1516 "#,
1517 )
1518 .file(
1519 "a/Cargo.toml",
1520 r#"
1521 [package]
1522 name = "a"
1523 version = "0.1.0"
1524
1525 [dependencies]
1526 somedep = {version="1.0", features=["optdep"]}
1527 "#,
1528 )
1529 .file("a/src/lib.rs", "")
1530 .file(
1531 "b/Cargo.toml",
1532 r#"
1533 [package]
1534 name = "b"
1535 version = "0.1.0"
1536
1537 [dependencies]
1538 somedep = "1.0"
1539 "#,
1540 )
1541 .file("b/src/lib.rs", "")
1542 .build();
1543
1544 p.cargo("tree")
1545 .with_stdout(
1546 "\
1547 a v0.1.0 ([..]/foo/a)
1548 └── somedep v1.0.0
1549 └── optdep v1.0.0
1550
1551 b v0.1.0 ([..]/foo/b)
1552 └── somedep v1.0.0 (*)
1553 ",
1554 )
1555 .run();
1556
1557 p.cargo("tree -p a")
1558 .with_stdout(
1559 "\
1560 a v0.1.0 ([..]/foo/a)
1561 └── somedep v1.0.0
1562 └── optdep v1.0.0
1563 ",
1564 )
1565 .run();
1566
1567 p.cargo("tree -p b")
1568 .with_stdout(
1569 "\
1570 b v0.1.0 ([..]/foo/b)
1571 └── somedep v1.0.0
1572 ",
1573 )
1574 .run();
1575 }
1576
1577 #[cargo_test]
1578 fn unknown_edge_kind() {
1579 let p = project()
1580 .file("Cargo.toml", "")
1581 .file("src/lib.rs", "")
1582 .build();
1583
1584 p.cargo("tree -e unknown")
1585 .with_stderr(
1586 "\
1587 [ERROR] unknown edge kind `unknown`, valid values are \
1588 \"normal\", \"build\", \"dev\", \
1589 \"no-normal\", \"no-build\", \"no-dev\", \"no-proc-macro\", \
1590 \"features\", or \"all\"
1591 ",
1592 )
1593 .with_status(101)
1594 .run();
1595 }
1596
1597 #[cargo_test]
1598 fn mixed_no_edge_kinds() {
1599 let p = project()
1600 .file(
1601 "Cargo.toml",
1602 r#"
1603 [package]
1604 name = "foo"
1605 version = "0.1.0"
1606 "#,
1607 )
1608 .file("src/lib.rs", "")
1609 .build();
1610
1611 p.cargo("tree -e no-build,normal")
1612 .with_stderr(
1613 "\
1614 [ERROR] `normal` dependency kind cannot be mixed with \
1615 \"no-normal\", \"no-build\", or \"no-dev\" dependency kinds
1616 ",
1617 )
1618 .with_status(101)
1619 .run();
1620
1621 // `no-proc-macro` can be mixed with others
1622 p.cargo("tree -e no-proc-macro,normal")
1623 .with_stdout(
1624 "\
1625 foo v0.1.0 ([..]/foo)
1626 ",
1627 )
1628 .run();
1629 }
1630
1631 #[cargo_test]
1632 fn depth_limit() {
1633 let p = make_simple_proj();
1634
1635 p.cargo("tree --depth 0")
1636 .with_stdout(
1637 "\
1638 foo v0.1.0 ([..]/foo)
1639 [build-dependencies]
1640 [dev-dependencies]
1641 ",
1642 )
1643 .run();
1644
1645 p.cargo("tree --depth 1")
1646 .with_stdout(
1647 "\
1648 foo v0.1.0 ([..]/foo)
1649 ├── a v1.0.0
1650 └── c v1.0.0
1651 [build-dependencies]
1652 └── bdep v1.0.0
1653 [dev-dependencies]
1654 └── devdep v1.0.0
1655 ",
1656 )
1657 .run();
1658
1659 p.cargo("tree --depth 2")
1660 .with_stdout(
1661 "\
1662 foo v0.1.0 ([..]/foo)
1663 ├── a v1.0.0
1664 │ └── b v1.0.0
1665 └── c v1.0.0
1666 [build-dependencies]
1667 └── bdep v1.0.0
1668 └── b v1.0.0 (*)
1669 [dev-dependencies]
1670 └── devdep v1.0.0
1671 └── b v1.0.0 (*)
1672 ",
1673 )
1674 .run();
1675
1676 // specify a package
1677 p.cargo("tree -p bdep --depth 1")
1678 .with_stdout(
1679 "\
1680 bdep v1.0.0
1681 └── b v1.0.0
1682 ",
1683 )
1684 .run();
1685
1686 // different prefix
1687 p.cargo("tree --depth 1 --prefix depth")
1688 .with_stdout(
1689 "\
1690 0foo v0.1.0 ([..]/foo)
1691 1a v1.0.0
1692 1c v1.0.0
1693 1bdep v1.0.0
1694 1devdep v1.0.0
1695 ",
1696 )
1697 .run();
1698
1699 // with edge-kinds
1700 p.cargo("tree --depth 1 -e no-dev")
1701 .with_stdout(
1702 "\
1703 foo v0.1.0 ([..]/foo)
1704 ├── a v1.0.0
1705 └── c v1.0.0
1706 [build-dependencies]
1707 └── bdep v1.0.0
1708 ",
1709 )
1710 .run();
1711
1712 // invert
1713 p.cargo("tree --depth 1 --invert c")
1714 .with_stdout(
1715 "\
1716 c v1.0.0
1717 ├── b v1.0.0
1718 └── foo v0.1.0 ([..]/foo)
1719 ",
1720 )
1721 .run();
1722 }
1723
1724 #[cargo_test]
1725 fn prune() {
1726 let p = make_simple_proj();
1727
1728 p.cargo("tree --prune c")
1729 .with_stdout(
1730 "\
1731 foo v0.1.0 ([..]/foo)
1732 └── a v1.0.0
1733 └── b v1.0.0
1734 [build-dependencies]
1735 └── bdep v1.0.0
1736 └── b v1.0.0 (*)
1737 [dev-dependencies]
1738 └── devdep v1.0.0
1739 └── b v1.0.0 (*)
1740 ",
1741 )
1742 .run();
1743
1744 // multiple prune
1745 p.cargo("tree --prune c --prune bdep")
1746 .with_stdout(
1747 "\
1748 foo v0.1.0 ([..]/foo)
1749 └── a v1.0.0
1750 └── b v1.0.0
1751 [build-dependencies]
1752 [dev-dependencies]
1753 └── devdep v1.0.0
1754 └── b v1.0.0 (*)
1755 ",
1756 )
1757 .run();
1758
1759 // with edge-kinds
1760 p.cargo("tree --prune c -e normal")
1761 .with_stdout(
1762 "\
1763 foo v0.1.0 ([..]/foo)
1764 └── a v1.0.0
1765 └── b v1.0.0
1766 ",
1767 )
1768 .run();
1769
1770 // pruning self does not works
1771 p.cargo("tree --prune foo")
1772 .with_stdout(
1773 "\
1774 foo v0.1.0 ([..]/foo)
1775 ├── a v1.0.0
1776 │ └── b v1.0.0
1777 │ └── c v1.0.0
1778 └── c v1.0.0
1779 [build-dependencies]
1780 └── bdep v1.0.0
1781 └── b v1.0.0 (*)
1782 [dev-dependencies]
1783 └── devdep v1.0.0
1784 └── b v1.0.0 (*)
1785 ",
1786 )
1787 .run();
1788
1789 // dep not exist
1790 p.cargo("tree --prune no-dep")
1791 .with_stderr(
1792 "\
1793 [ERROR] package ID specification `no-dep` did not match any packages
1794
1795 <tab>Did you mean `bdep`?
1796 ",
1797 )
1798 .with_status(101)
1799 .run();
1800 }