On Tue, May 15, 2012 at 11:05:26AM -0700, Chase Douglas wrote: > Signed-off-by: Chase Douglas <chase.doug...@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)
noinst_PROGRAMS is better here. > + > +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 shouldn't these be @param? Reviewed-by: Peter Hutterer <peter.hutte...@who-t.net> otherwise one question that remains though: my impression was that xorg-gtests would go into the xorg-gtest repo but these are for the xserver repo. What's the plan here? wait_for_event on a Display* seems generic enough that I don't quite understand why this isn't part of the xorg-gtest repo. Cheers, Peter > + * > + * @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 _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel