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/file_util.h"
10#include "base/files/file_path.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 "testing/gtest/include/gtest/gtest.h"
16
17namespace base {
18namespace win {
19
20namespace {
21
22static const char kFileContents[] = "This is a target.";
23static const char kFileContents2[] = "This is another target.";
24
25class ShortcutTest : public testing::Test {
26 protected:
27  virtual void SetUp() OVERRIDE {
28    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
29    ASSERT_TRUE(temp_dir_2_.CreateUniqueTempDir());
30
31    link_file_ = temp_dir_.path().Append(L"My Link.lnk");
32
33    // Shortcut 1's properties
34    {
35      const FilePath target_file(temp_dir_.path().Append(L"Target 1.txt"));
36      file_util::WriteFile(target_file, kFileContents,
37                           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      file_util::WriteFile(target_file_2, kFileContents2,
52                           arraysize(kFileContents2));
53
54      FilePath icon_path_2;
55      base::CreateTemporaryFileInDir(temp_dir_.path(), &icon_path_2);
56
57      link_properties_2_.set_target(target_file_2);
58      link_properties_2_.set_working_dir(temp_dir_2_.path());
59      link_properties_2_.set_arguments(L"--super --crazy");
60      link_properties_2_.set_description(L"The best in the west.");
61      link_properties_2_.set_icon(icon_path_2, 0);
62      link_properties_2_.set_app_id(L"Chrome.UserLevelCrazySuffix");
63      link_properties_2_.set_dual_mode(true);
64    }
65  }
66
67  ScopedCOMInitializer com_initializer_;
68  ScopedTempDir temp_dir_;
69  ScopedTempDir temp_dir_2_;
70
71  // The link file to be created/updated in the shortcut tests below.
72  FilePath link_file_;
73
74  // Properties for the created shortcut.
75  ShortcutProperties link_properties_;
76
77  // Properties for the updated shortcut.
78  ShortcutProperties link_properties_2_;
79};
80
81}  // namespace
82
83TEST_F(ShortcutTest, CreateAndResolveShortcut) {
84  ShortcutProperties only_target_properties;
85  only_target_properties.set_target(link_properties_.target);
86
87  ASSERT_TRUE(CreateOrUpdateShortcutLink(
88      link_file_, only_target_properties, SHORTCUT_CREATE_ALWAYS));
89
90  FilePath resolved_name;
91  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL));
92
93  char read_contents[arraysize(kFileContents)];
94  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
95  EXPECT_STREQ(kFileContents, read_contents);
96}
97
98TEST_F(ShortcutTest, ResolveShortcutWithArgs) {
99  ASSERT_TRUE(CreateOrUpdateShortcutLink(
100      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
101
102  FilePath resolved_name;
103  string16 args;
104  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, &args));
105
106  char read_contents[arraysize(kFileContents)];
107  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
108  EXPECT_STREQ(kFileContents, read_contents);
109  EXPECT_EQ(link_properties_.arguments, args);
110}
111
112TEST_F(ShortcutTest, CreateShortcutWithOnlySomeProperties) {
113  ShortcutProperties target_and_args_properties;
114  target_and_args_properties.set_target(link_properties_.target);
115  target_and_args_properties.set_arguments(link_properties_.arguments);
116
117  ASSERT_TRUE(CreateOrUpdateShortcutLink(
118      link_file_, target_and_args_properties,
119      SHORTCUT_CREATE_ALWAYS));
120
121  ValidateShortcut(link_file_, target_and_args_properties);
122}
123
124TEST_F(ShortcutTest, CreateShortcutVerifyProperties) {
125  ASSERT_TRUE(CreateOrUpdateShortcutLink(
126      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
127
128  ValidateShortcut(link_file_, link_properties_);
129}
130
131TEST_F(ShortcutTest, UpdateShortcutVerifyProperties) {
132  ASSERT_TRUE(CreateOrUpdateShortcutLink(
133      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
134
135  ASSERT_TRUE(CreateOrUpdateShortcutLink(
136      link_file_, link_properties_2_, SHORTCUT_UPDATE_EXISTING));
137
138  ValidateShortcut(link_file_, link_properties_2_);
139}
140
141TEST_F(ShortcutTest, UpdateShortcutUpdateOnlyTargetAndResolve) {
142  ASSERT_TRUE(CreateOrUpdateShortcutLink(
143      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
144
145  ShortcutProperties update_only_target_properties;
146  update_only_target_properties.set_target(link_properties_2_.target);
147
148  ASSERT_TRUE(CreateOrUpdateShortcutLink(
149      link_file_, update_only_target_properties,
150      SHORTCUT_UPDATE_EXISTING));
151
152  ShortcutProperties expected_properties = link_properties_;
153  expected_properties.set_target(link_properties_2_.target);
154  ValidateShortcut(link_file_, expected_properties);
155
156  FilePath resolved_name;
157  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL));
158
159  char read_contents[arraysize(kFileContents2)];
160  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
161  EXPECT_STREQ(kFileContents2, read_contents);
162}
163
164TEST_F(ShortcutTest, UpdateShortcutMakeDualMode) {
165  ASSERT_TRUE(CreateOrUpdateShortcutLink(
166      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
167
168  ShortcutProperties make_dual_mode_properties;
169  make_dual_mode_properties.set_dual_mode(true);
170
171  ASSERT_TRUE(CreateOrUpdateShortcutLink(
172      link_file_, make_dual_mode_properties,
173      SHORTCUT_UPDATE_EXISTING));
174
175  ShortcutProperties expected_properties = link_properties_;
176  expected_properties.set_dual_mode(true);
177  ValidateShortcut(link_file_, expected_properties);
178}
179
180TEST_F(ShortcutTest, UpdateShortcutRemoveDualMode) {
181  ASSERT_TRUE(CreateOrUpdateShortcutLink(
182      link_file_, link_properties_2_, SHORTCUT_CREATE_ALWAYS));
183
184  ShortcutProperties remove_dual_mode_properties;
185  remove_dual_mode_properties.set_dual_mode(false);
186
187  ASSERT_TRUE(CreateOrUpdateShortcutLink(
188      link_file_, remove_dual_mode_properties,
189      SHORTCUT_UPDATE_EXISTING));
190
191  ShortcutProperties expected_properties = link_properties_2_;
192  expected_properties.set_dual_mode(false);
193  ValidateShortcut(link_file_, expected_properties);
194}
195
196TEST_F(ShortcutTest, UpdateShortcutClearArguments) {
197  ASSERT_TRUE(CreateOrUpdateShortcutLink(
198      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
199
200  ShortcutProperties clear_arguments_properties;
201  clear_arguments_properties.set_arguments(string16());
202
203  ASSERT_TRUE(CreateOrUpdateShortcutLink(
204      link_file_, clear_arguments_properties,
205      SHORTCUT_UPDATE_EXISTING));
206
207  ShortcutProperties expected_properties = link_properties_;
208  expected_properties.set_arguments(string16());
209  ValidateShortcut(link_file_, expected_properties);
210}
211
212TEST_F(ShortcutTest, FailUpdateShortcutThatDoesNotExist) {
213  ASSERT_FALSE(CreateOrUpdateShortcutLink(
214      link_file_, link_properties_, SHORTCUT_UPDATE_EXISTING));
215  ASSERT_FALSE(PathExists(link_file_));
216}
217
218TEST_F(ShortcutTest, ReplaceShortcutAllProperties) {
219  ASSERT_TRUE(CreateOrUpdateShortcutLink(
220      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
221
222  ASSERT_TRUE(CreateOrUpdateShortcutLink(
223      link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING));
224
225  ValidateShortcut(link_file_, link_properties_2_);
226}
227
228TEST_F(ShortcutTest, ReplaceShortcutSomeProperties) {
229  ASSERT_TRUE(CreateOrUpdateShortcutLink(
230      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
231
232  ShortcutProperties new_properties;
233  new_properties.set_target(link_properties_2_.target);
234  new_properties.set_arguments(link_properties_2_.arguments);
235  new_properties.set_description(link_properties_2_.description);
236  ASSERT_TRUE(CreateOrUpdateShortcutLink(
237      link_file_, new_properties, SHORTCUT_REPLACE_EXISTING));
238
239  // Expect only properties in |new_properties| to be set, all other properties
240  // should have been overwritten.
241  ShortcutProperties expected_properties(new_properties);
242  expected_properties.set_working_dir(FilePath());
243  expected_properties.set_icon(FilePath(), 0);
244  expected_properties.set_app_id(string16());
245  expected_properties.set_dual_mode(false);
246  ValidateShortcut(link_file_, expected_properties);
247}
248
249TEST_F(ShortcutTest, FailReplaceShortcutThatDoesNotExist) {
250  ASSERT_FALSE(CreateOrUpdateShortcutLink(
251      link_file_, link_properties_, SHORTCUT_REPLACE_EXISTING));
252  ASSERT_FALSE(PathExists(link_file_));
253}
254
255// Test that the old arguments remain on the replaced shortcut when not
256// otherwise specified.
257TEST_F(ShortcutTest, ReplaceShortcutKeepOldArguments) {
258  ASSERT_TRUE(CreateOrUpdateShortcutLink(
259      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
260
261  // Do not explicitly set the arguments.
262  link_properties_2_.options &=
263      ~ShortcutProperties::PROPERTIES_ARGUMENTS;
264  ASSERT_TRUE(CreateOrUpdateShortcutLink(
265      link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING));
266
267  ShortcutProperties expected_properties(link_properties_2_);
268  expected_properties.set_arguments(link_properties_.arguments);
269  ValidateShortcut(link_file_, expected_properties);
270}
271
272}  // namespace win
273}  // namespace base
274