summaryrefslogtreecommitdiffstats
path: root/third_party/rust/nix/test/test_pty.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/nix/test/test_pty.rs
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/nix/test/test_pty.rs')
-rw-r--r--third_party/rust/nix/test/test_pty.rs203
1 files changed, 203 insertions, 0 deletions
diff --git a/third_party/rust/nix/test/test_pty.rs b/third_party/rust/nix/test/test_pty.rs
new file mode 100644
index 0000000000..4f428bed9a
--- /dev/null
+++ b/third_party/rust/nix/test/test_pty.rs
@@ -0,0 +1,203 @@
+use std::io::Write;
+use std::path::Path;
+use std::os::unix::prelude::*;
+use tempfile::tempfile;
+
+use nix::fcntl::{OFlag, open};
+use nix::pty::*;
+use nix::sys::stat;
+use nix::sys::termios::*;
+use nix::unistd::{write, close};
+
+/// Regression test for Issue #659
+/// This is the correct way to explicitly close a `PtyMaster`
+#[test]
+fn test_explicit_close() {
+ let mut f = {
+ let m = posix_openpt(OFlag::O_RDWR).unwrap();
+ close(m.into_raw_fd()).unwrap();
+ tempfile().unwrap()
+ };
+ // This should work. But if there's been a double close, then it will
+ // return EBADF
+ f.write_all(b"whatever").unwrap();
+}
+
+/// Test equivalence of `ptsname` and `ptsname_r`
+#[test]
+#[cfg(any(target_os = "android", target_os = "linux"))]
+fn test_ptsname_equivalence() {
+ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open a new PTTY master
+ let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
+ assert!(master_fd.as_raw_fd() > 0);
+
+ // Get the name of the slave
+ let slave_name = unsafe { ptsname(&master_fd) }.unwrap() ;
+ let slave_name_r = ptsname_r(&master_fd).unwrap();
+ assert_eq!(slave_name, slave_name_r);
+}
+
+/// Test data copying of `ptsname`
+// TODO need to run in a subprocess, since ptsname is non-reentrant
+#[test]
+#[cfg(any(target_os = "android", target_os = "linux"))]
+fn test_ptsname_copy() {
+ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open a new PTTY master
+ let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
+ assert!(master_fd.as_raw_fd() > 0);
+
+ // Get the name of the slave
+ let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap();
+ let slave_name2 = unsafe { ptsname(&master_fd) }.unwrap();
+ assert!(slave_name1 == slave_name2);
+ // Also make sure that the string was actually copied and they point to different parts of
+ // memory.
+ assert!(slave_name1.as_ptr() != slave_name2.as_ptr());
+}
+
+/// Test data copying of `ptsname_r`
+#[test]
+#[cfg(any(target_os = "android", target_os = "linux"))]
+fn test_ptsname_r_copy() {
+ // Open a new PTTY master
+ let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
+ assert!(master_fd.as_raw_fd() > 0);
+
+ // Get the name of the slave
+ let slave_name1 = ptsname_r(&master_fd).unwrap();
+ let slave_name2 = ptsname_r(&master_fd).unwrap();
+ assert!(slave_name1 == slave_name2);
+ assert!(slave_name1.as_ptr() != slave_name2.as_ptr());
+}
+
+/// Test that `ptsname` returns different names for different devices
+#[test]
+#[cfg(any(target_os = "android", target_os = "linux"))]
+fn test_ptsname_unique() {
+ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open a new PTTY master
+ let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap();
+ assert!(master1_fd.as_raw_fd() > 0);
+
+ // Open a second PTTY master
+ let master2_fd = posix_openpt(OFlag::O_RDWR).unwrap();
+ assert!(master2_fd.as_raw_fd() > 0);
+
+ // Get the name of the slave
+ let slave_name1 = unsafe { ptsname(&master1_fd) }.unwrap();
+ let slave_name2 = unsafe { ptsname(&master2_fd) }.unwrap();
+ assert!(slave_name1 != slave_name2);
+}
+
+/// Test opening a master/slave PTTY pair
+///
+/// This is a single larger test because much of these functions aren't useful by themselves. So for
+/// this test we perform the basic act of getting a file handle for a connect master/slave PTTY
+/// pair.
+#[test]
+fn test_open_ptty_pair() {
+ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open a new PTTY master
+ let master_fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
+ assert!(master_fd.as_raw_fd() > 0);
+
+ // Allow a slave to be generated for it
+ grantpt(&master_fd).expect("grantpt failed");
+ unlockpt(&master_fd).expect("unlockpt failed");
+
+ // Get the name of the slave
+ let slave_name = unsafe { ptsname(&master_fd) }.expect("ptsname failed");
+
+ // Open the slave device
+ let slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()).unwrap();
+ assert!(slave_fd > 0);
+}
+
+#[test]
+fn test_openpty() {
+ // openpty uses ptname(3) internally
+ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ let pty = openpty(None, None).unwrap();
+ assert!(pty.master > 0);
+ assert!(pty.slave > 0);
+
+ // Writing to one should be readable on the other one
+ let string = "foofoofoo\n";
+ let mut buf = [0u8; 10];
+ write(pty.master, string.as_bytes()).unwrap();
+ ::read_exact(pty.slave, &mut buf);
+
+ assert_eq!(&buf, string.as_bytes());
+
+ // Read the echo as well
+ let echoed_string = "foofoofoo\r\n";
+ let mut buf = [0u8; 11];
+ ::read_exact(pty.master, &mut buf);
+ assert_eq!(&buf, echoed_string.as_bytes());
+
+ let string2 = "barbarbarbar\n";
+ let echoed_string2 = "barbarbarbar\r\n";
+ let mut buf = [0u8; 14];
+ write(pty.slave, string2.as_bytes()).unwrap();
+ ::read_exact(pty.master, &mut buf);
+
+ assert_eq!(&buf, echoed_string2.as_bytes());
+
+ close(pty.master).unwrap();
+ close(pty.slave).unwrap();
+}
+
+#[test]
+fn test_openpty_with_termios() {
+ // openpty uses ptname(3) internally
+ let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+
+ // Open one pty to get attributes for the second one
+ let mut termios = {
+ let pty = openpty(None, None).unwrap();
+ assert!(pty.master > 0);
+ assert!(pty.slave > 0);
+ let termios = tcgetattr(pty.master).unwrap();
+ close(pty.master).unwrap();
+ close(pty.slave).unwrap();
+ termios
+ };
+ // Make sure newlines are not transformed so the data is preserved when sent.
+ termios.output_flags.remove(OutputFlags::ONLCR);
+
+ let pty = openpty(None, &termios).unwrap();
+ // Must be valid file descriptors
+ assert!(pty.master > 0);
+ assert!(pty.slave > 0);
+
+ // Writing to one should be readable on the other one
+ let string = "foofoofoo\n";
+ let mut buf = [0u8; 10];
+ write(pty.master, string.as_bytes()).unwrap();
+ ::read_exact(pty.slave, &mut buf);
+
+ assert_eq!(&buf, string.as_bytes());
+
+ // read the echo as well
+ let echoed_string = "foofoofoo\n";
+ ::read_exact(pty.master, &mut buf);
+ assert_eq!(&buf, echoed_string.as_bytes());
+
+ let string2 = "barbarbarbar\n";
+ let echoed_string2 = "barbarbarbar\n";
+ let mut buf = [0u8; 13];
+ write(pty.slave, string2.as_bytes()).unwrap();
+ ::read_exact(pty.master, &mut buf);
+
+ assert_eq!(&buf, echoed_string2.as_bytes());
+
+ close(pty.master).unwrap();
+ close(pty.slave).unwrap();
+}