| mod io { |
| use std::io::{BufRead, ErrorKind, Read, Write}; |
| |
| use gix_features::io; |
| |
| #[test] |
| fn threaded_read_to_end() { |
| let (mut writer, mut reader) = gix_features::io::pipe::unidirectional(0); |
| |
| let message = "Hello, world!"; |
| std::thread::spawn(move || { |
| writer |
| .write_all(message.as_bytes()) |
| .expect("writes to work if reader is present") |
| }); |
| |
| let mut received = String::new(); |
| reader.read_to_string(&mut received).unwrap(); |
| |
| assert_eq!(&received, message); |
| } |
| |
| #[test] |
| fn lack_of_reader_fails_with_broken_pipe() { |
| let (mut writer, _) = io::pipe::unidirectional(0); |
| assert_eq!( |
| writer.write_all(b"must fail").unwrap_err().kind(), |
| ErrorKind::BrokenPipe |
| ); |
| } |
| #[test] |
| fn line_reading_one_by_one() { |
| let (mut writer, mut reader) = io::pipe::unidirectional(2); |
| writer.write_all(b"a\n").expect("success"); |
| writer.write_all(b"b\nc").expect("success"); |
| drop(writer); |
| let mut buf = String::new(); |
| for expected in &["a\n", "b\n", "c"] { |
| buf.clear(); |
| assert_eq!(reader.read_line(&mut buf).expect("success"), expected.len()); |
| assert_eq!(buf, *expected); |
| } |
| } |
| |
| #[test] |
| fn line_reading() { |
| let (mut writer, reader) = io::pipe::unidirectional(2); |
| writer.write_all(b"a\n").expect("success"); |
| writer.write_all(b"b\nc\n").expect("success"); |
| drop(writer); |
| assert_eq!( |
| reader.lines().map_while(Result::ok).collect::<Vec<_>>(), |
| vec!["a", "b", "c"] |
| ) |
| } |
| |
| #[test] |
| fn writer_can_inject_errors() { |
| let (writer, mut reader) = io::pipe::unidirectional(1); |
| writer |
| .channel |
| .send(Err(std::io::Error::new(std::io::ErrorKind::Other, "the error"))) |
| .expect("send success"); |
| let mut buf = [0]; |
| assert_eq!( |
| reader.read(&mut buf).unwrap_err().to_string(), |
| "the error", |
| "using Read trait, errors are propagated" |
| ); |
| |
| writer |
| .channel |
| .send(Err(std::io::Error::new(std::io::ErrorKind::Other, "the error"))) |
| .expect("send success"); |
| assert_eq!( |
| reader.fill_buf().unwrap_err().to_string(), |
| "the error", |
| "using BufRead trait, errors are propagated" |
| ); |
| } |
| |
| #[test] |
| fn continue_on_empty_writes() { |
| let (mut writer, mut reader) = io::pipe::unidirectional(2); |
| writer.write_all(&[]).expect("write successful and non-blocking"); |
| let input = b"hello"; |
| writer |
| .write_all(input) |
| .expect("second write works as well as there is capacity"); |
| let mut buf = vec![0u8; input.len()]; |
| assert_eq!(reader.read(&mut buf).expect("read succeeds"), input.len()); |
| assert_eq!(buf, &input[..]); |
| } |
| |
| #[test] |
| fn small_reads() { |
| const BLOCK_SIZE: usize = 20; |
| let block_count = 20; |
| let (mut writer, mut reader) = io::pipe::unidirectional(4); |
| std::thread::spawn(move || { |
| for _ in 0..block_count { |
| let data = &[0; BLOCK_SIZE]; |
| writer.write_all(data).unwrap(); |
| } |
| }); |
| |
| let mut small_read_buf = [0; BLOCK_SIZE / 2]; |
| let mut bytes_read = 0; |
| while let Ok(size) = reader.read(&mut small_read_buf) { |
| if size == 0 { |
| break; |
| } |
| bytes_read += size; |
| } |
| assert_eq!(block_count * BLOCK_SIZE, bytes_read); |
| } |
| } |