Skip to content

Commit

Permalink
QObject: add unittest to check the order of eventFilter() calls
Browse files Browse the repository at this point in the history
installEventFilter() prepends new objects to the eventList, so that
events that are posted while processing events are left to the next
round of event processing.

This is a baseline test to check that subsequent commits preserve the
current behavior.

QCOMPARE_GT is available since Qt6.4, so make the check backportable to
older releases too.

Pick-to: 6.7 6.6 6.5 6.2 5.15
Task-number: QTBUG-120779
Change-Id: I5ed5e9c2917a9be62de4af19c3b72889399b4fe6
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
  • Loading branch information
ahmadsamir committed Feb 1, 2024
1 parent 28db390 commit 1fe88bf
Showing 1 changed file with 75 additions and 0 deletions.
75 changes: 75 additions & 0 deletions tests/auto/corelib/kernel/qobject/tst_qobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ private slots:
void childEvents();
void parentEvents();
void installEventFilter();
void installEventFilterOrder();
void deleteSelfInSlot();
void disconnectSelfInSlotAndDeleteAfterEmit();
void dumpObjectInfo();
Expand Down Expand Up @@ -3165,9 +3166,11 @@ class EventSpy : public QObject
bool eventFilter(QObject *object, QEvent *event) override
{
events.append(qMakePair(object, event->type()));
timeStamp = std::chrono::steady_clock::now();
return false;
}

std::chrono::steady_clock::time_point timeStamp;
private:
EventList events;
};
Expand Down Expand Up @@ -3369,6 +3372,78 @@ void tst_QObject::installEventFilter()
QVERIFY(spy.eventList().isEmpty());
}

void tst_QObject::installEventFilterOrder()
{
// installEventFilter() adds new objects to d_func()->extraData->eventFilters, which
// affects the order of calling each object's eventFilter() when processing the events.

QObject object;
EventSpy spy1;
object.installEventFilter(&spy1);
EventSpy spy2;
object.installEventFilter(&spy2);
EventSpy spy3;
object.installEventFilter(&spy3);

const EventSpy::EventList expected = { {&object, QEvent::Type(QEvent::User + 1)} };
auto checkExpected = [&] {
QCOMPARE(spy1.eventList(), expected);
QCOMPARE(spy2.eventList(), expected);
QCOMPARE(spy3.eventList(), expected);
};

auto clearSignalSpies = [&] {
for (auto *s : {&spy1, &spy2, &spy3})
s->clear();
};

auto checkCallOrder = [](EventSpy &a, EventSpy &b, EventSpy &c) {
QVERIFY(a.timeStamp > b.timeStamp);
QVERIFY(b.timeStamp > c.timeStamp);
};

QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1)));
QCoreApplication::processEvents();

checkExpected();
if (QTest::currentTestFailed())
return;

checkCallOrder(spy1, spy2, spy3);
if (QTest::currentTestFailed())
return;

clearSignalSpies();

// Install event filter for `spy1` again, which reorders spy1 in `eventFilters`
// (the list doesn't have duplicates).
object.installEventFilter(&spy1);

QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1)));
QCoreApplication::processEvents();

checkExpected();
if (QTest::currentTestFailed())
return;

checkCallOrder(spy2, spy3, spy1);
if (QTest::currentTestFailed())
return;

clearSignalSpies();

object.removeEventFilter(&spy3);

QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1)));
QCoreApplication::processEvents();

QVERIFY(spy3.eventList().isEmpty());
QCOMPARE(spy1.eventList(), expected);
QCOMPARE(spy2.eventList(), expected);

QVERIFY(spy2.timeStamp > spy1.timeStamp);
}

class EmitThread : public QThread
{ Q_OBJECT
public:
Expand Down

0 comments on commit 1fe88bf

Please sign in to comment.