QA: frame scores refuse NaN samples and mismatched buffers (#427 follow-up)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
This commit is contained in:
Claude
2026-10-10 12:53:09 +00:00
parent 4578f9090c
commit c5af482bce
2 changed files with 12 additions and 2 deletions
+11 -1
View File
@@ -2,17 +2,21 @@
use effectcraft_raster::Image;
/// How far a rendered frame is from its reference.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FrameScore {
/// Pixels compared (the frames' width × height).
pub compared_pixels: usize,
/// Mean absolute difference over every channel sample.
pub mean_absolute_error: f64,
/// Largest absolute difference of any channel sample.
pub max_error: f32,
}
/// Compare two premultiplied rendered frames. A size mismatch is reported as an error instead of
/// silently producing a misleading score.
pub fn compare_frames(actual: &Image, reference: &Image) -> Result<FrameScore, String> {
if actual.width != reference.width || actual.height != reference.height {
if actual.width != reference.width || actual.height != reference.height || actual.data.len() != reference.data.len() {
return Err(format!("frame size mismatch: {}x{} vs {}x{}", actual.width, actual.height, reference.width, reference.height));
}
let mut sum = 0.0f64;
@@ -20,6 +24,10 @@ pub fn compare_frames(actual: &Image, reference: &Image) -> Result<FrameScore, S
for (a, b) in actual.data.iter().zip(&reference.data) {
for (&x, &y) in a.iter().zip(b) {
let error = (x - y).abs();
// A NaN would make the mean NaN, which a `mean > tolerance` check reads as a pass.
if !error.is_finite() {
return Err("frame has a non-finite sample".into());
}
sum += f64::from(error);
max = max.max(error);
}
@@ -43,5 +51,7 @@ mod tests {
assert!((score.mean_absolute_error - 0.0625).abs() < f64::EPSILON);
assert_eq!(score.max_error, 0.5);
assert!(compare_frames(&actual, &Image::new(1, 1)).is_err());
actual.data[0][1] = f32::NAN;
assert!(compare_frames(&actual, &reference).is_err(), "NaN is an error, not a pass");
}
}
+1 -1
View File
@@ -21,12 +21,12 @@ mod color2;
mod color3;
mod color_fx;
pub mod controls;
pub mod fidelity;
mod distort;
mod distort2;
mod distort3;
pub mod distort4;
pub mod face_track;
pub mod fidelity;
mod generate;
mod generate2;
mod generate3;