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. 4 5 #include <string> 6 #include <utility> 7 8 #include "base/command_line.h" 9 #include "base/files/file_util.h" 10 #include "base/strings/string_util.h" 11 #include "base/test/test_reg_util_win.h" 12 #include "base/win/registry.h" 13 #include "chrome/installer/util/google_update_constants.h" 14 #include "chrome/installer/util/install_util.h" 15 #include "chrome/installer/util/product_unittest.h" 16 #include "chrome/installer/util/work_item.h" 17 #include "testing/gmock/include/gmock/gmock.h" 18 19 using base::win::RegKey; 20 using registry_util::RegistryOverrideManager; 21 using ::testing::_; 22 using ::testing::Return; 23 using ::testing::StrEq; 24 25 class MockRegistryValuePredicate : public InstallUtil::RegistryValuePredicate { 26 public: 27 MOCK_CONST_METHOD1(Evaluate, bool(const std::wstring&)); 28 }; 29 30 class InstallUtilTest : public TestWithTempDirAndDeleteTempOverrideKeys { 31 protected: 32 }; 33 34 TEST_F(InstallUtilTest, MakeUninstallCommand) { 35 CommandLine command_line(CommandLine::NO_PROGRAM); 36 37 std::pair<std::wstring, std::wstring> params[] = { 38 std::make_pair(std::wstring(L""), std::wstring(L"")), 39 std::make_pair(std::wstring(L""), std::wstring(L"--do-something --silly")), 40 std::make_pair(std::wstring(L"spam.exe"), std::wstring(L"")), 41 std::make_pair(std::wstring(L"spam.exe"), 42 std::wstring(L"--do-something --silly")), 43 }; 44 for (int i = 0; i < arraysize(params); ++i) { 45 std::pair<std::wstring, std::wstring>& param = params[i]; 46 InstallUtil::MakeUninstallCommand(param.first, param.second, &command_line); 47 EXPECT_EQ(param.first, command_line.GetProgram().value()); 48 if (param.second.empty()) { 49 EXPECT_TRUE(command_line.GetSwitches().empty()); 50 } else { 51 EXPECT_EQ(2U, command_line.GetSwitches().size()); 52 EXPECT_TRUE(command_line.HasSwitch("do-something")); 53 EXPECT_TRUE(command_line.HasSwitch("silly")); 54 } 55 } 56 } 57 58 TEST_F(InstallUtilTest, GetCurrentDate) { 59 std::wstring date(InstallUtil::GetCurrentDate()); 60 EXPECT_EQ(8, date.length()); 61 if (date.length() == 8) { 62 // For an invalid date value, SystemTimeToFileTime will fail. 63 // We use this to validate that we have a correct date string. 64 SYSTEMTIME systime = {0}; 65 FILETIME ft = {0}; 66 // Just to make sure our assumption holds. 67 EXPECT_FALSE(SystemTimeToFileTime(&systime, &ft)); 68 // Now fill in the values from our string. 69 systime.wYear = _wtoi(date.substr(0, 4).c_str()); 70 systime.wMonth = _wtoi(date.substr(4, 2).c_str()); 71 systime.wDay = _wtoi(date.substr(6, 2).c_str()); 72 // Check if they make sense. 73 EXPECT_TRUE(SystemTimeToFileTime(&systime, &ft)); 74 } 75 } 76 77 TEST_F(InstallUtilTest, UpdateInstallerStageAP) { 78 const bool system_level = false; 79 const HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 80 std::wstring state_key_path(L"PhonyClientState"); 81 82 // Update the stage when there's no "ap" value. 83 { 84 RegistryOverrideManager override_manager; 85 override_manager.OverrideRegistry(root); 86 RegKey(root, state_key_path.c_str(), KEY_SET_VALUE); 87 InstallUtil::UpdateInstallerStage(system_level, state_key_path, 88 installer::BUILDING); 89 std::wstring value; 90 EXPECT_EQ(ERROR_SUCCESS, 91 RegKey(root, state_key_path.c_str(), KEY_QUERY_VALUE) 92 .ReadValue(google_update::kRegApField, &value)); 93 EXPECT_EQ(L"-stage:building", value); 94 } 95 96 // Update the stage when there is an "ap" value. 97 { 98 RegistryOverrideManager override_manager; 99 override_manager.OverrideRegistry(root); 100 RegKey(root, state_key_path.c_str(), KEY_SET_VALUE) 101 .WriteValue(google_update::kRegApField, L"2.0-dev"); 102 InstallUtil::UpdateInstallerStage(system_level, state_key_path, 103 installer::BUILDING); 104 std::wstring value; 105 EXPECT_EQ(ERROR_SUCCESS, 106 RegKey(root, state_key_path.c_str(), KEY_QUERY_VALUE) 107 .ReadValue(google_update::kRegApField, &value)); 108 EXPECT_EQ(L"2.0-dev-stage:building", value); 109 } 110 111 // Clear the stage. 112 { 113 RegistryOverrideManager override_manager; 114 override_manager.OverrideRegistry(root); 115 RegKey(root, state_key_path.c_str(), KEY_SET_VALUE) 116 .WriteValue(google_update::kRegApField, L"2.0-dev-stage:building"); 117 InstallUtil::UpdateInstallerStage(system_level, state_key_path, 118 installer::NO_STAGE); 119 std::wstring value; 120 EXPECT_EQ(ERROR_SUCCESS, 121 RegKey(root, state_key_path.c_str(), KEY_QUERY_VALUE) 122 .ReadValue(google_update::kRegApField, &value)); 123 EXPECT_EQ(L"2.0-dev", value); 124 } 125 } 126 127 TEST_F(InstallUtilTest, UpdateInstallerStage) { 128 const bool system_level = false; 129 const HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 130 std::wstring state_key_path(L"PhonyClientState"); 131 132 // Update the stage when there's no "InstallerExtraCode1" value. 133 { 134 RegistryOverrideManager override_manager; 135 override_manager.OverrideRegistry(root); 136 RegKey(root, state_key_path.c_str(), KEY_SET_VALUE) 137 .DeleteValue(installer::kInstallerExtraCode1); 138 InstallUtil::UpdateInstallerStage(system_level, state_key_path, 139 installer::BUILDING); 140 DWORD value; 141 EXPECT_EQ(ERROR_SUCCESS, 142 RegKey(root, state_key_path.c_str(), KEY_QUERY_VALUE) 143 .ReadValueDW(installer::kInstallerExtraCode1, &value)); 144 EXPECT_EQ(static_cast<DWORD>(installer::BUILDING), value); 145 } 146 147 // Update the stage when there is an "InstallerExtraCode1" value. 148 { 149 RegistryOverrideManager override_manager; 150 override_manager.OverrideRegistry(root); 151 RegKey(root, state_key_path.c_str(), KEY_SET_VALUE) 152 .WriteValue(installer::kInstallerExtraCode1, 153 static_cast<DWORD>(installer::UNPACKING)); 154 InstallUtil::UpdateInstallerStage(system_level, state_key_path, 155 installer::BUILDING); 156 DWORD value; 157 EXPECT_EQ(ERROR_SUCCESS, 158 RegKey(root, state_key_path.c_str(), KEY_QUERY_VALUE) 159 .ReadValueDW(installer::kInstallerExtraCode1, &value)); 160 EXPECT_EQ(static_cast<DWORD>(installer::BUILDING), value); 161 } 162 163 // Clear the stage. 164 { 165 RegistryOverrideManager override_manager; 166 override_manager.OverrideRegistry(root); 167 RegKey(root, state_key_path.c_str(), KEY_SET_VALUE) 168 .WriteValue(installer::kInstallerExtraCode1, static_cast<DWORD>(5)); 169 InstallUtil::UpdateInstallerStage(system_level, state_key_path, 170 installer::NO_STAGE); 171 DWORD value; 172 EXPECT_EQ(ERROR_FILE_NOT_FOUND, 173 RegKey(root, state_key_path.c_str(), KEY_QUERY_VALUE) 174 .ReadValueDW(installer::kInstallerExtraCode1, &value)); 175 } 176 } 177 178 TEST_F(InstallUtilTest, DeleteRegistryKeyIf) { 179 const HKEY root = HKEY_CURRENT_USER; 180 std::wstring parent_key_path(L"SomeKey\\ToDelete"); 181 std::wstring child_key_path(parent_key_path); 182 child_key_path.append(L"\\ChildKey\\WithAValue"); 183 const wchar_t value_name[] = L"some_value_name"; 184 const wchar_t value[] = L"hi mom"; 185 186 { 187 RegistryOverrideManager override_manager; 188 override_manager.OverrideRegistry(root); 189 // Nothing to delete if the keys aren't even there. 190 { 191 MockRegistryValuePredicate pred; 192 193 EXPECT_CALL(pred, Evaluate(_)).Times(0); 194 ASSERT_FALSE(RegKey(root, parent_key_path.c_str(), 195 KEY_QUERY_VALUE).Valid()); 196 EXPECT_EQ(InstallUtil::NOT_FOUND, 197 InstallUtil::DeleteRegistryKeyIf(root, parent_key_path, 198 child_key_path, 199 WorkItem::kWow64Default, 200 value_name, pred)); 201 EXPECT_FALSE(RegKey(root, parent_key_path.c_str(), 202 KEY_QUERY_VALUE).Valid()); 203 } 204 205 // Parent exists, but not child: no delete. 206 { 207 MockRegistryValuePredicate pred; 208 209 EXPECT_CALL(pred, Evaluate(_)).Times(0); 210 ASSERT_TRUE(RegKey(root, parent_key_path.c_str(), KEY_SET_VALUE).Valid()); 211 EXPECT_EQ(InstallUtil::NOT_FOUND, 212 InstallUtil::DeleteRegistryKeyIf(root, parent_key_path, 213 child_key_path, 214 WorkItem::kWow64Default, 215 value_name, pred)); 216 EXPECT_TRUE(RegKey(root, parent_key_path.c_str(), 217 KEY_QUERY_VALUE).Valid()); 218 } 219 220 // Child exists, but no value: no delete. 221 { 222 MockRegistryValuePredicate pred; 223 224 EXPECT_CALL(pred, Evaluate(_)).Times(0); 225 ASSERT_TRUE(RegKey(root, child_key_path.c_str(), KEY_SET_VALUE).Valid()); 226 EXPECT_EQ(InstallUtil::NOT_FOUND, 227 InstallUtil::DeleteRegistryKeyIf(root, parent_key_path, 228 child_key_path, 229 WorkItem::kWow64Default, 230 value_name, pred)); 231 EXPECT_TRUE(RegKey(root, parent_key_path.c_str(), 232 KEY_QUERY_VALUE).Valid()); 233 } 234 235 // Value exists, but doesn't match: no delete. 236 { 237 MockRegistryValuePredicate pred; 238 239 EXPECT_CALL(pred, Evaluate(StrEq(L"foosball!"))).WillOnce(Return(false)); 240 ASSERT_EQ(ERROR_SUCCESS, 241 RegKey(root, child_key_path.c_str(), 242 KEY_SET_VALUE).WriteValue(value_name, L"foosball!")); 243 EXPECT_EQ(InstallUtil::NOT_FOUND, 244 InstallUtil::DeleteRegistryKeyIf(root, parent_key_path, 245 child_key_path, 246 WorkItem::kWow64Default, 247 value_name, pred)); 248 EXPECT_TRUE(RegKey(root, parent_key_path.c_str(), 249 KEY_QUERY_VALUE).Valid()); 250 } 251 252 // Value exists, and matches: delete. 253 { 254 MockRegistryValuePredicate pred; 255 256 EXPECT_CALL(pred, Evaluate(StrEq(value))).WillOnce(Return(true)); 257 ASSERT_EQ(ERROR_SUCCESS, 258 RegKey(root, child_key_path.c_str(), 259 KEY_SET_VALUE).WriteValue(value_name, value)); 260 EXPECT_EQ(InstallUtil::DELETED, 261 InstallUtil::DeleteRegistryKeyIf(root, parent_key_path, 262 child_key_path, 263 WorkItem::kWow64Default, 264 value_name, pred)); 265 EXPECT_FALSE(RegKey(root, parent_key_path.c_str(), 266 KEY_QUERY_VALUE).Valid()); 267 } 268 269 // Default value exists and matches: delete. 270 { 271 MockRegistryValuePredicate pred; 272 273 EXPECT_CALL(pred, Evaluate(StrEq(value))).WillOnce(Return(true)); 274 ASSERT_EQ(ERROR_SUCCESS, 275 RegKey(root, child_key_path.c_str(), 276 KEY_SET_VALUE).WriteValue(NULL, value)); 277 EXPECT_EQ(InstallUtil::DELETED, 278 InstallUtil::DeleteRegistryKeyIf(root, parent_key_path, 279 child_key_path, 280 WorkItem::kWow64Default, 281 NULL, pred)); 282 EXPECT_FALSE(RegKey(root, parent_key_path.c_str(), 283 KEY_QUERY_VALUE).Valid()); 284 } 285 } 286 } 287 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"; 293 294 { 295 RegistryOverrideManager override_manager; 296 override_manager.OverrideRegistry(root); 297 // Nothing to delete if the key isn't even there. 298 { 299 MockRegistryValuePredicate pred; 300 301 EXPECT_CALL(pred, Evaluate(_)).Times(0); 302 ASSERT_FALSE(RegKey(root, key_path.c_str(), KEY_QUERY_VALUE).Valid()); 303 EXPECT_EQ(InstallUtil::NOT_FOUND, 304 InstallUtil::DeleteRegistryValueIf(root, key_path.c_str(), 305 WorkItem::kWow64Default, 306 value_name, pred)); 307 EXPECT_FALSE(RegKey(root, key_path.c_str(), KEY_QUERY_VALUE).Valid()); 308 } 309 310 // Key exists, but no value: no delete. 311 { 312 MockRegistryValuePredicate pred; 313 314 EXPECT_CALL(pred, Evaluate(_)).Times(0); 315 ASSERT_TRUE(RegKey(root, key_path.c_str(), KEY_SET_VALUE).Valid()); 316 EXPECT_EQ(InstallUtil::NOT_FOUND, 317 InstallUtil::DeleteRegistryValueIf(root, key_path.c_str(), 318 WorkItem::kWow64Default, 319 value_name, pred)); 320 EXPECT_TRUE(RegKey(root, key_path.c_str(), KEY_QUERY_VALUE).Valid()); 321 } 322 323 // Value exists, but doesn't match: no delete. 324 { 325 MockRegistryValuePredicate pred; 326 327 EXPECT_CALL(pred, Evaluate(StrEq(L"foosball!"))).WillOnce(Return(false)); 328 ASSERT_EQ(ERROR_SUCCESS, 329 RegKey(root, key_path.c_str(), 330 KEY_SET_VALUE).WriteValue(value_name, L"foosball!")); 331 EXPECT_EQ(InstallUtil::NOT_FOUND, 332 InstallUtil::DeleteRegistryValueIf(root, key_path.c_str(), 333 WorkItem::kWow64Default, 334 value_name, pred)); 335 EXPECT_TRUE(RegKey(root, key_path.c_str(), KEY_QUERY_VALUE).Valid()); 336 EXPECT_TRUE(RegKey(root, key_path.c_str(), 337 KEY_QUERY_VALUE).HasValue(value_name)); 338 } 339 340 // Value exists, and matches: delete. 341 { 342 MockRegistryValuePredicate pred; 343 344 EXPECT_CALL(pred, Evaluate(StrEq(value))).WillOnce(Return(true)); 345 ASSERT_EQ(ERROR_SUCCESS, 346 RegKey(root, key_path.c_str(), 347 KEY_SET_VALUE).WriteValue(value_name, value)); 348 EXPECT_EQ(InstallUtil::DELETED, 349 InstallUtil::DeleteRegistryValueIf(root, key_path.c_str(), 350 WorkItem::kWow64Default, 351 value_name, pred)); 352 EXPECT_TRUE(RegKey(root, key_path.c_str(), KEY_QUERY_VALUE).Valid()); 353 EXPECT_FALSE(RegKey(root, key_path.c_str(), 354 KEY_QUERY_VALUE).HasValue(value_name)); 355 } 356 } 357 358 { 359 RegistryOverrideManager override_manager; 360 override_manager.OverrideRegistry(root); 361 // Default value matches: delete using empty string. 362 { 363 MockRegistryValuePredicate pred; 364 365 EXPECT_CALL(pred, Evaluate(StrEq(value))).WillOnce(Return(true)); 366 ASSERT_EQ(ERROR_SUCCESS, 367 RegKey(root, key_path.c_str(), 368 KEY_SET_VALUE).WriteValue(L"", value)); 369 EXPECT_EQ(InstallUtil::DELETED, 370 InstallUtil::DeleteRegistryValueIf(root, key_path.c_str(), 371 WorkItem::kWow64Default, L"", 372 pred)); 373 EXPECT_TRUE(RegKey(root, key_path.c_str(), KEY_QUERY_VALUE).Valid()); 374 EXPECT_FALSE(RegKey(root, key_path.c_str(), 375 KEY_QUERY_VALUE).HasValue(L"")); 376 } 377 } 378 379 { 380 RegistryOverrideManager override_manager; 381 override_manager.OverrideRegistry(root); 382 // Default value matches: delete using NULL. 383 { 384 MockRegistryValuePredicate pred; 385 386 EXPECT_CALL(pred, Evaluate(StrEq(value))).WillOnce(Return(true)); 387 ASSERT_EQ(ERROR_SUCCESS, 388 RegKey(root, key_path.c_str(), 389 KEY_SET_VALUE).WriteValue(L"", value)); 390 EXPECT_EQ(InstallUtil::DELETED, 391 InstallUtil::DeleteRegistryValueIf(root, key_path.c_str(), 392 WorkItem::kWow64Default, 393 NULL, pred)); 394 EXPECT_TRUE(RegKey(root, key_path.c_str(), KEY_QUERY_VALUE).Valid()); 395 EXPECT_FALSE(RegKey(root, key_path.c_str(), 396 KEY_QUERY_VALUE).HasValue(L"")); 397 } 398 } 399 } 400 401 TEST_F(InstallUtilTest, ValueEquals) { 402 InstallUtil::ValueEquals pred(L"howdy"); 403 404 EXPECT_FALSE(pred.Evaluate(L"")); 405 EXPECT_FALSE(pred.Evaluate(L"Howdy")); 406 EXPECT_FALSE(pred.Evaluate(L"howdy!")); 407 EXPECT_FALSE(pred.Evaluate(L"!howdy")); 408 EXPECT_TRUE(pred.Evaluate(L"howdy")); 409 } 410 411 TEST_F(InstallUtilTest, ProgramCompare) { 412 base::FilePath some_long_dir( 413 test_dir_.path().Append(L"Some Long Directory Name")); 414 base::FilePath expect(some_long_dir.Append(L"file.txt")); 415 base::FilePath expect_upcase(some_long_dir.Append(L"FILE.txt")); 416 base::FilePath other(some_long_dir.Append(L"otherfile.txt")); 417 418 // Tests where the expected file doesn't exist. 419 420 // Paths don't match. 421 EXPECT_FALSE(InstallUtil::ProgramCompare(expect).Evaluate( 422 L"\"" + other.value() + L"\"")); 423 // Paths match exactly. 424 EXPECT_TRUE(InstallUtil::ProgramCompare(expect).Evaluate( 425 L"\"" + expect.value() + L"\"")); 426 // Paths differ by case. 427 EXPECT_TRUE(InstallUtil::ProgramCompare(expect).Evaluate( 428 L"\"" + expect_upcase.value() + L"\"")); 429 430 // Tests where the expected file exists. 431 static const char data[] = "data"; 432 ASSERT_TRUE(base::CreateDirectory(some_long_dir)); 433 ASSERT_NE(-1, base::WriteFile(expect, data, arraysize(data) - 1)); 434 // Paths don't match. 435 EXPECT_FALSE(InstallUtil::ProgramCompare(expect).Evaluate( 436 L"\"" + other.value() + L"\"")); 437 // Paths match exactly. 438 EXPECT_TRUE(InstallUtil::ProgramCompare(expect).Evaluate( 439 L"\"" + expect.value() + L"\"")); 440 // Paths differ by case. 441 EXPECT_TRUE(InstallUtil::ProgramCompare(expect).Evaluate( 442 L"\"" + expect_upcase.value() + L"\"")); 443 444 // Test where strings don't match, but the same file is indicated. 445 std::wstring short_expect; 446 DWORD short_len = GetShortPathName(expect.value().c_str(), 447 WriteInto(&short_expect, MAX_PATH), 448 MAX_PATH); 449 ASSERT_NE(static_cast<DWORD>(0), short_len); 450 ASSERT_GT(static_cast<DWORD>(MAX_PATH), short_len); 451 short_expect.resize(short_len); 452 ASSERT_FALSE(base::FilePath::CompareEqualIgnoreCase(expect.value(), 453 short_expect)); 454 EXPECT_TRUE(InstallUtil::ProgramCompare(expect).Evaluate( 455 L"\"" + short_expect + L"\"")); 456 } 457