blob: 12c29a6e1350874d96e9805574b4391914c89e95 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 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 <QtCore>
#include <QtTest/QtTest>
#include <QtCore/private/qmetaobjectbuilder_p.h>
#include "tst_qmetatype.h"
#include "tst_qvariant_common.h"
#ifdef Q_OS_LINUX
# include <pthread.h>
#endif
#include <algorithm>
#include <memory>
// mingw gcc 4.8 also takes way too long, letting the CI system abort the test
#if defined(__MINGW32__)
# define TST_QMETATYPE_BROKEN_COMPILER
#endif
Q_DECLARE_METATYPE(QMetaType::Type)
class tst_QMetaType: public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QVariant> prop READ prop WRITE setProp)
public:
struct GadgetPropertyType {
QByteArray type;
QByteArray name;
QVariant testData;
};
tst_QMetaType() { propList << 42 << "Hello"; }
QList<QVariant> prop() const { return propList; }
void setProp(const QList<QVariant> &list) { propList = list; }
private:
void registerGadget(const char * name, const QVector<GadgetPropertyType> &gadgetProperties);
QList<QVariant> 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 flags_data();
void flags();
void flagsStaticLess_data();
void flagsStaticLess();
void flagsBinaryCompatibility5_0_data();
void flagsBinaryCompatibility5_0();
void construct_data();
void construct();
void typedConstruct();
void constructCopy_data();
void constructCopy();
void typedefs();
void registerType();
void isRegistered_data();
void isRegistered();
void isRegisteredStaticLess_data();
void isRegisteredStaticLess();
void isEnum();
void registerStreamBuiltin();
void automaticTemplateRegistration();
void saveAndLoadBuiltin_data();
void saveAndLoadBuiltin();
void saveAndLoadCustom();
void metaObject_data();
void metaObject();
void constexprMetaTypeIds();
void constRefs();
void convertCustomType_data();
void convertCustomType();
void compareCustomType_data();
void compareCustomType();
void compareCustomEqualOnlyType();
void customDebugStream();
void unknownType();
};
struct BaseGenericType
{
int m_typeId = -1;
virtual void *constructor(int typeId, void *where, const void *copy) = 0;
virtual void staticMetacallFunction(QMetaObject::Call _c, int _id, void **_a) = 0;
virtual void saveOperator(QDataStream & out) const = 0;
virtual void loadOperator(QDataStream &in) = 0;
virtual ~BaseGenericType() {}
};
struct GenericGadgetType : BaseGenericType
{
void *constructor(int typeId, void *where, const void *copy) override
{
GenericGadgetType *ret = where ? new(where) GenericGadgetType : new GenericGadgetType;
ret->m_typeId = typeId;
if (copy) {
Q_ASSERT(ret->m_typeId == reinterpret_cast<const GenericGadgetType*>(copy)->m_typeId);
*ret = *reinterpret_cast<const GenericGadgetType*>(copy);
} else {
ret->properties = properties;
}
return ret;
}
void staticMetacallFunction(QMetaObject::Call _c, int _id, void **_a) override
{
if (_c == QMetaObject::ReadProperty) {
if (_id < properties.size()) {
const auto &prop = properties.at(_id);
QMetaType::destruct(int(prop.userType()), _a[0]);
QMetaType::construct(int(prop.userType()), _a[0], prop.constData());
}
} else if (_c == QMetaObject::WriteProperty) {
if (_id < properties.size()) {
auto & prop = properties[_id];
prop = QVariant(prop.userType(), _a[0]);
}
}
}
void saveOperator(QDataStream & out) const override
{
for (const auto &prop : properties)
out << prop;
}
void loadOperator(QDataStream &in) override
{
for (auto &prop : properties)
in >> prop;
}
QVector<QVariant> properties;
};
struct GenericPODType : BaseGenericType
{
// BaseGenericType interface
void *constructor(int typeId, void *where, const void *copy) override
{
GenericPODType *ret = where ? new(where) GenericPODType : new GenericPODType;
ret->m_typeId = typeId;
if (copy) {
Q_ASSERT(ret->m_typeId == reinterpret_cast<const GenericPODType*>(copy)->m_typeId);
*ret = *reinterpret_cast<const GenericPODType*>(copy);
} else {
ret->podData = podData;
}
return ret;
}
void staticMetacallFunction(QMetaObject::Call _c, int _id, void **_a) override
{
Q_UNUSED(_c);
Q_UNUSED(_id);
Q_UNUSED(_a);
Q_ASSERT(false);
}
void saveOperator(QDataStream &out) const override
{
out << podData;
}
void loadOperator(QDataStream &in) override
{
in >> podData;
}
QByteArray podData;
};
using RegisteredType = QPair<std::shared_ptr<BaseGenericType>, std::shared_ptr<QMetaObject>>;
static QHash<int, RegisteredType> s_managedTypes;
static void GadgetsStaticMetacallFunction(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
reinterpret_cast<BaseGenericType*>(_o)->staticMetacallFunction(_c, _id, _a);
}
static void GadgetTypedDestructor(int typeId, void *ptr)
{
QCOMPARE(typeId, reinterpret_cast<BaseGenericType*>(ptr)->m_typeId);
reinterpret_cast<BaseGenericType*>(ptr)->~BaseGenericType();
}
static void *GadgetTypedConstructor(int type, void *where, const void *copy)
{
auto it = s_managedTypes.find(type);
if (it == s_managedTypes.end())
return nullptr; // crash the test
return it->first->constructor(type, where, copy);
}
static void GadgetSaveOperator(QDataStream & out, const void *data)
{
reinterpret_cast<const BaseGenericType *>(data)->saveOperator(out);
}
static void GadgetLoadOperator(QDataStream &in, void *data)
{
reinterpret_cast<BaseGenericType *>(data)->loadOperator(in);
}
struct Foo { int i; };
class CustomQObject : public QObject
{
Q_OBJECT
public:
CustomQObject(QObject *parent = 0)
: QObject(parent)
{
}
enum CustomQEnum { Val1, Val2 };
Q_ENUM(CustomQEnum)
};
class CustomGadget {
Q_GADGET
};
class CustomGadget_NonDefaultConstructible {
Q_GADGET
public:
CustomGadget_NonDefaultConstructible(int) {};
};
class CustomNonQObject {};
class GadgetDerived : public CustomGadget {};
// cannot use Q_GADGET due to moc limitations but wants to behave like
// a Q_GADGET in Qml land
template<typename T>
class GadgetDerivedAndTyped : public CustomGadget {};
Q_DECLARE_METATYPE(GadgetDerivedAndTyped<int>)
Q_DECLARE_METATYPE(GadgetDerivedAndTyped<int>*)
void tst_QMetaType::registerGadget(const char *name, const QVector<GadgetPropertyType> &gadgetProperties)
{
QMetaObjectBuilder gadgetBuilder;
gadgetBuilder.setClassName(name);
QMetaObjectBuilder::MetaObjectFlags metaObjectflags = QMetaObjectBuilder::DynamicMetaObject | QMetaObjectBuilder::PropertyAccessInStaticMetaCall;
gadgetBuilder.setFlags(metaObjectflags);
auto dynamicGadgetProperties = std::make_shared<GenericGadgetType>();
for (const auto &prop : gadgetProperties) {
int propertyType = QMetaType::type(prop.type);
dynamicGadgetProperties->properties.push_back(QVariant(QVariant::Type(propertyType)));
auto dynamicPropery = gadgetBuilder.addProperty(prop.name, prop.type);
dynamicPropery.setWritable(true);
dynamicPropery.setReadable(true);
}
auto meta = gadgetBuilder.toMetaObject();
meta->d.static_metacall = &GadgetsStaticMetacallFunction;
meta->d.superdata = nullptr;
const auto flags = QMetaType::WasDeclaredAsMetaType | QMetaType::IsGadget | QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
int gadgetTypeId = QMetaType::registerType(name,
&GadgetTypedDestructor,
&GadgetTypedConstructor,
sizeof(GenericGadgetType),
flags, meta);
QVERIFY(gadgetTypeId > 0);
QMetaType::registerStreamOperators(gadgetTypeId, &GadgetSaveOperator, &GadgetLoadOperator);
s_managedTypes[gadgetTypeId] = qMakePair(dynamicGadgetProperties, std::shared_ptr<QMetaObject>{meta, [](QMetaObject *ptr){ ::free(ptr); }});
}
void tst_QMetaType::defined()
{
QCOMPARE(int(QMetaTypeId2<QString>::Defined), 1);
QCOMPARE(int(QMetaTypeId2<Foo>::Defined), 0);
QCOMPARE(int(QMetaTypeId2<void*>::Defined), 1);
QCOMPARE(int(QMetaTypeId2<int*>::Defined), 0);
QCOMPARE(int(QMetaTypeId2<CustomQObject::CustomQEnum>::Defined), 1);
QCOMPARE(int(QMetaTypeId2<CustomGadget>::Defined), 1);
QCOMPARE(int(QMetaTypeId2<CustomGadget*>::Defined), 1);
QVERIFY(!QMetaTypeId2<GadgetDerived>::Defined);
QVERIFY(!QMetaTypeId2<GadgetDerived*>::Defined);
QVERIFY(int(QMetaTypeId2<CustomQObject*>::Defined));
QVERIFY(!QMetaTypeId2<CustomQObject>::Defined);
QVERIFY(!QMetaTypeId2<CustomNonQObject>::Defined);
QVERIFY(!QMetaTypeId2<CustomNonQObject*>::Defined);
QVERIFY(!QMetaTypeId2<CustomGadget_NonDefaultConstructible>::Defined);
// registered with Q_DECLARE_METATYPE
QVERIFY(QMetaTypeId2<GadgetDerivedAndTyped<int>>::Defined);
QVERIFY(QMetaTypeId2<GadgetDerivedAndTyped<int>*>::Defined);
}
struct Bar
{
Bar()
{
// check re-entrancy
if (!QMetaType::isRegistered(qRegisterMetaType<Foo>("Foo"))) {
qWarning("%s: re-entrancy test failed", Q_FUNC_INFO);
++failureCount;
}
}
~Bar() {}
public:
static int failureCount;
};
int Bar::failureCount = 0;
class MetaTypeTorturer: public QThread
{
Q_OBJECT
protected:
void run()
{
Bar space[1];
space[0].~Bar();
const QByteArray postFix = '_'
+ QByteArray::number(reinterpret_cast<quintptr>(QThread::currentThreadId()));
for (int i = 0; i < 1000; ++i) {
const QByteArray name = "Bar" + QByteArray::number(i) + postFix;
const char *nm = name.constData();
int tp = qRegisterMetaType<Bar>(nm);
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
pthread_yield();
#endif
QMetaType info(tp);
if (!info.isValid()) {
++failureCount;
qWarning() << "Wrong typeInfo returned for" << tp;
}
if (!info.isRegistered()) {
++failureCount;
qWarning() << name << "is not a registered metatype";
}
if (QMetaType::typeFlags(tp) != (QMetaType::NeedsConstruction | QMetaType::NeedsDestruction)) {
++failureCount;
qWarning() << "Wrong typeInfo returned for" << tp;
}
if (!QMetaType::isRegistered(tp)) {
++failureCount;
qWarning() << name << "is not a registered metatype";
}
if (QMetaType::type(nm) != tp) {
++failureCount;
qWarning() << "Wrong metatype returned for" << name;
}
if (QMetaType::typeName(tp) != name) {
++failureCount;
qWarning() << "Wrong typeName returned for" << tp;
}
void *buf1 = QMetaType::create(tp, 0);
void *buf2 = QMetaType::create(tp, buf1);
void *buf3 = info.create(tp, 0);
void *buf4 = info.create(tp, buf1);
QMetaType::construct(tp, space, 0);
QMetaType::destruct(tp, space);
QMetaType::construct(tp, space, buf1);
QMetaType::destruct(tp, space);
info.construct(space, 0);
info.destruct(space);
info.construct(space, buf1);
info.destruct(space);
if (!buf1) {
++failureCount;
qWarning() << "Null buffer returned by QMetaType::create(tp, 0)";
}
if (!buf2) {
++failureCount;
qWarning() << "Null buffer returned by QMetaType::create(tp, buf)";
}
if (!buf3) {
++failureCount;
qWarning() << "Null buffer returned by info.create(tp, 0)";
}
if (!buf4) {
++failureCount;
qWarning() << "Null buffer returned by infocreate(tp, buf)";
}
QMetaType::destroy(tp, buf1);
QMetaType::destroy(tp, buf2);
info.destroy(buf3);
info.destroy(buf4);
}
new (space) Bar;
}
public:
MetaTypeTorturer() : failureCount(0) { }
int failureCount;
};
void tst_QMetaType::threadSafety()
{
MetaTypeTorturer t1;
MetaTypeTorturer t2;
MetaTypeTorturer t3;
t1.start();
t2.start();
t3.start();
QVERIFY(t1.wait());
QVERIFY(t2.wait());
QVERIFY(t3.wait());
QCOMPARE(t1.failureCount, 0);
QCOMPARE(t2.failureCount, 0);
QCOMPARE(t3.failureCount, 0);
QCOMPARE(Bar::failureCount, 0);
}
namespace TestSpace
{
struct Foo { double d; public: ~Foo() {} };
struct QungTfu {};
}
Q_DECLARE_METATYPE(TestSpace::Foo)
#define ADD_TESTSPACE(F) TestSpace::F
Q_DECLARE_METATYPE(ADD_TESTSPACE(QungTfu))
void tst_QMetaType::namespaces()
{
TestSpace::Foo nf = { 11.12 };
QVariant v = QVariant::fromValue(nf);
QCOMPARE(qvariant_cast<TestSpace::Foo>(v).d, 11.12);
int qungTfuId = qRegisterMetaType<ADD_TESTSPACE(QungTfu)>();
QCOMPARE(QMetaType::typeName(qungTfuId), "TestSpace::QungTfu");
}
void tst_QMetaType::id()
{
QCOMPARE(QMetaType(QMetaType::QString).id(), QMetaType::QString);
QCOMPARE(QMetaType(::qMetaTypeId<TestSpace::Foo>()).id(), ::qMetaTypeId<TestSpace::Foo>());
}
void tst_QMetaType::qMetaTypeId()
{
QCOMPARE(::qMetaTypeId<QString>(), int(QMetaType::QString));
QCOMPARE(::qMetaTypeId<int>(), int(QMetaType::Int));
QCOMPARE(::qMetaTypeId<TestSpace::Foo>(), QMetaType::type("TestSpace::Foo"));
QCOMPARE(::qMetaTypeId<char>(), QMetaType::type("char"));
QCOMPARE(::qMetaTypeId<uchar>(), QMetaType::type("unsigned char"));
QCOMPARE(::qMetaTypeId<signed char>(), QMetaType::type("signed char"));
QVERIFY(::qMetaTypeId<signed char>() != ::qMetaTypeId<char>());
QCOMPARE(::qMetaTypeId<qint8>(), QMetaType::type("qint8"));
}
void tst_QMetaType::properties()
{
qRegisterMetaType<QList<QVariant> >("QList<QVariant>");
QVariant v = property("prop");
QCOMPARE(v.typeName(), "QVariantList");
QList<QVariant> values = v.toList();
QCOMPARE(values.count(), 2);
QCOMPARE(values.at(0).toInt(), 42);
values << 43 << "world";
QVERIFY(setProperty("prop", values));
v = property("prop");
QCOMPARE(v.toList().count(), 4);
}
template <typename T>
struct Whity { T t; Whity() {} };
Q_DECLARE_METATYPE( Whity < int > )
Q_DECLARE_METATYPE(Whity<double>)
#if !defined(Q_CC_CLANG) && defined(Q_CC_GNU) && Q_CC_GNU < 501
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(Whity<double>, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif
void tst_QMetaType::normalizedTypes()
{
int WhityIntId = ::qMetaTypeId<Whity<int> >();
int WhityDoubleId = ::qMetaTypeId<Whity<double> >();
QCOMPARE(QMetaType::type("Whity<int>"), WhityIntId);
QCOMPARE(QMetaType::type(" Whity < int > "), WhityIntId);
QCOMPARE(QMetaType::type("Whity<int >"), WhityIntId);
QCOMPARE(QMetaType::type("Whity<double>"), WhityDoubleId);
QCOMPARE(QMetaType::type(" Whity< double > "), WhityDoubleId);
QCOMPARE(QMetaType::type("Whity<double >"), WhityDoubleId);
QCOMPARE(qRegisterMetaType<Whity<int> >(" Whity < int > "), WhityIntId);
QCOMPARE(qRegisterMetaType<Whity<int> >("Whity<int>"), WhityIntId);
QCOMPARE(qRegisterMetaType<Whity<int> >("Whity<int > "), WhityIntId);
QCOMPARE(qRegisterMetaType<Whity<double> >(" Whity < double > "), WhityDoubleId);
QCOMPARE(qRegisterMetaType<Whity<double> >("Whity<double>"), WhityDoubleId);
QCOMPARE(qRegisterMetaType<Whity<double> >("Whity<double > "), WhityDoubleId);
}
#define TYPENAME_DATA(MetaTypeName, MetaTypeId, RealType)\
QTest::newRow(#RealType) << int(QMetaType::MetaTypeName) << #RealType;
void tst_QMetaType::typeName_data()
{
QTest::addColumn<int>("aType");
QTest::addColumn<QString>("aTypeName");
QT_FOR_EACH_STATIC_TYPE(TYPENAME_DATA)
QTest::newRow("QMetaType::UnknownType") << int(QMetaType::UnknownType) << static_cast<const char*>(0);
QTest::newRow("QMetaType::User-1") << (int(QMetaType::User) - 1) << static_cast<const char *>(nullptr);
QTest::newRow("QMetaType::FirstWidgetsType-1") << (int(QMetaType::FirstWidgetsType) - 1) << static_cast<const char *>(nullptr);
QTest::newRow("Whity<double>") << ::qMetaTypeId<Whity<double> >() << QString::fromLatin1("Whity<double>");
QTest::newRow("Whity<int>") << ::qMetaTypeId<Whity<int> >() << QString::fromLatin1("Whity<int>");
QTest::newRow("Testspace::Foo") << ::qMetaTypeId<TestSpace::Foo>() << QString::fromLatin1("TestSpace::Foo");
QTest::newRow("-1") << -1 << QString();
QTest::newRow("-124125534") << -124125534 << QString();
QTest::newRow("124125534") << 124125534 << QString();
// automatic registration
QTest::newRow("QList<int>") << ::qMetaTypeId<QList<int> >() << QString::fromLatin1("QList<int>");
QTest::newRow("QHash<int,int>") << ::qMetaTypeId<QHash<int, int> >() << QString::fromLatin1("QHash<int,int>");
QTest::newRow("QMap<int,int>") << ::qMetaTypeId<QMap<int, int> >() << QString::fromLatin1("QMap<int,int>");
QTest::newRow("QVector<QList<int>>") << ::qMetaTypeId<QVector<QList<int> > >() << QString::fromLatin1("QVector<QList<int> >");
QTest::newRow("QVector<QMap<int,int>>") << ::qMetaTypeId<QVector<QMap<int, int> > >() << QString::fromLatin1("QVector<QMap<int,int> >");
QTest::newRow("CustomQObject*") << ::qMetaTypeId<CustomQObject*>() << QString::fromLatin1("CustomQObject*");
QTest::newRow("CustomGadget") << ::qMetaTypeId<CustomGadget>() << QString::fromLatin1("CustomGadget");
QTest::newRow("CustomGadget*") << ::qMetaTypeId<CustomGadget*>() << QString::fromLatin1("CustomGadget*");
QTest::newRow("CustomQObject::CustomQEnum") << ::qMetaTypeId<CustomQObject::CustomQEnum>() << QString::fromLatin1("CustomQObject::CustomQEnum");
QTest::newRow("Qt::ArrowType") << ::qMetaTypeId<Qt::ArrowType>() << QString::fromLatin1("Qt::ArrowType");
// template instance class derived from Q_GADGET enabled class
QTest::newRow("GadgetDerivedAndTyped<int>") << ::qMetaTypeId<GadgetDerivedAndTyped<int>>() << QString::fromLatin1("GadgetDerivedAndTyped<int>");
QTest::newRow("GadgetDerivedAndTyped<int>*") << ::qMetaTypeId<GadgetDerivedAndTyped<int>*>() << QString::fromLatin1("GadgetDerivedAndTyped<int>*");
}
void tst_QMetaType::typeName()
{
QFETCH(int, aType);
QFETCH(QString, aTypeName);
const char *rawname = QMetaType::typeName(aType);
QString name = QString::fromLatin1(rawname);
QCOMPARE(name, aTypeName);
QCOMPARE(name.toLatin1(), QMetaObject::normalizedType(name.toLatin1().constData()));
QCOMPARE(rawname == nullptr, aTypeName.isNull());
}
void tst_QMetaType::type_data()
{
QTest::addColumn<int>("aType");
QTest::addColumn<QByteArray>("aTypeName");
#define TST_QMETATYPE_TYPE_DATA(MetaTypeName, MetaTypeId, RealType)\
QTest::newRow(#RealType) << int(QMetaType::MetaTypeName) << QByteArray( #RealType );
#define TST_QMETATYPE_TYPE_DATA_ALIAS(MetaTypeName, MetaTypeId, AliasType, RealTypeString)\
QTest::newRow(RealTypeString) << int(QMetaType::MetaTypeName) << QByteArray( #AliasType );
QTest::newRow("empty") << int(QMetaType::UnknownType) << QByteArray();
QT_FOR_EACH_STATIC_TYPE(TST_QMETATYPE_TYPE_DATA)
QT_FOR_EACH_STATIC_ALIAS_TYPE(TST_QMETATYPE_TYPE_DATA_ALIAS)
#undef TST_QMETATYPE_TYPE_DATA
#undef TST_METATYPE_TYPE_DATA_ALIAS
}
void tst_QMetaType::type()
{
QFETCH(int, aType);
QFETCH(QByteArray, aTypeName);
// QMetaType::type(QByteArray)
QCOMPARE(QMetaType::type(aTypeName), aType);
// QMetaType::type(const char *)
QCOMPARE(QMetaType::type(aTypeName.constData()), aType);
}
void tst_QMetaType::type_fromSubString_data()
{
QTest::addColumn<int>("offset");
QTest::addColumn<int>("size");
QTest::addColumn<int>("expectedType");
// The test string is defined in the test function below
QTest::newRow("int") << 0 << 3 << int(QMetaType::Int);
QTest::newRow("boo") << 3 << 3 << 0;
QTest::newRow("bool") << 3 << 4 << int(QMetaType::Bool);
QTest::newRow("intbool") << 0 << 7 << 0;
QTest::newRow("QMetaType::Type") << 7 << 15 << ::qMetaTypeId<QMetaType::Type>();
QTest::newRow("double") << 22 << 6 << int(QMetaType::Double);
}
void tst_QMetaType::type_fromSubString()
{
static const char *types = "intboolQMetaType::Typedoublexxx";
QFETCH(int, offset);
QFETCH(int, size);
QFETCH(int, expectedType);
QByteArray ba = QByteArray::fromRawData(types + offset, size);
QCOMPARE(QMetaType::type(ba), expectedType);
}
namespace {
template <typename T>
struct static_assert_trigger {
Q_STATIC_ASSERT(( QMetaTypeId2<T>::IsBuiltIn ));
enum { value = true };
};
}
#define CHECK_BUILTIN(MetaTypeName, MetaTypeId, RealType) static_assert_trigger< RealType >::value &&
Q_STATIC_ASSERT(( FOR_EACH_CORE_METATYPE(CHECK_BUILTIN) true ));
#undef CHECK_BUILTIN
Q_STATIC_ASSERT(( QMetaTypeId2<QList<QVariant> >::IsBuiltIn));
Q_STATIC_ASSERT(( QMetaTypeId2<QMap<QString,QVariant> >::IsBuiltIn));
Q_STATIC_ASSERT(( QMetaTypeId2<QObject*>::IsBuiltIn));
Q_STATIC_ASSERT((!QMetaTypeId2<tst_QMetaType*>::IsBuiltIn)); // QObject subclass
Q_STATIC_ASSERT((!QMetaTypeId2<QList<int> >::IsBuiltIn));
Q_STATIC_ASSERT((!QMetaTypeId2<QMap<int,int> >::IsBuiltIn));
Q_STATIC_ASSERT((!QMetaTypeId2<QMetaType::Type>::IsBuiltIn));
void tst_QMetaType::create_data()
{
QTest::addColumn<int>("type");
#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
QTest::newRow(QMetaType::typeName(QMetaType::MetaTypeName)) << int(QMetaType::MetaTypeName);
FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW)
#undef ADD_METATYPE_TEST_ROW
}
template<int ID>
static void testCreateHelper()
{
typedef typename MetaEnumToType<ID>::Type Type;
QMetaType info(ID);
void *actual1 = QMetaType::create(ID);
void *actual2 = info.create();
if (DefaultValueTraits<ID>::IsInitialized) {
Type *expected = DefaultValueFactory<ID>::create();
QCOMPARE(*static_cast<Type *>(actual1), *expected);
QCOMPARE(*static_cast<Type *>(actual2), *expected);
delete expected;
}
QMetaType::destroy(ID, actual1);
info.destroy(actual2);
}
template<>
void testCreateHelper<QMetaType::Void>()
{
void *actual = QMetaType::create(QMetaType::Void);
if (DefaultValueTraits<QMetaType::Void>::IsInitialized) {
QVERIFY(DefaultValueFactory<QMetaType::Void>::create());
}
QMetaType::destroy(QMetaType::Void, actual);
}
typedef void (*TypeTestFunction)();
void tst_QMetaType::create()
{
struct TypeTestFunctionGetter
{
static TypeTestFunction get(int type)
{
switch (type) {
#define RETURN_CREATE_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
case QMetaType::MetaTypeName: \
return testCreateHelper<QMetaType::MetaTypeName>;
FOR_EACH_CORE_METATYPE(RETURN_CREATE_FUNCTION)
#undef RETURN_CREATE_FUNCTION
}
return 0;
}
};
QFETCH(int, type);
TypeTestFunctionGetter::get(type)();
}
template<int ID>
static void testCreateCopyHelper()
{
typedef typename MetaEnumToType<ID>::Type Type;
Type *expected = TestValueFactory<ID>::create();
QMetaType info(ID);
void *actual1 = QMetaType::create(ID, expected);
void *actual2 = info.create(expected);
QCOMPARE(*static_cast<Type *>(actual1), *expected);
QCOMPARE(*static_cast<Type *>(actual2), *expected);
QMetaType::destroy(ID, actual1);
info.destroy(actual2);
delete expected;
}
template<>
void testCreateCopyHelper<QMetaType::Void>()
{
typedef MetaEnumToType<QMetaType::Void>::Type Type;
Type *expected = TestValueFactory<QMetaType::Void>::create();
void *actual = QMetaType::create(QMetaType::Void, expected);
QCOMPARE(static_cast<Type *>(actual), expected);
QMetaType::destroy(QMetaType::Void, actual);
}
void tst_QMetaType::createCopy_data()
{
create_data();
}
void tst_QMetaType::createCopy()
{
struct TypeTestFunctionGetter
{
static TypeTestFunction get(int type)
{
switch (type) {
#define RETURN_CREATE_COPY_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
case QMetaType::MetaTypeName: \
return testCreateCopyHelper<QMetaType::MetaTypeName>;
FOR_EACH_CORE_METATYPE(RETURN_CREATE_COPY_FUNCTION)
#undef RETURN_CREATE_COPY_FUNCTION
}
return 0;
}
};
QFETCH(int, type);
TypeTestFunctionGetter::get(type)();
}
void tst_QMetaType::sizeOf_data()
{
QTest::addColumn<int>("type");
QTest::addColumn<size_t>("size");
QTest::newRow("QMetaType::UnknownType") << int(QMetaType::UnknownType) << size_t(0);
#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
QTest::newRow(#RealType) << int(QMetaType::MetaTypeName) << size_t(QTypeInfo<RealType>::sizeOf);
FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW)
#undef ADD_METATYPE_TEST_ROW
QTest::newRow("Whity<double>") << ::qMetaTypeId<Whity<double> >() << sizeof(Whity<double>);
QTest::newRow("Whity<int>") << ::qMetaTypeId<Whity<int> >() << sizeof(Whity<int>);
QTest::newRow("Testspace::Foo") << ::qMetaTypeId<TestSpace::Foo>() << sizeof(TestSpace::Foo);
QTest::newRow("-1") << -1 << size_t(0);
QTest::newRow("-124125534") << -124125534 << size_t(0);
QTest::newRow("124125534") << 124125534 << size_t(0);
}
void tst_QMetaType::sizeOf()
{
QFETCH(int, type);
QFETCH(size_t, size);
QCOMPARE(size_t(QMetaType::sizeOf(type)), size);
}
void tst_QMetaType::sizeOfStaticLess_data()
{
sizeOf_data();
}
void tst_QMetaType::sizeOfStaticLess()
{
QFETCH(int, type);
QFETCH(size_t, size);
QCOMPARE(size_t(QMetaType(type).sizeOf()), size);
}
struct CustomMovable { CustomMovable() {} };
#if !defined(Q_CC_CLANG) && defined(Q_CC_GNU) && Q_CC_GNU < 501
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(CustomMovable, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif
Q_DECLARE_METATYPE(CustomMovable);
class CustomObject : public QObject
{
Q_OBJECT
public:
CustomObject(QObject *parent = 0)
: QObject(parent)
{
}
};
Q_DECLARE_METATYPE(CustomObject*);
struct SecondBase {};
class CustomMultiInheritanceObject : public QObject, SecondBase
{
Q_OBJECT
public:
CustomMultiInheritanceObject(QObject *parent = 0)
: QObject(parent)
{
}
};
Q_DECLARE_METATYPE(CustomMultiInheritanceObject*);
class C { char _[4]; public: C() = default; C(const C&) {} };
class M { char _[4]; public: M() {} };
class P { char _[4]; };
QT_BEGIN_NAMESPACE
#if defined(Q_CC_GNU) && Q_CC_GNU < 501
Q_DECLARE_TYPEINFO(M, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(P, Q_PRIMITIVE_TYPE);
#endif
QT_END_NAMESPACE
// avoid the comma:
typedef QPair<C,C> QPairCC;
typedef QPair<C,M> QPairCM;
typedef QPair<C,P> QPairCP;
typedef QPair<M,C> QPairMC;
typedef QPair<M,M> QPairMM;
typedef QPair<M,P> QPairMP;
typedef QPair<P,C> QPairPC;
typedef QPair<P,M> QPairPM;
typedef QPair<P,P> QPairPP;
Q_DECLARE_METATYPE(QPairCC)
Q_DECLARE_METATYPE(QPairCM)
Q_DECLARE_METATYPE(QPairCP)
Q_DECLARE_METATYPE(QPairMC)
Q_DECLARE_METATYPE(QPairMM)
Q_DECLARE_METATYPE(QPairMP)
Q_DECLARE_METATYPE(QPairPC)
Q_DECLARE_METATYPE(QPairPM)
Q_DECLARE_METATYPE(QPairPP)
enum FlagsDataEnum {};
Q_DECLARE_METATYPE(FlagsDataEnum);
void tst_QMetaType::flags_data()
{
QTest::addColumn<int>("type");
QTest::addColumn<bool>("isMovable");
QTest::addColumn<bool>("isComplex");
QTest::addColumn<bool>("isPointerToQObject");
QTest::addColumn<bool>("isEnum");
#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
QTest::newRow(#RealType) << MetaTypeId \
<< bool(QTypeInfoQuery<RealType>::isRelocatable) \
<< bool(QTypeInfoQuery<RealType>::isComplex) \
<< bool(QtPrivate::IsPointerToTypeDerivedFromQObject<RealType>::Value) \
<< bool(std::is_enum<RealType>::value);
QT_FOR_EACH_STATIC_CORE_CLASS(ADD_METATYPE_TEST_ROW)
QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(ADD_METATYPE_TEST_ROW)
QT_FOR_EACH_STATIC_CORE_POINTER(ADD_METATYPE_TEST_ROW)
#undef ADD_METATYPE_TEST_ROW
QTest::newRow("TestSpace::Foo") << ::qMetaTypeId<TestSpace::Foo>() << false << true << false << false;
QTest::newRow("Whity<double>") << ::qMetaTypeId<Whity<double> >() << true << true << false << false;
QTest::newRow("CustomMovable") << ::qMetaTypeId<CustomMovable>() << true << true << false << false;
QTest::newRow("CustomObject*") << ::qMetaTypeId<CustomObject*>() << true << false << true << false;
QTest::newRow("CustomMultiInheritanceObject*") << ::qMetaTypeId<CustomMultiInheritanceObject*>() << true << false << true << false;
QTest::newRow("QPair<C,C>") << ::qMetaTypeId<QPair<C,C> >() << false << true << false << false;
QTest::newRow("QPair<C,M>") << ::qMetaTypeId<QPair<C,M> >() << false << true << false << false;
QTest::newRow("QPair<C,P>") << ::qMetaTypeId<QPair<C,P> >() << false << true << false << false;
QTest::newRow("QPair<M,C>") << ::qMetaTypeId<QPair<M,C> >() << false << true << false << false;
QTest::newRow("QPair<M,M>") << ::qMetaTypeId<QPair<M,M> >() << true << true << false << false;
QTest::newRow("QPair<M,P>") << ::qMetaTypeId<QPair<M,P> >() << true << true << false << false;
QTest::newRow("QPair<P,C>") << ::qMetaTypeId<QPair<P,C> >() << false << true << false << false;
QTest::newRow("QPair<P,M>") << ::qMetaTypeId<QPair<P,M> >() << true << true << false << false;
QTest::newRow("QPair<P,P>") << ::qMetaTypeId<QPair<P,P> >() << true << false << false << false;
QTest::newRow("FlagsDataEnum") << ::qMetaTypeId<FlagsDataEnum>() << true << false << false << true;
// invalid ids.
QTest::newRow("-1") << -1 << false << false << false << false;
QTest::newRow("-124125534") << -124125534 << false << false << false << false;
QTest::newRow("124125534") << 124125534 << false << false << false << false;
}
void tst_QMetaType::flags()
{
QFETCH(int, type);
QFETCH(bool, isMovable);
QFETCH(bool, isComplex);
QFETCH(bool, isPointerToQObject);
QFETCH(bool, isEnum);
QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsConstruction), isComplex);
QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsDestruction), isComplex);
QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::MovableType), isMovable);
QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::PointerToQObject), isPointerToQObject);
QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::IsEnumeration), isEnum);
}
void tst_QMetaType::flagsStaticLess_data()
{
flags_data();
}
void tst_QMetaType::flagsStaticLess()
{
QFETCH(int, type);
QFETCH(bool, isMovable);
QFETCH(bool, isComplex);
int flags = QMetaType(type).flags();
QCOMPARE(bool(flags & QMetaType::NeedsConstruction), isComplex);
QCOMPARE(bool(flags & QMetaType::NeedsDestruction), isComplex);
QCOMPARE(bool(flags & QMetaType::MovableType), isMovable);
}
void tst_QMetaType::flagsBinaryCompatibility5_0_data()
{
// Changing traits of a built-in type is illegal from BC point of view.
// Traits are saved in code of an application and in the Qt library which means
// that there may be a mismatch.
// The test is loading data generated by this code:
//
// QByteArray buffer;
// buffer.reserve(2 * QMetaType::User);
// for (quint32 i = 0; i < QMetaType::User; ++i) {
// if (QMetaType::isRegistered(i)) {
// buffer.append(i);
// buffer.append(quint32(QMetaType::typeFlags(i)));
// }
// }
// QFile file("/tmp/typeFlags.bin");
// file.open(QIODevice::WriteOnly);
// file.write(buffer);
// file.close();
QTest::addColumn<quint32>("id");
QTest::addColumn<quint32>("flags");
QFile file(QFINDTESTDATA("typeFlags.bin"));
file.open(QIODevice::ReadOnly);
QByteArray buffer = file.readAll();
for (int i = 0; i < buffer.size(); i+=2) {
const quint32 id = buffer.at(i);
const quint32 flags = buffer.at(i + 1);
QVERIFY2(QMetaType::isRegistered(id), "A type could not be removed in BC way");
QTest::newRow(QMetaType::typeName(id)) << id << flags;
}
}
void tst_QMetaType::flagsBinaryCompatibility5_0()
{
QFETCH(quint32, id);
QFETCH(quint32, flags);
quint32 mask_5_0 = 0x1fb; // Only compare the values that were already defined in 5.0
QCOMPARE(quint32(QMetaType::typeFlags(id)) & mask_5_0, flags & mask_5_0);
}
void tst_QMetaType::construct_data()
{
create_data();
}
template<int ID>
static void testConstructHelper()
{
typedef typename MetaEnumToType<ID>::Type Type;
QMetaType info(ID);
int size = info.sizeOf();
void *storage1 = qMallocAligned(size, Q_ALIGNOF(Type));
void *actual1 = QMetaType::construct(ID, storage1, /*copy=*/0);
void *storage2 = qMallocAligned(size, Q_ALIGNOF(Type));
void *actual2 = info.construct(storage2, /*copy=*/0);
QCOMPARE(actual1, storage1);
QCOMPARE(actual2, storage2);
if (DefaultValueTraits<ID>::IsInitialized) {
Type *expected = DefaultValueFactory<ID>::create();
QCOMPARE(*static_cast<Type *>(actual1), *expected);
QCOMPARE(*static_cast<Type *>(actual2), *expected);
delete expected;
}
QMetaType::destruct(ID, actual1);
qFreeAligned(storage1);
info.destruct(actual2);
qFreeAligned(storage2);
QVERIFY(QMetaType::construct(ID, 0, /*copy=*/0) == 0);
QMetaType::destruct(ID, 0);
QVERIFY(info.construct(0, /*copy=*/0) == 0);
info.destruct(0);
}
template<>
void testConstructHelper<QMetaType::Void>()
{
/*int size = */ QMetaType::sizeOf(QMetaType::Void);
void *storage = 0;
void *actual = QMetaType::construct(QMetaType::Void, storage, /*copy=*/0);
QCOMPARE(actual, storage);
if (DefaultValueTraits<QMetaType::Void>::IsInitialized) {
QVERIFY(DefaultValueFactory<QMetaType::Void>::create());
}
QMetaType::destruct(QMetaType::Void, actual);
qFreeAligned(storage);
QVERIFY(QMetaType::construct(QMetaType::Void, 0, /*copy=*/0) == 0);
QMetaType::destruct(QMetaType::Void, 0);
}
void tst_QMetaType::construct()
{
struct TypeTestFunctionGetter
{
static TypeTestFunction get(int type)
{
switch (type) {
#define RETURN_CONSTRUCT_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
case QMetaType::MetaTypeName: \
return testConstructHelper<QMetaType::MetaTypeName>;
FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_FUNCTION)
#undef RETURN_CONSTRUCT_FUNCTION
}
return 0;
}
};
QFETCH(int, type);
TypeTestFunctionGetter::get(type)();
}
void tst_QMetaType::typedConstruct()
{
auto testMetaObjectWriteOnGadget = [](QVariant &gadget, const QVector<GadgetPropertyType> &properties)
{
auto metaObject = QMetaType::metaObjectForType(gadget.userType());
QVERIFY(metaObject != nullptr);
QCOMPARE(metaObject->methodCount(), 0);
QCOMPARE(metaObject->propertyCount(), properties.size());
for (int i = 0; i < metaObject->propertyCount(); ++i) {
auto prop = metaObject->property(i);
QCOMPARE(properties[i].name, prop.name());
QCOMPARE(properties[i].type, prop.typeName());
prop.writeOnGadget(gadget.data(), properties[i].testData);
}
};
auto testMetaObjectReadOnGadget = [](QVariant gadget, const QVector<GadgetPropertyType> &properties)
{
auto metaObject = QMetaType::metaObjectForType(gadget.userType());
QVERIFY(metaObject != nullptr);
QCOMPARE(metaObject->methodCount(), 0);
QCOMPARE(metaObject->propertyCount(), properties.size());
for (int i = 0; i < metaObject->propertyCount(); ++i) {
auto prop = metaObject->property(i);
QCOMPARE(properties[i].name, prop.name());
QCOMPARE(properties[i].type, prop.typeName());
if (!QMetaType::typeFlags(prop.userType()).testFlag(QMetaType::IsGadget))
QCOMPARE(properties[i].testData, prop.readOnGadget(gadget.constData()));
}
};
QVector<GadgetPropertyType> dynamicGadget1 = {
{"int", "int_prop", 34526},
{"float", "float_prop", 1.23f},
{"QString", "string_prop", QString{"Test QString"}}
};
registerGadget("DynamicGadget1", dynamicGadget1);
QVariant testGadget1(QVariant::Type(QMetaType::type("DynamicGadget1")));
testMetaObjectWriteOnGadget(testGadget1, dynamicGadget1);
testMetaObjectReadOnGadget(testGadget1, dynamicGadget1);
QVector<GadgetPropertyType> dynamicGadget2 = {
{"int", "int_prop", 512},
{"double", "double_prop", 4.56},
{"QString", "string_prop", QString{"Another String"}},
{"DynamicGadget1", "dynamicGadget1_prop", testGadget1}
};
registerGadget("DynamicGadget2", dynamicGadget2);
QVariant testGadget2(QVariant::Type(QMetaType::type("DynamicGadget2")));
testMetaObjectWriteOnGadget(testGadget2, dynamicGadget2);
testMetaObjectReadOnGadget(testGadget2, dynamicGadget2);
auto g2mo = QMetaType::metaObjectForType(testGadget2.userType());
auto dynamicGadget1_prop = g2mo->property(g2mo->indexOfProperty("dynamicGadget1_prop"));
testMetaObjectReadOnGadget(dynamicGadget1_prop.readOnGadget(testGadget2.constData()), dynamicGadget1);
// Register POD
const QByteArray myPodTesData = "My POD test data";
const char podTypeName[] = "DynamicPOD";
auto dynamicGadgetProperties = std::make_shared<GenericPODType>();
dynamicGadgetProperties->podData = myPodTesData;
const auto flags = QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
int podTypeId = QMetaType::registerType(podTypeName,
&GadgetTypedDestructor,
&GadgetTypedConstructor,
sizeof(GenericGadgetType),
flags, nullptr);
QVERIFY(podTypeId > 0);
QMetaType::registerStreamOperators(podTypeId, &GadgetSaveOperator, &GadgetLoadOperator);
s_managedTypes[podTypeId] = qMakePair(dynamicGadgetProperties, std::shared_ptr<QMetaObject>{});
// Test POD
QCOMPARE(podTypeId, QMetaType::type(podTypeName));
QVariant podVariant{QVariant::Type(podTypeId)};
QCOMPARE(myPodTesData, static_cast<const GenericPODType *>(reinterpret_cast<const BaseGenericType *>(podVariant.constData()))->podData);
QVariant podVariant1{podVariant};
podVariant1.detach(); // Test stream operators
static_cast<GenericPODType *>(reinterpret_cast<BaseGenericType *>(podVariant.data()))->podData.clear();
QCOMPARE(myPodTesData, static_cast<const GenericPODType *>(reinterpret_cast<const BaseGenericType *>(podVariant1.constData()))->podData);
}
template<int ID>
static void testConstructCopyHelper()
{
typedef typename MetaEnumToType<ID>::Type Type;
Type *expected = TestValueFactory<ID>::create();
QMetaType info(ID);
int size = QMetaType::sizeOf(ID);
QCOMPARE(info.sizeOf(), size);
void *storage1 = qMallocAligned(size, Q_ALIGNOF(Type));
void *actual1 = QMetaType::construct(ID, storage1, expected);
void *storage2 = qMallocAligned(size, Q_ALIGNOF(Type));
void *actual2 = info.construct(storage2, expected);
QCOMPARE(actual1, storage1);
QCOMPARE(actual2, storage2);
QCOMPARE(*static_cast<Type *>(actual1), *expected);
QCOMPARE(*static_cast<Type *>(actual2), *expected);
QMetaType::destruct(ID, actual1);
qFreeAligned(storage1);
info.destruct(actual2);
qFreeAligned(storage2);
QVERIFY(QMetaType::construct(ID, 0, expected) == 0);
QVERIFY(info.construct(0, expected) == 0);
delete expected;
}
template<>
void testConstructCopyHelper<QMetaType::Void>()
{
typedef MetaEnumToType<QMetaType::Void>::Type Type;
Type *expected = TestValueFactory<QMetaType::Void>::create();
/* int size = */QMetaType::sizeOf(QMetaType::Void);
void *storage = 0;
void *actual = QMetaType::construct(QMetaType::Void, storage, expected);
QCOMPARE(actual, storage);
QMetaType::destruct(QMetaType::Void, actual);
qFreeAligned(storage);
QVERIFY(QMetaType::construct(QMetaType::Void, 0, expected) == 0);
}
void tst_QMetaType::constructCopy_data()
{
create_data();
}
void tst_QMetaType::constructCopy()
{
struct TypeTestFunctionGetter
{
static TypeTestFunction get(int type)
{
switch (type) {
#define RETURN_CONSTRUCT_COPY_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
case QMetaType::MetaTypeName: \
return testConstructCopyHelper<QMetaType::MetaTypeName>;
FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_COPY_FUNCTION)
#undef RETURN_CONSTRUCT_COPY_FUNCTION
}
return 0;
}
};
QFETCH(int, type);
TypeTestFunctionGetter::get(type)();
}
typedef QString CustomString;
Q_DECLARE_METATYPE(CustomString) //this line is useless
void tst_QMetaType::typedefs()
{
QCOMPARE(QMetaType::type("long long"), int(QMetaType::LongLong));
QCOMPARE(QMetaType::type("unsigned long long"), int(QMetaType::ULongLong));
QCOMPARE(QMetaType::type("qint8"), int(QMetaType::SChar));
QCOMPARE(QMetaType::type("quint8"), int(QMetaType::UChar));
QCOMPARE(QMetaType::type("qint16"), int(QMetaType::Short));
QCOMPARE(QMetaType::type("quint16"), int(QMetaType::UShort));
QCOMPARE(QMetaType::type("qint32"), int(QMetaType::Int));
QCOMPARE(QMetaType::type("quint32"), int(QMetaType::UInt));
QCOMPARE(QMetaType::type("qint64"), int(QMetaType::LongLong));
QCOMPARE(QMetaType::type("quint64"), int(QMetaType::ULongLong));
// make sure the qreal typeId is the type id of the type it's defined to
QCOMPARE(QMetaType::type("qreal"), ::qMetaTypeId<qreal>());
qRegisterMetaType<CustomString>("CustomString");
QCOMPARE(QMetaType::type("CustomString"), ::qMetaTypeId<CustomString>());
typedef Whity<double> WhityDouble;
qRegisterMetaType<WhityDouble>("WhityDouble");
QCOMPARE(QMetaType::type("WhityDouble"), ::qMetaTypeId<WhityDouble>());
}
void tst_QMetaType::registerType()
{
// Built-in
QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString));
QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString));
// Custom
int fooId = qRegisterMetaType<TestSpace::Foo>("TestSpace::Foo");
QVERIFY(fooId >= int(QMetaType::User));
QCOMPARE(qRegisterMetaType<TestSpace::Foo>("TestSpace::Foo"), fooId);
int movableId = qRegisterMetaType<CustomMovable>("CustomMovable");
QVERIFY(movableId >= int(QMetaType::User));
QCOMPARE(qRegisterMetaType<CustomMovable>("CustomMovable"), movableId);
// Alias to built-in
typedef QString MyString;
QCOMPARE(qRegisterMetaType<MyString>("MyString"), int(QMetaType::QString));
QCOMPARE(qRegisterMetaType<MyString>("MyString"), int(QMetaType::QString));
QCOMPARE(QMetaType::type("MyString"), int(QMetaType::QString));
// Alias to custom type
typedef CustomMovable MyMovable;
typedef TestSpace::Foo MyFoo;
QCOMPARE(qRegisterMetaType<MyMovable>("MyMovable"), movableId);
QCOMPARE(qRegisterMetaType<MyMovable>("MyMovable"), movableId);
QCOMPARE(QMetaType::type("MyMovable"), movableId);
QCOMPARE(qRegisterMetaType<MyFoo>("MyFoo"), fooId);
QCOMPARE(qRegisterMetaType<MyFoo>("MyFoo"), fooId);
QCOMPARE(QMetaType::type("MyFoo"), fooId);
// cannot unregister built-in types
QVERIFY(!QMetaType::unregisterType(QMetaType::QString));
QCOMPARE(QMetaType::type("QString"), int(QMetaType::QString));
QCOMPARE(QMetaType::type("MyString"), int(QMetaType::QString));
// cannot unregister declared types
QVERIFY(!QMetaType::unregisterType(fooId));
QCOMPARE(QMetaType::type("TestSpace::Foo"), fooId);
QCOMPARE(QMetaType::type("MyFoo"), fooId);
// test unregistration of dynamic types (used by Qml)
int unregId = QMetaType::registerType("UnregisterMe",
0,
0,
QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
0, QMetaType::TypeFlags(), 0);
QCOMPARE(QMetaType::registerTypedef("UnregisterMeTypedef", unregId), unregId);
int unregId2 = QMetaType::registerType("UnregisterMe2",
0,
0,
QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
0, QMetaType::TypeFlags(), 0);
QVERIFY(unregId >= int(QMetaType::User));
QCOMPARE(unregId2, unregId + 2);
QVERIFY(QMetaType::unregisterType(unregId));
QCOMPARE(QMetaType::type("UnregisterMe"), 0);
QCOMPARE(QMetaType::type("UnregisterMeTypedef"), 0);
QCOMPARE(QMetaType::type("UnregisterMe2"), unregId2);
QVERIFY(QMetaType::unregisterType(unregId2));
QCOMPARE(QMetaType::type("UnregisterMe2"), 0);
// re-registering should always return the lowest free index
QCOMPARE(QMetaType::registerType("UnregisterMe2",
0,
0,
QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
0, QMetaType::TypeFlags(), 0), unregId);
QCOMPARE(QMetaType::registerType("UnregisterMe",
0,
0,
QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
0, QMetaType::TypeFlags(), 0), unregId + 1);
}
class IsRegisteredDummyType { };
void tst_QMetaType::isRegistered_data()
{
QTest::addColumn<int>("typeId");
QTest::addColumn<bool>("registered");
// predefined/custom types
QTest::newRow("QMetaType::Void") << int(QMetaType::Void) << true;
QTest::newRow("QMetaType::Int") << int(QMetaType::Int) << true;
int dummyTypeId = qRegisterMetaType<IsRegisteredDummyType>("IsRegisteredDummyType");
QTest::newRow("IsRegisteredDummyType") << dummyTypeId << true;
// unknown types
QTest::newRow("-1") << -1 << false;
QTest::newRow("-42") << -42 << false;
QTest::newRow("IsRegisteredDummyType + 1") << (dummyTypeId + 1) << false;
QTest::newRow("QMetaType::UnknownType") << int(QMetaType::UnknownType) << false;
}
void tst_QMetaType::isRegistered()
{
QFETCH(int, typeId);
QFETCH(bool, registered);
QCOMPARE(QMetaType::isRegistered(typeId), registered);
}
enum isEnumTest_Enum0 {};
struct isEnumTest_Struct0 { enum A{}; };
enum isEnumTest_Enum1 {};
struct isEnumTest_Struct1 {};
Q_DECLARE_METATYPE(isEnumTest_Struct1)
Q_DECLARE_METATYPE(isEnumTest_Enum1)
void tst_QMetaType::isEnum()
{
int type0 = qRegisterMetaType<int>("int");
QVERIFY((QMetaType::typeFlags(type0) & QMetaType::IsEnumeration) == 0);
int type1 = qRegisterMetaType<isEnumTest_Enum0>("isEnumTest_Enum0");
QVERIFY((QMetaType::typeFlags(type1) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration);
int type2 = qRegisterMetaType<isEnumTest_Struct0>("isEnumTest_Struct0");
QVERIFY((QMetaType::typeFlags(type2) & QMetaType::IsEnumeration) == 0);
int type3 = qRegisterMetaType<isEnumTest_Enum0 *>("isEnumTest_Enum0 *");
QVERIFY((QMetaType::typeFlags(type3) & QMetaType::IsEnumeration) == 0);
int type4 = qRegisterMetaType<isEnumTest_Struct0::A>("isEnumTest_Struct0::A");
QVERIFY((QMetaType::typeFlags(type4) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration);
int type5 = ::qMetaTypeId<isEnumTest_Struct1>();
QVERIFY((QMetaType::typeFlags(type5) & QMetaType::IsEnumeration) == 0);
int type6 = ::qMetaTypeId<isEnumTest_Enum1>();
QVERIFY((QMetaType::typeFlags(type6) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration);
}
void tst_QMetaType::isRegisteredStaticLess_data()
{
isRegistered_data();
}
void tst_QMetaType::isRegisteredStaticLess()
{
QFETCH(int, typeId);
QFETCH(bool, registered);
QCOMPARE(QMetaType(typeId).isRegistered(), registered);
}
void tst_QMetaType::registerStreamBuiltin()
{
//should not crash;
qRegisterMetaTypeStreamOperators<QString>("QString");
qRegisterMetaTypeStreamOperators<QVariant>("QVariant");
}
typedef QHash<int, uint> IntUIntHash;
Q_DECLARE_METATYPE(IntUIntHash)
typedef QMap<int, uint> IntUIntMap;
Q_DECLARE_METATYPE(IntUIntMap)
typedef QPair<int, uint> IntUIntPair;
Q_DECLARE_METATYPE(IntUIntPair)
struct CustomComparable
{
CustomComparable(int i_ = 0) :i(i_) { }
bool operator==(const CustomComparable &other) const
{
return i == other.i;
}
int i;
};
struct UnregisteredType {};
typedef QHash<int, CustomComparable> IntComparableHash;
Q_DECLARE_METATYPE(IntComparableHash)
typedef QMap<int, CustomComparable> IntComparableMap;
Q_DECLARE_METATYPE(IntComparableMap)
typedef QPair<int, CustomComparable> IntComparablePair;
Q_DECLARE_METATYPE(IntComparablePair)
typedef QHash<int, int> IntIntHash;
typedef int NaturalNumber;
class AutoMetaTypeObject : public QObject
{
Q_OBJECT
Q_PROPERTY(IntIntHash someHash READ someHash CONSTANT)
Q_PROPERTY(NaturalNumber someInt READ someInt CONSTANT)
public:
AutoMetaTypeObject(QObject *parent = 0)
: QObject(parent), m_int(42)
{
m_hash.insert(4, 2);
}
QHash<int,int> someHash() const
{
return m_hash;
}
int someInt() const
{
return m_int;
}
private:
QHash<int,int> m_hash;
int m_int;
};
class MyObject : public QObject
{
Q_OBJECT
public:
MyObject(QObject *parent = 0)
: QObject(parent)
{
}
};
typedef MyObject* MyObjectPtr;
Q_DECLARE_METATYPE(MyObjectPtr)
#if !defined(TST_QMETATYPE_BROKEN_COMPILER)
static QByteArray createTypeName(const char *begin, const char *va)
{
QByteArray tn(begin);
const QList<QByteArray> args = QByteArray(va).split(',');
tn += args.first().trimmed();
if (args.size() > 1) {
QList<QByteArray>::const_iterator it = args.constBegin() + 1;
const QList<QByteArray>::const_iterator end = args.constEnd();
for (; it != end; ++it) {
tn += ",";
tn += it->trimmed();
}
}
if (tn.endsWith('>'))
tn += ' ';
tn += '>';
return tn;
}
#endif
Q_DECLARE_METATYPE(const void*)
void tst_QMetaType::automaticTemplateRegistration()
{
#define TEST_SEQUENTIAL_CONTAINER(CONTAINER, VALUE_TYPE) \
{ \
CONTAINER<VALUE_TYPE> innerContainer; \
innerContainer.push_back(42); \
QVERIFY(*QVariant::fromValue(innerContainer).value<CONTAINER<VALUE_TYPE> >().begin() == 42); \
QVector<CONTAINER<VALUE_TYPE> > outerContainer; \
outerContainer << innerContainer; \
QVERIFY(*QVariant::fromValue(outerContainer).value<QVector<CONTAINER<VALUE_TYPE> > >().first().begin() == 42); \
}
TEST_SEQUENTIAL_CONTAINER(QList, int)
TEST_SEQUENTIAL_CONTAINER(std::vector, int)
TEST_SEQUENTIAL_CONTAINER(std::list, int)
{
std::vector<bool> vecbool;
vecbool.push_back(true);
vecbool.push_back(false);
vecbool.push_back(true);
QVERIFY(QVariant::fromValue(vecbool).value<std::vector<bool> >().front() == true);
QVector<std::vector<bool> > vectorList;
vectorList << vecbool;
QVERIFY(QVariant::fromValue(vectorList).value<QVector<std::vector<bool> > >().first().front() == true);
}
{
QList<unsigned> unsignedList;
unsignedList << 123;
QVERIFY(QVariant::fromValue(unsignedList).value<QList<unsigned> >().first() == 123);
QVector<QList<unsigned> > vectorList;
vectorList << unsignedList;
QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<unsigned> > >().first().first() == 123);
}
QCOMPARE(::qMetaTypeId<QVariantList>(), (int)QMetaType::QVariantList);
QCOMPARE(::qMetaTypeId<QList<QVariant> >(), (int)QMetaType::QVariantList);
TEST_SEQUENTIAL_CONTAINER(QList, QVariant)
TEST_SEQUENTIAL_CONTAINER(std::vector, QVariant)
TEST_SEQUENTIAL_CONTAINER(std::list, QVariant)
{
QList<QSharedPointer<QObject> > sharedPointerList;
QObject *testObject = new QObject;
sharedPointerList << QSharedPointer<QObject>(testObject);
QVERIFY(QVariant::fromValue(sharedPointerList).value<QList<QSharedPointer<QObject> > >().first() == testObject);
QVector<QList<QSharedPointer<QObject> > > vectorList;
vectorList << sharedPointerList;
QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<QSharedPointer<QObject> > > >().first().first() == testObject);
}
{
IntIntHash intIntHash;
intIntHash.insert(4, 2);
QCOMPARE(QVariant::fromValue(intIntHash).value<IntIntHash>().value(4), 2);
AutoMetaTypeObject amto;
qRegisterMetaType<QHash<int, int> >("IntIntHash");
QVariant hashVariant = amto.property("someHash");
QCOMPARE(hashVariant.value<IntIntHash>().value(4), 2);
qRegisterMetaType<int>("NaturalNumber");
QVariant intVariant = amto.property("someInt");
QCOMPARE(intVariant.value<NaturalNumber>(), 42);
}
{
IntUIntHash intUIntHash;
intUIntHash.insert(4, 2);
QCOMPARE(QVariant::fromValue(intUIntHash).value<IntUIntHash>().value(4), (uint)2);
}
{
IntComparableHash intComparableHash;
CustomComparable m;
intComparableHash.insert(4, m);
QCOMPARE(QVariant::fromValue(intComparableHash).value<IntComparableHash>().value(4), m);
}
{
QVariantHash variantHash;
variantHash.insert(QStringLiteral("4"), 2);
QCOMPARE(QVariant::fromValue(variantHash).value<QVariantHash>().value(QStringLiteral("4")), QVariant(2));
}
{
typedef QMap<int, int> IntIntMap;
IntIntMap intIntMap;
intIntMap.insert(4, 2);
QCOMPARE(QVariant::fromValue(intIntMap).value<IntIntMap>().value(4), 2);
}
{
IntUIntMap intUIntMap;
intUIntMap.insert(4, 2);
QCOMPARE(QVariant::fromValue(intUIntMap).value<IntUIntMap>().value(4), (uint)2);
}
{
IntComparableMap intComparableMap;
CustomComparable m;
intComparableMap.insert(4, m);
QCOMPARE(QVariant::fromValue(intComparableMap).value<IntComparableMap>().value(4), m);
}
{
QVariantMap variantMap;
variantMap.insert(QStringLiteral("4"), 2);
QCOMPARE(QVariant::fromValue(variantMap).value<QVariantMap>().value(QStringLiteral("4")), QVariant(2));
}
{
typedef std::map<int, int> IntIntMap;
IntIntMap intIntMap;
intIntMap[4] = 2;
QCOMPARE(QVariant::fromValue(intIntMap).value<IntIntMap>()[4], 2);
}
{
typedef std::map<int, uint> StdIntUIntMap;
StdIntUIntMap intUIntMap;
intUIntMap[4] = 2;
QCOMPARE(QVariant::fromValue(intUIntMap).value<StdIntUIntMap>()[4], (uint)2);
}
{
typedef std::map<int, CustomObject*> StdMapIntCustomObject ;
StdMapIntCustomObject intComparableMap;
CustomObject *o = 0;
intComparableMap[4] = o;
QCOMPARE(QVariant::fromValue(intComparableMap).value<StdMapIntCustomObject >()[4], o);
}
{
typedef std::map<QString, QVariant> StdMapStringVariant;
StdMapStringVariant variantMap;
variantMap[QStringLiteral("4")] = 2;
QCOMPARE(QVariant::fromValue(variantMap).value<StdMapStringVariant>()[QStringLiteral("4")], QVariant(2));
}
{
typedef QPair<int, int> IntIntPair;
IntIntPair intIntPair = qMakePair(4, 2);
QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().first, 4);
QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().second, 2);
}
{
IntUIntPair intUIntPair = qMakePair<int, uint>(4, 2);
QCOMPARE(QVariant::fromValue(intUIntPair).value<IntUIntPair>().first, 4);
QCOMPARE(QVariant::fromValue(intUIntPair).value<IntUIntPair>().second, (uint)2);
}
{
CustomComparable m;
IntComparablePair intComparablePair = qMakePair(4, m);
QCOMPARE(QVariant::fromValue(intComparablePair).value<IntComparablePair>().first, 4);
QCOMPARE(QVariant::fromValue(intComparablePair).value<IntComparablePair>().second, m);
}
{
typedef std::pair<int, int> IntIntPair;
IntIntPair intIntPair = std::make_pair(4, 2);
QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().first, 4);
QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().second, 2);
}
{
typedef std::pair<int, uint> StdIntUIntPair;
StdIntUIntPair intUIntPair = std::make_pair<int, uint>(4, 2);
QCOMPARE(QVariant::fromValue(intUIntPair).value<StdIntUIntPair>().first, 4);
QCOMPARE(QVariant::fromValue(intUIntPair).value<StdIntUIntPair>().second, (uint)2);
}
{
typedef std::pair<int, CustomQObject*> StdIntComparablePair;
CustomQObject* o = 0;
StdIntComparablePair intComparablePair = std::make_pair(4, o);
QCOMPARE(QVariant::fromValue(intComparablePair).value<StdIntComparablePair>().first, 4);
QCOMPARE(QVariant::fromValue(intComparablePair).value<StdIntComparablePair>().second, o);
}
{
typedef QHash<int, UnregisteredType> IntUnregisteredTypeHash;
QVERIFY(qRegisterMetaType<IntUnregisteredTypeHash>("IntUnregisteredTypeHash") > 0);
}
{
typedef QList<UnregisteredType> UnregisteredTypeList;
QVERIFY(qRegisterMetaType<UnregisteredTypeList>("UnregisteredTypeList") > 0);
}
#if !defined(TST_QMETATYPE_BROKEN_COMPILER)
#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 type = QMetaType::type(tn); \
const int expectedType = ::qMetaTypeId<CONTAINER< __VA_ARGS__ > >(); \
QCOMPARE(type, expectedType); \
}
#define FOR_EACH_1ARG_TEMPLATE_TYPE(F, TYPE) \
F(QList, TYPE) \
F(QVector, TYPE) \
F(QLinkedList, TYPE) \
F(QVector, TYPE) \
F(QVector, 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(QPair, 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> >(#TYPE "<" #ARG1 "," #ARG2 ">");
REGISTER_TYPEDEF(QHash, int, uint)
REGISTER_TYPEDEF(QMap, int, uint)
REGISTER_TYPEDEF(QPair, int, uint)
FOR_EACH_STATIC_PRIMITIVE_TYPE(
PRINT_1ARG_TEMPLATE
)
FOR_EACH_STATIC_PRIMITIVE_TYPE(
PRINT_2ARG_TEMPLATE
)
CREATE_AND_VERIFY_CONTAINER(QList, QList<QMap<int, QHash<char, QVariantList> > >)
CREATE_AND_VERIFY_CONTAINER(QVector, void*)
CREATE_AND_VERIFY_CONTAINER(QVector, const void*)
CREATE_AND_VERIFY_CONTAINER(QList, void*)
CREATE_AND_VERIFY_CONTAINER(QPair, void*, void*)
CREATE_AND_VERIFY_CONTAINER(QHash, void*, void*)
CREATE_AND_VERIFY_CONTAINER(QHash, const void*, const void*)
#endif // !defined(TST_QMETATYPE_BROKEN_COMPILER)
#define TEST_OWNING_SMARTPOINTER(SMARTPOINTER, ELEMENT_TYPE, FLAG_TEST, FROMVARIANTFUNCTION) \
{ \
SMARTPOINTER < ELEMENT_TYPE > sp(new ELEMENT_TYPE); \
sp.data()->setObjectName("Test name"); \
QVariant v = QVariant::fromValue(sp); \
QCOMPARE(v.typeName(), #SMARTPOINTER "<" #ELEMENT_TYPE ">"); \
QVERIFY(QMetaType::typeFlags(::qMetaTypeId<SMARTPOINTER < ELEMENT_TYPE > >()) & QMetaType::FLAG_TEST); \
SMARTPOINTER < QObject > extractedPtr = FROMVARIANTFUNCTION<QObject>(v); \
QCOMPARE(extractedPtr.data()->objectName(), sp.data()->objectName()); \
}
TEST_OWNING_SMARTPOINTER(QSharedPointer, QObject, SharedPointerToQObject, qSharedPointerFromVariant)
TEST_OWNING_SMARTPOINTER(QSharedPointer, QFile, SharedPointerToQObject, qSharedPointerFromVariant)
TEST_OWNING_SMARTPOINTER(QSharedPointer, QTemporaryFile, SharedPointerToQObject, qSharedPointerFromVariant)
TEST_OWNING_SMARTPOINTER(QSharedPointer, MyObject, SharedPointerToQObject, qSharedPointerFromVariant)
#undef TEST_OWNING_SMARTPOINTER
#define TEST_NONOWNING_SMARTPOINTER(SMARTPOINTER, ELEMENT_TYPE, FLAG_TEST, FROMVARIANTFUNCTION) \
{ \
ELEMENT_TYPE elem; \
SMARTPOINTER < ELEMENT_TYPE > sp(&elem); \
sp.data()->setObjectName("Test name"); \
QVariant v = QVariant::fromValue(sp); \
QCOMPARE(v.typeName(), #SMARTPOINTER "<" #ELEMENT_TYPE ">"); \
QVERIFY(QMetaType::typeFlags(::qMetaTypeId<SMARTPOINTER < ELEMENT_TYPE > >()) & QMetaType::FLAG_TEST); \
SMARTPOINTER < QObject > extractedPtr = FROMVARIANTFUNCTION<QObject>(v); \
QCOMPARE(extractedPtr.data()->objectName(), sp.data()->objectName()); \
}
#if QT_DEPRECATED_SINCE(5, 0)
TEST_NONOWNING_SMARTPOINTER(QWeakPointer, QObject, WeakPointerToQObject, qWeakPointerFromVariant)
TEST_NONOWNING_SMARTPOINTER(QWeakPointer, QFile, WeakPointerToQObject, qWeakPointerFromVariant)
TEST_NONOWNING_SMARTPOINTER(QWeakPointer, QTemporaryFile, WeakPointerToQObject, qWeakPointerFromVariant)
TEST_NONOWNING_SMARTPOINTER(QWeakPointer, MyObject, WeakPointerToQObject, qWeakPointerFromVariant)
#endif
TEST_NONOWNING_SMARTPOINTER(QPointer, QObject, TrackingPointerToQObject, qPointerFromVariant)
TEST_NONOWNING_SMARTPOINTER(QPointer, QFile, TrackingPointerToQObject, qPointerFromVariant)
TEST_NONOWNING_SMARTPOINTER(QPointer, QTemporaryFile, TrackingPointerToQObject, qPointerFromVariant)
TEST_NONOWNING_SMARTPOINTER(QPointer, MyObject, TrackingPointerToQObject, qPointerFromVariant)
#undef TEST_NONOWNING_SMARTPOINTER
#define TEST_WEAK_SMARTPOINTER(ELEMENT_TYPE, FLAG_TEST) \
{ \
ELEMENT_TYPE elem; \
QSharedPointer < ELEMENT_TYPE > shared(new ELEMENT_TYPE); \
QWeakPointer < ELEMENT_TYPE > sp(shared); \
sp.toStrongRef()->setObjectName("Test name"); \
QVariant v = QVariant::fromValue(sp); \
QCOMPARE(v.typeName(), "QWeakPointer<" #ELEMENT_TYPE ">"); \
QVERIFY(QMetaType::typeFlags(::qMetaTypeId<QWeakPointer < ELEMENT_TYPE > >()) & QMetaType::FLAG_TEST); \
}
TEST_WEAK_SMARTPOINTER(QObject, WeakPointerToQObject)
TEST_WEAK_SMARTPOINTER(QFile, WeakPointerToQObject)
TEST_WEAK_SMARTPOINTER(QTemporaryFile, WeakPointerToQObject)
TEST_WEAK_SMARTPOINTER(MyObject, WeakPointerToQObject)
#undef TEST_WEAK_SMARTPOINTER
}
template <typename T>
struct StreamingTraits
{
enum { isStreamable = 1 }; // Streamable by default
};
// Non-streamable types
#define DECLARE_NONSTREAMABLE(Type) \
template<> struct StreamingTraits<Type> { enum { isStreamable = 0 }; };
DECLARE_NONSTREAMABLE(void)
DECLARE_NONSTREAMABLE(void*)
DECLARE_NONSTREAMABLE(QModelIndex)
DECLARE_NONSTREAMABLE(QPersistentModelIndex)
DECLARE_NONSTREAMABLE(QObject*)
DECLARE_NONSTREAMABLE(QWidget*)
#define DECLARE_GUI_CLASS_NONSTREAMABLE(MetaTypeName, MetaTypeId, RealType) \
DECLARE_NONSTREAMABLE(RealType)
QT_FOR_EACH_STATIC_GUI_CLASS(DECLARE_GUI_CLASS_NONSTREAMABLE)
#undef DECLARE_GUI_CLASS_NONSTREAMABLE
#define DECLARE_WIDGETS_CLASS_NONSTREAMABLE(MetaTypeName, MetaTypeId, RealType) \
DECLARE_NONSTREAMABLE(RealType)
QT_FOR_EACH_STATIC_WIDGETS_CLASS(DECLARE_WIDGETS_CLASS_NONSTREAMABLE)
#undef DECLARE_WIDGETS_CLASS_NONSTREAMABLE
#undef DECLARE_NONSTREAMABLE
void tst_QMetaType::saveAndLoadBuiltin_data()
{
QTest::addColumn<int>("type");
QTest::addColumn<bool>("isStreamable");
#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
QTest::newRow(#RealType) << MetaTypeId << bool(StreamingTraits<RealType>::isStreamable);
QT_FOR_EACH_STATIC_TYPE(ADD_METATYPE_TEST_ROW)
#undef ADD_METATYPE_TEST_ROW
}
void tst_QMetaType::saveAndLoadBuiltin()
{
QFETCH(int, type);
QFETCH(bool, isStreamable);
void *value = QMetaType::create(type);
QByteArray ba;
QDataStream stream(&ba, QIODevice::ReadWrite);
QCOMPARE(QMetaType::save(stream, type, value), isStreamable);
QCOMPARE(stream.status(), QDataStream::Ok);
if (isStreamable) {
QVERIFY(QMetaType::load(stream, type, value)); // Hmmm, shouldn't it return false?
// std::nullptr_t is nullary: it doesn't actually read anything
if (type != QMetaType::Nullptr)
QCOMPARE(stream.status(), QDataStream::ReadPastEnd);
}
stream.device()->seek(0);
stream.resetStatus();
QCOMPARE(QMetaType::load(stream, type, value), isStreamable);
QCOMPARE(stream.status(), QDataStream::Ok);
if (isStreamable) {
QVERIFY(QMetaType::load(stream, type, value)); // Hmmm, shouldn't it return false?
// std::nullptr_t is nullary: it doesn't actually read anything
if (type != QMetaType::Nullptr)
QCOMPARE(stream.status(), QDataStream::ReadPastEnd);
}
QMetaType::destroy(type, value);
}
struct CustomStreamableType
{
int a;
};
Q_DECLARE_METATYPE(CustomStreamableType)
QDataStream &operator<<(QDataStream &out, const CustomStreamableType &t)
{
out << t.a; return out;
}
QDataStream &operator>>(QDataStream &in, CustomStreamableType &t)
{
int a;
in >> a;
if (in.status() == QDataStream::Ok)
t.a = a;
return in;
}
void tst_QMetaType::saveAndLoadCustom()
{
CustomStreamableType t;
t.a = 123;
int id = ::qMetaTypeId<CustomStreamableType>();
QByteArray ba;
QDataStream stream(&ba, QIODevice::ReadWrite);
QVERIFY(!QMetaType::save(stream, id, &t));
QCOMPARE(stream.status(), QDataStream::Ok);
QVERIFY(!QMetaType::load(stream, id, &t));
QCOMPARE(stream.status(), QDataStream::Ok);
qRegisterMetaTypeStreamOperators<CustomStreamableType>("CustomStreamableType");
QVERIFY(QMetaType::save(stream, id, &t));
QCOMPARE(stream.status(), QDataStream::Ok);
CustomStreamableType t2;
t2.a = -1;
QVERIFY(QMetaType::load(stream, id, &t2)); // Hmmm, shouldn't it return false?
QCOMPARE(stream.status(), QDataStream::ReadPastEnd);
QCOMPARE(t2.a, -1);
stream.device()->seek(0);
stream.resetStatus();
QVERIFY(QMetaType::load(stream, id, &t2));
QCOMPARE(stream.status(), QDataStream::Ok);
QCOMPARE(t2.a, t.a);
QVERIFY(QMetaType::load(stream, id, &t2)); // Hmmm, shouldn't it return false?
QCOMPARE(stream.status(), QDataStream::ReadPastEnd);
}
class MyGadget {
Q_GADGET;
public:
enum MyEnum { Val1, Val2, Val3 };
Q_ENUM(MyEnum)
};
class MyQObjectFromGadget : public QObject, public MyGadget
{
Q_OBJECT
public:
MyQObjectFromGadget(QObject *parent = 0)
: QObject(parent)
{}
};
Q_DECLARE_METATYPE(MyGadget);
Q_DECLARE_METATYPE(MyGadget*);
Q_DECLARE_METATYPE(const QMetaObject *);
Q_DECLARE_METATYPE(Qt::ScrollBarPolicy);
Q_DECLARE_METATYPE(MyGadget::MyEnum);
Q_DECLARE_METATYPE(MyQObjectFromGadget*);
void tst_QMetaType::metaObject_data()
{
QTest::addColumn<int>("type");
QTest::addColumn<const QMetaObject*>("result");
QTest::addColumn<bool>("isGadget");
QTest::addColumn<bool>("isGadgetPtr");
QTest::addColumn<bool>("isQObjectPtr");
QTest::newRow("QObject") << int(QMetaType::QObjectStar) << &QObject::staticMetaObject << false << false << true;
QTest::newRow("QFile*") << ::qMetaTypeId<QFile*>() << &QFile::staticMetaObject << false << false << true;
QTest::newRow("MyObject*") << ::qMetaTypeId<MyObject*>() << &MyObject::staticMetaObject << false << false << true;
QTest::newRow("int") << int(QMetaType::Int) << static_cast<const QMetaObject *>(0) << false << false << false;
QTest::newRow("QEasingCurve") << ::qMetaTypeId<QEasingCurve>() << &QEasingCurve::staticMetaObject << true << false << false;
QTest::newRow("MyGadget") << ::qMetaTypeId<MyGadget>() << &MyGadget::staticMetaObject << true << false << false;
QTest::newRow("MyGadget*") << ::qMetaTypeId<MyGadget*>() << &MyGadget::staticMetaObject << false << true << false;
QTest::newRow("MyEnum") << ::qMetaTypeId<MyGadget::MyEnum>() << &MyGadget::staticMetaObject << false << false << false;
QTest::newRow("Qt::ScrollBarPolicy") << ::qMetaTypeId<Qt::ScrollBarPolicy>() << &QObject::staticQtMetaObject << false << false << false;
QTest::newRow("MyQObjectFromGadget*") << ::qMetaTypeId<MyQObjectFromGadget*>() << &MyQObjectFromGadget::staticMetaObject << false << false << true;
QTest::newRow("GadgetDerivedAndTyped<int>") << ::qMetaTypeId<GadgetDerivedAndTyped<int>>() << &GadgetDerivedAndTyped<int>::staticMetaObject << true << false << false;
QTest::newRow("GadgetDerivedAndTyped<int>*") << ::qMetaTypeId<GadgetDerivedAndTyped<int>*>() << &GadgetDerivedAndTyped<int>::staticMetaObject << false << true << false;
}
void tst_QMetaType::metaObject()
{
QFETCH(int, type);
QFETCH(const QMetaObject *, result);
QFETCH(bool, isGadget);
QFETCH(bool, isGadgetPtr);
QFETCH(bool, isQObjectPtr);
QCOMPARE(QMetaType::metaObjectForType(type), result);
QMetaType mt(type);
QCOMPARE(mt.metaObject(), result);
QCOMPARE(!!(mt.flags() & QMetaType::IsGadget), isGadget);
QCOMPARE(!!(mt.flags() & QMetaType::PointerToGadget), isGadgetPtr);
QCOMPARE(!!(mt.flags() & QMetaType::PointerToQObject), isQObjectPtr);
}
#define METATYPE_ID_FUNCTION(Type, MetaTypeId, Name) \
case ::qMetaTypeId< Name >(): metaType = MetaTypeIdStruct<MetaTypeId>::Value; break;
#define REGISTER_METATYPE_FUNCTION(Type, MetaTypeId, Name) \
case qRegisterMetaType< Name >(): metaType = RegisterMetaTypeStruct<MetaTypeId>::Value; break;
template<int>
struct MetaTypeIdStruct
{
};
template<int>
struct RegisterMetaTypeStruct
{
};
#define METATYPE_ID_STRUCT(Type, MetaTypeId, Name) \
template<> \
struct MetaTypeIdStruct< ::qMetaTypeId< Name >()> \
{ \
enum { Value = ::qMetaTypeId< Name >() }; \
};
#define REGISTER_METATYPE_STRUCT(Type, MetaTypeId, Name) \
template<> \
struct RegisterMetaTypeStruct<qRegisterMetaType< Name >()> \
{ \
enum { Value = qRegisterMetaType< Name >() }; \
};
#if defined(Q_COMPILER_CONSTEXPR)
QT_FOR_EACH_STATIC_TYPE(METATYPE_ID_STRUCT)
QT_FOR_EACH_STATIC_TYPE(REGISTER_METATYPE_STRUCT)
template<int i = ::qMetaTypeId<int>()>
struct MetaTypeIdStructDefaultTemplateValue
{
enum { Value };
};
template<int i = qRegisterMetaType<int>()>
struct RegisterMetaTypeStructDefaultTemplateValue
{
enum { Value };
};
#endif
void tst_QMetaType::constexprMetaTypeIds()
{
#if defined(Q_COMPILER_CONSTEXPR)
int id = 0;
int metaType;
switch(id) {
QT_FOR_EACH_STATIC_TYPE(METATYPE_ID_FUNCTION)
metaType = MetaTypeIdStructDefaultTemplateValue<>::Value;
default:;
}
switch (id) {
QT_FOR_EACH_STATIC_TYPE(REGISTER_METATYPE_FUNCTION)
metaType = RegisterMetaTypeStructDefaultTemplateValue<>::Value;
default:;
}
Q_UNUSED(metaType);
#else
QSKIP("The test needs a compiler supporting constexpr");
#endif
}
void tst_QMetaType::constRefs()
{
QCOMPARE(::qMetaTypeId<const int &>(), ::qMetaTypeId<int>());
QCOMPARE(::qMetaTypeId<const QString &>(), ::qMetaTypeId<QString>());
QCOMPARE(::qMetaTypeId<const CustomMovable &>(), ::qMetaTypeId<CustomMovable>());
QCOMPARE(::qMetaTypeId<const QList<CustomMovable> &>(), ::qMetaTypeId<QList<CustomMovable> >());
#if defined(Q_COMPILER_CONSTEXPR)
Q_STATIC_ASSERT(::qMetaTypeId<const int &>() == ::qMetaTypeId<int>());
#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<typename To>
To convert() const { return s_value.value<To>();}
template<typename To>
To convertOk(bool *ok) const { *ok = s_ok; return s_value.value<To>();}
QVariant m_foo;
static QVariant s_value;
static bool s_ok;
};
bool operator<(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
{ return lhs.m_foo < rhs.m_foo; }
bool operator==(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
{ return lhs.m_foo == rhs.m_foo; }
bool operator!=(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
{ return !operator==(lhs, rhs); }
QVariant CustomConvertibleType::s_value;
bool CustomConvertibleType::s_ok = true;
struct CustomConvertibleType2
{
// implicit
CustomConvertibleType2(const CustomConvertibleType &t = CustomConvertibleType())
: m_foo(t.m_foo) {}
virtual ~CustomConvertibleType2() {}
QVariant m_foo;
};
struct CustomDebugStreamableType
{
QString toString() const { return "test"; }
};
QDebug operator<<(QDebug dbg, const CustomDebugStreamableType&)
{
return dbg << "string-content";
}
bool operator==(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs)
{ return lhs.m_foo == rhs.m_foo; }
bool operator!=(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs)
{ return !operator==(lhs, rhs); }
struct CustomEqualsOnlyType
{
explicit CustomEqualsOnlyType(int value = 0) : val(value) {}
virtual ~CustomEqualsOnlyType() {}
int val;
};
bool operator==(const CustomEqualsOnlyType &lhs, const CustomEqualsOnlyType &rhs)
{ return lhs.val == rhs.val;}
bool operator!=(const CustomEqualsOnlyType &lhs, const CustomEqualsOnlyType &rhs)
{ return !operator==(lhs, rhs); }
Q_DECLARE_METATYPE(CustomConvertibleType);
Q_DECLARE_METATYPE(CustomConvertibleType2);
Q_DECLARE_METATYPE(CustomDebugStreamableType);
Q_DECLARE_METATYPE(CustomEqualsOnlyType);
template<typename T, typename U>
U convert(const T &t)
{
return t;
}
template<typename From>
struct ConvertFunctor
{
CustomConvertibleType operator()(const From& f) const
{
return CustomConvertibleType(QVariant::fromValue(f));
}
};
template<typename From, typename To>
bool hasRegisteredConverterFunction()
{
return QMetaType::hasRegisteredConverterFunction<From, To>();
}
template<typename From, typename To>
void testCustomTypeNotYetConvertible()
{
QVERIFY((!hasRegisteredConverterFunction<From, To>()));
QVERIFY((!QVariant::fromValue<From>(From()).canConvert(qMetaTypeId<To>())));
}
template<typename From, typename To>
void testCustomTypeConvertible()
{
QVERIFY((hasRegisteredConverterFunction<From, To>()));
QVERIFY((QVariant::fromValue<From>(From()).canConvert(qMetaTypeId<To>())));
}
void customTypeNotYetConvertible()
{
testCustomTypeNotYetConvertible<CustomConvertibleType, QString>();
testCustomTypeNotYetConvertible<CustomConvertibleType, bool>();
testCustomTypeNotYetConvertible<CustomConvertibleType, int>();
testCustomTypeNotYetConvertible<CustomConvertibleType, double>();
testCustomTypeNotYetConvertible<CustomConvertibleType, float>();
testCustomTypeNotYetConvertible<CustomConvertibleType, QRect>();
testCustomTypeNotYetConvertible<CustomConvertibleType, QRectF>();
testCustomTypeNotYetConvertible<CustomConvertibleType, QPoint>();
testCustomTypeNotYetConvertible<CustomConvertibleType, QPointF>();
testCustomTypeNotYetConvertible<CustomConvertibleType, QSize>();
testCustomTypeNotYetConvertible<CustomConvertibleType, QSizeF>();
testCustomTypeNotYetConvertible<CustomConvertibleType, QLine>();
testCustomTypeNotYetConvertible<CustomConvertibleType, QLineF>();
testCustomTypeNotYetConvertible<CustomConvertibleType, QChar>();
testCustomTypeNotYetConvertible<QString, CustomConvertibleType>();
testCustomTypeNotYetConvertible<bool, CustomConvertibleType>();
testCustomTypeNotYetConvertible<int, CustomConvertibleType>();
testCustomTypeNotYetConvertible<double, CustomConvertibleType>();
testCustomTypeNotYetConvertible<float, CustomConvertibleType>();
testCustomTypeNotYetConvertible<QRect, CustomConvertibleType>();
testCustomTypeNotYetConvertible<QRectF, CustomConvertibleType>();
testCustomTypeNotYetConvertible<QPoint, CustomConvertibleType>();
testCustomTypeNotYetConvertible<QPointF, CustomConvertibleType>();
testCustomTypeNotYetConvertible<QSize, CustomConvertibleType>();
testCustomTypeNotYetConvertible<QSizeF, CustomConvertibleType>();
testCustomTypeNotYetConvertible<QLine, CustomConvertibleType>();
testCustomTypeNotYetConvertible<QLineF, CustomConvertibleType>();
testCustomTypeNotYetConvertible<QChar, CustomConvertibleType>();
testCustomTypeNotYetConvertible<CustomConvertibleType, CustomConvertibleType2>();
}
void registerCustomTypeConversions()
{
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QString>(&CustomConvertibleType::convertOk<QString>)));
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, bool>(&CustomConvertibleType::convert<bool>)));
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, int>(&CustomConvertibleType::convertOk<int>)));
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, double>(&CustomConvertibleType::convert<double>)));
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, float>(&CustomConvertibleType::convertOk<float>)));
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QRect>(&CustomConvertibleType::convert<QRect>)));
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QRectF>(&CustomConvertibleType::convertOk<QRectF>)));
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QPoint>(convert<CustomConvertibleType,QPoint>)));
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QPointF>(&CustomConvertibleType::convertOk<QPointF>)));
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QSize>(&CustomConvertibleType::convert<QSize>)));
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QSizeF>(&CustomConvertibleType::convertOk<QSizeF>)));
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<bool, CustomConvertibleType>(ConvertFunctor<bool>())));
QVERIFY((QMetaType::registerConverter<int, CustomConvertibleType>(ConvertFunctor<int>())));
QVERIFY((QMetaType::registerConverter<double, CustomConvertibleType>(ConvertFunctor<double>())));
QVERIFY((QMetaType::registerConverter<float, CustomConvertibleType>(ConvertFunctor<float>())));
QVERIFY((QMetaType::registerConverter<QRect, CustomConvertibleType>(ConvertFunctor<QRect>())));
QVERIFY((QMetaType::registerConverter<QRectF, CustomConvertibleType>(ConvertFunctor<QRectF>())));
QVERIFY((QMetaType::registerConverter<QPoint, CustomConvertibleType>(ConvertFunctor<QPoint>())));
QVERIFY((QMetaType::registerConverter<QPointF, CustomConvertibleType>(ConvertFunctor<QPointF>())));
QVERIFY((QMetaType::registerConverter<QSize, CustomConvertibleType>(ConvertFunctor<QSize>())));
QVERIFY((QMetaType::registerConverter<QSizeF, CustomConvertibleType>(ConvertFunctor<QSizeF>())));
QVERIFY((QMetaType::registerConverter<QLine, CustomConvertibleType>(ConvertFunctor<QLine>())));
QVERIFY((QMetaType::registerConverter<QLineF, CustomConvertibleType>(ConvertFunctor<QLineF>())));
QVERIFY((QMetaType::registerConverter<QChar, CustomConvertibleType>(ConvertFunctor<QChar>())));
QVERIFY((QMetaType::registerConverter<CustomConvertibleType, CustomConvertibleType2>()));
QTest::ignoreMessage(QtWarningMsg, "Type conversion already registered from type CustomConvertibleType to type CustomConvertibleType2");
QVERIFY((!QMetaType::registerConverter<CustomConvertibleType, CustomConvertibleType2>()));
}
void tst_QMetaType::convertCustomType_data()
{
customTypeNotYetConvertible();
registerCustomTypeConversions();
QTest::addColumn<bool>("ok");
QTest::addColumn<QString>("testQString");
QTest::addColumn<bool>("testBool");
QTest::addColumn<int>("testInt");
QTest::addColumn<double>("testDouble");
QTest::addColumn<float>("testFloat");
QTest::addColumn<QRect>("testQRect");
QTest::addColumn<QRectF>("testQRectF");
QTest::addColumn<QPoint>("testQPoint");
QTest::addColumn<QPointF>("testQPointF");
QTest::addColumn<QSize>("testQSize");
QTest::addColumn<QSizeF>("testQSizeF");
QTest::addColumn<QLine>("testQLine");
QTest::addColumn<QLineF>("testQLineF");
QTest::addColumn<QChar>("testQChar");
QTest::addColumn<CustomConvertibleType>("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<QString>(), ok ? testQString : QString());
QVERIFY(CustomConvertibleType::s_value.canConvert<CustomConvertibleType>());
QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toString()), testQString);
QFETCH(bool, testBool);
CustomConvertibleType::s_value = testBool;
QCOMPARE(v.toBool(), testBool);
QCOMPARE(v.value<bool>(), testBool);
QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toBool()), testBool);
QFETCH(int, testInt);
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);
QFETCH(double, testDouble);
CustomConvertibleType::s_value = testDouble;
QCOMPARE(v.toDouble(), testDouble);
QCOMPARE(v.value<double>(), testDouble);
QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toDouble()), testDouble);
QFETCH(float, testFloat);
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);
QFETCH(QRect, testQRect);
CustomConvertibleType::s_value = testQRect;
QCOMPARE(v.toRect(), testQRect);
QCOMPARE(v.value<QRect>(), testQRect);
QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toRect()), testQRect);
QFETCH(QRectF, testQRectF);
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);
QFETCH(QPoint, testQPoint);
CustomConvertibleType::s_value = testQPoint;
QCOMPARE(v.toPoint(), testQPoint);
QCOMPARE(v.value<QPoint>(), testQPoint);
QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toPoint()), testQPoint);
QFETCH(QPointF, testQPointF);
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);
QFETCH(QSize, testQSize);
CustomConvertibleType::s_value = testQSize;
QCOMPARE(v.toSize(), testQSize);
QCOMPARE(v.value<QSize>(), testQSize);
QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toSize()), testQSize);
QFETCH(QSizeF, testQSizeF);
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);
QFETCH(QLine, testQLine);
CustomConvertibleType::s_value = testQLine;
QCOMPARE(v.toLine(), testQLine);
QCOMPARE(v.value<QLine>(), testQLine);
QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toLine()), testQLine);
QFETCH(QLineF, testQLineF);
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);
QFETCH(QChar, testQChar);
CustomConvertibleType::s_value = testQChar;
QCOMPARE(v.toChar(), testQChar);
QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toChar()), testQChar);
QFETCH(CustomConvertibleType, testCustom);
v = QVariant::fromValue(testCustom);
QVERIFY(v.canConvert(::qMetaTypeId<CustomConvertibleType2>()));
QCOMPARE(v.value<CustomConvertibleType2>().m_foo, testCustom.m_foo);
}
void tst_QMetaType::compareCustomType_data()
{
QMetaType::registerComparators<CustomConvertibleType>();
QTest::addColumn<QVariantList>("unsorted");
QTest::addColumn<QVariantList>("sorted");
QTest::newRow("int") << (QVariantList() << 37 << 458 << 1 << 243 << -4 << 383)
<< (QVariantList() << -4 << 1 << 37 << 243 << 383 << 458);
QTest::newRow("dobule") << (QVariantList() << 4934.93 << 0.0 << 302.39 << -39.0)
<< (QVariantList() << -39.0 << 0.0 << 302.39 << 4934.93);
QTest::newRow("QString") << (QVariantList() << "Hello" << "World" << "this" << "is" << "a" << "test")
<< (QVariantList() << "a" << "Hello" << "is" << "test" << "this" << "World");
QTest::newRow("QTime") << (QVariantList() << QTime(14, 39) << QTime(0, 0) << QTime(18, 18) << QTime(9, 27))
<< (QVariantList() << QTime(0, 0) << QTime(9, 27) << QTime(14, 39) << QTime(18, 18));
QTest::newRow("QDate") << (QVariantList() << QDate(2013, 3, 23) << QDate(1900, 12, 1) << QDate(2001, 2, 2) << QDate(1982, 12, 16))
<< (QVariantList() << QDate(1900, 12, 1) << QDate(1982, 12, 16) << QDate(2001, 2, 2) << QDate(2013, 3, 23));
QTest::newRow("mixed") << (QVariantList() << "Hello" << "World" << QChar('a') << 38 << QChar('z') << -39 << 4.6)
<< (QVariantList() << -39 << 4.6 << 38 << QChar('a') << "Hello" << "World" << QChar('z'));
QTest::newRow("custom") << (QVariantList() << QVariant::fromValue(CustomConvertibleType(1)) << QVariant::fromValue(CustomConvertibleType(100)) << QVariant::fromValue(CustomConvertibleType(50)))
<< (QVariantList() << QVariant::fromValue(CustomConvertibleType(1)) << QVariant::fromValue(CustomConvertibleType(50)) << QVariant::fromValue(CustomConvertibleType(100)));
}
void tst_QMetaType::compareCustomType()
{
QFETCH(QVariantList, unsorted);
QFETCH(QVariantList, sorted);
std::sort(unsorted.begin(), unsorted.end());
QCOMPARE(unsorted, sorted);
}
void tst_QMetaType::compareCustomEqualOnlyType()
{
int metaTypeId = qRegisterMetaType<CustomEqualsOnlyType>();
QMetaType::registerEqualsComparator<CustomEqualsOnlyType>();
int result;
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);
// compare always fails
QVERIFY(!(variant50 < variant50));
QVERIFY(!(variant50 < variant100));
QVERIFY(!(variant100 < variant50));
// check QMetaType::compare works/doesn't crash for equals only comparators
bool wasSuccess = QMetaType::compare(variant50.constData(), variant50.constData(),
metaTypeId, &result);
QCOMPARE(result, 0);
QVERIFY(wasSuccess);
wasSuccess = QMetaType::compare(variant100.constData(), variant100x.constData(),
metaTypeId, &result);
QCOMPARE(result, 0);
QVERIFY(wasSuccess);
wasSuccess = QMetaType::compare(variant50.constData(), variant100.constData(),
metaTypeId, &result);
QVERIFY(!wasSuccess);
// check QMetaType::equals works for equals only comparator
wasSuccess = QMetaType::equals(variant50.constData(), variant50.constData(),
metaTypeId, &result);
QCOMPARE(result, 0);
QVERIFY(wasSuccess);
wasSuccess = QMetaType::equals(variant100.constData(), variant100.constData(),
metaTypeId, &result);
QCOMPARE(result, 0);
QVERIFY(wasSuccess);
wasSuccess = QMetaType::equals(variant100x.constData(), variant100x.constData(),
metaTypeId, &result);
QCOMPARE(result, 0);
QVERIFY(wasSuccess);
wasSuccess = QMetaType::equals(variant100.constData(), variant100x.constData(),
metaTypeId, &result);
QCOMPARE(result, 0);
QVERIFY(wasSuccess);
wasSuccess = QMetaType::equals(variant50.constData(), variant100.constData(),
metaTypeId, &result);
QCOMPARE(result, -1);
QVERIFY(wasSuccess);
wasSuccess = QMetaType::equals(variant50.constData(), variant100x.constData(),
metaTypeId, &result);
QCOMPARE(result, -1);
QVERIFY(wasSuccess);
//check QMetaType::equals for type w/o equals comparator being registered
CustomMovable movable1;
CustomMovable movable2;
wasSuccess = QMetaType::equals(&movable1, &movable2,
qRegisterMetaType<CustomMovable>(), &result);
QVERIFY(!wasSuccess);
}
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());
}
static QString expectedMessage;
};
QString MessageHandlerCustom::expectedMessage;
void tst_QMetaType::customDebugStream()
{
MessageHandlerCustom handler(::qMetaTypeId<CustomDebugStreamableType>());
QVariant v1 = QVariant::fromValue(CustomDebugStreamableType());
handler.expectedMessage = "QVariant(CustomDebugStreamableType, )";
qDebug() << v1;
QMetaType::registerConverter<CustomDebugStreamableType, QString>(&CustomDebugStreamableType::toString);
handler.expectedMessage = "QVariant(CustomDebugStreamableType, \"test\")";
qDebug() << v1;
QMetaType::registerDebugStreamOperator<CustomDebugStreamableType>();
handler.expectedMessage = "QVariant(CustomDebugStreamableType, string-content)";
qDebug() << v1;
}
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);
}
// 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);
QTEST_MAIN(tst_QMetaType)
#include "tst_qmetatype.moc"