2018-03-16 09:29:54 +00:00
|
|
|
use std::collections::{BTreeMap, HashSet};
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-01 18:14:17 +00:00
|
|
|
use hamcrest::{assert_that, contains, is_not};
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
use cargo::core::source::{GitReference, SourceId};
|
2015-09-17 03:37:45 +00:00
|
|
|
use cargo::core::dependency::Kind::{self, Development};
|
2018-06-29 19:21:05 +00:00
|
|
|
use cargo::core::{Dependency, PackageId, Registry, Summary, enable_nightly_features};
|
2018-03-20 21:33:10 +00:00
|
|
|
use cargo::util::{CargoResult, Config, ToUrl};
|
2015-01-04 09:02:16 +00:00
|
|
|
use cargo::core::resolver::{self, Method};
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-23 19:06:49 +00:00
|
|
|
use cargotest::ChannelChanger;
|
|
|
|
use cargotest::support::{execs, project};
|
|
|
|
use cargotest::support::registry::Package;
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
fn resolve(
|
|
|
|
pkg: &PackageId,
|
|
|
|
deps: Vec<Dependency>,
|
|
|
|
registry: &[Summary],
|
|
|
|
) -> CargoResult<Vec<PackageId>> {
|
2018-03-23 17:28:51 +00:00
|
|
|
resolve_with_config(pkg, deps, registry, None)
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
2018-03-20 21:33:10 +00:00
|
|
|
fn resolve_with_config(
|
|
|
|
pkg: &PackageId,
|
|
|
|
deps: Vec<Dependency>,
|
|
|
|
registry: &[Summary],
|
2018-03-23 17:28:51 +00:00
|
|
|
config: Option<&Config>,
|
2018-03-14 15:17:44 +00:00
|
|
|
) -> CargoResult<Vec<PackageId>> {
|
2017-06-05 14:44:16 +00:00
|
|
|
struct MyRegistry<'a>(&'a [Summary]);
|
|
|
|
impl<'a> Registry for MyRegistry<'a> {
|
2018-07-11 16:46:52 +00:00
|
|
|
fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary), fuzzy: bool) -> CargoResult<()> {
|
2017-06-05 14:44:16 +00:00
|
|
|
for summary in self.0.iter() {
|
2018-07-11 16:46:52 +00:00
|
|
|
if fuzzy || dep.matches(summary) {
|
2017-06-05 14:44:16 +00:00
|
|
|
f(summary.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let mut registry = MyRegistry(registry);
|
2018-07-07 15:12:22 +00:00
|
|
|
let summary = Summary::new(pkg.clone(), deps, BTreeMap::<String, Vec<String>>::new(), None::<String>, false).unwrap();
|
2014-11-19 06:29:19 +00:00
|
|
|
let method = Method::Everything;
|
2018-03-16 09:29:54 +00:00
|
|
|
let resolve = resolver::resolve(
|
|
|
|
&[(summary, method)],
|
|
|
|
&[],
|
|
|
|
&mut registry,
|
|
|
|
&HashSet::new(),
|
2018-03-23 17:28:51 +00:00
|
|
|
config,
|
2018-03-16 09:29:54 +00:00
|
|
|
false,
|
|
|
|
)?;
|
2016-11-04 00:18:48 +00:00
|
|
|
let res = resolve.iter().cloned().collect();
|
|
|
|
Ok(res)
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
trait ToDep {
|
|
|
|
fn to_dep(self) -> Dependency;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToDep for &'static str {
|
|
|
|
fn to_dep(self) -> Dependency {
|
|
|
|
let url = "http://example.com".to_url().unwrap();
|
2017-08-11 14:25:19 +00:00
|
|
|
let source_id = SourceId::for_registry(&url).unwrap();
|
2016-10-07 19:34:00 +00:00
|
|
|
Dependency::parse_no_deprecated(self, Some("1.0.0"), &source_id).unwrap()
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToDep for Dependency {
|
|
|
|
fn to_dep(self) -> Dependency {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
trait ToPkgId {
|
|
|
|
fn to_pkgid(&self) -> PackageId;
|
|
|
|
}
|
|
|
|
|
2018-02-27 15:08:19 +00:00
|
|
|
impl<'a> ToPkgId for &'a str {
|
2014-10-17 15:17:17 +00:00
|
|
|
fn to_pkgid(&self) -> PackageId {
|
|
|
|
PackageId::new(*self, "1.0.0", ®istry_loc()).unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-27 15:08:19 +00:00
|
|
|
impl<'a> ToPkgId for (&'a str, &'a str) {
|
2014-10-17 15:17:17 +00:00
|
|
|
fn to_pkgid(&self) -> PackageId {
|
|
|
|
let (name, vers) = *self;
|
|
|
|
PackageId::new(name, vers, ®istry_loc()).unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-27 15:08:19 +00:00
|
|
|
impl<'a> ToPkgId for (&'a str, String) {
|
2017-12-18 17:06:45 +00:00
|
|
|
fn to_pkgid(&self) -> PackageId {
|
|
|
|
let (name, ref vers) = *self;
|
|
|
|
PackageId::new(name, vers, ®istry_loc()).unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-19 18:38:32 +00:00
|
|
|
macro_rules! pkg {
|
2014-10-17 15:17:17 +00:00
|
|
|
($pkgid:expr => [$($deps:expr),+]) => ({
|
|
|
|
let d: Vec<Dependency> = vec![$($deps.to_dep()),+];
|
2018-01-30 19:46:58 +00:00
|
|
|
let pkgid = $pkgid.to_pkgid();
|
2018-07-06 19:32:05 +00:00
|
|
|
let link = if pkgid.name().ends_with("-sys") {Some(pkgid.name().as_str())} else {None};
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-07-07 15:12:22 +00:00
|
|
|
Summary::new(pkgid, d, BTreeMap::<String, Vec<String>>::new(), link, false).unwrap()
|
2014-10-17 15:17:17 +00:00
|
|
|
});
|
|
|
|
|
2018-01-30 19:46:58 +00:00
|
|
|
($pkgid:expr) => ({
|
|
|
|
let pkgid = $pkgid.to_pkgid();
|
2018-07-06 19:32:05 +00:00
|
|
|
let link = if pkgid.name().ends_with("-sys") {Some(pkgid.name().as_str())} else {None};
|
2018-07-07 15:12:22 +00:00
|
|
|
Summary::new(pkgid, Vec::new(), BTreeMap::<String, Vec<String>>::new(), link, false).unwrap()
|
2018-01-30 19:46:58 +00:00
|
|
|
})
|
2014-12-19 18:38:32 +00:00
|
|
|
}
|
2014-10-17 15:17:17 +00:00
|
|
|
|
|
|
|
fn registry_loc() -> SourceId {
|
|
|
|
let remote = "http://example.com".to_url().unwrap();
|
2017-08-11 14:25:19 +00:00
|
|
|
SourceId::for_registry(&remote).unwrap()
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn pkg(name: &str) -> Summary {
|
2018-03-14 15:17:44 +00:00
|
|
|
let link = if name.ends_with("-sys") {
|
2018-07-06 19:32:05 +00:00
|
|
|
Some(name)
|
2018-03-14 15:17:44 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2018-07-07 15:12:22 +00:00
|
|
|
Summary::new(pkg_id(name), Vec::new(), BTreeMap::<String, Vec<String>>::new(), link, false).unwrap()
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn pkg_id(name: &str) -> PackageId {
|
|
|
|
PackageId::new(name, "1.0.0", ®istry_loc()).unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pkg_id_loc(name: &str, loc: &str) -> PackageId {
|
|
|
|
let remote = loc.to_url();
|
2014-12-08 18:46:07 +00:00
|
|
|
let master = GitReference::Branch("master".to_string());
|
2017-08-11 14:25:19 +00:00
|
|
|
let source_id = SourceId::for_git(&remote.unwrap(), master).unwrap();
|
2014-10-17 15:17:17 +00:00
|
|
|
|
|
|
|
PackageId::new(name, "1.0.0", &source_id).unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pkg_loc(name: &str, loc: &str) -> Summary {
|
2018-03-14 15:17:44 +00:00
|
|
|
let link = if name.ends_with("-sys") {
|
2018-07-06 19:32:05 +00:00
|
|
|
Some(name)
|
2018-03-14 15:17:44 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2017-10-02 09:00:18 +00:00
|
|
|
Summary::new(
|
|
|
|
pkg_id_loc(name, loc),
|
|
|
|
Vec::new(),
|
2018-07-07 15:12:22 +00:00
|
|
|
BTreeMap::<String, Vec<String>>::new(),
|
2017-10-02 09:00:18 +00:00
|
|
|
link,
|
|
|
|
false,
|
|
|
|
).unwrap()
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
fn dep(name: &str) -> Dependency {
|
|
|
|
dep_req(name, "1.0.0")
|
|
|
|
}
|
2014-10-17 15:17:17 +00:00
|
|
|
fn dep_req(name: &str, req: &str) -> Dependency {
|
|
|
|
let url = "http://example.com".to_url().unwrap();
|
2017-08-11 14:25:19 +00:00
|
|
|
let source_id = SourceId::for_registry(&url).unwrap();
|
2016-10-07 19:34:00 +00:00
|
|
|
Dependency::parse_no_deprecated(name, Some(req), &source_id).unwrap()
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn dep_loc(name: &str, location: &str) -> Dependency {
|
|
|
|
let url = location.to_url().unwrap();
|
2014-12-08 18:46:07 +00:00
|
|
|
let master = GitReference::Branch("master".to_string());
|
2017-08-11 14:25:19 +00:00
|
|
|
let source_id = SourceId::for_git(&url, master).unwrap();
|
2016-10-07 19:34:00 +00:00
|
|
|
Dependency::parse_no_deprecated(name, Some("1.0.0"), &source_id).unwrap()
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
2015-09-17 03:37:45 +00:00
|
|
|
fn dep_kind(name: &str, kind: Kind) -> Dependency {
|
2017-06-02 13:59:16 +00:00
|
|
|
dep(name).set_kind(kind).clone()
|
2015-09-17 03:37:45 +00:00
|
|
|
}
|
2014-10-17 15:17:17 +00:00
|
|
|
|
|
|
|
fn registry(pkgs: Vec<Summary>) -> Vec<Summary> {
|
|
|
|
pkgs
|
|
|
|
}
|
|
|
|
|
|
|
|
fn names<P: ToPkgId>(names: &[P]) -> Vec<PackageId> {
|
|
|
|
names.iter().map(|name| name.to_pkgid()).collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn loc_names(names: &[(&'static str, &'static str)]) -> Vec<PackageId> {
|
2018-03-14 15:17:44 +00:00
|
|
|
names
|
|
|
|
.iter()
|
|
|
|
.map(|&(name, loc)| pkg_id_loc(name, loc))
|
|
|
|
.collect()
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
2018-03-23 14:26:50 +00:00
|
|
|
#[test]
|
2018-04-04 21:06:26 +00:00
|
|
|
#[should_panic(expected = "assertion failed: !name.is_empty()")]
|
2018-03-23 14:26:50 +00:00
|
|
|
fn test_dependency_with_empty_name() {
|
|
|
|
// Bug 5229, dependency-names must not be empty
|
|
|
|
"".to_dep();
|
|
|
|
}
|
|
|
|
|
2014-10-17 15:17:17 +00:00
|
|
|
#[test]
|
|
|
|
fn test_resolving_empty_dependency_list() {
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), Vec::new(), ®istry(vec![])).unwrap();
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-01 18:14:17 +00:00
|
|
|
assert_eq!(res, names(&["root"]));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn assert_same(a: &[PackageId], b: &[PackageId]) {
|
|
|
|
assert_eq!(a.len(), b.len());
|
|
|
|
for item in a {
|
|
|
|
assert!(b.contains(item));
|
|
|
|
}
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_resolving_only_package() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![pkg("foo")]);
|
2018-03-01 18:14:17 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep("foo")], ®).unwrap();
|
|
|
|
assert_same(&res, &names(&["root", "foo"]));
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_resolving_one_dep() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![pkg("foo"), pkg("bar")]);
|
2018-03-01 18:14:17 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep("foo")], ®).unwrap();
|
|
|
|
assert_same(&res, &names(&["root", "foo"]));
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_resolving_multiple_deps() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![pkg!("foo"), pkg!("bar"), pkg!("baz")]);
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep("foo"), dep("baz")], ®).unwrap();
|
2018-03-01 18:14:17 +00:00
|
|
|
assert_same(&res, &names(&["root", "foo", "baz"]));
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_resolving_transitive_deps() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![pkg!("foo"), pkg!("bar" => ["foo"])]);
|
2017-09-24 14:26:37 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep("bar")], ®).unwrap();
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2014-11-22 10:04:40 +00:00
|
|
|
assert_that(&res, contains(names(&["root", "foo", "bar"])));
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_resolving_common_transitive_deps() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![pkg!("foo" => ["bar"]), pkg!("bar")]);
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep("foo"), dep("bar")], ®).unwrap();
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2014-11-22 10:04:40 +00:00
|
|
|
assert_that(&res, contains(names(&["root", "foo", "bar"])));
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_resolving_with_same_name() {
|
2018-03-14 15:17:44 +00:00
|
|
|
let list = vec![
|
|
|
|
pkg_loc("foo", "http://first.example.com"),
|
|
|
|
pkg_loc("bar", "http://second.example.com"),
|
|
|
|
];
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(list);
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![
|
|
|
|
dep_loc("foo", "http://first.example.com"),
|
|
|
|
dep_loc("bar", "http://second.example.com"),
|
|
|
|
],
|
|
|
|
®,
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
let mut names = loc_names(&[
|
|
|
|
("foo", "http://first.example.com"),
|
|
|
|
("bar", "http://second.example.com"),
|
|
|
|
]);
|
2014-10-17 15:17:17 +00:00
|
|
|
|
|
|
|
names.push(pkg_id("root"));
|
2018-03-01 18:14:17 +00:00
|
|
|
assert_same(&res, &names);
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_resolving_with_dev_deps() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![
|
2015-09-17 03:37:45 +00:00
|
|
|
pkg!("foo" => ["bar", dep_kind("baz", Development)]),
|
|
|
|
pkg!("baz" => ["bat", dep_kind("bam", Development)]),
|
2014-10-17 15:17:17 +00:00
|
|
|
pkg!("bar"),
|
2018-03-14 15:17:44 +00:00
|
|
|
pkg!("bat"),
|
2015-11-23 16:56:10 +00:00
|
|
|
]);
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep("foo"), dep_kind("baz", Development)],
|
|
|
|
®,
|
|
|
|
).unwrap();
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2014-11-22 10:04:40 +00:00
|
|
|
assert_that(&res, contains(names(&["root", "foo", "bar", "baz"])));
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn resolving_with_many_versions() {
|
2018-03-14 15:17:44 +00:00
|
|
|
let reg = registry(vec![pkg!(("foo", "1.0.1")), pkg!(("foo", "1.0.2"))]);
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2017-09-24 14:26:37 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep("foo")], ®).unwrap();
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[("root", "1.0.0"), ("foo", "1.0.2")])),
|
|
|
|
);
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn resolving_with_specific_version() {
|
2018-03-14 15:17:44 +00:00
|
|
|
let reg = registry(vec![pkg!(("foo", "1.0.1")), pkg!(("foo", "1.0.2"))]);
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep_req("foo", "=1.0.1")], ®).unwrap();
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[("root", "1.0.0"), ("foo", "1.0.1")])),
|
|
|
|
);
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
2016-12-13 21:00:15 +00:00
|
|
|
#[test]
|
|
|
|
fn test_resolving_maximum_version_with_transitive_deps() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![
|
2016-12-13 21:00:15 +00:00
|
|
|
pkg!(("util", "1.2.2")),
|
|
|
|
pkg!(("util", "1.0.0")),
|
|
|
|
pkg!(("util", "1.1.1")),
|
|
|
|
pkg!("foo" => [dep_req("util", "1.0.0")]),
|
|
|
|
pkg!("bar" => [dep_req("util", ">=1.0.1")]),
|
|
|
|
]);
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep_req("foo", "1.0.0"), dep_req("bar", "1.0.0")],
|
|
|
|
®,
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
("foo", "1.0.0"),
|
|
|
|
("bar", "1.0.0"),
|
|
|
|
("util", "1.2.2"),
|
|
|
|
])),
|
|
|
|
);
|
2018-03-01 18:14:17 +00:00
|
|
|
assert_that(&res, is_not(contains(names(&[("util", "1.0.1")]))));
|
|
|
|
assert_that(&res, is_not(contains(names(&[("util", "1.1.1")]))));
|
2016-12-13 21:00:15 +00:00
|
|
|
}
|
|
|
|
|
2018-03-20 21:33:10 +00:00
|
|
|
#[test]
|
|
|
|
fn test_resolving_minimum_version_with_transitive_deps() {
|
2018-06-29 19:21:05 +00:00
|
|
|
enable_nightly_features(); // -Z minimal-versions
|
2018-03-23 17:28:51 +00:00
|
|
|
// When the minimal-versions config option is specified then the lowest
|
|
|
|
// possible version of a package should be selected. "util 1.0.0" can't be
|
|
|
|
// selected because of the requirements of "bar", so the minimum version
|
|
|
|
// must be 1.1.1.
|
2018-03-20 21:33:10 +00:00
|
|
|
let reg = registry(vec![
|
|
|
|
pkg!(("util", "1.2.2")),
|
|
|
|
pkg!(("util", "1.0.0")),
|
|
|
|
pkg!(("util", "1.1.1")),
|
|
|
|
pkg!("foo" => [dep_req("util", "1.0.0")]),
|
|
|
|
pkg!("bar" => [dep_req("util", ">=1.0.1")]),
|
|
|
|
]);
|
|
|
|
|
|
|
|
let mut config = Config::default().unwrap();
|
|
|
|
config
|
|
|
|
.configure(
|
|
|
|
1,
|
|
|
|
None,
|
|
|
|
&None,
|
|
|
|
false,
|
|
|
|
false,
|
2018-04-16 23:50:30 +00:00
|
|
|
&None,
|
2018-03-20 21:33:10 +00:00
|
|
|
&["minimal-versions".to_string()],
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let res = resolve_with_config(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep_req("foo", "1.0.0"), dep_req("bar", "1.0.0")],
|
|
|
|
®,
|
2018-03-23 17:28:51 +00:00
|
|
|
Some(&config),
|
2018-03-20 21:33:10 +00:00
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
("foo", "1.0.0"),
|
|
|
|
("bar", "1.0.0"),
|
|
|
|
("util", "1.1.1"),
|
|
|
|
])),
|
|
|
|
);
|
|
|
|
assert_that(&res, is_not(contains(names(&[("util", "1.2.2")]))));
|
|
|
|
assert_that(&res, is_not(contains(names(&[("util", "1.0.0")]))));
|
|
|
|
}
|
|
|
|
|
2018-03-23 19:06:49 +00:00
|
|
|
// Ensure that the "-Z minimal-versions" CLI option works and the minimal
|
|
|
|
// version of a dependency ends up in the lock file.
|
|
|
|
#[test]
|
|
|
|
fn minimal_version_cli() {
|
|
|
|
Package::new("dep", "1.0.0").publish();
|
|
|
|
Package::new("dep", "1.1.0").publish();
|
|
|
|
|
|
|
|
let p = project("foo")
|
|
|
|
.file(
|
|
|
|
"Cargo.toml",
|
|
|
|
r#"
|
|
|
|
[package]
|
|
|
|
name = "foo"
|
|
|
|
authors = []
|
|
|
|
version = "0.0.1"
|
|
|
|
|
|
|
|
[dependencies]
|
|
|
|
dep = "1.0"
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.file("src/main.rs", "fn main() {}")
|
|
|
|
.build();
|
|
|
|
|
|
|
|
assert_that(
|
|
|
|
p.cargo("generate-lockfile")
|
|
|
|
.masquerade_as_nightly_cargo()
|
|
|
|
.arg("-Zminimal-versions"),
|
|
|
|
execs().with_status(0),
|
|
|
|
);
|
|
|
|
|
|
|
|
let lock = p.read_lockfile();
|
|
|
|
|
|
|
|
assert!(lock.contains("dep 1.0.0"));
|
|
|
|
}
|
|
|
|
|
2014-10-17 15:17:17 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_incompat_versions() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![
|
2014-10-17 15:17:17 +00:00
|
|
|
pkg!(("foo", "1.0.1")),
|
|
|
|
pkg!(("foo", "1.0.2")),
|
|
|
|
pkg!("bar" => [dep_req("foo", "=1.0.2")]),
|
2015-11-23 16:56:10 +00:00
|
|
|
]);
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert!(
|
|
|
|
resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep_req("foo", "=1.0.1"), dep("bar")],
|
|
|
|
®
|
|
|
|
).is_err()
|
|
|
|
);
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 15:05:44 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_wrong_case_from_registry() {
|
|
|
|
// In the future we may #5678 allow this to happen.
|
|
|
|
// For back compatibility reasons, we probably won't.
|
|
|
|
// But we may want to future prove ourselves by understanding it.
|
|
|
|
// This test documents the current behavior.
|
|
|
|
let reg = registry(vec![
|
|
|
|
pkg!(("foo", "1.0.0")),
|
|
|
|
pkg!("bar" => ["Foo"]),
|
|
|
|
]);
|
|
|
|
|
|
|
|
assert!(
|
|
|
|
resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep("bar")],
|
|
|
|
®
|
|
|
|
).is_err()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn resolving_mis_hyphenated_from_registry() {
|
|
|
|
// In the future we may #2775 allow this to happen.
|
|
|
|
// For back compatibility reasons, we probably won't.
|
|
|
|
// But we may want to future prove ourselves by understanding it.
|
|
|
|
// This test documents the current behavior.
|
|
|
|
let reg = registry(vec![
|
|
|
|
pkg!(("fo-o", "1.0.0")),
|
|
|
|
pkg!("bar" => ["fo_o"]),
|
|
|
|
]);
|
|
|
|
|
|
|
|
assert!(
|
|
|
|
resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep("bar")],
|
|
|
|
®
|
|
|
|
).is_err()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-10-17 15:17:17 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_backtrack() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![
|
2014-10-17 15:17:17 +00:00
|
|
|
pkg!(("foo", "1.0.2") => [dep("bar")]),
|
|
|
|
pkg!(("foo", "1.0.1") => [dep("baz")]),
|
|
|
|
pkg!("bar" => [dep_req("foo", "=2.0.2")]),
|
|
|
|
pkg!("baz"),
|
2015-11-23 16:56:10 +00:00
|
|
|
]);
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep_req("foo", "^1")], ®).unwrap();
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
("foo", "1.0.1"),
|
|
|
|
("baz", "1.0.0"),
|
|
|
|
])),
|
|
|
|
);
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
2018-02-27 15:08:19 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_backtrack_features() {
|
|
|
|
// test for cargo/issues/4347
|
|
|
|
let mut bad = dep("bar");
|
2018-07-06 19:32:05 +00:00
|
|
|
bad.set_features(vec!["bad"]);
|
2018-02-27 15:08:19 +00:00
|
|
|
|
|
|
|
let reg = registry(vec![
|
|
|
|
pkg!(("foo", "1.0.2") => [bad]),
|
|
|
|
pkg!(("foo", "1.0.1") => [dep("bar")]),
|
|
|
|
pkg!("bar"),
|
|
|
|
]);
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep_req("foo", "^1")], ®).unwrap();
|
2018-02-27 15:08:19 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
("foo", "1.0.1"),
|
|
|
|
("bar", "1.0.0"),
|
|
|
|
])),
|
|
|
|
);
|
2018-02-27 15:08:19 +00:00
|
|
|
}
|
|
|
|
|
2014-10-17 15:17:17 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_allows_multiple_compatible_versions() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![
|
2014-10-17 15:17:17 +00:00
|
|
|
pkg!(("foo", "1.0.0")),
|
|
|
|
pkg!(("foo", "2.0.0")),
|
|
|
|
pkg!(("foo", "0.1.0")),
|
|
|
|
pkg!(("foo", "0.2.0")),
|
|
|
|
pkg!("bar" => ["d1", "d2", "d3", "d4"]),
|
|
|
|
pkg!("d1" => [dep_req("foo", "1")]),
|
|
|
|
pkg!("d2" => [dep_req("foo", "2")]),
|
|
|
|
pkg!("d3" => [dep_req("foo", "0.1")]),
|
|
|
|
pkg!("d4" => [dep_req("foo", "0.2")]),
|
2015-11-23 16:56:10 +00:00
|
|
|
]);
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep("bar")], ®).unwrap();
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
("foo", "1.0.0"),
|
|
|
|
("foo", "2.0.0"),
|
|
|
|
("foo", "0.1.0"),
|
|
|
|
("foo", "0.2.0"),
|
|
|
|
("d1", "1.0.0"),
|
|
|
|
("d2", "1.0.0"),
|
|
|
|
("d3", "1.0.0"),
|
|
|
|
("d4", "1.0.0"),
|
|
|
|
("bar", "1.0.0"),
|
|
|
|
])),
|
|
|
|
);
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn resolving_with_deep_backtracking() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![
|
2014-10-17 15:17:17 +00:00
|
|
|
pkg!(("foo", "1.0.1") => [dep_req("bar", "1")]),
|
|
|
|
pkg!(("foo", "1.0.0") => [dep_req("bar", "2")]),
|
|
|
|
pkg!(("bar", "1.0.0") => [dep_req("baz", "=1.0.2"),
|
|
|
|
dep_req("other", "1")]),
|
|
|
|
pkg!(("bar", "2.0.0") => [dep_req("baz", "=1.0.1")]),
|
|
|
|
pkg!(("baz", "1.0.2") => [dep_req("other", "2")]),
|
|
|
|
pkg!(("baz", "1.0.1")),
|
|
|
|
pkg!(("dep_req", "1.0.0")),
|
|
|
|
pkg!(("dep_req", "2.0.0")),
|
2015-11-23 16:56:10 +00:00
|
|
|
]);
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep_req("foo", "1")], ®).unwrap();
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
("foo", "1.0.0"),
|
|
|
|
("bar", "2.0.0"),
|
|
|
|
("baz", "1.0.1"),
|
|
|
|
])),
|
|
|
|
);
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
2018-01-30 19:46:58 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_with_sys_crates() {
|
|
|
|
// This is based on issues/4902
|
|
|
|
// With `l` a normal library we get 2copies so everyone gets the newest compatible.
|
|
|
|
// But `l-sys` a library with a links attribute we make sure there is only one.
|
|
|
|
let reg = registry(vec![
|
|
|
|
pkg!(("l-sys", "0.9.1")),
|
|
|
|
pkg!(("l-sys", "0.10.0")),
|
|
|
|
pkg!(("l", "0.9.1")),
|
|
|
|
pkg!(("l", "0.10.0")),
|
|
|
|
pkg!(("d", "1.0.0") => [dep_req("l-sys", ">=0.8.0, <=0.10.0"), dep_req("l", ">=0.8.0, <=0.10.0")]),
|
|
|
|
pkg!(("r", "1.0.0") => [dep_req("l-sys", "0.9"), dep_req("l", "0.9")]),
|
|
|
|
]);
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep_req("d", "1"), dep_req("r", "1")],
|
|
|
|
®,
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
("d", "1.0.0"),
|
|
|
|
("r", "1.0.0"),
|
|
|
|
("l-sys", "0.9.1"),
|
|
|
|
("l", "0.9.1"),
|
|
|
|
("l", "0.10.0"),
|
|
|
|
])),
|
|
|
|
);
|
2018-01-30 19:46:58 +00:00
|
|
|
}
|
|
|
|
|
2017-12-18 17:06:45 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_with_constrained_sibling_backtrack_parent() {
|
|
|
|
// There is no point in considering all of the backtrack_trap{1,2}
|
|
|
|
// candidates since they can't change the result of failing to
|
2018-02-03 21:49:42 +00:00
|
|
|
// resolve 'constrained'. Cargo should (ideally) skip past them and resume
|
2017-12-18 17:06:45 +00:00
|
|
|
// resolution once the activation of the parent, 'bar', is rolled back.
|
2018-02-03 21:49:42 +00:00
|
|
|
// Note that the traps are slightly more constrained to make sure they
|
|
|
|
// get picked first.
|
2017-12-18 17:06:45 +00:00
|
|
|
let mut reglist = vec![
|
|
|
|
pkg!(("foo", "1.0.0") => [dep_req("bar", "1.0"),
|
|
|
|
dep_req("constrained", "=1.0.0")]),
|
|
|
|
pkg!(("bar", "1.0.0") => [dep_req("backtrack_trap1", "1.0.2"),
|
|
|
|
dep_req("backtrack_trap2", "1.0.2"),
|
|
|
|
dep_req("constrained", "1.0.0")]),
|
|
|
|
pkg!(("constrained", "1.0.0")),
|
|
|
|
pkg!(("backtrack_trap1", "1.0.0")),
|
|
|
|
pkg!(("backtrack_trap2", "1.0.0")),
|
|
|
|
];
|
2018-02-03 21:49:42 +00:00
|
|
|
// Bump this to make the test harder - it adds more versions of bar that will
|
|
|
|
// fail to resolve, and more versions of the traps to consider.
|
|
|
|
const NUM_BARS_AND_TRAPS: usize = 50; // minimum 2
|
|
|
|
for i in 1..NUM_BARS_AND_TRAPS {
|
2017-12-18 17:06:45 +00:00
|
|
|
let vsn = format!("1.0.{}", i);
|
2018-03-14 15:17:44 +00:00
|
|
|
reglist.push(
|
|
|
|
pkg!(("bar", vsn.clone()) => [dep_req("backtrack_trap1", "1.0.2"),
|
2017-12-18 17:06:45 +00:00
|
|
|
dep_req("backtrack_trap2", "1.0.2"),
|
2018-03-14 15:17:44 +00:00
|
|
|
dep_req("constrained", "1.0.1")]),
|
|
|
|
);
|
2017-12-18 17:06:45 +00:00
|
|
|
reglist.push(pkg!(("backtrack_trap1", vsn.clone())));
|
|
|
|
reglist.push(pkg!(("backtrack_trap2", vsn.clone())));
|
|
|
|
reglist.push(pkg!(("constrained", vsn.clone())));
|
|
|
|
}
|
|
|
|
let reg = registry(reglist);
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep_req("foo", "1")], ®).unwrap();
|
2017-12-18 17:06:45 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
("foo", "1.0.0"),
|
|
|
|
("bar", "1.0.0"),
|
|
|
|
("constrained", "1.0.0"),
|
|
|
|
])),
|
|
|
|
);
|
2017-12-18 17:06:45 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 17:55:17 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_with_many_equivalent_backtracking() {
|
2018-03-12 21:36:02 +00:00
|
|
|
let mut reglist = Vec::new();
|
2018-02-22 17:55:17 +00:00
|
|
|
|
2018-03-09 19:34:45 +00:00
|
|
|
const DEPTH: usize = 200;
|
|
|
|
const BRANCHING_FACTOR: usize = 100;
|
2018-02-22 17:55:17 +00:00
|
|
|
|
2018-03-12 21:36:02 +00:00
|
|
|
// Each level depends on the next but the last level does not exist.
|
|
|
|
// Without cashing we need to test every path to the last level O(BRANCHING_FACTOR ^ DEPTH)
|
|
|
|
// and this test will time out. With cashing we need to discover that none of these
|
|
|
|
// can be activated O(BRANCHING_FACTOR * DEPTH)
|
2018-02-22 17:55:17 +00:00
|
|
|
for l in 0..DEPTH {
|
|
|
|
let name = format!("level{}", l);
|
|
|
|
let next = format!("level{}", l + 1);
|
|
|
|
for i in 1..BRANCHING_FACTOR {
|
|
|
|
let vsn = format!("1.0.{}", i);
|
|
|
|
reglist.push(pkg!((name.as_str(), vsn.as_str()) => [dep_req(next.as_str(), "*")]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-12 21:36:02 +00:00
|
|
|
let reg = registry(reglist.clone());
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep_req("level0", "*")], ®);
|
2018-03-12 21:36:02 +00:00
|
|
|
|
|
|
|
assert!(res.is_err());
|
|
|
|
|
|
|
|
// It is easy to write code that quickly returns an error.
|
|
|
|
// Lets make sure we can find a good answer if it is there.
|
|
|
|
reglist.push(pkg!(("level0", "1.0.0")));
|
|
|
|
|
2018-03-13 15:16:10 +00:00
|
|
|
let reg = registry(reglist.clone());
|
2018-02-22 17:55:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep_req("level0", "*")], ®).unwrap();
|
2018-02-22 17:55:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[("root", "1.0.0"), ("level0", "1.0.0")])),
|
|
|
|
);
|
2018-03-13 15:16:10 +00:00
|
|
|
|
|
|
|
// Make sure we have not special case no candidates.
|
|
|
|
reglist.push(pkg!(("constrained", "1.1.0")));
|
|
|
|
reglist.push(pkg!(("constrained", "1.0.0")));
|
2018-03-14 15:17:44 +00:00
|
|
|
reglist.push(
|
|
|
|
pkg!((format!("level{}", DEPTH).as_str(), "1.0.0") => [dep_req("constrained", "=1.0.0")]),
|
|
|
|
);
|
2018-03-13 15:16:10 +00:00
|
|
|
|
|
|
|
let reg = registry(reglist.clone());
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep_req("level0", "*"), dep_req("constrained", "*")],
|
|
|
|
®,
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
("level0", "1.0.0"),
|
|
|
|
("constrained", "1.1.0"),
|
|
|
|
])),
|
|
|
|
);
|
2018-03-13 15:16:10 +00:00
|
|
|
|
|
|
|
let reg = registry(reglist.clone());
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep_req("level0", "1.0.1"), dep_req("constrained", "*")],
|
|
|
|
®,
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
(format!("level{}", DEPTH).as_str(), "1.0.0"),
|
|
|
|
("constrained", "1.0.0"),
|
|
|
|
])),
|
|
|
|
);
|
2018-03-13 15:16:10 +00:00
|
|
|
|
|
|
|
let reg = registry(reglist.clone());
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep_req("level0", "1.0.1"), dep_req("constrained", "1.1.0")],
|
|
|
|
®,
|
|
|
|
);
|
2018-03-13 15:16:10 +00:00
|
|
|
|
|
|
|
assert!(res.is_err());
|
2018-02-22 17:55:17 +00:00
|
|
|
}
|
|
|
|
|
2018-03-15 17:30:42 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_with_deep_traps() {
|
|
|
|
let mut reglist = Vec::new();
|
|
|
|
|
|
|
|
const DEPTH: usize = 200;
|
|
|
|
const BRANCHING_FACTOR: usize = 100;
|
|
|
|
|
|
|
|
// Each backtrack_trap depends on the next, and adds a backtrack frame.
|
|
|
|
// None of witch is going to help with `bad`.
|
|
|
|
for l in 0..DEPTH {
|
|
|
|
let name = format!("backtrack_trap{}", l);
|
|
|
|
let next = format!("backtrack_trap{}", l + 1);
|
|
|
|
for i in 1..BRANCHING_FACTOR {
|
|
|
|
let vsn = format!("1.0.{}", i);
|
|
|
|
reglist.push(pkg!((name.as_str(), vsn.as_str()) => [dep_req(next.as_str(), "*")]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
let name = format!("backtrack_trap{}", DEPTH);
|
|
|
|
for i in 1..BRANCHING_FACTOR {
|
|
|
|
let vsn = format!("1.0.{}", i);
|
|
|
|
reglist.push(pkg!((name.as_str(), vsn.as_str())));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// slightly less constrained to make sure `cloaking` gets picked last.
|
|
|
|
for i in 1..(BRANCHING_FACTOR + 10) {
|
|
|
|
let vsn = format!("1.0.{}", i);
|
|
|
|
reglist.push(pkg!(("cloaking", vsn.as_str()) => [dep_req("bad", "1.0.1")]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let reg = registry(reglist.clone());
|
|
|
|
|
2018-03-15 19:02:40 +00:00
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep_req("backtrack_trap0", "*"), dep_req("cloaking", "*")],
|
|
|
|
®,
|
|
|
|
);
|
2018-03-15 17:30:42 +00:00
|
|
|
|
|
|
|
assert!(res.is_err());
|
|
|
|
}
|
|
|
|
|
2018-03-18 02:31:04 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_with_constrained_cousins_backtrack() {
|
|
|
|
let mut reglist = Vec::new();
|
|
|
|
|
2018-03-21 21:05:55 +00:00
|
|
|
const DEPTH: usize = 100;
|
|
|
|
const BRANCHING_FACTOR: usize = 50;
|
2018-03-18 02:31:04 +00:00
|
|
|
|
|
|
|
// Each backtrack_trap depends on the next.
|
|
|
|
// The last depends on a specific ver of constrained.
|
|
|
|
for l in 0..DEPTH {
|
|
|
|
let name = format!("backtrack_trap{}", l);
|
|
|
|
let next = format!("backtrack_trap{}", l + 1);
|
|
|
|
for i in 1..BRANCHING_FACTOR {
|
|
|
|
let vsn = format!("1.0.{}", i);
|
|
|
|
reglist.push(pkg!((name.as_str(), vsn.as_str()) => [dep_req(next.as_str(), "*")]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
let name = format!("backtrack_trap{}", DEPTH);
|
|
|
|
for i in 1..BRANCHING_FACTOR {
|
|
|
|
let vsn = format!("1.0.{}", i);
|
2018-03-21 21:05:55 +00:00
|
|
|
reglist.push(
|
|
|
|
pkg!((name.as_str(), vsn.as_str()) => [dep_req("constrained", ">=1.1.0, <=2.0.0")]),
|
|
|
|
);
|
2018-03-18 02:31:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// slightly less constrained to make sure `constrained` gets picked last.
|
|
|
|
for i in 0..(BRANCHING_FACTOR + 10) {
|
|
|
|
let vsn = format!("1.0.{}", i);
|
|
|
|
reglist.push(pkg!(("constrained", vsn.as_str())));
|
|
|
|
}
|
2018-03-21 21:05:55 +00:00
|
|
|
reglist.push(pkg!(("constrained", "1.1.0")));
|
|
|
|
reglist.push(pkg!(("constrained", "2.0.0")));
|
|
|
|
reglist.push(pkg!(("constrained", "2.0.1")));
|
2018-03-18 02:31:04 +00:00
|
|
|
}
|
2018-03-21 21:05:55 +00:00
|
|
|
reglist.push(pkg!(("cloaking", "1.0.0") => [dep_req("constrained", "~1.0.0")]));
|
2018-03-18 02:31:04 +00:00
|
|
|
|
|
|
|
let reg = registry(reglist.clone());
|
|
|
|
|
2018-03-21 21:05:55 +00:00
|
|
|
// `backtrack_trap0 = "*"` is a lot of ways of saying `constrained = ">=1.1.0, <=2.0.0"`
|
|
|
|
// but `constrained= "2.0.1"` is already picked.
|
|
|
|
// Only then to try and solve `constrained= "~1.0.0"` which is incompatible.
|
2018-03-18 02:31:04 +00:00
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![
|
|
|
|
dep_req("backtrack_trap0", "*"),
|
2018-03-21 21:05:55 +00:00
|
|
|
dep_req("constrained", "2.0.1"),
|
|
|
|
dep_req("cloaking", "*"),
|
2018-03-18 02:31:04 +00:00
|
|
|
],
|
|
|
|
®,
|
|
|
|
);
|
|
|
|
|
|
|
|
assert!(res.is_err());
|
2018-03-18 03:05:08 +00:00
|
|
|
|
|
|
|
// Each level depends on the next but the last depends on incompatible deps.
|
|
|
|
// Let's make sure that we can cache that a dep has incompatible deps.
|
|
|
|
for l in 0..DEPTH {
|
|
|
|
let name = format!("level{}", l);
|
|
|
|
let next = format!("level{}", l + 1);
|
|
|
|
for i in 1..BRANCHING_FACTOR {
|
|
|
|
let vsn = format!("1.0.{}", i);
|
|
|
|
reglist.push(pkg!((name.as_str(), vsn.as_str()) => [dep_req(next.as_str(), "*")]));
|
|
|
|
}
|
|
|
|
}
|
2018-03-21 21:05:55 +00:00
|
|
|
reglist.push(
|
|
|
|
pkg!((format!("level{}", DEPTH).as_str(), "1.0.0") => [dep_req("backtrack_trap0", "*"),
|
|
|
|
dep_req("cloaking", "*")
|
2018-03-23 20:40:51 +00:00
|
|
|
]),
|
2018-03-21 21:05:55 +00:00
|
|
|
);
|
2018-03-18 03:05:08 +00:00
|
|
|
|
|
|
|
let reg = registry(reglist.clone());
|
|
|
|
|
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
2018-03-21 21:05:55 +00:00
|
|
|
vec![dep_req("level0", "*"), dep_req("constrained", "2.0.1")],
|
2018-03-18 03:05:08 +00:00
|
|
|
®,
|
|
|
|
);
|
|
|
|
|
|
|
|
assert!(res.is_err());
|
2018-03-21 21:05:55 +00:00
|
|
|
|
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep_req("level0", "*"), dep_req("constrained", "2.0.0")],
|
|
|
|
®,
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[("constrained", "2.0.0"), ("cloaking", "1.0.0")])),
|
|
|
|
);
|
2018-03-18 02:31:04 +00:00
|
|
|
}
|
|
|
|
|
2017-12-18 17:06:45 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_with_constrained_sibling_backtrack_activation() {
|
|
|
|
// It makes sense to resolve most-constrained deps first, but
|
|
|
|
// with that logic the backtrack traps here come between the two
|
|
|
|
// attempted resolutions of 'constrained'. When backtracking,
|
|
|
|
// cargo should skip past them and resume resolution once the
|
|
|
|
// number of activations for 'constrained' changes.
|
|
|
|
let mut reglist = vec![
|
|
|
|
pkg!(("foo", "1.0.0") => [dep_req("bar", "=1.0.0"),
|
|
|
|
dep_req("backtrack_trap1", "1.0"),
|
|
|
|
dep_req("backtrack_trap2", "1.0"),
|
|
|
|
dep_req("constrained", "<=1.0.60")]),
|
|
|
|
pkg!(("bar", "1.0.0") => [dep_req("constrained", ">=1.0.60")]),
|
|
|
|
];
|
2018-02-03 21:49:42 +00:00
|
|
|
// Bump these to make the test harder, but you'll also need to
|
|
|
|
// change the version constraints on `constrained` above. To correctly
|
|
|
|
// exercise Cargo, the relationship between the values is:
|
|
|
|
// NUM_CONSTRAINED - vsn < NUM_TRAPS < vsn
|
|
|
|
// to make sure the traps are resolved between `constrained`.
|
|
|
|
const NUM_TRAPS: usize = 45; // min 1
|
|
|
|
const NUM_CONSTRAINED: usize = 100; // min 1
|
|
|
|
for i in 0..NUM_TRAPS {
|
2017-12-18 17:06:45 +00:00
|
|
|
let vsn = format!("1.0.{}", i);
|
|
|
|
reglist.push(pkg!(("backtrack_trap1", vsn.clone())));
|
|
|
|
reglist.push(pkg!(("backtrack_trap2", vsn.clone())));
|
|
|
|
}
|
2018-02-03 21:49:42 +00:00
|
|
|
for i in 0..NUM_CONSTRAINED {
|
2017-12-18 17:06:45 +00:00
|
|
|
let vsn = format!("1.0.{}", i);
|
|
|
|
reglist.push(pkg!(("constrained", vsn.clone())));
|
|
|
|
}
|
|
|
|
let reg = registry(reglist);
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep_req("foo", "1")], ®).unwrap();
|
2017-12-18 17:06:45 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
("foo", "1.0.0"),
|
|
|
|
("bar", "1.0.0"),
|
|
|
|
("constrained", "1.0.60"),
|
|
|
|
])),
|
|
|
|
);
|
2017-12-18 17:06:45 +00:00
|
|
|
}
|
|
|
|
|
2018-02-03 21:49:42 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_with_constrained_sibling_transitive_dep_effects() {
|
|
|
|
// When backtracking due to a failed dependency, if Cargo is
|
|
|
|
// trying to be clever and skip irrelevant dependencies, care must
|
|
|
|
// be taken to not miss the transitive effects of alternatives. E.g.
|
|
|
|
// in the right-to-left resolution of the graph below, B may
|
|
|
|
// affect whether D is successfully resolved.
|
|
|
|
//
|
|
|
|
// A
|
|
|
|
// / | \
|
|
|
|
// B C D
|
|
|
|
// | |
|
|
|
|
// C D
|
|
|
|
let reg = registry(vec![
|
|
|
|
pkg!(("A", "1.0.0") => [dep_req("B", "1.0"),
|
|
|
|
dep_req("C", "1.0"),
|
|
|
|
dep_req("D", "1.0.100")]),
|
|
|
|
pkg!(("B", "1.0.0") => [dep_req("C", ">=1.0.0")]),
|
|
|
|
pkg!(("B", "1.0.1") => [dep_req("C", ">=1.0.1")]),
|
|
|
|
pkg!(("C", "1.0.0") => [dep_req("D", "1.0.0")]),
|
|
|
|
pkg!(("C", "1.0.1") => [dep_req("D", ">=1.0.1,<1.0.100")]),
|
|
|
|
pkg!(("C", "1.0.2") => [dep_req("D", ">=1.0.2,<1.0.100")]),
|
|
|
|
pkg!(("D", "1.0.0")),
|
|
|
|
pkg!(("D", "1.0.1")),
|
|
|
|
pkg!(("D", "1.0.2")),
|
|
|
|
pkg!(("D", "1.0.100")),
|
|
|
|
pkg!(("D", "1.0.101")),
|
|
|
|
pkg!(("D", "1.0.102")),
|
|
|
|
pkg!(("D", "1.0.103")),
|
|
|
|
pkg!(("D", "1.0.104")),
|
|
|
|
pkg!(("D", "1.0.105")),
|
|
|
|
]);
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep_req("A", "1")], ®).unwrap();
|
2018-02-03 21:49:42 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("A", "1.0.0"),
|
|
|
|
("B", "1.0.0"),
|
|
|
|
("C", "1.0.0"),
|
|
|
|
("D", "1.0.105"),
|
|
|
|
])),
|
|
|
|
);
|
2018-02-03 21:49:42 +00:00
|
|
|
}
|
|
|
|
|
2014-10-17 15:17:17 +00:00
|
|
|
#[test]
|
|
|
|
fn resolving_but_no_exists() {
|
2018-03-14 15:17:44 +00:00
|
|
|
let reg = registry(vec![]);
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(&pkg_id("root"), vec![dep_req("foo", "1")], ®);
|
2014-10-17 15:17:17 +00:00
|
|
|
assert!(res.is_err());
|
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
assert_eq!(
|
|
|
|
res.err().unwrap().to_string(),
|
|
|
|
"\
|
|
|
|
no matching package named `foo` found\n\
|
|
|
|
location searched: registry `http://example.com/`\n\
|
|
|
|
required by package `root v1.0.0 (registry `http://example.com/`)`\
|
|
|
|
"
|
|
|
|
);
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn resolving_cycle() {
|
2018-03-14 15:17:44 +00:00
|
|
|
let reg = registry(vec![pkg!("foo" => ["foo"])]);
|
2014-10-17 15:17:17 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let _ = resolve(&pkg_id("root"), vec![dep_req("foo", "1")], ®);
|
2014-10-17 15:17:17 +00:00
|
|
|
}
|
2015-07-13 19:14:05 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn hard_equality() {
|
2017-06-07 15:23:36 +00:00
|
|
|
let reg = registry(vec![
|
2015-07-13 19:14:05 +00:00
|
|
|
pkg!(("foo", "1.0.1")),
|
|
|
|
pkg!(("foo", "1.0.0")),
|
|
|
|
pkg!(("bar", "1.0.0") => [dep_req("foo", "1.0.0")]),
|
2015-11-23 16:56:10 +00:00
|
|
|
]);
|
2015-07-13 19:14:05 +00:00
|
|
|
|
2018-03-14 15:17:44 +00:00
|
|
|
let res = resolve(
|
|
|
|
&pkg_id("root"),
|
|
|
|
vec![dep_req("bar", "1"), dep_req("foo", "=1.0.0")],
|
|
|
|
®,
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
assert_that(
|
|
|
|
&res,
|
|
|
|
contains(names(&[
|
|
|
|
("root", "1.0.0"),
|
|
|
|
("foo", "1.0.0"),
|
|
|
|
("bar", "1.0.0"),
|
|
|
|
])),
|
|
|
|
);
|
2015-07-13 19:14:05 +00:00
|
|
|
}
|