From 0f5abf0189a8f111e5a3762772f0750bac206ba8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Samuel=20R=C3=B8dal?= Date: Mon, 27 Feb 2012 16:23:39 +0100 Subject: [PATCH] Added auto-test for WaylandCompositor. Change-Id: I2fda66c30736218ee847d9f6827709507c84c301 Reviewed-by: Laszlo Agocs --- qtwayland.pro | 3 +- tests/auto/auto.pro | 2 + tests/auto/compositor/compositor.pro | 10 ++ tests/auto/compositor/mockclient.cpp | 185 +++++++++++++++++++++++++++++ tests/auto/compositor/mockclient.h | 106 +++++++++++++++++ tests/auto/compositor/testcompositor.cpp | 54 +++++++++ tests/auto/compositor/testcompositor.h | 53 +++++++++ tests/auto/compositor/tst_compositor.cpp | 195 +++++++++++++++++++++++++++++++ tests/tests.pro | 2 + 9 files changed, 609 insertions(+), 1 deletion(-) create mode 100644 tests/auto/auto.pro create mode 100644 tests/auto/compositor/compositor.pro create mode 100644 tests/auto/compositor/mockclient.cpp create mode 100644 tests/auto/compositor/mockclient.h create mode 100644 tests/auto/compositor/testcompositor.cpp create mode 100644 tests/auto/compositor/testcompositor.h create mode 100644 tests/auto/compositor/tst_compositor.cpp create mode 100644 tests/tests.pro diff --git a/qtwayland.pro b/qtwayland.pro index 2d56e73..07dea21 100644 --- a/qtwayland.pro +++ b/qtwayland.pro @@ -10,5 +10,6 @@ module_qtcompositor_examples.depends = module_qtcompositor_src module_qtcompositor_examples.CONFIG = no_default_target no_default_install } -SUBDIRS += module_qtcompositor_src \ +SUBDIRS += tests \ + module_qtcompositor_src \ module_qtcompositor_examples \ diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro new file mode 100644 index 0000000..1e1c070 --- /dev/null +++ b/tests/auto/auto.pro @@ -0,0 +1,2 @@ +TEMPLATE=subdirs +SUBDIRS=compositor diff --git a/tests/auto/compositor/compositor.pro b/tests/auto/compositor/compositor.pro new file mode 100644 index 0000000..49fbc1d --- /dev/null +++ b/tests/auto/compositor/compositor.pro @@ -0,0 +1,10 @@ +CONFIG += testcase +TARGET = tst_compositor + +QT += testlib +QT += core-private gui-private compositor + +LIBS += -lwayland-client + +SOURCES += tst_compositor.cpp testcompositor.cpp mockclient.cpp +HEADERS += testcompositor.h mockclient.h diff --git a/tests/auto/compositor/mockclient.cpp b/tests/auto/compositor/mockclient.cpp new file mode 100644 index 0000000..f47f253 --- /dev/null +++ b/tests/auto/compositor/mockclient.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockclient.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include + + +MockClient::MockClient() + : display(wl_display_connect(0)) + , compositor(0) + , output(0) +{ + if (!display) + qFatal("MockClient(): wl_display_connect() failed"); + + wl_display_add_global_listener(display, handleGlobal, this); + + fd = wl_display_get_fd(display, sourceUpdate, 0); + + QSocketNotifier *readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); + connect(readNotifier, SIGNAL(activated(int)), this, SLOT(readEvents())); + + QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; + connect(dispatcher, SIGNAL(awake()), this, SLOT(flushDisplay())); + + QElapsedTimer timeout; + timeout.start(); + do { + QCoreApplication::processEvents(); + } while (!(compositor && output) && timeout.elapsed() < 1000); + + if (!compositor || !output) + qFatal("MockClient(): failed to receive globals from display"); +} + +const wl_output_listener MockClient::outputListener = { + MockClient::outputGeometryEvent, + MockClient::outputModeEvent +}; + +MockClient::~MockClient() +{ + wl_display_disconnect(display); +} + +void MockClient::handleGlobal(wl_display *, uint32_t id, const char *interface, uint32_t, void *data) +{ + resolve(data)->handleGlobal(id, QByteArray(interface)); +} + +int MockClient::sourceUpdate(uint32_t, void *) +{ + return 0; +} + +void MockClient::outputGeometryEvent(void *data, wl_output *, + int32_t x, int32_t y, + int32_t width, int32_t height, + int, const char *, const char *) +{ + resolve(data)->geometry = QRect(x, y, width, height); +} + +void MockClient::outputModeEvent(void *, wl_output *, uint32_t, + int, int, int) +{ +} + +void MockClient::readEvents() +{ + wl_display_iterate(display, WL_DISPLAY_READABLE); +} + +void MockClient::flushDisplay() +{ + wl_display_flush(display); +} + +void MockClient::handleGlobal(uint32_t id, const QByteArray &interface) +{ + if (interface == "wl_compositor") { + compositor = static_cast(wl_display_bind(display, id, &wl_compositor_interface)); + } else if (interface == "wl_output") { + output = static_cast(wl_display_bind(display, id, &wl_output_interface)); + wl_output_add_listener(output, &outputListener, this); + } else if (interface == "wl_shm") { + shm = static_cast(wl_display_bind(display, id, &wl_shm_interface)); + } +} + +wl_surface *MockClient::createSurface() +{ + flushDisplay(); + return wl_compositor_create_surface(compositor); +} + +ShmBuffer::ShmBuffer(const QSize &size, wl_shm *shm) + : handle(0) +{ + int stride = size.width() * 4; + int alloc = stride * size.height(); + + char filename[] = "/tmp/wayland-shm-XXXXXX"; + + int fd = mkstemp(filename); + if (fd < 0) { + qWarning("open %s failed: %s", filename, strerror(errno)); + return; + } + + if (ftruncate(fd, alloc) < 0) { + qWarning("ftruncate failed: %s", strerror(errno)); + close(fd); + return; + } + + void *data = mmap(0, alloc, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + unlink(filename); + + if (data == MAP_FAILED) { + qWarning("mmap failed: %s", strerror(errno)); + close(fd); + return; + } + + image = QImage(static_cast(data), size.width(), size.height(), stride, QImage::Format_ARGB32_Premultiplied); + handle = wl_shm_create_buffer(shm,fd, size.width(), size.height(), + stride, WL_SHM_FORMAT_ARGB8888); + close(fd); +} + +ShmBuffer::~ShmBuffer() +{ + munmap(image.bits(), image.byteCount()); + wl_buffer_destroy(handle); +} + diff --git a/tests/auto/compositor/mockclient.h b/tests/auto/compositor/mockclient.h new file mode 100644 index 0000000..2f2f665 --- /dev/null +++ b/tests/auto/compositor/mockclient.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "wayland-client.h" + +#include +#include +#include + +class ShmBuffer +{ +public: + ShmBuffer(const QSize &size, wl_shm *shm); + ~ShmBuffer(); + + wl_buffer *handle; + QImage image; +}; + +class MockClient : public QObject +{ + Q_OBJECT + +public: + MockClient(); + ~MockClient(); + + wl_surface *createSurface(); + + wl_display *display; + wl_compositor *compositor; + wl_output *output; + wl_shm *shm; + + QRect geometry; + + int fd; + +private slots: + void readEvents(); + void flushDisplay(); + +private: + static MockClient *resolve(void *data) { return static_cast(data); } + + static void handleGlobal(wl_display *display, uint32_t id, const char *interface, uint32_t, void *data); + static int sourceUpdate(uint32_t mask, void *data); + + static void outputGeometryEvent(void *data, + wl_output *output, + int32_t x, int32_t y, + int32_t width, int32_t height, + int subpixel, + const char *make, + const char *model); + + static void outputModeEvent(void *data, + wl_output *wl_output, + uint32_t flags, + int width, + int height, + int refresh); + + void handleGlobal(uint32_t id, const QByteArray &interface); + + static const wl_output_listener outputListener; +}; + diff --git a/tests/auto/compositor/testcompositor.cpp b/tests/auto/compositor/testcompositor.cpp new file mode 100644 index 0000000..f222ba7 --- /dev/null +++ b/tests/auto/compositor/testcompositor.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "testcompositor.h" + +void TestCompositor::surfaceCreated(WaylandSurface *surface) +{ + surfaces << surface; +} + +void TestCompositor::surfaceAboutToBeDestroyed(WaylandSurface *surface) +{ + surfaces.removeOne(surface); +} + + diff --git a/tests/auto/compositor/testcompositor.h b/tests/auto/compositor/testcompositor.h new file mode 100644 index 0000000..580d733 --- /dev/null +++ b/tests/auto/compositor/testcompositor.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "waylandcompositor.h" +#include "waylandsurface.h" + +class TestCompositor : public WaylandCompositor +{ +public: + void surfaceCreated(WaylandSurface *surface); + void surfaceAboutToBeDestroyed(WaylandSurface *surface); + + QList surfaces; +}; + diff --git a/tests/auto/compositor/tst_compositor.cpp b/tests/auto/compositor/tst_compositor.cpp new file mode 100644 index 0000000..0e632c4 --- /dev/null +++ b/tests/auto/compositor/tst_compositor.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockclient.h" +#include "testcompositor.h" + +#include + +class tst_WaylandCompositor : public QObject +{ + Q_OBJECT + +public: + tst_WaylandCompositor() { + setenv("XDG_RUNTIME_DIR", ".", 1); + } + +private slots: + void singleClient(); + void multipleClients(); + void geometry(); + void mapSurface(); + void frameCallback(); +}; + +void tst_WaylandCompositor::singleClient() +{ + TestCompositor compositor; + + MockClient client; + + wl_surface *sa = client.createSurface(); + QTRY_COMPARE(compositor.surfaces.size(), 1); + + wl_surface *sb = client.createSurface(); + QTRY_COMPARE(compositor.surfaces.size(), 2); + + wl_surface_destroy(sa); + QTRY_COMPARE(compositor.surfaces.size(), 1); + + wl_surface_destroy(sb); + QTRY_COMPARE(compositor.surfaces.size(), 0); +} + +void tst_WaylandCompositor::multipleClients() +{ + TestCompositor compositor; + + MockClient a; + MockClient b; + MockClient c; + + wl_surface *sa = a.createSurface(); + wl_surface *sb = b.createSurface(); + wl_surface *sc = c.createSurface(); + + QTRY_COMPARE(compositor.surfaces.size(), 3); + + wl_surface_destroy(sa); + wl_surface_destroy(sb); + wl_surface_destroy(sc); + + QTRY_COMPARE(compositor.surfaces.size(), 0); +} + +void tst_WaylandCompositor::geometry() +{ + TestCompositor compositor; + + QRect geometry(0, 0, 4096, 3072); + compositor.setOutputGeometry(geometry); + + MockClient client; + + QTRY_COMPARE(client.geometry, geometry); +} + +void tst_WaylandCompositor::mapSurface() +{ + TestCompositor compositor; + + MockClient client; + + wl_surface *surface = client.createSurface(); + QTRY_COMPARE(compositor.surfaces.size(), 1); + + WaylandSurface *waylandSurface = compositor.surfaces.at(0); + + QSignalSpy mappedSpy(waylandSurface, SIGNAL(mapped())); + + QCOMPARE(waylandSurface->size(), QSize()); + QCOMPARE(waylandSurface->type(), WaylandSurface::Invalid); + + QSize size(256, 256); + ShmBuffer buffer(size, client.shm); + + wl_surface_attach(surface, buffer.handle, 0, 0); + wl_surface_damage(surface, 0, 0, size.width(), size.height()); + + QTRY_COMPARE(waylandSurface->size(), size); + QTRY_COMPARE(waylandSurface->type(), WaylandSurface::Shm); + QTRY_COMPARE(mappedSpy.count(), 1); + + wl_surface_destroy(surface); +} + +static void frameCallbackFunc(void *data, wl_callback *callback, uint32_t) +{ + ++*static_cast(data); + wl_callback_destroy(callback); +} + +static void registerFrameCallback(wl_surface *surface, int *counter) +{ + static const wl_callback_listener frameCallbackListener = { + frameCallbackFunc + }; + + wl_callback_add_listener(wl_surface_frame(surface), &frameCallbackListener, counter); +} + +void tst_WaylandCompositor::frameCallback() +{ + TestCompositor compositor; + + MockClient client; + + QSize size(8, 8); + ShmBuffer buffer(size, client.shm); + + wl_surface *surface = client.createSurface(); + wl_surface_attach(surface, buffer.handle, 0, 0); + + int frameCounter = 0; + + QTRY_COMPARE(compositor.surfaces.size(), 1); + WaylandSurface *waylandSurface = compositor.surfaces.at(0); + QSignalSpy damagedSpy(waylandSurface, SIGNAL(damaged(const QRect &))); + + for (int i = 0; i < 10; ++i) { + registerFrameCallback(surface, &frameCounter); + wl_surface_damage(surface, 0, 0, size.width(), size.height()); + + QTRY_COMPARE(waylandSurface->type(), WaylandSurface::Shm); + QTRY_COMPARE(damagedSpy.count(), i + 1); + + QCOMPARE(waylandSurface->image(), buffer.image); + waylandSurface->frameFinished(); + + QTRY_COMPARE(frameCounter, i + 1); + } + + wl_surface_destroy(surface); +} + +#include +QTEST_MAIN(tst_WaylandCompositor); diff --git a/tests/tests.pro b/tests/tests.pro new file mode 100644 index 0000000..85e4f3a --- /dev/null +++ b/tests/tests.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS += auto -- 2.7.4