diff options
Diffstat (limited to 'tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp')
-rw-r--r-- | tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp | 339 |
1 files changed, 162 insertions, 177 deletions
diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp index 333c7931d9..18e4e2a4a9 100644 --- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp +++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp @@ -1,32 +1,8 @@ -/**************************************************************************** -** -** 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 <QtTest/QtTest> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QSignalSpy> #include <QtCore/qlocale.h> #include <private/qmetaobjectbuilder_p.h> @@ -50,8 +26,6 @@ private slots: void relatedMetaObject(); void staticMetacall(); void copyMetaObject(); - void serialize(); - void relocatableData(); void removeNotifySignal(); void usage_signal(); @@ -64,13 +38,28 @@ private slots: void classNameFirstInStringData(); + void propertyMetaType(); + + void cleanupTestCase(); + + void ownMetaTypeNoProperties(); + private: static bool checkForSideEffects (const QMetaObjectBuilder& builder, QMetaObjectBuilder::AddMembers members); - static bool sameMetaObject - (const QMetaObject *meta1, const QMetaObject *meta2); + QList<QMetaObject *> dynamicMetaObjectsPendingFree; +}; + +struct MetaObjectComparison { + bool isSame = false; + QString details; + operator bool() {return isSame;} + + static inline auto Ok() {return MetaObjectComparison{true, QString()}; } + static inline auto Failed(QStringView message) {return MetaObjectComparison{false, message.toString()}; } }; +MetaObjectComparison sameMetaObject(const QMetaObject *meta1, const QMetaObject *meta2); // Dummy class that has something of every type of thing moc can generate. class SomethingOfEverything : public QObject @@ -85,7 +74,7 @@ class SomethingOfEverything : public QObject Q_PROPERTY(SomethingFlagEnum fprop READ fprop) Q_PROPERTY(QLocale::Language language READ language) Q_ENUMS(SomethingEnum) - Q_FLAGS(SomethingFlagEnum) + Q_FLAGS(SomethingFlag) public: Q_INVOKABLE SomethingOfEverything() {} ~SomethingOfEverything() {} @@ -101,6 +90,7 @@ public: XYZ = 1, UVW = 8 }; + Q_DECLARE_FLAGS(SomethingFlag, SomethingFlagEnum) Q_INVOKABLE Q_SCRIPTABLE void method1() {} @@ -193,8 +183,8 @@ void tst_QMetaObjectBuilder::flags() QCOMPARE(builder.flags(), 0); // Set flags - builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); - QCOMPARE(builder.flags(), QMetaObjectBuilder::DynamicMetaObject); + builder.setFlags(DynamicMetaObject); + QCOMPARE(builder.flags(), DynamicMetaObject); } void tst_QMetaObjectBuilder::method() @@ -747,13 +737,12 @@ void tst_QMetaObjectBuilder::variantProperty() QMetaObjectBuilder builder; builder.addProperty("variant", "const QVariant &"); QMetaObject *meta = builder.toMetaObject(); + dynamicMetaObjectsPendingFree.push_back(meta); QMetaProperty prop = meta->property(meta->propertyOffset()); - QCOMPARE(QMetaType::Type(prop.type()), QMetaType::QVariant); + QCOMPARE(QMetaType::Type(prop.userType()), QMetaType::QVariant); QCOMPARE(QMetaType::Type(prop.userType()), QMetaType::QVariant); QCOMPARE(QByteArray(prop.typeName()), QByteArray("QVariant")); - - free(meta); } void tst_QMetaObjectBuilder::notifySignal() @@ -790,6 +779,26 @@ void tst_QMetaObjectBuilder::notifySignal() void tst_QMetaObjectBuilder::enumerator() { + static const QtPrivate::QMetaTypeInterface fooFlagMetaType = { + 0, + 8, + 8, + QMetaType::IsEnumeration | QMetaType::IsUnsignedEnumeration | QMetaType::RelocatableType, + {}, + nullptr, + "fooFlag", + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + }; + QMetaObjectBuilder builder; // Add an enumerator and check its attributes. @@ -821,6 +830,7 @@ void tst_QMetaObjectBuilder::enumerator() enum1.setIsFlag(true); enum1.setIsScoped(true); enum1.setEnumName(QByteArrayLiteral("fooFlag")); + enum1.setMetaType(QMetaType(&fooFlagMetaType)); QCOMPARE(enum1.addKey("ABC", 0), 0); QCOMPARE(enum1.addKey("DEF", 1), 1); QCOMPARE(enum1.addKey("GHI", -1), 2); @@ -830,6 +840,7 @@ void tst_QMetaObjectBuilder::enumerator() QVERIFY(enum1.isFlag()); QVERIFY(enum1.isScoped()); QCOMPARE(enum1.enumName(), QByteArray("fooFlag")); + QCOMPARE(enum1.metaType(), QMetaType(&fooFlagMetaType)); QCOMPARE(enum1.keyCount(), 3); QCOMPARE(enum1.index(), 0); QCOMPARE(enum1.key(0), QByteArray("ABC")); @@ -997,106 +1008,23 @@ void tst_QMetaObjectBuilder::copyMetaObject() { QMetaObjectBuilder builder(&QObject::staticMetaObject); QMetaObject *meta = builder.toMetaObject(); - QVERIFY(sameMetaObject(meta, &QObject::staticMetaObject)); - free(meta); + dynamicMetaObjectsPendingFree.push_back(meta); + auto compared = sameMetaObject(meta, &QObject::staticMetaObject); + QVERIFY2(compared, qPrintable(compared.details)); QMetaObjectBuilder builder2(&staticMetaObject); meta = builder2.toMetaObject(); - QVERIFY(sameMetaObject(meta, &staticMetaObject)); - free(meta); + dynamicMetaObjectsPendingFree.push_back(meta); + compared = sameMetaObject(meta, &staticMetaObject); + QVERIFY2(compared, qPrintable(compared.details)); QMetaObjectBuilder builder3(&SomethingOfEverything::staticMetaObject); meta = builder3.toMetaObject(); - QVERIFY(sameMetaObject(meta, &SomethingOfEverything::staticMetaObject)); - free(meta); -} - -// Serialize and deserialize a meta object and check that -// it round-trips to the exact same value. -void tst_QMetaObjectBuilder::serialize() -{ - // Full QMetaObjectBuilder - { - QMetaObjectBuilder builder(&SomethingOfEverything::staticMetaObject); - QMetaObject *meta = builder.toMetaObject(); - - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append); - builder.serialize(stream); - - QMetaObjectBuilder builder2; - QDataStream stream2(data); - QMap<QByteArray, const QMetaObject *> references; - references.insert(QByteArray("QLocale"), &QLocale::staticMetaObject); - builder2.deserialize(stream2, references); - builder2.setStaticMetacallFunction(builder.staticMetacallFunction()); - QMetaObject *meta2 = builder2.toMetaObject(); - - QVERIFY(sameMetaObject(meta, meta2)); - free(meta); - free(meta2); - } - - // Partial QMetaObjectBuilder - { - QMetaObjectBuilder builder; - builder.setClassName("Test"); - builder.addProperty("foo", "int"); - - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append); - builder.serialize(stream); - - QMetaObjectBuilder builder2; - QDataStream stream2(data); - builder2.deserialize(stream2, QMap<QByteArray, const QMetaObject *>()); - - QCOMPARE(builder.superClass(), builder2.superClass()); - QCOMPARE(builder.className(), builder2.className()); - QCOMPARE(builder.propertyCount(), builder2.propertyCount()); - QCOMPARE(builder.property(0).name(), builder2.property(0).name()); - QCOMPARE(builder.property(0).type(), builder2.property(0).type()); - } -} - -void tst_QMetaObjectBuilder::relocatableData() -{ - QMetaObjectBuilder builder; - builder.setClassName("TestObject"); - - QMetaMethodBuilder intPropChanged = builder.addSignal("intPropChanged(int)"); - intPropChanged.setParameterNames(QList<QByteArray>() << "newIntPropValue"); - - QMetaPropertyBuilder prop = builder.addProperty("intProp", "int"); - prop.setNotifySignal(intPropChanged); - - QMetaMethodBuilder voidSlotInt = builder.addSlot("voidSlotInt(int)"); - voidSlotInt.setParameterNames(QList<QByteArray>() << "slotIntArg"); - - QMetaMethodBuilder listInvokableQRealQString = builder.addMethod("listInvokableQRealQString(qreal,QString)"); - listInvokableQRealQString.setReturnType("QVariantList"); - listInvokableQRealQString.setParameterNames(QList<QByteArray>() << "qrealArg" << "qstringArg"); - - bool ok = false; - QByteArray data = builder.toRelocatableData(&ok); - QVERIFY(ok); - - QMetaObjectBuilder builder2; - QMetaObject meta2; - builder2.fromRelocatableData(&meta2, &QObject::staticMetaObject, data); - - QMetaObject *meta = builder.toMetaObject(); - - QVERIFY(sameMetaObject(meta, &meta2)); - - QVERIFY(!meta2.d.extradata); - QVERIFY(!meta2.d.relatedMetaObjects); - QVERIFY(!meta2.d.static_metacall); - - free(meta); + dynamicMetaObjectsPendingFree.push_back(meta); + compared = sameMetaObject(meta, &SomethingOfEverything::staticMetaObject); + QVERIFY2(compared, qPrintable(compared.details)); } - // Check that removing a method updates notify signals appropriately void tst_QMetaObjectBuilder::removeNotifySignal() { @@ -1207,13 +1135,13 @@ static bool sameMethod(const QMetaMethod& method1, const QMetaMethod& method2) return true; } -static bool sameProperty(const QMetaProperty& prop1, const QMetaProperty& prop2) +static MetaObjectComparison sameProperty(const QMetaProperty& prop1, const QMetaProperty& prop2) { if (QByteArray(prop1.name()) != QByteArray(prop2.name())) - return false; + return MetaObjectComparison::Failed(QStringLiteral("Property names differ: %1 vs %2").arg(prop1.name(), prop2.name())); if (QByteArray(prop1.typeName()) != QByteArray(prop2.typeName())) - return false; + return MetaObjectComparison::Failed(QStringLiteral("Property type names differ: %1 vs %2").arg(prop1.typeName(), prop2.typeName())); if (prop1.isReadable() != prop2.isReadable() || prop1.isWritable() != prop2.isWritable() || @@ -1226,17 +1154,21 @@ static bool sameProperty(const QMetaProperty& prop1, const QMetaProperty& prop2) prop1.isEnumType() != prop2.isEnumType() || prop1.hasNotifySignal() != prop2.hasNotifySignal() || prop1.hasStdCppSet() != prop2.hasStdCppSet()) - return false; + return MetaObjectComparison::Failed(u"Flags differ"); if (prop1.hasNotifySignal()) { if (prop1.notifySignalIndex() != prop2.notifySignalIndex()) - return false; + return MetaObjectComparison::Failed(QStringLiteral("Notify signal index differ: %1 vs %2").arg( + QString::number(prop1.notifySignalIndex()), + QString::number(prop2.notifySignalIndex()))); } - if (prop1.revision() != prop2.revision()) - return false; + const int revision1 = prop1.revision(); + const int revision2 = prop2.revision(); + if (revision1 != revision2) + return MetaObjectComparison::Failed(QStringLiteral("Revisions differ: %1 vs %2").arg(QString::number(revision1), QString::number(revision2))); - return true; + return MetaObjectComparison::Ok(); } static bool sameEnumerator(const QMetaEnum& enum1, const QMetaEnum& enum2) @@ -1264,69 +1196,89 @@ static bool sameEnumerator(const QMetaEnum& enum1, const QMetaEnum& enum2) } // Determine if two meta objects are identical. -bool tst_QMetaObjectBuilder::sameMetaObject - (const QMetaObject *meta1, const QMetaObject *meta2) +MetaObjectComparison sameMetaObject(const QMetaObject *meta1, const QMetaObject *meta2) { int index; - if (strcmp(meta1->className(), meta2->className()) != 0) - return false; + if (strcmp(meta1->className(), meta2->className()) != 0) { + QString message = QLatin1String("Class names differ: %1 %2").arg(meta1->className(), meta2->className()); + return MetaObjectComparison::Failed(message); + } if (meta1->superClass() != meta2->superClass()) - return false; + return MetaObjectComparison::Failed(QStringLiteral("Super classes differ")); - if (meta1->constructorCount() != meta2->constructorCount() || - meta1->methodCount() != meta2->methodCount() || - meta1->enumeratorCount() != meta2->enumeratorCount() || - meta1->propertyCount() != meta2->propertyCount() || - meta1->classInfoCount() != meta2->classInfoCount()) - return false; + auto numCompare = [](int num1, int num2, const QString &message) { + if (num1 != num2) + return MetaObjectComparison::Failed(message.arg(QString::number(num1), QString::number(num2))); + return MetaObjectComparison::Ok(); + }; + + auto compared = numCompare(meta1->constructorCount(), meta2->constructorCount(), QStringLiteral("Construct counts differ: %1 %2")); + if (!compared.isSame) + return compared; + compared = numCompare(meta1->methodCount(), meta2->methodCount(), QStringLiteral("Method counts differ: %1 %2")); + if (!compared.isSame) + return compared; + compared = numCompare(meta1->enumeratorCount(), meta2->enumeratorCount(), QStringLiteral("Enumerator counts differ: %1 %2")); + if (!compared.isSame) + return compared; + compared = numCompare(meta1->propertyCount(), meta2->propertyCount(), QStringLiteral("Property counts differ: %1 %2")); + if (!compared.isSame) + return compared; + compared = numCompare(meta1->classInfoCount(), meta2->classInfoCount(), QStringLiteral("ClassInfo counts differ: %1 %2")); + if (!compared.isSame) + return compared; for (index = 0; index < meta1->constructorCount(); ++index) { if (!sameMethod(meta1->constructor(index), meta2->constructor(index))) - return false; + return MetaObjectComparison::Failed(QStringLiteral("Constructors difer at index %1").arg(index)); } for (index = 0; index < meta1->methodCount(); ++index) { if (!sameMethod(meta1->method(index), meta2->method(index))) - return false; + return MetaObjectComparison::Failed(QStringLiteral("Methods difer at index %1").arg(index)); } for (index = 0; index < meta1->propertyCount(); ++index) { - if (!sameProperty(meta1->property(index), meta2->property(index))) - return false; + if (auto compared = sameProperty(meta1->property(index), meta2->property(index)); !compared) { + compared.details += QStringLiteral(" at index %1").arg(index); + return compared; + } } for (index = 0; index < meta1->enumeratorCount(); ++index) { if (!sameEnumerator(meta1->enumerator(index), meta2->enumerator(index))) - return false; + return MetaObjectComparison::Failed(QStringLiteral("Enumerators difer at index %1").arg(index)); } for (index = 0; index < meta1->classInfoCount(); ++index) { - if (QByteArray(meta1->classInfo(index).name()) != - QByteArray(meta2->classInfo(index).name())) - return false; - if (QByteArray(meta1->classInfo(index).value()) != - QByteArray(meta2->classInfo(index).value())) - return false; + const auto name1= QByteArray(meta1->classInfo(index).name()); + const auto name2= QByteArray(meta1->classInfo(index).name()); + if (name1 != name2) + return MetaObjectComparison::Failed(QStringLiteral("Class infos difer at index %1: %2 vs %3").arg(QString::number(index), name1, name2)); + const auto value1 = QByteArray(meta1->classInfo(index).value()); + const auto value2= QByteArray(meta2->classInfo(index).value()); + if ( value1 != value2) + return MetaObjectComparison::Failed(QStringLiteral("Class infos difer at index %1: %2 vs %3").arg(QString::number(index), value1, value2)); } const auto *objects1 = meta1->d.relatedMetaObjects; const auto *objects2 = meta2->d.relatedMetaObjects; if (objects1 && !objects2) - return false; + return MetaObjectComparison::Failed(u"Metaobject 1 had related metaobjects, but Metaoject 2 did not"); if (objects2 && !objects1) - return false; + return MetaObjectComparison::Failed(u"Metaobject 2 had related metaobjects, but Metaoject 1 did not"); if (objects1 && objects2) { while (*objects1 != 0 && *objects2 != 0) { if (*objects1 != *objects2) - return false; + return MetaObjectComparison::Failed(QStringLiteral("Related metaobjects differ at index %1").arg(index)); ++objects1; ++objects2; } } - return true; + return MetaObjectComparison::Ok(); } @@ -1350,7 +1302,7 @@ private: //Q_PROPERTY(int intProp READ intProp WRITE setIntProp NOTIFY intPropChanged) public: - TestObject(QObject *parent = 0); // Q_INVOKABLE + TestObject(QObject *parent = nullptr); // Q_INVOKABLE ~TestObject(); // Property accessors @@ -1529,9 +1481,7 @@ int TestObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a) if (_id < ownMethodCount) qt_static_metacall(this, _c, _id, _a); _id -= ownMethodCount; - } -#ifndef QT_NO_PROPERTIES - else if (_c == QMetaObject::ReadProperty) { + } else if (_c == QMetaObject::ReadProperty) { void *_v = _a[0]; switch (_id) { case 0: *reinterpret_cast< int*>(_v) = intProp(); break; @@ -1554,7 +1504,6 @@ int TestObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a) } else if (_c == QMetaObject::ResetProperty) { _id -= ownPropertyCount; } -#endif // QT_NO_PROPERTIES return _id; } @@ -1572,8 +1521,8 @@ void tst_QMetaObjectBuilder::usage_signal() QSignalSpy propChangedSpy(testObject.data(), &TestObject::intPropChanged); testObject->emitIntPropChanged(); - QCOMPARE(propChangedSpy.count(), 1); - QCOMPARE(propChangedSpy.at(0).count(), 1); + QCOMPARE(propChangedSpy.size(), 1); + QCOMPARE(propChangedSpy.at(0).size(), 1); QCOMPARE(propChangedSpy.at(0).at(0).toInt(), testObject->intProp()); } @@ -1582,15 +1531,15 @@ void tst_QMetaObjectBuilder::usage_property() QScopedPointer<TestObject> testObject(new TestObject); QVariant prop = testObject->property("intProp"); - QCOMPARE(prop.type(), QVariant::Int); + QCOMPARE(prop.metaType(), QMetaType(QMetaType::Int)); QCOMPARE(prop.toInt(), testObject->intProp()); QSignalSpy propChangedSpy(testObject.data(), &TestObject::intPropChanged); QVERIFY(testObject->intProp() != 123); testObject->setProperty("intProp", 123); - QCOMPARE(propChangedSpy.count(), 1); + QCOMPARE(propChangedSpy.size(), 1); prop = testObject->property("intProp"); - QCOMPARE(prop.type(), QVariant::Int); + QCOMPARE(prop.metaType(), QMetaType(QMetaType::Int)); QCOMPARE(prop.toInt(), 123); } @@ -1618,9 +1567,9 @@ void tst_QMetaObjectBuilder::usage_method() QVERIFY(listInvokableQRealQString.invoke(testObject.data(), Q_RETURN_ARG(QVariantList, list), Q_ARG(qreal, 123.0), Q_ARG(QString, "ciao"))); QCOMPARE(list.size(), 2); - QCOMPARE(list.at(0).type(), QVariant::Type(QMetaType::QReal)); + QCOMPARE(list.at(0).metaType(), QMetaType(QMetaType::QReal)); QCOMPARE(list.at(0).toDouble(), double(123)); - QCOMPARE(list.at(1).type(), QVariant::String); + QCOMPARE(list.at(1).metaType(), QMetaType(QMetaType::QString)); QCOMPARE(list.at(1).toString(), QString::fromLatin1("ciao")); } @@ -1688,6 +1637,42 @@ void tst_QMetaObjectBuilder::classNameFirstInStringData() free(mo); } +struct MyFoo {}; +struct myParameter {}; + +void tst_QMetaObjectBuilder::propertyMetaType() +{ + qRegisterMetaType<myParameter>(); + QMetaType meta = QMetaType::fromType<MyFoo>(); + auto metaId = meta.id(); + QMetaObjectBuilder builder; + builder.setClassName("Test"); + builder.addProperty("myParameter", "MyFoo"); + auto mo = builder.toMetaObject(); + + QMetaProperty metaProp = mo->property(mo->indexOfProperty("myParameter")); + QCOMPARE(metaProp.typeName(), meta.name()); + QCOMPARE(metaProp.typeId(), metaId); + QCOMPARE(metaProp.metaType(), meta); + free(mo); +} + +void tst_QMetaObjectBuilder::ownMetaTypeNoProperties() +{ + QMetaObjectBuilder builder; + builder.setClassName("NoProperties"); + auto mo = builder.toMetaObject(); + auto cleanup = qScopeGuard([&](){ free(mo); }); + // own metatype should be invalid, as the dynamic metaobject has not been registered + QVERIFY(!mo->metaType().isValid());// should not crash +} + +void tst_QMetaObjectBuilder::cleanupTestCase() +{ + for (QMetaObject *obj: dynamicMetaObjectsPendingFree) + free(obj); +} + QTEST_MAIN(tst_QMetaObjectBuilder) #include "tst_qmetaobjectbuilder.moc" |