/**************************************************************************** ** ** Copyright (C) 2021 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 "tst_qmetatype.h" #include "tst_qvariant_common.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 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(); } 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(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); QVERIFY((QMetaType::registerConverter(ConvertFunctor()))); 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::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")); 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); } 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()), testQString); 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()), testInt); 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()), testFloat); 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()), testQRectF); 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()), testQPointF); 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()), testQSizeF); 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()), testQLineF); 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(::qMetaTypeId())); QCOMPARE(v.value().m_foo, testCustom.m_foo); } 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; }; 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); } 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"); } // 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);