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 |