[XCB] Add test fixtures for xcb connection and keyboard setup
Signed-off-by: Chris Burel <burelc@amazon.com>
This commit is contained in:
@@ -28,6 +28,10 @@ xcb_generic_event_t* xcb_poll_for_event(xcb_connection_t* c)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xcb_poll_for_event(c);
|
||||
}
|
||||
xcb_generic_error_t* xcb_request_check(xcb_connection_t* c, xcb_void_cookie_t cookie)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xcb_request_check(c, cookie);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// xcb-xkb
|
||||
@@ -39,6 +43,10 @@ xcb_xkb_use_extension_reply_t* xcb_xkb_use_extension_reply(xcb_connection_t* c,
|
||||
{
|
||||
return MockXcbInterface::Instance()->xcb_xkb_use_extension_reply(c, cookie, e);
|
||||
}
|
||||
xcb_void_cookie_t xcb_xkb_select_events(xcb_connection_t* c, xcb_xkb_device_spec_t deviceSpec, uint16_t affectWhich, uint16_t clear, uint16_t selectAll, uint16_t affectMap, uint16_t map, const void* details)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xcb_xkb_select_events(c, deviceSpec, affectWhich, clear, selectAll, affectMap, map, details);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// xkb-x11
|
||||
@@ -46,7 +54,7 @@ int32_t xkb_x11_get_core_keyboard_device_id(xcb_connection_t* connection)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_x11_get_core_keyboard_device_id(connection);
|
||||
}
|
||||
struct xkb_keymap* xkb_x11_keymap_new_from_device(struct xkb_context* context, xcb_connection_t* connection, int32_t device_id, enum xkb_keymap_compile_flags flags)
|
||||
xkb_keymap* xkb_x11_keymap_new_from_device(xkb_context* context, xcb_connection_t* connection, int32_t device_id, xkb_keymap_compile_flags flags)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_x11_keymap_new_from_device(context, connection, device_id, flags);
|
||||
}
|
||||
@@ -54,28 +62,46 @@ xkb_state* xkb_x11_state_new_from_device(xkb_keymap* keymap, xcb_connection_t* c
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_x11_state_new_from_device(keymap, connection, device_id);
|
||||
}
|
||||
int xkb_x11_setup_xkb_extension(
|
||||
xcb_connection_t* connection,
|
||||
uint16_t major_xkb_version,
|
||||
uint16_t minor_xkb_version,
|
||||
xkb_x11_setup_xkb_extension_flags flags,
|
||||
uint16_t* major_xkb_version_out,
|
||||
uint16_t* minor_xkb_version_out,
|
||||
uint8_t* base_event_out,
|
||||
uint8_t* base_error_out)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_x11_setup_xkb_extension(
|
||||
connection, major_xkb_version, minor_xkb_version, flags, major_xkb_version_out, minor_xkb_version_out, base_event_out,
|
||||
base_error_out);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// xkbcommon
|
||||
xkb_context* xkb_context_new(enum xkb_context_flags flags)
|
||||
xkb_context* xkb_context_new(xkb_context_flags flags)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_context_new(flags);
|
||||
}
|
||||
void xkb_context_unref(xkb_context *context)
|
||||
void xkb_context_unref(xkb_context* context)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_context_unref(context);
|
||||
}
|
||||
void xkb_keymap_unref(xkb_keymap *keymap)
|
||||
void xkb_keymap_unref(xkb_keymap* keymap)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_keymap_unref(keymap);
|
||||
}
|
||||
void xkb_state_unref(xkb_state *state)
|
||||
void xkb_state_unref(xkb_state* state)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_state_unref(state);
|
||||
}
|
||||
xkb_keysym_t xkb_state_key_get_one_sym(xkb_state *state, xkb_keycode_t key)
|
||||
xkb_keysym_t xkb_state_key_get_one_sym(xkb_state* state, xkb_keycode_t key)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_state_key_get_one_sym(state, key);
|
||||
}
|
||||
int xkb_state_key_get_utf8(xkb_state* state, xkb_keycode_t key, char* buffer, size_t size)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_state_key_get_utf8(state, key, buffer, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <xcb/xkb.h>
|
||||
#undef explicit
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-x11.h>
|
||||
|
||||
#include "Printers.h"
|
||||
|
||||
@@ -35,6 +36,14 @@ struct xkb_keymap
|
||||
|
||||
struct xkb_state
|
||||
{
|
||||
enum class Modifier
|
||||
{
|
||||
None = 0,
|
||||
Shift = 1,
|
||||
Ctrl = 1 << 1,
|
||||
Alt = 1 << 2,
|
||||
};
|
||||
Modifier m_modifiers;
|
||||
};
|
||||
|
||||
class MockXcbInterface
|
||||
@@ -48,7 +57,7 @@ public:
|
||||
MockXcbInterface(MockXcbInterface&&) = delete;
|
||||
MockXcbInterface& operator=(const MockXcbInterface&) = delete;
|
||||
MockXcbInterface& operator=(MockXcbInterface&&) = delete;
|
||||
~MockXcbInterface()
|
||||
virtual ~MockXcbInterface()
|
||||
{
|
||||
self = nullptr;
|
||||
}
|
||||
@@ -59,22 +68,26 @@ public:
|
||||
MOCK_CONST_METHOD2(xcb_connect, xcb_connection_t*(const char* displayname, int* screenp));
|
||||
MOCK_CONST_METHOD1(xcb_disconnect, void(xcb_connection_t* c));
|
||||
MOCK_CONST_METHOD1(xcb_poll_for_event, xcb_generic_event_t*(xcb_connection_t* c));
|
||||
MOCK_CONST_METHOD2(xcb_request_check, xcb_generic_error_t*(xcb_connection_t* c, xcb_void_cookie_t cookie));
|
||||
|
||||
// xcb-xkb
|
||||
MOCK_CONST_METHOD3(xcb_xkb_use_extension, xcb_xkb_use_extension_cookie_t(xcb_connection_t* c, uint16_t wantedMajor, uint16_t wantedMinor));
|
||||
MOCK_CONST_METHOD3(xcb_xkb_use_extension_reply, xcb_xkb_use_extension_reply_t*(xcb_connection_t* c, xcb_xkb_use_extension_cookie_t cookie, xcb_generic_error_t** e));
|
||||
MOCK_CONST_METHOD8(xcb_xkb_select_events, xcb_void_cookie_t(xcb_connection_t* c, xcb_xkb_device_spec_t deviceSpec, uint16_t affectWhich, uint16_t clear, uint16_t selectAll, uint16_t affectMap, uint16_t map, const void* details));
|
||||
|
||||
// xkb-x11
|
||||
MOCK_CONST_METHOD1(xkb_x11_get_core_keyboard_device_id, int32_t(xcb_connection_t* connection));
|
||||
MOCK_CONST_METHOD4(xkb_x11_keymap_new_from_device, xkb_keymap*(xkb_context* context, xcb_connection_t* connection, int32_t device_id, xkb_keymap_compile_flags flags));
|
||||
MOCK_CONST_METHOD3(xkb_x11_state_new_from_device, xkb_state*(xkb_keymap* keymap, xcb_connection_t* connection, int32_t device_id));
|
||||
MOCK_CONST_METHOD8(xkb_x11_setup_xkb_extension, int(xcb_connection_t* connection, uint16_t major_xkb_version, uint16_t minor_xkb_version, xkb_x11_setup_xkb_extension_flags flags, uint16_t* major_xkb_version_out, uint16_t* minor_xkb_version_out, uint8_t* base_event_out, uint8_t* base_error_out));
|
||||
|
||||
// xkbcommon
|
||||
MOCK_CONST_METHOD1(xkb_context_new, xkb_context*(xkb_context_flags flags));
|
||||
MOCK_CONST_METHOD1(xkb_context_unref, void(xkb_context* context));
|
||||
MOCK_CONST_METHOD1(xkb_keymap_unref, void(xkb_keymap* keymap));
|
||||
MOCK_CONST_METHOD1(xkb_state_unref, void(xkb_state* state));
|
||||
MOCK_CONST_METHOD2(xkb_state_key_get_one_sym, xkb_keysym_t(xkb_state *state, xkb_keycode_t key));
|
||||
MOCK_CONST_METHOD2(xkb_state_key_get_one_sym, xkb_keysym_t(xkb_state* state, xkb_keycode_t key));
|
||||
MOCK_CONST_METHOD4(xkb_state_key_get_utf8, int(struct xkb_state* state, xkb_keycode_t key, char* buffer, size_t size));
|
||||
|
||||
private:
|
||||
static inline MockXcbInterface* self = nullptr;
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "XcbBaseTestFixture.h"
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
void XcbBaseTestFixture::SetUp()
|
||||
{
|
||||
using testing::Return;
|
||||
using testing::_;
|
||||
|
||||
testing::Test::SetUp();
|
||||
|
||||
EXPECT_CALL(m_interface, xcb_connect(_, _))
|
||||
.WillOnce(Return(&m_connection));
|
||||
EXPECT_CALL(m_interface, xcb_disconnect(&m_connection))
|
||||
.Times(1);
|
||||
}
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include "MockXcbInterface.h"
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
// Sets up mock behavior for the xcb library, providing an xcb_connection_t that is returned from a call to xcb_connect
|
||||
class XcbBaseTestFixture
|
||||
: public testing::Test
|
||||
{
|
||||
public:
|
||||
void SetUp() override;
|
||||
|
||||
protected:
|
||||
testing::NiceMock<MockXcbInterface> m_interface;
|
||||
xcb_connection_t m_connection{};
|
||||
};
|
||||
} // namespace AzFramework
|
||||
+74
-47
@@ -6,6 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gmock/gmock-actions.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <AzFramework/XcbInputDeviceKeyboard.h>
|
||||
#include "MockXcbInterface.h"
|
||||
#include "Actions.h"
|
||||
#include "XcbBaseTestFixture.h"
|
||||
|
||||
template<typename T>
|
||||
xcb_generic_event_t MakeEvent(T event)
|
||||
@@ -24,26 +26,74 @@ xcb_generic_event_t MakeEvent(T event)
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
TEST(XcbInputDeviceKeyboard, InputChannelsUpdateStateFromXcbEvents)
|
||||
// Sets up default behavior for mock keyboard responses to xcb methods
|
||||
class XcbInputDeviceKeyboardTests
|
||||
: public XcbBaseTestFixture
|
||||
{
|
||||
using testing::Return;
|
||||
void SetUp() override
|
||||
{
|
||||
using testing::Return;
|
||||
using testing::SetArgPointee;
|
||||
using testing::_;
|
||||
|
||||
XcbBaseTestFixture::SetUp();
|
||||
EXPECT_CALL(m_interface, xkb_context_new(XKB_CONTEXT_NO_FLAGS))
|
||||
.WillOnce(Return(&m_xkbContext));
|
||||
EXPECT_CALL(m_interface, xkb_context_unref(&m_xkbContext))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(m_interface, xkb_x11_keymap_new_from_device(&m_xkbContext, &m_connection, s_coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS))
|
||||
.WillOnce(Return(&m_xkbKeymap));
|
||||
EXPECT_CALL(m_interface, xkb_keymap_unref(&m_xkbKeymap))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(m_interface, xkb_x11_state_new_from_device(&m_xkbKeymap, &m_connection, s_coreDeviceId))
|
||||
.WillOnce(Return(&m_xkbState));
|
||||
EXPECT_CALL(m_interface, xkb_state_unref(&m_xkbState))
|
||||
.Times(1);
|
||||
|
||||
ON_CALL(m_interface, xkb_x11_setup_xkb_extension(&m_connection, 1, 0, XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, _, _, _, _))
|
||||
.WillByDefault(DoAll(
|
||||
SetArgPointee<6>(s_xkbEventCode), // Set the "base_event_out" argument to the xkbEventCode, the value to identify XKB events
|
||||
Return(1)
|
||||
));
|
||||
|
||||
constexpr unsigned int xcbXkbSelectEventsSequence = 1;
|
||||
ON_CALL(m_interface, xcb_xkb_select_events(&m_connection, _, _, _, _, _, _, _))
|
||||
.WillByDefault(Return(xcb_void_cookie_t{/*.sequence = */ xcbXkbSelectEventsSequence}));
|
||||
ON_CALL(m_interface, xcb_request_check(&m_connection, testing::Field(&xcb_void_cookie_t::sequence, testing::Eq(xcbXkbSelectEventsSequence))))
|
||||
.WillByDefault(Return(nullptr)); // indicates success
|
||||
|
||||
ON_CALL(m_interface, xkb_x11_get_core_keyboard_device_id(&m_connection))
|
||||
.WillByDefault(Return(s_coreDeviceId));
|
||||
|
||||
ON_CALL(m_interface, xkb_state_key_get_one_sym(&m_xkbState, s_keycodeForAKey))
|
||||
.WillByDefault(Return(XKB_KEY_a))
|
||||
;
|
||||
}
|
||||
|
||||
protected:
|
||||
xkb_context m_xkbContext{};
|
||||
xkb_keymap m_xkbKeymap{};
|
||||
xkb_state m_xkbState{};
|
||||
static constexpr int32_t s_coreDeviceId{1};
|
||||
static constexpr uint8_t s_xkbEventCode{85};
|
||||
static constexpr xcb_keycode_t s_keycodeForAKey{38};
|
||||
};
|
||||
|
||||
TEST_F(XcbInputDeviceKeyboardTests, InputChannelsUpdateStateFromXcbEvents)
|
||||
{
|
||||
using testing::DoAll;
|
||||
using testing::Eq;
|
||||
using testing::Return;
|
||||
using testing::SetArgPointee;
|
||||
using testing::_;
|
||||
MockXcbInterface interface;
|
||||
|
||||
xcb_connection_t connection{};
|
||||
xkb_context xkbContext{};
|
||||
xkb_keymap xkbKeymap{};
|
||||
xkb_state xkbState{};
|
||||
const int32_t coreDeviceId{1};
|
||||
|
||||
constexpr xcb_keycode_t keycodeForAKey = 38;
|
||||
|
||||
const AZStd::array events
|
||||
{
|
||||
MakeEvent(xcb_key_press_event_t{
|
||||
/*.response_type = */ XCB_KEY_PRESS,
|
||||
/*.detail = */ keycodeForAKey,
|
||||
/*.detail = */ s_keycodeForAKey,
|
||||
/*.sequence = */ 0,
|
||||
/*.time = */ 0,
|
||||
/*.root = */ 0,
|
||||
@@ -59,7 +109,7 @@ namespace AzFramework
|
||||
}),
|
||||
MakeEvent(xcb_key_release_event_t{
|
||||
/*.response_type = */ XCB_KEY_RELEASE,
|
||||
/*.detail = */ keycodeForAKey,
|
||||
/*.detail = */ s_keycodeForAKey,
|
||||
/*.sequence = */ 0,
|
||||
/*.time = */ 0,
|
||||
/*.root = */ 0,
|
||||
@@ -75,51 +125,28 @@ namespace AzFramework
|
||||
}),
|
||||
};
|
||||
|
||||
EXPECT_CALL(interface, xcb_connect(_, _))
|
||||
.WillOnce(Return(&connection));
|
||||
EXPECT_CALL(interface, xcb_disconnect(&connection))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(interface, xkb_context_new(XKB_CONTEXT_NO_FLAGS))
|
||||
.WillOnce(Return(&xkbContext));
|
||||
EXPECT_CALL(interface, xkb_context_unref(&xkbContext))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(interface, xkb_x11_keymap_new_from_device(&xkbContext, &connection, coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS))
|
||||
.WillOnce(Return(&xkbKeymap));
|
||||
EXPECT_CALL(interface, xkb_keymap_unref(&xkbKeymap))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(interface, xkb_x11_state_new_from_device(&xkbKeymap, &connection, coreDeviceId))
|
||||
.WillOnce(Return(&xkbState));
|
||||
EXPECT_CALL(interface, xkb_state_unref(&xkbState))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(interface, xcb_xkb_use_extension(&connection, 1, 0));
|
||||
EXPECT_CALL(interface, xcb_xkb_use_extension_reply(&connection, _, _))
|
||||
.WillOnce(ReturnMalloc<xcb_xkb_use_extension_reply_t>(
|
||||
/* .response_type =*/static_cast<uint8_t>(XCB_XKB_USE_EXTENSION),
|
||||
/* .supported =*/ static_cast<uint8_t>(1))
|
||||
);
|
||||
EXPECT_CALL(interface, xkb_x11_get_core_keyboard_device_id(&connection))
|
||||
.WillRepeatedly(Return(coreDeviceId));
|
||||
|
||||
// Set the expectations for the events that will be generated
|
||||
// nullptr entries represent when the event queue is empty, and will cause
|
||||
// PumpSystemEventLoopUntilEmpty to return
|
||||
// event pointers are freed by the calling code, so we malloc new copies
|
||||
// here
|
||||
EXPECT_CALL(interface, xcb_poll_for_event(&connection))
|
||||
EXPECT_CALL(m_interface, xcb_poll_for_event(&m_connection))
|
||||
.WillOnce(ReturnMalloc<xcb_generic_event_t>(events[0]))
|
||||
.WillOnce(Return(nullptr))
|
||||
.WillOnce(ReturnMalloc<xcb_generic_event_t>(events[1]))
|
||||
.WillOnce(Return(nullptr))
|
||||
;
|
||||
|
||||
EXPECT_CALL(interface, xkb_state_key_get_one_sym(&xkbState, keycodeForAKey))
|
||||
.WillOnce(Return(XKB_KEY_a))
|
||||
.WillOnce(Return(XKB_KEY_a))
|
||||
;
|
||||
EXPECT_CALL(m_interface, xkb_state_key_get_one_sym(&m_xkbState, s_keycodeForAKey))
|
||||
.Times(2);
|
||||
|
||||
EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, nullptr, 0))
|
||||
.WillRepeatedly(Return(1));
|
||||
EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, _, 2))
|
||||
.WillRepeatedly(DoAll(
|
||||
SetArgPointee<2>('a'),
|
||||
Return(1)
|
||||
));
|
||||
|
||||
Application application;
|
||||
application.Start({}, {});
|
||||
|
||||
@@ -13,5 +13,7 @@ set(FILES
|
||||
MockXcbInterface.h
|
||||
Printers.cpp
|
||||
Printers.h
|
||||
XcbBaseTestFixture.cpp
|
||||
XcbBaseTestFixture.h
|
||||
XcbInputDeviceKeyboardTests.cpp
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user