use std::{ io::{self, prelude::*, Cursor}, sync::{Arc, Mutex}, thread, time::Duration, }; #[cfg(feature = "async")] use futures_lite::AsyncBufReadExt; #[cfg(feature = "async")] use futures_lite::AsyncReadExt; use expectrl::session; use expectrl::spawn; #[test] #[cfg(windows)] #[cfg(not(feature = "async"))] fn log() { let writer = StubWriter::default(); let mut session = session::log( spawn("python ./tests/actions/cat/main.py").unwrap(), writer.clone(), ) .unwrap(); thread::sleep(Duration::from_millis(300)); session.send_line("Hello World").unwrap(); thread::sleep(Duration::from_millis(300)); let mut buf = vec![0; 1024]; let _ = session.read(&mut buf).unwrap(); let bytes = writer.inner.lock().unwrap(); let log_str = String::from_utf8_lossy(bytes.get_ref()); assert!(log_str.as_ref().contains("write")); assert!(log_str.as_ref().contains("read")); } #[test] #[cfg(windows)] #[cfg(feature = "async")] fn log() { futures_lite::future::block_on(async { let writer = StubWriter::default(); let mut session = session::log( spawn("python ./tests/actions/cat/main.py").unwrap(), writer.clone(), ) .unwrap(); thread::sleep(Duration::from_millis(300)); session.send_line("Hello World").await.unwrap(); thread::sleep(Duration::from_millis(300)); let mut buf = vec![0; 1024]; let _ = session.read(&mut buf).await.unwrap(); let bytes = writer.inner.lock().unwrap(); let log_str = String::from_utf8_lossy(bytes.get_ref()); assert!(log_str.as_ref().contains("write")); assert!(log_str.as_ref().contains("read")); }); } #[test] #[cfg(unix)] fn log() { let writer = StubWriter::default(); #[cfg(feature = "async")] futures_lite::future::block_on(async { let mut session = session::log(spawn("cat").unwrap(), writer.clone()).unwrap(); session.send_line("Hello World").await.unwrap(); // give some time to cat // since sometimes we doesn't keep up to read whole string thread::sleep(Duration::from_millis(300)); let mut buf = vec![0; 1024]; let _ = session.read(&mut buf).await.unwrap(); let bytes = writer.inner.lock().unwrap(); let text = String::from_utf8_lossy(bytes.get_ref()); assert!( text.contains("read") && text.contains("write"), "unexpected output {text:?}" ); }); #[cfg(not(feature = "async"))] { let mut session = session::log(spawn("cat").unwrap(), writer.clone()).unwrap(); session.send_line("Hello World").unwrap(); // give some time to cat // since sometimes we doesn't keep up to read whole string thread::sleep(Duration::from_millis(300)); let mut buf = vec![0; 1024]; let _ = session.read(&mut buf).unwrap(); let bytes = writer.inner.lock().unwrap(); let text = String::from_utf8_lossy(bytes.get_ref()); assert!( text.contains("read") && text.contains("write"), "unexpected output {text:?}" ); } } #[test] #[cfg(unix)] fn log_read_line() { let writer = StubWriter::default(); #[cfg(feature = "async")] futures_lite::future::block_on(async { let mut session = session::log(spawn("cat").unwrap(), writer.clone()).unwrap(); session.send_line("Hello World").await.unwrap(); let mut buf = String::new(); let _ = session.read_line(&mut buf).await.unwrap(); assert_eq!(buf, "Hello World\r\n"); let bytes = writer.inner.lock().unwrap(); let text = String::from_utf8_lossy(bytes.get_ref()); assert!( text.contains("read") && text.contains("write"), "unexpected output {text:?}" ); }); #[cfg(not(feature = "async"))] { let mut session = session::log(spawn("cat").unwrap(), writer.clone()).unwrap(); session.send_line("Hello World").unwrap(); let mut buf = String::new(); let _ = session.read_line(&mut buf).unwrap(); assert_eq!(buf, "Hello World\r\n"); let bytes = writer.inner.lock().unwrap(); let text = String::from_utf8_lossy(bytes.get_ref()); if !matches!( text.as_ref(), "write: \"Hello World\\n\"\nread: \"Hello World\"\nread: \"\\r\\n\"\n" | "write: \"Hello World\\n\"\nread: \"Hello World\\r\\n\"\n" | "write: \"Hello World\"\nwrite: \"\\n\"\nread: \"Hello World\\r\\n\"\n", ) { panic!("unexpected output {text:?}"); } } } #[derive(Debug, Clone, Default)] struct StubWriter { inner: Arc>>>, } impl Write for StubWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.lock().unwrap().write(buf) } fn flush(&mut self) -> io::Result<()> { self.inner.lock().unwrap().flush() } }