// Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "tst_qmetatype.h" #include "tst_qmetatype_libs.h" #include void tst_QMetaType::constRefs() { QCOMPARE(::qMetaTypeId(), ::qMetaTypeId()); QCOMPARE(::qMetaTypeId(), ::qMetaTypeId()); QCOMPARE(::qMetaTypeId(), ::qMetaTypeId()); QCOMPARE(::qMetaTypeId &>(), ::qMetaTypeId >()); static_assert(::qMetaTypeId() == ::qMetaTypeId()); } template U convert(const T &t) { return t; } template struct ConvertFunctor { CustomConvertibleType operator()(const From& f) const { return CustomConvertibleType(QVariant::fromValue(f)); } }; template struct OptionalWrapper { std::optional operator()(const T& t) const { if (!CustomConvertibleType::s_ok) return std::nullopt; return t; } }; template struct ConvertFunctorWithOptional { std::optional operator()(const From& f) const { if (!CustomConvertibleType::s_ok) return std::nullopt; return CustomConvertibleType(QVariant::fromValue(f)); } }; template bool hasRegisteredConverterFunction() { return QMetaType::hasRegisteredConverterFunction(); } template void testCustomTypeNotYetConvertible() { QVERIFY((!hasRegisteredConverterFunction())); QVERIFY((!QVariant::fromValue(From()).template canConvert())); } template void testCustomTypeConvertible() { QVERIFY((hasRegisteredConverterFunction())); QVERIFY((QVariant::fromValue(From()).template canConvert())); } void customTypeNotYetConvertible() { testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible(); testCustomTypeNotYetConvertible>(); } void registerCustomTypeConversions() { QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convertOk))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convert))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convertOk))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convert))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convertOk))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convert))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convertOk))); QVERIFY((QMetaType::registerConverter(convert))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convertOk))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convert))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convertOk))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convert))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convertOk))); QVERIFY((QMetaType::registerConverter(&CustomConvertibleType::convert))); QVERIFY((QMetaType::registerConverter(ConvertFunctorWithOptional()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctorWithOptional()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctorWithOptional()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctorWithOptional()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctorWithOptional()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctorWithOptional()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctorWithOptional()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter>(OptionalWrapper()))); QVERIFY((QMetaType::registerConverter())); QTest::ignoreMessage(QtWarningMsg, "Type conversion already registered from type CustomConvertibleType to type CustomConvertibleType2"); QVERIFY((!QMetaType::registerConverter())); } void tst_QMetaType::convertCustomType_data() { customTypeNotYetConvertible(); registerCustomTypeConversions(); QTest::addColumn("ok"); QTest::addColumn("testQString"); QTest::addColumn("testBool"); QTest::addColumn("testInt"); QTest::addColumn("testDouble"); QTest::addColumn("testFloat"); QTest::addColumn("testQRect"); QTest::addColumn("testQRectF"); QTest::addColumn("testQPoint"); QTest::addColumn("testQPointF"); QTest::addColumn("testQSize"); QTest::addColumn("testQSizeF"); QTest::addColumn("testQLine"); QTest::addColumn("testQLineF"); QTest::addColumn("testQChar"); QTest::addColumn("testCustom"); QTest::addColumn("testDerived"); QTest::newRow("default") << true << QString::fromLatin1("string") << true << 15 << double(3.14) << float(3.6) << QRect(1, 2, 3, 4) << QRectF(1.4, 1.9, 10.9, 40.2) << QPoint(12, 34) << QPointF(9.2, 2.7) << QSize(4, 9) << QSizeF(3.3, 9.8) << QLine(3, 9, 29, 4) << QLineF(38.9, 28.9, 102.3, 0.0) << QChar('Q') << CustomConvertibleType(QString::fromLatin1("test")) << DerivedGadgetType(QString::fromLatin1("test")); QTest::newRow("not ok") << false << QString::fromLatin1("string") << true << 15 << double(3.14) << float(3.6) << QRect(1, 2, 3, 4) << QRectF(1.4, 1.9, 10.9, 40.2) << QPoint(12, 34) << QPointF(9.2, 2.7) << QSize(4, 9) << QSizeF(3.3, 9.8) << QLine(3, 9, 29, 4) << QLineF() << QChar('Q') << CustomConvertibleType(42) << DerivedGadgetType(42); } void tst_QMetaType::convertCustomType() { QFETCH(bool, ok); CustomConvertibleType::s_ok = ok; CustomConvertibleType t; QVariant v = QVariant::fromValue(t); QFETCH(QString, testQString); CustomConvertibleType::s_value = testQString; QCOMPARE(v.toString(), ok ? testQString : QString()); QCOMPARE(v.value(), ok ? testQString : QString()); QVERIFY(CustomConvertibleType::s_value.canConvert()); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toString()), ok ? testQString : QString()); QFETCH(bool, testBool); CustomConvertibleType::s_value = testBool; QCOMPARE(v.toBool(), testBool); QCOMPARE(v.value(), testBool); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toBool()), testBool); QFETCH(int, testInt); CustomConvertibleType::s_value = testInt; QCOMPARE(v.toInt(), ok ? testInt : 0); QCOMPARE(v.value(), ok ? testInt : 0); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toInt()), ok ? testInt : 0); QFETCH(double, testDouble); CustomConvertibleType::s_value = testDouble; QCOMPARE(v.toDouble(), testDouble); QCOMPARE(v.value(), testDouble); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toDouble()), testDouble); QFETCH(float, testFloat); CustomConvertibleType::s_value = testFloat; QCOMPARE(v.toFloat(), ok ? testFloat : 0.0); QCOMPARE(v.value(), ok ? testFloat : 0.0); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toFloat()), ok ? testFloat : 0); QFETCH(QRect, testQRect); CustomConvertibleType::s_value = testQRect; QCOMPARE(v.toRect(), testQRect); QCOMPARE(v.value(), testQRect); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toRect()), testQRect); QFETCH(QRectF, testQRectF); CustomConvertibleType::s_value = testQRectF; QCOMPARE(v.toRectF(), ok ? testQRectF : QRectF()); QCOMPARE(v.value(), ok ? testQRectF : QRectF()); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toRectF()), ok ? testQRectF : QRectF()); QFETCH(QPoint, testQPoint); CustomConvertibleType::s_value = testQPoint; QCOMPARE(v.toPoint(), testQPoint); QCOMPARE(v.value(), testQPoint); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toPoint()), testQPoint); QFETCH(QPointF, testQPointF); CustomConvertibleType::s_value = testQPointF; QCOMPARE(v.toPointF(), ok ? testQPointF : QPointF()); QCOMPARE(v.value(), ok ? testQPointF : QPointF()); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toPointF()), ok ? testQPointF : QPointF()); QFETCH(QSize, testQSize); CustomConvertibleType::s_value = testQSize; QCOMPARE(v.toSize(), testQSize); QCOMPARE(v.value(), testQSize); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toSize()), testQSize); QFETCH(QSizeF, testQSizeF); CustomConvertibleType::s_value = testQSizeF; QCOMPARE(v.toSizeF(), ok ? testQSizeF : QSizeF()); QCOMPARE(v.value(), ok ? testQSizeF : QSizeF()); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toSizeF()), ok ? testQSizeF : QSizeF()); QFETCH(QLine, testQLine); CustomConvertibleType::s_value = testQLine; QCOMPARE(v.toLine(), testQLine); QCOMPARE(v.value(), testQLine); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toLine()), testQLine); QFETCH(QLineF, testQLineF); CustomConvertibleType::s_value = testQLineF; QCOMPARE(v.toLineF(), ok ? testQLineF : QLineF()); QCOMPARE(v.value(), ok ? testQLineF : QLineF()); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toLineF()), ok ? testQLineF : QLineF()); QFETCH(QChar, testQChar); CustomConvertibleType::s_value = testQChar; QCOMPARE(v.toChar(), testQChar); QCOMPARE((CustomConvertibleType::s_value.value().m_foo.toChar()), testQChar); QFETCH(CustomConvertibleType, testCustom); v = QVariant::fromValue(testCustom); QVERIFY(v.canConvert(QMetaType(::qMetaTypeId()))); QCOMPARE(v.value().m_foo, testCustom.m_foo); // Check that converters that actually convert to std::optional are not // taken to indicate success or failure of the conversion. In these cases, // the conversion must always succeed, even if the converter has returned a // nullopt. v = QVariant::fromValue(testCustom); QVERIFY(v.canConvert(QMetaType::fromType>())); QVERIFY(v.convert(QMetaType::fromType>())); QCOMPARE(v.value>().has_value(), ok); if (ok) { QCOMPARE(v.value>().value().m_foo, testCustom.m_foo); } QFETCH(DerivedGadgetType, testDerived); v = QVariant::fromValue(testDerived); QCOMPARE(v.metaType(), QMetaType::fromType()); QCOMPARE(v.value().m_foo, testDerived.m_foo); QVERIFY(v.canConvert(QMetaType::fromType())); QVERIFY(v.convert(QMetaType::fromType())); QCOMPARE(v.metaType(), QMetaType::fromType()); QCOMPARE(v.value().m_foo, testDerived.m_foo); } void tst_QMetaType::convertConstNonConst() { auto mtConstObj = QMetaType::fromType(); auto mtObj = QMetaType::fromType(); auto mtConstDerived = QMetaType::fromType(); auto mtDerived = QMetaType::fromType(); QVERIFY(QMetaType::canConvert(mtConstObj, mtObj)); QVERIFY(QMetaType::canConvert(mtObj, mtConstObj)); // casting const away is allowed (but can lead to UB) QVERIFY(QMetaType::canConvert(mtConstDerived, mtObj)); QVERIFY(QMetaType::canConvert(mtDerived, mtConstObj)); QVERIFY(QMetaType::canConvert(mtObj, mtConstDerived)); } void tst_QMetaType::compareCustomEqualOnlyType() { QMetaType type = QMetaType::fromType(); CustomEqualsOnlyType val50(50); CustomEqualsOnlyType val100(100); CustomEqualsOnlyType val100x(100); QVariant variant50 = QVariant::fromValue(val50); QVariant variant100 = QVariant::fromValue(val100); QVariant variant100x = QVariant::fromValue(val100x); QVERIFY(variant50 != variant100); QVERIFY(variant50 != variant100x); QVERIFY(variant100 != variant50); QVERIFY(variant100x != variant50); QCOMPARE(variant100, variant100x); QCOMPARE(variant100, variant100); // check QMetaType::compare works/doesn't crash for equals only comparators auto cmp = type.compare(variant50.constData(), variant50.constData()); QCOMPARE(cmp, QPartialOrdering::Unordered); bool equals = type.equals(variant50.constData(), variant50.constData()); QVERIFY(equals); cmp = type.compare(variant100.constData(), variant100x.constData()); QCOMPARE(cmp, QPartialOrdering::Unordered); equals = type.equals(variant100.constData(), variant100x.constData()); QVERIFY(equals); cmp = type.compare(variant50.constData(), variant100.constData()); QCOMPARE(cmp, QPartialOrdering::Unordered); equals = type.equals(variant50.constData(), variant100.constData()); QVERIFY(!equals); //check QMetaType::equals for type w/o equals comparator being registered CustomMovable movable1; CustomMovable movable2; type = QMetaType::fromType(); equals = type.equals(&movable1, &movable2); } void tst_QMetaType::customDebugStream() { MessageHandlerCustom handler(::qMetaTypeId()); QVariant v1 = QVariant::fromValue(CustomDebugStreamableType()); handler.expectedMessage = "QVariant(CustomDebugStreamableType, string-content)"; qDebug() << v1; MessageHandlerCustom handler2(::qMetaTypeId()); QMetaType::registerConverter(&CustomDebugStreamableType2::toString); handler2.expectedMessage = "QVariant(CustomDebugStreamableType2, \"test\")"; QVariant v2 = QVariant::fromValue(CustomDebugStreamableType2()); qDebug() << v2; } void tst_QMetaType::unknownType() { QMetaType invalid(QMetaType::UnknownType); QVERIFY(!invalid.create()); QVERIFY(!invalid.sizeOf()); QVERIFY(!invalid.metaObject()); int buffer = 0xBAD; invalid.construct(&buffer); QCOMPARE(buffer, 0xBAD); } void tst_QMetaType::fromType() { #define FROMTYPE_CHECK(MetaTypeName, MetaTypeId, RealType) \ QCOMPARE(QMetaType::fromType(), QMetaType(MetaTypeId)); \ QVERIFY(QMetaType::fromType() == QMetaType(MetaTypeId)); \ QVERIFY(!(QMetaType::fromType() != QMetaType(MetaTypeId))); \ if (MetaTypeId != QMetaType::Void) \ QCOMPARE(QMetaType::fromType().id(), MetaTypeId); FOR_EACH_CORE_METATYPE(FROMTYPE_CHECK) QVERIFY(QMetaType::fromType() != QMetaType()); QCOMPARE(QMetaType(), QMetaType()); QCOMPARE(QMetaType(QMetaType::UnknownType), QMetaType()); FROMTYPE_CHECK(_, ::qMetaTypeId>(), Whity) #undef FROMTYPE_CHECK } template struct CharTemplate { struct { int a; } x; union { int a; } y; }; void tst_QMetaType::operatorEq_data() { QTest::addColumn("typeA"); QTest::addColumn("typeB"); QTest::addColumn("eq"); QTest::newRow("String") << QMetaType(QMetaType::QString) << QMetaType::fromType() << true; QTest::newRow("void1") << QMetaType(QMetaType::UnknownType) << QMetaType::fromType() << false; QTest::newRow("void2") << QMetaType::fromType() << QMetaType::fromType() << true; QTest::newRow("list1") << QMetaType::fromType>() << QMetaType::fromType>() << true; QTest::newRow("list2") << QMetaType::fromType>() << QMetaType::fromType>() << false; QTest::newRow("char1") << QMetaType::fromType'>>() << QMetaType::fromType', void>>() << true; QTest::newRow("annon1") << QMetaType::fromType'>::x)>() << QMetaType::fromType'>::x)>() << true; QTest::newRow("annon2") << QMetaType::fromType'>::x)>() << QMetaType::fromType::x)>() << false; } void tst_QMetaType::operatorEq() { QFETCH(QMetaType, typeA); QFETCH(QMetaType, typeB); QFETCH(bool, eq); QCOMPARE(typeA == typeB, eq); QCOMPARE(typeB == typeA, eq); QCOMPARE(typeA != typeB, !eq); QCOMPARE(typeB != typeA, !eq); #if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY) // for built-in types or locally-defined types, this must also hold true if (eq) QCOMPARE(typeA.iface(), typeB.iface()); #endif } void tst_QMetaType::operatorEq2_data() { create_data(); } void tst_QMetaType::operatorEq2() { QFETCH(int, type); QMetaType fromType1, fromType2; QMetaType fromId1(type), fromId2(type); switch (type) { case QMetaType::UnknownType: break; #define GET_METATYPE_FROM_TYPE(MetaTypeName, MetaTypeId, RealType) \ case QMetaType::MetaTypeName: \ fromType1 = QMetaType::fromType(); \ fromType2 = QMetaType::fromType(); \ break; FOR_EACH_CORE_METATYPE(GET_METATYPE_FROM_TYPE) #undef GET_METATYPE_FROM_TYPE } // sanity check QCOMPARE(fromId1.id(), type); QCOMPARE(fromId2.id(), type); // confirm that they're all equal QCOMPARE(fromId1, fromId2); QCOMPARE(fromType1, fromType2); QCOMPARE(fromType1, fromId1); QCOMPARE(fromType2, fromId2); #if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY) // for built-in types (other than void), this must be true if (type != QMetaType::Void) { QCOMPARE(fromType1.iface(), fromId1.iface()); QCOMPARE(fromType2.iface(), fromId1.iface()); } #endif } #define DECLARE_LIB_FUNCTION(TYPE, ID) \ Q_DECL_IMPORT QMetaType metatype_ ## TYPE(); namespace Lib1 { FOR_EACH_METATYPE_LIBS(DECLARE_LIB_FUNCTION) } namespace Lib2 { FOR_EACH_METATYPE_LIBS(DECLARE_LIB_FUNCTION) } #undef DECLARE_LIB_FUNCTION using LibMetatypeFunction = QMetaType (*)(); void tst_QMetaType::operatorEqAcrossLibs_data() { QTest::addColumn("builtinTypeId"); QTest::addColumn("localType"); QTest::addColumn("lib1Function"); QTest::addColumn("lib2Function"); #define ADD_ROW(TYPE, ID) \ QTest::addRow(QT_STRINGIFY(TYPE)) << int(ID) \ << QMetaType::fromType() \ << &Lib1::metatype_ ## TYPE \ << &Lib2::metatype_ ## TYPE; FOR_EACH_METATYPE_LIBS(ADD_ROW) #undef ADD_ROW } void tst_QMetaType::operatorEqAcrossLibs() { QFETCH(int, builtinTypeId); QFETCH(QMetaType, localType); QFETCH(LibMetatypeFunction, lib1Function); QFETCH(LibMetatypeFunction, lib2Function); QMetaType lib1Type = lib1Function(); QMetaType lib2Type = lib2Function(); const QtPrivate::QMetaTypeInterface *localIface = localType.iface(); const QtPrivate::QMetaTypeInterface *lib1Iface = lib1Type.iface(); const QtPrivate::QMetaTypeInterface *lib2Iface = lib2Type.iface(); // DO THIS FIRST: // if this isn't a built-in type, then the QMetaTypeInterface::typeId is // initially set to 0 QCOMPARE(lib1Type, lib2Type); int actualTypeId = localType.id(); bool builtinTypeExpected = builtinTypeId != QMetaType::UnknownType; bool builtinTypeActually = actualTypeId < QMetaType::User; qDebug() << "QMetaType for type" << QByteArray(localType.name()) << "(type ID" << (actualTypeId >= 0x1000 ? Qt::hex : Qt::dec) << actualTypeId << ')' << (builtinTypeActually ? "IS" : "is NOT") << "a built-in type;" << "local interface:" << static_cast(localIface) << "lib1 interface:" << static_cast(lib1Iface) << "lib2 interface:" << static_cast(lib2Iface); QCOMPARE(builtinTypeActually, builtinTypeExpected); QCOMPARE(lib1Type.id(), actualTypeId); QCOMPARE(lib2Type.id(), actualTypeId); QCOMPARE(QByteArray(lib1Type.name()), QByteArray(localType.name())); QCOMPARE(QByteArray(lib2Type.name()), QByteArray(localType.name())); QCOMPARE(lib1Type, localType); QCOMPARE(lib2Type, localType); #if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY) if (actualTypeId < QMetaType::FirstGuiType && actualTypeId != QMetaType::Void) { // for built-in QtCore types, we expect the interfaces to be the same too QCOMPARE(lib1Iface, localIface); QCOMPARE(lib2Iface, localIface); } #endif } class WithPrivateDTor { ~WithPrivateDTor(){}; }; struct WithDeletedDtor { ~WithDeletedDtor() = delete; }; void tst_QMetaType::typesWithInaccessibleDTors() { // should compile Q_UNUSED(QMetaType::fromType()); Q_UNUSED(QMetaType::fromType()); } void tst_QMetaType::voidIsNotUnknown() { QMetaType voidType = QMetaType::fromType(); QMetaType voidType2 = QMetaType(QMetaType::Void); QCOMPARE(voidType, voidType2); QVERIFY(voidType != QMetaType(QMetaType::UnknownType)); } void tst_QMetaType::typeNameNormalization() { // check the we normalize types the right way #define CHECK_TYPE_NORMALIZATION(Normalized, ...) \ do { \ /*QCOMPARE(QtPrivate::typenameHelper(), Normalized);*/ \ QByteArray typeName = QMetaObject::normalizedType(#__VA_ARGS__); \ QCOMPARE(typeName, Normalized); \ typeName = QMetaType::fromType<__VA_ARGS__>().name(); \ QCOMPARE(typeName, Normalized); \ } while (0) CHECK_TYPE_NORMALIZATION("QList", QList); CHECK_TYPE_NORMALIZATION("QList", QList); CHECK_TYPE_NORMALIZATION("QList", QList); CHECK_TYPE_NORMALIZATION("QList", QList); CHECK_TYPE_NORMALIZATION("QList", QList); CHECK_TYPE_NORMALIZATION("QList", QList); CHECK_TYPE_NORMALIZATION("uint", uint); CHECK_TYPE_NORMALIZATION("QList>", QList>); CHECK_TYPE_NORMALIZATION("QList", QList); CHECK_TYPE_NORMALIZATION("QList", QList); CHECK_TYPE_NORMALIZATION("QList", QList); CHECK_TYPE_NORMALIZATION("QList", QList); CHECK_TYPE_NORMALIZATION("QList", QList); CHECK_TYPE_NORMALIZATION("QList", QList); #ifdef Q_CC_MSVC CHECK_TYPE_NORMALIZATION("qulonglong", __int64 unsigned); #endif CHECK_TYPE_NORMALIZATION("std::pair", QPair); // The string based normalization doesn't handle aliases, QMetaType::fromType() does // CHECK_TYPE_NORMALIZATION("qulonglong", quint64); QCOMPARE(QMetaType::fromType().name(), "qulonglong"); // noramlizedType and metatype name agree { auto type = QMetaType::fromType::x)>(); QCOMPARE(type.name(), QMetaObject::normalizedType(type.name())); } { auto type = QMetaType::fromType::y)>(); QCOMPARE(type.name(), QMetaObject::normalizedType(type.name())); } } QT_BEGIN_NAMESPACE namespace QtPrivate { struct tst_QMetaType_TestType {}; } QT_END_NAMESPACE void tst_QMetaType::typeNameInQtPrivate() { using T = QT_PREPEND_NAMESPACE(QtPrivate::tst_QMetaType_TestType); // some compilers (GCC) are known to suppress the namespace prefix if the // type and the function where it is expanded on are on the same namespace static constexpr char expectedName[] = "QtPrivate::tst_QMetaType_TestType"; QMetaType mt = QMetaType::fromType(); QCOMPARE(mt.name(), expectedName); } #if QT_DEPRECATED_SINCE(6, 0) void tst_QMetaType::testDeprecatedGetters() { QFETCH(int, aType); QFETCH(QByteArray, aTypeName); if (aType >= QMetaType::FirstWidgetsType) QSKIP("The test doesn't link against QtWidgets."); // QMetaType::type("name") -> QMetaType::fromName("name").id() QT_IGNORE_DEPRECATIONS(QCOMPARE(QMetaType::type(aTypeName), QMetaType::fromName(aTypeName).id());) // QMetaType::typeName(int) -> QMetaType(int).name() QT_IGNORE_DEPRECATIONS(QCOMPARE(QLatin1String(QMetaType::typeName(aType)), QLatin1String(QMetaType(aType).name()));) // QMetaType::typeFlags(int) -> QMetaType(int).flags() QT_IGNORE_DEPRECATIONS(QCOMPARE(QMetaType::typeFlags(aType), QMetaType(aType).flags());) // QMetaType::metaObjectForType(int) -> QMetaType(int).metaObject() QT_IGNORE_DEPRECATIONS(QCOMPARE(QMetaType::metaObjectForType(aType), QMetaType(aType).metaObject());) } void tst_QMetaType::testDeprecatedLoadSave() { QFETCH(int, type); QFETCH(bool, isStreamable); if (!isStreamable) return; QMetaType metaType(type); void *value = metaType.create(); auto cleanup = qScopeGuard([&metaType, value]() { metaType.destroy(value); }); QByteArray ba; QDataStream stream(&ba, QIODevice::ReadWrite); // Write using deprecated API QT_IGNORE_DEPRECATIONS(QVERIFY(QMetaType::save(stream, type, value));) QCOMPARE(stream.status(), QDataStream::Ok); // Read using non-deprecated API stream.device()->seek(0); QVERIFY(metaType.load(stream, value)); QCOMPARE(stream.status(), QDataStream::Ok); // Write using non-deprecated API stream.device()->seek(0); ba.clear(); QVERIFY(metaType.save(stream, value)); QCOMPARE(stream.status(), QDataStream::Ok); // Read using deprecated API stream.device()->seek(0); QT_IGNORE_DEPRECATIONS(QVERIFY(QMetaType::load(stream, type, value));) QCOMPARE(stream.status(), QDataStream::Ok); } #endif // QT_DEPRECATED_SINCE(6, 0) // Compile-time test, it should be possible to register function pointer types class Undefined; typedef Undefined (*UndefinedFunction0)(); typedef Undefined (*UndefinedFunction1)(Undefined); typedef Undefined (*UndefinedFunction2)(Undefined, Undefined); typedef Undefined (*UndefinedFunction3)(Undefined, Undefined, Undefined); typedef Undefined (*UndefinedFunction4)(Undefined, Undefined, Undefined, Undefined, Undefined, Undefined, Undefined, Undefined); Q_DECLARE_METATYPE(UndefinedFunction0); Q_DECLARE_METATYPE(UndefinedFunction1); Q_DECLARE_METATYPE(UndefinedFunction2); Q_DECLARE_METATYPE(UndefinedFunction3); Q_DECLARE_METATYPE(UndefinedFunction4);