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