use pixelflow_core::Frame;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct GoldenTolerance {
pub u8_abs: u8,
pub u16_abs: u16,
pub f32_abs: f32,
}
pub const EXACT_GOLDEN_TOLERANCE: GoldenTolerance = GoldenTolerance {
u8_abs: 0,
u16_abs: 0,
f32_abs: 0.0,
};
pub fn assert_plane_u8_near(
frame: &Frame,
plane_index: usize,
expected: &[&[u8]],
tolerance: GoldenTolerance,
) {
let plane = frame
.plane::<u8>(plane_index)
.expect("frame plane should have u8 storage");
assert_eq!(plane.height(), expected.len(), "plane height mismatch");
for (y, expected_row) in expected.iter().enumerate() {
let row = plane.row(y).expect("row should exist");
assert_eq!(
row.len(),
expected_row.len(),
"plane row width mismatch at row {y}"
);
for (x, (&actual, &want)) in row.iter().zip(expected_row.iter()).enumerate() {
let delta = actual.abs_diff(want);
assert!(
delta <= tolerance.u8_abs,
"sample mismatch at plane {plane_index} ({x}, {y}): expected {want}, got {actual}, tolerance {}",
tolerance.u8_abs
);
}
}
}
pub fn assert_plane_u16_near(
frame: &Frame,
plane_index: usize,
expected: &[&[u16]],
tolerance: GoldenTolerance,
) {
let plane = frame
.plane::<u16>(plane_index)
.expect("frame plane should have u16 storage");
assert_eq!(plane.height(), expected.len(), "plane height mismatch");
for (y, expected_row) in expected.iter().enumerate() {
let row = plane.row(y).expect("row should exist");
assert_eq!(
row.len(),
expected_row.len(),
"plane row width mismatch at row {y}"
);
for (x, (&actual, &want)) in row.iter().zip(expected_row.iter()).enumerate() {
let delta = actual.abs_diff(want);
assert!(
delta <= tolerance.u16_abs,
"sample mismatch at plane {plane_index} ({x}, {y}): expected {want}, got {actual}, tolerance {}",
tolerance.u16_abs
);
}
}
}
pub fn assert_plane_f32_near(
frame: &Frame,
plane_index: usize,
expected: &[&[f32]],
tolerance: GoldenTolerance,
) {
let plane = frame
.plane::<f32>(plane_index)
.expect("frame plane should have f32 storage");
assert_eq!(plane.height(), expected.len(), "plane height mismatch");
for (y, expected_row) in expected.iter().enumerate() {
let row = plane.row(y).expect("row should exist");
assert_eq!(
row.len(),
expected_row.len(),
"plane row width mismatch at row {y}"
);
for (x, (&actual, &want)) in row.iter().zip(expected_row.iter()).enumerate() {
let delta = (actual - want).abs();
assert!(
delta <= tolerance.f32_abs,
"sample mismatch at plane {plane_index} ({x}, {y}): expected {want}, got {actual}, tolerance {}",
tolerance.f32_abs
);
}
}
}
pub fn assert_frame_u8_near(
frame: &Frame,
expected_planes: &[&[&[u8]]],
tolerance: GoldenTolerance,
) {
assert_eq!(
frame.format().planes().len(),
expected_planes.len(),
"plane count mismatch"
);
for (plane_index, expected) in expected_planes.iter().enumerate() {
assert_plane_u8_near(frame, plane_index, expected, tolerance);
}
}
pub fn assert_frame_u16_near(
frame: &Frame,
expected_planes: &[&[&[u16]]],
tolerance: GoldenTolerance,
) {
assert_eq!(
frame.format().planes().len(),
expected_planes.len(),
"plane count mismatch"
);
for (plane_index, expected) in expected_planes.iter().enumerate() {
assert_plane_u16_near(frame, plane_index, expected, tolerance);
}
}
pub fn assert_frame_f32_near(
frame: &Frame,
expected_planes: &[&[&[f32]]],
tolerance: GoldenTolerance,
) {
assert_eq!(
frame.format().planes().len(),
expected_planes.len(),
"plane count mismatch"
);
for (plane_index, expected) in expected_planes.iter().enumerate() {
assert_plane_f32_near(frame, plane_index, expected, tolerance);
}
}
#[cfg(test)]
mod tests {
use crate::{synthetic_f32_frame, synthetic_u8_frame, synthetic_u16_frame};
use super::{
EXACT_GOLDEN_TOLERANCE, GoldenTolerance, assert_frame_f32_near, assert_frame_u8_near,
assert_frame_u16_near, assert_plane_u8_near,
};
#[test]
fn exact_golden_tolerance_is_zero_for_all_storage_types() {
assert_eq!(EXACT_GOLDEN_TOLERANCE.u8_abs, 0);
assert_eq!(EXACT_GOLDEN_TOLERANCE.u16_abs, 0);
assert_eq!(EXACT_GOLDEN_TOLERANCE.f32_abs, 0.0);
}
#[test]
fn plane_u8_assertion_accepts_declared_tolerance() {
let frame = synthetic_u8_frame("gray8", 2, 1, |_plane, x, _y| {
u8::try_from(x).expect("fixture sample fits u8")
})
.expect("synthetic frame should build");
assert_plane_u8_near(
&frame,
0,
&[&[1, 2]],
GoldenTolerance {
u8_abs: 1,
u16_abs: 0,
f32_abs: 0.0,
},
);
}
#[test]
fn frame_u8_assertion_checks_all_planes() {
let frame = synthetic_u8_frame("yuv444p8", 2, 1, |plane, x, _y| match plane {
0 => match x {
0 => 1,
1 => 2,
_ => unreachable!("fixture width is 2"),
},
1 => match x {
0 => 3,
1 => 4,
_ => unreachable!("fixture width is 2"),
},
2 => match x {
0 => 5,
1 => 6,
_ => unreachable!("fixture width is 2"),
},
_ => unreachable!("yuv444p8 has exactly 3 planes"),
})
.expect("synthetic frame should build");
let p0 = [&[1_u8, 2][..]];
let p1 = [&[3_u8, 4][..]];
let p2 = [&[5_u8, 6][..]];
let expected = [&p0[..], &p1[..], &p2[..]];
assert_frame_u8_near(&frame, &expected, EXACT_GOLDEN_TOLERANCE);
}
#[test]
fn frame_u16_assertion_checks_all_planes() {
let frame = synthetic_u16_frame("gray10", 2, 1, |_plane, x, _y| match x {
0 => 100,
1 => 101,
_ => unreachable!("fixture width is 2"),
})
.expect("synthetic frame should build");
let p0 = [&[100_u16, 101][..]];
let expected = [&p0[..]];
assert_frame_u16_near(&frame, &expected, EXACT_GOLDEN_TOLERANCE);
}
#[test]
fn frame_f32_assertion_checks_all_planes() {
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");
let p0 = [&[0.25_f32, 1.25][..]];
let expected = [&p0[..]];
assert_frame_f32_near(&frame, &expected, EXACT_GOLDEN_TOLERANCE);
}
}