In tst_qqmlnotifier, verify the result of QObject::receivers()
[profile/ivi/qtdeclarative.git] / tests / auto / qml / qqmlnotifier / tst_qqmlnotifier.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Research In Motion
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the test suite 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 #include <qtest.h>
42 #include <QDebug>
43 #include <QQmlEngine>
44 #include <QQmlComponent>
45 #include <QQmlContext>
46 #include <qqml.h>
47 #include <QMetaMethod>
48
49 #include "../../shared/util.h"
50
51 class ExportedClass : public QObject
52 {
53     Q_OBJECT
54     Q_PROPERTY(int qmlObjectProp READ qmlObjectProp NOTIFY qmlObjectPropChanged)
55     Q_PROPERTY(int cppObjectProp READ cppObjectProp NOTIFY cppObjectPropChanged)
56     Q_PROPERTY(int unboundProp READ unboundProp NOTIFY unboundPropChanged)
57     Q_PROPERTY(int v8BindingProp READ v8BindingProp NOTIFY v8BindingPropChanged)
58     Q_PROPERTY(int v4BindingProp READ v4BindingProp NOTIFY v4BindingPropChanged)
59     Q_PROPERTY(int v4BindingProp2 READ v4BindingProp2 NOTIFY v4BindingProp2Changed)
60     Q_PROPERTY(int scriptBindingProp READ scriptBindingProp NOTIFY scriptBindingPropChanged)
61 public:
62     int qmlObjectPropConnections;
63     int cppObjectPropConnections;
64     int unboundPropConnections;
65     int v8BindingPropConnections;
66     int v4BindingPropConnections;
67     int v4BindingProp2Connections;
68     int scriptBindingPropConnections;
69     int boundSignalConnections;
70     int unusedSignalConnections;
71
72     ExportedClass()
73         : qmlObjectPropConnections(0), cppObjectPropConnections(0), unboundPropConnections(0),
74           v8BindingPropConnections(0), v4BindingPropConnections(0), v4BindingProp2Connections(0),
75           scriptBindingPropConnections(0), boundSignalConnections(0), unusedSignalConnections(0)
76     {}
77
78     ~ExportedClass()
79     {
80         QCOMPARE(qmlObjectPropConnections, 0);
81         QCOMPARE(cppObjectPropConnections, 0);
82         QCOMPARE(unboundPropConnections, 0);
83         QCOMPARE(v8BindingPropConnections, 0);
84         QCOMPARE(v4BindingPropConnections, 0);
85         QCOMPARE(v4BindingProp2Connections, 0);
86         QCOMPARE(scriptBindingPropConnections, 0);
87         QCOMPARE(boundSignalConnections, 0);
88         QCOMPARE(unusedSignalConnections, 0);
89     }
90
91     int qmlObjectProp() const { return 42; }
92     int unboundProp() const { return 42; }
93     int v8BindingProp() const { return 42; }
94     int v4BindingProp() const { return 42; }
95     int v4BindingProp2() const { return 42; }
96     int cppObjectProp() const { return 42; }
97     int scriptBindingProp() const { return 42; }
98
99     void verifyReceiverCount()
100     {
101         QCOMPARE(receivers(SIGNAL(qmlObjectPropChanged())), qmlObjectPropConnections);
102         QCOMPARE(receivers(SIGNAL(cppObjectPropChanged())), cppObjectPropConnections);
103         QCOMPARE(receivers(SIGNAL(unboundPropChanged())), unboundPropConnections);
104         QCOMPARE(receivers(SIGNAL(v8BindingPropChanged())), v8BindingPropConnections);
105         QCOMPARE(receivers(SIGNAL(v4BindingPropChanged())), v4BindingPropConnections);
106         QCOMPARE(receivers(SIGNAL(v4BindingProp2Changed())), v4BindingProp2Connections);
107         QCOMPARE(receivers(SIGNAL(scriptBindingPropChanged())), scriptBindingPropConnections);
108         QCOMPARE(receivers(SIGNAL(boundSignal())), boundSignalConnections);
109         QCOMPARE(receivers(SIGNAL(unusedSignal())), unusedSignalConnections);
110     }
111
112 protected:
113     void connectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE {
114         if (signal.name() == "qmlObjectPropChanged") qmlObjectPropConnections++;
115         if (signal.name() == "cppObjectPropChanged") cppObjectPropConnections++;
116         if (signal.name() == "unboundPropChanged") unboundPropConnections++;
117         if (signal.name() == "v8BindingPropChanged") v8BindingPropConnections++;
118         if (signal.name() == "v4BindingPropChanged") v4BindingPropConnections++;
119         if (signal.name() == "v4BindingProp2Changed") v4BindingProp2Connections++;
120         if (signal.name() == "scriptBindingPropChanged") scriptBindingPropConnections++;
121         if (signal.name() == "boundSignal")   boundSignalConnections++;
122         if (signal.name() == "unusedSignal") unusedSignalConnections++;
123         //qDebug() << Q_FUNC_INFO << this << signal.name();
124     }
125
126     void disconnectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE {
127         if (signal.name() == "qmlObjectPropChanged") qmlObjectPropConnections--;
128         if (signal.name() == "cppObjectPropChanged") cppObjectPropConnections--;
129         if (signal.name() == "unboundPropChanged") unboundPropConnections--;
130         if (signal.name() == "v8BindingPropChanged") v8BindingPropConnections--;
131         if (signal.name() == "v4BindingPropChanged") v4BindingPropConnections--;
132         if (signal.name() == "v4BindingProp2Changed") v4BindingProp2Connections--;
133         if (signal.name() == "scriptBindingPropChanged") scriptBindingPropConnections--;
134         if (signal.name() == "boundSignal")   boundSignalConnections--;
135         if (signal.name() == "unusedSignal") unusedSignalConnections--;
136         //qDebug() << Q_FUNC_INFO << this << signal.methodSignature();
137     }
138
139 signals:
140     void qmlObjectPropChanged();
141     void cppObjectPropChanged();
142     void unboundPropChanged();
143     void v8BindingPropChanged();
144     void v4BindingPropChanged();
145     void v4BindingProp2Changed();
146     void scriptBindingPropChanged();
147     void boundSignal();
148     void unusedSignal();
149 };
150
151 class tst_qqmlnotifier : public QQmlDataTest
152 {
153     Q_OBJECT
154 public:
155     tst_qqmlnotifier()
156         : root(0), exportedClass(0), exportedObject(0)
157     {}
158
159 private slots:
160     void initTestCase() Q_DECL_OVERRIDE;
161     void cleanupTestCase();
162     void connectNotify();
163
164     void removeV4Binding();
165     void removeV4Binding2();
166     void removeV8Binding();
167     void removeScriptBinding();
168     // No need to test value type proxy bindings - the user can't override disconnectNotify() anyway,
169     // as the classes are private to the QML engine
170
171     void readProperty();
172     void propertyChange();
173     void disconnectOnDestroy();
174
175 private:
176     void createObjects();
177
178     QQmlEngine engine;
179     QObject *root;
180     ExportedClass *exportedClass;
181     ExportedClass *exportedObject;
182 };
183
184 void tst_qqmlnotifier::initTestCase()
185 {
186     QQmlDataTest::initTestCase();
187     qmlRegisterType<ExportedClass>("Test", 1, 0, "ExportedClass");
188 }
189
190 void tst_qqmlnotifier::createObjects()
191 {
192     delete root;
193     root = 0;
194     exportedClass = exportedObject = 0;
195
196     QQmlComponent component(&engine, testFileUrl("connectnotify.qml"));
197     exportedObject = new ExportedClass();
198     exportedObject->setObjectName("exportedObject");
199     engine.rootContext()->setContextProperty("_exportedObject", exportedObject);
200     root = component.create();
201     QVERIFY(root != 0);
202
203     exportedClass = qobject_cast<ExportedClass *>(
204                 root->findChild<ExportedClass*>("exportedClass"));
205     QVERIFY(exportedClass != 0);
206 }
207
208 void tst_qqmlnotifier::cleanupTestCase()
209 {
210     delete root;
211     root = 0;
212     delete exportedObject;
213     exportedObject = 0;
214 }
215
216 void tst_qqmlnotifier::connectNotify()
217 {
218     createObjects();
219
220     QCOMPARE(exportedClass->qmlObjectPropConnections, 1);
221     QCOMPARE(exportedClass->cppObjectPropConnections, 0);
222     QCOMPARE(exportedClass->unboundPropConnections, 0);
223     QCOMPARE(exportedClass->v8BindingPropConnections, 1);
224     QCOMPARE(exportedClass->v4BindingPropConnections, 1);
225     QCOMPARE(exportedClass->v4BindingProp2Connections, 2);
226     QCOMPARE(exportedClass->scriptBindingPropConnections, 1);
227     QCOMPARE(exportedClass->boundSignalConnections, 1);
228     QCOMPARE(exportedClass->unusedSignalConnections, 0);
229     exportedClass->verifyReceiverCount();
230
231     QCOMPARE(exportedObject->qmlObjectPropConnections, 0);
232     QCOMPARE(exportedObject->cppObjectPropConnections, 1);
233     QCOMPARE(exportedObject->unboundPropConnections, 0);
234     QCOMPARE(exportedObject->v8BindingPropConnections, 0);
235     QCOMPARE(exportedObject->v4BindingPropConnections, 0);
236     QCOMPARE(exportedObject->v4BindingProp2Connections, 0);
237     QCOMPARE(exportedObject->scriptBindingPropConnections, 0);
238     QCOMPARE(exportedObject->boundSignalConnections, 0);
239     QCOMPARE(exportedObject->unusedSignalConnections, 0);
240     exportedObject->verifyReceiverCount();
241 }
242
243 void tst_qqmlnotifier::removeV4Binding()
244 {
245     createObjects();
246
247     // Removing a binding should disconnect all of its guarded properties
248     QVERIFY(QMetaObject::invokeMethod(root, "removeV4Binding"));
249     QCOMPARE(exportedClass->v4BindingPropConnections, 0);
250     exportedClass->verifyReceiverCount();
251 }
252
253 void tst_qqmlnotifier::removeV4Binding2()
254 {
255     createObjects();
256
257     // In this case, the v4BindingProp2 property is used by two v4 bindings.
258     // Make sure that removing one binding doesn't by accident disconnect all.
259     QVERIFY(QMetaObject::invokeMethod(root, "removeV4Binding2"));
260     QCOMPARE(exportedClass->v4BindingProp2Connections, 1);
261     exportedClass->verifyReceiverCount();
262 }
263
264 void tst_qqmlnotifier::removeV8Binding()
265 {
266     createObjects();
267
268     // Removing a binding should disconnect all of its guarded properties
269     QVERIFY(QMetaObject::invokeMethod(root, "removeV8Binding"));
270     QCOMPARE(exportedClass->v8BindingPropConnections, 0);
271     exportedClass->verifyReceiverCount();
272 }
273
274 void tst_qqmlnotifier::removeScriptBinding()
275 {
276     createObjects();
277
278     // Removing a binding should disconnect all of its guarded properties
279     QVERIFY(QMetaObject::invokeMethod(root, "removeScriptBinding"));
280     QCOMPARE(exportedClass->scriptBindingPropConnections, 0);
281     exportedClass->verifyReceiverCount();
282 }
283
284 void tst_qqmlnotifier::readProperty()
285 {
286     createObjects();
287
288     // Reading a property should not connect to it
289     QVERIFY(QMetaObject::invokeMethod(root, "readProperty"));
290     QCOMPARE(exportedClass->unboundPropConnections, 0);
291     exportedClass->verifyReceiverCount();
292 }
293
294 void tst_qqmlnotifier::propertyChange()
295 {
296     createObjects();
297
298     // Changing the state will trigger the PropertyChange to overwrite a value with a binding.
299     // For this, the new binding needs to be connected, and afterwards disconnected.
300     QVERIFY(QMetaObject::invokeMethod(root, "changeState"));
301     QCOMPARE(exportedClass->unboundPropConnections, 1);
302     exportedClass->verifyReceiverCount();
303     QVERIFY(QMetaObject::invokeMethod(root, "changeState"));
304     QCOMPARE(exportedClass->unboundPropConnections, 0);
305     exportedClass->verifyReceiverCount();
306 }
307
308 void tst_qqmlnotifier::disconnectOnDestroy()
309 {
310     createObjects();
311
312     // Deleting a QML object should remove all connections. For exportedClass, this is tested in
313     // the destructor, and for exportedObject, it is tested below.
314     delete root;
315     root = 0;
316     QCOMPARE(exportedObject->cppObjectPropConnections, 0);
317     exportedObject->verifyReceiverCount();
318 }
319
320 QTEST_MAIN(tst_qqmlnotifier)
321
322 #include "tst_qqmlnotifier.moc"