use pixelflow_core::{
AllocatorConfig, ClipMedia, Frame, FrameBuilder, MetadataSchema, Rational, Result, Sample,
resolve_format_alias,
};
#[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())
}
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)
}
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)
}
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);
}
}