// Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include #include "tst_qmetatype_common.h" #include "tst_qvariant_common.h" struct Derived : QObject { Q_OBJECT }; struct MessageHandlerCustom : public MessageHandler { MessageHandlerCustom(const int typeId) : MessageHandler(typeId, handler) {} static void handler(QtMsgType, const QMessageLogContext &, const QString &msg) { QCOMPARE(msg.trimmed(), expectedMessage.trimmed()); } inline static QString expectedMessage; }; class tst_QMetaType: public QObject { Q_OBJECT Q_PROPERTY(QList prop READ prop WRITE setProp) public: struct GadgetPropertyType { QByteArray type; QByteArray name; QVariant testData; }; tst_QMetaType() { propList << 42 << "Hello"; } QList prop() const { return propList; } void setProp(const QList &list) { propList = list; } private: void registerGadget(const char * name, const QList &gadgetProperties); QList propList; private slots: void defined(); void threadSafety(); void namespaces(); void id(); void qMetaTypeId(); void properties(); void normalizedTypes(); void typeName_data(); void typeName(); void type_data(); void type(); void type_fromSubString_data(); void type_fromSubString(); void create_data(); void create(); void createCopy_data(); void createCopy(); void sizeOf_data(); void sizeOf(); void sizeOfStaticLess_data(); void sizeOfStaticLess(); void alignOf_data(); void alignOf(); void flags_data(); void flags(); void flagsStaticLess_data(); void flagsStaticLess(); void flagsBinaryCompatibility6_0_data(); void flagsBinaryCompatibility6_0(); void construct_data(); void construct(); void typedConstruct(); void constructCopy_data(); void constructCopy(); void selfCompare_data(); void selfCompare(); void typedefs(); void registerType(); void isRegistered_data(); void isRegistered(); void isRegisteredStaticLess_data(); void isRegisteredStaticLess(); void isEnum(); void automaticTemplateRegistration_1(); void automaticTemplateRegistration_2(); // defined in tst_qmetatype3.cpp void saveAndLoadBuiltin_data(); void saveAndLoadBuiltin(); void saveAndLoadCustom(); void metaObject_data(); void metaObject(); void constexprMetaTypeIds(); // tst_qmetatype2.cpp void constRefs(); void convertCustomType_data(); void convertCustomType(); void convertConstNonConst(); void compareCustomEqualOnlyType(); void customDebugStream(); void unknownType(); void fromType(); void operatorEq_data(); void operatorEq(); void typesWithInaccessibleDTors(); void voidIsNotUnknown(); void typeNameNormalization(); }; template struct Whity { T t; Whity() {} }; Q_DECLARE_METATYPE(Whity) Q_DECLARE_METATYPE(Whity) #if !defined(Q_CC_CLANG) && defined(Q_CC_GNU) && Q_CC_GNU < 501 QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(Whity, Q_RELOCATABLE_TYPE); QT_END_NAMESPACE #endif struct CustomConvertibleType { explicit CustomConvertibleType(const QVariant &foo = QVariant()) : m_foo(foo) {} virtual ~CustomConvertibleType() {} QString toString() const { return m_foo.toString(); } operator QPoint() const { return QPoint(12, 34); } template To convert() const { return s_value.value();} template To convertOk(bool *ok) const { *ok = s_ok; return s_value.value();} QVariant m_foo; inline static QVariant s_value; inline static bool s_ok = true; friend bool operator<(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs) { return lhs.m_foo.toString() < rhs.m_foo.toString(); } friend bool operator==(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs) { return lhs.m_foo == rhs.m_foo; } friend bool operator!=(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs) { return !operator==(lhs, rhs); } }; struct CustomConvertibleType2 { // implicit CustomConvertibleType2(const CustomConvertibleType &t = CustomConvertibleType()) : m_foo(t.m_foo) {} virtual ~CustomConvertibleType2() {} QVariant m_foo; friend bool operator==(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs) { return lhs.m_foo == rhs.m_foo; } friend bool operator!=(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs) { return !operator==(lhs, rhs); } }; struct CustomDebugStreamableType { QString toString() const { return "test"; } friend QDebug operator<<(QDebug dbg, const CustomDebugStreamableType&) { return dbg << "string-content"; } }; struct CustomDebugStreamableType2 { QString toString() const { return "test"; } }; struct CustomEqualsOnlyType { explicit CustomEqualsOnlyType(int value = 0) : val(value) {} virtual ~CustomEqualsOnlyType() {} int val; friend bool operator==(const CustomEqualsOnlyType &lhs, const CustomEqualsOnlyType &rhs) { return lhs.val == rhs.val;} friend bool operator!=(const CustomEqualsOnlyType &lhs, const CustomEqualsOnlyType &rhs) { return !operator==(lhs, rhs); } }; static_assert(QTypeTraits::has_operator_equal_v); static_assert(!QTypeTraits::has_operator_less_than_v); struct BaseGadgetType { Q_GADGET public: explicit BaseGadgetType(QVariant foo = QVariant()) : m_foo(std::move(foo)) {} QVariant m_foo; }; struct DerivedGadgetType : public BaseGadgetType { Q_GADGET public: explicit DerivedGadgetType(QVariant foo = QVariant()) : BaseGadgetType(std::move(foo)) {} int bar = 25; }; Q_DECLARE_METATYPE(CustomConvertibleType); Q_DECLARE_METATYPE(CustomConvertibleType2); Q_DECLARE_METATYPE(CustomDebugStreamableType); Q_DECLARE_METATYPE(CustomEqualsOnlyType); struct CustomMovable { CustomMovable() {} friend bool operator==(const CustomMovable &, const CustomMovable &) { return true; } // needed for QSet. We actually check that it makes sense. friend qsizetype qHash(const CustomMovable &, qsizetype seed = 0) { return seed; } }; #if !defined(Q_CC_CLANG) && defined(Q_CC_GNU) && Q_CC_GNU < 501 QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(CustomMovable, Q_RELOCATABLE_TYPE); QT_END_NAMESPACE #endif Q_DECLARE_METATYPE(CustomMovable); #define FOR_EACH_STATIC_PRIMITIVE_TYPE(F) \ F(bool) \ F(int) \ F(qulonglong) \ F(double) \ F(short) \ F(char) \ F(ulong) \ F(uchar) \ F(float) \ F(QObject*) \ F(QString) \ F(CustomMovable) #define FOR_EACH_STATIC_PRIMITIVE_TYPE2(F, SecondaryRealName) \ F(uint, SecondaryRealName) \ F(qlonglong, SecondaryRealName) \ F(char, SecondaryRealName) \ F(uchar, SecondaryRealName) \ F(QObject*, SecondaryRealName) #define CREATE_AND_VERIFY_CONTAINER(CONTAINER, ...) \ { \ CONTAINER< __VA_ARGS__ > t; \ const QVariant v = QVariant::fromValue(t); \ QByteArray tn = createTypeName(#CONTAINER "<", #__VA_ARGS__); \ const int expectedType = ::qMetaTypeId >(); \ const int type = QMetaType::type(tn); \ QCOMPARE(type, expectedType); \ QCOMPARE((QMetaType::fromType>().id()), expectedType); \ } #define FOR_EACH_1ARG_TEMPLATE_TYPE(F, TYPE) \ F(QList, TYPE) \ F(QQueue, TYPE) \ F(QStack, TYPE) \ F(QSet, TYPE) #define PRINT_1ARG_TEMPLATE(RealName) \ FOR_EACH_1ARG_TEMPLATE_TYPE(CREATE_AND_VERIFY_CONTAINER, RealName) #define FOR_EACH_2ARG_TEMPLATE_TYPE(F, RealName1, RealName2) \ F(QHash, RealName1, RealName2) \ F(QMap, RealName1, RealName2) \ F(std::pair, RealName1, RealName2) #define PRINT_2ARG_TEMPLATE_INTERNAL(RealName1, RealName2) \ FOR_EACH_2ARG_TEMPLATE_TYPE(CREATE_AND_VERIFY_CONTAINER, RealName1, RealName2) #define PRINT_2ARG_TEMPLATE(RealName) \ FOR_EACH_STATIC_PRIMITIVE_TYPE2(PRINT_2ARG_TEMPLATE_INTERNAL, RealName) #define REGISTER_TYPEDEF(TYPE, ARG1, ARG2) \ qRegisterMetaType>(#TYPE "<" #ARG1 "," #ARG2 ">"); static inline QByteArray createTypeName(const char *begin, const char *va) { QByteArray tn(begin); const QList args = QByteArray(va).split(','); tn += args.first().trimmed(); if (args.size() > 1) { QList::const_iterator it = args.constBegin() + 1; const QList::const_iterator end = args.constEnd(); for (; it != end; ++it) { tn += ","; tn += it->trimmed(); } } if (tn.endsWith('>')) tn += ' '; tn += '>'; return tn; } Q_DECLARE_METATYPE(const void*)