diff options
Diffstat (limited to 'tests/test_common')
-rw-r--r-- | tests/test_common/mouse_report_util.cpp | 58 | ||||
-rw-r--r-- | tests/test_common/mouse_report_util.hpp | 38 | ||||
-rw-r--r-- | tests/test_common/pointing_device_driver.c | 109 | ||||
-rw-r--r-- | tests/test_common/test_driver.cpp | 1 | ||||
-rw-r--r-- | tests/test_common/test_driver.hpp | 42 | ||||
-rw-r--r-- | tests/test_common/test_fixture.cpp | 4 | ||||
-rw-r--r-- | tests/test_common/test_pointing_device_driver.h | 32 |
7 files changed, 284 insertions, 0 deletions
diff --git a/tests/test_common/mouse_report_util.cpp b/tests/test_common/mouse_report_util.cpp new file mode 100644 index 0000000000..60cdeced24 --- /dev/null +++ b/tests/test_common/mouse_report_util.cpp @@ -0,0 +1,58 @@ +/* Copyright 2017 Fred Sundvik + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 "mouse_report_util.hpp" +#include <cstdint> +#include <vector> +#include <algorithm> + +using namespace testing; + +bool operator==(const report_mouse_t& lhs, const report_mouse_t& rhs) { + return lhs.x == rhs.x && lhs.y == rhs.y && lhs.h == rhs.h && lhs.v == rhs.v && lhs.buttons == rhs.buttons; +} + +std::ostream& operator<<(std::ostream& os, const report_mouse_t& report) { + os << std::setw(10) << std::left << "mouse report: "; + + if (report.x == 0 && report.y == 0 && report.h == 0 && report.v == 0 && report.buttons == 0) { + return os << "empty" << std::endl; + } + + os << "(X:" << (int)report.x << ", Y:" << (int)report.y << ", H:" << (int)report.h << ", V:" << (int)report.v << ", B:" << (int)report.buttons << ")"; + return os << std::endl; +} + +MouseReportMatcher::MouseReportMatcher(int16_t x, int16_t y, int8_t h, int8_t v, uint8_t button_mask) { + memset(&m_report, 0, sizeof(report_mouse_t)); + m_report.x = x; + m_report.y = y; + m_report.h = h; + m_report.v = v; + m_report.buttons = button_mask; +} + +bool MouseReportMatcher::MatchAndExplain(report_mouse_t& report, MatchResultListener* listener) const { + return m_report == report; +} + +void MouseReportMatcher::DescribeTo(::std::ostream* os) const { + *os << "is equal to " << m_report; +} + +void MouseReportMatcher::DescribeNegationTo(::std::ostream* os) const { + *os << "is not equal to " << m_report; +} diff --git a/tests/test_common/mouse_report_util.hpp b/tests/test_common/mouse_report_util.hpp new file mode 100644 index 0000000000..645f6aa58c --- /dev/null +++ b/tests/test_common/mouse_report_util.hpp @@ -0,0 +1,38 @@ +/* Copyright 2017 Fred Sundvik + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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/>. + */ + +#pragma once +#include "report.h" +#include <ostream> +#include "gmock/gmock.h" + +bool operator==(const report_mouse_t& lhs, const report_mouse_t& rhs); +std::ostream& operator<<(std::ostream& stream, const report_mouse_t& value); + +class MouseReportMatcher : public testing::MatcherInterface<report_mouse_t&> { + public: + MouseReportMatcher(int16_t x, int16_t y, int8_t h, int8_t v, uint8_t button_mask); + virtual bool MatchAndExplain(report_mouse_t& report, testing::MatchResultListener* listener) const override; + virtual void DescribeTo(::std::ostream* os) const override; + virtual void DescribeNegationTo(::std::ostream* os) const override; + + private: + report_mouse_t m_report; +}; + +inline testing::Matcher<report_mouse_t&> MouseReport(int16_t x, int16_t y, int8_t h, int8_t v, uint8_t button_mask) { + return testing::MakeMatcher(new MouseReportMatcher(x, y, h, v, button_mask)); +} diff --git a/tests/test_common/pointing_device_driver.c b/tests/test_common/pointing_device_driver.c new file mode 100644 index 0000000000..b64dbad506 --- /dev/null +++ b/tests/test_common/pointing_device_driver.c @@ -0,0 +1,109 @@ +// Copyright 2024 Dasky (@daskygit) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "report.h" +#include "test_pointing_device_driver.h" +#include <string.h> + +typedef struct { + bool pressed; + bool dirty; +} pd_button_state_t; + +typedef struct { + int16_t x; + int16_t y; + int16_t h; + int16_t v; + pd_button_state_t button_state[8]; + uint16_t cpi; + bool initiated; +} pd_config_t; + +static pd_config_t pd_config = {0}; + +void pointing_device_driver_init(void) { + pd_set_init(true); +} + +report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report) { + for (uint8_t i = 0; i < 8; i++) { + if (pd_config.button_state[i].dirty) { + pd_config.button_state[i].dirty = false; + if (pd_config.button_state[i].pressed) { + mouse_report.buttons |= 1 << (i); + } else { + mouse_report.buttons &= ~(1 << (i)); + } + } + } + mouse_report.x = pd_config.x; + mouse_report.y = pd_config.y; + mouse_report.h = pd_config.h; + mouse_report.v = pd_config.v; + return mouse_report; +} + +__attribute__((weak)) uint16_t pointing_device_driver_get_cpi(void) { + return pd_config.cpi; +} + +__attribute__((weak)) void pointing_device_driver_set_cpi(uint16_t cpi) { + pd_config.cpi = cpi; +} + +void pd_press_button(uint8_t btn) { + pd_config.button_state[btn].dirty = true; + pd_config.button_state[btn].pressed = true; +} +void pd_release_button(uint8_t btn) { + pd_config.button_state[btn].dirty = true; + pd_config.button_state[btn].pressed = false; +} + +void pd_clear_all_buttons(void) { + for (uint8_t i = 0; i < 8; i++) { + pd_config.button_state[i].dirty = true; + pd_config.button_state[i].pressed = false; + } +} + +void pd_set_x(int16_t x) { + pd_config.x = x; +} + +void pd_clear_x(void) { + pd_set_x(0); +} + +void pd_set_y(int16_t y) { + pd_config.y = y; +} +void pd_clear_y(void) { + pd_set_y(0); +} + +void pd_set_h(int16_t h) { + pd_config.h = h; +} +void pd_clear_h(void) { + pd_set_h(0); +} + +void pd_set_v(int16_t v) { + pd_config.v = v; +} +void pd_clear_v(void) { + pd_set_v(0); +} + +void pd_clear_movement(void) { + pd_set_x(0); + pd_set_y(0); + pd_set_h(0); + pd_set_v(0); +} + +void pd_set_init(bool success) { + pd_config.initiated = success; +} diff --git a/tests/test_common/test_driver.cpp b/tests/test_common/test_driver.cpp index d410b225f9..70b920ac86 100644 --- a/tests/test_common/test_driver.cpp +++ b/tests/test_common/test_driver.cpp @@ -54,6 +54,7 @@ void TestDriver::send_nkro(report_nkro_t* report) { } void TestDriver::send_mouse(report_mouse_t* report) { + test_logger.trace() << std::setw(10) << std::left << "send_mouse: (X:" << (int)report->x << ", Y:" << (int)report->y << ", H:" << (int)report->h << ", V:" << (int)report->v << ", B:" << (int)report->buttons << ")" << std::endl; m_this->send_mouse_mock(*report); } diff --git a/tests/test_common/test_driver.hpp b/tests/test_common/test_driver.hpp index ec75d3fff2..fea8225953 100644 --- a/tests/test_common/test_driver.hpp +++ b/tests/test_common/test_driver.hpp @@ -67,6 +67,25 @@ class TestDriver { #define EXPECT_REPORT(driver, report) EXPECT_CALL((driver), send_keyboard_mock(KeyboardReport report)) /** + * @brief Sets gmock expectation that a mouse report of `report` will be sent. + * For this macro to parse correctly, the `report` arg must be surrounded by + * parentheses ( ). For instance, + * + * // Expect that a report of "X:-10 Y:0 H:0 V:10 BTN:1 " is sent to the host. + * EXPECT_REPORT(driver, (-10, 0, 0, 0, 1)); + * + * is shorthand for + * + * EXPECT_CALL(driver, send_mouse_mock(MouseReport(-10, 0, 0, 0, 1))); + * + * It is possible to use .Times() and other gmock APIS with EXPECT_REPORT, for instance, + * allow only single report to be sent: + * + * EXPECT_REPORT(driver, (-10, 0, 0, 0, 1)).Times(1); + */ +#define EXPECT_MOUSE_REPORT(driver, report) EXPECT_CALL((driver), send_mouse_mock(MouseReport report)) + +/** * @brief Sets gmock expectation that Unicode `code_point` is sent with UNICODE_MODE_LINUX input * mode. For instance for U+2013, * @@ -88,6 +107,15 @@ class TestDriver { #define EXPECT_EMPTY_REPORT(driver) EXPECT_REPORT(driver, ()) /** + * @brief Sets gmock expectation that a empty keyboard report will be sent. + * It is possible to use .Times() and other gmock APIS with EXPECT_EMPTY_MOUSE_REPORT, for instance, + * allow any number of empty reports with: + * + * EXPECT_EMPTY_MOUSE_REPORT(driver).Times(AnyNumber()); + */ +#define EXPECT_EMPTY_MOUSE_REPORT(driver) EXPECT_MOUSE_REPORT(driver, (0, 0, 0, 0, 0)) + +/** * @brief Sets gmock expectation that a keyboard report will be sent, without matching its content. * It is possible to use .Times() and other gmock APIS with EXPECT_ANY_REPORT, for instance, * allow a single arbitrary report with: @@ -97,10 +125,24 @@ class TestDriver { #define EXPECT_ANY_REPORT(driver) EXPECT_CALL((driver), send_keyboard_mock(_)) /** + * @brief Sets gmock expectation that a mouse report will be sent, without matching its content. + * It is possible to use .Times() and other gmock APIS with EXPECT_ANY_MOUSE_REPORT, for instance, + * allow a single arbitrary report with: + * + * EXPECT_ANY_MOUSE_REPORT(driver).Times(1); + */ +#define EXPECT_ANY_MOUSE_REPORT(driver) EXPECT_CALL((driver), send_mouse_mock(_)) + +/** * @brief Sets gmock expectation that no keyboard report will be sent at all. */ #define EXPECT_NO_REPORT(driver) EXPECT_ANY_REPORT(driver).Times(0) +/** + * @brief Sets gmock expectation that no keyboard report will be sent at all. + */ +#define EXPECT_NO_MOUSE_REPORT(driver) EXPECT_ANY_MOUSE_REPORT(driver).Times(0) + /** @brief Tests whether keycode `actual` is equal to `expected`. */ #define EXPECT_KEYCODE_EQ(actual, expected) EXPECT_THAT((actual), KeycodeEq((expected))) diff --git a/tests/test_common/test_fixture.cpp b/tests/test_common/test_fixture.cpp index 3cfb2cb4c2..81806b0e6d 100644 --- a/tests/test_common/test_fixture.cpp +++ b/tests/test_common/test_fixture.cpp @@ -7,6 +7,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include "keyboard_report_util.hpp" +#include "mouse_report_util.hpp" #include "keycode.h" #include "test_driver.hpp" #include "test_logger.hpp" @@ -69,6 +70,9 @@ TestFixture::~TestFixture() { /* Reset keyboard state. */ clear_all_keys(); +#ifdef MOUSEKEY_ENABLE + EXPECT_EMPTY_MOUSE_REPORT(driver); +#endif clear_keyboard(); clear_oneshot_mods(); diff --git a/tests/test_common/test_pointing_device_driver.h b/tests/test_common/test_pointing_device_driver.h new file mode 100644 index 0000000000..ae136b21cd --- /dev/null +++ b/tests/test_common/test_pointing_device_driver.h @@ -0,0 +1,32 @@ +// Copyright 2024 Dasky (@daskygit) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void pd_press_button(uint8_t btn); +void pd_release_button(uint8_t btn); +void pd_clear_all_buttons(void); + +void pd_set_x(int16_t x); +void clear_x(void); + +void pd_set_y(int16_t y); +void pd_clear_y(void); + +void pd_set_h(int16_t h); +void pd_clear_h(void); + +void pd_set_v(int16_t v); +void pd_clear_v(void); + +void pd_clear_movement(void); + +void pd_set_init(bool success); + +#ifdef __cplusplus +} +#endif |