// Copyright (c) 2012 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. #include #include #include "ash/accelerators/accelerator_table.h" #include "base/hash/md5.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "testing/gtest/include/gtest/gtest.h" namespace ash { namespace { // The number of non-Search-based accelerators. constexpr int kNonSearchAcceleratorsNum = 109; // The hash of non-Search-based accelerators. See HashAcceleratorData(). constexpr char kNonSearchAcceleratorsHash[] = "2cada710fecfc1ae0fa22ecad7900f16"; struct Cmp { bool operator()(const AcceleratorData& lhs, const AcceleratorData& rhs) const { // Do not check |action|. return std::tie(lhs.trigger_on_press, lhs.keycode, lhs.modifiers) < std::tie(rhs.trigger_on_press, rhs.keycode, rhs.modifiers); } }; std::string AcceleratorDataToString(const AcceleratorData& accelerator) { return base::StringPrintf( "trigger_on_press=%s keycode=%d shift=%s control=%s alt=%s search=%s", accelerator.trigger_on_press ? "true" : "false", accelerator.keycode, (accelerator.modifiers & ui::EF_SHIFT_DOWN) ? "true" : "false", (accelerator.modifiers & ui::EF_CONTROL_DOWN) ? "true" : "false", (accelerator.modifiers & ui::EF_ALT_DOWN) ? "true" : "false", (accelerator.modifiers & ui::EF_COMMAND_DOWN) ? "true" : "false"); } std::string HashAcceleratorData( const std::vector accelerators) { base::MD5Context context; base::MD5Init(&context); for (const AcceleratorData& accelerator : accelerators) base::MD5Update(&context, AcceleratorDataToString(accelerator)); base::MD5Digest digest; base::MD5Final(&digest, &context); return MD5DigestToBase16(digest); } } // namespace TEST(AcceleratorTableTest, CheckDuplicatedAccelerators) { std::set accelerators; for (size_t i = 0; i < kAcceleratorDataLength; ++i) { const AcceleratorData& entry = kAcceleratorData[i]; EXPECT_TRUE(accelerators.insert(entry).second) << "Duplicated accelerator: " << AcceleratorDataToString(entry); } for (size_t i = 0; i < kDisableWithNewMappingAcceleratorDataLength; ++i) { const AcceleratorData& entry = kDisableWithNewMappingAcceleratorData[i]; EXPECT_TRUE(accelerators.insert(entry).second) << "Duplicated accelerator: " << AcceleratorDataToString(entry); } } TEST(AcceleratorTableTest, CheckDuplicatedReservedActions) { std::set actions; for (size_t i = 0; i < kReservedActionsLength; ++i) { EXPECT_TRUE(actions.insert(kReservedActions[i]).second) << "Duplicated action: " << kReservedActions[i]; } } TEST(AcceleratorTableTest, CheckDuplicatedActionsAllowedAtLoginOrLockScreen) { std::set actions; for (size_t i = 0; i < kActionsAllowedAtLoginOrLockScreenLength; ++i) { EXPECT_TRUE(actions.insert(kActionsAllowedAtLoginOrLockScreen[i]).second) << "Duplicated action: " << kActionsAllowedAtLoginOrLockScreen[i]; } for (size_t i = 0; i < kActionsAllowedAtLockScreenLength; ++i) { EXPECT_TRUE(actions.insert(kActionsAllowedAtLockScreen[i]).second) << "Duplicated action: " << kActionsAllowedAtLockScreen[i]; } } TEST(AcceleratorTableTest, CheckDuplicatedActionsAllowedAtPowerMenu) { std::set actions; for (size_t i = 0; i < kActionsAllowedAtPowerMenuLength; ++i) { EXPECT_TRUE(actions.insert(kActionsAllowedAtPowerMenu[i]).second) << "Duplicated action: " << kActionsAllowedAtPowerMenu[i]; } } TEST(AcceleratorTableTest, CheckDuplicatedActionsAllowedAtModalWindow) { std::set actions; for (size_t i = 0; i < kActionsAllowedAtModalWindowLength; ++i) { EXPECT_TRUE(actions.insert(kActionsAllowedAtModalWindow[i]).second) << "Duplicated action: " << kActionsAllowedAtModalWindow[i] << " at index: " << i; } } TEST(AcceleratorTableTest, CheckDuplicatedRepeatableActions) { std::set actions; for (size_t i = 0; i < kRepeatableActionsLength; ++i) { EXPECT_TRUE(actions.insert(kRepeatableActions[i]).second) << "Duplicated action: " << kRepeatableActions[i] << " at index: " << i; } } TEST(AcceleratorTableTest, CheckDeprecatedAccelerators) { std::set deprecated_actions; for (size_t i = 0; i < kDeprecatedAcceleratorsLength; ++i) { // A deprecated action can never appear twice in the list. const AcceleratorData& entry = kDeprecatedAccelerators[i]; EXPECT_TRUE(deprecated_actions.insert(entry).second) << "Duplicate deprecated accelerator: " << AcceleratorDataToString(entry); } std::set actions; for (size_t i = 0; i < kDeprecatedAcceleratorsDataLength; ++i) { // There must never be any duplicated actions. const DeprecatedAcceleratorData& data = kDeprecatedAcceleratorsData[i]; EXPECT_TRUE(actions.insert(data.action).second) << "Deprecated action: " << data.action; // The UMA histogram name must be of the format "Ash.Accelerators.*" std::string uma_histogram(data.uma_histogram_name); EXPECT_TRUE(base::StartsWith(uma_histogram, "Ash.Accelerators.", base::CompareCase::SENSITIVE)); } } // All new accelerators should be Search-based and approved by UX. TEST(AcceleratorTableTest, CheckSearchBasedAccelerators) { std::vector non_search_accelerators; for (size_t i = 0; i < kAcceleratorDataLength; ++i) { const AcceleratorData& entry = kAcceleratorData[i]; if (entry.modifiers & ui::EF_COMMAND_DOWN) continue; non_search_accelerators.emplace_back(entry); } for (size_t i = 0; i < kDisableWithNewMappingAcceleratorDataLength; ++i) { const AcceleratorData& entry = kDisableWithNewMappingAcceleratorData[i]; if (entry.modifiers & ui::EF_COMMAND_DOWN) continue; non_search_accelerators.emplace_back(entry); } const int accelerators_number = non_search_accelerators.size(); EXPECT_EQ(accelerators_number, kNonSearchAcceleratorsNum) << "All new accelerators should be Search-based and approved by UX."; std::stable_sort(non_search_accelerators.begin(), non_search_accelerators.end(), Cmp()); const std::string non_search_accelerators_hash = HashAcceleratorData(non_search_accelerators); EXPECT_EQ(non_search_accelerators_hash, kNonSearchAcceleratorsHash) << "New accelerators must use the Search key. Please talk to the UX " "team.\n" "If you are removing a non-Search-based accelerator, please update " "the date along with the following values\n" << "kNonSearchAcceleratorsNum=" << accelerators_number << " and " << "kNonSearchAcceleratorsHash=\"" << non_search_accelerators_hash << "\""; } } // namespace ash