summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp5
-rw-r--r--src/testlib/qsignalspy.h42
-rw-r--r--src/testlib/qsignalspy.qdoc14
-rw-r--r--tests/auto/testlib/qsignalspy/tst_qsignalspy.cpp168
4 files changed, 229 insertions, 0 deletions
diff --git a/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp b/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp
index e4702c6e0b..0856de9450 100644
--- a/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp
+++ b/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp
@@ -83,3 +83,8 @@ QSignalSpy spy(myPushButton, SIGNAL(clicked(bool)));
//! [5]
QVERIFY(spy.wait(1000));
//! [5]
+
+//! [6]
+QSignalSpy spy(myPushButton, &QPushButton::clicked);
+//! [6]
+
diff --git a/src/testlib/qsignalspy.h b/src/testlib/qsignalspy.h
index 72a5df1ed9..a8a776aff0 100644
--- a/src/testlib/qsignalspy.h
+++ b/src/testlib/qsignalspy.h
@@ -98,6 +98,48 @@ public:
initArgs(mo->method(sigIndex), obj);
}
+#ifdef Q_QDOC
+ QSignalSpy(const QObject *object, PointerToMemberFunction signal);
+#else
+ template <typename Func>
+ QSignalSpy(const typename QtPrivate::FunctionPointer<Func>::Object *obj, Func signal0)
+ : m_waiting(false)
+ {
+#ifdef Q_CC_BOR
+ const int memberOffset = QObject::staticMetaObject.methodCount();
+#else
+ static const int memberOffset = QObject::staticMetaObject.methodCount();
+#endif
+ if (!obj) {
+ qWarning("QSignalSpy: Cannot spy on a null object");
+ return;
+ }
+
+ if (!signal0) {
+ qWarning("QSignalSpy: Null signal name is not valid");
+ return;
+ }
+
+ const QMetaObject * const mo = obj->metaObject();
+ const QMetaMethod signalMetaMethod = QMetaMethod::fromSignal(signal0);
+ const int sigIndex = signalMetaMethod.methodIndex();
+ if (!signalMetaMethod.isValid() ||
+ signalMetaMethod.methodType() != QMetaMethod::Signal) {
+ qWarning("QSignalSpy: Not a valid signal: '%s'",
+ signalMetaMethod.methodSignature().constData());
+ return;
+ }
+
+ if (!QMetaObject::connect(obj, sigIndex, this, memberOffset,
+ Qt::DirectConnection, 0)) {
+ qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
+ return;
+ }
+ sig = signalMetaMethod.methodSignature();
+ initArgs(mo->method(sigIndex), obj);
+ }
+#endif // Q_QDOC
+
inline bool isValid() const { return !sig.isEmpty(); }
inline QByteArray signal() const { return sig; }
diff --git a/src/testlib/qsignalspy.qdoc b/src/testlib/qsignalspy.qdoc
index 9559090e8f..31cdeaba6a 100644
--- a/src/testlib/qsignalspy.qdoc
+++ b/src/testlib/qsignalspy.qdoc
@@ -72,6 +72,20 @@
\snippet code/doc_src_qsignalspy.cpp 4
*/
+/*! \fn QSignalSpy::QSignalSpy(const QObject *object, PointerToMemberFunction signal)
+ \since 5.4
+
+ Constructs a new QSignalSpy that listens for emissions of the \a signal
+ from the QObject \a object. If QSignalSpy is not able to listen for a
+ valid signal (for example, because \a object is null or \a signal does
+ not denote a valid signal of \a object), an explanatory warning message
+ will be output using qWarning() and subsequent calls to \c isValid() will
+ return false.
+
+ Example:
+ \snippet code/doc_src_qsignalspy.cpp 6
+*/
+
/*! \fn QSignalSpy::isValid() const
Returns \c true if the signal spy listens to a valid signal, otherwise false.
diff --git a/tests/auto/testlib/qsignalspy/tst_qsignalspy.cpp b/tests/auto/testlib/qsignalspy/tst_qsignalspy.cpp
index 47d6789327..40e1070fcc 100644
--- a/tests/auto/testlib/qsignalspy/tst_qsignalspy.cpp
+++ b/tests/auto/testlib/qsignalspy/tst_qsignalspy.cpp
@@ -65,6 +65,19 @@ private slots:
void wait_signalEmittedLater();
void wait_signalEmittedTooLate();
void wait_signalEmittedMultipleTimes();
+
+ void spyFunctionPointerWithoutArgs();
+ void spyFunctionPointerWithBasicArgs();
+ void spyFunctionPointerWithPointers();
+ void spyFunctionPointerWithQtClasses();
+ void spyFunctionPointerWithBasicQtClasses();
+ void spyFunctionPointerWithQtTypedefs();
+
+ void waitFunctionPointer_signalEmitted();
+ void waitFunctionPointer_timeout();
+ void waitFunctionPointer_signalEmittedLater();
+ void waitFunctionPointer_signalEmittedTooLate();
+ void waitFunctionPointer_signalEmittedMultipleTimes();
};
class QtTestObject: public QObject
@@ -278,5 +291,160 @@ void tst_QSignalSpy::wait_signalEmittedMultipleTimes()
QCOMPARE(spy.count(), 3);
}
+void tst_QSignalSpy::spyFunctionPointerWithoutArgs()
+{
+ QtTestObject obj;
+
+ QSignalSpy spy(&obj, &QtTestObject::sig0);
+ QCOMPARE(spy.count(), 0);
+
+ emit obj.sig0();
+ QCOMPARE(spy.count(), 1);
+ emit obj.sig0();
+ QCOMPARE(spy.count(), 2);
+
+ QList<QVariant> args = spy.takeFirst();
+ QCOMPARE(args.count(), 0);
+}
+
+void tst_QSignalSpy::spyFunctionPointerWithBasicArgs()
+{
+ QtTestObject obj;
+ QSignalSpy spy(&obj, &QtTestObject::sig1);
+
+ emit obj.sig1(1, 2);
+ QCOMPARE(spy.count(), 1);
+
+ QList<QVariant> args = spy.takeFirst();
+ QCOMPARE(args.count(), 2);
+ QCOMPARE(args.at(0).toInt(), 1);
+ QCOMPARE(args.at(1).toInt(), 2);
+
+ QSignalSpy spyl(&obj, &QtTestObject::sigLong);
+
+ emit obj.sigLong(1l, 2l);
+ args = spyl.takeFirst();
+ QCOMPARE(args.count(), 2);
+ QCOMPARE(qvariant_cast<long>(args.at(0)), 1l);
+ QCOMPARE(qvariant_cast<long>(args.at(1)), 2l);
+}
+
+
+void tst_QSignalSpy::spyFunctionPointerWithPointers()
+{
+ qRegisterMetaType<int *>("int*");
+
+ QtTestObject obj;
+ QSignalSpy spy(&obj, &QtTestObject::sig2);
+
+ int i1 = 1;
+ int i2 = 2;
+
+ emit obj.sig2(&i1, &i2);
+ QCOMPARE(spy.count(), 1);
+
+ QList<QVariant> args = spy.takeFirst();
+ QCOMPARE(args.count(), 2);
+ QCOMPARE(*static_cast<int * const *>(args.at(0).constData()), &i1);
+ QCOMPARE(*static_cast<int * const *>(args.at(1).constData()), &i2);
+}
+
+void tst_QSignalSpy::spyFunctionPointerWithBasicQtClasses()
+{
+ QtTestObject2 obj;
+
+ QSignalSpy spy(&obj, &QtTestObject2::sig);
+ emit obj.sig(QString("bubu"));
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.at(0).count(), 1);
+ QCOMPARE(spy.at(0).at(0).toString(), QString("bubu"));
+
+ QSignalSpy spy2(&obj, &QtTestObject2::sig5);
+ QVariant val(45);
+ emit obj.sig5(val);
+ QCOMPARE(spy2.count(), 1);
+ QCOMPARE(spy2.at(0).count(), 1);
+ QCOMPARE(spy2.at(0).at(0), val);
+ QCOMPARE(qvariant_cast<QVariant>(spy2.at(0).at(0)), val);
+}
+
+void tst_QSignalSpy::spyFunctionPointerWithQtClasses()
+{
+ QtTestObject2 obj;
+
+ QSignalSpy spy(&obj, &QtTestObject2::sig2);
+ QDateTime dt = QDateTime::currentDateTime();
+ emit obj.sig2(dt);
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.at(0).count(), 1);
+ QCOMPARE(spy.at(0).at(0).typeName(), "QDateTime");
+ QCOMPARE(*static_cast<const QDateTime *>(spy.at(0).at(0).constData()), dt);
+ QCOMPARE(spy.at(0).at(0).toDateTime(), dt);
+
+ QSignalSpy spy2(&obj, &QtTestObject2::sig3);
+ emit obj.sig3(this);
+ QCOMPARE(*static_cast<QObject * const *>(spy2.value(0).value(0).constData()),
+ (QObject *)this);
+ QCOMPARE(qvariant_cast<QObject *>(spy2.value(0).value(0)), (QObject*)this);
+
+ QSignalSpy spy3(&obj, &QtTestObject2::sig4);
+ emit obj.sig4(QChar('A'));
+ QCOMPARE(qvariant_cast<QChar>(spy3.value(0).value(0)), QChar('A'));
+}
+
+void tst_QSignalSpy::spyFunctionPointerWithQtTypedefs()
+{
+ QtTestObject3 obj;
+
+ QSignalSpy spy2(&obj, &QtTestObject3::sig2);
+ emit obj.sig2(42, 43);
+ QCOMPARE(spy2.value(0).value(0).toInt(), 42);
+ QCOMPARE(spy2.value(0).value(1).toInt(), 43);
+}
+
+void tst_QSignalSpy::waitFunctionPointer_signalEmitted()
+{
+ QTimer::singleShot(0, this, SIGNAL(sigFoo()));
+ QSignalSpy spy(this, &tst_QSignalSpy::sigFoo);
+ QVERIFY(spy.wait(1));
+}
+
+void tst_QSignalSpy::waitFunctionPointer_timeout()
+{
+ QSignalSpy spy(this, &tst_QSignalSpy::sigFoo);
+ QVERIFY(!spy.wait(1));
+}
+
+void tst_QSignalSpy::waitFunctionPointer_signalEmittedLater()
+{
+ QTimer::singleShot(500, this, SIGNAL(sigFoo()));
+ QSignalSpy spy(this, &tst_QSignalSpy::sigFoo);
+ QVERIFY(spy.wait(1000));
+}
+
+void tst_QSignalSpy::waitFunctionPointer_signalEmittedTooLate()
+{
+ QTimer::singleShot(500, this, SIGNAL(sigFoo()));
+ QSignalSpy spy(this, &tst_QSignalSpy::sigFoo);
+ QVERIFY(!spy.wait(200));
+ QTest::qWait(400);
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_QSignalSpy::waitFunctionPointer_signalEmittedMultipleTimes()
+{
+ QTimer::singleShot(100, this, SIGNAL(sigFoo()));
+ QTimer::singleShot(800, this, SIGNAL(sigFoo()));
+ QSignalSpy spy(this, &tst_QSignalSpy::sigFoo);
+ QVERIFY(spy.wait());
+ QCOMPARE(spy.count(), 1); // we don't wait for the second signal...
+ QVERIFY(spy.wait());
+ QCOMPARE(spy.count(), 2);
+ QVERIFY(!spy.wait(1));
+ QTimer::singleShot(10, this, SIGNAL(sigFoo()));
+ QVERIFY(spy.wait());
+ QCOMPARE(spy.count(), 3);
+}
+
QTEST_MAIN(tst_QSignalSpy)
#include "tst_qsignalspy.moc"