#![cfg(test)]
#![allow(
clippy::unwrap_used,
clippy::expect_used,
reason = "test modules may unwrap"
)]
use super::{Dpb, DpbError, DpbSlot, H264_MAX_DPB_SLOTS, compute_frame_num_wrap};
#[test]
fn new_clamps_capacity_to_at_least_one() {
let dpb = Dpb::new(0);
assert_eq!(dpb.capacity(), 1);
}
#[test]
fn new_clamps_capacity_to_h264_max() {
let dpb = Dpb::new(1000);
assert_eq!(dpb.capacity(), H264_MAX_DPB_SLOTS);
}
#[test]
fn free_slot_index_picks_first_free() {
let mut dpb = Dpb::new(4);
dpb.insert(0, DpbSlot::new_reference(0, 0, 0)).unwrap();
dpb.insert(2, DpbSlot::new_reference(2, 2, 4)).unwrap();
assert_eq!(dpb.free_slot_index(), Some(1));
}
#[test]
fn allocate_slot_reuses_free_before_evicting() {
let mut dpb = Dpb::new(2);
dpb.insert(0, DpbSlot::new_reference(0, 0, 0)).unwrap();
let allocated = dpb.allocate_slot().unwrap();
assert_eq!(allocated, 1);
assert!(dpb.slot(0).is_some());
}
#[test]
fn allocate_slot_evicts_smallest_frame_num_wrap_when_full() {
let mut dpb = Dpb::new(2);
dpb.insert(0, DpbSlot::new_reference(5, 5, 10)).unwrap();
dpb.insert(1, DpbSlot::new_reference(2, 2, 4)).unwrap();
let allocated = dpb.allocate_slot().unwrap();
assert_eq!(allocated, 1);
assert!(dpb.slot(1).is_none());
assert!(dpb.slot(0).is_some());
}
#[test]
fn allocate_slot_ignores_non_reference_slots_for_eviction() {
let mut dpb = Dpb::new(1);
let mut non_ref = DpbSlot::new_reference(0, 0, 0);
non_ref.used_for_reference = false;
dpb.insert(0, non_ref).unwrap();
let err = dpb.allocate_slot().unwrap_err();
assert_eq!(err, DpbError::NoFreeSlot { capacity: 1 });
}
#[test]
fn insert_into_outstanding_slot_fails_loudly() {
let mut dpb = Dpb::new(2);
dpb.insert(0, DpbSlot::new_reference(0, 0, 0)).unwrap();
dpb.mark_outstanding(0).unwrap();
let err = dpb.insert(0, DpbSlot::new_reference(1, 1, 2)).unwrap_err();
assert_eq!(err, DpbError::SlotOutstanding { index: 0 });
}
#[test]
fn evict_outstanding_slot_fails_loudly() {
let mut dpb = Dpb::new(2);
dpb.insert(0, DpbSlot::new_reference(0, 0, 0)).unwrap();
dpb.mark_outstanding(0).unwrap();
let err = dpb.evict(0).unwrap_err();
assert_eq!(err, DpbError::SlotOutstanding { index: 0 });
assert!(dpb.slot(0).is_some());
}
#[test]
fn clear_outstanding_allows_eviction_again() {
let mut dpb = Dpb::new(2);
dpb.insert(0, DpbSlot::new_reference(0, 0, 0)).unwrap();
dpb.mark_outstanding(0).unwrap();
assert!(dpb.evict(0).is_err());
dpb.clear_outstanding(0).unwrap();
dpb.evict(0).unwrap();
assert!(dpb.slot(0).is_none());
}
#[test]
fn out_of_range_index_reports_invalid_slot_index() {
let mut dpb = Dpb::new(2);
let err = dpb.insert(5, DpbSlot::new_reference(0, 0, 0)).unwrap_err();
assert_eq!(
err,
DpbError::InvalidSlotIndex {
index: 5,
capacity: 2
}
);
assert_eq!(
dpb.mark_outstanding(9).unwrap_err(),
DpbError::InvalidSlotIndex {
index: 9,
capacity: 2
}
);
}
#[test]
fn clear_all_evicts_every_occupied_slot() {
let mut dpb = Dpb::new(4);
dpb.insert(0, DpbSlot::new_reference(0, 0, 0)).unwrap();
dpb.insert(2, DpbSlot::new_reference(2, 2, 4)).unwrap();
dpb.clear_all().unwrap();
assert!(dpb.slot(0).is_none());
assert!(dpb.slot(2).is_none());
}
#[test]
fn clear_all_fails_loudly_on_outstanding_slot() {
let mut dpb = Dpb::new(2);
dpb.insert(0, DpbSlot::new_reference(0, 0, 0)).unwrap();
dpb.mark_outstanding(0).unwrap();
let err = dpb.clear_all().unwrap_err();
assert_eq!(err, DpbError::SlotOutstanding { index: 0 });
}
#[test]
fn is_outstanding_defaults_false_and_out_of_range_is_false() {
let dpb = Dpb::new(2);
assert!(!dpb.is_outstanding(0));
assert!(!dpb.is_outstanding(99));
}
#[test]
fn occupied_slots_reports_index_and_slot_in_order() {
let mut dpb = Dpb::new(3);
dpb.insert(2, DpbSlot::new_reference(2, 2, 4)).unwrap();
dpb.insert(0, DpbSlot::new_reference(0, 0, 0)).unwrap();
let occupied: Vec<_> = dpb
.occupied_slots()
.map(|(i, s)| (i, s.frame_num))
.collect();
assert_eq!(occupied, vec![(0, 0), (2, 2)]);
}
#[test]
fn sliding_window_evict_target_none_when_empty() {
let dpb = Dpb::new(4);
assert_eq!(dpb.sliding_window_evict_target(), None);
}
#[test]
fn refresh_frame_num_wraps_recomputes_relative_to_current_picture() {
let mut dpb = Dpb::new(4);
dpb.insert(0, DpbSlot::new_reference(14, 14, 28)).unwrap();
dpb.refresh_frame_num_wraps(1, 16);
assert_eq!(dpb.slot(0).unwrap().frame_num_wrap, -2);
}
#[test]
fn compute_frame_num_wrap_no_wrap_when_not_greater() {
assert_eq!(compute_frame_num_wrap(3, 5, 16), 3);
assert_eq!(compute_frame_num_wrap(5, 5, 16), 5);
}
#[test]
fn compute_frame_num_wrap_wraps_when_greater() {
assert_eq!(compute_frame_num_wrap(15, 2, 16), 15 - 16);
}