Skip to content

Commit 37cb9bb

Browse files
committed
Auto merge of #7045 - Eh2406:resolver-test/debug-cleanup, r=alexcrichton
Resolver test/debug cleanup This is several small things salvaged from abandoned PRs and implemented on top of #7011 In working on this I noted that the prop tests are very sensitive to whether backtrace are turned on. Maybe we should set that env to 0 for that builder?
2 parents eebd1da + cb95f5e commit 37cb9bb

File tree

7 files changed

+233
-225
lines changed

7 files changed

+233
-225
lines changed

crates/resolver-tests/src/lib.rs

+121-75
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
use std::cell::RefCell;
12
use std::cmp::PartialEq;
23
use std::cmp::{max, min};
34
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
45
use std::fmt;
6+
use std::fmt::Write;
7+
use std::rc::Rc;
58
use std::time::Instant;
69

710
use cargo::core::dependency::Kind;
@@ -17,92 +20,99 @@ use proptest::sample::Index;
1720
use proptest::string::string_regex;
1821
use varisat::{self, ExtendFormula};
1922

20-
pub fn resolve(
21-
pkg: PackageId,
22-
deps: Vec<Dependency>,
23-
registry: &[Summary],
24-
) -> CargoResult<Vec<PackageId>> {
25-
resolve_with_config(pkg, deps, registry, None)
23+
pub fn resolve(deps: Vec<Dependency>, registry: &[Summary]) -> CargoResult<Vec<PackageId>> {
24+
resolve_with_config(deps, registry, None)
2625
}
2726

2827
pub fn resolve_and_validated(
29-
pkg: PackageId,
3028
deps: Vec<Dependency>,
3129
registry: &[Summary],
32-
sat_resolve: Option<&mut SatResolve>,
30+
sat_resolve: Option<SatResolve>,
3331
) -> CargoResult<Vec<PackageId>> {
34-
let should_resolve = if let Some(sat) = sat_resolve {
35-
sat.sat_resolve(&deps)
36-
} else {
37-
SatResolve::new(registry).sat_resolve(&deps)
38-
};
39-
let resolve = resolve_with_config_raw(pkg, deps, registry, None);
40-
assert_eq!(resolve.is_ok(), should_resolve);
41-
42-
let resolve = resolve?;
43-
let mut stack = vec![pkg];
44-
let mut used = HashSet::new();
45-
let mut links = HashSet::new();
46-
while let Some(p) = stack.pop() {
47-
assert!(resolve.contains(&p));
48-
if used.insert(p) {
49-
// in the tests all `links` crates end in `-sys`
50-
if p.name().ends_with("-sys") {
51-
assert!(links.insert(p.name()));
32+
let resolve = resolve_with_config_raw(deps.clone(), registry, None);
33+
34+
match resolve {
35+
Err(e) => {
36+
let sat_resolve = sat_resolve.unwrap_or_else(|| SatResolve::new(registry));
37+
if sat_resolve.sat_resolve(&deps) {
38+
panic!(
39+
"the resolve err but the sat_resolve thinks this will work:\n{}",
40+
sat_resolve.use_packages().unwrap()
41+
);
5242
}
53-
stack.extend(resolve.deps(p).map(|(dp, deps)| {
54-
for d in deps {
55-
assert!(d.matches_id(dp));
56-
}
57-
dp
58-
}));
43+
Err(e)
5944
}
60-
}
61-
let out = resolve.sort();
62-
assert_eq!(out.len(), used.len());
63-
64-
let mut pub_deps: HashMap<PackageId, HashSet<_>> = HashMap::new();
65-
for &p in out.iter() {
66-
// make the list of `p` public dependencies
67-
let mut self_pub_dep = HashSet::new();
68-
self_pub_dep.insert(p);
69-
for (dp, deps) in resolve.deps(p) {
70-
if deps.iter().any(|d| d.is_public()) {
71-
self_pub_dep.extend(pub_deps[&dp].iter().cloned())
45+
Ok(resolve) => {
46+
let mut stack = vec![pkg_id("root")];
47+
let mut used = HashSet::new();
48+
let mut links = HashSet::new();
49+
while let Some(p) = stack.pop() {
50+
assert!(resolve.contains(&p));
51+
if used.insert(p) {
52+
// in the tests all `links` crates end in `-sys`
53+
if p.name().ends_with("-sys") {
54+
assert!(links.insert(p.name()));
55+
}
56+
stack.extend(resolve.deps(p).map(|(dp, deps)| {
57+
for d in deps {
58+
assert!(d.matches_id(dp));
59+
}
60+
dp
61+
}));
62+
}
7263
}
73-
}
74-
pub_deps.insert(p, self_pub_dep);
64+
let out = resolve.sort();
65+
assert_eq!(out.len(), used.len());
66+
67+
let mut pub_deps: HashMap<PackageId, HashSet<_>> = HashMap::new();
68+
for &p in out.iter() {
69+
// make the list of `p` public dependencies
70+
let mut self_pub_dep = HashSet::new();
71+
self_pub_dep.insert(p);
72+
for (dp, deps) in resolve.deps(p) {
73+
if deps.iter().any(|d| d.is_public()) {
74+
self_pub_dep.extend(pub_deps[&dp].iter().cloned())
75+
}
76+
}
77+
pub_deps.insert(p, self_pub_dep);
7578

76-
// check if `p` has a public dependencies conflicts
77-
let seen_dep: BTreeSet<_> = resolve
78-
.deps(p)
79-
.flat_map(|(dp, _)| pub_deps[&dp].iter().cloned())
80-
.collect();
81-
let seen_dep: Vec<_> = seen_dep.iter().collect();
82-
for a in seen_dep.windows(2) {
83-
if a[0].name() == a[1].name() {
79+
// check if `p` has a public dependencies conflicts
80+
let seen_dep: BTreeSet<_> = resolve
81+
.deps(p)
82+
.flat_map(|(dp, _)| pub_deps[&dp].iter().cloned())
83+
.collect();
84+
let seen_dep: Vec<_> = seen_dep.iter().collect();
85+
for a in seen_dep.windows(2) {
86+
if a[0].name() == a[1].name() {
87+
panic!(
88+
"the package {:?} can publicly see {:?} and {:?}",
89+
p, a[0], a[1]
90+
)
91+
}
92+
}
93+
}
94+
let sat_resolve = sat_resolve.unwrap_or_else(|| SatResolve::new(registry));
95+
if !sat_resolve.sat_is_valid_solution(&out) {
8496
panic!(
85-
"the package {:?} can publicly see {:?} and {:?}",
86-
p, a[0], a[1]
87-
)
97+
"the sat_resolve err but the resolve thinks this will work:\n{:?}",
98+
resolve
99+
);
88100
}
101+
Ok(out)
89102
}
90103
}
91-
Ok(out)
92104
}
93105

94106
pub fn resolve_with_config(
95-
pkg: PackageId,
96107
deps: Vec<Dependency>,
97108
registry: &[Summary],
98109
config: Option<&Config>,
99110
) -> CargoResult<Vec<PackageId>> {
100-
let resolve = resolve_with_config_raw(pkg, deps, registry, config)?;
111+
let resolve = resolve_with_config_raw(deps, registry, config)?;
101112
Ok(resolve.sort())
102113
}
103114

104115
pub fn resolve_with_config_raw(
105-
pkg: PackageId,
106116
deps: Vec<Dependency>,
107117
registry: &[Summary],
108118
config: Option<&Config>,
@@ -158,7 +168,7 @@ pub fn resolve_with_config_raw(
158168
used: HashSet::new(),
159169
};
160170
let summary = Summary::new(
161-
pkg,
171+
pkg_id("root"),
162172
deps,
163173
&BTreeMap::<String, Vec<String>>::new(),
164174
None::<String>,
@@ -241,7 +251,9 @@ fn sat_at_most_one_by_key<K: std::hash::Hash + Eq>(
241251
///
242252
/// The SAT library dose not optimize for the newer version,
243253
/// so the selected packages may not match the real resolver.
244-
pub struct SatResolve {
254+
#[derive(Clone)]
255+
pub struct SatResolve(Rc<RefCell<SatResolveInner>>);
256+
struct SatResolveInner {
245257
solver: varisat::Solver<'static>,
246258
var_for_is_packages_used: HashMap<PackageId, varisat::Var>,
247259
by_name: HashMap<&'static str, Vec<PackageId>>,
@@ -404,50 +416,86 @@ impl SatResolve {
404416
solver
405417
.solve()
406418
.expect("docs say it can't error in default config");
407-
408-
SatResolve {
419+
SatResolve(Rc::new(RefCell::new(SatResolveInner {
409420
solver,
410421
var_for_is_packages_used,
411422
by_name,
412-
}
423+
})))
413424
}
414-
pub fn sat_resolve(&mut self, deps: &[Dependency]) -> bool {
425+
pub fn sat_resolve(&self, deps: &[Dependency]) -> bool {
426+
let mut s = self.0.borrow_mut();
415427
let mut assumption = vec![];
416428
let mut this_call = None;
417429

418430
// the starting `deps` need to be satisfied
419431
for dep in deps.iter() {
420432
let empty_vec = vec![];
421-
let matches: Vec<varisat::Lit> = self
433+
let matches: Vec<varisat::Lit> = s
422434
.by_name
423435
.get(dep.package_name().as_str())
424436
.unwrap_or(&empty_vec)
425437
.iter()
426438
.filter(|&p| dep.matches_id(*p))
427-
.map(|p| self.var_for_is_packages_used[p].positive())
439+
.map(|p| s.var_for_is_packages_used[p].positive())
428440
.collect();
429441
if matches.is_empty() {
430442
return false;
431443
} else if matches.len() == 1 {
432444
assumption.extend_from_slice(&matches)
433445
} else {
434446
if this_call.is_none() {
435-
let new_var = self.solver.new_var();
447+
let new_var = s.solver.new_var();
436448
this_call = Some(new_var);
437449
assumption.push(new_var.positive());
438450
}
439451
let mut matches = matches;
440452
matches.push(this_call.unwrap().negative());
441-
self.solver.add_clause(&matches);
453+
s.solver.add_clause(&matches);
454+
}
455+
}
456+
457+
s.solver.assume(&assumption);
458+
459+
s.solver
460+
.solve()
461+
.expect("docs say it can't error in default config")
462+
}
463+
pub fn sat_is_valid_solution(&self, pids: &[PackageId]) -> bool {
464+
let mut s = self.0.borrow_mut();
465+
for p in pids {
466+
if p.name().as_str() != "root" && !s.var_for_is_packages_used.contains_key(p) {
467+
return false;
442468
}
443469
}
470+
let assumption: Vec<_> = s
471+
.var_for_is_packages_used
472+
.iter()
473+
.map(|(p, v)| v.lit(pids.contains(p)))
474+
.collect();
444475

445-
self.solver.assume(&assumption);
476+
s.solver.assume(&assumption);
446477

447-
self.solver
478+
s.solver
448479
.solve()
449480
.expect("docs say it can't error in default config")
450481
}
482+
fn use_packages(&self) -> Option<String> {
483+
self.0.borrow().solver.model().map(|lits| {
484+
let lits: HashSet<_> = lits
485+
.iter()
486+
.filter(|l| l.is_positive())
487+
.map(|l| l.var())
488+
.collect();
489+
let mut out = String::new();
490+
out.push_str("used:\n");
491+
for (p, v) in self.0.borrow().var_for_is_packages_used.iter() {
492+
if lits.contains(v) {
493+
writeln!(&mut out, " {}", p).unwrap();
494+
}
495+
}
496+
out
497+
})
498+
}
451499
}
452500

453501
pub trait ToDep {
@@ -856,7 +904,6 @@ fn meta_test_deep_trees_from_strategy() {
856904
let reg = registry(input.clone());
857905
for this in input.iter().rev().take(10) {
858906
let res = resolve(
859-
pkg_id("root"),
860907
vec![dep_req(&this.name(), &format!("={}", this.version()))],
861908
&reg,
862909
);
@@ -898,7 +945,6 @@ fn meta_test_multiple_versions_strategy() {
898945
let reg = registry(input.clone());
899946
for this in input.iter().rev().take(10) {
900947
let res = resolve(
901-
pkg_id("root"),
902948
vec![dep_req(&this.name(), &format!("={}", this.version()))],
903949
&reg,
904950
);

0 commit comments

Comments
 (0)