#![cfg(windows)]
use std::sync::{Arc, Mutex};
use std::time::Duration;
use rust_expect::{Pattern, Session};
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn bytes_pattern_matches_once_enough_received() {
let mut session = Session::spawn("cmd.exe", &["/c", "exit 0"])
.await
.expect("spawn cmd.exe");
let m = session
.expect_timeout(Pattern::bytes(3), Duration::from_secs(10))
.await
.expect("Bytes(3) should match once >=3 bytes arrive");
assert_eq!(
m.matched.len(),
3,
"Bytes(3) should consume exactly 3 bytes, got {:?}",
m.matched
);
session.wait_timeout(Duration::from_secs(5)).await.ok();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn bytes_pattern_waits_for_enough_data() {
let mut session = Session::spawn("cmd.exe", &["/c", "exit 0"])
.await
.expect("spawn cmd.exe");
let result = session
.expect_timeout(Pattern::bytes(1_000_000), Duration::from_secs(2))
.await;
assert!(
result.is_err(),
"Bytes(1_000_000) must not match on a tiny output (got {result:?})"
);
session.wait_timeout(Duration::from_secs(5)).await.ok();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn drains_buffered_output_on_exit() {
let mut session = Session::spawn("cmd.exe", &["/c", "exit 0"])
.await
.expect("spawn cmd.exe");
let captured: Arc<Mutex<Vec<u8>>> = Arc::new(Mutex::new(Vec::new()));
let sink = Arc::clone(&captured);
session.add_output_tap(move |chunk: &[u8]| sink.lock().unwrap().extend_from_slice(chunk));
session
.wait_timeout(Duration::from_secs(10))
.await
.expect("child should exit");
let bytes = captured.lock().unwrap().clone();
assert!(
bytes.len() > 40,
"buffered ConPTY output was truncated on exit: drained only {} bytes ({:?})",
bytes.len(),
String::from_utf8_lossy(&bytes)
);
}