#[allow(unused_imports)]
pub use super::*;
#[cfg(test)]
mod frame_consumer_contract {
use super::*;
#[test]
fn the_preview_id_is_reserved_and_zero_sizes_are_invalid() {
assert_eq!(FrameConsumer::PREVIEW_ID, 0);
assert!(
!FrameConsumer::new(0, 100, 100).is_valid(),
"id 0 is the preview"
);
assert!(!FrameConsumer::new(7, 0, 100).is_valid());
assert!(!FrameConsumer::new(7, 100, 0).is_valid());
assert!(FrameConsumer::new(7, 500, 200).is_valid());
assert_eq!(FrameConsumer::default(), FrameConsumer::new(0, 0, 0));
}
#[test]
fn consumers_round_trip_through_the_ffi_vec() {
let bob = FrameConsumer::new(7, 500, 200);
let rec = FrameConsumer::new(8, 1280, 720);
let v: FrameConsumerVec = alloc::vec![bob, rec].into();
assert_eq!(v.as_ref(), &[bob, rec]);
let cloned = v.clone();
assert_eq!(cloned, v);
let cut = ConsumerFrame::new(
bob,
VideoFrame::new(500, 200, U8Vec::from_vec(alloc::vec![0; 500 * 200 * 4])),
);
assert_eq!(cut.consumer.id, 7);
assert_eq!(cut.frame.bytes.as_ref().len(), 500 * 200 * 4);
}
}
#[cfg(test)]
mod autotest_generated {
use alloc::{string::String, vec, vec::Vec};
use super::*;
fn u8v(bytes: Vec<u8>) -> U8Vec {
U8Vec::from_vec(bytes)
}
fn frame(width: u32, height: u32, bytes: Vec<u8>) -> VideoFrame {
VideoFrame::new(width, height, u8v(bytes))
}
fn source_bytes(source: &VideoSource) -> &U8Vec {
match source {
VideoSource::Bytes(b) => b,
other => panic!("expected VideoSource::Bytes, got {other:?}"),
}
}
fn declared_len(width: u32, height: u32) -> u128 {
u128::from(width) * u128::from(height) * 4
}
#[test]
fn config_new_fields_match_args() {
let url = Url::from_parts("https", "example.com", 443, "/movie.mp4");
let c = VideoConfig::new(VideoSource::Url(url.clone()));
assert_eq!(c.source, VideoSource::Url(url));
assert!((c.timestamp - 0.0).abs() < f32::EPSILON);
assert!(c.autoplay);
assert!(!c.looping);
assert_eq!(c.output_format, RawImageFormat::BGRA8);
}
#[test]
fn config_new_only_overrides_source() {
let d = VideoConfig::default();
for source in [
VideoSource::Url(Url::from_parts("http", "a.tld", 8080, "/v")),
VideoSource::File(AzString::from_const_str("/tmp/clip.mp4")),
VideoSource::Bytes(u8v(vec![0xFF; 8])),
] {
let c = VideoConfig::new(source.clone());
assert_eq!(c.source, source, "source must round-trip unchanged");
assert_eq!(c.timestamp.to_bits(), d.timestamp.to_bits());
assert_eq!(c.autoplay, d.autoplay);
assert_eq!(c.looping, d.looping);
assert_eq!(c.output_format, d.output_format);
}
}
#[test]
fn config_new_with_default_source_equals_default() {
assert_eq!(
VideoConfig::new(VideoSource::default()),
VideoConfig::default()
);
assert_eq!(VideoSource::default(), VideoSource::Url(Url::default()));
}
#[test]
fn config_new_unicode_file_path_roundtrip() {
let path = String::from("/tmp/vídeos/𝔘𝔫𝔦/影片 🎬/مقطع/e\u{0301}.mp4");
let c = VideoConfig::new(VideoSource::File(AzString::from(path.clone())));
match &c.source {
VideoSource::File(s) => {
assert_eq!(s.as_str(), path.as_str());
assert_eq!(s.as_str().len(), path.len(), "byte length preserved");
assert_eq!(s.as_str().chars().count(), path.chars().count());
}
other => panic!("expected File, got {other:?}"),
}
}
#[test]
fn config_new_file_path_with_interior_nul_preserved() {
let path = String::from("/tmp/a\0b\r\n\t.mp4");
let c = VideoConfig::new(VideoSource::File(AzString::from(path.clone())));
match &c.source {
VideoSource::File(s) => {
assert_eq!(s.as_str(), path.as_str());
assert_eq!(s.as_str().len(), 15);
assert!(s.as_str().contains('\0'));
}
other => panic!("expected File, got {other:?}"),
}
}
#[test]
fn config_new_empty_sources_no_panic() {
let empty_file = VideoConfig::new(VideoSource::File(AzString::from(String::new())));
match &empty_file.source {
VideoSource::File(s) => assert_eq!(s.as_str(), ""),
other => panic!("expected File, got {other:?}"),
}
let empty_bytes = VideoConfig::new(VideoSource::Bytes(u8v(Vec::new())));
let b = source_bytes(&empty_bytes.source);
assert!(b.is_empty());
assert_eq!(b.len(), 0);
assert_eq!(b.as_ref(), &[] as &[u8]);
}
#[test]
fn config_new_huge_bytes_source_preserved() {
const N: usize = 1 << 20;
let data: Vec<u8> = (0..N).map(|i| (i % 251) as u8).collect();
let c = VideoConfig::new(VideoSource::Bytes(u8v(data.clone())));
let b = source_bytes(&c.source);
let last = ((N - 1) % 251) as u8;
assert_eq!(b.len(), N);
assert_eq!(b.as_ref(), data.as_slice());
assert_eq!(b.get(0), Some(&0));
assert_eq!(b.get(N - 1), Some(&last));
assert_eq!(b.get(N), None, "one past the end must be None, not UB");
}
#[test]
fn config_clone_of_bytes_is_deep_and_survives_original_drop() {
let original = VideoConfig::new(VideoSource::Bytes(u8v(vec![1, 2, 3, 4, 5])));
let original_ptr = source_bytes(&original.source).as_ptr();
let cloned = original.clone();
let cloned_ptr = source_bytes(&cloned.source).as_ptr();
assert_ne!(
original_ptr, cloned_ptr,
"clone must not alias the original buffer"
);
drop(original);
assert_eq!(source_bytes(&cloned.source).as_ref(), &[1, 2, 3, 4, 5]);
}
#[test]
fn config_source_variants_are_distinct() {
let text = "https://example.com/v.mp4";
let as_file = VideoConfig::new(VideoSource::File(AzString::from_const_str(text)));
let as_url = VideoConfig::new(VideoSource::Url(Url::from_parts(
"https",
"example.com",
443,
"/v.mp4",
)));
assert_ne!(as_file, as_url);
assert_ne!(as_file.source, as_url.source);
assert_eq!(as_url.source, as_url.source.clone());
}
#[test]
fn config_extreme_timestamps_stored_verbatim() {
let base = VideoConfig::new(VideoSource::default());
for t in [
f32::INFINITY,
f32::NEG_INFINITY,
f32::MAX,
f32::MIN,
f32::MIN_POSITIVE,
f32::MIN_POSITIVE / 2.0, -1.0,
1e30,
] {
let c = VideoConfig {
timestamp: t,
..base.clone()
};
assert_eq!(
c.timestamp.to_bits(),
t.to_bits(),
"timestamp {t} was altered"
);
assert_eq!(c, c.clone(), "non-NaN config must be self-equal");
}
}
#[test]
fn config_nan_timestamp_breaks_reflexive_equality() {
let nan_a = VideoConfig {
timestamp: f32::NAN,
..VideoConfig::new(VideoSource::default())
};
let nan_b = nan_a.clone();
assert!(nan_a.timestamp.is_nan());
assert_ne!(
nan_a, nan_b,
"NaN timestamp: derived PartialEq is not reflexive"
);
let fresh = VideoConfig::new(VideoSource::default());
assert!(!fresh.timestamp.is_nan());
assert_eq!(fresh, fresh.clone());
}
#[test]
fn config_negative_zero_timestamp_equals_default() {
let fresh = VideoConfig::new(VideoSource::default());
let neg_zero = VideoConfig {
timestamp: -0.0,
..VideoConfig::new(VideoSource::default())
};
assert!(neg_zero.timestamp.is_sign_negative());
assert_ne!(neg_zero.timestamp.to_bits(), fresh.timestamp.to_bits());
assert_eq!(neg_zero, fresh, "IEEE: -0.0 == +0.0");
}
#[test]
fn frame_new_fields_match_args() {
let pixels: Vec<u8> = (0..(3 * 2 * 4)).map(|i| i as u8).collect();
let f = frame(3, 2, pixels.clone());
assert_eq!(f.width, 3);
assert_eq!(f.height, 2);
assert_eq!(f.bytes.as_ref(), pixels.as_slice());
assert_eq!(u128::from(f.bytes.len() as u64), declared_len(3, 2));
}
#[test]
fn frame_bytes_roundtrip_all_byte_values() {
let pixels: Vec<u8> = (0..=255u8).collect(); let f = frame(8, 8, pixels.clone());
assert_eq!(f.bytes.as_ref(), pixels.as_slice());
assert_eq!(f.bytes.len(), 256);
assert_eq!(u128::from(f.bytes.len() as u64), declared_len(8, 8));
assert_eq!(f.bytes.get(0), Some(&0));
assert_eq!(f.bytes.get(255), Some(&255));
assert_eq!(f.bytes.get(256), None);
assert!(f.bytes.iter().copied().eq(pixels.iter().copied()));
}
#[test]
fn frame_new_zero_dimensions_empty_bytes() {
let f = frame(0, 0, Vec::new());
assert_eq!(f.width, 0);
assert_eq!(f.height, 0);
assert!(f.bytes.is_empty());
assert_eq!(f.bytes.as_ref(), &[] as &[u8]);
assert_eq!(declared_len(0, 0), 0);
}
#[test]
fn frame_new_degenerate_strips() {
let wide = frame(1920, 0, Vec::new());
assert_eq!((wide.width, wide.height), (1920, 0));
assert!(wide.bytes.is_empty());
let tall = frame(0, 1080, Vec::new());
assert_eq!((tall.width, tall.height), (0, 1080));
assert!(tall.bytes.is_empty());
}
#[test]
fn frame_new_max_dimensions_no_panic_and_size_math_overflows() {
let f = VideoFrame::new(u32::MAX, u32::MAX, U8Vec::from_vec(Vec::new()));
assert_eq!(f.width, u32::MAX);
assert_eq!(f.height, u32::MAX);
assert!(f.bytes.is_empty(), "new does no allocation of its own");
assert_eq!(u32::MAX.checked_mul(u32::MAX), None);
assert_eq!(
u64::from(u32::MAX)
.checked_mul(u64::from(u32::MAX))
.and_then(|px| px.checked_mul(4)),
None,
"even u64 overflows: callers must size-check before allocating"
);
assert_eq!(
declared_len(u32::MAX, u32::MAX),
4 * (u128::from(u32::MAX)).pow(2)
);
}
#[test]
fn frame_new_u32_pixel_size_overflow_boundary() {
let f = VideoFrame::new(32_768, 32_768, U8Vec::from_vec(Vec::new()));
assert_eq!((f.width, f.height), (32_768, 32_768));
assert_eq!(
32_768u32
.checked_mul(32_768)
.and_then(|px| px.checked_mul(4)),
None,
"2^30 px * 4 == 2^32 overflows u32"
);
assert_eq!(declared_len(32_768, 32_768), 1u128 << 32);
assert_eq!(
32_767u32
.checked_mul(32_768)
.and_then(|px| px.checked_mul(4)),
Some(4_294_836_224)
);
}
#[test]
fn frame_new_does_not_validate_buffer_length() {
let short = frame(1, 1, vec![0xAA, 0xBB, 0xCC]); assert_eq!(short.bytes.len(), 3);
assert_ne!(u128::from(short.bytes.len() as u64), declared_len(1, 1));
let long = frame(1, 1, vec![0; 64]); assert_eq!(long.bytes.len(), 64);
let lying = frame(3840, 2160, Vec::new());
assert!(lying.bytes.is_empty());
assert_eq!(declared_len(3840, 2160), 33_177_600);
}
#[test]
fn frame_new_is_const_evaluable() {
const F: VideoFrame = VideoFrame::new(1, 1, U8Vec::from_const_slice(&[1, 2, 3, 4]));
assert_eq!(F.width, 1);
assert_eq!(F.height, 1);
assert_eq!(F.bytes.as_ref(), &[1, 2, 3, 4]);
assert_eq!(u128::from(F.bytes.len() as u64), declared_len(1, 1));
}
#[test]
fn frame_equality_is_fieldwise() {
let base = frame(2, 1, vec![1, 2, 3, 4, 5, 6, 7, 8]);
assert_eq!(base, frame(2, 1, vec![1, 2, 3, 4, 5, 6, 7, 8]));
assert_ne!(
base,
frame(1, 2, vec![1, 2, 3, 4, 5, 6, 7, 8]),
"w/h swap differs"
);
assert_ne!(
base,
frame(2, 1, vec![1, 2, 3, 4, 5, 6, 7, 9]),
"last byte differs"
);
assert_ne!(
base,
frame(2, 1, vec![1, 2, 3, 4]),
"truncated buffer differs"
);
}
#[test]
fn frame_clone_is_deep_and_survives_original_drop() {
let original = frame(2, 2, (0..16).collect());
let original_ptr = original.bytes.as_ptr();
let cloned = original.clone();
assert_ne!(original_ptr, cloned.bytes.as_ptr(), "clone must not alias");
assert_eq!(cloned, original);
drop(original);
assert_eq!(
cloned.bytes.as_ref(),
(0..16u8).collect::<Vec<_>>().as_slice()
);
assert_eq!(cloned.width, 2);
assert_eq!(cloned.height, 2);
}
#[test]
fn option_video_frame_roundtrip() {
let f = frame(1, 1, vec![9, 8, 7, 6]);
let some: OptionVideoFrame = Some(f.clone()).into();
assert!(some.is_some());
assert!(!some.is_none());
assert_eq!(some.as_ref(), Some(&f));
assert_eq!(Option::<VideoFrame>::from(some.clone()), Some(f.clone()));
assert_eq!(some.into_option(), Some(f));
let none: OptionVideoFrame = Option::<VideoFrame>::None.into();
assert!(none.is_none());
assert_eq!(none.as_ref(), None);
assert_eq!(Option::<VideoFrame>::from(none), None);
assert_eq!(OptionVideoFrame::default().into_option(), None);
}
#[test]
fn option_video_frame_replace_returns_previous() {
let first = frame(1, 1, vec![1, 1, 1, 1]);
let second = frame(1, 1, vec![2, 2, 2, 2]);
let mut slot = OptionVideoFrame::None;
assert_eq!(slot.replace(first.clone()).into_option(), None);
assert_eq!(slot.replace(second.clone()).into_option(), Some(first));
assert_eq!(slot.into_option(), Some(second));
}
#[test]
fn frame_vec_roundtrip_and_bounds() {
let frames = vec![
frame(1, 1, vec![0, 0, 0, 255]),
frame(2, 1, vec![1; 8]),
frame(0, 0, Vec::new()),
];
let v = VideoFrameVec::from_vec(frames.clone());
assert_eq!(v.len(), 3);
assert!(!v.is_empty());
assert_eq!(v.as_ref(), frames.as_slice());
assert_eq!(v.get(0), Some(&frames[0]));
assert_eq!(v.get(2), Some(&frames[2]));
assert_eq!(v.get(3), None, "out of bounds must be None");
assert_eq!(v.get(usize::MAX), None, "usize::MAX index must be None");
assert!(v.iter().eq(frames.iter()), "iteration order preserved");
assert_eq!(v.c_get(1).into_option(), Some(frames[1].clone()));
assert!(v.c_get(3).is_none());
let cloned = v.clone();
assert_eq!(cloned, v);
assert_ne!(cloned.as_ptr(), v.as_ptr());
}
#[test]
fn frame_vec_empty_is_well_formed() {
let v = VideoFrameVec::from_vec(Vec::new());
assert!(v.is_empty());
assert_eq!(v.len(), 0);
assert_eq!(v.as_ref(), &[] as &[VideoFrame]);
assert_eq!(v.get(0), None);
assert_eq!(v.clone(), v);
assert_eq!(VideoFrameVec::new(), v);
}
#[test]
fn frame_vec_from_const_slice_no_destructor() {
static FRAMES: [VideoFrame; 2] = [
VideoFrame::new(1, 1, U8Vec::from_const_slice(&[1, 2, 3, 4])),
VideoFrame::new(1, 1, U8Vec::from_const_slice(&[5, 6, 7, 8])),
];
let v = VideoFrameVec::from_const_slice(&FRAMES);
assert_eq!(v.len(), 2);
assert_eq!(v.as_ref(), &FRAMES[..]);
assert_eq!(v.get(1).map(|f| f.bytes.as_ref()), Some(&[5, 6, 7, 8][..]));
let cloned = v.clone();
assert_eq!(cloned, v);
drop(v);
assert_eq!(cloned.len(), 2);
}
}