Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / base / win / registry_unittest.cc
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.
4
5 #include "base/win/registry.h"
6
7 #include <cstring>
8 #include <vector>
9
10 #include "base/compiler_specific.h"
11 #include "base/stl_util.h"
12 #include "base/win/windows_version.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace base {
16 namespace win {
17
18 namespace {
19
20 class RegistryTest : public testing::Test {
21  protected:
22 #if defined(_WIN64)
23   static const REGSAM kNativeViewMask = KEY_WOW64_64KEY;
24   static const REGSAM kRedirectedViewMask = KEY_WOW64_32KEY;
25 #else
26   static const REGSAM kNativeViewMask = KEY_WOW64_32KEY;
27   static const REGSAM kRedirectedViewMask = KEY_WOW64_64KEY;
28 #endif  //  _WIN64
29
30   RegistryTest() {}
31   virtual void SetUp() OVERRIDE {
32     // Create a temporary key.
33     RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
34     key.DeleteKey(kRootKey);
35     ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
36     ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, kRootKey, KEY_READ));
37     foo_software_key_ = L"Software\\";
38     foo_software_key_ += kRootKey;
39     foo_software_key_ += L"\\Foo";
40   }
41
42   virtual void TearDown() OVERRIDE {
43     // Clean up the temporary key.
44     RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE);
45     ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
46     ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
47   }
48
49   static bool IsRedirectorPresent() {
50 #if defined(_WIN64)
51     return true;
52 #else
53     return OSInfo::GetInstance()->wow64_status() == OSInfo::WOW64_ENABLED;
54 #endif
55   }
56
57   const wchar_t* const kRootKey = L"Base_Registry_Unittest";
58   std::wstring foo_software_key_;
59
60  private:
61   DISALLOW_COPY_AND_ASSIGN(RegistryTest);
62 };
63
64 // static
65 const REGSAM RegistryTest::kNativeViewMask;
66 const REGSAM RegistryTest::kRedirectedViewMask;
67
68 TEST_F(RegistryTest, ValueTest) {
69   RegKey key;
70
71   std::wstring foo_key(kRootKey);
72   foo_key += L"\\Foo";
73   ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
74                                       KEY_READ));
75
76   {
77     ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
78                                       KEY_READ | KEY_SET_VALUE));
79     ASSERT_TRUE(key.Valid());
80
81     const wchar_t kStringValueName[] = L"StringValue";
82     const wchar_t kDWORDValueName[] = L"DWORDValue";
83     const wchar_t kInt64ValueName[] = L"Int64Value";
84     const wchar_t kStringData[] = L"string data";
85     const DWORD kDWORDData = 0xdeadbabe;
86     const int64 kInt64Data = 0xdeadbabedeadbabeLL;
87
88     // Test value creation
89     ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kStringValueName, kStringData));
90     ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kDWORDValueName, kDWORDData));
91     ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kInt64ValueName, &kInt64Data,
92                                             sizeof(kInt64Data), REG_QWORD));
93     EXPECT_EQ(3U, key.GetValueCount());
94     EXPECT_TRUE(key.HasValue(kStringValueName));
95     EXPECT_TRUE(key.HasValue(kDWORDValueName));
96     EXPECT_TRUE(key.HasValue(kInt64ValueName));
97
98     // Test Read
99     std::wstring string_value;
100     DWORD dword_value = 0;
101     int64 int64_value = 0;
102     ASSERT_EQ(ERROR_SUCCESS, key.ReadValue(kStringValueName, &string_value));
103     ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(kDWORDValueName, &dword_value));
104     ASSERT_EQ(ERROR_SUCCESS, key.ReadInt64(kInt64ValueName, &int64_value));
105     EXPECT_STREQ(kStringData, string_value.c_str());
106     EXPECT_EQ(kDWORDData, dword_value);
107     EXPECT_EQ(kInt64Data, int64_value);
108
109     // Make sure out args are not touched if ReadValue fails
110     const wchar_t* kNonExistent = L"NonExistent";
111     ASSERT_NE(ERROR_SUCCESS, key.ReadValue(kNonExistent, &string_value));
112     ASSERT_NE(ERROR_SUCCESS, key.ReadValueDW(kNonExistent, &dword_value));
113     ASSERT_NE(ERROR_SUCCESS, key.ReadInt64(kNonExistent, &int64_value));
114     EXPECT_STREQ(kStringData, string_value.c_str());
115     EXPECT_EQ(kDWORDData, dword_value);
116     EXPECT_EQ(kInt64Data, int64_value);
117
118     // Test delete
119     ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kStringValueName));
120     ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kDWORDValueName));
121     ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kInt64ValueName));
122     EXPECT_EQ(0U, key.GetValueCount());
123     EXPECT_FALSE(key.HasValue(kStringValueName));
124     EXPECT_FALSE(key.HasValue(kDWORDValueName));
125     EXPECT_FALSE(key.HasValue(kInt64ValueName));
126   }
127 }
128
129 TEST_F(RegistryTest, BigValueIteratorTest) {
130   RegKey key;
131   std::wstring foo_key(kRootKey);
132   foo_key += L"\\Foo";
133   ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
134                                       KEY_READ));
135   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
136                                     KEY_READ | KEY_SET_VALUE));
137   ASSERT_TRUE(key.Valid());
138
139   // Create a test value that is larger than MAX_PATH.
140   std::wstring data(MAX_PATH * 2, L'a');
141
142   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(data.c_str(), data.c_str()));
143
144   RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str());
145   ASSERT_TRUE(iterator.Valid());
146   EXPECT_STREQ(data.c_str(), iterator.Name());
147   EXPECT_STREQ(data.c_str(), iterator.Value());
148   // ValueSize() is in bytes, including NUL.
149   EXPECT_EQ((MAX_PATH * 2 + 1) * sizeof(wchar_t), iterator.ValueSize());
150   ++iterator;
151   EXPECT_FALSE(iterator.Valid());
152 }
153
154 TEST_F(RegistryTest, TruncatedCharTest) {
155   RegKey key;
156   std::wstring foo_key(kRootKey);
157   foo_key += L"\\Foo";
158   ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
159                                       KEY_READ));
160   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
161                                     KEY_READ | KEY_SET_VALUE));
162   ASSERT_TRUE(key.Valid());
163
164   const wchar_t kName[] = L"name";
165   // kData size is not a multiple of sizeof(wchar_t).
166   const uint8 kData[] = { 1, 2, 3, 4, 5 };
167   EXPECT_EQ(5, arraysize(kData));
168   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kName, kData,
169                                           arraysize(kData), REG_BINARY));
170
171   RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str());
172   ASSERT_TRUE(iterator.Valid());
173   EXPECT_STREQ(kName, iterator.Name());
174   // ValueSize() is in bytes.
175   ASSERT_EQ(arraysize(kData), iterator.ValueSize());
176   // Value() is NUL terminated.
177   int end = (iterator.ValueSize() + sizeof(wchar_t) - 1) / sizeof(wchar_t);
178   EXPECT_NE(L'\0', iterator.Value()[end-1]);
179   EXPECT_EQ(L'\0', iterator.Value()[end]);
180   EXPECT_EQ(0, std::memcmp(kData, iterator.Value(), arraysize(kData)));
181   ++iterator;
182   EXPECT_FALSE(iterator.Valid());
183 }
184
185 TEST_F(RegistryTest, RecursiveDelete) {
186   RegKey key;
187   // Create kRootKey->Foo
188   //                  \->Bar (TestValue)
189   //                     \->Foo (TestValue)
190   //                        \->Bar
191   //                           \->Foo
192   //                  \->Moo
193   //                  \->Foo
194   // and delete kRootKey->Foo
195   std::wstring foo_key(kRootKey);
196   foo_key += L"\\Foo";
197   ASSERT_EQ(ERROR_SUCCESS,
198             key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
199   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
200   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
201   ASSERT_EQ(ERROR_SUCCESS,
202             key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
203   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Moo", KEY_WRITE));
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"Foo", KEY_WRITE));
207   foo_key += L"\\Bar";
208   ASSERT_EQ(ERROR_SUCCESS,
209             key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
210   foo_key += L"\\Foo";
211   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
212   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
213   ASSERT_EQ(ERROR_SUCCESS,
214             key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
215
216   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
217   ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Bar"));
218   ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo"));
219   ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar\\Foo"));
220   ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar"));
221   ASSERT_EQ(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Foo"));
222
223   ASSERT_EQ(ERROR_SUCCESS,
224             key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
225   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
226   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
227   ASSERT_EQ(ERROR_SUCCESS,
228             key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
229   ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L""));
230   ASSERT_NE(ERROR_SUCCESS,
231             key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
232
233   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
234   ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"Foo"));
235   ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Foo"));
236   ASSERT_NE(ERROR_SUCCESS,
237             key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
238 }
239
240 // This test requires running as an Administrator as it tests redirected
241 // registry writes to HKLM\Software
242 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384253.aspx
243 // TODO(wfh): flaky test on Vista.  See http://crbug.com/377917
244 TEST_F(RegistryTest, DISABLED_Wow64RedirectedFromNative) {
245   if (!IsRedirectorPresent())
246     return;
247
248   RegKey key;
249
250   // Test redirected key access from non-redirected.
251   ASSERT_EQ(ERROR_SUCCESS,
252             key.Create(HKEY_LOCAL_MACHINE,
253                        foo_software_key_.c_str(),
254                        KEY_WRITE | kRedirectedViewMask));
255   ASSERT_NE(ERROR_SUCCESS,
256             key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
257   ASSERT_NE(ERROR_SUCCESS,
258             key.Open(HKEY_LOCAL_MACHINE,
259                      foo_software_key_.c_str(),
260                      KEY_READ | kNativeViewMask));
261
262   // Open the non-redirected view of the parent and try to delete the test key.
263   ASSERT_EQ(ERROR_SUCCESS,
264             key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE));
265   ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
266   ASSERT_EQ(ERROR_SUCCESS,
267             key.Open(HKEY_LOCAL_MACHINE,
268                      L"Software",
269                      KEY_SET_VALUE | kNativeViewMask));
270   ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
271
272   // Open the redirected view and delete the key created above.
273   ASSERT_EQ(ERROR_SUCCESS,
274             key.Open(HKEY_LOCAL_MACHINE,
275                      L"Software",
276                      KEY_SET_VALUE | kRedirectedViewMask));
277   ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
278 }
279
280 // Test for the issue found in http://crbug.com/384587 where OpenKey would call
281 // Close() and reset wow64_access_ flag to 0 and cause a NOTREACHED to hit on a
282 // subsequent OpenKey call.
283 TEST_F(RegistryTest, SameWowFlags) {
284   RegKey key;
285
286   ASSERT_EQ(ERROR_SUCCESS,
287             key.Open(HKEY_LOCAL_MACHINE,
288                      L"Software",
289                      KEY_READ | KEY_WOW64_64KEY));
290   ASSERT_EQ(ERROR_SUCCESS,
291             key.OpenKey(L"Microsoft",
292                         KEY_READ | KEY_WOW64_64KEY));
293   ASSERT_EQ(ERROR_SUCCESS,
294             key.OpenKey(L"Windows",
295                         KEY_READ | KEY_WOW64_64KEY));
296 }
297
298 // TODO(wfh): flaky test on Vista.  See http://crbug.com/377917
299 TEST_F(RegistryTest, DISABLED_Wow64NativeFromRedirected) {
300   if (!IsRedirectorPresent())
301     return;
302   RegKey key;
303
304   // Test non-redirected key access from redirected.
305   ASSERT_EQ(ERROR_SUCCESS,
306             key.Create(HKEY_LOCAL_MACHINE,
307                        foo_software_key_.c_str(),
308                        KEY_WRITE | kNativeViewMask));
309   ASSERT_EQ(ERROR_SUCCESS,
310             key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
311   ASSERT_NE(ERROR_SUCCESS,
312             key.Open(HKEY_LOCAL_MACHINE,
313                      foo_software_key_.c_str(),
314                      KEY_READ | kRedirectedViewMask));
315
316   // Open the redirected view of the parent and try to delete the test key
317   // from the non-redirected view.
318   ASSERT_EQ(ERROR_SUCCESS,
319             key.Open(HKEY_LOCAL_MACHINE,
320                      L"Software",
321                      KEY_SET_VALUE | kRedirectedViewMask));
322   ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
323
324   ASSERT_EQ(ERROR_SUCCESS,
325             key.Open(HKEY_LOCAL_MACHINE,
326                      L"Software",
327                      KEY_SET_VALUE | kNativeViewMask));
328   ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
329 }
330
331 TEST_F(RegistryTest, OpenSubKey) {
332   RegKey key;
333   ASSERT_EQ(ERROR_SUCCESS,
334             key.Open(HKEY_CURRENT_USER,
335                      kRootKey,
336                      KEY_READ | KEY_CREATE_SUB_KEY));
337
338   ASSERT_NE(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
339   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"foo", KEY_READ));
340   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
341   ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
342
343   std::wstring foo_key(kRootKey);
344   foo_key += L"\\Foo";
345   ASSERT_EQ(ERROR_SUCCESS,
346             key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
347
348   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
349   ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"foo"));
350 }
351
352 }  // namespace
353
354 }  // namespace win
355 }  // namespace base