1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/win/registry.h"
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/stl_util.h"
15 #include "base/win/windows_version.h"
16 #include "testing/gtest/include/gtest/gtest.h"
23 class RegistryTest
: public testing::Test
{
26 static const REGSAM kNativeViewMask
= KEY_WOW64_64KEY
;
27 static const REGSAM kRedirectedViewMask
= KEY_WOW64_32KEY
;
29 static const REGSAM kNativeViewMask
= KEY_WOW64_32KEY
;
30 static const REGSAM kRedirectedViewMask
= KEY_WOW64_64KEY
;
34 void SetUp() override
{
35 // Create a temporary key.
36 RegKey
key(HKEY_CURRENT_USER
, L
"", KEY_ALL_ACCESS
);
37 key
.DeleteKey(kRootKey
);
38 ASSERT_NE(ERROR_SUCCESS
, key
.Open(HKEY_CURRENT_USER
, kRootKey
, KEY_READ
));
39 ASSERT_EQ(ERROR_SUCCESS
, key
.Create(HKEY_CURRENT_USER
, kRootKey
, KEY_READ
));
40 foo_software_key_
= L
"Software\\";
41 foo_software_key_
+= kRootKey
;
42 foo_software_key_
+= L
"\\Foo";
45 void TearDown() override
{
46 // Clean up the temporary key.
47 RegKey
key(HKEY_CURRENT_USER
, L
"", KEY_SET_VALUE
);
48 ASSERT_EQ(ERROR_SUCCESS
, key
.DeleteKey(kRootKey
));
49 ASSERT_NE(ERROR_SUCCESS
, key
.Open(HKEY_CURRENT_USER
, kRootKey
, KEY_READ
));
52 static bool IsRedirectorPresent() {
56 return OSInfo::GetInstance()->wow64_status() == OSInfo::WOW64_ENABLED
;
60 const wchar_t* const kRootKey
= L
"Base_Registry_Unittest";
61 std::wstring foo_software_key_
;
64 DISALLOW_COPY_AND_ASSIGN(RegistryTest
);
68 const REGSAM
RegistryTest::kNativeViewMask
;
69 const REGSAM
RegistryTest::kRedirectedViewMask
;
71 TEST_F(RegistryTest
, ValueTest
) {
74 std::wstring
foo_key(kRootKey
);
76 ASSERT_EQ(ERROR_SUCCESS
, key
.Create(HKEY_CURRENT_USER
, foo_key
.c_str(),
80 ASSERT_EQ(ERROR_SUCCESS
, key
.Open(HKEY_CURRENT_USER
, foo_key
.c_str(),
81 KEY_READ
| KEY_SET_VALUE
));
82 ASSERT_TRUE(key
.Valid());
84 const wchar_t kStringValueName
[] = L
"StringValue";
85 const wchar_t kDWORDValueName
[] = L
"DWORDValue";
86 const wchar_t kInt64ValueName
[] = L
"Int64Value";
87 const wchar_t kStringData
[] = L
"string data";
88 const DWORD kDWORDData
= 0xdeadbabe;
89 const int64 kInt64Data
= 0xdeadbabedeadbabeLL
;
91 // Test value creation
92 ASSERT_EQ(ERROR_SUCCESS
, key
.WriteValue(kStringValueName
, kStringData
));
93 ASSERT_EQ(ERROR_SUCCESS
, key
.WriteValue(kDWORDValueName
, kDWORDData
));
94 ASSERT_EQ(ERROR_SUCCESS
, key
.WriteValue(kInt64ValueName
, &kInt64Data
,
95 sizeof(kInt64Data
), REG_QWORD
));
96 EXPECT_EQ(3U, key
.GetValueCount());
97 EXPECT_TRUE(key
.HasValue(kStringValueName
));
98 EXPECT_TRUE(key
.HasValue(kDWORDValueName
));
99 EXPECT_TRUE(key
.HasValue(kInt64ValueName
));
102 std::wstring string_value
;
103 DWORD dword_value
= 0;
104 int64 int64_value
= 0;
105 ASSERT_EQ(ERROR_SUCCESS
, key
.ReadValue(kStringValueName
, &string_value
));
106 ASSERT_EQ(ERROR_SUCCESS
, key
.ReadValueDW(kDWORDValueName
, &dword_value
));
107 ASSERT_EQ(ERROR_SUCCESS
, key
.ReadInt64(kInt64ValueName
, &int64_value
));
108 EXPECT_STREQ(kStringData
, string_value
.c_str());
109 EXPECT_EQ(kDWORDData
, dword_value
);
110 EXPECT_EQ(kInt64Data
, int64_value
);
112 // Make sure out args are not touched if ReadValue fails
113 const wchar_t* kNonExistent
= L
"NonExistent";
114 ASSERT_NE(ERROR_SUCCESS
, key
.ReadValue(kNonExistent
, &string_value
));
115 ASSERT_NE(ERROR_SUCCESS
, key
.ReadValueDW(kNonExistent
, &dword_value
));
116 ASSERT_NE(ERROR_SUCCESS
, key
.ReadInt64(kNonExistent
, &int64_value
));
117 EXPECT_STREQ(kStringData
, string_value
.c_str());
118 EXPECT_EQ(kDWORDData
, dword_value
);
119 EXPECT_EQ(kInt64Data
, int64_value
);
122 ASSERT_EQ(ERROR_SUCCESS
, key
.DeleteValue(kStringValueName
));
123 ASSERT_EQ(ERROR_SUCCESS
, key
.DeleteValue(kDWORDValueName
));
124 ASSERT_EQ(ERROR_SUCCESS
, key
.DeleteValue(kInt64ValueName
));
125 EXPECT_EQ(0U, key
.GetValueCount());
126 EXPECT_FALSE(key
.HasValue(kStringValueName
));
127 EXPECT_FALSE(key
.HasValue(kDWORDValueName
));
128 EXPECT_FALSE(key
.HasValue(kInt64ValueName
));
132 TEST_F(RegistryTest
, BigValueIteratorTest
) {
134 std::wstring
foo_key(kRootKey
);
136 ASSERT_EQ(ERROR_SUCCESS
, key
.Create(HKEY_CURRENT_USER
, foo_key
.c_str(),
138 ASSERT_EQ(ERROR_SUCCESS
, key
.Open(HKEY_CURRENT_USER
, foo_key
.c_str(),
139 KEY_READ
| KEY_SET_VALUE
));
140 ASSERT_TRUE(key
.Valid());
142 // Create a test value that is larger than MAX_PATH.
143 std::wstring
data(MAX_PATH
* 2, L
'a');
145 ASSERT_EQ(ERROR_SUCCESS
, key
.WriteValue(data
.c_str(), data
.c_str()));
147 RegistryValueIterator
iterator(HKEY_CURRENT_USER
, foo_key
.c_str());
148 ASSERT_TRUE(iterator
.Valid());
149 EXPECT_STREQ(data
.c_str(), iterator
.Name());
150 EXPECT_STREQ(data
.c_str(), iterator
.Value());
151 // ValueSize() is in bytes, including NUL.
152 EXPECT_EQ((MAX_PATH
* 2 + 1) * sizeof(wchar_t), iterator
.ValueSize());
154 EXPECT_FALSE(iterator
.Valid());
157 TEST_F(RegistryTest
, TruncatedCharTest
) {
159 std::wstring
foo_key(kRootKey
);
161 ASSERT_EQ(ERROR_SUCCESS
, key
.Create(HKEY_CURRENT_USER
, foo_key
.c_str(),
163 ASSERT_EQ(ERROR_SUCCESS
, key
.Open(HKEY_CURRENT_USER
, foo_key
.c_str(),
164 KEY_READ
| KEY_SET_VALUE
));
165 ASSERT_TRUE(key
.Valid());
167 const wchar_t kName
[] = L
"name";
168 // kData size is not a multiple of sizeof(wchar_t).
169 const uint8 kData
[] = { 1, 2, 3, 4, 5 };
170 EXPECT_EQ(5, arraysize(kData
));
171 ASSERT_EQ(ERROR_SUCCESS
, key
.WriteValue(kName
, kData
,
172 arraysize(kData
), REG_BINARY
));
174 RegistryValueIterator
iterator(HKEY_CURRENT_USER
, foo_key
.c_str());
175 ASSERT_TRUE(iterator
.Valid());
176 EXPECT_STREQ(kName
, iterator
.Name());
177 // ValueSize() is in bytes.
178 ASSERT_EQ(arraysize(kData
), iterator
.ValueSize());
179 // Value() is NUL terminated.
180 int end
= (iterator
.ValueSize() + sizeof(wchar_t) - 1) / sizeof(wchar_t);
181 EXPECT_NE(L
'\0', iterator
.Value()[end
-1]);
182 EXPECT_EQ(L
'\0', iterator
.Value()[end
]);
183 EXPECT_EQ(0, std::memcmp(kData
, iterator
.Value(), arraysize(kData
)));
185 EXPECT_FALSE(iterator
.Valid());
188 TEST_F(RegistryTest
, RecursiveDelete
) {
190 // Create kRootKey->Foo
191 // \->Bar (TestValue)
192 // \->Foo (TestValue)
197 // and delete kRootKey->Foo
198 std::wstring
foo_key(kRootKey
);
200 ASSERT_EQ(ERROR_SUCCESS
,
201 key
.Create(HKEY_CURRENT_USER
, foo_key
.c_str(), KEY_WRITE
));
202 ASSERT_EQ(ERROR_SUCCESS
, key
.CreateKey(L
"Bar", KEY_WRITE
));
203 ASSERT_EQ(ERROR_SUCCESS
, key
.WriteValue(L
"TestValue", L
"TestData"));
204 ASSERT_EQ(ERROR_SUCCESS
,
205 key
.Create(HKEY_CURRENT_USER
, foo_key
.c_str(), KEY_WRITE
));
206 ASSERT_EQ(ERROR_SUCCESS
, key
.CreateKey(L
"Moo", KEY_WRITE
));
207 ASSERT_EQ(ERROR_SUCCESS
,
208 key
.Create(HKEY_CURRENT_USER
, foo_key
.c_str(), KEY_WRITE
));
209 ASSERT_EQ(ERROR_SUCCESS
, key
.CreateKey(L
"Foo", KEY_WRITE
));
211 ASSERT_EQ(ERROR_SUCCESS
,
212 key
.Open(HKEY_CURRENT_USER
, foo_key
.c_str(), KEY_WRITE
));
214 ASSERT_EQ(ERROR_SUCCESS
, key
.CreateKey(L
"Foo", KEY_WRITE
));
215 ASSERT_EQ(ERROR_SUCCESS
, key
.WriteValue(L
"TestValue", L
"TestData"));
216 ASSERT_EQ(ERROR_SUCCESS
,
217 key
.Open(HKEY_CURRENT_USER
, foo_key
.c_str(), KEY_READ
));
219 ASSERT_EQ(ERROR_SUCCESS
, key
.Open(HKEY_CURRENT_USER
, kRootKey
, KEY_WRITE
));
220 ASSERT_NE(ERROR_SUCCESS
, key
.DeleteKey(L
"Bar"));
221 ASSERT_NE(ERROR_SUCCESS
, key
.DeleteEmptyKey(L
"Foo"));
222 ASSERT_NE(ERROR_SUCCESS
, key
.DeleteEmptyKey(L
"Foo\\Bar\\Foo"));
223 ASSERT_NE(ERROR_SUCCESS
, key
.DeleteEmptyKey(L
"Foo\\Bar"));
224 ASSERT_EQ(ERROR_SUCCESS
, key
.DeleteEmptyKey(L
"Foo\\Foo"));
226 ASSERT_EQ(ERROR_SUCCESS
,
227 key
.Open(HKEY_CURRENT_USER
, foo_key
.c_str(), KEY_WRITE
));
228 ASSERT_EQ(ERROR_SUCCESS
, key
.CreateKey(L
"Bar", KEY_WRITE
));
229 ASSERT_EQ(ERROR_SUCCESS
, key
.CreateKey(L
"Foo", KEY_WRITE
));
230 ASSERT_EQ(ERROR_SUCCESS
,
231 key
.Open(HKEY_CURRENT_USER
, foo_key
.c_str(), KEY_WRITE
));
232 ASSERT_EQ(ERROR_SUCCESS
, key
.DeleteKey(L
""));
233 ASSERT_NE(ERROR_SUCCESS
,
234 key
.Open(HKEY_CURRENT_USER
, foo_key
.c_str(), KEY_READ
));
236 ASSERT_EQ(ERROR_SUCCESS
, key
.Open(HKEY_CURRENT_USER
, kRootKey
, KEY_WRITE
));
237 ASSERT_EQ(ERROR_SUCCESS
, key
.DeleteKey(L
"Foo"));
238 ASSERT_NE(ERROR_SUCCESS
, key
.DeleteKey(L
"Foo"));
239 ASSERT_NE(ERROR_SUCCESS
,
240 key
.Open(HKEY_CURRENT_USER
, foo_key
.c_str(), KEY_READ
));
243 // This test requires running as an Administrator as it tests redirected
244 // registry writes to HKLM\Software
245 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384253.aspx
246 // TODO(wfh): flaky test on Vista. See http://crbug.com/377917
247 TEST_F(RegistryTest
, DISABLED_Wow64RedirectedFromNative
) {
248 if (!IsRedirectorPresent())
253 // Test redirected key access from non-redirected.
254 ASSERT_EQ(ERROR_SUCCESS
,
255 key
.Create(HKEY_LOCAL_MACHINE
,
256 foo_software_key_
.c_str(),
257 KEY_WRITE
| kRedirectedViewMask
));
258 ASSERT_NE(ERROR_SUCCESS
,
259 key
.Open(HKEY_LOCAL_MACHINE
, foo_software_key_
.c_str(), KEY_READ
));
260 ASSERT_NE(ERROR_SUCCESS
,
261 key
.Open(HKEY_LOCAL_MACHINE
,
262 foo_software_key_
.c_str(),
263 KEY_READ
| kNativeViewMask
));
265 // Open the non-redirected view of the parent and try to delete the test key.
266 ASSERT_EQ(ERROR_SUCCESS
,
267 key
.Open(HKEY_LOCAL_MACHINE
, L
"Software", KEY_SET_VALUE
));
268 ASSERT_NE(ERROR_SUCCESS
, key
.DeleteKey(kRootKey
));
269 ASSERT_EQ(ERROR_SUCCESS
,
270 key
.Open(HKEY_LOCAL_MACHINE
,
272 KEY_SET_VALUE
| kNativeViewMask
));
273 ASSERT_NE(ERROR_SUCCESS
, key
.DeleteKey(kRootKey
));
275 // Open the redirected view and delete the key created above.
276 ASSERT_EQ(ERROR_SUCCESS
,
277 key
.Open(HKEY_LOCAL_MACHINE
,
279 KEY_SET_VALUE
| kRedirectedViewMask
));
280 ASSERT_EQ(ERROR_SUCCESS
, key
.DeleteKey(kRootKey
));
283 // Test for the issue found in http://crbug.com/384587 where OpenKey would call
284 // Close() and reset wow64_access_ flag to 0 and cause a NOTREACHED to hit on a
285 // subsequent OpenKey call.
286 TEST_F(RegistryTest
, SameWowFlags
) {
289 ASSERT_EQ(ERROR_SUCCESS
,
290 key
.Open(HKEY_LOCAL_MACHINE
,
292 KEY_READ
| KEY_WOW64_64KEY
));
293 ASSERT_EQ(ERROR_SUCCESS
,
294 key
.OpenKey(L
"Microsoft",
295 KEY_READ
| KEY_WOW64_64KEY
));
296 ASSERT_EQ(ERROR_SUCCESS
,
297 key
.OpenKey(L
"Windows",
298 KEY_READ
| KEY_WOW64_64KEY
));
301 // TODO(wfh): flaky test on Vista. See http://crbug.com/377917
302 TEST_F(RegistryTest
, DISABLED_Wow64NativeFromRedirected
) {
303 if (!IsRedirectorPresent())
307 // Test non-redirected key access from redirected.
308 ASSERT_EQ(ERROR_SUCCESS
,
309 key
.Create(HKEY_LOCAL_MACHINE
,
310 foo_software_key_
.c_str(),
311 KEY_WRITE
| kNativeViewMask
));
312 ASSERT_EQ(ERROR_SUCCESS
,
313 key
.Open(HKEY_LOCAL_MACHINE
, foo_software_key_
.c_str(), KEY_READ
));
314 ASSERT_NE(ERROR_SUCCESS
,
315 key
.Open(HKEY_LOCAL_MACHINE
,
316 foo_software_key_
.c_str(),
317 KEY_READ
| kRedirectedViewMask
));
319 // Open the redirected view of the parent and try to delete the test key
320 // from the non-redirected view.
321 ASSERT_EQ(ERROR_SUCCESS
,
322 key
.Open(HKEY_LOCAL_MACHINE
,
324 KEY_SET_VALUE
| kRedirectedViewMask
));
325 ASSERT_NE(ERROR_SUCCESS
, key
.DeleteKey(kRootKey
));
327 ASSERT_EQ(ERROR_SUCCESS
,
328 key
.Open(HKEY_LOCAL_MACHINE
,
330 KEY_SET_VALUE
| kNativeViewMask
));
331 ASSERT_EQ(ERROR_SUCCESS
, key
.DeleteKey(kRootKey
));
334 TEST_F(RegistryTest
, OpenSubKey
) {
336 ASSERT_EQ(ERROR_SUCCESS
,
337 key
.Open(HKEY_CURRENT_USER
,
339 KEY_READ
| KEY_CREATE_SUB_KEY
));
341 ASSERT_NE(ERROR_SUCCESS
, key
.OpenKey(L
"foo", KEY_READ
));
342 ASSERT_EQ(ERROR_SUCCESS
, key
.CreateKey(L
"foo", KEY_READ
));
343 ASSERT_EQ(ERROR_SUCCESS
, key
.Open(HKEY_CURRENT_USER
, kRootKey
, KEY_READ
));
344 ASSERT_EQ(ERROR_SUCCESS
, key
.OpenKey(L
"foo", KEY_READ
));
346 std::wstring
foo_key(kRootKey
);
348 ASSERT_EQ(ERROR_SUCCESS
,
349 key
.Open(HKEY_CURRENT_USER
, foo_key
.c_str(), KEY_READ
));
351 ASSERT_EQ(ERROR_SUCCESS
, key
.Open(HKEY_CURRENT_USER
, kRootKey
, KEY_WRITE
));
352 ASSERT_EQ(ERROR_SUCCESS
, key
.DeleteKey(L
"foo"));
355 class TestChangeDelegate
{
357 TestChangeDelegate() : called_(false) {}
358 ~TestChangeDelegate() {}
360 void OnKeyChanged() {
361 MessageLoop::current()->QuitWhenIdle();
366 bool was_called
= called_
;
375 TEST_F(RegistryTest
, ChangeCallback
) {
377 TestChangeDelegate delegate
;
378 MessageLoop message_loop
;
380 std::wstring
foo_key(kRootKey
);
382 ASSERT_EQ(ERROR_SUCCESS
, key
.Create(HKEY_CURRENT_USER
, foo_key
.c_str(),
385 ASSERT_TRUE(key
.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged
,
386 Unretained(&delegate
))));
387 EXPECT_FALSE(delegate
.WasCalled());
391 ASSERT_EQ(ERROR_SUCCESS
, key2
.Open(HKEY_CURRENT_USER
, foo_key
.c_str(),
392 KEY_READ
| KEY_SET_VALUE
));
393 ASSERT_TRUE(key2
.Valid());
394 EXPECT_EQ(ERROR_SUCCESS
, key2
.WriteValue(L
"name", L
"data"));
396 // Allow delivery of the notification.
397 EXPECT_FALSE(delegate
.WasCalled());
398 base::RunLoop().Run();
400 ASSERT_TRUE(delegate
.WasCalled());
401 EXPECT_FALSE(delegate
.WasCalled());
403 ASSERT_TRUE(key
.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged
,
404 Unretained(&delegate
))));
406 // Change something else.
407 EXPECT_EQ(ERROR_SUCCESS
, key2
.WriteValue(L
"name2", L
"data2"));
408 base::RunLoop().Run();
409 ASSERT_TRUE(delegate
.WasCalled());
411 ASSERT_TRUE(key
.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged
,
412 Unretained(&delegate
))));
413 base::RunLoop().RunUntilIdle();
414 EXPECT_FALSE(delegate
.WasCalled());