Introduce QMetaType::UnknownType.
[profile/ivi/qtbase.git] / tests / auto / corelib / kernel / qmetatype / tst_qmetatype.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtCore>
44 #include <QtTest/QtTest>
45
46 #ifdef Q_OS_LINUX
47 # include <pthread.h>
48 #endif
49
50 Q_DECLARE_METATYPE(QMetaType::Type)
51
52 class tst_QMetaType: public QObject
53 {
54     Q_OBJECT
55     Q_PROPERTY(QList<QVariant> prop READ prop WRITE setProp)
56
57 public:
58     tst_QMetaType() { propList << 42 << "Hello"; }
59
60     QList<QVariant> prop() const { return propList; }
61     void setProp(const QList<QVariant> &list) { propList = list; }
62
63 private:
64     QList<QVariant> propList;
65
66 private slots:
67     void defined();
68     void threadSafety();
69     void namespaces();
70     void qMetaTypeId();
71     void properties();
72     void normalizedTypes();
73     void typeName_data();
74     void typeName();
75     void create_data();
76     void create();
77     void createCopy_data();
78     void createCopy();
79     void sizeOf_data();
80     void sizeOf();
81     void sizeOfStaticLess_data();
82     void sizeOfStaticLess();
83     void flags_data();
84     void flags();
85     void flagsStaticLess_data();
86     void flagsStaticLess();
87     void construct_data();
88     void construct();
89     void constructCopy_data();
90     void constructCopy();
91     void typedefs();
92     void registerType();
93     void isRegistered_data();
94     void isRegistered();
95     void isRegisteredStaticLess_data();
96     void isRegisteredStaticLess();
97     void registerStreamBuiltin();
98     void automaticTemplateRegistration();
99 };
100
101 struct Foo { int i; };
102
103 void tst_QMetaType::defined()
104 {
105     QCOMPARE(int(QMetaTypeId2<QString>::Defined), 1);
106     QCOMPARE(int(QMetaTypeId2<Foo>::Defined), 0);
107     QCOMPARE(int(QMetaTypeId2<void*>::Defined), 1);
108     QCOMPARE(int(QMetaTypeId2<int*>::Defined), 0);
109 }
110
111 struct Bar
112 {
113     Bar()
114     {
115         // check re-entrancy
116         if (!QMetaType::isRegistered(qRegisterMetaType<Foo>("Foo"))) {
117             qWarning("%s: re-entrancy test failed", Q_FUNC_INFO);
118             ++failureCount;
119         }
120     }
121
122 public:
123     static int failureCount;
124 };
125
126 int Bar::failureCount = 0;
127
128 class MetaTypeTorturer: public QThread
129 {
130     Q_OBJECT
131 protected:
132     void run()
133     {
134         Bar space[1];
135         space[0].~Bar();
136
137         for (int i = 0; i < 1000; ++i) {
138             const QByteArray name = QString("Bar%1_%2").arg(i).arg((size_t)QThread::currentThreadId()).toLatin1();
139             const char *nm = name.constData();
140             int tp = qRegisterMetaType<Bar>(nm);
141 #ifdef Q_OS_LINUX
142             pthread_yield();
143 #endif
144             QMetaType info(tp);
145             if (!info.isValid()) {
146                 ++failureCount;
147                 qWarning() << "Wrong typeInfo returned for" << tp;
148             }
149             if (!info.isRegistered()) {
150                 ++failureCount;
151                 qWarning() << name << "is not a registered metatype";
152             }
153             if (QMetaType::typeFlags(tp) != (QMetaType::NeedsConstruction | QMetaType::NeedsDestruction)) {
154                 ++failureCount;
155                 qWarning() << "Wrong typeInfo returned for" << tp;
156             }
157             if (!QMetaType::isRegistered(tp)) {
158                 ++failureCount;
159                 qWarning() << name << "is not a registered metatype";
160             }
161             if (QMetaType::type(nm) != tp) {
162                 ++failureCount;
163                 qWarning() << "Wrong metatype returned for" << name;
164             }
165             if (QMetaType::typeName(tp) != name) {
166                 ++failureCount;
167                 qWarning() << "Wrong typeName returned for" << tp;
168             }
169             void *buf1 = QMetaType::create(tp, 0);
170             void *buf2 = QMetaType::create(tp, buf1);
171             void *buf3 = info.create(tp, 0);
172             void *buf4 = info.create(tp, buf1);
173
174             QMetaType::construct(tp, space, 0);
175             QMetaType::destruct(tp, space);
176             QMetaType::construct(tp, space, buf1);
177             QMetaType::destruct(tp, space);
178
179             info.construct(space, 0);
180             info.destruct(space);
181             info.construct(space, buf1);
182             info.destruct(space);
183
184             if (!buf1) {
185                 ++failureCount;
186                 qWarning() << "Null buffer returned by QMetaType::create(tp, 0)";
187             }
188             if (!buf2) {
189                 ++failureCount;
190                 qWarning() << "Null buffer returned by QMetaType::create(tp, buf)";
191             }
192             if (!buf3) {
193                 ++failureCount;
194                 qWarning() << "Null buffer returned by info.create(tp, 0)";
195             }
196             if (!buf4) {
197                 ++failureCount;
198                 qWarning() << "Null buffer returned by infocreate(tp, buf)";
199             }
200             QMetaType::destroy(tp, buf1);
201             QMetaType::destroy(tp, buf2);
202             info.destroy(buf3);
203             info.destroy(buf4);
204         }
205         new (space) Bar;
206     }
207 public:
208     MetaTypeTorturer() : failureCount(0) { }
209     int failureCount;
210 };
211
212 void tst_QMetaType::threadSafety()
213 {
214     MetaTypeTorturer t1;
215     MetaTypeTorturer t2;
216     MetaTypeTorturer t3;
217
218     t1.start();
219     t2.start();
220     t3.start();
221
222     QVERIFY(t1.wait());
223     QVERIFY(t2.wait());
224     QVERIFY(t3.wait());
225
226     QCOMPARE(t1.failureCount, 0);
227     QCOMPARE(t2.failureCount, 0);
228     QCOMPARE(t3.failureCount, 0);
229     QCOMPARE(Bar::failureCount, 0);
230 }
231
232 namespace TestSpace
233 {
234     struct Foo { double d; };
235
236 }
237 Q_DECLARE_METATYPE(TestSpace::Foo)
238
239 void tst_QMetaType::namespaces()
240 {
241     TestSpace::Foo nf = { 11.12 };
242     QVariant v = qVariantFromValue(nf);
243     QCOMPARE(qvariant_cast<TestSpace::Foo>(v).d, 11.12);
244 }
245
246 void tst_QMetaType::qMetaTypeId()
247 {
248     QCOMPARE(::qMetaTypeId<QString>(), int(QMetaType::QString));
249     QCOMPARE(::qMetaTypeId<int>(), int(QMetaType::Int));
250     QCOMPARE(::qMetaTypeId<TestSpace::Foo>(), QMetaType::type("TestSpace::Foo"));
251
252     QCOMPARE(::qMetaTypeId<char>(), QMetaType::type("char"));
253     QCOMPARE(::qMetaTypeId<uchar>(), QMetaType::type("unsigned char"));
254     QCOMPARE(::qMetaTypeId<signed char>(), QMetaType::type("signed char"));
255     QCOMPARE(::qMetaTypeId<qint8>(), QMetaType::type("qint8"));
256 }
257
258 void tst_QMetaType::properties()
259 {
260     qRegisterMetaType<QList<QVariant> >("QList<QVariant>");
261
262     QVariant v = property("prop");
263
264     QCOMPARE(v.typeName(), "QVariantList");
265
266     QList<QVariant> values = v.toList();
267     QCOMPARE(values.count(), 2);
268     QCOMPARE(values.at(0).toInt(), 42);
269
270     values << 43 << "world";
271
272     QVERIFY(setProperty("prop", values));
273     v = property("prop");
274     QCOMPARE(v.toList().count(), 4);
275 }
276
277 template <typename T>
278 struct Whity { T t; };
279
280 Q_DECLARE_METATYPE( Whity < int > )
281 Q_DECLARE_METATYPE(Whity<double>)
282
283 void tst_QMetaType::normalizedTypes()
284 {
285     int WhityIntId = ::qMetaTypeId<Whity<int> >();
286     int WhityDoubleId = ::qMetaTypeId<Whity<double> >();
287
288     QCOMPARE(QMetaType::type("Whity<int>"), WhityIntId);
289     QCOMPARE(QMetaType::type(" Whity < int > "), WhityIntId);
290     QCOMPARE(QMetaType::type("Whity<int >"), WhityIntId);
291
292     QCOMPARE(QMetaType::type("Whity<double>"), WhityDoubleId);
293     QCOMPARE(QMetaType::type(" Whity< double > "), WhityDoubleId);
294     QCOMPARE(QMetaType::type("Whity<double >"), WhityDoubleId);
295
296     QCOMPARE(qRegisterMetaType<Whity<int> >(" Whity < int > "), WhityIntId);
297     QCOMPARE(qRegisterMetaType<Whity<int> >("Whity<int>"), WhityIntId);
298     QCOMPARE(qRegisterMetaType<Whity<int> >("Whity<int > "), WhityIntId);
299
300     QCOMPARE(qRegisterMetaType<Whity<double> >(" Whity < double > "), WhityDoubleId);
301     QCOMPARE(qRegisterMetaType<Whity<double> >("Whity<double>"), WhityDoubleId);
302     QCOMPARE(qRegisterMetaType<Whity<double> >("Whity<double > "), WhityDoubleId);
303 }
304
305 #define TYPENAME_DATA(MetaTypeName, MetaTypeId, RealType)\
306     QTest::newRow(#RealType) << QMetaType::MetaTypeName << #RealType;
307
308 #define TYPENAME_DATA_ALIAS(MetaTypeName, MetaTypeId, AliasType, RealTypeString)\
309     QTest::newRow(RealTypeString) << QMetaType::MetaTypeName << #AliasType;
310
311 void tst_QMetaType::typeName_data()
312 {
313     QTest::addColumn<QMetaType::Type>("aType");
314     QTest::addColumn<QString>("aTypeName");
315
316     QT_FOR_EACH_STATIC_TYPE(TYPENAME_DATA)
317     QT_FOR_EACH_STATIC_ALIAS_TYPE(TYPENAME_DATA_ALIAS)
318     QTest::newRow("QMetaType::UnknownType") << QMetaType::UnknownType << static_cast<const char*>(0);
319 }
320
321 void tst_QMetaType::typeName()
322 {
323     QFETCH(QMetaType::Type, aType);
324     QFETCH(QString, aTypeName);
325
326     QCOMPARE(QString::fromLatin1(QMetaType::typeName(aType)), aTypeName);
327 }
328
329 #define FOR_EACH_PRIMITIVE_METATYPE(F) \
330     QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F) \
331     QT_FOR_EACH_STATIC_CORE_POINTER(F) \
332
333 #define FOR_EACH_COMPLEX_CORE_METATYPE(F) \
334     QT_FOR_EACH_STATIC_CORE_CLASS(F)
335
336 #define FOR_EACH_CORE_METATYPE(F) \
337     FOR_EACH_PRIMITIVE_METATYPE(F) \
338     FOR_EACH_COMPLEX_CORE_METATYPE(F) \
339
340 template <int ID>
341 struct MetaEnumToType {};
342
343 #define DEFINE_META_ENUM_TO_TYPE(MetaTypeName, MetaTypeId, RealType) \
344 template<> \
345 struct MetaEnumToType<QMetaType::MetaTypeName> { \
346     typedef RealType Type; \
347 };
348 FOR_EACH_CORE_METATYPE(DEFINE_META_ENUM_TO_TYPE)
349 #undef DEFINE_META_ENUM_TO_TYPE
350
351 template <int ID>
352 struct DefaultValueFactory
353 {
354     typedef typename MetaEnumToType<ID>::Type Type;
355     static Type *create() { return new Type; }
356 };
357
358 template <>
359 struct DefaultValueFactory<QMetaType::Void>
360 {
361     typedef MetaEnumToType<QMetaType::Void>::Type Type;
362     static Type *create() { return 0; }
363 };
364
365 template <int ID>
366 struct DefaultValueTraits
367 {
368     // By default we assume that a default-constructed value (new T) is
369     // initialized; e.g. QCOMPARE(*(new T), *(new T)) should succeed
370     enum { IsInitialized = true };
371 };
372
373 #define DEFINE_NON_INITIALIZED_DEFAULT_VALUE_TRAITS(MetaTypeName, MetaTypeId, RealType) \
374 template<> struct DefaultValueTraits<QMetaType::MetaTypeName> { \
375     enum { IsInitialized = false }; \
376 };
377 // Primitive types (int et al) aren't initialized
378 FOR_EACH_PRIMITIVE_METATYPE(DEFINE_NON_INITIALIZED_DEFAULT_VALUE_TRAITS)
379 #undef DEFINE_NON_INITIALIZED_DEFAULT_VALUE_TRAITS
380
381 template <int ID>
382 struct TestValueFactory {};
383
384 template<> struct TestValueFactory<QMetaType::Void> {
385     static void *create() { return 0; }
386 };
387
388 template<> struct TestValueFactory<QMetaType::QString> {
389     static QString *create() { return new QString(QString::fromLatin1("QString")); }
390 };
391 template<> struct TestValueFactory<QMetaType::Int> {
392     static int *create() { return new int(0x12345678); }
393 };
394 template<> struct TestValueFactory<QMetaType::UInt> {
395     static uint *create() { return new uint(0x12345678); }
396 };
397 template<> struct TestValueFactory<QMetaType::Bool> {
398     static bool *create() { return new bool(true); }
399 };
400 template<> struct TestValueFactory<QMetaType::Double> {
401     static double *create() { return new double(3.14); }
402 };
403 template<> struct TestValueFactory<QMetaType::QByteArray> {
404     static QByteArray *create() { return new QByteArray(QByteArray("QByteArray")); }
405 };
406 template<> struct TestValueFactory<QMetaType::QChar> {
407     static QChar *create() { return new QChar(QChar('q')); }
408 };
409 template<> struct TestValueFactory<QMetaType::Long> {
410     static long *create() { return new long(0x12345678); }
411 };
412 template<> struct TestValueFactory<QMetaType::Short> {
413     static short *create() { return new short(0x1234); }
414 };
415 template<> struct TestValueFactory<QMetaType::Char> {
416     static char *create() { return new char('c'); }
417 };
418 template<> struct TestValueFactory<QMetaType::ULong> {
419     static ulong *create() { return new ulong(0x12345678); }
420 };
421 template<> struct TestValueFactory<QMetaType::UShort> {
422     static ushort *create() { return new ushort(0x1234); }
423 };
424 template<> struct TestValueFactory<QMetaType::UChar> {
425     static uchar *create() { return new uchar('u'); }
426 };
427 template<> struct TestValueFactory<QMetaType::Float> {
428     static float *create() { return new float(3.14); }
429 };
430 template<> struct TestValueFactory<QMetaType::QObjectStar> {
431     static QObject * *create() { return new QObject *(0); }
432 };
433 template<> struct TestValueFactory<QMetaType::QWidgetStar> {
434     static QWidget * *create() { return new QWidget *(0); }
435 };
436 template<> struct TestValueFactory<QMetaType::VoidStar> {
437     static void * *create() { return new void *(0); }
438 };
439 template<> struct TestValueFactory<QMetaType::LongLong> {
440     static qlonglong *create() { return new qlonglong(0x12345678); }
441 };
442 template<> struct TestValueFactory<QMetaType::ULongLong> {
443     static qulonglong *create() { return new qulonglong(0x12345678); }
444 };
445 template<> struct TestValueFactory<QMetaType::QStringList> {
446     static QStringList *create() { return new QStringList(QStringList() << "Q" << "t"); }
447 };
448 template<> struct TestValueFactory<QMetaType::QBitArray> {
449     static QBitArray *create() { return new QBitArray(QBitArray(256, true)); }
450 };
451 template<> struct TestValueFactory<QMetaType::QDate> {
452     static QDate *create() { return new QDate(QDate::currentDate()); }
453 };
454 template<> struct TestValueFactory<QMetaType::QTime> {
455     static QTime *create() { return new QTime(QTime::currentTime()); }
456 };
457 template<> struct TestValueFactory<QMetaType::QDateTime> {
458     static QDateTime *create() { return new QDateTime(QDateTime::currentDateTime()); }
459 };
460 template<> struct TestValueFactory<QMetaType::QUrl> {
461     static QUrl *create() { return new QUrl("http://www.example.org"); }
462 };
463 template<> struct TestValueFactory<QMetaType::QLocale> {
464     static QLocale *create() { return new QLocale(QLocale::c()); }
465 };
466 template<> struct TestValueFactory<QMetaType::QRect> {
467     static QRect *create() { return new QRect(10, 20, 30, 40); }
468 };
469 template<> struct TestValueFactory<QMetaType::QRectF> {
470     static QRectF *create() { return new QRectF(10, 20, 30, 40); }
471 };
472 template<> struct TestValueFactory<QMetaType::QSize> {
473     static QSize *create() { return new QSize(10, 20); }
474 };
475 template<> struct TestValueFactory<QMetaType::QSizeF> {
476     static QSizeF *create() { return new QSizeF(10, 20); }
477 };
478 template<> struct TestValueFactory<QMetaType::QLine> {
479     static QLine *create() { return new QLine(10, 20, 30, 40); }
480 };
481 template<> struct TestValueFactory<QMetaType::QLineF> {
482     static QLineF *create() { return new QLineF(10, 20, 30, 40); }
483 };
484 template<> struct TestValueFactory<QMetaType::QPoint> {
485     static QPoint *create() { return new QPoint(10, 20); }
486 };
487 template<> struct TestValueFactory<QMetaType::QPointF> {
488     static QPointF *create() { return new QPointF(10, 20); }
489 };
490 template<> struct TestValueFactory<QMetaType::QEasingCurve> {
491     static QEasingCurve *create() { return new QEasingCurve(QEasingCurve::InOutElastic); }
492 };
493 template<> struct TestValueFactory<QMetaType::QUuid> {
494     static QUuid *create() { return new QUuid(); }
495 };
496 template<> struct TestValueFactory<QMetaType::QModelIndex> {
497     static QModelIndex *create() { return new QModelIndex(); }
498 };
499 template<> struct TestValueFactory<QMetaType::QRegExp> {
500     static QRegExp *create()
501     {
502 #ifndef QT_NO_REGEXP
503         return new QRegExp("A*");
504 #else
505         return 0;
506 #endif
507     }
508 };
509 template<> struct TestValueFactory<QMetaType::QVariant> {
510     static QVariant *create() { return new QVariant(QStringList(QStringList() << "Q" << "t")); }
511 };
512
513 void tst_QMetaType::create_data()
514 {
515     QTest::addColumn<QMetaType::Type>("type");
516 #define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
517     QTest::newRow(QMetaType::typeName(QMetaType::MetaTypeName)) << QMetaType::MetaTypeName;
518 FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW)
519 #undef ADD_METATYPE_TEST_ROW
520 }
521
522 template<int ID>
523 static void testCreateHelper()
524 {
525     typedef typename MetaEnumToType<ID>::Type Type;
526     QMetaType info(ID);
527     void *actual1 = QMetaType::create(ID);
528     void *actual2 = info.create();
529     if (DefaultValueTraits<ID>::IsInitialized) {
530         Type *expected = DefaultValueFactory<ID>::create();
531         QCOMPARE(*static_cast<Type *>(actual1), *expected);
532         QCOMPARE(*static_cast<Type *>(actual2), *expected);
533         delete expected;
534     }
535     QMetaType::destroy(ID, actual1);
536     info.destroy(actual2);
537 }
538
539 template<>
540 void testCreateHelper<QMetaType::Void>()
541 {
542     typedef MetaEnumToType<QMetaType::Void>::Type Type;
543     void *actual = QMetaType::create(QMetaType::Void);
544     if (DefaultValueTraits<QMetaType::Void>::IsInitialized) {
545         QVERIFY(DefaultValueFactory<QMetaType::Void>::create());
546     }
547     QMetaType::destroy(QMetaType::Void, actual);
548 }
549
550
551 typedef void (*TypeTestFunction)();
552
553 void tst_QMetaType::create()
554 {
555     struct TypeTestFunctionGetter
556     {
557         static TypeTestFunction get(int type)
558         {
559             switch (type) {
560 #define RETURN_CREATE_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
561             case QMetaType::MetaTypeName: \
562             return testCreateHelper<QMetaType::MetaTypeName>;
563 FOR_EACH_CORE_METATYPE(RETURN_CREATE_FUNCTION)
564 #undef RETURN_CREATE_FUNCTION
565             }
566             return 0;
567         }
568     };
569
570     QFETCH(QMetaType::Type, type);
571     TypeTestFunctionGetter::get(type)();
572 }
573
574 template<int ID>
575 static void testCreateCopyHelper()
576 {
577     typedef typename MetaEnumToType<ID>::Type Type;
578     Type *expected = TestValueFactory<ID>::create();
579     QMetaType info(ID);
580     void *actual1 = QMetaType::create(ID, expected);
581     void *actual2 = info.create(expected);
582     QCOMPARE(*static_cast<Type *>(actual1), *expected);
583     QCOMPARE(*static_cast<Type *>(actual2), *expected);
584     QMetaType::destroy(ID, actual1);
585     info.destroy(actual2);
586     delete expected;
587 }
588
589 template<>
590 void testCreateCopyHelper<QMetaType::Void>()
591 {
592     typedef MetaEnumToType<QMetaType::Void>::Type Type;
593     Type *expected = TestValueFactory<QMetaType::Void>::create();
594     void *actual = QMetaType::create(QMetaType::Void, expected);
595     QCOMPARE(static_cast<Type *>(actual), expected);
596     QMetaType::destroy(QMetaType::Void, actual);
597 }
598
599 void tst_QMetaType::createCopy_data()
600 {
601     create_data();
602 }
603
604 void tst_QMetaType::createCopy()
605 {
606     struct TypeTestFunctionGetter
607     {
608         static TypeTestFunction get(int type)
609         {
610             switch (type) {
611 #define RETURN_CREATE_COPY_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
612             case QMetaType::MetaTypeName: \
613             return testCreateCopyHelper<QMetaType::MetaTypeName>;
614 FOR_EACH_CORE_METATYPE(RETURN_CREATE_COPY_FUNCTION)
615 #undef RETURN_CREATE_COPY_FUNCTION
616             }
617             return 0;
618         }
619     };
620
621     QFETCH(QMetaType::Type, type);
622     TypeTestFunctionGetter::get(type)();
623 }
624
625 void tst_QMetaType::sizeOf_data()
626 {
627     QTest::addColumn<QMetaType::Type>("type");
628     QTest::addColumn<int>("size");
629
630     QTest::newRow("QMetaType::UnknownType") << QMetaType::UnknownType << 0;
631 #define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
632     QTest::newRow(#RealType) << QMetaType::MetaTypeName << int(QTypeInfo<RealType>::sizeOf);
633 FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW)
634 #undef ADD_METATYPE_TEST_ROW
635 }
636
637 void tst_QMetaType::sizeOf()
638 {
639     QFETCH(QMetaType::Type, type);
640     QFETCH(int, size);
641     QCOMPARE(QMetaType::sizeOf(type), size);
642 }
643
644 void tst_QMetaType::sizeOfStaticLess_data()
645 {
646     sizeOf_data();
647 }
648
649 void tst_QMetaType::sizeOfStaticLess()
650 {
651     QFETCH(QMetaType::Type, type);
652     QFETCH(int, size);
653     QCOMPARE(QMetaType(type).sizeOf(), size);
654 }
655
656 struct CustomMovable {};
657 QT_BEGIN_NAMESPACE
658 Q_DECLARE_TYPEINFO(CustomMovable, Q_MOVABLE_TYPE);
659 QT_END_NAMESPACE
660 Q_DECLARE_METATYPE(CustomMovable);
661
662 class CustomObject : public QObject
663 {
664     Q_OBJECT
665 public:
666     CustomObject(QObject *parent = 0)
667       : QObject(parent)
668     {
669
670     }
671 };
672 Q_DECLARE_METATYPE(CustomObject*);
673
674 struct SecondBase {};
675
676 class CustomMultiInheritanceObject : public QObject, SecondBase
677 {
678     Q_OBJECT
679 public:
680     CustomMultiInheritanceObject(QObject *parent = 0)
681       : QObject(parent)
682     {
683
684     }
685 };
686 Q_DECLARE_METATYPE(CustomMultiInheritanceObject*);
687
688 void tst_QMetaType::flags_data()
689 {
690     QTest::addColumn<int>("type");
691     QTest::addColumn<bool>("isMovable");
692     QTest::addColumn<bool>("isComplex");
693     QTest::addColumn<bool>("isPointerToQObject");
694
695 #define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
696     QTest::newRow(#RealType) << MetaTypeId << bool(!QTypeInfo<RealType>::isStatic) << bool(QTypeInfo<RealType>::isComplex) << bool(QtPrivate::IsPointerToTypeDerivedFromQObject<RealType>::Value);
697 QT_FOR_EACH_STATIC_CORE_CLASS(ADD_METATYPE_TEST_ROW)
698 QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(ADD_METATYPE_TEST_ROW)
699 QT_FOR_EACH_STATIC_CORE_POINTER(ADD_METATYPE_TEST_ROW)
700 #undef ADD_METATYPE_TEST_ROW
701     QTest::newRow("TestSpace::Foo") << ::qMetaTypeId<TestSpace::Foo>() << false << true << false;
702     QTest::newRow("Whity<double>") << ::qMetaTypeId<Whity<double> >() << false << true << false;
703     QTest::newRow("CustomMovable") << ::qMetaTypeId<CustomMovable>() << true << true << false;
704     QTest::newRow("CustomObject*") << ::qMetaTypeId<CustomObject*>() << true << false << true;
705     QTest::newRow("CustomMultiInheritanceObject*") << ::qMetaTypeId<CustomMultiInheritanceObject*>() << true << false << true;
706 }
707
708 void tst_QMetaType::flags()
709 {
710     QFETCH(int, type);
711     QFETCH(bool, isMovable);
712     QFETCH(bool, isComplex);
713     QFETCH(bool, isPointerToQObject);
714
715     QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsConstruction), isComplex);
716     QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsDestruction), isComplex);
717     QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::MovableType), isMovable);
718     QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::PointerToQObject), isPointerToQObject);
719 }
720
721 void tst_QMetaType::flagsStaticLess_data()
722 {
723     flags_data();
724 }
725
726 void tst_QMetaType::flagsStaticLess()
727 {
728     QFETCH(int, type);
729     QFETCH(bool, isMovable);
730     QFETCH(bool, isComplex);
731
732     int flags = QMetaType(type).flags();
733     QCOMPARE(bool(flags & QMetaType::NeedsConstruction), isComplex);
734     QCOMPARE(bool(flags & QMetaType::NeedsDestruction), isComplex);
735     QCOMPARE(bool(flags & QMetaType::MovableType), isMovable);
736 }
737
738 void tst_QMetaType::construct_data()
739 {
740     create_data();
741 }
742
743 #ifndef Q_ALIGNOF
744 template<uint N>
745 struct RoundToNextHighestPowerOfTwo
746 {
747 private:
748     enum { V1 = N-1 };
749     enum { V2 = V1 | (V1 >> 1) };
750     enum { V3 = V2 | (V2 >> 2) };
751     enum { V4 = V3 | (V3 >> 4) };
752     enum { V5 = V4 | (V4 >> 8) };
753     enum { V6 = V5 | (V5 >> 16) };
754 public:
755     enum { Value = V6 + 1 };
756 };
757 #endif
758
759 template<class T>
760 struct TypeAlignment
761 {
762 #ifdef Q_ALIGNOF
763     enum { Value = Q_ALIGNOF(T) };
764 #else
765     enum { Value = RoundToNextHighestPowerOfTwo<sizeof(T)>::Value };
766 #endif
767 };
768
769 template<int ID>
770 static void testConstructHelper()
771 {
772     typedef typename MetaEnumToType<ID>::Type Type;
773     QMetaType info(ID);
774     int size = info.sizeOf();
775     void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value);
776     void *actual1 = QMetaType::construct(ID, storage1, /*copy=*/0);
777     void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value);
778     void *actual2 = info.construct(storage2, /*copy=*/0);
779     QCOMPARE(actual1, storage1);
780     QCOMPARE(actual2, storage2);
781     if (DefaultValueTraits<ID>::IsInitialized) {
782         Type *expected = DefaultValueFactory<ID>::create();
783         QCOMPARE(*static_cast<Type *>(actual1), *expected);
784         QCOMPARE(*static_cast<Type *>(actual2), *expected);
785         delete expected;
786     }
787     QMetaType::destruct(ID, actual1);
788     qFreeAligned(storage1);
789     info.destruct(actual2);
790     qFreeAligned(storage2);
791
792     QVERIFY(QMetaType::construct(ID, 0, /*copy=*/0) == 0);
793     QMetaType::destruct(ID, 0);
794
795     QVERIFY(info.construct(0, /*copy=*/0) == 0);
796     info.destruct(0);
797 }
798
799 template<>
800 void testConstructHelper<QMetaType::Void>()
801 {
802     typedef MetaEnumToType<QMetaType::Void>::Type Type;
803     /*int size = */ QMetaType::sizeOf(QMetaType::Void);
804     void *storage = 0;
805     void *actual = QMetaType::construct(QMetaType::Void, storage, /*copy=*/0);
806     QCOMPARE(actual, storage);
807     if (DefaultValueTraits<QMetaType::Void>::IsInitialized) {
808         /*Type *expected = */ DefaultValueFactory<QMetaType::Void>::create();
809     }
810     QMetaType::destruct(QMetaType::Void, actual);
811     qFreeAligned(storage);
812
813     QVERIFY(QMetaType::construct(QMetaType::Void, 0, /*copy=*/0) == 0);
814     QMetaType::destruct(QMetaType::Void, 0);
815 }
816
817 void tst_QMetaType::construct()
818 {
819     struct TypeTestFunctionGetter
820     {
821         static TypeTestFunction get(int type)
822         {
823             switch (type) {
824 #define RETURN_CONSTRUCT_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
825             case QMetaType::MetaTypeName: \
826             return testConstructHelper<QMetaType::MetaTypeName>;
827 FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_FUNCTION)
828 #undef RETURN_CONSTRUCT_FUNCTION
829             }
830             return 0;
831         }
832     };
833
834     QFETCH(QMetaType::Type, type);
835     TypeTestFunctionGetter::get(type)();
836 }
837
838 template<int ID>
839 static void testConstructCopyHelper()
840 {
841     typedef typename MetaEnumToType<ID>::Type Type;
842     Type *expected = TestValueFactory<ID>::create();
843     QMetaType info(ID);
844     int size = QMetaType::sizeOf(ID);
845     QCOMPARE(info.sizeOf(), size);
846     void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value);
847     void *actual1 = QMetaType::construct(ID, storage1, expected);
848     void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value);
849     void *actual2 = info.construct(storage2, expected);
850     QCOMPARE(actual1, storage1);
851     QCOMPARE(actual2, storage2);
852     QCOMPARE(*static_cast<Type *>(actual1), *expected);
853     QCOMPARE(*static_cast<Type *>(actual2), *expected);
854     QMetaType::destruct(ID, actual1);
855     qFreeAligned(storage1);
856     info.destruct(actual2);
857     qFreeAligned(storage2);
858
859     QVERIFY(QMetaType::construct(ID, 0, expected) == 0);
860     QVERIFY(info.construct(0, expected) == 0);
861
862     delete expected;
863 }
864
865 template<>
866 void testConstructCopyHelper<QMetaType::Void>()
867 {
868     typedef MetaEnumToType<QMetaType::Void>::Type Type;
869     Type *expected = TestValueFactory<QMetaType::Void>::create();
870     /* int size = */QMetaType::sizeOf(QMetaType::Void);
871     void *storage = 0;
872     void *actual = QMetaType::construct(QMetaType::Void, storage, expected);
873     QCOMPARE(actual, storage);
874     QMetaType::destruct(QMetaType::Void, actual);
875     qFreeAligned(storage);
876
877     QVERIFY(QMetaType::construct(QMetaType::Void, 0, expected) == 0);
878 }
879
880 void tst_QMetaType::constructCopy_data()
881 {
882     create_data();
883 }
884
885 void tst_QMetaType::constructCopy()
886 {
887     struct TypeTestFunctionGetter
888     {
889         static TypeTestFunction get(int type)
890         {
891             switch (type) {
892 #define RETURN_CONSTRUCT_COPY_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
893             case QMetaType::MetaTypeName: \
894             return testConstructCopyHelper<QMetaType::MetaTypeName>;
895 FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_COPY_FUNCTION)
896 #undef RETURN_CONSTRUCT_COPY_FUNCTION
897             }
898             return 0;
899         }
900     };
901
902     QFETCH(QMetaType::Type, type);
903     TypeTestFunctionGetter::get(type)();
904 }
905
906 typedef QString CustomString;
907 Q_DECLARE_METATYPE(CustomString) //this line is useless
908
909 void tst_QMetaType::typedefs()
910 {
911     QCOMPARE(QMetaType::type("long long"), int(QMetaType::LongLong));
912     QCOMPARE(QMetaType::type("unsigned long long"), int(QMetaType::ULongLong));
913     QCOMPARE(QMetaType::type("qint8"), int(QMetaType::Char));
914     QCOMPARE(QMetaType::type("quint8"), int(QMetaType::UChar));
915     QCOMPARE(QMetaType::type("qint16"), int(QMetaType::Short));
916     QCOMPARE(QMetaType::type("quint16"), int(QMetaType::UShort));
917     QCOMPARE(QMetaType::type("qint32"), int(QMetaType::Int));
918     QCOMPARE(QMetaType::type("quint32"), int(QMetaType::UInt));
919     QCOMPARE(QMetaType::type("qint64"), int(QMetaType::LongLong));
920     QCOMPARE(QMetaType::type("quint64"), int(QMetaType::ULongLong));
921
922     // make sure the qreal typeId is the type id of the type it's defined to
923     QCOMPARE(QMetaType::type("qreal"), ::qMetaTypeId<qreal>());
924
925     qRegisterMetaType<CustomString>("CustomString");
926     QCOMPARE(QMetaType::type("CustomString"), ::qMetaTypeId<CustomString>());
927
928     typedef Whity<double> WhityDouble;
929     qRegisterMetaType<WhityDouble>("WhityDouble");
930     QCOMPARE(QMetaType::type("WhityDouble"), ::qMetaTypeId<WhityDouble>());
931 }
932
933 void tst_QMetaType::registerType()
934 {
935     // Built-in
936     QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString));
937     QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString));
938
939     // Custom
940     int fooId = qRegisterMetaType<TestSpace::Foo>("TestSpace::Foo");
941     QVERIFY(fooId >= int(QMetaType::User));
942     QCOMPARE(qRegisterMetaType<TestSpace::Foo>("TestSpace::Foo"), fooId);
943
944     int movableId = qRegisterMetaType<CustomMovable>("CustomMovable");
945     QVERIFY(movableId >= int(QMetaType::User));
946     QCOMPARE(qRegisterMetaType<CustomMovable>("CustomMovable"), movableId);
947
948     // Alias to built-in
949     typedef QString MyString;
950
951     QCOMPARE(qRegisterMetaType<MyString>("MyString"), int(QMetaType::QString));
952     QCOMPARE(qRegisterMetaType<MyString>("MyString"), int(QMetaType::QString));
953
954     QCOMPARE(QMetaType::type("MyString"), int(QMetaType::QString));
955
956     // Alias to custom type
957     typedef CustomMovable MyMovable;
958     typedef TestSpace::Foo MyFoo;
959
960     QCOMPARE(qRegisterMetaType<MyMovable>("MyMovable"), movableId);
961     QCOMPARE(qRegisterMetaType<MyMovable>("MyMovable"), movableId);
962
963     QCOMPARE(QMetaType::type("MyMovable"), movableId);
964
965     QCOMPARE(qRegisterMetaType<MyFoo>("MyFoo"), fooId);
966     QCOMPARE(qRegisterMetaType<MyFoo>("MyFoo"), fooId);
967
968     QCOMPARE(QMetaType::type("MyFoo"), fooId);
969 }
970
971 class IsRegisteredDummyType { };
972
973 void tst_QMetaType::isRegistered_data()
974 {
975     QTest::addColumn<int>("typeId");
976     QTest::addColumn<bool>("registered");
977
978     // predefined/custom types
979     QTest::newRow("QMetaType::Void") << int(QMetaType::Void) << true;
980     QTest::newRow("QMetaType::Int") << int(QMetaType::Int) << true;
981
982     int dummyTypeId = qRegisterMetaType<IsRegisteredDummyType>("IsRegisteredDummyType");
983
984     QTest::newRow("IsRegisteredDummyType") << dummyTypeId << true;
985
986     // unknown types
987     QTest::newRow("-1") << -1 << false;
988     QTest::newRow("-42") << -42 << false;
989     QTest::newRow("IsRegisteredDummyType + 1") << (dummyTypeId + 1) << false;
990     QTest::newRow("QMetaType::UnknownType") << int(QMetaType::UnknownType) << false;
991 }
992
993 void tst_QMetaType::isRegistered()
994 {
995     QFETCH(int, typeId);
996     QFETCH(bool, registered);
997     QCOMPARE(QMetaType::isRegistered(typeId), registered);
998 }
999
1000 void tst_QMetaType::isRegisteredStaticLess_data()
1001 {
1002     isRegistered_data();
1003 }
1004
1005 void tst_QMetaType::isRegisteredStaticLess()
1006 {
1007     QFETCH(int, typeId);
1008     QFETCH(bool, registered);
1009     QCOMPARE(QMetaType(typeId).isRegistered(), registered);
1010 }
1011
1012 void tst_QMetaType::registerStreamBuiltin()
1013 {
1014     //should not crash;
1015     qRegisterMetaTypeStreamOperators<QString>("QString");
1016     qRegisterMetaTypeStreamOperators<QVariant>("QVariant");
1017 }
1018
1019 Q_DECLARE_METATYPE(QSharedPointer<QObject>)
1020
1021 void tst_QMetaType::automaticTemplateRegistration()
1022 {
1023   {
1024     QList<int> intList;
1025     intList << 42;
1026     QVERIFY(QVariant::fromValue(intList).value<QList<int> >().first() == 42);
1027     QVector<QList<int> > vectorList;
1028     vectorList << intList;
1029     QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<int> > >().first().first() == 42);
1030   }
1031
1032   {
1033     QList<QByteArray> bytearrayList;
1034     bytearrayList << QByteArray("foo");
1035     QVERIFY(QVariant::fromValue(bytearrayList).value<QList<QByteArray> >().first() == QByteArray("foo"));
1036     QVector<QList<QByteArray> > vectorList;
1037     vectorList << bytearrayList;
1038     QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<QByteArray> > >().first().first() == QByteArray("foo"));
1039   }
1040
1041   QCOMPARE(::qMetaTypeId<QVariantList>(), (int)QMetaType::QVariantList);
1042   QCOMPARE(::qMetaTypeId<QList<QVariant> >(), (int)QMetaType::QVariantList);
1043
1044   {
1045     QList<QVariant> variantList;
1046     variantList << 42;
1047     QVERIFY(QVariant::fromValue(variantList).value<QList<QVariant> >().first() == 42);
1048     QVector<QList<QVariant> > vectorList;
1049     vectorList << variantList;
1050     QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<QVariant> > >().first().first() == 42);
1051   }
1052
1053   {
1054     QList<QSharedPointer<QObject> > sharedPointerList;
1055     QObject *testObject = new QObject;
1056     sharedPointerList << QSharedPointer<QObject>(testObject);
1057     QVERIFY(QVariant::fromValue(sharedPointerList).value<QList<QSharedPointer<QObject> > >().first() == testObject);
1058     QVector<QList<QSharedPointer<QObject> > > vectorList;
1059     vectorList << sharedPointerList;
1060     QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<QSharedPointer<QObject> > > >().first().first() == testObject);
1061   }
1062 }
1063
1064 // Compile-time test, it should be possible to register function pointer types
1065 class Undefined;
1066
1067 typedef Undefined (*UndefinedFunction0)();
1068 typedef Undefined (*UndefinedFunction1)(Undefined);
1069 typedef Undefined (*UndefinedFunction2)(Undefined, Undefined);
1070 typedef Undefined (*UndefinedFunction3)(Undefined, Undefined, Undefined);
1071
1072 Q_DECLARE_METATYPE(UndefinedFunction0);
1073 Q_DECLARE_METATYPE(UndefinedFunction1);
1074 Q_DECLARE_METATYPE(UndefinedFunction2);
1075 Q_DECLARE_METATYPE(UndefinedFunction3);
1076
1077 QTEST_MAIN(tst_QMetaType)
1078 #include "tst_qmetatype.moc"