Skip to content

Commit a04390b

Browse files
gh-132742: Add more tests for fcntl.ioctl() (GH-132756)
Test with different types of argument: integer, mutable and immutable buffers, immutable buffer with mutable_flag set to false.
1 parent 78cfee6 commit a04390b

File tree

1 file changed

+78
-7
lines changed

1 file changed

+78
-7
lines changed

Lib/test/test_ioctl.py

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
else:
1515
with tty:
1616
# Skip if another process is in foreground
17-
r = fcntl.ioctl(tty, termios.TIOCGPGRP, " ")
17+
r = fcntl.ioctl(tty, termios.TIOCGPGRP, struct.pack("i", 0))
1818
rpgrp = struct.unpack("i", r)[0]
1919
if rpgrp not in (os.getpgrp(), os.getsid(0)):
2020
raise unittest.SkipTest("Neither the process group nor the session "
@@ -27,19 +27,54 @@
2727
pty = None
2828

2929
class IoctlTests(unittest.TestCase):
30-
def test_ioctl(self):
30+
def test_ioctl_immutable_buf(self):
3131
# If this process has been put into the background, TIOCGPGRP returns
3232
# the session ID instead of the process group id.
3333
ids = (os.getpgrp(), os.getsid(0))
3434
with open("/dev/tty", "rb") as tty:
35-
r = fcntl.ioctl(tty, termios.TIOCGPGRP, " ")
36-
rpgrp = struct.unpack("i", r)[0]
35+
# string
36+
buf = " "*8
37+
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf)
38+
self.assertIsInstance(r, bytes)
39+
rpgrp = memoryview(r).cast('i')[0]
3740
self.assertIn(rpgrp, ids)
3841

39-
def _check_ioctl_mutate_len(self, nbytes=None):
42+
# bytes
43+
buf = b" "*8
44+
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf)
45+
self.assertIsInstance(r, bytes)
46+
rpgrp = memoryview(r).cast('i')[0]
47+
self.assertIn(rpgrp, ids)
48+
49+
# read-only buffer
50+
r = fcntl.ioctl(tty, termios.TIOCGPGRP, memoryview(buf))
51+
self.assertIsInstance(r, bytes)
52+
rpgrp = memoryview(r).cast('i')[0]
53+
self.assertIn(rpgrp, ids)
54+
55+
def test_ioctl_mutable_buf(self):
56+
ids = (os.getpgrp(), os.getsid(0))
57+
with open("/dev/tty", "rb") as tty:
58+
buf = bytearray(b" "*8)
59+
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf)
60+
self.assertEqual(r, 0)
61+
rpgrp = memoryview(buf).cast('i')[0]
62+
self.assertIn(rpgrp, ids)
63+
64+
def test_ioctl_no_mutate_buf(self):
65+
ids = (os.getpgrp(), os.getsid(0))
66+
with open("/dev/tty", "rb") as tty:
67+
buf = bytearray(b" "*8)
68+
save_buf = bytes(buf)
69+
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf, False)
70+
self.assertEqual(bytes(buf), save_buf)
71+
self.assertIsInstance(r, bytes)
72+
rpgrp = memoryview(r).cast('i')[0]
73+
self.assertIn(rpgrp, ids)
74+
75+
def _create_int_buf(self, nbytes=None):
4076
buf = array.array('i')
4177
intsize = buf.itemsize
42-
ids = (os.getpgrp(), os.getsid(0))
4378
# A fill value unlikely to be in `ids`
4479
fill = -12345
4580
if nbytes is not None:
@@ -48,23 +83,59 @@ def _check_ioctl_mutate_len(self, nbytes=None):
4883
self.assertEqual(len(buf) * intsize, nbytes) # sanity check
4984
else:
5085
buf.append(fill)
86+
return buf
87+
88+
def _check_ioctl_mutate_len(self, nbytes=None):
89+
ids = (os.getpgrp(), os.getsid(0))
90+
buf = self._create_int_buf(nbytes)
5191
with open("/dev/tty", "rb") as tty:
52-
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf, True)
92+
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf)
5393
rpgrp = buf[0]
5494
self.assertEqual(r, 0)
5595
self.assertIn(rpgrp, ids)
5696

97+
def _check_ioctl_not_mutate_len(self, nbytes=None):
98+
ids = (os.getpgrp(), os.getsid(0))
99+
buf = self._create_int_buf(nbytes)
100+
save_buf = bytes(buf)
101+
with open("/dev/tty", "rb") as tty:
102+
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf, False)
103+
self.assertIsInstance(r, bytes)
104+
self.assertEqual(len(r), len(save_buf))
105+
self.assertEqual(bytes(buf), save_buf)
106+
rpgrp = array.array('i', r)[0]
107+
rpgrp = memoryview(r).cast('i')[0]
108+
self.assertIn(rpgrp, ids)
109+
110+
buf = bytes(buf)
111+
with open("/dev/tty", "rb") as tty:
112+
r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf, True)
113+
self.assertIsInstance(r, bytes)
114+
self.assertEqual(len(r), len(save_buf))
115+
self.assertEqual(buf, save_buf)
116+
rpgrp = array.array('i', r)[0]
117+
rpgrp = memoryview(r).cast('i')[0]
118+
self.assertIn(rpgrp, ids)
119+
57120
def test_ioctl_mutate(self):
58121
self._check_ioctl_mutate_len()
122+
self._check_ioctl_not_mutate_len()
59123

60124
def test_ioctl_mutate_1024(self):
61125
# Issue #9758: a mutable buffer of exactly 1024 bytes wouldn't be
62126
# copied back after the system call.
63127
self._check_ioctl_mutate_len(1024)
128+
self._check_ioctl_not_mutate_len(1024)
64129

65130
def test_ioctl_mutate_2048(self):
66131
# Test with a larger buffer, just for the record.
67132
self._check_ioctl_mutate_len(2048)
133+
self.assertRaises(ValueError, self._check_ioctl_not_mutate_len, 2048)
134+
135+
def test_ioctl_tcflush(self):
136+
with open("/dev/tty", "rb") as tty:
137+
r = fcntl.ioctl(tty, termios.TCFLSH, termios.TCIFLUSH)
138+
self.assertEqual(r, 0)
68139

69140
@unittest.skipIf(pty is None, 'pty module required')
70141
def test_ioctl_set_window_size(self):

0 commit comments

Comments
 (0)