15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/command.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CommandTest : public testing::Test {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)typedef const struct {
1803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bool expected_result;
1903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ui::Accelerator accelerator;
2003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const char* command_name;
2103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const char* key;
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const char* description;
2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} ConstCommandsTestData;
2403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Checks the |suggested_key| value parses into a command when specified as a
2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// string or dictionary of platform specific keys. If
2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// |platform_specific_only| is true, only the latter is tested. |platforms|
2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// specifies all platforms to use when populating the |suggested_key|
2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// dictionary.
3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CheckParse(ConstCommandsTestData data,
3103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                int i,
3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                bool platform_specific_only,
3303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                std::vector<std::string>& platforms) {
3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  SCOPED_TRACE(std::string("Command name: |") + data.command_name + "| key: |" +
3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)               data.key + "| description: |" + data.description + "| index: " +
3603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)               base::IntToString(i));
3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  extensions::Command command;
3903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> input(new base::DictionaryValue);
4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  base::string16 error;
4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // First, test the parse of a string suggested_key value.
4303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  input->SetString("suggested_key", data.key);
4403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  input->SetString("description", data.description);
4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!platform_specific_only) {
4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool result = command.Parse(input.get(), data.command_name, i, &error);
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    EXPECT_EQ(data.expected_result, result);
4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (result) {
5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      EXPECT_STREQ(data.description,
5103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                   base::UTF16ToASCII(command.description()).c_str());
5203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      EXPECT_STREQ(data.command_name, command.command_name().c_str());
5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      EXPECT_EQ(data.accelerator, command.accelerator());
5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
5503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
5603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
5703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Now, test the parse of a platform dictionary suggested_key value.
5803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (data.key[0] != '\0') {
5903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    std::string current_platform = extensions::Command::CommandPlatform();
6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (platform_specific_only &&
6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        std::find(platforms.begin(), platforms.end(), current_platform) ==
6203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            platforms.end()) {
6303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Given a |current_platform| without a |suggested_key|, |default| is
6403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // used. However, some keys, such as Search on Chrome OS, are only valid
6503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // for platform specific entries. Skip the test in this case.
6603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
6703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
6803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
6903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    input.reset(new base::DictionaryValue);
7003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    base::DictionaryValue* key_dict = new base::DictionaryValue();
7103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
7203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    for (size_t j = 0; j < platforms.size(); ++j)
7303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      key_dict->SetString(platforms[j], data.key);
7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
7503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    input->Set("suggested_key", key_dict);
7603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    input->SetString("description", data.description);
7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
7803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool result = command.Parse(input.get(), data.command_name, i, &error);
7903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    EXPECT_EQ(data.expected_result, result);
8003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (result) {
8203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      EXPECT_STREQ(data.description,
8303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                   base::UTF16ToASCII(command.description()).c_str());
8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      EXPECT_STREQ(data.command_name, command.command_name().c_str());
8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      EXPECT_EQ(data.accelerator, command.accelerator());
8603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
8903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(CommandTest, ExtensionCommandParsing) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ui::Accelerator none = ui::Accelerator();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ui::Accelerator shift_f = ui::Accelerator(ui::VKEY_F,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  ui::EF_SHIFT_DOWN);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int ctrl = ui::EF_COMMAND_DOWN;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int ctrl = ui::EF_CONTROL_DOWN;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ui::Accelerator ctrl_f = ui::Accelerator(ui::VKEY_F, ctrl);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ui::Accelerator alt_f = ui::Accelerator(ui::VKEY_F, ui::EF_ALT_DOWN);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ui::Accelerator ctrl_shift_f =
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::Accelerator(ui::VKEY_F, ctrl | ui::EF_SHIFT_DOWN);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ui::Accelerator alt_shift_f =
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::Accelerator(ui::VKEY_F, ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ui::Accelerator ctrl_1 = ui::Accelerator(ui::VKEY_1, ctrl);
107a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_comma = ui::Accelerator(ui::VKEY_OEM_COMMA, ctrl);
108a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_dot = ui::Accelerator(ui::VKEY_OEM_PERIOD, ctrl);
109a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_left = ui::Accelerator(ui::VKEY_LEFT, ctrl);
110a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_right = ui::Accelerator(ui::VKEY_RIGHT, ctrl);
111a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_up = ui::Accelerator(ui::VKEY_UP, ctrl);
112a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_down = ui::Accelerator(ui::VKEY_DOWN, ctrl);
113a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_ins = ui::Accelerator(ui::VKEY_INSERT, ctrl);
114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_del = ui::Accelerator(ui::VKEY_DELETE, ctrl);
115a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_home = ui::Accelerator(ui::VKEY_HOME, ctrl);
116a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_end = ui::Accelerator(ui::VKEY_END, ctrl);
117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_pgup = ui::Accelerator(ui::VKEY_PRIOR, ctrl);
118a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const ui::Accelerator ctrl_pgdwn = ui::Accelerator(ui::VKEY_NEXT, ctrl);
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const ui::Accelerator next_track =
12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE);
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const ui::Accelerator prev_track =
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      ui::Accelerator(ui::VKEY_MEDIA_PREV_TRACK, ui::EF_NONE);
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const ui::Accelerator play_pause =
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, ui::EF_NONE);
12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const ui::Accelerator stop =
12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      ui::Accelerator(ui::VKEY_MEDIA_STOP, ui::EF_NONE);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ConstCommandsTestData kTests[] = {
12903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Negative test (one or more missing required fields). We don't need to
13003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // test |command_name| being blank as it is used as a key in the manifest,
13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // so it can't be blank (and we CHECK() when it is). A blank shortcut is
13203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // permitted.
13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, none, "command", "", ""},
13403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, none, "command", "Ctrl+f", ""},
13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Ctrl+Alt is not permitted, see MSDN link in comments in Parse function.
13603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, none, "command", "Ctrl+Alt+F", "description"},
13703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Unsupported shortcuts/too many, or missing modifier.
13803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, none, "command", "A", "description"},
13903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, none, "command", "F10", "description"},
14003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, none, "command", "Ctrl+F+G", "description"},
14103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, none, "command", "Ctrl+Alt+Shift+G", "description"},
14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Shift on its own is not supported.
14303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, shift_f, "command", "Shift+F", "description"},
14403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, shift_f, "command", "F+Shift", "description"},
14503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Basic tests.
14603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, none, "command", "", "description"},
14703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_f, "command", "Ctrl+F", "description"},
14803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, alt_f, "command", "Alt+F", "description"},
14903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_shift_f, "command", "Ctrl+Shift+F", "description"},
15003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, alt_shift_f, "command", "Alt+Shift+F", "description"},
15103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_1, "command", "Ctrl+1", "description"},
15203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Shortcut token order tests.
15303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_f, "command", "F+Ctrl", "description"},
15403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, alt_f, "command", "F+Alt", "description"},
15503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_shift_f, "command", "F+Ctrl+Shift", "description"},
15603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_shift_f, "command", "F+Shift+Ctrl", "description"},
15703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, alt_shift_f, "command", "F+Alt+Shift", "description"},
15803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, alt_shift_f, "command", "F+Shift+Alt", "description"},
15903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Case insensitivity is not OK.
16003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, ctrl_f, "command", "Ctrl+f", "description"},
16103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, ctrl_f, "command", "cTrL+F", "description"},
16203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Skipping description is OK for browser- and pageActions.
16303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_f, "_execute_browser_action", "Ctrl+F", ""},
16403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_f, "_execute_page_action", "Ctrl+F", ""},
16503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Home, End, Arrow keys, etc.
16603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_comma, "_execute_browser_action", "Ctrl+Comma", ""},
16703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_dot, "_execute_browser_action", "Ctrl+Period", ""},
16803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_left, "_execute_browser_action", "Ctrl+Left", ""},
16903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_right, "_execute_browser_action", "Ctrl+Right", ""},
17003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_up, "_execute_browser_action", "Ctrl+Up", ""},
17103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_down, "_execute_browser_action", "Ctrl+Down", ""},
17203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_ins, "_execute_browser_action", "Ctrl+Insert", ""},
17303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_del, "_execute_browser_action", "Ctrl+Delete", ""},
17403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_home, "_execute_browser_action", "Ctrl+Home", ""},
17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_end, "_execute_browser_action", "Ctrl+End", ""},
17603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_pgup, "_execute_browser_action", "Ctrl+PageUp", ""},
17703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, ctrl_pgdwn, "_execute_browser_action", "Ctrl+PageDown", ""},
17803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Media keys.
17903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, next_track, "command", "MediaNextTrack", "description"},
18003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, play_pause, "command", "MediaPlayPause", "description"},
18103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, prev_track, "command", "MediaPrevTrack", "description"},
18203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, stop, "command", "MediaStop", "description"},
18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, none, "_execute_browser_action", "MediaNextTrack", ""},
18403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, none, "_execute_page_action", "MediaPrevTrack", ""},
18503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, none, "command", "Ctrl+Shift+MediaPrevTrack", "description"},
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
18703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::vector<std::string> all_platforms;
18803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  all_platforms.push_back("default");
18903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  all_platforms.push_back("chromeos");
19003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  all_platforms.push_back("linux");
19103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  all_platforms.push_back("mac");
19203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  all_platforms.push_back("windows");
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i)
19503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    CheckParse(kTests[i], i, false, all_platforms);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(CommandTest, ExtensionCommandParsingFallback) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string description = "desc";
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string command_name = "foo";
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test that platform specific keys are honored on each platform, despite
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // fallback being given.
2047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> input(new base::DictionaryValue);
2057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::DictionaryValue* key_dict = new base::DictionaryValue();
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_dict->SetString("default",  "Ctrl+Shift+D");
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_dict->SetString("windows",  "Ctrl+Shift+W");
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_dict->SetString("mac",      "Ctrl+Shift+M");
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_dict->SetString("linux",    "Ctrl+Shift+L");
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_dict->SetString("chromeos", "Ctrl+Shift+C");
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  input->Set("suggested_key", key_dict);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  input->SetString("description", description);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extensions::Command command;
215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 error;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(command.Parse(input.get(), command_name, 0, &error));
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_STREQ(description.c_str(),
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               base::UTF16ToASCII(command.description()).c_str());
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_STREQ(command_name.c_str(), command.command_name().c_str());
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::Accelerator accelerator(ui::VKEY_W,
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_MACOSX)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::Accelerator accelerator(ui::VKEY_M,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              ui::EF_SHIFT_DOWN | ui::EF_COMMAND_DOWN);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_CHROMEOS)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::Accelerator accelerator(ui::VKEY_C,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_LINUX)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::Accelerator accelerator(ui::VKEY_L,
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::Accelerator accelerator(ui::VKEY_D,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(accelerator, command.accelerator());
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Misspell a platform.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_dict->SetString("windosw", "Ctrl+M");
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(key_dict->Remove("windosw", NULL));
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now remove platform specific keys (leaving just "default") and make sure
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // every platform falls back to the default.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(key_dict->Remove("windows", NULL));
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(key_dict->Remove("mac", NULL));
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(key_dict->Remove("linux", NULL));
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(key_dict->Remove("chromeos", NULL));
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(command.Parse(input.get(), command_name, 0, &error));
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(ui::VKEY_D, command.accelerator().key_code());
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now remove "default", leaving no option but failure. Or, in the words of
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the immortal Adam Savage: "Failure is always an option".
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(key_dict->Remove("default", NULL));
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure Command is not supported for non-Mac platforms.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_dict->SetString("default", "Command+M");
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(key_dict->Remove("default", NULL));
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_dict->SetString("windows", "Command+M");
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(key_dict->Remove("windows", NULL));
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now add only a valid platform that we are not running on to make sure devs
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are notified of errors on other platforms.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_dict->SetString("mac", "Ctrl+Shift+M");
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_dict->SetString("windows", "Ctrl+Shift+W");
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure Mac specific keys are not processed on other platforms.
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_dict->SetString("windows", "Command+Shift+M");
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
28103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
28203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)TEST(CommandTest, ExtensionCommandParsingPlatformSpecific) {
28303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ui::Accelerator search_a(ui::VKEY_A, ui::EF_COMMAND_DOWN);
28403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ui::Accelerator search_shift_z(ui::VKEY_Z,
28503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                 ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN);
28603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
28703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ConstCommandsTestData kChromeOsTests[] = {
28803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, search_shift_z, "command", "Search+Shift+Z", "description"},
28903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {true, search_a, "command", "Search+A", "description"},
29003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Command is not valid on Chrome OS.
29103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, search_shift_z, "command", "Command+Shift+Z", "description"},
29203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
29303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
29403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::vector<std::string> chromeos;
29503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  chromeos.push_back("chromeos");
29603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kChromeOsTests); ++i)
29703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    CheckParse(kChromeOsTests[i], i, true, chromeos);
29803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
29903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ConstCommandsTestData kNonChromeOsSearchTests[] = {
30003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      {false, search_shift_z, "command", "Search+Shift+Z", "description"},
30103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
30203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::vector<std::string> non_chromeos;
30303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  non_chromeos.push_back("default");
30403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  non_chromeos.push_back("windows");
30503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  non_chromeos.push_back("mac");
30603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  non_chromeos.push_back("linux");
30703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
30803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kNonChromeOsSearchTests); ++i)
30903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    CheckParse(kNonChromeOsSearchTests[i], i, true, non_chromeos);
31003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
311