https://github.com/python/cpython/commit/46e8f7a9e794bfb0fdc5ee82348623eb2b91a0b5
commit: 46e8f7a9e794bfb0fdc5ee82348623eb2b91a0b5
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-05-25T16:17:38+03:00
summary:
gh-80198: Improve test_pwd and test_grp (GH-150380)
Fix tests for non-existing names and ids when getpwall()/getgrall()
don't return all users/groups.
Add tests for out-of-range uids, integer float ids, bytes names,
null-terminated names, names with surrogates, empty names, excessive
arguments.
files:
M Lib/test/test_grp.py
M Lib/test/test_pwd.py
diff --git a/Lib/test/test_grp.py b/Lib/test/test_grp.py
index e52e17b8dc7366..ed86802f069e0f 100644
--- a/Lib/test/test_grp.py
+++ b/Lib/test/test_grp.py
@@ -1,5 +1,7 @@
"""Test script for the grp module."""
+import random
+import string
import unittest
from test.support import import_helper
@@ -50,61 +52,51 @@ def test_values_extended(self):
def test_errors(self):
self.assertRaises(TypeError, grp.getgrgid)
self.assertRaises(TypeError, grp.getgrgid, 3.14)
+ self.assertRaises(TypeError, grp.getgrgid, 0.0)
+ self.assertRaises(TypeError, grp.getgrgid, 0, 0)
+ # should be out of gid_t range
+ self.assertRaises(OverflowError, grp.getgrgid, 2**128)
+ self.assertRaises(OverflowError, grp.getgrgid, -2**128)
self.assertRaises(TypeError, grp.getgrnam)
self.assertRaises(TypeError, grp.getgrnam, 42)
- self.assertRaises(TypeError, grp.getgrall, 42)
+ self.assertRaises(TypeError, grp.getgrnam, b'root')
+ self.assertRaises(TypeError, grp.getgrnam, 'root', 0)
# embedded null character
self.assertRaisesRegex(ValueError, 'null', grp.getgrnam, 'a\x00b')
+ self.assertRaisesRegex(ValueError, 'null', grp.getgrnam, 'root\x00')
+ self.assertRaises(UnicodeEncodeError, grp.getgrnam, 'roo\udc74')
+ self.assertRaises(KeyError, grp.getgrnam, '')
+ self.assertRaises(TypeError, grp.getgrall, 42)
- # try to get some errors
- bynames = {}
- bygids = {}
- for (n, p, g, mem) in grp.getgrall():
- if not n or n == '+':
- continue # skip NIS entries etc.
- bynames[n] = g
- bygids[g] = n
-
- allnames = list(bynames.keys())
- namei = 0
- fakename = allnames[namei]
- while fakename in bynames:
- chars = list(fakename)
- for i in range(len(chars)):
- if chars[i] == 'z':
- chars[i] = 'A'
- break
- elif chars[i] == 'Z':
- continue
+ # Find a non-existent group name.
+ # getgrall() will not necessarily report all existing groups
+ # (typical for LDAP based directories in big organizations).
+ for _ in range(30):
+ fakename = ''.join(random.choices(string.ascii_lowercase, k=6))
+ try:
+ grp.getgrnam(fakename)
+ except KeyError:
+ break
+ else:
+ self.fail('Cannot find non-existent group name')
+
+ # Find a non-existent gid.
+ maxgid = 2**31
+ for _ in range(30):
+ fakegid = random.randrange(maxgid)
+ try:
+ grp.getgrgid(fakegid)
+ except KeyError:
+ break
+ except OverflowError:
+ if maxgid == 2**31:
+ maxgid = 2**16-1
+ elif maxgid == 2**16-1:
+ maxgid = 2**15
else:
- chars[i] = chr(ord(chars[i]) + 1)
- break
- else:
- namei = namei + 1
- try:
- fakename = allnames[namei]
- except IndexError:
- # should never happen... if so, just forget it
- break
- fakename = ''.join(chars)
-
- self.assertRaises(KeyError, grp.getgrnam, fakename)
-
- # Choose a non-existent gid.
- fakegid = 4127
- while fakegid in bygids:
- fakegid = (fakegid * 3) % 0x10000
-
- self.assertRaises(KeyError, grp.getgrgid, fakegid)
-
- def test_noninteger_gid(self):
- entries = grp.getgrall()
- if not entries:
- self.skipTest('no groups')
- # Choose an existent gid.
- gid = entries[0][2]
- self.assertRaises(TypeError, grp.getgrgid, float(gid))
- self.assertRaises(TypeError, grp.getgrgid, str(gid))
+ raise
+ else:
+ self.fail('Cannot find non-existent gid')
if __name__ == "__main__":
diff --git a/Lib/test/test_pwd.py b/Lib/test/test_pwd.py
index d0ef30ec493084..bdf57776c82be1 100644
--- a/Lib/test/test_pwd.py
+++ b/Lib/test/test_pwd.py
@@ -1,3 +1,5 @@
+import random
+import string
import sys
import unittest
from test.support import import_helper
@@ -56,61 +58,57 @@ def test_values_extended(self):
def test_errors(self):
self.assertRaises(TypeError, pwd.getpwuid)
self.assertRaises(TypeError, pwd.getpwuid, 3.14)
+ self.assertRaises(TypeError, pwd.getpwuid, 0.0)
+ self.assertRaises(TypeError, pwd.getpwuid, 0, 0)
+ # should be out of uid_t range
+ self.assertRaises(KeyError, pwd.getpwuid, 2**128)
+ self.assertRaises(KeyError, pwd.getpwuid, -2**128)
self.assertRaises(TypeError, pwd.getpwnam)
self.assertRaises(TypeError, pwd.getpwnam, 42)
- self.assertRaises(TypeError, pwd.getpwall, 42)
+ self.assertRaises(TypeError, pwd.getpwnam, b'root')
+ self.assertRaises(TypeError, pwd.getpwnam, 'root', 0)
# embedded null character
self.assertRaisesRegex(ValueError, 'null', pwd.getpwnam, 'a\x00b')
+ self.assertRaisesRegex(ValueError, 'null', pwd.getpwnam, 'root\x00')
+ self.assertRaises(UnicodeEncodeError, pwd.getpwnam, 'roo\udc74')
+ self.assertRaises(KeyError, pwd.getpwnam, '')
+ self.assertRaises(TypeError, pwd.getpwall, 42)
- # try to get some errors
- bynames = {}
- byuids = {}
- for (n, p, u, g, gecos, d, s) in pwd.getpwall():
- bynames[n] = u
- byuids[u] = n
-
- allnames = list(bynames.keys())
- namei = 0
- fakename = allnames[namei] if allnames else "invaliduser"
- while fakename in bynames:
- chars = list(fakename)
- for i in range(len(chars)):
- if chars[i] == 'z':
- chars[i] = 'A'
- break
- elif chars[i] == 'Z':
- continue
- else:
- chars[i] = chr(ord(chars[i]) + 1)
- break
- else:
- namei = namei + 1
- try:
- fakename = allnames[namei]
- except IndexError:
- # should never happen... if so, just forget it
- break
- fakename = ''.join(chars)
-
- self.assertRaises(KeyError, pwd.getpwnam, fakename)
-
- # In some cases, byuids isn't a complete list of all users in the
- # system, so if we try to pick a value not in byuids (via a perturbing
- # loop, say), pwd.getpwuid() might still be able to find data for that
- # uid. Using sys.maxint may provoke the same problems, but hopefully
- # it will be a more repeatable failure.
- fakeuid = sys.maxsize
- self.assertNotIn(fakeuid, byuids)
- self.assertRaises(KeyError, pwd.getpwuid, fakeuid)
+ # Find a non-existent user name.
+ # getpwall() will not necessarily report all existing users
+ # (typical for LDAP based directories in big organizations).
+ for _ in range(30):
+ fakename = ''.join(random.choices(string.ascii_lowercase, k=6))
+ try:
+ pwd.getpwnam(fakename)
+ except KeyError:
+ break
+ else:
+ self.fail('Cannot find non-existent user name')
+
+ # Find a non-existent uid.
+ maxuid = max(e.pw_uid for e in pwd.getpwall())
+ if maxuid < 2**15:
+ maxuid = 2**15
+ elif maxuid < 2**16:
+ maxuid = 2**16-1
+ else:
+ maxuid = 2**31
+ for _ in range(30):
+ fakeuid = random.randrange(maxuid)
+ try:
+ pwd.getpwuid(fakeuid)
+ except KeyError:
+ break
+ else:
+ self.fail('Cannot find non-existent uid')
# On Cygwin, getpwuid(-1) returns 'Unknown+User' user
if sys.platform != 'cygwin':
# -1 shouldn't be a valid uid because it has a special meaning in
many
# uid-related functions
self.assertRaises(KeyError, pwd.getpwuid, -1)
- # should be out of uid_t range
- self.assertRaises(KeyError, pwd.getpwuid, 2**128)
- self.assertRaises(KeyError, pwd.getpwuid, -2**128)
+
if __name__ == "__main__":
unittest.main()
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]