1 | // Copyright (C) 2018 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 QTESTSUPPORT_CORE_H |
5 | #define QTESTSUPPORT_CORE_H |
6 | |
7 | #include <QtCore/qcoreapplication.h> |
8 | #include <QtCore/qdeadlinetimer.h> |
9 | |
10 | #include <chrono> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | namespace QTest { |
15 | |
16 | Q_CORE_EXPORT void qSleep(int ms); |
17 | Q_CORE_EXPORT void qSleep(std::chrono::milliseconds msecs); |
18 | |
19 | template <typename Functor> |
20 | [[nodiscard]] bool |
21 | qWaitFor(Functor predicate, QDeadlineTimer deadline = QDeadlineTimer(std::chrono::seconds{5})) |
22 | { |
23 | // We should not spin the event loop in case the predicate is already true, |
24 | // otherwise we might send new events that invalidate the predicate. |
25 | if (predicate()) |
26 | return true; |
27 | |
28 | // qWait() is expected to spin the event loop at least once, even when |
29 | // called with a small timeout like 1ns. |
30 | |
31 | do { |
32 | // We explicitly do not pass the remaining time to processEvents, as |
33 | // that would keep spinning processEvents for the whole duration if |
34 | // new events were posted as part of processing events, and we need |
35 | // to return back to this function to check the predicate between |
36 | // each pass of processEvents. Our own timer will take care of the |
37 | // timeout. |
38 | QCoreApplication::processEvents(flags: QEventLoop::AllEvents); |
39 | QCoreApplication::sendPostedEvents(receiver: nullptr, event_type: QEvent::DeferredDelete); |
40 | |
41 | if (predicate()) |
42 | return true; |
43 | |
44 | using namespace std::chrono; |
45 | |
46 | if (const auto remaining = deadline.remainingTimeAsDuration(); remaining > 0ns) |
47 | qSleep(msecs: (std::min)(a: 10ms, b: ceil<milliseconds>(d: remaining))); |
48 | |
49 | } while (!deadline.hasExpired()); |
50 | |
51 | return predicate(); // Last chance |
52 | } |
53 | |
54 | template <typename Functor> |
55 | [[nodiscard]] bool qWaitFor(Functor predicate, int timeout) |
56 | { |
57 | return qWaitFor(predicate, QDeadlineTimer{timeout, Qt::PreciseTimer}); |
58 | } |
59 | |
60 | Q_CORE_EXPORT void qWait(int ms); |
61 | |
62 | Q_CORE_EXPORT void qWait(std::chrono::milliseconds msecs); |
63 | |
64 | } // namespace QTest |
65 | |
66 | QT_END_NAMESPACE |
67 | |
68 | #endif |
69 | |