diff options
Diffstat (limited to 'tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp')
-rw-r--r-- | tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp | 268 |
1 files changed, 251 insertions, 17 deletions
diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp index 95cc0e7ed8..68bcb53056 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp @@ -1,8 +1,8 @@ // Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "tst_qmetatype.h" -#include "tst_qvariant_common.h" +#include "tst_qmetatype_libs.h" #include <QtCore/private/qmetaobjectbuilder_p.h> @@ -30,6 +30,30 @@ struct ConvertFunctor } }; +template<typename T> +struct OptionalWrapper +{ + std::optional<T> operator()(const T& t) const + { + if (!CustomConvertibleType::s_ok) + return std::nullopt; + + return t; + } +}; + +template<typename From> +struct ConvertFunctorWithOptional +{ + std::optional<CustomConvertibleType> operator()(const From& f) const + { + if (!CustomConvertibleType::s_ok) + return std::nullopt; + + return CustomConvertibleType(QVariant::fromValue(f)); + } +}; + template<typename From, typename To> bool hasRegisteredConverterFunction() { @@ -81,6 +105,7 @@ void customTypeNotYetConvertible() testCustomTypeNotYetConvertible<QLineF, CustomConvertibleType>(); testCustomTypeNotYetConvertible<QChar, CustomConvertibleType>(); testCustomTypeNotYetConvertible<CustomConvertibleType, CustomConvertibleType2>(); + testCustomTypeNotYetConvertible<CustomConvertibleType, std::optional<CustomConvertibleType>>(); } void registerCustomTypeConversions() @@ -99,20 +124,22 @@ void registerCustomTypeConversions() QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QLine>(&CustomConvertibleType::convert<QLine>))); QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QLineF>(&CustomConvertibleType::convertOk<QLineF>))); QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QChar>(&CustomConvertibleType::convert<QChar>))); - QVERIFY((QMetaType::registerConverter<QString, CustomConvertibleType>(ConvertFunctor<QString>()))); + QVERIFY((QMetaType::registerConverter<QString, CustomConvertibleType>(ConvertFunctorWithOptional<QString>()))); QVERIFY((QMetaType::registerConverter<bool, CustomConvertibleType>(ConvertFunctor<bool>()))); - QVERIFY((QMetaType::registerConverter<int, CustomConvertibleType>(ConvertFunctor<int>()))); + QVERIFY((QMetaType::registerConverter<int, CustomConvertibleType>(ConvertFunctorWithOptional<int>()))); QVERIFY((QMetaType::registerConverter<double, CustomConvertibleType>(ConvertFunctor<double>()))); - QVERIFY((QMetaType::registerConverter<float, CustomConvertibleType>(ConvertFunctor<float>()))); + QVERIFY((QMetaType::registerConverter<float, CustomConvertibleType>(ConvertFunctorWithOptional<float>()))); QVERIFY((QMetaType::registerConverter<QRect, CustomConvertibleType>(ConvertFunctor<QRect>()))); - QVERIFY((QMetaType::registerConverter<QRectF, CustomConvertibleType>(ConvertFunctor<QRectF>()))); + QVERIFY((QMetaType::registerConverter<QRectF, CustomConvertibleType>(ConvertFunctorWithOptional<QRectF>()))); QVERIFY((QMetaType::registerConverter<QPoint, CustomConvertibleType>(ConvertFunctor<QPoint>()))); - QVERIFY((QMetaType::registerConverter<QPointF, CustomConvertibleType>(ConvertFunctor<QPointF>()))); + QVERIFY((QMetaType::registerConverter<QPointF, CustomConvertibleType>(ConvertFunctorWithOptional<QPointF>()))); QVERIFY((QMetaType::registerConverter<QSize, CustomConvertibleType>(ConvertFunctor<QSize>()))); - QVERIFY((QMetaType::registerConverter<QSizeF, CustomConvertibleType>(ConvertFunctor<QSizeF>()))); + QVERIFY((QMetaType::registerConverter<QSizeF, CustomConvertibleType>(ConvertFunctorWithOptional<QSizeF>()))); QVERIFY((QMetaType::registerConverter<QLine, CustomConvertibleType>(ConvertFunctor<QLine>()))); - QVERIFY((QMetaType::registerConverter<QLineF, CustomConvertibleType>(ConvertFunctor<QLineF>()))); + QVERIFY((QMetaType::registerConverter<QLineF, CustomConvertibleType>(ConvertFunctorWithOptional<QLineF>()))); QVERIFY((QMetaType::registerConverter<QChar, CustomConvertibleType>(ConvertFunctor<QChar>()))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, std::optional<CustomConvertibleType>>(OptionalWrapper<CustomConvertibleType>()))); + QVERIFY((QMetaType::registerConverter<CustomConvertibleType, CustomConvertibleType2>())); QTest::ignoreMessage(QtWarningMsg, "Type conversion already registered from type CustomConvertibleType to type CustomConvertibleType2"); QVERIFY((!QMetaType::registerConverter<CustomConvertibleType, CustomConvertibleType2>())); @@ -171,7 +198,7 @@ void tst_QMetaType::convertCustomType() QCOMPARE(v.toString(), ok ? testQString : QString()); QCOMPARE(v.value<QString>(), ok ? testQString : QString()); QVERIFY(CustomConvertibleType::s_value.canConvert<CustomConvertibleType>()); - QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toString()), testQString); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toString()), ok ? testQString : QString()); QFETCH(bool, testBool); CustomConvertibleType::s_value = testBool; @@ -183,7 +210,7 @@ void tst_QMetaType::convertCustomType() CustomConvertibleType::s_value = testInt; QCOMPARE(v.toInt(), ok ? testInt : 0); QCOMPARE(v.value<int>(), ok ? testInt : 0); - QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toInt()), testInt); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toInt()), ok ? testInt : 0); QFETCH(double, testDouble); CustomConvertibleType::s_value = testDouble; @@ -195,7 +222,7 @@ void tst_QMetaType::convertCustomType() CustomConvertibleType::s_value = testFloat; QCOMPARE(v.toFloat(), ok ? testFloat : 0.0); QCOMPARE(v.value<float>(), ok ? testFloat : 0.0); - QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toFloat()), testFloat); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toFloat()), ok ? testFloat : 0); QFETCH(QRect, testQRect); CustomConvertibleType::s_value = testQRect; @@ -207,7 +234,7 @@ void tst_QMetaType::convertCustomType() CustomConvertibleType::s_value = testQRectF; QCOMPARE(v.toRectF(), ok ? testQRectF : QRectF()); QCOMPARE(v.value<QRectF>(), ok ? testQRectF : QRectF()); - QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toRectF()), testQRectF); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toRectF()), ok ? testQRectF : QRectF()); QFETCH(QPoint, testQPoint); CustomConvertibleType::s_value = testQPoint; @@ -219,7 +246,7 @@ void tst_QMetaType::convertCustomType() CustomConvertibleType::s_value = testQPointF; QCOMPARE(v.toPointF(), ok ? testQPointF : QPointF()); QCOMPARE(v.value<QPointF>(), ok ? testQPointF : QPointF()); - QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toPointF()), testQPointF); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toPointF()), ok ? testQPointF : QPointF()); QFETCH(QSize, testQSize); CustomConvertibleType::s_value = testQSize; @@ -231,7 +258,7 @@ void tst_QMetaType::convertCustomType() CustomConvertibleType::s_value = testQSizeF; QCOMPARE(v.toSizeF(), ok ? testQSizeF : QSizeF()); QCOMPARE(v.value<QSizeF>(), ok ? testQSizeF : QSizeF()); - QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toSizeF()), testQSizeF); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toSizeF()), ok ? testQSizeF : QSizeF()); QFETCH(QLine, testQLine); CustomConvertibleType::s_value = testQLine; @@ -243,7 +270,7 @@ void tst_QMetaType::convertCustomType() CustomConvertibleType::s_value = testQLineF; QCOMPARE(v.toLineF(), ok ? testQLineF : QLineF()); QCOMPARE(v.value<QLineF>(), ok ? testQLineF : QLineF()); - QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toLineF()), testQLineF); + QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toLineF()), ok ? testQLineF : QLineF()); QFETCH(QChar, testQChar); CustomConvertibleType::s_value = testQChar; @@ -252,9 +279,21 @@ void tst_QMetaType::convertCustomType() QFETCH(CustomConvertibleType, testCustom); v = QVariant::fromValue(testCustom); - QVERIFY(v.canConvert(::qMetaTypeId<CustomConvertibleType2>())); + QVERIFY(v.canConvert(QMetaType(::qMetaTypeId<CustomConvertibleType2>()))); QCOMPARE(v.value<CustomConvertibleType2>().m_foo, testCustom.m_foo); + // Check that converters that actually convert to std::optional<T> 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<std::optional<CustomConvertibleType>>())); + QVERIFY(v.convert(QMetaType::fromType<std::optional<CustomConvertibleType>>())); + QCOMPARE(v.value<std::optional<CustomConvertibleType>>().has_value(), ok); + if (ok) { + QCOMPARE(v.value<std::optional<CustomConvertibleType>>().value().m_foo, testCustom.m_foo); + } + QFETCH(DerivedGadgetType, testDerived); v = QVariant::fromValue(testDerived); QCOMPARE(v.metaType(), QMetaType::fromType<DerivedGadgetType>()); @@ -412,6 +451,124 @@ void tst_QMetaType::operatorEq() 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<RealType>(); \ + fromType2 = QMetaType::fromType<RealType>(); \ + 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<int>("builtinTypeId"); + QTest::addColumn<QMetaType>("localType"); + QTest::addColumn<LibMetatypeFunction>("lib1Function"); + QTest::addColumn<LibMetatypeFunction>("lib2Function"); + +#define ADD_ROW(TYPE, ID) \ + QTest::addRow(QT_STRINGIFY(TYPE)) << int(ID) \ + << QMetaType::fromType<TYPE>() \ + << &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<const void *>(localIface) + << "lib1 interface:" << static_cast<const void *>(lib1Iface) + << "lib2 interface:" << static_cast<const void *>(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 { @@ -483,6 +640,83 @@ void tst_QMetaType::typeNameNormalization() } } +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<T>(); + 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; |