]> git.proxmox.com Git - cargo.git/blob - tests/testsuite/tree.rs
`cargo tree`: Fix stack overflow on cyclic features.
[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 Package::new("other-dep", "1.0.0").publish();
1013
1014 Package::new("dep_that_is_awesome", "1.0.0")
1015 .file(
1016 "Cargo.toml",
1017 r#"
1018 [package]
1019 name = "dep_that_is_awesome"
1020 version = "1.0.0"
1021
1022 [lib]
1023 name = "awesome_dep"
1024 "#,
1025 )
1026 .file("src/lib.rs", "pub struct Straw;")
1027 .publish();
1028
1029 let p = project()
1030 .file(
1031 "Cargo.toml",
1032 r#"
1033 [package]
1034 name = "foo"
1035 version = "0.1.0"
1036 license = "MIT"
1037 repository = "https://github.com/rust-lang/cargo"
1038
1039 [dependencies]
1040 dep = {version="1.0", optional=true}
1041 other-dep = {version="1.0", optional=true}
1042 dep_that_is_awesome = {version="1.0", optional=true}
1043
1044
1045 [features]
1046 default = ["foo"]
1047 foo = ["bar"]
1048 bar = []
1049 "#,
1050 )
1051 .file("src/main.rs", "")
1052 .build();
1053
1054 p.cargo("tree --format <<<{p}>>>")
1055 .with_stdout("<<<foo v0.1.0 ([..]/foo)>>>")
1056 .run();
1057
1058 p.cargo("tree --format {}")
1059 .with_stderr(
1060 "\
1061 [ERROR] tree format `{}` not valid
1062
1063 Caused by:
1064 unsupported pattern ``
1065 ",
1066 )
1067 .with_status(101)
1068 .run();
1069
1070 p.cargo("tree --format {p}-{{hello}}")
1071 .with_stdout("foo v0.1.0 ([..]/foo)-{hello}")
1072 .run();
1073
1074 p.cargo("tree --format")
1075 .arg("{p} {l} {r}")
1076 .with_stdout("foo v0.1.0 ([..]/foo) MIT https://github.com/rust-lang/cargo")
1077 .run();
1078
1079 p.cargo("tree --format")
1080 .arg("{p} {f}")
1081 .with_stdout("foo v0.1.0 ([..]/foo) bar,default,foo")
1082 .run();
1083
1084 p.cargo("tree --all-features --format")
1085 .arg("{p} [{f}]")
1086 .with_stdout(
1087 "\
1088 foo v0.1.0 ([..]/foo) [bar,default,dep,dep_that_is_awesome,foo,other-dep]
1089 ├── dep v1.0.0 []
1090 ├── dep_that_is_awesome v1.0.0 []
1091 └── other-dep v1.0.0 []
1092 ",
1093 )
1094 .run();
1095
1096 p.cargo("tree")
1097 .arg("--features=other-dep,dep_that_is_awesome")
1098 .arg("--format={lib}")
1099 .with_stdout(
1100 "
1101 ├── awesome_dep
1102 └── other_dep
1103 ",
1104 )
1105 .run();
1106 }
1107
1108 #[cargo_test]
1109 fn dev_dep_feature() {
1110 // New feature resolver with optional dep
1111 Package::new("optdep", "1.0.0").publish();
1112 Package::new("bar", "1.0.0")
1113 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1114 .publish();
1115 let p = project()
1116 .file(
1117 "Cargo.toml",
1118 r#"
1119 [package]
1120 name = "foo"
1121 version = "0.1.0"
1122
1123 [dev-dependencies]
1124 bar = { version = "1.0", features = ["optdep"] }
1125
1126 [dependencies]
1127 bar = "1.0"
1128 "#,
1129 )
1130 .file("src/lib.rs", "")
1131 .build();
1132
1133 // Old behavior.
1134 p.cargo("tree")
1135 .with_stdout(
1136 "\
1137 foo v0.1.0 ([..]/foo)
1138 └── bar v1.0.0
1139 └── optdep v1.0.0
1140 [dev-dependencies]
1141 └── bar v1.0.0 (*)
1142 ",
1143 )
1144 .run();
1145
1146 p.cargo("tree -e normal")
1147 .with_stdout(
1148 "\
1149 foo v0.1.0 ([..]/foo)
1150 └── bar v1.0.0
1151 └── optdep v1.0.0
1152 ",
1153 )
1154 .run();
1155
1156 // New behavior.
1157 switch_to_resolver_2(&p);
1158
1159 p.cargo("tree")
1160 .with_stdout(
1161 "\
1162 foo v0.1.0 ([..]/foo)
1163 └── bar v1.0.0
1164 └── optdep v1.0.0
1165 [dev-dependencies]
1166 └── bar v1.0.0 (*)
1167 ",
1168 )
1169 .run();
1170
1171 p.cargo("tree -e normal")
1172 .with_stdout(
1173 "\
1174 foo v0.1.0 ([..]/foo)
1175 └── bar v1.0.0
1176 ",
1177 )
1178 .run();
1179 }
1180
1181 #[cargo_test]
1182 fn host_dep_feature() {
1183 // New feature resolver with optional build dep
1184 Package::new("optdep", "1.0.0").publish();
1185 Package::new("bar", "1.0.0")
1186 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1187 .publish();
1188 let p = project()
1189 .file(
1190 "Cargo.toml",
1191 r#"
1192 [package]
1193 name = "foo"
1194 version = "0.1.0"
1195
1196 [build-dependencies]
1197 bar = { version = "1.0", features = ["optdep"] }
1198
1199 [dependencies]
1200 bar = "1.0"
1201 "#,
1202 )
1203 .file("src/lib.rs", "")
1204 .file("build.rs", "fn main() {}")
1205 .build();
1206
1207 // Old behavior
1208 p.cargo("tree")
1209 .with_stdout(
1210 "\
1211 foo v0.1.0 ([..]/foo)
1212 └── bar v1.0.0
1213 └── optdep v1.0.0
1214 [build-dependencies]
1215 └── bar v1.0.0 (*)
1216 ",
1217 )
1218 .run();
1219
1220 // -p
1221 p.cargo("tree -p bar")
1222 .with_stdout(
1223 "\
1224 bar v1.0.0
1225 └── optdep v1.0.0
1226 ",
1227 )
1228 .run();
1229
1230 // invert
1231 p.cargo("tree -i optdep")
1232 .with_stdout(
1233 "\
1234 optdep v1.0.0
1235 └── bar v1.0.0
1236 └── foo v0.1.0 ([..]/foo)
1237 [build-dependencies]
1238 └── foo v0.1.0 ([..]/foo)
1239 ",
1240 )
1241 .run();
1242
1243 // New behavior.
1244 switch_to_resolver_2(&p);
1245
1246 p.cargo("tree")
1247 .with_stdout(
1248 "\
1249 foo v0.1.0 ([..]/foo)
1250 └── bar v1.0.0
1251 [build-dependencies]
1252 └── bar v1.0.0
1253 └── optdep v1.0.0
1254 ",
1255 )
1256 .run();
1257
1258 p.cargo("tree -p bar")
1259 .with_stdout(
1260 "\
1261 bar v1.0.0
1262
1263 bar v1.0.0
1264 └── optdep v1.0.0
1265 ",
1266 )
1267 .run();
1268
1269 p.cargo("tree -i optdep")
1270 .with_stdout(
1271 "\
1272 optdep v1.0.0
1273 └── bar v1.0.0
1274 [build-dependencies]
1275 └── foo v0.1.0 ([..]/foo)
1276 ",
1277 )
1278 .run();
1279
1280 // Check that -d handles duplicates with features.
1281 p.cargo("tree -d")
1282 .with_stdout(
1283 "\
1284 bar v1.0.0
1285 └── foo v0.1.0 ([..]/foo)
1286
1287 bar v1.0.0
1288 [build-dependencies]
1289 └── foo v0.1.0 ([..]/foo)
1290 ",
1291 )
1292 .run();
1293 }
1294
1295 #[cargo_test]
1296 fn proc_macro_features() {
1297 // New feature resolver with a proc-macro
1298 Package::new("optdep", "1.0.0").publish();
1299 Package::new("somedep", "1.0.0")
1300 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1301 .publish();
1302 Package::new("pm", "1.0.0")
1303 .proc_macro(true)
1304 .feature_dep("somedep", "1.0", &["optdep"])
1305 .publish();
1306 let p = project()
1307 .file(
1308 "Cargo.toml",
1309 r#"
1310 [package]
1311 name = "foo"
1312 version = "0.1.0"
1313
1314 [dependencies]
1315 pm = "1.0"
1316 somedep = "1.0"
1317 "#,
1318 )
1319 .file("src/lib.rs", "")
1320 .build();
1321
1322 // Old behavior
1323 p.cargo("tree")
1324 .with_stdout(
1325 "\
1326 foo v0.1.0 ([..]/foo)
1327 ├── pm v1.0.0 (proc-macro)
1328 │ └── somedep v1.0.0
1329 │ └── optdep v1.0.0
1330 └── somedep v1.0.0 (*)
1331 ",
1332 )
1333 .run();
1334
1335 // Old behavior + no-proc-macro
1336 p.cargo("tree -e no-proc-macro")
1337 .with_stdout(
1338 "\
1339 foo v0.1.0 ([..]/foo)
1340 └── somedep v1.0.0
1341 └── optdep v1.0.0
1342 ",
1343 )
1344 .run();
1345
1346 // -p
1347 p.cargo("tree -p somedep")
1348 .with_stdout(
1349 "\
1350 somedep v1.0.0
1351 └── optdep v1.0.0
1352 ",
1353 )
1354 .run();
1355
1356 // -p -e no-proc-macro
1357 p.cargo("tree -p somedep -e no-proc-macro")
1358 .with_stdout(
1359 "\
1360 somedep v1.0.0
1361 └── optdep v1.0.0
1362 ",
1363 )
1364 .run();
1365
1366 // invert
1367 p.cargo("tree -i somedep")
1368 .with_stdout(
1369 "\
1370 somedep v1.0.0
1371 ├── foo v0.1.0 ([..]/foo)
1372 └── pm v1.0.0 (proc-macro)
1373 └── foo v0.1.0 ([..]/foo)
1374 ",
1375 )
1376 .run();
1377
1378 // invert + no-proc-macro
1379 p.cargo("tree -i somedep -e no-proc-macro")
1380 .with_stdout(
1381 "\
1382 somedep v1.0.0
1383 └── foo v0.1.0 ([..]/foo)
1384 ",
1385 )
1386 .run();
1387
1388 // New behavior.
1389 switch_to_resolver_2(&p);
1390
1391 // Note the missing (*)
1392 p.cargo("tree")
1393 .with_stdout(
1394 "\
1395 foo v0.1.0 ([..]/foo)
1396 ├── pm v1.0.0 (proc-macro)
1397 │ └── somedep v1.0.0
1398 │ └── optdep v1.0.0
1399 └── somedep v1.0.0
1400 ",
1401 )
1402 .run();
1403
1404 p.cargo("tree -e no-proc-macro")
1405 .with_stdout(
1406 "\
1407 foo v0.1.0 ([..]/foo)
1408 └── somedep v1.0.0
1409 ",
1410 )
1411 .run();
1412
1413 p.cargo("tree -p somedep")
1414 .with_stdout(
1415 "\
1416 somedep v1.0.0
1417
1418 somedep v1.0.0
1419 └── optdep v1.0.0
1420 ",
1421 )
1422 .run();
1423
1424 p.cargo("tree -i somedep")
1425 .with_stdout(
1426 "\
1427 somedep v1.0.0
1428 └── foo v0.1.0 ([..]/foo)
1429
1430 somedep v1.0.0
1431 └── pm v1.0.0 (proc-macro)
1432 └── foo v0.1.0 ([..]/foo)
1433 ",
1434 )
1435 .run();
1436
1437 p.cargo("tree -i somedep -e no-proc-macro")
1438 .with_stdout(
1439 "\
1440 somedep v1.0.0
1441 └── foo v0.1.0 ([..]/foo)
1442
1443 somedep v1.0.0
1444 ",
1445 )
1446 .run();
1447 }
1448
1449 #[cargo_test]
1450 fn itarget_opt_dep() {
1451 // New feature resolver with optional target dep
1452 Package::new("optdep", "1.0.0").publish();
1453 Package::new("common", "1.0.0")
1454 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1455 .publish();
1456
1457 let p = project()
1458 .file(
1459 "Cargo.toml",
1460 r#"
1461 [package]
1462 name = "foo"
1463 version = "1.0.0"
1464
1465 [dependencies]
1466 common = "1.0"
1467
1468 [target.'cfg(whatever)'.dependencies]
1469 common = { version = "1.0", features = ["optdep"] }
1470
1471 "#,
1472 )
1473 .file("src/lib.rs", "")
1474 .build();
1475
1476 // Old behavior
1477 p.cargo("tree")
1478 .with_stdout(
1479 "\
1480 foo v1.0.0 ([..]/foo)
1481 └── common v1.0.0
1482 └── optdep v1.0.0
1483 ",
1484 )
1485 .run();
1486
1487 // New behavior.
1488 switch_to_resolver_2(&p);
1489
1490 p.cargo("tree")
1491 .with_stdout(
1492 "\
1493 foo v1.0.0 ([..]/foo)
1494 └── common v1.0.0
1495 ",
1496 )
1497 .run();
1498 }
1499
1500 #[cargo_test]
1501 fn ambiguous_name() {
1502 // -p that is ambiguous.
1503 Package::new("dep", "1.0.0").publish();
1504 Package::new("dep", "2.0.0").publish();
1505 Package::new("bar", "1.0.0").dep("dep", "2.0").publish();
1506 let p = project()
1507 .file(
1508 "Cargo.toml",
1509 r#"
1510 [package]
1511 name = "foo"
1512 version = "0.1.0"
1513
1514 [dependencies]
1515 dep = "1.0"
1516 bar = "1.0"
1517 "#,
1518 )
1519 .file("src/lib.rs", "")
1520 .build();
1521
1522 p.cargo("tree -p dep")
1523 .with_stderr_contains(
1524 "\
1525 error: There are multiple `dep` packages in your project, and the specification `dep` is ambiguous.
1526 Please re-run this command with `-p <spec>` where `<spec>` is one of the following:
1527 dep:1.0.0
1528 dep:2.0.0
1529 ",
1530 )
1531 .with_status(101)
1532 .run();
1533 }
1534
1535 #[cargo_test]
1536 fn workspace_features_are_local() {
1537 // The features for workspace packages should be the same as `cargo build`
1538 // (i.e., the features selected depend on the "current" package).
1539 Package::new("optdep", "1.0.0").publish();
1540 Package::new("somedep", "1.0.0")
1541 .add_dep(Dependency::new("optdep", "1.0").optional(true))
1542 .publish();
1543 let p = project()
1544 .file(
1545 "Cargo.toml",
1546 r#"
1547 [workspace]
1548 members = ["a", "b"]
1549 "#,
1550 )
1551 .file(
1552 "a/Cargo.toml",
1553 r#"
1554 [package]
1555 name = "a"
1556 version = "0.1.0"
1557
1558 [dependencies]
1559 somedep = {version="1.0", features=["optdep"]}
1560 "#,
1561 )
1562 .file("a/src/lib.rs", "")
1563 .file(
1564 "b/Cargo.toml",
1565 r#"
1566 [package]
1567 name = "b"
1568 version = "0.1.0"
1569
1570 [dependencies]
1571 somedep = "1.0"
1572 "#,
1573 )
1574 .file("b/src/lib.rs", "")
1575 .build();
1576
1577 p.cargo("tree")
1578 .with_stdout(
1579 "\
1580 a v0.1.0 ([..]/foo/a)
1581 └── somedep v1.0.0
1582 └── optdep v1.0.0
1583
1584 b v0.1.0 ([..]/foo/b)
1585 └── somedep v1.0.0 (*)
1586 ",
1587 )
1588 .run();
1589
1590 p.cargo("tree -p a")
1591 .with_stdout(
1592 "\
1593 a v0.1.0 ([..]/foo/a)
1594 └── somedep v1.0.0
1595 └── optdep v1.0.0
1596 ",
1597 )
1598 .run();
1599
1600 p.cargo("tree -p b")
1601 .with_stdout(
1602 "\
1603 b v0.1.0 ([..]/foo/b)
1604 └── somedep v1.0.0
1605 ",
1606 )
1607 .run();
1608 }
1609
1610 #[cargo_test]
1611 fn unknown_edge_kind() {
1612 let p = project()
1613 .file("Cargo.toml", "")
1614 .file("src/lib.rs", "")
1615 .build();
1616
1617 p.cargo("tree -e unknown")
1618 .with_stderr(
1619 "\
1620 [ERROR] unknown edge kind `unknown`, valid values are \
1621 \"normal\", \"build\", \"dev\", \
1622 \"no-normal\", \"no-build\", \"no-dev\", \"no-proc-macro\", \
1623 \"features\", or \"all\"
1624 ",
1625 )
1626 .with_status(101)
1627 .run();
1628 }
1629
1630 #[cargo_test]
1631 fn mixed_no_edge_kinds() {
1632 let p = project()
1633 .file(
1634 "Cargo.toml",
1635 r#"
1636 [package]
1637 name = "foo"
1638 version = "0.1.0"
1639 "#,
1640 )
1641 .file("src/lib.rs", "")
1642 .build();
1643
1644 p.cargo("tree -e no-build,normal")
1645 .with_stderr(
1646 "\
1647 [ERROR] `normal` dependency kind cannot be mixed with \
1648 \"no-normal\", \"no-build\", or \"no-dev\" dependency kinds
1649 ",
1650 )
1651 .with_status(101)
1652 .run();
1653
1654 // `no-proc-macro` can be mixed with others
1655 p.cargo("tree -e no-proc-macro,normal")
1656 .with_stdout(
1657 "\
1658 foo v0.1.0 ([..]/foo)
1659 ",
1660 )
1661 .run();
1662 }
1663
1664 #[cargo_test]
1665 fn depth_limit() {
1666 let p = make_simple_proj();
1667
1668 p.cargo("tree --depth 0")
1669 .with_stdout(
1670 "\
1671 foo v0.1.0 ([..]/foo)
1672 [build-dependencies]
1673 [dev-dependencies]
1674 ",
1675 )
1676 .run();
1677
1678 p.cargo("tree --depth 1")
1679 .with_stdout(
1680 "\
1681 foo v0.1.0 ([..]/foo)
1682 ├── a v1.0.0
1683 └── c v1.0.0
1684 [build-dependencies]
1685 └── bdep v1.0.0
1686 [dev-dependencies]
1687 └── devdep v1.0.0
1688 ",
1689 )
1690 .run();
1691
1692 p.cargo("tree --depth 2")
1693 .with_stdout(
1694 "\
1695 foo v0.1.0 ([..]/foo)
1696 ├── a v1.0.0
1697 │ └── b v1.0.0
1698 └── c v1.0.0
1699 [build-dependencies]
1700 └── bdep v1.0.0
1701 └── b v1.0.0 (*)
1702 [dev-dependencies]
1703 └── devdep v1.0.0
1704 └── b v1.0.0 (*)
1705 ",
1706 )
1707 .run();
1708
1709 // specify a package
1710 p.cargo("tree -p bdep --depth 1")
1711 .with_stdout(
1712 "\
1713 bdep v1.0.0
1714 └── b v1.0.0
1715 ",
1716 )
1717 .run();
1718
1719 // different prefix
1720 p.cargo("tree --depth 1 --prefix depth")
1721 .with_stdout(
1722 "\
1723 0foo v0.1.0 ([..]/foo)
1724 1a v1.0.0
1725 1c v1.0.0
1726 1bdep v1.0.0
1727 1devdep v1.0.0
1728 ",
1729 )
1730 .run();
1731
1732 // with edge-kinds
1733 p.cargo("tree --depth 1 -e no-dev")
1734 .with_stdout(
1735 "\
1736 foo v0.1.0 ([..]/foo)
1737 ├── a v1.0.0
1738 └── c v1.0.0
1739 [build-dependencies]
1740 └── bdep v1.0.0
1741 ",
1742 )
1743 .run();
1744
1745 // invert
1746 p.cargo("tree --depth 1 --invert c")
1747 .with_stdout(
1748 "\
1749 c v1.0.0
1750 ├── b v1.0.0
1751 └── foo v0.1.0 ([..]/foo)
1752 ",
1753 )
1754 .run();
1755 }
1756
1757 #[cargo_test]
1758 fn prune() {
1759 let p = make_simple_proj();
1760
1761 p.cargo("tree --prune c")
1762 .with_stdout(
1763 "\
1764 foo v0.1.0 ([..]/foo)
1765 └── a v1.0.0
1766 └── b v1.0.0
1767 [build-dependencies]
1768 └── bdep v1.0.0
1769 └── b v1.0.0 (*)
1770 [dev-dependencies]
1771 └── devdep v1.0.0
1772 └── b v1.0.0 (*)
1773 ",
1774 )
1775 .run();
1776
1777 // multiple prune
1778 p.cargo("tree --prune c --prune bdep")
1779 .with_stdout(
1780 "\
1781 foo v0.1.0 ([..]/foo)
1782 └── a v1.0.0
1783 └── b v1.0.0
1784 [build-dependencies]
1785 [dev-dependencies]
1786 └── devdep v1.0.0
1787 └── b v1.0.0 (*)
1788 ",
1789 )
1790 .run();
1791
1792 // with edge-kinds
1793 p.cargo("tree --prune c -e normal")
1794 .with_stdout(
1795 "\
1796 foo v0.1.0 ([..]/foo)
1797 └── a v1.0.0
1798 └── b v1.0.0
1799 ",
1800 )
1801 .run();
1802
1803 // pruning self does not works
1804 p.cargo("tree --prune foo")
1805 .with_stdout(
1806 "\
1807 foo v0.1.0 ([..]/foo)
1808 ├── a v1.0.0
1809 │ └── b v1.0.0
1810 │ └── c v1.0.0
1811 └── c v1.0.0
1812 [build-dependencies]
1813 └── bdep v1.0.0
1814 └── b v1.0.0 (*)
1815 [dev-dependencies]
1816 └── devdep v1.0.0
1817 └── b v1.0.0 (*)
1818 ",
1819 )
1820 .run();
1821
1822 // dep not exist
1823 p.cargo("tree --prune no-dep")
1824 .with_stderr(
1825 "\
1826 [ERROR] package ID specification `no-dep` did not match any packages
1827
1828 <tab>Did you mean `bdep`?
1829 ",
1830 )
1831 .with_status(101)
1832 .run();
1833 }
1834
1835 #[cargo_test]
1836 fn cyclic_features() {
1837 // Check for stack overflow with cyclic features (oops!).
1838 let p = project()
1839 .file(
1840 "Cargo.toml",
1841 r#"
1842 [package]
1843 name = "foo"
1844 version = "1.0.0"
1845
1846 [features]
1847 a = ["b"]
1848 b = ["a"]
1849 default = ["a"]
1850 "#,
1851 )
1852 .file("src/lib.rs", "")
1853 .build();
1854
1855 p.cargo("tree -e features")
1856 .with_stdout("foo v1.0.0 ([ROOT]/foo)")
1857 .run();
1858
1859 p.cargo("tree -e features -i foo")
1860 .with_stdout(
1861 "\
1862 foo v1.0.0 ([ROOT]/foo)
1863 ├── foo feature \"a\"
1864 │ ├── foo feature \"b\"
1865 │ │ └── foo feature \"a\" (*)
1866 │ └── foo feature \"default\" (command-line)
1867 ├── foo feature \"b\" (*)
1868 └── foo feature \"default\" (command-line)
1869 ",
1870 )
1871 .run();
1872 }
1873
1874 #[cargo_test]
1875 fn dev_dep_cycle_with_feature() {
1876 // Cycle with features and a dev-dependency.
1877 let p = project()
1878 .file(
1879 "Cargo.toml",
1880 r#"
1881 [package]
1882 name = "foo"
1883 version = "1.0.0"
1884
1885 [dev-dependencies]
1886 bar = { path = "bar" }
1887
1888 [features]
1889 a = ["bar/feat1"]
1890 "#,
1891 )
1892 .file("src/lib.rs", "")
1893 .file(
1894 "bar/Cargo.toml",
1895 r#"
1896 [package]
1897 name = "bar"
1898 version = "1.0.0"
1899
1900 [dependencies]
1901 foo = { path = ".." }
1902
1903 [features]
1904 feat1 = ["foo/a"]
1905 "#,
1906 )
1907 .file("bar/src/lib.rs", "")
1908 .build();
1909
1910 p.cargo("tree -e features --features a")
1911 .with_stdout(
1912 "\
1913 foo v1.0.0 ([ROOT]/foo)
1914 [dev-dependencies]
1915 └── bar feature \"default\"
1916 └── bar v1.0.0 ([ROOT]/foo/bar)
1917 └── foo feature \"default\" (command-line)
1918 └── foo v1.0.0 ([ROOT]/foo) (*)
1919 ",
1920 )
1921 .run();
1922
1923 p.cargo("tree -e features --features a -i foo")
1924 .with_stdout(
1925 "\
1926 foo v1.0.0 ([ROOT]/foo)
1927 ├── foo feature \"a\" (command-line)
1928 │ └── bar feature \"feat1\"
1929 │ └── foo feature \"a\" (command-line) (*)
1930 └── foo feature \"default\" (command-line)
1931 └── bar v1.0.0 ([ROOT]/foo/bar)
1932 ├── bar feature \"default\"
1933 │ [dev-dependencies]
1934 │ └── foo v1.0.0 ([ROOT]/foo) (*)
1935 └── bar feature \"feat1\" (*)
1936 ",
1937 )
1938 .run();
1939 }