use std::os::unix::io::{AsFd, AsRawFd};
use tempfile::tempfile;
use nix::errno::Errno;
use nix::fcntl;
use nix::pty::openpty;
use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags};
use nix::unistd::{read, write};
fn write_all<Fd: AsFd>(f: Fd, buf: &[u8]) {
let mut len = 0;
while len < buf.len() {
len += write(f.as_fd().as_raw_fd(), &buf[len..]).unwrap();
}
}
#[test]
fn test_tcgetattr_pty() {
let _m = crate::PTSNAME_MTX.lock();
let pty = openpty(None, None).expect("openpty failed");
termios::tcgetattr(&pty.slave).unwrap();
}
#[test]
fn test_tcgetattr_enotty() {
let file = tempfile().unwrap();
assert_eq!(termios::tcgetattr(&file).err(), Some(Errno::ENOTTY));
}
#[test]
fn test_output_flags() {
let _m = crate::PTSNAME_MTX.lock();
let mut termios = {
let pty = openpty(None, None).expect("openpty failed");
tcgetattr(&pty.slave).expect("tcgetattr failed")
};
assert!(!termios
.output_flags
.contains(OutputFlags::OPOST | OutputFlags::OCRNL));
termios
.output_flags
.insert(OutputFlags::OPOST | OutputFlags::OCRNL);
let pty = openpty(None, &termios).unwrap();
let string = "foofoofoo\r";
write_all(&pty.master, string.as_bytes());
let mut buf = [0u8; 10];
crate::read_exact(&pty.slave, &mut buf);
let transformed_string = "foofoofoo\n";
assert_eq!(&buf, transformed_string.as_bytes());
}
#[test]
fn test_local_flags() {
let _m = crate::PTSNAME_MTX.lock();
let mut termios = {
let pty = openpty(None, None).unwrap();
tcgetattr(&pty.slave).unwrap()
};
assert!(termios.local_flags.contains(LocalFlags::ECHO));
termios.local_flags.remove(LocalFlags::ECHO);
let pty = openpty(None, &termios).unwrap();
let flags = fcntl::fcntl(pty.master.as_raw_fd(), fcntl::F_GETFL).unwrap();
let new_flags =
fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK;
fcntl::fcntl(pty.master.as_raw_fd(), fcntl::F_SETFL(new_flags)).unwrap();
let string = "foofoofoo\r";
write_all(&pty.master, string.as_bytes());
let mut buf = [0u8; 10];
let read = read(pty.master.as_raw_fd(), &mut buf).unwrap_err();
assert_eq!(read, Errno::EAGAIN);
}