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 "base/win/shortcut.h"
6
7#include <string>
8
9#include "base/files/file_path.h"
10#include "base/files/file_util.h"
11#include "base/files/scoped_temp_dir.h"
12#include "base/test/test_file_util.h"
13#include "base/test/test_shortcut_win.h"
14#include "base/win/scoped_com_initializer.h"
15#include "base/win/windows_version.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace base {
19namespace win {
20
21namespace {
22
23static const char kFileContents[] = "This is a target.";
24static const char kFileContents2[] = "This is another target.";
25
26class ShortcutTest : public testing::Test {
27 protected:
28  virtual void SetUp() OVERRIDE {
29    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
30    ASSERT_TRUE(temp_dir_2_.CreateUniqueTempDir());
31
32    link_file_ = temp_dir_.path().Append(L"My Link.lnk");
33
34    // Shortcut 1's properties
35    {
36      const FilePath target_file(temp_dir_.path().Append(L"Target 1.txt"));
37      WriteFile(target_file, kFileContents, arraysize(kFileContents));
38
39      link_properties_.set_target(target_file);
40      link_properties_.set_working_dir(temp_dir_.path());
41      link_properties_.set_arguments(L"--magic --awesome");
42      link_properties_.set_description(L"Chrome is awesome.");
43      link_properties_.set_icon(link_properties_.target, 4);
44      link_properties_.set_app_id(L"Chrome");
45      link_properties_.set_dual_mode(false);
46    }
47
48    // Shortcut 2's properties (all different from properties of shortcut 1).
49    {
50      const FilePath target_file_2(temp_dir_.path().Append(L"Target 2.txt"));
51      WriteFile(target_file_2, kFileContents2, arraysize(kFileContents2));
52
53      FilePath icon_path_2;
54      CreateTemporaryFileInDir(temp_dir_.path(), &icon_path_2);
55
56      link_properties_2_.set_target(target_file_2);
57      link_properties_2_.set_working_dir(temp_dir_2_.path());
58      link_properties_2_.set_arguments(L"--super --crazy");
59      link_properties_2_.set_description(L"The best in the west.");
60      link_properties_2_.set_icon(icon_path_2, 0);
61      link_properties_2_.set_app_id(L"Chrome.UserLevelCrazySuffix");
62      link_properties_2_.set_dual_mode(true);
63    }
64  }
65
66  ScopedCOMInitializer com_initializer_;
67  ScopedTempDir temp_dir_;
68  ScopedTempDir temp_dir_2_;
69
70  // The link file to be created/updated in the shortcut tests below.
71  FilePath link_file_;
72
73  // Properties for the created shortcut.
74  ShortcutProperties link_properties_;
75
76  // Properties for the updated shortcut.
77  ShortcutProperties link_properties_2_;
78};
79
80}  // namespace
81
82TEST_F(ShortcutTest, CreateAndResolveShortcutProperties) {
83  uint32 valid_properties = ShortcutProperties::PROPERTIES_BASIC;
84  if (GetVersion() >= VERSION_WIN7)
85    valid_properties |= ShortcutProperties::PROPERTIES_WIN7;
86
87  // Test all properties.
88  FilePath file_1(temp_dir_.path().Append(L"Link1.lnk"));
89  ASSERT_TRUE(CreateOrUpdateShortcutLink(
90      file_1, link_properties_, SHORTCUT_CREATE_ALWAYS));
91
92  ShortcutProperties properties_read_1;
93  ASSERT_TRUE(ResolveShortcutProperties(
94      file_1, ShortcutProperties::PROPERTIES_ALL, &properties_read_1));
95  EXPECT_EQ(valid_properties, properties_read_1.options);
96  ValidatePathsAreEqual(link_properties_.target, properties_read_1.target);
97  ValidatePathsAreEqual(link_properties_.working_dir,
98                        properties_read_1.working_dir);
99  EXPECT_EQ(link_properties_.arguments, properties_read_1.arguments);
100  EXPECT_EQ(link_properties_.description, properties_read_1.description);
101  ValidatePathsAreEqual(link_properties_.icon, properties_read_1.icon);
102  EXPECT_EQ(link_properties_.icon_index, properties_read_1.icon_index);
103  if (GetVersion() >= VERSION_WIN7) {
104    EXPECT_EQ(link_properties_.app_id, properties_read_1.app_id);
105    EXPECT_EQ(link_properties_.dual_mode, properties_read_1.dual_mode);
106  }
107
108  // Test simple shortcut with no special properties set.
109  FilePath file_2(temp_dir_.path().Append(L"Link2.lnk"));
110  ShortcutProperties only_target_properties;
111  only_target_properties.set_target(link_properties_.target);
112  ASSERT_TRUE(CreateOrUpdateShortcutLink(
113      file_2, only_target_properties, SHORTCUT_CREATE_ALWAYS));
114
115  ShortcutProperties properties_read_2;
116  ASSERT_TRUE(ResolveShortcutProperties(
117      file_2, ShortcutProperties::PROPERTIES_ALL, &properties_read_2));
118  EXPECT_EQ(valid_properties, properties_read_2.options);
119  ValidatePathsAreEqual(only_target_properties.target,
120                        properties_read_2.target);
121  ValidatePathsAreEqual(FilePath(), properties_read_2.working_dir);
122  EXPECT_EQ(L"", properties_read_2.arguments);
123  EXPECT_EQ(L"", properties_read_2.description);
124  ValidatePathsAreEqual(FilePath(), properties_read_2.icon);
125  EXPECT_EQ(0, properties_read_2.icon_index);
126  if (GetVersion() >= VERSION_WIN7) {
127    EXPECT_EQ(L"", properties_read_2.app_id);
128    EXPECT_FALSE(properties_read_2.dual_mode);
129  }
130}
131
132TEST_F(ShortcutTest, CreateAndResolveShortcut) {
133  ShortcutProperties only_target_properties;
134  only_target_properties.set_target(link_properties_.target);
135
136  ASSERT_TRUE(CreateOrUpdateShortcutLink(
137      link_file_, only_target_properties, SHORTCUT_CREATE_ALWAYS));
138
139  FilePath resolved_name;
140  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL));
141
142  char read_contents[arraysize(kFileContents)];
143  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
144  EXPECT_STREQ(kFileContents, read_contents);
145}
146
147TEST_F(ShortcutTest, ResolveShortcutWithArgs) {
148  ASSERT_TRUE(CreateOrUpdateShortcutLink(
149      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
150
151  FilePath resolved_name;
152  string16 args;
153  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, &args));
154
155  char read_contents[arraysize(kFileContents)];
156  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
157  EXPECT_STREQ(kFileContents, read_contents);
158  EXPECT_EQ(link_properties_.arguments, args);
159}
160
161TEST_F(ShortcutTest, CreateShortcutWithOnlySomeProperties) {
162  ShortcutProperties target_and_args_properties;
163  target_and_args_properties.set_target(link_properties_.target);
164  target_and_args_properties.set_arguments(link_properties_.arguments);
165
166  ASSERT_TRUE(CreateOrUpdateShortcutLink(
167      link_file_, target_and_args_properties,
168      SHORTCUT_CREATE_ALWAYS));
169
170  ValidateShortcut(link_file_, target_and_args_properties);
171}
172
173TEST_F(ShortcutTest, CreateShortcutVerifyProperties) {
174  ASSERT_TRUE(CreateOrUpdateShortcutLink(
175      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
176
177  ValidateShortcut(link_file_, link_properties_);
178}
179
180TEST_F(ShortcutTest, UpdateShortcutVerifyProperties) {
181  ASSERT_TRUE(CreateOrUpdateShortcutLink(
182      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
183
184  ASSERT_TRUE(CreateOrUpdateShortcutLink(
185      link_file_, link_properties_2_, SHORTCUT_UPDATE_EXISTING));
186
187  ValidateShortcut(link_file_, link_properties_2_);
188}
189
190TEST_F(ShortcutTest, UpdateShortcutUpdateOnlyTargetAndResolve) {
191  ASSERT_TRUE(CreateOrUpdateShortcutLink(
192      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
193
194  ShortcutProperties update_only_target_properties;
195  update_only_target_properties.set_target(link_properties_2_.target);
196
197  ASSERT_TRUE(CreateOrUpdateShortcutLink(
198      link_file_, update_only_target_properties,
199      SHORTCUT_UPDATE_EXISTING));
200
201  ShortcutProperties expected_properties = link_properties_;
202  expected_properties.set_target(link_properties_2_.target);
203  ValidateShortcut(link_file_, expected_properties);
204
205  FilePath resolved_name;
206  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL));
207
208  char read_contents[arraysize(kFileContents2)];
209  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
210  EXPECT_STREQ(kFileContents2, read_contents);
211}
212
213TEST_F(ShortcutTest, UpdateShortcutMakeDualMode) {
214  ASSERT_TRUE(CreateOrUpdateShortcutLink(
215      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
216
217  ShortcutProperties make_dual_mode_properties;
218  make_dual_mode_properties.set_dual_mode(true);
219
220  ASSERT_TRUE(CreateOrUpdateShortcutLink(
221      link_file_, make_dual_mode_properties,
222      SHORTCUT_UPDATE_EXISTING));
223
224  ShortcutProperties expected_properties = link_properties_;
225  expected_properties.set_dual_mode(true);
226  ValidateShortcut(link_file_, expected_properties);
227}
228
229TEST_F(ShortcutTest, UpdateShortcutRemoveDualMode) {
230  ASSERT_TRUE(CreateOrUpdateShortcutLink(
231      link_file_, link_properties_2_, SHORTCUT_CREATE_ALWAYS));
232
233  ShortcutProperties remove_dual_mode_properties;
234  remove_dual_mode_properties.set_dual_mode(false);
235
236  ASSERT_TRUE(CreateOrUpdateShortcutLink(
237      link_file_, remove_dual_mode_properties,
238      SHORTCUT_UPDATE_EXISTING));
239
240  ShortcutProperties expected_properties = link_properties_2_;
241  expected_properties.set_dual_mode(false);
242  ValidateShortcut(link_file_, expected_properties);
243}
244
245TEST_F(ShortcutTest, UpdateShortcutClearArguments) {
246  ASSERT_TRUE(CreateOrUpdateShortcutLink(
247      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
248
249  ShortcutProperties clear_arguments_properties;
250  clear_arguments_properties.set_arguments(string16());
251
252  ASSERT_TRUE(CreateOrUpdateShortcutLink(
253      link_file_, clear_arguments_properties,
254      SHORTCUT_UPDATE_EXISTING));
255
256  ShortcutProperties expected_properties = link_properties_;
257  expected_properties.set_arguments(string16());
258  ValidateShortcut(link_file_, expected_properties);
259}
260
261TEST_F(ShortcutTest, FailUpdateShortcutThatDoesNotExist) {
262  ASSERT_FALSE(CreateOrUpdateShortcutLink(
263      link_file_, link_properties_, SHORTCUT_UPDATE_EXISTING));
264  ASSERT_FALSE(PathExists(link_file_));
265}
266
267TEST_F(ShortcutTest, ReplaceShortcutAllProperties) {
268  ASSERT_TRUE(CreateOrUpdateShortcutLink(
269      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
270
271  ASSERT_TRUE(CreateOrUpdateShortcutLink(
272      link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING));
273
274  ValidateShortcut(link_file_, link_properties_2_);
275}
276
277TEST_F(ShortcutTest, ReplaceShortcutSomeProperties) {
278  ASSERT_TRUE(CreateOrUpdateShortcutLink(
279      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
280
281  ShortcutProperties new_properties;
282  new_properties.set_target(link_properties_2_.target);
283  new_properties.set_arguments(link_properties_2_.arguments);
284  new_properties.set_description(link_properties_2_.description);
285  ASSERT_TRUE(CreateOrUpdateShortcutLink(
286      link_file_, new_properties, SHORTCUT_REPLACE_EXISTING));
287
288  // Expect only properties in |new_properties| to be set, all other properties
289  // should have been overwritten.
290  ShortcutProperties expected_properties(new_properties);
291  expected_properties.set_working_dir(FilePath());
292  expected_properties.set_icon(FilePath(), 0);
293  expected_properties.set_app_id(string16());
294  expected_properties.set_dual_mode(false);
295  ValidateShortcut(link_file_, expected_properties);
296}
297
298TEST_F(ShortcutTest, FailReplaceShortcutThatDoesNotExist) {
299  ASSERT_FALSE(CreateOrUpdateShortcutLink(
300      link_file_, link_properties_, SHORTCUT_REPLACE_EXISTING));
301  ASSERT_FALSE(PathExists(link_file_));
302}
303
304// Test that the old arguments remain on the replaced shortcut when not
305// otherwise specified.
306TEST_F(ShortcutTest, ReplaceShortcutKeepOldArguments) {
307  ASSERT_TRUE(CreateOrUpdateShortcutLink(
308      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
309
310  // Do not explicitly set the arguments.
311  link_properties_2_.options &=
312      ~ShortcutProperties::PROPERTIES_ARGUMENTS;
313  ASSERT_TRUE(CreateOrUpdateShortcutLink(
314      link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING));
315
316  ShortcutProperties expected_properties(link_properties_2_);
317  expected_properties.set_arguments(link_properties_.arguments);
318  ValidateShortcut(link_file_, expected_properties);
319}
320
321}  // namespace win
322}  // namespace base
323