pixelflow-test-support 0.1.0

Deterministic test helpers for PixelFlow filters, plugins, and embedders.
Documentation
//! Synthetic frame and media builders.

use pixelflow_core::{
    AllocatorConfig, ClipMedia, Frame, FrameBuilder, MetadataSchema, Rational, Result, Sample,
    resolve_format_alias,
};

/// Creates fixed media with deterministic test defaults.
#[must_use]
pub fn fixed_media(alias: &str, width: usize, height: usize) -> ClipMedia {
    ClipMedia::fixed(
        resolve_format_alias(alias).expect("format alias should resolve"),
        width,
        height,
        24,
        Rational {
            numerator: 24_000,
            denominator: 1_001,
        },
    )
}

fn synthetic_frame<T: Sample>(
    alias: &str,
    width: usize,
    height: usize,
    mut sample: impl FnMut(usize, usize, usize) -> T,
) -> Result<Frame> {
    let format = resolve_format_alias(alias)?;
    let schema = MetadataSchema::core();
    let mut builder = FrameBuilder::new(
        format.clone(),
        width,
        height,
        &schema,
        AllocatorConfig::default(),
    )?;

    for plane_index in 0..format.planes().len() {
        let mut plane = builder.plane_mut::<T>(plane_index)?;
        for y in 0..plane.height() {
            let row = plane.row_mut(y).expect("row should exist");
            for (x, value) in row.iter_mut().enumerate() {
                *value = sample(plane_index, x, y);
            }
        }
    }

    Ok(builder.finish())
}

/// Builds one synthetic frame with `u8` storage using per-plane coordinates.
pub fn synthetic_u8_frame(
    alias: &str,
    width: usize,
    height: usize,
    sample: impl FnMut(usize, usize, usize) -> u8,
) -> Result<Frame> {
    synthetic_frame(alias, width, height, sample)
}

/// Builds one synthetic frame with `u16` storage using per-plane coordinates.
pub fn synthetic_u16_frame(
    alias: &str,
    width: usize,
    height: usize,
    sample: impl FnMut(usize, usize, usize) -> u16,
) -> Result<Frame> {
    synthetic_frame(alias, width, height, sample)
}

/// Builds one synthetic frame with `f32` storage using per-plane coordinates.
pub fn synthetic_f32_frame(
    alias: &str,
    width: usize,
    height: usize,
    sample: impl FnMut(usize, usize, usize) -> f32,
) -> Result<Frame> {
    synthetic_frame(alias, width, height, sample)
}

#[cfg(test)]
mod tests {
    use pixelflow_core::{ClipFormat, FrameCount, FrameRate, Rational};

    use crate::{
        EXACT_GOLDEN_TOLERANCE, assert_plane_f32_near, assert_plane_u8_near, assert_plane_u16_near,
    };

    use super::{fixed_media, synthetic_f32_frame, synthetic_u8_frame, synthetic_u16_frame};

    #[test]
    fn fixed_media_uses_standard_test_defaults() {
        let media = fixed_media("gray8", 8, 6);

        assert!(matches!(
            media.format(),
            ClipFormat::Fixed(format) if format.name() == "gray8"
        ));
        assert_eq!(media.frame_count(), FrameCount::Finite(24));
        assert_eq!(
            media.frame_rate(),
            FrameRate::Cfr(Rational {
                numerator: 24_000,
                denominator: 1_001,
            })
        );
    }

    #[test]
    fn synthetic_u8_frame_builds_deterministic_rows() {
        let frame = synthetic_u8_frame("gray8", 3, 2, |_plane, x, y| {
            u8::try_from(x + y * 10).expect("fixture sample fits u8")
        })
        .expect("synthetic frame should build");

        assert_plane_u8_near(
            &frame,
            0,
            &[&[0, 1, 2], &[10, 11, 12]],
            EXACT_GOLDEN_TOLERANCE,
        );
    }

    #[test]
    fn synthetic_u16_frame_uses_u16_storage() {
        let frame = synthetic_u16_frame("gray10", 2, 1, |_plane, x, _y| {
            100 + u16::try_from(x).expect("fixture sample fits u16")
        })
        .expect("synthetic frame should build");

        assert_plane_u16_near(&frame, 0, &[&[100, 101]], EXACT_GOLDEN_TOLERANCE);
    }

    #[test]
    fn synthetic_f32_frame_uses_f32_storage() {
        let frame = synthetic_f32_frame("grayf32", 2, 1, |_plane, x, _y| match x {
            0 => 0.25,
            1 => 1.25,
            _ => unreachable!("fixture width is 2"),
        })
        .expect("synthetic frame should build");

        assert_plane_f32_near(&frame, 0, &[&[0.25, 1.25]], EXACT_GOLDEN_TOLERANCE);
    }
}