diff --git a/futures/tests/io_lines.rs b/futures/tests/io_lines.rs index 5ce01a694..6dd1449ac 100644 --- a/futures/tests/io_lines.rs +++ b/futures/tests/io_lines.rs @@ -1,6 +1,6 @@ use futures::executor::block_on; use futures::future::{Future, FutureExt}; -use futures::io::{AsyncBufReadExt, Cursor}; +use futures::io::{AsyncBufReadExt, AsyncRead, Cursor}; use futures::stream::{self, StreamExt, TryStreamExt}; use futures::task::Poll; use futures_test::io::AsyncReadTestExt; @@ -27,6 +27,24 @@ macro_rules! run_next { }; } +struct IOErrorRead(bool); + +impl AsyncRead for IOErrorRead { + fn poll_read( + mut self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + b: &mut [u8], + ) -> Poll> { + if self.0 { + Poll::Ready(Err(std::io::ErrorKind::InvalidInput.into())) + } else { + self.0 = true; + b.fill(b'x'); + Ok(b.len()).into() + } + } +} + #[test] fn lines() { let buf = Cursor::new(&b"12\r"[..]); @@ -58,3 +76,9 @@ fn maybe_pending() { assert_eq!(run_next!(s), "".to_string()); assert!(run(s.next()).is_none()); } + +#[test] +fn issue2862() { + let mut lines = futures::io::BufReader::new(IOErrorRead(false)).lines(); + assert!(block_on(lines.next()).unwrap().is_err()) +} diff --git a/futures/tests/io_read_line.rs b/futures/tests/io_read_line.rs index 88a877928..1a99872a2 100644 --- a/futures/tests/io_read_line.rs +++ b/futures/tests/io_read_line.rs @@ -3,6 +3,7 @@ use futures::future::{Future, FutureExt}; use futures::io::{AsyncBufReadExt, Cursor}; use futures::stream::{self, StreamExt, TryStreamExt}; use futures::task::Poll; +use futures::AsyncRead; use futures_test::io::AsyncReadTestExt; use futures_test::task::noop_context; @@ -15,6 +16,24 @@ fn run(mut f: F) -> F::Output { } } +struct IOErrorRead(bool); + +impl AsyncRead for IOErrorRead { + fn poll_read( + mut self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + b: &mut [u8], + ) -> Poll> { + if self.0 { + Poll::Ready(Err(std::io::ErrorKind::InvalidInput.into())) + } else { + self.0 = true; + b.fill(b'x'); + Ok(b.len()).into() + } + } +} + #[test] fn read_line() { let mut buf = Cursor::new(b"12"); @@ -34,6 +53,30 @@ fn read_line() { assert_eq!(v, ""); } +#[test] +fn read_line_drop() { + // string contents should be preserved if the future is dropped + let mut buf = Cursor::new(b"12\n\n"); + let mut v = String::from("abc"); + drop(buf.read_line(&mut v)); + assert_eq!(v, "abc"); +} + +#[test] +fn read_line_io_error() { + let mut r = futures::io::BufReader::new(IOErrorRead(false)); + let _ = block_on(r.read_line(&mut String::new())); +} + +#[test] +fn read_line_utf8_error() { + let mut buf = Cursor::new(b"12\xFF\n\n"); + let mut v = String::from("abc"); + let res = block_on(buf.read_line(&mut v)); + assert_eq!(res.unwrap_err().kind(), std::io::ErrorKind::InvalidData); + assert_eq!(v, "abc"); +} + #[test] fn maybe_pending() { let mut buf = b"12".interleave_pending();