[PATCH v2 2/3] Add XInput 2.x integration test framework
Chase Douglas
chase.douglas at canonical.com
Tue May 15 11:05:26 PDT 2012
Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
---
Changes since v1:
* Split commit into XInput 2.x integration test framework and XIQueryPointer
test
configure.ac | 14 +++
test/integration/.gitignore | 1 +
test/integration/Makefile.am | 24 ++++++
test/integration/xi2.cpp | 194 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 233 insertions(+)
create mode 100644 test/integration/.gitignore
create mode 100644 test/integration/xi2.cpp
diff --git a/configure.ac b/configure.ac
index fe350c9..bc9f46f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2141,6 +2141,20 @@ if [test "x$XORG" = xyes && test "x$enable_integration_tests" != xno]; then
fi
fi
+PKG_CHECK_MODULES(TEST_X11, x11, have_test_x11=yes, have_test_x11=no)
+PKG_CHECK_MODULES(TEST_XINPUT, [xi >= 1.6], have_test_xinput=yes, have_test_xinput=no)
+
+if [test "x$have_test_x11" != xyes]; then
+ AC_MSG_NOTICE([libX11 not available, skipping input tests])
+elif [test "x$have_test_xinput" != xyes]; then
+ AC_MSG_NOTICE([libXi 1.6 not available, skipping input tests])
+elif [test "x$have_xorg_gtest_evemu" != xyes]; then
+ AC_MSG_NOTICE([uTouch-Evemu not available, skipping input tests])
+else
+ enable_input_tests=yes
+fi
+AM_CONDITIONAL(ENABLE_XORG_GTEST_INPUT_TESTS, [test "x$enable_input_tests" = xyes])
+
dnl and the rest of these are generic, so they're in config.h
dnl
dnl though, thanks to the passing of some significant amount of time, the
diff --git a/test/integration/.gitignore b/test/integration/.gitignore
new file mode 100644
index 0000000..ab86ebf
--- /dev/null
+++ b/test/integration/.gitignore
@@ -0,0 +1 @@
+gtest-tests
diff --git a/test/integration/Makefile.am b/test/integration/Makefile.am
index e70d642..3b7c858 100644
--- a/test/integration/Makefile.am
+++ b/test/integration/Makefile.am
@@ -1,4 +1,28 @@
+TESTS =
+
if ENABLE_XORG_GTEST_TESTS
include $(top_srcdir)/test/integration/Makefile-xorg-gtest.am
check_LIBRARIES = $(XORG_GTEST_BUILD_LIBS)
+
+if ENABLE_XORG_GTEST_INPUT_TESTS
+TESTS += gtest-tests
endif
+endif
+
+check_PROGRAMS = $(TESTS)
+
+AM_CPPFLAGS = \
+ -DDEFAULT_XORG_SERVER=\"$(abs_top_builddir)/hw/xfree86/Xorg\" \
+ -DTEST_ROOT_DIR=\"$(abs_top_srcdir)/test/integration/\" \
+ $(GTEST_CPPFLAGS) \
+ $(XORG_GTEST_CPPFLAGS)
+
+AM_CXXFLAGS = $(GTEST_CXXFLAGS) $(XORG_GTEST_CXXFLAGS)
+
+gtest_tests_SOURCES = xi2.cpp
+gtest_tests_LDADD = \
+ $(TEST_XINPUT_LIBS) \
+ $(TEST_X11_LIBS) \
+ $(XORG_GTEST_LIBS) \
+ $(EVEMU_LIBS) \
+ $(XORG_GTEST_MAIN_LIBS)
diff --git a/test/integration/xi2.cpp b/test/integration/xi2.cpp
new file mode 100644
index 0000000..68974a9
--- /dev/null
+++ b/test/integration/xi2.cpp
@@ -0,0 +1,194 @@
+#include <stdexcept>
+
+#include <xorg/gtest/xorg-gtest.h>
+
+#include <X11/extensions/XInput2.h>
+
+namespace {
+
+/**
+ * Wait for an event on the X connection.
+ *
+ * param [in] display The X display connection
+ * param [in] timeout The timeout in milliseconds
+ *
+ * @return Whether an event is available
+ */
+bool wait_for_event(::Display *display, time_t timeout = 1000)
+{
+ fd_set fds;
+ FD_ZERO(&fds);
+
+ int display_fd = ConnectionNumber(display);
+
+ XSync(display, False);
+
+ if (XPending(display))
+ return true;
+ else {
+ FD_SET(display_fd, &fds);
+
+ struct timeval timeval = {
+ static_cast<time_t>(timeout / 1000),
+ static_cast<time_t>(timeout % 1000),
+ };
+
+ int ret;
+ if (timeout)
+ ret = select(display_fd + 1, &fds, NULL, NULL, &timeval);
+ else
+ ret = select(display_fd + 1, &fds, NULL, NULL, NULL);
+
+ if (ret < 0)
+ throw std::runtime_error("Failed to select on X fd");
+
+ if (ret == 0)
+ return false;
+
+ return XPending(display);
+ }
+}
+
+/**
+ * Wait for an event of a specific type on the X connection.
+ *
+ * All events preceding the matching event are discarded. If no event was found
+ * before the timeout expires, all events in the queue will have been discarded.
+ *
+ * param [in] display The X display connection
+ * param [in] type The X core protocol event type
+ * param [in] extension The X extension opcode of a generic event, or -1 for any
+ * generic event
+ * param [in] evtype The X extension event type of a generic event, or -1 for
+ * any event of the given extension
+ * param [in] timeout The timeout in milliseconds
+ *
+ * @return Whether an event is available
+ */
+bool wait_for_event_of_type(::Display *display, int type, int extension,
+ int evtype, time_t timeout = 1000)
+{
+ while (wait_for_event(display)) {
+ XEvent event;
+ if (!XPeekEvent(display, &event))
+ throw std::runtime_error("Failed to peek X event");
+
+ if (event.type != type) {
+ if (XNextEvent(display, &event) != Success)
+ throw std::runtime_error("Failed to remove X event");
+ continue;
+ }
+
+ if (event.type != GenericEvent || extension == -1)
+ return true;
+
+ XGenericEvent *generic_event = reinterpret_cast<XGenericEvent*>(&event);
+
+ if (generic_event->extension != extension) {
+ if (XNextEvent(display, &event) != Success)
+ throw std::runtime_error("Failed to remove X event");
+ continue;
+ }
+
+ if (evtype == -1 || generic_event->evtype == evtype)
+ return true;
+
+ if (XNextEvent(display, &event) != Success)
+ throw std::runtime_error("Failed to remove X event");
+ }
+}
+
+/**
+ * Wait for a specific device to be added to the server.
+ *
+ * param [in] display The X display connection
+ * param [in] name The name of the device to wait for
+ * param [in] timeout The timeout in milliseconds
+ *
+ * @return Whether the device was added
+ */
+bool wait_for_device(::Display *display, const std::string &name,
+ time_t timeout = 1000)
+{
+ int opcode;
+ int event_start;
+ int error_start;
+
+ if (!XQueryExtension(display, "XInputExtension", &opcode, &event_start,
+ &error_start))
+ throw std::runtime_error("Failed to query XInput extension");
+
+ while (wait_for_event_of_type(display, GenericEvent, opcode,
+ XI_HierarchyChanged)) {
+ XEvent event;
+ if (XNextEvent(display, &event) != Success)
+ throw std::runtime_error("Failed to get X event");
+
+ XGenericEventCookie *xcookie =
+ reinterpret_cast<XGenericEventCookie*>(&event.xcookie);
+ if (!XGetEventData(display, xcookie))
+ throw std::runtime_error("Failed to get X event data");
+
+ XIHierarchyEvent *hierarchy_event =
+ reinterpret_cast<XIHierarchyEvent*>(xcookie->data);
+
+ if (!(hierarchy_event->flags & XISlaveAdded)) {
+ XFreeEventData(display, xcookie);
+ continue;
+ }
+
+ bool device_found = false;
+ for (int i = 0; i < hierarchy_event->num_info; i++) {
+ if (!(hierarchy_event->info[i].flags & XISlaveAdded))
+ continue;
+
+ int num_devices;
+ XIDeviceInfo *device_info =
+ XIQueryDevice(display, hierarchy_event->info[i].deviceid,
+ &num_devices);
+ if (num_devices != 1 || !device_info)
+ throw std::runtime_error("Failed to query device");
+
+ if (name.compare(device_info[0].name) == 0) {
+ device_found = true;
+ break;
+ }
+ }
+
+ XFreeEventData(display, xcookie);
+
+ if (device_found)
+ return true;
+ }
+
+ return false;
+}
+
+}
+
+/**
+ * A test fixture for testing the XInput 2.x extension.
+ *
+ * @tparam The XInput 2.x minor version
+ */
+class XInput2Test : public xorg::testing::Test,
+ public ::testing::WithParamInterface<int> {
+protected:
+ virtual void SetUp()
+ {
+ ASSERT_NO_FATAL_FAILURE(xorg::testing::Test::SetUp());
+
+ int event_start;
+ int error_start;
+
+ ASSERT_TRUE(XQueryExtension(Display(), "XInputExtension", &xi2_opcode_,
+ &event_start, &error_start));
+
+ int major = 2;
+ int minor = GetParam();
+
+ ASSERT_EQ(Success, XIQueryVersion(Display(), &major, &minor));
+ }
+
+ int xi2_opcode_;
+};
--
1.7.9.5
More information about the xorg-devel
mailing list