QObject: fix installEventFilterOrder() test flakiness

Don't rely on timer precision and use int counter instead.

Amends 1fe88bf4cd919d4b5cadb4be2cf0193525c54673

Pick-to: 6.6 6.5 6.2 5.15
Change-Id: I057b4dd51014784ec9b244301b43583f3de6ddd1
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
(cherry picked from commit 0d0810e2dcc8a9ee28935af5daadc2ef36ed25a2)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Jarek Kobus 2024-02-03 14:45:34 +01:00 committed by Qt Cherry-pick Bot
parent f48faee770
commit c160f3340e

View File

@ -3142,6 +3142,8 @@ void tst_QObject::blockingQueuedConnection()
}
}
static int s_eventSpyCounter = -1;
class EventSpy : public QObject
{
Q_OBJECT
@ -3161,16 +3163,17 @@ public:
void clear()
{
events.clear();
thisCounter = -1;
}
bool eventFilter(QObject *object, QEvent *event) override
{
events.append(qMakePair(object, event->type()));
timeStamp = std::chrono::steady_clock::now();
thisCounter = ++s_eventSpyCounter;
return false;
}
std::chrono::steady_clock::time_point timeStamp;
int thisCounter = -1;
private:
EventList events;
};
@ -3372,76 +3375,68 @@ void tst_QObject::installEventFilter()
QVERIFY(spy.eventList().isEmpty());
}
#define CHECK_FAIL(message) \
do {\
if (QTest::currentTestFailed())\
QFAIL("failed one line above on " message);\
} while (false)
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);
};
EventSpy spy1, spy2, spy3;
auto clearSignalSpies = [&] {
for (auto *s : {&spy1, &spy2, &spy3})
s->clear();
s_eventSpyCounter = -1;
};
auto checkCallOrder = [](EventSpy &a, EventSpy &b, EventSpy &c) {
QVERIFY(a.timeStamp > b.timeStamp);
QVERIFY(b.timeStamp > c.timeStamp);
const EventSpy::EventList expected = { { &object, QEvent::Type(QEvent::User + 1) } };
// Call Order: from first to last
auto checkCallOrder = [&expected](const QList<EventSpy *> &spies) {
for (int i = 0; i < spies.size(); ++i) {
EventSpy *spy = spies.at(i);
QVERIFY2(spy->eventList() == expected,
QString("The spy %1 wasn't triggered exactly once.").arg(i).toLatin1());
QCOMPARE(spy->thisCounter, i);
}
};
// Install event filters and check the order of invocations:
// The last installed = the first called.
object.installEventFilter(&spy1);
object.installEventFilter(&spy2);
object.installEventFilter(&spy3);
clearSignalSpies();
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();
checkCallOrder({ &spy3, &spy2, &spy1 });
CHECK_FAIL("checkCallOrder() - 1st round");
// 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();
checkCallOrder({ &spy1, &spy3, &spy2 });
CHECK_FAIL("checkCallOrder() - 2nd round");
// Remove event filter for `spy3`, ensure it's not called anymore and the
// existing filters order is preserved.
object.removeEventFilter(&spy3);
clearSignalSpies();
QCoreApplication::postEvent(&object, new QEvent(QEvent::Type(QEvent::User + 1)));
QCoreApplication::processEvents();
checkCallOrder({ &spy1, &spy2 });
CHECK_FAIL("checkCallOrder() - 3rd round");
QVERIFY(spy3.eventList().isEmpty());
QCOMPARE(spy1.eventList(), expected);
QCOMPARE(spy2.eventList(), expected);
QVERIFY(spy2.timeStamp > spy1.timeStamp);
QCOMPARE(spy3.thisCounter, -1);
}
class EmitThread : public QThread