Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / common / extensions / command_unittest.cc
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 "chrome/common/extensions/command.h"
6
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 class CommandTest : public testing::Test {
15 };
16
17 typedef const struct {
18   bool expected_result;
19   ui::Accelerator accelerator;
20   const char* command_name;
21   const char* key;
22   const char* description;
23 } ConstCommandsTestData;
24
25 // Checks the |suggested_key| value parses into a command when specified as a
26 // string or dictionary of platform specific keys. If
27 // |platform_specific_only| is true, only the latter is tested. |platforms|
28 // specifies all platforms to use when populating the |suggested_key|
29 // dictionary.
30 void CheckParse(ConstCommandsTestData data,
31                 int i,
32                 bool platform_specific_only,
33                 std::vector<std::string>& platforms) {
34   SCOPED_TRACE(std::string("Command name: |") + data.command_name + "| key: |" +
35                data.key + "| description: |" + data.description + "| index: " +
36                base::IntToString(i));
37
38   extensions::Command command;
39   scoped_ptr<base::DictionaryValue> input(new base::DictionaryValue);
40   base::string16 error;
41
42   // First, test the parse of a string suggested_key value.
43   input->SetString("suggested_key", data.key);
44   input->SetString("description", data.description);
45
46   if (!platform_specific_only) {
47     bool result = command.Parse(input.get(), data.command_name, i, &error);
48     EXPECT_EQ(data.expected_result, result);
49     if (result) {
50       EXPECT_STREQ(data.description,
51                    base::UTF16ToASCII(command.description()).c_str());
52       EXPECT_STREQ(data.command_name, command.command_name().c_str());
53       EXPECT_EQ(data.accelerator, command.accelerator());
54     }
55   }
56
57   // Now, test the parse of a platform dictionary suggested_key value.
58   if (data.key[0] != '\0') {
59     std::string current_platform = extensions::Command::CommandPlatform();
60     if (platform_specific_only &&
61         std::find(platforms.begin(), platforms.end(), current_platform) ==
62             platforms.end()) {
63       // Given a |current_platform| without a |suggested_key|, |default| is
64       // used. However, some keys, such as Search on Chrome OS, are only valid
65       // for platform specific entries. Skip the test in this case.
66       return;
67     }
68
69     input.reset(new base::DictionaryValue);
70     base::DictionaryValue* key_dict = new base::DictionaryValue();
71
72     for (size_t j = 0; j < platforms.size(); ++j)
73       key_dict->SetString(platforms[j], data.key);
74
75     input->Set("suggested_key", key_dict);
76     input->SetString("description", data.description);
77
78     bool result = command.Parse(input.get(), data.command_name, i, &error);
79     EXPECT_EQ(data.expected_result, result);
80
81     if (result) {
82       EXPECT_STREQ(data.description,
83                    base::UTF16ToASCII(command.description()).c_str());
84       EXPECT_STREQ(data.command_name, command.command_name().c_str());
85       EXPECT_EQ(data.accelerator, command.accelerator());
86     }
87   }
88 }
89
90 TEST(CommandTest, ExtensionCommandParsing) {
91   const ui::Accelerator none = ui::Accelerator();
92   const ui::Accelerator shift_f = ui::Accelerator(ui::VKEY_F,
93                                                   ui::EF_SHIFT_DOWN);
94 #if defined(OS_MACOSX)
95   int ctrl = ui::EF_COMMAND_DOWN;
96 #else
97   int ctrl = ui::EF_CONTROL_DOWN;
98 #endif
99
100   const ui::Accelerator ctrl_f = ui::Accelerator(ui::VKEY_F, ctrl);
101   const ui::Accelerator alt_f = ui::Accelerator(ui::VKEY_F, ui::EF_ALT_DOWN);
102   const ui::Accelerator ctrl_shift_f =
103       ui::Accelerator(ui::VKEY_F, ctrl | ui::EF_SHIFT_DOWN);
104   const ui::Accelerator alt_shift_f =
105       ui::Accelerator(ui::VKEY_F, ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
106   const ui::Accelerator ctrl_1 = ui::Accelerator(ui::VKEY_1, ctrl);
107   const ui::Accelerator ctrl_comma = ui::Accelerator(ui::VKEY_OEM_COMMA, ctrl);
108   const ui::Accelerator ctrl_dot = ui::Accelerator(ui::VKEY_OEM_PERIOD, ctrl);
109   const ui::Accelerator ctrl_left = ui::Accelerator(ui::VKEY_LEFT, ctrl);
110   const ui::Accelerator ctrl_right = ui::Accelerator(ui::VKEY_RIGHT, ctrl);
111   const ui::Accelerator ctrl_up = ui::Accelerator(ui::VKEY_UP, ctrl);
112   const ui::Accelerator ctrl_down = ui::Accelerator(ui::VKEY_DOWN, ctrl);
113   const ui::Accelerator ctrl_ins = ui::Accelerator(ui::VKEY_INSERT, ctrl);
114   const ui::Accelerator ctrl_del = ui::Accelerator(ui::VKEY_DELETE, ctrl);
115   const ui::Accelerator ctrl_home = ui::Accelerator(ui::VKEY_HOME, ctrl);
116   const ui::Accelerator ctrl_end = ui::Accelerator(ui::VKEY_END, ctrl);
117   const ui::Accelerator ctrl_pgup = ui::Accelerator(ui::VKEY_PRIOR, ctrl);
118   const ui::Accelerator ctrl_pgdwn = ui::Accelerator(ui::VKEY_NEXT, ctrl);
119   const ui::Accelerator next_track =
120       ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE);
121   const ui::Accelerator prev_track =
122       ui::Accelerator(ui::VKEY_MEDIA_PREV_TRACK, ui::EF_NONE);
123   const ui::Accelerator play_pause =
124       ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, ui::EF_NONE);
125   const ui::Accelerator stop =
126       ui::Accelerator(ui::VKEY_MEDIA_STOP, ui::EF_NONE);
127
128   ConstCommandsTestData kTests[] = {
129       // Negative test (one or more missing required fields). We don't need to
130       // test |command_name| being blank as it is used as a key in the manifest,
131       // so it can't be blank (and we CHECK() when it is). A blank shortcut is
132       // permitted.
133       {false, none, "command", "", ""},
134       {false, none, "command", "Ctrl+f", ""},
135       // Ctrl+Alt is not permitted, see MSDN link in comments in Parse function.
136       {false, none, "command", "Ctrl+Alt+F", "description"},
137       // Unsupported shortcuts/too many, or missing modifier.
138       {false, none, "command", "A", "description"},
139       {false, none, "command", "F10", "description"},
140       {false, none, "command", "Ctrl+F+G", "description"},
141       {false, none, "command", "Ctrl+Alt+Shift+G", "description"},
142       // Shift on its own is not supported.
143       {false, shift_f, "command", "Shift+F", "description"},
144       {false, shift_f, "command", "F+Shift", "description"},
145       // Basic tests.
146       {true, none, "command", "", "description"},
147       {true, ctrl_f, "command", "Ctrl+F", "description"},
148       {true, alt_f, "command", "Alt+F", "description"},
149       {true, ctrl_shift_f, "command", "Ctrl+Shift+F", "description"},
150       {true, alt_shift_f, "command", "Alt+Shift+F", "description"},
151       {true, ctrl_1, "command", "Ctrl+1", "description"},
152       // Shortcut token order tests.
153       {true, ctrl_f, "command", "F+Ctrl", "description"},
154       {true, alt_f, "command", "F+Alt", "description"},
155       {true, ctrl_shift_f, "command", "F+Ctrl+Shift", "description"},
156       {true, ctrl_shift_f, "command", "F+Shift+Ctrl", "description"},
157       {true, alt_shift_f, "command", "F+Alt+Shift", "description"},
158       {true, alt_shift_f, "command", "F+Shift+Alt", "description"},
159       // Case insensitivity is not OK.
160       {false, ctrl_f, "command", "Ctrl+f", "description"},
161       {false, ctrl_f, "command", "cTrL+F", "description"},
162       // Skipping description is OK for browser- and pageActions.
163       {true, ctrl_f, "_execute_browser_action", "Ctrl+F", ""},
164       {true, ctrl_f, "_execute_page_action", "Ctrl+F", ""},
165       // Home, End, Arrow keys, etc.
166       {true, ctrl_comma, "_execute_browser_action", "Ctrl+Comma", ""},
167       {true, ctrl_dot, "_execute_browser_action", "Ctrl+Period", ""},
168       {true, ctrl_left, "_execute_browser_action", "Ctrl+Left", ""},
169       {true, ctrl_right, "_execute_browser_action", "Ctrl+Right", ""},
170       {true, ctrl_up, "_execute_browser_action", "Ctrl+Up", ""},
171       {true, ctrl_down, "_execute_browser_action", "Ctrl+Down", ""},
172       {true, ctrl_ins, "_execute_browser_action", "Ctrl+Insert", ""},
173       {true, ctrl_del, "_execute_browser_action", "Ctrl+Delete", ""},
174       {true, ctrl_home, "_execute_browser_action", "Ctrl+Home", ""},
175       {true, ctrl_end, "_execute_browser_action", "Ctrl+End", ""},
176       {true, ctrl_pgup, "_execute_browser_action", "Ctrl+PageUp", ""},
177       {true, ctrl_pgdwn, "_execute_browser_action", "Ctrl+PageDown", ""},
178       // Media keys.
179       {true, next_track, "command", "MediaNextTrack", "description"},
180       {true, play_pause, "command", "MediaPlayPause", "description"},
181       {true, prev_track, "command", "MediaPrevTrack", "description"},
182       {true, stop, "command", "MediaStop", "description"},
183       {false, none, "_execute_browser_action", "MediaNextTrack", ""},
184       {false, none, "_execute_page_action", "MediaPrevTrack", ""},
185       {false, none, "command", "Ctrl+Shift+MediaPrevTrack", "description"},
186   };
187   std::vector<std::string> all_platforms;
188   all_platforms.push_back("default");
189   all_platforms.push_back("chromeos");
190   all_platforms.push_back("linux");
191   all_platforms.push_back("mac");
192   all_platforms.push_back("windows");
193
194   for (size_t i = 0; i < arraysize(kTests); ++i)
195     CheckParse(kTests[i], i, false, all_platforms);
196 }
197
198 TEST(CommandTest, ExtensionCommandParsingFallback) {
199   std::string description = "desc";
200   std::string command_name = "foo";
201
202   // Test that platform specific keys are honored on each platform, despite
203   // fallback being given.
204   scoped_ptr<base::DictionaryValue> input(new base::DictionaryValue);
205   base::DictionaryValue* key_dict = new base::DictionaryValue();
206   key_dict->SetString("default",  "Ctrl+Shift+D");
207   key_dict->SetString("windows",  "Ctrl+Shift+W");
208   key_dict->SetString("mac",      "Ctrl+Shift+M");
209   key_dict->SetString("linux",    "Ctrl+Shift+L");
210   key_dict->SetString("chromeos", "Ctrl+Shift+C");
211   input->Set("suggested_key", key_dict);
212   input->SetString("description", description);
213
214   extensions::Command command;
215   base::string16 error;
216   EXPECT_TRUE(command.Parse(input.get(), command_name, 0, &error));
217   EXPECT_STREQ(description.c_str(),
218                base::UTF16ToASCII(command.description()).c_str());
219   EXPECT_STREQ(command_name.c_str(), command.command_name().c_str());
220
221 #if defined(OS_WIN)
222   ui::Accelerator accelerator(ui::VKEY_W,
223                               ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
224 #elif defined(OS_MACOSX)
225   ui::Accelerator accelerator(ui::VKEY_M,
226                               ui::EF_SHIFT_DOWN | ui::EF_COMMAND_DOWN);
227 #elif defined(OS_CHROMEOS)
228   ui::Accelerator accelerator(ui::VKEY_C,
229                               ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
230 #elif defined(OS_LINUX)
231   ui::Accelerator accelerator(ui::VKEY_L,
232                               ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
233 #else
234   ui::Accelerator accelerator(ui::VKEY_D,
235                               ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
236 #endif
237   EXPECT_EQ(accelerator, command.accelerator());
238
239   // Misspell a platform.
240   key_dict->SetString("windosw", "Ctrl+M");
241   EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
242   EXPECT_TRUE(key_dict->Remove("windosw", NULL));
243
244   // Now remove platform specific keys (leaving just "default") and make sure
245   // every platform falls back to the default.
246   EXPECT_TRUE(key_dict->Remove("windows", NULL));
247   EXPECT_TRUE(key_dict->Remove("mac", NULL));
248   EXPECT_TRUE(key_dict->Remove("linux", NULL));
249   EXPECT_TRUE(key_dict->Remove("chromeos", NULL));
250   EXPECT_TRUE(command.Parse(input.get(), command_name, 0, &error));
251   EXPECT_EQ(ui::VKEY_D, command.accelerator().key_code());
252
253   // Now remove "default", leaving no option but failure. Or, in the words of
254   // the immortal Adam Savage: "Failure is always an option".
255   EXPECT_TRUE(key_dict->Remove("default", NULL));
256   EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
257
258   // Make sure Command is not supported for non-Mac platforms.
259   key_dict->SetString("default", "Command+M");
260   EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
261   EXPECT_TRUE(key_dict->Remove("default", NULL));
262   key_dict->SetString("windows", "Command+M");
263   EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
264   EXPECT_TRUE(key_dict->Remove("windows", NULL));
265
266   // Now add only a valid platform that we are not running on to make sure devs
267   // are notified of errors on other platforms.
268 #if defined(OS_WIN)
269   key_dict->SetString("mac", "Ctrl+Shift+M");
270 #else
271   key_dict->SetString("windows", "Ctrl+Shift+W");
272 #endif
273   EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
274
275   // Make sure Mac specific keys are not processed on other platforms.
276 #if !defined(OS_MACOSX)
277   key_dict->SetString("windows", "Command+Shift+M");
278   EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
279 #endif
280 }
281
282 TEST(CommandTest, ExtensionCommandParsingPlatformSpecific) {
283   ui::Accelerator search_a(ui::VKEY_A, ui::EF_COMMAND_DOWN);
284   ui::Accelerator search_shift_z(ui::VKEY_Z,
285                                  ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN);
286
287   ConstCommandsTestData kChromeOsTests[] = {
288       {true, search_shift_z, "command", "Search+Shift+Z", "description"},
289       {true, search_a, "command", "Search+A", "description"},
290       // Command is not valid on Chrome OS.
291       {false, search_shift_z, "command", "Command+Shift+Z", "description"},
292   };
293
294   std::vector<std::string> chromeos;
295   chromeos.push_back("chromeos");
296   for (size_t i = 0; i < arraysize(kChromeOsTests); ++i)
297     CheckParse(kChromeOsTests[i], i, true, chromeos);
298
299   ConstCommandsTestData kNonChromeOsSearchTests[] = {
300       {false, search_shift_z, "command", "Search+Shift+Z", "description"},
301   };
302   std::vector<std::string> non_chromeos;
303   non_chromeos.push_back("default");
304   non_chromeos.push_back("windows");
305   non_chromeos.push_back("mac");
306   non_chromeos.push_back("linux");
307
308   for (size_t i = 0; i < arraysize(kNonChromeOsSearchTests); ++i)
309     CheckParse(kNonChromeOsSearchTests[i], i, true, non_chromeos);
310 }