#![feature(test)]
#![feature(core_io_borrowed_buf)]
#![allow(unused)]
extern crate test;
use std::{
io::BorrowedBuf,
mem::MaybeUninit,
panic,
sync::atomic::{AtomicUsize, Ordering},
};
use axio::{
BufReader, BufWriter, Cursor, Error, LineWriter, Result, SeekFrom, empty, prelude::*, sink,
};
pub struct ShortReader {
lengths: Vec<usize>,
}
impl Read for ShortReader {
fn read(&mut self, _: &mut [u8]) -> Result<usize> {
if self.lengths.is_empty() {
Ok(0)
} else {
Ok(self.lengths.remove(0))
}
}
}
#[test]
fn test_buffered_reader() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, inner);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 3);
assert_eq!(buf, [5, 6, 7]);
assert_eq!(reader.buffer(), []);
let mut buf = [0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 2);
assert_eq!(buf, [0, 1]);
assert_eq!(reader.buffer(), []);
let mut buf = [0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
assert_eq!(buf, [2]);
assert_eq!(reader.buffer(), [3]);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
assert_eq!(buf, [3, 0, 0]);
assert_eq!(reader.buffer(), []);
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
assert_eq!(buf, [4, 0, 0]);
assert_eq!(reader.buffer(), []);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_buffered_reader_read_buf() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, inner);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 3];
let mut buf: BorrowedBuf<'_> = buf.into();
reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [5, 6, 7]);
assert_eq!(reader.buffer(), []);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 2];
let mut buf: BorrowedBuf<'_> = buf.into();
reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [0, 1]);
assert_eq!(reader.buffer(), []);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1];
let mut buf: BorrowedBuf<'_> = buf.into();
reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [2]);
assert_eq!(reader.buffer(), [3]);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 3];
let mut buf: BorrowedBuf<'_> = buf.into();
reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [3]);
assert_eq!(reader.buffer(), []);
reader.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.filled(), [3, 4]);
assert_eq!(reader.buffer(), []);
buf.clear();
reader.read_buf(buf.unfilled()).unwrap();
assert!(buf.filled().is_empty());
}
#[test]
fn test_buffered_reader_seek() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, Cursor::new(inner));
assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3));
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert_eq!(reader.stream_position().ok(), Some(3));
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4));
assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..]));
reader.consume(1);
assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3));
}
#[test]
fn test_buffered_reader_seek_relative() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, Cursor::new(inner));
assert!(reader.seek_relative(3).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert!(reader.seek_relative(0).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert!(reader.seek_relative(1).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[1][..]));
assert!(reader.seek_relative(-1).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert!(reader.seek_relative(2).is_ok());
assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..]));
}
#[test]
fn test_buffered_reader_stream_position() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, Cursor::new(inner));
assert_eq!(reader.stream_position().ok(), Some(0));
assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3));
assert_eq!(reader.stream_position().ok(), Some(3));
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
assert!(reader.seek_relative(0).is_ok());
assert_eq!(reader.stream_position().ok(), Some(3));
assert_eq!(reader.buffer(), &[0, 1][..]);
assert!(reader.seek_relative(1).is_ok());
assert_eq!(reader.stream_position().ok(), Some(4));
assert_eq!(reader.buffer(), &[1][..]);
assert!(reader.seek_relative(-1).is_ok());
assert_eq!(reader.stream_position().ok(), Some(3));
assert_eq!(reader.buffer(), &[0, 1][..]);
assert!(reader.seek_relative(2).is_ok());
assert_eq!(reader.stream_position().ok(), Some(5));
assert_eq!(reader.buffer(), &[][..]);
}
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_buffered_reader_stream_position_panic() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(4, Cursor::new(inner));
let mut buffer = [0, 0];
assert!(reader.read_exact(&mut buffer).is_ok());
let inner = reader.get_mut();
assert!(inner.seek(SeekFrom::Start(0)).is_ok());
let result = panic::catch_unwind(panic::AssertUnwindSafe(|| reader.stream_position().ok()));
assert!(result.is_err());
}
#[test]
fn test_buffered_reader_invalidated_after_read() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(3, Cursor::new(inner));
assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..]));
reader.consume(3);
let mut buffer = [0, 0, 0, 0, 0];
assert_eq!(reader.read(&mut buffer).ok(), Some(5));
assert_eq!(buffer, [0, 1, 2, 3, 4]);
assert!(reader.seek_relative(-2).is_ok());
let mut buffer = [0, 0];
assert_eq!(reader.read(&mut buffer).ok(), Some(2));
assert_eq!(buffer, [3, 4]);
}
#[test]
fn test_buffered_reader_invalidated_after_seek() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(3, Cursor::new(inner));
assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..]));
reader.consume(3);
assert!(reader.seek(SeekFrom::Current(5)).is_ok());
assert!(reader.seek_relative(-2).is_ok());
let mut buffer = [0, 0];
assert_eq!(reader.read(&mut buffer).ok(), Some(2));
assert_eq!(buffer, [3, 4]);
}
#[test]
fn test_buffered_reader_seek_underflow() {
struct PositionReader {
pos: u64,
}
impl Read for PositionReader {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let len = buf.len();
for x in buf {
*x = self.pos as u8;
self.pos = self.pos.wrapping_add(1);
}
Ok(len)
}
}
impl Seek for PositionReader {
fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
match pos {
SeekFrom::Start(n) => {
self.pos = n;
}
SeekFrom::Current(n) => {
self.pos = self.pos.wrapping_add(n as u64);
}
SeekFrom::End(n) => {
self.pos = u64::MAX.wrapping_add(n as u64);
}
}
Ok(self.pos)
}
}
let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 });
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..]));
assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::MAX - 5));
assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
let expected = 9223372036854775802;
assert_eq!(
reader.seek(SeekFrom::Current(i64::MIN)).ok(),
Some(expected)
);
assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected));
assert_eq!(reader.get_ref().pos, expected);
}
#[test]
fn test_buffered_reader_seek_underflow_discard_buffer_between_seeks() {
struct ErrAfterFirstSeekReader {
first_seek: bool,
}
impl Read for ErrAfterFirstSeekReader {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
for x in &mut *buf {
*x = 0;
}
Ok(buf.len())
}
}
impl Seek for ErrAfterFirstSeekReader {
fn seek(&mut self, _: SeekFrom) -> Result<u64> {
if self.first_seek {
self.first_seek = false;
Ok(0)
} else {
Err(Error::Io)
}
}
}
let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true });
assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..]));
assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err());
assert_eq!(reader.buffer().len(), 0);
}
#[cfg(feature = "alloc")]
#[test]
fn test_buffered_reader_read_to_end_consumes_buffer() {
let data: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7];
let mut reader = BufReader::with_capacity(3, data);
let mut buf = Vec::new();
assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2][..]));
assert_eq!(reader.read_to_end(&mut buf).ok(), Some(8));
assert_eq!(&buf, &[0, 1, 2, 3, 4, 5, 6, 7]);
assert!(reader.buffer().is_empty());
}
#[cfg(feature = "alloc")]
#[test]
fn test_buffered_reader_read_to_string_consumes_buffer() {
let data: &[u8] = "deadbeef".as_bytes();
let mut reader = BufReader::with_capacity(3, data);
let mut buf = String::new();
assert_eq!(reader.fill_buf().ok(), Some("dea".as_bytes()));
assert_eq!(reader.read_to_string(&mut buf).ok(), Some(8));
assert_eq!(&buf, "deadbeef");
assert!(reader.buffer().is_empty());
}
#[cfg(feature = "alloc")]
#[test]
fn test_buffered_writer() {
let inner = Vec::new();
let mut writer = BufWriter::with_capacity(2, inner);
writer.write(&[0, 1]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[2]).unwrap();
assert_eq!(writer.buffer(), [2]);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[3]).unwrap();
assert_eq!(writer.buffer(), [2, 3]);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.flush().unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[4]).unwrap();
writer.write(&[5]).unwrap();
assert_eq!(writer.buffer(), [4, 5]);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[6]).unwrap();
assert_eq!(writer.buffer(), [6]);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]);
writer.write(&[7, 8]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]);
writer.write(&[9, 10, 11]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
writer.flush().unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
}
#[cfg(feature = "alloc")]
#[test]
fn test_buffered_writer_inner_flushes() {
let mut w = BufWriter::with_capacity(3, Vec::new());
w.write(&[0, 1]).unwrap();
assert_eq!(*w.get_ref(), []);
let w = w.into_inner().unwrap();
assert_eq!(w, [0, 1]);
}
#[cfg(feature = "alloc")]
#[test]
fn test_buffered_writer_seek() {
let mut w = BufWriter::with_capacity(3, Cursor::new(Vec::new()));
w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap();
w.write_all(&[6, 7]).unwrap();
assert_eq!(w.stream_position().ok(), Some(8));
assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]);
assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2));
w.write_all(&[8, 9]).unwrap();
assert_eq!(
&w.into_inner().unwrap().into_inner()[..],
&[0, 1, 8, 9, 4, 5, 6, 7]
);
}
#[cfg(feature = "alloc")]
#[test]
fn test_read_until() {
let inner: &[u8] = &[0, 1, 2, 1, 0];
let mut reader = BufReader::with_capacity(2, inner);
let mut v = Vec::new();
reader.read_until(0, &mut v).unwrap();
assert_eq!(v, [0]);
v.truncate(0);
reader.read_until(2, &mut v).unwrap();
assert_eq!(v, [1, 2]);
v.truncate(0);
reader.read_until(1, &mut v).unwrap();
assert_eq!(v, [1]);
v.truncate(0);
reader.read_until(8, &mut v).unwrap();
assert_eq!(v, [0]);
v.truncate(0);
reader.read_until(9, &mut v).unwrap();
assert_eq!(v, []);
}
#[cfg(feature = "alloc")]
#[test]
fn test_line_buffer() {
let mut writer = LineWriter::new(Vec::new());
writer.write(&[0]).unwrap();
assert_eq!(*writer.get_ref(), []);
writer.write(&[1]).unwrap();
assert_eq!(*writer.get_ref(), []);
writer.flush().unwrap();
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']);
writer.flush().unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]);
writer.write(&[3, b'\n']).unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']);
}
#[cfg(feature = "alloc")]
#[test]
fn test_read_line() {
let in_buf: &[u8] = b"a\nb\nc";
let mut reader = BufReader::with_capacity(2, in_buf);
let mut s = String::new();
reader.read_line(&mut s).unwrap();
assert_eq!(s, "a\n");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "b\n");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "c");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "");
}
#[cfg(feature = "alloc")]
#[test]
fn test_lines() {
let in_buf: &[u8] = b"a\nb\nc";
let reader = BufReader::with_capacity(2, in_buf);
let mut it = reader.lines();
assert_eq!(it.next().unwrap().unwrap(), "a".to_string());
assert_eq!(it.next().unwrap().unwrap(), "b".to_string());
assert_eq!(it.next().unwrap().unwrap(), "c".to_string());
assert!(it.next().is_none());
}
#[test]
fn test_short_reads() {
let inner = ShortReader {
lengths: vec![0, 1, 2, 0, 1, 0],
};
let mut reader = BufReader::new(inner);
let mut buf = [0, 0];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.read(&mut buf).unwrap(), 2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
#[should_panic]
fn dont_panic_in_drop_on_panicked_flush() {
struct FailFlushWriter;
impl Write for FailFlushWriter {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
Ok(buf.len())
}
fn flush(&mut self) -> Result<()> {
Err(Error::Io)
}
}
let writer = FailFlushWriter;
let _writer = BufWriter::new(writer);
panic!();
}
#[test]
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] fn panic_in_write_doesnt_flush_in_drop() {
static WRITES: AtomicUsize = AtomicUsize::new(0);
struct PanicWriter;
impl Write for PanicWriter {
fn write(&mut self, _: &[u8]) -> Result<usize> {
WRITES.fetch_add(1, Ordering::SeqCst);
panic!();
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
std::thread::spawn(|| {
let mut writer = BufWriter::new(PanicWriter);
let _ = writer.write(b"hello world");
let _ = writer.flush();
})
.join()
.unwrap_err();
assert_eq!(WRITES.load(Ordering::SeqCst), 1);
}
#[bench]
fn bench_buffered_reader(b: &mut test::Bencher) {
b.iter(|| BufReader::new(empty()));
}
#[bench]
fn bench_buffered_reader_small_reads(b: &mut test::Bencher) {
let data = (0..u8::MAX).cycle().take(1024 * 4).collect::<Vec<_>>();
b.iter(|| {
let mut reader = BufReader::new(&data[..]);
let mut buf = [0u8; 4];
for _ in 0..1024 {
reader.read_exact(&mut buf).unwrap();
core::hint::black_box(&buf);
}
});
}
#[bench]
fn bench_buffered_writer(b: &mut test::Bencher) {
b.iter(|| BufWriter::new(sink()));
}
#[derive(Default, Clone)]
struct ProgrammableSink {
pub buffer: Vec<u8>,
pub always_write_error: bool,
pub always_flush_error: bool,
pub accept_prefix: Option<usize>,
pub max_writes: Option<usize>,
pub error_after_max_writes: bool,
}
impl Write for ProgrammableSink {
fn write(&mut self, data: &[u8]) -> Result<usize> {
if self.always_write_error {
return Err(Error::Io);
}
match self.max_writes {
Some(0) if self.error_after_max_writes => {
return Err(Error::Io);
}
Some(0) => return Ok(0),
Some(ref mut count) => *count -= 1,
None => {}
}
let len = match self.accept_prefix {
None => data.len(),
Some(prefix) => data.len().min(prefix),
};
let data = &data[..len];
self.buffer.extend_from_slice(data);
Ok(len)
}
fn flush(&mut self) -> Result<()> {
if self.always_flush_error {
Err(Error::Io)
} else {
Ok(())
}
}
}
#[test]
fn erroneous_flush_retried() {
let writer = ProgrammableSink {
accept_prefix: Some(4),
max_writes: Some(2),
error_after_max_writes: true,
..Default::default()
};
let mut writer = LineWriter::new(writer);
assert_eq!(writer.write(b"a\nb\nc\nd\ne").unwrap(), 8);
assert_eq!(writer.write(b"e").unwrap(), 1);
assert_eq!(&writer.get_ref().buffer, b"a\nb\nc\nd\n");
}
#[test]
fn partial_write_buffers_line() {
let writer = ProgrammableSink {
accept_prefix: Some(13),
..Default::default()
};
let mut writer = LineWriter::new(writer);
assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3\nLine4").unwrap(), 21);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2");
assert_eq!(writer.write(b"Line 4").unwrap(), 6);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
}
#[test]
fn partial_line_buffered_after_line_write() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::new(writer);
assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3").unwrap(), 20);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\n");
assert!(writer.flush().is_ok());
assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3");
}
#[cfg(feature = "alloc")]
#[test]
fn long_line_flushed() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::with_capacity(5, writer);
assert_eq!(writer.write(b"0123456789").unwrap(), 10);
assert_eq!(&writer.get_ref().buffer, b"0123456789");
}
#[cfg(feature = "alloc")]
#[test]
fn line_long_tail_not_flushed() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::with_capacity(5, writer);
let bytes = b"Line 1\n0123456789";
writer.write(bytes).unwrap();
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
}
#[cfg(feature = "alloc")]
#[test]
fn line_full_buffer_flushed() {
let writer = ProgrammableSink::default();
let mut writer = LineWriter::with_capacity(5, writer);
assert_eq!(writer.write(b"01234").unwrap(), 5);
assert_eq!(writer.write(b"5").unwrap(), 1);
assert_eq!(&writer.get_ref().buffer, b"01234");
}
#[test]
fn line_buffer_write0_error() {
let writer = ProgrammableSink {
max_writes: Some(1),
..Default::default()
};
let mut writer = LineWriter::new(writer);
assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
let err = writer.write(b" Line End\n").unwrap_err();
assert_eq!(err, Error::WriteZero);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
}
#[test]
fn line_buffer_write0_normal() {
let writer = ProgrammableSink {
max_writes: Some(2),
..Default::default()
};
let mut writer = LineWriter::new(writer);
assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14);
assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
assert_eq!(writer.write(b" Line End\n").unwrap(), 0);
assert_eq!(&writer.get_ref().buffer, b"Line 1\nPartial");
}
#[test]
fn line_write_all() {
let writer = ProgrammableSink {
accept_prefix: Some(5),
..Default::default()
};
let mut writer = LineWriter::new(writer);
writer
.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial")
.unwrap();
assert_eq!(
&writer.get_ref().buffer,
b"Line 1\nLine 2\nLine 3\nLine 4\n"
);
writer.write_all(b" Line 5\n").unwrap();
assert_eq!(
writer.get_ref().buffer.as_slice(),
b"Line 1\nLine 2\nLine 3\nLine 4\nPartial Line 5\n".as_ref(),
);
}
#[test]
fn line_write_all_error() {
let writer = ProgrammableSink {
accept_prefix: Some(5),
max_writes: Some(3),
..Default::default()
};
let mut writer = LineWriter::new(writer);
let res = writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial");
assert!(res.is_err());
}
#[cfg(feature = "alloc")]
#[test]
fn partial_multiline_buffering() {
let writer = ProgrammableSink {
accept_prefix: Some(5),
..Default::default()
};
let mut writer = LineWriter::with_capacity(10, writer);
let content = b"AAAAABBBBB\nCCCCDDDDDD\nEEE";
assert_eq!(writer.write(content).unwrap(), 11);
assert_eq!(writer.get_ref().buffer, *b"AAAAA");
writer.flush().unwrap();
assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB\n");
}
#[cfg(feature = "alloc")]
#[test]
fn partial_multiline_buffering_without_full_line() {
let writer = ProgrammableSink {
accept_prefix: Some(5),
..Default::default()
};
let mut writer = LineWriter::with_capacity(5, writer);
let content = b"AAAAABBBBBBBBBB\nCCCCC\nDDDDD";
assert_eq!(writer.write(content).unwrap(), 10);
assert_eq!(writer.get_ref().buffer, *b"AAAAA");
writer.flush().unwrap();
assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB");
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum RecordedEvent {
Write(String),
Flush,
}
#[derive(Debug, Clone, Default)]
struct WriteRecorder {
pub events: Vec<RecordedEvent>,
}
impl Write for WriteRecorder {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.events.push(RecordedEvent::Write(
str::from_utf8(buf).unwrap().to_string(),
));
Ok(buf.len())
}
fn flush(&mut self) -> Result<()> {
self.events.push(RecordedEvent::Flush);
Ok(())
}
}
#[test]
fn single_formatted_write() {
let writer = WriteRecorder::default();
let mut writer = LineWriter::new(writer);
#[allow(clippy::write_literal)]
writeln!(&mut writer, "{}, {}!", "hello", "world").unwrap();
assert_eq!(
writer.get_ref().events,
[RecordedEvent::Write("hello, world!\n".to_string())]
);
}