blob: 902309a558e388caeba98e49291bb73a1e338739 [file] [log] [blame]
Guido van Rossumde598552000-03-28 20:36:51 +00001# Test the windows specific win32reg module.
2# Only win32reg functions not hit here: FlushKey, LoadKey and SaveKey
3
Fred Drake252af9c2000-06-29 19:42:00 +00004from _winreg import *
Guido van Rossumde598552000-03-28 20:36:51 +00005import os, sys
Georg Brandl3376a9a2007-08-24 17:38:49 +00006import unittest
Guido van Rossumde598552000-03-28 20:36:51 +00007
Georg Brandl3376a9a2007-08-24 17:38:49 +00008from test import test_support
Brian Curtinb7b21f12010-05-26 13:24:57 +00009threading = test_support.import_module("threading")
10from platform import machine
Fredrik Lundhf7850422001-01-17 21:51:36 +000011
Guido van Rossumde598552000-03-28 20:36:51 +000012test_key_name = "SOFTWARE\\Python Registry Test Key - Delete Me"
13
14test_data = [
15 ("Int Value", 45, REG_DWORD),
Guido van Rossum0a185522003-11-30 22:46:18 +000016 ("String Val", "A string value", REG_SZ),
Guido van Rossumde598552000-03-28 20:36:51 +000017 ("StringExpand", "The path is %path%", REG_EXPAND_SZ),
Guido van Rossumde598552000-03-28 20:36:51 +000018 ("Multi-string", ["Lots", "of", "string", "values"], REG_MULTI_SZ),
Guido van Rossumde598552000-03-28 20:36:51 +000019 ("Raw Data", ("binary"+chr(0)+"data"), REG_BINARY),
Guido van Rossum291481b2003-12-03 15:24:02 +000020 ("Big String", "x"*(2**14-1), REG_SZ),
21 ("Big Binary", "x"*(2**14), REG_BINARY),
Guido van Rossumde598552000-03-28 20:36:51 +000022]
Georg Brandl3376a9a2007-08-24 17:38:49 +000023
24if test_support.have_unicode:
25 test_data += [
26 (unicode("Unicode Val"), unicode("A Unicode value"), REG_SZ,),
27 ("UnicodeExpand", unicode("The path is %path%"), REG_EXPAND_SZ),
28 ("Multi-unicode", [unicode("Lots"), unicode("of"), unicode("unicode"),
29 unicode("values")], REG_MULTI_SZ),
30 ("Multi-mixed", [unicode("Unicode"), unicode("and"), "string",
31 "values"], REG_MULTI_SZ),
Martin v. Löwis339d0f72001-08-17 18:39:25 +000032 ]
Guido van Rossumde598552000-03-28 20:36:51 +000033
Georg Brandl3376a9a2007-08-24 17:38:49 +000034class WinregTests(unittest.TestCase):
Guido van Rossumde598552000-03-28 20:36:51 +000035 remote_name = None
36
Georg Brandl3376a9a2007-08-24 17:38:49 +000037 def WriteTestData(self, root_key):
38 # Set the default value for this key.
39 SetValue(root_key, test_key_name, REG_SZ, "Default value")
40 key = CreateKey(root_key, test_key_name)
41 # Create a sub-key
42 sub_key = CreateKey(key, "sub_key")
43 # Give the sub-key some named values
44
45 for value_name, value_data, value_type in test_data:
46 SetValueEx(sub_key, value_name, 0, value_type, value_data)
47
48 # Check we wrote as many items as we thought.
49 nkeys, nvalues, since_mod = QueryInfoKey(key)
50 self.assertEquals(nkeys, 1, "Not the correct number of sub keys")
51 self.assertEquals(nvalues, 1, "Not the correct number of values")
52 nkeys, nvalues, since_mod = QueryInfoKey(sub_key)
53 self.assertEquals(nkeys, 0, "Not the correct number of sub keys")
54 self.assertEquals(nvalues, len(test_data),
55 "Not the correct number of values")
56 # Close this key this way...
57 # (but before we do, copy the key as an integer - this allows
58 # us to test that the key really gets closed).
59 int_sub_key = int(sub_key)
60 CloseKey(sub_key)
61 try:
62 QueryInfoKey(int_sub_key)
63 self.fail("It appears the CloseKey() function does "
64 "not close the actual key!")
65 except EnvironmentError:
66 pass
67 # ... and close that key that way :-)
68 int_key = int(key)
69 key.Close()
70 try:
71 QueryInfoKey(int_key)
72 self.fail("It appears the key.Close() function "
73 "does not close the actual key!")
74 except EnvironmentError:
75 pass
76
77 def ReadTestData(self, root_key):
78 # Check we can get default value for this key.
79 val = QueryValue(root_key, test_key_name)
80 self.assertEquals(val, "Default value",
81 "Registry didn't give back the correct value")
82
83 key = OpenKey(root_key, test_key_name)
84 # Read the sub-keys
Christian Heimesb39a7562008-01-08 15:46:10 +000085 with OpenKey(key, "sub_key") as sub_key:
86 # Check I can enumerate over the values.
87 index = 0
88 while 1:
89 try:
90 data = EnumValue(sub_key, index)
91 except EnvironmentError:
92 break
93 self.assertEquals(data in test_data, True,
94 "Didn't read back the correct test data")
95 index = index + 1
96 self.assertEquals(index, len(test_data),
97 "Didn't read the correct number of items")
98 # Check I can directly access each item
99 for value_name, value_data, value_type in test_data:
100 read_val, read_typ = QueryValueEx(sub_key, value_name)
101 self.assertEquals(read_val, value_data,
102 "Could not directly read the value")
103 self.assertEquals(read_typ, value_type,
104 "Could not directly read the value")
Georg Brandl3376a9a2007-08-24 17:38:49 +0000105 sub_key.Close()
106 # Enumerate our main key.
107 read_val = EnumKey(key, 0)
108 self.assertEquals(read_val, "sub_key", "Read subkey value wrong")
109 try:
110 EnumKey(key, 1)
111 self.fail("Was able to get a second key when I only have one!")
112 except EnvironmentError:
113 pass
114
115 key.Close()
116
117 def DeleteTestData(self, root_key):
118 key = OpenKey(root_key, test_key_name, 0, KEY_ALL_ACCESS)
119 sub_key = OpenKey(key, "sub_key", 0, KEY_ALL_ACCESS)
120 # It is not necessary to delete the values before deleting
121 # the key (although subkeys must not exist). We delete them
122 # manually just to prove we can :-)
123 for value_name, value_data, value_type in test_data:
124 DeleteValue(sub_key, value_name)
125
126 nkeys, nvalues, since_mod = QueryInfoKey(sub_key)
127 self.assertEquals(nkeys, 0, "subkey not empty before delete")
128 self.assertEquals(nvalues, 0, "subkey not empty before delete")
129 sub_key.Close()
130 DeleteKey(key, "sub_key")
131
132 try:
133 # Shouldnt be able to delete it twice!
134 DeleteKey(key, "sub_key")
135 self.fail("Deleting the key twice succeeded")
136 except EnvironmentError:
137 pass
138 key.Close()
139 DeleteKey(root_key, test_key_name)
140 # Opening should now fail!
141 try:
142 key = OpenKey(root_key, test_key_name)
143 self.fail("Could open the non-existent key")
144 except WindowsError: # Use this error name this time
145 pass
146
147 def TestAll(self, root_key):
148 self.WriteTestData(root_key)
149 self.ReadTestData(root_key)
150 self.DeleteTestData(root_key)
151
152 def testLocalMachineRegistryWorks(self):
153 self.TestAll(HKEY_CURRENT_USER)
154
155 def testConnectRegistryToLocalMachineWorks(self):
156 # perform minimal ConnectRegistry test which just invokes it
157 h = ConnectRegistry(None, HKEY_LOCAL_MACHINE)
158 h.Close()
159
160 def testRemoteMachineRegistryWorks(self):
161 if not self.remote_name:
Georg Brandl0226d852007-08-30 12:32:23 +0000162 return # remote machine name not specified
Georg Brandl3376a9a2007-08-24 17:38:49 +0000163 remote_key = ConnectRegistry(self.remote_name, HKEY_CURRENT_USER)
164 self.TestAll(remote_key)
165
Christian Heimesb39a7562008-01-08 15:46:10 +0000166 def testExpandEnvironmentStrings(self):
167 r = ExpandEnvironmentStrings(u"%windir%\\test")
168 self.assertEqual(type(r), unicode)
169 self.assertEqual(r, os.environ["windir"] + "\\test")
170
Brian Curtinb7b21f12010-05-26 13:24:57 +0000171 def test_changing_value(self):
172 # Issue2810: A race condition in 2.6 and 3.1 may cause
173 # EnumValue or QueryValue to throw "WindowsError: More data is
174 # available"
175 done = False
176
177 class VeryActiveThread(threading.Thread):
178 def run(self):
179 with CreateKey(HKEY_CURRENT_USER, test_key_name) as key:
180 use_short = True
181 long_string = 'x'*2000
182 while not done:
183 s = 'x' if use_short else long_string
184 use_short = not use_short
185 SetValue(key, 'changing_value', REG_SZ, s)
186
187 thread = VeryActiveThread()
188 thread.start()
189 try:
190 with CreateKey(HKEY_CURRENT_USER,
191 test_key_name+'\\changing_value') as key:
192 for _ in range(1000):
193 num_subkeys, num_values, t = QueryInfoKey(key)
194 for i in range(num_values):
195 name = EnumValue(key, i)
196 QueryValue(key, name[0])
197 finally:
198 done = True
199 thread.join()
200 DeleteKey(HKEY_CURRENT_USER, test_key_name+'\\changing_value')
201 DeleteKey(HKEY_CURRENT_USER, test_key_name)
202
203 def test_long_key(self):
204 # Issue2810, in 2.6 and 3.1 when the key name was exactly 256
205 # characters, EnumKey threw "WindowsError: More data is
206 # available"
207 name = 'x'*256
208 try:
209 with CreateKey(HKEY_CURRENT_USER, test_key_name) as key:
210 SetValue(key, name, REG_SZ, 'x')
211 num_subkeys, num_values, t = QueryInfoKey(key)
212 EnumKey(key, 0)
213 finally:
214 DeleteKey(HKEY_CURRENT_USER, '\\'.join((test_key_name, name)))
215 DeleteKey(HKEY_CURRENT_USER, test_key_name)
216
217 def test_dynamic_key(self):
218 # Issue2810, when the value is dynamically generated, these
219 # throw "WindowsError: More data is available" in 2.6 and 3.1
220 EnumValue(HKEY_PERFORMANCE_DATA, 0)
221 QueryValueEx(HKEY_PERFORMANCE_DATA, None)
222
Georg Brandl3376a9a2007-08-24 17:38:49 +0000223def test_main():
224 test_support.run_unittest(WinregTests)
225
226if __name__ == "__main__":
Guido van Rossumde598552000-03-28 20:36:51 +0000227 try:
Georg Brandl3376a9a2007-08-24 17:38:49 +0000228 WinregTests.remote_name = sys.argv[sys.argv.index("--remote")+1]
229 except (IndexError, ValueError):
230 print "Remote registry calls can be tested using",
231 print "'test_winreg.py --remote \\\\machine_name'"
232 WinregTests.remote_name = None
233 test_main()