extern crate alloc;
use super::*;
use alloc::vec;
use alloc::vec::Vec;
#[test]
fn extend_writes_at_tail() {
let mut buf = vec![0u8; 32];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3, 4]);
assert_eq!(b.len(), 4);
assert_eq!(b.tail(), 4);
b.extend(&[5, 6]);
let (s, t) = b.as_slices();
assert_eq!(s, &[1, 2, 3, 4, 5, 6]);
assert!(t.is_empty());
}
#[test]
fn extend_and_fill_repeats_byte() {
let mut buf = vec![0u8; 16];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[0xAA]);
b.extend_and_fill(0xBB, 4);
let (s, _) = b.as_slices();
assert_eq!(s, &[0xAA, 0xBB, 0xBB, 0xBB, 0xBB]);
}
#[test]
fn extend_from_within_unchecked_copies_non_overlapping() {
let mut buf = vec![0u8; 32];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[10, 20, 30, 40, 50]);
unsafe { b.extend_from_within_unchecked(0, 3) };
let (s, _) = b.as_slices();
assert_eq!(s, &[10, 20, 30, 40, 50, 10, 20, 30]);
}
#[test]
fn drop_first_n_advances_head_keeps_history() {
let mut buf = vec![0u8; 32];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3, 4, 5]);
b.drop_first_n(2);
assert_eq!(b.len(), 3);
let (s, _) = b.as_slices();
assert_eq!(s, &[3, 4, 5]);
unsafe { b.extend_from_within_unchecked(0, 3) };
let (s, _) = b.as_slices();
assert_eq!(s, &[3, 4, 5, 3, 4, 5]);
}
#[test]
fn set_tail_rollback() {
let mut buf = vec![0u8; 32];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3]);
let saved = b.tail();
b.extend(&[4, 5, 6, 7]);
assert_eq!(b.len(), 7);
unsafe { b.set_tail(saved) };
assert_eq!(b.len(), 3);
let (s, _) = b.as_slices();
assert_eq!(s, &[1, 2, 3]);
}
#[test]
fn clear_resets_cursors() {
let mut buf = vec![0u8; 32];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3]);
b.drop_first_n(1);
b.clear();
assert_eq!(b.len(), 0);
assert_eq!(b.tail(), 0);
}
#[test]
fn extend_from_reader_into_slice() {
let mut buf = vec![0u8; 16];
let mut b = UserSliceBackend::from_slice(&mut buf);
let src = [9u8, 8, 7, 6, 5];
b.extend_from_reader(&src[..], 5).unwrap();
let (s, _) = b.as_slices();
assert_eq!(s, &[9, 8, 7, 6, 5]);
}
#[test]
fn extend_from_reader_over_capacity_errors() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
let src = [9u8, 8, 7, 6, 5];
assert!(b.extend_from_reader(&src[..], 5).is_err());
assert_eq!(b.tail(), 0);
}
use super::super::buffer_backend::BufferBackend;
#[test]
fn try_extend_exact_fit_succeeds_and_advances_tail() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
assert!(b.try_extend(&[1, 2, 3, 4]).is_ok());
assert_eq!(b.tail(), 4);
let (s, _) = b.as_slices();
assert_eq!(s, &[1, 2, 3, 4]);
}
#[test]
fn try_extend_over_capacity_returns_overflow_and_keeps_tail() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
let err = b.try_extend(&[1, 2, 3, 4, 5]).unwrap_err();
assert_eq!(err.tail, 0);
assert_eq!(err.requested, 5);
assert_eq!(err.capacity, 4);
assert_eq!(b.tail(), 0);
}
#[test]
fn try_extend_partially_full_overshoot_reports_current_tail() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2]);
let err = b.try_extend(&[3, 4, 5]).unwrap_err();
assert_eq!(err.tail, 2);
assert_eq!(err.requested, 3);
assert_eq!(err.capacity, 4);
assert_eq!(b.tail(), 2);
}
#[test]
fn try_extend_zero_length_succeeds_and_leaves_tail_unchanged() {
let mut buf = vec![0u8; 8];
let mut b = UserSliceBackend::from_slice(&mut buf);
assert!(b.try_extend(&[]).is_ok());
assert_eq!(b.tail(), 0);
b.extend(&[1, 2, 3]);
assert!(b.try_extend(&[]).is_ok());
assert_eq!(b.tail(), 3);
}
#[test]
fn try_extend_and_fill_exact_fit_writes_pattern() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
assert!(b.try_extend_and_fill(0xAB, 4).is_ok());
assert_eq!(b.tail(), 4);
let (s, _) = b.as_slices();
assert_eq!(s, &[0xAB, 0xAB, 0xAB, 0xAB]);
}
#[test]
fn try_extend_and_fill_over_capacity_returns_overflow() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2]);
let err = b.try_extend_and_fill(0xCD, 5).unwrap_err();
assert_eq!(err.tail, 2);
assert_eq!(err.requested, 5);
assert_eq!(err.capacity, 4);
assert_eq!(b.tail(), 2);
}
#[test]
fn try_extend_from_within_within_bounds_repeats_history() {
let mut buf = vec![0u8; 8];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3]);
assert!(b.try_extend_from_within(0, 3).is_ok());
let (s, _) = b.as_slices();
assert_eq!(s, &[1, 2, 3, 1, 2, 3]);
assert_eq!(b.tail(), 6);
}
#[test]
fn try_extend_from_within_source_past_tail_returns_overflow() {
let mut buf = vec![0u8; 8];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2]);
let err = b.try_extend_from_within(0, 5).unwrap_err();
assert_eq!(err.tail, 2);
assert_eq!(err.requested, 5);
assert_eq!(b.tail(), 2);
}
#[test]
fn try_extend_from_within_destination_overflow_returns_err() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3]);
let err = b.try_extend_from_within(0, 2).unwrap_err();
assert_eq!(err.tail, 3);
assert_eq!(err.requested, 2);
assert_eq!(err.capacity, 4);
assert_eq!(b.tail(), 3);
}
#[test]
fn exec_sequence_inline_overflow_returns_output_buffer_overflow() {
use super::super::errors::ExecuteSequencesError;
let mut buf = vec![0u8; 16];
for (i, slot) in buf.iter_mut().take(8).enumerate() {
*slot = i as u8;
}
let mut b = UserSliceBackend::from_slice(&mut buf);
b.tail = 8;
let lits = [0xAAu8; 16];
let err = unsafe { b.exec_sequence_inline(lits.as_ptr(), 8, 4, 8) }
.expect_err("overshoot must return OutputBufferOverflow");
assert!(
matches!(err, ExecuteSequencesError::OutputBufferOverflow { .. }),
"expected OutputBufferOverflow, got {err:?}"
);
assert_eq!(b.tail, 8, "tail must not advance on overflow");
}
#[test]
fn exec_sequence_inline_short_literal_plus_long_offset_match() {
const WILDCOPY: usize = super::super::buffer_backend::WILDCOPY_OVERLENGTH;
let mut buf = vec![0u8; 256 + WILDCOPY];
for (i, slot) in buf.iter_mut().take(32).enumerate() {
*slot = i as u8;
}
let mut b = UserSliceBackend::from_slice(&mut buf);
b.tail = 32;
let lits: [u8; 16] = [
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, 0x10,
0x20,
];
unsafe {
b.exec_sequence_inline(lits.as_ptr(), 8, 16, 8).unwrap();
}
assert_eq!(b.tail, 48);
assert_eq!(&buf[32..40], &lits[..8]);
assert_eq!(&buf[40..48], &[24u8, 25, 26, 27, 28, 29, 30, 31]);
}
#[test]
fn exec_sequence_inline_long_literal_uses_wildcopy_tail() {
const WILDCOPY: usize = super::super::buffer_backend::WILDCOPY_OVERLENGTH;
let mut buf = vec![0u8; 256 + WILDCOPY];
for (i, slot) in buf.iter_mut().take(32).enumerate() {
*slot = i as u8;
}
let mut b = UserSliceBackend::from_slice(&mut buf);
b.tail = 32;
let lits: Vec<u8> = (0..40u8 + 16).map(|i| 0x80 + i).collect();
unsafe {
b.exec_sequence_inline(lits.as_ptr(), 40, 16, 8).unwrap();
}
assert_eq!(b.tail, 80);
assert_eq!(&buf[32..72], &lits[..40]);
assert_eq!(&buf[72..80], &lits[24..32]);
}
#[test]
fn exec_sequence_inline_short_offset_match_uses_overlap_copy() {
const WILDCOPY: usize = super::super::buffer_backend::WILDCOPY_OVERLENGTH;
let mut buf = vec![0u8; 256 + WILDCOPY];
let seed = [0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7];
buf[24..32].copy_from_slice(&seed);
let mut b = UserSliceBackend::from_slice(&mut buf);
b.tail = 32;
let lits: [u8; 16] = [0xFF; 16];
unsafe {
b.exec_sequence_inline(lits.as_ptr(), 4, 8, 12).unwrap();
}
assert_eq!(b.tail, 48);
assert_eq!(&buf[32..36], &lits[..4]);
assert_eq!(&buf[36..40], &seed[4..8]);
}
#[cfg(all(target_arch = "x86_64", feature = "std"))]
#[test]
fn exec_sequence_inline_avx2_offset_boundary_correctness() {
if !std::arch::is_x86_feature_detected!("avx2") {
return;
}
const WILDCOPY: usize = super::super::buffer_backend::WILDCOPY_OVERLENGTH;
for offset in [20usize, 32, 64] {
let mut buf = vec![0u8; 512 + WILDCOPY];
for (i, slot) in buf.iter_mut().take(200).enumerate() {
*slot = ((i * 31 + 7) & 0xFF) as u8;
}
let match_length = 96usize;
let mut reference = buf.clone();
for i in 0..match_length {
reference[200 + i] = reference[200 + i - offset];
}
let mut b = UserSliceBackend::from_slice(&mut buf);
b.tail = 200;
let dummy_lits: [u8; 16] = [0xAA; 16];
unsafe {
b.exec_sequence_inline_avx2(dummy_lits.as_ptr(), 0, offset, match_length)
.unwrap();
}
assert_eq!(b.tail, 200 + match_length);
for i in 0..match_length {
assert_eq!(
buf[200 + i],
reference[200 + i],
"exec_sequence_inline_avx2 offset={offset} byte {i}: \
got {:#x}, expected {:#x} (regression: AVX2 wildcopy \
reading past first-store boundary)",
buf[200 + i],
reference[200 + i],
);
}
}
}