1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QTESTEVENTLOOP_H
5#define QTESTEVENTLOOP_H
6
7#include <QtTest/qttestglobal.h>
8#include <QtTest/qtestcase.h>
9
10#include <QtCore/qcoreapplication.h>
11#include <QtCore/qeventloop.h>
12#include <QtCore/qobject.h>
13#include <QtCore/qpointer.h>
14#include <QtCore/qthread.h>
15
16QT_BEGIN_NAMESPACE
17
18
19class Q_TESTLIB_EXPORT QTestEventLoop : public QObject
20{
21 Q_OBJECT
22
23public:
24 QTestEventLoop(QObject *parent = nullptr)
25 : QObject(parent), _timeout(false)
26 {}
27
28 void enterLoopMSecs(int ms) { enterLoop(msecs: std::chrono::milliseconds{ms}); };
29 void enterLoop(int secs) { enterLoop(msecs: std::chrono::seconds{secs}); }
30 inline void enterLoop(std::chrono::milliseconds msecs);
31
32 inline void changeInterval(int secs)
33 { killTimer(id: timerId); timerId = startTimer(interval: secs * 1000); }
34
35 inline bool timeout() const
36 { return _timeout; }
37
38 inline static QTestEventLoop &instance()
39 {
40 Q_CONSTINIT static QPointer<QTestEventLoop> testLoop;
41 if (testLoop.isNull())
42 testLoop = new QTestEventLoop(QCoreApplication::instance());
43 return *static_cast<QTestEventLoop *>(testLoop);
44 }
45
46public Q_SLOTS:
47 inline void exitLoop();
48
49protected:
50 inline void timerEvent(QTimerEvent *e) override;
51
52private:
53 QEventLoop *loop = nullptr;
54 int timerId = -1;
55 uint _timeout :1;
56 Q_DECL_UNUSED_MEMBER uint reserved :31;
57};
58
59inline void QTestEventLoop::enterLoop(std::chrono::milliseconds msecs)
60{
61 Q_ASSERT(!loop);
62 _timeout = false;
63
64 if (QTest::runningTest() && QTest::currentTestResolved())
65 return;
66
67 using namespace std::chrono_literals;
68 QEventLoop l;
69 // if tests want to measure sub-second precision, use a precise timer
70 timerId = startTimer(time: msecs, timerType: msecs < 1s ? Qt::PreciseTimer : Qt::CoarseTimer);
71
72 loop = &l;
73 l.exec();
74 loop = nullptr;
75}
76
77inline void QTestEventLoop::exitLoop()
78{
79 if (thread() != QThread::currentThread())
80 {
81 QMetaObject::invokeMethod(obj: this, member: "exitLoop", c: Qt::QueuedConnection);
82 return;
83 }
84
85 if (timerId != -1)
86 killTimer(id: timerId);
87 timerId = -1;
88
89 if (loop)
90 loop->exit();
91}
92
93inline void QTestEventLoop::timerEvent(QTimerEvent *e)
94{
95 if (e->timerId() != timerId)
96 return;
97 _timeout = true;
98 exitLoop();
99}
100
101QT_END_NAMESPACE
102
103#endif
104

source code of qtbase/src/testlib/qtesteventloop.h