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