/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include "../../shared/util.h" Q_DECLARE_METATYPE(QMetaMethod::MethodType) class MyQmlObject : public QObject { Q_OBJECT }; QML_DECLARE_TYPE(MyQmlObject) class tst_QQmlMetaObject : public QQmlDataTest { Q_OBJECT private slots: void initTestCase(); void property_data(); void property(); void method_data(); void method(); private: MyQmlObject myQmlObject; }; void tst_QQmlMetaObject::initTestCase() { QQmlDataTest::initTestCase(); qmlRegisterType("Qt.test", 1,0, "MyQmlObject"); } void tst_QQmlMetaObject::property_data() { QTest::addColumn("testFile"); QTest::addColumn("cppTypeName"); QTest::addColumn("cppType"); QTest::addColumn("isDefault"); QTest::addColumn("expectedValue"); QTest::addColumn("isWritable"); QTest::addColumn("newValue"); QTest::newRow("int") << "property.int.qml" << QByteArray("int") << int(QMetaType::Int) << false // default << QVariant(19) << true << QVariant(42); QTest::newRow("bool") << "property.bool.qml" << QByteArray("bool") << int(QMetaType::Bool) << true // default << QVariant(true) << true << QVariant(false); QTest::newRow("double") << "property.double.qml" << QByteArray("double") << int(QMetaType::Double) << false // default << QVariant(double(1234567890.)) << true // writable << QVariant(double(1.23456789)); QTest::newRow("real") << "property.real.qml" << QByteArray("double") << int(QMetaType::Double) << false // default << QVariant(double(1234567890.)) << true // writable << QVariant(double(1.23456789)); QTest::newRow("string") << "property.string.qml" << QByteArray("QString") << int(QMetaType::QString) << true // default << QVariant(QString::fromLatin1("dog")) << true // writable << QVariant(QString::fromLatin1("food")); QTest::newRow("url") << "property.url.qml" << QByteArray("QUrl") << int(QMetaType::QUrl) << false // default << QVariant(QUrl("http://foo.bar")) << true //writable << QVariant(QUrl("http://bar.baz")); QTest::newRow("color") << "property.color.qml" << QByteArray("QColor") << int(QMetaType::QColor) << true // default << QVariant(QColor("#ff0000")) << true // writable << QVariant(QColor("#00ff00")); QTest::newRow("date") << "property.date.qml" << QByteArray("QDateTime") << int(QMetaType::QDateTime) << false // default << QVariant(QDateTime(QDate(2012, 2, 7))) << true // writable << QVariant(QDateTime(QDate(2010, 7, 2))); QTest::newRow("variant") << "property.variant.qml" << QByteArray("QVariant") << int(QMetaType::QVariant) << true // default << QVariant(QPointF(12, 34)) << true // writable << QVariant(QSizeF(45, 67)); QTest::newRow("var") << "property.var.qml" << QByteArray("QVariant") << int(QMetaType::QVariant) << false // default << QVariant(QVariantList() << 5 << true << "ciao") << true // writable << QVariant(QVariantList() << 17.0); QTest::newRow("QtObject") << "property.QtObject.qml" << QByteArray("QObject*") << int(QMetaType::QObjectStar) << false // default << QVariant() << true // writable << QVariant::fromValue(static_cast(this)); QTest::newRow("list") << "property.list.QtObject.qml" << QByteArray("QQmlListProperty") << qMetaTypeId >() << false // default << QVariant() << false // writable << QVariant(); QTest::newRow("MyQmlObject") << "property.MyQmlObject.qml" << QByteArray("MyQmlObject*") << qMetaTypeId() << false // default << QVariant() << true // writable << QVariant::fromValue(&myQmlObject); QTest::newRow("list") << "property.list.MyQmlObject.qml" << QByteArray("QQmlListProperty") << qMetaTypeId >() << false // default << QVariant() << false // writable << QVariant(); QTest::newRow("alias") << "property.alias.qml" << QByteArray("QString") << int(QMetaType::QString) << false // default << QVariant(QString::fromLatin1("Joe")) << true // writable << QVariant(QString::fromLatin1("Bob")); QTest::newRow("alias-2") << "property.alias.2.qml" << QByteArray("QObject*") << int(QMetaType::QObjectStar) << false // default << QVariant() << false // writable << QVariant(); QTest::newRow("alias-3") << "property.alias.3.qml" << QByteArray("QString") << int(QMetaType::QString) << false // default << QVariant(QString::fromLatin1("Arial")) << true // writable << QVariant(QString::fromLatin1("Helvetica")); } void tst_QQmlMetaObject::property() { QFETCH(QString, testFile); QFETCH(QByteArray, cppTypeName); QFETCH(int, cppType); QFETCH(bool, isDefault); QFETCH(QVariant, expectedValue); QFETCH(bool, isWritable); QFETCH(QVariant, newValue); QQmlEngine engine; QQmlComponent component(&engine, testFileUrl(testFile)); QObject *object = component.create(); QVERIFY(object != nullptr); const QMetaObject *mo = object->metaObject(); QVERIFY(mo->superClass() != nullptr); QVERIFY(QByteArray(mo->className()).contains("_QML_")); QCOMPARE(mo->propertyOffset(), mo->superClass()->propertyCount()); QCOMPARE(mo->propertyCount(), mo->superClass()->propertyCount() + 1); QMetaProperty prop = mo->property(mo->propertyOffset()); QCOMPARE(prop.name(), "test"); QCOMPARE(QByteArray(prop.typeName()), cppTypeName); if (prop.userType() < QMetaType::User) QCOMPARE(prop.type(), QVariant::Type(cppType)); else QCOMPARE(prop.type(), QVariant::UserType); QCOMPARE(prop.userType(), cppType); QVERIFY(!prop.isConstant()); QVERIFY(!prop.isDesignable()); QVERIFY(!prop.isEnumType()); QVERIFY(!prop.isFinal()); QVERIFY(!prop.isFlagType()); QVERIFY(prop.isReadable()); QVERIFY(!prop.isResettable()); QVERIFY(prop.isScriptable()); QVERIFY(!prop.isStored()); QVERIFY(!prop.isUser()); QVERIFY(prop.isValid()); QCOMPARE(prop.isWritable(), isWritable); QCOMPARE(mo->classInfoOffset(), mo->superClass()->classInfoCount()); QCOMPARE(mo->classInfoCount(), mo->superClass()->classInfoCount() + (isDefault ? 1 : 0)); if (isDefault) { QMetaClassInfo info = mo->classInfo(mo->classInfoOffset()); QCOMPARE(info.name(), "DefaultProperty"); QCOMPARE(info.value(), "test"); } QCOMPARE(mo->methodOffset(), mo->superClass()->methodCount()); QCOMPARE(mo->methodCount(), mo->superClass()->methodCount() + 1); // the signal QVERIFY(prop.notifySignalIndex() != -1); QMetaMethod signal = prop.notifySignal(); QCOMPARE(signal.methodType(), QMetaMethod::Signal); QCOMPARE(signal.name(), QByteArray("testChanged")); QCOMPARE(signal.methodSignature(), QByteArray("testChanged()")); QCOMPARE(signal.access(), QMetaMethod::Public); QCOMPARE(signal.parameterCount(), 0); QCOMPARE(signal.parameterTypes(), QList()); QCOMPARE(signal.parameterNames(), QList()); QCOMPARE(signal.tag(), ""); QCOMPARE(signal.typeName(), "void"); QCOMPARE(signal.returnType(), int(QMetaType::Void)); QSignalSpy changedSpy(object, SIGNAL(testChanged())); QObject::connect(object, SIGNAL(testChanged()), object, SLOT(deleteLater())); QVariant value = prop.read(object); if (value.userType() == qMetaTypeId()) value = value.value().toVariant(); if (expectedValue.isValid()) QCOMPARE(value, expectedValue); else QVERIFY(value.isValid()); QCOMPARE(changedSpy.count(), 0); if (isWritable) { QVERIFY(prop.write(object, newValue)); QCOMPARE(changedSpy.count(), 1); QVariant value = prop.read(object); if (value.userType() == qMetaTypeId()) value = value.value().toVariant(); QCOMPARE(value, newValue); } else { QVERIFY(!prop.write(object, prop.read(object))); QCOMPARE(changedSpy.count(), 0); } delete object; } void tst_QQmlMetaObject::method_data() { QTest::addColumn("testFile"); QTest::addColumn("signature"); QTest::addColumn("methodType"); QTest::addColumn("returnType"); QTest::addColumn("returnTypeName"); QTest::addColumn >("parameterTypes"); QTest::addColumn >("parameterTypeNames"); QTest::addColumn >("parameterNames"); QTest::newRow("testFunction()") << "method.1.qml" << "testFunction()" << QMetaMethod::Slot << int(QMetaType::QVariant) << "QVariant" << QList() << QList() << QList(); QTest::newRow("testFunction(foo)") << "method.2.qml" << "testFunction(QVariant)" << QMetaMethod::Slot << int(QMetaType::QVariant) << "QVariant" << (QList() << QMetaType::QVariant) << (QList() << "QVariant") << (QList() << "foo"); QTest::newRow("testFunction(foo, bar, baz)") << "method.3.qml" << "testFunction(QVariant,QVariant,QVariant)" << QMetaMethod::Slot << int(QMetaType::QVariant) << "QVariant" << (QList() << QMetaType::QVariant << QMetaType::QVariant << QMetaType::QVariant) << (QList() << "QVariant" << "QVariant" << "QVariant") << (QList() << "foo" << "bar" << "baz"); QTest::newRow("testSignal") << "signal.1.qml" << "testSignal()" << QMetaMethod::Signal << int(QMetaType::Void) << "void" << QList() << QList() << QList(); QTest::newRow("testSignal(string foo)") << "signal.2.qml" << "testSignal(QString)" << QMetaMethod::Signal << int(QMetaType::Void) << "void" << (QList() << QMetaType::QString) << (QList() << "QString") << (QList() << "foo"); QTest::newRow("testSignal(int foo, bool bar, real baz)") << "signal.3.qml" << "testSignal(int,bool,double)" << QMetaMethod::Signal << int(QMetaType::Void) << "void" << (QList() << QMetaType::Int << QMetaType::Bool << QMetaType::Double) << (QList() << "int" << "bool" << "double") << (QList() << "foo" << "bar" << "baz"); QTest::newRow("testSignal(variant foo, var bar)") << "signal.4.qml" << "testSignal(QVariant,QVariant)" << QMetaMethod::Signal << int(QMetaType::Void) << "void" << (QList() << QMetaType::QVariant << QMetaType::QVariant) << (QList() << "QVariant" << "QVariant") << (QList() << "foo" << "bar"); QTest::newRow("testSignal(color foo, date bar, url baz)") << "signal.5.qml" << "testSignal(QColor,QDateTime,QUrl)" << QMetaMethod::Signal << int(QMetaType::Void) << "void" << (QList() << QMetaType::QColor << QMetaType::QDateTime << QMetaType::QUrl) << (QList() << "QColor" << "QDateTime" << "QUrl") << (QList() << "foo" << "bar" << "baz"); QTest::newRow("testSignal(double foo)") << "signal.6.qml" << "testSignal(double)" << QMetaMethod::Signal << int(QMetaType::Void) << "void" << (QList() << QMetaType::Double) << (QList() << "double") << (QList() << "foo"); } void tst_QQmlMetaObject::method() { QFETCH(QString, testFile); QFETCH(QString, signature); QFETCH(QMetaMethod::MethodType, methodType); QFETCH(int, returnType); QFETCH(QString, returnTypeName); QFETCH(QList, parameterTypes); QFETCH(QList, parameterTypeNames); QFETCH(QList, parameterNames); QCOMPARE(parameterTypes.size(), parameterTypeNames.size()); QCOMPARE(parameterTypeNames.size(), parameterNames.size()); QQmlEngine engine; QQmlComponent component(&engine, testFileUrl(testFile)); QObject *object = component.create(); QVERIFY(object != nullptr); const QMetaObject *mo = object->metaObject(); QVERIFY(mo->superClass() != nullptr); QVERIFY(QByteArray(mo->className()).contains("_QML_")); QCOMPARE(mo->methodOffset(), mo->superClass()->methodCount()); QCOMPARE(mo->methodCount(), mo->superClass()->methodCount() + 1); QMetaMethod method = mo->method(mo->methodOffset()); QCOMPARE(method.methodType(), methodType); QCOMPARE(QString::fromUtf8(method.methodSignature().constData()), signature); QCOMPARE(method.access(), QMetaMethod::Public); QString computedName = signature.left(signature.indexOf('(')); QCOMPARE(QString::fromUtf8(method.name()), computedName); QCOMPARE(method.parameterCount(), parameterTypes.size()); for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(method.parameterType(i), parameterTypes.at(i)); QCOMPARE(method.parameterTypes(), parameterTypeNames); QCOMPARE(method.tag(), ""); QCOMPARE(QString::fromUtf8(method.typeName()), returnTypeName); QCOMPARE(method.returnType(), returnType); delete object; } QTEST_MAIN(tst_QQmlMetaObject) #include "tst_qqmlmetaobject.moc"