From fb067d4001ad8d3b9b4e30edc77671f546a44632 Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Sun, 10 Jan 2021 13:39:39 +0200 Subject: [PATCH] gui/test: Add tests for Hotkey serialization to QSettings --- src/gui/CMakeLists.txt | 9 +- src/gui/test/HotkeyTests.cpp | 244 ++++++++++++++++++++++++++++++ src/gui/test/KeySequenceTests.cpp | 27 ++++ src/gui/test/Utils.h | 8 + 4 files changed, 284 insertions(+), 4 deletions(-) create mode 100644 src/gui/test/HotkeyTests.cpp diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index f06b1cfb..2875adf4 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -8,16 +8,19 @@ set (CMAKE_INCLUDE_CURRENT_DIR ON) # files that are used both in tests and the app set(GUI_COMMON_SOURCE_FILES + src/Action.cpp + src/Hotkey.cpp src/KeySequence.cpp ) set(GUI_COMMON_HEADER_FILES + src/Action.h + src/Hotkey.h src/KeySequence.h ) set(GUI_SOURCE_FILES src/AboutDialog.cpp - src/Action.cpp src/ActionDialog.cpp src/AddClientDialog.cpp src/AppConfig.cpp @@ -27,7 +30,6 @@ set(GUI_SOURCE_FILES src/DataDownloader.cpp src/DisplayIsValid.cpp src/Fingerprint.cpp - src/Hotkey.cpp src/HotkeyDialog.cpp src/IpcClient.cpp src/Ipc.cpp @@ -60,7 +62,6 @@ set(GUI_SOURCE_FILES set(GUI_HEADER_FILES src/AboutDialog.h src/ActionDialog.h - src/Action.h src/AddClientDialog.h src/AppConfig.h src/BarrierLocale.h @@ -71,7 +72,6 @@ set(GUI_HEADER_FILES src/ElevateMode.h src/Fingerprint.h src/HotkeyDialog.h - src/Hotkey.h src/IpcClient.h src/Ipc.h src/IpcReader.h @@ -164,6 +164,7 @@ endif() if (BARRIER_BUILD_TESTS) set(GUI_TEST_SOURCE_FILES test/KeySequenceTests.cpp + test/HotkeyTests.cpp test/main.cpp ) diff --git a/src/gui/test/HotkeyTests.cpp b/src/gui/test/HotkeyTests.cpp new file mode 100644 index 00000000..e3d31ac5 --- /dev/null +++ b/src/gui/test/HotkeyTests.cpp @@ -0,0 +1,244 @@ +/* barrier -- mouse and keyboard sharing utility + Copyright (C) 2021 Povilas Kanapickas + + This package is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + found in the file LICENSE that should have accompanied this file. + + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#include "../src/Hotkey.h" +#include +#include "Utils.h" + +#include + +struct TestAction +{ + Action::ActionType type = Action::keyDown; + std::vector keys; + std::vector type_screen_names; + std::string screen_name; + Action::SwitchDirection switch_direction; + Action::LockCursorMode lock_cursor_mode; + + static TestAction createKeyAction(Action::ActionType type, const std::vector& keys, + const std::vector& type_screen_names = {}) + { + TestAction action; + action.type = Action::keyDown; + action.keys = keys; + action.type_screen_names = type_screen_names; + return action; + } + + static TestAction createKeyDown(const std::vector& keys, + const std::vector& type_screen_names = {}) + { + return createKeyAction(Action::keyDown, keys, type_screen_names); + } + + static TestAction createKeyUp(const std::vector& keys, + const std::vector& type_screen_names = {}) + { + return createKeyAction(Action::keyUp, keys, type_screen_names); + } + + static TestAction createKeyStroke(const std::vector& keys, + const std::vector& type_screen_names = {}) + { + return createKeyAction(Action::keystroke, keys, type_screen_names); + } + + static TestAction createSwitchToScreen(const std::string& screen_name) + { + TestAction action; + action.type = Action::switchToScreen; + action.screen_name = screen_name; + return action; + } + + static TestAction createToggleScreen() + { + TestAction action; + action.type = Action::toggleScreen; + return action; + } + + static TestAction createSwitchInDirection(Action::SwitchDirection switch_direction) + { + TestAction action; + action.type = Action::switchInDirection; + action.switch_direction = switch_direction; + return action; + } + + static TestAction createLockCursorToScreen(Action::LockCursorMode lock_cursor_mode) + { + TestAction action; + action.type = Action::lockCursorToScreen; + action.lock_cursor_mode = lock_cursor_mode; + return action; + } +}; + +struct TestHotKey +{ + std::vector keys; + std::vector actions; +}; + +Action createAction(const TestAction& test_action) +{ + Action action; + action.setType(test_action.type); + + switch (test_action.type) { + case Action::keyDown: + case Action::keyUp: + case Action::keystroke: { + KeySequence sequence; + for (auto key : test_action.keys) { + sequence.appendKey(key.key, key.modifier); + } + action.setKeySequence(sequence); + for (const auto& type_screen_name : test_action.type_screen_names) { + action.appendTypeScreenName(QString::fromStdString(type_screen_name)); + } + break; + } + case Action::switchToScreen: + action.setSwitchScreenName(QString::fromStdString(test_action.screen_name)); + break; + case Action::toggleScreen: + break; + case Action::switchInDirection: + action.setSwitchDirection(test_action.switch_direction); + break; + case Action::lockCursorToScreen: + action.setLockCursorMode(test_action.lock_cursor_mode); + break; + } + return action; +} + +void doHotkeyLoadSaveTest(const TestHotKey& test_hotkey, QSettings::Format format) +{ + auto filename = getTemporaryFilename(); + + Hotkey hotkey_before, hotkey_after; + { + QSettings settings(filename, format); + + + KeySequence sequence; + for (auto key : test_hotkey.keys) { + sequence.appendKey(key.key, key.modifier); + } + hotkey_before.setKeySequence(sequence); + + for (auto action : test_hotkey.actions) { + hotkey_before.appendAction(createAction(action)); + } + + settings.beginGroup("test"); + hotkey_before.saveSettings(settings); + settings.endGroup(); + } + { + QSettings settings(filename, format); + + settings.beginGroup("test"); + hotkey_after.loadSettings(settings); + settings.endGroup(); + + ASSERT_EQ(hotkey_before.keySequence().sequence(), hotkey_after.keySequence().sequence()); + ASSERT_EQ(hotkey_before.keySequence().modifiers(), hotkey_after.keySequence().modifiers()); + + const auto& actions_before = hotkey_before.actions(); + const auto& actions_after = hotkey_after.actions(); + + ASSERT_EQ(actions_before.size(), actions_after.size()); + for (int i = 0; i < actions_before.size(); ++i) { + const auto& action_before = actions_before[i]; + const auto& action_after = actions_after[i]; + + ASSERT_EQ(action_before.keySequence().sequence(), action_after.keySequence().sequence()); + ASSERT_EQ(action_before.keySequence().modifiers(), action_after.keySequence().modifiers()); + ASSERT_EQ(action_before.type(), action_after.type()); + ASSERT_EQ(action_before.typeScreenNames(), action_after.typeScreenNames()); + ASSERT_EQ(action_before.switchScreenName(), action_after.switchScreenName()); + ASSERT_EQ(action_before.switchDirection(), action_after.switchDirection()); + ASSERT_EQ(action_before.lockCursorMode(), action_after.lockCursorMode()); + ASSERT_EQ(action_before.activeOnRelease(), action_after.activeOnRelease()); + ASSERT_EQ(action_before.haveScreens(), action_after.haveScreens()); + } + } + + QFile::remove(filename); +} + +TEST(HotkeyLoadSaveTests, Empty) +{ + TestHotKey hotkey; + doHotkeyLoadSaveTest(hotkey, QSettings::NativeFormat); + doHotkeyLoadSaveTest(hotkey, QSettings::IniFormat); +} + +TEST(HotkeyLoadSaveTests, KeysNoActions) +{ + TestHotKey hotkey = {{{Qt::Key_A, Qt::NoModifier}, {Qt::Key_B, Qt::NoModifier}}, {}}; + doHotkeyLoadSaveTest(hotkey, QSettings::NativeFormat); + doHotkeyLoadSaveTest(hotkey, QSettings::IniFormat); +} + +TEST(HotkeyLoadSaveTests, CommaKeyNoActions) +{ + TestHotKey hotkey = { + { + {Qt::Key_A, Qt::NoModifier}, + {Qt::Key_Comma, Qt::NoModifier}, + {Qt::Key_B, Qt::NoModifier} + }, {}}; + doHotkeyLoadSaveTest(hotkey, QSettings::NativeFormat); + doHotkeyLoadSaveTest(hotkey, QSettings::IniFormat); +} + +TEST(HotkeyLoadSaveTests, KeysSingleAction) +{ + TestHotKey hotkey = { + { + {Qt::Key_A, Qt::NoModifier}, + {Qt::Key_B, Qt::NoModifier} + }, + { + TestAction::createKeyDown({{Qt::Key_Z, Qt::NoModifier}}) + } + }; + doHotkeyLoadSaveTest(hotkey, QSettings::NativeFormat); + doHotkeyLoadSaveTest(hotkey, QSettings::IniFormat); +} + +TEST(HotkeyLoadSaveTests, KeysMultipleAction) +{ + TestHotKey hotkey = { + { + {Qt::Key_A, Qt::NoModifier}, + {Qt::Key_B, Qt::NoModifier} + }, + { + TestAction::createKeyDown({{Qt::Key_Z, Qt::NoModifier}}), + TestAction::createSwitchToScreen("test_screen") + } + }; + doHotkeyLoadSaveTest(hotkey, QSettings::NativeFormat); + doHotkeyLoadSaveTest(hotkey, QSettings::IniFormat); +} diff --git a/src/gui/test/KeySequenceTests.cpp b/src/gui/test/KeySequenceTests.cpp index 5e089de9..1e22ac4b 100644 --- a/src/gui/test/KeySequenceTests.cpp +++ b/src/gui/test/KeySequenceTests.cpp @@ -74,6 +74,15 @@ namespace { Qt::Key_Launch1, Qt::Key_Select, }; + + std::string keySequenceToString(const std::vector& key_pairs) + { + KeySequence sequence; + for (auto key_pair : key_pairs) { + sequence.appendKey(key_pair.key, key_pair.modifier); + } + return sequence.toString().toStdString(); + } } // namespace class KeySequenceLoadSaveTestFixture : @@ -118,3 +127,21 @@ INSTANTIATE_TEST_CASE_P( KeySequenceLoadSaveTestFixture, ::testing::Combine(::testing::ValuesIn(s_key_sequence_test_keys), ::testing::Values(QSettings::NativeFormat, QSettings::IniFormat))); + +TEST(KeySequenceTests, ToString) +{ + ASSERT_EQ(keySequenceToString({{Qt::Key_Menu, Qt::MetaModifier}}), + "Meta"); + ASSERT_EQ(keySequenceToString({{Qt::Key_A, 0}, {Qt::Key_B, 0}}), + "a+b"); + ASSERT_EQ(keySequenceToString({{Qt::Key_A, 0}, {Qt::Key_Comma, 0}, {Qt::Key_B, 0}}), + "a+,+b"); + ASSERT_EQ(keySequenceToString({{Qt::Key_A, 0}, {Qt::Key_Semicolon, 0}, {Qt::Key_B, 0}}), + "a+;+b"); + ASSERT_EQ(keySequenceToString({{Qt::Key_A, 0}, {Qt::Key_Shift, Qt::ShiftModifier}, + {Qt::Key_0, Qt::ShiftModifier}}), + "a+Shift+0"); + ASSERT_EQ(keySequenceToString({{Qt::Key_A, 0}, {Qt::Key_Control, Qt::ControlModifier}, + {Qt::Key_0, Qt::ControlModifier}}), + "a+Control+0"); +} diff --git a/src/gui/test/Utils.h b/src/gui/test/Utils.h index 5ca78c20..da66ce74 100644 --- a/src/gui/test/Utils.h +++ b/src/gui/test/Utils.h @@ -20,6 +20,14 @@ #include #include +struct TestKey +{ + int key = 0; + int modifier = Qt::NoModifier; + + TestKey(int key, int modifier) : key{key}, modifier{modifier} {} +}; + inline QString getTemporaryFilename() { QTemporaryFile temp_file;