1 //! Tests for workspaces.
2
3 use cargo_test_support::registry::Package;
4 use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project, sleep_ms};
5 use std::env;
6 use std::fs;
7
8 #[cargo_test]
simple_explicit()9 fn simple_explicit() {
10 let p = project()
11 .file(
12 "Cargo.toml",
13 r#"
14 [project]
15 name = "foo"
16 version = "0.1.0"
17 authors = []
18
19 [workspace]
20 members = ["bar"]
21 "#,
22 )
23 .file("src/main.rs", "fn main() {}")
24 .file(
25 "bar/Cargo.toml",
26 r#"
27 [project]
28 name = "bar"
29 version = "0.1.0"
30 authors = []
31 workspace = ".."
32 "#,
33 )
34 .file("bar/src/main.rs", "fn main() {}");
35 let p = p.build();
36
37 p.cargo("build").run();
38 assert!(p.bin("foo").is_file());
39 assert!(!p.bin("bar").is_file());
40
41 p.cargo("build").cwd("bar").run();
42 assert!(p.bin("foo").is_file());
43 assert!(p.bin("bar").is_file());
44
45 assert!(p.root().join("Cargo.lock").is_file());
46 assert!(!p.root().join("bar/Cargo.lock").is_file());
47 }
48
49 #[cargo_test]
simple_explicit_default_members()50 fn simple_explicit_default_members() {
51 let p = project()
52 .file(
53 "Cargo.toml",
54 r#"
55 [project]
56 name = "foo"
57 version = "0.1.0"
58 authors = []
59
60 [workspace]
61 members = ["bar"]
62 default-members = ["bar"]
63 "#,
64 )
65 .file("src/main.rs", "fn main() {}")
66 .file(
67 "bar/Cargo.toml",
68 r#"
69 [project]
70 name = "bar"
71 version = "0.1.0"
72 authors = []
73 workspace = ".."
74 "#,
75 )
76 .file("bar/src/main.rs", "fn main() {}");
77 let p = p.build();
78
79 p.cargo("build").run();
80 assert!(p.bin("bar").is_file());
81 assert!(!p.bin("foo").is_file());
82 }
83
84 #[cargo_test]
non_virtual_default_members_build_other_member()85 fn non_virtual_default_members_build_other_member() {
86 let p = project()
87 .file(
88 "Cargo.toml",
89 r#"
90 [project]
91 name = "foo"
92 version = "0.1.0"
93 authors = []
94
95 [workspace]
96 members = [".", "bar", "baz"]
97 default-members = ["baz"]
98 "#,
99 )
100 .file("src/main.rs", "fn main() {}")
101 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
102 .file("bar/src/lib.rs", "pub fn bar() {}")
103 .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
104 .file("baz/src/lib.rs", "pub fn baz() {}")
105 .build();
106
107 p.cargo("build")
108 .with_stderr(
109 "[..] Compiling baz v0.1.0 ([..])\n\
110 [..] Finished dev [unoptimized + debuginfo] target(s) in [..]\n",
111 )
112 .run();
113
114 p.cargo("build --manifest-path bar/Cargo.toml")
115 .with_stderr(
116 "[..] Compiling bar v0.1.0 ([..])\n\
117 [..] Finished dev [unoptimized + debuginfo] target(s) in [..]\n",
118 )
119 .run();
120 }
121
122 #[cargo_test]
inferred_root()123 fn inferred_root() {
124 let p = project()
125 .file(
126 "Cargo.toml",
127 r#"
128 [project]
129 name = "foo"
130 version = "0.1.0"
131 authors = []
132
133 [workspace]
134 members = ["bar"]
135 "#,
136 )
137 .file("src/main.rs", "fn main() {}")
138 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
139 .file("bar/src/main.rs", "fn main() {}");
140 let p = p.build();
141
142 p.cargo("build").run();
143 assert!(p.bin("foo").is_file());
144 assert!(!p.bin("bar").is_file());
145
146 p.cargo("build").cwd("bar").run();
147 assert!(p.bin("foo").is_file());
148 assert!(p.bin("bar").is_file());
149
150 assert!(p.root().join("Cargo.lock").is_file());
151 assert!(!p.root().join("bar/Cargo.lock").is_file());
152 }
153
154 #[cargo_test]
inferred_path_dep()155 fn inferred_path_dep() {
156 let p = project()
157 .file(
158 "Cargo.toml",
159 r#"
160 [project]
161 name = "foo"
162 version = "0.1.0"
163 authors = []
164
165 [dependencies]
166 bar = { path = "bar" }
167
168 [workspace]
169 "#,
170 )
171 .file("src/main.rs", "fn main() {}")
172 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
173 .file("bar/src/main.rs", "fn main() {}")
174 .file("bar/src/lib.rs", "");
175 let p = p.build();
176
177 p.cargo("build").run();
178 assert!(p.bin("foo").is_file());
179 assert!(!p.bin("bar").is_file());
180
181 p.cargo("build").cwd("bar").run();
182 assert!(p.bin("foo").is_file());
183 assert!(p.bin("bar").is_file());
184
185 assert!(p.root().join("Cargo.lock").is_file());
186 assert!(!p.root().join("bar/Cargo.lock").is_file());
187 }
188
189 #[cargo_test]
transitive_path_dep()190 fn transitive_path_dep() {
191 let p = project()
192 .file(
193 "Cargo.toml",
194 r#"
195 [project]
196 name = "foo"
197 version = "0.1.0"
198 authors = []
199
200 [dependencies]
201 bar = { path = "bar" }
202
203 [workspace]
204 "#,
205 )
206 .file("src/main.rs", "fn main() {}")
207 .file(
208 "bar/Cargo.toml",
209 r#"
210 [project]
211 name = "bar"
212 version = "0.1.0"
213 authors = []
214
215 [dependencies]
216 baz = { path = "../baz" }
217 "#,
218 )
219 .file("bar/src/main.rs", "fn main() {}")
220 .file("bar/src/lib.rs", "")
221 .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
222 .file("baz/src/main.rs", "fn main() {}")
223 .file("baz/src/lib.rs", "");
224 let p = p.build();
225
226 p.cargo("build").run();
227 assert!(p.bin("foo").is_file());
228 assert!(!p.bin("bar").is_file());
229 assert!(!p.bin("baz").is_file());
230
231 p.cargo("build").cwd("bar").run();
232 assert!(p.bin("foo").is_file());
233 assert!(p.bin("bar").is_file());
234 assert!(!p.bin("baz").is_file());
235
236 p.cargo("build").cwd("baz").run();
237 assert!(p.bin("foo").is_file());
238 assert!(p.bin("bar").is_file());
239 assert!(p.bin("baz").is_file());
240
241 assert!(p.root().join("Cargo.lock").is_file());
242 assert!(!p.root().join("bar/Cargo.lock").is_file());
243 assert!(!p.root().join("baz/Cargo.lock").is_file());
244 }
245
246 #[cargo_test]
parent_pointer_works()247 fn parent_pointer_works() {
248 let p = project()
249 .file(
250 "foo/Cargo.toml",
251 r#"
252 [project]
253 name = "foo"
254 version = "0.1.0"
255 authors = []
256
257 [dependencies]
258 bar = { path = "../bar" }
259
260 [workspace]
261 "#,
262 )
263 .file("foo/src/main.rs", "fn main() {}")
264 .file(
265 "bar/Cargo.toml",
266 r#"
267 [project]
268 name = "bar"
269 version = "0.1.0"
270 authors = []
271 workspace = "../foo"
272 "#,
273 )
274 .file("bar/src/main.rs", "fn main() {}")
275 .file("bar/src/lib.rs", "");
276 let p = p.build();
277
278 p.cargo("build").cwd("foo").run();
279 p.cargo("build").cwd("bar").run();
280 assert!(p.root().join("foo/Cargo.lock").is_file());
281 assert!(!p.root().join("bar/Cargo.lock").is_file());
282 }
283
284 #[cargo_test]
same_names_in_workspace()285 fn same_names_in_workspace() {
286 let p = project()
287 .file(
288 "Cargo.toml",
289 r#"
290 [project]
291 name = "foo"
292 version = "0.1.0"
293 authors = []
294
295 [workspace]
296 members = ["bar"]
297 "#,
298 )
299 .file("src/main.rs", "fn main() {}")
300 .file(
301 "bar/Cargo.toml",
302 r#"
303 [project]
304 name = "foo"
305 version = "0.1.0"
306 authors = []
307 workspace = ".."
308 "#,
309 )
310 .file("bar/src/main.rs", "fn main() {}");
311 let p = p.build();
312
313 p.cargo("build")
314 .with_status(101)
315 .with_stderr(
316 "\
317 error: two packages named `foo` in this workspace:
318 - [..]Cargo.toml
319 - [..]Cargo.toml
320 ",
321 )
322 .run();
323 }
324
325 #[cargo_test]
parent_doesnt_point_to_child()326 fn parent_doesnt_point_to_child() {
327 let p = project()
328 .file(
329 "Cargo.toml",
330 r#"
331 [project]
332 name = "foo"
333 version = "0.1.0"
334 authors = []
335
336 [workspace]
337 "#,
338 )
339 .file("src/main.rs", "fn main() {}")
340 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
341 .file("bar/src/main.rs", "fn main() {}");
342 let p = p.build();
343
344 p.cargo("build")
345 .cwd("bar")
346 .with_status(101)
347 .with_stderr(
348 "\
349 error: current package believes it's in a workspace when it's not:
350 current: [..]Cargo.toml
351 workspace: [..]Cargo.toml
352
353 this may be fixable [..]
354 [..]
355 ",
356 )
357 .run();
358 }
359
360 #[cargo_test]
invalid_parent_pointer()361 fn invalid_parent_pointer() {
362 let p = project()
363 .file(
364 "Cargo.toml",
365 r#"
366 [project]
367 name = "foo"
368 version = "0.1.0"
369 authors = []
370 workspace = "foo"
371 "#,
372 )
373 .file("src/main.rs", "fn main() {}");
374 let p = p.build();
375
376 p.cargo("build")
377 .with_status(101)
378 .with_stderr(
379 "\
380 error: failed to read `[..]Cargo.toml`
381
382 Caused by:
383 [..]
384 ",
385 )
386 .run();
387 }
388
389 #[cargo_test]
invalid_members()390 fn invalid_members() {
391 let p = project()
392 .file(
393 "Cargo.toml",
394 r#"
395 [project]
396 name = "foo"
397 version = "0.1.0"
398 authors = []
399
400 [workspace]
401 members = ["foo"]
402 "#,
403 )
404 .file("src/main.rs", "fn main() {}");
405 let p = p.build();
406
407 p.cargo("build")
408 .with_status(101)
409 .with_stderr(
410 "\
411 [ERROR] failed to load manifest for workspace member `[..]/foo`
412
413 Caused by:
414 failed to read `[..]foo/foo/Cargo.toml`
415
416 Caused by:
417 [..]
418 ",
419 )
420 .run();
421 }
422
423 #[cargo_test]
bare_workspace_ok()424 fn bare_workspace_ok() {
425 let p = project()
426 .file(
427 "Cargo.toml",
428 r#"
429 [project]
430 name = "foo"
431 version = "0.1.0"
432 authors = []
433
434 [workspace]
435 "#,
436 )
437 .file("src/main.rs", "fn main() {}");
438 let p = p.build();
439
440 p.cargo("build").run();
441 }
442
443 #[cargo_test]
two_roots()444 fn two_roots() {
445 let p = project()
446 .file(
447 "Cargo.toml",
448 r#"
449 [project]
450 name = "foo"
451 version = "0.1.0"
452 authors = []
453
454 [workspace]
455 members = ["bar"]
456 "#,
457 )
458 .file("src/main.rs", "fn main() {}")
459 .file(
460 "bar/Cargo.toml",
461 r#"
462 [project]
463 name = "bar"
464 version = "0.1.0"
465 authors = []
466
467 [workspace]
468 members = [".."]
469 "#,
470 )
471 .file("bar/src/main.rs", "fn main() {}");
472 let p = p.build();
473
474 p.cargo("build")
475 .with_status(101)
476 .with_stderr(
477 "\
478 error: multiple workspace roots found in the same workspace:
479 [..]
480 [..]
481 ",
482 )
483 .run();
484 }
485
486 #[cargo_test]
workspace_isnt_root()487 fn workspace_isnt_root() {
488 let p = project()
489 .file(
490 "Cargo.toml",
491 r#"
492 [project]
493 name = "foo"
494 version = "0.1.0"
495 authors = []
496 workspace = "bar"
497 "#,
498 )
499 .file("src/main.rs", "fn main() {}")
500 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
501 .file("bar/src/main.rs", "fn main() {}");
502 let p = p.build();
503
504 p.cargo("build")
505 .with_status(101)
506 .with_stderr("error: root of a workspace inferred but wasn't a root: [..]")
507 .run();
508 }
509
510 #[cargo_test]
dangling_member()511 fn dangling_member() {
512 let p = project()
513 .file(
514 "Cargo.toml",
515 r#"
516 [project]
517 name = "foo"
518 version = "0.1.0"
519 authors = []
520
521 [workspace]
522 members = ["bar"]
523 "#,
524 )
525 .file("src/main.rs", "fn main() {}")
526 .file(
527 "bar/Cargo.toml",
528 r#"
529 [project]
530 name = "bar"
531 version = "0.1.0"
532 authors = []
533 workspace = "../baz"
534 "#,
535 )
536 .file("bar/src/main.rs", "fn main() {}")
537 .file(
538 "baz/Cargo.toml",
539 r#"
540 [project]
541 name = "baz"
542 version = "0.1.0"
543 authors = []
544 workspace = "../baz"
545 "#,
546 )
547 .file("baz/src/main.rs", "fn main() {}");
548 let p = p.build();
549
550 p.cargo("build")
551 .with_status(101)
552 .with_stderr(
553 "\
554 error: package `[..]` is a member of the wrong workspace
555 expected: [..]
556 actual: [..]
557 ",
558 )
559 .run();
560 }
561
562 #[cargo_test]
cycle()563 fn cycle() {
564 let p = project()
565 .file(
566 "Cargo.toml",
567 r#"
568 [project]
569 name = "foo"
570 version = "0.1.0"
571 authors = []
572 workspace = "bar"
573 "#,
574 )
575 .file("src/main.rs", "fn main() {}")
576 .file(
577 "bar/Cargo.toml",
578 r#"
579 [project]
580 name = "bar"
581 version = "0.1.0"
582 authors = []
583 workspace = ".."
584 "#,
585 )
586 .file("bar/src/main.rs", "fn main() {}");
587 let p = p.build();
588
589 p.cargo("build")
590 .with_status(101)
591 .with_stderr(
592 "[ERROR] root of a workspace inferred but wasn't a root: [..]/foo/bar/Cargo.toml",
593 )
594 .run();
595 }
596
597 #[cargo_test]
share_dependencies()598 fn share_dependencies() {
599 let p = project()
600 .file(
601 "Cargo.toml",
602 r#"
603 [project]
604 name = "foo"
605 version = "0.1.0"
606 authors = []
607
608 [dependencies]
609 dep1 = "0.1"
610
611 [workspace]
612 members = ["bar"]
613 "#,
614 )
615 .file("src/main.rs", "fn main() {}")
616 .file(
617 "bar/Cargo.toml",
618 r#"
619 [project]
620 name = "bar"
621 version = "0.1.0"
622 authors = []
623
624 [dependencies]
625 dep1 = "< 0.1.5"
626 "#,
627 )
628 .file("bar/src/main.rs", "fn main() {}");
629 let p = p.build();
630
631 Package::new("dep1", "0.1.3").publish();
632 Package::new("dep1", "0.1.8").publish();
633
634 p.cargo("build")
635 .with_stderr(
636 "\
637 [UPDATING] `[..]` index
638 [DOWNLOADING] crates ...
639 [DOWNLOADED] dep1 v0.1.3 ([..])
640 [COMPILING] dep1 v0.1.3
641 [COMPILING] foo v0.1.0 ([..])
642 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
643 ",
644 )
645 .run();
646 }
647
648 #[cargo_test]
fetch_fetches_all()649 fn fetch_fetches_all() {
650 let p = project()
651 .file(
652 "Cargo.toml",
653 r#"
654 [project]
655 name = "foo"
656 version = "0.1.0"
657 authors = []
658
659 [workspace]
660 members = ["bar"]
661 "#,
662 )
663 .file("src/main.rs", "fn main() {}")
664 .file(
665 "bar/Cargo.toml",
666 r#"
667 [project]
668 name = "bar"
669 version = "0.1.0"
670 authors = []
671
672 [dependencies]
673 dep1 = "*"
674 "#,
675 )
676 .file("bar/src/main.rs", "fn main() {}");
677 let p = p.build();
678
679 Package::new("dep1", "0.1.3").publish();
680
681 p.cargo("fetch")
682 .with_stderr(
683 "\
684 [UPDATING] `[..]` index
685 [DOWNLOADING] crates ...
686 [DOWNLOADED] dep1 v0.1.3 ([..])
687 ",
688 )
689 .run();
690 }
691
692 #[cargo_test]
lock_works_for_everyone()693 fn lock_works_for_everyone() {
694 let p = project()
695 .file(
696 "Cargo.toml",
697 r#"
698 [project]
699 name = "foo"
700 version = "0.1.0"
701 authors = []
702
703 [dependencies]
704 dep2 = "0.1"
705
706 [workspace]
707 members = ["bar"]
708 "#,
709 )
710 .file("src/main.rs", "fn main() {}")
711 .file(
712 "bar/Cargo.toml",
713 r#"
714 [project]
715 name = "bar"
716 version = "0.1.0"
717 authors = []
718
719 [dependencies]
720 dep1 = "0.1"
721 "#,
722 )
723 .file("bar/src/main.rs", "fn main() {}");
724 let p = p.build();
725
726 Package::new("dep1", "0.1.0").publish();
727 Package::new("dep2", "0.1.0").publish();
728
729 p.cargo("generate-lockfile")
730 .with_stderr("[UPDATING] `[..]` index")
731 .run();
732
733 Package::new("dep1", "0.1.1").publish();
734 Package::new("dep2", "0.1.1").publish();
735
736 p.cargo("build")
737 .with_stderr(
738 "\
739 [DOWNLOADING] crates ...
740 [DOWNLOADED] dep2 v0.1.0 ([..])
741 [COMPILING] dep2 v0.1.0
742 [COMPILING] foo v0.1.0 ([..])
743 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
744 ",
745 )
746 .run();
747
748 p.cargo("build")
749 .cwd("bar")
750 .with_stderr(
751 "\
752 [DOWNLOADING] crates ...
753 [DOWNLOADED] dep1 v0.1.0 ([..])
754 [COMPILING] dep1 v0.1.0
755 [COMPILING] bar v0.1.0 ([..])
756 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
757 ",
758 )
759 .run();
760 }
761
762 #[cargo_test]
virtual_works()763 fn virtual_works() {
764 let p = project()
765 .file(
766 "Cargo.toml",
767 r#"
768 [workspace]
769 members = ["bar"]
770 "#,
771 )
772 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
773 .file("bar/src/main.rs", "fn main() {}");
774 let p = p.build();
775 p.cargo("build").cwd("bar").run();
776 assert!(p.root().join("Cargo.lock").is_file());
777 assert!(p.bin("bar").is_file());
778 assert!(!p.root().join("bar/Cargo.lock").is_file());
779 }
780
781 #[cargo_test]
explicit_package_argument_works_with_virtual_manifest()782 fn explicit_package_argument_works_with_virtual_manifest() {
783 let p = project()
784 .file(
785 "Cargo.toml",
786 r#"
787 [workspace]
788 members = ["bar"]
789 "#,
790 )
791 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
792 .file("bar/src/main.rs", "fn main() {}");
793 let p = p.build();
794 p.cargo("build --package bar").run();
795 assert!(p.root().join("Cargo.lock").is_file());
796 assert!(p.bin("bar").is_file());
797 assert!(!p.root().join("bar/Cargo.lock").is_file());
798 }
799
800 #[cargo_test]
virtual_misconfigure()801 fn virtual_misconfigure() {
802 let p = project()
803 .file(
804 "Cargo.toml",
805 r#"
806 [workspace]
807 "#,
808 )
809 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
810 .file("bar/src/main.rs", "fn main() {}");
811 let p = p.build();
812 p.cargo("build")
813 .cwd("bar")
814 .with_status(101)
815 .with_stderr(
816 "\
817 error: current package believes it's in a workspace when it's not:
818 current: [CWD]/Cargo.toml
819 workspace: [..]Cargo.toml
820
821 this may be fixable by adding `bar` to the `workspace.members` array of the \
822 manifest located at: [..]
823 [..]
824 ",
825 )
826 .run();
827 }
828
829 #[cargo_test]
virtual_build_all_implied()830 fn virtual_build_all_implied() {
831 let p = project()
832 .file(
833 "Cargo.toml",
834 r#"
835 [workspace]
836 members = ["bar"]
837 "#,
838 )
839 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
840 .file("bar/src/main.rs", "fn main() {}");
841 let p = p.build();
842 p.cargo("build").run();
843 }
844
845 #[cargo_test]
virtual_default_members()846 fn virtual_default_members() {
847 let p = project()
848 .file(
849 "Cargo.toml",
850 r#"
851 [workspace]
852 members = ["bar", "baz"]
853 default-members = ["bar"]
854 "#,
855 )
856 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
857 .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
858 .file("bar/src/main.rs", "fn main() {}")
859 .file("baz/src/main.rs", "fn main() {}");
860 let p = p.build();
861 p.cargo("build").run();
862 assert!(p.bin("bar").is_file());
863 assert!(!p.bin("baz").is_file());
864 }
865
866 #[cargo_test]
virtual_default_member_is_not_a_member()867 fn virtual_default_member_is_not_a_member() {
868 let p = project()
869 .file(
870 "Cargo.toml",
871 r#"
872 [workspace]
873 members = ["bar"]
874 default-members = ["something-else"]
875 "#,
876 )
877 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
878 .file("bar/src/main.rs", "fn main() {}");
879 let p = p.build();
880 p.cargo("build")
881 .with_status(101)
882 .with_stderr(
883 "\
884 error: package `[..]something-else` is listed in workspace’s default-members \
885 but is not a member.
886 ",
887 )
888 .run();
889 }
890
891 #[cargo_test]
virtual_default_members_build_other_member()892 fn virtual_default_members_build_other_member() {
893 let p = project()
894 .file(
895 "Cargo.toml",
896 r#"
897 [workspace]
898 members = ["bar", "baz"]
899 default-members = ["baz"]
900 "#,
901 )
902 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
903 .file("bar/src/lib.rs", "pub fn bar() {}")
904 .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
905 .file("baz/src/lib.rs", "pub fn baz() {}")
906 .build();
907
908 p.cargo("build --manifest-path bar/Cargo.toml")
909 .with_stderr(
910 "[..] Compiling bar v0.1.0 ([..])\n\
911 [..] Finished dev [unoptimized + debuginfo] target(s) in [..]\n",
912 )
913 .run();
914 }
915
916 #[cargo_test]
virtual_build_no_members()917 fn virtual_build_no_members() {
918 let p = project().file(
919 "Cargo.toml",
920 r#"
921 [workspace]
922 "#,
923 );
924 let p = p.build();
925 p.cargo("build")
926 .with_status(101)
927 .with_stderr(
928 "\
929 error: manifest path `[..]` contains no package: The manifest is virtual, \
930 and the workspace has no members.
931 ",
932 )
933 .run();
934 }
935
936 #[cargo_test]
include_virtual()937 fn include_virtual() {
938 let p = project()
939 .file(
940 "Cargo.toml",
941 r#"
942 [project]
943 name = "bar"
944 version = "0.1.0"
945 authors = []
946 [workspace]
947 members = ["bar"]
948 "#,
949 )
950 .file("src/main.rs", "")
951 .file(
952 "bar/Cargo.toml",
953 r#"
954 [workspace]
955 "#,
956 );
957 let p = p.build();
958 p.cargo("build")
959 .with_status(101)
960 .with_stderr(
961 "\
962 error: multiple workspace roots found in the same workspace:
963 [..]
964 [..]
965 ",
966 )
967 .run();
968 }
969
970 #[cargo_test]
members_include_path_deps()971 fn members_include_path_deps() {
972 let p = project()
973 .file(
974 "Cargo.toml",
975 r#"
976 [project]
977 name = "foo"
978 version = "0.1.0"
979 authors = []
980
981 [workspace]
982 members = ["p1"]
983
984 [dependencies]
985 p3 = { path = "p3" }
986 "#,
987 )
988 .file("src/lib.rs", "")
989 .file(
990 "p1/Cargo.toml",
991 r#"
992 [project]
993 name = "p1"
994 version = "0.1.0"
995 authors = []
996
997 [dependencies]
998 p2 = { path = "../p2" }
999 "#,
1000 )
1001 .file("p1/src/lib.rs", "")
1002 .file("p2/Cargo.toml", &basic_manifest("p2", "0.1.0"))
1003 .file("p2/src/lib.rs", "")
1004 .file("p3/Cargo.toml", &basic_manifest("p3", "0.1.0"))
1005 .file("p3/src/lib.rs", "");
1006 let p = p.build();
1007
1008 p.cargo("build").cwd("p1").run();
1009 p.cargo("build").cwd("p2").run();
1010 p.cargo("build").cwd("p3").run();
1011 p.cargo("build").run();
1012
1013 assert!(p.root().join("target").is_dir());
1014 assert!(!p.root().join("p1/target").is_dir());
1015 assert!(!p.root().join("p2/target").is_dir());
1016 assert!(!p.root().join("p3/target").is_dir());
1017 }
1018
1019 #[cargo_test]
new_warns_you_this_will_not_work()1020 fn new_warns_you_this_will_not_work() {
1021 let p = project()
1022 .file(
1023 "Cargo.toml",
1024 r#"
1025 [project]
1026 name = "foo"
1027 version = "0.1.0"
1028 authors = []
1029
1030 [workspace]
1031 "#,
1032 )
1033 .file("src/lib.rs", "");
1034 let p = p.build();
1035
1036 p.cargo("new --lib bar")
1037 .with_stderr(
1038 "\
1039 warning: compiling this new package may not work due to invalid workspace configuration
1040
1041 current package believes it's in a workspace when it's not:
1042 current: [..]
1043 workspace: [..]
1044
1045 this may be fixable by ensuring that this crate is depended on by the workspace \
1046 root: [..]
1047 [..]
1048 [CREATED] library `bar` package
1049 ",
1050 )
1051 .run();
1052 }
1053
1054 #[cargo_test]
new_warning_with_corrupt_ws()1055 fn new_warning_with_corrupt_ws() {
1056 let p = project().file("Cargo.toml", "asdf").build();
1057 p.cargo("new bar")
1058 .with_stderr(
1059 "\
1060 [WARNING] compiling this new package may not work due to invalid workspace configuration
1061
1062 failed to parse manifest at `[..]foo/Cargo.toml`
1063
1064 Caused by:
1065 could not parse input as TOML
1066
1067 Caused by:
1068 expected an equals, found eof at line 1 column 5
1069 Created binary (application) `bar` package
1070 ",
1071 )
1072 .run();
1073 }
1074
1075 #[cargo_test]
lock_doesnt_change_depending_on_crate()1076 fn lock_doesnt_change_depending_on_crate() {
1077 let p = project()
1078 .file(
1079 "Cargo.toml",
1080 r#"
1081 [project]
1082 name = "foo"
1083 version = "0.1.0"
1084 authors = []
1085
1086 [workspace]
1087 members = ['baz']
1088
1089 [dependencies]
1090 foo = "*"
1091 "#,
1092 )
1093 .file("src/lib.rs", "")
1094 .file(
1095 "baz/Cargo.toml",
1096 r#"
1097 [project]
1098 name = "baz"
1099 version = "0.1.0"
1100 authors = []
1101
1102 [dependencies]
1103 bar = "*"
1104 "#,
1105 )
1106 .file("baz/src/lib.rs", "");
1107 let p = p.build();
1108
1109 Package::new("foo", "1.0.0").publish();
1110 Package::new("bar", "1.0.0").publish();
1111
1112 p.cargo("build").run();
1113
1114 let lockfile = p.read_lockfile();
1115
1116 p.cargo("build").cwd("baz").run();
1117
1118 let lockfile2 = p.read_lockfile();
1119
1120 assert_eq!(lockfile, lockfile2);
1121 }
1122
1123 #[cargo_test]
rebuild_please()1124 fn rebuild_please() {
1125 let p = project()
1126 .file(
1127 "Cargo.toml",
1128 r#"
1129 [workspace]
1130 members = ['lib', 'bin']
1131 "#,
1132 )
1133 .file("lib/Cargo.toml", &basic_manifest("lib", "0.1.0"))
1134 .file(
1135 "lib/src/lib.rs",
1136 r#"
1137 pub fn foo() -> u32 { 0 }
1138 "#,
1139 )
1140 .file(
1141 "bin/Cargo.toml",
1142 r#"
1143 [package]
1144 name = "bin"
1145 version = "0.1.0"
1146
1147 [dependencies]
1148 lib = { path = "../lib" }
1149 "#,
1150 )
1151 .file(
1152 "bin/src/main.rs",
1153 r#"
1154 extern crate lib;
1155
1156 fn main() {
1157 assert_eq!(lib::foo(), 0);
1158 }
1159 "#,
1160 );
1161 let p = p.build();
1162
1163 p.cargo("run").cwd("bin").run();
1164
1165 sleep_ms(1000);
1166
1167 p.change_file("lib/src/lib.rs", "pub fn foo() -> u32 { 1 }");
1168
1169 p.cargo("build").cwd("lib").run();
1170
1171 p.cargo("run")
1172 .cwd("bin")
1173 .with_status(101)
1174 .with_stderr_contains("[..]assertion[..]")
1175 .run();
1176 }
1177
1178 #[cargo_test]
workspace_in_git()1179 fn workspace_in_git() {
1180 let git_project = git::new("dep1", |project| {
1181 project
1182 .file(
1183 "Cargo.toml",
1184 r#"
1185 [workspace]
1186 members = ["foo"]
1187 "#,
1188 )
1189 .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
1190 .file("foo/src/lib.rs", "")
1191 });
1192 let p = project()
1193 .file(
1194 "Cargo.toml",
1195 &format!(
1196 r#"
1197 [package]
1198 name = "lib"
1199 version = "0.1.0"
1200
1201 [dependencies.foo]
1202 git = '{}'
1203 "#,
1204 git_project.url()
1205 ),
1206 )
1207 .file(
1208 "src/lib.rs",
1209 r#"
1210 pub fn foo() -> u32 { 0 }
1211 "#,
1212 );
1213 let p = p.build();
1214
1215 p.cargo("build").run();
1216 }
1217
1218 #[cargo_test]
lockfile_can_specify_nonexistant_members()1219 fn lockfile_can_specify_nonexistant_members() {
1220 let p = project()
1221 .file(
1222 "Cargo.toml",
1223 r#"
1224 [workspace]
1225 members = ["a"]
1226 "#,
1227 )
1228 .file("a/Cargo.toml", &basic_manifest("a", "0.1.0"))
1229 .file("a/src/main.rs", "fn main() {}")
1230 .file(
1231 "Cargo.lock",
1232 r#"
1233 [[package]]
1234 name = "a"
1235 version = "0.1.0"
1236
1237 [[package]]
1238 name = "b"
1239 version = "0.1.0"
1240 "#,
1241 );
1242
1243 let p = p.build();
1244
1245 p.cargo("build").cwd("a").run();
1246 }
1247
1248 #[cargo_test]
you_cannot_generate_lockfile_for_empty_workspaces()1249 fn you_cannot_generate_lockfile_for_empty_workspaces() {
1250 let p = project()
1251 .file(
1252 "Cargo.toml",
1253 r#"
1254 [workspace]
1255 "#,
1256 )
1257 .file("bar/Cargo.toml", &basic_manifest("foo", "0.1.0"))
1258 .file("bar/src/main.rs", "fn main() {}");
1259 let p = p.build();
1260
1261 p.cargo("update")
1262 .with_status(101)
1263 .with_stderr("error: you can't generate a lockfile for an empty workspace.")
1264 .run();
1265 }
1266
1267 #[cargo_test]
workspace_with_transitive_dev_deps()1268 fn workspace_with_transitive_dev_deps() {
1269 let p = project()
1270 .file(
1271 "Cargo.toml",
1272 r#"
1273 [project]
1274 name = "foo"
1275 version = "0.5.0"
1276 authors = ["mbrubeck@example.com"]
1277
1278 [dependencies.bar]
1279 path = "bar"
1280
1281 [workspace]
1282 "#,
1283 )
1284 .file("src/main.rs", r#"fn main() {}"#)
1285 .file(
1286 "bar/Cargo.toml",
1287 r#"
1288 [project]
1289 name = "bar"
1290 version = "0.5.0"
1291 authors = ["mbrubeck@example.com"]
1292
1293 [dev-dependencies.baz]
1294 path = "../baz"
1295 "#,
1296 )
1297 .file(
1298 "bar/src/lib.rs",
1299 r#"
1300 pub fn init() {}
1301
1302 #[cfg(test)]
1303
1304 #[test]
1305 fn test() {
1306 extern crate baz;
1307 baz::do_stuff();
1308 }
1309 "#,
1310 )
1311 .file("baz/Cargo.toml", &basic_manifest("baz", "0.5.0"))
1312 .file("baz/src/lib.rs", r#"pub fn do_stuff() {}"#);
1313 let p = p.build();
1314
1315 p.cargo("test -p bar").run();
1316 }
1317
1318 #[cargo_test]
error_if_parent_cargo_toml_is_invalid()1319 fn error_if_parent_cargo_toml_is_invalid() {
1320 let p = project()
1321 .file("Cargo.toml", "Totally not a TOML file")
1322 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
1323 .file("bar/src/main.rs", "fn main() {}");
1324 let p = p.build();
1325
1326 p.cargo("build")
1327 .cwd("bar")
1328 .with_status(101)
1329 .with_stderr_contains("[ERROR] failed to parse manifest at `[..]`")
1330 .run();
1331 }
1332
1333 #[cargo_test]
relative_path_for_member_works()1334 fn relative_path_for_member_works() {
1335 let p = project()
1336 .file(
1337 "foo/Cargo.toml",
1338 r#"
1339 [project]
1340 name = "foo"
1341 version = "0.1.0"
1342 authors = []
1343
1344 [workspace]
1345 members = ["../bar"]
1346 "#,
1347 )
1348 .file("foo/src/main.rs", "fn main() {}")
1349 .file(
1350 "bar/Cargo.toml",
1351 r#"
1352 [project]
1353 name = "bar"
1354 version = "0.1.0"
1355 authors = []
1356 workspace = "../foo"
1357 "#,
1358 )
1359 .file("bar/src/main.rs", "fn main() {}");
1360 let p = p.build();
1361
1362 p.cargo("build").cwd("foo").run();
1363 p.cargo("build").cwd("bar").run();
1364 }
1365
1366 #[cargo_test]
relative_path_for_root_works()1367 fn relative_path_for_root_works() {
1368 let p = project()
1369 .file(
1370 "Cargo.toml",
1371 r#"
1372 [project]
1373 name = "foo"
1374 version = "0.1.0"
1375 authors = []
1376
1377 [workspace]
1378
1379 [dependencies]
1380 subproj = { path = "./subproj" }
1381 "#,
1382 )
1383 .file("src/main.rs", "fn main() {}")
1384 .file("subproj/Cargo.toml", &basic_manifest("subproj", "0.1.0"))
1385 .file("subproj/src/main.rs", "fn main() {}");
1386 let p = p.build();
1387
1388 p.cargo("build --manifest-path ./Cargo.toml").run();
1389
1390 p.cargo("build --manifest-path ../Cargo.toml")
1391 .cwd("subproj")
1392 .run();
1393 }
1394
1395 #[cargo_test]
path_dep_outside_workspace_is_not_member()1396 fn path_dep_outside_workspace_is_not_member() {
1397 let p = project()
1398 .no_manifest()
1399 .file(
1400 "ws/Cargo.toml",
1401 r#"
1402 [project]
1403 name = "ws"
1404 version = "0.1.0"
1405 authors = []
1406
1407 [dependencies]
1408 foo = { path = "../foo" }
1409
1410 [workspace]
1411 "#,
1412 )
1413 .file("ws/src/lib.rs", "extern crate foo;")
1414 .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
1415 .file("foo/src/lib.rs", "");
1416 let p = p.build();
1417
1418 p.cargo("build").cwd("ws").run();
1419 }
1420
1421 #[cargo_test]
test_in_and_out_of_workspace()1422 fn test_in_and_out_of_workspace() {
1423 let p = project()
1424 .no_manifest()
1425 .file(
1426 "ws/Cargo.toml",
1427 r#"
1428 [project]
1429 name = "ws"
1430 version = "0.1.0"
1431 authors = []
1432
1433 [dependencies]
1434 foo = { path = "../foo" }
1435
1436 [workspace]
1437 members = [ "../bar" ]
1438 "#,
1439 )
1440 .file("ws/src/lib.rs", "extern crate foo; pub fn f() { foo::f() }")
1441 .file(
1442 "foo/Cargo.toml",
1443 r#"
1444 [project]
1445 name = "foo"
1446 version = "0.1.0"
1447 authors = []
1448
1449 [dependencies]
1450 bar = { path = "../bar" }
1451 "#,
1452 )
1453 .file(
1454 "foo/src/lib.rs",
1455 "extern crate bar; pub fn f() { bar::f() }",
1456 )
1457 .file(
1458 "bar/Cargo.toml",
1459 r#"
1460 [project]
1461 workspace = "../ws"
1462 name = "bar"
1463 version = "0.1.0"
1464 authors = []
1465 "#,
1466 )
1467 .file("bar/src/lib.rs", "pub fn f() { }");
1468 let p = p.build();
1469
1470 p.cargo("build").cwd("ws").run();
1471
1472 assert!(p.root().join("ws/Cargo.lock").is_file());
1473 assert!(p.root().join("ws/target").is_dir());
1474 assert!(!p.root().join("foo/Cargo.lock").is_file());
1475 assert!(!p.root().join("foo/target").is_dir());
1476 assert!(!p.root().join("bar/Cargo.lock").is_file());
1477 assert!(!p.root().join("bar/target").is_dir());
1478
1479 p.cargo("build").cwd("foo").run();
1480 assert!(p.root().join("foo/Cargo.lock").is_file());
1481 assert!(p.root().join("foo/target").is_dir());
1482 assert!(!p.root().join("bar/Cargo.lock").is_file());
1483 assert!(!p.root().join("bar/target").is_dir());
1484 }
1485
1486 #[cargo_test]
test_path_dependency_under_member()1487 fn test_path_dependency_under_member() {
1488 let p = project()
1489 .file(
1490 "ws/Cargo.toml",
1491 r#"
1492 [project]
1493 name = "ws"
1494 version = "0.1.0"
1495 authors = []
1496
1497 [dependencies]
1498 foo = { path = "../foo" }
1499
1500 [workspace]
1501 "#,
1502 )
1503 .file("ws/src/lib.rs", "extern crate foo; pub fn f() { foo::f() }")
1504 .file(
1505 "foo/Cargo.toml",
1506 r#"
1507 [project]
1508 workspace = "../ws"
1509 name = "foo"
1510 version = "0.1.0"
1511 authors = []
1512
1513 [dependencies]
1514 bar = { path = "./bar" }
1515 "#,
1516 )
1517 .file(
1518 "foo/src/lib.rs",
1519 "extern crate bar; pub fn f() { bar::f() }",
1520 )
1521 .file("foo/bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
1522 .file("foo/bar/src/lib.rs", "pub fn f() { }");
1523 let p = p.build();
1524
1525 p.cargo("build").cwd("ws").run();
1526
1527 assert!(!p.root().join("foo/bar/Cargo.lock").is_file());
1528 assert!(!p.root().join("foo/bar/target").is_dir());
1529
1530 p.cargo("build").cwd("foo/bar").run();
1531
1532 assert!(!p.root().join("foo/bar/Cargo.lock").is_file());
1533 assert!(!p.root().join("foo/bar/target").is_dir());
1534 }
1535
1536 #[cargo_test]
excluded_simple()1537 fn excluded_simple() {
1538 let p = project()
1539 .file(
1540 "Cargo.toml",
1541 r#"
1542 [project]
1543 name = "ws"
1544 version = "0.1.0"
1545 authors = []
1546
1547 [workspace]
1548 exclude = ["foo"]
1549 "#,
1550 )
1551 .file("src/lib.rs", "")
1552 .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
1553 .file("foo/src/lib.rs", "");
1554 let p = p.build();
1555
1556 p.cargo("build").run();
1557 assert!(p.root().join("target").is_dir());
1558 p.cargo("build").cwd("foo").run();
1559 assert!(p.root().join("foo/target").is_dir());
1560 }
1561
1562 #[cargo_test]
exclude_members_preferred()1563 fn exclude_members_preferred() {
1564 let p = project()
1565 .file(
1566 "Cargo.toml",
1567 r#"
1568 [project]
1569 name = "ws"
1570 version = "0.1.0"
1571 authors = []
1572
1573 [workspace]
1574 members = ["foo/bar"]
1575 exclude = ["foo"]
1576 "#,
1577 )
1578 .file("src/lib.rs", "")
1579 .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
1580 .file("foo/src/lib.rs", "")
1581 .file("foo/bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
1582 .file("foo/bar/src/lib.rs", "");
1583 let p = p.build();
1584
1585 p.cargo("build").run();
1586 assert!(p.root().join("target").is_dir());
1587 p.cargo("build").cwd("foo").run();
1588 assert!(p.root().join("foo/target").is_dir());
1589 p.cargo("build").cwd("foo/bar").run();
1590 assert!(!p.root().join("foo/bar/target").is_dir());
1591 }
1592
1593 #[cargo_test]
exclude_but_also_depend()1594 fn exclude_but_also_depend() {
1595 let p = project()
1596 .file(
1597 "Cargo.toml",
1598 r#"
1599 [project]
1600 name = "ws"
1601 version = "0.1.0"
1602 authors = []
1603
1604 [dependencies]
1605 bar = { path = "foo/bar" }
1606
1607 [workspace]
1608 exclude = ["foo"]
1609 "#,
1610 )
1611 .file("src/lib.rs", "")
1612 .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
1613 .file("foo/src/lib.rs", "")
1614 .file("foo/bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
1615 .file("foo/bar/src/lib.rs", "");
1616 let p = p.build();
1617
1618 p.cargo("build").run();
1619 assert!(p.root().join("target").is_dir());
1620 p.cargo("build").cwd("foo").run();
1621 assert!(p.root().join("foo/target").is_dir());
1622 p.cargo("build").cwd("foo/bar").run();
1623 assert!(p.root().join("foo/bar/target").is_dir());
1624 }
1625
1626 #[cargo_test]
excluded_default_members_still_must_be_members()1627 fn excluded_default_members_still_must_be_members() {
1628 let p = project()
1629 .file(
1630 "Cargo.toml",
1631 r#"
1632 [workspace]
1633 members = ["foo"]
1634 default-members = ["foo", "bar"]
1635 exclude = ["bar"]
1636 "#,
1637 )
1638 .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
1639 .file("foo/src/lib.rs", "")
1640 .file("bar/something.txt", "");
1641 let p = p.build();
1642 p.cargo("build")
1643 .with_status(101)
1644 .with_stderr(
1645 "\
1646 error: package `[..]bar` is listed in workspace’s default-members \
1647 but is not a member.
1648 ",
1649 )
1650 .run();
1651 }
1652
1653 #[cargo_test]
excluded_default_members_crate_glob()1654 fn excluded_default_members_crate_glob() {
1655 let p = project()
1656 .file(
1657 "Cargo.toml",
1658 r#"
1659 [workspace]
1660 members = ["foo", "bar/*"]
1661 default-members = ["bar/*"]
1662 exclude = ["bar/quux"]
1663 "#,
1664 )
1665 .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
1666 .file("foo/src/main.rs", "fn main() {}")
1667 .file("bar/baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
1668 .file("bar/baz/src/main.rs", "fn main() {}")
1669 .file("bar/quux/Cargo.toml", &basic_manifest("quux", "0.1.0"))
1670 .file("bar/quux/src/main.rs", "fn main() {}");
1671
1672 let p = p.build();
1673 p.cargo("build").run();
1674
1675 assert!(p.root().join("target").is_dir());
1676 assert!(!p.bin("foo").is_file());
1677 assert!(p.bin("baz").is_file());
1678 assert!(!p.bin("quux").exists());
1679
1680 p.cargo("build --workspace").run();
1681 assert!(p.root().join("target").is_dir());
1682 assert!(p.bin("foo").is_file());
1683 assert!(!p.bin("quux").exists());
1684
1685 p.cargo("build").cwd("bar/quux").run();
1686 assert!(p.root().join("bar/quux/target").is_dir());
1687 }
1688
1689 #[cargo_test]
excluded_default_members_not_crate_glob()1690 fn excluded_default_members_not_crate_glob() {
1691 let p = project()
1692 .file(
1693 "Cargo.toml",
1694 r#"
1695 [workspace]
1696 members = ["foo", "bar/*"]
1697 default-members = ["bar/*"]
1698 exclude = ["bar/docs"]
1699 "#,
1700 )
1701 .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
1702 .file("foo/src/main.rs", "fn main() {}")
1703 .file("bar/baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
1704 .file("bar/baz/src/main.rs", "fn main() {}")
1705 .file("bar/docs/readme.txt", "This folder is not a crate!");
1706
1707 let p = p.build();
1708 p.cargo("build").run();
1709
1710 assert!(!p.bin("foo").is_file());
1711 assert!(p.bin("baz").is_file());
1712 p.cargo("build --workspace").run();
1713 assert!(p.bin("foo").is_file());
1714 }
1715
1716 #[cargo_test]
glob_syntax()1717 fn glob_syntax() {
1718 let p = project()
1719 .file(
1720 "Cargo.toml",
1721 r#"
1722 [project]
1723 name = "foo"
1724 version = "0.1.0"
1725 authors = []
1726
1727 [workspace]
1728 members = ["crates/*"]
1729 exclude = ["crates/qux"]
1730 "#,
1731 )
1732 .file("src/main.rs", "fn main() {}")
1733 .file(
1734 "crates/bar/Cargo.toml",
1735 r#"
1736 [project]
1737 name = "bar"
1738 version = "0.1.0"
1739 authors = []
1740 workspace = "../.."
1741 "#,
1742 )
1743 .file("crates/bar/src/main.rs", "fn main() {}")
1744 .file(
1745 "crates/baz/Cargo.toml",
1746 r#"
1747 [project]
1748 name = "baz"
1749 version = "0.1.0"
1750 authors = []
1751 workspace = "../.."
1752 "#,
1753 )
1754 .file("crates/baz/src/main.rs", "fn main() {}")
1755 .file(
1756 "crates/qux/Cargo.toml",
1757 r#"
1758 [project]
1759 name = "qux"
1760 version = "0.1.0"
1761 authors = []
1762 "#,
1763 )
1764 .file("crates/qux/src/main.rs", "fn main() {}");
1765 let p = p.build();
1766
1767 p.cargo("build").run();
1768 assert!(p.bin("foo").is_file());
1769 assert!(!p.bin("bar").is_file());
1770 assert!(!p.bin("baz").is_file());
1771
1772 p.cargo("build").cwd("crates/bar").run();
1773 assert!(p.bin("foo").is_file());
1774 assert!(p.bin("bar").is_file());
1775
1776 p.cargo("build").cwd("crates/baz").run();
1777 assert!(p.bin("foo").is_file());
1778 assert!(p.bin("baz").is_file());
1779
1780 p.cargo("build").cwd("crates/qux").run();
1781 assert!(!p.bin("qux").is_file());
1782
1783 assert!(p.root().join("Cargo.lock").is_file());
1784 assert!(!p.root().join("crates/bar/Cargo.lock").is_file());
1785 assert!(!p.root().join("crates/baz/Cargo.lock").is_file());
1786 assert!(p.root().join("crates/qux/Cargo.lock").is_file());
1787 }
1788
1789 /*FIXME: This fails because of how workspace.exclude and workspace.members are working.
1790 #[cargo_test]
1791 fn glob_syntax_2() {
1792 let p = project()
1793 .file("Cargo.toml", r#"
1794 [project]
1795 name = "foo"
1796 version = "0.1.0"
1797 authors = []
1798
1799 [workspace]
1800 members = ["crates/b*"]
1801 exclude = ["crates/q*"]
1802 "#)
1803 .file("src/main.rs", "fn main() {}")
1804 .file("crates/bar/Cargo.toml", r#"
1805 [project]
1806 name = "bar"
1807 version = "0.1.0"
1808 authors = []
1809 workspace = "../.."
1810 "#)
1811 .file("crates/bar/src/main.rs", "fn main() {}")
1812 .file("crates/baz/Cargo.toml", r#"
1813 [project]
1814 name = "baz"
1815 version = "0.1.0"
1816 authors = []
1817 workspace = "../.."
1818 "#)
1819 .file("crates/baz/src/main.rs", "fn main() {}")
1820 .file("crates/qux/Cargo.toml", r#"
1821 [project]
1822 name = "qux"
1823 version = "0.1.0"
1824 authors = []
1825 "#)
1826 .file("crates/qux/src/main.rs", "fn main() {}");
1827 p.build();
1828
1829 p.cargo("build").run();
1830 assert!(p.bin("foo").is_file());
1831 assert!(!p.bin("bar").is_file());
1832 assert!(!p.bin("baz").is_file());
1833
1834 p.cargo("build").cwd("crates/bar").run();
1835 assert!(p.bin("foo").is_file());
1836 assert!(p.bin("bar").is_file());
1837
1838 p.cargo("build").cwd("crates/baz").run();
1839 assert!(p.bin("foo").is_file());
1840 assert!(p.bin("baz").is_file());
1841
1842 p.cargo("build").cwd("crates/qux").run();
1843 assert!(!p.bin("qux").is_file());
1844
1845 assert!(p.root().join("Cargo.lock").is_file());
1846 assert!(!p.root().join("crates/bar/Cargo.lock").is_file());
1847 assert!(!p.root().join("crates/baz/Cargo.lock").is_file());
1848 assert!(p.root().join("crates/qux/Cargo.lock").is_file());
1849 }
1850 */
1851
1852 #[cargo_test]
glob_syntax_invalid_members()1853 fn glob_syntax_invalid_members() {
1854 let p = project()
1855 .file(
1856 "Cargo.toml",
1857 r#"
1858 [project]
1859 name = "foo"
1860 version = "0.1.0"
1861 authors = []
1862
1863 [workspace]
1864 members = ["crates/*"]
1865 "#,
1866 )
1867 .file("src/main.rs", "fn main() {}")
1868 .file("crates/bar/src/main.rs", "fn main() {}");
1869 let p = p.build();
1870
1871 p.cargo("build")
1872 .with_status(101)
1873 .with_stderr(
1874 "\
1875 [ERROR] failed to load manifest for workspace member `[..]/crates/bar`
1876
1877 Caused by:
1878 failed to read `[..]foo/crates/bar/Cargo.toml`
1879
1880 Caused by:
1881 [..]
1882 ",
1883 )
1884 .run();
1885 }
1886
1887 /// This is a freshness test for feature use with workspaces.
1888 ///
1889 /// `feat_lib` is used by `caller1` and `caller2`, but with different features enabled.
1890 /// This test ensures that alternating building `caller1`, `caller2` doesn't force
1891 /// recompile of `feat_lib`.
1892 ///
1893 /// Ideally, once we solve rust-lang/cargo#3620, then a single Cargo build at the top level
1894 /// will be enough.
1895 #[cargo_test]
dep_used_with_separate_features()1896 fn dep_used_with_separate_features() {
1897 let p = project()
1898 .file(
1899 "Cargo.toml",
1900 r#"
1901 [workspace]
1902 members = ["feat_lib", "caller1", "caller2"]
1903 "#,
1904 )
1905 .file(
1906 "feat_lib/Cargo.toml",
1907 r#"
1908 [project]
1909 name = "feat_lib"
1910 version = "0.1.0"
1911 authors = []
1912
1913 [features]
1914 myfeature = []
1915 "#,
1916 )
1917 .file("feat_lib/src/lib.rs", "")
1918 .file(
1919 "caller1/Cargo.toml",
1920 r#"
1921 [project]
1922 name = "caller1"
1923 version = "0.1.0"
1924 authors = []
1925
1926 [dependencies]
1927 feat_lib = { path = "../feat_lib" }
1928 "#,
1929 )
1930 .file("caller1/src/main.rs", "fn main() {}")
1931 .file("caller1/src/lib.rs", "")
1932 .file(
1933 "caller2/Cargo.toml",
1934 r#"
1935 [project]
1936 name = "caller2"
1937 version = "0.1.0"
1938 authors = []
1939
1940 [dependencies]
1941 feat_lib = { path = "../feat_lib", features = ["myfeature"] }
1942 caller1 = { path = "../caller1" }
1943 "#,
1944 )
1945 .file("caller2/src/main.rs", "fn main() {}")
1946 .file("caller2/src/lib.rs", "");
1947 let p = p.build();
1948
1949 // Build the entire workspace.
1950 p.cargo("build --workspace")
1951 .with_stderr(
1952 "\
1953 [..]Compiling feat_lib v0.1.0 ([..])
1954 [..]Compiling caller1 v0.1.0 ([..])
1955 [..]Compiling caller2 v0.1.0 ([..])
1956 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1957 ",
1958 )
1959 .run();
1960 assert!(p.bin("caller1").is_file());
1961 assert!(p.bin("caller2").is_file());
1962
1963 // Build `caller1`. Should build the dep library. Because the features
1964 // are different than the full workspace, it rebuilds.
1965 // Ideally once we solve rust-lang/cargo#3620, then a single Cargo build at the top level
1966 // will be enough.
1967 p.cargo("build")
1968 .cwd("caller1")
1969 .with_stderr(
1970 "\
1971 [..]Compiling feat_lib v0.1.0 ([..])
1972 [..]Compiling caller1 v0.1.0 ([..])
1973 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1974 ",
1975 )
1976 .run();
1977
1978 // Alternate building `caller2`/`caller1` a few times, just to make sure
1979 // features are being built separately. Should not rebuild anything.
1980 p.cargo("build")
1981 .cwd("caller2")
1982 .with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]")
1983 .run();
1984 p.cargo("build")
1985 .cwd("caller1")
1986 .with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]")
1987 .run();
1988 p.cargo("build")
1989 .cwd("caller2")
1990 .with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]")
1991 .run();
1992 }
1993
1994 #[cargo_test]
dont_recurse_out_of_cargo_home()1995 fn dont_recurse_out_of_cargo_home() {
1996 let git_project = git::new("dep", |project| {
1997 project
1998 .file("Cargo.toml", &basic_manifest("dep", "0.1.0"))
1999 .file("src/lib.rs", "")
2000 .file(
2001 "build.rs",
2002 r#"
2003 use std::env;
2004 use std::path::Path;
2005 use std::process::{self, Command};
2006
2007 fn main() {
2008 let cargo = env::var_os("CARGO").unwrap();
2009 let cargo_manifest_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap();
2010 let output = Command::new(cargo)
2011 .args(&["metadata", "--format-version", "1", "--manifest-path"])
2012 .arg(&Path::new(&cargo_manifest_dir).join("Cargo.toml"))
2013 .output()
2014 .unwrap();
2015 if !output.status.success() {
2016 eprintln!("{}", String::from_utf8(output.stderr).unwrap());
2017 process::exit(1);
2018 }
2019 }
2020 "#,
2021 )
2022 });
2023 let p = project()
2024 .file(
2025 "Cargo.toml",
2026 &format!(
2027 r#"
2028 [package]
2029 name = "foo"
2030 version = "0.1.0"
2031
2032 [dependencies.dep]
2033 git = "{}"
2034
2035 [workspace]
2036 "#,
2037 git_project.url()
2038 ),
2039 )
2040 .file("src/lib.rs", "");
2041 let p = p.build();
2042
2043 p.cargo("build")
2044 .env("CARGO_HOME", p.root().join(".cargo"))
2045 .run();
2046 }
2047
2048 // FIXME: this fails because of how workspace.exclude and workspace.members are working.
2049 /*
2050 #[cargo_test]
2051 fn include_and_exclude() {
2052 let p = project()
2053 .file("Cargo.toml", r#"
2054 [workspace]
2055 members = ["foo"]
2056 exclude = ["foo/bar"]
2057 "#)
2058 .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
2059 .file("foo/src/lib.rs", "")
2060 .file("foo/bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
2061 .file("foo/bar/src/lib.rs", "");
2062 p.build();
2063
2064 p.cargo("build").cwd("foo").run();
2065 assert!(p.root().join("target").is_dir());
2066 assert!(!p.root().join("foo/target").is_dir());
2067 p.cargo("build").cwd("foo/bar").run();
2068 assert!(p.root().join("foo/bar/target").is_dir());
2069 }
2070 */
2071
2072 #[cargo_test]
cargo_home_at_root_works()2073 fn cargo_home_at_root_works() {
2074 let p = project()
2075 .file(
2076 "Cargo.toml",
2077 r#"
2078 [package]
2079 name = "foo"
2080 version = "0.1.0"
2081
2082 [workspace]
2083 members = ["a"]
2084 "#,
2085 )
2086 .file("src/lib.rs", "")
2087 .file("a/Cargo.toml", &basic_manifest("a", "0.1.0"))
2088 .file("a/src/lib.rs", "");
2089 let p = p.build();
2090
2091 p.cargo("build").run();
2092 p.cargo("build --frozen").env("CARGO_HOME", p.root()).run();
2093 }
2094
2095 #[cargo_test]
relative_rustc()2096 fn relative_rustc() {
2097 let p = project()
2098 .file(
2099 "src/main.rs",
2100 r#"
2101 use std::process::Command;
2102 use std::env;
2103
2104 fn main() {
2105 let mut cmd = Command::new("rustc");
2106 for arg in env::args_os().skip(1) {
2107 cmd.arg(arg);
2108 }
2109 std::process::exit(cmd.status().unwrap().code().unwrap());
2110 }
2111 "#,
2112 )
2113 .build();
2114 p.cargo("build").run();
2115
2116 let src = p
2117 .root()
2118 .join("target/debug/foo")
2119 .with_extension(env::consts::EXE_EXTENSION);
2120
2121 Package::new("a", "0.1.0").publish();
2122
2123 let p = project()
2124 .at("lib")
2125 .file(
2126 "Cargo.toml",
2127 r#"
2128 [package]
2129 name = "lib"
2130 version = "0.1.0"
2131
2132 [dependencies]
2133 a = "0.1"
2134 "#,
2135 )
2136 .file("src/lib.rs", "")
2137 .build();
2138
2139 fs::copy(&src, p.root().join(src.file_name().unwrap())).unwrap();
2140
2141 let file = format!("./foo{}", env::consts::EXE_SUFFIX);
2142 p.cargo("build").env("RUSTC", &file).run();
2143 }
2144
2145 #[cargo_test]
ws_rustc_err()2146 fn ws_rustc_err() {
2147 let p = project()
2148 .file(
2149 "Cargo.toml",
2150 r#"
2151 [workspace]
2152 members = ["a"]
2153 "#,
2154 )
2155 .file("a/Cargo.toml", &basic_lib_manifest("a"))
2156 .file("a/src/lib.rs", "")
2157 .build();
2158
2159 p.cargo("rustc")
2160 .with_status(101)
2161 .with_stderr("[ERROR] [..]against an actual package[..]")
2162 .run();
2163
2164 p.cargo("rustdoc")
2165 .with_status(101)
2166 .with_stderr("[ERROR] [..]against an actual package[..]")
2167 .run();
2168 }
2169
2170 #[cargo_test]
ws_err_unused()2171 fn ws_err_unused() {
2172 for key in &[
2173 "[lib]",
2174 "[[bin]]",
2175 "[[example]]",
2176 "[[test]]",
2177 "[[bench]]",
2178 "[dependencies]",
2179 "[dev-dependencies]",
2180 "[build-dependencies]",
2181 "[features]",
2182 "[target]",
2183 "[badges]",
2184 ] {
2185 let p = project()
2186 .file(
2187 "Cargo.toml",
2188 &format!(
2189 r#"
2190 [workspace]
2191 members = ["a"]
2192
2193 {}
2194 "#,
2195 key
2196 ),
2197 )
2198 .file("a/Cargo.toml", &basic_lib_manifest("a"))
2199 .file("a/src/lib.rs", "")
2200 .build();
2201 p.cargo("check")
2202 .with_status(101)
2203 .with_stderr(&format!(
2204 "\
2205 [ERROR] failed to parse manifest at `[..]/foo/Cargo.toml`
2206
2207 Caused by:
2208 this virtual manifest specifies a {} section, which is not allowed
2209 ",
2210 key
2211 ))
2212 .run();
2213 }
2214 }
2215
2216 #[cargo_test]
ws_warn_unused()2217 fn ws_warn_unused() {
2218 for (key, name) in &[
2219 ("[profile.dev]\nopt-level = 1", "profiles"),
2220 ("[replace]\n\"bar:0.1.0\" = { path = \"bar\" }", "replace"),
2221 ("[patch.crates-io]\nbar = { path = \"bar\" }", "patch"),
2222 ] {
2223 let p = project()
2224 .file(
2225 "Cargo.toml",
2226 r#"
2227 [workspace]
2228 members = ["a"]
2229 "#,
2230 )
2231 .file(
2232 "a/Cargo.toml",
2233 &format!(
2234 r#"
2235 [package]
2236 name = "a"
2237 version = "0.1.0"
2238
2239 {}
2240 "#,
2241 key
2242 ),
2243 )
2244 .file("a/src/lib.rs", "")
2245 .build();
2246 p.cargo("check")
2247 .with_stderr_contains(&format!(
2248 "\
2249 [WARNING] {} for the non root package will be ignored, specify {} at the workspace root:
2250 package: [..]/foo/a/Cargo.toml
2251 workspace: [..]/foo/Cargo.toml
2252 ",
2253 name, name
2254 ))
2255 .run();
2256 }
2257 }
2258
2259 #[cargo_test]
ws_warn_path()2260 fn ws_warn_path() {
2261 // Warnings include path to manifest.
2262 let p = project()
2263 .file(
2264 "Cargo.toml",
2265 r#"
2266 [workspace]
2267 members = ["a"]
2268 "#,
2269 )
2270 .file(
2271 "a/Cargo.toml",
2272 r#"
2273 cargo-features = ["edition"]
2274 [package]
2275 name = "foo"
2276 version = "0.1.0"
2277 "#,
2278 )
2279 .file("a/src/lib.rs", "")
2280 .build();
2281
2282 p.cargo("check")
2283 .with_stderr_contains("[WARNING] [..]/foo/a/Cargo.toml: the cargo feature `edition`[..]")
2284 .run();
2285 }
2286
2287 #[cargo_test]
invalid_missing()2288 fn invalid_missing() {
2289 // Make sure errors are not suppressed with -q.
2290 let p = project()
2291 .file(
2292 "Cargo.toml",
2293 r#"
2294 [package]
2295 name = "foo"
2296 version = "0.1.0"
2297
2298 [dependencies]
2299 x = { path = 'x' }
2300 "#,
2301 )
2302 .file("src/lib.rs", "")
2303 .build();
2304
2305 p.cargo("build -q")
2306 .with_status(101)
2307 .with_stderr(
2308 "\
2309 [ERROR] failed to get `x` as a dependency of package `foo v0.1.0 [..]`
2310
2311 Caused by:
2312 failed to load source for dependency `x`
2313
2314 Caused by:
2315 Unable to update [..]/foo/x
2316
2317 Caused by:
2318 failed to read `[..]foo/x/Cargo.toml`
2319
2320 Caused by:
2321 [..]
2322 ",
2323 )
2324 .run();
2325 }
2326
2327 #[cargo_test]
member_dep_missing()2328 fn member_dep_missing() {
2329 // Make sure errors are not suppressed with -q.
2330 let p = project()
2331 .file(
2332 "Cargo.toml",
2333 r#"
2334 [project]
2335 name = "foo"
2336 version = "0.1.0"
2337
2338 [workspace]
2339 members = ["bar"]
2340 "#,
2341 )
2342 .file("src/main.rs", "fn main() {}")
2343 .file(
2344 "bar/Cargo.toml",
2345 r#"
2346 [project]
2347 name = "bar"
2348 version = "0.1.0"
2349
2350 [dependencies]
2351 baz = { path = "baz" }
2352 "#,
2353 )
2354 .file("bar/src/main.rs", "fn main() {}")
2355 .build();
2356
2357 p.cargo("build -q")
2358 .with_status(101)
2359 .with_stderr(
2360 "\
2361 [ERROR] failed to load manifest for workspace member `[..]/bar`
2362
2363 Caused by:
2364 failed to load manifest for dependency `baz`
2365
2366 Caused by:
2367 failed to read `[..]foo/bar/baz/Cargo.toml`
2368
2369 Caused by:
2370 [..]
2371 ",
2372 )
2373 .run();
2374 }
2375
2376 #[cargo_test]
simple_primary_package_env_var()2377 fn simple_primary_package_env_var() {
2378 let is_primary_package = r#"
2379 #[test]
2380 fn verify_primary_package() {{
2381 assert!(option_env!("CARGO_PRIMARY_PACKAGE").is_some());
2382 }}
2383 "#;
2384
2385 let p = project()
2386 .file(
2387 "Cargo.toml",
2388 r#"
2389 [project]
2390 name = "foo"
2391 version = "0.1.0"
2392 authors = []
2393
2394 [workspace]
2395 members = ["bar"]
2396 "#,
2397 )
2398 .file("src/lib.rs", is_primary_package)
2399 .file(
2400 "bar/Cargo.toml",
2401 r#"
2402 [project]
2403 name = "bar"
2404 version = "0.1.0"
2405 authors = []
2406 workspace = ".."
2407 "#,
2408 )
2409 .file("bar/src/lib.rs", is_primary_package);
2410 let p = p.build();
2411
2412 p.cargo("test").run();
2413
2414 // Again, this time selecting a specific crate
2415 p.cargo("clean").run();
2416 p.cargo("test -p bar").run();
2417
2418 // Again, this time selecting all crates
2419 p.cargo("clean").run();
2420 p.cargo("test --all").run();
2421 }
2422
2423 #[cargo_test]
virtual_primary_package_env_var()2424 fn virtual_primary_package_env_var() {
2425 let is_primary_package = r#"
2426 #[test]
2427 fn verify_primary_package() {{
2428 assert!(option_env!("CARGO_PRIMARY_PACKAGE").is_some());
2429 }}
2430 "#;
2431
2432 let p = project()
2433 .file(
2434 "Cargo.toml",
2435 r#"
2436 [workspace]
2437 members = ["foo", "bar"]
2438 "#,
2439 )
2440 .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
2441 .file("foo/src/lib.rs", is_primary_package)
2442 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
2443 .file("bar/src/lib.rs", is_primary_package);
2444 let p = p.build();
2445
2446 p.cargo("test").run();
2447
2448 // Again, this time selecting a specific crate
2449 p.cargo("clean").run();
2450 p.cargo("test -p foo").run();
2451 }
2452