diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6aacc1a..808558f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -38,3 +38,12 @@ jobs: - name: Run tests run: cargo test --verbose --features std + build_arbitrary: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Build + run: cargo build --verbose --features arbitrary + - name: Run tests + run: cargo test --verbose --features arbitrary diff --git a/Cargo.toml b/Cargo.toml index c4a0bac..c088db2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ categories = ["embedded", "no-std", "data-structures"] [dependencies] +arbitrary = { version = "1.4.1", optional = true } [features] default = [] @@ -23,3 +24,4 @@ default = [] # types. Apart from that, this crate works without explicit indication both on # std and no_std systems. std = [] +arbitrary = ["dep:arbitrary"] diff --git a/src/lib.rs b/src/lib.rs index 2348265..4e2bd2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -383,6 +383,13 @@ macro_rules! implement_common { self.wrapping_sub(other) } } + + #[cfg(feature = "arbitrary")] + impl<'a> arbitrary::Arbitrary<'a> for $name { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + Ok($name($type::arbitrary(u)?).mask()) + } + } }; } @@ -967,3 +974,23 @@ mod tests { } } } + +#[cfg(all(test, feature = "arbitrary"))] +mod tests_arbitrary { + use super::*; + use arbitrary::Arbitrary; + + #[test] + fn generate_from_unstructured_data() { + let data = [0x0, 0x0, 0x0, 0x0]; + let mut unstructured = arbitrary::Unstructured::new(&data); + assert_eq!(u31::arbitrary(&mut unstructured), Ok(u31(0x0))); + } + + #[test] + fn data_is_masked_appropriately_on_generation() { + let data = [0xFF, 0xFF, 0xFF, 0xFF]; + let mut unstructured = arbitrary::Unstructured::new(&data); + assert_eq!(u31::arbitrary(&mut unstructured), Ok(u31(0x7FFFFFFF))); + } +}