use proptest::prelude::*;

impl<T: Arbitrary + 'static> Arbitrary for crate::Bucket<T> {
	type Parameters = ();
	type Strategy = BoxedStrategy<Self>;

	fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
		(
			any::<T>(),
			any::<usize>())
			.prop_map(|(period, count)| {
				crate::Bucket::new(period, count)
			})
			.boxed()
	}
}

impl<T: Arbitrary + std::cmp::PartialOrd + 'static> Arbitrary for crate::Config<T> {
	type Parameters = ();
	type Strategy = BoxedStrategy<Self>;

	fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
		any::<Vec<crate::Bucket<T>>>()
			.prop_map(|buckets| {
				let mut config = crate::Config::empty();
				for b in buckets {
					config.add_bucket(b);
				}
				config
			})
			.boxed()
	}
}

proptest::proptest! {
	#[test]
	fn test(
		config: crate::Config<u32>,
		mut candidates: Vec<u32>
	) {
		candidates.sort();
		for evicted in crate::prune(&config, candidates.clone()) {
			let i = candidates.iter().take_while(|c| **c != evicted).count();
			candidates.remove(i);
		}
	}
}
