// Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #include #include #include #include #include #include #include static const int minResolution = 400; // the minimum resolution for the tests QT_BEGIN_NAMESPACE namespace QTest { template<> char *toString(const QDeadlineTimer &dt) { if (dt.isForever()) return qstrdup("QDeadlineTimer::Forever"); qint64 deadline = dt.deadlineNSecs(); char *buf = new char[256]; qsnprintf(buf, 256, "%lld.%09d%s", deadline / 1000 / 1000 / 1000, qAbs(deadline) % (1000 * 1000 * 1000), dt.hasExpired() ? " (expired)" : ""); return buf; } } QT_END_NAMESPACE class tst_QDeadlineTimer : public QObject { Q_OBJECT private Q_SLOTS: void basics(); void foreverness(); void current(); void deadlines(); void setDeadline(); void overflow(); void expire(); void stdchrono(); }; static constexpr auto timerType = Qt::PreciseTimer; void tst_QDeadlineTimer::basics() { QDeadlineTimer deadline; QCOMPARE(deadline.timerType(), Qt::CoarseTimer); deadline = QDeadlineTimer(timerType); QCOMPARE(deadline.timerType(), timerType); QVERIFY(!deadline.isForever()); QCOMPARE(deadline, QDeadlineTimer(timerType)); QVERIFY(!(deadline != QDeadlineTimer(timerType))); QVERIFY(!(deadline < QDeadlineTimer())); QCOMPARE_LE(deadline, QDeadlineTimer()); QCOMPARE_GE(deadline, QDeadlineTimer()); QVERIFY(!(deadline > QDeadlineTimer())); QVERIFY(!(deadline < deadline)); QCOMPARE_LE(deadline, deadline); QCOMPARE_GE(deadline, deadline); QVERIFY(!(deadline > deadline)); // should have expired, but we may be running too early after boot QTRY_VERIFY_WITH_TIMEOUT(deadline.hasExpired(), 100); QCOMPARE(deadline.remainingTime(), qint64(0)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(0)); QCOMPARE(deadline.deadline(), qint64(0)); QCOMPARE(deadline.deadlineNSecs(), qint64(0)); deadline.setRemainingTime(0, timerType); QCOMPARE(deadline.remainingTime(), qint64(0)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(0)); QCOMPARE_NE(deadline.deadline(), 0); QCOMPARE_NE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE_NE(deadline.deadlineNSecs(), 0); QCOMPARE_NE(deadline.deadlineNSecs(), std::numeric_limits::max()); deadline.setPreciseRemainingTime(0, 0, timerType); QCOMPARE(deadline.remainingTime(), qint64(0)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(0)); QCOMPARE_NE(deadline.deadline(), 0); QCOMPARE_NE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE_NE(deadline.deadlineNSecs(), 0); QCOMPARE_NE(deadline.deadlineNSecs(), std::numeric_limits::max()); deadline.setDeadline(0, timerType); QCOMPARE(deadline.remainingTime(), qint64(0)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(0)); QCOMPARE(deadline.deadline(), qint64(0)); QCOMPARE(deadline.deadlineNSecs(), qint64(0)); deadline.setPreciseDeadline(0, 0, timerType); QCOMPARE(deadline.remainingTime(), qint64(0)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(0)); QCOMPARE(deadline.deadline(), qint64(0)); QCOMPARE(deadline.deadlineNSecs(), qint64(0)); } void tst_QDeadlineTimer::foreverness() { QDeadlineTimer deadline = QDeadlineTimer::Forever; QCOMPARE(deadline.timerType(), Qt::CoarseTimer); QVERIFY(deadline.isForever()); QVERIFY(!deadline.hasExpired()); QCOMPARE(deadline.remainingTime(), qint64(-1)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(-1)); QCOMPARE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE(deadline.deadlineNSecs(), std::numeric_limits::max()); deadline = QDeadlineTimer(-1, timerType); QVERIFY(deadline.isForever()); QVERIFY(!deadline.hasExpired()); QCOMPARE(deadline.remainingTime(), qint64(-1)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(-1)); QCOMPARE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE(deadline.deadlineNSecs(), std::numeric_limits::max()); deadline.setRemainingTime(-1, timerType); QVERIFY(deadline.isForever()); QVERIFY(!deadline.hasExpired()); QCOMPARE(deadline.remainingTime(), qint64(-1)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(-1)); QCOMPARE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE(deadline.deadlineNSecs(), std::numeric_limits::max()); deadline.setPreciseRemainingTime(-1, 0, timerType); QVERIFY(deadline.isForever()); QVERIFY(!deadline.hasExpired()); QCOMPARE(deadline.remainingTime(), qint64(-1)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(-1)); QCOMPARE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE(deadline.deadlineNSecs(), std::numeric_limits::max()); deadline.setPreciseRemainingTime(-1, -1, timerType); QVERIFY(deadline.isForever()); QVERIFY(!deadline.hasExpired()); QCOMPARE(deadline.remainingTime(), qint64(-1)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(-1)); QCOMPARE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE(deadline.deadlineNSecs(), std::numeric_limits::max()); deadline.setDeadline(std::numeric_limits::max(), timerType); QVERIFY(deadline.isForever()); QVERIFY(!deadline.hasExpired()); QCOMPARE(deadline.remainingTime(), qint64(-1)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(-1)); QCOMPARE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE(deadline.deadlineNSecs(), std::numeric_limits::max()); deadline.setPreciseDeadline(std::numeric_limits::max(), 0, timerType); QVERIFY(deadline.isForever()); QVERIFY(!deadline.hasExpired()); QCOMPARE(deadline.remainingTime(), qint64(-1)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(-1)); QCOMPARE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE(deadline.deadlineNSecs(), std::numeric_limits::max()); QCOMPARE(deadline, deadline); QVERIFY(!(deadline < deadline)); QCOMPARE_LE(deadline, deadline); QCOMPARE_GE(deadline, deadline); QVERIFY(!(deadline > deadline)); // adding to forever must still be forever QDeadlineTimer deadline2 = deadline + 1; QVERIFY(deadline2.isForever()); QVERIFY(!deadline2.hasExpired()); QCOMPARE(deadline2.remainingTime(), qint64(-1)); QCOMPARE(deadline2.remainingTimeNSecs(), qint64(-1)); QCOMPARE(deadline2.deadline(), std::numeric_limits::max()); QCOMPARE(deadline2.deadlineNSecs(), std::numeric_limits::max()); QCOMPARE(deadline2.timerType(), deadline.timerType()); QCOMPARE(deadline2 - deadline, qint64(0)); QCOMPARE(deadline2, deadline); QVERIFY(!(deadline2 < deadline)); QCOMPARE_LE(deadline2, deadline); QCOMPARE_GE(deadline2, deadline); QVERIFY(!(deadline2 > deadline)); // subtracting from forever is *also* forever deadline2 = deadline - 1; QVERIFY(deadline2.isForever()); QVERIFY(!deadline2.hasExpired()); QCOMPARE(deadline2.remainingTime(), qint64(-1)); QCOMPARE(deadline2.remainingTimeNSecs(), qint64(-1)); QCOMPARE(deadline2.deadline(), std::numeric_limits::max()); QCOMPARE(deadline2.deadlineNSecs(), std::numeric_limits::max()); QCOMPARE(deadline2.timerType(), deadline.timerType()); QCOMPARE(deadline2 - deadline, qint64(0)); QCOMPARE(deadline2, deadline); QVERIFY(!(deadline2 < deadline)); QCOMPARE_LE(deadline2, deadline); QCOMPARE_GE(deadline2, deadline); QVERIFY(!(deadline2 > deadline)); // compare and order against a default-constructed object QDeadlineTimer expired; QVERIFY(!(deadline == expired)); QCOMPARE_NE(deadline, expired); QVERIFY(!(deadline < expired)); QVERIFY(!(deadline <= expired)); QCOMPARE_GE(deadline, expired); QCOMPARE_GT(deadline, expired); } void tst_QDeadlineTimer::current() { auto deadline = QDeadlineTimer::current(timerType); QVERIFY(deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE(deadline.remainingTime(), qint64(0)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(0)); QCOMPARE_NE(deadline.deadline(), 0); QCOMPARE_NE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE_NE(deadline.deadlineNSecs(), 0); QCOMPARE_NE(deadline.deadlineNSecs(), std::numeric_limits::max()); // subtracting from current should be "more expired" QDeadlineTimer earlierDeadline = deadline - 1; QVERIFY(earlierDeadline.hasExpired()); QVERIFY(!earlierDeadline.isForever()); QCOMPARE(earlierDeadline.timerType(), timerType); QCOMPARE(earlierDeadline.remainingTime(), qint64(0)); QCOMPARE(earlierDeadline.remainingTimeNSecs(), qint64(0)); QCOMPARE_NE(earlierDeadline.deadline(), 0); QCOMPARE_NE(earlierDeadline.deadline(), std::numeric_limits::max()); QCOMPARE_NE(earlierDeadline.deadlineNSecs(), 0); QCOMPARE_NE(earlierDeadline.deadlineNSecs(), std::numeric_limits::max()); QCOMPARE(earlierDeadline.deadline(), deadline.deadline() - 1); QCOMPARE(earlierDeadline.deadlineNSecs(), deadline.deadlineNSecs() - 1000*1000); QCOMPARE(earlierDeadline - deadline, qint64(-1)); QCOMPARE_NE(earlierDeadline, deadline); QCOMPARE_LT(earlierDeadline, deadline); QCOMPARE_LE(earlierDeadline, deadline); QVERIFY(!(earlierDeadline >= deadline)); QVERIFY(!(earlierDeadline > deadline)); } void tst_QDeadlineTimer::deadlines() { QDeadlineTimer deadline(4 * minResolution, timerType); QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE_GT(deadline.remainingTime(), (3 * minResolution)); QCOMPARE_LE(deadline.remainingTime(), (4 * minResolution)); QCOMPARE_GT(deadline.remainingTimeNSecs(), (3000000 * minResolution)); QCOMPARE_LE(deadline.remainingTimeNSecs(), (4000000 * minResolution)); QCOMPARE_NE(deadline.deadline(), 0); QCOMPARE_NE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE_NE(deadline.deadlineNSecs(), 0); QCOMPARE_NE(deadline.deadlineNSecs(), std::numeric_limits::max()); deadline.setRemainingTime(4 * minResolution, timerType); QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE_GT(deadline.remainingTime(), (3 * minResolution)); QCOMPARE_LE(deadline.remainingTime(), (4 * minResolution)); QCOMPARE_GT(deadline.remainingTimeNSecs(), (3000000 * minResolution)); QCOMPARE_LE(deadline.remainingTimeNSecs(), (4000000 * minResolution)); QCOMPARE_NE(deadline.deadline(), 0); QCOMPARE_NE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE_NE(deadline.deadlineNSecs(), 0); QCOMPARE_NE(deadline.deadlineNSecs(), std::numeric_limits::max()); deadline.setPreciseRemainingTime(0, 4000000 * minResolution, timerType); QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE_GT(deadline.remainingTime(), (3 * minResolution)); QCOMPARE_LE(deadline.remainingTime(), (4 * minResolution)); QCOMPARE_GT(deadline.remainingTimeNSecs(), (3000000 * minResolution)); QCOMPARE_LE(deadline.remainingTimeNSecs(), (4000000 * minResolution)); QCOMPARE_NE(deadline.deadline(), 0); QCOMPARE_NE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE_NE(deadline.deadlineNSecs(), 0); QCOMPARE_NE(deadline.deadlineNSecs(), std::numeric_limits::max()); deadline.setPreciseRemainingTime(1, 0, timerType); // 1 sec QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE_GT(deadline.remainingTime(), (1000 - minResolution)); QCOMPARE_LE(deadline.remainingTime(), 1000); QCOMPARE_GT(deadline.remainingTimeNSecs(), (1000 - minResolution)*1000*1000); QCOMPARE_LE(deadline.remainingTimeNSecs(), (1000*1000*1000)); QCOMPARE_NE(deadline.deadline(), 0); QCOMPARE_NE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE_NE(deadline.deadlineNSecs(), 0); QCOMPARE_NE(deadline.deadlineNSecs(), std::numeric_limits::max()); // adding to a future deadline must still be further in the future QDeadlineTimer laterDeadline = deadline + 1; QVERIFY(!laterDeadline.hasExpired()); QVERIFY(!laterDeadline.isForever()); QCOMPARE(laterDeadline.timerType(), timerType); QCOMPARE_GT(laterDeadline.remainingTime(), (1000 - minResolution)); QCOMPARE_LE(laterDeadline.remainingTime(), 1001); QCOMPARE_GT(laterDeadline.remainingTimeNSecs(), (1001 - minResolution)*1000*1000); QCOMPARE_LE(laterDeadline.remainingTimeNSecs(), (1001*1000*1000)); QCOMPARE_NE(laterDeadline.deadline(), 0); QCOMPARE_NE(laterDeadline.deadline(), std::numeric_limits::max()); QCOMPARE_NE(laterDeadline.deadlineNSecs(), 0); QCOMPARE_NE(laterDeadline.deadlineNSecs(), std::numeric_limits::max()); QCOMPARE(laterDeadline.deadline(), deadline.deadline() + 1); QCOMPARE(laterDeadline.deadlineNSecs(), deadline.deadlineNSecs() + 1000*1000); QCOMPARE(laterDeadline - deadline, qint64(1)); QCOMPARE_NE(laterDeadline, deadline); QVERIFY(!(laterDeadline < deadline)); QVERIFY(!(laterDeadline <= deadline)); QCOMPARE_GE(laterDeadline, deadline); QCOMPARE_GT(laterDeadline, deadline); // compare and order against a default-constructed object QDeadlineTimer expired; QVERIFY(!(deadline == expired)); QCOMPARE_NE(deadline, expired); QVERIFY(!(deadline < expired)); QVERIFY(!(deadline <= expired)); QCOMPARE_GE(deadline, expired); QCOMPARE_GT(deadline, expired); // compare and order against a forever deadline QDeadlineTimer forever_(QDeadlineTimer::Forever); QVERIFY(!(deadline == forever_)); QCOMPARE_NE(deadline, forever_); QCOMPARE_LT(deadline, forever_); QCOMPARE_LE(deadline, forever_); QVERIFY(!(deadline >= forever_)); QVERIFY(!(deadline > forever_)); } void tst_QDeadlineTimer::setDeadline() { auto now = QDeadlineTimer::current(timerType); QDeadlineTimer deadline; deadline.setDeadline(now.deadline(), timerType); QVERIFY(deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE(deadline.remainingTime(), qint64(0)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(0)); QCOMPARE(deadline.deadline(), now.deadline()); // don't check deadlineNSecs! deadline.setPreciseDeadline(now.deadlineNSecs() / (1000 * 1000 * 1000), now.deadlineNSecs() % (1000 * 1000 * 1000), timerType); QVERIFY(deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE(deadline.remainingTime(), qint64(0)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(0)); QCOMPARE(deadline.deadline(), now.deadline()); QCOMPARE(deadline.deadlineNSecs(), now.deadlineNSecs()); now = QDeadlineTimer::current(timerType); deadline.setDeadline(now.deadline() + 4 * minResolution, timerType); QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE_GT(deadline.remainingTime(), (3 * minResolution)); QCOMPARE_LE(deadline.remainingTime(), (4 * minResolution)); QCOMPARE_GT(deadline.remainingTimeNSecs(), (3000000 * minResolution)); QCOMPARE_LE(deadline.remainingTimeNSecs(), (4000000 * minResolution)); QCOMPARE(deadline.deadline(), now.deadline() + 4 * minResolution); // yes, it's exact // don't check deadlineNSecs! now = QDeadlineTimer::current(timerType); qint64 nsec = now.deadlineNSecs() + 4000000 * minResolution; deadline.setPreciseDeadline(nsec / (1000 * 1000 * 1000), nsec % (1000 * 1000 * 1000), timerType); QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE_GT(deadline.remainingTime(), (3 * minResolution)); QCOMPARE_LE(deadline.remainingTime(), (4 * minResolution)); QCOMPARE_GT(deadline.remainingTimeNSecs(), (3000000 * minResolution)); QCOMPARE_LE(deadline.remainingTimeNSecs(), (4000000 * minResolution)); QCOMPARE(deadline.deadline(), nsec / (1000 * 1000)); QCOMPARE(deadline.deadlineNSecs(), nsec); } void tst_QDeadlineTimer::overflow() { // Check the constructor for overflows (should also cover saturating the result of the deadline() method if overflowing) QDeadlineTimer now = QDeadlineTimer::current(timerType), deadline(std::numeric_limits::max() - 1, timerType); QVERIFY(deadline.isForever() || deadline.deadline() >= now.deadline()); // Check the setDeadline with milliseconds (should also cover implicitly setting the nanoseconds as qint64 max) deadline.setDeadline(std::numeric_limits::max() - 1, timerType); QVERIFY(deadline.isForever() || deadline.deadline() >= now.deadline()); // Check the setRemainingTime with milliseconds (should also cover implicitly setting the nanoseconds as qint64 max) deadline.setRemainingTime(std::numeric_limits::max() - 1, timerType); QVERIFY(deadline.isForever() || deadline.deadline() >= now.deadline()); // Check that the deadline gets saturated when the arguments of setPreciseDeadline are large deadline.setPreciseDeadline(std::numeric_limits::max() - 1, std::numeric_limits::max() - 1, timerType); QCOMPARE(deadline.deadline(), std::numeric_limits::max()); QVERIFY(deadline.isForever()); // Check that remainingTime gets saturated if we overflow deadline.setPreciseRemainingTime(std::numeric_limits::max() - 1, std::numeric_limits::max() - 1, timerType); QCOMPARE(deadline.remainingTime(), qint64(-1)); QVERIFY(deadline.isForever()); // Check that we saturate the getter for nanoseconds deadline.setPreciseDeadline(std::numeric_limits::max() - 1, 0, timerType); QCOMPARE(deadline.deadlineNSecs(), std::numeric_limits::max()); // Check that adding nanoseconds and overflowing is consistent and saturates the timer deadline = QDeadlineTimer::addNSecs(deadline, std::numeric_limits::max() - 1); QVERIFY(deadline.isForever()); // Make sure forever is forever, regardless of us subtracting time from it deadline = QDeadlineTimer(QDeadlineTimer::Forever, timerType); deadline = QDeadlineTimer::addNSecs(deadline, -10000); QVERIFY(deadline.isForever()); // Make sure we get the correct result when moving the deadline back and forth in time QDeadlineTimer current = QDeadlineTimer::current(timerType); QDeadlineTimer takenNSecs = QDeadlineTimer::addNSecs(current, -1000); QVERIFY(takenNSecs.deadlineNSecs() - current.deadlineNSecs() == -1000); QDeadlineTimer addedNSecs = QDeadlineTimer::addNSecs(current, 1000); QVERIFY(addedNSecs.deadlineNSecs() - current.deadlineNSecs() == 1000); // Make sure the calculation goes as expected when we need to subtract nanoseconds // We make use of an additional timer to be certain that // even when the environment is under load we can track the // time needed to do the calls static constexpr qint64 nsExpected = 1000 * 1000 * 1000 - 1000; // 1s - 1000ns, what we pass to setPreciseRemainingTime() later QElapsedTimer callTimer; callTimer.start(); deadline = QDeadlineTimer::current(timerType); qint64 nsDeadline = deadline.deadlineNSecs(); // We adjust in relation to current() here, so we expect the difference to be a tad over the exact number. // However we are tracking the elapsed time, so it shouldn't be a problem. deadline.setPreciseRemainingTime(1, -1000, timerType); qint64 difference = (deadline.deadlineNSecs() - nsDeadline) - nsExpected; QCOMPARE_GE(difference, 0); // Should always be true, but just in case QCOMPARE_LE(difference, callTimer.nsecsElapsed()); // Ideally difference should be 0 exactly // Make sure setRemainingTime underflows gracefully deadline.setPreciseRemainingTime(std::numeric_limits::min() / 10, 0, timerType); QVERIFY(deadline.isForever()); // The above could underflow, so make sure we did set to Forever QCOMPARE(deadline.remainingTimeNSecs(), -1); QCOMPARE(deadline.remainingTime(), -1); // If the timer is saturated we don't want to get a valid number of milliseconds QCOMPARE(deadline.deadline(), std::numeric_limits::max()); // Check that the conversion to milliseconds and nanoseconds underflows gracefully deadline.setPreciseDeadline(std::numeric_limits::min() / 10, 0, timerType); QVERIFY(!deadline.isForever()); // The above underflows, make sure we don't saturate to Forever QVERIFY(deadline.deadline() == std::numeric_limits::min()); QVERIFY(deadline.deadlineNSecs() == std::numeric_limits::min()); // Check that subtracting max() twice doesn't make it become positive deadline.setPreciseDeadline(0); deadline -= std::numeric_limits::max(); deadline -= std::numeric_limits::max(); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.deadline(), std::numeric_limits::min()); QCOMPARE(deadline.deadlineNSecs(), std::numeric_limits::min()); // Ditto for adding max() deadline.setPreciseDeadline(0); deadline += std::numeric_limits::max(); deadline += std::numeric_limits::max(); QVERIFY(deadline.isForever()); // it's so far in the future it's effectively forever QCOMPARE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE(deadline.deadlineNSecs(), std::numeric_limits::max()); // But we don't un-become forever after saturation deadline -= std::numeric_limits::max(); QVERIFY(deadline.isForever()); QCOMPARE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE(deadline.deadlineNSecs(), std::numeric_limits::max()); } void tst_QDeadlineTimer::expire() { QDeadlineTimer deadline(minResolution, timerType); QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); qint64 previousDeadline = deadline.deadlineNSecs(); QTest::qSleep(2 * minResolution); QCOMPARE(deadline.remainingTime(), qint64(0)); QCOMPARE(deadline.remainingTimeNSecs(), qint64(0)); QCOMPARE_NE(deadline.deadline(), 0); QCOMPARE_NE(deadline.deadline(), std::numeric_limits::max()); QCOMPARE_NE(deadline.deadlineNSecs(), 0); QCOMPARE_NE(deadline.deadlineNSecs(), std::numeric_limits::max()); QCOMPARE(deadline.deadlineNSecs(), previousDeadline); } void tst_QDeadlineTimer::stdchrono() { using namespace std::chrono; using namespace std::chrono_literals; // create some forevers QDeadlineTimer deadline = milliseconds::max(); QVERIFY(deadline.isForever()); deadline = milliseconds::max(); QVERIFY(deadline.isForever()); deadline.setRemainingTime(milliseconds::max(), timerType); QVERIFY(deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); deadline = nanoseconds::max(); QVERIFY(deadline.isForever()); deadline.setRemainingTime(nanoseconds::max(), timerType); QVERIFY(deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); deadline = hours::max(); QVERIFY(deadline.isForever()); deadline.setRemainingTime(hours::max(), timerType); QVERIFY(deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); deadline = time_point::max(); QVERIFY(deadline.isForever()); deadline.setDeadline(time_point::max(), timerType); QVERIFY(deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); deadline = time_point::max(); QVERIFY(deadline.isForever()); deadline.setDeadline(time_point::max(), timerType); QVERIFY(deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QVERIFY(deadline == time_point::max()); QVERIFY(deadline == time_point::max()); QCOMPARE(deadline.remainingTimeAsDuration(), nanoseconds::max()); // make it expired deadline = time_point(); QVERIFY(deadline.hasExpired()); deadline.setDeadline(time_point(), timerType); QVERIFY(deadline.hasExpired()); QCOMPARE(deadline.timerType(), timerType); deadline = time_point(); QVERIFY(deadline.hasExpired()); deadline.setDeadline(time_point(), timerType); QVERIFY(deadline.hasExpired()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE(deadline.remainingTimeAsDuration(), nanoseconds::zero()); QDeadlineTimer now; bool timersExecuted = false; auto steady_before = steady_clock::now(); auto system_before = system_clock::now(); decltype(steady_before) steady_after, steady_deadline; decltype(system_before) system_after, system_deadline; QTimer::singleShot(minResolution, Qt::PreciseTimer, [&]() { now = QDeadlineTimer::current(timerType); QTimer::singleShot(minResolution, Qt::PreciseTimer, [&]() { steady_deadline = now.deadline(); system_deadline = now.deadline(); steady_after = steady_clock::now(); system_after = system_clock::now(); timersExecuted = true; }); }); QTRY_VERIFY2_WITH_TIMEOUT(timersExecuted, "Looks like timers didn't fire on time.", 4 * minResolution); { qint64 before = duration_cast(steady_before.time_since_epoch()).count(); qint64 after = duration_cast(steady_after.time_since_epoch()).count(); QCOMPARE_GT(now.deadlineNSecs(), before); QCOMPARE_LT(now.deadlineNSecs(), after); } { auto diff = duration_cast(steady_after - steady_deadline); QCOMPARE_GT(diff.count(), minResolution / 2); QCOMPARE_LT(diff.count(), 3 * minResolution / 2); QDeadlineTimer dt_after(steady_after, timerType); QCOMPARE_LT(now, dt_after); diff = duration_cast(steady_deadline - steady_before); QCOMPARE_GT(diff.count(), minResolution / 2); QCOMPARE_LT(diff.count(), 3 * minResolution / 2); QDeadlineTimer dt_before(steady_before, timerType); QCOMPARE_GT(now, dt_before); } { auto diff = duration_cast(system_after - system_deadline); QCOMPARE_GT(diff.count(), minResolution / 2); QCOMPARE_LT(diff.count(), 3 * minResolution / 2); QDeadlineTimer dt_after(system_after, timerType); QCOMPARE_LT(now, dt_after); diff = duration_cast(system_deadline - system_before); QCOMPARE_GT(diff.count(), minResolution / 2); QCOMPARE_LT(diff.count(), 3 * minResolution / 2); QDeadlineTimer dt_before(system_before, timerType); QCOMPARE_GT(now, dt_before); } // make it regular now = QDeadlineTimer::current(timerType); deadline.setRemainingTime(4ms * minResolution, timerType); QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE_GT(deadline.remainingTimeAsDuration(), 3ms * minResolution); QCOMPARE_LT(deadline.remainingTimeAsDuration(), 5ms * minResolution); QCOMPARE_GT(deadline.remainingTimeAsDuration(), 3'000'000ns * minResolution); QCOMPARE_LT(deadline.remainingTimeAsDuration(), 5'000'000ns * minResolution); QCOMPARE_GT(deadline.deadline(), (steady_clock::now() + 3ms * minResolution)); QCOMPARE_LT(deadline.deadline(), (steady_clock::now() + 5ms * minResolution)); QCOMPARE_GT(deadline.deadline(), (system_clock::now() + 3ms * minResolution)); QCOMPARE_LT(deadline.deadline(), (system_clock::now() + 5ms * minResolution)); QCOMPARE_GT((deadline.deadline()), steady_clock::now() + 3ms * minResolution); QCOMPARE_LT((deadline.deadline()), steady_clock::now() + 5ms * minResolution); QCOMPARE_GT((deadline.deadline()), system_clock::now() + 3ms * minResolution); QCOMPARE_LT((deadline.deadline()), system_clock::now() + 5ms * minResolution); QCOMPARE_GT(deadline, now + 3ms * minResolution); QCOMPARE_LT(deadline, now + 5ms * minResolution); QCOMPARE_GT(deadline, now + 3000000ns * minResolution); QCOMPARE_LT(deadline, now + 5000000ns * minResolution); QCOMPARE_GT(deadline, 3ms * minResolution); QCOMPARE_LT(deadline, 5ms * minResolution); QCOMPARE_GT(deadline, 3000000ns * minResolution); QCOMPARE_LT(deadline, 5000000ns * minResolution); QCOMPARE_GE(deadline, steady_clock::now()); QCOMPARE_GE(deadline, system_clock::now()); now = QDeadlineTimer::current(timerType); deadline = QDeadlineTimer(1s, timerType); QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE_GT(deadline.remainingTimeAsDuration(), 1s - 1ms * minResolution); QCOMPARE_LE(deadline.remainingTimeAsDuration(), 1s); QCOMPARE_GT(deadline.deadline(), steady_clock::now() + 1s - 1ms * minResolution); QCOMPARE_LE(deadline.deadline(), steady_clock::now() + 1s + 1ms * minResolution); QCOMPARE_GT(deadline.deadline(), system_clock::now() + 1s - 1ms * minResolution); QCOMPARE_LE(deadline.deadline(), system_clock::now() + 1s + 1ms * minResolution); QCOMPARE_GT(deadline, 1s - 1ms * minResolution); QCOMPARE_LE(deadline, 1s); now = QDeadlineTimer::current(timerType); deadline.setRemainingTime(1h, timerType); QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE_GT(deadline.remainingTimeAsDuration(), 1h - 1ms * minResolution); QCOMPARE_LE(deadline.remainingTimeAsDuration(), 1h); QCOMPARE_GT(deadline.deadline(), steady_clock::now() + 1h - 1ms * minResolution); QCOMPARE_LE(deadline.deadline(), steady_clock::now() + 1h + 1ms * minResolution); QCOMPARE_GT(deadline.deadline(), system_clock::now() + 1h - 1ms * minResolution); QCOMPARE_LE(deadline.deadline(), system_clock::now() + 1h + 1ms * minResolution); now = QDeadlineTimer::current(timerType); deadline.setDeadline(system_clock::now() + 1s, timerType); QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE_GT(deadline.remainingTimeAsDuration(), 1s - 1ms * minResolution); QCOMPARE_LE(deadline.remainingTimeAsDuration(), 1s); QCOMPARE_GT(deadline.deadline(), steady_clock::now() + 1s - 1ms * minResolution); QCOMPARE_LE(deadline.deadline(), steady_clock::now() + 1s + 1ms * minResolution); QCOMPARE_GT(deadline.deadline(), system_clock::now() + 1s - 1ms * minResolution); QCOMPARE_LE(deadline.deadline(), system_clock::now() + 1s + 1ms * minResolution); now = QDeadlineTimer::current(timerType); deadline.setDeadline(steady_clock::now() + 1s, timerType); QVERIFY(!deadline.hasExpired()); QVERIFY(!deadline.isForever()); QCOMPARE(deadline.timerType(), timerType); QCOMPARE_GT(deadline.remainingTimeAsDuration(), 1s - 1ms * minResolution); QCOMPARE_LE(deadline.remainingTimeAsDuration(), 1s); QCOMPARE_GT(deadline.deadline(), steady_clock::now() + 1s - 1ms * minResolution); QCOMPARE_LE(deadline.deadline(), steady_clock::now() + 1s + 1ms * minResolution); QCOMPARE_GT(deadline.deadline(), system_clock::now() + 1s - 1ms * minResolution); QCOMPARE_LE(deadline.deadline(), system_clock::now() + 1s + 1ms * minResolution); } QTEST_MAIN(tst_QDeadlineTimer) #include "tst_qdeadlinetimer.moc"