summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp')
-rw-r--r--tests/auto/corelib/kernel/qmetatype/tst_qmetatype2.cpp268
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;