use std::borrow::Cow;
use std::fmt;
use std::ops::Range;
use std::sync::Arc;
use bit_set::BitSet;
use bits::{self, BitSetValueTree, SampledBitSetStrategy};
use num;
use strategy::*;
use test_runner::*;
pub use collection::{SizeRange, size_range};
pub fn subsequence<T, A, S>(values: A, size: S) -> Subsequence<T>
where
A : 'static + Into<Cow<'static, [T]>>,
T : Clone + 'static,
S : Into<SizeRange>
{
let values = values.into();
let len = values.len();
let size: Range<usize> = size.into().into();
assert!(size.start != size.end, "Zero-length range passed to subsequence");
assert!(size.end <= len + 1,
"Maximum size of subsequence {} exceeds length of input {}",
size.end, len);
Subsequence {
values: Arc::new(values),
bit_strategy: bits::bitset::sampled(size, 0..len),
}
}
#[derive(Debug, Clone)]
pub struct Subsequence<T : Clone + 'static> {
values: Arc<Cow<'static, [T]>>,
bit_strategy: SampledBitSetStrategy<BitSet>,
}
impl<T : fmt::Debug + Clone + 'static> Strategy for Subsequence<T> {
type Value = SubsequenceValueTree<T>;
fn new_value(&self, runner: &mut TestRunner) -> NewTree<Self> {
Ok(SubsequenceValueTree {
values: Arc::clone(&self.values),
inner: self.bit_strategy.new_value(runner)?,
})
}
}
#[derive(Debug, Clone)]
pub struct SubsequenceValueTree<T : Clone + 'static> {
values: Arc<Cow<'static, [T]>>,
inner: BitSetValueTree<BitSet>,
}
impl<T : fmt::Debug + Clone + 'static> ValueTree for SubsequenceValueTree<T> {
type Value = Vec<T>;
fn current(&self) -> Self::Value {
self.inner.current().into_iter().map(
|ix| self.values[ix].clone()).collect()
}
fn simplify(&mut self) -> bool {
self.inner.simplify()
}
fn complicate(&mut self) -> bool {
self.inner.complicate()
}
}
#[derive(Debug, Clone)]
struct SelectMapFn<T : Clone + 'static>(Arc<Cow<'static, [T]>>);
impl<T : fmt::Debug + Clone + 'static> statics::MapFn<usize>
for SelectMapFn<T> {
type Output = T;
fn apply(&self, ix: usize) -> T {
self.0[ix].clone()
}
}
opaque_strategy_wrapper! {
#[derive(Clone, Debug)]
pub struct Select[<T>][where T : Clone + fmt::Debug + 'static](
statics::Map<Range<usize>, SelectMapFn<T>>)
-> SelectValueTree<T>;
#[derive(Clone, Debug)]
pub struct SelectValueTree[<T>][where T : Clone + fmt::Debug + 'static](
statics::Map<num::usize::BinarySearch, SelectMapFn<T>>)
-> T;
}
pub fn select<T, A>(values: A) -> Select<T>
where A : 'static + Into<Cow<'static, [T]>>, T : Clone + fmt::Debug + 'static {
let cow = values.into();
Select(statics::Map::new(
0..cow.len(), SelectMapFn(Arc::new(cow))))
}
#[cfg(test)]
mod test {
use std::collections::HashSet;
use super::*;
#[test]
fn sample_slice() {
static VALUES: &[usize] = &[0, 1, 2, 3, 4, 5, 6, 7];
let mut size_counts = [0; 8];
let mut value_counts = [0; 8];
let mut runner = TestRunner::default();
let input = subsequence(VALUES, 3..7);
for _ in 0..2048 {
let value = input.new_value(&mut runner).unwrap().current();
assert!(value.len() >= 3 && value.len() < 7);
assert_eq!(value.len(),
value.iter().cloned().collect::<HashSet<_>>().len());
let mut sorted = value.clone();
sorted.sort();
assert_eq!(sorted, value);
size_counts[value.len()] += 1;
for value in value {
value_counts[value] += 1;
}
}
for i in 3..7 {
assert!(size_counts[i] >= 256 && size_counts[i] < 1024,
"size {} was chosen {} times", i, size_counts[i]);
}
for (ix, &v) in value_counts.iter().enumerate() {
assert!(v >= 1024 && v < 1500,
"Value {} was chosen {} times", ix, v);
}
}
#[test]
fn sample_vec() {
let values = vec![0, 1, 2, 3, 4];
let mut runner = TestRunner::default();
let input = subsequence(values, 1..3);
let _ = input.new_value(&mut runner).unwrap().current();
}
#[test]
fn test_select() {
let values = vec![0, 1, 2, 3, 4, 5, 6, 7];
let mut counts = [0; 8];
let mut runner = TestRunner::default();
let input = select(values);
for _ in 0..1024 {
counts[input.new_value(&mut runner).unwrap().current()] += 1;
}
for (ix, &count) in counts.iter().enumerate() {
assert!(count >= 64 && count < 256,
"Generated value {} {} times", ix, count);
}
}
#[test]
fn test_sample_sanity() {
check_strategy_sanity(subsequence(vec![0, 1, 2, 3, 4], 1..3), None);
}
#[test]
fn test_select_sanity() {
check_strategy_sanity(select(vec![0, 1, 2, 3, 4]), None);
}
}