usecrate::{Arbitrary, Error, Result}; use std::marker::PhantomData; use std::ops::ControlFlow; use std::{mem, ops};
/// A source of unstructured data. /// /// An `Unstructured` helps `Arbitrary` implementations interpret raw data /// (typically provided by a fuzzer) as a "DNA string" that describes how to /// construct the `Arbitrary` type. The goal is that a small change to the "DNA /// string" (the raw data wrapped by an `Unstructured`) results in a small /// change to the generated `Arbitrary` instance. This helps a fuzzer /// efficiently explore the `Arbitrary`'s input space. /// /// `Unstructured` is deterministic: given the same raw data, the same series of /// API calls will return the same results (modulo system resource constraints, /// like running out of memory). However, `Unstructured` does not guarantee /// anything beyond that: it makes not guarantee that it will yield bytes from /// the underlying data in any particular order. /// /// You shouldn't generally need to use an `Unstructured` unless you are writing /// a custom `Arbitrary` implementation by hand, instead of deriving it. Mostly, /// you should just be passing it through to nested `Arbitrary::arbitrary` /// calls. /// /// # Example /// /// Imagine you were writing a color conversion crate. You might want to write /// fuzz tests that take a random RGB color and assert various properties, run /// functions and make sure nothing panics, etc. /// /// Below is what translating the fuzzer's raw input into an `Unstructured` and /// using that to generate an arbitrary RGB color might look like: /// /// ``` /// # #[cfg(feature = "derive")] fn foo() { /// use arbitrary::{Arbitrary, Unstructured}; /// /// /// An RGB color. /// #[derive(Arbitrary)] /// pub struct Rgb { /// r: u8, /// g: u8, /// b: u8, /// } /// /// // Get the raw bytes from the fuzzer. /// # let get_input_from_fuzzer = || &[]; /// let raw_data: &[u8] = get_input_from_fuzzer(); /// /// // Wrap it in an `Unstructured`. /// let mut unstructured = Unstructured::new(raw_data); /// /// // Generate an `Rgb` color and run our checks. /// if let Ok(rgb) = Rgb::arbitrary(&mut unstructured) { /// # let run_my_color_conversion_checks = |_| {}; /// run_my_color_conversion_checks(rgb); /// } /// # } /// ``` pubstruct Unstructured<'a> {
data: &'a [u8],
}
impl<'a> Unstructured<'a> { /// Create a new `Unstructured` from the given raw data. /// /// # Example /// /// ``` /// use arbitrary::Unstructured; /// /// let u = Unstructured::new(&[1, 2, 3, 4]); /// ``` pubfn new(data: &'a [u8]) -> Self {
Unstructured { data }
}
/// Get the number of remaining bytes of underlying data that are still /// available. /// /// # Example /// /// ``` /// use arbitrary::{Arbitrary, Unstructured}; /// /// let mut u = Unstructured::new(&[1, 2, 3]); /// /// // Initially have three bytes of data. /// assert_eq!(u.len(), 3); /// /// // Generating a `bool` consumes one byte from the underlying data, so /// // we are left with two bytes afterwards. /// let _ = bool::arbitrary(&mut u); /// assert_eq!(u.len(), 2); /// ``` #[inline] pubfn len(&self) -> usize { self.data.len()
}
/// Is the underlying unstructured data exhausted? /// /// `unstructured.is_empty()` is the same as `unstructured.len() == 0`. /// /// # Example /// /// ``` /// use arbitrary::{Arbitrary, Unstructured}; /// /// let mut u = Unstructured::new(&[1, 2, 3, 4]); /// /// // Initially, we are not empty. /// assert!(!u.is_empty()); /// /// // Generating a `u32` consumes all four bytes of the underlying data, so /// // we become empty afterwards. /// let _ = u32::arbitrary(&mut u); /// assert!(u.is_empty()); /// ``` #[inline] pubfn is_empty(&self) -> bool { self.len() == 0
}
/// Generate an arbitrary instance of `A`. /// /// This is simply a helper method that is equivalent to `<A as /// Arbitrary>::arbitrary(self)`. This helper is a little bit more concise, /// and can be used in situations where Rust's type inference will figure /// out what `A` should be. /// /// # Example /// /// ``` /// # #[cfg(feature="derive")] fn foo() -> arbitrary::Result<()> { /// use arbitrary::{Arbitrary, Unstructured}; /// /// #[derive(Arbitrary)] /// struct MyType { /// // ... /// } /// /// fn do_stuff(value: MyType) { /// # let _ = value; /// // ... /// } /// /// let mut u = Unstructured::new(&[1, 2, 3, 4]); /// /// // Rust's type inference can figure out that `value` should be of type /// // `MyType` here: /// let value = u.arbitrary()?; /// do_stuff(value); /// # Ok(()) } /// ``` pubfn arbitrary<A>(&mutself) -> Result<A> where
A: Arbitrary<'a>,
{
<A as Arbitrary<'a>>::arbitrary(self)
}
/// Get the number of elements to insert when building up a collection of /// arbitrary `ElementType`s. /// /// This uses the [`<ElementType as /// Arbitrary>::size_hint`][crate::Arbitrary::size_hint] method to smartly /// choose a length such that we most likely have enough underlying bytes to /// construct that many arbitrary `ElementType`s. /// /// This should only be called within an `Arbitrary` implementation. /// /// # Example /// /// ``` /// use arbitrary::{Arbitrary, Result, Unstructured}; /// # pub struct MyCollection<T> { _t: std::marker::PhantomData<T> } /// # impl<T> MyCollection<T> { /// # pub fn with_capacity(capacity: usize) -> Self { MyCollection { _t: std::marker::PhantomData } } /// # pub fn insert(&mut self, element: T) {} /// # } /// /// impl<'a, T> Arbitrary<'a> for MyCollection<T> /// where /// T: Arbitrary<'a>, /// { /// fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> { /// // Get the number of `T`s we should insert into our collection. /// let len = u.arbitrary_len::<T>()?; /// /// // And then create a collection of that length! /// let mut my_collection = MyCollection::with_capacity(len); /// for _ in 0..len { /// let element = T::arbitrary(u)?; /// my_collection.insert(element); /// } /// /// Ok(my_collection) /// } /// } /// ``` pubfn arbitrary_len<ElementType>(&mutself) -> Result<usize> where
ElementType: Arbitrary<'a>,
{ let byte_size = self.arbitrary_byte_size()?; let (lower, upper) = <ElementType as Arbitrary>::size_hint(0); let elem_size = upper.unwrap_or(lower * 2); let elem_size = std::cmp::max(1, elem_size);
Ok(byte_size / elem_size)
}
// We only consume as many bytes as necessary to cover the entire // range of the byte string. // Note: We cast to u64 so we don't overflow when checking std::u32::MAX + 4 on 32-bit archs let len = ifself.data.len() as u64 <= std::u8::MAX as u64 + 1 { let bytes = 1; let max_size = self.data.len() - bytes; let (rest, for_size) = self.data.split_at(max_size); self.data = rest; Self::int_in_range_impl(0..=max_size as u8, for_size.iter().copied())?.0as usize
} elseifself.data.len() as u64 <= std::u16::MAX as u64 + 2 { let bytes = 2; let max_size = self.data.len() - bytes; let (rest, for_size) = self.data.split_at(max_size); self.data = rest; Self::int_in_range_impl(0..=max_size as u16, for_size.iter().copied())?.0as usize
} elseifself.data.len() as u64 <= std::u32::MAX as u64 + 4 { let bytes = 4; let max_size = self.data.len() - bytes; let (rest, for_size) = self.data.split_at(max_size); self.data = rest; Self::int_in_range_impl(0..=max_size as u32, for_size.iter().copied())?.0as usize
} else { let bytes = 8; let max_size = self.data.len() - bytes; let (rest, for_size) = self.data.split_at(max_size); self.data = rest; Self::int_in_range_impl(0..=max_size as u64, for_size.iter().copied())?.0as usize
};
Ok(len)
}
}
/// Generate an integer within the given range. /// /// Do not use this to generate the size of a collection. Use /// `arbitrary_len` instead. /// /// # Panics /// /// Panics if `range.start > range.end`. That is, the given range must be /// non-empty. /// /// # Example /// /// ``` /// use arbitrary::{Arbitrary, Unstructured}; /// /// let mut u = Unstructured::new(&[1, 2, 3, 4]); /// /// let x: i32 = u.int_in_range(-5_000..=-1_000) /// .expect("constructed `u` with enough bytes to generate an `i32`"); /// /// assert!(-5_000 <= x); /// assert!(x <= -1_000); /// ``` pubfn int_in_range<T>(&mutself, range: ops::RangeInclusive<T>) -> Result<T> where
T: Int,
{ let (result, bytes_consumed) = Self::int_in_range_impl(range, self.data.iter().cloned())?; self.data = &self.data[bytes_consumed..];
Ok(result)
}
fn int_in_range_impl<T>(
range: ops::RangeInclusive<T>, mut bytes: impl Iterator<Item = u8>,
) -> Result<(T, usize)> where
T: Int,
{ let start = *range.start(); let end = *range.end();
assert!(
start <= end, "`arbitrary::Unstructured::int_in_range` requires a non-empty range"
);
// When there is only one possible choice, don't waste any entropy from // the underlying data. if start == end { return Ok((start, 0));
}
// From here on out we work with the unsigned representation. All of the // operations performed below work out just as well whether or not `T` // is a signed or unsigned integer. let start = start.to_unsigned(); let end = end.to_unsigned();
let delta = end.wrapping_sub(start);
debug_assert_ne!(delta, T::Unsigned::ZERO);
// Compute an arbitrary integer offset from the start of the range. We // do this by consuming `size_of(T)` bytes from the input to create an // arbitrary integer and then clamping that int into our range bounds // with a modulo operation. letmut arbitrary_int = T::Unsigned::ZERO; letmut bytes_consumed: usize = 0;
while (bytes_consumed < mem::size_of::<T>())
&& (delta >> T::Unsigned::from_usize(bytes_consumed * 8)) > T::Unsigned::ZERO
{ let byte = match bytes.next() {
None => break,
Some(b) => b,
};
bytes_consumed += 1;
// Combine this byte into our arbitrary integer, but avoid // overflowing the shift for `u8` and `i8`.
arbitrary_int = if mem::size_of::<T>() == 1 {
T::Unsigned::from_u8(byte)
} else {
(arbitrary_int << 8) | T::Unsigned::from_u8(byte)
};
}
let offset = if delta == T::Unsigned::MAX {
arbitrary_int
} else {
arbitrary_int % (delta.checked_add(T::Unsigned::ONE).unwrap())
};
// Finally, we add `start` to our offset from `start` to get the result // actual value within the range. let result = start.wrapping_add(offset);
// And convert back to our maybe-signed representation. let result = T::from_unsigned(result);
debug_assert!(*range.start() <= result);
debug_assert!(result <= *range.end());
Ok((result, bytes_consumed))
}
/// Choose one of the given choices. /// /// This should only be used inside of `Arbitrary` implementations. /// /// Returns an error if there is not enough underlying data to make a /// choice or if no choices are provided. /// /// # Examples /// /// Selecting from an array of choices: /// /// ``` /// use arbitrary::Unstructured; /// /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); /// let choices = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; /// /// let choice = u.choose(&choices).unwrap(); /// /// println!("chose {}", choice); /// ``` /// /// An error is returned if no choices are provided: /// /// ``` /// use arbitrary::Unstructured; /// /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); /// let choices: [char; 0] = []; /// /// let result = u.choose(&choices); /// /// assert!(result.is_err()); /// ``` pubfn choose<'b, T>(&mut self, choices: &'b [T]) -> Result<&'b T> { let idx = self.choose_index(choices.len())?;
Ok(&choices[idx])
}
/// Choose a value in `0..len`. /// /// Returns an error if the `len` is zero. /// /// # Examples /// /// Using Fisher–Yates shuffle shuffle to gerate an arbitrary permutation. /// /// [Fisher–Yates shuffle]: https://en.wikipedia.org/wiki/Fisher–Yates_shuffle /// /// ``` /// use arbitrary::Unstructured; /// /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); /// let mut permutation = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; /// let mut to_permute = &mut permutation[..]; /// while to_permute.len() > 1 { /// let idx = u.choose_index(to_permute.len()).unwrap(); /// to_permute.swap(0, idx); /// to_permute = &mut to_permute[1..]; /// } /// /// println!("permutation: {:?}", permutation); /// ``` /// /// An error is returned if the length is zero: /// /// ``` /// use arbitrary::Unstructured; /// /// let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); /// let array: [i32; 0] = []; /// /// let result = u.choose_index(array.len()); /// /// assert!(result.is_err()); /// ``` pubfn choose_index(&mutself, len: usize) -> Result<usize> { if len == 0 { return Err(Error::EmptyChoose);
} let idx = self.int_in_range(0..=len - 1)?;
Ok(idx)
}
/// Generate a boolean according to the given ratio. /// /// # Panics /// /// Panics when the numerator and denominator do not meet these constraints: /// /// * `0 < numerator <= denominator` /// /// # Example /// /// Generate a boolean that is `true` five sevenths of the time: /// /// ``` /// # fn foo() -> arbitrary::Result<()> { /// use arbitrary::Unstructured; /// /// # let my_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; /// let mut u = Unstructured::new(&my_data); /// /// if u.ratio(5, 7)? { /// // Take this branch 5/7 of the time. /// } /// # Ok(()) /// # } /// ``` pubfn ratio<T>(&mutself, numerator: T, denominator: T) -> Result<bool> where
T: Int,
{
assert!(T::ZERO < numerator);
assert!(numerator <= denominator); let x = self.int_in_range(T::ONE..=denominator)?;
Ok(x <= numerator)
}
/// Fill a `buffer` with bytes from the underlying raw data. /// /// This should only be called within an `Arbitrary` implementation. This is /// a very low-level operation. You should generally prefer calling nested /// `Arbitrary` implementations like `<Vec<u8>>::arbitrary` and /// `String::arbitrary` over using this method directly. /// /// If this `Unstructured` does not have enough underlying data to fill the /// whole `buffer`, it pads the buffer out with zeros. /// /// # Example /// /// ``` /// use arbitrary::Unstructured; /// /// let mut u = Unstructured::new(&[1, 2, 3, 4]); /// /// let mut buf = [0; 2]; /// /// assert!(u.fill_buffer(&mut buf).is_ok()); /// assert_eq!(buf, [1, 2]); /// /// assert!(u.fill_buffer(&mut buf).is_ok()); /// assert_eq!(buf, [3, 4]); /// /// assert!(u.fill_buffer(&mut buf).is_ok()); /// assert_eq!(buf, [0, 0]); /// ``` pubfn fill_buffer(&mutself, buffer: &mut [u8]) -> Result<()> { let n = std::cmp::min(buffer.len(), self.data.len());
buffer[..n].copy_from_slice(&self.data[..n]); for byte in buffer[n..].iter_mut() {
*byte = 0;
} self.data = &self.data[n..];
Ok(())
}
/// Provide `size` bytes from the underlying raw data. /// /// This should only be called within an `Arbitrary` implementation. This is /// a very low-level operation. You should generally prefer calling nested /// `Arbitrary` implementations like `<Vec<u8>>::arbitrary` and /// `String::arbitrary` over using this method directly. /// /// # Example /// /// ``` /// use arbitrary::Unstructured; /// /// let mut u = Unstructured::new(&[1, 2, 3, 4]); /// /// assert!(u.bytes(2).unwrap() == &[1, 2]); /// assert!(u.bytes(2).unwrap() == &[3, 4]); /// ``` pubfn bytes(&mutself, size: usize) -> Result<&'a [u8]> { ifself.data.len() < size { return Err(Error::NotEnoughData);
}
let (for_buf, rest) = self.data.split_at(size); self.data = rest;
Ok(for_buf)
}
/// Peek at `size` number of bytes of the underlying raw input. /// /// Does not consume the bytes, only peeks at them. /// /// Returns `None` if there are not `size` bytes left in the underlying raw /// input. /// /// # Example /// /// ``` /// use arbitrary::Unstructured; /// /// let u = Unstructured::new(&[1, 2, 3]); /// /// assert_eq!(u.peek_bytes(0).unwrap(), []); /// assert_eq!(u.peek_bytes(1).unwrap(), [1]); /// assert_eq!(u.peek_bytes(2).unwrap(), [1, 2]); /// assert_eq!(u.peek_bytes(3).unwrap(), [1, 2, 3]); /// /// assert!(u.peek_bytes(4).is_none()); /// ``` pubfn peek_bytes(&self, size: usize) -> Option<&'a [u8]> { self.data.get(..size)
}
/// Consume all of the rest of the remaining underlying bytes. /// /// Returns a slice of all the remaining, unconsumed bytes. /// /// # Example /// /// ``` /// use arbitrary::Unstructured; /// /// let mut u = Unstructured::new(&[1, 2, 3]); /// /// let mut remaining = u.take_rest(); /// /// assert_eq!(remaining, [1, 2, 3]); /// ``` pubfn take_rest(mutself) -> &'a [u8] {
mem::take(&mutself.data)
}
/// Provide an iterator over elements for constructing a collection /// /// This is useful for implementing [`Arbitrary::arbitrary`] on collections /// since the implementation is simply `u.arbitrary_iter()?.collect()` pubfn arbitrary_iter<'b, ElementType: Arbitrary<'a>>(
&'b mut self,
) -> Result<ArbitraryIter<'a, 'b, ElementType>> {
Ok(ArbitraryIter {
u: &mut *self,
_marker: PhantomData,
})
}
/// Provide an iterator over elements for constructing a collection from /// all the remaining bytes. /// /// This is useful for implementing [`Arbitrary::arbitrary_take_rest`] on collections /// since the implementation is simply `u.arbitrary_take_rest_iter()?.collect()` pubfn arbitrary_take_rest_iter<ElementType: Arbitrary<'a>>( self,
) -> Result<ArbitraryTakeRestIter<'a, ElementType>> {
Ok(ArbitraryTakeRestIter {
u: self,
_marker: PhantomData,
})
}
/// Call the given function an arbitrary number of times. /// /// The function is given this `Unstructured` so that it can continue to /// generate arbitrary data and structures. /// /// You may optionaly specify minimum and maximum bounds on the number of /// times the function is called. /// /// You may break out of the loop early by returning /// `Ok(std::ops::ControlFlow::Break)`. To continue the loop, return /// `Ok(std::ops::ControlFlow::Continue)`. /// /// # Panics /// /// Panics if `min > max`. /// /// # Example /// /// Call a closure that generates an arbitrary type inside a context an /// arbitrary number of times: /// /// ``` /// use arbitrary::{Result, Unstructured}; /// use std::ops::ControlFlow; /// /// enum Type { /// /// A boolean type. /// Bool, /// /// /// An integer type. /// Int, /// /// /// A list of the `i`th type in this type's context. /// List(usize), /// } /// /// fn arbitrary_types_context(u: &mut Unstructured) -> Result<Vec<Type>> { /// let mut context = vec![]; /// /// u.arbitrary_loop(Some(10), Some(20), |u| { /// let num_choices = if context.is_empty() { /// 2 /// } else { /// 3 /// }; /// let ty = match u.int_in_range::<u8>(1..=num_choices)? { /// 1 => Type::Bool, /// 2 => Type::Int, /// 3 => Type::List(u.int_in_range(0..=context.len() - 1)?), /// _ => unreachable!(), /// }; /// context.push(ty); /// Ok(ControlFlow::Continue(())) /// })?; /// /// // The number of loop iterations are constrained by the min/max /// // bounds that we provided. /// assert!(context.len() >= 10); /// assert!(context.len() <= 20); /// /// Ok(context) /// } /// ``` pubfn arbitrary_loop(
&mutself,
min: Option<u32>,
max: Option<u32>, mut f: impl FnMut(&mutSelf) -> Result<ControlFlow<(), ()>>,
) -> Result<()> { let min = min.unwrap_or(0); let max = max.unwrap_or(u32::MAX);
for _ in0..self.int_in_range(min..=max)? { match f(self)? {
ControlFlow::Continue(_) => continue,
ControlFlow::Break(_) => break,
}
}
Ok(())
}
}
/// Utility iterator produced by [`Unstructured::arbitrary_iter`] pubstruct ArbitraryIter<'a, 'b, ElementType> {
u: &'b mut Unstructured<'a>,
_marker: PhantomData<ElementType>,
}
impl<'a, 'b, ElementType: Arbitrary<'a>> Iterator for ArbitraryIter<'a, 'b, ElementType> { type Item = Result<ElementType>; fn next(&mutself) -> Option<Result<ElementType>> { let keep_going = self.u.arbitrary().unwrap_or(false); if keep_going {
Some(Arbitrary::arbitrary(self.u))
} else {
None
}
}
}
/// Utility iterator produced by [`Unstructured::arbitrary_take_rest_iter`] pubstruct ArbitraryTakeRestIter<'a, ElementType> {
u: Unstructured<'a>,
_marker: PhantomData<ElementType>,
}
impl<'a, ElementType: Arbitrary<'a>> Iterator for ArbitraryTakeRestIter<'a, ElementType> { type Item = Result<ElementType>; fn next(&mutself) -> Option<Result<ElementType>> { let keep_going = self.u.arbitrary().unwrap_or(false); if keep_going {
Some(Arbitrary::arbitrary(&mutself.u))
} else {
None
}
}
}
/// A trait that is implemented for all of the primitive integers: /// /// * `u8` /// * `u16` /// * `u32` /// * `u64` /// * `u128` /// * `usize` /// * `i8` /// * `i16` /// * `i32` /// * `i64` /// * `i128` /// * `isize` /// /// Don't implement this trait yourself. pubtrait Int:
Copy
+ std::fmt::Debug
+ PartialOrd
+ Ord
+ ops::Sub<Self, Output = Self>
+ ops::Rem<Self, Output = Self>
+ ops::Shr<Self, Output = Self>
+ ops::Shl<usize, Output = Self>
+ ops::BitOr<Self, Output = Self>
{ #[doc(hidden)] type Unsigned: Int;
#[test] fn test_byte_size() { letmut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 6]); // Should take one byte off the end
assert_eq!(u.arbitrary_byte_size().unwrap(), 6);
assert_eq!(u.len(), 9); letmut v = vec![];
v.resize(260, 0);
v.push(1);
v.push(4); letmut u = Unstructured::new(&v); // Should read two bytes off the end
assert_eq!(u.arbitrary_byte_size().unwrap(), 0x104);
assert_eq!(u.len(), 260);
}
#[test] fn int_in_range_of_one() { letmut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 6]); let x = u.int_in_range(0..=0).unwrap();
assert_eq!(x, 0); let choice = *u.choose(&[42]).unwrap();
assert_eq!(choice, 42)
}
letmut u = Unstructured::new(&[1, 2]);
assert_eq!(1, u.int_in_range::<u32>(0..=u8::MAX as u32).unwrap());
assert_eq!(u.len(), 1);
letmut u = Unstructured::new(&[1]);
assert_eq!(1, u.int_in_range::<u32>(0..=u8::MAX as u32 + 1).unwrap());
assert!(u.is_empty());
}
#[test] fn int_in_range_in_bounds() { for input in u8::MIN..=u8::MAX { let input = [input];
letmut u = Unstructured::new(&input); let x = u.int_in_range(1..=u8::MAX).unwrap();
assert_ne!(x, 0);
letmut u = Unstructured::new(&input); let x = u.int_in_range(0..=u8::MAX - 1).unwrap();
assert_ne!(x, u8::MAX);
}
}
#[test] fn int_in_range_covers_unsigned_range() { // Test that we generate all values within the range given to // `int_in_range`.
letmut full = [false; u8::MAX as usize + 1]; letmut no_zero = [false; u8::MAX as usize]; letmut no_max = [false; u8::MAX as usize]; letmut narrow = [false; 10];
for input in u8::MIN..=u8::MAX { let input = [input];
letmut u = Unstructured::new(&input); let x = u.int_in_range(0..=u8::MAX).unwrap();
full[x as usize] = true;
letmut u = Unstructured::new(&input); let x = u.int_in_range(1..=u8::MAX).unwrap();
no_zero[x as usize - 1] = true;
letmut u = Unstructured::new(&input); let x = u.int_in_range(0..=u8::MAX - 1).unwrap();
no_max[x as usize] = true;
letmut u = Unstructured::new(&input); let x = u.int_in_range(100..=109).unwrap();
narrow[x as usize - 100] = true;
}
for (i, covered) in full.iter().enumerate() {
assert!(covered, "full[{}] should have been generated", i);
} for (i, covered) in no_zero.iter().enumerate() {
assert!(covered, "no_zero[{}] should have been generated", i);
} for (i, covered) in no_max.iter().enumerate() {
assert!(covered, "no_max[{}] should have been generated", i);
} for (i, covered) in narrow.iter().enumerate() {
assert!(covered, "narrow[{}] should have been generated", i);
}
}
#[test] fn int_in_range_covers_signed_range() { // Test that we generate all values within the range given to // `int_in_range`.
letmut full = [false; u8::MAX as usize + 1]; letmut no_min = [false; u8::MAX as usize]; letmut no_max = [false; u8::MAX as usize]; letmut narrow = [false; 21];
let abs_i8_min: isize = 128;
for input in0..=u8::MAX { let input = [input];
letmut u = Unstructured::new(&input); let x = u.int_in_range(i8::MIN..=i8::MAX).unwrap();
full[(x as isize + abs_i8_min) as usize] = true;
letmut u = Unstructured::new(&input); let x = u.int_in_range(i8::MIN + 1..=i8::MAX).unwrap();
no_min[(x as isize + abs_i8_min - 1) as usize] = true;
letmut u = Unstructured::new(&input); let x = u.int_in_range(i8::MIN..=i8::MAX - 1).unwrap();
no_max[(x as isize + abs_i8_min) as usize] = true;
letmut u = Unstructured::new(&input); let x = u.int_in_range(-10..=10).unwrap();
narrow[(x as isize + 10) as usize] = true;
}
for (i, covered) in full.iter().enumerate() {
assert!(covered, "full[{}] should have been generated", i);
} for (i, covered) in no_min.iter().enumerate() {
assert!(covered, "no_min[{}] should have been generated", i);
} for (i, covered) in no_max.iter().enumerate() {
assert!(covered, "no_max[{}] should have been generated", i);
} for (i, covered) in narrow.iter().enumerate() {
assert!(covered, "narrow[{}] should have been generated", i);
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.35 Sekunden
(vorverarbeitet am 2026-06-22)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.