xref: /aosp_15_r20/external/cronet/base/win/registry_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/win/registry.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <windows.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include <shlobj.h>
10*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
11*6777b538SAndroid Build Coastguard Worker 
12*6777b538SAndroid Build Coastguard Worker #include <cstring>
13*6777b538SAndroid Build Coastguard Worker #include <iterator>
14*6777b538SAndroid Build Coastguard Worker #include <string_view>
15*6777b538SAndroid Build Coastguard Worker #include <utility>
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/memory/scoped_refptr.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/run_loop.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/test/bind.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/test/gmock_expected_support.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/test/mock_callback.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/test/task_environment.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/test/test_mock_time_task_runner.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/test/test_reg_util_win.h"
30*6777b538SAndroid Build Coastguard Worker #include "base/threading/simple_thread.h"
31*6777b538SAndroid Build Coastguard Worker #include "base/win/win_util.h"
32*6777b538SAndroid Build Coastguard Worker #include "base/win/windows_version.h"
33*6777b538SAndroid Build Coastguard Worker #include "testing/gmock/include/gmock/gmock.h"
34*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
35*6777b538SAndroid Build Coastguard Worker 
36*6777b538SAndroid Build Coastguard Worker namespace base::win {
37*6777b538SAndroid Build Coastguard Worker 
38*6777b538SAndroid Build Coastguard Worker namespace {
39*6777b538SAndroid Build Coastguard Worker 
40*6777b538SAndroid Build Coastguard Worker constexpr wchar_t kRootKey[] = L"Base_Registry_Unittest";
41*6777b538SAndroid Build Coastguard Worker 
42*6777b538SAndroid Build Coastguard Worker // A test harness for registry tests that operate in HKCU. Each test is given
43*6777b538SAndroid Build Coastguard Worker // a valid key distinct from that used by other tests.
44*6777b538SAndroid Build Coastguard Worker class RegistryTest : public testing::Test {
45*6777b538SAndroid Build Coastguard Worker  protected:
RegistryTest()46*6777b538SAndroid Build Coastguard Worker   RegistryTest() : root_key_(std::wstring(L"Software\\") + kRootKey) {}
47*6777b538SAndroid Build Coastguard Worker 
SetUp()48*6777b538SAndroid Build Coastguard Worker   void SetUp() override {
49*6777b538SAndroid Build Coastguard Worker     ASSERT_NO_FATAL_FAILURE(registry_override_.OverrideRegistry(
50*6777b538SAndroid Build Coastguard Worker         HKEY_CURRENT_USER, &override_path_));
51*6777b538SAndroid Build Coastguard Worker 
52*6777b538SAndroid Build Coastguard Worker     // Create the test's root key.
53*6777b538SAndroid Build Coastguard Worker     RegKey key(HKEY_CURRENT_USER, L"", KEY_CREATE_SUB_KEY);
54*6777b538SAndroid Build Coastguard Worker     ASSERT_NE(ERROR_SUCCESS,
55*6777b538SAndroid Build Coastguard Worker               key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ));
56*6777b538SAndroid Build Coastguard Worker     ASSERT_EQ(ERROR_SUCCESS,
57*6777b538SAndroid Build Coastguard Worker               key.Create(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ));
58*6777b538SAndroid Build Coastguard Worker   }
59*6777b538SAndroid Build Coastguard Worker 
60*6777b538SAndroid Build Coastguard Worker   // Returns the path to a key under HKCU that is made available for exclusive
61*6777b538SAndroid Build Coastguard Worker   // use by a test.
root_key() const62*6777b538SAndroid Build Coastguard Worker   const std::wstring& root_key() const { return root_key_; }
63*6777b538SAndroid Build Coastguard Worker 
override_path() const64*6777b538SAndroid Build Coastguard Worker   const std::wstring& override_path() const { return override_path_; }
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker  private:
67*6777b538SAndroid Build Coastguard Worker   registry_util::RegistryOverrideManager registry_override_;
68*6777b538SAndroid Build Coastguard Worker   const std::wstring root_key_;
69*6777b538SAndroid Build Coastguard Worker   std::wstring override_path_;
70*6777b538SAndroid Build Coastguard Worker };
71*6777b538SAndroid Build Coastguard Worker 
72*6777b538SAndroid Build Coastguard Worker }  // namespace
73*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,ValueTest)74*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, ValueTest) {
75*6777b538SAndroid Build Coastguard Worker   RegKey key;
76*6777b538SAndroid Build Coastguard Worker 
77*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(),
78*6777b538SAndroid Build Coastguard Worker                                     KEY_READ | KEY_SET_VALUE));
79*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(key.Valid());
80*6777b538SAndroid Build Coastguard Worker 
81*6777b538SAndroid Build Coastguard Worker   const wchar_t kStringValueName[] = L"StringValue";
82*6777b538SAndroid Build Coastguard Worker   const wchar_t kDWORDValueName[] = L"DWORDValue";
83*6777b538SAndroid Build Coastguard Worker   const wchar_t kInt64ValueName[] = L"Int64Value";
84*6777b538SAndroid Build Coastguard Worker   const wchar_t kStringData[] = L"string data";
85*6777b538SAndroid Build Coastguard Worker   const DWORD kDWORDData = 0xdeadbabe;
86*6777b538SAndroid Build Coastguard Worker   const int64_t kInt64Data = 0xdeadbabedeadbabeLL;
87*6777b538SAndroid Build Coastguard Worker 
88*6777b538SAndroid Build Coastguard Worker   // Test value creation
89*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kStringValueName, kStringData));
90*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kDWORDValueName, kDWORDData));
91*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kInt64ValueName, &kInt64Data,
92*6777b538SAndroid Build Coastguard Worker                                           sizeof(kInt64Data), REG_QWORD));
93*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(key.GetValueCount(), base::test::ValueIs(3U));
94*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(key.HasValue(kStringValueName));
95*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(key.HasValue(kDWORDValueName));
96*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(key.HasValue(kInt64ValueName));
97*6777b538SAndroid Build Coastguard Worker 
98*6777b538SAndroid Build Coastguard Worker   // Test Read
99*6777b538SAndroid Build Coastguard Worker   std::wstring string_value;
100*6777b538SAndroid Build Coastguard Worker   DWORD dword_value = 0;
101*6777b538SAndroid Build Coastguard Worker   int64_t int64_value = 0;
102*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.ReadValue(kStringValueName, &string_value));
103*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(kDWORDValueName, &dword_value));
104*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.ReadInt64(kInt64ValueName, &int64_value));
105*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kStringData, string_value);
106*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kDWORDData, dword_value);
107*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kInt64Data, int64_value);
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker   // Make sure out args are not touched if ReadValue fails
110*6777b538SAndroid Build Coastguard Worker   const wchar_t* kNonExistent = L"NonExistent";
111*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS, key.ReadValue(kNonExistent, &string_value));
112*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS, key.ReadValueDW(kNonExistent, &dword_value));
113*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS, key.ReadInt64(kNonExistent, &int64_value));
114*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kStringData, string_value);
115*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kDWORDData, dword_value);
116*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kInt64Data, int64_value);
117*6777b538SAndroid Build Coastguard Worker 
118*6777b538SAndroid Build Coastguard Worker   // Test delete
119*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kStringValueName));
120*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kDWORDValueName));
121*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kInt64ValueName));
122*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(key.GetValueCount(), base::test::ValueIs(0U));
123*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(key.HasValue(kStringValueName));
124*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(key.HasValue(kDWORDValueName));
125*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(key.HasValue(kInt64ValueName));
126*6777b538SAndroid Build Coastguard Worker }
127*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,BigValueIteratorTest)128*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, BigValueIteratorTest) {
129*6777b538SAndroid Build Coastguard Worker   RegKey key;
130*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(),
131*6777b538SAndroid Build Coastguard Worker                                     KEY_READ | KEY_SET_VALUE));
132*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(key.Valid());
133*6777b538SAndroid Build Coastguard Worker 
134*6777b538SAndroid Build Coastguard Worker   // Create a test value that is larger than MAX_PATH.
135*6777b538SAndroid Build Coastguard Worker   std::wstring data(MAX_PATH * 2, 'a');
136*6777b538SAndroid Build Coastguard Worker 
137*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(data.c_str(), data.c_str()));
138*6777b538SAndroid Build Coastguard Worker 
139*6777b538SAndroid Build Coastguard Worker   RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str());
140*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(iterator.Valid());
141*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(data, iterator.Name());
142*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(data, iterator.Value());
143*6777b538SAndroid Build Coastguard Worker   // ValueSize() is in bytes, including NUL.
144*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ((MAX_PATH * 2 + 1) * sizeof(wchar_t), iterator.ValueSize());
145*6777b538SAndroid Build Coastguard Worker   ++iterator;
146*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(iterator.Valid());
147*6777b538SAndroid Build Coastguard Worker }
148*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,TruncatedCharTest)149*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, TruncatedCharTest) {
150*6777b538SAndroid Build Coastguard Worker   RegKey key;
151*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(),
152*6777b538SAndroid Build Coastguard Worker                                     KEY_READ | KEY_SET_VALUE));
153*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(key.Valid());
154*6777b538SAndroid Build Coastguard Worker 
155*6777b538SAndroid Build Coastguard Worker   const wchar_t kName[] = L"name";
156*6777b538SAndroid Build Coastguard Worker   // kData size is not a multiple of sizeof(wchar_t).
157*6777b538SAndroid Build Coastguard Worker   const uint8_t kData[] = {1, 2, 3, 4, 5};
158*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(5u, std::size(kData));
159*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
160*6777b538SAndroid Build Coastguard Worker             key.WriteValue(kName, kData, std::size(kData), REG_BINARY));
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker   RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str());
163*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(iterator.Valid());
164*6777b538SAndroid Build Coastguard Worker   // Avoid having to use EXPECT_STREQ here by leveraging std::string_view's
165*6777b538SAndroid Build Coastguard Worker   // operator== to perform a deep comparison.
166*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(std::wstring_view(kName), std::wstring_view(iterator.Name()));
167*6777b538SAndroid Build Coastguard Worker   // ValueSize() is in bytes.
168*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(std::size(kData), iterator.ValueSize());
169*6777b538SAndroid Build Coastguard Worker   // Value() is NUL terminated.
170*6777b538SAndroid Build Coastguard Worker   int end = (iterator.ValueSize() + sizeof(wchar_t) - 1) / sizeof(wchar_t);
171*6777b538SAndroid Build Coastguard Worker   EXPECT_NE('\0', iterator.Value()[end - 1]);
172*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ('\0', iterator.Value()[end]);
173*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0, std::memcmp(kData, iterator.Value(), std::size(kData)));
174*6777b538SAndroid Build Coastguard Worker   ++iterator;
175*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(iterator.Valid());
176*6777b538SAndroid Build Coastguard Worker }
177*6777b538SAndroid Build Coastguard Worker 
178*6777b538SAndroid Build Coastguard Worker // Tests that the value iterator is okay with an empty key.
TEST_F(RegistryTest,ValueIteratorEmptyKey)179*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, ValueIteratorEmptyKey) {
180*6777b538SAndroid Build Coastguard Worker   RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str());
181*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(iterator.ValueCount(), 0U);
182*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(iterator.Valid());
183*6777b538SAndroid Build Coastguard Worker }
184*6777b538SAndroid Build Coastguard Worker 
185*6777b538SAndroid Build Coastguard Worker // Tests that the default value is seen by a value iterator.
TEST_F(RegistryTest,ValueIteratorDefaultValue)186*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, ValueIteratorDefaultValue) {
187*6777b538SAndroid Build Coastguard Worker   const std::wstring_view kTestString(L"i miss you");
188*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(RegKey(HKEY_CURRENT_USER, root_key().c_str(), KEY_SET_VALUE)
189*6777b538SAndroid Build Coastguard Worker                 .WriteValue(nullptr, kTestString.data()),
190*6777b538SAndroid Build Coastguard Worker             ERROR_SUCCESS);
191*6777b538SAndroid Build Coastguard Worker   RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str());
192*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(iterator.ValueCount(), 1U);
193*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(iterator.Valid());
194*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(std::wstring_view(iterator.Name()), std::wstring_view());
195*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(iterator.ValueSize(), (kTestString.size() + 1) * sizeof(wchar_t));
196*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(iterator.Type(), REG_SZ);
197*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(std::wstring_view(iterator.Value()), kTestString);
198*6777b538SAndroid Build Coastguard Worker   ++iterator;
199*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(iterator.Valid());
200*6777b538SAndroid Build Coastguard Worker }
201*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,NonRecursiveDelete)202*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, NonRecursiveDelete) {
203*6777b538SAndroid Build Coastguard Worker   RegKey key;
204*6777b538SAndroid Build Coastguard Worker   // Create root_key()
205*6777b538SAndroid Build Coastguard Worker   //                  \->Bar (TestValue)
206*6777b538SAndroid Build Coastguard Worker   //                     \->Foo (TestValue)
207*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(),
208*6777b538SAndroid Build Coastguard Worker                                     KEY_CREATE_SUB_KEY));
209*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
210*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
211*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
212*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
213*6777b538SAndroid Build Coastguard Worker   key.Close();
214*6777b538SAndroid Build Coastguard Worker 
215*6777b538SAndroid Build Coastguard Worker   const std::wstring bar_path = root_key() + L"\\Bar";
216*6777b538SAndroid Build Coastguard Worker   // Non-recursive delete of Bar from root_key() should fail.
217*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
218*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_QUERY_VALUE));
219*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS,
220*6777b538SAndroid Build Coastguard Worker             key.DeleteKey(L"Bar", RegKey::RecursiveDelete(false)));
221*6777b538SAndroid Build Coastguard Worker   key.Close();
222*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(
223*6777b538SAndroid Build Coastguard Worker       RegKey(HKEY_CURRENT_USER, bar_path.c_str(), KEY_QUERY_VALUE).Valid());
224*6777b538SAndroid Build Coastguard Worker 
225*6777b538SAndroid Build Coastguard Worker   // Non-recursive delete of Bar from itself should fail.
226*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
227*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, bar_path.c_str(), KEY_QUERY_VALUE));
228*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"", RegKey::RecursiveDelete(false)));
229*6777b538SAndroid Build Coastguard Worker   key.Close();
230*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(
231*6777b538SAndroid Build Coastguard Worker       RegKey(HKEY_CURRENT_USER, root_key().c_str(), KEY_QUERY_VALUE).Valid());
232*6777b538SAndroid Build Coastguard Worker 
233*6777b538SAndroid Build Coastguard Worker   // Non-recursive delete of the subkey and then root_key() should succeed.
234*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
235*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, bar_path.c_str(), KEY_QUERY_VALUE));
236*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
237*6777b538SAndroid Build Coastguard Worker             key.DeleteKey(L"Foo", RegKey::RecursiveDelete(false)));
238*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"", RegKey::RecursiveDelete(false)));
239*6777b538SAndroid Build Coastguard Worker   key.Close();
240*6777b538SAndroid Build Coastguard Worker   ASSERT_FALSE(
241*6777b538SAndroid Build Coastguard Worker       RegKey(HKEY_CURRENT_USER, bar_path.c_str(), KEY_QUERY_VALUE).Valid());
242*6777b538SAndroid Build Coastguard Worker }
243*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,RecursiveDelete)244*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, RecursiveDelete) {
245*6777b538SAndroid Build Coastguard Worker   RegKey key;
246*6777b538SAndroid Build Coastguard Worker   // Create root_key()
247*6777b538SAndroid Build Coastguard Worker   //                  \->Bar (TestValue)
248*6777b538SAndroid Build Coastguard Worker   //                     \->Foo (TestValue)
249*6777b538SAndroid Build Coastguard Worker   //                        \->Bar
250*6777b538SAndroid Build Coastguard Worker   //                           \->Foo
251*6777b538SAndroid Build Coastguard Worker   //                  \->Moo
252*6777b538SAndroid Build Coastguard Worker   //                  \->Foo
253*6777b538SAndroid Build Coastguard Worker   // and delete root_key()
254*6777b538SAndroid Build Coastguard Worker   std::wstring key_path = root_key();
255*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
256*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_CREATE_SUB_KEY));
257*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
258*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
259*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
260*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_CREATE_SUB_KEY));
261*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Moo", KEY_WRITE));
262*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
263*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_CREATE_SUB_KEY));
264*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
265*6777b538SAndroid Build Coastguard Worker 
266*6777b538SAndroid Build Coastguard Worker   key_path += L"\\Bar";
267*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
268*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_CREATE_SUB_KEY));
269*6777b538SAndroid Build Coastguard Worker   key_path += L"\\Foo";
270*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
271*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
272*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
273*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ));
274*6777b538SAndroid Build Coastguard Worker 
275*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
276*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_CREATE_SUB_KEY));
277*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
278*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
279*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
280*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE));
281*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L""));
282*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS,
283*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ));
284*6777b538SAndroid Build Coastguard Worker 
285*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
286*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_WRITE));
287*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"Bar"));
288*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Bar"));
289*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS,
290*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ));
291*6777b538SAndroid Build Coastguard Worker }
292*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,OpenSubKey)293*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, OpenSubKey) {
294*6777b538SAndroid Build Coastguard Worker   RegKey key;
295*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(),
296*6777b538SAndroid Build Coastguard Worker                                     KEY_READ | KEY_CREATE_SUB_KEY));
297*6777b538SAndroid Build Coastguard Worker 
298*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
299*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"foo", KEY_READ));
300*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
301*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ));
302*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
303*6777b538SAndroid Build Coastguard Worker 
304*6777b538SAndroid Build Coastguard Worker   std::wstring foo_key = root_key() + L"\\Foo";
305*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
306*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
307*6777b538SAndroid Build Coastguard Worker 
308*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
309*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_WRITE));
310*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"foo"));
311*6777b538SAndroid Build Coastguard Worker }
312*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,InvalidRelativeKeyCreate)313*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, InvalidRelativeKeyCreate) {
314*6777b538SAndroid Build Coastguard Worker   RegKey key(HKEY_CURRENT_USER,
315*6777b538SAndroid Build Coastguard Worker              base::StrCat({this->root_key(), L"_DoesNotExist"}).c_str(),
316*6777b538SAndroid Build Coastguard Worker              KEY_WOW64_32KEY | KEY_READ);
317*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(key.CreateKey(L"SomeSubKey", KEY_WOW64_32KEY | KEY_WRITE),
318*6777b538SAndroid Build Coastguard Worker             ERROR_INVALID_HANDLE);
319*6777b538SAndroid Build Coastguard Worker }
320*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,InvalidRelativeKeyOpen)321*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, InvalidRelativeKeyOpen) {
322*6777b538SAndroid Build Coastguard Worker   RegKey key(HKEY_CURRENT_USER,
323*6777b538SAndroid Build Coastguard Worker              base::StrCat({this->root_key(), L"_DoesNotExist"}).c_str(),
324*6777b538SAndroid Build Coastguard Worker              KEY_WOW64_32KEY | KEY_READ);
325*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(key.OpenKey(L"SomeSubKey", KEY_WOW64_32KEY | KEY_READ),
326*6777b538SAndroid Build Coastguard Worker             ERROR_INVALID_HANDLE);
327*6777b538SAndroid Build Coastguard Worker }
328*6777b538SAndroid Build Coastguard Worker 
329*6777b538SAndroid Build Coastguard Worker namespace {
330*6777b538SAndroid Build Coastguard Worker 
331*6777b538SAndroid Build Coastguard Worker class TestChangeDelegate {
332*6777b538SAndroid Build Coastguard Worker  public:
333*6777b538SAndroid Build Coastguard Worker   TestChangeDelegate() = default;
334*6777b538SAndroid Build Coastguard Worker   ~TestChangeDelegate() = default;
335*6777b538SAndroid Build Coastguard Worker 
OnKeyChanged(base::OnceClosure quit_closure)336*6777b538SAndroid Build Coastguard Worker   void OnKeyChanged(base::OnceClosure quit_closure) {
337*6777b538SAndroid Build Coastguard Worker     std::move(quit_closure).Run();
338*6777b538SAndroid Build Coastguard Worker     called_ = true;
339*6777b538SAndroid Build Coastguard Worker   }
340*6777b538SAndroid Build Coastguard Worker 
WasCalled()341*6777b538SAndroid Build Coastguard Worker   bool WasCalled() {
342*6777b538SAndroid Build Coastguard Worker     bool was_called = called_;
343*6777b538SAndroid Build Coastguard Worker     called_ = false;
344*6777b538SAndroid Build Coastguard Worker     return was_called;
345*6777b538SAndroid Build Coastguard Worker   }
346*6777b538SAndroid Build Coastguard Worker 
347*6777b538SAndroid Build Coastguard Worker  private:
348*6777b538SAndroid Build Coastguard Worker   bool called_ = false;
349*6777b538SAndroid Build Coastguard Worker };
350*6777b538SAndroid Build Coastguard Worker 
351*6777b538SAndroid Build Coastguard Worker }  // namespace
352*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,ChangeCallback)353*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, ChangeCallback) {
354*6777b538SAndroid Build Coastguard Worker   RegKey key;
355*6777b538SAndroid Build Coastguard Worker   TestChangeDelegate delegate;
356*6777b538SAndroid Build Coastguard Worker   test::TaskEnvironment task_environment;
357*6777b538SAndroid Build Coastguard Worker   base::RunLoop loop1;
358*6777b538SAndroid Build Coastguard Worker   base::RunLoop loop2;
359*6777b538SAndroid Build Coastguard Worker   base::RunLoop loop3;
360*6777b538SAndroid Build Coastguard Worker 
361*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
362*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ));
363*6777b538SAndroid Build Coastguard Worker 
364*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(key.StartWatching(BindOnce(&TestChangeDelegate::OnKeyChanged,
365*6777b538SAndroid Build Coastguard Worker                                          Unretained(&delegate),
366*6777b538SAndroid Build Coastguard Worker                                          loop1.QuitWhenIdleClosure())));
367*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(delegate.WasCalled());
368*6777b538SAndroid Build Coastguard Worker 
369*6777b538SAndroid Build Coastguard Worker   // Make some change.
370*6777b538SAndroid Build Coastguard Worker   RegKey key2;
371*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key2.Open(HKEY_CURRENT_USER, root_key().c_str(),
372*6777b538SAndroid Build Coastguard Worker                                      KEY_READ | KEY_SET_VALUE));
373*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(key2.Valid());
374*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(ERROR_SUCCESS, key2.WriteValue(L"name", L"data"));
375*6777b538SAndroid Build Coastguard Worker 
376*6777b538SAndroid Build Coastguard Worker   // Allow delivery of the notification.
377*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(delegate.WasCalled());
378*6777b538SAndroid Build Coastguard Worker   loop1.Run();
379*6777b538SAndroid Build Coastguard Worker 
380*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(delegate.WasCalled());
381*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(delegate.WasCalled());
382*6777b538SAndroid Build Coastguard Worker 
383*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(key.StartWatching(BindOnce(&TestChangeDelegate::OnKeyChanged,
384*6777b538SAndroid Build Coastguard Worker                                          Unretained(&delegate),
385*6777b538SAndroid Build Coastguard Worker                                          loop2.QuitWhenIdleClosure())));
386*6777b538SAndroid Build Coastguard Worker 
387*6777b538SAndroid Build Coastguard Worker   // Change something else.
388*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(ERROR_SUCCESS, key2.WriteValue(L"name2", L"data2"));
389*6777b538SAndroid Build Coastguard Worker   loop2.Run();
390*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(delegate.WasCalled());
391*6777b538SAndroid Build Coastguard Worker 
392*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(key.StartWatching(BindOnce(&TestChangeDelegate::OnKeyChanged,
393*6777b538SAndroid Build Coastguard Worker                                          Unretained(&delegate),
394*6777b538SAndroid Build Coastguard Worker                                          loop3.QuitWhenIdleClosure())));
395*6777b538SAndroid Build Coastguard Worker   loop3.RunUntilIdle();
396*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(delegate.WasCalled());
397*6777b538SAndroid Build Coastguard Worker }
398*6777b538SAndroid Build Coastguard Worker 
399*6777b538SAndroid Build Coastguard Worker namespace {
400*6777b538SAndroid Build Coastguard Worker 
401*6777b538SAndroid Build Coastguard Worker // A thread that runs tasks from a TestMockTimeTaskRunner.
402*6777b538SAndroid Build Coastguard Worker class RegistryWatcherThread : public SimpleThread {
403*6777b538SAndroid Build Coastguard Worker  public:
RegistryWatcherThread(scoped_refptr<base::TestMockTimeTaskRunner> task_runner)404*6777b538SAndroid Build Coastguard Worker   explicit RegistryWatcherThread(
405*6777b538SAndroid Build Coastguard Worker       scoped_refptr<base::TestMockTimeTaskRunner> task_runner)
406*6777b538SAndroid Build Coastguard Worker       : SimpleThread("RegistryWatcherThread"),
407*6777b538SAndroid Build Coastguard Worker         task_runner_(std::move(task_runner)) {}
408*6777b538SAndroid Build Coastguard Worker 
409*6777b538SAndroid Build Coastguard Worker  private:
Run()410*6777b538SAndroid Build Coastguard Worker   void Run() override {
411*6777b538SAndroid Build Coastguard Worker     task_runner_->DetachFromThread();
412*6777b538SAndroid Build Coastguard Worker     task_runner_->RunUntilIdle();
413*6777b538SAndroid Build Coastguard Worker   }
414*6777b538SAndroid Build Coastguard Worker   const scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
415*6777b538SAndroid Build Coastguard Worker };
416*6777b538SAndroid Build Coastguard Worker 
417*6777b538SAndroid Build Coastguard Worker }  // namespace
418*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,WatcherNotSignaledOnInitiatingThreadExit)419*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, WatcherNotSignaledOnInitiatingThreadExit) {
420*6777b538SAndroid Build Coastguard Worker   RegKey key;
421*6777b538SAndroid Build Coastguard Worker 
422*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ),
423*6777b538SAndroid Build Coastguard Worker             ERROR_SUCCESS);
424*6777b538SAndroid Build Coastguard Worker 
425*6777b538SAndroid Build Coastguard Worker   auto test_task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
426*6777b538SAndroid Build Coastguard Worker       base::TestMockTimeTaskRunner::Type::kBoundToThread);
427*6777b538SAndroid Build Coastguard Worker   ::testing::StrictMock<base::MockCallback<base::win::RegKey::ChangeCallback>>
428*6777b538SAndroid Build Coastguard Worker       change_cb;
429*6777b538SAndroid Build Coastguard Worker 
430*6777b538SAndroid Build Coastguard Worker   test_task_runner->PostTask(FROM_HERE,
431*6777b538SAndroid Build Coastguard Worker                              BindOnce(IgnoreResult(&RegKey::StartWatching),
432*6777b538SAndroid Build Coastguard Worker                                       Unretained(&key), change_cb.Get()));
433*6777b538SAndroid Build Coastguard Worker 
434*6777b538SAndroid Build Coastguard Worker   {
435*6777b538SAndroid Build Coastguard Worker     // Start the watch on a thread that then goes away.
436*6777b538SAndroid Build Coastguard Worker     RegistryWatcherThread watcher_thread(test_task_runner);
437*6777b538SAndroid Build Coastguard Worker     watcher_thread.Start();
438*6777b538SAndroid Build Coastguard Worker     watcher_thread.Join();
439*6777b538SAndroid Build Coastguard Worker   }
440*6777b538SAndroid Build Coastguard Worker 
441*6777b538SAndroid Build Coastguard Worker   // Termination of the thread should not cause a notification to get sent.
442*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(&change_cb));
443*6777b538SAndroid Build Coastguard Worker   test_task_runner->DetachFromThread();
444*6777b538SAndroid Build Coastguard Worker   ASSERT_FALSE(test_task_runner->HasPendingTask());
445*6777b538SAndroid Build Coastguard Worker 
446*6777b538SAndroid Build Coastguard Worker   // Expect that a notification is sent when a change is made. Exit the run loop
447*6777b538SAndroid Build Coastguard Worker   // when this happens.
448*6777b538SAndroid Build Coastguard Worker   base::RunLoop run_loop;
449*6777b538SAndroid Build Coastguard Worker   EXPECT_CALL(change_cb, Run).WillOnce([&run_loop]() { run_loop.Quit(); });
450*6777b538SAndroid Build Coastguard Worker 
451*6777b538SAndroid Build Coastguard Worker   // Make some change.
452*6777b538SAndroid Build Coastguard Worker   RegKey key2;
453*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(key2.Open(HKEY_CURRENT_USER, root_key().c_str(),
454*6777b538SAndroid Build Coastguard Worker                       KEY_READ | KEY_SET_VALUE),
455*6777b538SAndroid Build Coastguard Worker             ERROR_SUCCESS);
456*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(key2.Valid());
457*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(key2.WriteValue(L"name", L"data"), ERROR_SUCCESS);
458*6777b538SAndroid Build Coastguard Worker 
459*6777b538SAndroid Build Coastguard Worker   // Wait for the watcher to be signaled.
460*6777b538SAndroid Build Coastguard Worker   run_loop.Run();
461*6777b538SAndroid Build Coastguard Worker }
462*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,TestMoveConstruct)463*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, TestMoveConstruct) {
464*6777b538SAndroid Build Coastguard Worker   RegKey key;
465*6777b538SAndroid Build Coastguard Worker 
466*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_SET_VALUE),
467*6777b538SAndroid Build Coastguard Worker             ERROR_SUCCESS);
468*6777b538SAndroid Build Coastguard Worker   RegKey key2(std::move(key));
469*6777b538SAndroid Build Coastguard Worker 
470*6777b538SAndroid Build Coastguard Worker   // The old key should be meaningless now.
471*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(key.Handle(), nullptr);
472*6777b538SAndroid Build Coastguard Worker 
473*6777b538SAndroid Build Coastguard Worker   // And the new one should work just fine.
474*6777b538SAndroid Build Coastguard Worker   EXPECT_NE(key2.Handle(), nullptr);
475*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(key2.WriteValue(L"foo", 1U), ERROR_SUCCESS);
476*6777b538SAndroid Build Coastguard Worker }
477*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTest,TestMoveAssign)478*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, TestMoveAssign) {
479*6777b538SAndroid Build Coastguard Worker   RegKey key;
480*6777b538SAndroid Build Coastguard Worker   RegKey key2;
481*6777b538SAndroid Build Coastguard Worker   const wchar_t kFooValueName[] = L"foo";
482*6777b538SAndroid Build Coastguard Worker 
483*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(key.Open(HKEY_CURRENT_USER, root_key().c_str(),
484*6777b538SAndroid Build Coastguard Worker                      KEY_SET_VALUE | KEY_QUERY_VALUE),
485*6777b538SAndroid Build Coastguard Worker             ERROR_SUCCESS);
486*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(key.WriteValue(kFooValueName, 1U), ERROR_SUCCESS);
487*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(key2.Create(HKEY_CURRENT_USER, (root_key() + L"\\child").c_str(),
488*6777b538SAndroid Build Coastguard Worker                         KEY_SET_VALUE),
489*6777b538SAndroid Build Coastguard Worker             ERROR_SUCCESS);
490*6777b538SAndroid Build Coastguard Worker   key2 = std::move(key);
491*6777b538SAndroid Build Coastguard Worker 
492*6777b538SAndroid Build Coastguard Worker   // The old key should be meaningless now.
493*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(key.Handle(), nullptr);
494*6777b538SAndroid Build Coastguard Worker 
495*6777b538SAndroid Build Coastguard Worker   // And the new one should hold what was the old one.
496*6777b538SAndroid Build Coastguard Worker   EXPECT_NE(key2.Handle(), nullptr);
497*6777b538SAndroid Build Coastguard Worker   DWORD foo = 0;
498*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(key2.ReadValueDW(kFooValueName, &foo), ERROR_SUCCESS);
499*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(foo, 1U);
500*6777b538SAndroid Build Coastguard Worker }
501*6777b538SAndroid Build Coastguard Worker 
502*6777b538SAndroid Build Coastguard Worker // Verify that either the platform, or the API-integration, causes deletion
503*6777b538SAndroid Build Coastguard Worker // attempts via an invalid handle to fail with the expected error code.
TEST_F(RegistryTest,DeleteWithInvalidRegKey)504*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTest, DeleteWithInvalidRegKey) {
505*6777b538SAndroid Build Coastguard Worker   RegKey key;
506*6777b538SAndroid Build Coastguard Worker 
507*6777b538SAndroid Build Coastguard Worker   static const wchar_t kFooName[] = L"foo";
508*6777b538SAndroid Build Coastguard Worker 
509*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(key.DeleteKey(kFooName), ERROR_INVALID_HANDLE);
510*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(key.DeleteValue(kFooName), ERROR_INVALID_HANDLE);
511*6777b538SAndroid Build Coastguard Worker }
512*6777b538SAndroid Build Coastguard Worker 
513*6777b538SAndroid Build Coastguard Worker // A test harness for tests of RegKey::DeleteKey; parameterized on whether to
514*6777b538SAndroid Build Coastguard Worker // perform non-recursive or recursive deletes.
515*6777b538SAndroid Build Coastguard Worker class DeleteKeyRegistryTest
516*6777b538SAndroid Build Coastguard Worker     : public RegistryTest,
517*6777b538SAndroid Build Coastguard Worker       public ::testing::WithParamInterface<RegKey::RecursiveDelete> {
518*6777b538SAndroid Build Coastguard Worker  protected:
519*6777b538SAndroid Build Coastguard Worker   DeleteKeyRegistryTest() = default;
520*6777b538SAndroid Build Coastguard Worker 
521*6777b538SAndroid Build Coastguard Worker  private:
522*6777b538SAndroid Build Coastguard Worker };
523*6777b538SAndroid Build Coastguard Worker 
524*6777b538SAndroid Build Coastguard Worker // Test that DeleteKey does not follow symbolic links.
TEST_P(DeleteKeyRegistryTest,DoesNotFollowLinks)525*6777b538SAndroid Build Coastguard Worker TEST_P(DeleteKeyRegistryTest, DoesNotFollowLinks) {
526*6777b538SAndroid Build Coastguard Worker   // Create a subkey that should not be deleted.
527*6777b538SAndroid Build Coastguard Worker   std::wstring target_path = root_key() + L"\\LinkTarget";
528*6777b538SAndroid Build Coastguard Worker   {
529*6777b538SAndroid Build Coastguard Worker     RegKey target;
530*6777b538SAndroid Build Coastguard Worker     ASSERT_EQ(target.Create(HKEY_CURRENT_USER, target_path.c_str(), KEY_WRITE),
531*6777b538SAndroid Build Coastguard Worker               ERROR_SUCCESS);
532*6777b538SAndroid Build Coastguard Worker     ASSERT_EQ(target.WriteValue(L"IsTarget", 1U), ERROR_SUCCESS);
533*6777b538SAndroid Build Coastguard Worker   }
534*6777b538SAndroid Build Coastguard Worker 
535*6777b538SAndroid Build Coastguard Worker   // Create a link to the above key.
536*6777b538SAndroid Build Coastguard Worker   std::wstring source_path = root_key() + L"\\LinkSource";
537*6777b538SAndroid Build Coastguard Worker   {
538*6777b538SAndroid Build Coastguard Worker     HKEY link_handle = {};
539*6777b538SAndroid Build Coastguard Worker     ASSERT_EQ(RegCreateKeyEx(HKEY_CURRENT_USER, source_path.c_str(), 0, nullptr,
540*6777b538SAndroid Build Coastguard Worker                              REG_OPTION_CREATE_LINK | REG_OPTION_NON_VOLATILE,
541*6777b538SAndroid Build Coastguard Worker                              KEY_WRITE, nullptr, &link_handle, nullptr),
542*6777b538SAndroid Build Coastguard Worker               ERROR_SUCCESS);
543*6777b538SAndroid Build Coastguard Worker     RegKey link(std::exchange(link_handle, HKEY{}));
544*6777b538SAndroid Build Coastguard Worker     ASSERT_TRUE(link.Valid());
545*6777b538SAndroid Build Coastguard Worker 
546*6777b538SAndroid Build Coastguard Worker     std::wstring user_sid;
547*6777b538SAndroid Build Coastguard Worker     ASSERT_TRUE(GetUserSidString(&user_sid));
548*6777b538SAndroid Build Coastguard Worker 
549*6777b538SAndroid Build Coastguard Worker     std::wstring value =
550*6777b538SAndroid Build Coastguard Worker         base::StrCat({L"\\Registry\\User\\", user_sid, L"\\", override_path(),
551*6777b538SAndroid Build Coastguard Worker                       L"\\", root_key(), L"\\LinkTarget"});
552*6777b538SAndroid Build Coastguard Worker     ASSERT_EQ(link.WriteValue(L"SymbolicLinkValue", value.data(),
553*6777b538SAndroid Build Coastguard Worker                               value.size() * sizeof(wchar_t), REG_LINK),
554*6777b538SAndroid Build Coastguard Worker               ERROR_SUCCESS);
555*6777b538SAndroid Build Coastguard Worker   }
556*6777b538SAndroid Build Coastguard Worker 
557*6777b538SAndroid Build Coastguard Worker   // Verify that the link works.
558*6777b538SAndroid Build Coastguard Worker   {
559*6777b538SAndroid Build Coastguard Worker     RegKey link;
560*6777b538SAndroid Build Coastguard Worker     ASSERT_EQ(link.Open(HKEY_CURRENT_USER, source_path.c_str(), KEY_READ),
561*6777b538SAndroid Build Coastguard Worker               ERROR_SUCCESS);
562*6777b538SAndroid Build Coastguard Worker     DWORD value = 0;
563*6777b538SAndroid Build Coastguard Worker     ASSERT_EQ(link.ReadValueDW(L"IsTarget", &value), ERROR_SUCCESS);
564*6777b538SAndroid Build Coastguard Worker     ASSERT_EQ(value, 1U);
565*6777b538SAndroid Build Coastguard Worker   }
566*6777b538SAndroid Build Coastguard Worker 
567*6777b538SAndroid Build Coastguard Worker   // Now delete the link and ensure that it was deleted, but not the target.
568*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(RegKey(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ)
569*6777b538SAndroid Build Coastguard Worker                 .DeleteKey(L"LinkSource", GetParam()),
570*6777b538SAndroid Build Coastguard Worker             ERROR_SUCCESS);
571*6777b538SAndroid Build Coastguard Worker   {
572*6777b538SAndroid Build Coastguard Worker     RegKey source;
573*6777b538SAndroid Build Coastguard Worker     ASSERT_NE(source.Open(HKEY_CURRENT_USER, source_path.c_str(), KEY_READ),
574*6777b538SAndroid Build Coastguard Worker               ERROR_SUCCESS);
575*6777b538SAndroid Build Coastguard Worker   }
576*6777b538SAndroid Build Coastguard Worker   {
577*6777b538SAndroid Build Coastguard Worker     RegKey target;
578*6777b538SAndroid Build Coastguard Worker     ASSERT_EQ(target.Open(HKEY_CURRENT_USER, target_path.c_str(), KEY_READ),
579*6777b538SAndroid Build Coastguard Worker               ERROR_SUCCESS);
580*6777b538SAndroid Build Coastguard Worker   }
581*6777b538SAndroid Build Coastguard Worker }
582*6777b538SAndroid Build Coastguard Worker 
583*6777b538SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(NonRecursive,
584*6777b538SAndroid Build Coastguard Worker                          DeleteKeyRegistryTest,
585*6777b538SAndroid Build Coastguard Worker                          ::testing::Values(RegKey::RecursiveDelete(false)));
586*6777b538SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(Recursive,
587*6777b538SAndroid Build Coastguard Worker                          DeleteKeyRegistryTest,
588*6777b538SAndroid Build Coastguard Worker                          ::testing::Values(RegKey::RecursiveDelete(true)));
589*6777b538SAndroid Build Coastguard Worker 
590*6777b538SAndroid Build Coastguard Worker // A test harness for tests that use HKLM to test WoW redirection and such.
591*6777b538SAndroid Build Coastguard Worker // TODO(https://crbug.com/377917): The tests here that write to the registry are
592*6777b538SAndroid Build Coastguard Worker // disabled because they need work to handle parallel runs of different tests.
593*6777b538SAndroid Build Coastguard Worker class RegistryTestHKLM : public ::testing::Test {
594*6777b538SAndroid Build Coastguard Worker  protected:
595*6777b538SAndroid Build Coastguard Worker   enum : REGSAM {
596*6777b538SAndroid Build Coastguard Worker #if defined(_WIN64)
597*6777b538SAndroid Build Coastguard Worker     kNativeViewMask = KEY_WOW64_64KEY,
598*6777b538SAndroid Build Coastguard Worker     kRedirectedViewMask = KEY_WOW64_32KEY,
599*6777b538SAndroid Build Coastguard Worker #else
600*6777b538SAndroid Build Coastguard Worker     kNativeViewMask = KEY_WOW64_32KEY,
601*6777b538SAndroid Build Coastguard Worker     kRedirectedViewMask = KEY_WOW64_64KEY,
602*6777b538SAndroid Build Coastguard Worker #endif  //  _WIN64
603*6777b538SAndroid Build Coastguard Worker   };
604*6777b538SAndroid Build Coastguard Worker 
RegistryTestHKLM()605*6777b538SAndroid Build Coastguard Worker   RegistryTestHKLM()
606*6777b538SAndroid Build Coastguard Worker       : foo_software_key_(std::wstring(L"Software\\") + kRootKey + L"\\Foo") {}
607*6777b538SAndroid Build Coastguard Worker 
IsRedirectorPresent()608*6777b538SAndroid Build Coastguard Worker   static bool IsRedirectorPresent() {
609*6777b538SAndroid Build Coastguard Worker #if defined(_WIN64)
610*6777b538SAndroid Build Coastguard Worker     return true;
611*6777b538SAndroid Build Coastguard Worker #else
612*6777b538SAndroid Build Coastguard Worker     return OSInfo::GetInstance()->IsWowX86OnAMD64();
613*6777b538SAndroid Build Coastguard Worker #endif
614*6777b538SAndroid Build Coastguard Worker   }
615*6777b538SAndroid Build Coastguard Worker 
616*6777b538SAndroid Build Coastguard Worker   const std::wstring foo_software_key_;
617*6777b538SAndroid Build Coastguard Worker };
618*6777b538SAndroid Build Coastguard Worker 
619*6777b538SAndroid Build Coastguard Worker class RegistryTestHKLMAdmin : public RegistryTestHKLM {
620*6777b538SAndroid Build Coastguard Worker  protected:
SetUp()621*6777b538SAndroid Build Coastguard Worker   void SetUp() override {
622*6777b538SAndroid Build Coastguard Worker     if (!IsRedirectorPresent()) {
623*6777b538SAndroid Build Coastguard Worker       GTEST_SKIP();
624*6777b538SAndroid Build Coastguard Worker     }
625*6777b538SAndroid Build Coastguard Worker     if (!::IsUserAnAdmin()) {
626*6777b538SAndroid Build Coastguard Worker       GTEST_SKIP();
627*6777b538SAndroid Build Coastguard Worker     }
628*6777b538SAndroid Build Coastguard Worker     // Clean up any stale registry keys.
629*6777b538SAndroid Build Coastguard Worker     for (const REGSAM mask :
630*6777b538SAndroid Build Coastguard Worker          {this->kNativeViewMask, this->kRedirectedViewMask}) {
631*6777b538SAndroid Build Coastguard Worker       RegKey key;
632*6777b538SAndroid Build Coastguard Worker       if (key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE | mask) ==
633*6777b538SAndroid Build Coastguard Worker           ERROR_SUCCESS) {
634*6777b538SAndroid Build Coastguard Worker         key.DeleteKey(kRootKey);
635*6777b538SAndroid Build Coastguard Worker       }
636*6777b538SAndroid Build Coastguard Worker     }
637*6777b538SAndroid Build Coastguard Worker   }
638*6777b538SAndroid Build Coastguard Worker };
639*6777b538SAndroid Build Coastguard Worker 
640*6777b538SAndroid Build Coastguard Worker // This test requires running as an Administrator as it tests redirected
641*6777b538SAndroid Build Coastguard Worker // registry writes to HKLM\Software
642*6777b538SAndroid Build Coastguard Worker // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384253.aspx
TEST_F(RegistryTestHKLMAdmin,Wow64RedirectedFromNative)643*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTestHKLMAdmin, Wow64RedirectedFromNative) {
644*6777b538SAndroid Build Coastguard Worker   RegKey key;
645*6777b538SAndroid Build Coastguard Worker 
646*6777b538SAndroid Build Coastguard Worker   // Test redirected key access from non-redirected.
647*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
648*6777b538SAndroid Build Coastguard Worker             key.Create(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(),
649*6777b538SAndroid Build Coastguard Worker                        KEY_WRITE | kRedirectedViewMask));
650*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS,
651*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
652*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS,
653*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(),
654*6777b538SAndroid Build Coastguard Worker                      KEY_READ | kNativeViewMask));
655*6777b538SAndroid Build Coastguard Worker 
656*6777b538SAndroid Build Coastguard Worker   // Open the non-redirected view of the parent and try to delete the test key.
657*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
658*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE));
659*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
660*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software",
661*6777b538SAndroid Build Coastguard Worker                                     KEY_SET_VALUE | kNativeViewMask));
662*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
663*6777b538SAndroid Build Coastguard Worker 
664*6777b538SAndroid Build Coastguard Worker   // Open the redirected view and delete the key created above.
665*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software",
666*6777b538SAndroid Build Coastguard Worker                                     KEY_SET_VALUE | kRedirectedViewMask));
667*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
668*6777b538SAndroid Build Coastguard Worker }
669*6777b538SAndroid Build Coastguard Worker 
670*6777b538SAndroid Build Coastguard Worker // Test for the issue found in http://crbug.com/384587 where OpenKey would call
671*6777b538SAndroid Build Coastguard Worker // Close() and reset wow64_access_ flag to 0 and cause a NOTREACHED to hit on a
672*6777b538SAndroid Build Coastguard Worker // subsequent OpenKey call.
TEST_F(RegistryTestHKLM,SameWowFlags)673*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTestHKLM, SameWowFlags) {
674*6777b538SAndroid Build Coastguard Worker   RegKey key;
675*6777b538SAndroid Build Coastguard Worker 
676*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software",
677*6777b538SAndroid Build Coastguard Worker                                     KEY_READ | KEY_WOW64_64KEY));
678*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
679*6777b538SAndroid Build Coastguard Worker             key.OpenKey(L"Microsoft", KEY_READ | KEY_WOW64_64KEY));
680*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"Windows", KEY_READ | KEY_WOW64_64KEY));
681*6777b538SAndroid Build Coastguard Worker }
682*6777b538SAndroid Build Coastguard Worker 
TEST_F(RegistryTestHKLMAdmin,Wow64NativeFromRedirected)683*6777b538SAndroid Build Coastguard Worker TEST_F(RegistryTestHKLMAdmin, Wow64NativeFromRedirected) {
684*6777b538SAndroid Build Coastguard Worker   RegKey key;
685*6777b538SAndroid Build Coastguard Worker 
686*6777b538SAndroid Build Coastguard Worker   // Test non-redirected key access from redirected.
687*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
688*6777b538SAndroid Build Coastguard Worker             key.Create(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(),
689*6777b538SAndroid Build Coastguard Worker                        KEY_WRITE | kNativeViewMask));
690*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS,
691*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
692*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS,
693*6777b538SAndroid Build Coastguard Worker             key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(),
694*6777b538SAndroid Build Coastguard Worker                      KEY_READ | kRedirectedViewMask));
695*6777b538SAndroid Build Coastguard Worker 
696*6777b538SAndroid Build Coastguard Worker   // Open the redirected view of the parent and try to delete the test key
697*6777b538SAndroid Build Coastguard Worker   // from the non-redirected view.
698*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software",
699*6777b538SAndroid Build Coastguard Worker                                     KEY_SET_VALUE | kRedirectedViewMask));
700*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
701*6777b538SAndroid Build Coastguard Worker 
702*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software",
703*6777b538SAndroid Build Coastguard Worker                                     KEY_SET_VALUE | kNativeViewMask));
704*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
705*6777b538SAndroid Build Coastguard Worker }
706*6777b538SAndroid Build Coastguard Worker 
707*6777b538SAndroid Build Coastguard Worker }  // namespace base::win
708