Skip to content

Commit aea3404

Browse files
committed
Auto merge of #14614 - x-hgg-x:more-sat-resolver-tests, r=Eh2406
Add more SAT resolver tests ### What does this PR try to resolve? This is a follow-up of #14583. ### How should we test and review this PR? * Commit 1 splits tests into smaller modules. * Commit 2 adds more helper trait methods. * Commit 3 refactors computation of the SAT clauses, by introducing intermediate boolean variables for each dependency and each dependency feature declared in a package. The old behavior was incorrect: package features specified in an optional dependency were activated if the package was activated, even if the dependency wasn't activated. * Commit 4 add tests from https://github.com/Eh2406/pubgrub-crates-benchmark/tree/main/out/index_ron. r? Eh2406
2 parents fbcd9bb + dedf251 commit aea3404

File tree

9 files changed

+2242
-1220
lines changed

9 files changed

+2242
-1220
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/resolver-tests/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ publish = false
66

77
[dependencies]
88
cargo.workspace = true
9+
cargo-platform.workspace = true
910
cargo-util-schemas.workspace = true
1011
cargo-util.workspace = true
1112
proptest.workspace = true

crates/resolver-tests/src/helpers.rs

+260
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
use std::collections::BTreeMap;
2+
use std::fmt::Debug;
3+
use std::sync::OnceLock;
4+
5+
use cargo::core::dependency::DepKind;
6+
use cargo::core::{Dependency, GitReference, PackageId, SourceId, Summary};
7+
use cargo::util::IntoUrl;
8+
9+
pub trait ToDep {
10+
fn to_dep(self) -> Dependency;
11+
fn opt(self) -> Dependency;
12+
fn with(self, features: &[&'static str]) -> Dependency;
13+
fn with_default(self) -> Dependency;
14+
fn rename(self, name: &str) -> Dependency;
15+
}
16+
17+
impl ToDep for &'static str {
18+
fn to_dep(self) -> Dependency {
19+
Dependency::parse(self, Some("1.0.0"), registry_loc()).unwrap()
20+
}
21+
fn opt(self) -> Dependency {
22+
let mut dep = self.to_dep();
23+
dep.set_optional(true);
24+
dep
25+
}
26+
fn with(self, features: &[&'static str]) -> Dependency {
27+
let mut dep = self.to_dep();
28+
dep.set_default_features(false);
29+
dep.set_features(features.into_iter().copied());
30+
dep
31+
}
32+
fn with_default(self) -> Dependency {
33+
let mut dep = self.to_dep();
34+
dep.set_default_features(true);
35+
dep
36+
}
37+
fn rename(self, name: &str) -> Dependency {
38+
let mut dep = self.to_dep();
39+
dep.set_explicit_name_in_toml(name);
40+
dep
41+
}
42+
}
43+
44+
impl ToDep for Dependency {
45+
fn to_dep(self) -> Dependency {
46+
self
47+
}
48+
fn opt(mut self) -> Dependency {
49+
self.set_optional(true);
50+
self
51+
}
52+
fn with(mut self, features: &[&'static str]) -> Dependency {
53+
self.set_default_features(false);
54+
self.set_features(features.into_iter().copied());
55+
self
56+
}
57+
fn with_default(mut self) -> Dependency {
58+
self.set_default_features(true);
59+
self
60+
}
61+
fn rename(mut self, name: &str) -> Dependency {
62+
self.set_explicit_name_in_toml(name);
63+
self
64+
}
65+
}
66+
67+
pub trait ToPkgId {
68+
fn to_pkgid(&self) -> PackageId;
69+
}
70+
71+
impl ToPkgId for PackageId {
72+
fn to_pkgid(&self) -> PackageId {
73+
*self
74+
}
75+
}
76+
77+
impl<'a> ToPkgId for &'a str {
78+
fn to_pkgid(&self) -> PackageId {
79+
PackageId::try_new(*self, "1.0.0", registry_loc()).unwrap()
80+
}
81+
}
82+
83+
impl<T: AsRef<str>, U: AsRef<str>> ToPkgId for (T, U) {
84+
fn to_pkgid(&self) -> PackageId {
85+
let (name, vers) = self;
86+
PackageId::try_new(name.as_ref(), vers.as_ref(), registry_loc()).unwrap()
87+
}
88+
}
89+
90+
#[macro_export]
91+
macro_rules! pkg {
92+
($pkgid:expr => [$($deps:expr),* $(,)? ]) => ({
93+
use $crate::helpers::ToDep;
94+
let d: Vec<Dependency> = vec![$($deps.to_dep()),*];
95+
$crate::helpers::pkg_dep($pkgid, d)
96+
});
97+
98+
($pkgid:expr) => ({
99+
$crate::helpers::pkg($pkgid)
100+
})
101+
}
102+
103+
fn registry_loc() -> SourceId {
104+
static EXAMPLE_DOT_COM: OnceLock<SourceId> = OnceLock::new();
105+
let example_dot = EXAMPLE_DOT_COM.get_or_init(|| {
106+
SourceId::for_registry(&"https://example.com".into_url().unwrap()).unwrap()
107+
});
108+
*example_dot
109+
}
110+
111+
pub fn pkg<T: ToPkgId>(name: T) -> Summary {
112+
pkg_dep(name, Vec::new())
113+
}
114+
115+
pub fn pkg_dep<T: ToPkgId>(name: T, dep: Vec<Dependency>) -> Summary {
116+
let pkgid = name.to_pkgid();
117+
let link = if pkgid.name().ends_with("-sys") {
118+
Some(pkgid.name())
119+
} else {
120+
None
121+
};
122+
Summary::new(name.to_pkgid(), dep, &BTreeMap::new(), link, None).unwrap()
123+
}
124+
125+
pub fn pkg_dep_with<T: ToPkgId>(
126+
name: T,
127+
dep: Vec<Dependency>,
128+
features: &[(&'static str, &[&'static str])],
129+
) -> Summary {
130+
let pkgid = name.to_pkgid();
131+
let link = if pkgid.name().ends_with("-sys") {
132+
Some(pkgid.name())
133+
} else {
134+
None
135+
};
136+
let features = features
137+
.into_iter()
138+
.map(|&(name, values)| (name.into(), values.into_iter().map(|&v| v.into()).collect()))
139+
.collect();
140+
Summary::new(name.to_pkgid(), dep, &features, link, None).unwrap()
141+
}
142+
143+
pub fn pkg_dep_link<T: ToPkgId>(name: T, link: &str, dep: Vec<Dependency>) -> Summary {
144+
Summary::new(name.to_pkgid(), dep, &BTreeMap::new(), Some(link), None).unwrap()
145+
}
146+
147+
pub fn pkg_id(name: &str) -> PackageId {
148+
PackageId::try_new(name, "1.0.0", registry_loc()).unwrap()
149+
}
150+
151+
pub fn pkg_id_source(name: &str, source: &str) -> PackageId {
152+
PackageId::try_new(
153+
name,
154+
"1.0.0",
155+
SourceId::for_registry(&source.into_url().unwrap()).unwrap(),
156+
)
157+
.unwrap()
158+
}
159+
160+
fn pkg_id_loc(name: &str, loc: &str) -> PackageId {
161+
let remote = loc.into_url();
162+
let master = GitReference::Branch("master".to_string());
163+
let source_id = SourceId::for_git(&remote.unwrap(), master).unwrap();
164+
165+
PackageId::try_new(name, "1.0.0", source_id).unwrap()
166+
}
167+
168+
pub fn pkg_loc(name: &str, loc: &str) -> Summary {
169+
let link = if name.ends_with("-sys") {
170+
Some(name)
171+
} else {
172+
None
173+
};
174+
Summary::new(
175+
pkg_id_loc(name, loc),
176+
Vec::new(),
177+
&BTreeMap::new(),
178+
link,
179+
None,
180+
)
181+
.unwrap()
182+
}
183+
184+
pub fn remove_dep(sum: &Summary, ind: usize) -> Summary {
185+
let mut deps = sum.dependencies().to_vec();
186+
deps.remove(ind);
187+
// note: more things will need to be copied over in the future, but it works for now.
188+
Summary::new(sum.package_id(), deps, &BTreeMap::new(), sum.links(), None).unwrap()
189+
}
190+
191+
pub fn dep(name: &str) -> Dependency {
192+
dep_req(name, "*")
193+
}
194+
195+
pub fn dep_req(name: &str, req: &str) -> Dependency {
196+
Dependency::parse(name, Some(req), registry_loc()).unwrap()
197+
}
198+
199+
pub fn dep_req_kind(name: &str, req: &str, kind: DepKind) -> Dependency {
200+
let mut dep = dep_req(name, req);
201+
dep.set_kind(kind);
202+
dep
203+
}
204+
205+
pub fn dep_req_platform(name: &str, req: &str, platform: &str) -> Dependency {
206+
let mut dep = dep_req(name, req);
207+
dep.set_platform(Some(platform.parse().unwrap()));
208+
dep
209+
}
210+
211+
pub fn dep_loc(name: &str, location: &str) -> Dependency {
212+
let url = location.into_url().unwrap();
213+
let master = GitReference::Branch("master".to_string());
214+
let source_id = SourceId::for_git(&url, master).unwrap();
215+
Dependency::parse(name, Some("1.0.0"), source_id).unwrap()
216+
}
217+
218+
pub fn dep_kind(name: &str, kind: DepKind) -> Dependency {
219+
let mut dep = dep(name);
220+
dep.set_kind(kind);
221+
dep
222+
}
223+
224+
pub fn dep_platform(name: &str, platform: &str) -> Dependency {
225+
let mut dep = dep(name);
226+
dep.set_platform(Some(platform.parse().unwrap()));
227+
dep
228+
}
229+
230+
pub fn registry(pkgs: Vec<Summary>) -> Vec<Summary> {
231+
pkgs
232+
}
233+
234+
pub fn names<P: ToPkgId>(names: &[P]) -> Vec<PackageId> {
235+
names.iter().map(|name| name.to_pkgid()).collect()
236+
}
237+
238+
pub fn loc_names(names: &[(&'static str, &'static str)]) -> Vec<PackageId> {
239+
names
240+
.iter()
241+
.map(|&(name, loc)| pkg_id_loc(name, loc))
242+
.collect()
243+
}
244+
245+
/// Assert `xs` contains `elems`
246+
#[track_caller]
247+
pub fn assert_contains<A: PartialEq + Debug>(xs: &[A], elems: &[A]) {
248+
for elem in elems {
249+
assert!(
250+
xs.contains(elem),
251+
"missing element\nset: {xs:?}\nmissing: {elem:?}"
252+
);
253+
}
254+
}
255+
256+
#[track_caller]
257+
pub fn assert_same<A: PartialEq + Debug>(a: &[A], b: &[A]) {
258+
assert_eq!(a.len(), b.len(), "not equal\n{a:?}\n{b:?}");
259+
assert_contains(b, a);
260+
}

0 commit comments

Comments
 (0)