cargo/tests/testsuite/patch.rs
2018-03-14 17:48:44 -07:00

1112 lines
24 KiB
Rust

use std::fs::{self, File};
use std::io::{Read, Write};
use toml;
use cargotest::support::git;
use cargotest::support::paths;
use cargotest::support::registry::Package;
use cargotest::support::{execs, project};
use hamcrest::assert_that;
#[test]
fn replace() {
Package::new("foo", "0.1.0").publish();
Package::new("deep-foo", "0.1.0")
.file(
"src/lib.rs",
r#"
extern crate foo;
pub fn deep() {
foo::foo();
}
"#,
)
.dep("foo", "0.1.0")
.publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
deep-foo = "0.1.0"
[patch.crates-io]
foo = { path = "foo" }
"#,
)
.file(
"src/lib.rs",
"
extern crate foo;
extern crate deep_foo;
pub fn bar() {
foo::foo();
deep_foo::deep();
}
",
)
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#,
)
.file(
"foo/src/lib.rs",
r#"
pub fn foo() {}
"#,
)
.build();
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `file://[..]`
[DOWNLOADING] deep-foo v0.1.0 ([..])
[COMPILING] foo v0.1.0 (file://[..])
[COMPILING] deep-foo v0.1.0
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
assert_that(
p.cargo("build"), //.env("RUST_LOG", "trace"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
}
#[test]
fn nonexistent() {
Package::new("baz", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[patch.crates-io]
foo = { path = "foo" }
"#,
)
.file(
"src/lib.rs",
"
extern crate foo;
pub fn bar() {
foo::foo();
}
",
)
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#,
)
.file(
"foo/src/lib.rs",
r#"
pub fn foo() {}
"#,
)
.build();
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `file://[..]`
[COMPILING] foo v0.1.0 (file://[..])
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
}
#[test]
fn patch_git() {
let foo = git::repo(&paths::root().join("override"))
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#,
)
.file("src/lib.rs", "")
.build();
let p = project("bar")
.file(
"Cargo.toml",
&format!(
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = {{ git = '{}' }}
[patch.'{0}']
foo = {{ path = "foo" }}
"#,
foo.url()
),
)
.file(
"src/lib.rs",
"
extern crate foo;
pub fn bar() {
foo::foo();
}
",
)
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#,
)
.file(
"foo/src/lib.rs",
r#"
pub fn foo() {}
"#,
)
.build();
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] git repository `file://[..]`
[COMPILING] foo v0.1.0 (file://[..])
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
}
#[test]
fn patch_to_git() {
let foo = git::repo(&paths::root().join("override"))
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#,
)
.file("src/lib.rs", "pub fn foo() {}")
.build();
Package::new("foo", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
&format!(
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1"
[patch.crates-io]
foo = {{ git = '{}' }}
"#,
foo.url()
),
)
.file(
"src/lib.rs",
"
extern crate foo;
pub fn bar() {
foo::foo();
}
",
)
.build();
assert_that(
p.cargo("build"), //.env("RUST_LOG", "cargo=trace"),
execs().with_status(0).with_stderr(
"\
[UPDATING] git repository `file://[..]`
[UPDATING] registry `file://[..]`
[COMPILING] foo v0.1.0 (file://[..])
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
}
#[test]
fn unused() {
Package::new("foo", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[patch.crates-io]
foo = { path = "foo" }
"#,
)
.file("src/lib.rs", "")
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.2.0"
authors = []
"#,
)
.file(
"foo/src/lib.rs",
r#"
not rust code
"#,
)
.build();
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `file://[..]`
[DOWNLOADING] foo v0.1.0 [..]
[COMPILING] foo v0.1.0
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
// unused patch should be in the lock file
let mut lock = String::new();
File::open(p.root().join("Cargo.lock"))
.unwrap()
.read_to_string(&mut lock)
.unwrap();
let toml: toml::Value = toml::from_str(&lock).unwrap();
assert_eq!(toml["patch"]["unused"].as_array().unwrap().len(), 1);
assert_eq!(toml["patch"]["unused"][0]["name"].as_str(), Some("foo"));
assert_eq!(
toml["patch"]["unused"][0]["version"].as_str(),
Some("0.2.0")
);
}
#[test]
fn unused_git() {
Package::new("foo", "0.1.0").publish();
let foo = git::repo(&paths::root().join("override"))
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.2.0"
authors = []
"#,
)
.file("src/lib.rs", "")
.build();
let p = project("bar")
.file(
"Cargo.toml",
&format!(
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1"
[patch.crates-io]
foo = {{ git = '{}' }}
"#,
foo.url()
),
)
.file("src/lib.rs", "")
.build();
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] git repository `file://[..]`
[UPDATING] registry `file://[..]`
[DOWNLOADING] foo v0.1.0 [..]
[COMPILING] foo v0.1.0
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
}
#[test]
fn add_patch() {
Package::new("foo", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#,
)
.file("foo/src/lib.rs", r#""#)
.build();
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `file://[..]`
[DOWNLOADING] foo v0.1.0 [..]
[COMPILING] foo v0.1.0
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
t!(t!(File::create(p.root().join("Cargo.toml"))).write_all(
br#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[patch.crates-io]
foo = { path = 'foo' }
"#
));
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[COMPILING] foo v0.1.0 (file://[..])
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
}
#[test]
fn add_ignored_patch() {
Package::new("foo", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.1"
authors = []
"#,
)
.file("foo/src/lib.rs", r#""#)
.build();
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `file://[..]`
[DOWNLOADING] foo v0.1.0 [..]
[COMPILING] foo v0.1.0
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
t!(t!(File::create(p.root().join("Cargo.toml"))).write_all(
br#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[patch.crates-io]
foo = { path = 'foo' }
"#
));
assert_that(
p.cargo("build"),
execs()
.with_status(0)
.with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]"),
);
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
}
#[test]
fn new_minor() {
Package::new("foo", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[patch.crates-io]
foo = { path = 'foo' }
"#,
)
.file("src/lib.rs", "")
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.1"
authors = []
"#,
)
.file("foo/src/lib.rs", r#""#)
.build();
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `file://[..]`
[COMPILING] foo v0.1.1 [..]
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
}
#[test]
fn transitive_new_minor() {
Package::new("foo", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
subdir = { path = 'subdir' }
[patch.crates-io]
foo = { path = 'foo' }
"#,
)
.file("src/lib.rs", "")
.file(
"subdir/Cargo.toml",
r#"
[package]
name = "subdir"
version = "0.1.0"
authors = []
[dependencies]
foo = '0.1.0'
"#,
)
.file("subdir/src/lib.rs", r#""#)
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.1"
authors = []
"#,
)
.file("foo/src/lib.rs", r#""#)
.build();
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `file://[..]`
[COMPILING] foo v0.1.1 [..]
[COMPILING] subdir v0.1.0 [..]
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
}
#[test]
fn new_major() {
Package::new("foo", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.2.0"
[patch.crates-io]
foo = { path = 'foo' }
"#,
)
.file("src/lib.rs", "")
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.2.0"
authors = []
"#,
)
.file("foo/src/lib.rs", r#""#)
.build();
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `file://[..]`
[COMPILING] foo v0.2.0 [..]
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
Package::new("foo", "0.2.0").publish();
assert_that(p.cargo("update"), execs().with_status(0));
assert_that(
p.cargo("build"),
execs()
.with_status(0)
.with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]"),
);
t!(t!(File::create(p.root().join("Cargo.toml"))).write_all(
br#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.2.0"
"#
));
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `file://[..]`
[DOWNLOADING] foo v0.2.0 [..]
[COMPILING] foo v0.2.0
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
}
#[test]
fn transitive_new_major() {
Package::new("foo", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
subdir = { path = 'subdir' }
[patch.crates-io]
foo = { path = 'foo' }
"#,
)
.file("src/lib.rs", "")
.file(
"subdir/Cargo.toml",
r#"
[package]
name = "subdir"
version = "0.1.0"
authors = []
[dependencies]
foo = '0.2.0'
"#,
)
.file("subdir/src/lib.rs", r#""#)
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.2.0"
authors = []
"#,
)
.file("foo/src/lib.rs", r#""#)
.build();
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr(
"\
[UPDATING] registry `file://[..]`
[COMPILING] foo v0.2.0 [..]
[COMPILING] subdir v0.1.0 [..]
[COMPILING] bar v0.0.1 (file://[..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
),
);
}
#[test]
fn remove_patch() {
Package::new("foo", "0.1.0").publish();
Package::new("bar", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1"
[patch.crates-io]
foo = { path = 'foo' }
bar = { path = 'bar' }
"#,
)
.file("src/lib.rs", "")
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#,
)
.file("foo/src/lib.rs", r#""#)
.file(
"bar/Cargo.toml",
r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
"#,
)
.file("bar/src/lib.rs", r#""#)
.build();
// Generate a lock file where `bar` is unused
assert_that(p.cargo("build"), execs().with_status(0));
let mut lock_file1 = String::new();
File::open(p.root().join("Cargo.lock"))
.unwrap()
.read_to_string(&mut lock_file1)
.unwrap();
// Remove `bar` and generate a new lock file form the old one
File::create(p.root().join("Cargo.toml"))
.unwrap()
.write_all(
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1"
[patch.crates-io]
foo = { path = 'foo' }
"#.as_bytes(),
)
.unwrap();
assert_that(p.cargo("build"), execs().with_status(0));
let mut lock_file2 = String::new();
File::open(p.root().join("Cargo.lock"))
.unwrap()
.read_to_string(&mut lock_file2)
.unwrap();
// Remove the lock file and build from scratch
fs::remove_file(p.root().join("Cargo.lock")).unwrap();
assert_that(p.cargo("build"), execs().with_status(0));
let mut lock_file3 = String::new();
File::open(p.root().join("Cargo.lock"))
.unwrap()
.read_to_string(&mut lock_file3)
.unwrap();
assert!(lock_file1.contains("bar"));
assert_eq!(lock_file2, lock_file3);
assert_ne!(lock_file1, lock_file2);
}
#[test]
fn non_crates_io() {
Package::new("foo", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[patch.some-other-source]
foo = { path = 'foo' }
"#,
)
.file("src/lib.rs", "")
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#,
)
.file("foo/src/lib.rs", r#""#)
.build();
assert_that(
p.cargo("build"),
execs().with_status(101).with_stderr(
"\
error: failed to parse manifest at `[..]`
Caused by:
invalid url `some-other-source`: relative URL without a base
",
),
);
}
#[test]
fn replace_with_crates_io() {
Package::new("foo", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[patch.crates-io]
foo = "0.1"
"#,
)
.file("src/lib.rs", "")
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#,
)
.file("foo/src/lib.rs", r#""#)
.build();
assert_that(
p.cargo("build"),
execs().with_status(101).with_stderr(
"\
[UPDATING] [..]
error: failed to resolve patches for `[..]`
Caused by:
patch for `foo` in `[..]` points to the same source, but patches must point \
to different sources
",
),
);
}
#[test]
fn patch_in_virtual() {
Package::new("foo", "0.1.0").publish();
let p = project("bar")
.file(
"Cargo.toml",
r#"
[workspace]
members = ["bar"]
[patch.crates-io]
foo = { path = "foo" }
"#,
)
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#,
)
.file("foo/src/lib.rs", r#""#)
.file(
"bar/Cargo.toml",
r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
[dependencies]
foo = "0.1"
"#,
)
.file("bar/src/lib.rs", r#""#)
.build();
assert_that(p.cargo("build"), execs().with_status(0));
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
}
#[test]
fn patch_depends_on_another_patch() {
Package::new("foo", "0.1.0")
.file("src/lib.rs", "broken code")
.publish();
Package::new("bar", "0.1.0")
.dep("foo", "0.1")
.file("src/lib.rs", "broken code")
.publish();
let p = project("p")
.file(
"Cargo.toml",
r#"
[package]
name = "p"
authors = []
version = "0.1.0"
[dependencies]
foo = "0.1"
bar = "0.1"
[patch.crates-io]
foo = { path = "foo" }
bar = { path = "bar" }
"#,
)
.file("src/lib.rs", "")
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.1"
authors = []
"#,
)
.file("foo/src/lib.rs", r#""#)
.file(
"bar/Cargo.toml",
r#"
[package]
name = "bar"
version = "0.1.1"
authors = []
[dependencies]
foo = "0.1"
"#,
)
.file("bar/src/lib.rs", r#""#)
.build();
assert_that(p.cargo("build"), execs().with_status(0));
// Nothing should be rebuilt, no registry should be updated.
assert_that(
p.cargo("build"),
execs().with_status(0).with_stderr("[FINISHED] [..]"),
);
}