use crate::{
PackageId,
graph::{
PackageGraph, PackageLink, PackageQuery, PackageResolver, Workspace,
cargo::{CargoOptions, CargoResolverVersion, InitialsPlatform},
},
platform::PlatformSpec,
};
use fixedbitset::FixedBitSet;
use petgraph::{prelude::*, visit::VisitMap};
use proptest::{
collection::{hash_set, vec},
prelude::*,
};
impl PackageGraph {
pub fn proptest1_id_strategy(&self) -> impl Strategy<Value = &PackageId> {
let dep_graph = &self.dep_graph;
any::<prop::sample::Index>().prop_map(move |index| {
let package_ix = NodeIndex::new(index.index(dep_graph.node_count()));
&self.dep_graph[package_ix]
})
}
pub fn proptest1_link_strategy(&self) -> impl Strategy<Value = PackageLink<'_>> {
any::<prop::sample::Index>().prop_map(move |index| {
let edge_ix = EdgeIndex::new(index.index(self.link_count()));
self.edge_ix_to_link(edge_ix)
})
}
pub fn proptest1_resolver_strategy(&self) -> impl Strategy<Value = Prop010Resolver> + use<> {
fixedbitset_strategy(self.dep_graph.edge_count()).prop_map(Prop010Resolver::new)
}
pub fn proptest1_cargo_options_strategy(&self) -> impl Strategy<Value = CargoOptions<'_>> {
let omitted_packages = hash_set(self.proptest1_id_strategy(), 0..4);
(
any::<CargoResolverVersion>(),
any::<bool>(),
any::<InitialsPlatform>(),
any::<PlatformSpec>(),
any::<PlatformSpec>(),
omitted_packages,
)
.prop_map(
|(
version,
include_dev,
initials_platform,
host_platform,
target_platform,
omitted_packages,
)| {
let mut options = CargoOptions::new();
options
.set_resolver(version)
.set_include_dev(include_dev)
.set_initials_platform(initials_platform)
.set_host_platform(host_platform)
.set_target_platform(target_platform)
.add_omitted_packages(omitted_packages);
options
},
)
}
}
impl<'g> Workspace<'g> {
pub fn proptest1_name_strategy(&self) -> impl Strategy<Value = &'g str> + 'g + use<'g> {
let name_list = self.name_list();
(0..name_list.len()).prop_map(move |idx| name_list[idx].as_ref())
}
pub fn proptest1_id_strategy(&self) -> impl Strategy<Value = &'g PackageId> + 'g + use<'g> {
let members_by_name = &self.inner.members_by_name;
self.proptest1_name_strategy()
.prop_map(move |name| &members_by_name[name])
}
fn name_list(&self) -> &'g [Box<str>] {
self.inner
.name_list
.get_or_init(|| self.inner.members_by_name.keys().cloned().collect())
}
}
#[derive(Clone, Debug)]
pub struct Prop010Resolver {
included_edges: FixedBitSet,
check_depends_on: bool,
}
impl Prop010Resolver {
fn new(included_edges: FixedBitSet) -> Self {
Self {
included_edges,
check_depends_on: false,
}
}
pub fn check_depends_on(&mut self, check: bool) {
self.check_depends_on = check;
}
pub fn accept_link(&self, link: PackageLink<'_>) -> bool {
self.included_edges.is_visited(&link.edge_ix().index())
}
}
impl<'g> PackageResolver<'g> for Prop010Resolver {
fn accept(&mut self, query: &PackageQuery<'g>, link: PackageLink<'g>) -> bool {
if self.check_depends_on {
assert!(
query
.graph()
.depends_on(link.from().id(), link.to().id())
.expect("valid package IDs"),
"package '{}' should depend on '{}'",
link.from().id(),
link.to().id()
);
}
self.accept_link(link)
}
}
pub(super) fn fixedbitset_strategy(len: usize) -> impl Strategy<Value = FixedBitSet> {
vec(any::<bool>(), len).prop_map(|bits| {
bits.into_iter()
.enumerate()
.filter_map(|(idx, bit)| if bit { Some(idx) } else { None })
.collect()
})
}