cargo/tests/testsuite/workspaces.rs

2371 lines
56 KiB
Rust
Raw Normal View History

use std::env;
use std::fs::{self, File};
use std::io::{Read, Write};
use cargotest::sleep_ms;
use cargotest::support::{basic_lib_manifest, execs, git, project};
use cargotest::support::registry::Package;
2018-03-14 15:17:44 +00:00
use hamcrest::{assert_that, existing_dir, existing_file, is_not};
#[test]
fn simple_explicit() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
workspace = ".."
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), is_not(existing_file()));
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("bar")),
execs().with_status(0),
);
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), existing_file());
assert_that(&p.root().join("Cargo.lock"), existing_file());
assert_that(&p.root().join("bar/Cargo.lock"), is_not(existing_file()));
}
#[test]
fn simple_explicit_default_members() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["bar"]
default-members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
workspace = ".."
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.bin("bar"), existing_file());
assert_that(&p.bin("foo"), is_not(existing_file()));
}
#[test]
fn inferred_root() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), is_not(existing_file()));
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("bar")),
execs().with_status(0),
);
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), existing_file());
assert_that(&p.root().join("Cargo.lock"), existing_file());
assert_that(&p.root().join("bar/Cargo.lock"), is_not(existing_file()));
}
#[test]
fn inferred_path_dep() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
bar = { path = "bar" }
[workspace]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}")
.file("bar/src/lib.rs", "");
let p = p.build();
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), is_not(existing_file()));
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("bar")),
execs().with_status(0),
);
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), existing_file());
assert_that(&p.root().join("Cargo.lock"), existing_file());
assert_that(&p.root().join("bar/Cargo.lock"), is_not(existing_file()));
}
#[test]
fn transitive_path_dep() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
bar = { path = "bar" }
[workspace]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
[dependencies]
baz = { path = "../baz" }
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}")
.file("bar/src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"baz/Cargo.toml",
r#"
[project]
name = "baz"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("baz/src/main.rs", "fn main() {}")
.file("baz/src/lib.rs", "");
let p = p.build();
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), is_not(existing_file()));
assert_that(&p.bin("baz"), is_not(existing_file()));
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("bar")),
execs().with_status(0),
);
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), existing_file());
assert_that(&p.bin("baz"), is_not(existing_file()));
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("baz")),
execs().with_status(0),
);
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), existing_file());
assert_that(&p.bin("baz"), existing_file());
assert_that(&p.root().join("Cargo.lock"), existing_file());
assert_that(&p.root().join("bar/Cargo.lock"), is_not(existing_file()));
assert_that(&p.root().join("baz/Cargo.lock"), is_not(existing_file()));
}
#[test]
fn parent_pointer_works() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"foo/Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
bar = { path = "../bar" }
[workspace]
2018-03-14 15:17:44 +00:00
"#,
)
.file("foo/src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
workspace = "../foo"
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}")
.file("bar/src/lib.rs", "");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("foo")),
execs().with_status(0),
);
assert_that(
p.cargo("build").cwd(p.root().join("bar")),
execs().with_status(0),
);
assert_that(&p.root().join("foo/Cargo.lock"), existing_file());
assert_that(&p.root().join("bar/Cargo.lock"), is_not(existing_file()));
}
#[test]
fn same_names_in_workspace() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
workspace = ".."
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
execs().with_status(101).with_stderr(
"\
error: two packages named `foo` in this workspace:
- [..]Cargo.toml
- [..]Cargo.toml
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn parent_doesnt_point_to_child() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("bar")),
execs().with_status(101).with_stderr(
"\
error: current package believes it's in a workspace when it's not:
current: [..]Cargo.toml
workspace: [..]Cargo.toml
this may be fixable [..]
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn invalid_parent_pointer() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
workspace = "foo"
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
execs().with_status(101).with_stderr(
"\
error: failed to read `[..]Cargo.toml`
Caused by:
[..]
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn invalid_members() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["foo"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
execs().with_status(101).with_stderr(
"\
error: failed to read `[..]Cargo.toml`
Caused by:
[..]
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn bare_workspace_ok() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}");
let p = p.build();
assert_that(p.cargo("build"), execs().with_status(0));
}
#[test]
fn two_roots() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
[workspace]
members = [".."]
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
execs().with_status(101).with_stderr(
"\
error: multiple workspace roots found in the same workspace:
[..]
[..]
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn workspace_isnt_root() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
workspace = "bar"
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
2018-03-14 15:43:41 +00:00
execs()
.with_status(101)
.with_stderr("error: root of a workspace inferred but wasn't a root: [..]"),
2018-03-14 15:17:44 +00:00
);
}
#[test]
fn dangling_member() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
workspace = "../baz"
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"baz/Cargo.toml",
r#"
[project]
name = "baz"
version = "0.1.0"
authors = []
workspace = "../baz"
2018-03-14 15:17:44 +00:00
"#,
)
.file("baz/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
execs().with_status(101).with_stderr(
"\
error: package `[..]` is a member of the wrong workspace
expected: [..]
actual: [..]
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn cycle() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
workspace = "bar"
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
workspace = ".."
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(p.cargo("build"), execs().with_status(101));
}
#[test]
fn share_dependencies() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
dep1 = "0.1"
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
[dependencies]
dep1 = "< 0.1.5"
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
Package::new("dep1", "0.1.3").publish();
Package::new("dep1", "0.1.8").publish();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `[..]`
[DOWNLOADING] dep1 v0.1.3 ([..])
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[COMPILING] dep1 v0.1.3
[COMPILING] foo v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn fetch_fetches_all() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
[dependencies]
dep1 = "*"
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
Package::new("dep1", "0.1.3").publish();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("fetch"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `[..]`
[DOWNLOADING] dep1 v0.1.3 ([..])
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn lock_works_for_everyone() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
dep2 = "0.1"
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
[dependencies]
dep1 = "0.1"
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
Package::new("dep1", "0.1.0").publish();
Package::new("dep2", "0.1.0").publish();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("generate-lockfile"),
2018-03-14 15:43:41 +00:00
execs()
.with_status(0)
.with_stderr("[UPDATING] registry `[..]`"),
2018-03-14 15:17:44 +00:00
);
Package::new("dep1", "0.1.1").publish();
Package::new("dep2", "0.1.1").publish();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[DOWNLOADING] dep2 v0.1.0 ([..])
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[COMPILING] dep2 v0.1.0
[COMPILING] foo v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
),
);
assert_that(
p.cargo("build").cwd(p.root().join("bar")),
execs().with_status(0).with_stderr(
"\
[DOWNLOADING] dep1 v0.1.0 ([..])
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[COMPILING] dep1 v0.1.0
[COMPILING] bar v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn virtual_works() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("bar")),
execs().with_status(0),
);
assert_that(&p.root().join("Cargo.lock"), existing_file());
assert_that(&p.bin("bar"), existing_file());
assert_that(&p.root().join("bar/Cargo.lock"), is_not(existing_file()));
}
#[test]
fn explicit_package_argument_works_with_virtual_manifest() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root()).args(&["--package", "bar"]),
execs().with_status(0),
);
assert_that(&p.root().join("Cargo.lock"), existing_file());
assert_that(&p.bin("bar"), existing_file());
assert_that(&p.root().join("bar/Cargo.lock"), is_not(existing_file()));
}
#[test]
fn virtual_misconfigure() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("bar")),
execs().with_status(101).with_stderr(
"\
error: current package believes it's in a workspace when it's not:
current: [..]bar[..]Cargo.toml
workspace: [..]Cargo.toml
this may be fixable by adding `bar` to the `workspace.members` array of the \
manifest located at: [..]
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
2017-05-26 21:00:45 +00:00
fn virtual_build_all_implied() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(p.cargo("build"), execs().with_status(0));
}
#[test]
fn virtual_default_members() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["bar", "baz"]
default-members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"baz/Cargo.toml",
r#"
[project]
name = "baz"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}")
.file("baz/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.bin("bar"), existing_file());
assert_that(&p.bin("baz"), is_not(existing_file()));
}
#[test]
fn virtual_default_member_is_not_a_member() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["bar"]
default-members = ["something-else"]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
execs().with_status(101).with_stderr(
"\
error: package `[..]something-else` is listed in workspaces default-members \
but is not a member.
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn virtual_build_no_members() {
let p = project().file(
2018-03-14 15:17:44 +00:00
"Cargo.toml",
r#"
[workspace]
2018-03-14 15:17:44 +00:00
"#,
);
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
execs().with_status(101).with_stderr(
"\
error: manifest path `[..]` contains no package: The manifest is virtual, \
and the workspace has no members.
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn include_virtual() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
[workspace]
members = ["bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[workspace]
2018-03-14 15:17:44 +00:00
"#,
);
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
execs().with_status(101).with_stderr(
"\
error: multiple workspace roots found in the same workspace:
[..]
[..]
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn members_include_path_deps() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["p1"]
[dependencies]
p3 = { path = "p3" }
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"p1/Cargo.toml",
r#"
[project]
name = "p1"
version = "0.1.0"
authors = []
[dependencies]
p2 = { path = "../p2" }
2018-03-14 15:17:44 +00:00
"#,
)
.file("p1/src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"p2/Cargo.toml",
r#"
[project]
name = "p2"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("p2/src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"p3/Cargo.toml",
r#"
[project]
name = "p3"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("p3/src/lib.rs", "");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("p1")),
execs().with_status(0),
);
assert_that(
p.cargo("build").cwd(p.root().join("p2")),
execs().with_status(0),
);
assert_that(
p.cargo("build").cwd(p.root().join("p3")),
execs().with_status(0),
);
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.root().join("target"), existing_dir());
assert_that(&p.root().join("p1/target"), is_not(existing_dir()));
assert_that(&p.root().join("p2/target"), is_not(existing_dir()));
assert_that(&p.root().join("p3/target"), is_not(existing_dir()));
}
#[test]
fn new_warns_you_this_will_not_work() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/lib.rs", "");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("new").arg("--lib").arg("bar").env("USER", "foo"),
execs().with_status(0).with_stderr(
"\
warning: compiling this new crate may not work due to invalid workspace \
configuration
current package believes it's in a workspace when it's not:
current: [..]
workspace: [..]
this may be fixable by ensuring that this crate is depended on by the workspace \
root: [..]
[CREATED] library `bar` project
2018-03-14 15:17:44 +00:00
",
),
);
}
#[test]
fn lock_doesnt_change_depending_on_crate() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ['baz']
[dependencies]
foo = "*"
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"baz/Cargo.toml",
r#"
[project]
name = "baz"
version = "0.1.0"
authors = []
[dependencies]
bar = "*"
2018-03-14 15:17:44 +00:00
"#,
)
.file("baz/src/lib.rs", "");
let p = p.build();
Package::new("foo", "1.0.0").publish();
Package::new("bar", "1.0.0").publish();
2018-03-14 15:17:44 +00:00
assert_that(p.cargo("build"), execs().with_status(0));
let mut lockfile = String::new();
t!(t!(File::open(p.root().join("Cargo.lock"))).read_to_string(&mut lockfile));
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("baz")),
execs().with_status(0),
);
let mut lockfile2 = String::new();
t!(t!(File::open(p.root().join("Cargo.lock"))).read_to_string(&mut lockfile2));
assert_eq!(lockfile, lockfile2);
}
#[test]
fn rebuild_please() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ['lib', 'bin']
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"lib/Cargo.toml",
r#"
[package]
name = "lib"
version = "0.1.0"
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"lib/src/lib.rs",
r#"
pub fn foo() -> u32 { 0 }
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"bin/Cargo.toml",
r#"
[package]
name = "bin"
version = "0.1.0"
[dependencies]
lib = { path = "../lib" }
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"bin/src/main.rs",
r#"
extern crate lib;
fn main() {
assert_eq!(lib::foo(), 0);
}
2018-03-14 15:17:44 +00:00
"#,
);
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("run").cwd(p.root().join("bin")),
execs().with_status(0),
);
sleep_ms(1000);
2018-03-14 15:17:44 +00:00
t!(t!(File::create(p.root().join("lib/src/lib.rs"))).write_all(
br#"
pub fn foo() -> u32 { 1 }
2018-03-14 15:17:44 +00:00
"#
));
assert_that(
p.cargo("build").cwd(p.root().join("lib")),
execs().with_status(0),
);
assert_that(
p.cargo("run").cwd(p.root().join("bin")),
execs().with_status(101),
);
}
#[test]
fn workspace_in_git() {
let git_project = git::new("dep1", |project| {
project
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["foo"]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
2018-03-14 15:17:44 +00:00
"#,
)
.file("foo/src/lib.rs", "")
}).unwrap();
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
&format!(
r#"
[package]
name = "lib"
version = "0.1.0"
[dependencies.foo]
git = '{}'
2018-03-14 15:17:44 +00:00
"#,
git_project.url()
),
)
.file(
"src/lib.rs",
r#"
pub fn foo() -> u32 { 0 }
2018-03-14 15:17:44 +00:00
"#,
);
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(p.cargo("build"), execs().with_status(0));
}
#[test]
fn lockfile_can_specify_nonexistant_members() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["a"]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"a/Cargo.toml",
r#"
[project]
name = "a"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("a/src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"Cargo.lock",
r#"
[[package]]
name = "a"
version = "0.1.0"
[[package]]
name = "b"
version = "0.1.0"
2018-03-14 15:17:44 +00:00
"#,
);
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("a")),
execs().with_status(0),
);
}
#[test]
fn you_cannot_generate_lockfile_for_empty_workspaces() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"bar/Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("update"),
2018-03-14 15:43:41 +00:00
execs()
.with_status(101)
.with_stderr("error: you can't generate a lockfile for an empty workspace."),
2018-03-14 15:17:44 +00:00
);
}
#[test]
fn workspace_with_transitive_dev_deps() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["mbrubeck@example.com"]
[dependencies.bar]
path = "bar"
[workspace]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/main.rs", r#"fn main() {}"#)
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["mbrubeck@example.com"]
[dev-dependencies.baz]
path = "../baz"
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"bar/src/lib.rs",
r#"
pub fn init() {}
#[cfg(test)]
#[test]
fn test() {
extern crate baz;
baz::do_stuff();
}
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"baz/Cargo.toml",
r#"
[project]
name = "baz"
version = "0.5.0"
authors = ["mbrubeck@example.com"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("baz/src/lib.rs", r#"pub fn do_stuff() {}"#);
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(p.cargo("test").args(&["-p", "bar"]), execs().with_status(0));
}
#[test]
fn error_if_parent_cargo_toml_is_invalid() {
let p = project()
.file("Cargo.toml", "Totally not a TOML file")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("bar")),
2018-03-14 15:43:41 +00:00
execs()
.with_status(101)
.with_stderr_contains("[ERROR] failed to parse manifest at `[..]`"),
2018-03-14 15:17:44 +00:00
);
}
#[test]
fn relative_path_for_member_works() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"foo/Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["../bar"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("foo/src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
workspace = "../foo"
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("foo")),
execs().with_status(0),
);
assert_that(
p.cargo("build").cwd(p.root().join("bar")),
execs().with_status(0),
);
}
2017-02-14 20:04:24 +00:00
#[test]
fn relative_path_for_root_works() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2017-02-14 20:04:24 +00:00
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
[dependencies]
subproj = { path = "./subproj" }
2018-03-14 15:17:44 +00:00
"#,
)
2017-02-14 20:04:24 +00:00
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"subproj/Cargo.toml",
r#"
2017-02-14 20:04:24 +00:00
[project]
name = "subproj"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
2017-02-14 20:04:24 +00:00
.file("subproj/src/main.rs", "fn main() {}");
let p = p.build();
2017-02-14 20:04:24 +00:00
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build")
.cwd(p.root())
.arg("--manifest-path")
.arg("./Cargo.toml"),
execs().with_status(0),
);
assert_that(
p.cargo("build")
.cwd(p.root().join("subproj"))
.arg("--manifest-path")
.arg("../Cargo.toml"),
execs().with_status(0),
);
2017-02-14 20:04:24 +00:00
}
#[test]
fn path_dep_outside_workspace_is_not_member() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"ws/Cargo.toml",
r#"
[project]
name = "ws"
version = "0.1.0"
authors = []
[dependencies]
foo = { path = "../foo" }
[workspace]
2018-03-14 15:17:44 +00:00
"#,
)
.file("ws/src/lib.rs", r"extern crate foo;")
2018-03-14 15:17:44 +00:00
.file(
"foo/Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("foo/src/lib.rs", "");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("ws")),
execs().with_status(0),
);
}
#[test]
fn test_in_and_out_of_workspace() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"ws/Cargo.toml",
r#"
[project]
name = "ws"
version = "0.1.0"
authors = []
[dependencies]
foo = { path = "../foo" }
[workspace]
members = [ "../bar" ]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"ws/src/lib.rs",
r"extern crate foo; pub fn f() { foo::f() }",
)
.file(
"foo/Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
bar = { path = "../bar" }
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"foo/src/lib.rs",
"extern crate bar; pub fn f() { bar::f() }",
)
.file(
"bar/Cargo.toml",
r#"
[project]
workspace = "../ws"
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("bar/src/lib.rs", "pub fn f() { }");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("ws")),
execs().with_status(0),
);
assert_that(&p.root().join("ws/Cargo.lock"), existing_file());
assert_that(&p.root().join("ws/target"), existing_dir());
assert_that(&p.root().join("foo/Cargo.lock"), is_not(existing_file()));
assert_that(&p.root().join("foo/target"), is_not(existing_dir()));
assert_that(&p.root().join("bar/Cargo.lock"), is_not(existing_file()));
assert_that(&p.root().join("bar/target"), is_not(existing_dir()));
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("foo")),
execs().with_status(0),
);
assert_that(&p.root().join("foo/Cargo.lock"), existing_file());
assert_that(&p.root().join("foo/target"), existing_dir());
assert_that(&p.root().join("bar/Cargo.lock"), is_not(existing_file()));
assert_that(&p.root().join("bar/target"), is_not(existing_dir()));
}
#[test]
fn test_path_dependency_under_member() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"ws/Cargo.toml",
r#"
[project]
name = "ws"
version = "0.1.0"
authors = []
[dependencies]
foo = { path = "../foo" }
[workspace]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"ws/src/lib.rs",
r"extern crate foo; pub fn f() { foo::f() }",
)
.file(
"foo/Cargo.toml",
r#"
[project]
workspace = "../ws"
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
bar = { path = "./bar" }
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"foo/src/lib.rs",
"extern crate bar; pub fn f() { bar::f() }",
)
.file(
"foo/bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("foo/bar/src/lib.rs", "pub fn f() { }");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("ws")),
execs().with_status(0),
);
2018-03-14 15:17:44 +00:00
assert_that(
&p.root().join("foo/bar/Cargo.lock"),
is_not(existing_file()),
);
assert_that(&p.root().join("foo/bar/target"), is_not(existing_dir()));
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("foo/bar")),
execs().with_status(0),
);
2018-03-14 15:17:44 +00:00
assert_that(
&p.root().join("foo/bar/Cargo.lock"),
is_not(existing_file()),
);
assert_that(&p.root().join("foo/bar/target"), is_not(existing_dir()));
}
#[test]
fn excluded_simple() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "ws"
version = "0.1.0"
authors = []
[workspace]
exclude = ["foo"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"foo/Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("foo/src/lib.rs", "");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.root().join("target"), existing_dir());
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("foo")),
execs().with_status(0),
);
assert_that(&p.root().join("foo/target"), existing_dir());
}
#[test]
fn exclude_members_preferred() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "ws"
version = "0.1.0"
authors = []
[workspace]
members = ["foo/bar"]
exclude = ["foo"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"foo/Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("foo/src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"foo/bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("foo/bar/src/lib.rs", "");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.root().join("target"), existing_dir());
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("foo")),
execs().with_status(0),
);
assert_that(&p.root().join("foo/target"), existing_dir());
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("foo/bar")),
execs().with_status(0),
);
assert_that(&p.root().join("foo/bar/target"), is_not(existing_dir()));
}
#[test]
fn exclude_but_also_depend() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "ws"
version = "0.1.0"
authors = []
[dependencies]
bar = { path = "foo/bar" }
[workspace]
exclude = ["foo"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"foo/Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("foo/src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"foo/bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("foo/bar/src/lib.rs", "");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.root().join("target"), existing_dir());
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("foo")),
execs().with_status(0),
);
assert_that(&p.root().join("foo/target"), existing_dir());
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("foo/bar")),
execs().with_status(0),
);
assert_that(&p.root().join("foo/bar/target"), existing_dir());
}
#[test]
fn glob_syntax() {
let p = project()
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["crates/*"]
exclude = ["crates/qux"]
"#)
.file("src/main.rs", "fn main() {}")
.file("crates/bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
workspace = "../.."
"#)
.file("crates/bar/src/main.rs", "fn main() {}")
.file("crates/baz/Cargo.toml", r#"
[project]
name = "baz"
version = "0.1.0"
authors = []
workspace = "../.."
"#)
.file("crates/baz/src/main.rs", "fn main() {}")
.file("crates/qux/Cargo.toml", r#"
[project]
name = "qux"
version = "0.1.0"
authors = []
"#)
.file("crates/qux/src/main.rs", "fn main() {}");
let p = p.build();
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), is_not(existing_file()));
assert_that(&p.bin("baz"), is_not(existing_file()));
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("crates/bar")),
execs().with_status(0),
);
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), existing_file());
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("crates/baz")),
execs().with_status(0),
);
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("baz"), existing_file());
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("crates/qux")),
execs().with_status(0),
);
assert_that(&p.bin("qux"), is_not(existing_file()));
assert_that(&p.root().join("Cargo.lock"), existing_file());
2018-03-14 15:17:44 +00:00
assert_that(
&p.root().join("crates/bar/Cargo.lock"),
is_not(existing_file()),
);
assert_that(
&p.root().join("crates/baz/Cargo.lock"),
is_not(existing_file()),
);
assert_that(&p.root().join("crates/qux/Cargo.lock"), existing_file());
}
/*FIXME: This fails because of how workspace.exclude and workspace.members are working.
#[test]
fn glob_syntax_2() {
let p = project()
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["crates/b*"]
exclude = ["crates/q*"]
"#)
.file("src/main.rs", "fn main() {}")
.file("crates/bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
workspace = "../.."
"#)
.file("crates/bar/src/main.rs", "fn main() {}")
.file("crates/baz/Cargo.toml", r#"
[project]
name = "baz"
version = "0.1.0"
authors = []
workspace = "../.."
"#)
.file("crates/baz/src/main.rs", "fn main() {}")
.file("crates/qux/Cargo.toml", r#"
[project]
name = "qux"
version = "0.1.0"
authors = []
"#)
.file("crates/qux/src/main.rs", "fn main() {}");
p.build();
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), is_not(existing_file()));
assert_that(&p.bin("baz"), is_not(existing_file()));
assert_that(p.cargo("build").cwd(p.root().join("crates/bar")),
execs().with_status(0));
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("bar"), existing_file());
assert_that(p.cargo("build").cwd(p.root().join("crates/baz")),
execs().with_status(0));
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("baz"), existing_file());
assert_that(p.cargo("build").cwd(p.root().join("crates/qux")),
execs().with_status(0));
assert_that(&p.bin("qux"), is_not(existing_file()));
assert_that(&p.root().join("Cargo.lock"), existing_file());
assert_that(&p.root().join("crates/bar/Cargo.lock"), is_not(existing_file()));
assert_that(&p.root().join("crates/baz/Cargo.lock"), is_not(existing_file()));
assert_that(&p.root().join("crates/qux/Cargo.lock"), existing_file());
}
*/
#[test]
fn glob_syntax_invalid_members() {
let p = project()
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
[workspace]
members = ["crates/*"]
"#)
.file("src/main.rs", "fn main() {}")
.file("crates/bar/src/main.rs", "fn main() {}");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build"),
execs().with_status(101).with_stderr(
"\
error: failed to read `[..]Cargo.toml`
Caused by:
[..]
2018-03-14 15:17:44 +00:00
",
),
);
}
/// This is a freshness test for feature use with workspaces
///
/// feat_lib is used by caller1 and caller2, but with different features enabled.
/// This test ensures that alternating building caller1, caller2 doesn't force
/// recompile of feat_lib.
///
/// Ideally once we solve https://github.com/rust-lang/cargo/issues/3620, then
/// a single cargo build at the top level will be enough.
#[test]
fn dep_used_with_separate_features() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["feat_lib", "caller1", "caller2"]
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"feat_lib/Cargo.toml",
r#"
[project]
name = "feat_lib"
version = "0.1.0"
authors = []
[features]
myfeature = []
2018-03-14 15:17:44 +00:00
"#,
)
.file("feat_lib/src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"caller1/Cargo.toml",
r#"
[project]
name = "caller1"
version = "0.1.0"
authors = []
[dependencies]
feat_lib = { path = "../feat_lib" }
2018-03-14 15:17:44 +00:00
"#,
)
.file("caller1/src/main.rs", "fn main() {}")
.file("caller1/src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"caller2/Cargo.toml",
r#"
[project]
name = "caller2"
version = "0.1.0"
authors = []
[dependencies]
feat_lib = { path = "../feat_lib", features = ["myfeature"] }
caller1 = { path = "../caller1" }
2018-03-14 15:17:44 +00:00
"#,
)
.file("caller2/src/main.rs", "fn main() {}")
.file("caller2/src/lib.rs", "");
let p = p.build();
// Build the entire workspace
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").arg("--all"),
execs().with_status(0).with_stderr(
"\
[..]Compiling feat_lib v0.1.0 ([..])
[..]Compiling caller1 v0.1.0 ([..])
[..]Compiling caller2 v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
),
);
assert_that(&p.bin("caller1"), existing_file());
assert_that(&p.bin("caller2"), existing_file());
// Build caller1. should build the dep library. Because the features
// are different than the full workspace, it rebuilds.
2017-09-05 08:46:22 +00:00
// Ideally once we solve https://github.com/rust-lang/cargo/issues/3620, then
// a single cargo build at the top level will be enough.
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("caller1")),
execs().with_status(0).with_stderr(
"\
[..]Compiling feat_lib v0.1.0 ([..])
[..]Compiling caller1 v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
),
);
// Alternate building caller2/caller1 a few times, just to make sure
// features are being built separately. Should not rebuild anything
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").cwd(p.root().join("caller2")),
2018-03-14 15:43:41 +00:00
execs()
.with_status(0)
.with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]"),
2018-03-14 15:17:44 +00:00
);
assert_that(
p.cargo("build").cwd(p.root().join("caller1")),
2018-03-14 15:43:41 +00:00
execs()
.with_status(0)
.with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]"),
2018-03-14 15:17:44 +00:00
);
assert_that(
p.cargo("build").cwd(p.root().join("caller2")),
2018-03-14 15:43:41 +00:00
execs()
.with_status(0)
.with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]"),
2018-03-14 15:17:44 +00:00
);
}
#[test]
fn dont_recurse_out_of_cargo_home() {
let git_project = git::new("dep", |project| {
project
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "dep"
version = "0.1.0"
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"build.rs",
r#"
use std::env;
use std::path::Path;
use std::process::{self, Command};
fn main() {
let cargo = env::var_os("CARGO").unwrap();
let cargo_manifest_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap();
let output = Command::new(cargo)
.args(&["metadata", "--format-version", "1", "--manifest-path"])
.arg(&Path::new(&cargo_manifest_dir).join("Cargo.toml"))
.output()
.unwrap();
if !output.status.success() {
eprintln!("{}", String::from_utf8(output.stderr).unwrap());
process::exit(1);
}
}
2018-03-14 15:17:44 +00:00
"#,
)
}).unwrap();
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
&format!(
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies.dep]
git = "{}"
[workspace]
2018-03-14 15:17:44 +00:00
"#,
git_project.url()
),
)
.file("src/lib.rs", "");
let p = p.build();
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").env("CARGO_HOME", p.root().join(".cargo")),
execs().with_status(0),
);
}
/*FIXME: This fails because of how workspace.exclude and workspace.members are working.
#[test]
fn include_and_exclude() {
let p = project()
.file("Cargo.toml", r#"
[workspace]
members = ["foo"]
exclude = ["foo/bar"]
"#)
.file("foo/Cargo.toml", r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("foo/src/lib.rs", "")
.file("foo/bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.1.0"
authors = []
"#)
.file("foo/bar/src/lib.rs", "");
p.build();
assert_that(p.cargo("build").cwd(p.root().join("foo")),
execs().with_status(0));
assert_that(&p.root().join("target"), existing_dir());
assert_that(&p.root().join("foo/target"), is_not(existing_dir()));
assert_that(p.cargo("build").cwd(p.root().join("foo/bar")),
execs().with_status(0));
assert_that(&p.root().join("foo/bar/target"), existing_dir());
}
*/
#[test]
fn cargo_home_at_root_works() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[workspace]
members = ["a"]
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"a/Cargo.toml",
r#"
[package]
name = "a"
version = "0.1.0"
2018-03-14 15:17:44 +00:00
"#,
)
.file("a/src/lib.rs", "");
let p = p.build();
assert_that(p.cargo("build"), execs().with_status(0));
2018-03-14 15:17:44 +00:00
assert_that(
p.cargo("build").arg("--frozen").env("CARGO_HOME", p.root()),
execs().with_status(0),
);
}
#[test]
fn relative_rustc() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
2018-03-14 15:17:44 +00:00
"#,
)
.file(
"src/main.rs",
r#"
use std::process::Command;
use std::env;
fn main() {
let mut cmd = Command::new("rustc");
for arg in env::args_os().skip(1) {
cmd.arg(arg);
}
std::process::exit(cmd.status().unwrap().code().unwrap());
}
2018-03-14 15:17:44 +00:00
"#,
)
.build();
assert_that(p.cargo("build"), execs().with_status(0));
let src = p.root()
.join("target/debug/foo")
.with_extension(env::consts::EXE_EXTENSION);
Package::new("a", "0.1.0").publish();
let p = project().at("lib")
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "lib"
version = "0.1.0"
[dependencies]
a = "0.1"
2018-03-14 15:17:44 +00:00
"#,
)
.file("src/lib.rs", "")
.build();
fs::copy(&src, p.root().join(src.file_name().unwrap())).unwrap();
let file = format!("./foo{}", env::consts::EXE_SUFFIX);
2018-03-14 15:17:44 +00:00
assert_that(p.cargo("build").env("RUSTC", &file), execs().with_status(0));
}
#[test]
fn ws_rustc_err() {
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["a"]
"#,
)
.file("a/Cargo.toml", &basic_lib_manifest("a"))
.file("a/src/lib.rs", "")
.build();
assert_that(
p.cargo("rustc"),
execs()
.with_status(101)
.with_stderr("[ERROR] [..]against an actual package[..]"),
);
assert_that(
p.cargo("rustdoc"),
execs()
.with_status(101)
.with_stderr("[ERROR] [..]against an actual package[..]"),
);
}