mirror of
https://github.com/rust-lang/cargo
synced 2024-09-13 21:11:44 +00:00
a start on using proptest to fuzz the resolver
This commit is contained in:
parent
0ec7281b9c
commit
56a222cd30
|
@ -93,6 +93,7 @@ features = [
|
|||
|
||||
[dev-dependencies]
|
||||
bufstream = "0.1"
|
||||
proptest = "0.8.4"
|
||||
|
||||
[[bin]]
|
||||
name = "cargo"
|
||||
|
|
|
@ -11,6 +11,8 @@ extern crate glob;
|
|||
extern crate hex;
|
||||
extern crate libc;
|
||||
#[macro_use]
|
||||
extern crate proptest;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
#[macro_use]
|
||||
extern crate serde_json;
|
||||
|
|
|
@ -12,6 +12,12 @@ use support::ChannelChanger;
|
|||
use support::{execs, project};
|
||||
use support::registry::Package;
|
||||
|
||||
use proptest::collection::btree_map;
|
||||
use proptest::collection::vec;
|
||||
use proptest::prelude::*;
|
||||
use proptest::sample::subsequence;
|
||||
use std::iter;
|
||||
|
||||
fn resolve(
|
||||
pkg: &PackageId,
|
||||
deps: Vec<Dependency>,
|
||||
|
@ -185,6 +191,88 @@ fn loc_names(names: &[(&'static str, &'static str)]) -> Vec<PackageId> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// This generates a random registry index.
|
||||
/// Unlike vec((Name, Ver, vec((Name, VerRq), ..), ..)
|
||||
/// This strategy has a high probability of having valid dependencies
|
||||
fn registry_strategy() -> impl Strategy<Value = Vec<Summary>> {
|
||||
const VALID_NAME_STRATEGY: &str = "[A-Za-z_-][A-Za-z0-9_-]*";
|
||||
const MAX_CRATES: usize = 10;
|
||||
const MAX_VERSIONS: usize = 10;
|
||||
|
||||
fn range(max: usize) -> impl Strategy<Value = (usize, usize)> {
|
||||
(0..max).prop_flat_map(move |low| (Just(low), low..=max))
|
||||
}
|
||||
btree_map(VALID_NAME_STRATEGY, 1..=MAX_CRATES, 1..=MAX_VERSIONS)
|
||||
.prop_map(|mut b| {
|
||||
// root is the name of the thing being compiled
|
||||
// so it would be confusing to have it in the index
|
||||
b.remove("root");
|
||||
(
|
||||
b.iter().map(|(name, _)| name.clone()).collect::<Vec<_>>(),
|
||||
b.iter()
|
||||
.flat_map(|(name, &num)| {
|
||||
iter::repeat(name.clone())
|
||||
.take(num)
|
||||
.enumerate()
|
||||
.map(|(i, name)| (name, format!("{}.0.0", i + 1)))
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.prop_flat_map(|(names, data)| {
|
||||
let names_len = names.len();
|
||||
let data_len = data.len();
|
||||
(
|
||||
Just(data),
|
||||
vec(subsequence(names, 0..names_len), data_len..=data_len),
|
||||
)
|
||||
})
|
||||
.prop_flat_map(|(data, deps)| {
|
||||
let len = deps.iter().map(|x| x.len()).sum();
|
||||
(
|
||||
Just(data),
|
||||
Just(deps),
|
||||
vec(
|
||||
range(MAX_VERSIONS).prop_map(|(b, e)| format!(">={}.0.0, <={}.0.0", b, e)),
|
||||
len..=len,
|
||||
),
|
||||
)
|
||||
})
|
||||
.prop_map(|(data, deps, vers)| {
|
||||
let mut i = 0;
|
||||
data.into_iter()
|
||||
.zip(deps.into_iter())
|
||||
.map(|((name, ver), deps)| {
|
||||
let d: Vec<Dependency> = deps.into_iter()
|
||||
.filter(|n| &name < n)
|
||||
.map(|n| {
|
||||
i += 1;
|
||||
dep_req(&n, &vers[i - 1])
|
||||
})
|
||||
.collect();
|
||||
let pkgid = (name.as_str(), ver).to_pkgid();
|
||||
let link = if pkgid.name().ends_with("-sys") { Some(pkgid.name().as_str()) } else { None };
|
||||
|
||||
Summary::new(pkgid, d, &BTreeMap::<String, Vec<String>>::new(), link, false).unwrap()
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
proptest! {
|
||||
#[test]
|
||||
fn doesnt_crash(reg in registry_strategy()) {
|
||||
let this = reg.last().unwrap().name();
|
||||
let reg = registry(reg);
|
||||
|
||||
resolve(
|
||||
&pkg_id("root"),
|
||||
vec![dep(&this)],
|
||||
®,
|
||||
).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "assertion failed: !name.is_empty()")]
|
||||
fn test_dependency_with_empty_name() {
|
||||
|
|
Loading…
Reference in a new issue