#![cfg(all(windows, feature = "blocking"))]
pub mod helpers;
use std::time::{Duration, Instant};
use conpty_oxide::blocking::{Command, Session};
use helpers::{wait_until, with_timeout};
const FLOOD: &str = "/c for /l %i in (1,1,4000) do @echo \
0123456789012345678901234567890123456789012345678901234567890123456789";
const BUDGET: Duration = Duration::from_secs(20);
const FILL: Duration = Duration::from_millis(500);
const TEARDOWN_BUDGET: Duration = Duration::from_secs(5);
fn drop_order_completes(teardown: impl FnOnce(Session)) {
with_timeout(BUDGET, || {
let mut session = Command::new("cmd.exe")
.raw_arg(FLOOD)
.spawn()
.expect("spawning must succeed");
let exited = wait_until(FILL, || {
session.try_wait().expect("polling must succeed").is_some()
});
assert!(
!exited,
"the child finished despite nobody reading its output, so the \
pipe buffer never filled and this case is not exercising a \
blocked console host"
);
let started = Instant::now();
teardown(session);
let elapsed = started.elapsed();
assert!(
elapsed < TEARDOWN_BUDGET,
"tearing the session down took {elapsed:?}, over the \
{TEARDOWN_BUDGET:?} budget"
);
});
}
fn read_half_first(session: Session) {
let parts = session.into_parts();
drop(parts.output);
drop(parts.input);
drop(parts.controller);
drop(parts.child);
}
fn controller_first(session: Session) {
let parts = session.into_parts();
drop(parts.controller);
drop(parts.input);
drop(parts.output);
drop(parts.child);
}
fn write_half_first(session: Session) {
let parts = session.into_parts();
drop(parts.input);
drop(parts.controller);
drop(parts.output);
drop(parts.child);
}
#[test]
fn dropping_the_whole_session_completes() {
drop_order_completes(drop);
}
#[test]
fn dropping_the_read_half_first_completes() {
drop_order_completes(read_half_first);
}
#[test]
fn dropping_the_controller_first_completes() {
drop_order_completes(controller_first);
}
#[test]
fn dropping_the_write_half_first_completes() {
drop_order_completes(write_half_first);
}