diff options
author | Johan Klokkhammer Helsing <johan.helsing@qt.io> | 2019-02-14 10:26:48 +0100 |
---|---|---|
committer | Johan Helsing <johan.helsing@qt.io> | 2019-02-20 14:13:13 +0000 |
commit | 81e154e264274907e329bfb1d54d20e0db0bbfd2 (patch) | |
tree | 5d3dd97d2dc1c5e421c9887ed23a9b6557906ba7 /tests/auto/client/shared | |
parent | eb66211ea9b58537a21630893229c7d3c86a10b3 (diff) |
Client: Add test for wl_data_offer leaks
Also refactors the mocking code for data device manager and implements its
isClean method to verify there are no leaks after each test.
MockCompositor::DataDevice now persists across get_data_device requests.
Task-number: QTBUG-73825
Change-Id: Ib5866e0c54d021e12557f9a96f27950010f2611b
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
Diffstat (limited to 'tests/auto/client/shared')
-rw-r--r-- | tests/auto/client/shared/coreprotocol.h | 3 | ||||
-rw-r--r-- | tests/auto/client/shared/datadevice.cpp | 54 | ||||
-rw-r--r-- | tests/auto/client/shared/datadevice.h | 36 |
3 files changed, 76 insertions, 17 deletions
diff --git a/tests/auto/client/shared/coreprotocol.h b/tests/auto/client/shared/coreprotocol.h index 699dcbded..5cef476c8 100644 --- a/tests/auto/client/shared/coreprotocol.h +++ b/tests/auto/client/shared/coreprotocol.h @@ -250,9 +250,6 @@ public: Keyboard* m_keyboard = nullptr; QVector<Keyboard *> m_oldKeyboards; - DataDevice *dataDevice() { return m_dataDevice.data(); } - QScopedPointer<DataDevice> m_dataDevice; - uint m_capabilities = 0; protected: diff --git a/tests/auto/client/shared/datadevice.cpp b/tests/auto/client/shared/datadevice.cpp index c136c7596..dfa18952c 100644 --- a/tests/auto/client/shared/datadevice.cpp +++ b/tests/auto/client/shared/datadevice.cpp @@ -30,29 +30,60 @@ namespace MockCompositor { +bool DataDeviceManager::isClean() +{ + for (auto *device : qAsConst(m_dataDevices)) { + // The client should not leak selection offers, i.e. if this fails, there is a missing + // data_offer.destroy request + if (!device->m_sentSelectionOffers.empty()) + return false; + } + return true; +} + +DataDevice *DataDeviceManager::deviceFor(Seat *seat) +{ + Q_ASSERT(seat); + if (auto *device = m_dataDevices.value(seat, nullptr)) + return device; + + auto *device = new DataDevice(this, seat); + m_dataDevices[seat] = device; + return device; +} + void DataDeviceManager::data_device_manager_get_data_device(Resource *resource, uint32_t id, wl_resource *seatResource) { auto *seat = fromResource<Seat>(seatResource); QVERIFY(seat); - QVERIFY(!seat->m_dataDevice); - seat->m_dataDevice.reset(new DataDevice(resource->client(), id, resource->version())); + auto *device = deviceFor(seat); + device->add(resource->client(), id, resource->version()); } DataDevice::~DataDevice() { - // If the client hasn't deleted the wayland object, just ignore subsequent events - if (auto *r = resource()->handle) - wl_resource_set_implementation(r, nullptr, nullptr, nullptr); + // If the client(s) hasn't deleted the wayland object, just ignore subsequent events + for (auto *r : resourceMap()) + wl_resource_set_implementation(r->handle, nullptr, nullptr, nullptr); } -void DataDevice::sendDataOffer(DataOffer *offer) +DataOffer *DataDevice::sendDataOffer(wl_client *client, const QStringList &mimeTypes) { - wl_data_device::send_data_offer(offer->resource()->handle); + Q_ASSERT(client); + auto *offer = new DataOffer(this, client, m_manager->m_version); + for (auto *resource : resourceMap().values(client)) + wl_data_device::send_data_offer(resource->handle, offer->resource()->handle); + for (const auto &mimeType : mimeTypes) + offer->send_offer(mimeType); + return offer; } void DataDevice::sendSelection(DataOffer *offer) { - wl_data_device::send_selection(offer->resource()->handle); + auto *client = offer->resource()->client(); + for (auto *resource : resourceMap().values(client)) + wl_data_device::send_selection(resource->handle, offer->resource()->handle); + m_sentSelectionOffers << offer; } void DataOffer::data_offer_destroy_resource(Resource *resource) @@ -67,4 +98,11 @@ void DataOffer::data_offer_receive(Resource *resource, const QString &mime_type, emit receive(mime_type, fd); } +void DataOffer::data_offer_destroy(QtWaylandServer::wl_data_offer::Resource *resource) +{ + bool removed = m_dataDevice->m_sentSelectionOffers.removeOne(this); + QVERIFY(removed); + wl_resource_destroy(resource->handle); +} + } // namespace MockCompositor diff --git a/tests/auto/client/shared/datadevice.h b/tests/auto/client/shared/datadevice.h index 4613db776..a96da86f0 100644 --- a/tests/auto/client/shared/datadevice.h +++ b/tests/auto/client/shared/datadevice.h @@ -42,8 +42,14 @@ class DataDeviceManager : public Global, public QtWaylandServer::wl_data_device_ public: explicit DataDeviceManager(CoreCompositor *compositor, int version = 1) : QtWaylandServer::wl_data_device_manager(compositor->m_display, version) + , m_version(version) {} - QVector<DataDevice *> m_dataDevices; + ~DataDeviceManager() override { qDeleteAll(m_dataDevices); } + bool isClean() override; + DataDevice *deviceFor(Seat *seat); + + int m_version = 1; // TODO: remove on libwayland upgrade + QMap<Seat *, DataDevice *> m_dataDevices; protected: void data_device_manager_get_data_device(Resource *resource, uint32_t id, ::wl_resource *seatResource) override; @@ -52,24 +58,42 @@ protected: class DataDevice : public QtWaylandServer::wl_data_device { public: - explicit DataDevice(::wl_client *client, int id, int version) - : QtWaylandServer::wl_data_device(client, id, version) + explicit DataDevice(DataDeviceManager *manager, Seat *seat) + : m_manager(manager) + , m_seat(seat) {} ~DataDevice() override; void send_data_offer(::wl_resource *resource) = delete; - void sendDataOffer(DataOffer *offer); + DataOffer *sendDataOffer(::wl_client *client, const QStringList &mimeTypes = {}); + DataOffer *sendDataOffer(const QStringList &mimeTypes = {}); + void send_selection(::wl_resource *resource) = delete; void sendSelection(DataOffer *offer); + + DataDeviceManager *m_manager = nullptr; + Seat *m_seat = nullptr; + QVector<DataOffer *> m_sentSelectionOffers; + +protected: + void data_device_release(Resource *resource) override + { + int removed = m_manager->m_dataDevices.remove(m_seat); + QVERIFY(removed); + wl_resource_destroy(resource->handle); + } }; class DataOffer : public QObject, public QtWaylandServer::wl_data_offer { Q_OBJECT public: - explicit DataOffer(::wl_client *client, int version) + explicit DataOffer(DataDevice *dataDevice, ::wl_client *client, int version) : QtWaylandServer::wl_data_offer (client, 0, version) + , m_dataDevice(dataDevice) {} + DataDevice *m_dataDevice = nullptr; + signals: void receive(QString mimeType, int fd); @@ -77,7 +101,7 @@ protected: void data_offer_destroy_resource(Resource *resource) override; void data_offer_receive(Resource *resource, const QString &mime_type, int32_t fd) override; // void data_offer_accept(Resource *resource, uint32_t serial, const QString &mime_type) override; -// void data_offer_destroy(Resource *resource) override; + void data_offer_destroy(Resource *resource) override; }; } // namespace MockCompositor |