blob: ce3f2772f7a133d54f7487509c0c9e83213444d5 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <Cocoa/Cocoa.h>
#include "base/logging.h"
#import "chrome/browser/ui/cocoa/accelerators_cocoa.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
#include "testing/gtest_mac.h"
typedef InProcessBrowserTest AcceleratorsCocoaBrowserTest;
namespace {
// Adds all NSMenuItems with an accelerator to the array.
void AddAcceleratorItemsToArray(NSMenu* menu, NSMutableArray* array) {
for (NSMenuItem* item in [menu itemArray]) {
NSMenu* submenu = item.submenu;
if (submenu)
AddAcceleratorItemsToArray(submenu, array);
if (item.keyEquivalent.length > 0)
[array addObject:item];
}
}
// Returns the NSMenuItem that has the given keyEquivalent and modifiers, or
// nil.
NSMenuItem* MenuContainsAccelerator(NSMenu* menu,
NSString* key_equivalent,
NSUInteger modifiers) {
for (NSMenuItem* item in [menu itemArray]) {
NSMenu* submenu = item.submenu;
if (submenu) {
NSMenuItem* result =
MenuContainsAccelerator(submenu, key_equivalent, modifiers);
if (result)
return result;
}
if ([item.keyEquivalent isEqual:key_equivalent]) {
BOOL maskEqual =
(modifiers == item.keyEquivalentModifierMask) ||
((modifiers & (~NSShiftKeyMask)) == item.keyEquivalentModifierMask);
if (maskEqual)
return item;
}
}
return nil;
}
} // namespace
// Checks that each NSMenuItem in the main menu has a corresponding accelerator,
// and the keyEquivalent/modifiers match.
IN_PROC_BROWSER_TEST_F(AcceleratorsCocoaBrowserTest,
MainMenuAcceleratorsInMapping) {
NSMenu* menu = [NSApp mainMenu];
NSMutableArray* array = [NSMutableArray array];
AddAcceleratorItemsToArray(menu, array);
for (NSMenuItem* item in array) {
NSInteger command_id = item.tag;
AcceleratorsCocoa* keymap = AcceleratorsCocoa::GetInstance();
const ui::Accelerator* accelerator;
// If the tag is zero, then the NSMenuItem must use a custom selector.
// Check that the accelerator is present as an un-mapped accelerator.
if (command_id == 0) {
accelerator = keymap->GetAcceleratorForHotKey(
item.keyEquivalent, item.keyEquivalentModifierMask);
EXPECT_TRUE(accelerator);
return;
}
// If the tag isn't zero, then it must correspond to an IDC_* command.
accelerator = keymap->GetAcceleratorForCommand(command_id);
EXPECT_TRUE(accelerator);
if (!accelerator)
continue;
// Get the Cocoa key_equivalent associated with the accelerator.
const ui::PlatformAcceleratorCocoa* platform_accelerator =
static_cast<const ui::PlatformAcceleratorCocoa*>(
accelerator->platform_accelerator());
NSString* key_equivalent = platform_accelerator->characters();
// Check that the menu item's keyEquivalent matches the one from the
// Cocoa accelerator map.
EXPECT_NSEQ(key_equivalent, item.keyEquivalent);
// Check that the menu item's modifier mask matches the one stored in the
// accelerator. A mask that include NSShiftKeyMask may not include the
// relevant bit (the information is reflected in the keyEquivalent of the
// NSMenuItem).
NSUInteger mask = platform_accelerator->modifier_mask();
BOOL maskEqual =
(mask == item.keyEquivalentModifierMask) ||
((mask & (~NSShiftKeyMask)) == item.keyEquivalentModifierMask);
EXPECT_TRUE(maskEqual);
}
}
// Check that each accelerator with a command_id has an associated NSMenuItem
// in the main menu. If the selector is commandDispatch:, then the tag must
// match the command_id.
IN_PROC_BROWSER_TEST_F(AcceleratorsCocoaBrowserTest,
MappingAcceleratorsInMainMenu) {
AcceleratorsCocoa* keymap = AcceleratorsCocoa::GetInstance();
for (AcceleratorsCocoa::AcceleratorMap::iterator it =
keymap->accelerators_.begin();
it != keymap->accelerators_.end();
++it) {
const ui::PlatformAcceleratorCocoa* platform_accelerator =
static_cast<const ui::PlatformAcceleratorCocoa*>(
it->second.platform_accelerator());
// Check that there exists a corresponding NSMenuItem.
NSMenuItem* item =
MenuContainsAccelerator([NSApp mainMenu],
platform_accelerator->characters(),
platform_accelerator->modifier_mask());
EXPECT_TRUE(item);
// If the menu uses a commandDispatch:, the tag must match the command id!
if (item.action == @selector(commandDispatch:))
EXPECT_EQ(item.tag, it->first);
}
}