| // Copyright 2015 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <algorithm> |
| #include <vector> |
| |
| #include "cobalt/base/tokens.h" |
| #include "cobalt/dom/keyboard_event.h" |
| #include "cobalt/dom/keyboard_event_init.h" |
| #include "cobalt/dom/keycode.h" |
| #include "cobalt/webdriver/keyboard.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::Each; |
| using testing::ElementsAre; |
| using testing::Eq; |
| |
| namespace cobalt { |
| namespace webdriver { |
| namespace { |
| |
| int32 GetKeyCode(std::pair<base::Token, const dom::KeyboardEventInit&> event) { |
| scoped_refptr<dom::KeyboardEvent> keyboard_event( |
| new dom::KeyboardEvent(event.first.c_str(), event.second)); |
| return keyboard_event->key_code(); |
| } |
| |
| int32 GetCharCode(std::pair<base::Token, const dom::KeyboardEventInit&> event) { |
| scoped_refptr<dom::KeyboardEvent> keyboard_event( |
| new dom::KeyboardEvent(event.first.c_str(), event.second)); |
| return keyboard_event->char_code(); |
| } |
| |
| const uint32 kNoModifier = 0; |
| const uint32 kShift = 1; |
| const uint32 kAlt = 2; |
| const uint32 kOtherModifier = 4; |
| const uint32 kAltAndShift = kAlt | kShift; |
| |
| uint32 GetModifierBitfield( |
| std::pair<base::Token, const dom::KeyboardEventInit&> event) { |
| scoped_refptr<dom::KeyboardEvent> keyboard_event( |
| new dom::KeyboardEvent(event.first.c_str(), event.second)); |
| uint32 modifiers = kNoModifier; |
| if (keyboard_event->shift_key()) { |
| modifiers |= kShift; |
| } |
| if (keyboard_event->alt_key()) { |
| modifiers |= kAlt; |
| } |
| if (keyboard_event->ctrl_key() || keyboard_event->meta_key()) { |
| modifiers |= kOtherModifier; |
| } |
| return modifiers; |
| } |
| |
| std::string GetType( |
| std::pair<base::Token, const dom::KeyboardEventInit&> event) { |
| scoped_refptr<dom::KeyboardEvent> keyboard_event( |
| new dom::KeyboardEvent(event.first.c_str(), event.second)); |
| return keyboard_event->type().c_str(); |
| } |
| |
| int GetLocation(std::pair<base::Token, const dom::KeyboardEventInit&> event) { |
| scoped_refptr<dom::KeyboardEvent> keyboard_event( |
| new dom::KeyboardEvent(event.first.c_str(), event.second)); |
| return keyboard_event->location(); |
| } |
| |
| const int kLocationStandard = |
| dom::KeyboardEvent::kDomKeyLocationStandard; |
| const int kLocationLeft = dom::KeyboardEvent::kDomKeyLocationLeft; |
| |
| class KeyboardTest : public ::testing::Test { |
| protected: |
| std::vector<int32> GetKeyCodes() { |
| std::vector<int32> key_codes(events_.size()); |
| std::transform(events_.begin(), events_.end(), key_codes.begin(), |
| GetKeyCode); |
| return key_codes; |
| } |
| std::vector<int32> GetCharCodes() { |
| std::vector<int32> char_codes(events_.size()); |
| std::transform(events_.begin(), events_.end(), char_codes.begin(), |
| GetCharCode); |
| return char_codes; |
| } |
| std::vector<uint32> GetModifiers() { |
| std::vector<uint32> modifiers(events_.size()); |
| std::transform(events_.begin(), events_.end(), modifiers.begin(), |
| GetModifierBitfield); |
| return modifiers; |
| } |
| std::vector<int> GetLocations() { |
| std::vector<int> locations(events_.size()); |
| std::transform(events_.begin(), events_.end(), locations.begin(), |
| GetLocation); |
| return locations; |
| } |
| std::vector<std::string> GetTypes() { |
| std::vector<std::string> types(events_.size()); |
| std::transform(events_.begin(), events_.end(), types.begin(), GetType); |
| return types; |
| } |
| Keyboard::KeyboardEventVector events_; |
| }; |
| } // namespace |
| |
| TEST_F(KeyboardTest, LowerCaseCharacter) { |
| std::string keys = "r"; |
| Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_); |
| |
| ASSERT_EQ(events_.size(), 3); |
| EXPECT_THAT(GetTypes(), ElementsAre("keydown", "keypress", "keyup")); |
| EXPECT_THAT(GetKeyCodes(), ElementsAre('R', 0, 'R')); |
| EXPECT_THAT(GetCharCodes(), ElementsAre(0, 'r', 0)); |
| EXPECT_THAT(GetModifiers(), Each(Eq(kNoModifier))); |
| EXPECT_THAT(GetLocations(), Each(Eq(kLocationStandard))); |
| } |
| |
| TEST_F(KeyboardTest, UpperCaseCharacter) { |
| std::string keys = "R"; |
| Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_); |
| |
| // keydown(shift) |
| // keydown(R), keypress(R), keyup(R) |
| // keyup(shift) |
| ASSERT_EQ(events_.size(), 5); |
| EXPECT_THAT(GetTypes(), |
| ElementsAre("keydown", "keydown", "keypress", "keyup", "keyup")); |
| EXPECT_THAT(GetKeyCodes(), |
| ElementsAre(static_cast<int>(dom::keycode::kShift), 'R', 0, 'R', |
| static_cast<int>(dom::keycode::kShift))); |
| EXPECT_THAT(GetCharCodes(), ElementsAre(0, 0, 'R', 0, 0)); |
| EXPECT_THAT(GetModifiers(), |
| ElementsAre(kShift, kShift, kShift, kShift, kNoModifier)); |
| EXPECT_THAT(GetLocations(), |
| ElementsAre(kLocationLeft, kLocationStandard, kLocationStandard, |
| kLocationStandard, kLocationLeft)); |
| } |
| |
| TEST_F(KeyboardTest, ShiftedCharacter) { |
| std::string keys = "&"; |
| Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_); |
| |
| // keydown(shift) |
| // keydown(7), keypress(&), keyup(7) |
| // keyup(shift) |
| ASSERT_EQ(events_.size(), 5); |
| EXPECT_THAT(GetTypes(), |
| ElementsAre("keydown", "keydown", "keypress", "keyup", "keyup")); |
| EXPECT_THAT(GetKeyCodes(), |
| ElementsAre(static_cast<int>(dom::keycode::kShift), '7', 0, '7', |
| static_cast<int>(dom::keycode::kShift))); |
| EXPECT_THAT(GetCharCodes(), ElementsAre(0, 0, '&', 0, 0)); |
| EXPECT_THAT(GetModifiers(), |
| ElementsAre(kShift, kShift, kShift, kShift, kNoModifier)); |
| EXPECT_THAT(GetLocations(), |
| ElementsAre(kLocationLeft, kLocationStandard, kLocationStandard, |
| kLocationStandard, kLocationLeft)); |
| } |
| |
| TEST_F(KeyboardTest, Modifier) { |
| // \uE00A is the Alt-key modifier. |
| std::string keys = "\uE00A"; |
| Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_); |
| |
| ASSERT_EQ(events_.size(), 1); |
| EXPECT_THAT(GetTypes(), ElementsAre("keydown")); |
| EXPECT_THAT(GetKeyCodes(), |
| ElementsAre(static_cast<int>(dom::keycode::kMenu))); |
| EXPECT_THAT(GetCharCodes(), ElementsAre(0)); |
| EXPECT_THAT(GetModifiers(), ElementsAre(kAlt)); |
| EXPECT_THAT(GetLocations(), ElementsAre(kLocationLeft)); |
| } |
| |
| TEST_F(KeyboardTest, ModifiersAreKept) { |
| // \uE00A is the Alt-key modifier. |
| // \uE008 is the Shift-key modifier. |
| std::string keys = "\uE00A\uE008"; |
| Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_); |
| |
| ASSERT_EQ(events_.size(), 2); |
| EXPECT_THAT(GetTypes(), ElementsAre("keydown", "keydown")); |
| EXPECT_THAT(GetKeyCodes(), |
| ElementsAre(static_cast<int>(dom::keycode::kMenu), |
| static_cast<int>(dom::keycode::kShift))); |
| EXPECT_THAT(GetCharCodes(), Each(Eq(0))); |
| EXPECT_THAT(GetModifiers(), ElementsAre(kAlt, kAltAndShift)); |
| EXPECT_THAT(GetLocations(), Each(Eq(kLocationLeft))); |
| } |
| |
| TEST_F(KeyboardTest, ModifiersAreReleased) { |
| // \uE00A is the Alt-key modifier. |
| // \uE008 is the Shift-key modifier. |
| std::string keys = "\uE00A\uE008"; |
| Keyboard::TranslateToKeyEvents(keys, Keyboard::kReleaseModifiers, &events_); |
| |
| ASSERT_EQ(events_.size(), 4); |
| EXPECT_THAT(GetTypes(), ElementsAre("keydown", "keydown", "keyup", "keyup")); |
| EXPECT_THAT(GetKeyCodes(), |
| ElementsAre(static_cast<int>(dom::keycode::kMenu), |
| static_cast<int>(dom::keycode::kShift), |
| static_cast<int>(dom::keycode::kMenu), |
| static_cast<int>(dom::keycode::kShift))); |
| EXPECT_THAT(GetCharCodes(), Each(Eq(0))); |
| EXPECT_THAT(GetModifiers(), |
| ElementsAre(kAlt, kAltAndShift, kShift, kNoModifier)); |
| EXPECT_THAT(GetLocations(), Each(Eq(kLocationLeft))); |
| } |
| |
| TEST_F(KeyboardTest, SpecialCharacter) { |
| // \uE012 is the Left-arrow key. |
| std::string keys = "\uE012"; |
| Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_); |
| |
| ASSERT_EQ(events_.size(), 2); |
| EXPECT_THAT(GetTypes(), ElementsAre("keydown", "keyup")); |
| EXPECT_THAT(GetKeyCodes(), Each(Eq(static_cast<int>(dom::keycode::kLeft)))); |
| EXPECT_THAT(GetCharCodes(), Each(Eq(0))); |
| EXPECT_THAT(GetModifiers(), Each(Eq(kNoModifier))); |
| EXPECT_THAT(GetLocations(), Each(Eq(kLocationStandard))); |
| } |
| |
| TEST_F(KeyboardTest, ModifierIsSticky) { |
| // \uE00A is the Alt-key modifier. Corresponds to the kMenu key code. |
| std::string keys = "\uE00AaB"; |
| Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_); |
| |
| // keydown(alt) |
| // keydown(A), keypress(a), keyup(A), |
| // keydown(shift) |
| // keydown(B), keypress(B), keyup(B) |
| // keyup(shift) |
| ASSERT_EQ(events_.size(), 9); |
| EXPECT_THAT(GetTypes(), |
| ElementsAre("keydown", "keydown", "keypress", "keyup", "keydown", |
| "keydown", "keypress", "keyup", "keyup")); |
| EXPECT_THAT(GetKeyCodes(), |
| ElementsAre(static_cast<int>(dom::keycode::kMenu), 'A', 0, 'A', |
| static_cast<int>(dom::keycode::kShift), 'B', 0, 'B', |
| static_cast<int>(dom::keycode::kShift))); |
| EXPECT_THAT(GetCharCodes(), ElementsAre(0, 0, 'a', 0, 0, 0, 'B', 0, 0)); |
| EXPECT_THAT(GetModifiers(), |
| ElementsAre(kAlt, kAlt, kAlt, kAlt, kAltAndShift, kAltAndShift, |
| kAltAndShift, kAltAndShift, kAlt)); |
| EXPECT_THAT(GetLocations(), |
| ElementsAre(kLocationLeft, kLocationStandard, kLocationStandard, |
| kLocationStandard, kLocationLeft, kLocationStandard, |
| kLocationStandard, kLocationStandard, kLocationLeft)); |
| } |
| |
| TEST_F(KeyboardTest, ToggleModifier) { |
| // \uE008 is the Shift-key modifier. |
| std::string keys = "\uE008a\uE008a"; |
| Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_); |
| |
| // keydown(shift) |
| // keydown(A), keypress(A), keyup(A) |
| // keyup(shift) |
| // keydown(A), keypress(a), keyup(A) |
| ASSERT_EQ(events_.size(), 8); |
| EXPECT_THAT(GetTypes(), ElementsAre("keydown", "keydown", "keypress", "keyup", |
| "keyup", "keydown", "keypress", "keyup")); |
| EXPECT_THAT(GetKeyCodes(), |
| ElementsAre(static_cast<int>(dom::keycode::kShift), 'A', 0, 'A', |
| static_cast<int>(dom::keycode::kShift), 'A', 0, 'A')); |
| EXPECT_THAT(GetCharCodes(), ElementsAre(0, 0, 'A', 0, 0, 0, 'a', 0)); |
| |
| EXPECT_THAT(GetModifiers(), |
| ElementsAre(kShift, kShift, kShift, kShift, kNoModifier, |
| kNoModifier, kNoModifier, kNoModifier)); |
| EXPECT_THAT(GetLocations(), |
| ElementsAre(kLocationLeft, kLocationStandard, kLocationStandard, |
| kLocationStandard, kLocationLeft, kLocationStandard, |
| kLocationStandard, kLocationStandard)); |
| } |
| |
| TEST_F(KeyboardTest, NullClearsModifiers) { |
| std::string keys = "\uE008\uE00A\uE000a"; |
| Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_); |
| |
| // keydown(shift) |
| // keydown(alt) |
| // keyup(alt) |
| // keyup(shift) |
| // keydown(A), keypress(a), keyup(A) |
| ASSERT_EQ(events_.size(), 7); |
| EXPECT_THAT(GetTypes(), ElementsAre("keydown", "keydown", "keyup", "keyup", |
| "keydown", "keypress", "keyup")); |
| EXPECT_THAT(GetKeyCodes(), |
| ElementsAre(static_cast<int>(dom::keycode::kShift), |
| static_cast<int>(dom::keycode::kMenu), |
| static_cast<int>(dom::keycode::kMenu), |
| static_cast<int>(dom::keycode::kShift), 'A', 0, 'A')); |
| EXPECT_THAT(GetCharCodes(), ElementsAre(0, 0, 0, 0, 0, 'a', 0)); |
| |
| EXPECT_THAT(GetModifiers(), |
| ElementsAre(kShift, kAltAndShift, kShift, kNoModifier, |
| kNoModifier, kNoModifier, kNoModifier)); |
| EXPECT_THAT( |
| GetLocations(), |
| ElementsAre(kLocationLeft, kLocationLeft, kLocationLeft, kLocationLeft, |
| kLocationStandard, kLocationStandard, kLocationStandard)); |
| } |
| |
| } // namespace webdriver |
| } // namespace cobalt |