1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QtTest>
30#include <QtQml/qqmlcomponent.h>
31#include <QtQml/qqmlengine.h>
32#include "../../shared/util.h"
33
34Q_DECLARE_METATYPE(QMetaMethod::MethodType)
35
36class MyQmlObject : public QObject
37{
38 Q_OBJECT
39};
40QML_DECLARE_TYPE(MyQmlObject)
41
42class tst_QQmlMetaObject : public QQmlDataTest
43{
44 Q_OBJECT
45private slots:
46 void initTestCase();
47
48 void property_data();
49 void property();
50 void method_data();
51 void method();
52
53private:
54 MyQmlObject myQmlObject;
55};
56
57void tst_QQmlMetaObject::initTestCase()
58{
59 QQmlDataTest::initTestCase();
60
61 qmlRegisterType<MyQmlObject>(uri: "Qt.test", versionMajor: 1,versionMinor: 0, qmlName: "MyQmlObject");
62}
63
64void tst_QQmlMetaObject::property_data()
65{
66 QTest::addColumn<QString>(name: "testFile");
67 QTest::addColumn<QByteArray>(name: "cppTypeName");
68 QTest::addColumn<int>(name: "cppType");
69 QTest::addColumn<bool>(name: "isDefault");
70 QTest::addColumn<QVariant>(name: "expectedValue");
71 QTest::addColumn<bool>(name: "isWritable");
72 QTest::addColumn<QVariant>(name: "newValue");
73
74 QTest::newRow(dataTag: "int") << "property.int.qml"
75 << QByteArray("int") << int(QMetaType::Int)
76 << false // default
77 << QVariant(19) << true << QVariant(42);
78 QTest::newRow(dataTag: "bool") << "property.bool.qml"
79 << QByteArray("bool") << int(QMetaType::Bool)
80 << true // default
81 << QVariant(true) << true << QVariant(false);
82 QTest::newRow(dataTag: "double") << "property.double.qml"
83 << QByteArray("double") << int(QMetaType::Double)
84 << false // default
85 << QVariant(double(1234567890.))
86 << true // writable
87 << QVariant(double(1.23456789));
88 QTest::newRow(dataTag: "real") << "property.real.qml"
89 << QByteArray("double") << int(QMetaType::Double)
90 << false // default
91 << QVariant(double(1234567890.))
92 << true // writable
93 << QVariant(double(1.23456789));
94 QTest::newRow(dataTag: "string") << "property.string.qml"
95 << QByteArray("QString") << int(QMetaType::QString)
96 << true // default
97 << QVariant(QString::fromLatin1(str: "dog"))
98 << true // writable
99 << QVariant(QString::fromLatin1(str: "food"));
100 QTest::newRow(dataTag: "url") << "property.url.qml"
101 << QByteArray("QUrl") << int(QMetaType::QUrl)
102 << false // default
103 << QVariant(QUrl("http://foo.bar"))
104 << true //writable
105 << QVariant(QUrl("http://bar.baz"));
106 QTest::newRow(dataTag: "color") << "property.color.qml"
107 << QByteArray("QColor") << int(QMetaType::QColor)
108 << true // default
109 << QVariant(QColor("#ff0000"))
110 << true // writable
111 << QVariant(QColor("#00ff00"));
112 QTest::newRow(dataTag: "date") << "property.date.qml"
113 << QByteArray("QDateTime") << int(QMetaType::QDateTime)
114 << false // default
115 << QVariant(QDate(2012, 2, 7).startOfDay())
116 << true // writable
117 << QVariant(QDate(2010, 7, 2).startOfDay());
118 QTest::newRow(dataTag: "variant") << "property.variant.qml"
119 << QByteArray("QVariant") << int(QMetaType::QVariant)
120 << true // default
121 << QVariant(QPointF(12, 34))
122 << true // writable
123 << QVariant(QSizeF(45, 67));
124 QTest::newRow(dataTag: "var") << "property.var.qml"
125 << QByteArray("QVariant") << int(QMetaType::QVariant)
126 << false // default
127 << QVariant(QVariantList() << 5 << true << "ciao")
128 << true // writable
129 << QVariant(QVariantList() << 17.0);
130 QTest::newRow(dataTag: "QtObject") << "property.QtObject.qml"
131 << QByteArray("QObject*") << int(QMetaType::QObjectStar)
132 << false // default
133 << QVariant()
134 << true // writable
135 << QVariant::fromValue(value: static_cast<QObject*>(this));
136 QTest::newRow(dataTag: "list<QtObject>") << "property.list.QtObject.qml"
137 << QByteArray("QQmlListProperty<QObject>")
138 << qMetaTypeId<QQmlListProperty<QObject> >()
139 << false // default
140 << QVariant()
141 << false // writable
142 << QVariant();
143 QTest::newRow(dataTag: "MyQmlObject") << "property.MyQmlObject.qml"
144 << QByteArray("MyQmlObject*") << qMetaTypeId<MyQmlObject*>()
145 << false // default
146 << QVariant()
147 << true // writable
148 << QVariant::fromValue(value: &myQmlObject);
149 QTest::newRow(dataTag: "list<MyQmlObject>") << "property.list.MyQmlObject.qml"
150 << QByteArray("QQmlListProperty<MyQmlObject>")
151 << qMetaTypeId<QQmlListProperty<MyQmlObject> >()
152 << false // default
153 << QVariant()
154 << false // writable
155 << QVariant();
156 QTest::newRow(dataTag: "alias") << "property.alias.qml"
157 << QByteArray("QString") << int(QMetaType::QString)
158 << false // default
159 << QVariant(QString::fromLatin1(str: "Joe"))
160 << true // writable
161 << QVariant(QString::fromLatin1(str: "Bob"));
162 QTest::newRow(dataTag: "alias-2") << "property.alias.2.qml"
163 << QByteArray("QObject*") << int(QMetaType::QObjectStar)
164 << false // default
165 << QVariant()
166 << false // writable
167 << QVariant();
168 QTest::newRow(dataTag: "alias-3") << "property.alias.3.qml"
169 << QByteArray("QString") << int(QMetaType::QString)
170 << false // default
171 << QVariant(QString::fromLatin1(str: "Arial"))
172 << true // writable
173 << QVariant(QString::fromLatin1(str: "Helvetica"));
174}
175
176void tst_QQmlMetaObject::property()
177{
178 QFETCH(QString, testFile);
179 QFETCH(QByteArray, cppTypeName);
180 QFETCH(int, cppType);
181 QFETCH(bool, isDefault);
182 QFETCH(QVariant, expectedValue);
183 QFETCH(bool, isWritable);
184 QFETCH(QVariant, newValue);
185
186 QQmlEngine engine;
187 QQmlComponent component(&engine, testFileUrl(fileName: testFile));
188 QObject *object = component.create();
189 QVERIFY(object != nullptr);
190
191 const QMetaObject *mo = object->metaObject();
192 QVERIFY(mo->superClass() != nullptr);
193 QVERIFY(QByteArray(mo->className()).contains("_QML_"));
194 QCOMPARE(mo->propertyOffset(), mo->superClass()->propertyCount());
195 QCOMPARE(mo->propertyCount(), mo->superClass()->propertyCount() + 1);
196
197 QMetaProperty prop = mo->property(index: mo->propertyOffset());
198 QCOMPARE(prop.name(), "test");
199
200 QCOMPARE(QByteArray(prop.typeName()), cppTypeName);
201 if (prop.userType() < QMetaType::User)
202 QCOMPARE(prop.type(), QVariant::Type(cppType));
203 else
204 QCOMPARE(prop.type(), QVariant::UserType);
205 QCOMPARE(prop.userType(), cppType);
206
207 QVERIFY(!prop.isConstant());
208 QVERIFY(!prop.isDesignable());
209 QVERIFY(!prop.isEnumType());
210 QVERIFY(!prop.isFinal());
211 QVERIFY(!prop.isFlagType());
212 QVERIFY(prop.isReadable());
213 QVERIFY(!prop.isResettable());
214 QVERIFY(prop.isScriptable());
215 QVERIFY(!prop.isStored());
216 QVERIFY(!prop.isUser());
217 QVERIFY(prop.isValid());
218 QCOMPARE(prop.isWritable(), isWritable);
219
220 QCOMPARE(mo->classInfoOffset(), mo->superClass()->classInfoCount());
221 QCOMPARE(mo->classInfoCount(), mo->superClass()->classInfoCount() + (isDefault ? 1 : 0));
222 if (isDefault) {
223 QMetaClassInfo info = mo->classInfo(index: mo->classInfoOffset());
224 QCOMPARE(info.name(), "DefaultProperty");
225 QCOMPARE(info.value(), "test");
226 }
227
228 QCOMPARE(mo->methodOffset(), mo->superClass()->methodCount());
229 QCOMPARE(mo->methodCount(), mo->superClass()->methodCount() + 1); // the signal
230
231 QVERIFY(prop.notifySignalIndex() != -1);
232 QMetaMethod signal = prop.notifySignal();
233 QCOMPARE(signal.methodType(), QMetaMethod::Signal);
234 QCOMPARE(signal.name(), QByteArray("testChanged"));
235 QCOMPARE(signal.methodSignature(), QByteArray("testChanged()"));
236 QCOMPARE(signal.access(), QMetaMethod::Public);
237 QCOMPARE(signal.parameterCount(), 0);
238 QCOMPARE(signal.parameterTypes(), QList<QByteArray>());
239 QCOMPARE(signal.parameterNames(), QList<QByteArray>());
240 QCOMPARE(signal.tag(), "");
241 QCOMPARE(signal.typeName(), "void");
242 QCOMPARE(signal.returnType(), int(QMetaType::Void));
243
244 QSignalSpy changedSpy(object, SIGNAL(testChanged()));
245 QObject::connect(sender: object, SIGNAL(testChanged()), receiver: object, SLOT(deleteLater()));
246
247 QVariant value = prop.read(obj: object);
248 if (value.userType() == qMetaTypeId<QJSValue>())
249 value = value.value<QJSValue>().toVariant();
250 if (expectedValue.isValid())
251 QCOMPARE(value, expectedValue);
252 else
253 QVERIFY(value.isValid());
254 QCOMPARE(changedSpy.count(), 0);
255
256 if (isWritable) {
257 QVERIFY(prop.write(object, newValue));
258 QCOMPARE(changedSpy.count(), 1);
259 QVariant value = prop.read(obj: object);
260 if (value.userType() == qMetaTypeId<QJSValue>())
261 value = value.value<QJSValue>().toVariant();
262 QCOMPARE(value, newValue);
263 } else {
264 QVERIFY(!prop.write(object, prop.read(object)));
265 QCOMPARE(changedSpy.count(), 0);
266 }
267
268 delete object;
269}
270
271void tst_QQmlMetaObject::method_data()
272{
273 QTest::addColumn<QString>(name: "testFile");
274 QTest::addColumn<QString>(name: "signature");
275 QTest::addColumn<QMetaMethod::MethodType>(name: "methodType");
276 QTest::addColumn<int>(name: "returnType");
277 QTest::addColumn<QString>(name: "returnTypeName");
278 QTest::addColumn<QList<int> >(name: "parameterTypes");
279 QTest::addColumn<QList<QByteArray> >(name: "parameterTypeNames");
280 QTest::addColumn<QList<QByteArray> >(name: "parameterNames");
281
282 QTest::newRow(dataTag: "testFunction()") << "method.1.qml"
283 << "testFunction()"
284 << QMetaMethod::Slot
285 << int(QMetaType::QVariant) << "QVariant"
286 << QList<int>()
287 << QList<QByteArray>()
288 << QList<QByteArray>();
289 QTest::newRow(dataTag: "testFunction(foo)") << "method.2.qml"
290 << "testFunction(QVariant)"
291 << QMetaMethod::Slot
292 << int(QMetaType::QVariant) << "QVariant"
293 << (QList<int>() << QMetaType::QVariant)
294 << (QList<QByteArray>() << "QVariant")
295 << (QList<QByteArray>() << "foo");
296 QTest::newRow(dataTag: "testFunction(foo, bar, baz)") << "method.3.qml"
297 << "testFunction(QVariant,QVariant,QVariant)"
298 << QMetaMethod::Slot
299 << int(QMetaType::QVariant) << "QVariant"
300 << (QList<int>() << QMetaType::QVariant << QMetaType::QVariant << QMetaType::QVariant)
301 << (QList<QByteArray>() << "QVariant" << "QVariant" << "QVariant")
302 << (QList<QByteArray>() << "foo" << "bar" << "baz");
303 QTest::newRow(dataTag: "testSignal") << "signal.1.qml"
304 << "testSignal()"
305 << QMetaMethod::Signal
306 << int(QMetaType::Void) << "void"
307 << QList<int>()
308 << QList<QByteArray>()
309 << QList<QByteArray>();
310 QTest::newRow(dataTag: "testSignal(string foo)") << "signal.2.qml"
311 << "testSignal(QString)"
312 << QMetaMethod::Signal
313 << int(QMetaType::Void) << "void"
314 << (QList<int>() << QMetaType::QString)
315 << (QList<QByteArray>() << "QString")
316 << (QList<QByteArray>() << "foo");
317 QTest::newRow(dataTag: "testSignal(int foo, bool bar, real baz)") << "signal.3.qml"
318 << "testSignal(int,bool,double)"
319 << QMetaMethod::Signal
320 << int(QMetaType::Void) << "void"
321 << (QList<int>() << QMetaType::Int << QMetaType::Bool << QMetaType::Double)
322 << (QList<QByteArray>() << "int" << "bool" << "double")
323 << (QList<QByteArray>() << "foo" << "bar" << "baz");
324 QTest::newRow(dataTag: "testSignal(variant foo, var bar)") << "signal.4.qml"
325 << "testSignal(QVariant,QVariant)"
326 << QMetaMethod::Signal
327 << int(QMetaType::Void) << "void"
328 << (QList<int>() << QMetaType::QVariant << QMetaType::QVariant)
329 << (QList<QByteArray>() << "QVariant" << "QVariant")
330 << (QList<QByteArray>() << "foo" << "bar");
331 QTest::newRow(dataTag: "testSignal(color foo, date bar, url baz)") << "signal.5.qml"
332 << "testSignal(QColor,QDateTime,QUrl)"
333 << QMetaMethod::Signal
334 << int(QMetaType::Void) << "void"
335 << (QList<int>() << QMetaType::QColor << QMetaType::QDateTime << QMetaType::QUrl)
336 << (QList<QByteArray>() << "QColor" << "QDateTime" << "QUrl")
337 << (QList<QByteArray>() << "foo" << "bar" << "baz");
338 QTest::newRow(dataTag: "testSignal(double foo)") << "signal.6.qml"
339 << "testSignal(double)"
340 << QMetaMethod::Signal
341 << int(QMetaType::Void) << "void"
342 << (QList<int>() << QMetaType::Double)
343 << (QList<QByteArray>() << "double")
344 << (QList<QByteArray>() << "foo");
345}
346
347void tst_QQmlMetaObject::method()
348{
349 QFETCH(QString, testFile);
350 QFETCH(QString, signature);
351 QFETCH(QMetaMethod::MethodType, methodType);
352 QFETCH(int, returnType);
353 QFETCH(QString, returnTypeName);
354 QFETCH(QList<int>, parameterTypes);
355 QFETCH(QList<QByteArray>, parameterTypeNames);
356 QFETCH(QList<QByteArray>, parameterNames);
357
358 QCOMPARE(parameterTypes.size(), parameterTypeNames.size());
359 QCOMPARE(parameterTypeNames.size(), parameterNames.size());
360
361 QQmlEngine engine;
362 QQmlComponent component(&engine, testFileUrl(fileName: testFile));
363 QObject *object = component.create();
364 QVERIFY(object != nullptr);
365
366 const QMetaObject *mo = object->metaObject();
367 QVERIFY(mo->superClass() != nullptr);
368 QVERIFY(QByteArray(mo->className()).contains("_QML_"));
369 QCOMPARE(mo->methodOffset(), mo->superClass()->methodCount());
370 QCOMPARE(mo->methodCount(), mo->superClass()->methodCount() + 1);
371
372 QMetaMethod method = mo->method(index: mo->methodOffset());
373 QCOMPARE(method.methodType(), methodType);
374 QCOMPARE(QString::fromUtf8(method.methodSignature().constData()), signature);
375 QCOMPARE(method.access(), QMetaMethod::Public);
376
377 QString computedName = signature.left(n: signature.indexOf(c: '('));
378 QCOMPARE(QString::fromUtf8(method.name()), computedName);
379
380 QCOMPARE(method.parameterCount(), parameterTypes.size());
381 for (int i = 0; i < parameterTypes.size(); ++i)
382 QCOMPARE(method.parameterType(i), parameterTypes.at(i));
383 QCOMPARE(method.parameterTypes(), parameterTypeNames);
384 QCOMPARE(method.tag(), "");
385
386 QCOMPARE(QString::fromUtf8(method.typeName()), returnTypeName);
387 QCOMPARE(method.returnType(), returnType);
388
389 delete object;
390}
391
392QTEST_MAIN(tst_QQmlMetaObject)
393
394#include "tst_qqmlmetaobject.moc"
395

source code of qtdeclarative/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp