gui/test: Add tests for Hotkey serialization to QSettings

This commit is contained in:
Povilas Kanapickas 2021-01-10 13:39:39 +02:00
parent 68cfb4e585
commit fb067d4001
4 changed files with 284 additions and 4 deletions

View File

@ -8,16 +8,19 @@ set (CMAKE_INCLUDE_CURRENT_DIR ON)
# files that are used both in tests and the app # files that are used both in tests and the app
set(GUI_COMMON_SOURCE_FILES set(GUI_COMMON_SOURCE_FILES
src/Action.cpp
src/Hotkey.cpp
src/KeySequence.cpp src/KeySequence.cpp
) )
set(GUI_COMMON_HEADER_FILES set(GUI_COMMON_HEADER_FILES
src/Action.h
src/Hotkey.h
src/KeySequence.h src/KeySequence.h
) )
set(GUI_SOURCE_FILES set(GUI_SOURCE_FILES
src/AboutDialog.cpp src/AboutDialog.cpp
src/Action.cpp
src/ActionDialog.cpp src/ActionDialog.cpp
src/AddClientDialog.cpp src/AddClientDialog.cpp
src/AppConfig.cpp src/AppConfig.cpp
@ -27,7 +30,6 @@ set(GUI_SOURCE_FILES
src/DataDownloader.cpp src/DataDownloader.cpp
src/DisplayIsValid.cpp src/DisplayIsValid.cpp
src/Fingerprint.cpp src/Fingerprint.cpp
src/Hotkey.cpp
src/HotkeyDialog.cpp src/HotkeyDialog.cpp
src/IpcClient.cpp src/IpcClient.cpp
src/Ipc.cpp src/Ipc.cpp
@ -60,7 +62,6 @@ set(GUI_SOURCE_FILES
set(GUI_HEADER_FILES set(GUI_HEADER_FILES
src/AboutDialog.h src/AboutDialog.h
src/ActionDialog.h src/ActionDialog.h
src/Action.h
src/AddClientDialog.h src/AddClientDialog.h
src/AppConfig.h src/AppConfig.h
src/BarrierLocale.h src/BarrierLocale.h
@ -71,7 +72,6 @@ set(GUI_HEADER_FILES
src/ElevateMode.h src/ElevateMode.h
src/Fingerprint.h src/Fingerprint.h
src/HotkeyDialog.h src/HotkeyDialog.h
src/Hotkey.h
src/IpcClient.h src/IpcClient.h
src/Ipc.h src/Ipc.h
src/IpcReader.h src/IpcReader.h
@ -164,6 +164,7 @@ endif()
if (BARRIER_BUILD_TESTS) if (BARRIER_BUILD_TESTS)
set(GUI_TEST_SOURCE_FILES set(GUI_TEST_SOURCE_FILES
test/KeySequenceTests.cpp test/KeySequenceTests.cpp
test/HotkeyTests.cpp
test/main.cpp test/main.cpp
) )

View File

@ -0,0 +1,244 @@
/* barrier -- mouse and keyboard sharing utility
Copyright (C) 2021 Povilas Kanapickas <povilas@radix.lt>
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 <http://www.gnu.org/licenses/>.
*/
#include "../src/Hotkey.h"
#include <gtest/gtest.h>
#include "Utils.h"
#include <QtCore/QSettings>
struct TestAction
{
Action::ActionType type = Action::keyDown;
std::vector<TestKey> keys;
std::vector<std::string> 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<TestKey>& keys,
const std::vector<std::string>& 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<TestKey>& keys,
const std::vector<std::string>& type_screen_names = {})
{
return createKeyAction(Action::keyDown, keys, type_screen_names);
}
static TestAction createKeyUp(const std::vector<TestKey>& keys,
const std::vector<std::string>& type_screen_names = {})
{
return createKeyAction(Action::keyUp, keys, type_screen_names);
}
static TestAction createKeyStroke(const std::vector<TestKey>& keys,
const std::vector<std::string>& 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<TestKey> keys;
std::vector<TestAction> 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);
}

View File

@ -74,6 +74,15 @@ namespace {
Qt::Key_Launch1, Qt::Key_Launch1,
Qt::Key_Select, Qt::Key_Select,
}; };
std::string keySequenceToString(const std::vector<TestKey>& key_pairs)
{
KeySequence sequence;
for (auto key_pair : key_pairs) {
sequence.appendKey(key_pair.key, key_pair.modifier);
}
return sequence.toString().toStdString();
}
} // namespace } // namespace
class KeySequenceLoadSaveTestFixture : class KeySequenceLoadSaveTestFixture :
@ -118,3 +127,21 @@ INSTANTIATE_TEST_CASE_P(
KeySequenceLoadSaveTestFixture, KeySequenceLoadSaveTestFixture,
::testing::Combine(::testing::ValuesIn(s_key_sequence_test_keys), ::testing::Combine(::testing::ValuesIn(s_key_sequence_test_keys),
::testing::Values(QSettings::NativeFormat, QSettings::IniFormat))); ::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");
}

View File

@ -20,6 +20,14 @@
#include <QtCore/QFile> #include <QtCore/QFile>
#include <QtCore/QTemporaryFile> #include <QtCore/QTemporaryFile>
struct TestKey
{
int key = 0;
int modifier = Qt::NoModifier;
TestKey(int key, int modifier) : key{key}, modifier{modifier} {}
};
inline QString getTemporaryFilename() inline QString getTemporaryFilename()
{ {
QTemporaryFile temp_file; QTemporaryFile temp_file;