#![cfg_attr(not(unix), allow(unused))]
use std::io::{Read, Write};
use std::process::Stdio;
use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::time::timeout;
const CHILD_ENV: &str = "IS_STDIO_TEST_CHILD";
const READ_TIMEOUT: Duration = Duration::from_millis(500);
const SCHED_TIMEOUT: Duration = Duration::from_millis(100);
#[cfg(not(unix))]
fn main() {}
#[cfg(unix)]
fn main() {
if std::env::var(CHILD_ENV).is_err() {
parent();
} else {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(child());
}
}
#[cfg(unix)]
fn parent() {
let this_exe = std::env::current_exe().unwrap();
let mut child = std::process::Command::new(this_exe)
.env(CHILD_ENV, "1")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.spawn()
.expect("failed to spawn");
let childin = child.stdin.as_mut().unwrap();
let childout = child.stdout.as_mut().unwrap();
let mut buf = [0u8; 64];
assert_eq!(childout.read(&mut buf).unwrap(), 4);
assert_eq!(&buf[..4], b"ping");
childin.write_all(b"pong").unwrap();
let output = child.wait_with_output().unwrap();
assert!(output.status.success());
assert_eq!(output.stdout, b"2");
}
#[cfg(unix)]
async fn child() {
use async_lsp::stdio::{PipeStdin, PipeStdout};
let mut stdin = PipeStdin::lock_tokio().unwrap();
let mut stdout = PipeStdout::lock_tokio().unwrap();
let mut buf = [0u8; 64];
let std_stdin = tokio::task::spawn_blocking(|| drop(std::io::stdin().lock()));
let std_stdout = tokio::task::spawn_blocking(|| print!("2"));
timeout(READ_TIMEOUT, stdin.read(&mut buf))
.await
.expect_err("should timeout");
timeout(Duration::ZERO, stdout.write_all(b"ping"))
.await
.expect("should not block")
.unwrap();
assert_eq!(
timeout(SCHED_TIMEOUT, stdin.read(&mut buf))
.await
.expect("should not timeout")
.expect("should read something"),
4
);
assert_eq!(&buf[..4], b"pong");
assert!(!std_stdin.is_finished());
assert!(!std_stdout.is_finished());
drop(stdin);
drop(stdout);
timeout(SCHED_TIMEOUT, std_stdin)
.await
.expect("no timeout")
.expect("no panic");
timeout(SCHED_TIMEOUT, std_stdout)
.await
.expect("no timeout")
.expect("no panic");
}