use std::fmt;
use std::marker::PhantomData;
use std::mem;
use bit_set::BitSet;
use rand::Rng;
use strategy::*;
use test_runner::*;
pub trait BitSetLike : Clone + fmt::Debug {
fn new_bitset(max: usize) -> Self;
fn max(&self) -> usize;
fn test(&self, ix: usize) -> bool;
fn set(&mut self, ix: usize);
fn clear(&mut self, ix: usize);
}
macro_rules! int_bitset {
($typ:ty) => {
impl BitSetLike for $typ {
fn new_bitset(_: usize) -> Self { 0 }
fn max(&self) -> usize { mem::size_of::<$typ>()*8 }
fn test(&self, ix: usize) -> bool {
0 != (*self & ((1 as $typ) << ix))
}
fn set(&mut self, ix: usize) {
*self |= (1 as $typ) << ix;
}
fn clear(&mut self, ix: usize) {
*self &= !((1 as $typ) << ix);
}
}
}
}
int_bitset!(u8);
int_bitset!(u16);
int_bitset!(u32);
int_bitset!(u64);
int_bitset!(usize);
int_bitset!(i8);
int_bitset!(i16);
int_bitset!(i32);
int_bitset!(i64);
int_bitset!(isize);
impl BitSetLike for BitSet {
fn new_bitset(max: usize) -> Self {
BitSet::with_capacity(max)
}
fn max(&self) -> usize {
self.capacity()
}
fn test(&self, bit: usize) -> bool {
self.contains(bit)
}
fn set(&mut self, bit: usize) {
self.insert(bit);
}
fn clear(&mut self, bit: usize) {
self.remove(bit);
}
}
pub struct BitSetStrategy<T : BitSetLike> {
min: usize,
max: usize,
_marker: PhantomData<T>,
}
impl<T : BitSetLike> Clone for BitSetStrategy<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T : BitSetLike> Copy for BitSetStrategy<T> { }
impl<T : BitSetLike> fmt::Debug for BitSetStrategy<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BitSetStrategy")
.field("min", &self.min)
.field("max", &self.max)
.finish()
}
}
impl<T : BitSetLike> BitSetStrategy<T> {
pub fn new(min: usize, max: usize) -> Self {
BitSetStrategy {
min, max, _marker: PhantomData
}
}
}
impl<T : BitSetLike> Strategy for BitSetStrategy<T> {
type Value = BitSetValueTree<T>;
fn new_value(&self, runner: &mut TestRunner)
-> Result<Self::Value, String> {
let mut inner = T::new_bitset(self.max);
for bit in self.min..self.max {
if runner.rng().gen() {
inner.set(bit);
}
}
Ok(BitSetValueTree { inner, shrink: self.min, prev_shrink: None })
}
}
#[derive(Clone, Copy, Debug)]
pub struct BitSetValueTree<T : BitSetLike> {
inner: T,
shrink: usize,
prev_shrink: Option<usize>,
}
impl<T : BitSetLike> ValueTree for BitSetValueTree<T> {
type Value = T;
fn current(&self) -> T {
self.inner.clone()
}
fn simplify(&mut self) -> bool {
while self.shrink < self.inner.max() &&
!self.inner.test(self.shrink)
{ self.shrink += 1; }
if self.shrink >= self.inner.max() {
self.prev_shrink = None;
false
} else {
self.prev_shrink = Some(self.shrink);
self.inner.clear(self.shrink);
self.shrink += 1;
true
}
}
fn complicate(&mut self) -> bool {
if let Some(bit) = self.prev_shrink.take() {
self.inner.set(bit);
true
} else {
false
}
}
}
macro_rules! int_api {
($typ:ident, $max:expr) => {
#[allow(missing_docs)]
pub mod $typ {
use super::*;
pub const ANY: BitSetStrategy<$typ> = BitSetStrategy {
min: 0,
max: $max,
_marker: PhantomData
};
pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> {
BitSetStrategy::new(min, max)
}
}
}
}
int_api!(u8, 8);
int_api!(u16, 16);
int_api!(u32, 32);
int_api!(u64, 64);
int_api!(i8, 8);
int_api!(i16, 16);
int_api!(i32, 32);
int_api!(i64, 64);
macro_rules! minimal_api {
($md:ident, $typ:ty) => {
#[allow(missing_docs)]
pub mod $md {
use super::*;
pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> {
BitSetStrategy::new(min, max)
}
}
}
}
minimal_api!(usize, usize);
minimal_api!(isize, isize);
minimal_api!(bitset, BitSet);
#[cfg(test)]
mod test {
use super::*;
#[test]
fn generates_values_in_range() {
let input = u32::between(4, 8);
let mut runner = TestRunner::new(Config::default());
for _ in 0..256 {
let value = input.new_value(&mut runner).unwrap().current();
assert!(0 == value & !0xF0u32,
"Generate value {}", value);
}
}
#[test]
fn shrinks_to_zero() {
let input = u32::between(4, 24);
let mut runner = TestRunner::new(Config::default());
for _ in 0..256 {
let mut value = input.new_value(&mut runner).unwrap();
let mut prev = value.current();
while value.simplify() {
let v = value.current();
assert!(1 == (prev & !v).count_ones(),
"Shrank from {} to {}", prev, v);
prev = v;
}
assert_eq!(0, value.current());
}
}
#[test]
fn complicates_to_previous() {
let input = u32::between(4, 24);
let mut runner = TestRunner::new(Config::default());
for _ in 0..256 {
let mut value = input.new_value(&mut runner).unwrap();
let orig = value.current();
if value.simplify() {
assert!(value.complicate());
assert_eq!(orig, value.current());
}
}
}
}