cargo/tests/git.rs
Alex Crichton 763ba535eb Shared the test suite into multiple binaries
Compiling everything in one binary was getting annoying as it just took forever
to build, instead shard it all up so we can build just particular test suites at
a time.
2016-05-25 21:25:13 -07:00

1797 lines
51 KiB
Rust

extern crate cargo;
extern crate cargotest;
extern crate git2;
extern crate hamcrest;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::Path;
use cargo::util::process;
use cargotest::{sleep_ms, RUSTC};
use cargotest::support::paths::{self, CargoPathExt};
use cargotest::support::{git, project, execs, main_file, path2url};
use hamcrest::{assert_that,existing_file};
#[test]
fn cargo_compile_simple_git_dep() {
let project = project("foo");
let git_project = git::new("dep1", |project| {
project
.file("Cargo.toml", r#"
[project]
name = "dep1"
version = "0.5.0"
authors = ["carlhuda@example.com"]
[lib]
name = "dep1"
"#)
.file("src/dep1.rs", r#"
pub fn hello() -> &'static str {
"hello world"
}
"#)
}).unwrap();
let project = project
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.dep1]
git = '{}'
[[bin]]
name = "foo"
"#, git_project.url()))
.file("src/foo.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]));
let root = project.root();
let git_root = git_project.root();
assert_that(project.cargo_process("build"),
execs()
.with_stderr(&format!("[UPDATING] git repository `{}`\n\
[COMPILING] dep1 v0.5.0 ({}#[..])\n\
[COMPILING] foo v0.5.0 ({})\n",
path2url(git_root.clone()),
path2url(git_root),
path2url(root))));
assert_that(&project.bin("foo"), existing_file());
assert_that(
process(&project.bin("foo")),
execs().with_stdout("hello world\n"));
}
#[test]
fn cargo_compile_git_dep_branch() {
let project = project("foo");
let git_project = git::new("dep1", |project| {
project
.file("Cargo.toml", r#"
[project]
name = "dep1"
version = "0.5.0"
authors = ["carlhuda@example.com"]
[lib]
name = "dep1"
"#)
.file("src/dep1.rs", r#"
pub fn hello() -> &'static str {
"hello world"
}
"#)
}).unwrap();
// Make a new branch based on the current HEAD commit
let repo = git2::Repository::open(&git_project.root()).unwrap();
let head = repo.head().unwrap().target().unwrap();
let head = repo.find_commit(head).unwrap();
repo.branch("branchy", &head, true).unwrap();
let project = project
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.dep1]
git = '{}'
branch = "branchy"
[[bin]]
name = "foo"
"#, git_project.url()))
.file("src/foo.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]));
let root = project.root();
let git_root = git_project.root();
assert_that(project.cargo_process("build"),
execs()
.with_stderr(&format!("[UPDATING] git repository `{}`\n\
[COMPILING] dep1 v0.5.0 ({}?branch=branchy#[..])\n\
[COMPILING] foo v0.5.0 ({})\n",
path2url(git_root.clone()),
path2url(git_root),
path2url(root))));
assert_that(&project.bin("foo"), existing_file());
assert_that(
process(&project.bin("foo")),
execs().with_stdout("hello world\n"));
}
#[test]
fn cargo_compile_git_dep_tag() {
let project = project("foo");
let git_project = git::new("dep1", |project| {
project
.file("Cargo.toml", r#"
[project]
name = "dep1"
version = "0.5.0"
authors = ["carlhuda@example.com"]
[lib]
name = "dep1"
"#)
.file("src/dep1.rs", r#"
pub fn hello() -> &'static str {
"hello world"
}
"#)
}).unwrap();
// Make a tag corresponding to the current HEAD
let repo = git2::Repository::open(&git_project.root()).unwrap();
let head = repo.head().unwrap().target().unwrap();
repo.tag("v0.1.0",
&repo.find_object(head, None).unwrap(),
&repo.signature().unwrap(),
"make a new tag",
false).unwrap();
let project = project
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.dep1]
git = '{}'
tag = "v0.1.0"
[[bin]]
name = "foo"
"#, git_project.url()))
.file("src/foo.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]));
let root = project.root();
let git_root = git_project.root();
assert_that(project.cargo_process("build"),
execs()
.with_stderr(&format!("[UPDATING] git repository `{}`\n\
[COMPILING] dep1 v0.5.0 ({}?tag=v0.1.0#[..])\n\
[COMPILING] foo v0.5.0 ({})\n",
path2url(git_root.clone()),
path2url(git_root),
path2url(root))));
assert_that(&project.bin("foo"), existing_file());
assert_that(process(&project.bin("foo")),
execs().with_stdout("hello world\n"));
assert_that(project.cargo("build"),
execs().with_status(0));
}
#[test]
fn cargo_compile_with_nested_paths() {
let git_project = git::new("dep1", |project| {
project
.file("Cargo.toml", r#"
[project]
name = "dep1"
version = "0.5.0"
authors = ["carlhuda@example.com"]
[dependencies.dep2]
version = "0.5.0"
path = "vendor/dep2"
[lib]
name = "dep1"
"#)
.file("src/dep1.rs", r#"
extern crate dep2;
pub fn hello() -> &'static str {
dep2::hello()
}
"#)
.file("vendor/dep2/Cargo.toml", r#"
[project]
name = "dep2"
version = "0.5.0"
authors = ["carlhuda@example.com"]
[lib]
name = "dep2"
"#)
.file("vendor/dep2/src/dep2.rs", r#"
pub fn hello() -> &'static str {
"hello world"
}
"#)
}).unwrap();
let p = project("parent")
.file("Cargo.toml", &format!(r#"
[project]
name = "parent"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.dep1]
version = "0.5.0"
git = '{}'
[[bin]]
name = "parent"
"#, git_project.url()))
.file("src/parent.rs",
&main_file(r#""{}", dep1::hello()"#, &["dep1"]));
p.cargo_process("build")
.exec_with_output()
.unwrap();
assert_that(&p.bin("parent"), existing_file());
assert_that(process(&p.bin("parent")),
execs().with_stdout("hello world\n"));
}
#[test]
fn cargo_compile_with_meta_package() {
let git_project = git::new("meta-dep", |project| {
project
.file("dep1/Cargo.toml", r#"
[project]
name = "dep1"
version = "0.5.0"
authors = ["carlhuda@example.com"]
[lib]
name = "dep1"
"#)
.file("dep1/src/dep1.rs", r#"
pub fn hello() -> &'static str {
"this is dep1"
}
"#)
.file("dep2/Cargo.toml", r#"
[project]
name = "dep2"
version = "0.5.0"
authors = ["carlhuda@example.com"]
[lib]
name = "dep2"
"#)
.file("dep2/src/dep2.rs", r#"
pub fn hello() -> &'static str {
"this is dep2"
}
"#)
}).unwrap();
let p = project("parent")
.file("Cargo.toml", &format!(r#"
[project]
name = "parent"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.dep1]
version = "0.5.0"
git = '{}'
[dependencies.dep2]
version = "0.5.0"
git = '{}'
[[bin]]
name = "parent"
"#, git_project.url(), git_project.url()))
.file("src/parent.rs",
&main_file(r#""{} {}", dep1::hello(), dep2::hello()"#, &["dep1", "dep2"]));
p.cargo_process("build")
.exec_with_output()
.unwrap();
assert_that(&p.bin("parent"), existing_file());
assert_that(process(&p.bin("parent")),
execs().with_stdout("this is dep1 this is dep2\n"));
}
#[test]
fn cargo_compile_with_short_ssh_git() {
let url = "git@github.com:a/dep";
let project = project("project")
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.dep]
git = "{}"
[[bin]]
name = "foo"
"#, url))
.file("src/foo.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]));
assert_that(project.cargo_process("build"),
execs()
.with_stdout("")
.with_stderr(&format!("\
[ERROR] failed to parse manifest at `[..]`
Caused by:
invalid url `{}`: relative URL without a base
", url)));
}
#[test]
fn two_revs_same_deps() {
let bar = git::new("meta-dep", |project| {
project.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.0.0"
authors = []
"#)
.file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
}).unwrap();
let repo = git2::Repository::open(&bar.root()).unwrap();
let rev1 = repo.revparse_single("HEAD").unwrap().id();
// Commit the changes and make sure we trigger a recompile
File::create(&bar.root().join("src/lib.rs")).unwrap().write_all(br#"
pub fn bar() -> i32 { 2 }
"#).unwrap();
git::add(&repo);
let rev2 = git::commit(&repo);
let foo = project("foo")
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.0.0"
authors = []
[dependencies.bar]
git = '{}'
rev = "{}"
[dependencies.baz]
path = "../baz"
"#, bar.url(), rev1))
.file("src/main.rs", r#"
extern crate bar;
extern crate baz;
fn main() {
assert_eq!(bar::bar(), 1);
assert_eq!(baz::baz(), 2);
}
"#);
let baz = project("baz")
.file("Cargo.toml", &format!(r#"
[package]
name = "baz"
version = "0.0.0"
authors = []
[dependencies.bar]
git = '{}'
rev = "{}"
"#, bar.url(), rev2))
.file("src/lib.rs", r#"
extern crate bar;
pub fn baz() -> i32 { bar::bar() }
"#);
baz.build();
assert_that(foo.cargo_process("build").arg("-v"),
execs().with_status(0));
assert_that(&foo.bin("foo"), existing_file());
assert_that(foo.process(&foo.bin("foo")), execs().with_status(0));
}
#[test]
fn recompilation() {
let git_project = git::new("bar", |project| {
project
.file("Cargo.toml", r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["carlhuda@example.com"]
[lib]
name = "bar"
"#)
.file("src/bar.rs", r#"
pub fn bar() {}
"#)
}).unwrap();
let p = project("foo")
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.bar]
version = "0.5.0"
git = '{}'
[[bin]]
name = "foo"
"#, git_project.url()))
.file("src/foo.rs",
&main_file(r#""{:?}", bar::bar()"#, &["bar"]));
// First time around we should compile both foo and bar
assert_that(p.cargo_process("build"),
execs().with_stderr(&format!("[UPDATING] git repository `{}`\n\
[COMPILING] bar v0.5.0 ({}#[..])\n\
[COMPILING] foo v0.5.0 ({})\n",
git_project.url(),
git_project.url(),
p.url())));
// Don't recompile the second time
assert_that(p.cargo("build"),
execs().with_stdout(""));
// Modify a file manually, shouldn't trigger a recompile
File::create(&git_project.root().join("src/bar.rs")).unwrap().write_all(br#"
pub fn bar() { println!("hello!"); }
"#).unwrap();
assert_that(p.cargo("build"),
execs().with_stdout(""));
assert_that(p.cargo("update"),
execs().with_stderr(&format!("[UPDATING] git repository `{}`",
git_project.url())));
assert_that(p.cargo("build"),
execs().with_stdout(""));
// Commit the changes and make sure we don't trigger a recompile because the
// lockfile says not to change
let repo = git2::Repository::open(&git_project.root()).unwrap();
git::add(&repo);
git::commit(&repo);
println!("compile after commit");
assert_that(p.cargo("build"),
execs().with_stdout(""));
p.root().move_into_the_past();
// Update the dependency and carry on!
assert_that(p.cargo("update"),
execs().with_stderr(&format!("[UPDATING] git repository `{}`\n\
[UPDATING] bar v0.5.0 ([..]) -> #[..]\n\
",
git_project.url())));
println!("going for the last compile");
assert_that(p.cargo("build"),
execs().with_stderr(&format!("[COMPILING] bar v0.5.0 ({}#[..])\n\
[COMPILING] foo v0.5.0 ({})\n",
git_project.url(),
p.url())));
// Make sure clean only cleans one dep
assert_that(p.cargo("clean")
.arg("-p").arg("foo"),
execs().with_stdout(""));
assert_that(p.cargo("build"),
execs().with_stderr(&format!("[COMPILING] foo v0.5.0 ({})\n",
p.url())));
}
#[test]
fn update_with_shared_deps() {
let git_project = git::new("bar", |project| {
project
.file("Cargo.toml", r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["carlhuda@example.com"]
[lib]
name = "bar"
"#)
.file("src/bar.rs", r#"
pub fn bar() {}
"#)
}).unwrap();
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.dep1]
path = "dep1"
[dependencies.dep2]
path = "dep2"
"#)
.file("src/main.rs", r#"
extern crate dep1;
extern crate dep2;
fn main() {}
"#)
.file("dep1/Cargo.toml", &format!(r#"
[package]
name = "dep1"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.bar]
version = "0.5.0"
git = '{}'
"#, git_project.url()))
.file("dep1/src/lib.rs", "")
.file("dep2/Cargo.toml", &format!(r#"
[package]
name = "dep2"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.bar]
version = "0.5.0"
git = '{}'
"#, git_project.url()))
.file("dep2/src/lib.rs", "");
// First time around we should compile both foo and bar
assert_that(p.cargo_process("build"),
execs().with_stderr(&format!("\
[UPDATING] git repository `{git}`
[COMPILING] bar v0.5.0 ({git}#[..])
[COMPILING] [..] v0.5.0 ([..])
[COMPILING] [..] v0.5.0 ([..])
[COMPILING] foo v0.5.0 ({dir})\n", git = git_project.url(), dir = p.url())));
// Modify a file manually, and commit it
File::create(&git_project.root().join("src/bar.rs")).unwrap().write_all(br#"
pub fn bar() { println!("hello!"); }
"#).unwrap();
let repo = git2::Repository::open(&git_project.root()).unwrap();
let old_head = repo.head().unwrap().target().unwrap();
git::add(&repo);
git::commit(&repo);
sleep_ms(1000);
// By default, not transitive updates
println!("dep1 update");
assert_that(p.cargo("update")
.arg("-p").arg("dep1"),
execs().with_stdout(""));
// Don't do anything bad on a weird --precise argument
println!("bar bad precise update");
assert_that(p.cargo("update")
.arg("-p").arg("bar")
.arg("--precise").arg("0.1.2"),
execs().with_status(101).with_stderr("\
[UPDATING] git repository [..]
[ERROR] Unable to update [..]
To learn more, run the command again with --verbose.
"));
// Specifying a precise rev to the old rev shouldn't actually update
// anything because we already have the rev in the db.
println!("bar precise update");
assert_that(p.cargo("update")
.arg("-p").arg("bar")
.arg("--precise").arg(&old_head.to_string()),
execs().with_stdout(""));
// Updating aggressively should, however, update the repo.
println!("dep1 aggressive update");
assert_that(p.cargo("update")
.arg("-p").arg("dep1")
.arg("--aggressive"),
execs().with_stderr(&format!("[UPDATING] git repository `{}`\n\
[UPDATING] bar v0.5.0 ([..]) -> #[..]\n\
", git_project.url())));
// Make sure we still only compile one version of the git repo
println!("build");
assert_that(p.cargo("build"),
execs().with_stderr(&format!("\
[COMPILING] bar v0.5.0 ({git}#[..])
[COMPILING] [..] v0.5.0 ({dir}[..]dep[..])
[COMPILING] [..] v0.5.0 ({dir}[..]dep[..])
[COMPILING] foo v0.5.0 ({dir})\n",
git = git_project.url(), dir = p.url())));
// We should be able to update transitive deps
assert_that(p.cargo("update").arg("-p").arg("bar"),
execs().with_stderr(&format!("[UPDATING] git repository `{}`",
git_project.url())));
}
#[test]
fn dep_with_submodule() {
let project = project("foo");
let git_project = git::new("dep1", |project| {
project
.file("Cargo.toml", r#"
[package]
name = "dep1"
version = "0.5.0"
authors = ["carlhuda@example.com"]
"#)
}).unwrap();
let git_project2 = git::new("dep2", |project| {
project.file("lib.rs", "pub fn dep() {}")
}).unwrap();
let repo = git2::Repository::open(&git_project.root()).unwrap();
let url = path2url(git_project2.root()).to_string();
git::add_submodule(&repo, &url, Path::new("src"));
git::commit(&repo);
let project = project
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.dep1]
git = '{}'
"#, git_project.url()))
.file("src/lib.rs", "
extern crate dep1;
pub fn foo() { dep1::dep() }
");
assert_that(project.cargo_process("build"),
execs().with_stderr("\
[UPDATING] git repository [..]
[COMPILING] dep1 [..]
[COMPILING] foo [..]").with_status(0));
}
#[test]
fn two_deps_only_update_one() {
let project = project("foo");
let git1 = git::new("dep1", |project| {
project
.file("Cargo.toml", r#"
[package]
name = "dep1"
version = "0.5.0"
authors = ["carlhuda@example.com"]
"#)
.file("src/lib.rs", "")
}).unwrap();
let git2 = git::new("dep2", |project| {
project
.file("Cargo.toml", r#"
[package]
name = "dep2"
version = "0.5.0"
authors = ["carlhuda@example.com"]
"#)
.file("src/lib.rs", "")
}).unwrap();
let project = project
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.dep1]
git = '{}'
[dependencies.dep2]
git = '{}'
"#, git1.url(), git2.url()))
.file("src/main.rs", "fn main() {}");
assert_that(project.cargo_process("build"),
execs()
.with_stderr(&format!("[UPDATING] git repository `[..]`\n\
[UPDATING] git repository `[..]`\n\
[COMPILING] [..] v0.5.0 ([..])\n\
[COMPILING] [..] v0.5.0 ([..])\n\
[COMPILING] foo v0.5.0 ({})\n",
project.url())));
File::create(&git1.root().join("src/lib.rs")).unwrap().write_all(br#"
pub fn foo() {}
"#).unwrap();
let repo = git2::Repository::open(&git1.root()).unwrap();
git::add(&repo);
git::commit(&repo);
assert_that(project.cargo("update")
.arg("-p").arg("dep1"),
execs()
.with_stderr(&format!("[UPDATING] git repository `{}`\n\
[UPDATING] dep1 v0.5.0 ([..]) -> #[..]\n\
", git1.url())));
}
#[test]
fn stale_cached_version() {
let bar = git::new("meta-dep", |project| {
project.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.0.0"
authors = []
"#)
.file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
}).unwrap();
// Update the git database in the cache with the current state of the git
// repo
let foo = project("foo")
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.0.0"
authors = []
[dependencies.bar]
git = '{}'
"#, bar.url()))
.file("src/main.rs", r#"
extern crate bar;
fn main() { assert_eq!(bar::bar(), 1) }
"#);
assert_that(foo.cargo_process("build"), execs().with_status(0));
assert_that(foo.process(&foo.bin("foo")), execs().with_status(0));
// Update the repo, and simulate someone else updating the lockfile and then
// us pulling it down.
File::create(&bar.root().join("src/lib.rs")).unwrap().write_all(br#"
pub fn bar() -> i32 { 1 + 0 }
"#).unwrap();
let repo = git2::Repository::open(&bar.root()).unwrap();
git::add(&repo);
git::commit(&repo);
sleep_ms(1000);
let rev = repo.revparse_single("HEAD").unwrap().id();
File::create(&foo.root().join("Cargo.lock")).unwrap().write_all(format!(r#"
[root]
name = "foo"
version = "0.0.0"
dependencies = [
'bar 0.0.0 (git+{url}#{hash})'
]
[[package]]
name = "bar"
version = "0.0.0"
source = 'git+{url}#{hash}'
"#, url = bar.url(), hash = rev).as_bytes()).unwrap();
// Now build!
assert_that(foo.cargo("build"),
execs().with_status(0)
.with_stderr(&format!("\
[UPDATING] git repository `{bar}`
[COMPILING] bar v0.0.0 ({bar}#[..])
[COMPILING] foo v0.0.0 ({foo})
", bar = bar.url(), foo = foo.url())));
assert_that(foo.process(&foo.bin("foo")), execs().with_status(0));
}
#[test]
fn dep_with_changed_submodule() {
let project = project("foo");
let git_project = git::new("dep1", |project| {
project
.file("Cargo.toml", r#"
[package]
name = "dep1"
version = "0.5.0"
authors = ["carlhuda@example.com"]
"#)
}).unwrap();
let git_project2 = git::new("dep2", |project| {
project
.file("lib.rs", "pub fn dep() -> &'static str { \"project2\" }")
}).unwrap();
let git_project3 = git::new("dep3", |project| {
project
.file("lib.rs", "pub fn dep() -> &'static str { \"project3\" }")
}).unwrap();
let repo = git2::Repository::open(&git_project.root()).unwrap();
let mut sub = git::add_submodule(&repo, &git_project2.url().to_string(),
&Path::new("src"));
git::commit(&repo);
let project = project
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.dep1]
git = '{}'
"#, git_project.url()))
.file("src/main.rs", "
extern crate dep1;
pub fn main() { println!(\"{}\", dep1::dep()) }
");
println!("first run");
assert_that(project.cargo_process("run"), execs()
.with_stderr("[UPDATING] git repository `[..]`\n\
[COMPILING] dep1 v0.5.0 ([..])\n\
[COMPILING] foo v0.5.0 ([..])\n\
[RUNNING] `target[..]foo[..]`\n")
.with_stdout("project2\n")
.with_status(0));
File::create(&git_project.root().join(".gitmodules")).unwrap()
.write_all(format!("[submodule \"src\"]\n\tpath = src\n\turl={}",
git_project3.url()).as_bytes()).unwrap();
// Sync the submodule and reset it to the new remote.
sub.sync().unwrap();
{
let subrepo = sub.open().unwrap();
subrepo.remote_add_fetch("origin",
"refs/heads/*:refs/heads/*").unwrap();
subrepo.remote_set_url("origin",
&git_project3.url().to_string()).unwrap();
let mut origin = subrepo.find_remote("origin").unwrap();
origin.fetch(&[], None, None).unwrap();
let id = subrepo.refname_to_id("refs/remotes/origin/master").unwrap();
let obj = subrepo.find_object(id, None).unwrap();
subrepo.reset(&obj, git2::ResetType::Hard, None).unwrap();
}
sub.add_to_index(true).unwrap();
git::add(&repo);
git::commit(&repo);
sleep_ms(1000);
// Update the dependency and carry on!
println!("update");
assert_that(project.cargo("update").arg("-v"),
execs()
.with_stderr("")
.with_stderr(&format!("[UPDATING] git repository `{}`\n\
[UPDATING] dep1 v0.5.0 ([..]) -> #[..]\n\
", git_project.url())));
println!("last run");
assert_that(project.cargo("run"), execs()
.with_stderr("[COMPILING] dep1 v0.5.0 ([..])\n\
[COMPILING] foo v0.5.0 ([..])\n\
[RUNNING] `target[..]foo[..]`\n")
.with_stdout("project3\n")
.with_status(0));
}
#[test]
fn dev_deps_with_testing() {
let p2 = git::new("bar", |project| {
project.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", r#"
pub fn gimme() -> &'static str { "zoidberg" }
"#)
}).unwrap();
let p = project("foo")
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dev-dependencies.bar]
version = "0.5.0"
git = '{}'
"#, p2.url()))
.file("src/main.rs", r#"
fn main() {}
#[cfg(test)]
mod tests {
extern crate bar;
#[test] fn foo() { bar::gimme(); }
}
"#);
// Generate a lockfile which did not use `bar` to compile, but had to update
// `bar` to generate the lockfile
assert_that(p.cargo_process("build"),
execs().with_stderr(&format!("\
[UPDATING] git repository `{bar}`
[COMPILING] foo v0.5.0 ({url})
", url = p.url(), bar = p2.url())));
// Make sure we use the previous resolution of `bar` instead of updating it
// a second time.
assert_that(p.cargo("test"),
execs().with_stderr("\
[COMPILING] [..] v0.5.0 ([..])
[COMPILING] [..] v0.5.0 ([..]
[RUNNING] target[..]foo-[..]")
.with_stdout("
running 1 test
test tests::foo ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
"));
}
#[test]
fn git_build_cmd_freshness() {
let foo = git::new("foo", |project| {
project.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
build = "build.rs"
"#)
.file("build.rs", "fn main() {}")
.file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
.file(".gitignore", "
src/bar.rs
")
}).unwrap();
foo.root().move_into_the_past();
sleep_ms(1000);
assert_that(foo.cargo("build"),
execs().with_status(0)
.with_stderr(&format!("\
[COMPILING] foo v0.0.0 ({url})
", url = foo.url())));
// Smoke test to make sure it doesn't compile again
println!("first pass");
assert_that(foo.cargo("build"),
execs().with_status(0)
.with_stdout(""));
// Modify an ignored file and make sure we don't rebuild
println!("second pass");
File::create(&foo.root().join("src/bar.rs")).unwrap();
assert_that(foo.cargo("build"),
execs().with_status(0)
.with_stdout(""));
}
#[test]
fn git_name_not_always_needed() {
let p2 = git::new("bar", |project| {
project.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", r#"
pub fn gimme() -> &'static str { "zoidberg" }
"#)
}).unwrap();
let repo = git2::Repository::open(&p2.root()).unwrap();
let mut cfg = repo.config().unwrap();
let _ = cfg.remove("user.name");
let _ = cfg.remove("user.email");
let p = project("foo")
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = []
[dev-dependencies.bar]
git = '{}'
"#, p2.url()))
.file("src/main.rs", "fn main() {}");
// Generate a lockfile which did not use `bar` to compile, but had to update
// `bar` to generate the lockfile
assert_that(p.cargo_process("build"),
execs().with_stderr(&format!("\
[UPDATING] git repository `{bar}`
[COMPILING] foo v0.5.0 ({url})
", url = p.url(), bar = p2.url())));
}
#[test]
fn git_repo_changing_no_rebuild() {
let bar = git::new("bar", |project| {
project.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
}).unwrap();
// Lock p1 to the first rev in the git repo
let p1 = project("p1")
.file("Cargo.toml", &format!(r#"
[project]
name = "p1"
version = "0.5.0"
authors = []
build = 'build.rs'
[dependencies.bar]
git = '{}'
"#, bar.url()))
.file("src/main.rs", "fn main() {}")
.file("build.rs", "fn main() {}");
p1.build();
p1.root().move_into_the_past();
assert_that(p1.cargo("build"),
execs().with_stderr(&format!("\
[UPDATING] git repository `{bar}`
[COMPILING] [..]
[COMPILING] [..]
", bar = bar.url())));
// Make a commit to lock p2 to a different rev
File::create(&bar.root().join("src/lib.rs")).unwrap().write_all(br#"
pub fn bar() -> i32 { 2 }
"#).unwrap();
let repo = git2::Repository::open(&bar.root()).unwrap();
git::add(&repo);
git::commit(&repo);
// Lock p2 to the second rev
let p2 = project("p2")
.file("Cargo.toml", &format!(r#"
[project]
name = "p2"
version = "0.5.0"
authors = []
[dependencies.bar]
git = '{}'
"#, bar.url()))
.file("src/main.rs", "fn main() {}");
assert_that(p2.cargo_process("build"),
execs().with_stderr(&format!("\
[UPDATING] git repository `{bar}`
[COMPILING] [..]
[COMPILING] [..]
", bar = bar.url())));
// And now for the real test! Make sure that p1 doesn't get rebuilt
// even though the git repo has changed.
assert_that(p1.cargo("build"),
execs().with_stdout(""));
}
#[test]
fn git_dep_build_cmd() {
let p = git::new("foo", |project| {
project.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.bar]
version = "0.5.0"
path = "bar"
[[bin]]
name = "foo"
"#)
.file("src/foo.rs",
&main_file(r#""{}", bar::gimme()"#, &["bar"]))
.file("bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
build = "build.rs"
[lib]
name = "bar"
"#)
.file("bar/src/bar.rs.in", r#"
pub fn gimme() -> i32 { 0 }
"#)
.file("bar/build.rs", r#"
use std::fs;
fn main() {
fs::copy("src/bar.rs.in", "src/bar.rs").unwrap();
}
"#)
}).unwrap();
p.root().join("bar").move_into_the_past();
assert_that(p.cargo("build"),
execs().with_status(0));
assert_that(process(&p.bin("foo")),
execs().with_stdout("0\n"));
// Touching bar.rs.in should cause the `build` command to run again.
fs::File::create(&p.root().join("bar/src/bar.rs.in")).unwrap()
.write_all(b"pub fn gimme() -> i32 { 1 }").unwrap();
assert_that(p.cargo("build"),
execs().with_status(0));
assert_that(process(&p.bin("foo")),
execs().with_stdout("1\n"));
}
#[test]
fn fetch_downloads() {
let bar = git::new("bar", |project| {
project.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
}).unwrap();
let p = project("p1")
.file("Cargo.toml", &format!(r#"
[project]
name = "p1"
version = "0.5.0"
authors = []
[dependencies.bar]
git = '{}'
"#, bar.url()))
.file("src/main.rs", "fn main() {}");
assert_that(p.cargo_process("fetch"),
execs().with_status(0).with_stderr(&format!("\
[UPDATING] git repository `{url}`
", url = bar.url())));
assert_that(p.cargo("fetch"),
execs().with_status(0).with_stdout(""));
}
#[test]
fn warnings_in_git_dep() {
let bar = git::new("bar", |project| {
project.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "fn unused() {}")
}).unwrap();
let p = project("foo")
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = []
[dependencies.bar]
git = '{}'
"#, bar.url()))
.file("src/main.rs", "fn main() {}");
assert_that(p.cargo_process("build"),
execs()
.with_stderr(&format!("[UPDATING] git repository `{}`\n\
[COMPILING] bar v0.5.0 ({}#[..])\n\
[COMPILING] foo v0.5.0 ({})\n",
bar.url(),
bar.url(),
p.url())));
}
#[test]
fn update_ambiguous() {
let foo1 = git::new("foo1", |project| {
project.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "")
}).unwrap();
let foo2 = git::new("foo2", |project| {
project.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.6.0"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "")
}).unwrap();
let bar = git::new("bar", |project| {
project.file("Cargo.toml", &format!(r#"
[package]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.foo]
git = '{}'
"#, foo2.url()))
.file("src/lib.rs", "")
}).unwrap();
let p = project("project")
.file("Cargo.toml", &format!(r#"
[project]
name = "project"
version = "0.5.0"
authors = []
[dependencies.foo]
git = '{}'
[dependencies.bar]
git = '{}'
"#, foo1.url(), bar.url()))
.file("src/main.rs", "fn main() {}");
assert_that(p.cargo_process("generate-lockfile"), execs().with_status(0));
assert_that(p.cargo("update")
.arg("-p").arg("foo"),
execs().with_status(101)
.with_stderr("\
[ERROR] There are multiple `foo` packages in your project, and the specification `foo` \
is ambiguous.
Please re-run this command with `-p <spec>` where `<spec>` is one of the \
following:
foo:0.[..].0
foo:0.[..].0
"));
}
#[test]
fn update_one_dep_in_repo_with_many_deps() {
let foo = git::new("foo", |project| {
project.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "")
.file("a/Cargo.toml", r#"
[package]
name = "a"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("a/src/lib.rs", "")
}).unwrap();
let p = project("project")
.file("Cargo.toml", &format!(r#"
[project]
name = "project"
version = "0.5.0"
authors = []
[dependencies.foo]
git = '{}'
[dependencies.a]
git = '{}'
"#, foo.url(), foo.url()))
.file("src/main.rs", "fn main() {}");
assert_that(p.cargo_process("generate-lockfile"), execs().with_status(0));
assert_that(p.cargo("update")
.arg("-p").arg("foo"),
execs().with_status(0)
.with_stderr(&format!("\
[UPDATING] git repository `{}`
", foo.url())));
}
#[test]
fn switch_deps_does_not_update_transitive() {
let transitive = git::new("transitive", |project| {
project.file("Cargo.toml", r#"
[package]
name = "transitive"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "")
}).unwrap();
let dep1 = git::new("dep1", |project| {
project.file("Cargo.toml", &format!(r#"
[package]
name = "dep"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.transitive]
git = '{}'
"#, transitive.url()))
.file("src/lib.rs", "")
}).unwrap();
let dep2 = git::new("dep2", |project| {
project.file("Cargo.toml", &format!(r#"
[package]
name = "dep"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.transitive]
git = '{}'
"#, transitive.url()))
.file("src/lib.rs", "")
}).unwrap();
let p = project("project")
.file("Cargo.toml", &format!(r#"
[project]
name = "project"
version = "0.5.0"
authors = []
[dependencies.dep]
git = '{}'
"#, dep1.url()))
.file("src/main.rs", "fn main() {}");
p.build();
assert_that(p.cargo("build"),
execs().with_status(0)
.with_stderr(&format!("\
[UPDATING] git repository `{}`
[UPDATING] git repository `{}`
[COMPILING] transitive [..]
[COMPILING] dep [..]
[COMPILING] project [..]
", dep1.url(), transitive.url())));
// Update the dependency to point to the second repository, but this
// shouldn't update the transitive dependency which is the same.
File::create(&p.root().join("Cargo.toml")).unwrap().write_all(format!(r#"
[project]
name = "project"
version = "0.5.0"
authors = []
[dependencies.dep]
git = '{}'
"#, dep2.url()).as_bytes()).unwrap();
assert_that(p.cargo("build"),
execs().with_status(0)
.with_stderr(&format!("\
[UPDATING] git repository `{}`
[COMPILING] dep [..]
[COMPILING] project [..]
", dep2.url())));
}
#[test]
fn update_one_source_updates_all_packages_in_that_git_source() {
let dep = git::new("dep", |project| {
project.file("Cargo.toml", r#"
[package]
name = "dep"
version = "0.5.0"
authors = []
[dependencies.a]
path = "a"
"#)
.file("src/lib.rs", "")
.file("a/Cargo.toml", r#"
[package]
name = "a"
version = "0.5.0"
authors = []
"#)
.file("a/src/lib.rs", "")
}).unwrap();
let p = project("project")
.file("Cargo.toml", &format!(r#"
[project]
name = "project"
version = "0.5.0"
authors = []
[dependencies.dep]
git = '{}'
"#, dep.url()))
.file("src/main.rs", "fn main() {}");
p.build();
assert_that(p.cargo("build"),
execs().with_status(0));
let repo = git2::Repository::open(&dep.root()).unwrap();
let rev1 = repo.revparse_single("HEAD").unwrap().id();
// Just be sure to change a file
File::create(&dep.root().join("src/lib.rs")).unwrap().write_all(br#"
pub fn bar() -> i32 { 2 }
"#).unwrap();
git::add(&repo);
git::commit(&repo);
assert_that(p.cargo("update").arg("-p").arg("dep"),
execs().with_status(0));
let mut lockfile = String::new();
File::open(&p.root().join("Cargo.lock")).unwrap()
.read_to_string(&mut lockfile).unwrap();
assert!(!lockfile.contains(&rev1.to_string()),
"{} in {}", rev1, lockfile);
}
#[test]
fn switch_sources() {
let a1 = git::new("a1", |project| {
project.file("Cargo.toml", r#"
[package]
name = "a"
version = "0.5.0"
authors = []
"#)
.file("src/lib.rs", "")
}).unwrap();
let a2 = git::new("a2", |project| {
project.file("Cargo.toml", r#"
[package]
name = "a"
version = "0.5.1"
authors = []
"#)
.file("src/lib.rs", "")
}).unwrap();
let p = project("project")
.file("Cargo.toml", r#"
[project]
name = "project"
version = "0.5.0"
authors = []
[dependencies.b]
path = "b"
"#)
.file("src/main.rs", "fn main() {}")
.file("b/Cargo.toml", &format!(r#"
[project]
name = "b"
version = "0.5.0"
authors = []
[dependencies.a]
git = '{}'
"#, a1.url()))
.file("b/src/lib.rs", "pub fn main() {}");
p.build();
assert_that(p.cargo("build"),
execs().with_status(0)
.with_stderr("\
[UPDATING] git repository `file://[..]a1`
[COMPILING] a v0.5.0 ([..]a1#[..]
[COMPILING] b v0.5.0 ([..])
[COMPILING] project v0.5.0 ([..])
"));
File::create(&p.root().join("b/Cargo.toml")).unwrap().write_all(format!(r#"
[project]
name = "b"
version = "0.5.0"
authors = []
[dependencies.a]
git = '{}'
"#, a2.url()).as_bytes()).unwrap();
assert_that(p.cargo("build"),
execs().with_status(0)
.with_stderr("\
[UPDATING] git repository `file://[..]a2`
[COMPILING] a v0.5.1 ([..]a2#[..]
[COMPILING] b v0.5.0 ([..])
[COMPILING] project v0.5.0 ([..])
"));
}
#[test]
fn dont_require_submodules_are_checked_out() {
let project = project("foo");
let git1 = git::new("dep1", |p| {
p.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = []
build = "build.rs"
"#)
.file("build.rs", "fn main() {}")
.file("src/lib.rs", "")
.file("a/foo", "")
}).unwrap();
let git2 = git::new("dep2", |p| p).unwrap();
let repo = git2::Repository::open(&git1.root()).unwrap();
let url = path2url(git2.root()).to_string();
git::add_submodule(&repo, &url, &Path::new("a/submodule"));
git::commit(&repo);
git2::Repository::init(&project.root()).unwrap();
let url = path2url(git1.root()).to_string();
let dst = paths::home().join("foo");
git2::Repository::clone(&url, &dst).unwrap();
assert_that(git1.cargo("build").arg("-v").cwd(&dst),
execs().with_status(0));
}
#[test]
fn doctest_same_name() {
let a2 = git::new("a2", |p| {
p.file("Cargo.toml", r#"
[project]
name = "a"
version = "0.5.0"
authors = []
"#)
.file("src/lib.rs", "pub fn a2() {}")
}).unwrap();
let a1 = git::new("a1", |p| {
p.file("Cargo.toml", &format!(r#"
[project]
name = "a"
version = "0.5.0"
authors = []
[dependencies]
a = {{ git = '{}' }}
"#, a2.url()))
.file("src/lib.rs", "extern crate a; pub fn a1() {}")
}).unwrap();
let p = project("foo")
.file("Cargo.toml", &format!(r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
a = {{ git = '{}' }}
"#, a1.url()))
.file("src/lib.rs", r#"
#[macro_use]
extern crate a;
"#);
assert_that(p.cargo_process("test").arg("-v"),
execs().with_status(0));
}
#[test]
fn lints_are_suppressed() {
let a = git::new("a", |p| {
p.file("Cargo.toml", r#"
[project]
name = "a"
version = "0.5.0"
authors = []
"#)
.file("src/lib.rs", "
use std::option;
")
}).unwrap();
let p = project("foo")
.file("Cargo.toml", &format!(r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
a = {{ git = '{}' }}
"#, a.url()))
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(0).with_stderr("\
[UPDATING] git repository `[..]`
[COMPILING] a v0.5.0 ([..])
[COMPILING] foo v0.0.1 ([..])
"));
}
#[test]
fn denied_lints_are_allowed() {
let enabled = RUSTC.with(|r| r.cap_lints);
if !enabled { return }
let a = git::new("a", |p| {
p.file("Cargo.toml", r#"
[project]
name = "a"
version = "0.5.0"
authors = []
"#)
.file("src/lib.rs", "
#![deny(warnings)]
use std::option;
")
}).unwrap();
let p = project("foo")
.file("Cargo.toml", &format!(r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
a = {{ git = '{}' }}
"#, a.url()))
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(0).with_stderr("\
[UPDATING] git repository `[..]`
[COMPILING] a v0.5.0 ([..])
[COMPILING] foo v0.0.1 ([..])
"));
}
#[test]
fn add_a_git_dep() {
let git = git::new("git", |p| {
p.file("Cargo.toml", r#"
[project]
name = "git"
version = "0.5.0"
authors = []
"#)
.file("src/lib.rs", "")
}).unwrap();
let p = project("foo")
.file("Cargo.toml", &format!(r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
a = {{ path = 'a' }}
git = {{ git = '{}' }}
"#, git.url()))
.file("src/lib.rs", "")
.file("a/Cargo.toml", r#"
[package]
name = "a"
version = "0.0.1"
authors = []
"#)
.file("a/src/lib.rs", "");
assert_that(p.cargo_process("build"), execs().with_status(0));
File::create(p.root().join("a/Cargo.toml")).unwrap().write_all(format!(r#"
[package]
name = "a"
version = "0.0.1"
authors = []
[dependencies]
git = {{ git = '{}' }}
"#, git.url()).as_bytes()).unwrap();
assert_that(p.cargo("build"), execs().with_status(0));
}