use std::convert::Infallible;
use bytesbuf::mem::testing::TransparentMemory;
use bytesbuf::mem::{HasMemory, Memory, MemoryShared, OpaqueMemory};
use bytesbuf::{BytesBuf, BytesView};
use crate::Write;
#[derive(Debug)]
pub struct FakeWrite {
contents: BytesBuf,
memory: OpaqueMemory,
}
impl FakeWrite {
#[must_use]
pub fn builder() -> FakeWriteBuilder {
FakeWriteBuilder {
memory: OpaqueMemory::new(TransparentMemory::new()),
}
}
#[must_use]
pub fn new() -> Self {
Self::builder().build()
}
#[must_use]
pub fn into_contents(mut self) -> BytesView {
self.contents.consume_all()
}
#[must_use]
pub fn contents(&self) -> &BytesBuf {
&self.contents
}
#[expect(clippy::unused_async, reason = "API compatibility between trait and inherent fn")]
pub async fn write(&mut self, data: BytesView) -> Result<(), Infallible> {
self.contents.put_bytes(data);
Ok(())
}
#[must_use]
pub fn memory(&self) -> impl MemoryShared {
self.memory.clone()
}
#[must_use]
pub fn reserve(&self, min_bytes: usize) -> BytesBuf {
self.memory.reserve(min_bytes)
}
}
impl Default for FakeWrite {
fn default() -> Self {
Self::new()
}
}
#[cfg_attr(coverage_nightly, coverage(off))] impl Write for FakeWrite {
type Error = Infallible;
#[cfg_attr(test, mutants::skip)] async fn write(&mut self, data: BytesView) -> Result<(), Infallible> {
self.write(data).await
}
}
#[cfg_attr(coverage_nightly, coverage(off))] impl Memory for FakeWrite {
#[cfg_attr(test, mutants::skip)] fn reserve(&self, min_bytes: usize) -> BytesBuf {
self.reserve(min_bytes)
}
}
#[cfg_attr(coverage_nightly, coverage(off))] impl HasMemory for FakeWrite {
#[cfg_attr(test, mutants::skip)] fn memory(&self) -> impl MemoryShared {
self.memory()
}
}
#[derive(Debug)]
pub struct FakeWriteBuilder {
memory: OpaqueMemory,
}
impl FakeWriteBuilder {
#[must_use]
pub fn memory(mut self, memory: OpaqueMemory) -> Self {
self.memory = memory;
self
}
#[must_use]
pub fn build(self) -> FakeWrite {
FakeWrite {
contents: BytesBuf::new(),
memory: self.memory,
}
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use bytesbuf::mem::CallbackMemory;
use testing_aids::async_test;
use super::*;
use crate::WriteExt;
#[test]
fn smoke_test() {
async_test(async || {
let mut write_stream = FakeWrite::new();
write_stream
.prepare_and_write(1234, |mut buf| {
buf.put_byte(1);
buf.put_byte(2);
buf.put_byte(3);
Ok::<BytesView, Infallible>(buf.consume_all())
})
.await
.unwrap();
assert_eq!(write_stream.contents().len(), 3);
let mut contents = write_stream.into_contents();
assert_eq!(contents.len(), 3);
assert_eq!(contents.get_byte(), 1);
assert_eq!(contents.get_byte(), 2);
assert_eq!(contents.get_byte(), 3);
assert_eq!(contents.len(), 0);
});
}
#[test]
fn default_returns_working_instance() {
async_test(async || {
let mut write_stream = FakeWrite::default();
write_stream
.prepare_and_write(10, |mut buf| {
buf.put_byte(42);
Ok::<BytesView, Infallible>(buf.consume_all())
})
.await
.unwrap();
assert_eq!(write_stream.contents().len(), 1);
let mut contents = write_stream.into_contents();
assert_eq!(contents.get_byte(), 42);
});
}
#[test]
fn memory_returns_configured_provider() {
let callback_called = Arc::new(AtomicBool::new(false));
let custom_memory = OpaqueMemory::new(CallbackMemory::new({
let callback_called = Arc::clone(&callback_called);
move |min_bytes| {
callback_called.store(true, Ordering::SeqCst);
TransparentMemory::new().reserve(min_bytes)
}
}));
let write_stream = FakeWrite::builder().memory(custom_memory).build();
let stream_memory = write_stream.memory();
let _buf = stream_memory.reserve(10);
assert!(
callback_called.load(Ordering::SeqCst),
"Custom memory callback should have been called"
);
}
}