diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index 2aafcb4c473..785cf677818 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -440,7 +440,8 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv return; } QByteArray methodName(member+1, bracketPosition - 1 - member); // extract method name - QMetaObject::invokeMethod(const_cast(receiver), methodName.constData(), Qt::QueuedConnection); + QMetaObject::invokeMethod(const_cast(receiver), methodName.trimmed().constData(), + Qt::QueuedConnection); return; } (void) new QSingleShotTimer(msec, timerType, receiver, member); diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp index b4f7aa5bd8d..3e6954355a8 100644 --- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp +++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp @@ -32,6 +32,12 @@ private slots: void zeroTimer(); void singleShotTimeout(); void timeout(); + void singleShotNormalizes_data(); + void singleShotNormalizes(); + void sequentialTimers_data(); + void sequentialTimers(); + void singleShotSequentialTimers_data(); + void singleShotSequentialTimers(); void remainingTime(); void remainingTimeInitial_data(); void remainingTimeInitial(); @@ -120,6 +126,142 @@ void tst_QTimer::timeout() QTRY_VERIFY_WITH_TIMEOUT(timeoutSpy.size() > oldCount, TIMEOUT_TIMEOUT); } +void tst_QTimer::singleShotNormalizes_data() +{ + QTest::addColumn("slotName"); + + QTest::newRow("normalized") << QByteArray(SLOT(exitLoop())); + + QTest::newRow("space-before") << QByteArray(SLOT( exitLoop())); + QTest::newRow("space-after") << QByteArray(SLOT(exitLoop ())); + QTest::newRow("space-around") << QByteArray(SLOT( exitLoop ())); + QTest::newRow("spaces-before") << QByteArray(SLOT( exitLoop())); + QTest::newRow("spaces-after") << QByteArray(SLOT(exitLoop ())); + QTest::newRow("spaces-around") << QByteArray(SLOT( exitLoop ())); + + QTest::newRow("space-in-parens") << QByteArray(SLOT(exitLoop( ))); + QTest::newRow("spaces-in-parens") << QByteArray(SLOT(exitLoop( ))); + QTest::newRow("space-after-parens") << QByteArray(SLOT(exitLoop() )); + QTest::newRow("spaces-after-parens") << QByteArray(SLOT(exitLoop() )); +} + +void tst_QTimer::singleShotNormalizes() +{ + using namespace std::chrono_literals; + static constexpr auto TestTimeout = 250ms; + QFETCH(QByteArray, slotName); + QEventLoop loop; + + // control test: regular connection + { + QTimer timer; + QVERIFY(QObject::connect(&timer, SIGNAL(timeout()), &QTestEventLoop::instance(), slotName)); + timer.setSingleShot(true); + timer.start(1); + QTestEventLoop::instance().enterLoop(TestTimeout); + QVERIFY(!QTestEventLoop::instance().timeout()); + } + + // non-zero time + QTimer::singleShot(1, &QTestEventLoop::instance(), slotName); + QTestEventLoop::instance().enterLoop(TestTimeout); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QTimer::singleShot(1ms, &QTestEventLoop::instance(), slotName); + QTestEventLoop::instance().enterLoop(TestTimeout); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // zero time + QTimer::singleShot(0, &QTestEventLoop::instance(), slotName); + QTestEventLoop::instance().enterLoop(TestTimeout); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QTimer::singleShot(0ms, &QTestEventLoop::instance(), slotName); + QTestEventLoop::instance().enterLoop(TestTimeout); + QVERIFY(!QTestEventLoop::instance().timeout()); +} + +void tst_QTimer::sequentialTimers_data() +{ +#ifdef Q_OS_WIN + QSKIP("The API used by QEventDispatcherWin32 doesn't respect the order"); +#endif + QTest::addColumn>("timeouts"); + auto addRow = [](const QList &l) { + QByteArray name; + int last = -1; + for (int i = 0; i < l.size(); ++i) { + Q_ASSERT_X(l[i] >= last, "tst_QTimer", "input list must be sorted"); + name += QByteArray::number(l[i]) + ','; + } + name.chop(1); + QTest::addRow("%s", name.constData()) << l; + }; + // PreciseTimers + addRow({0, 0, 0, 0, 0, 0}); + addRow({0, 1, 2}); + addRow({1, 1, 1, 2, 2, 2, 2}); + addRow({1, 2, 3}); + addRow({19, 19, 19}); + // CoarseTimer for setInterval + addRow({20, 20, 20, 20, 20}); + addRow({25, 25, 25, 25, 25, 25, 50}); +} + +void tst_QTimer::sequentialTimers() +{ + QFETCH(const QList, timeouts); + QByteArray result, expected; + std::vector> timers; + expected.resize(timeouts.size()); + result.reserve(timeouts.size()); + timers.reserve(timeouts.size()); + for (int i = 0; i < timeouts.size(); ++i) { + auto timer = std::make_unique(); + timer->setSingleShot(true); + timer->setInterval(timeouts[i]); + + char c = 'A' + i; + expected[i] = c; + QObject::connect(timer.get(), &QTimer::timeout, this, [&result, c = c]() { + result.append(c); + }); + timers.push_back(std::move(timer)); + } + + // start the timers + for (auto &timer : timers) + timer->start(); + + QTestEventLoop::instance().enterLoopMSecs(timeouts.last() * 2 + 10); + + QCOMPARE(result, expected); +} + +void tst_QTimer::singleShotSequentialTimers_data() +{ + sequentialTimers_data(); +} + +void tst_QTimer::singleShotSequentialTimers() +{ + QFETCH(const QList, timeouts); + QByteArray result, expected; + expected.resize(timeouts.size()); + result.reserve(timeouts.size()); + for (int i = 0; i < timeouts.size(); ++i) { + char c = 'A' + i; + expected[i] = c; + QTimer::singleShot(timeouts[i], this, [&result, c = c]() { + result.append(c); + }); + } + + QTestEventLoop::instance().enterLoopMSecs(timeouts.last() * 2 + 10); + + QCOMPARE(result, expected); +} + void tst_QTimer::remainingTime() { QTimer tested;