blob: fd44e20e610bfd534d29c29e00d3f658aa5eb610 [file]
use super::Domain;
use anyhow;
use rand::distr::uniform::SampleUniform;
use rand::distr::uniform::UniformSampler;
/// Generates values of type `T` in a given range.
///
/// For example, `InRange::new(0, 100)` generates integer
/// values from the inclusive range `[0, 100]`.
///
/// Example usage:
/// ```
/// # use fuzztest::domains::Domain;
/// # use fuzztest::domains::range::InRange;
/// # use rand::prelude::*;
///
/// let range_i32 = InRange::new(21i32, 73);
/// let sample = range_i32.init(&mut rand::rng());
///
/// assert!(sample.is_ok());
/// let sample = sample.unwrap();
/// assert!(sample >= 21);
/// assert!(sample <= 73);
/// ```
pub struct InRange<T> {
lower: T,
upper: T,
}
impl InRange<i32> {
pub fn new(lower: i32, upper: i32) -> Self {
Self { lower, upper }
}
pub fn get_in_range(&self, rng: &mut dyn rand::Rng) -> i32 {
<i32 as SampleUniform>::Sampler::sample_single(self.lower, self.upper, rng)
.expect("Failed to sample from Uniform distribution")
}
}
impl Domain for InRange<i32> {
type UserValue<'user> = i32;
type CorpusValue = i32;
fn init(&self, rng: &mut dyn rand::Rng) -> anyhow::Result<Self::CorpusValue> {
Ok(self.get_in_range(rng))
}
fn mutate(
&self,
val: &mut Self::CorpusValue,
rng: &mut dyn rand::Rng,
only_shrink: bool,
) -> anyhow::Result<()> {
if only_shrink {
*val -= 1;
} else {
*val = self.get_in_range(rng);
}
Ok(())
}
fn get_user_value<'a>(
&self,
corpus_value: &'a Self::CorpusValue,
) -> anyhow::Result<Self::UserValue<'a>> {
Ok(*corpus_value)
}
}
#[cfg(test)]
mod tests {
use rand::SeedableRng;
use super::*;
#[test]
fn test_in_range() {
let in_range = InRange::<i32>::new(0, 100);
let mut rng = rand::rngs::StdRng::from_seed([73; 32]);
let in_range_val = in_range.get_in_range(&mut rng);
assert!(in_range_val >= 0 && in_range_val <= 100);
}
}