pub mod tests {
use rstest::rstest;
#[test]
fn test_simple_create() {
let buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(10);
assert_eq!(buffer.get_idx, buffer.put_idx);
assert_eq!(buffer.len, 0);
assert_eq!(buffer.capacity, 10);
}
#[test]
#[should_panic(expected = "Capacity cannot be zero!")]
fn test_with_capacity_zero_panics() {
let _ = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(0);
}
#[test]
fn test_enqueue_dequeue_simple() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::with_capacity(10);
buffer.enqueue(255);
assert_eq!(buffer.get_idx, 0);
assert_eq!(buffer.put_idx, 1);
assert_eq!(buffer.len, 1);
assert_eq!(buffer.data, vec![255, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
buffer.enqueue(254);
assert_eq!(buffer.get_idx, 0);
assert_eq!(buffer.put_idx, 2);
assert_eq!(buffer.len, 2);
assert_eq!(buffer.data, vec![255, 254, 0, 0, 0, 0, 0, 0, 0, 0]);
let result = buffer.dequeue();
assert_eq!(buffer.get_idx, 1);
assert_eq!(buffer.put_idx, 2);
assert_eq!(buffer.len, 1);
assert_eq!(buffer.data, vec![255, 254, 0, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(result, Some(255));
let result = buffer.dequeue();
assert_eq!(buffer.get_idx, 2);
assert_eq!(buffer.put_idx, 2);
assert_eq!(buffer.len, 0);
assert_eq!(buffer.data, vec![255, 254, 0, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(result, Some(254));
}
#[test]
fn test_enqueue_dequeue_wrapped() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(10);
for i in 0..12 {
buffer.enqueue(255 - i);
}
assert_eq!(buffer.get_idx, 2);
assert_eq!(buffer.put_idx, 2);
assert_eq!(buffer.len, buffer.capacity);
assert_eq!(
buffer.data,
vec![245, 244, 253, 252, 251, 250, 249, 248, 247, 246]
);
for i in 0..10 {
let value = buffer.dequeue();
assert_eq!(Some(253 - i), value);
}
let value = buffer.dequeue();
assert_eq!(None, value);
}
#[test]
fn test_front_back_empty_returns_none() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(4);
assert_eq!(buffer.front(), None);
assert_eq!(buffer.back(), None);
assert_eq!(buffer.front_mut(), None);
assert_eq!(buffer.back_mut(), None);
}
#[test]
fn test_front_back_non_wrapped() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(5);
buffer.enqueue_slice(&[10, 20, 30]);
assert_eq!(buffer.front(), Some(&10));
assert_eq!(buffer.back(), Some(&30));
}
#[test]
fn test_front_back_wrapped_after_overwrite() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(3);
buffer.enqueue_slice(&[1, 2, 3, 4]);
assert_eq!(buffer.front(), Some(&2));
assert_eq!(buffer.back(), Some(&4));
}
#[test]
fn test_front_back_when_put_idx_is_zero() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(4);
buffer.enqueue_slice(&[1, 2, 3, 4]);
assert_eq!(buffer.put_idx, 0);
assert_eq!(buffer.front(), Some(&1));
assert_eq!(buffer.back(), Some(&4));
}
#[test]
fn test_front_back_mut_modify_expected_elements() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(4);
buffer.enqueue_slice(&[1, 2, 3, 4]);
if let Some(front) = buffer.front_mut() {
*front = 10;
}
if let Some(back) = buffer.back_mut() {
*back = 40;
}
assert_eq!(buffer.dequeue(), Some(10));
assert_eq!(buffer.dequeue(), Some(2));
assert_eq!(buffer.dequeue(), Some(3));
assert_eq!(buffer.dequeue(), Some(40));
}
#[rstest]
#[case::empty_slice(
5,
vec![],
vec![0, 0, 0, 0, 0],
0,
0,
0
)]
#[case::single_element(
5,
vec![42],
vec![42, 0, 0, 0, 0],
0,
1,
1
)]
#[case::slice_less_than_cap_no_wrap(
20,
vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
0,
10,
10
)]
#[case::slice_one_less_than_cap(
5,
vec![1, 2, 3, 4],
vec![1, 2, 3, 4, 0],
0,
4,
4
)]
#[case::slice_eq_to_cap(
5,
vec![1, 2, 3, 4, 5],
vec![1, 2, 3, 4, 5],
0,
0,
5
)]
#[case::slice_greated_than_cap(
5,
vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
vec![6, 7, 8, 9, 10],
0,
0,
5
)]
#[case::slice_much_greater_than_cap(
3,
vec![1, 2, 3, 4, 5, 6, 7],
vec![5, 6, 7],
0,
0,
3
)]
fn test_enqueue_slice(
#[case] capacity: usize,
#[case] data: Vec<u8>,
#[case] expected_data: Vec<u8>,
#[case] expected_get_idx: usize,
#[case] expected_put_idx: usize,
#[case] expected_len: usize,
) {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(capacity);
buffer.enqueue_slice(data.as_slice());
assert_eq!(buffer.get_idx, expected_get_idx);
assert_eq!(buffer.put_idx, expected_put_idx);
assert_eq!(buffer.data, expected_data);
assert_eq!(buffer.len, expected_len);
}
#[rstest]
#[case::append_no_wrap(
10,
vec![1, 2, 3, 4, 5],
vec![6, 7, 8],
vec![1, 2, 3, 4, 5, 6, 7, 8, 0, 0],
0,
8,
8
)]
#[case::fill_exactly_with_wrap(
5,
vec![1, 2, 3, 4],
vec![5],
vec![1, 2, 3, 4, 5],
0,
0,
5
)]
#[case::overwrite_no_wrap(
5,
vec![1, 2, 3, 4, 5],
vec![6, 7],
vec![6, 7, 3, 4, 5],
2,
2,
5
)]
#[case::wrap_with_overwrite(
5,
vec![1, 2, 3],
vec![4, 5, 6],
vec![6, 2, 3, 4, 5],
1,
1,
5
)]
#[case::wrap_and_overwrite(
5,
vec![1, 2, 3, 4],
vec![5, 6, 7],
vec![6, 7, 3, 4, 5],
2,
2,
5
)]
fn test_enqueue_slice_prefilled(
#[case] capacity: usize,
#[case] initial: Vec<u8>,
#[case] slice: Vec<u8>,
#[case] expected_data: Vec<u8>,
#[case] expected_get_idx: usize,
#[case] expected_put_idx: usize,
#[case] expected_len: usize,
) {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(capacity);
buffer.enqueue_slice(initial.as_slice());
buffer.enqueue_slice(slice.as_slice());
assert_eq!(buffer.get_idx, expected_get_idx);
assert_eq!(buffer.put_idx, expected_put_idx);
assert_eq!(buffer.data, expected_data);
assert_eq!(buffer.len, expected_len);
}
#[rstest]
#[case::less_no_wrap(
10,
vec![1, 2, 3, 4, 5],
vec![],
10,
3,
3,
vec![1, 2, 3],
3,
5,
2
)]
#[case::equal_no_wrap(
10,
vec![1, 2, 3, 4, 5],
vec![],
10,
5,
5,
vec![1, 2, 3, 4, 5],
5,
5,
0
)]
#[case::greater_clamps_to_len(
10,
vec![1, 2, 3],
vec![],
10,
8,
3,
vec![1, 2, 3],
3,
3,
0
)]
#[case::less_with_wrap(
5,
vec![1, 2, 3, 4, 5],
vec![6, 7],
10,
4,
4,
vec![3, 4, 5, 6],
1,
2,
1
)]
fn test_dequeue_slice(
#[case] capacity: usize,
#[case] first: Vec<u8>,
#[case] second: Vec<u8>,
#[case] out_cap: usize,
#[case] dequeue_size: usize,
#[case] expected_returned: usize,
#[case] expected_output: Vec<u8>,
#[case] expected_get_idx: usize,
#[case] expected_put_idx: usize,
#[case] expected_len: usize,
) {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(capacity);
buffer.enqueue_slice(first.as_slice());
buffer.enqueue_slice(second.as_slice());
let mut out = vec![0u8; out_cap];
let returned = buffer.dequeue_slice(out.as_mut_slice(), dequeue_size);
assert_eq!(returned, expected_returned);
assert_eq!(&out[..returned], expected_output.as_slice());
assert_eq!(buffer.get_idx, expected_get_idx);
assert_eq!(buffer.put_idx, expected_put_idx);
assert_eq!(buffer.len, expected_len);
}
#[test]
fn test_dequeue_slice_wrapped_equal() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(5);
buffer.enqueue_slice(&[1, 2, 3, 4, 5]);
buffer.enqueue_slice(&[6, 7]);
let mut out = vec![0u8; 8];
let n = buffer.dequeue_slice(&mut out, 1);
assert_eq!(n, 1);
assert_eq!(&out[..n], &[3]);
assert_eq!(buffer.get_idx, 3);
assert_eq!(buffer.put_idx, 2);
assert_eq!(buffer.len, 4);
let mut out = vec![0u8; 8];
let n = buffer.dequeue_slice(&mut out, 4);
assert_eq!(n, 4);
assert_eq!(&out[..n], &[4, 5, 6, 7]);
assert_eq!(buffer.get_idx, 2);
assert_eq!(buffer.put_idx, 2);
assert_eq!(buffer.len, 0);
}
#[test]
fn test_dequeue_slice_empty_returns_zero() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(5);
let mut out = vec![0u8; 5];
let n = buffer.dequeue_slice(&mut out, 3);
assert_eq!(n, 0);
assert_eq!(out, vec![0, 0, 0, 0, 0]);
assert_eq!(buffer.get_idx, 0);
assert_eq!(buffer.put_idx, 0);
assert_eq!(buffer.len, 0);
}
#[test]
#[should_panic(expected = "Dequeue size cannot be greater than out buffer")]
fn test_dequeue_slice_out_buffer_too_small_panics() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(10);
buffer.enqueue_slice(&[1, 2, 3, 4, 5]);
let mut out = vec![0u8; 2]; let _ = buffer.dequeue_slice(&mut out, 3);
}
#[test]
fn test_dequeue_slice_full_buffer_dequeue_all() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(5);
buffer.enqueue_slice(&[1, 2, 3, 4, 5]);
let mut out = vec![0u8; 5];
let n = buffer.dequeue_slice(&mut out, 5);
assert_eq!(n, 5);
assert_eq!(&out[..n], &[1, 2, 3, 4, 5]);
assert_eq!(buffer.len, 0);
}
#[test]
fn test_clone_is_independent() {
let mut original = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(5);
original.extend([1u8, 2, 3]);
let clone = original.clone();
original.enqueue(4);
assert_eq!(clone.iter().copied().collect::<Vec<_>>(), vec![1, 2, 3]);
assert_eq!(
original.iter().copied().collect::<Vec<_>>(),
vec![1, 2, 3, 4]
);
}
#[test]
fn test_extend_appends_in_order() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(5);
buffer.extend([1u8, 2, 3]);
buffer.extend(vec![4u8, 5]);
assert_eq!(
buffer.iter().copied().collect::<Vec<_>>(),
vec![1, 2, 3, 4, 5]
);
assert_eq!(buffer.len, 5);
}
#[test]
fn test_extend_beyond_capacity_overwrites_oldest() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(3);
buffer.extend([1u8, 2, 3, 4, 5]);
assert_eq!(buffer.len, 3);
assert_eq!(buffer.iter().copied().collect::<Vec<_>>(), vec![3, 4, 5]);
}
#[test]
fn test_into_iterator_drains_in_order() {
let buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::from(vec![10u8, 20, 30]);
let mut iter = buffer.into_iter();
assert_eq!(iter.size_hint(), (3, Some(3)));
assert_eq!(iter.next(), Some(10));
assert_eq!(iter.by_ref().collect::<Vec<_>>(), vec![20, 30]);
}
#[test]
fn test_into_iterator_wrapped() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(3);
buffer.extend([1u8, 2, 3, 4]);
assert_eq!(buffer.into_iter().collect::<Vec<_>>(), vec![2, 3, 4]);
}
#[test]
fn test_borrowing_iterator() {
let buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::from(&[7u8, 8, 9][..]);
let by_ref: Vec<u8> = (&buffer).clone().into_iter().collect();
let by_method: Vec<u8> = buffer.iter().copied().collect();
assert_eq!(by_ref, vec![7, 8, 9]);
assert_eq!(by_method, vec![7, 8, 9]);
assert_eq!(buffer.len, 3);
}
#[test]
fn test_from_iterator_collect() {
let buffer: crate::ring_buffer::BoundedRingBuffer<u8> =
[1u8, 2, 3, 4].into_iter().collect();
assert_eq!(buffer.len, 4);
assert_eq!(buffer.capacity, 4);
assert_eq!(buffer.iter().copied().collect::<Vec<_>>(), vec![1, 2, 3, 4]);
}
#[test]
fn test_from_iterator_empty() {
let buffer: crate::ring_buffer::BoundedRingBuffer<u8> = std::iter::empty::<u8>().collect();
assert_eq!(buffer.len, 0);
assert!(buffer.is_empty());
}
#[test]
fn test_from_slice() {
let buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::from(&[5u8, 6, 7][..]);
assert_eq!(buffer.capacity, 3);
assert_eq!(buffer.iter().copied().collect::<Vec<_>>(), vec![5, 6, 7]);
}
#[test]
fn test_from_vec() {
let buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::from(vec![1u8, 2, 3, 4, 5]);
assert_eq!(buffer.capacity, 5);
assert_eq!(
buffer.iter().copied().collect::<Vec<_>>(),
vec![1, 2, 3, 4, 5]
);
}
macro_rules! specialization_roundtrip_test {
($name:ident, $enqueue_fn:ident, $dequeue_fn:ident, $peek_fn:ident, $ty:ty, $value:expr) => {
#[test]
fn $name() {
let value: $ty = $value;
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(
size_of::<$ty>() * 2,
);
let _ = buffer.$enqueue_fn(value);
assert_eq!(buffer.len, size_of::<$ty>());
assert_eq!(
&buffer.data[..size_of::<$ty>()],
value.to_be_bytes().as_slice()
);
let popped = buffer.$peek_fn();
assert_eq!(popped, Some(value));
assert_eq!(buffer.len, size_of::<$ty>());
let dequeued = buffer.$dequeue_fn();
assert_eq!(dequeued, Some(value));
assert!(buffer.is_empty());
}
};
}
specialization_roundtrip_test!(
test_specialization_roundtrip_u8,
enqueue_u8,
dequeue_u8,
peek_u8,
u8,
201u8
);
specialization_roundtrip_test!(
test_specialization_roundtrip_u16,
enqueue_u16,
dequeue_u16,
peek_u16,
u16,
0xABCDu16
);
specialization_roundtrip_test!(
test_specialization_roundtrip_u32,
enqueue_u32,
dequeue_u32,
peek_u32,
u32,
0xABCD_1234u32
);
specialization_roundtrip_test!(
test_specialization_roundtrip_u64,
enqueue_u64,
dequeue_u64,
peek_u64,
u64,
0x0123_4567_89AB_CDEFu64
);
specialization_roundtrip_test!(
test_specialization_roundtrip_u128,
enqueue_u128,
dequeue_u128,
peek_u128,
u128,
0x0123_4567_89AB_CDEF_0011_2233_4455_6677u128
);
specialization_roundtrip_test!(
test_specialization_roundtrip_i8,
enqueue_i8,
dequeue_i8,
peek_i8,
i8,
-99i8
);
specialization_roundtrip_test!(
test_specialization_roundtrip_i16,
enqueue_i16,
dequeue_i16,
peek_i16,
i16,
-12_345i16
);
specialization_roundtrip_test!(
test_specialization_roundtrip_i32,
enqueue_i32,
dequeue_i32,
peek_i32,
i32,
-123_456_789i32
);
specialization_roundtrip_test!(
test_specialization_roundtrip_i64,
enqueue_i64,
dequeue_i64,
peek_i64,
i64,
-123_456_789_012_345_678i64
);
specialization_roundtrip_test!(
test_specialization_roundtrip_i128,
enqueue_i128,
dequeue_i128,
peek_i128,
i128,
-123_456_789_012_345_678_901_234_567_890i128
);
specialization_roundtrip_test!(
test_specialization_roundtrip_usize,
enqueue_usize,
dequeue_usize,
peek_usize,
usize,
1_234_567usize
);
specialization_roundtrip_test!(
test_specialization_roundtrip_isize,
enqueue_isize,
dequeue_isize,
peek_isize,
isize,
-1_234_567isize
);
specialization_roundtrip_test!(
test_specialization_roundtrip_f32,
enqueue_f32,
dequeue_f32,
peek_f32,
f32,
123.25f32
);
specialization_roundtrip_test!(
test_specialization_roundtrip_f64,
enqueue_f64,
dequeue_f64,
peek_f64,
f64,
-9_876.125f64
);
macro_rules! specialization_empty_or_short_buffer_test {
($name:ident, $dequeue_fn:ident, $peek_fn:ident, $enqueue_fn:ident, $ty:ty, $value:expr) => {
#[test]
fn $name() {
let mut empty = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(
size_of::<$ty>() + 1,
);
assert_eq!(empty.$dequeue_fn(), None);
assert_eq!(empty.$peek_fn(), None);
let mut short = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(
size_of::<$ty>() + 2,
);
let _ = short.$enqueue_fn($value);
let _ = short.dequeue();
assert_eq!(short.$dequeue_fn(), None);
assert_eq!(short.$peek_fn(), None);
}
};
}
specialization_empty_or_short_buffer_test!(
test_specialization_empty_or_short_u32,
dequeue_u32,
peek_u32,
enqueue_u32,
u32,
0xDEAD_BEEFu32
);
specialization_empty_or_short_buffer_test!(
test_specialization_empty_or_short_i64,
dequeue_i64,
peek_i64,
enqueue_i64,
i64,
-5_555_555i64
);
specialization_empty_or_short_buffer_test!(
test_specialization_empty_or_short_f64,
dequeue_f64,
peek_f64,
enqueue_f64,
f64,
11.75f64
);
macro_rules! specialization_peek_contract_test {
($name:ident, $enqueue_fn:ident, $peek_fn:ident, $dequeue_fn:ident, $ty:ty, $value:expr) => {
#[test]
fn $name() {
let value: $ty = $value;
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(
size_of::<$ty>() * 3,
);
let _ = buffer.$enqueue_fn(value);
let before_get_idx = buffer.get_idx;
let before_put_idx = buffer.put_idx;
let before_len = buffer.len;
let peeked = buffer.$peek_fn();
assert_eq!(peeked, Some(value));
assert_eq!(buffer.get_idx, before_get_idx);
assert_eq!(buffer.put_idx, before_put_idx);
assert_eq!(buffer.len, before_len);
let dequeued = buffer.$dequeue_fn();
assert_eq!(dequeued, Some(value));
assert!(buffer.is_empty());
}
};
}
specialization_peek_contract_test!(
test_specialization_peek_contract_u16,
enqueue_u16,
peek_u16,
dequeue_u16,
u16,
0xCAFEu16
);
specialization_peek_contract_test!(
test_specialization_peek_contract_i64,
enqueue_i64,
peek_i64,
dequeue_i64,
i64,
-7_654_321i64
);
specialization_peek_contract_test!(
test_specialization_peek_contract_f64,
enqueue_f64,
peek_f64,
dequeue_f64,
f64,
345.875f64
);
#[test]
fn test_specialization_peek_contract_u16_wrapped_layout() {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(4);
let _ = buffer.enqueue_u16(0xA1B2u16);
let _ = buffer.enqueue_u16(0xC3D4u16);
let _ = buffer.dequeue_u16();
let _ = buffer.enqueue_u16(0xE5F6u16);
let before_get_idx = buffer.get_idx;
let before_put_idx = buffer.put_idx;
let before_len = buffer.len;
let peeked = buffer.peek_u16();
assert_eq!(peeked, Some(0xC3D4u16));
assert_eq!(buffer.get_idx, before_get_idx);
assert_eq!(buffer.put_idx, before_put_idx);
assert_eq!(buffer.len, before_len);
let dequeued = buffer.dequeue_u16();
assert_eq!(dequeued, Some(0xC3D4u16));
assert_eq!(buffer.peek_u16(), Some(0xE5F6u16));
}
#[rstest]
#[case::advance_from_empty(5, vec![], 2, 0, 2, 2)]
#[case::advance_without_overwrite(5, vec![1, 2, 3], 1, 0, 4, 4)]
#[case::advance_with_overwrite(5, vec![1, 2, 3, 4], 3, 2, 2, 5)]
#[case::advance_clamps_to_capacity(5, vec![1, 2], 99, 2, 2, 5)]
fn test_advance(
#[case] capacity: usize,
#[case] initial: Vec<u8>,
#[case] advance_by: usize,
#[case] expected_get_idx: usize,
#[case] expected_put_idx: usize,
#[case] expected_len: usize,
) {
let mut buffer = crate::ring_buffer::BoundedRingBuffer::<u8>::with_capacity(capacity);
buffer.enqueue_slice(initial.as_slice());
buffer.advance(advance_by);
assert_eq!(buffer.get_idx, expected_get_idx);
assert_eq!(buffer.put_idx, expected_put_idx);
assert_eq!(buffer.len, expected_len);
}
}