use super::{
util::{be_encoded_u16_buf, le_encoded_u16_buf},
*,
};
use std::{vec, vec::Vec};
fn p10_planes() -> (Vec<u16>, Vec<u16>, Vec<u16>) {
(vec![0u16; 16 * 8], vec![512u16; 8 * 4], vec![512u16; 8 * 4])
}
#[test]
fn yuv420p10_try_new_accepts_valid_tight() {
let (y, u, v) = p10_planes();
let f = Yuv420p10Frame::try_new(&y, &u, &v, 16, 8, 16, 8, 8).expect("valid");
assert_eq!(f.width(), 16);
assert_eq!(f.height(), 8);
assert_eq!(f.bits(), 10);
}
#[test]
fn yuv420p10_try_new_accepts_odd_height() {
let y = vec![0u16; 16 * 9];
let u = vec![512u16; 8 * 5];
let v = vec![512u16; 8 * 5];
let f = Yuv420p10Frame::try_new(&y, &u, &v, 16, 9, 16, 8, 8).expect("odd height valid");
assert_eq!(f.height(), 9);
}
#[test]
fn yuv420p10_try_new_rejects_odd_width() {
let (y, u, v) = p10_planes();
let e = Yuv420p10Frame::try_new(&y, &u, &v, 15, 8, 16, 8, 8).unwrap_err();
assert!(matches!(
e,
Yuv420pFrame16Error::WidthAlignment(WidthAlignment {
required: WidthAlignmentRequirement::Even,
..
})
));
}
#[test]
fn yuv420p10_try_new_rejects_zero_dim() {
let (y, u, v) = p10_planes();
let e = Yuv420p10Frame::try_new(&y, &u, &v, 0, 8, 16, 8, 8).unwrap_err();
assert!(matches!(e, Yuv420pFrame16Error::ZeroDimension(_)));
}
#[test]
fn yuv420p10_try_new_rejects_short_y_plane() {
let y = vec![0u16; 10];
let u = vec![512u16; 8 * 4];
let v = vec![512u16; 8 * 4];
let e = Yuv420p10Frame::try_new(&y, &u, &v, 16, 8, 16, 8, 8).unwrap_err();
assert!(matches!(e, Yuv420pFrame16Error::InsufficientYPlane(_)));
}
#[test]
fn yuv420p10_try_new_rejects_short_u_plane() {
let y = vec![0u16; 16 * 8];
let u = vec![512u16; 4];
let v = vec![512u16; 8 * 4];
let e = Yuv420p10Frame::try_new(&y, &u, &v, 16, 8, 16, 8, 8).unwrap_err();
assert!(matches!(e, Yuv420pFrame16Error::InsufficientUPlane(_)));
}
#[test]
fn yuv420p_frame16_try_new_rejects_unsupported_bits() {
let y = vec![0u16; 16 * 8];
let u = vec![128u16; 8 * 4];
let v = vec![128u16; 8 * 4];
let e = Yuv420pFrame16::<11>::try_new(&y, &u, &v, 16, 8, 16, 8, 8).unwrap_err();
assert!(matches!(e, Yuv420pFrame16Error::UnsupportedBits(_)));
let e15 = Yuv420pFrame16::<15>::try_new(&y, &u, &v, 16, 8, 16, 8, 8).unwrap_err();
assert!(matches!(e15, Yuv420pFrame16Error::UnsupportedBits(_)));
}
#[test]
fn yuv420p16_try_new_accepts_12_14_and_16() {
let y = vec![0u16; 16 * 8];
let u = vec![2048u16; 8 * 4];
let v = vec![2048u16; 8 * 4];
let f12 = Yuv420pFrame16::<12>::try_new(&y, &u, &v, 16, 8, 16, 8, 8).expect("12-bit valid");
assert_eq!(f12.bits(), 12);
let f14 = Yuv420pFrame16::<14>::try_new(&y, &u, &v, 16, 8, 16, 8, 8).expect("14-bit valid");
assert_eq!(f14.bits(), 14);
let f16 = Yuv420p16Frame::try_new(&y, &u, &v, 16, 8, 16, 8, 8).expect("16-bit valid");
assert_eq!(f16.bits(), 16);
}
#[test]
fn yuv420p16_try_new_checked_accepts_full_u16_range() {
let y = vec![65535u16; 16 * 8];
let u = vec![32768u16; 8 * 4];
let v = vec![32768u16; 8 * 4];
Yuv420p16Frame::try_new_checked(&y, &u, &v, 16, 8, 16, 8, 8)
.expect("every u16 value is in range at 16 bits");
}
#[test]
fn p016_try_new_accepts_16bit() {
let y = vec![0xFFFFu16; 16 * 8];
let uv = vec![0x8000u16; 16 * 4];
let f = P016Frame::try_new(&y, &uv, 16, 8, 16, 16).expect("P016 valid");
assert_eq!(f.bits(), 16);
}
#[test]
fn p016_try_new_checked_is_a_noop() {
let y = vec![0x1234u16; 16 * 8];
let uv = vec![0x5678u16; 16 * 4];
P016Frame::try_new_checked(&y, &uv, 16, 8, 16, 16)
.expect("every u16 passes the low-bits check at BITS == 16");
}
#[test]
fn pn_try_new_rejects_bits_other_than_10_12_16() {
let y = vec![0u16; 16 * 8];
let uv = vec![0u16; 16 * 4];
let e14 = PnFrame::<14>::try_new(&y, &uv, 16, 8, 16, 16).unwrap_err();
assert!(matches!(e14, PnFrameError::UnsupportedBits(_)));
let e11 = PnFrame::<11>::try_new(&y, &uv, 16, 8, 16, 16).unwrap_err();
assert!(matches!(e11, PnFrameError::UnsupportedBits(_)));
}
#[test]
#[should_panic(expected = "invalid Yuv420pFrame16")]
fn yuv420p10_new_panics_on_invalid() {
let y = vec![0u16; 10];
let u = vec![512u16; 8 * 4];
let v = vec![512u16; 8 * 4];
let _ = Yuv420p10Frame::new(&y, &u, &v, 16, 8, 16, 8, 8);
}
#[cfg(target_pointer_width = "32")]
#[test]
fn yuv420p10_try_new_rejects_geometry_overflow() {
let big: u32 = 0x1_0000;
let y: [u16; 0] = [];
let u: [u16; 0] = [];
let v: [u16; 0] = [];
let e = Yuv420p10Frame::try_new(&y, &u, &v, big, big, big, big / 2, big / 2).unwrap_err();
assert!(matches!(e, Yuv420pFrame16Error::GeometryOverflow(_)));
}
#[test]
fn yuv420p10_try_new_checked_accepts_in_range_samples() {
let (intended_y, intended_u, intended_v) = p10_planes();
let y = le_encoded_u16_buf(&intended_y);
let u = le_encoded_u16_buf(&intended_u);
let v = le_encoded_u16_buf(&intended_v);
let f = Yuv420p10Frame::try_new_checked(&y, &u, &v, 16, 8, 16, 8, 8).expect("valid");
assert_eq!(f.width(), 16);
assert_eq!(f.bits(), 10);
}
#[test]
fn yuv420p10_try_new_checked_rejects_y_high_bit_set() {
let mut intended_y = vec![0u16; 16 * 8];
intended_y[3 * 16 + 5] = 0x8000; let intended_uv = vec![512u16; 8 * 4];
let y = le_encoded_u16_buf(&intended_y);
let u = le_encoded_u16_buf(&intended_uv);
let v = le_encoded_u16_buf(&intended_uv);
let e = Yuv420p10Frame::try_new_checked(&y, &u, &v, 16, 8, 16, 8, 8).unwrap_err();
match e {
Yuv420pFrame16Error::SampleOutOfRange(p) => {
assert_eq!(p.plane(), Yuv420pFrame16Plane::Y);
assert_eq!(p.value(), 0x8000);
assert_eq!(p.max_valid(), 1023);
}
other => panic!("expected SampleOutOfRange, got {other:?}"),
}
}
#[test]
fn yuv420p10_try_new_checked_rejects_u_plane_sample() {
let intended_y = vec![0u16; 16 * 8];
let mut intended_u = vec![512u16; 8 * 4];
intended_u[2 * 8 + 3] = 1024; let intended_v = vec![512u16; 8 * 4];
let y = le_encoded_u16_buf(&intended_y);
let u = le_encoded_u16_buf(&intended_u);
let v = le_encoded_u16_buf(&intended_v);
let e = Yuv420p10Frame::try_new_checked(&y, &u, &v, 16, 8, 16, 8, 8).unwrap_err();
assert!(matches!(e, Yuv420pFrame16Error::SampleOutOfRange(_)));
}
#[test]
fn yuv420p10_try_new_checked_rejects_v_plane_sample() {
let intended_y = vec![0u16; 16 * 8];
let intended_u = vec![512u16; 8 * 4];
let mut intended_v = vec![512u16; 8 * 4];
intended_v[8 + 7] = 0xFFFF; let y = le_encoded_u16_buf(&intended_y);
let u = le_encoded_u16_buf(&intended_u);
let v = le_encoded_u16_buf(&intended_v);
let e = Yuv420p10Frame::try_new_checked(&y, &u, &v, 16, 8, 16, 8, 8).unwrap_err();
assert!(matches!(e, Yuv420pFrame16Error::SampleOutOfRange(_)));
}
#[test]
fn yuv420p10_try_new_checked_accepts_exact_max_sample() {
let mut intended_y = vec![0u16; 16 * 8];
intended_y[0] = 1023;
let intended_uv = vec![512u16; 8 * 4];
let y = le_encoded_u16_buf(&intended_y);
let u = le_encoded_u16_buf(&intended_uv);
let v = le_encoded_u16_buf(&intended_uv);
Yuv420p10Frame::try_new_checked(&y, &u, &v, 16, 8, 16, 8, 8).expect("1023 is in range");
}
#[test]
fn yuv420p10_try_new_checked_reports_geometry_errors_first() {
let y = vec![0u16; 10]; let u = vec![512u16; 8 * 4];
let v = vec![512u16; 8 * 4];
let e = Yuv420p10Frame::try_new_checked(&y, &u, &v, 16, 8, 16, 8, 8).unwrap_err();
assert!(matches!(e, Yuv420pFrame16Error::InsufficientYPlane(_)));
}
fn p010_planes() -> (Vec<u16>, Vec<u16>) {
(vec![0xFFC0u16; 16 * 8], vec![0x8000u16; 16 * 4])
}
#[test]
fn p010_try_new_accepts_valid_tight() {
let (y, uv) = p010_planes();
let f = P010Frame::try_new(&y, &uv, 16, 8, 16, 16).expect("valid");
assert_eq!(f.width(), 16);
assert_eq!(f.height(), 8);
assert_eq!(f.uv_stride(), 16);
}
#[test]
fn p010_try_new_accepts_odd_height() {
let y = vec![0u16; 640 * 481];
let uv = vec![0x8000u16; 640 * 241];
let f = P010Frame::try_new(&y, &uv, 640, 481, 640, 640).expect("odd height valid");
assert_eq!(f.height(), 481);
}
#[test]
fn p010_try_new_rejects_odd_width() {
let (y, uv) = p010_planes();
let e = P010Frame::try_new(&y, &uv, 15, 8, 16, 16).unwrap_err();
assert!(matches!(
e,
PnFrameError::WidthAlignment(WidthAlignment {
required: WidthAlignmentRequirement::Even,
..
})
));
}
#[test]
fn p010_try_new_rejects_zero_dim() {
let (y, uv) = p010_planes();
let e = P010Frame::try_new(&y, &uv, 0, 8, 16, 16).unwrap_err();
assert!(matches!(e, PnFrameError::ZeroDimension(_)));
}
#[test]
fn p010_try_new_rejects_y_stride_under_width() {
let (y, uv) = p010_planes();
let e = P010Frame::try_new(&y, &uv, 16, 8, 8, 16).unwrap_err();
assert!(matches!(e, PnFrameError::InsufficientYStride(_)));
}
#[test]
fn p010_try_new_rejects_uv_stride_under_width() {
let (y, uv) = p010_planes();
let e = P010Frame::try_new(&y, &uv, 16, 8, 16, 8).unwrap_err();
assert!(matches!(e, PnFrameError::InsufficientUvStride(_)));
}
#[test]
fn p010_try_new_rejects_odd_uv_stride() {
let y = vec![0u16; 16 * 8];
let uv = vec![0x8000u16; 17 * 4];
let e = P010Frame::try_new(&y, &uv, 16, 8, 16, 17).unwrap_err();
assert!(matches!(e, PnFrameError::UvStrideOdd(_)));
}
#[test]
fn p210_try_new_rejects_odd_uv_stride() {
let y = vec![0u16; 16 * 8];
let uv = vec![0x8000u16; 17 * 8];
let e = P210Frame::try_new(&y, &uv, 16, 8, 16, 17).unwrap_err();
assert!(matches!(e, PnFrameError::UvStrideOdd(_)));
}
#[test]
fn p410_try_new_rejects_odd_uv_stride() {
let y = vec![0u16; 16 * 8];
let uv = vec![0x8000u16; 33 * 8];
let e = P410Frame::try_new(&y, &uv, 16, 8, 16, 33).unwrap_err();
assert!(matches!(e, PnFrameError::UvStrideOdd(_)));
}
#[test]
fn p010_try_new_rejects_short_y_plane() {
let y = vec![0u16; 10];
let uv = vec![0x8000u16; 16 * 4];
let e = P010Frame::try_new(&y, &uv, 16, 8, 16, 16).unwrap_err();
assert!(matches!(e, PnFrameError::InsufficientYPlane(_)));
}
#[test]
fn p010_try_new_rejects_short_uv_plane() {
let y = vec![0u16; 16 * 8];
let uv = vec![0x8000u16; 8];
let e = P010Frame::try_new(&y, &uv, 16, 8, 16, 16).unwrap_err();
assert!(matches!(e, PnFrameError::InsufficientUvPlane(_)));
}
#[test]
#[should_panic(expected = "invalid PnFrame")]
fn p010_new_panics_on_invalid() {
let y = vec![0u16; 10];
let uv = vec![0x8000u16; 16 * 4];
let _ = P010Frame::new(&y, &uv, 16, 8, 16, 16);
}
#[cfg(target_pointer_width = "32")]
#[test]
fn p010_try_new_rejects_geometry_overflow() {
let big: u32 = 0x1_0000;
let y: [u16; 0] = [];
let uv: [u16; 0] = [];
let e = P010Frame::try_new(&y, &uv, big, big, big, big).unwrap_err();
assert!(matches!(e, PnFrameError::GeometryOverflow(_)));
}
#[test]
fn p010_try_new_checked_accepts_shifted_samples() {
let intended_y = vec![0xFFC0u16; 16 * 8];
let intended_uv = vec![0x8000u16; 16 * 4];
let y = le_encoded_u16_buf(&intended_y);
let uv = le_encoded_u16_buf(&intended_uv);
P010Frame::try_new_checked(&y, &uv, 16, 8, 16, 16).expect("shifted samples valid");
}
#[test]
fn p010_try_new_checked_rejects_y_low_bits_set() {
let mut intended_y = vec![0xFFC0u16; 16 * 8];
intended_y[3 * 16 + 5] = 0x03FF; let intended_uv = vec![0x8000u16; 16 * 4];
let y = le_encoded_u16_buf(&intended_y);
let uv = le_encoded_u16_buf(&intended_uv);
let e = P010Frame::try_new_checked(&y, &uv, 16, 8, 16, 16).unwrap_err();
match e {
PnFrameError::SampleLowBitsSet(p) => {
assert_eq!(p.plane(), P010FramePlane::Y);
assert_eq!(p.value(), 0x03FF);
}
other => panic!("expected SampleLowBitsSet, got {other:?}"),
}
}
#[test]
fn p010_try_new_checked_rejects_uv_plane_sample() {
let intended_y = vec![0xFFC0u16; 16 * 8];
let mut intended_uv = vec![0x8000u16; 16 * 4];
intended_uv[2 * 16 + 3] = 0x0001; let y = le_encoded_u16_buf(&intended_y);
let uv = le_encoded_u16_buf(&intended_uv);
let e = P010Frame::try_new_checked(&y, &uv, 16, 8, 16, 16).unwrap_err();
assert!(matches!(e, PnFrameError::SampleLowBitsSet(_)));
}
#[test]
fn p010_try_new_checked_reports_geometry_errors_first() {
let y = vec![0u16; 10]; let uv = vec![0x8000u16; 16 * 4];
let e = P010Frame::try_new_checked(&y, &uv, 16, 8, 16, 16).unwrap_err();
assert!(matches!(e, PnFrameError::InsufficientYPlane(_)));
}
#[test]
fn p010_try_new_checked_accepts_ambiguous_yuv420p10le_samples() {
let intended_y = vec![0x0040u16; 16 * 8]; let intended_uv = vec![0x0200u16; 16 * 4]; let y = le_encoded_u16_buf(&intended_y);
let uv = le_encoded_u16_buf(&intended_uv);
let f = P010Frame::try_new_checked(&y, &uv, 16, 8, 16, 16)
.expect("known limitation: low-6-bits-zero check cannot tell yuv420p10le from P010");
assert_eq!(f.width(), 16);
}
#[test]
fn p012_try_new_checked_accepts_shifted_samples() {
let y = vec![(2048u16) << 4; 16 * 8]; let uv = vec![(2048u16) << 4; 16 * 4];
P012Frame::try_new_checked(&y, &uv, 16, 8, 16, 16).expect("shifted samples valid");
}
#[test]
fn p012_try_new_checked_rejects_low_bits_set() {
let mut intended_y = vec![(2048u16) << 4; 16 * 8];
intended_y[3 * 16 + 5] = 0x0ABC; let intended_uv = vec![(2048u16) << 4; 16 * 4];
let y = le_encoded_u16_buf(&intended_y);
let uv = le_encoded_u16_buf(&intended_uv);
let e = P012Frame::try_new_checked(&y, &uv, 16, 8, 16, 16).unwrap_err();
match e {
PnFrameError::SampleLowBitsSet(p) => {
assert_eq!(p.plane(), PnFramePlane::Y);
assert_eq!(p.value(), 0x0ABC);
assert_eq!(p.low_bits(), 4);
}
other => panic!("expected SampleLowBitsSet, got {other:?}"),
}
}
#[test]
fn p012_try_new_checked_accepts_low_packed_flat_content_by_design() {
let intended_y = vec![0x0100u16; 16 * 8]; let intended_uv = vec![0x0800u16; 16 * 4]; let y = le_encoded_u16_buf(&intended_y);
let uv = le_encoded_u16_buf(&intended_uv);
let f = P012Frame::try_new_checked(&y, &uv, 16, 8, 16, 16)
.expect("known limitation: 4-low-bits-zero check cannot tell yuv420p12le from P012");
assert_eq!(f.width(), 16);
}
#[test]
fn yuv420p10_try_new_checked_accepts_le_encoded_buffer_on_any_host() {
let intended_y = vec![1023u16; 16 * 8];
let intended_uv = vec![512u16; 8 * 4];
let y = le_encoded_u16_buf(&intended_y);
let u = le_encoded_u16_buf(&intended_uv);
let v = le_encoded_u16_buf(&intended_uv);
Yuv420p10Frame::try_new_checked(&y, &u, &v, 16, 8, 16, 8, 8)
.expect("LE-encoded valid yuv420p10le must be accepted on both LE and BE hosts");
}
#[test]
fn yuv420p10_try_new_checked_rejects_le_encoded_out_of_range_on_any_host() {
let intended_y = vec![0u16; 16 * 8];
let mut intended_u = vec![512u16; 8 * 4];
intended_u[2 * 8 + 3] = 1024;
let intended_v = vec![512u16; 8 * 4];
let y = le_encoded_u16_buf(&intended_y);
let u = le_encoded_u16_buf(&intended_u);
let v = le_encoded_u16_buf(&intended_v);
let e = Yuv420p10Frame::try_new_checked(&y, &u, &v, 16, 8, 16, 8, 8).unwrap_err();
assert!(matches!(e, Yuv420pFrame16Error::SampleOutOfRange(_)));
}
#[test]
fn p010_try_new_checked_accepts_le_encoded_buffer_on_any_host() {
let intended_y = vec![0xFFC0u16; 16 * 8];
let intended_uv = vec![0x8000u16; 16 * 4];
let y = le_encoded_u16_buf(&intended_y);
let uv = le_encoded_u16_buf(&intended_uv);
P010Frame::try_new_checked(&y, &uv, 16, 8, 16, 16)
.expect("LE-encoded valid P010 must be accepted on both LE and BE hosts");
}
#[test]
fn p010_try_new_checked_rejects_le_encoded_low_bits_on_any_host() {
let mut intended_y = vec![0xFFC0u16; 16 * 8];
intended_y[3 * 16 + 5] = 0x03FF;
let intended_uv = vec![0x8000u16; 16 * 4];
let y = le_encoded_u16_buf(&intended_y);
let uv = le_encoded_u16_buf(&intended_uv);
let e = P010Frame::try_new_checked(&y, &uv, 16, 8, 16, 16).unwrap_err();
assert!(matches!(e, PnFrameError::SampleLowBitsSet(_)));
}
#[test]
fn p012_try_new_checked_accepts_le_encoded_buffer_on_any_host() {
let intended_y = vec![(2048u16) << 4; 16 * 8];
let intended_uv = vec![(2048u16) << 4; 16 * 4];
let y = le_encoded_u16_buf(&intended_y);
let uv = le_encoded_u16_buf(&intended_uv);
P012Frame::try_new_checked(&y, &uv, 16, 8, 16, 16)
.expect("LE-encoded valid P012 must be accepted on both LE and BE hosts");
}
#[test]
fn p010_be_try_new_checked_accepts_be_encoded_buffer_on_any_host() {
let intended_y = vec![0xFFC0u16; 16 * 8];
let intended_uv = vec![0x8000u16; 16 * 4];
let y = be_encoded_u16_buf(&intended_y);
let uv = be_encoded_u16_buf(&intended_uv);
P010BeFrame::try_new_checked(&y, &uv, 16, 8, 16, 16)
.expect("BE-encoded valid P010 must be accepted on both LE and BE hosts");
}
#[test]
fn p010_be_try_new_checked_rejects_be_encoded_low_bits_set() {
let mut intended_y = vec![0xFFC0u16; 16 * 8];
intended_y[3 * 16 + 5] = 0xFFCF;
let intended_uv = vec![0x8000u16; 16 * 4];
let y = be_encoded_u16_buf(&intended_y);
let uv = be_encoded_u16_buf(&intended_uv);
let e = P010BeFrame::try_new_checked(&y, &uv, 16, 8, 16, 16).unwrap_err();
assert!(matches!(e, PnFrameError::SampleLowBitsSet(_)));
}
#[test]
fn yuv420p10_be_try_new_checked_accepts_be_encoded_buffer_on_any_host() {
let intended_y = vec![1023u16; 16 * 8];
let intended_uv = vec![512u16; 8 * 4];
let y = be_encoded_u16_buf(&intended_y);
let u = be_encoded_u16_buf(&intended_uv);
let v = be_encoded_u16_buf(&intended_uv);
Yuv420p10BeFrame::try_new_checked(&y, &u, &v, 16, 8, 16, 8, 8)
.expect("BE-encoded valid yuv420p10be must be accepted on both LE and BE hosts");
}
#[test]
fn yuv420p10_be_try_new_checked_rejects_be_encoded_out_of_range() {
let intended_y = vec![0u16; 16 * 8];
let mut intended_u = vec![512u16; 8 * 4];
intended_u[2 * 8 + 3] = 1024;
let intended_v = vec![512u16; 8 * 4];
let y = be_encoded_u16_buf(&intended_y);
let u = be_encoded_u16_buf(&intended_u);
let v = be_encoded_u16_buf(&intended_v);
let e = Yuv420p10BeFrame::try_new_checked(&y, &u, &v, 16, 8, 16, 8, 8).unwrap_err();
assert!(matches!(e, Yuv420pFrame16Error::SampleOutOfRange(_)));
}