1 // Copyright (c) 2012 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 "chrome/installer/setup/setup_util_unittest.h"
11 #include "base/command_line.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/macros.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/process/kill.h"
17 #include "base/process/launch.h"
18 #include "base/process/process_handle.h"
19 #include "base/strings/string_util.h"
20 #include "base/test/test_reg_util_win.h"
21 #include "base/test/test_timeouts.h"
22 #include "base/threading/platform_thread.h"
23 #include "base/version.h"
24 #include "base/win/registry.h"
25 #include "base/win/scoped_handle.h"
26 #include "base/win/windows_version.h"
27 #include "chrome/installer/setup/setup_constants.h"
28 #include "chrome/installer/setup/setup_util.h"
29 #include "chrome/installer/util/browser_distribution.h"
30 #include "chrome/installer/util/google_update_constants.h"
31 #include "chrome/installer/util/installation_state.h"
32 #include "chrome/installer/util/installer_state.h"
33 #include "chrome/installer/util/updating_app_registration_data.h"
34 #include "chrome/installer/util/util_constants.h"
35 #include "testing/gtest/include/gtest/gtest.h"
39 // The privilege tested in ScopeTokenPrivilege tests below.
40 // Use SE_RESTORE_NAME as it is one of the many privileges that is available,
41 // but not enabled by default on processes running at high integrity.
42 static const wchar_t kTestedPrivilege
[] = SE_RESTORE_NAME
;
44 // Returns true if the current process' token has privilege |privilege_name|
46 bool CurrentProcessHasPrivilege(const wchar_t* privilege_name
) {
48 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY
,
54 base::win::ScopedHandle
token(temp_handle
);
56 // First get the size of the buffer needed for |privileges| below.
58 EXPECT_FALSE(::GetTokenInformation(token
.Get(), TokenPrivileges
, NULL
, 0,
61 scoped_ptr
<BYTE
[]> privileges_bytes(new BYTE
[size
]);
62 TOKEN_PRIVILEGES
* privileges
=
63 reinterpret_cast<TOKEN_PRIVILEGES
*>(privileges_bytes
.get());
65 if (!::GetTokenInformation(token
.Get(), TokenPrivileges
, privileges
, size
,
71 // There is no point getting a buffer to store more than |privilege_name|\0 as
72 // anything longer will obviously not be equal to |privilege_name|.
73 const DWORD desired_size
= static_cast<DWORD
>(wcslen(privilege_name
));
74 const DWORD buffer_size
= desired_size
+ 1;
75 scoped_ptr
<wchar_t[]> name_buffer(new wchar_t[buffer_size
]);
76 for (int i
= privileges
->PrivilegeCount
- 1; i
>= 0 ; --i
) {
77 LUID_AND_ATTRIBUTES
& luid_and_att
= privileges
->Privileges
[i
];
78 DWORD size
= buffer_size
;
79 ::LookupPrivilegeName(NULL
, &luid_and_att
.Luid
, name_buffer
.get(), &size
);
80 if (size
== desired_size
&&
81 wcscmp(name_buffer
.get(), privilege_name
) == 0) {
82 return luid_and_att
.Attributes
== SE_PRIVILEGE_ENABLED
;
90 // Test that we are parsing Chrome version correctly.
91 TEST(SetupUtilTest
, GetMaxVersionFromArchiveDirTest
) {
92 // Create a version dir
93 base::ScopedTempDir test_dir
;
94 ASSERT_TRUE(test_dir
.CreateUniqueTempDir());
95 base::FilePath chrome_dir
= test_dir
.path().AppendASCII("1.0.0.0");
96 base::CreateDirectory(chrome_dir
);
97 ASSERT_TRUE(base::PathExists(chrome_dir
));
98 scoped_ptr
<Version
> version(
99 installer::GetMaxVersionFromArchiveDir(test_dir
.path()));
100 ASSERT_EQ(version
->GetString(), "1.0.0.0");
102 base::DeleteFile(chrome_dir
, true);
103 ASSERT_FALSE(base::PathExists(chrome_dir
)) << chrome_dir
.value();
104 ASSERT_TRUE(installer::GetMaxVersionFromArchiveDir(test_dir
.path()) == NULL
);
106 chrome_dir
= test_dir
.path().AppendASCII("ABC");
107 base::CreateDirectory(chrome_dir
);
108 ASSERT_TRUE(base::PathExists(chrome_dir
));
109 ASSERT_TRUE(installer::GetMaxVersionFromArchiveDir(test_dir
.path()) == NULL
);
111 chrome_dir
= test_dir
.path().AppendASCII("2.3.4.5");
112 base::CreateDirectory(chrome_dir
);
113 ASSERT_TRUE(base::PathExists(chrome_dir
));
114 version
.reset(installer::GetMaxVersionFromArchiveDir(test_dir
.path()));
115 ASSERT_EQ(version
->GetString(), "2.3.4.5");
117 // Create multiple version dirs, ensure that we select the greatest.
118 chrome_dir
= test_dir
.path().AppendASCII("9.9.9.9");
119 base::CreateDirectory(chrome_dir
);
120 ASSERT_TRUE(base::PathExists(chrome_dir
));
121 chrome_dir
= test_dir
.path().AppendASCII("1.1.1.1");
122 base::CreateDirectory(chrome_dir
);
123 ASSERT_TRUE(base::PathExists(chrome_dir
));
125 version
.reset(installer::GetMaxVersionFromArchiveDir(test_dir
.path()));
126 ASSERT_EQ(version
->GetString(), "9.9.9.9");
129 TEST(SetupUtilTest
, DeleteFileFromTempProcess
) {
130 base::ScopedTempDir test_dir
;
131 ASSERT_TRUE(test_dir
.CreateUniqueTempDir());
132 base::FilePath test_file
;
133 base::CreateTemporaryFileInDir(test_dir
.path(), &test_file
);
134 ASSERT_TRUE(base::PathExists(test_file
));
135 base::WriteFile(test_file
, "foo", 3);
136 EXPECT_TRUE(installer::DeleteFileFromTempProcess(test_file
, 0));
137 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 3);
138 EXPECT_FALSE(base::PathExists(test_file
)) << test_file
.value();
141 // Note: This test is only valid when run at high integrity (i.e. it will fail
142 // at medium integrity).
143 TEST(SetupUtilTest
, ScopedTokenPrivilegeBasic
) {
144 ASSERT_FALSE(CurrentProcessHasPrivilege(kTestedPrivilege
));
147 installer::ScopedTokenPrivilege
test_scoped_privilege(kTestedPrivilege
);
148 ASSERT_TRUE(test_scoped_privilege
.is_enabled());
149 ASSERT_TRUE(CurrentProcessHasPrivilege(kTestedPrivilege
));
152 ASSERT_FALSE(CurrentProcessHasPrivilege(kTestedPrivilege
));
155 // Note: This test is only valid when run at high integrity (i.e. it will fail
156 // at medium integrity).
157 TEST(SetupUtilTest
, ScopedTokenPrivilegeAlreadyEnabled
) {
158 ASSERT_FALSE(CurrentProcessHasPrivilege(kTestedPrivilege
));
161 installer::ScopedTokenPrivilege
test_scoped_privilege(kTestedPrivilege
);
162 ASSERT_TRUE(test_scoped_privilege
.is_enabled());
163 ASSERT_TRUE(CurrentProcessHasPrivilege(kTestedPrivilege
));
165 installer::ScopedTokenPrivilege
dup_scoped_privilege(kTestedPrivilege
);
166 ASSERT_TRUE(dup_scoped_privilege
.is_enabled());
167 ASSERT_TRUE(CurrentProcessHasPrivilege(kTestedPrivilege
));
169 ASSERT_TRUE(CurrentProcessHasPrivilege(kTestedPrivilege
));
172 ASSERT_FALSE(CurrentProcessHasPrivilege(kTestedPrivilege
));
175 TEST(SetupUtilTest
, GuidToSquid
) {
176 ASSERT_EQ(installer::GuidToSquid(L
"EDA620E3-AA98-3846-B81E-3493CB2E0E02"),
177 L
"3E026ADE89AA64838BE14339BCE2E020");
180 const char kAdjustProcessPriority
[] = "adjust-process-priority";
182 PriorityClassChangeResult
DoProcessPriorityAdjustment() {
183 return installer::AdjustProcessPriority() ? PCCR_CHANGED
: PCCR_UNCHANGED
;
188 // A scoper that sets/resets the current process's priority class.
189 class ScopedPriorityClass
{
191 // Applies |priority_class|, returning an instance if a change was made.
192 // Otherwise, returns an empty scoped_ptr.
193 static scoped_ptr
<ScopedPriorityClass
> Create(DWORD priority_class
);
194 ~ScopedPriorityClass();
197 explicit ScopedPriorityClass(DWORD original_priority_class
);
198 DWORD original_priority_class_
;
199 DISALLOW_COPY_AND_ASSIGN(ScopedPriorityClass
);
202 scoped_ptr
<ScopedPriorityClass
> ScopedPriorityClass::Create(
203 DWORD priority_class
) {
204 HANDLE this_process
= ::GetCurrentProcess();
205 DWORD original_priority_class
= ::GetPriorityClass(this_process
);
206 EXPECT_NE(0U, original_priority_class
);
207 if (original_priority_class
&& original_priority_class
!= priority_class
) {
208 BOOL result
= ::SetPriorityClass(this_process
, priority_class
);
209 EXPECT_NE(FALSE
, result
);
211 return scoped_ptr
<ScopedPriorityClass
>(
212 new ScopedPriorityClass(original_priority_class
));
215 return scoped_ptr
<ScopedPriorityClass
>();
218 ScopedPriorityClass::ScopedPriorityClass(DWORD original_priority_class
)
219 : original_priority_class_(original_priority_class
) {}
221 ScopedPriorityClass::~ScopedPriorityClass() {
222 BOOL result
= ::SetPriorityClass(::GetCurrentProcess(),
223 original_priority_class_
);
224 EXPECT_NE(FALSE
, result
);
227 PriorityClassChangeResult
RelaunchAndDoProcessPriorityAdjustment() {
228 base::CommandLine
cmd_line(*base::CommandLine::ForCurrentProcess());
229 cmd_line
.AppendSwitch(kAdjustProcessPriority
);
230 base::Process process
= base::LaunchProcess(cmd_line
, base::LaunchOptions());
232 if (!process
.IsValid()) {
233 ADD_FAILURE() << " to launch subprocess.";
234 } else if (!process
.WaitForExit(&exit_code
)) {
235 ADD_FAILURE() << " to wait for subprocess to exit.";
237 return static_cast<PriorityClassChangeResult
>(exit_code
);
244 // Launching a subprocess at normal priority class is a noop.
245 TEST(SetupUtilTest
, AdjustFromNormalPriority
) {
246 ASSERT_EQ(NORMAL_PRIORITY_CLASS
, ::GetPriorityClass(::GetCurrentProcess()));
247 EXPECT_EQ(PCCR_UNCHANGED
, RelaunchAndDoProcessPriorityAdjustment());
250 // Launching a subprocess below normal priority class drops it to bg mode for
251 // sufficiently recent operating systems.
252 TEST(SetupUtilTest
, AdjustFromBelowNormalPriority
) {
253 scoped_ptr
<ScopedPriorityClass
> below_normal
=
254 ScopedPriorityClass::Create(BELOW_NORMAL_PRIORITY_CLASS
);
255 ASSERT_TRUE(below_normal
);
256 if (base::win::GetVersion() > base::win::VERSION_SERVER_2003
)
257 EXPECT_EQ(PCCR_CHANGED
, RelaunchAndDoProcessPriorityAdjustment());
259 EXPECT_EQ(PCCR_UNCHANGED
, RelaunchAndDoProcessPriorityAdjustment());
264 // A test fixture that configures an InstallationState and an InstallerState
265 // with a product being updated.
266 class FindArchiveToPatchTest
: public testing::Test
{
268 class FakeInstallationState
: public installer::InstallationState
{
271 class FakeProductState
: public installer::ProductState
{
273 static FakeProductState
* FromProductState(const ProductState
* product
) {
274 return static_cast<FakeProductState
*>(const_cast<ProductState
*>(product
));
277 void set_version(const Version
& version
) {
278 if (version
.IsValid())
279 version_
.reset(new Version(version
));
284 void set_uninstall_command(const base::CommandLine
& uninstall_command
) {
285 uninstall_command_
= uninstall_command
;
289 FindArchiveToPatchTest() {}
291 void SetUp() override
{
292 ASSERT_TRUE(test_dir_
.CreateUniqueTempDir());
293 registry_override_manager_
.OverrideRegistry(HKEY_CURRENT_USER
);
294 registry_override_manager_
.OverrideRegistry(HKEY_LOCAL_MACHINE
);
295 product_version_
= Version("30.0.1559.0");
296 max_version_
= Version("47.0.1559.0");
298 // Install the product according to the version.
299 original_state_
.reset(new FakeInstallationState());
302 // Prepare to update the product in the temp dir.
303 installer_state_
.reset(new installer::InstallerState(
304 kSystemInstall_
? installer::InstallerState::SYSTEM_LEVEL
:
305 installer::InstallerState::USER_LEVEL
));
306 installer_state_
->AddProductFromState(
308 *original_state_
->GetProductState(kSystemInstall_
, kProductType_
));
310 // Create archives in the two version dirs.
312 base::CreateDirectory(GetProductVersionArchivePath().DirName()));
313 ASSERT_EQ(1, base::WriteFile(GetProductVersionArchivePath(), "a", 1));
315 base::CreateDirectory(GetMaxVersionArchivePath().DirName()));
316 ASSERT_EQ(1, base::WriteFile(GetMaxVersionArchivePath(), "b", 1));
319 void TearDown() override
{
320 original_state_
.reset();
323 base::FilePath
GetArchivePath(const Version
& version
) const {
324 return test_dir_
.path()
325 .AppendASCII(version
.GetString())
326 .Append(installer::kInstallerDir
)
327 .Append(installer::kChromeArchive
);
330 base::FilePath
GetMaxVersionArchivePath() const {
331 return GetArchivePath(max_version_
);
334 base::FilePath
GetProductVersionArchivePath() const {
335 return GetArchivePath(product_version_
);
338 void InstallProduct() {
339 FakeProductState
* product
= FakeProductState::FromProductState(
340 original_state_
->GetNonVersionedProductState(kSystemInstall_
,
343 product
->set_version(product_version_
);
344 base::CommandLine
uninstall_command(
346 .AppendASCII(product_version_
.GetString())
347 .Append(installer::kInstallerDir
)
348 .Append(installer::kSetupExe
));
349 uninstall_command
.AppendSwitch(installer::switches::kUninstall
);
350 product
->set_uninstall_command(uninstall_command
);
353 void UninstallProduct() {
354 FakeProductState::FromProductState(
355 original_state_
->GetNonVersionedProductState(kSystemInstall_
,
357 ->set_version(Version());
360 static const bool kSystemInstall_
;
361 static const BrowserDistribution::Type kProductType_
;
362 base::ScopedTempDir test_dir_
;
363 Version product_version_
;
364 Version max_version_
;
365 scoped_ptr
<FakeInstallationState
> original_state_
;
366 scoped_ptr
<installer::InstallerState
> installer_state_
;
369 registry_util::RegistryOverrideManager registry_override_manager_
;
371 DISALLOW_COPY_AND_ASSIGN(FindArchiveToPatchTest
);
374 const bool FindArchiveToPatchTest::kSystemInstall_
= false;
375 const BrowserDistribution::Type
FindArchiveToPatchTest::kProductType_
=
376 BrowserDistribution::CHROME_BROWSER
;
380 // Test that the path to the advertised product version is found.
381 TEST_F(FindArchiveToPatchTest
, ProductVersionFound
) {
382 base::FilePath
patch_source(installer::FindArchiveToPatch(
383 *original_state_
, *installer_state_
, base::Version()));
384 EXPECT_EQ(GetProductVersionArchivePath().value(), patch_source
.value());
387 // Test that the path to the max version is found if the advertised version is
389 TEST_F(FindArchiveToPatchTest
, MaxVersionFound
) {
390 // The patch file is absent.
391 ASSERT_TRUE(base::DeleteFile(GetProductVersionArchivePath(), false));
392 base::FilePath
patch_source(installer::FindArchiveToPatch(
393 *original_state_
, *installer_state_
, base::Version()));
394 EXPECT_EQ(GetMaxVersionArchivePath().value(), patch_source
.value());
396 // The product doesn't appear to be installed, so the max version is found.
398 patch_source
= installer::FindArchiveToPatch(
399 *original_state_
, *installer_state_
, base::Version());
400 EXPECT_EQ(GetMaxVersionArchivePath().value(), patch_source
.value());
403 // Test that an empty path is returned if no version is found.
404 TEST_F(FindArchiveToPatchTest
, NoVersionFound
) {
405 // The product doesn't appear to be installed and no archives are present.
407 ASSERT_TRUE(base::DeleteFile(GetProductVersionArchivePath(), false));
408 ASSERT_TRUE(base::DeleteFile(GetMaxVersionArchivePath(), false));
410 base::FilePath
patch_source(installer::FindArchiveToPatch(
411 *original_state_
, *installer_state_
, base::Version()));
412 EXPECT_EQ(base::FilePath::StringType(), patch_source
.value());
415 TEST_F(FindArchiveToPatchTest
, DesiredVersionFound
) {
416 base::FilePath
patch_source1(installer::FindArchiveToPatch(
417 *original_state_
, *installer_state_
, product_version_
));
418 EXPECT_EQ(GetProductVersionArchivePath().value(), patch_source1
.value());
419 base::FilePath
patch_source2(installer::FindArchiveToPatch(
420 *original_state_
, *installer_state_
, max_version_
));
421 EXPECT_EQ(GetMaxVersionArchivePath().value(), patch_source2
.value());
424 TEST_F(FindArchiveToPatchTest
, DesiredVersionNotFound
) {
425 base::FilePath
patch_source(installer::FindArchiveToPatch(
426 *original_state_
, *installer_state_
, base::Version("1.2.3.4")));
427 EXPECT_EQ(base::FilePath().value(), patch_source
.value());
430 #if defined(GOOGLE_CHROME_BUILD)
432 const bool kSystemLevel
= false;
433 const HKEY kRootKey
= kSystemLevel
? HKEY_LOCAL_MACHINE
: HKEY_CURRENT_USER
;
434 const wchar_t kVersionString
[] = L
"30.0.1574.0";
435 const wchar_t kMultiChannel
[] = L
"2.0-dev-multi-chromeframe";
437 class MigrateMultiToSingleTest
: public testing::Test
{
439 void SetUp() override
{
440 registry_override_manager_
.OverrideRegistry(kRootKey
);
444 registry_util::RegistryOverrideManager registry_override_manager_
;
448 // Test migrating Chrome Frame from multi to single.
449 TEST_F(MigrateMultiToSingleTest
, ChromeFrame
) {
450 installer::ProductState chrome_frame
;
451 installer::ProductState binaries
;
452 DWORD usagestats
= 0;
454 // Set up a config with dev-channel multi-install GCF.
455 base::win::RegKey key
;
457 BrowserDistribution
* dist
= BrowserDistribution::GetSpecificDistribution(
458 BrowserDistribution::CHROME_BINARIES
);
459 ASSERT_EQ(ERROR_SUCCESS
,
460 base::win::RegKey(kRootKey
, dist
->GetVersionKey().c_str(),
462 .WriteValue(google_update::kRegVersionField
, kVersionString
));
463 ASSERT_EQ(ERROR_SUCCESS
,
464 base::win::RegKey(kRootKey
, dist
->GetStateKey().c_str(),
466 .WriteValue(google_update::kRegApField
, kMultiChannel
));
467 ASSERT_EQ(ERROR_SUCCESS
,
468 base::win::RegKey(kRootKey
, dist
->GetStateKey().c_str(),
470 .WriteValue(google_update::kRegUsageStatsField
, 1U));
472 dist
= BrowserDistribution::GetSpecificDistribution(
473 BrowserDistribution::CHROME_FRAME
);
474 ASSERT_EQ(ERROR_SUCCESS
,
475 base::win::RegKey(kRootKey
, dist
->GetVersionKey().c_str(),
477 .WriteValue(google_update::kRegVersionField
, kVersionString
));
478 ASSERT_EQ(ERROR_SUCCESS
,
479 base::win::RegKey(kRootKey
, dist
->GetStateKey().c_str(),
481 .WriteValue(google_update::kRegApField
, kMultiChannel
));
483 // Do the registry migration.
484 installer::InstallationState machine_state
;
485 machine_state
.Initialize();
487 installer::MigrateGoogleUpdateStateMultiToSingle(
489 BrowserDistribution::CHROME_FRAME
,
492 // Confirm that usagestats were copied to CF and that its channel was
494 ASSERT_TRUE(chrome_frame
.Initialize(kSystemLevel
,
495 BrowserDistribution::CHROME_FRAME
));
496 EXPECT_TRUE(chrome_frame
.GetUsageStats(&usagestats
));
497 EXPECT_EQ(1U, usagestats
);
498 EXPECT_EQ(L
"2.0-dev", chrome_frame
.channel().value());
500 // Confirm that the binaries' channel no longer contains GCF.
501 ASSERT_TRUE(binaries
.Initialize(kSystemLevel
,
502 BrowserDistribution::CHROME_BINARIES
));
503 EXPECT_EQ(L
"2.0-dev-multi", binaries
.channel().value());
507 TEST(SetupUtilTest
, ContainsUnsupportedSwitch
) {
508 EXPECT_FALSE(installer::ContainsUnsupportedSwitch(
509 base::CommandLine::FromString(L
"foo.exe")));
510 EXPECT_FALSE(installer::ContainsUnsupportedSwitch(
511 base::CommandLine::FromString(L
"foo.exe --multi-install --chrome")));
512 EXPECT_TRUE(installer::ContainsUnsupportedSwitch(
513 base::CommandLine::FromString(L
"foo.exe --chrome-frame")));
516 TEST(SetupUtilTest
, GetRegistrationDataCommandKey
) {
517 base::string16 app_guid
= L
"{AAAAAAAA-BBBB-1111-0123-456789ABCDEF}";
518 UpdatingAppRegistrationData
reg_data(app_guid
);
520 installer::GetRegistrationDataCommandKey(reg_data
, L
"test_name");
521 EXPECT_TRUE(base::EndsWith(key
, app_guid
+ L
"\\Commands\\test_name",
522 base::CompareCase::SENSITIVE
));
525 namespace installer
{
527 class DeleteRegistryKeyPartialTest
: public ::testing::Test
{
529 using RegKey
= base::win::RegKey
;
531 void SetUp() override
{
532 _registry_override_manager
.OverrideRegistry(root_
);
533 to_preserve_
.push_back(L
"preSERve1");
534 to_preserve_
.push_back(L
"1evRESerp");
537 void CreateSubKeys(bool with_preserves
) {
538 ASSERT_FALSE(RegKey(root_
, path_
.c_str(), KEY_READ
).Valid());
539 // These subkeys are added such that 1) keys to preserve are intermixed with
540 // other keys, and 2) the case of the keys to preserve doesn't match the
541 // values in |to_preserve_|.
542 ASSERT_EQ(ERROR_SUCCESS
, RegKey(root_
, path_
.c_str(), KEY_WRITE
)
543 .CreateKey(L
"0sub", KEY_WRITE
));
544 if (with_preserves
) {
545 ASSERT_EQ(ERROR_SUCCESS
, RegKey(root_
, path_
.c_str(), KEY_WRITE
)
546 .CreateKey(L
"1evreserp", KEY_WRITE
));
548 ASSERT_EQ(ERROR_SUCCESS
, RegKey(root_
, path_
.c_str(), KEY_WRITE
)
549 .CreateKey(L
"asub", KEY_WRITE
));
550 if (with_preserves
) {
551 ASSERT_EQ(ERROR_SUCCESS
, RegKey(root_
, path_
.c_str(), KEY_WRITE
)
552 .CreateKey(L
"preserve1", KEY_WRITE
));
554 ASSERT_EQ(ERROR_SUCCESS
, RegKey(root_
, path_
.c_str(), KEY_WRITE
)
555 .CreateKey(L
"sub1", KEY_WRITE
));
558 const HKEY root_
= HKEY_CURRENT_USER
;
559 base::string16 path_
= L
"key_path";
560 std::vector
<base::string16
> to_preserve_
;
563 registry_util::RegistryOverrideManager _registry_override_manager
;
566 TEST_F(DeleteRegistryKeyPartialTest
, NoKey
) {
567 DeleteRegistryKeyPartial(root_
, L
"does_not_exist",
568 std::vector
<base::string16
>());
569 DeleteRegistryKeyPartial(root_
, L
"does_not_exist", to_preserve_
);
572 TEST_F(DeleteRegistryKeyPartialTest
, EmptyKey
) {
573 ASSERT_FALSE(RegKey(root_
, path_
.c_str(), KEY_READ
).Valid());
574 ASSERT_TRUE(RegKey(root_
, path_
.c_str(), KEY_WRITE
).Valid());
575 DeleteRegistryKeyPartial(root_
, path_
.c_str(), std::vector
<base::string16
>());
576 ASSERT_FALSE(RegKey(root_
, path_
.c_str(), KEY_READ
).Valid());
578 ASSERT_TRUE(RegKey(root_
, path_
.c_str(), KEY_WRITE
).Valid());
579 DeleteRegistryKeyPartial(root_
, path_
.c_str(), to_preserve_
);
580 ASSERT_FALSE(RegKey(root_
, path_
.c_str(), KEY_READ
).Valid());
583 TEST_F(DeleteRegistryKeyPartialTest
, NonEmptyKey
) {
584 CreateSubKeys(false); /* !with_preserves */
585 DeleteRegistryKeyPartial(root_
, path_
.c_str(), std::vector
<base::string16
>());
586 ASSERT_FALSE(RegKey(root_
, path_
.c_str(), KEY_READ
).Valid());
588 CreateSubKeys(false); /* !with_preserves */
589 ASSERT_TRUE(RegKey(root_
, path_
.c_str(), KEY_WRITE
).Valid());
590 DeleteRegistryKeyPartial(root_
, path_
.c_str(), to_preserve_
);
591 ASSERT_FALSE(RegKey(root_
, path_
.c_str(), KEY_READ
).Valid());
594 TEST_F(DeleteRegistryKeyPartialTest
, NonEmptyKeyWithPreserve
) {
595 CreateSubKeys(true); /* with_preserves */
597 // Put some values into the main key.
599 RegKey
key(root_
, path_
.c_str(), KEY_SET_VALUE
);
600 ASSERT_TRUE(key
.Valid());
601 ASSERT_EQ(ERROR_SUCCESS
, key
.WriteValue(nullptr, 5U));
603 1, base::win::RegistryValueIterator(root_
, path_
.c_str()).ValueCount());
604 ASSERT_EQ(ERROR_SUCCESS
, key
.WriteValue(L
"foo", L
"bar"));
606 2, base::win::RegistryValueIterator(root_
, path_
.c_str()).ValueCount());
607 ASSERT_EQ(ERROR_SUCCESS
, key
.WriteValue(L
"baz", L
"huh"));
609 3, base::win::RegistryValueIterator(root_
, path_
.c_str()).ValueCount());
612 ASSERT_TRUE(RegKey(root_
, path_
.c_str(), KEY_WRITE
).Valid());
613 DeleteRegistryKeyPartial(root_
, path_
.c_str(), to_preserve_
);
614 ASSERT_TRUE(RegKey(root_
, path_
.c_str(), KEY_READ
).Valid());
616 // Ensure that the preserved subkeys are still present.
618 base::win::RegistryKeyIterator
it(root_
, path_
.c_str());
619 ASSERT_EQ(to_preserve_
.size(), it
.SubkeyCount());
620 for (it
; it
.Valid(); ++it
) {
621 ASSERT_NE(to_preserve_
.end(),
622 std::find_if(to_preserve_
.begin(), to_preserve_
.end(),
623 [&it
](const base::string16
& key_name
) {
624 return base::ToLowerASCII(it
.Name()) ==
625 base::ToLowerASCII(key_name
);
631 // Ensure that all values are absent.
633 base::win::RegistryValueIterator
it(root_
, path_
.c_str());
634 ASSERT_EQ(0, it
.ValueCount());
638 } // namespace installer