OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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 "chrome/install_static/product_install_details.h" |
| 6 |
| 7 #include "base/base_paths.h" |
| 8 #include "base/files/file_path.h" |
| 9 #include "base/i18n/case_conversion.h" |
| 10 #include "base/macros.h" |
| 11 #include "base/path_service.h" |
| 12 #include "base/strings/stringprintf.h" |
| 13 #include "base/test/test_reg_util_win.h" |
| 14 #include "base/win/registry.h" |
| 15 #include "base/win/windows_version.h" |
| 16 #include "chrome/install_static/install_constants.h" |
| 17 #include "chrome/install_static/install_modes.h" |
| 18 #include "chrome_elf/nt_registry/nt_registry.h" |
| 19 #include "testing/gmock/include/gmock/gmock.h" |
| 20 #include "testing/gtest/include/gtest/gtest.h" |
| 21 |
| 22 using ::testing::Eq; |
| 23 using ::testing::StrEq; |
| 24 |
| 25 namespace install_static { |
| 26 |
| 27 namespace { |
| 28 |
| 29 TEST(ProductInstallDetailsTest, IsPathParentOf) { |
| 30 std::wstring path = L"C:\\Program Files\\Company\\Product\\Application\\foo"; |
| 31 static constexpr const wchar_t* kFalseExpectations[] = { |
| 32 L"", |
| 33 L"\\", |
| 34 L"\\\\", |
| 35 L"C:\\Program File", |
| 36 L"C:\\Program Filesz", |
| 37 }; |
| 38 for (const wchar_t* false_expectation : kFalseExpectations) { |
| 39 EXPECT_FALSE(IsPathParentOf( |
| 40 false_expectation, std::wstring::traits_type::length(false_expectation), |
| 41 path)); |
| 42 } |
| 43 |
| 44 static constexpr const wchar_t* kTrueExpectations[] = { |
| 45 L"C:\\Program Files", |
| 46 L"C:\\PROGRAM FILES", |
| 47 L"C:\\Program Files\\", |
| 48 L"C:\\Program Files\\\\\\", |
| 49 }; |
| 50 for (const wchar_t* true_expectation : kTrueExpectations) { |
| 51 EXPECT_TRUE(IsPathParentOf( |
| 52 true_expectation, std::wstring::traits_type::length(true_expectation), |
| 53 path)); |
| 54 } |
| 55 } |
| 56 |
| 57 TEST(ProductInstallDetailsTest, PathIsInProgramFiles) { |
| 58 static constexpr const wchar_t* kInvalidPaths[] = { |
| 59 L"", |
| 60 L"hello", |
| 61 L"C:\\Program File", |
| 62 L"C:\\Program Filesz", |
| 63 L"C:\\foo\\Program Files", |
| 64 L"C:\\foo\\Program Files\\", |
| 65 L"C:\\foo\\Program Files (x86)", |
| 66 L"C:\\foo\\Program Files (x86)\\", |
| 67 }; |
| 68 for (const wchar_t* invalid : kInvalidPaths) |
| 69 EXPECT_FALSE(PathIsInProgramFiles(invalid)) << invalid; |
| 70 |
| 71 // 32-bit on 32-bit: only check C:\Program Files. |
| 72 // 32-bit and 64-bit on 64-bit: check both. |
| 73 const bool is_x64 = base::win::OSInfo::GetInstance()->architecture() != |
| 74 base::win::OSInfo::X86_ARCHITECTURE; |
| 75 std::vector<int> program_files_keys; |
| 76 program_files_keys.push_back(base::DIR_PROGRAM_FILESX86); |
| 77 if (is_x64) |
| 78 program_files_keys.push_back(base::DIR_PROGRAM_FILES6432); |
| 79 std::vector<std::wstring> program_files_paths; |
| 80 for (int key : program_files_keys) { |
| 81 base::FilePath path; |
| 82 ASSERT_TRUE(base::PathService::Get(key, &path)); |
| 83 program_files_paths.push_back(path.value()); |
| 84 } |
| 85 |
| 86 static constexpr const wchar_t* kValidFormats[] = { |
| 87 L"%ls", |
| 88 L"%ls\\", |
| 89 L"%ls\\spam", |
| 90 }; |
| 91 for (const wchar_t* valid : kValidFormats) { |
| 92 for (const std::wstring& program_files_path : program_files_paths) { |
| 93 std::wstring path = base::StringPrintf(valid, program_files_path.c_str()); |
| 94 EXPECT_TRUE(PathIsInProgramFiles(path)) << path; |
| 95 |
| 96 path = base::StringPrintf( |
| 97 valid, base::i18n::ToLower(program_files_path).c_str()); |
| 98 EXPECT_TRUE(PathIsInProgramFiles(path)) << path; |
| 99 } |
| 100 } |
| 101 } |
| 102 |
| 103 TEST(ProductInstallDetailsTest, GetInstallSuffix) { |
| 104 std::wstring suffix; |
| 105 const std::pair<const wchar_t*, const wchar_t*> kData[] = { |
| 106 {L"%ls\\Application", L""}, |
| 107 {L"%ls\\Application\\", L""}, |
| 108 {L"\\%ls\\Application", L""}, |
| 109 {L"\\%ls\\Application\\", L""}, |
| 110 {L"C:\\foo\\%ls\\Application\\foo.exe", L""}, |
| 111 {L"%ls Blorf\\Application", L" Blorf"}, |
| 112 {L"%ls Blorf\\Application\\", L" Blorf"}, |
| 113 {L"\\%ls Blorf\\Application", L" Blorf"}, |
| 114 {L"\\%ls Blorf\\Application\\", L" Blorf"}, |
| 115 {L"C:\\foo\\%ls Blorf\\Application\\foo.exe", L" Blorf"}, |
| 116 }; |
| 117 for (const auto& data : kData) { |
| 118 const std::wstring path = base::StringPrintf(data.first, kProductPathName); |
| 119 EXPECT_EQ(std::wstring(data.second), GetInstallSuffix(path)) << path; |
| 120 } |
| 121 } |
| 122 |
| 123 struct TestData { |
| 124 const wchar_t* path; |
| 125 InstallConstantIndex index; |
| 126 bool system_level; |
| 127 const wchar_t* channel; |
| 128 }; |
| 129 |
| 130 #if defined(GOOGLE_CHROME_BUILD) |
| 131 constexpr TestData kTestData[] = { |
| 132 { |
| 133 L"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", |
| 134 STABLE_INDEX, true, L"", |
| 135 }, |
| 136 { |
| 137 L"C:\\Users\\user\\AppData\\Local\\Google\\Chrome\\Application" |
| 138 L"\\chrome.exe", |
| 139 STABLE_INDEX, false, L"", |
| 140 }, |
| 141 { |
| 142 L"C:\\Users\\user\\AppData\\Local\\Google\\Chrome SxS\\Application" |
| 143 L"\\chrome.exe", |
| 144 CANARY_INDEX, false, L"canary", |
| 145 }, |
| 146 { |
| 147 L"C:\\Users\\user\\AppData\\Local\\Google\\CHROME SXS\\application" |
| 148 L"\\chrome.exe", |
| 149 CANARY_INDEX, false, L"canary", |
| 150 }, |
| 151 }; |
| 152 #else // GOOGLE_CHROME_BUILD |
| 153 constexpr TestData kTestData[] = { |
| 154 { |
| 155 L"C:\\Program Files (x86)\\Chromium\\Application\\chrome.exe", |
| 156 CHROMIUM_INDEX, true, L"", |
| 157 }, |
| 158 { |
| 159 L"C:\\Users\\user\\AppData\\Local\\Chromium\\Application\\chrome.exe", |
| 160 CHROMIUM_INDEX, false, L"", |
| 161 }, |
| 162 }; |
| 163 #endif // !GOOGLE_CHROME_BUILD |
| 164 |
| 165 } // namespace |
| 166 |
| 167 // Test that MakeProductDetails properly sniffs out an install's details. |
| 168 class MakeProductDetailsTest : public testing::TestWithParam<TestData> { |
| 169 protected: |
| 170 MakeProductDetailsTest() |
| 171 : test_data_(GetParam()), |
| 172 root_key_(test_data_.system_level ? HKEY_LOCAL_MACHINE |
| 173 : HKEY_CURRENT_USER), |
| 174 nt_root_key_(test_data_.system_level ? nt::HKLM : nt::HKCU) { |
| 175 base::string16 path; |
| 176 override_manager_.OverrideRegistry(root_key_, &path); |
| 177 nt::SetTestingOverride(nt_root_key_, path); |
| 178 } |
| 179 |
| 180 ~MakeProductDetailsTest() { |
| 181 nt::SetTestingOverride(nt_root_key_, base::string16()); |
| 182 } |
| 183 |
| 184 const TestData& test_data() const { return test_data_; } |
| 185 |
| 186 void SetUninstallArguments(const wchar_t* value) { |
| 187 ASSERT_THAT( |
| 188 base::win::RegKey(root_key_, GetClientStateKeyPath(false).c_str(), |
| 189 KEY_WOW64_32KEY | KEY_SET_VALUE) |
| 190 .WriteValue(L"UninstallArguments", value), |
| 191 Eq(ERROR_SUCCESS)); |
| 192 } |
| 193 |
| 194 void SetAp(const wchar_t* value, bool binaries) { |
| 195 ASSERT_TRUE(!binaries || |
| 196 kInstallModes[test_data().index].supports_multi_install); |
| 197 ASSERT_THAT( |
| 198 base::win::RegKey(root_key_, GetClientStateKeyPath(binaries).c_str(), |
| 199 KEY_WOW64_32KEY | KEY_SET_VALUE) |
| 200 .WriteValue(L"ap", value), |
| 201 Eq(ERROR_SUCCESS)); |
| 202 } |
| 203 |
| 204 private: |
| 205 // Returns the registry path for the product's ClientState key. |
| 206 std::wstring GetClientStateKeyPath(bool binaries) { |
| 207 EXPECT_TRUE(!binaries || |
| 208 kInstallModes[test_data().index].supports_multi_install); |
| 209 std::wstring result(L"Software\\"); |
| 210 if (kUseGoogleUpdateIntegration) { |
| 211 result.append(L"Google\\Update\\ClientState\\"); |
| 212 if (binaries) |
| 213 result.append(kBinariesAppGuid); |
| 214 else |
| 215 result.append(kInstallModes[test_data().index].app_guid); |
| 216 } else if (binaries) { |
| 217 result.append(kBinariesPathName); |
| 218 } else { |
| 219 result.append(kProductPathName); |
| 220 } |
| 221 return result; |
| 222 } |
| 223 |
| 224 registry_util::RegistryOverrideManager override_manager_; |
| 225 const TestData& test_data_; |
| 226 HKEY root_key_; |
| 227 nt::ROOT_KEY nt_root_key_; |
| 228 |
| 229 DISALLOW_COPY_AND_ASSIGN(MakeProductDetailsTest); |
| 230 }; |
| 231 |
| 232 // Test that the install mode is sniffed properly based on the path. |
| 233 TEST_P(MakeProductDetailsTest, Index) { |
| 234 std::unique_ptr<PrimaryInstallDetails> details( |
| 235 MakeProductDetails(test_data().path)); |
| 236 EXPECT_THAT(details->install_mode_index(), Eq(test_data().index)); |
| 237 } |
| 238 |
| 239 // Test that user/system level is sniffed properly based on the path. |
| 240 TEST_P(MakeProductDetailsTest, SystemLevel) { |
| 241 std::unique_ptr<PrimaryInstallDetails> details( |
| 242 MakeProductDetails(test_data().path)); |
| 243 EXPECT_THAT(details->system_level(), Eq(test_data().system_level)); |
| 244 } |
| 245 |
| 246 // Test that the default channel is sniffed properly based on the path. |
| 247 TEST_P(MakeProductDetailsTest, DefaultChannel) { |
| 248 std::unique_ptr<PrimaryInstallDetails> details( |
| 249 MakeProductDetails(test_data().path)); |
| 250 EXPECT_THAT(details->channel(), StrEq(test_data().channel)); |
| 251 } |
| 252 |
| 253 // Test that multi-install is properly parsed out of the registry. |
| 254 TEST_P(MakeProductDetailsTest, MultiInstall) { |
| 255 { |
| 256 std::unique_ptr<PrimaryInstallDetails> details( |
| 257 MakeProductDetails(test_data().path)); |
| 258 EXPECT_FALSE(details->multi_install()); |
| 259 } |
| 260 |
| 261 { |
| 262 SetUninstallArguments(L"--uninstall"); |
| 263 std::unique_ptr<PrimaryInstallDetails> details( |
| 264 MakeProductDetails(test_data().path)); |
| 265 EXPECT_FALSE(details->multi_install()); |
| 266 } |
| 267 |
| 268 if (!kInstallModes[test_data().index].supports_multi_install) |
| 269 return; |
| 270 |
| 271 { |
| 272 SetUninstallArguments(L"--uninstall --multi-install --chrome"); |
| 273 std::unique_ptr<PrimaryInstallDetails> details( |
| 274 MakeProductDetails(test_data().path)); |
| 275 EXPECT_TRUE(details->multi_install()); |
| 276 } |
| 277 } |
| 278 |
| 279 // Test that the channel name is properly parsed out of additional parameters. |
| 280 TEST_P(MakeProductDetailsTest, AdditionalParametersChannels) { |
| 281 const std::pair<const wchar_t*, const wchar_t*> kApChannels[] = { |
| 282 // stable |
| 283 {L"", L""}, |
| 284 {L"-full", L""}, |
| 285 {L"x64-stable", L""}, |
| 286 {L"x64-stable-full", L""}, |
| 287 {L"baz-x64-stable", L""}, |
| 288 {L"foo-1.1-beta", L""}, |
| 289 {L"2.0-beta", L""}, |
| 290 {L"bar-2.0-dev", L""}, |
| 291 {L"1.0-dev", L""}, |
| 292 {L"fuzzy", L""}, |
| 293 {L"foo", L""}, |
| 294 {L"-multi-chrome", L""}, |
| 295 {L"x64-stable-multi-chrome", L""}, |
| 296 {L"-stage:ensemble_patching-multi-chrome-full", L""}, |
| 297 {L"-multi-chrome-full", L""}, |
| 298 // beta |
| 299 {L"1.1-beta", L"beta"}, |
| 300 {L"1.1-beta-full", L"beta"}, |
| 301 {L"x64-beta", L"beta"}, |
| 302 {L"x64-beta-full", L"beta"}, |
| 303 {L"1.1-bar", L"beta"}, |
| 304 {L"1n1-foobar", L"beta"}, |
| 305 {L"x64-Beta", L"beta"}, |
| 306 {L"bar-x64-beta", L"beta"}, |
| 307 // dev |
| 308 {L"2.0-dev", L"dev"}, |
| 309 {L"2.0-dev-full", L"dev"}, |
| 310 {L"x64-dev", L"dev"}, |
| 311 {L"x64-dev-full", L"dev"}, |
| 312 {L"2.0-DEV", L"dev"}, |
| 313 {L"2.0-dev-eloper", L"dev"}, |
| 314 {L"2.0-doom", L"dev"}, |
| 315 {L"250-doom", L"dev"}, |
| 316 }; |
| 317 |
| 318 for (const auto& ap_and_channel : kApChannels) { |
| 319 SetAp(ap_and_channel.first, false); |
| 320 std::unique_ptr<PrimaryInstallDetails> details( |
| 321 MakeProductDetails(test_data().path)); |
| 322 if (kInstallModes[test_data().index].channel_strategy == |
| 323 ChannelStrategy::ADDITIONAL_PARAMETERS) { |
| 324 EXPECT_THAT(details->channel(), StrEq(ap_and_channel.second)); |
| 325 } else { |
| 326 // "ap" is ignored for this mode. |
| 327 EXPECT_THAT(details->channel(), StrEq(test_data().channel)); |
| 328 } |
| 329 } |
| 330 |
| 331 if (!kInstallModes[test_data().index].supports_multi_install) |
| 332 return; |
| 333 |
| 334 // For multi-install modes, "ap" is pulled from the binaries' key. |
| 335 for (const auto& ap_and_channel : kApChannels) { |
| 336 SetAp(ap_and_channel.first, true); |
| 337 SetUninstallArguments(L"--uninstall --multi-install --chrome"); |
| 338 std::unique_ptr<PrimaryInstallDetails> details( |
| 339 MakeProductDetails(test_data().path)); |
| 340 if (kInstallModes[test_data().index].channel_strategy == |
| 341 ChannelStrategy::ADDITIONAL_PARAMETERS) { |
| 342 EXPECT_THAT(details->channel(), StrEq(ap_and_channel.second)); |
| 343 } else { |
| 344 // "ap" is ignored for this mode. |
| 345 EXPECT_THAT(details->channel(), StrEq(test_data().channel)); |
| 346 } |
| 347 } |
| 348 } |
| 349 |
| 350 INSTANTIATE_TEST_CASE_P(All, |
| 351 MakeProductDetailsTest, |
| 352 testing::ValuesIn(kTestData)); |
| 353 |
| 354 } // namespace install_static |
OLD | NEW |