use { super::{Arbitrary, Result, Unstructured}, std::{collections::HashSet, fmt::Debug, hash::Hash, rc::Rc, sync::Arc}, }; /// Assert that the given expected values are all generated. /// /// Exhaustively enumerates all buffers up to length 10 containing the /// following bytes: `0x00`, `0x01`, `0x61` (aka ASCII 'a'), and `0xff` fn assert_generates(expected_values: impl IntoIterator) where T: Clone + Debug + Hash + Eq + for<'a> Arbitrary<'a>, { let expected_values: HashSet<_> = expected_values.into_iter().collect(); let mut arbitrary_expected = expected_values.clone(); let mut arbitrary_take_rest_expected = expected_values; let bytes = [0, 1, b'a', 0xff]; let max_len = 10; let mut buf = Vec::with_capacity(max_len); let mut g = exhaustigen::Gen::new(); while !g.done() { let len = g.gen(max_len); buf.clear(); buf.extend( std::iter::repeat_with(|| { let index = g.gen(bytes.len() - 1); bytes[index] }) .take(len), ); let mut u = Unstructured::new(&buf); let val = T::arbitrary(&mut u).unwrap(); arbitrary_expected.remove(&val); let u = Unstructured::new(&buf); let val = T::arbitrary_take_rest(u).unwrap(); arbitrary_take_rest_expected.remove(&val); if arbitrary_expected.is_empty() && arbitrary_take_rest_expected.is_empty() { return; } } panic!( "failed to generate all expected values!\n\n\ T::arbitrary did not generate: {arbitrary_expected:#?}\n\n\ T::arbitrary_take_rest did not generate {arbitrary_take_rest_expected:#?}" ) } /// Generates an arbitrary `T`, and checks that the result is consistent with the /// `size_hint()` reported by `T`. fn checked_arbitrary<'a, T: Arbitrary<'a>>(u: &mut Unstructured<'a>) -> Result { let (min, max) = T::size_hint(0); let len_before = u.len(); let result = T::arbitrary(u); let consumed = len_before - u.len(); if let Some(max) = max { assert!( consumed <= max, "incorrect maximum size: indicated {}, actually consumed {}", max, consumed ); } if result.is_ok() { assert!( consumed >= min, "incorrect minimum size: indicated {}, actually consumed {}", min, consumed ); } result } /// Like `checked_arbitrary()`, but calls `arbitrary_take_rest()` instead of `arbitrary()`. fn checked_arbitrary_take_rest<'a, T: Arbitrary<'a>>(u: Unstructured<'a>) -> Result { let (min, _) = T::size_hint(0); let len_before = u.len(); let result = T::arbitrary_take_rest(u); if result.is_ok() { assert!( len_before >= min, "incorrect minimum size: indicated {}, worked with {}", min, len_before ); } result } #[test] fn finite_buffer_fill_buffer() { let x = [1, 2, 3, 4]; let mut rb = Unstructured::new(&x); let mut z = [0; 2]; rb.fill_buffer(&mut z).unwrap(); assert_eq!(z, [1, 2]); rb.fill_buffer(&mut z).unwrap(); assert_eq!(z, [3, 4]); rb.fill_buffer(&mut z).unwrap(); assert_eq!(z, [0, 0]); } #[test] fn arbitrary_for_integers() { let x = [1, 2, 3, 4]; let mut buf = Unstructured::new(&x); let expected = 1 | (2 << 8) | (3 << 16) | (4 << 24); let actual = checked_arbitrary::(&mut buf).unwrap(); assert_eq!(expected, actual); assert_generates([ i32::from_ne_bytes([0, 0, 0, 0]), i32::from_ne_bytes([0, 0, 0, 1]), i32::from_ne_bytes([0, 0, 1, 0]), i32::from_ne_bytes([0, 1, 0, 0]), i32::from_ne_bytes([1, 0, 0, 0]), i32::from_ne_bytes([1, 1, 1, 1]), i32::from_ne_bytes([0xff, 0xff, 0xff, 0xff]), ]); } #[test] fn arbitrary_for_bytes() { let x = [1, 2, 3, 4, 4]; let mut buf = Unstructured::new(&x); let expected = &[1, 2, 3, 4]; let actual = checked_arbitrary::<&[u8]>(&mut buf).unwrap(); assert_eq!(expected, actual); } #[test] fn arbitrary_take_rest_for_bytes() { let x = [1, 2, 3, 4]; let buf = Unstructured::new(&x); let expected = &[1, 2, 3, 4]; let actual = checked_arbitrary_take_rest::<&[u8]>(buf).unwrap(); assert_eq!(expected, actual); } #[test] fn arbitrary_for_vec_u8() { assert_generates::>([ vec![], vec![0], vec![1], vec![0, 0], vec![0, 1], vec![1, 0], vec![1, 1], vec![0, 0, 0], vec![0, 0, 1], vec![0, 1, 0], vec![0, 1, 1], vec![1, 0, 0], vec![1, 0, 1], vec![1, 1, 0], vec![1, 1, 1], ]); } #[test] fn arbitrary_for_vec_vec_u8() { assert_generates::>>([ vec![], vec![vec![]], vec![vec![0]], vec![vec![1]], vec![vec![0, 1]], vec![vec![], vec![]], vec![vec![0], vec![]], vec![vec![], vec![1]], vec![vec![0], vec![1]], vec![vec![0, 1], vec![]], vec![vec![], vec![1, 0]], vec![vec![], vec![], vec![]], ]); } #[test] fn arbitrary_for_vec_vec_vec_u8() { assert_generates::>>>([ vec![], vec![vec![]], vec![vec![vec![0]]], vec![vec![vec![1]]], vec![vec![vec![0, 1]]], vec![vec![], vec![]], vec![vec![], vec![vec![]]], vec![vec![vec![]], vec![]], vec![vec![vec![]], vec![vec![]]], vec![vec![vec![0]], vec![]], vec![vec![], vec![vec![1]]], vec![vec![vec![0]], vec![vec![1]]], vec![vec![vec![0, 1]], vec![]], vec![vec![], vec![vec![0, 1]]], vec![vec![], vec![], vec![]], vec![vec![vec![]], vec![], vec![]], vec![vec![], vec![vec![]], vec![]], vec![vec![], vec![], vec![vec![]]], ]); } #[test] fn arbitrary_for_string() { assert_generates::(["".into(), "a".into(), "aa".into(), "aaa".into()]); } #[test] fn arbitrary_collection() { let x = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 12, ]; assert_eq!( checked_arbitrary::<&[u8]>(&mut Unstructured::new(&x)).unwrap(), &[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3] ); assert_eq!( checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), &[2, 4, 6, 8, 1] ); assert_eq!( &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), &[2, 4, 6, 8, 1] ); assert_eq!( &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), &[2, 4, 6, 8, 1] ); assert_eq!( &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), &[2, 4, 6, 8, 1] ); assert_eq!( checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), &[84148994] ); assert_eq!( checked_arbitrary::(&mut Unstructured::new(&x)).unwrap(), "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x01\x02\x03" ); } #[test] fn arbitrary_take_rest() { // Basic examples let x = [1, 2, 3, 4]; assert_eq!( checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&x)).unwrap(), &[1, 2, 3, 4] ); assert_eq!( checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), &[2, 4] ); assert_eq!( &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), &[2, 4] ); assert_eq!( &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), &[2, 4] ); assert_eq!( &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), &[2, 4] ); assert_eq!( checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), &[0x040302] ); assert_eq!( checked_arbitrary_take_rest::(Unstructured::new(&x)).unwrap(), "\x01\x02\x03\x04" ); // Empty remainder assert_eq!( checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&[])).unwrap(), &[] ); assert_eq!( checked_arbitrary_take_rest::>(Unstructured::new(&[])).unwrap(), &[] ); // Cannot consume all but can consume part of the input assert_eq!( checked_arbitrary_take_rest::(Unstructured::new(&[1, 0xFF, 2])).unwrap(), "\x01" ); } #[test] fn size_hint_for_tuples() { assert_eq!( (7, Some(7)), <(bool, u16, i32) as Arbitrary<'_>>::size_hint(0) ); assert_eq!((1, None), <(u8, Vec) as Arbitrary>::size_hint(0)); }