QtTest Testing Class with delayed event
-
Hi,
Out of curiosity, why not use QTest::mouseClick ?
-
But that only works if i directly override
mousePressEvent
in the Cell class or doesn't it?I cannot do that because in reality the
Cell
Events get managed from aCellInputHandler
eventfilter Class which gets the events before to also detect stuff like move events from one to annother widget.That EventFilter normally calls
handleMousePressEvent
More ont this here:
https://forum.qt.io/topic/107430/detect-if-mouse-buttons-are-pressed-when-sliding-into-widget/8
So its then used like this:
bool CellInputHandler::eventFilter(QObject *watched, QEvent *event) { if(event->type() == QEvent::MouseButtonPress){ handleMouseButtonPressEvents(watched, event); return true; } if(event->type() == QEvent::MouseButtonRelease){ handleMouseButtonReleaseEvents(watched, event); return true; } if(event->type() == QEvent::MouseMove) { handleMouseMoveEvents(event); return true; } return false; } void CellInputHandler::handleMouseButtonPressEvents( QObject *watched, QEvent *event) { auto mouseEvent = static_cast<QMouseEvent*>(event); auto cell = qobject_cast<Cell *>(watched); cell->handleMousePressEvent(mouseEvent); }
-
Since you are testing a functionality that requires your custom filter, why not install it as part of your test ?
It would match closer the real situation, no ? -
Yes i guess you are right. I was thinking of making
CellInputHandler
a Singleton because the same Handler needs to be installed on allCells
. That way i could maybe install it in the constructor ofCell
or is that not possible?Currently the parent of all
Cells
holds the Handler and installs it on all theCells
it owns aswell. -
Your current situation is cleaner. There's no need for a singleton.
-
Ok so i adjusted my tests to Test
Cell
with an installedCellInputHandler
.To Check for an click and release event there is no issue:
void TestCell::hitMine_data() { QTest::addColumn<Cell::State>("cellState"); QTest::addColumn<int>("result"); QTest::newRow("has mine") << Cell::State::mine << 1; QTest::newRow("is empty") << Cell::State::empty << 0; } void TestCell::hitMine() { QFETCH(Cell::State, cellState); QFETCH(int, result); CellInputHandler filter; Cell obj{ cellState }; obj.installEventFilter(&filter); QSignalSpy spy(&obj, &Cell::hitMine); QTest::mouseClick(&obj, Qt::LeftButton, Qt::NoModifier); QCOMPARE(spy.count(), result); }
This passes. The Widget gets clicked and released and we have the
hitMine
signal emited.However still doing the right click does not pass:
void TestCell::flagged_data() { QTest::addColumn<Cell::State>("cellState"); QTest::addColumn<int>("result"); QTest::newRow("has mine") << Cell::State::mine << 1; QTest::newRow("is empty") << Cell::State::empty << 1; } void TestCell::flagged() { QFETCH(Cell::State, cellState); QFETCH(int, result); CellInputHandler filter; Cell obj{ cellState }; obj.installEventFilter(&filter); QSignalSpy spy(&obj, &Cell::flagged); QTest::mousePress(&obj, Qt::RightButton, Qt::NoModifier); QTest::mouseRelease(&obj, Qt::RightButton, Qt::NoModifier, obj.rect().center(), 100); QCOMPARE(spy.count(), result); }
here the signal gets emitted when right was clicked and 50ms are passed (See the Description in my first post).
So what am i doing wrong here?
-
I would go with QTest::qWaitFor.
-
This post is deleted!
-
I tryed these two things but both don't work:
QTest::mousePress(&obj, Qt::RightButton, Qt::NoModifier, obj.rect().center()); QTest::qWaitFor([]() { return false; }, 3000); QTest::mouseRelease(&obj, Qt::RightButton, Qt::NoModifier, obj.rect().center(), 100); QCOMPARE(spy.count(), result);
and
QTest::mousePress(&obj, Qt::RightButton, Qt::NoModifier, obj.rect().center()); QTest::mouseRelease(&obj, Qt::RightButton, Qt::NoModifier, obj.rect().center(), 100); QTest::qWaitFor([&]() { return spy.count() == 1; }, 3000); QCOMPARE(spy.count(), result);
-
i solved the issue. I found out that only when I add two press statements with a delay after the second the method works correctly.
I fixed the bug like this:
void Cell::handleMousePressEvent(QMouseEvent *event) { if(!(event->buttons().testFlag(Qt::LeftButton) || event->buttons().testFlag(Qt::RightButton))) { return; } if(event->buttons().testFlag(Qt::LeftButton)) { mSingleMouseTimerLeft.start(); } else if (event->buttons().testFlag(Qt::RightButton)){ mSingleMouseTimerRight.start(); } const auto elapsedTime = mElapsedTimer.restart(); if(elapsedTime < QApplication::doubleClickInterval() && event->buttons().testFlag(Qt::LeftButton) && event->buttons().testFlag(Qt::RightButton)) { if(!isPressed()) { pressIfReleased(); mNeighboursPressed = true; emit pressNeighbours(); } for(QTimer* timer : { &mSingleMouseTimerRight, &mSingleMouseTimerLeft }) { timer->stop(); } return; } }
Before we always slided into
elapsedTime < QApplication::doubleClickInterval
and then the first time:for(QTimer* timer : { &mSingleMouseTimerRight, &mSingleMouseTimerLeft }) { timer->stop(); }
was triggered erasing the passed time. only with two nice delays i could get it to work. Now after fix it works as expected:
void TestCell::flagged() { constexpr auto delayClickRightAndLeftTogether = 50; QFETCH(Cell::State, cellState); QFETCH(int, result); CellInputHandler filter; Cell obj{ cellState }; obj.installEventFilter(&filter); QSignalSpy spy(&obj, &Cell::flagged); QTest::mousePress(&obj, Qt::RightButton, Qt::NoModifier, obj.rect().center()); spy.wait(delayClickRightAndLeftTogether); QCOMPARE(spy.count(), result); }
So i already found a bug. Thats great.
Note: I used
spy.wait
but i think its likeQTest::qWaitFor
Without condition right?
11/11