Line data Source code
1 : /****************************************************************************
2 : **
3 : ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 : ** Contact: http://www.qt-project.org/legal
5 : **
6 : ** This file is part of the QtTest module of the Qt Toolkit.
7 : **
8 : ** $QT_BEGIN_LICENSE:LGPL$
9 : ** Commercial License Usage
10 : ** Licensees holding valid commercial Qt licenses may use this file in
11 : ** accordance with the commercial license agreement provided with the
12 : ** Software or, alternatively, in accordance with the terms contained in
13 : ** a written agreement between you and Digia. For licensing terms and
14 : ** conditions see http://qt.digia.com/licensing. For further information
15 : ** use the contact form at http://qt.digia.com/contact-us.
16 : **
17 : ** GNU Lesser General Public License Usage
18 : ** Alternatively, this file may be used under the terms of the GNU Lesser
19 : ** General Public License version 2.1 as published by the Free Software
20 : ** Foundation and appearing in the file LICENSE.LGPL included in the
21 : ** packaging of this file. Please review the following information to
22 : ** ensure the GNU Lesser General Public License version 2.1 requirements
23 : ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 : **
25 : ** In addition, as a special exception, Digia gives you certain additional
26 : ** rights. These rights are described in the Digia Qt LGPL Exception
27 : ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 : **
29 : ** GNU General Public License Usage
30 : ** Alternatively, this file may be used under the terms of the GNU
31 : ** General Public License version 3.0 as published by the Free Software
32 : ** Foundation and appearing in the file LICENSE.GPL included in the
33 : ** packaging of this file. Please review the following information to
34 : ** ensure the GNU General Public License version 3.0 requirements will be
35 : ** met: http://www.gnu.org/copyleft/gpl.html.
36 : **
37 : **
38 : ** $QT_END_LICENSE$
39 : **
40 : ****************************************************************************/
41 :
42 : #ifndef QSIGNALSPY_H
43 : #define QSIGNALSPY_H
44 :
45 : #include <QtCore/qbytearray.h>
46 : #include <QtCore/qlist.h>
47 : #include <QtCore/qobject.h>
48 : #include <QtCore/qmetaobject.h>
49 : #include <QtCore/qvariant.h>
50 : #include <QtCore/qvector.h>
51 : #include <QtTest/qtesteventloop.h>
52 :
53 : QT_BEGIN_NAMESPACE
54 :
55 :
56 : class QVariant;
57 :
58 4 : class QSignalSpy: public QObject, public QList<QList<QVariant> >
59 : {
60 : public:
61 4 : explicit QSignalSpy(const QObject *obj, const char *aSignal)
62 4 : : m_waiting(false)
63 : {
64 : #ifdef Q_CC_BOR
65 : const int memberOffset = QObject::staticMetaObject.methodCount();
66 : #else
67 4 : static const int memberOffset = QObject::staticMetaObject.methodCount();
68 : #endif
69 4 : if (!obj) {
70 0 : qWarning("QSignalSpy: Cannot spy on a null object");
71 0 : return;
72 : }
73 :
74 4 : if (!aSignal) {
75 0 : qWarning("QSignalSpy: Null signal name is not valid");
76 0 : return;
77 : }
78 :
79 4 : if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) {
80 0 : qWarning("QSignalSpy: Not a valid signal, use the SIGNAL macro");
81 0 : return;
82 : }
83 :
84 4 : const QByteArray ba = QMetaObject::normalizedSignature(aSignal + 1);
85 4 : const QMetaObject * const mo = obj->metaObject();
86 4 : const int sigIndex = mo->indexOfMethod(ba.constData());
87 4 : if (sigIndex < 0) {
88 0 : qWarning("QSignalSpy: No such signal: '%s'", ba.constData());
89 0 : return;
90 : }
91 :
92 8 : if (!QMetaObject::connect(obj, sigIndex, this, memberOffset,
93 8 : Qt::DirectConnection, 0)) {
94 0 : qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
95 0 : return;
96 : }
97 4 : sig = ba;
98 4 : initArgs(mo->method(sigIndex), obj);
99 : }
100 :
101 : inline bool isValid() const { return !sig.isEmpty(); }
102 : inline QByteArray signal() const { return sig; }
103 :
104 5 : bool wait(int timeout = 5000)
105 : {
106 5 : Q_ASSERT(!m_waiting);
107 5 : const int origCount = count();
108 5 : m_waiting = true;
109 5 : m_loop.enterLoopMSecs(timeout);
110 5 : m_waiting = false;
111 5 : return count() > origCount;
112 : }
113 :
114 5 : int qt_metacall(QMetaObject::Call call, int methodId, void **a) Q_DECL_OVERRIDE
115 : {
116 5 : methodId = QObject::qt_metacall(call, methodId, a);
117 5 : if (methodId < 0)
118 0 : return methodId;
119 :
120 5 : if (call == QMetaObject::InvokeMetaMethod) {
121 5 : if (methodId == 0) {
122 5 : appendArgs(a);
123 : }
124 5 : --methodId;
125 : }
126 5 : return methodId;
127 : }
128 :
129 : private:
130 : void initArgs(const QMetaMethod &member)
131 : {
132 : initArgs(member, 0);
133 : }
134 :
135 4 : void initArgs(const QMetaMethod &member, const QObject *obj)
136 : {
137 4 : const QList<QByteArray> params = member.parameterTypes();
138 4 : args.reserve(params.size());
139 4 : for (int i = 0; i < params.count(); ++i) {
140 0 : int tp = QMetaType::type(params.at(i).constData());
141 0 : if (tp == QMetaType::UnknownType && obj) {
142 0 : void *argv[] = { &tp, &i };
143 : QMetaObject::metacall(const_cast<QObject*>(obj),
144 : QMetaObject::RegisterMethodArgumentMetaType,
145 0 : member.methodIndex(), argv);
146 0 : if (tp == -1)
147 0 : tp = QMetaType::UnknownType;
148 : }
149 0 : if (tp == QMetaType::UnknownType) {
150 0 : Q_ASSERT(tp != QMetaType::Void); // void parameter => metaobject is corrupt
151 : qWarning("Don't know how to handle '%s', use qRegisterMetaType to register it.",
152 0 : params.at(i).constData());
153 : }
154 0 : args << tp;
155 4 : }
156 4 : }
157 :
158 5 : void appendArgs(void **a)
159 : {
160 5 : QList<QVariant> list;
161 5 : list.reserve(args.count());
162 5 : for (int i = 0; i < args.count(); ++i) {
163 0 : const QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
164 0 : if (type == QMetaType::QVariant)
165 0 : list << *reinterpret_cast<QVariant *>(a[i + 1]);
166 : else
167 0 : list << QVariant(type, a[i + 1]);
168 : }
169 5 : append(list);
170 :
171 5 : if (m_waiting)
172 5 : m_loop.exitLoop();
173 5 : }
174 :
175 : // the full, normalized signal name
176 : QByteArray sig;
177 : // holds the QMetaType types for the argument list of the signal
178 : QVector<int> args;
179 :
180 : QTestEventLoop m_loop;
181 : bool m_waiting;
182 : };
183 :
184 : QT_END_NAMESPACE
185 :
186 : #endif
|