audio-codec-bsd 0.1.1

FLAC/PCM/WAV multi-format audio container decoder (symphonia + hound, pure Rust) emitting planar audio-core-bsd AudioFrames
Documentation
//! Property tests for the audio-codec-bsd crate.
//!
//! These `proptest`-driven tests complement the deterministic byte-exact gate
//! in `wav_byte_exact.rs`:
//!
//! - **`wav_byte_exact_for_random_pcm`** — losslessness holds for *any* `i16`
//!   sequence, not just hand-picked edge values.
//! - **`malformed_bytes_never_panic`** — the decoder degrades gracefully on
//!   arbitrary byte sequences (the §3.3 "Sanitizer" gate for untrusted files).
//! - **`planar_length_invariant`** — every decoded `AudioFrame` honours the
//!   planar length invariant `samples.len() == channels * num_frames()`.

use std::path::PathBuf;

use audio_codec_bsd::{open, ContainerDecoder, WavDecoder};
use hound::{SampleFormat, WavSpec, WavWriter};
use proptest::prelude::*;

/// Write `interleaved` 16-bit PCM to a temp WAV and return its path.
fn write_pcm_wav(channels: u16, sample_rate: u32, interleaved: &[i16], name: &str) -> PathBuf {
    let spec = WavSpec {
        channels,
        sample_rate,
        bits_per_sample: 16,
        sample_format: SampleFormat::Int,
    };
    let mut path = std::env::temp_dir();
    path.push(format!(
        "audio_codec_bsd_prop_{id}_{name}.wav",
        id = std::process::id(),
    ));
    let mut writer = WavWriter::create(&path, spec).expect("create wav");
    for &v in interleaved {
        writer.write_sample(v).expect("write sample");
    }
    writer.finalize().expect("finalize wav");
    path
}

/// Drain all planar samples from `dec`, converting each `f32` back to `i16` via
/// the exact inverse `(s * 32768).round()` (clamped defensively).
fn drain_to_planar_i16(dec: &mut dyn ContainerDecoder) -> Vec<i16> {
    let mut out: Vec<i16> = Vec::new();
    while let Ok(Some(frame)) = dec.next_frame() {
        for &s in &frame.samples {
            let scaled = s * 32_768.0_f32;
            let clamped = scaled.clamp(-32_768.0_f32, 32_767.0_f32);
            out.push((clamped.round()) as i16);
        }
    }
    out
}

proptest! {
    #![proptest_config(ProptestConfig {
        cases: 64,
        ..ProptestConfig::default()
    })]

    /// Byte-exact losslessness holds for *any* bounded `i16` sequence, any
    /// channel count (1–2), and any sample rate. The decoder normalises as
    /// `i16 / 32768`; the exact inverse `(f32 * 32768).round()` recovers the
    /// original `i16` for every value.
    #[test]
    fn wav_byte_exact_for_random_pcm(
        samples in proptest::collection::vec(-32768i16..=32767i16, 1..1024),
        channels in 1u16..=2u16,
        sr in 8000u32..=96000u32,
    ) {
        let ch = usize::from(channels);
        // Truncate to a whole number of frames.
        let n = samples.len() - (samples.len() % ch);
        let interleaved = &samples[..n];
        let frames = n / ch;

        let path = write_pcm_wav(channels, sr, interleaved, "pcm");
        let mut dec = WavDecoder::open(&path).expect("open");
        let _info = dec.open(&path).expect("trait open");
        let recovered = drain_to_planar_i16(&mut dec);
        let _ = std::fs::remove_file(&path);

        prop_assert_eq!(recovered.len(), n);
        // Compare in interleaved order: input[i] is channel (i % ch), frame
        // (i / ch), which maps to recovered planar index (i % ch) * frames + (i / ch).
        for (i, &want) in interleaved.iter().enumerate() {
            let c = i % ch;
            let f = i / ch;
            prop_assert_eq!(recovered[c * frames + f], want);
        }
    }

    /// Arbitrary byte sequences never cause a panic. The factory may return
    /// `Err` (expected for garbage) or route to a decoder that yields some
    /// frames or hits a decode error — all acceptable. The ONLY failure is a
    /// panic. This is the §3.3 "Sanitizer" graceful-degradation gate.
    #[test]
    fn malformed_bytes_never_panic(
        bytes in proptest::collection::vec(any::<u8>(), 0..4096),
    ) {
        let mut path = std::env::temp_dir();
        path.push(format!(
            "audio_codec_bsd_prop_malformed_{id}.bin",
            id = std::process::id(),
        ));
        let _ = std::fs::write(&path, &bytes);

        // Attempt full decode pipeline; any Result (Ok or Err) is acceptable.
        if let Ok(mut dec) = open(&path) {
            let _ = dec.open(&path);
            while let Ok(Some(_)) = dec.next_frame() {
                // drain — content ignored
            }
        }

        let _ = std::fs::remove_file(&path);
    }

    /// Every decoded `AudioFrame` honours the planar length invariant
    /// `samples.len() == channels * num_frames()`.
    #[test]
    fn planar_length_invariant(
        channels in 1u16..=2u16,
        n in 0usize..512,
    ) {
        let ch = usize::from(channels);
        let total = ch * n;
        // The invariant is structural; sample values are irrelevant, so silence
        // suffices and avoids any integer casts in the fixture.
        let samples: Vec<i16> = vec![0; total];

        let path = write_pcm_wav(channels, 48_000, &samples, "planar_inv");
        let mut dec = WavDecoder::open(&path).expect("open");
        let _info = dec.open(&path).expect("trait open");
        while let Ok(Some(frame)) = dec.next_frame() {
            prop_assert_eq!(
                frame.samples.len(),
                usize::from(frame.channels) * frame.num_frames()
            );
        }
        let _ = std::fs::remove_file(&path);
    }
}