minerva 0.2.0

Causal ordering for distributed systems
use crate::metis::Rhapsody;
use proptest::prelude::*;

use super::{arb_weaves, build};

proptest! {
    /// Decode never panics on arbitrary bytes, and every accepted frame re-encodes
    /// to exactly the bytes it decoded from.
    #[test]
    fn prop_rhapsody_from_bytes_never_panics(
        bytes in prop::collection::vec(any::<u8>(), 0..128),
    ) {
        if let Ok(rhapsody) = Rhapsody::from_bytes(&bytes) {
            prop_assert_eq!(rhapsody.to_bytes(), bytes.clone());
        }
        if let Ok((rhapsody, tail)) = Rhapsody::from_prefix(&bytes) {
            let consumed = bytes.len() - tail.len();
            let reencoded = rhapsody.to_bytes();
            prop_assert_eq!(reencoded.as_slice(), &bytes[..consumed]);
        }
    }

    /// Truncating a valid frame at every prefix length never panics, and any
    /// accepted prefix re-encodes to the bytes it consumed.
    #[test]
    fn prop_rhapsody_truncation_never_panics(weaves in arb_weaves(), keep in any::<usize>()) {
        let bytes = build(&weaves).to_bytes();
        let cut = keep % (bytes.len() + 1);
        let prefix = &bytes[..cut];
        if let Ok(rhapsody) = Rhapsody::from_bytes(prefix) {
            let reencoded = rhapsody.to_bytes();
            prop_assert_eq!(reencoded.as_slice(), prefix);
        }
        if let Ok((rhapsody, tail)) = Rhapsody::from_prefix(prefix) {
            let consumed = prefix.len() - tail.len();
            let reencoded = rhapsody.to_bytes();
            prop_assert_eq!(reencoded.as_slice(), &prefix[..consumed]);
        }
    }

    /// Shaped totality on mutated valid frames: flipping one byte keeps the
    /// decoder total, and any accepted mutant re-encodes to exactly its own bytes.
    #[test]
    fn prop_rhapsody_flip_byte_stays_total(
        weaves in arb_weaves(),
        offset in any::<usize>(),
        xor in 1u8..=u8::MAX,
    ) {
        let mut bytes = build(&weaves).to_bytes();
        let len = bytes.len();
        bytes[offset % len] ^= xor;
        if let Ok(rhapsody) = Rhapsody::from_bytes(&bytes) {
            prop_assert_eq!(&rhapsody.to_bytes(), &bytes);
        }
    }
}