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/util/install_util.h"
10 #include "base/base_paths.h"
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/macros.h"
16 #include "base/path_service.h"
17 #include "base/strings/string_util.h"
18 #include "base/test/scoped_path_override.h"
19 #include "base/test/test_reg_util_win.h"
20 #include "base/win/registry.h"
21 #include "chrome/installer/util/google_update_constants.h"
22 #include "chrome/installer/util/work_item.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 using base::win::RegKey
;
28 using ::testing::Return
;
29 using ::testing::StrEq
;
31 class MockRegistryValuePredicate
: public InstallUtil::RegistryValuePredicate
{
33 MOCK_CONST_METHOD1(Evaluate
, bool(const std::wstring
&));
36 class InstallUtilTest
: public testing::Test
{
40 void SetUp() override
{
41 ResetRegistryOverrides();
44 void ResetRegistryOverrides() {
45 registry_override_manager_
.reset(
46 new registry_util::RegistryOverrideManager
);
47 registry_override_manager_
->OverrideRegistry(HKEY_CURRENT_USER
);
48 registry_override_manager_
->OverrideRegistry(HKEY_LOCAL_MACHINE
);
52 scoped_ptr
<registry_util::RegistryOverrideManager
> registry_override_manager_
;
54 DISALLOW_COPY_AND_ASSIGN(InstallUtilTest
);
57 TEST_F(InstallUtilTest
, ComposeCommandLine
) {
58 base::CommandLine
command_line(base::CommandLine::NO_PROGRAM
);
60 std::pair
<std::wstring
, std::wstring
> params
[] = {
61 std::make_pair(std::wstring(L
""), std::wstring(L
"")),
62 std::make_pair(std::wstring(L
""), std::wstring(L
"--do-something --silly")),
63 std::make_pair(std::wstring(L
"spam.exe"), std::wstring(L
"")),
64 std::make_pair(std::wstring(L
"spam.exe"),
65 std::wstring(L
"--do-something --silly")),
67 for (int i
= 0; i
< arraysize(params
); ++i
) {
68 std::pair
<std::wstring
, std::wstring
>& param
= params
[i
];
69 InstallUtil::ComposeCommandLine(param
.first
, param
.second
, &command_line
);
70 EXPECT_EQ(param
.first
, command_line
.GetProgram().value());
71 if (param
.second
.empty()) {
72 EXPECT_TRUE(command_line
.GetSwitches().empty());
74 EXPECT_EQ(2U, command_line
.GetSwitches().size());
75 EXPECT_TRUE(command_line
.HasSwitch("do-something"));
76 EXPECT_TRUE(command_line
.HasSwitch("silly"));
81 TEST_F(InstallUtilTest
, GetCurrentDate
) {
82 std::wstring
date(InstallUtil::GetCurrentDate());
83 EXPECT_EQ(8, date
.length());
84 if (date
.length() == 8) {
85 // For an invalid date value, SystemTimeToFileTime will fail.
86 // We use this to validate that we have a correct date string.
87 SYSTEMTIME systime
= {0};
89 // Just to make sure our assumption holds.
90 EXPECT_FALSE(SystemTimeToFileTime(&systime
, &ft
));
91 // Now fill in the values from our string.
92 systime
.wYear
= _wtoi(date
.substr(0, 4).c_str());
93 systime
.wMonth
= _wtoi(date
.substr(4, 2).c_str());
94 systime
.wDay
= _wtoi(date
.substr(6, 2).c_str());
95 // Check if they make sense.
96 EXPECT_TRUE(SystemTimeToFileTime(&systime
, &ft
));
100 TEST_F(InstallUtilTest
, UpdateInstallerStageAP
) {
101 const bool system_level
= false;
102 const HKEY root
= system_level
? HKEY_LOCAL_MACHINE
: HKEY_CURRENT_USER
;
103 std::wstring
state_key_path(L
"PhonyClientState");
105 // Update the stage when there's no "ap" value.
107 ResetRegistryOverrides();
108 RegKey(root
, state_key_path
.c_str(), KEY_SET_VALUE
);
109 InstallUtil::UpdateInstallerStage(system_level
, state_key_path
,
110 installer::BUILDING
);
112 EXPECT_EQ(ERROR_SUCCESS
,
113 RegKey(root
, state_key_path
.c_str(), KEY_QUERY_VALUE
)
114 .ReadValue(google_update::kRegApField
, &value
));
115 EXPECT_EQ(L
"-stage:building", value
);
118 // Update the stage when there is an "ap" value.
120 ResetRegistryOverrides();
121 RegKey(root
, state_key_path
.c_str(), KEY_SET_VALUE
)
122 .WriteValue(google_update::kRegApField
, L
"2.0-dev");
123 InstallUtil::UpdateInstallerStage(system_level
, state_key_path
,
124 installer::BUILDING
);
126 EXPECT_EQ(ERROR_SUCCESS
,
127 RegKey(root
, state_key_path
.c_str(), KEY_QUERY_VALUE
)
128 .ReadValue(google_update::kRegApField
, &value
));
129 EXPECT_EQ(L
"2.0-dev-stage:building", value
);
134 ResetRegistryOverrides();
135 RegKey(root
, state_key_path
.c_str(), KEY_SET_VALUE
)
136 .WriteValue(google_update::kRegApField
, L
"2.0-dev-stage:building");
137 InstallUtil::UpdateInstallerStage(system_level
, state_key_path
,
138 installer::NO_STAGE
);
140 EXPECT_EQ(ERROR_SUCCESS
,
141 RegKey(root
, state_key_path
.c_str(), KEY_QUERY_VALUE
)
142 .ReadValue(google_update::kRegApField
, &value
));
143 EXPECT_EQ(L
"2.0-dev", value
);
147 TEST_F(InstallUtilTest
, UpdateInstallerStage
) {
148 const bool system_level
= false;
149 const HKEY root
= system_level
? HKEY_LOCAL_MACHINE
: HKEY_CURRENT_USER
;
150 std::wstring
state_key_path(L
"PhonyClientState");
152 // Update the stage when there's no "InstallerExtraCode1" value.
154 ResetRegistryOverrides();
155 RegKey(root
, state_key_path
.c_str(), KEY_SET_VALUE
)
156 .DeleteValue(installer::kInstallerExtraCode1
);
157 InstallUtil::UpdateInstallerStage(system_level
, state_key_path
,
158 installer::BUILDING
);
160 EXPECT_EQ(ERROR_SUCCESS
,
161 RegKey(root
, state_key_path
.c_str(), KEY_QUERY_VALUE
)
162 .ReadValueDW(installer::kInstallerExtraCode1
, &value
));
163 EXPECT_EQ(static_cast<DWORD
>(installer::BUILDING
), value
);
166 // Update the stage when there is an "InstallerExtraCode1" value.
168 ResetRegistryOverrides();
169 RegKey(root
, state_key_path
.c_str(), KEY_SET_VALUE
)
170 .WriteValue(installer::kInstallerExtraCode1
,
171 static_cast<DWORD
>(installer::UNPACKING
));
172 InstallUtil::UpdateInstallerStage(system_level
, state_key_path
,
173 installer::BUILDING
);
175 EXPECT_EQ(ERROR_SUCCESS
,
176 RegKey(root
, state_key_path
.c_str(), KEY_QUERY_VALUE
)
177 .ReadValueDW(installer::kInstallerExtraCode1
, &value
));
178 EXPECT_EQ(static_cast<DWORD
>(installer::BUILDING
), value
);
183 ResetRegistryOverrides();
184 RegKey(root
, state_key_path
.c_str(), KEY_SET_VALUE
)
185 .WriteValue(installer::kInstallerExtraCode1
, static_cast<DWORD
>(5));
186 InstallUtil::UpdateInstallerStage(system_level
, state_key_path
,
187 installer::NO_STAGE
);
189 EXPECT_EQ(ERROR_FILE_NOT_FOUND
,
190 RegKey(root
, state_key_path
.c_str(), KEY_QUERY_VALUE
)
191 .ReadValueDW(installer::kInstallerExtraCode1
, &value
));
195 TEST_F(InstallUtilTest
, DeleteRegistryKeyIf
) {
196 const HKEY root
= HKEY_CURRENT_USER
;
197 std::wstring
parent_key_path(L
"SomeKey\\ToDelete");
198 std::wstring
child_key_path(parent_key_path
);
199 child_key_path
.append(L
"\\ChildKey\\WithAValue");
200 const wchar_t value_name
[] = L
"some_value_name";
201 const wchar_t value
[] = L
"hi mom";
203 // Nothing to delete if the keys aren't even there.
205 MockRegistryValuePredicate pred
;
207 EXPECT_CALL(pred
, Evaluate(_
)).Times(0);
209 RegKey(root
, parent_key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
210 EXPECT_EQ(InstallUtil::NOT_FOUND
,
211 InstallUtil::DeleteRegistryKeyIf(
212 root
, parent_key_path
, child_key_path
,
213 WorkItem::kWow64Default
, value_name
, pred
));
215 RegKey(root
, parent_key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
218 // Parent exists, but not child: no delete.
220 MockRegistryValuePredicate pred
;
222 EXPECT_CALL(pred
, Evaluate(_
)).Times(0);
223 ASSERT_TRUE(RegKey(root
, parent_key_path
.c_str(), KEY_SET_VALUE
).Valid());
224 EXPECT_EQ(InstallUtil::NOT_FOUND
,
225 InstallUtil::DeleteRegistryKeyIf(
226 root
, parent_key_path
, child_key_path
,
227 WorkItem::kWow64Default
, value_name
, pred
));
228 EXPECT_TRUE(RegKey(root
, parent_key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
231 // Child exists, but no value: no delete.
233 MockRegistryValuePredicate pred
;
235 EXPECT_CALL(pred
, Evaluate(_
)).Times(0);
236 ASSERT_TRUE(RegKey(root
, child_key_path
.c_str(), KEY_SET_VALUE
).Valid());
237 EXPECT_EQ(InstallUtil::NOT_FOUND
,
238 InstallUtil::DeleteRegistryKeyIf(
239 root
, parent_key_path
, child_key_path
,
240 WorkItem::kWow64Default
, value_name
, pred
));
241 EXPECT_TRUE(RegKey(root
, parent_key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
244 // Value exists, but doesn't match: no delete.
246 MockRegistryValuePredicate pred
;
248 EXPECT_CALL(pred
, Evaluate(StrEq(L
"foosball!"))).WillOnce(Return(false));
249 ASSERT_EQ(ERROR_SUCCESS
, RegKey(root
, child_key_path
.c_str(), KEY_SET_VALUE
)
250 .WriteValue(value_name
, L
"foosball!"));
251 EXPECT_EQ(InstallUtil::NOT_FOUND
,
252 InstallUtil::DeleteRegistryKeyIf(
253 root
, parent_key_path
, child_key_path
,
254 WorkItem::kWow64Default
, value_name
, pred
));
255 EXPECT_TRUE(RegKey(root
, parent_key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
258 // Value exists, and matches: delete.
260 MockRegistryValuePredicate pred
;
262 EXPECT_CALL(pred
, Evaluate(StrEq(value
))).WillOnce(Return(true));
263 ASSERT_EQ(ERROR_SUCCESS
, RegKey(root
, child_key_path
.c_str(), KEY_SET_VALUE
)
264 .WriteValue(value_name
, value
));
265 EXPECT_EQ(InstallUtil::DELETED
,
266 InstallUtil::DeleteRegistryKeyIf(
267 root
, parent_key_path
, child_key_path
,
268 WorkItem::kWow64Default
, value_name
, pred
));
270 RegKey(root
, parent_key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
273 // Default value exists and matches: delete.
275 MockRegistryValuePredicate pred
;
277 EXPECT_CALL(pred
, Evaluate(StrEq(value
))).WillOnce(Return(true));
278 ASSERT_EQ(ERROR_SUCCESS
, RegKey(root
, child_key_path
.c_str(), KEY_SET_VALUE
)
279 .WriteValue(NULL
, value
));
280 EXPECT_EQ(InstallUtil::DELETED
, InstallUtil::DeleteRegistryKeyIf(
281 root
, parent_key_path
, child_key_path
,
282 WorkItem::kWow64Default
, NULL
, pred
));
284 RegKey(root
, parent_key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
288 TEST_F(InstallUtilTest
, DeleteRegistryValueIf
) {
289 const HKEY root
= HKEY_CURRENT_USER
;
290 std::wstring
key_path(L
"SomeKey\\ToDelete");
291 const wchar_t value_name
[] = L
"some_value_name";
292 const wchar_t value
[] = L
"hi mom";
295 ResetRegistryOverrides();
296 // Nothing to delete if the key isn't even there.
298 MockRegistryValuePredicate pred
;
300 EXPECT_CALL(pred
, Evaluate(_
)).Times(0);
301 ASSERT_FALSE(RegKey(root
, key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
302 EXPECT_EQ(InstallUtil::NOT_FOUND
,
303 InstallUtil::DeleteRegistryValueIf(root
, key_path
.c_str(),
304 WorkItem::kWow64Default
,
306 EXPECT_FALSE(RegKey(root
, key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
309 // Key exists, but no value: no delete.
311 MockRegistryValuePredicate pred
;
313 EXPECT_CALL(pred
, Evaluate(_
)).Times(0);
314 ASSERT_TRUE(RegKey(root
, key_path
.c_str(), KEY_SET_VALUE
).Valid());
315 EXPECT_EQ(InstallUtil::NOT_FOUND
,
316 InstallUtil::DeleteRegistryValueIf(root
, key_path
.c_str(),
317 WorkItem::kWow64Default
,
319 EXPECT_TRUE(RegKey(root
, key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
322 // Value exists, but doesn't match: no delete.
324 MockRegistryValuePredicate pred
;
326 EXPECT_CALL(pred
, Evaluate(StrEq(L
"foosball!"))).WillOnce(Return(false));
327 ASSERT_EQ(ERROR_SUCCESS
,
328 RegKey(root
, key_path
.c_str(),
329 KEY_SET_VALUE
).WriteValue(value_name
, L
"foosball!"));
330 EXPECT_EQ(InstallUtil::NOT_FOUND
,
331 InstallUtil::DeleteRegistryValueIf(root
, key_path
.c_str(),
332 WorkItem::kWow64Default
,
334 EXPECT_TRUE(RegKey(root
, key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
335 EXPECT_TRUE(RegKey(root
, key_path
.c_str(),
336 KEY_QUERY_VALUE
).HasValue(value_name
));
339 // Value exists, and matches: delete.
341 MockRegistryValuePredicate pred
;
343 EXPECT_CALL(pred
, Evaluate(StrEq(value
))).WillOnce(Return(true));
344 ASSERT_EQ(ERROR_SUCCESS
,
345 RegKey(root
, key_path
.c_str(),
346 KEY_SET_VALUE
).WriteValue(value_name
, value
));
347 EXPECT_EQ(InstallUtil::DELETED
,
348 InstallUtil::DeleteRegistryValueIf(root
, key_path
.c_str(),
349 WorkItem::kWow64Default
,
351 EXPECT_TRUE(RegKey(root
, key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
352 EXPECT_FALSE(RegKey(root
, key_path
.c_str(),
353 KEY_QUERY_VALUE
).HasValue(value_name
));
358 ResetRegistryOverrides();
359 // Default value matches: delete using empty string.
361 MockRegistryValuePredicate pred
;
363 EXPECT_CALL(pred
, Evaluate(StrEq(value
))).WillOnce(Return(true));
364 ASSERT_EQ(ERROR_SUCCESS
,
365 RegKey(root
, key_path
.c_str(),
366 KEY_SET_VALUE
).WriteValue(L
"", value
));
367 EXPECT_EQ(InstallUtil::DELETED
,
368 InstallUtil::DeleteRegistryValueIf(root
, key_path
.c_str(),
369 WorkItem::kWow64Default
, L
"",
371 EXPECT_TRUE(RegKey(root
, key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
372 EXPECT_FALSE(RegKey(root
, key_path
.c_str(),
373 KEY_QUERY_VALUE
).HasValue(L
""));
378 ResetRegistryOverrides();
379 // Default value matches: delete using NULL.
381 MockRegistryValuePredicate pred
;
383 EXPECT_CALL(pred
, Evaluate(StrEq(value
))).WillOnce(Return(true));
384 ASSERT_EQ(ERROR_SUCCESS
,
385 RegKey(root
, key_path
.c_str(),
386 KEY_SET_VALUE
).WriteValue(L
"", value
));
387 EXPECT_EQ(InstallUtil::DELETED
,
388 InstallUtil::DeleteRegistryValueIf(root
, key_path
.c_str(),
389 WorkItem::kWow64Default
,
391 EXPECT_TRUE(RegKey(root
, key_path
.c_str(), KEY_QUERY_VALUE
).Valid());
392 EXPECT_FALSE(RegKey(root
, key_path
.c_str(),
393 KEY_QUERY_VALUE
).HasValue(L
""));
398 TEST_F(InstallUtilTest
, ValueEquals
) {
399 InstallUtil::ValueEquals
pred(L
"howdy");
401 EXPECT_FALSE(pred
.Evaluate(L
""));
402 EXPECT_FALSE(pred
.Evaluate(L
"Howdy"));
403 EXPECT_FALSE(pred
.Evaluate(L
"howdy!"));
404 EXPECT_FALSE(pred
.Evaluate(L
"!howdy"));
405 EXPECT_TRUE(pred
.Evaluate(L
"howdy"));
408 TEST_F(InstallUtilTest
, ProgramCompare
) {
409 base::ScopedTempDir test_dir
;
410 ASSERT_TRUE(test_dir
.CreateUniqueTempDir());
411 const base::FilePath
some_long_dir(
412 test_dir
.path().Append(L
"Some Long Directory Name"));
413 const base::FilePath
expect(some_long_dir
.Append(L
"file.txt"));
414 const base::FilePath
expect_upcase(some_long_dir
.Append(L
"FILE.txt"));
415 const base::FilePath
other(some_long_dir
.Append(L
"otherfile.txt"));
417 // Tests where the expected file doesn't exist.
419 // Paths don't match.
420 EXPECT_FALSE(InstallUtil::ProgramCompare(expect
).Evaluate(
421 L
"\"" + other
.value() + L
"\""));
422 // Paths match exactly.
423 EXPECT_TRUE(InstallUtil::ProgramCompare(expect
).Evaluate(
424 L
"\"" + expect
.value() + L
"\""));
425 // Paths differ by case.
426 EXPECT_TRUE(InstallUtil::ProgramCompare(expect
).Evaluate(
427 L
"\"" + expect_upcase
.value() + L
"\""));
429 // Tests where the expected file exists.
430 static const char data
[] = "data";
431 ASSERT_TRUE(base::CreateDirectory(some_long_dir
));
432 ASSERT_NE(-1, base::WriteFile(expect
, data
, arraysize(data
) - 1));
433 // Paths don't match.
434 EXPECT_FALSE(InstallUtil::ProgramCompare(expect
).Evaluate(
435 L
"\"" + other
.value() + L
"\""));
436 // Paths match exactly.
437 EXPECT_TRUE(InstallUtil::ProgramCompare(expect
).Evaluate(
438 L
"\"" + expect
.value() + L
"\""));
439 // Paths differ by case.
440 EXPECT_TRUE(InstallUtil::ProgramCompare(expect
).Evaluate(
441 L
"\"" + expect_upcase
.value() + L
"\""));
443 // Test where strings don't match, but the same file is indicated.
444 std::wstring short_expect
;
445 DWORD short_len
= GetShortPathName(expect
.value().c_str(),
446 base::WriteInto(&short_expect
, MAX_PATH
),
448 ASSERT_NE(static_cast<DWORD
>(0), short_len
);
449 ASSERT_GT(static_cast<DWORD
>(MAX_PATH
), short_len
);
450 short_expect
.resize(short_len
);
451 ASSERT_FALSE(base::FilePath::CompareEqualIgnoreCase(expect
.value(),
453 EXPECT_TRUE(InstallUtil::ProgramCompare(expect
).Evaluate(
454 L
"\"" + short_expect
+ L
"\""));
457 // Win64 Chrome is always installed in the 32-bit Program Files directory. Test
458 // that IsPerUserInstall returns false for an arbitrary path with
459 // DIR_PROGRAM_FILESX86 as a suffix but not DIR_PROGRAM_FILES when the two are
461 TEST_F(InstallUtilTest
, IsPerUserInstall
) {
463 const int kChromeProgramFilesKey
= base::DIR_PROGRAM_FILESX86
;
465 const int kChromeProgramFilesKey
= base::DIR_PROGRAM_FILES
;
467 base::ScopedPathOverride
program_files_override(kChromeProgramFilesKey
);
468 base::FilePath some_exe
;
469 ASSERT_TRUE(PathService::Get(kChromeProgramFilesKey
, &some_exe
));
470 some_exe
= some_exe
.AppendASCII("Company")
471 .AppendASCII("Product")
472 .AppendASCII("product.exe");
473 EXPECT_FALSE(InstallUtil::IsPerUserInstall(some_exe
));
476 const int kOtherProgramFilesKey
= base::DIR_PROGRAM_FILES
;
477 base::ScopedPathOverride
other_program_files_override(kOtherProgramFilesKey
);
478 ASSERT_TRUE(PathService::Get(kOtherProgramFilesKey
, &some_exe
));
479 some_exe
= some_exe
.AppendASCII("Company")
480 .AppendASCII("Product")
481 .AppendASCII("product.exe");
482 EXPECT_TRUE(InstallUtil::IsPerUserInstall(some_exe
));
483 #endif // defined(_WIN64)