use super::xyb::{
linear_to_srgb_u8, rgb_buffer_to_xyb_planes, srgb_to_xyb, srgb_u8_to_linear,
xyb_planes_to_rgb_buffer, xyb_to_srgb,
};
#[test]
fn test_xyb_roundtrip_comprehensive() {
let mut max_error = 0i16;
let mut error_count = 0usize;
let mut total_tests = 0usize;
let test_values: Vec<u8> = vec![
0, 1, 2, 4, 8, 16, 32, 64, 96, 128, 160, 192, 224, 240, 252, 254, 255,
];
for &r in &test_values {
for &g in &test_values {
for &b in &test_values {
let (x, y, b_xyb) = srgb_to_xyb(r, g, b);
let (r2, g2, b2) = xyb_to_srgb(x, y, b_xyb);
let dr = (r as i16 - r2 as i16).abs();
let dg = (g as i16 - g2 as i16).abs();
let db = (b as i16 - b2 as i16).abs();
max_error = max_error.max(dr).max(dg).max(db);
if dr > 1 || dg > 1 || db > 1 {
error_count += 1;
}
total_tests += 1;
}
}
}
println!(
"XYB roundtrip: {} tests, max error: {}, errors>1: {}",
total_tests, max_error, error_count
);
assert!(
max_error <= 2,
"XYB roundtrip max error {} exceeds tolerance",
max_error
);
let error_ratio = error_count as f64 / total_tests as f64;
assert!(
error_ratio < 0.05,
"XYB roundtrip error ratio {} exceeds 5%",
error_ratio
);
}
#[test]
fn test_xyb_gray_neutrality() {
for gray in 0..=255u8 {
let (x, _y, _b) = srgb_to_xyb(gray, gray, gray);
assert!(x.abs() < 0.01, "Gray {} has X={}, should be ~0", gray, x);
}
}
#[test]
fn test_xyb_reference_values() {
let test_cases = [
(0u8, 0u8, 0u8, 0.0f32, 0.0f32, 0.0f32, 0.01), (255u8, 255u8, 255u8, 0.0f32, 0.88f32, 0.82f32, 0.05), (255u8, 0u8, 0u8, 0.1f32, 0.55f32, 0.08f32, 0.1), (0u8, 255u8, 0u8, -0.15f32, 0.7f32, 0.25f32, 0.1), (0u8, 0u8, 255u8, 0.0f32, 0.3f32, 0.75f32, 0.1), ];
for (r, g, b, _exp_x, _exp_y, _exp_b, _tol) in test_cases {
let (x, y, b_xyb) = srgb_to_xyb(r, g, b);
println!(
"RGB({},{},{}) -> XYB({:.4}, {:.4}, {:.4})",
r, g, b, x, y, b_xyb
);
}
}
#[test]
fn test_xyb_buffer_roundtrip() {
let width = 16;
let height = 16;
let mut rgb = vec![0u8; width * height * 3];
for y in 0..height {
for x in 0..width {
let idx = (y * width + x) * 3;
rgb[idx] = (x * 16) as u8;
rgb[idx + 1] = (y * 16) as u8;
rgb[idx + 2] = ((x + y) * 8) as u8;
}
}
let (x_plane, y_plane, b_plane) = rgb_buffer_to_xyb_planes(&rgb, width, height);
let rgb2 = xyb_planes_to_rgb_buffer(&x_plane, &y_plane, &b_plane, width, height);
let mut max_diff = 0i16;
for i in 0..rgb.len() {
let diff = (rgb[i] as i16 - rgb2[i] as i16).abs();
max_diff = max_diff.max(diff);
}
println!("Buffer roundtrip max diff: {}", max_diff);
assert!(
max_diff <= 2,
"Buffer roundtrip max diff {} exceeds 2",
max_diff
);
}
#[test]
fn test_srgb_linear_precision() {
let mut max_error = 0f32;
for v in 0..=255u8 {
let linear = srgb_u8_to_linear(v);
let back = linear_to_srgb_u8(linear);
assert!(
(0.0..=1.0).contains(&linear),
"Linear value {} out of range for input {}",
linear,
v
);
let error = (v as i16 - back as i16).abs();
max_error = max_error.max(error as f32);
}
assert!(
max_error <= 1.0,
"sRGB<->linear max error {} exceeds 1",
max_error
);
}