diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/ringbuf/src/tests | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/ringbuf/src/tests')
-rw-r--r-- | third_party/rust/ringbuf/src/tests/access.rs | 304 | ||||
-rw-r--r-- | third_party/rust/ringbuf/src/tests/drop.rs | 240 | ||||
-rw-r--r-- | third_party/rust/ringbuf/src/tests/iter.rs | 51 | ||||
-rw-r--r-- | third_party/rust/ringbuf/src/tests/message.rs | 166 | ||||
-rw-r--r-- | third_party/rust/ringbuf/src/tests/mod.rs | 9 | ||||
-rw-r--r-- | third_party/rust/ringbuf/src/tests/multiple.rs | 193 | ||||
-rw-r--r-- | third_party/rust/ringbuf/src/tests/read_write.rs | 159 | ||||
-rw-r--r-- | third_party/rust/ringbuf/src/tests/single.rs | 203 |
8 files changed, 1325 insertions, 0 deletions
diff --git a/third_party/rust/ringbuf/src/tests/access.rs b/third_party/rust/ringbuf/src/tests/access.rs new file mode 100644 index 0000000000..17481b38bc --- /dev/null +++ b/third_party/rust/ringbuf/src/tests/access.rs @@ -0,0 +1,304 @@ +use crate::RingBuffer; +use alloc::rc::Rc; +use core::mem::MaybeUninit; + +#[test] +fn push() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (mut prod, mut cons) = buf.split(); + + let vs_20 = (123, 456); + let push_fn_20 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + assert_eq!(left.len(), 2); + assert_eq!(right.len(), 0); + left[0] = MaybeUninit::new(vs_20.0); + left[1] = MaybeUninit::new(vs_20.1); + 2 + }; + + assert_eq!(unsafe { prod.push_access(push_fn_20) }, 2); + + assert_eq!(cons.pop().unwrap(), vs_20.0); + assert_eq!(cons.pop().unwrap(), vs_20.1); + assert_eq!(cons.pop(), None); + + let vs_11 = (123, 456); + let push_fn_11 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + assert_eq!(left.len(), 1); + assert_eq!(right.len(), 1); + left[0] = MaybeUninit::new(vs_11.0); + right[0] = MaybeUninit::new(vs_11.1); + 2 + }; + + assert_eq!(unsafe { prod.push_access(push_fn_11) }, 2); + + assert_eq!(cons.pop().unwrap(), vs_11.0); + assert_eq!(cons.pop().unwrap(), vs_11.1); + assert_eq!(cons.pop(), None); +} + +#[test] +fn pop_full() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (_, mut cons) = buf.split(); + + let dummy_fn = |_l: &mut [MaybeUninit<i32>], _r: &mut [MaybeUninit<i32>]| -> usize { 0 }; + assert_eq!(unsafe { cons.pop_access(dummy_fn) }, 0); +} + +#[test] +fn pop_empty() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (_, mut cons) = buf.split(); + + let dummy_fn = |_l: &mut [MaybeUninit<i32>], _r: &mut [MaybeUninit<i32>]| -> usize { 0 }; + assert_eq!(unsafe { cons.pop_access(dummy_fn) }, 0); +} + +#[test] +fn pop() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (mut prod, mut cons) = buf.split(); + + let vs_20 = (123, 456); + + assert_eq!(prod.push(vs_20.0), Ok(())); + assert_eq!(prod.push(vs_20.1), Ok(())); + assert_eq!(prod.push(0), Err(0)); + + let pop_fn_20 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + unsafe { + assert_eq!(left.len(), 2); + assert_eq!(right.len(), 0); + assert_eq!(left[0].assume_init(), vs_20.0); + assert_eq!(left[1].assume_init(), vs_20.1); + 2 + } + }; + + assert_eq!(unsafe { cons.pop_access(pop_fn_20) }, 2); + + let vs_11 = (123, 456); + + assert_eq!(prod.push(vs_11.0), Ok(())); + assert_eq!(prod.push(vs_11.1), Ok(())); + assert_eq!(prod.push(0), Err(0)); + + let pop_fn_11 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + unsafe { + assert_eq!(left.len(), 1); + assert_eq!(right.len(), 1); + assert_eq!(left[0].assume_init(), vs_11.0); + assert_eq!(right[0].assume_init(), vs_11.1); + 2 + } + }; + + assert_eq!(unsafe { cons.pop_access(pop_fn_11) }, 2); +} + +#[test] +fn push_return() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (mut prod, mut cons) = buf.split(); + + let push_fn_0 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + assert_eq!(left.len(), 2); + assert_eq!(right.len(), 0); + 0 + }; + + assert_eq!(unsafe { prod.push_access(push_fn_0) }, 0); + + let push_fn_1 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + assert_eq!(left.len(), 2); + assert_eq!(right.len(), 0); + left[0] = MaybeUninit::new(12); + 1 + }; + + assert_eq!(unsafe { prod.push_access(push_fn_1) }, 1); + + let push_fn_2 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + assert_eq!(left.len(), 1); + assert_eq!(right.len(), 0); + left[0] = MaybeUninit::new(34); + 1 + }; + + assert_eq!(unsafe { prod.push_access(push_fn_2) }, 1); + + assert_eq!(cons.pop().unwrap(), 12); + assert_eq!(cons.pop().unwrap(), 34); + assert_eq!(cons.pop(), None); +} + +#[test] +fn pop_return() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (mut prod, mut cons) = buf.split(); + + assert_eq!(prod.push(12), Ok(())); + assert_eq!(prod.push(34), Ok(())); + assert_eq!(prod.push(0), Err(0)); + + let pop_fn_0 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + assert_eq!(left.len(), 2); + assert_eq!(right.len(), 0); + 0 + }; + + assert_eq!(unsafe { cons.pop_access(pop_fn_0) }, 0); + + let pop_fn_1 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + unsafe { + assert_eq!(left.len(), 2); + assert_eq!(right.len(), 0); + assert_eq!(left[0].assume_init(), 12); + 1 + } + }; + + assert_eq!(unsafe { cons.pop_access(pop_fn_1) }, 1); + + let pop_fn_2 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + unsafe { + assert_eq!(left.len(), 1); + assert_eq!(right.len(), 0); + assert_eq!(left[0].assume_init(), 34); + 1 + } + }; + + assert_eq!(unsafe { cons.pop_access(pop_fn_2) }, 1); +} + +#[test] +fn push_pop() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (mut prod, mut cons) = buf.split(); + + let vs_20 = (123, 456); + let push_fn_20 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + assert_eq!(left.len(), 2); + assert_eq!(right.len(), 0); + left[0] = MaybeUninit::new(vs_20.0); + left[1] = MaybeUninit::new(vs_20.1); + 2 + }; + + assert_eq!(unsafe { prod.push_access(push_fn_20) }, 2); + + let pop_fn_20 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + unsafe { + assert_eq!(left.len(), 2); + assert_eq!(right.len(), 0); + assert_eq!(left[0].assume_init(), vs_20.0); + assert_eq!(left[1].assume_init(), vs_20.1); + 2 + } + }; + + assert_eq!(unsafe { cons.pop_access(pop_fn_20) }, 2); + + let vs_11 = (123, 456); + let push_fn_11 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + assert_eq!(left.len(), 1); + assert_eq!(right.len(), 1); + left[0] = MaybeUninit::new(vs_11.0); + right[0] = MaybeUninit::new(vs_11.1); + 2 + }; + + assert_eq!(unsafe { prod.push_access(push_fn_11) }, 2); + + let pop_fn_11 = |left: &mut [MaybeUninit<i32>], right: &mut [MaybeUninit<i32>]| -> usize { + unsafe { + assert_eq!(left.len(), 1); + assert_eq!(right.len(), 1); + assert_eq!(left[0].assume_init(), vs_11.0); + assert_eq!(right[0].assume_init(), vs_11.1); + 2 + } + }; + + assert_eq!(unsafe { cons.pop_access(pop_fn_11) }, 2); +} + +#[test] +fn discard() { + // Initialize ringbuffer, prod and cons + let rb = RingBuffer::<i8>::new(10); + let (mut prod, mut cons) = rb.split(); + let mut i = 0; + + // Fill the buffer + for _ in 0..10 { + prod.push(i).unwrap(); + i += 1; + } + + // Pop in the middle of the buffer + assert_eq!(cons.discard(5), 5); + + // Make sure changes are taken into account + assert_eq!(cons.pop().unwrap(), 5); + + // Fill the buffer again + for _ in 0..5 { + prod.push(i).unwrap(); + i += 1; + } + + assert_eq!(cons.discard(6), 6); + assert_eq!(cons.pop().unwrap(), 12); + + // Fill the buffer again + for _ in 0..7 { + prod.push(i).unwrap(); + i += 1; + } + + // Ask too much, delete the max number of elements + assert_eq!(cons.discard(10), 9); + + // Try to remove more than possible + assert_eq!(cons.discard(1), 0); + + // Make sure it is still usable + assert_eq!(cons.pop(), None); + assert_eq!(prod.push(0), Ok(())); + assert_eq!(cons.pop(), Some(0)); +} + +#[test] +fn discard_drop() { + let rc = Rc::<()>::new(()); + + static N: usize = 10; + + let rb = RingBuffer::<Rc<()>>::new(N); + let (mut prod, mut cons) = rb.split(); + + for _ in 0..N { + prod.push(rc.clone()).unwrap(); + } + + assert_eq!(cons.len(), N); + assert_eq!(Rc::strong_count(&rc), N + 1); + + assert_eq!(cons.discard(N), N); + + // Check ring buffer is empty + assert_eq!(cons.len(), 0); + // Check that items are dropped + assert_eq!(Rc::strong_count(&rc), 1); +} diff --git a/third_party/rust/ringbuf/src/tests/drop.rs b/third_party/rust/ringbuf/src/tests/drop.rs new file mode 100644 index 0000000000..54f14cf6cf --- /dev/null +++ b/third_party/rust/ringbuf/src/tests/drop.rs @@ -0,0 +1,240 @@ +use crate::RingBuffer; +use alloc::{collections::BTreeSet, vec, vec::Vec}; +use core::cell::RefCell; + +#[derive(Debug)] +struct Dropper<'a> { + id: i32, + set: &'a RefCell<BTreeSet<i32>>, +} + +impl<'a> Dropper<'a> { + fn new(set: &'a RefCell<BTreeSet<i32>>, id: i32) -> Self { + if !set.borrow_mut().insert(id) { + panic!("value {} already exists", id); + } + Self { set, id } + } +} + +impl<'a> Drop for Dropper<'a> { + fn drop(&mut self) { + if !self.set.borrow_mut().remove(&self.id) { + panic!("value {} already removed", self.id); + } + } +} + +#[test] +fn single() { + let set = RefCell::new(BTreeSet::new()); + + let cap = 3; + let buf = RingBuffer::new(cap); + + assert_eq!(set.borrow().len(), 0); + + { + let (mut prod, mut cons) = buf.split(); + + prod.push(Dropper::new(&set, 1)).unwrap(); + assert_eq!(set.borrow().len(), 1); + prod.push(Dropper::new(&set, 2)).unwrap(); + assert_eq!(set.borrow().len(), 2); + prod.push(Dropper::new(&set, 3)).unwrap(); + assert_eq!(set.borrow().len(), 3); + + cons.pop().unwrap(); + assert_eq!(set.borrow().len(), 2); + cons.pop().unwrap(); + assert_eq!(set.borrow().len(), 1); + + prod.push(Dropper::new(&set, 4)).unwrap(); + assert_eq!(set.borrow().len(), 2); + } + + assert_eq!(set.borrow().len(), 0); +} + +#[test] +fn multiple_each() { + let set = RefCell::new(BTreeSet::new()); + + let cap = 5; + let buf = RingBuffer::new(cap); + + assert_eq!(set.borrow().len(), 0); + + { + let (mut prod, mut cons) = buf.split(); + let mut id = 0; + let mut cnt = 0; + + assert_eq!( + prod.push_each(|| { + if cnt < 4 { + id += 1; + cnt += 1; + Some(Dropper::new(&set, id)) + } else { + None + } + }), + 4 + ); + assert_eq!(cnt, 4); + assert_eq!(cnt, set.borrow().len()); + + assert_eq!( + cons.pop_each( + |_| { + cnt -= 1; + true + }, + Some(2) + ), + 2 + ); + assert_eq!(cnt, 2); + assert_eq!(cnt, set.borrow().len()); + + assert_eq!( + prod.push_each(|| { + id += 1; + cnt += 1; + Some(Dropper::new(&set, id)) + }), + 3 + ); + assert_eq!(cnt, 5); + assert_eq!(cnt, set.borrow().len()); + + assert_eq!( + cons.pop_each( + |_| { + cnt -= 1; + true + }, + None + ), + 5 + ); + assert_eq!(cnt, 0); + assert_eq!(cnt, set.borrow().len()); + + assert_eq!( + prod.push_each(|| { + id += 1; + cnt += 1; + Some(Dropper::new(&set, id)) + }), + 5 + ); + assert_eq!(cnt, 5); + assert_eq!(cnt, set.borrow().len()); + } + + assert_eq!(set.borrow().len(), 0); +} + +/// Test the `pop_each` with internal function that returns false +#[test] +fn pop_each_test1() { + let cap = 10usize; + let (mut producer, mut consumer) = RingBuffer::new(cap).split(); + + for i in 0..cap { + producer.push((i, vec![0u8; 1000])).unwrap(); + } + + for _ in 0..cap { + let removed = consumer.pop_each(|_val| -> bool { false }, None); + assert_eq!(removed, 1); + } + + assert_eq!(consumer.len(), 0); +} + +/// Test the `pop_each` with capped pop +#[test] +fn pop_each_test2() { + let cap = 10usize; + let (mut producer, mut consumer) = RingBuffer::new(cap).split(); + + for i in 0..cap { + producer.push((i, vec![0u8; 1000])).unwrap(); + } + + for _ in 0..cap { + let removed = consumer.pop_each(|_val| -> bool { true }, Some(1)); + assert_eq!(removed, 1); + } + + assert_eq!(consumer.len(), 0); +} + +/// Test the `push_each` with internal function that adds only 1 element. +#[test] +fn push_each_test1() { + let cap = 10usize; + let (mut producer, mut consumer) = RingBuffer::new(cap).split(); + + for i in 0..cap { + let mut count = 0; + // Add 1 element at a time + let added = producer.push_each(|| -> Option<(usize, Vec<u8>)> { + if count == 0 { + count += 1; + Some((i, vec![0u8; 1000])) + } else { + None + } + }); + assert_eq!(added, 1); + } + + for _ in 0..cap { + consumer.pop().unwrap(); + } + + assert_eq!(consumer.len(), 0); +} + +/// Test the `push_each` with split internal buffer +#[test] +fn push_each_test2() { + let cap = 10usize; + let cap_half = 5usize; + let (mut producer, mut consumer) = RingBuffer::new(cap).split(); + + // Fill the entire buffer + for i in 0..cap { + producer.push((i, vec![0u8; 1000])).unwrap(); + } + + // Remove half elements + for _ in 0..cap_half { + consumer.pop().unwrap(); + } + + // Re add half elements one by one and check the return count. + for i in 0..cap_half { + let mut count = 0; + // Add 1 element at a time + let added = producer.push_each(|| -> Option<(usize, Vec<u8>)> { + if count == 0 { + count += 1; + Some((i, vec![0u8; 1000])) + } else { + None + } + }); + assert_eq!(added, 1); + } + + for _ in 0..cap { + consumer.pop().unwrap(); + } + + assert_eq!(consumer.len(), 0); +} diff --git a/third_party/rust/ringbuf/src/tests/iter.rs b/third_party/rust/ringbuf/src/tests/iter.rs new file mode 100644 index 0000000000..ed361f8020 --- /dev/null +++ b/third_party/rust/ringbuf/src/tests/iter.rs @@ -0,0 +1,51 @@ +use crate::RingBuffer; + +#[test] +fn iter() { + let buf = RingBuffer::<i32>::new(2); + let (mut prod, mut cons) = buf.split(); + + prod.push(10).unwrap(); + prod.push(20).unwrap(); + + let sum: i32 = cons.iter().sum(); + + let first = cons.pop().expect("First element not available"); + let second = cons.pop().expect("Second element not available"); + + assert_eq!(sum, first + second); +} + +#[test] +fn iter_mut() { + let buf = RingBuffer::<i32>::new(2); + let (mut prod, mut cons) = buf.split(); + + prod.push(10).unwrap(); + prod.push(20).unwrap(); + + for v in cons.iter_mut() { + *v *= 2; + } + + let sum: i32 = cons.iter().sum(); + + let first = cons.pop().expect("First element not available"); + let second = cons.pop().expect("Second element not available"); + + assert_eq!(sum, first + second); +} + +#[test] +fn into_iter() { + let buf = RingBuffer::<i32>::new(2); + let (mut prod, cons) = buf.split(); + + prod.push(10).unwrap(); + prod.push(20).unwrap(); + + for (i, v) in cons.into_iter().enumerate() { + assert_eq!(10 * (i + 1) as i32, v); + } + assert!(prod.is_empty()); +} diff --git a/third_party/rust/ringbuf/src/tests/message.rs b/third_party/rust/ringbuf/src/tests/message.rs new file mode 100644 index 0000000000..8a382f2c17 --- /dev/null +++ b/third_party/rust/ringbuf/src/tests/message.rs @@ -0,0 +1,166 @@ +use crate::RingBuffer; +use alloc::{string::String, vec::Vec}; +use std::{ + io::{self, Read, Write}, + thread, + time::Duration, +}; + +const THE_BOOK_FOREWORD: &str = " +It wasn’t always so clear, but the Rust programming language is fundamentally about empowerment: no matter what kind of code you are writing now, Rust empowers you to reach farther, to program with confidence in a wider variety of domains than you did before. +Take, for example, “systems-level” work that deals with low-level details of memory management, data representation, and concurrency. Traditionally, this realm of programming is seen as arcane, accessible only to a select few who have devoted the necessary years learning to avoid its infamous pitfalls. And even those who practice it do so with caution, lest their code be open to exploits, crashes, or corruption. +Rust breaks down these barriers by eliminating the old pitfalls and providing a friendly, polished set of tools to help you along the way. Programmers who need to “dip down” into lower-level control can do so with Rust, without taking on the customary risk of crashes or security holes, and without having to learn the fine points of a fickle toolchain. Better yet, the language is designed to guide you naturally towards reliable code that is efficient in terms of speed and memory usage. +Programmers who are already working with low-level code can use Rust to raise their ambitions. For example, introducing parallelism in Rust is a relatively low-risk operation: the compiler will catch the classical mistakes for you. And you can tackle more aggressive optimizations in your code with the confidence that you won’t accidentally introduce crashes or vulnerabilities. +But Rust isn’t limited to low-level systems programming. It’s expressive and ergonomic enough to make CLI apps, web servers, and many other kinds of code quite pleasant to write — you’ll find simple examples of both later in the book. Working with Rust allows you to build skills that transfer from one domain to another; you can learn Rust by writing a web app, then apply those same skills to target your Raspberry Pi. +This book fully embraces the potential of Rust to empower its users. It’s a friendly and approachable text intended to help you level up not just your knowledge of Rust, but also your reach and confidence as a programmer in general. So dive in, get ready to learn—and welcome to the Rust community! + +— Nicholas Matsakis and Aaron Turon +"; + +#[test] +#[cfg_attr(miri, ignore)] +fn push_pop_slice() { + let buf = RingBuffer::<u8>::new(7); + let (mut prod, mut cons) = buf.split(); + + let smsg = THE_BOOK_FOREWORD; + + let pjh = thread::spawn(move || { + let mut bytes = smsg.as_bytes(); + while !bytes.is_empty() { + let n = prod.push_slice(bytes); + if n > 0 { + bytes = &bytes[n..bytes.len()] + } else { + thread::sleep(Duration::from_millis(1)) + } + } + loop { + match prod.push(0) { + Ok(()) => break, + Err(_) => thread::sleep(Duration::from_millis(1)), + } + } + }); + + let cjh = thread::spawn(move || { + let mut bytes = Vec::<u8>::new(); + let mut buffer = [0; 5]; + loop { + let n = cons.pop_slice(&mut buffer); + if n > 0 { + bytes.extend_from_slice(&buffer[0..n]) + } else if bytes.ends_with(&[0]) { + break; + } else { + thread::sleep(Duration::from_millis(1)); + } + } + + assert_eq!(bytes.pop().unwrap(), 0); + String::from_utf8(bytes).unwrap() + }); + + pjh.join().unwrap(); + let rmsg = cjh.join().unwrap(); + + assert_eq!(smsg, rmsg); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn read_from_write_into() { + let buf = RingBuffer::<u8>::new(7); + let (mut prod, mut cons) = buf.split(); + + let smsg = THE_BOOK_FOREWORD; + + let pjh = thread::spawn(move || { + let zero = [0]; + let mut bytes = smsg.as_bytes().chain(&zero[..]); + loop { + if prod.is_full() { + thread::sleep(Duration::from_millis(1)); + } else if prod.read_from(&mut bytes, None).unwrap() == 0 { + break; + } + } + }); + + let cjh = thread::spawn(move || { + let mut bytes = Vec::<u8>::new(); + loop { + if cons.is_empty() { + if bytes.ends_with(&[0]) { + break; + } else { + thread::sleep(Duration::from_millis(1)); + } + } else { + cons.write_into(&mut bytes, None).unwrap(); + } + } + + assert_eq!(bytes.pop().unwrap(), 0); + String::from_utf8(bytes).unwrap() + }); + + pjh.join().unwrap(); + let rmsg = cjh.join().unwrap(); + + assert_eq!(smsg, rmsg); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn read_write() { + let buf = RingBuffer::<u8>::new(7); + let (mut prod, mut cons) = buf.split(); + + let smsg = THE_BOOK_FOREWORD; + + let pjh = thread::spawn(move || { + let mut bytes = smsg.as_bytes(); + while !bytes.is_empty() { + match prod.write(bytes) { + Ok(n) => bytes = &bytes[n..bytes.len()], + Err(err) => { + assert_eq!(err.kind(), io::ErrorKind::WouldBlock); + thread::sleep(Duration::from_millis(1)); + } + } + } + loop { + match prod.push(0) { + Ok(()) => break, + Err(_) => thread::sleep(Duration::from_millis(1)), + } + } + }); + + let cjh = thread::spawn(move || { + let mut bytes = Vec::<u8>::new(); + let mut buffer = [0; 5]; + loop { + match cons.read(&mut buffer) { + Ok(n) => bytes.extend_from_slice(&buffer[0..n]), + Err(err) => { + assert_eq!(err.kind(), io::ErrorKind::WouldBlock); + if bytes.ends_with(&[0]) { + break; + } else { + thread::sleep(Duration::from_millis(1)); + } + } + } + } + + assert_eq!(bytes.pop().unwrap(), 0); + String::from_utf8(bytes).unwrap() + }); + + pjh.join().unwrap(); + let rmsg = cjh.join().unwrap(); + + assert_eq!(smsg, rmsg); +} diff --git a/third_party/rust/ringbuf/src/tests/mod.rs b/third_party/rust/ringbuf/src/tests/mod.rs new file mode 100644 index 0000000000..472070eb5f --- /dev/null +++ b/third_party/rust/ringbuf/src/tests/mod.rs @@ -0,0 +1,9 @@ +mod access; +mod drop; +mod iter; +#[cfg(feature = "std")] +mod message; +mod multiple; +#[cfg(feature = "std")] +mod read_write; +mod single; diff --git a/third_party/rust/ringbuf/src/tests/multiple.rs b/third_party/rust/ringbuf/src/tests/multiple.rs new file mode 100644 index 0000000000..193fcbb028 --- /dev/null +++ b/third_party/rust/ringbuf/src/tests/multiple.rs @@ -0,0 +1,193 @@ +use crate::RingBuffer; + +#[test] +fn for_each() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (mut prod, mut cons) = buf.split(); + + prod.push(10).unwrap(); + prod.push(20).unwrap(); + + let mut sum_1 = 0; + for v in cons.iter() { + sum_1 += *v; + } + + let first = cons.pop().expect("First element not available"); + let second = cons.pop().expect("Second element not available"); + + assert_eq!(sum_1, first + second); +} + +#[test] +fn for_each_mut() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (mut prod, mut cons) = buf.split(); + + prod.push(10).unwrap(); + prod.push(20).unwrap(); + + for v in cons.iter_mut() { + *v *= 2; + } + + let mut sum_1 = 0; + for v in cons.iter_mut() { + sum_1 += *v; + } + + let first = cons.pop().expect("First element not available"); + let second = cons.pop().expect("Second element not available"); + + assert_eq!(sum_1, first + second); +} + +#[test] +fn pop_each() { + let cap = 3; + let buf = RingBuffer::<i32>::new(cap); + let (mut prod, mut cons) = buf.split(); + + prod.push(10).unwrap(); + prod.push(20).unwrap(); + + let mut sum_1 = 0; + cons.pop_each( + |v| { + sum_1 += v; + v != 20 + }, + Some(2), + ); + + prod.push(30).unwrap(); + prod.push(40).unwrap(); + prod.push(50).unwrap(); + + cons.pop_each( + |v| { + sum_1 += v; + true + }, + Some(2), + ); + + prod.push(60).unwrap(); + + cons.pop_each( + |v| { + sum_1 += v; + v != 50 + }, + None, + ); + + prod.push(70).unwrap(); + + cons.pop_each( + |v| { + sum_1 += v; + true + }, + Some(2), + ); + + assert_eq!(sum_1, 10 + 20 + 30 + 40 + 50 + 60 + 70); +} + +#[test] +fn push_pop_slice() { + let buf = RingBuffer::<i32>::new(4); + let (mut prod, mut cons) = buf.split(); + + let mut tmp = [0; 5]; + + assert_eq!(prod.push_slice(&[]), 0); + assert_eq!(prod.push_slice(&[0, 1, 2]), 3); + + assert_eq!(cons.pop_slice(&mut tmp[0..2]), 2); + assert_eq!(tmp[0..2], [0, 1]); + + assert_eq!(prod.push_slice(&[3, 4]), 2); + assert_eq!(prod.push_slice(&[5, 6]), 1); + + assert_eq!(cons.pop_slice(&mut tmp[0..3]), 3); + assert_eq!(tmp[0..3], [2, 3, 4]); + + assert_eq!(prod.push_slice(&[6, 7, 8, 9]), 3); + + assert_eq!(cons.pop_slice(&mut tmp), 4); + assert_eq!(tmp[0..4], [5, 6, 7, 8]); +} + +#[test] +fn move_slice() { + let buf0 = RingBuffer::<i32>::new(4); + let buf1 = RingBuffer::<i32>::new(4); + let (mut prod0, mut cons0) = buf0.split(); + let (mut prod1, mut cons1) = buf1.split(); + + let mut tmp = [0; 5]; + + assert_eq!(prod0.push_slice(&[0, 1, 2]), 3); + + assert_eq!(prod1.move_from(&mut cons0, None), 3); + assert_eq!(prod1.move_from(&mut cons0, None), 0); + + assert_eq!(cons1.pop_slice(&mut tmp), 3); + assert_eq!(tmp[0..3], [0, 1, 2]); + + assert_eq!(prod0.push_slice(&[3, 4, 5]), 3); + + assert_eq!(prod1.move_from(&mut cons0, None), 3); + + assert_eq!(cons1.pop_slice(&mut tmp), 3); + assert_eq!(tmp[0..3], [3, 4, 5]); + + assert_eq!(prod1.push_slice(&[6, 7, 8]), 3); + assert_eq!(prod0.push_slice(&[9, 10]), 2); + + assert_eq!(prod1.move_from(&mut cons0, None), 1); + assert_eq!(prod1.move_from(&mut cons0, None), 0); + + assert_eq!(cons1.pop_slice(&mut tmp), 4); + assert_eq!(tmp[0..4], [6, 7, 8, 9]); +} + +#[test] +fn move_slice_count() { + let buf0 = RingBuffer::<i32>::new(4); + let buf1 = RingBuffer::<i32>::new(4); + let (mut prod0, mut cons0) = buf0.split(); + let (mut prod1, mut cons1) = buf1.split(); + + let mut tmp = [0; 5]; + + assert_eq!(prod0.push_slice(&[0, 1, 2]), 3); + + assert_eq!(prod1.move_from(&mut cons0, Some(2)), 2); + + assert_eq!(cons1.pop_slice(&mut tmp), 2); + assert_eq!(tmp[0..2], [0, 1]); + + assert_eq!(prod1.move_from(&mut cons0, Some(2)), 1); + + assert_eq!(cons1.pop_slice(&mut tmp), 1); + assert_eq!(tmp[0..1], [2]); + + assert_eq!(prod0.push_slice(&[3, 4, 5, 6]), 4); + + assert_eq!(prod1.move_from(&mut cons0, Some(3)), 3); + + assert_eq!(cons1.pop_slice(&mut tmp), 3); + assert_eq!(tmp[0..3], [3, 4, 5]); + + assert_eq!(prod0.push_slice(&[7, 8, 9]), 3); + + assert_eq!(prod1.move_from(&mut cons0, Some(5)), 4); + + assert_eq!(cons1.pop_slice(&mut tmp), 4); + assert_eq!(tmp[0..4], [6, 7, 8, 9]); +} diff --git a/third_party/rust/ringbuf/src/tests/read_write.rs b/third_party/rust/ringbuf/src/tests/read_write.rs new file mode 100644 index 0000000000..f09938c014 --- /dev/null +++ b/third_party/rust/ringbuf/src/tests/read_write.rs @@ -0,0 +1,159 @@ +use std::io; + +use crate::RingBuffer; + +#[test] +fn from() { + let buf0 = RingBuffer::<u8>::new(4); + let buf1 = RingBuffer::<u8>::new(4); + let (mut prod0, mut cons0) = buf0.split(); + let (mut prod1, mut cons1) = buf1.split(); + + let mut tmp = [0; 5]; + + assert_eq!(prod0.push_slice(&[0, 1, 2]), 3); + + match prod1.read_from(&mut cons0, None) { + Ok(n) => assert_eq!(n, 3), + other => panic!("{:?}", other), + } + match prod1.read_from(&mut cons0, None) { + Err(e) => { + assert_eq!(e.kind(), io::ErrorKind::WouldBlock); + } + other => panic!("{:?}", other), + } + + assert_eq!(cons1.pop_slice(&mut tmp), 3); + assert_eq!(tmp[0..3], [0, 1, 2]); + + assert_eq!(prod0.push_slice(&[3, 4, 5]), 3); + + match prod1.read_from(&mut cons0, None) { + Ok(n) => assert_eq!(n, 2), + other => panic!("{:?}", other), + } + assert_eq!(cons1.pop_slice(&mut tmp), 2); + assert_eq!(tmp[0..2], [3, 4]); + + match prod1.read_from(&mut cons0, None) { + Ok(n) => assert_eq!(n, 1), + other => panic!("{:?}", other), + } + assert_eq!(cons1.pop_slice(&mut tmp), 1); + assert_eq!(tmp[0..1], [5]); + + assert_eq!(prod1.push_slice(&[6, 7, 8]), 3); + assert_eq!(prod0.push_slice(&[9, 10]), 2); + + match prod1.read_from(&mut cons0, None) { + Ok(n) => assert_eq!(n, 1), + other => panic!("{:?}", other), + } + match prod1.read_from(&mut cons0, None) { + Ok(n) => assert_eq!(n, 0), + other => panic!("{:?}", other), + } + + assert_eq!(cons1.pop_slice(&mut tmp), 4); + assert_eq!(tmp[0..4], [6, 7, 8, 9]); +} + +#[test] +fn into() { + let buf0 = RingBuffer::<u8>::new(4); + let buf1 = RingBuffer::<u8>::new(4); + let (mut prod0, mut cons0) = buf0.split(); + let (mut prod1, mut cons1) = buf1.split(); + + let mut tmp = [0; 5]; + + assert_eq!(prod0.push_slice(&[0, 1, 2]), 3); + + match cons0.write_into(&mut prod1, None) { + Ok(n) => assert_eq!(n, 3), + other => panic!("{:?}", other), + } + match cons0.write_into(&mut prod1, None) { + Ok(n) => assert_eq!(n, 0), + other => panic!("{:?}", other), + } + + assert_eq!(cons1.pop_slice(&mut tmp), 3); + assert_eq!(tmp[0..3], [0, 1, 2]); + + assert_eq!(prod0.push_slice(&[3, 4, 5]), 3); + + match cons0.write_into(&mut prod1, None) { + Ok(n) => assert_eq!(n, 2), + other => panic!("{:?}", other), + } + assert_eq!(cons1.pop_slice(&mut tmp), 2); + assert_eq!(tmp[0..2], [3, 4]); + + match cons0.write_into(&mut prod1, None) { + Ok(n) => assert_eq!(n, 1), + other => panic!("{:?}", other), + } + assert_eq!(cons1.pop_slice(&mut tmp), 1); + assert_eq!(tmp[0..1], [5]); + + assert_eq!(prod1.push_slice(&[6, 7, 8]), 3); + assert_eq!(prod0.push_slice(&[9, 10]), 2); + + match cons0.write_into(&mut prod1, None) { + Ok(n) => assert_eq!(n, 1), + other => panic!("{:?}", other), + } + match cons0.write_into(&mut prod1, None) { + Err(e) => { + assert_eq!(e.kind(), io::ErrorKind::WouldBlock); + } + other => panic!("{:?}", other), + } + + assert_eq!(cons1.pop_slice(&mut tmp), 4); + assert_eq!(tmp[0..4], [6, 7, 8, 9]); +} + +#[test] +fn count() { + let buf0 = RingBuffer::<u8>::new(4); + let buf1 = RingBuffer::<u8>::new(4); + let (mut prod0, mut cons0) = buf0.split(); + let (mut prod1, mut cons1) = buf1.split(); + + let mut tmp = [0; 5]; + + assert_eq!(prod0.push_slice(&[0, 1, 2, 3]), 4); + + match prod1.read_from(&mut cons0, Some(3)) { + Ok(n) => assert_eq!(n, 3), + other => panic!("{:?}", other), + } + match prod1.read_from(&mut cons0, Some(2)) { + Ok(n) => assert_eq!(n, 1), + other => panic!("{:?}", other), + } + + assert_eq!(cons1.pop_slice(&mut tmp), 4); + assert_eq!(tmp[0..4], [0, 1, 2, 3]); + + assert_eq!(prod0.push_slice(&[4, 5, 6, 7]), 4); + + match cons0.write_into(&mut prod1, Some(3)) { + Ok(n) => assert_eq!(n, 1), + other => panic!("{:?}", other), + } + match cons0.write_into(&mut prod1, Some(2)) { + Ok(n) => assert_eq!(n, 2), + other => panic!("{:?}", other), + } + match cons0.write_into(&mut prod1, Some(2)) { + Ok(n) => assert_eq!(n, 1), + other => panic!("{:?}", other), + } + + assert_eq!(cons1.pop_slice(&mut tmp), 4); + assert_eq!(tmp[0..4], [4, 5, 6, 7]); +} diff --git a/third_party/rust/ringbuf/src/tests/single.rs b/third_party/rust/ringbuf/src/tests/single.rs new file mode 100644 index 0000000000..16f8af6455 --- /dev/null +++ b/third_party/rust/ringbuf/src/tests/single.rs @@ -0,0 +1,203 @@ +use crate::RingBuffer; +use core::sync::atomic::Ordering; +#[cfg(feature = "std")] +use std::thread; + +fn head_tail<T>(rb: &RingBuffer<T>) -> (usize, usize) { + ( + rb.head.load(Ordering::Acquire), + rb.tail.load(Ordering::Acquire), + ) +} + +#[test] +fn capacity() { + let cap = 13; + let buf = RingBuffer::<i32>::new(cap); + assert_eq!(buf.capacity(), cap); +} +#[test] +fn split_capacity() { + let cap = 13; + let buf = RingBuffer::<i32>::new(cap); + let (prod, cons) = buf.split(); + + assert_eq!(prod.capacity(), cap); + assert_eq!(cons.capacity(), cap); +} + +#[cfg(feature = "std")] +#[test] +fn split_threads() { + let buf = RingBuffer::<i32>::new(10); + let (prod, cons) = buf.split(); + + let pjh = thread::spawn(move || { + let _ = prod; + }); + + let cjh = thread::spawn(move || { + let _ = cons; + }); + + pjh.join().unwrap(); + cjh.join().unwrap(); +} + +#[test] +fn push() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (mut prod, _) = buf.split(); + + assert_eq!(head_tail(&prod.rb), (0, 0)); + + assert_eq!(prod.push(123), Ok(())); + assert_eq!(head_tail(&prod.rb), (0, 1)); + + assert_eq!(prod.push(234), Ok(())); + assert_eq!(head_tail(&prod.rb), (0, 2)); + + assert_eq!(prod.push(345), Err(345)); + assert_eq!(head_tail(&prod.rb), (0, 2)); +} + +#[test] +fn pop_empty() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (_, mut cons) = buf.split(); + + assert_eq!(head_tail(&cons.rb), (0, 0)); + + assert_eq!(cons.pop(), None); + assert_eq!(head_tail(&cons.rb), (0, 0)); +} + +#[test] +fn push_pop_one() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (mut prod, mut cons) = buf.split(); + + let vcap = cap + 1; + let values = [12, 34, 56, 78, 90]; + assert_eq!(head_tail(&cons.rb), (0, 0)); + + for (i, v) in values.iter().enumerate() { + assert_eq!(prod.push(*v), Ok(())); + assert_eq!(head_tail(&cons.rb), (i % vcap, (i + 1) % vcap)); + + assert_eq!(cons.pop().unwrap(), *v); + assert_eq!(head_tail(&cons.rb), ((i + 1) % vcap, (i + 1) % vcap)); + + assert_eq!(cons.pop(), None); + assert_eq!(head_tail(&cons.rb), ((i + 1) % vcap, (i + 1) % vcap)); + } +} + +#[test] +fn push_pop_all() { + let cap = 2; + let buf = RingBuffer::<i32>::new(cap); + let (mut prod, mut cons) = buf.split(); + + let vcap = cap + 1; + let values = [(12, 34, 13), (56, 78, 57), (90, 10, 91)]; + assert_eq!(head_tail(&cons.rb), (0, 0)); + + for (i, v) in values.iter().enumerate() { + assert_eq!(prod.push(v.0), Ok(())); + assert_eq!(head_tail(&cons.rb), (cap * i % vcap, (cap * i + 1) % vcap)); + + assert_eq!(prod.push(v.1), Ok(())); + assert_eq!(head_tail(&cons.rb), (cap * i % vcap, (cap * i + 2) % vcap)); + + assert_eq!(prod.push(v.2).unwrap_err(), v.2); + assert_eq!(head_tail(&cons.rb), (cap * i % vcap, (cap * i + 2) % vcap)); + + assert_eq!(cons.pop().unwrap(), v.0); + assert_eq!( + head_tail(&cons.rb), + ((cap * i + 1) % vcap, (cap * i + 2) % vcap) + ); + + assert_eq!(cons.pop().unwrap(), v.1); + assert_eq!( + head_tail(&cons.rb), + ((cap * i + 2) % vcap, (cap * i + 2) % vcap) + ); + + assert_eq!(cons.pop(), None); + assert_eq!( + head_tail(&cons.rb), + ((cap * i + 2) % vcap, (cap * i + 2) % vcap) + ); + } +} + +#[test] +fn empty_full() { + let buf = RingBuffer::<i32>::new(1); + let (mut prod, cons) = buf.split(); + + assert!(prod.is_empty()); + assert!(cons.is_empty()); + assert!(!prod.is_full()); + assert!(!cons.is_full()); + + assert_eq!(prod.push(123), Ok(())); + + assert!(!prod.is_empty()); + assert!(!cons.is_empty()); + assert!(prod.is_full()); + assert!(cons.is_full()); +} + +#[test] +fn len_remaining() { + let buf = RingBuffer::<i32>::new(2); + let (mut prod, mut cons) = buf.split(); + + assert_eq!(prod.len(), 0); + assert_eq!(cons.len(), 0); + assert_eq!(prod.remaining(), 2); + assert_eq!(cons.remaining(), 2); + + assert_eq!(prod.push(123), Ok(())); + + assert_eq!(prod.len(), 1); + assert_eq!(cons.len(), 1); + assert_eq!(prod.remaining(), 1); + assert_eq!(cons.remaining(), 1); + + assert_eq!(prod.push(456), Ok(())); + + assert_eq!(prod.len(), 2); + assert_eq!(cons.len(), 2); + assert_eq!(prod.remaining(), 0); + assert_eq!(cons.remaining(), 0); + + assert_eq!(cons.pop(), Some(123)); + + assert_eq!(prod.len(), 1); + assert_eq!(cons.len(), 1); + assert_eq!(prod.remaining(), 1); + assert_eq!(cons.remaining(), 1); + + assert_eq!(cons.pop(), Some(456)); + + assert_eq!(prod.len(), 0); + assert_eq!(cons.len(), 0); + assert_eq!(prod.remaining(), 2); + assert_eq!(cons.remaining(), 2); + + // now head is at 2, so tail will be at 0. This caught an overflow error + // when tail+1 < head because of the substraction of usize. + assert_eq!(prod.push(789), Ok(())); + + assert_eq!(prod.len(), 1); + assert_eq!(cons.len(), 1); + assert_eq!(prod.remaining(), 1); + assert_eq!(cons.remaining(), 1); +} |