Skip to content

Commit 75f55c3

Browse files
committed
Merge #680
680: Fix some bugs in the termios tests r=asomers * Make test_tcgetattr deterministic. The old version behaved differently depending on what file descriptors were opened by the harness or by other tests, and could race against other tests. * Close some file descriptor leaks Fixes #154
2 parents 5d29650 + ce7c961 commit 75f55c3

File tree

2 files changed

+32
-17
lines changed

2 files changed

+32
-17
lines changed

src/pty.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ use {Errno, Result, Error, fcntl};
1414

1515
/// Representation of a master/slave pty pair
1616
///
17-
/// This is returned by `openpty`
17+
/// This is returned by `openpty`. Note that this type does *not* implement `Drop`, so the user
18+
/// must manually close the file descriptors.
1819
pub struct OpenptyResult {
1920
pub master: RawFd,
2021
pub slave: RawFd,

test/sys/test_termios.rs

+30-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::os::unix::prelude::*;
2+
use tempfile::tempfile;
23

3-
use nix::{Error, fcntl, unistd};
4+
use nix::{Error, fcntl};
45
use nix::errno::Errno;
56
use nix::pty::openpty;
67
use nix::sys::termios::{self, ECHO, OPOST, OCRNL, Termios, tcgetattr};
@@ -14,22 +15,27 @@ fn write_all(f: RawFd, buf: &[u8]) {
1415
}
1516
}
1617

18+
// Test tcgetattr on a terminal
1719
#[test]
18-
fn test_tcgetattr() {
19-
for fd in 0..5 {
20-
let termios = termios::tcgetattr(fd);
21-
match unistd::isatty(fd) {
22-
// If `fd` is a TTY, tcgetattr must succeed.
23-
Ok(true) => assert!(termios.is_ok()),
24-
// If it's an invalid file descriptor, tcgetattr should also return
25-
// the same error
26-
Err(Error::Sys(Errno::EBADF)) => {
27-
assert_eq!(termios.err(), Some(Error::Sys(Errno::EBADF)));
28-
},
29-
// Otherwise it should return any error
30-
_ => assert!(termios.is_err())
31-
}
32-
}
20+
fn test_tcgetattr_pty() {
21+
let pty = openpty(None, None).unwrap();
22+
assert!(termios::tcgetattr(pty.master).is_ok());
23+
close(pty.master).unwrap();
24+
close(pty.slave).unwrap();
25+
}
26+
// Test tcgetattr on something that isn't a terminal
27+
#[test]
28+
fn test_tcgetattr_enotty() {
29+
let file = tempfile().unwrap();
30+
assert_eq!(termios::tcgetattr(file.as_raw_fd()).err(),
31+
Some(Error::Sys(Errno::ENOTTY)));
32+
}
33+
34+
// Test tcgetattr on an invalid file descriptor
35+
#[test]
36+
fn test_tcgetattr_ebadf() {
37+
assert_eq!(termios::tcgetattr(-1).err(),
38+
Some(Error::Sys(Errno::EBADF)));
3339
}
3440

3541
// Test modifying output flags
@@ -41,6 +47,8 @@ fn test_output_flags() {
4147
assert!(pty.master > 0);
4248
assert!(pty.slave > 0);
4349
let termios = tcgetattr(pty.master).unwrap();
50+
close(pty.master).unwrap();
51+
close(pty.slave).unwrap();
4452
termios
4553
};
4654

@@ -64,6 +72,8 @@ fn test_output_flags() {
6472
let mut buf = [0u8; 10];
6573
::read_exact(pty.slave, &mut buf);
6674
let transformed_string = "foofoofoo\n";
75+
close(pty.master).unwrap();
76+
close(pty.slave).unwrap();
6777
assert_eq!(&buf, transformed_string.as_bytes());
6878
}
6979

@@ -76,6 +86,8 @@ fn test_local_flags() {
7686
assert!(pty.master > 0);
7787
assert!(pty.slave > 0);
7888
let termios = tcgetattr(pty.master).unwrap();
89+
close(pty.master).unwrap();
90+
close(pty.slave).unwrap();
7991
termios
8092
};
8193

@@ -102,6 +114,8 @@ fn test_local_flags() {
102114
// Try to read from the master, which should not have anything as echoing was disabled.
103115
let mut buf = [0u8; 10];
104116
let read = read(pty.master, &mut buf).unwrap_err();
117+
close(pty.master).unwrap();
118+
close(pty.slave).unwrap();
105119
assert_eq!(read, Error::Sys(Errno::EAGAIN));
106120
}
107121

0 commit comments

Comments
 (0)