diff --git a/src/wayland/autotests/client/CMakeLists.txt b/src/wayland/autotests/client/CMakeLists.txt index 9fe7dad433..2e33960491 100644 --- a/src/wayland/autotests/client/CMakeLists.txt +++ b/src/wayland/autotests/client/CMakeLists.txt @@ -277,3 +277,14 @@ add_executable(testShadow ${testShadow_SRCS}) target_link_libraries( testShadow Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) add_test(kwayland-testShadow testShadow) ecm_mark_as_test(testShadow) + +######################################################## +# Test FakeInput +######################################################## +set( testFakeInput_SRCS + test_fake_input.cpp + ) +add_executable(testFakeInput ${testFakeInput_SRCS}) +target_link_libraries( testFakeInput Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) +add_test(kwayland-testFakeInput testFakeInput) +ecm_mark_as_test(testFakeInput) diff --git a/src/wayland/autotests/client/test_fake_input.cpp b/src/wayland/autotests/client/test_fake_input.cpp new file mode 100644 index 0000000000..999e97084e --- /dev/null +++ b/src/wayland/autotests/client/test_fake_input.cpp @@ -0,0 +1,321 @@ +/******************************************************************** +Copyright 2016 Martin Gräßlin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +// Qt +#include +// client +#include "../../src/client/connection_thread.h" +#include "../../src/client/event_queue.h" +#include "../../src/client/fakeinput.h" +#include "../../src/client/registry.h" +// server +#include "../../src/server/display.h" +#include "../../src/server/fakeinput_interface.h" + +#include + +using namespace KWayland::Client; +using namespace KWayland::Server; + +Q_DECLARE_METATYPE(Qt::MouseButton) + +class FakeInputTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void init(); + void cleanup(); + + void testAuthenticate(); + void testMotion(); + void testPointerButtonQt_data(); + void testPointerButtonQt(); + void testPointerButtonLinux_data(); + void testPointerButtonLinux(); + void testAxis_data(); + void testAxis(); + +private: + Display *m_display = nullptr; + FakeInputInterface *m_fakeInputInterface = nullptr; + FakeInputDevice *m_device = nullptr; + ConnectionThread *m_connection = nullptr; + QThread *m_thread = nullptr; + EventQueue *m_queue = nullptr; + FakeInput *m_fakeInput = nullptr; +}; + +static const QString s_socketName = QStringLiteral("kwayland-test-fake-input-0"); + +void FakeInputTest::init() +{ + delete m_display; + m_display = new Display(this); + m_display->setSocketName(s_socketName); + m_display->start(); + QVERIFY(m_display->isRunning()); + m_display->createShm(); + m_fakeInputInterface = m_display->createFakeInput(); + m_fakeInputInterface->create(); + QSignalSpy deviceCreatedSpy(m_fakeInputInterface, &FakeInputInterface::deviceCreated); + QVERIFY(deviceCreatedSpy.isValid()); + + // setup connection + m_connection = new KWayland::Client::ConnectionThread; + QSignalSpy connectedSpy(m_connection, &ConnectionThread::connected); + QVERIFY(connectedSpy.isValid()); + m_connection->setSocketName(s_socketName); + + m_thread = new QThread(this); + m_connection->moveToThread(m_thread); + m_thread->start(); + + m_connection->initConnection(); + QVERIFY(connectedSpy.wait()); + + m_queue = new EventQueue(this); + m_queue->setup(m_connection); + + Registry registry; + QSignalSpy interfacesAnnouncedSpy(®istry, &Registry::interfacesAnnounced); + QVERIFY(interfacesAnnouncedSpy.isValid()); + registry.setEventQueue(m_queue); + registry.create(m_connection); + QVERIFY(registry.isValid()); + registry.setup(); + QVERIFY(interfacesAnnouncedSpy.wait()); + + m_fakeInput = registry.createFakeInput(registry.interface(Registry::Interface::FakeInput).name, + registry.interface(Registry::Interface::FakeInput).version, + this); + QVERIFY(m_fakeInput->isValid()); + + QVERIFY(deviceCreatedSpy.wait()); + m_device = deviceCreatedSpy.first().first().value(); + QVERIFY(m_device); +} + +void FakeInputTest::cleanup() +{ +#define CLEANUP(variable) \ + if (variable) { \ + delete variable; \ + variable = nullptr; \ + } + CLEANUP(m_fakeInput) + CLEANUP(m_queue) + if (m_connection) { + m_connection->deleteLater(); + m_connection = nullptr; + } + if (m_thread) { + m_thread->quit(); + m_thread->wait(); + delete m_thread; + m_thread = nullptr; + } + + CLEANUP(m_device) + CLEANUP(m_fakeInputInterface) + CLEANUP(m_display) +#undef CLEANUP +} + +void FakeInputTest::testAuthenticate() +{ + // this test verifies that an authenticate request is passed to the Server + QVERIFY(!m_device->isAuthenticated()); + QSignalSpy authenticationRequestedSpy(m_device, &FakeInputDevice::authenticationRequested); + QVERIFY(authenticationRequestedSpy.isValid()); + + m_fakeInput->authenticate(QStringLiteral("test-case"), QStringLiteral("to test")); + QVERIFY(authenticationRequestedSpy.wait()); + QCOMPARE(authenticationRequestedSpy.count(), 1); + QCOMPARE(authenticationRequestedSpy.first().at(0).toString(), QStringLiteral("test-case")); + QCOMPARE(authenticationRequestedSpy.first().at(1).toString(), QStringLiteral("to test")); + m_device->setAuthentication(true); + QVERIFY(m_device->isAuthenticated()); +} + +void FakeInputTest::testMotion() +{ + // this test verifies that motion is properly passed to the server + QVERIFY(!m_device->isAuthenticated()); + QSignalSpy motionSpy(m_device, &FakeInputDevice::pointerMotionRequested); + QVERIFY(motionSpy.isValid()); + + // without an authentication we shouldn't get the signals + m_fakeInput->requestPointerMove(QSizeF(1, 2)); + QVERIFY(!motionSpy.wait(100)); + + // now let's authenticate the interface + m_device->setAuthentication(true); + m_fakeInput->requestPointerMove(QSizeF(1, 2)); + QVERIFY(motionSpy.wait()); + QCOMPARE(motionSpy.count(), 1); + QCOMPARE(motionSpy.last().first().toSizeF(), QSizeF(1, 2)); + + // just for the fun: once more + m_fakeInput->requestPointerMove(QSizeF(0, 0)); + QVERIFY(motionSpy.wait()); + QCOMPARE(motionSpy.count(), 2); + QCOMPARE(motionSpy.last().first().toSizeF(), QSizeF(0, 0)); +} + +void FakeInputTest::testPointerButtonQt_data() +{ + QTest::addColumn("qtButton"); + QTest::addColumn("linuxButton"); + + QTest::newRow("left") << Qt::LeftButton << quint32(BTN_LEFT); + QTest::newRow("right") << Qt::RightButton << quint32(BTN_RIGHT); + QTest::newRow("middle") << Qt::MiddleButton << quint32(BTN_MIDDLE); +} + +void FakeInputTest::testPointerButtonQt() +{ + // this test verifies that pointer button events are properly passed to the server with Qt button codes + QVERIFY(!m_device->isAuthenticated()); + QSignalSpy pressedSpy(m_device, &FakeInputDevice::pointerButtonPressRequested); + QVERIFY(pressedSpy.isValid()); + QSignalSpy releasedSpy(m_device, &FakeInputDevice::pointerButtonReleaseRequested); + QVERIFY(releasedSpy.isValid()); + + // without an authentication we shouldn't get the signals + QFETCH(Qt::MouseButton, qtButton); + m_fakeInput->requestPointerButtonClick(qtButton); + QVERIFY(!pressedSpy.wait(100)); + QVERIFY(pressedSpy.isEmpty()); + QVERIFY(releasedSpy.isEmpty()); + + // now authenticate + m_device->setAuthentication(true); + // now our click should work + m_fakeInput->requestPointerButtonClick(qtButton); + QVERIFY(releasedSpy.wait()); + QCOMPARE(pressedSpy.count(), 1); + QCOMPARE(releasedSpy.count(), 1); + QTEST(pressedSpy.last().first().value(), "linuxButton"); + QTEST(releasedSpy.last().first().value(), "linuxButton"); + + // and a press/release "manually" + m_fakeInput->requestPointerButtonPress(qtButton); + QVERIFY(pressedSpy.wait()); + QCOMPARE(pressedSpy.count(), 2); + QCOMPARE(releasedSpy.count(), 1); + QTEST(pressedSpy.last().first().value(), "linuxButton"); + // and release + m_fakeInput->requestPointerButtonRelease(qtButton); + QVERIFY(releasedSpy.wait()); + QCOMPARE(pressedSpy.count(), 2); + QCOMPARE(releasedSpy.count(), 2); + QTEST(releasedSpy.last().first().value(), "linuxButton"); +} + +void FakeInputTest::testPointerButtonLinux_data() +{ + QTest::addColumn("linuxButton"); + + QTest::newRow("left") << quint32(BTN_LEFT); + QTest::newRow("right") << quint32(BTN_RIGHT); + QTest::newRow("middle") << quint32(BTN_MIDDLE); + QTest::newRow("side") << quint32(BTN_SIDE); + QTest::newRow("extra") << quint32(BTN_EXTRA); + QTest::newRow("forward") << quint32(BTN_FORWARD); + QTest::newRow("back") << quint32(BTN_BACK); + QTest::newRow("task") << quint32(BTN_TASK); +} + +void FakeInputTest::testPointerButtonLinux() +{ + // this test verifies that pointer button events are properly passed to the server with Qt button codes + QVERIFY(!m_device->isAuthenticated()); + QSignalSpy pressedSpy(m_device, &FakeInputDevice::pointerButtonPressRequested); + QVERIFY(pressedSpy.isValid()); + QSignalSpy releasedSpy(m_device, &FakeInputDevice::pointerButtonReleaseRequested); + QVERIFY(releasedSpy.isValid()); + + // without an authentication we shouldn't get the signals + QFETCH(quint32, linuxButton); + m_fakeInput->requestPointerButtonClick(linuxButton); + QVERIFY(!pressedSpy.wait(100)); + QVERIFY(pressedSpy.isEmpty()); + QVERIFY(releasedSpy.isEmpty()); + + // now authenticate + m_device->setAuthentication(true); + // now our click should work + m_fakeInput->requestPointerButtonClick(linuxButton); + QVERIFY(releasedSpy.wait()); + QCOMPARE(pressedSpy.count(), 1); + QCOMPARE(releasedSpy.count(), 1); + QTEST(pressedSpy.last().first().value(), "linuxButton"); + QTEST(releasedSpy.last().first().value(), "linuxButton"); + + // and a press/release "manually" + m_fakeInput->requestPointerButtonPress(linuxButton); + QVERIFY(pressedSpy.wait()); + QCOMPARE(pressedSpy.count(), 2); + QCOMPARE(releasedSpy.count(), 1); + QTEST(pressedSpy.last().first().value(), "linuxButton"); + // and release + m_fakeInput->requestPointerButtonRelease(linuxButton); + QVERIFY(releasedSpy.wait()); + QCOMPARE(pressedSpy.count(), 2); + QCOMPARE(releasedSpy.count(), 2); + QTEST(releasedSpy.last().first().value(), "linuxButton"); +} + +void FakeInputTest::testAxis_data() +{ + QTest::addColumn("orientation"); + QTest::addColumn("delta"); + + QTest::newRow("horizontal/1") << Qt::Horizontal << 1.0; + QTest::newRow("horizontal/-2") << Qt::Horizontal << -2.0; + QTest::newRow("vertical/10") << Qt::Vertical << 10.0; + QTest::newRow("vertical/-20") << Qt::Vertical << -22.0; +} + +void FakeInputTest::testAxis() +{ + // this test verifies that pointer axis events are properly passed to the server + QVERIFY(!m_device->isAuthenticated()); + QSignalSpy axisSpy(m_device, &FakeInputDevice::pointerAxisRequested); + QVERIFY(axisSpy.isValid()); + + QFETCH(Qt::Orientation, orientation); + QFETCH(qreal, delta); + // without an authentication we shouldn't get the signals + m_fakeInput->requestPointerAxis(orientation, delta); + QVERIFY(!axisSpy.wait(100)); + + // now authenticate + m_device->setAuthentication(true); + + // now we can properly test + m_fakeInput->requestPointerAxis(orientation, delta); + QVERIFY(axisSpy.wait()); + QCOMPARE(axisSpy.count(), 1); + QCOMPARE(axisSpy.first().at(0).value(), orientation); + QCOMPARE(axisSpy.first().at(1).value(), delta); +} + +QTEST_GUILESS_MAIN(FakeInputTest) +#include "test_fake_input.moc"