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]
|
[dev-dependencies]
|
||||||
bufstream = "0.1"
|
bufstream = "0.1"
|
||||||
|
proptest = "0.8.4"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "cargo"
|
name = "cargo"
|
||||||
|
|
|
@ -11,6 +11,8 @@ extern crate glob;
|
||||||
extern crate hex;
|
extern crate hex;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
extern crate proptest;
|
||||||
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
|
@ -12,6 +12,12 @@ use support::ChannelChanger;
|
||||||
use support::{execs, project};
|
use support::{execs, project};
|
||||||
use support::registry::Package;
|
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(
|
fn resolve(
|
||||||
pkg: &PackageId,
|
pkg: &PackageId,
|
||||||
deps: Vec<Dependency>,
|
deps: Vec<Dependency>,
|
||||||
|
@ -185,6 +191,88 @@ fn loc_names(names: &[(&'static str, &'static str)]) -> Vec<PackageId> {
|
||||||
.collect()
|
.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]
|
#[test]
|
||||||
#[should_panic(expected = "assertion failed: !name.is_empty()")]
|
#[should_panic(expected = "assertion failed: !name.is_empty()")]
|
||||||
fn test_dependency_with_empty_name() {
|
fn test_dependency_with_empty_name() {
|
||||||
|
|
Loading…
Reference in a new issue