mopenzl 0.2.3

OpenZL compression and decompression in safe Rust; encoding is byte-identical to Meta's reference library
Documentation
use super::*;
use crate::Backend;

#[test]
fn checked_sizes_reservations_and_future_versions_report_specific_failures() {
    assert!(matches!(add(u64::MAX, 1), Err(E::Overflow)));
    assert!(matches!(index_size(usize::MAX), Err(E::Overflow)));
    assert!(matches!(
        reserve(&mut Vec::<u64>::new(), usize::MAX),
        Err(E::Allocation)
    ));
    assert!(matches!(number::<8>(&[], usize::MAX), Err(E::Overflow)));
    assert!(matches!(
        number::<8>(&[0; 7], 0),
        Err(E::UnexpectedEndOfInput)
    ));
    assert!(matches!(
        check_magic(b"MOZFRM\x02\0"),
        Err(E::UnsupportedVersion(2))
    ));
    assert!(
        validate(FramingConfig {
            max_resources: usize::MAX,
            ..Default::default()
        })
        .is_err()
    );
    assert!(
        validate(FramingConfig {
            max_metadata_bytes: usize::MAX,
            ..Default::default()
        })
        .is_err()
    );
}

#[test]
fn scalar_and_host_backends_write_and_read_identical_containers() {
    use crate::framing::{FramedCompressor, FramedDecompressor, FramedResource};
    let payload = [0x5a; 1024];
    let resources = [FramedResource::from(&payload[..])];
    let mut expected = None;
    for backend in Backend::available() {
        let raw = crate::Compressor::builder(Default::default())
            .with_backend(backend)
            .build()
            .unwrap();
        let bytes = FramedCompressor::from(raw)
            .compress(resources.as_slice().into())
            .unwrap();
        if let Some(previous) = &expected {
            assert_eq!(&bytes, previous);
        }
        expected = Some(bytes.clone());
        let raw = crate::Decompressor::builder(Default::default())
            .with_backend(backend)
            .build();
        assert_eq!(
            FramedDecompressor::from(raw)
                .decompress(&bytes)
                .unwrap()
                .resources[0]
                .outputs[0]
                .content(),
            payload
        );
    }
}

#[test]
fn checksum_valid_directory_cannot_overlap_skip_or_change_aggregate_sizes() {
    let level = Backend::SCALAR.0;
    let config = FramingConfig::default();
    let entries = [ResourceInfo {
        offset: 8,
        length: 100,
        decoded_size: 7,
    }];
    let bytes = suffix(&entries, 108, level, config).unwrap();
    let len = index_size(1).unwrap();
    assert_eq!(index(&bytes[..len], 108, level, config).unwrap(), entries);
    for (at, value) in [(8, 9u64), (16, 1u64), (24, config.max_output_bytes + 1)] {
        let mut changed = bytes[..len].to_vec();
        changed[at..at + 8].copy_from_slice(&value.to_le_bytes());
        let hash = xxh3::hash32(level, &changed[..len - 4]);
        changed[len - 4..].copy_from_slice(&hash.to_le_bytes());
        assert!(index(&changed, 108, level, config).is_err());
    }
    assert!(index(&bytes[..len], 109, level, config).is_err());
    assert!(index(&bytes[..len - 1], 108, level, config).is_err());
    assert!(metadata(&[b'A', b'B', 2, 0, 0, 0, 1]).is_err());
    assert!(metadata(b"A").is_err());
}

#[test]
fn checksum_valid_record_must_match_inner_content_size_and_exact_frame_extent() {
    use crate::framing::{FramedCompressor, FramedResource};
    let mut encoder = FramedCompressor::new(Default::default()).unwrap();
    let bytes = encoder
        .compress([FramedResource::from(&b"abc"[..])].as_slice().into())
        .unwrap();
    let length = decode::record_length(&bytes[8..], FramingConfig::default()).unwrap();
    let mut record = bytes[8..8 + length].to_vec();
    record[16..24].copy_from_slice(&4u64.to_le_bytes());
    let hash = xxh3::hash32(Backend::SCALAR.0, &record[..24]);
    record[24..28].copy_from_slice(&hash.to_le_bytes());
    let mut raw = crate::Decompressor::default();
    let info = ResourceInfo {
        offset: 8,
        length: length as u64,
        decoded_size: 4,
    };
    assert!(matches!(
        decode::resource(&mut raw, &record, info, FramingConfig::default()),
        Err(E::Invalid("resource decoded size"))
    ));
    let info = ResourceInfo {
        decoded_size: 3,
        ..info
    };
    assert!(decode::resource(&mut raw, &record, info, FramingConfig::default()).is_err());
    let len = u64::from_le_bytes(number(&record, 8).unwrap());
    record[8..16].copy_from_slice(&(len + 1).to_le_bytes());
    record[16..24].copy_from_slice(&3u64.to_le_bytes());
    let hash = xxh3::hash32(Backend::SCALAR.0, &record[..24]);
    record[24..28].copy_from_slice(&hash.to_le_bytes());
    record.push(0);
    let info = ResourceInfo {
        length: record.len() as u64,
        ..info
    };
    assert!(matches!(
        decode::resource(&mut raw, &record, info, FramingConfig::default()),
        Err(E::Decode(crate::DecodeError::TrailingData { .. }))
    ));
}