1import sys
2import unittest
3from test import support
4
5pwd = support.import_module('pwd')
6
7@unittest.skipUnless(hasattr(pwd, 'getpwall'), 'Does not have getpwall()')
8class PwdTest(unittest.TestCase):
9
10    def test_values(self):
11        entries = pwd.getpwall()
12
13        for e in entries:
14            self.assertEqual(len(e), 7)
15            self.assertEqual(e[0], e.pw_name)
16            self.assertIsInstance(e.pw_name, str)
17            self.assertEqual(e[1], e.pw_passwd)
18            self.assertIsInstance(e.pw_passwd, str)
19            self.assertEqual(e[2], e.pw_uid)
20            self.assertIsInstance(e.pw_uid, int)
21            self.assertEqual(e[3], e.pw_gid)
22            self.assertIsInstance(e.pw_gid, int)
23            self.assertEqual(e[4], e.pw_gecos)
24            self.assertIn(type(e.pw_gecos), (str, type(None)))
25            self.assertEqual(e[5], e.pw_dir)
26            self.assertIsInstance(e.pw_dir, str)
27            self.assertEqual(e[6], e.pw_shell)
28            self.assertIsInstance(e.pw_shell, str)
29
30            # The following won't work, because of duplicate entries
31            # for one uid
32            #    self.assertEqual(pwd.getpwuid(e.pw_uid), e)
33            # instead of this collect all entries for one uid
34            # and check afterwards (done in test_values_extended)
35
36    def test_values_extended(self):
37        entries = pwd.getpwall()
38        entriesbyname = {}
39        entriesbyuid = {}
40
41        if len(entries) > 1000:  # Huge passwd file (NIS?) -- skip this test
42            self.skipTest('passwd file is huge; extended test skipped')
43
44        for e in entries:
45            entriesbyname.setdefault(e.pw_name, []).append(e)
46            entriesbyuid.setdefault(e.pw_uid, []).append(e)
47
48        # check whether the entry returned by getpwuid()
49        # for each uid is among those from getpwall() for this uid
50        for e in entries:
51            if not e[0] or e[0] == '+':
52                continue # skip NIS entries etc.
53            self.assertIn(pwd.getpwnam(e.pw_name), entriesbyname[e.pw_name])
54            self.assertIn(pwd.getpwuid(e.pw_uid), entriesbyuid[e.pw_uid])
55
56    def test_errors(self):
57        self.assertRaises(TypeError, pwd.getpwuid)
58        self.assertRaises(TypeError, pwd.getpwuid, 3.14)
59        self.assertRaises(TypeError, pwd.getpwnam)
60        self.assertRaises(TypeError, pwd.getpwnam, 42)
61        self.assertRaises(TypeError, pwd.getpwall, 42)
62
63        # try to get some errors
64        bynames = {}
65        byuids = {}
66        for (n, p, u, g, gecos, d, s) in pwd.getpwall():
67            bynames[n] = u
68            byuids[u] = n
69
70        allnames = list(bynames.keys())
71        namei = 0
72        fakename = allnames[namei]
73        while fakename in bynames:
74            chars = list(fakename)
75            for i in range(len(chars)):
76                if chars[i] == 'z':
77                    chars[i] = 'A'
78                    break
79                elif chars[i] == 'Z':
80                    continue
81                else:
82                    chars[i] = chr(ord(chars[i]) + 1)
83                    break
84            else:
85                namei = namei + 1
86                try:
87                    fakename = allnames[namei]
88                except IndexError:
89                    # should never happen... if so, just forget it
90                    break
91            fakename = ''.join(chars)
92
93        self.assertRaises(KeyError, pwd.getpwnam, fakename)
94
95        # In some cases, byuids isn't a complete list of all users in the
96        # system, so if we try to pick a value not in byuids (via a perturbing
97        # loop, say), pwd.getpwuid() might still be able to find data for that
98        # uid. Using sys.maxint may provoke the same problems, but hopefully
99        # it will be a more repeatable failure.
100        fakeuid = sys.maxsize
101        self.assertNotIn(fakeuid, byuids)
102        self.assertRaises(KeyError, pwd.getpwuid, fakeuid)
103
104        # -1 shouldn't be a valid uid because it has a special meaning in many
105        # uid-related functions
106        self.assertRaises(KeyError, pwd.getpwuid, -1)
107        # should be out of uid_t range
108        self.assertRaises(KeyError, pwd.getpwuid, 2**128)
109        self.assertRaises(KeyError, pwd.getpwuid, -2**128)
110
111if __name__ == "__main__":
112    unittest.main()
113