72913d10f27d4e06448ad20178e0e62424926ffc
[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 }
319
320 void tst_QMetaType::typeName()
321 {
322     QFETCH(QMetaType::Type, aType);
323     QFETCH(QString, aTypeName);
324
325     QCOMPARE(QString::fromLatin1(QMetaType::typeName(aType)), aTypeName);
326 }
327
328 #define FOR_EACH_PRIMITIVE_METATYPE(F) \
329     QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F) \
330     QT_FOR_EACH_STATIC_CORE_POINTER(F) \
331
332 #define FOR_EACH_COMPLEX_CORE_METATYPE(F) \
333     QT_FOR_EACH_STATIC_CORE_CLASS(F)
334
335 #define FOR_EACH_CORE_METATYPE(F) \
336     FOR_EACH_PRIMITIVE_METATYPE(F) \
337     FOR_EACH_COMPLEX_CORE_METATYPE(F) \
338
339 template <int ID>
340 struct MetaEnumToType {};
341
342 #define DEFINE_META_ENUM_TO_TYPE(MetaTypeName, MetaTypeId, RealType) \
343 template<> \
344 struct MetaEnumToType<QMetaType::MetaTypeName> { \
345     typedef RealType Type; \
346 };
347 FOR_EACH_CORE_METATYPE(DEFINE_META_ENUM_TO_TYPE)
348 #undef DEFINE_META_ENUM_TO_TYPE
349
350 template <int ID>
351 struct DefaultValueFactory
352 {
353     typedef typename MetaEnumToType<ID>::Type Type;
354     static Type *create() { return new Type; }
355 };
356
357 template <>
358 struct DefaultValueFactory<QMetaType::Void>
359 {
360     typedef MetaEnumToType<QMetaType::Void>::Type Type;
361     static Type *create() { return 0; }
362 };
363
364 template <int ID>
365 struct DefaultValueTraits
366 {
367     // By default we assume that a default-constructed value (new T) is
368     // initialized; e.g. QCOMPARE(*(new T), *(new T)) should succeed
369     enum { IsInitialized = true };
370 };
371
372 #define DEFINE_NON_INITIALIZED_DEFAULT_VALUE_TRAITS(MetaTypeName, MetaTypeId, RealType) \
373 template<> struct DefaultValueTraits<QMetaType::MetaTypeName> { \
374     enum { IsInitialized = false }; \
375 };
376 // Primitive types (int et al) aren't initialized
377 FOR_EACH_PRIMITIVE_METATYPE(DEFINE_NON_INITIALIZED_DEFAULT_VALUE_TRAITS)
378 #undef DEFINE_NON_INITIALIZED_DEFAULT_VALUE_TRAITS
379
380 template <int ID>
381 struct TestValueFactory {};
382
383 template<> struct TestValueFactory<QMetaType::Void> {
384     static void *create() { return 0; }
385 };
386
387 template<> struct TestValueFactory<QMetaType::QString> {
388     static QString *create() { return new QString(QString::fromLatin1("QString")); }
389 };
390 template<> struct TestValueFactory<QMetaType::Int> {
391     static int *create() { return new int(0x12345678); }
392 };
393 template<> struct TestValueFactory<QMetaType::UInt> {
394     static uint *create() { return new uint(0x12345678); }
395 };
396 template<> struct TestValueFactory<QMetaType::Bool> {
397     static bool *create() { return new bool(true); }
398 };
399 template<> struct TestValueFactory<QMetaType::Double> {
400     static double *create() { return new double(3.14); }
401 };
402 template<> struct TestValueFactory<QMetaType::QByteArray> {
403     static QByteArray *create() { return new QByteArray(QByteArray("QByteArray")); }
404 };
405 template<> struct TestValueFactory<QMetaType::QChar> {
406     static QChar *create() { return new QChar(QChar('q')); }
407 };
408 template<> struct TestValueFactory<QMetaType::Long> {
409     static long *create() { return new long(0x12345678); }
410 };
411 template<> struct TestValueFactory<QMetaType::Short> {
412     static short *create() { return new short(0x1234); }
413 };
414 template<> struct TestValueFactory<QMetaType::Char> {
415     static char *create() { return new char('c'); }
416 };
417 template<> struct TestValueFactory<QMetaType::ULong> {
418     static ulong *create() { return new ulong(0x12345678); }
419 };
420 template<> struct TestValueFactory<QMetaType::UShort> {
421     static ushort *create() { return new ushort(0x1234); }
422 };
423 template<> struct TestValueFactory<QMetaType::UChar> {
424     static uchar *create() { return new uchar('u'); }
425 };
426 template<> struct TestValueFactory<QMetaType::Float> {
427     static float *create() { return new float(3.14); }
428 };
429 template<> struct TestValueFactory<QMetaType::QObjectStar> {
430     static QObject * *create() { return new QObject *(0); }
431 };
432 template<> struct TestValueFactory<QMetaType::QWidgetStar> {
433     static QWidget * *create() { return new QWidget *(0); }
434 };
435 template<> struct TestValueFactory<QMetaType::VoidStar> {
436     static void * *create() { return new void *(0); }
437 };
438 template<> struct TestValueFactory<QMetaType::LongLong> {
439     static qlonglong *create() { return new qlonglong(0x12345678); }
440 };
441 template<> struct TestValueFactory<QMetaType::ULongLong> {
442     static qulonglong *create() { return new qulonglong(0x12345678); }
443 };
444 template<> struct TestValueFactory<QMetaType::QStringList> {
445     static QStringList *create() { return new QStringList(QStringList() << "Q" << "t"); }
446 };
447 template<> struct TestValueFactory<QMetaType::QBitArray> {
448     static QBitArray *create() { return new QBitArray(QBitArray(256, true)); }
449 };
450 template<> struct TestValueFactory<QMetaType::QDate> {
451     static QDate *create() { return new QDate(QDate::currentDate()); }
452 };
453 template<> struct TestValueFactory<QMetaType::QTime> {
454     static QTime *create() { return new QTime(QTime::currentTime()); }
455 };
456 template<> struct TestValueFactory<QMetaType::QDateTime> {
457     static QDateTime *create() { return new QDateTime(QDateTime::currentDateTime()); }
458 };
459 template<> struct TestValueFactory<QMetaType::QUrl> {
460     static QUrl *create() { return new QUrl("http://www.example.org"); }
461 };
462 template<> struct TestValueFactory<QMetaType::QLocale> {
463     static QLocale *create() { return new QLocale(QLocale::c()); }
464 };
465 template<> struct TestValueFactory<QMetaType::QRect> {
466     static QRect *create() { return new QRect(10, 20, 30, 40); }
467 };
468 template<> struct TestValueFactory<QMetaType::QRectF> {
469     static QRectF *create() { return new QRectF(10, 20, 30, 40); }
470 };
471 template<> struct TestValueFactory<QMetaType::QSize> {
472     static QSize *create() { return new QSize(10, 20); }
473 };
474 template<> struct TestValueFactory<QMetaType::QSizeF> {
475     static QSizeF *create() { return new QSizeF(10, 20); }
476 };
477 template<> struct TestValueFactory<QMetaType::QLine> {
478     static QLine *create() { return new QLine(10, 20, 30, 40); }
479 };
480 template<> struct TestValueFactory<QMetaType::QLineF> {
481     static QLineF *create() { return new QLineF(10, 20, 30, 40); }
482 };
483 template<> struct TestValueFactory<QMetaType::QPoint> {
484     static QPoint *create() { return new QPoint(10, 20); }
485 };
486 template<> struct TestValueFactory<QMetaType::QPointF> {
487     static QPointF *create() { return new QPointF(10, 20); }
488 };
489 template<> struct TestValueFactory<QMetaType::QEasingCurve> {
490     static QEasingCurve *create() { return new QEasingCurve(QEasingCurve::InOutElastic); }
491 };
492 template<> struct TestValueFactory<QMetaType::QUuid> {
493     static QUuid *create() { return new QUuid(); }
494 };
495 template<> struct TestValueFactory<QMetaType::QModelIndex> {
496     static QModelIndex *create() { return new QModelIndex(); }
497 };
498 template<> struct TestValueFactory<QMetaType::QRegExp> {
499     static QRegExp *create()
500     {
501 #ifndef QT_NO_REGEXP
502         return new QRegExp("A*");
503 #else
504         return 0;
505 #endif
506     }
507 };
508 template<> struct TestValueFactory<QMetaType::QVariant> {
509     static QVariant *create() { return new QVariant(QStringList(QStringList() << "Q" << "t")); }
510 };
511
512 void tst_QMetaType::create_data()
513 {
514     QTest::addColumn<QMetaType::Type>("type");
515 #define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
516     QTest::newRow(QMetaType::typeName(QMetaType::MetaTypeName)) << QMetaType::MetaTypeName;
517 FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW)
518 #undef ADD_METATYPE_TEST_ROW
519 }
520
521 template<int ID>
522 static void testCreateHelper()
523 {
524     typedef typename MetaEnumToType<ID>::Type Type;
525     QMetaType info(ID);
526     void *actual1 = QMetaType::create(ID);
527     void *actual2 = info.create();
528     if (DefaultValueTraits<ID>::IsInitialized) {
529         Type *expected = DefaultValueFactory<ID>::create();
530         QCOMPARE(*static_cast<Type *>(actual1), *expected);
531         QCOMPARE(*static_cast<Type *>(actual2), *expected);
532         delete expected;
533     }
534     QMetaType::destroy(ID, actual1);
535     info.destroy(actual2);
536 }
537
538 template<>
539 void testCreateHelper<QMetaType::Void>()
540 {
541     typedef MetaEnumToType<QMetaType::Void>::Type Type;
542     void *actual = QMetaType::create(QMetaType::Void);
543     if (DefaultValueTraits<QMetaType::Void>::IsInitialized) {
544         QVERIFY(DefaultValueFactory<QMetaType::Void>::create());
545     }
546     QMetaType::destroy(QMetaType::Void, actual);
547 }
548
549
550 typedef void (*TypeTestFunction)();
551
552 void tst_QMetaType::create()
553 {
554     struct TypeTestFunctionGetter
555     {
556         static TypeTestFunction get(int type)
557         {
558             switch (type) {
559 #define RETURN_CREATE_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
560             case QMetaType::MetaTypeName: \
561             return testCreateHelper<QMetaType::MetaTypeName>;
562 FOR_EACH_CORE_METATYPE(RETURN_CREATE_FUNCTION)
563 #undef RETURN_CREATE_FUNCTION
564             }
565             return 0;
566         }
567     };
568
569     QFETCH(QMetaType::Type, type);
570     TypeTestFunctionGetter::get(type)();
571 }
572
573 template<int ID>
574 static void testCreateCopyHelper()
575 {
576     typedef typename MetaEnumToType<ID>::Type Type;
577     Type *expected = TestValueFactory<ID>::create();
578     QMetaType info(ID);
579     void *actual1 = QMetaType::create(ID, expected);
580     void *actual2 = info.create(expected);
581     QCOMPARE(*static_cast<Type *>(actual1), *expected);
582     QCOMPARE(*static_cast<Type *>(actual2), *expected);
583     QMetaType::destroy(ID, actual1);
584     info.destroy(actual2);
585     delete expected;
586 }
587
588 template<>
589 void testCreateCopyHelper<QMetaType::Void>()
590 {
591     typedef MetaEnumToType<QMetaType::Void>::Type Type;
592     Type *expected = TestValueFactory<QMetaType::Void>::create();
593     void *actual = QMetaType::create(QMetaType::Void, expected);
594     QCOMPARE(static_cast<Type *>(actual), expected);
595     QMetaType::destroy(QMetaType::Void, actual);
596 }
597
598 void tst_QMetaType::createCopy_data()
599 {
600     create_data();
601 }
602
603 void tst_QMetaType::createCopy()
604 {
605     struct TypeTestFunctionGetter
606     {
607         static TypeTestFunction get(int type)
608         {
609             switch (type) {
610 #define RETURN_CREATE_COPY_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
611             case QMetaType::MetaTypeName: \
612             return testCreateCopyHelper<QMetaType::MetaTypeName>;
613 FOR_EACH_CORE_METATYPE(RETURN_CREATE_COPY_FUNCTION)
614 #undef RETURN_CREATE_COPY_FUNCTION
615             }
616             return 0;
617         }
618     };
619
620     QFETCH(QMetaType::Type, type);
621     TypeTestFunctionGetter::get(type)();
622 }
623
624 void tst_QMetaType::sizeOf_data()
625 {
626     QTest::addColumn<QMetaType::Type>("type");
627     QTest::addColumn<int>("size");
628 #define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
629     QTest::newRow(#RealType) << QMetaType::MetaTypeName << int(QTypeInfo<RealType>::sizeOf);
630 FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW)
631 #undef ADD_METATYPE_TEST_ROW
632 }
633
634 void tst_QMetaType::sizeOf()
635 {
636     QFETCH(QMetaType::Type, type);
637     QFETCH(int, size);
638     QCOMPARE(QMetaType::sizeOf(type), size);
639 }
640
641 void tst_QMetaType::sizeOfStaticLess_data()
642 {
643     sizeOf_data();
644 }
645
646 void tst_QMetaType::sizeOfStaticLess()
647 {
648     QFETCH(QMetaType::Type, type);
649     QFETCH(int, size);
650     QCOMPARE(QMetaType(type).sizeOf(), size);
651 }
652
653 struct CustomMovable {};
654 QT_BEGIN_NAMESPACE
655 Q_DECLARE_TYPEINFO(CustomMovable, Q_MOVABLE_TYPE);
656 QT_END_NAMESPACE
657 Q_DECLARE_METATYPE(CustomMovable);
658
659 class CustomObject : public QObject
660 {
661     Q_OBJECT
662 public:
663     CustomObject(QObject *parent = 0)
664       : QObject(parent)
665     {
666
667     }
668 };
669 Q_DECLARE_METATYPE(CustomObject*);
670
671 struct SecondBase {};
672
673 class CustomMultiInheritanceObject : public QObject, SecondBase
674 {
675     Q_OBJECT
676 public:
677     CustomMultiInheritanceObject(QObject *parent = 0)
678       : QObject(parent)
679     {
680
681     }
682 };
683 Q_DECLARE_METATYPE(CustomMultiInheritanceObject*);
684
685 void tst_QMetaType::flags_data()
686 {
687     QTest::addColumn<int>("type");
688     QTest::addColumn<bool>("isMovable");
689     QTest::addColumn<bool>("isComplex");
690     QTest::addColumn<bool>("isPointerToQObject");
691
692 #define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
693     QTest::newRow(#RealType) << MetaTypeId << bool(!QTypeInfo<RealType>::isStatic) << bool(QTypeInfo<RealType>::isComplex) << bool(QtPrivate::IsPointerToTypeDerivedFromQObject<RealType>::Value);
694 QT_FOR_EACH_STATIC_CORE_CLASS(ADD_METATYPE_TEST_ROW)
695 QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(ADD_METATYPE_TEST_ROW)
696 QT_FOR_EACH_STATIC_CORE_POINTER(ADD_METATYPE_TEST_ROW)
697 #undef ADD_METATYPE_TEST_ROW
698     QTest::newRow("TestSpace::Foo") << ::qMetaTypeId<TestSpace::Foo>() << false << true << false;
699     QTest::newRow("Whity<double>") << ::qMetaTypeId<Whity<double> >() << false << true << false;
700     QTest::newRow("CustomMovable") << ::qMetaTypeId<CustomMovable>() << true << true << false;
701     QTest::newRow("CustomObject*") << ::qMetaTypeId<CustomObject*>() << true << false << true;
702     QTest::newRow("CustomMultiInheritanceObject*") << ::qMetaTypeId<CustomMultiInheritanceObject*>() << true << false << true;
703 }
704
705 void tst_QMetaType::flags()
706 {
707     QFETCH(int, type);
708     QFETCH(bool, isMovable);
709     QFETCH(bool, isComplex);
710     QFETCH(bool, isPointerToQObject);
711
712     QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsConstruction), isComplex);
713     QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::NeedsDestruction), isComplex);
714     QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::MovableType), isMovable);
715     QCOMPARE(bool(QMetaType::typeFlags(type) & QMetaType::PointerToQObject), isPointerToQObject);
716 }
717
718 void tst_QMetaType::flagsStaticLess_data()
719 {
720     flags_data();
721 }
722
723 void tst_QMetaType::flagsStaticLess()
724 {
725     QFETCH(int, type);
726     QFETCH(bool, isMovable);
727     QFETCH(bool, isComplex);
728
729     int flags = QMetaType(type).flags();
730     QCOMPARE(bool(flags & QMetaType::NeedsConstruction), isComplex);
731     QCOMPARE(bool(flags & QMetaType::NeedsDestruction), isComplex);
732     QCOMPARE(bool(flags & QMetaType::MovableType), isMovable);
733 }
734
735 void tst_QMetaType::construct_data()
736 {
737     create_data();
738 }
739
740 #ifndef Q_ALIGNOF
741 template<uint N>
742 struct RoundToNextHighestPowerOfTwo
743 {
744 private:
745     enum { V1 = N-1 };
746     enum { V2 = V1 | (V1 >> 1) };
747     enum { V3 = V2 | (V2 >> 2) };
748     enum { V4 = V3 | (V3 >> 4) };
749     enum { V5 = V4 | (V4 >> 8) };
750     enum { V6 = V5 | (V5 >> 16) };
751 public:
752     enum { Value = V6 + 1 };
753 };
754 #endif
755
756 template<class T>
757 struct TypeAlignment
758 {
759 #ifdef Q_ALIGNOF
760     enum { Value = Q_ALIGNOF(T) };
761 #else
762     enum { Value = RoundToNextHighestPowerOfTwo<sizeof(T)>::Value };
763 #endif
764 };
765
766 template<int ID>
767 static void testConstructHelper()
768 {
769     typedef typename MetaEnumToType<ID>::Type Type;
770     QMetaType info(ID);
771     int size = info.sizeOf();
772     void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value);
773     void *actual1 = QMetaType::construct(ID, storage1, /*copy=*/0);
774     void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value);
775     void *actual2 = info.construct(storage2, /*copy=*/0);
776     QCOMPARE(actual1, storage1);
777     QCOMPARE(actual2, storage2);
778     if (DefaultValueTraits<ID>::IsInitialized) {
779         Type *expected = DefaultValueFactory<ID>::create();
780         QCOMPARE(*static_cast<Type *>(actual1), *expected);
781         QCOMPARE(*static_cast<Type *>(actual2), *expected);
782         delete expected;
783     }
784     QMetaType::destruct(ID, actual1);
785     qFreeAligned(storage1);
786     info.destruct(actual2);
787     qFreeAligned(storage2);
788
789     QVERIFY(QMetaType::construct(ID, 0, /*copy=*/0) == 0);
790     QMetaType::destruct(ID, 0);
791
792     QVERIFY(info.construct(0, /*copy=*/0) == 0);
793     info.destruct(0);
794 }
795
796 template<>
797 void testConstructHelper<QMetaType::Void>()
798 {
799     typedef MetaEnumToType<QMetaType::Void>::Type Type;
800     /*int size = */ QMetaType::sizeOf(QMetaType::Void);
801     void *storage = 0;
802     void *actual = QMetaType::construct(QMetaType::Void, storage, /*copy=*/0);
803     QCOMPARE(actual, storage);
804     if (DefaultValueTraits<QMetaType::Void>::IsInitialized) {
805         /*Type *expected = */ DefaultValueFactory<QMetaType::Void>::create();
806     }
807     QMetaType::destruct(QMetaType::Void, actual);
808     qFreeAligned(storage);
809
810     QVERIFY(QMetaType::construct(QMetaType::Void, 0, /*copy=*/0) == 0);
811     QMetaType::destruct(QMetaType::Void, 0);
812 }
813
814 void tst_QMetaType::construct()
815 {
816     struct TypeTestFunctionGetter
817     {
818         static TypeTestFunction get(int type)
819         {
820             switch (type) {
821 #define RETURN_CONSTRUCT_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
822             case QMetaType::MetaTypeName: \
823             return testConstructHelper<QMetaType::MetaTypeName>;
824 FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_FUNCTION)
825 #undef RETURN_CONSTRUCT_FUNCTION
826             }
827             return 0;
828         }
829     };
830
831     QFETCH(QMetaType::Type, type);
832     TypeTestFunctionGetter::get(type)();
833 }
834
835 template<int ID>
836 static void testConstructCopyHelper()
837 {
838     typedef typename MetaEnumToType<ID>::Type Type;
839     Type *expected = TestValueFactory<ID>::create();
840     QMetaType info(ID);
841     int size = QMetaType::sizeOf(ID);
842     QCOMPARE(info.sizeOf(), size);
843     void *storage1 = qMallocAligned(size, TypeAlignment<Type>::Value);
844     void *actual1 = QMetaType::construct(ID, storage1, expected);
845     void *storage2 = qMallocAligned(size, TypeAlignment<Type>::Value);
846     void *actual2 = info.construct(storage2, expected);
847     QCOMPARE(actual1, storage1);
848     QCOMPARE(actual2, storage2);
849     QCOMPARE(*static_cast<Type *>(actual1), *expected);
850     QCOMPARE(*static_cast<Type *>(actual2), *expected);
851     QMetaType::destruct(ID, actual1);
852     qFreeAligned(storage1);
853     info.destruct(actual2);
854     qFreeAligned(storage2);
855
856     QVERIFY(QMetaType::construct(ID, 0, expected) == 0);
857     QVERIFY(info.construct(0, expected) == 0);
858
859     delete expected;
860 }
861
862 template<>
863 void testConstructCopyHelper<QMetaType::Void>()
864 {
865     typedef MetaEnumToType<QMetaType::Void>::Type Type;
866     Type *expected = TestValueFactory<QMetaType::Void>::create();
867     /* int size = */QMetaType::sizeOf(QMetaType::Void);
868     void *storage = 0;
869     void *actual = QMetaType::construct(QMetaType::Void, storage, expected);
870     QCOMPARE(actual, storage);
871     QMetaType::destruct(QMetaType::Void, actual);
872     qFreeAligned(storage);
873
874     QVERIFY(QMetaType::construct(QMetaType::Void, 0, expected) == 0);
875 }
876
877 void tst_QMetaType::constructCopy_data()
878 {
879     create_data();
880 }
881
882 void tst_QMetaType::constructCopy()
883 {
884     struct TypeTestFunctionGetter
885     {
886         static TypeTestFunction get(int type)
887         {
888             switch (type) {
889 #define RETURN_CONSTRUCT_COPY_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
890             case QMetaType::MetaTypeName: \
891             return testConstructCopyHelper<QMetaType::MetaTypeName>;
892 FOR_EACH_CORE_METATYPE(RETURN_CONSTRUCT_COPY_FUNCTION)
893 #undef RETURN_CONSTRUCT_COPY_FUNCTION
894             }
895             return 0;
896         }
897     };
898
899     QFETCH(QMetaType::Type, type);
900     TypeTestFunctionGetter::get(type)();
901 }
902
903 typedef QString CustomString;
904 Q_DECLARE_METATYPE(CustomString) //this line is useless
905
906 void tst_QMetaType::typedefs()
907 {
908     QCOMPARE(QMetaType::type("long long"), int(QMetaType::LongLong));
909     QCOMPARE(QMetaType::type("unsigned long long"), int(QMetaType::ULongLong));
910     QCOMPARE(QMetaType::type("qint8"), int(QMetaType::Char));
911     QCOMPARE(QMetaType::type("quint8"), int(QMetaType::UChar));
912     QCOMPARE(QMetaType::type("qint16"), int(QMetaType::Short));
913     QCOMPARE(QMetaType::type("quint16"), int(QMetaType::UShort));
914     QCOMPARE(QMetaType::type("qint32"), int(QMetaType::Int));
915     QCOMPARE(QMetaType::type("quint32"), int(QMetaType::UInt));
916     QCOMPARE(QMetaType::type("qint64"), int(QMetaType::LongLong));
917     QCOMPARE(QMetaType::type("quint64"), int(QMetaType::ULongLong));
918
919     // make sure the qreal typeId is the type id of the type it's defined to
920     QCOMPARE(QMetaType::type("qreal"), ::qMetaTypeId<qreal>());
921
922     qRegisterMetaType<CustomString>("CustomString");
923     QCOMPARE(QMetaType::type("CustomString"), ::qMetaTypeId<CustomString>());
924
925     typedef Whity<double> WhityDouble;
926     qRegisterMetaType<WhityDouble>("WhityDouble");
927     QCOMPARE(QMetaType::type("WhityDouble"), ::qMetaTypeId<WhityDouble>());
928 }
929
930 void tst_QMetaType::registerType()
931 {
932     // Built-in
933     QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString));
934     QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString));
935
936     // Custom
937     int fooId = qRegisterMetaType<TestSpace::Foo>("TestSpace::Foo");
938     QVERIFY(fooId >= int(QMetaType::User));
939     QCOMPARE(qRegisterMetaType<TestSpace::Foo>("TestSpace::Foo"), fooId);
940
941     int movableId = qRegisterMetaType<CustomMovable>("CustomMovable");
942     QVERIFY(movableId >= int(QMetaType::User));
943     QCOMPARE(qRegisterMetaType<CustomMovable>("CustomMovable"), movableId);
944
945     // Alias to built-in
946     typedef QString MyString;
947
948     QCOMPARE(qRegisterMetaType<MyString>("MyString"), int(QMetaType::QString));
949     QCOMPARE(qRegisterMetaType<MyString>("MyString"), int(QMetaType::QString));
950
951     QCOMPARE(QMetaType::type("MyString"), int(QMetaType::QString));
952
953     // Alias to custom type
954     typedef CustomMovable MyMovable;
955     typedef TestSpace::Foo MyFoo;
956
957     QCOMPARE(qRegisterMetaType<MyMovable>("MyMovable"), movableId);
958     QCOMPARE(qRegisterMetaType<MyMovable>("MyMovable"), movableId);
959
960     QCOMPARE(QMetaType::type("MyMovable"), movableId);
961
962     QCOMPARE(qRegisterMetaType<MyFoo>("MyFoo"), fooId);
963     QCOMPARE(qRegisterMetaType<MyFoo>("MyFoo"), fooId);
964
965     QCOMPARE(QMetaType::type("MyFoo"), fooId);
966 }
967
968 class IsRegisteredDummyType { };
969
970 void tst_QMetaType::isRegistered_data()
971 {
972     QTest::addColumn<int>("typeId");
973     QTest::addColumn<bool>("registered");
974
975     // predefined/custom types
976     QTest::newRow("QMetaType::Void") << int(QMetaType::Void) << true;
977     QTest::newRow("QMetaType::Int") << int(QMetaType::Int) << true;
978
979     int dummyTypeId = qRegisterMetaType<IsRegisteredDummyType>("IsRegisteredDummyType");
980
981     QTest::newRow("IsRegisteredDummyType") << dummyTypeId << true;
982
983     // unknown types
984     QTest::newRow("-1") << -1 << false;
985     QTest::newRow("-42") << -42 << false;
986     QTest::newRow("IsRegisteredDummyType + 1") << (dummyTypeId + 1) << false;
987 }
988
989 void tst_QMetaType::isRegistered()
990 {
991     QFETCH(int, typeId);
992     QFETCH(bool, registered);
993     QCOMPARE(QMetaType::isRegistered(typeId), registered);
994 }
995
996 void tst_QMetaType::isRegisteredStaticLess_data()
997 {
998     isRegistered_data();
999 }
1000
1001 void tst_QMetaType::isRegisteredStaticLess()
1002 {
1003     QFETCH(int, typeId);
1004     QFETCH(bool, registered);
1005     QCOMPARE(QMetaType(typeId).isRegistered(), registered);
1006 }
1007
1008 void tst_QMetaType::registerStreamBuiltin()
1009 {
1010     //should not crash;
1011     qRegisterMetaTypeStreamOperators<QString>("QString");
1012     qRegisterMetaTypeStreamOperators<QVariant>("QVariant");
1013 }
1014
1015 Q_DECLARE_METATYPE(QSharedPointer<QObject>)
1016
1017 void tst_QMetaType::automaticTemplateRegistration()
1018 {
1019   {
1020     QList<int> intList;
1021     intList << 42;
1022     QVERIFY(QVariant::fromValue(intList).value<QList<int> >().first() == 42);
1023     QVector<QList<int> > vectorList;
1024     vectorList << intList;
1025     QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<int> > >().first().first() == 42);
1026   }
1027
1028   {
1029     QList<QByteArray> bytearrayList;
1030     bytearrayList << QByteArray("foo");
1031     QVERIFY(QVariant::fromValue(bytearrayList).value<QList<QByteArray> >().first() == QByteArray("foo"));
1032     QVector<QList<QByteArray> > vectorList;
1033     vectorList << bytearrayList;
1034     QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<QByteArray> > >().first().first() == QByteArray("foo"));
1035   }
1036
1037   QCOMPARE(::qMetaTypeId<QVariantList>(), (int)QMetaType::QVariantList);
1038   QCOMPARE(::qMetaTypeId<QList<QVariant> >(), (int)QMetaType::QVariantList);
1039
1040   {
1041     QList<QVariant> variantList;
1042     variantList << 42;
1043     QVERIFY(QVariant::fromValue(variantList).value<QList<QVariant> >().first() == 42);
1044     QVector<QList<QVariant> > vectorList;
1045     vectorList << variantList;
1046     QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<QVariant> > >().first().first() == 42);
1047   }
1048
1049   {
1050     QList<QSharedPointer<QObject> > sharedPointerList;
1051     QObject *testObject = new QObject;
1052     sharedPointerList << QSharedPointer<QObject>(testObject);
1053     QVERIFY(QVariant::fromValue(sharedPointerList).value<QList<QSharedPointer<QObject> > >().first() == testObject);
1054     QVector<QList<QSharedPointer<QObject> > > vectorList;
1055     vectorList << sharedPointerList;
1056     QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<QSharedPointer<QObject> > > >().first().first() == testObject);
1057   }
1058 }
1059
1060 // Compile-time test, it should be possible to register function pointer types
1061 class Undefined;
1062
1063 typedef Undefined (*UndefinedFunction0)();
1064 typedef Undefined (*UndefinedFunction1)(Undefined);
1065 typedef Undefined (*UndefinedFunction2)(Undefined, Undefined);
1066 typedef Undefined (*UndefinedFunction3)(Undefined, Undefined, Undefined);
1067
1068 Q_DECLARE_METATYPE(UndefinedFunction0);
1069 Q_DECLARE_METATYPE(UndefinedFunction1);
1070 Q_DECLARE_METATYPE(UndefinedFunction2);
1071 Q_DECLARE_METATYPE(UndefinedFunction3);
1072
1073 QTEST_MAIN(tst_QMetaType)
1074 #include "tst_qmetatype.moc"