1 // Copyright (c) 2013 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 <memory>
6 #include <utility>
7
8 #include "base/threading/thread_restrictions.h"
9 #include "base/values.h"
10 #include "build/build_config.h"
11 #include "chrome/browser/extensions/api/commands/command_service.h"
12 #include "chrome/browser/extensions/extension_apitest.h"
13 #include "chrome/common/pref_names.h"
14 #include "components/prefs/scoped_user_pref_update.h"
15 #include "content/public/test/browser_test.h"
16 #include "content/public/test/test_utils.h"
17 #include "extensions/browser/extension_registry.h"
18 #include "extensions/common/api/extension_action/action_info.h"
19 #include "extensions/common/manifest_constants.h"
20
21 namespace {
22 const char kBasicBrowserActionKeybinding[] = "Ctrl+Shift+F";
23 const char kBasicNamedKeybinding[] = "Ctrl+Shift+Y";
24 const char kBasicAlternateKeybinding[] = "Ctrl+Shift+G";
25 const char kBasicNamedCommand[] = "toggle-feature";
26
27 // Get another command platform, whcih is used for simulating a command has been
28 // assigned with a shortcut on another platform.
GetAnotherCommandPlatform()29 std::string GetAnotherCommandPlatform() {
30 #if defined(OS_WIN)
31 return extensions::manifest_values::kKeybindingPlatformMac;
32 #elif defined(OS_MAC)
33 return extensions::manifest_values::kKeybindingPlatformChromeOs;
34 #elif defined(OS_CHROMEOS)
35 return extensions::manifest_values::kKeybindingPlatformLinux;
36 #elif defined(OS_LINUX)
37 return extensions::manifest_values::kKeybindingPlatformWin;
38 #else
39 return "";
40 #endif
41 }
42
43 } // namespace
44
45 namespace extensions {
46
47 typedef ExtensionApiTest CommandServiceTest;
48
IN_PROC_BROWSER_TEST_F(CommandServiceTest,RemoveShortcutSurvivesUpdate)49 IN_PROC_BROWSER_TEST_F(CommandServiceTest, RemoveShortcutSurvivesUpdate) {
50 base::ScopedAllowBlockingForTesting allow_blocking;
51 base::ScopedTempDir scoped_temp_dir;
52 EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
53 base::FilePath pem_path = test_data_dir_.
54 AppendASCII("keybinding").AppendASCII("keybinding.pem");
55 base::FilePath path_v1 =
56 PackExtensionWithOptions(test_data_dir_.AppendASCII("keybinding")
57 .AppendASCII("update")
58 .AppendASCII("v1"),
59 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
60 pem_path, base::FilePath());
61 base::FilePath path_v2 =
62 PackExtensionWithOptions(test_data_dir_.AppendASCII("keybinding")
63 .AppendASCII("update")
64 .AppendASCII("v2"),
65 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
66 pem_path, base::FilePath());
67
68 ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile());
69 CommandService* command_service = CommandService::Get(browser()->profile());
70
71 const char kId[] = "pgoakhfeplldmjheffidklpoklkppipp";
72
73 // Install v1 of the extension.
74 ASSERT_TRUE(InstallExtension(path_v1, 1));
75 EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED));
76
77 // Verify it has a command of Alt+Shift+F.
78 ui::Accelerator accelerator = command_service->FindCommandByName(
79 kId, manifest_values::kBrowserActionCommandEvent).accelerator();
80 EXPECT_EQ(ui::VKEY_F, accelerator.key_code());
81 EXPECT_FALSE(accelerator.IsCtrlDown());
82 EXPECT_TRUE(accelerator.IsShiftDown());
83 EXPECT_TRUE(accelerator.IsAltDown());
84
85 // Remove the keybinding.
86 command_service->RemoveKeybindingPrefs(
87 kId, manifest_values::kBrowserActionCommandEvent);
88
89 // Verify it got removed.
90 accelerator = command_service->FindCommandByName(
91 kId, manifest_values::kBrowserActionCommandEvent).accelerator();
92 EXPECT_EQ(ui::VKEY_UNKNOWN, accelerator.key_code());
93
94 // Update to version 2.
95 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
96 EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED));
97
98 // Verify it is still set to nothing.
99 accelerator = command_service->FindCommandByName(
100 kId, manifest_values::kBrowserActionCommandEvent).accelerator();
101 EXPECT_EQ(ui::VKEY_UNKNOWN, accelerator.key_code());
102 }
103
IN_PROC_BROWSER_TEST_F(CommandServiceTest,RemoveKeybindingPrefsShouldBePlatformSpecific)104 IN_PROC_BROWSER_TEST_F(CommandServiceTest,
105 RemoveKeybindingPrefsShouldBePlatformSpecific) {
106 base::FilePath extension_dir =
107 test_data_dir_.AppendASCII("keybinding").AppendASCII("basics");
108 const Extension* extension = InstallExtension(extension_dir, 1);
109 ASSERT_TRUE(extension);
110
111 DictionaryPrefUpdate updater(browser()->profile()->GetPrefs(),
112 prefs::kExtensionCommands);
113 base::DictionaryValue* bindings = updater.Get();
114
115 // Simulate command |toggle-feature| has been assigned with a shortcut on
116 // another platform.
117 std::string anotherPlatformKey = GetAnotherCommandPlatform() + ":Alt+G";
118 const char kNamedCommandName[] = "toggle-feature";
119 auto keybinding = std::make_unique<base::DictionaryValue>();
120 keybinding->SetString("extension", extension->id());
121 keybinding->SetString("command_name", kNamedCommandName);
122 keybinding->SetBoolean("global", false);
123 bindings->Set(anotherPlatformKey, std::move(keybinding));
124
125 CommandService* command_service = CommandService::Get(browser()->profile());
126 command_service->RemoveKeybindingPrefs(extension->id(), kNamedCommandName);
127
128 // Removal of keybinding preference should be platform-specific, so the key on
129 // another platform should always remained.
130 EXPECT_TRUE(bindings->HasKey(anotherPlatformKey));
131 }
132
IN_PROC_BROWSER_TEST_F(CommandServiceTest,GetExtensionActionCommandQueryAll)133 IN_PROC_BROWSER_TEST_F(CommandServiceTest,
134 GetExtensionActionCommandQueryAll) {
135 base::FilePath extension_dir =
136 test_data_dir_.AppendASCII("keybinding").AppendASCII("basics");
137 const Extension* extension = InstallExtension(extension_dir, 1);
138 ASSERT_TRUE(extension);
139
140 CommandService* command_service = CommandService::Get(browser()->profile());
141
142 {
143 Command command;
144 bool active = false;
145 EXPECT_TRUE(command_service->GetExtensionActionCommand(
146 extension->id(), ActionInfo::TYPE_BROWSER, CommandService::ALL,
147 &command, &active));
148
149 EXPECT_EQ(kBasicBrowserActionKeybinding,
150 Command::AcceleratorToString(command.accelerator()));
151 EXPECT_TRUE(active);
152 }
153
154 command_service->UpdateKeybindingPrefs(
155 extension->id(), manifest_values::kBrowserActionCommandEvent,
156 kBasicAlternateKeybinding);
157
158 {
159 Command command;
160 bool active = false;
161 EXPECT_TRUE(command_service->GetExtensionActionCommand(
162 extension->id(), ActionInfo::TYPE_BROWSER, CommandService::ALL,
163 &command, &active));
164
165 EXPECT_EQ(kBasicAlternateKeybinding,
166 Command::AcceleratorToString(command.accelerator()));
167 EXPECT_TRUE(active);
168 }
169
170 command_service->RemoveKeybindingPrefs(
171 extension->id(), manifest_values::kBrowserActionCommandEvent);
172
173 {
174 Command command;
175 bool active = true;
176 EXPECT_TRUE(command_service->GetExtensionActionCommand(
177 extension->id(), ActionInfo::TYPE_BROWSER, CommandService::ALL,
178 &command, &active));
179
180 EXPECT_EQ(kBasicBrowserActionKeybinding,
181 Command::AcceleratorToString(command.accelerator()));
182 EXPECT_FALSE(active);
183 }
184 }
185
IN_PROC_BROWSER_TEST_F(CommandServiceTest,GetExtensionActionCommandQueryActive)186 IN_PROC_BROWSER_TEST_F(CommandServiceTest,
187 GetExtensionActionCommandQueryActive) {
188 base::FilePath extension_dir =
189 test_data_dir_.AppendASCII("keybinding").AppendASCII("basics");
190 const Extension* extension = InstallExtension(extension_dir, 1);
191 ASSERT_TRUE(extension);
192
193 CommandService* command_service = CommandService::Get(browser()->profile());
194
195 {
196 Command command;
197 bool active = false;
198 EXPECT_TRUE(command_service->GetExtensionActionCommand(
199 extension->id(), ActionInfo::TYPE_BROWSER, CommandService::ACTIVE,
200 &command, &active));
201
202 EXPECT_EQ(kBasicBrowserActionKeybinding,
203 Command::AcceleratorToString(command.accelerator()));
204 EXPECT_TRUE(active);
205 }
206
207 command_service->UpdateKeybindingPrefs(
208 extension->id(), manifest_values::kBrowserActionCommandEvent,
209 kBasicAlternateKeybinding);
210
211 {
212 Command command;
213 bool active = false;
214 EXPECT_TRUE(command_service->GetExtensionActionCommand(
215 extension->id(), ActionInfo::TYPE_BROWSER, CommandService::ACTIVE,
216 &command, &active));
217
218 EXPECT_EQ(kBasicAlternateKeybinding,
219 Command::AcceleratorToString(command.accelerator()));
220 EXPECT_TRUE(active);
221 }
222
223 command_service->RemoveKeybindingPrefs(
224 extension->id(), manifest_values::kBrowserActionCommandEvent);
225
226 {
227 Command command;
228 bool active = false;
229 EXPECT_FALSE(command_service->GetExtensionActionCommand(
230 extension->id(), ActionInfo::TYPE_BROWSER, CommandService::ACTIVE,
231 &command, &active));
232 }
233 }
234
IN_PROC_BROWSER_TEST_F(CommandServiceTest,GetNamedCommandsQueryAll)235 IN_PROC_BROWSER_TEST_F(CommandServiceTest,
236 GetNamedCommandsQueryAll) {
237 base::FilePath extension_dir =
238 test_data_dir_.AppendASCII("keybinding").AppendASCII("basics");
239 const Extension* extension = InstallExtension(extension_dir, 1);
240 ASSERT_TRUE(extension);
241
242 CommandService* command_service = CommandService::Get(browser()->profile());
243
244 {
245 CommandMap command_map;
246 EXPECT_TRUE(command_service->GetNamedCommands(
247 extension->id(), CommandService::ALL, CommandService::ANY_SCOPE,
248 &command_map));
249
250 ASSERT_EQ(1u, command_map.count(kBasicNamedCommand));
251 Command command = command_map[kBasicNamedCommand];
252 EXPECT_EQ(kBasicNamedKeybinding,
253 Command::AcceleratorToString(command.accelerator()));
254 }
255
256 command_service->UpdateKeybindingPrefs(
257 extension->id(), kBasicNamedCommand, kBasicAlternateKeybinding);
258
259 {
260 CommandMap command_map;
261 EXPECT_TRUE(command_service->GetNamedCommands(
262 extension->id(), CommandService::ALL, CommandService::ANY_SCOPE,
263 &command_map));
264
265 ASSERT_EQ(1u, command_map.count(kBasicNamedCommand));
266 Command command = command_map[kBasicNamedCommand];
267 EXPECT_EQ(kBasicAlternateKeybinding,
268 Command::AcceleratorToString(command.accelerator()));
269 }
270
271 command_service->RemoveKeybindingPrefs(extension->id(), kBasicNamedCommand);
272
273 {
274 CommandMap command_map;
275 EXPECT_TRUE(command_service->GetNamedCommands(
276 extension->id(), CommandService::ALL, CommandService::ANY_SCOPE,
277 &command_map));
278
279 ASSERT_EQ(1u, command_map.count(kBasicNamedCommand));
280 Command command = command_map[kBasicNamedCommand];
281 EXPECT_EQ(kBasicNamedKeybinding,
282 Command::AcceleratorToString(command.accelerator()));
283 }
284 }
285
IN_PROC_BROWSER_TEST_F(CommandServiceTest,GetNamedCommandsQueryActive)286 IN_PROC_BROWSER_TEST_F(CommandServiceTest, GetNamedCommandsQueryActive) {
287 base::FilePath extension_dir =
288 test_data_dir_.AppendASCII("keybinding").AppendASCII("basics");
289 const Extension* extension = InstallExtension(extension_dir, 1);
290 ASSERT_TRUE(extension);
291
292 CommandService* command_service = CommandService::Get(browser()->profile());
293
294 {
295 CommandMap command_map;
296 EXPECT_TRUE(command_service->GetNamedCommands(
297 extension->id(), CommandService::ACTIVE, CommandService::ANY_SCOPE,
298 &command_map));
299
300 ASSERT_EQ(1u, command_map.count(kBasicNamedCommand));
301 Command command = command_map[kBasicNamedCommand];
302 EXPECT_EQ(kBasicNamedKeybinding,
303 Command::AcceleratorToString(command.accelerator()));
304 }
305
306 command_service->UpdateKeybindingPrefs(
307 extension->id(), kBasicNamedCommand, kBasicAlternateKeybinding);
308
309 {
310 CommandMap command_map;
311 EXPECT_TRUE(command_service->GetNamedCommands(
312 extension->id(), CommandService::ACTIVE, CommandService::ANY_SCOPE,
313 &command_map));
314
315 ASSERT_EQ(1u, command_map.count(kBasicNamedCommand));
316 Command command = command_map[kBasicNamedCommand];
317 EXPECT_EQ(kBasicAlternateKeybinding,
318 Command::AcceleratorToString(command.accelerator()));
319 }
320
321 command_service->RemoveKeybindingPrefs(extension->id(), kBasicNamedCommand);
322
323 {
324 CommandMap command_map;
325 command_service->GetNamedCommands(
326 extension->id(), CommandService::ACTIVE, CommandService::ANY_SCOPE,
327 &command_map);
328 EXPECT_EQ(0u, command_map.count(kBasicNamedCommand));
329 }
330 }
331
332 } // namespace extensions
333