summaryrefslogtreecommitdiffstats
path: root/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp')
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp80
1 files changed, 60 insertions, 20 deletions
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
index 42f336bc0b..a3698de203 100644
--- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
+++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
@@ -247,7 +247,7 @@ private slots:
void closeAndShowNativeChild();
void closeAndShowWithNativeChild();
void transientParent();
- void qobject_castInDestroyedSlot();
+ void qobject_castOnDestruction();
void showHideEvent_data();
void showHideEvent();
@@ -5390,34 +5390,74 @@ void tst_QWidget::scrollNativeChildren()
#endif // Mac OS
-class DestroyedSlotChecker : public QObject
+/*
+ This class is used as a slot object to test two different steps of
+ QWidget destruction.
+
+ The first step is connecting the destroyed() signal to an object of
+ this class (through its operator()). In widgets, destroyed() is
+ emitted by ~QWidget, and not by ~QObject. This means that in our
+ operator() we expect the sender of the signal to still be a
+ QWidget.
+
+ The connection realized at the first step means that now there's
+ an instance of this class owned by the sender object. That instance
+ is destroyed when the signal/slot connections are destroyed.
+ That happens in ~QObject, not in ~QWidget. Therefore, in the
+ destructor of this class, check that indeed the target is no longer
+ a QWidget but just a QObject.
+*/
+class QObjectCastChecker
{
- Q_OBJECT
-
public:
- bool wasQWidget = false;
+ explicit QObjectCastChecker(QWidget *target)
+ : m_target(target)
+ {
+ }
-public slots:
- void destroyedSlot(QObject *object)
+ ~QObjectCastChecker()
{
- wasQWidget = (qobject_cast<QWidget *>(object) != nullptr || object->isWidgetType());
+ if (!m_target)
+ return;
+
+ // When ~QObject is reached, check that indeed the object is no
+ // longer a QWidget. This relies on slots being disconnected in
+ // ~QObject (and this "slot object" being destroyed there).
+ QVERIFY(!qobject_cast<QWidget *>(m_target));
+ QVERIFY(!dynamic_cast<QWidget *>(m_target));
+ QVERIFY(!m_target->isWidgetType());
}
-};
-/*
- Test that qobject_cast<QWidget*> returns 0 in a slot
- connected to QObject::destroyed.
-*/
-void tst_QWidget::qobject_castInDestroyedSlot()
-{
- DestroyedSlotChecker checker;
+ QObjectCastChecker(QObjectCastChecker &&other) noexcept
+ : m_target(qExchange(other.m_target, nullptr))
+ {}
- QWidget *widget = new QWidget();
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QObjectCastChecker)
- QObject::connect(widget, &QObject::destroyed, &checker, &DestroyedSlotChecker::destroyedSlot);
- delete widget;
+ void swap(QObjectCastChecker &other) noexcept
+ {
+ qSwap(m_target, other.m_target);
+ }
+
+ void operator()(QObject *object) const
+ {
+ // Test that in a slot connected to destroyed() the emitter is
+ // still a QWidget. This is because ~QWidget() itself emits the
+ // signal.
+ QVERIFY(qobject_cast<QWidget *>(object));
+ QVERIFY(dynamic_cast<QWidget *>(object));
+ QVERIFY(object->isWidgetType());
+ }
- QVERIFY(checker.wasQWidget);
+private:
+ Q_DISABLE_COPY(QObjectCastChecker)
+ QObject *m_target;
+};
+
+void tst_QWidget::qobject_castOnDestruction()
+{
+ QWidget widget;
+ QObject::connect(&widget, &QObject::destroyed, QObjectCastChecker(&widget));
}
// Since X11 WindowManager operations are all async, and we have no way to know if the window