1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtCore>
31#include <QtTest/QtTest>
32#include <QtCore/private/qmetaobjectbuilder_p.h>
33
34#include "tst_qmetatype.h"
35#include "tst_qvariant_common.h"
36
37#ifdef Q_OS_LINUX
38# include <pthread.h>
39#endif
40
41#include <algorithm>
42#include <memory>
43
44// mingw gcc 4.8 also takes way too long, letting the CI system abort the test
45#if defined(__MINGW32__)
46# define TST_QMETATYPE_BROKEN_COMPILER
47#endif
48
49Q_DECLARE_METATYPE(QMetaType::Type)
50
51class tst_QMetaType: public QObject
52{
53 Q_OBJECT
54 Q_PROPERTY(QList<QVariant> prop READ prop WRITE setProp)
55
56public:
57 struct GadgetPropertyType {
58 QByteArray type;
59 QByteArray name;
60 QVariant testData;
61 };
62
63 tst_QMetaType() { propList << 42 << "Hello"; }
64
65 QList<QVariant> prop() const { return propList; }
66 void setProp(const QList<QVariant> &list) { propList = list; }
67
68private:
69 void registerGadget(const char * name, const QVector<GadgetPropertyType> &gadgetProperties);
70 QList<QVariant> propList;
71
72private slots:
73 void defined();
74 void threadSafety();
75 void namespaces();
76 void id();
77 void qMetaTypeId();
78 void properties();
79 void normalizedTypes();
80 void typeName_data();
81 void typeName();
82 void type_data();
83 void type();
84 void type_fromSubString_data();
85 void type_fromSubString();
86 void create_data();
87 void create();
88 void createCopy_data();
89 void createCopy();
90 void sizeOf_data();
91 void sizeOf();
92 void sizeOfStaticLess_data();
93 void sizeOfStaticLess();
94 void flags_data();
95 void flags();
96 void flagsStaticLess_data();
97 void flagsStaticLess();
98 void flagsBinaryCompatibility5_0_data();
99 void flagsBinaryCompatibility5_0();
100 void construct_data();
101 void construct();
102 void typedConstruct();
103 void constructCopy_data();
104 void constructCopy();
105 void typedefs();
106 void registerType();
107 void isRegistered_data();
108 void isRegistered();
109 void isRegisteredStaticLess_data();
110 void isRegisteredStaticLess();
111 void isEnum();
112 void registerStreamBuiltin();
113 void automaticTemplateRegistration();
114 void saveAndLoadBuiltin_data();
115 void saveAndLoadBuiltin();
116 void saveAndLoadCustom();
117 void metaObject_data();
118 void metaObject();
119 void constexprMetaTypeIds();
120 void constRefs();
121 void convertCustomType_data();
122 void convertCustomType();
123 void compareCustomType_data();
124 void compareCustomType();
125 void compareCustomEqualOnlyType();
126 void customDebugStream();
127 void unknownType();
128 void fromType();
129};
130
131struct BaseGenericType
132{
133 int m_typeId = -1;
134 virtual void *constructor(int typeId, void *where, const void *copy) = 0;
135 virtual void staticMetacallFunction(QMetaObject::Call _c, int _id, void **_a) = 0;
136 virtual void saveOperator(QDataStream & out) const = 0;
137 virtual void loadOperator(QDataStream &in) = 0;
138 virtual ~BaseGenericType() {}
139};
140
141struct GenericGadgetType : BaseGenericType
142{
143 void *constructor(int typeId, void *where, const void *copy) override
144 {
145 GenericGadgetType *ret = where ? new(where) GenericGadgetType : new GenericGadgetType;
146 ret->m_typeId = typeId;
147 if (copy) {
148 Q_ASSERT(ret->m_typeId == reinterpret_cast<const GenericGadgetType*>(copy)->m_typeId);
149 *ret = *reinterpret_cast<const GenericGadgetType*>(copy);
150 } else {
151 ret->properties = properties;
152 }
153 return ret;
154 }
155
156 void staticMetacallFunction(QMetaObject::Call _c, int _id, void **_a) override
157 {
158 if (_c == QMetaObject::ReadProperty) {
159 if (_id < properties.size()) {
160 const auto &prop = properties.at(i: _id);
161 QMetaType::destruct(type: int(prop.userType()), where: _a[0]);
162 QMetaType::construct(type: int(prop.userType()), where: _a[0], copy: prop.constData());
163 }
164 } else if (_c == QMetaObject::WriteProperty) {
165 if (_id < properties.size()) {
166 auto & prop = properties[_id];
167 prop = QVariant(prop.userType(), _a[0]);
168 }
169 }
170 }
171
172 void saveOperator(QDataStream & out) const override
173 {
174 for (const auto &prop : properties)
175 out << prop;
176 }
177
178 void loadOperator(QDataStream &in) override
179 {
180 for (auto &prop : properties)
181 in >> prop;
182 }
183 QVector<QVariant> properties;
184};
185
186struct GenericPODType : BaseGenericType
187{
188 // BaseGenericType interface
189 void *constructor(int typeId, void *where, const void *copy) override
190 {
191 GenericPODType *ret = where ? new(where) GenericPODType : new GenericPODType;
192 ret->m_typeId = typeId;
193 if (copy) {
194 Q_ASSERT(ret->m_typeId == reinterpret_cast<const GenericPODType*>(copy)->m_typeId);
195 *ret = *reinterpret_cast<const GenericPODType*>(copy);
196 } else {
197 ret->podData = podData;
198 }
199 return ret;
200 }
201
202 void staticMetacallFunction(QMetaObject::Call _c, int _id, void **_a) override
203 {
204 Q_UNUSED(_c);
205 Q_UNUSED(_id);
206 Q_UNUSED(_a);
207 Q_ASSERT(false);
208 }
209
210 void saveOperator(QDataStream &out) const override
211 {
212 out << podData;
213 }
214 void loadOperator(QDataStream &in) override
215 {
216 in >> podData;
217 }
218 QByteArray podData;
219};
220
221using RegisteredType = QPair<std::shared_ptr<BaseGenericType>, std::shared_ptr<QMetaObject>>;
222static QHash<int, RegisteredType> s_managedTypes;
223
224static void GadgetsStaticMetacallFunction(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
225{
226 reinterpret_cast<BaseGenericType*>(_o)->staticMetacallFunction(_c, _id, _a);
227}
228
229static void GadgetTypedDestructor(int typeId, void *ptr)
230{
231 QCOMPARE(typeId, reinterpret_cast<BaseGenericType*>(ptr)->m_typeId);
232 reinterpret_cast<BaseGenericType*>(ptr)->~BaseGenericType();
233}
234
235static void *GadgetTypedConstructor(int type, void *where, const void *copy)
236{
237 auto it = s_managedTypes.find(key: type);
238 if (it == s_managedTypes.end())
239 return nullptr; // crash the test
240 return it->first->constructor(typeId: type, where, copy);
241}
242
243static void GadgetSaveOperator(QDataStream & out, const void *data)
244{
245 reinterpret_cast<const BaseGenericType *>(data)->saveOperator(out);
246}
247
248static void GadgetLoadOperator(QDataStream &in, void *data)
249{
250 reinterpret_cast<BaseGenericType *>(data)->loadOperator(in);
251}
252
253struct Foo { int i; };
254
255
256class CustomQObject : public QObject
257{
258 Q_OBJECT
259public:
260 CustomQObject(QObject *parent = 0)
261 : QObject(parent)
262 {
263 }
264 enum CustomQEnum { Val1, Val2 };
265 Q_ENUM(CustomQEnum)
266};
267class CustomGadget {
268 Q_GADGET
269};
270class CustomGadget_NonDefaultConstructible {
271 Q_GADGET
272public:
273 CustomGadget_NonDefaultConstructible(int) {};
274};
275
276class CustomNonQObject {};
277class GadgetDerived : public CustomGadget {};
278
279// cannot use Q_GADGET due to moc limitations but wants to behave like
280// a Q_GADGET in Qml land
281template<typename T>
282class GadgetDerivedAndTyped : public CustomGadget {};
283
284Q_DECLARE_METATYPE(GadgetDerivedAndTyped<int>)
285Q_DECLARE_METATYPE(GadgetDerivedAndTyped<int>*)
286
287void tst_QMetaType::registerGadget(const char *name, const QVector<GadgetPropertyType> &gadgetProperties)
288{
289 QMetaObjectBuilder gadgetBuilder;
290 gadgetBuilder.setClassName(name);
291 QMetaObjectBuilder::MetaObjectFlags metaObjectflags = QMetaObjectBuilder::DynamicMetaObject | QMetaObjectBuilder::PropertyAccessInStaticMetaCall;
292 gadgetBuilder.setFlags(metaObjectflags);
293 auto dynamicGadgetProperties = std::make_shared<GenericGadgetType>();
294 for (const auto &prop : gadgetProperties) {
295 int propertyType = QMetaType::type(typeName: prop.type);
296 dynamicGadgetProperties->properties.push_back(t: QVariant(QVariant::Type(propertyType)));
297 auto dynamicPropery = gadgetBuilder.addProperty(name: prop.name, type: prop.type);
298 dynamicPropery.setWritable(true);
299 dynamicPropery.setReadable(true);
300 }
301 auto meta = gadgetBuilder.toMetaObject();
302 meta->d.static_metacall = &GadgetsStaticMetacallFunction;
303 meta->d.superdata = nullptr;
304 const auto flags = QMetaType::WasDeclaredAsMetaType | QMetaType::IsGadget | QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
305 int gadgetTypeId = QMetaType::registerType(typeName: name,
306 destructor: &GadgetTypedDestructor,
307 constructor: &GadgetTypedConstructor,
308 size: sizeof(GenericGadgetType),
309 flags, metaObject: meta);
310 QVERIFY(gadgetTypeId > 0);
311 QMetaType::registerStreamOperators(type: gadgetTypeId, saveOp: &GadgetSaveOperator, loadOp: &GadgetLoadOperator);
312 s_managedTypes[gadgetTypeId] = qMakePair(x: dynamicGadgetProperties, y: std::shared_ptr<QMetaObject>{meta, [](QMetaObject *ptr){ ::free(ptr: ptr); }});
313}
314
315void tst_QMetaType::defined()
316{
317 QCOMPARE(int(QMetaTypeId2<QString>::Defined), 1);
318 QCOMPARE(int(QMetaTypeId2<Foo>::Defined), 0);
319 QCOMPARE(int(QMetaTypeId2<void*>::Defined), 1);
320 QCOMPARE(int(QMetaTypeId2<int*>::Defined), 0);
321 QCOMPARE(int(QMetaTypeId2<CustomQObject::CustomQEnum>::Defined), 1);
322 QCOMPARE(int(QMetaTypeId2<CustomGadget>::Defined), 1);
323 QCOMPARE(int(QMetaTypeId2<CustomGadget*>::Defined), 1);
324 QVERIFY(!QMetaTypeId2<GadgetDerived>::Defined);
325 QVERIFY(!QMetaTypeId2<GadgetDerived*>::Defined);
326 QVERIFY(int(QMetaTypeId2<CustomQObject*>::Defined));
327 QVERIFY(!QMetaTypeId2<CustomQObject>::Defined);
328 QVERIFY(!QMetaTypeId2<CustomNonQObject>::Defined);
329 QVERIFY(!QMetaTypeId2<CustomNonQObject*>::Defined);
330 QVERIFY(!QMetaTypeId2<CustomGadget_NonDefaultConstructible>::Defined);
331
332 // registered with Q_DECLARE_METATYPE
333 QVERIFY(QMetaTypeId2<GadgetDerivedAndTyped<int>>::Defined);
334 QVERIFY(QMetaTypeId2<GadgetDerivedAndTyped<int>*>::Defined);
335}
336
337struct Bar
338{
339 Bar()
340 {
341 // check re-entrancy
342 if (!QMetaType::isRegistered(type: qRegisterMetaType<Foo>(typeName: "Foo"))) {
343 qWarning(msg: "%s: re-entrancy test failed", Q_FUNC_INFO);
344 ++failureCount;
345 }
346 }
347 ~Bar() {}
348
349public:
350 static int failureCount;
351};
352
353int Bar::failureCount = 0;
354
355class MetaTypeTorturer: public QThread
356{
357 Q_OBJECT
358protected:
359 void run()
360 {
361 Bar space[1];
362 space[0].~Bar();
363
364 const QByteArray postFix = '_'
365 + QByteArray::number(reinterpret_cast<quintptr>(QThread::currentThreadId()));
366
367 for (int i = 0; i < 1000; ++i) {
368 const QByteArray name = "Bar" + QByteArray::number(i) + postFix;
369 const char *nm = name.constData();
370 int tp = qRegisterMetaType<Bar>(typeName: nm);
371#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
372 pthread_yield();
373#endif
374 QMetaType info(tp);
375 if (!info.isValid()) {
376 ++failureCount;
377 qWarning() << "Wrong typeInfo returned for" << tp;
378 }
379 if (!info.isRegistered()) {
380 ++failureCount;
381 qWarning() << name << "is not a registered metatype";
382 }
383 if (QMetaType::typeFlags(type: tp) != (QMetaType::NeedsConstruction | QMetaType::NeedsDestruction)) {
384 ++failureCount;
385 qWarning() << "Wrong typeInfo returned for" << tp;
386 }
387 if (!QMetaType::isRegistered(type: tp)) {
388 ++failureCount;
389 qWarning() << name << "is not a registered metatype";
390 }
391 if (QMetaType::type(typeName: nm) != tp) {
392 ++failureCount;
393 qWarning() << "Wrong metatype returned for" << name;
394 }
395 if (QMetaType::typeName(type: tp) != name) {
396 ++failureCount;
397 qWarning() << "Wrong typeName returned for" << tp;
398 }
399 void *buf1 = QMetaType::create(type: tp, copy: 0);
400 void *buf2 = QMetaType::create(type: tp, copy: buf1);
401 void *buf3 = info.create(type: tp, copy: 0);
402 void *buf4 = info.create(type: tp, copy: buf1);
403
404 QMetaType::construct(type: tp, where: space, copy: 0);
405 QMetaType::destruct(type: tp, where: space);
406 QMetaType::construct(type: tp, where: space, copy: buf1);
407 QMetaType::destruct(type: tp, where: space);
408
409 info.construct(where: space, copy: 0);
410 info.destruct(data: space);
411 info.construct(where: space, copy: buf1);
412 info.destruct(data: space);
413
414 if (!buf1) {
415 ++failureCount;
416 qWarning() << "Null buffer returned by QMetaType::create(tp, 0)";
417 }
418 if (!buf2) {
419 ++failureCount;
420 qWarning() << "Null buffer returned by QMetaType::create(tp, buf)";
421 }
422 if (!buf3) {
423 ++failureCount;
424 qWarning() << "Null buffer returned by info.create(tp, 0)";
425 }
426 if (!buf4) {
427 ++failureCount;
428 qWarning() << "Null buffer returned by infocreate(tp, buf)";
429 }
430 QMetaType::destroy(type: tp, data: buf1);
431 QMetaType::destroy(type: tp, data: buf2);
432 info.destroy(data: buf3);
433 info.destroy(data: buf4);
434 }
435 new (space) Bar;
436 }
437public:
438 MetaTypeTorturer() : failureCount(0) { }
439 int failureCount;
440};
441
442void tst_QMetaType::threadSafety()
443{
444 MetaTypeTorturer t1;
445 MetaTypeTorturer t2;
446 MetaTypeTorturer t3;
447
448 t1.start();
449 t2.start();
450 t3.start();
451
452 QVERIFY(t1.wait());
453 QVERIFY(t2.wait());
454 QVERIFY(t3.wait());
455
456 QCOMPARE(t1.failureCount, 0);
457 QCOMPARE(t2.failureCount, 0);
458 QCOMPARE(t3.failureCount, 0);
459 QCOMPARE(Bar::failureCount, 0);
460}
461
462namespace TestSpace
463{
464 struct Foo { double d; public: ~Foo() {} };
465 struct QungTfu {};
466}
467Q_DECLARE_METATYPE(TestSpace::Foo)
468
469#define ADD_TESTSPACE(F) TestSpace::F
470Q_DECLARE_METATYPE(ADD_TESTSPACE(QungTfu))
471
472void tst_QMetaType::namespaces()
473{
474 TestSpace::Foo nf = { .d: 11.12 };
475 QVariant v = QVariant::fromValue(value: nf);
476 QCOMPARE(qvariant_cast<TestSpace::Foo>(v).d, 11.12);
477
478 int qungTfuId = qRegisterMetaType<ADD_TESTSPACE(QungTfu)>();
479 QCOMPARE(QMetaType::typeName(qungTfuId), "TestSpace::QungTfu");
480}
481
482void tst_QMetaType::id()
483{
484 QCOMPARE(QMetaType(QMetaType::QString).id(), QMetaType::QString);
485 QCOMPARE(QMetaType(::qMetaTypeId<TestSpace::Foo>()).id(), ::qMetaTypeId<TestSpace::Foo>());
486 QCOMPARE(QMetaType::fromType<TestSpace::Foo>().id(), ::qMetaTypeId<TestSpace::Foo>());
487}
488
489void tst_QMetaType::qMetaTypeId()
490{
491 QCOMPARE(::qMetaTypeId<QString>(), int(QMetaType::QString));
492 QCOMPARE(::qMetaTypeId<int>(), int(QMetaType::Int));
493 QCOMPARE(::qMetaTypeId<TestSpace::Foo>(), QMetaType::type("TestSpace::Foo"));
494
495 QCOMPARE(::qMetaTypeId<char>(), QMetaType::type("char"));
496 QCOMPARE(::qMetaTypeId<uchar>(), QMetaType::type("unsigned char"));
497 QCOMPARE(::qMetaTypeId<signed char>(), QMetaType::type("signed char"));
498 QVERIFY(::qMetaTypeId<signed char>() != ::qMetaTypeId<char>());
499 QCOMPARE(::qMetaTypeId<qint8>(), QMetaType::type("qint8"));
500}
501
502void tst_QMetaType::properties()
503{
504 qRegisterMetaType<QList<QVariant> >(typeName: "QList<QVariant>");
505
506 QVariant v = property(name: "prop");
507
508 QCOMPARE(v.typeName(), "QVariantList");
509
510 QList<QVariant> values = v.toList();
511 QCOMPARE(values.count(), 2);
512 QCOMPARE(values.at(0).toInt(), 42);
513
514 values << 43 << "world";
515
516 QVERIFY(setProperty("prop", values));
517 v = property(name: "prop");
518 QCOMPARE(v.toList().count(), 4);
519}
520
521template <typename T>
522struct Whity { T t; Whity() {} };
523
524Q_DECLARE_METATYPE( Whity < int > )
525Q_DECLARE_METATYPE(Whity<double>)
526
527#if !defined(Q_CC_CLANG) && defined(Q_CC_GNU) && Q_CC_GNU < 501
528QT_BEGIN_NAMESPACE
529Q_DECLARE_TYPEINFO(Whity<double>, Q_MOVABLE_TYPE);
530QT_END_NAMESPACE
531#endif
532
533void tst_QMetaType::normalizedTypes()
534{
535 int WhityIntId = ::qMetaTypeId<Whity<int> >();
536 int WhityDoubleId = ::qMetaTypeId<Whity<double> >();
537
538 QCOMPARE(QMetaType::type("Whity<int>"), WhityIntId);
539 QCOMPARE(QMetaType::type(" Whity < int > "), WhityIntId);
540 QCOMPARE(QMetaType::type("Whity<int >"), WhityIntId);
541
542 QCOMPARE(QMetaType::type("Whity<double>"), WhityDoubleId);
543 QCOMPARE(QMetaType::type(" Whity< double > "), WhityDoubleId);
544 QCOMPARE(QMetaType::type("Whity<double >"), WhityDoubleId);
545
546 QCOMPARE(qRegisterMetaType<Whity<int> >(" Whity < int > "), WhityIntId);
547 QCOMPARE(qRegisterMetaType<Whity<int> >("Whity<int>"), WhityIntId);
548 QCOMPARE(qRegisterMetaType<Whity<int> >("Whity<int > "), WhityIntId);
549
550 QCOMPARE(qRegisterMetaType<Whity<double> >(" Whity < double > "), WhityDoubleId);
551 QCOMPARE(qRegisterMetaType<Whity<double> >("Whity<double>"), WhityDoubleId);
552 QCOMPARE(qRegisterMetaType<Whity<double> >("Whity<double > "), WhityDoubleId);
553}
554
555#define TYPENAME_DATA(MetaTypeName, MetaTypeId, RealType)\
556 QTest::newRow(#RealType) << int(QMetaType::MetaTypeName) << #RealType;
557
558void tst_QMetaType::typeName_data()
559{
560 QTest::addColumn<int>(name: "aType");
561 QTest::addColumn<QString>(name: "aTypeName");
562
563 QT_FOR_EACH_STATIC_TYPE(TYPENAME_DATA)
564 QTest::newRow(dataTag: "QMetaType::UnknownType") << int(QMetaType::UnknownType) << static_cast<const char*>(0);
565 QTest::newRow(dataTag: "QMetaType::User-1") << (int(QMetaType::User) - 1) << static_cast<const char *>(nullptr);
566 QTest::newRow(dataTag: "QMetaType::FirstWidgetsType-1") << (int(QMetaType::FirstWidgetsType) - 1) << static_cast<const char *>(nullptr);
567
568 QTest::newRow(dataTag: "Whity<double>") << ::qMetaTypeId<Whity<double> >() << QString::fromLatin1(str: "Whity<double>");
569 QTest::newRow(dataTag: "Whity<int>") << ::qMetaTypeId<Whity<int> >() << QString::fromLatin1(str: "Whity<int>");
570 QTest::newRow(dataTag: "Testspace::Foo") << ::qMetaTypeId<TestSpace::Foo>() << QString::fromLatin1(str: "TestSpace::Foo");
571
572 QTest::newRow(dataTag: "-1") << -1 << QString();
573 QTest::newRow(dataTag: "-124125534") << -124125534 << QString();
574 QTest::newRow(dataTag: "124125534") << 124125534 << QString();
575
576 // automatic registration
577 QTest::newRow(dataTag: "QList<int>") << ::qMetaTypeId<QList<int> >() << QString::fromLatin1(str: "QList<int>");
578 QTest::newRow(dataTag: "QHash<int,int>") << ::qMetaTypeId<QHash<int, int> >() << QString::fromLatin1(str: "QHash<int,int>");
579 QTest::newRow(dataTag: "QMap<int,int>") << ::qMetaTypeId<QMap<int, int> >() << QString::fromLatin1(str: "QMap<int,int>");
580 QTest::newRow(dataTag: "QVector<QList<int>>") << ::qMetaTypeId<QVector<QList<int> > >() << QString::fromLatin1(str: "QVector<QList<int> >");
581 QTest::newRow(dataTag: "QVector<QMap<int,int>>") << ::qMetaTypeId<QVector<QMap<int, int> > >() << QString::fromLatin1(str: "QVector<QMap<int,int> >");
582
583 QTest::newRow(dataTag: "CustomQObject*") << ::qMetaTypeId<CustomQObject*>() << QString::fromLatin1(str: "CustomQObject*");
584 QTest::newRow(dataTag: "CustomGadget") << ::qMetaTypeId<CustomGadget>() << QString::fromLatin1(str: "CustomGadget");
585 QTest::newRow(dataTag: "CustomGadget*") << ::qMetaTypeId<CustomGadget*>() << QString::fromLatin1(str: "CustomGadget*");
586 QTest::newRow(dataTag: "CustomQObject::CustomQEnum") << ::qMetaTypeId<CustomQObject::CustomQEnum>() << QString::fromLatin1(str: "CustomQObject::CustomQEnum");
587 QTest::newRow(dataTag: "Qt::ArrowType") << ::qMetaTypeId<Qt::ArrowType>() << QString::fromLatin1(str: "Qt::ArrowType");
588
589 // template instance class derived from Q_GADGET enabled class
590 QTest::newRow(dataTag: "GadgetDerivedAndTyped<int>") << ::qMetaTypeId<GadgetDerivedAndTyped<int>>() << QString::fromLatin1(str: "GadgetDerivedAndTyped<int>");
591 QTest::newRow(dataTag: "GadgetDerivedAndTyped<int>*") << ::qMetaTypeId<GadgetDerivedAndTyped<int>*>() << QString::fromLatin1(str: "GadgetDerivedAndTyped<int>*");
592}
593
594void tst_QMetaType::typeName()
595{
596 QFETCH(int, aType);
597 QFETCH(QString, aTypeName);
598
599 const char *rawname = QMetaType::typeName(type: aType);
600 QString name = QString::fromLatin1(str: rawname);
601
602 QCOMPARE(name, aTypeName);
603 QCOMPARE(name.toLatin1(), QMetaObject::normalizedType(name.toLatin1().constData()));
604 QCOMPARE(rawname == nullptr, aTypeName.isNull());
605
606 QMetaType mt(aType);
607 if (mt.isValid()) { // Gui type are not valid
608 QCOMPARE(QString::fromLatin1(QMetaType(aType).name()), aTypeName);
609 }
610
611}
612
613void tst_QMetaType::type_data()
614{
615 QTest::addColumn<int>(name: "aType");
616 QTest::addColumn<QByteArray>(name: "aTypeName");
617
618#define TST_QMETATYPE_TYPE_DATA(MetaTypeName, MetaTypeId, RealType)\
619 QTest::newRow(#RealType) << int(QMetaType::MetaTypeName) << QByteArray( #RealType );
620#define TST_QMETATYPE_TYPE_DATA_ALIAS(MetaTypeName, MetaTypeId, AliasType, RealTypeString)\
621 QTest::newRow(RealTypeString) << int(QMetaType::MetaTypeName) << QByteArray( #AliasType );
622
623 QTest::newRow(dataTag: "empty") << int(QMetaType::UnknownType) << QByteArray();
624
625 QT_FOR_EACH_STATIC_TYPE(TST_QMETATYPE_TYPE_DATA)
626 QT_FOR_EACH_STATIC_ALIAS_TYPE(TST_QMETATYPE_TYPE_DATA_ALIAS)
627
628#undef TST_QMETATYPE_TYPE_DATA
629#undef TST_METATYPE_TYPE_DATA_ALIAS
630}
631
632void tst_QMetaType::type()
633{
634 QFETCH(int, aType);
635 QFETCH(QByteArray, aTypeName);
636
637 // QMetaType::type(QByteArray)
638 QCOMPARE(QMetaType::type(aTypeName), aType);
639 // QMetaType::type(const char *)
640 QCOMPARE(QMetaType::type(aTypeName.constData()), aType);
641}
642
643void tst_QMetaType::type_fromSubString_data()
644{
645 QTest::addColumn<int>(name: "offset");
646 QTest::addColumn<int>(name: "size");
647 QTest::addColumn<int>(name: "expectedType");
648
649 // The test string is defined in the test function below
650 QTest::newRow(dataTag: "int") << 0 << 3 << int(QMetaType::Int);
651 QTest::newRow(dataTag: "boo") << 3 << 3 << 0;
652 QTest::newRow(dataTag: "bool") << 3 << 4 << int(QMetaType::Bool);
653 QTest::newRow(dataTag: "intbool") << 0 << 7 << 0;
654 QTest::newRow(dataTag: "QMetaType::Type") << 7 << 15 << ::qMetaTypeId<QMetaType::Type>();
655 QTest::newRow(dataTag: "double") << 22 << 6 << int(QMetaType::Double);
656}
657
658void tst_QMetaType::type_fromSubString()
659{
660 static const char *types = "intboolQMetaType::Typedoublexxx";
661 QFETCH(int, offset);
662 QFETCH(int, size);
663 QFETCH(int, expectedType);
664 QByteArray ba = QByteArray::fromRawData(types + offset, size);
665 QCOMPARE(QMetaType::type(ba), expectedType);
666}
667
668namespace {
669 template <typename T>
670 struct static_assert_trigger {
671 Q_STATIC_ASSERT(( QMetaTypeId2<T>::IsBuiltIn ));
672 enum { value = true };
673 };
674}
675
676#define CHECK_BUILTIN(MetaTypeName, MetaTypeId, RealType) static_assert_trigger< RealType >::value &&
677Q_STATIC_ASSERT(( FOR_EACH_CORE_METATYPE(CHECK_BUILTIN) true ));
678#undef CHECK_BUILTIN
679Q_STATIC_ASSERT(( QMetaTypeId2<QList<QVariant> >::IsBuiltIn));
680Q_STATIC_ASSERT(( QMetaTypeId2<QMap<QString,QVariant> >::IsBuiltIn));
681Q_STATIC_ASSERT(( QMetaTypeId2<QObject*>::IsBuiltIn));
682Q_STATIC_ASSERT((!QMetaTypeId2<tst_QMetaType*>::IsBuiltIn)); // QObject subclass
683Q_STATIC_ASSERT((!QMetaTypeId2<QList<int> >::IsBuiltIn));
684Q_STATIC_ASSERT((!QMetaTypeId2<QMap<int,int> >::IsBuiltIn));
685Q_STATIC_ASSERT((!QMetaTypeId2<QMetaType::Type>::IsBuiltIn));
686
687void tst_QMetaType::create_data()
688{
689 QTest::addColumn<int>(name: "type");
690#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
691 QTest::newRow(QMetaType::typeName(QMetaType::MetaTypeName)) << int(QMetaType::MetaTypeName);
692FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW)
693#undef ADD_METATYPE_TEST_ROW
694}
695
696template<int ID>
697static void testCreateHelper()
698{
699 typedef typename MetaEnumToType<ID>::Type Type;
700 QMetaType info(ID);
701 void *actual1 = QMetaType::create(type: ID);
702 void *actual2 = info.create();
703 if (DefaultValueTraits<ID>::IsInitialized) {
704 Type *expected = DefaultValueFactory<ID>::create();
705 QCOMPARE(*static_cast<Type *>(actual1), *expected);
706 QCOMPARE(*static_cast<Type *>(actual2), *expected);
707 delete expected;
708 }
709 QMetaType::destroy(type: ID, data: actual1);
710 info.destroy(data: actual2);
711}
712
713template<>
714void testCreateHelper<QMetaType::Void>()
715{
716 void *actual = QMetaType::create(type: QMetaType::Void);
717 if (DefaultValueTraits<QMetaType::Void>::IsInitialized) {
718 QVERIFY(DefaultValueFactory<QMetaType::Void>::create());
719 }
720 QMetaType::destroy(type: QMetaType::Void, data: actual);
721}
722
723
724typedef void (*TypeTestFunction)();
725
726void tst_QMetaType::create()
727{
728 struct TypeTestFunctionGetter
729 {
730 static TypeTestFunction get(int type)
731 {
732 switch (type) {
733#define RETURN_CREATE_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
734 case QMetaType::MetaTypeName: \
735 return testCreateHelper<QMetaType::MetaTypeName>;
736FOR_EACH_CORE_METATYPE(RETURN_CREATE_FUNCTION)
737#undef RETURN_CREATE_FUNCTION
738 }
739 return 0;
740 }
741 };
742
743 QFETCH(int, type);
744 TypeTestFunctionGetter::get(type)();
745}
746
747template<int ID>
748static void testCreateCopyHelper()
749{
750 typedef typename MetaEnumToType<ID>::Type Type;
751 Type *expected = TestValueFactory<ID>::create();
752 QMetaType info(ID);
753 void *actual1 = QMetaType::create(ID, expected);
754 void *actual2 = info.create(expected);
755 QCOMPARE(*static_cast<Type *>(actual1), *expected);
756 QCOMPARE(*static_cast<Type *>(actual2), *expected);
757 QMetaType::destroy(type: ID, data: actual1);
758 info.destroy(data: actual2);
759 delete expected;
760}
761
762template<>
763void testCreateCopyHelper<QMetaType::Void>()
764{
765 typedef MetaEnumToType<QMetaType::Void>::Type Type;
766 Type *expected = TestValueFactory<QMetaType::Void>::create();
767 void *actual = QMetaType::create(type: QMetaType::Void, copy: expected);
768 QCOMPARE(static_cast<Type *>(actual), expected);
769 QMetaType::destroy(type: QMetaType::Void, data: actual);
770}
771
772void tst_QMetaType::createCopy_data()
773{
774 create_data();
775}
776
777void tst_QMetaType::createCopy()
778{
779 struct TypeTestFunctionGetter
780 {
781 static TypeTestFunction get(int type)
782 {
783 switch (type) {
784#define RETURN_CREATE_COPY_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
785 case QMetaType::MetaTypeName: \
786 return testCreateCopyHelper<QMetaType::MetaTypeName>;
787FOR_EACH_CORE_METATYPE(RETURN_CREATE_COPY_FUNCTION)
788#undef RETURN_CREATE_COPY_FUNCTION
789 }
790 return 0;
791 }
792 };
793
794 QFETCH(int, type);
795 TypeTestFunctionGetter::get(type)();
796}
797
798void tst_QMetaType::sizeOf_data()
799{
800 QTest::addColumn<int>(name: "type");
801 QTest::addColumn<size_t>(name: "size");
802
803 QTest::newRow(dataTag: "QMetaType::UnknownType") << int(QMetaType::UnknownType) << size_t(0);
804#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
805 QTest::newRow(#RealType) << int(QMetaType::MetaTypeName) << size_t(QTypeInfo<RealType>::sizeOf);
806FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW)
807#undef ADD_METATYPE_TEST_ROW
808
809 QTest::newRow(dataTag: "Whity<double>") << ::qMetaTypeId<Whity<double> >() << sizeof(Whity<double>);
810 QTest::newRow(dataTag: "Whity<int>") << ::qMetaTypeId<Whity<int> >() << sizeof(Whity<int>);
811 QTest::newRow(dataTag: "Testspace::Foo") << ::qMetaTypeId<TestSpace::Foo>() << sizeof(TestSpace::Foo);
812
813 QTest::newRow(dataTag: "-1") << -1 << size_t(0);
814 QTest::newRow(dataTag: "-124125534") << -124125534 << size_t(0);
815 QTest::newRow(dataTag: "124125534") << 124125534 << size_t(0);
816}
817
818void tst_QMetaType::sizeOf()
819{
820 QFETCH(int, type);
821 QFETCH(size_t, size);
822 QCOMPARE(size_t(QMetaType::sizeOf(type)), size);
823}
824
825void tst_QMetaType::sizeOfStaticLess_data()
826{
827 sizeOf_data();
828}
829
830void tst_QMetaType::sizeOfStaticLess()
831{
832 QFETCH(int, type);
833 QFETCH(size_t, size);
834 QCOMPARE(size_t(QMetaType(type).sizeOf()), size);
835}
836
837struct CustomMovable { CustomMovable() {} };
838#if !defined(Q_CC_CLANG) && defined(Q_CC_GNU) && Q_CC_GNU < 501
839QT_BEGIN_NAMESPACE
840Q_DECLARE_TYPEINFO(CustomMovable, Q_MOVABLE_TYPE);
841QT_END_NAMESPACE
842#endif
843
844Q_DECLARE_METATYPE(CustomMovable);
845
846class CustomObject : public QObject
847{
848 Q_OBJECT
849public:
850 CustomObject(QObject *parent = 0)
851 : QObject(parent)
852 {
853
854 }
855};
856Q_DECLARE_METATYPE(CustomObject*);
857
858struct SecondBase {};
859
860class CustomMultiInheritanceObject : public QObject, SecondBase
861{
862 Q_OBJECT
863public:
864 CustomMultiInheritanceObject(QObject *parent = 0)
865 : QObject(parent)
866 {
867
868 }
869};
870Q_DECLARE_METATYPE(CustomMultiInheritanceObject*);
871
872class C { char _[4]; public: C() = default; C(const C&) {} };
873class M { char _[4]; public: M() {} };
874class P { char _[4]; };
875
876QT_BEGIN_NAMESPACE
877#if defined(Q_CC_GNU) && Q_CC_GNU < 501
878Q_DECLARE_TYPEINFO(M, Q_MOVABLE_TYPE);
879Q_DECLARE_TYPEINFO(P, Q_PRIMITIVE_TYPE);
880#endif
881QT_END_NAMESPACE
882
883// avoid the comma:
884typedef QPair<C,C> QPairCC;
885typedef QPair<C,M> QPairCM;
886typedef QPair<C,P> QPairCP;
887typedef QPair<M,C> QPairMC;
888typedef QPair<M,M> QPairMM;
889typedef QPair<M,P> QPairMP;
890typedef QPair<P,C> QPairPC;
891typedef QPair<P,M> QPairPM;
892typedef QPair<P,P> QPairPP;
893
894Q_DECLARE_METATYPE(QPairCC)
895Q_DECLARE_METATYPE(QPairCM)
896Q_DECLARE_METATYPE(QPairCP)
897Q_DECLARE_METATYPE(QPairMC)
898Q_DECLARE_METATYPE(QPairMM)
899Q_DECLARE_METATYPE(QPairMP)
900Q_DECLARE_METATYPE(QPairPC)
901Q_DECLARE_METATYPE(QPairPM)
902Q_DECLARE_METATYPE(QPairPP)
903
904enum FlagsDataEnum {};
905Q_DECLARE_METATYPE(FlagsDataEnum);
906
907void tst_QMetaType::flags_data()
908{
909 QTest::addColumn<int>(name: "type");
910 QTest::addColumn<bool>(name: "isMovable");
911 QTest::addColumn<bool>(name: "isComplex");
912 QTest::addColumn<bool>(name: "isPointerToQObject");
913 QTest::addColumn<bool>(name: "isEnum");
914
915#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
916 QTest::newRow(#RealType) << MetaTypeId \
917 << bool(QTypeInfoQuery<RealType>::isRelocatable) \
918 << bool(QTypeInfoQuery<RealType>::isComplex) \
919 << bool(QtPrivate::IsPointerToTypeDerivedFromQObject<RealType>::Value) \
920 << bool(std::is_enum<RealType>::value);
921QT_FOR_EACH_STATIC_CORE_CLASS(ADD_METATYPE_TEST_ROW)
922QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(ADD_METATYPE_TEST_ROW)
923QT_FOR_EACH_STATIC_CORE_POINTER(ADD_METATYPE_TEST_ROW)
924#undef ADD_METATYPE_TEST_ROW
925 QTest::newRow(dataTag: "TestSpace::Foo") << ::qMetaTypeId<TestSpace::Foo>() << false << true << false << false;
926 QTest::newRow(dataTag: "Whity<double>") << ::qMetaTypeId<Whity<double> >() << true << true << false << false;
927 QTest::newRow(dataTag: "CustomMovable") << ::qMetaTypeId<CustomMovable>() << true << true << false << false;
928 QTest::newRow(dataTag: "CustomObject*") << ::qMetaTypeId<CustomObject*>() << true << false << true << false;
929 QTest::newRow(dataTag: "CustomMultiInheritanceObject*") << ::qMetaTypeId<CustomMultiInheritanceObject*>() << true << false << true << false;
930 QTest::newRow(dataTag: "QPair<C,C>") << ::qMetaTypeId<QPair<C,C> >() << false << true << false << false;
931 QTest::newRow(dataTag: "QPair<C,M>") << ::qMetaTypeId<QPair<C,M> >() << false << true << false << false;
932 QTest::newRow(dataTag: "QPair<C,P>") << ::qMetaTypeId<QPair<C,P> >() << false << true << false << false;
933 QTest::newRow(dataTag: "QPair<M,C>") << ::qMetaTypeId<QPair<M,C> >() << false << true << false << false;
934 QTest::newRow(dataTag: "QPair<M,M>") << ::qMetaTypeId<QPair<M,M> >() << true << true << false << false;
935 QTest::newRow(dataTag: "QPair<M,P>") << ::qMetaTypeId<QPair<M,P> >() << true << true << false << false;
936 QTest::newRow(dataTag: "QPair<P,C>") << ::qMetaTypeId<QPair<P,C> >() << false << true << false << false;
937 QTest::newRow(dataTag: "QPair<P,M>") << ::qMetaTypeId<QPair<P,M> >() << true << true << false << false;
938 QTest::newRow(dataTag: "QPair<P,P>") << ::qMetaTypeId<QPair<P,P> >() << true << false << false << false;
939 QTest::newRow(dataTag: "FlagsDataEnum") << ::qMetaTypeId<FlagsDataEnum>() << true << false << false << true;
940
941 // invalid ids.
942 QTest::newRow(dataTag: "-1") << -1 << false << false << false << false;
943 QTest::newRow(dataTag: "-124125534") << -124125534 << false << false << false << false;
944 QTest::newRow(dataTag: "124125534") << 124125534 << false << false << false << false;
945}
946
947void tst_QMetaType::flags()
948{
949 QFETCH(int, type);
950 QFETCH(bool, isMovable);
951 QFETCH(bool, isComplex);
952 QFETCH(bool, isPointerToQObject);
953 QFETCH(bool, isEnum);
954
955 QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsConstruction), isComplex);
956 QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsDestruction), isComplex);
957 QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::MovableType), isMovable);
958 QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::PointerToQObject), isPointerToQObject);
959 QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::IsEnumeration), isEnum);
960}
961
962void tst_QMetaType::flagsStaticLess_data()
963{
964 flags_data();
965}
966
967void tst_QMetaType::flagsStaticLess()
968{
969 QFETCH(int, type);
970 QFETCH(bool, isMovable);
971 QFETCH(bool, isComplex);
972
973 int flags = QMetaType(type).flags();
974 QCOMPARE(bool(flags & QMetaType::NeedsConstruction), isComplex);
975 QCOMPARE(bool(flags & QMetaType::NeedsDestruction), isComplex);
976 QCOMPARE(bool(flags & QMetaType::MovableType), isMovable);
977}
978
979void tst_QMetaType::flagsBinaryCompatibility5_0_data()
980{
981 // Changing traits of a built-in type is illegal from BC point of view.
982 // Traits are saved in code of an application and in the Qt library which means
983 // that there may be a mismatch.
984 // The test is loading data generated by this code:
985 //
986 // QByteArray buffer;
987 // buffer.reserve(2 * QMetaType::User);
988 // for (quint32 i = 0; i < QMetaType::User; ++i) {
989 // if (QMetaType::isRegistered(i)) {
990 // buffer.append(i);
991 // buffer.append(quint32(QMetaType::typeFlags(i)));
992 // }
993 // }
994 // QFile file("/tmp/typeFlags.bin");
995 // file.open(QIODevice::WriteOnly);
996 // file.write(buffer);
997 // file.close();
998
999 QTest::addColumn<quint32>(name: "id");
1000 QTest::addColumn<quint32>(name: "flags");
1001
1002 QFile file(QFINDTESTDATA("typeFlags.bin"));
1003 file.open(flags: QIODevice::ReadOnly);
1004 QByteArray buffer = file.readAll();
1005
1006 for (int i = 0; i < buffer.size(); i+=2) {
1007 const quint32 id = buffer.at(i);
1008 const quint32 flags = buffer.at(i: i + 1);
1009 QVERIFY2(QMetaType::isRegistered(id), "A type could not be removed in BC way");
1010 QTest::newRow(dataTag: QMetaType::typeName(type: id)) << id << flags;
1011 }
1012}
1013
1014void tst_QMetaType::flagsBinaryCompatibility5_0()
1015{
1016 QFETCH(quint32, id);
1017 QFETCH(quint32, flags);
1018
1019 quint32 mask_5_0 = 0x1fb; // Only compare the values that were already defined in 5.0
1020
1021 QCOMPARE(quint32(QMetaType::typeFlags(id)) & mask_5_0, flags & mask_5_0);
1022}
1023
1024void tst_QMetaType::construct_data()
1025{
1026 create_data();
1027}
1028
1029template<int ID>
1030static void testConstructHelper()
1031{
1032 typedef typename MetaEnumToType<ID>::Type Type;
1033 QMetaType info(ID);
1034 int size = info.sizeOf();
1035 void *storage1 = qMallocAligned(size, Q_ALIGNOF(Type));
1036 void *actual1 = QMetaType::construct(type: ID, where: storage1, /*copy=*/0);
1037 void *storage2 = qMallocAligned(size, Q_ALIGNOF(Type));
1038 void *actual2 = info.construct(where: storage2, /*copy=*/0);
1039 QCOMPARE(actual1, storage1);
1040 QCOMPARE(actual2, storage2);
1041 if (DefaultValueTraits<ID>::IsInitialized) {
1042 Type *expected = DefaultValueFactory<ID>::create();
1043 QCOMPARE(*static_cast<Type *>(actual1), *expected);
1044 QCOMPARE(*static_cast<Type *>(actual2), *expected);
1045 delete expected;
1046 }
1047 QMetaType::destruct(type: ID, where: actual1);
1048 qFreeAligned(ptr: storage1);
1049 info.destruct(data: actual2);
1050 qFreeAligned(ptr: storage2);
1051
1052 QVERIFY(QMetaType::construct(ID, 0, /*copy=*/0) == 0);
1053 QMetaType::destruct(type: ID, where: 0);
1054
1055 QVERIFY(info.construct(0, /*copy=*/0) == 0);
1056 info.destruct(data: 0);
1057}
1058
1059template<>
1060void testConstructHelper<QMetaType::Void>()
1061{
1062 /*int size = */ QMetaType::sizeOf(type: QMetaType::Void);
1063 void *storage = 0;
1064 void *actual = QMetaType::construct(type: QMetaType::Void, where: storage, /*copy=*/0);
1065 QCOMPARE(actual, storage);
1066 if (DefaultValueTraits<QMetaType::Void>::IsInitialized) {
1067 QVERIFY(DefaultValueFactory<QMetaType::Void>::create());
1068 }
1069 QMetaType::destruct(type: QMetaType::Void, where: actual);
1070 qFreeAligned(ptr: storage);
1071
1072 QVERIFY(QMetaType::construct(QMetaType::Void, 0, /*copy=*/0) == 0);
1073 QMetaType::destruct(type: QMetaType::Void, where: 0);
1074}
1075
1076void tst_QMetaType::construct()
1077{
1078 struct TypeTestFunctionGetter
1079 {
1080 static TypeTestFunction get(int type)
1081 {
1082 switch (type) {
1083#define RETURN_CONSTRUCT_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
1084 case QMetaType::MetaTypeName: \
1085 return testConstructHelper<QMetaType::MetaTypeName>;
1086FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_FUNCTION)
1087#undef RETURN_CONSTRUCT_FUNCTION
1088 }
1089 return 0;
1090 }
1091 };
1092
1093 QFETCH(int, type);
1094 TypeTestFunctionGetter::get(type)();
1095}
1096
1097void tst_QMetaType::typedConstruct()
1098{
1099 auto testMetaObjectWriteOnGadget = [](QVariant &gadget, const QVector<GadgetPropertyType> &properties)
1100 {
1101 auto metaObject = QMetaType::metaObjectForType(type: gadget.userType());
1102 QVERIFY(metaObject != nullptr);
1103 QCOMPARE(metaObject->methodCount(), 0);
1104 QCOMPARE(metaObject->propertyCount(), properties.size());
1105 for (int i = 0; i < metaObject->propertyCount(); ++i) {
1106 auto prop = metaObject->property(index: i);
1107 QCOMPARE(properties[i].name, prop.name());
1108 QCOMPARE(properties[i].type, prop.typeName());
1109 prop.writeOnGadget(gadget: gadget.data(), value: properties[i].testData);
1110 }
1111 };
1112
1113 auto testMetaObjectReadOnGadget = [](QVariant gadget, const QVector<GadgetPropertyType> &properties)
1114 {
1115 auto metaObject = QMetaType::metaObjectForType(type: gadget.userType());
1116 QVERIFY(metaObject != nullptr);
1117 QCOMPARE(metaObject->methodCount(), 0);
1118 QCOMPARE(metaObject->propertyCount(), properties.size());
1119 for (int i = 0; i < metaObject->propertyCount(); ++i) {
1120 auto prop = metaObject->property(index: i);
1121 QCOMPARE(properties[i].name, prop.name());
1122 QCOMPARE(properties[i].type, prop.typeName());
1123 if (!QMetaType::typeFlags(type: prop.userType()).testFlag(flag: QMetaType::IsGadget))
1124 QCOMPARE(properties[i].testData, prop.readOnGadget(gadget.constData()));
1125 }
1126 };
1127
1128 QVector<GadgetPropertyType> dynamicGadget1 = {
1129 {.type: "int", .name: "int_prop", .testData: 34526},
1130 {.type: "float", .name: "float_prop", .testData: 1.23f},
1131 {.type: "QString", .name: "string_prop", .testData: QString{"Test QString"}}
1132 };
1133 registerGadget(name: "DynamicGadget1", gadgetProperties: dynamicGadget1);
1134
1135 QVariant testGadget1(QVariant::Type(QMetaType::type(typeName: "DynamicGadget1")));
1136 testMetaObjectWriteOnGadget(testGadget1, dynamicGadget1);
1137 testMetaObjectReadOnGadget(testGadget1, dynamicGadget1);
1138
1139
1140 QVector<GadgetPropertyType> dynamicGadget2 = {
1141 {.type: "int", .name: "int_prop", .testData: 512},
1142 {.type: "double", .name: "double_prop", .testData: 4.56},
1143 {.type: "QString", .name: "string_prop", .testData: QString{"Another String"}},
1144 {.type: "DynamicGadget1", .name: "dynamicGadget1_prop", .testData: testGadget1}
1145 };
1146 registerGadget(name: "DynamicGadget2", gadgetProperties: dynamicGadget2);
1147 QVariant testGadget2(QVariant::Type(QMetaType::type(typeName: "DynamicGadget2")));
1148 testMetaObjectWriteOnGadget(testGadget2, dynamicGadget2);
1149 testMetaObjectReadOnGadget(testGadget2, dynamicGadget2);
1150 auto g2mo = QMetaType::metaObjectForType(type: testGadget2.userType());
1151 auto dynamicGadget1_prop = g2mo->property(index: g2mo->indexOfProperty(name: "dynamicGadget1_prop"));
1152 testMetaObjectReadOnGadget(dynamicGadget1_prop.readOnGadget(gadget: testGadget2.constData()), dynamicGadget1);
1153
1154
1155 // Register POD
1156 const QByteArray myPodTesData = "My POD test data";
1157 const char podTypeName[] = "DynamicPOD";
1158 auto dynamicGadgetProperties = std::make_shared<GenericPODType>();
1159 dynamicGadgetProperties->podData = myPodTesData;
1160 const auto flags = QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
1161 int podTypeId = QMetaType::registerType(typeName: podTypeName,
1162 destructor: &GadgetTypedDestructor,
1163 constructor: &GadgetTypedConstructor,
1164 size: sizeof(GenericGadgetType),
1165 flags, metaObject: nullptr);
1166 QVERIFY(podTypeId > 0);
1167 QMetaType::registerStreamOperators(type: podTypeId, saveOp: &GadgetSaveOperator, loadOp: &GadgetLoadOperator);
1168 s_managedTypes[podTypeId] = qMakePair(x: dynamicGadgetProperties, y: std::shared_ptr<QMetaObject>{});
1169
1170 // Test POD
1171 QCOMPARE(podTypeId, QMetaType::type(podTypeName));
1172 QVariant podVariant{QVariant::Type(podTypeId)};
1173 QCOMPARE(myPodTesData, static_cast<const GenericPODType *>(reinterpret_cast<const BaseGenericType *>(podVariant.constData()))->podData);
1174
1175 QVariant podVariant1{podVariant};
1176 podVariant1.detach(); // Test stream operators
1177 static_cast<GenericPODType *>(reinterpret_cast<BaseGenericType *>(podVariant.data()))->podData.clear();
1178 QCOMPARE(myPodTesData, static_cast<const GenericPODType *>(reinterpret_cast<const BaseGenericType *>(podVariant1.constData()))->podData);
1179}
1180
1181template<int ID>
1182static void testConstructCopyHelper()
1183{
1184 typedef typename MetaEnumToType<ID>::Type Type;
1185 Type *expected = TestValueFactory<ID>::create();
1186 QMetaType info(ID);
1187 int size = QMetaType::sizeOf(type: ID);
1188 QCOMPARE(info.sizeOf(), size);
1189 void *storage1 = qMallocAligned(size, Q_ALIGNOF(Type));
1190 void *actual1 = QMetaType::construct(ID, storage1, expected);
1191 void *storage2 = qMallocAligned(size, Q_ALIGNOF(Type));
1192 void *actual2 = info.construct(storage2, expected);
1193 QCOMPARE(actual1, storage1);
1194 QCOMPARE(actual2, storage2);
1195 QCOMPARE(*static_cast<Type *>(actual1), *expected);
1196 QCOMPARE(*static_cast<Type *>(actual2), *expected);
1197 QMetaType::destruct(type: ID, where: actual1);
1198 qFreeAligned(ptr: storage1);
1199 info.destruct(data: actual2);
1200 qFreeAligned(ptr: storage2);
1201
1202 QVERIFY(QMetaType::construct(ID, 0, expected) == 0);
1203 QVERIFY(info.construct(0, expected) == 0);
1204
1205 delete expected;
1206}
1207
1208template<>
1209void testConstructCopyHelper<QMetaType::Void>()
1210{
1211 typedef MetaEnumToType<QMetaType::Void>::Type Type;
1212 Type *expected = TestValueFactory<QMetaType::Void>::create();
1213 /* int size = */QMetaType::sizeOf(type: QMetaType::Void);
1214 void *storage = 0;
1215 void *actual = QMetaType::construct(type: QMetaType::Void, where: storage, copy: expected);
1216 QCOMPARE(actual, storage);
1217 QMetaType::destruct(type: QMetaType::Void, where: actual);
1218 qFreeAligned(ptr: storage);
1219
1220 QVERIFY(QMetaType::construct(QMetaType::Void, 0, expected) == 0);
1221}
1222
1223void tst_QMetaType::constructCopy_data()
1224{
1225 create_data();
1226}
1227
1228void tst_QMetaType::constructCopy()
1229{
1230 struct TypeTestFunctionGetter
1231 {
1232 static TypeTestFunction get(int type)
1233 {
1234 switch (type) {
1235#define RETURN_CONSTRUCT_COPY_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
1236 case QMetaType::MetaTypeName: \
1237 return testConstructCopyHelper<QMetaType::MetaTypeName>;
1238FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_COPY_FUNCTION)
1239#undef RETURN_CONSTRUCT_COPY_FUNCTION
1240 }
1241 return 0;
1242 }
1243 };
1244
1245 QFETCH(int, type);
1246 TypeTestFunctionGetter::get(type)();
1247}
1248
1249typedef QString CustomString;
1250Q_DECLARE_METATYPE(CustomString) //this line is useless
1251
1252void tst_QMetaType::typedefs()
1253{
1254 QCOMPARE(QMetaType::type("long long"), int(QMetaType::LongLong));
1255 QCOMPARE(QMetaType::type("unsigned long long"), int(QMetaType::ULongLong));
1256 QCOMPARE(QMetaType::type("qint8"), int(QMetaType::SChar));
1257 QCOMPARE(QMetaType::type("quint8"), int(QMetaType::UChar));
1258 QCOMPARE(QMetaType::type("qint16"), int(QMetaType::Short));
1259 QCOMPARE(QMetaType::type("quint16"), int(QMetaType::UShort));
1260 QCOMPARE(QMetaType::type("qint32"), int(QMetaType::Int));
1261 QCOMPARE(QMetaType::type("quint32"), int(QMetaType::UInt));
1262 QCOMPARE(QMetaType::type("qint64"), int(QMetaType::LongLong));
1263 QCOMPARE(QMetaType::type("quint64"), int(QMetaType::ULongLong));
1264
1265 // make sure the qreal typeId is the type id of the type it's defined to
1266 QCOMPARE(QMetaType::type("qreal"), ::qMetaTypeId<qreal>());
1267
1268 qRegisterMetaType<CustomString>(typeName: "CustomString");
1269 QCOMPARE(QMetaType::type("CustomString"), ::qMetaTypeId<CustomString>());
1270
1271 typedef Whity<double> WhityDouble;
1272 qRegisterMetaType<WhityDouble>(typeName: "WhityDouble");
1273 QCOMPARE(QMetaType::type("WhityDouble"), ::qMetaTypeId<WhityDouble>());
1274}
1275
1276void tst_QMetaType::registerType()
1277{
1278 // Built-in
1279 QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString));
1280 QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString));
1281
1282 // Custom
1283 int fooId = qRegisterMetaType<TestSpace::Foo>(typeName: "TestSpace::Foo");
1284 QVERIFY(fooId >= int(QMetaType::User));
1285 QCOMPARE(qRegisterMetaType<TestSpace::Foo>("TestSpace::Foo"), fooId);
1286
1287 int movableId = qRegisterMetaType<CustomMovable>(typeName: "CustomMovable");
1288 QVERIFY(movableId >= int(QMetaType::User));
1289 QCOMPARE(qRegisterMetaType<CustomMovable>("CustomMovable"), movableId);
1290
1291 // Alias to built-in
1292 typedef QString MyString;
1293
1294 QCOMPARE(qRegisterMetaType<MyString>("MyString"), int(QMetaType::QString));
1295 QCOMPARE(qRegisterMetaType<MyString>("MyString"), int(QMetaType::QString));
1296
1297 QCOMPARE(QMetaType::type("MyString"), int(QMetaType::QString));
1298
1299 // Alias to custom type
1300 typedef CustomMovable MyMovable;
1301 typedef TestSpace::Foo MyFoo;
1302
1303 QCOMPARE(qRegisterMetaType<MyMovable>("MyMovable"), movableId);
1304 QCOMPARE(qRegisterMetaType<MyMovable>("MyMovable"), movableId);
1305
1306 QCOMPARE(QMetaType::type("MyMovable"), movableId);
1307
1308 QCOMPARE(qRegisterMetaType<MyFoo>("MyFoo"), fooId);
1309 QCOMPARE(qRegisterMetaType<MyFoo>("MyFoo"), fooId);
1310
1311 QCOMPARE(QMetaType::type("MyFoo"), fooId);
1312
1313 // cannot unregister built-in types
1314 QVERIFY(!QMetaType::unregisterType(QMetaType::QString));
1315 QCOMPARE(QMetaType::type("QString"), int(QMetaType::QString));
1316 QCOMPARE(QMetaType::type("MyString"), int(QMetaType::QString));
1317
1318 // cannot unregister declared types
1319 QVERIFY(!QMetaType::unregisterType(fooId));
1320 QCOMPARE(QMetaType::type("TestSpace::Foo"), fooId);
1321 QCOMPARE(QMetaType::type("MyFoo"), fooId);
1322
1323 // test unregistration of dynamic types (used by Qml)
1324 int unregId = QMetaType::registerType(typeName: "UnregisterMe",
1325 deleter: 0,
1326 creator: 0,
1327 destructor: QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
1328 constructor: QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
1329 size: 0, flags: QMetaType::TypeFlags(), metaObject: 0);
1330 QCOMPARE(QMetaType::registerTypedef("UnregisterMeTypedef", unregId), unregId);
1331 int unregId2 = QMetaType::registerType(typeName: "UnregisterMe2",
1332 deleter: 0,
1333 creator: 0,
1334 destructor: QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
1335 constructor: QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
1336 size: 0, flags: QMetaType::TypeFlags(), metaObject: 0);
1337 QVERIFY(unregId >= int(QMetaType::User));
1338 QCOMPARE(unregId2, unregId + 2);
1339
1340 QVERIFY(QMetaType::unregisterType(unregId));
1341 QCOMPARE(QMetaType::type("UnregisterMe"), 0);
1342 QCOMPARE(QMetaType::type("UnregisterMeTypedef"), 0);
1343 QCOMPARE(QMetaType::type("UnregisterMe2"), unregId2);
1344 QVERIFY(QMetaType::unregisterType(unregId2));
1345 QCOMPARE(QMetaType::type("UnregisterMe2"), 0);
1346
1347 // re-registering should always return the lowest free index
1348 QCOMPARE(QMetaType::registerType("UnregisterMe2",
1349 0,
1350 0,
1351 QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
1352 QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
1353 0, QMetaType::TypeFlags(), 0), unregId);
1354 QCOMPARE(QMetaType::registerType("UnregisterMe",
1355 0,
1356 0,
1357 QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Destruct,
1358 QtMetaTypePrivate::QMetaTypeFunctionHelper<void>::Construct,
1359 0, QMetaType::TypeFlags(), 0), unregId + 1);
1360}
1361
1362class IsRegisteredDummyType { };
1363
1364void tst_QMetaType::isRegistered_data()
1365{
1366 QTest::addColumn<int>(name: "typeId");
1367 QTest::addColumn<bool>(name: "registered");
1368
1369 // predefined/custom types
1370 QTest::newRow(dataTag: "QMetaType::Void") << int(QMetaType::Void) << true;
1371 QTest::newRow(dataTag: "QMetaType::Int") << int(QMetaType::Int) << true;
1372
1373 int dummyTypeId = qRegisterMetaType<IsRegisteredDummyType>(typeName: "IsRegisteredDummyType");
1374
1375 QTest::newRow(dataTag: "IsRegisteredDummyType") << dummyTypeId << true;
1376
1377 // unknown types
1378 QTest::newRow(dataTag: "-1") << -1 << false;
1379 QTest::newRow(dataTag: "-42") << -42 << false;
1380 QTest::newRow(dataTag: "IsRegisteredDummyType + 1") << (dummyTypeId + 1) << false;
1381 QTest::newRow(dataTag: "QMetaType::UnknownType") << int(QMetaType::UnknownType) << false;
1382}
1383
1384void tst_QMetaType::isRegistered()
1385{
1386 QFETCH(int, typeId);
1387 QFETCH(bool, registered);
1388 QCOMPARE(QMetaType::isRegistered(typeId), registered);
1389}
1390
1391enum isEnumTest_Enum0 {};
1392struct isEnumTest_Struct0 { enum A{}; };
1393
1394enum isEnumTest_Enum1 {};
1395struct isEnumTest_Struct1 {};
1396
1397Q_DECLARE_METATYPE(isEnumTest_Struct1)
1398Q_DECLARE_METATYPE(isEnumTest_Enum1)
1399
1400void tst_QMetaType::isEnum()
1401{
1402 int type0 = qRegisterMetaType<int>(typeName: "int");
1403 QVERIFY((QMetaType::typeFlags(type0) & QMetaType::IsEnumeration) == 0);
1404
1405 int type1 = qRegisterMetaType<isEnumTest_Enum0>(typeName: "isEnumTest_Enum0");
1406 QVERIFY((QMetaType::typeFlags(type1) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration);
1407
1408 int type2 = qRegisterMetaType<isEnumTest_Struct0>(typeName: "isEnumTest_Struct0");
1409 QVERIFY((QMetaType::typeFlags(type2) & QMetaType::IsEnumeration) == 0);
1410
1411 int type3 = qRegisterMetaType<isEnumTest_Enum0 *>(typeName: "isEnumTest_Enum0 *");
1412 QVERIFY((QMetaType::typeFlags(type3) & QMetaType::IsEnumeration) == 0);
1413
1414 int type4 = qRegisterMetaType<isEnumTest_Struct0::A>(typeName: "isEnumTest_Struct0::A");
1415 QVERIFY((QMetaType::typeFlags(type4) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration);
1416
1417 int type5 = ::qMetaTypeId<isEnumTest_Struct1>();
1418 QVERIFY((QMetaType::typeFlags(type5) & QMetaType::IsEnumeration) == 0);
1419
1420 int type6 = ::qMetaTypeId<isEnumTest_Enum1>();
1421 QVERIFY((QMetaType::typeFlags(type6) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration);
1422}
1423
1424void tst_QMetaType::isRegisteredStaticLess_data()
1425{
1426 isRegistered_data();
1427}
1428
1429void tst_QMetaType::isRegisteredStaticLess()
1430{
1431 QFETCH(int, typeId);
1432 QFETCH(bool, registered);
1433 QCOMPARE(QMetaType(typeId).isRegistered(), registered);
1434}
1435
1436void tst_QMetaType::registerStreamBuiltin()
1437{
1438 //should not crash;
1439 qRegisterMetaTypeStreamOperators<QString>(typeName: "QString");
1440 qRegisterMetaTypeStreamOperators<QVariant>(typeName: "QVariant");
1441}
1442
1443typedef QHash<int, uint> IntUIntHash;
1444Q_DECLARE_METATYPE(IntUIntHash)
1445typedef QMap<int, uint> IntUIntMap;
1446Q_DECLARE_METATYPE(IntUIntMap)
1447typedef QPair<int, uint> IntUIntPair;
1448Q_DECLARE_METATYPE(IntUIntPair)
1449
1450struct CustomComparable
1451{
1452 CustomComparable(int i_ = 0) :i(i_) { }
1453 bool operator==(const CustomComparable &other) const
1454 {
1455 return i == other.i;
1456 }
1457 int i;
1458};
1459
1460struct UnregisteredType {};
1461
1462typedef QHash<int, CustomComparable> IntComparableHash;
1463Q_DECLARE_METATYPE(IntComparableHash)
1464typedef QMap<int, CustomComparable> IntComparableMap;
1465Q_DECLARE_METATYPE(IntComparableMap)
1466typedef QPair<int, CustomComparable> IntComparablePair;
1467Q_DECLARE_METATYPE(IntComparablePair)
1468
1469typedef QHash<int, int> IntIntHash;
1470typedef int NaturalNumber;
1471class AutoMetaTypeObject : public QObject
1472{
1473 Q_OBJECT
1474 Q_PROPERTY(IntIntHash someHash READ someHash CONSTANT)
1475 Q_PROPERTY(NaturalNumber someInt READ someInt CONSTANT)
1476public:
1477 AutoMetaTypeObject(QObject *parent = 0)
1478 : QObject(parent), m_int(42)
1479 {
1480 m_hash.insert(key: 4, value: 2);
1481 }
1482
1483 QHash<int,int> someHash() const
1484 {
1485 return m_hash;
1486 }
1487
1488 int someInt() const
1489 {
1490 return m_int;
1491 }
1492
1493private:
1494 QHash<int,int> m_hash;
1495 int m_int;
1496};
1497
1498class MyObject : public QObject
1499{
1500 Q_OBJECT
1501public:
1502 MyObject(QObject *parent = 0)
1503 : QObject(parent)
1504 {
1505 }
1506};
1507typedef MyObject* MyObjectPtr;
1508Q_DECLARE_METATYPE(MyObjectPtr)
1509
1510#if !defined(TST_QMETATYPE_BROKEN_COMPILER)
1511static QByteArray createTypeName(const char *begin, const char *va)
1512{
1513 QByteArray tn(begin);
1514 const QList<QByteArray> args = QByteArray(va).split(sep: ',');
1515 tn += args.first().trimmed();
1516 if (args.size() > 1) {
1517 QList<QByteArray>::const_iterator it = args.constBegin() + 1;
1518 const QList<QByteArray>::const_iterator end = args.constEnd();
1519 for (; it != end; ++it) {
1520 tn += ",";
1521 tn += it->trimmed();
1522 }
1523 }
1524 if (tn.endsWith(c: '>'))
1525 tn += ' ';
1526 tn += '>';
1527 return tn;
1528}
1529#endif
1530
1531Q_DECLARE_METATYPE(const void*)
1532
1533void tst_QMetaType::automaticTemplateRegistration()
1534{
1535#define TEST_SEQUENTIAL_CONTAINER(CONTAINER, VALUE_TYPE) \
1536 { \
1537 CONTAINER<VALUE_TYPE> innerContainer; \
1538 innerContainer.push_back(42); \
1539 QVERIFY(*QVariant::fromValue(innerContainer).value<CONTAINER<VALUE_TYPE> >().begin() == 42); \
1540 QVector<CONTAINER<VALUE_TYPE> > outerContainer; \
1541 outerContainer << innerContainer; \
1542 QVERIFY(*QVariant::fromValue(outerContainer).value<QVector<CONTAINER<VALUE_TYPE> > >().first().begin() == 42); \
1543 }
1544
1545 TEST_SEQUENTIAL_CONTAINER(QList, int)
1546 TEST_SEQUENTIAL_CONTAINER(std::vector, int)
1547 TEST_SEQUENTIAL_CONTAINER(std::list, int)
1548
1549 {
1550 std::vector<bool> vecbool;
1551 vecbool.push_back(x: true);
1552 vecbool.push_back(x: false);
1553 vecbool.push_back(x: true);
1554 QVERIFY(QVariant::fromValue(vecbool).value<std::vector<bool> >().front() == true);
1555 QVector<std::vector<bool> > vectorList;
1556 vectorList << vecbool;
1557 QVERIFY(QVariant::fromValue(vectorList).value<QVector<std::vector<bool> > >().first().front() == true);
1558 }
1559
1560 {
1561 QList<unsigned> unsignedList;
1562 unsignedList << 123;
1563 QVERIFY(QVariant::fromValue(unsignedList).value<QList<unsigned> >().first() == 123);
1564 QVector<QList<unsigned> > vectorList;
1565 vectorList << unsignedList;
1566 QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<unsigned> > >().first().first() == 123);
1567 }
1568
1569 QCOMPARE(::qMetaTypeId<QVariantList>(), (int)QMetaType::QVariantList);
1570 QCOMPARE(::qMetaTypeId<QList<QVariant> >(), (int)QMetaType::QVariantList);
1571
1572 TEST_SEQUENTIAL_CONTAINER(QList, QVariant)
1573 TEST_SEQUENTIAL_CONTAINER(std::vector, QVariant)
1574 TEST_SEQUENTIAL_CONTAINER(std::list, QVariant)
1575
1576 {
1577 QList<QSharedPointer<QObject> > sharedPointerList;
1578 QObject *testObject = new QObject;
1579 sharedPointerList << QSharedPointer<QObject>(testObject);
1580 QVERIFY(QVariant::fromValue(sharedPointerList).value<QList<QSharedPointer<QObject> > >().first() == testObject);
1581 QVector<QList<QSharedPointer<QObject> > > vectorList;
1582 vectorList << sharedPointerList;
1583 QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<QSharedPointer<QObject> > > >().first().first() == testObject);
1584 }
1585 {
1586 IntIntHash intIntHash;
1587 intIntHash.insert(key: 4, value: 2);
1588 QCOMPARE(QVariant::fromValue(intIntHash).value<IntIntHash>().value(4), 2);
1589
1590 AutoMetaTypeObject amto;
1591
1592 qRegisterMetaType<QHash<int, int> >(typeName: "IntIntHash");
1593 QVariant hashVariant = amto.property(name: "someHash");
1594 QCOMPARE(hashVariant.value<IntIntHash>().value(4), 2);
1595
1596 qRegisterMetaType<int>(typeName: "NaturalNumber");
1597 QVariant intVariant = amto.property(name: "someInt");
1598 QCOMPARE(intVariant.value<NaturalNumber>(), 42);
1599 }
1600 {
1601 IntUIntHash intUIntHash;
1602 intUIntHash.insert(key: 4, value: 2);
1603 QCOMPARE(QVariant::fromValue(intUIntHash).value<IntUIntHash>().value(4), (uint)2);
1604 }
1605 {
1606 IntComparableHash intComparableHash;
1607 CustomComparable m;
1608 intComparableHash.insert(key: 4, value: m);
1609 QCOMPARE(QVariant::fromValue(intComparableHash).value<IntComparableHash>().value(4), m);
1610 }
1611 {
1612 QVariantHash variantHash;
1613 variantHash.insert(QStringLiteral("4"), value: 2);
1614 QCOMPARE(QVariant::fromValue(variantHash).value<QVariantHash>().value(QStringLiteral("4")), QVariant(2));
1615 }
1616 {
1617 typedef QMap<int, int> IntIntMap;
1618 IntIntMap intIntMap;
1619 intIntMap.insert(key: 4, value: 2);
1620 QCOMPARE(QVariant::fromValue(intIntMap).value<IntIntMap>().value(4), 2);
1621 }
1622 {
1623 IntUIntMap intUIntMap;
1624 intUIntMap.insert(key: 4, value: 2);
1625 QCOMPARE(QVariant::fromValue(intUIntMap).value<IntUIntMap>().value(4), (uint)2);
1626 }
1627 {
1628 IntComparableMap intComparableMap;
1629 CustomComparable m;
1630 intComparableMap.insert(key: 4, value: m);
1631 QCOMPARE(QVariant::fromValue(intComparableMap).value<IntComparableMap>().value(4), m);
1632 }
1633 {
1634 QVariantMap variantMap;
1635 variantMap.insert(QStringLiteral("4"), value: 2);
1636 QCOMPARE(QVariant::fromValue(variantMap).value<QVariantMap>().value(QStringLiteral("4")), QVariant(2));
1637 }
1638 {
1639 typedef std::map<int, int> IntIntMap;
1640 IntIntMap intIntMap;
1641 intIntMap[4] = 2;
1642 QCOMPARE(QVariant::fromValue(intIntMap).value<IntIntMap>()[4], 2);
1643 }
1644 {
1645 typedef std::map<int, uint> StdIntUIntMap;
1646 StdIntUIntMap intUIntMap;
1647 intUIntMap[4] = 2;
1648 QCOMPARE(QVariant::fromValue(intUIntMap).value<StdIntUIntMap>()[4], (uint)2);
1649 }
1650 {
1651 typedef std::map<int, CustomObject*> StdMapIntCustomObject ;
1652 StdMapIntCustomObject intComparableMap;
1653 CustomObject *o = 0;
1654 intComparableMap[4] = o;
1655 QCOMPARE(QVariant::fromValue(intComparableMap).value<StdMapIntCustomObject >()[4], o);
1656 }
1657 {
1658 typedef std::map<QString, QVariant> StdMapStringVariant;
1659 StdMapStringVariant variantMap;
1660 variantMap[QStringLiteral("4")] = 2;
1661 QCOMPARE(QVariant::fromValue(variantMap).value<StdMapStringVariant>()[QStringLiteral("4")], QVariant(2));
1662 }
1663 {
1664 typedef QPair<int, int> IntIntPair;
1665 IntIntPair intIntPair = qMakePair(x: 4, y: 2);
1666 QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().first, 4);
1667 QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().second, 2);
1668 }
1669 {
1670 IntUIntPair intUIntPair = qMakePair<int, uint>(x: 4, y: 2);
1671 QCOMPARE(QVariant::fromValue(intUIntPair).value<IntUIntPair>().first, 4);
1672 QCOMPARE(QVariant::fromValue(intUIntPair).value<IntUIntPair>().second, (uint)2);
1673 }
1674 {
1675 CustomComparable m;
1676 IntComparablePair intComparablePair = qMakePair(x: 4, y: m);
1677 QCOMPARE(QVariant::fromValue(intComparablePair).value<IntComparablePair>().first, 4);
1678 QCOMPARE(QVariant::fromValue(intComparablePair).value<IntComparablePair>().second, m);
1679 }
1680 {
1681 typedef std::pair<int, int> IntIntPair;
1682 IntIntPair intIntPair = std::make_pair(x: 4, y: 2);
1683 QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().first, 4);
1684 QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().second, 2);
1685 }
1686 {
1687 typedef std::pair<int, uint> StdIntUIntPair;
1688 StdIntUIntPair intUIntPair = std::make_pair<int, uint>(x: 4, y: 2);
1689 QCOMPARE(QVariant::fromValue(intUIntPair).value<StdIntUIntPair>().first, 4);
1690 QCOMPARE(QVariant::fromValue(intUIntPair).value<StdIntUIntPair>().second, (uint)2);
1691 }
1692 {
1693 typedef std::pair<int, CustomQObject*> StdIntComparablePair;
1694 CustomQObject* o = 0;
1695 StdIntComparablePair intComparablePair = std::make_pair(x: 4, y&: o);
1696 QCOMPARE(QVariant::fromValue(intComparablePair).value<StdIntComparablePair>().first, 4);
1697 QCOMPARE(QVariant::fromValue(intComparablePair).value<StdIntComparablePair>().second, o);
1698 }
1699 {
1700 typedef QHash<int, UnregisteredType> IntUnregisteredTypeHash;
1701 QVERIFY(qRegisterMetaType<IntUnregisteredTypeHash>("IntUnregisteredTypeHash") > 0);
1702 }
1703 {
1704 typedef QList<UnregisteredType> UnregisteredTypeList;
1705 QVERIFY(qRegisterMetaType<UnregisteredTypeList>("UnregisteredTypeList") > 0);
1706 }
1707
1708#if !defined(TST_QMETATYPE_BROKEN_COMPILER)
1709
1710 #define FOR_EACH_STATIC_PRIMITIVE_TYPE(F) \
1711 F(bool) \
1712 F(int) \
1713 F(qulonglong) \
1714 F(double) \
1715 F(short) \
1716 F(char) \
1717 F(ulong) \
1718 F(uchar) \
1719 F(float) \
1720 F(QObject*) \
1721 F(QString) \
1722 F(CustomMovable)
1723
1724 #define FOR_EACH_STATIC_PRIMITIVE_TYPE2(F, SecondaryRealName) \
1725 F(uint, SecondaryRealName) \
1726 F(qlonglong, SecondaryRealName) \
1727 F(char, SecondaryRealName) \
1728 F(uchar, SecondaryRealName) \
1729 F(QObject*, SecondaryRealName)
1730
1731 #define CREATE_AND_VERIFY_CONTAINER(CONTAINER, ...) \
1732 { \
1733 CONTAINER< __VA_ARGS__ > t; \
1734 const QVariant v = QVariant::fromValue(t); \
1735 QByteArray tn = createTypeName(#CONTAINER "<", #__VA_ARGS__); \
1736 const int type = QMetaType::type(tn); \
1737 const int expectedType = ::qMetaTypeId<CONTAINER< __VA_ARGS__ > >(); \
1738 QCOMPARE(type, expectedType); \
1739 QCOMPARE((QMetaType::fromType<CONTAINER< __VA_ARGS__ >>().id()), expectedType); \
1740 }
1741
1742 #define FOR_EACH_1ARG_TEMPLATE_TYPE(F, TYPE) \
1743 F(QList, TYPE) \
1744 F(QVector, TYPE) \
1745 F(QLinkedList, TYPE) \
1746 F(QVector, TYPE) \
1747 F(QVector, TYPE) \
1748 F(QQueue, TYPE) \
1749 F(QStack, TYPE) \
1750 F(QSet, TYPE)
1751
1752 #define PRINT_1ARG_TEMPLATE(RealName) \
1753 FOR_EACH_1ARG_TEMPLATE_TYPE(CREATE_AND_VERIFY_CONTAINER, RealName)
1754
1755 #define FOR_EACH_2ARG_TEMPLATE_TYPE(F, RealName1, RealName2) \
1756 F(QHash, RealName1, RealName2) \
1757 F(QMap, RealName1, RealName2) \
1758 F(QPair, RealName1, RealName2)
1759
1760 #define PRINT_2ARG_TEMPLATE_INTERNAL(RealName1, RealName2) \
1761 FOR_EACH_2ARG_TEMPLATE_TYPE(CREATE_AND_VERIFY_CONTAINER, RealName1, RealName2)
1762
1763 #define PRINT_2ARG_TEMPLATE(RealName) \
1764 FOR_EACH_STATIC_PRIMITIVE_TYPE2(PRINT_2ARG_TEMPLATE_INTERNAL, RealName)
1765
1766 #define REGISTER_TYPEDEF(TYPE, ARG1, ARG2) \
1767 qRegisterMetaType<TYPE <ARG1, ARG2> >(#TYPE "<" #ARG1 "," #ARG2 ">");
1768
1769 REGISTER_TYPEDEF(QHash, int, uint)
1770 REGISTER_TYPEDEF(QMap, int, uint)
1771 REGISTER_TYPEDEF(QPair, int, uint)
1772
1773 FOR_EACH_STATIC_PRIMITIVE_TYPE(
1774 PRINT_1ARG_TEMPLATE
1775 )
1776 FOR_EACH_STATIC_PRIMITIVE_TYPE(
1777 PRINT_2ARG_TEMPLATE
1778 )
1779
1780 CREATE_AND_VERIFY_CONTAINER(QList, QList<QMap<int, QHash<char, QVariantList> > >)
1781 CREATE_AND_VERIFY_CONTAINER(QVector, void*)
1782 CREATE_AND_VERIFY_CONTAINER(QVector, const void*)
1783 CREATE_AND_VERIFY_CONTAINER(QList, void*)
1784 CREATE_AND_VERIFY_CONTAINER(QPair, void*, void*)
1785 CREATE_AND_VERIFY_CONTAINER(QHash, void*, void*)
1786 CREATE_AND_VERIFY_CONTAINER(QHash, const void*, const void*)
1787
1788#endif // !defined(TST_QMETATYPE_BROKEN_COMPILER)
1789
1790#define TEST_OWNING_SMARTPOINTER(SMARTPOINTER, ELEMENT_TYPE, FLAG_TEST, FROMVARIANTFUNCTION) \
1791 { \
1792 SMARTPOINTER < ELEMENT_TYPE > sp(new ELEMENT_TYPE); \
1793 sp.data()->setObjectName("Test name"); \
1794 QVariant v = QVariant::fromValue(sp); \
1795 QCOMPARE(v.typeName(), #SMARTPOINTER "<" #ELEMENT_TYPE ">"); \
1796 QVERIFY(QMetaType::typeFlags(::qMetaTypeId<SMARTPOINTER < ELEMENT_TYPE > >()) & QMetaType::FLAG_TEST); \
1797 SMARTPOINTER < QObject > extractedPtr = FROMVARIANTFUNCTION<QObject>(v); \
1798 QCOMPARE(extractedPtr.data()->objectName(), sp.data()->objectName()); \
1799 }
1800
1801 TEST_OWNING_SMARTPOINTER(QSharedPointer, QObject, SharedPointerToQObject, qSharedPointerFromVariant)
1802 TEST_OWNING_SMARTPOINTER(QSharedPointer, QFile, SharedPointerToQObject, qSharedPointerFromVariant)
1803 TEST_OWNING_SMARTPOINTER(QSharedPointer, QTemporaryFile, SharedPointerToQObject, qSharedPointerFromVariant)
1804 TEST_OWNING_SMARTPOINTER(QSharedPointer, MyObject, SharedPointerToQObject, qSharedPointerFromVariant)
1805#undef TEST_OWNING_SMARTPOINTER
1806
1807#define TEST_NONOWNING_SMARTPOINTER(SMARTPOINTER, ELEMENT_TYPE, FLAG_TEST, FROMVARIANTFUNCTION) \
1808 { \
1809 ELEMENT_TYPE elem; \
1810 SMARTPOINTER < ELEMENT_TYPE > sp(&elem); \
1811 sp.data()->setObjectName("Test name"); \
1812 QVariant v = QVariant::fromValue(sp); \
1813 QCOMPARE(v.typeName(), #SMARTPOINTER "<" #ELEMENT_TYPE ">"); \
1814 QVERIFY(QMetaType::typeFlags(::qMetaTypeId<SMARTPOINTER < ELEMENT_TYPE > >()) & QMetaType::FLAG_TEST); \
1815 SMARTPOINTER < QObject > extractedPtr = FROMVARIANTFUNCTION<QObject>(v); \
1816 QCOMPARE(extractedPtr.data()->objectName(), sp.data()->objectName()); \
1817 }
1818
1819#if QT_DEPRECATED_SINCE(5, 0)
1820 TEST_NONOWNING_SMARTPOINTER(QWeakPointer, QObject, WeakPointerToQObject, qWeakPointerFromVariant)
1821 TEST_NONOWNING_SMARTPOINTER(QWeakPointer, QFile, WeakPointerToQObject, qWeakPointerFromVariant)
1822 TEST_NONOWNING_SMARTPOINTER(QWeakPointer, QTemporaryFile, WeakPointerToQObject, qWeakPointerFromVariant)
1823 TEST_NONOWNING_SMARTPOINTER(QWeakPointer, MyObject, WeakPointerToQObject, qWeakPointerFromVariant)
1824#endif
1825
1826 TEST_NONOWNING_SMARTPOINTER(QPointer, QObject, TrackingPointerToQObject, qPointerFromVariant)
1827 TEST_NONOWNING_SMARTPOINTER(QPointer, QFile, TrackingPointerToQObject, qPointerFromVariant)
1828 TEST_NONOWNING_SMARTPOINTER(QPointer, QTemporaryFile, TrackingPointerToQObject, qPointerFromVariant)
1829 TEST_NONOWNING_SMARTPOINTER(QPointer, MyObject, TrackingPointerToQObject, qPointerFromVariant)
1830#undef TEST_NONOWNING_SMARTPOINTER
1831
1832
1833#define TEST_WEAK_SMARTPOINTER(ELEMENT_TYPE, FLAG_TEST) \
1834 { \
1835 ELEMENT_TYPE elem; \
1836 QSharedPointer < ELEMENT_TYPE > shared(new ELEMENT_TYPE); \
1837 QWeakPointer < ELEMENT_TYPE > sp(shared); \
1838 sp.toStrongRef()->setObjectName("Test name"); \
1839 QVariant v = QVariant::fromValue(sp); \
1840 QCOMPARE(v.typeName(), "QWeakPointer<" #ELEMENT_TYPE ">"); \
1841 QVERIFY(QMetaType::typeFlags(::qMetaTypeId<QWeakPointer < ELEMENT_TYPE > >()) & QMetaType::FLAG_TEST); \
1842 }
1843
1844 TEST_WEAK_SMARTPOINTER(QObject, WeakPointerToQObject)
1845 TEST_WEAK_SMARTPOINTER(QFile, WeakPointerToQObject)
1846 TEST_WEAK_SMARTPOINTER(QTemporaryFile, WeakPointerToQObject)
1847 TEST_WEAK_SMARTPOINTER(MyObject, WeakPointerToQObject)
1848#undef TEST_WEAK_SMARTPOINTER
1849}
1850
1851template <typename T>
1852struct StreamingTraits
1853{
1854 enum { isStreamable = 1 }; // Streamable by default
1855};
1856
1857// Non-streamable types
1858
1859#define DECLARE_NONSTREAMABLE(Type) \
1860 template<> struct StreamingTraits<Type> { enum { isStreamable = 0 }; };
1861
1862DECLARE_NONSTREAMABLE(void)
1863DECLARE_NONSTREAMABLE(void*)
1864DECLARE_NONSTREAMABLE(QModelIndex)
1865DECLARE_NONSTREAMABLE(QPersistentModelIndex)
1866DECLARE_NONSTREAMABLE(QObject*)
1867DECLARE_NONSTREAMABLE(QWidget*)
1868
1869#define DECLARE_GUI_CLASS_NONSTREAMABLE(MetaTypeName, MetaTypeId, RealType) \
1870 DECLARE_NONSTREAMABLE(RealType)
1871QT_FOR_EACH_STATIC_GUI_CLASS(DECLARE_GUI_CLASS_NONSTREAMABLE)
1872#undef DECLARE_GUI_CLASS_NONSTREAMABLE
1873
1874#define DECLARE_WIDGETS_CLASS_NONSTREAMABLE(MetaTypeName, MetaTypeId, RealType) \
1875 DECLARE_NONSTREAMABLE(RealType)
1876QT_FOR_EACH_STATIC_WIDGETS_CLASS(DECLARE_WIDGETS_CLASS_NONSTREAMABLE)
1877#undef DECLARE_WIDGETS_CLASS_NONSTREAMABLE
1878
1879#undef DECLARE_NONSTREAMABLE
1880
1881void tst_QMetaType::saveAndLoadBuiltin_data()
1882{
1883 QTest::addColumn<int>(name: "type");
1884 QTest::addColumn<bool>(name: "isStreamable");
1885
1886#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
1887 QTest::newRow(#RealType) << MetaTypeId << bool(StreamingTraits<RealType>::isStreamable);
1888 QT_FOR_EACH_STATIC_TYPE(ADD_METATYPE_TEST_ROW)
1889#undef ADD_METATYPE_TEST_ROW
1890}
1891
1892void tst_QMetaType::saveAndLoadBuiltin()
1893{
1894 QFETCH(int, type);
1895 QFETCH(bool, isStreamable);
1896
1897 void *value = QMetaType::create(type);
1898
1899 QByteArray ba;
1900 QDataStream stream(&ba, QIODevice::ReadWrite);
1901 QCOMPARE(QMetaType::save(stream, type, value), isStreamable);
1902 QCOMPARE(stream.status(), QDataStream::Ok);
1903
1904 if (isStreamable) {
1905 QVERIFY(QMetaType::load(stream, type, value)); // Hmmm, shouldn't it return false?
1906
1907 // std::nullptr_t is nullary: it doesn't actually read anything
1908 if (type != QMetaType::Nullptr)
1909 QCOMPARE(stream.status(), QDataStream::ReadPastEnd);
1910 }
1911
1912 stream.device()->seek(pos: 0);
1913 stream.resetStatus();
1914 QCOMPARE(QMetaType::load(stream, type, value), isStreamable);
1915 QCOMPARE(stream.status(), QDataStream::Ok);
1916
1917 if (isStreamable) {
1918 QVERIFY(QMetaType::load(stream, type, value)); // Hmmm, shouldn't it return false?
1919
1920 // std::nullptr_t is nullary: it doesn't actually read anything
1921 if (type != QMetaType::Nullptr)
1922 QCOMPARE(stream.status(), QDataStream::ReadPastEnd);
1923 }
1924
1925 QMetaType::destroy(type, data: value);
1926}
1927
1928struct CustomStreamableType
1929{
1930 int a;
1931};
1932Q_DECLARE_METATYPE(CustomStreamableType)
1933
1934QDataStream &operator<<(QDataStream &out, const CustomStreamableType &t)
1935{
1936 out << t.a; return out;
1937}
1938
1939QDataStream &operator>>(QDataStream &in, CustomStreamableType &t)
1940{
1941 int a;
1942 in >> a;
1943 if (in.status() == QDataStream::Ok)
1944 t.a = a;
1945 return in;
1946}
1947
1948void tst_QMetaType::saveAndLoadCustom()
1949{
1950 CustomStreamableType t;
1951 t.a = 123;
1952
1953 int id = ::qMetaTypeId<CustomStreamableType>();
1954 QByteArray ba;
1955 QDataStream stream(&ba, QIODevice::ReadWrite);
1956 QVERIFY(!QMetaType::save(stream, id, &t));
1957 QCOMPARE(stream.status(), QDataStream::Ok);
1958 QVERIFY(!QMetaType::load(stream, id, &t));
1959 QCOMPARE(stream.status(), QDataStream::Ok);
1960
1961 qRegisterMetaTypeStreamOperators<CustomStreamableType>(typeName: "CustomStreamableType");
1962 QVERIFY(QMetaType::save(stream, id, &t));
1963 QCOMPARE(stream.status(), QDataStream::Ok);
1964
1965 CustomStreamableType t2;
1966 t2.a = -1;
1967 QVERIFY(QMetaType::load(stream, id, &t2)); // Hmmm, shouldn't it return false?
1968 QCOMPARE(stream.status(), QDataStream::ReadPastEnd);
1969 QCOMPARE(t2.a, -1);
1970
1971 stream.device()->seek(pos: 0);
1972 stream.resetStatus();
1973 QVERIFY(QMetaType::load(stream, id, &t2));
1974 QCOMPARE(stream.status(), QDataStream::Ok);
1975 QCOMPARE(t2.a, t.a);
1976
1977 QVERIFY(QMetaType::load(stream, id, &t2)); // Hmmm, shouldn't it return false?
1978 QCOMPARE(stream.status(), QDataStream::ReadPastEnd);
1979}
1980
1981class MyGadget {
1982 Q_GADGET;
1983public:
1984 enum MyEnum { Val1, Val2, Val3 };
1985 Q_ENUM(MyEnum)
1986};
1987
1988class MyQObjectFromGadget : public QObject, public MyGadget
1989{
1990 Q_OBJECT
1991public:
1992 MyQObjectFromGadget(QObject *parent = 0)
1993 : QObject(parent)
1994 {}
1995};
1996
1997Q_DECLARE_METATYPE(MyGadget);
1998Q_DECLARE_METATYPE(MyGadget*);
1999Q_DECLARE_METATYPE(const QMetaObject *);
2000Q_DECLARE_METATYPE(Qt::ScrollBarPolicy);
2001Q_DECLARE_METATYPE(MyGadget::MyEnum);
2002Q_DECLARE_METATYPE(MyQObjectFromGadget*);
2003
2004void tst_QMetaType::metaObject_data()
2005{
2006 QTest::addColumn<int>(name: "type");
2007 QTest::addColumn<const QMetaObject*>(name: "result");
2008 QTest::addColumn<bool>(name: "isGadget");
2009 QTest::addColumn<bool>(name: "isGadgetPtr");
2010 QTest::addColumn<bool>(name: "isQObjectPtr");
2011
2012 QTest::newRow(dataTag: "QObject") << int(QMetaType::QObjectStar) << &QObject::staticMetaObject << false << false << true;
2013 QTest::newRow(dataTag: "QFile*") << ::qMetaTypeId<QFile*>() << &QFile::staticMetaObject << false << false << true;
2014 QTest::newRow(dataTag: "MyObject*") << ::qMetaTypeId<MyObject*>() << &MyObject::staticMetaObject << false << false << true;
2015 QTest::newRow(dataTag: "int") << int(QMetaType::Int) << static_cast<const QMetaObject *>(0) << false << false << false;
2016 QTest::newRow(dataTag: "QEasingCurve") << ::qMetaTypeId<QEasingCurve>() << &QEasingCurve::staticMetaObject << true << false << false;
2017 QTest::newRow(dataTag: "MyGadget") << ::qMetaTypeId<MyGadget>() << &MyGadget::staticMetaObject << true << false << false;
2018 QTest::newRow(dataTag: "MyGadget*") << ::qMetaTypeId<MyGadget*>() << &MyGadget::staticMetaObject << false << true << false;
2019 QTest::newRow(dataTag: "MyEnum") << ::qMetaTypeId<MyGadget::MyEnum>() << &MyGadget::staticMetaObject << false << false << false;
2020 QTest::newRow(dataTag: "Qt::ScrollBarPolicy") << ::qMetaTypeId<Qt::ScrollBarPolicy>() << &QObject::staticQtMetaObject << false << false << false;
2021 QTest::newRow(dataTag: "MyQObjectFromGadget*") << ::qMetaTypeId<MyQObjectFromGadget*>() << &MyQObjectFromGadget::staticMetaObject << false << false << true;
2022
2023 QTest::newRow(dataTag: "GadgetDerivedAndTyped<int>") << ::qMetaTypeId<GadgetDerivedAndTyped<int>>() << &GadgetDerivedAndTyped<int>::staticMetaObject << true << false << false;
2024 QTest::newRow(dataTag: "GadgetDerivedAndTyped<int>*") << ::qMetaTypeId<GadgetDerivedAndTyped<int>*>() << &GadgetDerivedAndTyped<int>::staticMetaObject << false << true << false;
2025}
2026
2027
2028void tst_QMetaType::metaObject()
2029{
2030 QFETCH(int, type);
2031 QFETCH(const QMetaObject *, result);
2032 QFETCH(bool, isGadget);
2033 QFETCH(bool, isGadgetPtr);
2034 QFETCH(bool, isQObjectPtr);
2035
2036 QCOMPARE(QMetaType::metaObjectForType(type), result);
2037 QMetaType mt(type);
2038 QCOMPARE(mt.metaObject(), result);
2039 QCOMPARE(!!(mt.flags() & QMetaType::IsGadget), isGadget);
2040 QCOMPARE(!!(mt.flags() & QMetaType::PointerToGadget), isGadgetPtr);
2041 QCOMPARE(!!(mt.flags() & QMetaType::PointerToQObject), isQObjectPtr);
2042}
2043
2044#define METATYPE_ID_FUNCTION(Type, MetaTypeId, Name) \
2045 case ::qMetaTypeId< Name >(): metaType = MetaTypeIdStruct<MetaTypeId>::Value; break;
2046
2047#define REGISTER_METATYPE_FUNCTION(Type, MetaTypeId, Name) \
2048 case qRegisterMetaType< Name >(): metaType = RegisterMetaTypeStruct<MetaTypeId>::Value; break;
2049
2050template<int>
2051struct MetaTypeIdStruct
2052{
2053};
2054
2055template<int>
2056struct RegisterMetaTypeStruct
2057{
2058};
2059
2060#define METATYPE_ID_STRUCT(Type, MetaTypeId, Name) \
2061template<> \
2062struct MetaTypeIdStruct< ::qMetaTypeId< Name >()> \
2063{ \
2064 enum { Value = ::qMetaTypeId< Name >() }; \
2065};
2066
2067#define REGISTER_METATYPE_STRUCT(Type, MetaTypeId, Name) \
2068template<> \
2069struct RegisterMetaTypeStruct<qRegisterMetaType< Name >()> \
2070{ \
2071 enum { Value = qRegisterMetaType< Name >() }; \
2072};
2073
2074#if defined(Q_COMPILER_CONSTEXPR)
2075QT_FOR_EACH_STATIC_TYPE(METATYPE_ID_STRUCT)
2076QT_FOR_EACH_STATIC_TYPE(REGISTER_METATYPE_STRUCT)
2077
2078template<int i = ::qMetaTypeId<int>()>
2079struct MetaTypeIdStructDefaultTemplateValue
2080{
2081 enum { Value };
2082};
2083
2084template<int i = qRegisterMetaType<int>()>
2085struct RegisterMetaTypeStructDefaultTemplateValue
2086{
2087 enum { Value };
2088};
2089#endif
2090
2091void tst_QMetaType::constexprMetaTypeIds()
2092{
2093#if defined(Q_COMPILER_CONSTEXPR)
2094 int id = 0;
2095 int metaType;
2096
2097 switch(id) {
2098 QT_FOR_EACH_STATIC_TYPE(METATYPE_ID_FUNCTION)
2099 metaType = MetaTypeIdStructDefaultTemplateValue<>::Value;
2100 default:;
2101 }
2102
2103 switch (id) {
2104 QT_FOR_EACH_STATIC_TYPE(REGISTER_METATYPE_FUNCTION)
2105 metaType = RegisterMetaTypeStructDefaultTemplateValue<>::Value;
2106 default:;
2107 }
2108 Q_UNUSED(metaType);
2109#else
2110 QSKIP("The test needs a compiler supporting constexpr");
2111#endif
2112}
2113
2114void tst_QMetaType::constRefs()
2115{
2116 QCOMPARE(::qMetaTypeId<const int &>(), ::qMetaTypeId<int>());
2117 QCOMPARE(::qMetaTypeId<const QString &>(), ::qMetaTypeId<QString>());
2118 QCOMPARE(::qMetaTypeId<const CustomMovable &>(), ::qMetaTypeId<CustomMovable>());
2119 QCOMPARE(::qMetaTypeId<const QList<CustomMovable> &>(), ::qMetaTypeId<QList<CustomMovable> >());
2120#if defined(Q_COMPILER_CONSTEXPR)
2121 Q_STATIC_ASSERT(::qMetaTypeId<const int &>() == ::qMetaTypeId<int>());
2122#endif
2123}
2124
2125struct CustomConvertibleType
2126{
2127 explicit CustomConvertibleType(const QVariant &foo = QVariant()) : m_foo(foo) {}
2128 virtual ~CustomConvertibleType() {}
2129 QString toString() const { return m_foo.toString(); }
2130 operator QPoint() const { return QPoint(12, 34); }
2131 template<typename To>
2132 To convert() const { return s_value.value<To>();}
2133 template<typename To>
2134 To convertOk(bool *ok) const { *ok = s_ok; return s_value.value<To>();}
2135
2136 QVariant m_foo;
2137 static QVariant s_value;
2138 static bool s_ok;
2139};
2140
2141bool operator<(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
2142{ return lhs.m_foo < rhs.m_foo; }
2143bool operator==(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
2144{ return lhs.m_foo == rhs.m_foo; }
2145bool operator!=(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
2146{ return !operator==(lhs, rhs); }
2147
2148QVariant CustomConvertibleType::s_value;
2149bool CustomConvertibleType::s_ok = true;
2150
2151struct CustomConvertibleType2
2152{
2153 // implicit
2154 CustomConvertibleType2(const CustomConvertibleType &t = CustomConvertibleType())
2155 : m_foo(t.m_foo) {}
2156 virtual ~CustomConvertibleType2() {}
2157
2158 QVariant m_foo;
2159};
2160
2161struct CustomDebugStreamableType
2162{
2163 QString toString() const { return "test"; }
2164};
2165
2166QDebug operator<<(QDebug dbg, const CustomDebugStreamableType&)
2167{
2168 return dbg << "string-content";
2169}
2170
2171bool operator==(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs)
2172{ return lhs.m_foo == rhs.m_foo; }
2173bool operator!=(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs)
2174{ return !operator==(lhs, rhs); }
2175
2176
2177struct CustomEqualsOnlyType
2178{
2179 explicit CustomEqualsOnlyType(int value = 0) : val(value) {}
2180 virtual ~CustomEqualsOnlyType() {}
2181
2182 int val;
2183};
2184bool operator==(const CustomEqualsOnlyType &lhs, const CustomEqualsOnlyType &rhs)
2185{ return lhs.val == rhs.val;}
2186bool operator!=(const CustomEqualsOnlyType &lhs, const CustomEqualsOnlyType &rhs)
2187{ return !operator==(lhs, rhs); }
2188
2189Q_DECLARE_METATYPE(CustomConvertibleType);
2190Q_DECLARE_METATYPE(CustomConvertibleType2);
2191Q_DECLARE_METATYPE(CustomDebugStreamableType);
2192Q_DECLARE_METATYPE(CustomEqualsOnlyType);
2193
2194template<typename T, typename U>
2195U convert(const T &t)
2196{
2197 return t;
2198}
2199
2200template<typename From>
2201struct ConvertFunctor
2202{
2203 CustomConvertibleType operator()(const From& f) const
2204 {
2205 return CustomConvertibleType(QVariant::fromValue(f));
2206 }
2207};
2208
2209template<typename From, typename To>
2210bool hasRegisteredConverterFunction()
2211{
2212 return QMetaType::hasRegisteredConverterFunction<From, To>();
2213}
2214
2215template<typename From, typename To>
2216void testCustomTypeNotYetConvertible()
2217{
2218 QVERIFY((!hasRegisteredConverterFunction<From, To>()));
2219 QVERIFY((!QVariant::fromValue<From>(From()).canConvert(qMetaTypeId<To>())));
2220}
2221
2222template<typename From, typename To>
2223void testCustomTypeConvertible()
2224{
2225 QVERIFY((hasRegisteredConverterFunction<From, To>()));
2226 QVERIFY((QVariant::fromValue<From>(From()).canConvert(qMetaTypeId<To>())));
2227}
2228
2229void customTypeNotYetConvertible()
2230{
2231 testCustomTypeNotYetConvertible<CustomConvertibleType, QString>();
2232 testCustomTypeNotYetConvertible<CustomConvertibleType, bool>();
2233 testCustomTypeNotYetConvertible<CustomConvertibleType, int>();
2234 testCustomTypeNotYetConvertible<CustomConvertibleType, double>();
2235 testCustomTypeNotYetConvertible<CustomConvertibleType, float>();
2236 testCustomTypeNotYetConvertible<CustomConvertibleType, QRect>();
2237 testCustomTypeNotYetConvertible<CustomConvertibleType, QRectF>();
2238 testCustomTypeNotYetConvertible<CustomConvertibleType, QPoint>();
2239 testCustomTypeNotYetConvertible<CustomConvertibleType, QPointF>();
2240 testCustomTypeNotYetConvertible<CustomConvertibleType, QSize>();
2241 testCustomTypeNotYetConvertible<CustomConvertibleType, QSizeF>();
2242 testCustomTypeNotYetConvertible<CustomConvertibleType, QLine>();
2243 testCustomTypeNotYetConvertible<CustomConvertibleType, QLineF>();
2244 testCustomTypeNotYetConvertible<CustomConvertibleType, QChar>();
2245 testCustomTypeNotYetConvertible<QString, CustomConvertibleType>();
2246 testCustomTypeNotYetConvertible<bool, CustomConvertibleType>();
2247 testCustomTypeNotYetConvertible<int, CustomConvertibleType>();
2248 testCustomTypeNotYetConvertible<double, CustomConvertibleType>();
2249 testCustomTypeNotYetConvertible<float, CustomConvertibleType>();
2250 testCustomTypeNotYetConvertible<QRect, CustomConvertibleType>();
2251 testCustomTypeNotYetConvertible<QRectF, CustomConvertibleType>();
2252 testCustomTypeNotYetConvertible<QPoint, CustomConvertibleType>();
2253 testCustomTypeNotYetConvertible<QPointF, CustomConvertibleType>();
2254 testCustomTypeNotYetConvertible<QSize, CustomConvertibleType>();
2255 testCustomTypeNotYetConvertible<QSizeF, CustomConvertibleType>();
2256 testCustomTypeNotYetConvertible<QLine, CustomConvertibleType>();
2257 testCustomTypeNotYetConvertible<QLineF, CustomConvertibleType>();
2258 testCustomTypeNotYetConvertible<QChar, CustomConvertibleType>();
2259 testCustomTypeNotYetConvertible<CustomConvertibleType, CustomConvertibleType2>();
2260}
2261
2262void registerCustomTypeConversions()
2263{
2264 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QString>(&CustomConvertibleType::convertOk<QString>)));
2265 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, bool>(&CustomConvertibleType::convert<bool>)));
2266 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, int>(&CustomConvertibleType::convertOk<int>)));
2267 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, double>(&CustomConvertibleType::convert<double>)));
2268 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, float>(&CustomConvertibleType::convertOk<float>)));
2269 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QRect>(&CustomConvertibleType::convert<QRect>)));
2270 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QRectF>(&CustomConvertibleType::convertOk<QRectF>)));
2271 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QPoint>(convert<CustomConvertibleType,QPoint>)));
2272 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QPointF>(&CustomConvertibleType::convertOk<QPointF>)));
2273 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QSize>(&CustomConvertibleType::convert<QSize>)));
2274 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QSizeF>(&CustomConvertibleType::convertOk<QSizeF>)));
2275 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QLine>(&CustomConvertibleType::convert<QLine>)));
2276 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QLineF>(&CustomConvertibleType::convertOk<QLineF>)));
2277 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QChar>(&CustomConvertibleType::convert<QChar>)));
2278 QVERIFY((QMetaType::registerConverter<QString, CustomConvertibleType>(ConvertFunctor<QString>())));
2279 QVERIFY((QMetaType::registerConverter<bool, CustomConvertibleType>(ConvertFunctor<bool>())));
2280 QVERIFY((QMetaType::registerConverter<int, CustomConvertibleType>(ConvertFunctor<int>())));
2281 QVERIFY((QMetaType::registerConverter<double, CustomConvertibleType>(ConvertFunctor<double>())));
2282 QVERIFY((QMetaType::registerConverter<float, CustomConvertibleType>(ConvertFunctor<float>())));
2283 QVERIFY((QMetaType::registerConverter<QRect, CustomConvertibleType>(ConvertFunctor<QRect>())));
2284 QVERIFY((QMetaType::registerConverter<QRectF, CustomConvertibleType>(ConvertFunctor<QRectF>())));
2285 QVERIFY((QMetaType::registerConverter<QPoint, CustomConvertibleType>(ConvertFunctor<QPoint>())));
2286 QVERIFY((QMetaType::registerConverter<QPointF, CustomConvertibleType>(ConvertFunctor<QPointF>())));
2287 QVERIFY((QMetaType::registerConverter<QSize, CustomConvertibleType>(ConvertFunctor<QSize>())));
2288 QVERIFY((QMetaType::registerConverter<QSizeF, CustomConvertibleType>(ConvertFunctor<QSizeF>())));
2289 QVERIFY((QMetaType::registerConverter<QLine, CustomConvertibleType>(ConvertFunctor<QLine>())));
2290 QVERIFY((QMetaType::registerConverter<QLineF, CustomConvertibleType>(ConvertFunctor<QLineF>())));
2291 QVERIFY((QMetaType::registerConverter<QChar, CustomConvertibleType>(ConvertFunctor<QChar>())));
2292 QVERIFY((QMetaType::registerConverter<CustomConvertibleType, CustomConvertibleType2>()));
2293 QTest::ignoreMessage(type: QtWarningMsg, message: "Type conversion already registered from type CustomConvertibleType to type CustomConvertibleType2");
2294 QVERIFY((!QMetaType::registerConverter<CustomConvertibleType, CustomConvertibleType2>()));
2295}
2296
2297void tst_QMetaType::convertCustomType_data()
2298{
2299 customTypeNotYetConvertible();
2300 registerCustomTypeConversions();
2301
2302 QTest::addColumn<bool>(name: "ok");
2303 QTest::addColumn<QString>(name: "testQString");
2304 QTest::addColumn<bool>(name: "testBool");
2305 QTest::addColumn<int>(name: "testInt");
2306 QTest::addColumn<double>(name: "testDouble");
2307 QTest::addColumn<float>(name: "testFloat");
2308 QTest::addColumn<QRect>(name: "testQRect");
2309 QTest::addColumn<QRectF>(name: "testQRectF");
2310 QTest::addColumn<QPoint>(name: "testQPoint");
2311 QTest::addColumn<QPointF>(name: "testQPointF");
2312 QTest::addColumn<QSize>(name: "testQSize");
2313 QTest::addColumn<QSizeF>(name: "testQSizeF");
2314 QTest::addColumn<QLine>(name: "testQLine");
2315 QTest::addColumn<QLineF>(name: "testQLineF");
2316 QTest::addColumn<QChar>(name: "testQChar");
2317 QTest::addColumn<CustomConvertibleType>(name: "testCustom");
2318
2319 QTest::newRow(dataTag: "default") << true
2320 << QString::fromLatin1(str: "string") << true << 15
2321 << double(3.14) << float(3.6) << QRect(1, 2, 3, 4)
2322 << QRectF(1.4, 1.9, 10.9, 40.2) << QPoint(12, 34)
2323 << QPointF(9.2, 2.7) << QSize(4, 9) << QSizeF(3.3, 9.8)
2324 << QLine(3, 9, 29, 4) << QLineF(38.9, 28.9, 102.3, 0.0)
2325 << QChar('Q') << CustomConvertibleType(QString::fromLatin1(str: "test"));
2326 QTest::newRow(dataTag: "not ok") << false
2327 << QString::fromLatin1(str: "string") << true << 15
2328 << double(3.14) << float(3.6) << QRect(1, 2, 3, 4)
2329 << QRectF(1.4, 1.9, 10.9, 40.2) << QPoint(12, 34)
2330 << QPointF(9.2, 2.7) << QSize(4, 9) << QSizeF(3.3, 9.8)
2331 << QLine(3, 9, 29, 4) << QLineF()
2332 << QChar('Q') << CustomConvertibleType(42);
2333}
2334
2335void tst_QMetaType::convertCustomType()
2336{
2337 QFETCH(bool, ok);
2338 CustomConvertibleType::s_ok = ok;
2339
2340 CustomConvertibleType t;
2341 QVariant v = QVariant::fromValue(value: t);
2342 QFETCH(QString, testQString);
2343 CustomConvertibleType::s_value = testQString;
2344 QCOMPARE(v.toString(), ok ? testQString : QString());
2345 QCOMPARE(v.value<QString>(), ok ? testQString : QString());
2346 QVERIFY(CustomConvertibleType::s_value.canConvert<CustomConvertibleType>());
2347 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toString()), testQString);
2348
2349 QFETCH(bool, testBool);
2350 CustomConvertibleType::s_value = testBool;
2351 QCOMPARE(v.toBool(), testBool);
2352 QCOMPARE(v.value<bool>(), testBool);
2353 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toBool()), testBool);
2354
2355 QFETCH(int, testInt);
2356 CustomConvertibleType::s_value = testInt;
2357 QCOMPARE(v.toInt(), ok ? testInt : 0);
2358 QCOMPARE(v.value<int>(), ok ? testInt : 0);
2359 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toInt()), testInt);
2360
2361 QFETCH(double, testDouble);
2362 CustomConvertibleType::s_value = testDouble;
2363 QCOMPARE(v.toDouble(), testDouble);
2364 QCOMPARE(v.value<double>(), testDouble);
2365 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toDouble()), testDouble);
2366
2367 QFETCH(float, testFloat);
2368 CustomConvertibleType::s_value = testFloat;
2369 QCOMPARE(v.toFloat(), ok ? testFloat : 0.0);
2370 QCOMPARE(v.value<float>(), ok ? testFloat : 0.0);
2371 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toFloat()), testFloat);
2372
2373 QFETCH(QRect, testQRect);
2374 CustomConvertibleType::s_value = testQRect;
2375 QCOMPARE(v.toRect(), testQRect);
2376 QCOMPARE(v.value<QRect>(), testQRect);
2377 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toRect()), testQRect);
2378
2379 QFETCH(QRectF, testQRectF);
2380 CustomConvertibleType::s_value = testQRectF;
2381 QCOMPARE(v.toRectF(), ok ? testQRectF : QRectF());
2382 QCOMPARE(v.value<QRectF>(), ok ? testQRectF : QRectF());
2383 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toRectF()), testQRectF);
2384
2385 QFETCH(QPoint, testQPoint);
2386 CustomConvertibleType::s_value = testQPoint;
2387 QCOMPARE(v.toPoint(), testQPoint);
2388 QCOMPARE(v.value<QPoint>(), testQPoint);
2389 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toPoint()), testQPoint);
2390
2391 QFETCH(QPointF, testQPointF);
2392 CustomConvertibleType::s_value = testQPointF;
2393 QCOMPARE(v.toPointF(), ok ? testQPointF : QPointF());
2394 QCOMPARE(v.value<QPointF>(), ok ? testQPointF : QPointF());
2395 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toPointF()), testQPointF);
2396
2397 QFETCH(QSize, testQSize);
2398 CustomConvertibleType::s_value = testQSize;
2399 QCOMPARE(v.toSize(), testQSize);
2400 QCOMPARE(v.value<QSize>(), testQSize);
2401 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toSize()), testQSize);
2402
2403 QFETCH(QSizeF, testQSizeF);
2404 CustomConvertibleType::s_value = testQSizeF;
2405 QCOMPARE(v.toSizeF(), ok ? testQSizeF : QSizeF());
2406 QCOMPARE(v.value<QSizeF>(), ok ? testQSizeF : QSizeF());
2407 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toSizeF()), testQSizeF);
2408
2409 QFETCH(QLine, testQLine);
2410 CustomConvertibleType::s_value = testQLine;
2411 QCOMPARE(v.toLine(), testQLine);
2412 QCOMPARE(v.value<QLine>(), testQLine);
2413 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toLine()), testQLine);
2414
2415 QFETCH(QLineF, testQLineF);
2416 CustomConvertibleType::s_value = testQLineF;
2417 QCOMPARE(v.toLineF(), ok ? testQLineF : QLineF());
2418 QCOMPARE(v.value<QLineF>(), ok ? testQLineF : QLineF());
2419 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toLineF()), testQLineF);
2420
2421 QFETCH(QChar, testQChar);
2422 CustomConvertibleType::s_value = testQChar;
2423 QCOMPARE(v.toChar(), testQChar);
2424 QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toChar()), testQChar);
2425
2426 QFETCH(CustomConvertibleType, testCustom);
2427 v = QVariant::fromValue(value: testCustom);
2428 QVERIFY(v.canConvert(::qMetaTypeId<CustomConvertibleType2>()));
2429 QCOMPARE(v.value<CustomConvertibleType2>().m_foo, testCustom.m_foo);
2430}
2431
2432void tst_QMetaType::compareCustomType_data()
2433{
2434 QMetaType::registerComparators<CustomConvertibleType>();
2435
2436 QTest::addColumn<QVariantList>(name: "unsorted");
2437 QTest::addColumn<QVariantList>(name: "sorted");
2438
2439 QTest::newRow(dataTag: "int") << (QVariantList() << 37 << 458 << 1 << 243 << -4 << 383)
2440 << (QVariantList() << -4 << 1 << 37 << 243 << 383 << 458);
2441
2442 QTest::newRow(dataTag: "dobule") << (QVariantList() << 4934.93 << 0.0 << 302.39 << -39.0)
2443 << (QVariantList() << -39.0 << 0.0 << 302.39 << 4934.93);
2444
2445 QTest::newRow(dataTag: "QString") << (QVariantList() << "Hello" << "World" << "this" << "is" << "a" << "test")
2446 << (QVariantList() << "a" << "Hello" << "is" << "test" << "this" << "World");
2447
2448 QTest::newRow(dataTag: "QTime") << (QVariantList() << QTime(14, 39) << QTime(0, 0) << QTime(18, 18) << QTime(9, 27))
2449 << (QVariantList() << QTime(0, 0) << QTime(9, 27) << QTime(14, 39) << QTime(18, 18));
2450
2451 QTest::newRow(dataTag: "QDate") << (QVariantList() << QDate(2013, 3, 23) << QDate(1900, 12, 1) << QDate(2001, 2, 2) << QDate(1982, 12, 16))
2452 << (QVariantList() << QDate(1900, 12, 1) << QDate(1982, 12, 16) << QDate(2001, 2, 2) << QDate(2013, 3, 23));
2453
2454 QTest::newRow(dataTag: "mixed") << (QVariantList() << "Hello" << "World" << QChar('a') << 38 << QChar('z') << -39 << 4.6)
2455 << (QVariantList() << -39 << 4.6 << 38 << QChar('a') << "Hello" << "World" << QChar('z'));
2456
2457 QTest::newRow(dataTag: "custom") << (QVariantList() << QVariant::fromValue(value: CustomConvertibleType(1)) << QVariant::fromValue(value: CustomConvertibleType(100)) << QVariant::fromValue(value: CustomConvertibleType(50)))
2458 << (QVariantList() << QVariant::fromValue(value: CustomConvertibleType(1)) << QVariant::fromValue(value: CustomConvertibleType(50)) << QVariant::fromValue(value: CustomConvertibleType(100)));
2459}
2460
2461void tst_QMetaType::compareCustomType()
2462{
2463 QFETCH(QVariantList, unsorted);
2464 QFETCH(QVariantList, sorted);
2465 std::sort(first: unsorted.begin(), last: unsorted.end());
2466 QCOMPARE(unsorted, sorted);
2467}
2468
2469void tst_QMetaType::compareCustomEqualOnlyType()
2470{
2471 int metaTypeId = qRegisterMetaType<CustomEqualsOnlyType>();
2472 QMetaType::registerEqualsComparator<CustomEqualsOnlyType>();
2473 int result;
2474
2475 CustomEqualsOnlyType val50(50);
2476 CustomEqualsOnlyType val100(100);
2477 CustomEqualsOnlyType val100x(100);
2478
2479 QVariant variant50 = QVariant::fromValue(value: val50);
2480 QVariant variant100 = QVariant::fromValue(value: val100);
2481 QVariant variant100x = QVariant::fromValue(value: val100x);
2482
2483 QVERIFY(variant50 != variant100);
2484 QVERIFY(variant50 != variant100x);
2485 QVERIFY(variant100 != variant50);
2486 QVERIFY(variant100x != variant50);
2487 QCOMPARE(variant100, variant100x);
2488 QCOMPARE(variant100, variant100);
2489
2490 // compare always fails
2491 QVERIFY(!(variant50 < variant50));
2492 QVERIFY(!(variant50 < variant100));
2493 QVERIFY(!(variant100 < variant50));
2494
2495 // check QMetaType::compare works/doesn't crash for equals only comparators
2496 bool wasSuccess = QMetaType::compare(lhs: variant50.constData(), rhs: variant50.constData(),
2497 typeId: metaTypeId, result: &result);
2498 QCOMPARE(result, 0);
2499 QVERIFY(wasSuccess);
2500 wasSuccess = QMetaType::compare(lhs: variant100.constData(), rhs: variant100x.constData(),
2501 typeId: metaTypeId, result: &result);
2502 QCOMPARE(result, 0);
2503 QVERIFY(wasSuccess);
2504
2505 wasSuccess = QMetaType::compare(lhs: variant50.constData(), rhs: variant100.constData(),
2506 typeId: metaTypeId, result: &result);
2507 QVERIFY(!wasSuccess);
2508
2509 // check QMetaType::equals works for equals only comparator
2510 wasSuccess = QMetaType::equals(lhs: variant50.constData(), rhs: variant50.constData(),
2511 typeId: metaTypeId, result: &result);
2512 QCOMPARE(result, 0);
2513 QVERIFY(wasSuccess);
2514 wasSuccess = QMetaType::equals(lhs: variant100.constData(), rhs: variant100.constData(),
2515 typeId: metaTypeId, result: &result);
2516 QCOMPARE(result, 0);
2517 QVERIFY(wasSuccess);
2518 wasSuccess = QMetaType::equals(lhs: variant100x.constData(), rhs: variant100x.constData(),
2519 typeId: metaTypeId, result: &result);
2520 QCOMPARE(result, 0);
2521 QVERIFY(wasSuccess);
2522 wasSuccess = QMetaType::equals(lhs: variant100.constData(), rhs: variant100x.constData(),
2523 typeId: metaTypeId, result: &result);
2524 QCOMPARE(result, 0);
2525 QVERIFY(wasSuccess);
2526 wasSuccess = QMetaType::equals(lhs: variant50.constData(), rhs: variant100.constData(),
2527 typeId: metaTypeId, result: &result);
2528 QCOMPARE(result, -1);
2529 QVERIFY(wasSuccess);
2530 wasSuccess = QMetaType::equals(lhs: variant50.constData(), rhs: variant100x.constData(),
2531 typeId: metaTypeId, result: &result);
2532 QCOMPARE(result, -1);
2533 QVERIFY(wasSuccess);
2534
2535 //check QMetaType::equals for type w/o equals comparator being registered
2536 CustomMovable movable1;
2537 CustomMovable movable2;
2538 wasSuccess = QMetaType::equals(lhs: &movable1, rhs: &movable2,
2539 typeId: qRegisterMetaType<CustomMovable>(), result: &result);
2540 QVERIFY(!wasSuccess);
2541
2542}
2543
2544struct MessageHandlerCustom : public MessageHandler
2545{
2546 MessageHandlerCustom(const int typeId)
2547 : MessageHandler(typeId, handler)
2548 {}
2549 static void handler(QtMsgType, const QMessageLogContext &, const QString &msg)
2550 {
2551 QCOMPARE(msg.trimmed(), expectedMessage.trimmed());
2552 }
2553 static QString expectedMessage;
2554};
2555
2556QString MessageHandlerCustom::expectedMessage;
2557
2558void tst_QMetaType::customDebugStream()
2559{
2560 MessageHandlerCustom handler(::qMetaTypeId<CustomDebugStreamableType>());
2561 QVariant v1 = QVariant::fromValue(value: CustomDebugStreamableType());
2562 handler.expectedMessage = "QVariant(CustomDebugStreamableType, )";
2563 qDebug() << v1;
2564
2565 QMetaType::registerConverter<CustomDebugStreamableType, QString>(function: &CustomDebugStreamableType::toString);
2566 handler.expectedMessage = "QVariant(CustomDebugStreamableType, \"test\")";
2567 qDebug() << v1;
2568
2569 QMetaType::registerDebugStreamOperator<CustomDebugStreamableType>();
2570 handler.expectedMessage = "QVariant(CustomDebugStreamableType, string-content)";
2571 qDebug() << v1;
2572}
2573
2574void tst_QMetaType::unknownType()
2575{
2576 QMetaType invalid(QMetaType::UnknownType);
2577 QVERIFY(!invalid.create());
2578 QVERIFY(!invalid.sizeOf());
2579 QVERIFY(!invalid.metaObject());
2580 int buffer = 0xBAD;
2581 invalid.construct(where: &buffer);
2582 QCOMPARE(buffer, 0xBAD);
2583}
2584
2585void tst_QMetaType::fromType()
2586{
2587 #define FROMTYPE_CHECK(MetaTypeName, MetaTypeId, RealType) \
2588 QCOMPARE(QMetaType::fromType<RealType>(), QMetaType(MetaTypeId)); \
2589 QVERIFY(QMetaType::fromType<RealType>() == QMetaType(MetaTypeId)); \
2590 QVERIFY(!(QMetaType::fromType<RealType>() != QMetaType(MetaTypeId))); \
2591 QCOMPARE(QMetaType::fromType<RealType>().id(), MetaTypeId);
2592
2593 FOR_EACH_CORE_METATYPE(FROMTYPE_CHECK)
2594
2595 QVERIFY(QMetaType::fromType<QString>() != QMetaType());
2596 QCOMPARE(QMetaType(), QMetaType());
2597 QCOMPARE(QMetaType(QMetaType::UnknownType), QMetaType());
2598
2599 FROMTYPE_CHECK(_, ::qMetaTypeId<Whity<int>>(), Whity<int>)
2600 #undef FROMTYPE_CHECK
2601}
2602
2603
2604// Compile-time test, it should be possible to register function pointer types
2605class Undefined;
2606
2607typedef Undefined (*UndefinedFunction0)();
2608typedef Undefined (*UndefinedFunction1)(Undefined);
2609typedef Undefined (*UndefinedFunction2)(Undefined, Undefined);
2610typedef Undefined (*UndefinedFunction3)(Undefined, Undefined, Undefined);
2611typedef Undefined (*UndefinedFunction4)(Undefined, Undefined, Undefined, Undefined, Undefined, Undefined, Undefined, Undefined);
2612
2613Q_DECLARE_METATYPE(UndefinedFunction0);
2614Q_DECLARE_METATYPE(UndefinedFunction1);
2615Q_DECLARE_METATYPE(UndefinedFunction2);
2616Q_DECLARE_METATYPE(UndefinedFunction3);
2617Q_DECLARE_METATYPE(UndefinedFunction4);
2618
2619QTEST_MAIN(tst_QMetaType)
2620#include "tst_qmetatype.moc"
2621

source code of qtbase/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp