Fix quadratic behavior in QMetaObjectBuilder when writing string table
[qt:qtbase.git] / tests / auto / corelib / kernel / qmetaobjectbuilder / tst_qmetaobjectbuilder.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtTest/QtTest>
43 #include <QtCore/qlocale.h>
44 #include <private/qmetaobjectbuilder_p.h>
45
46 class tst_QMetaObjectBuilder : public QObject
47 {
48     Q_OBJECT
49 private slots:
50     void create();
51     void className();
52     void superClass();
53     void flags();
54     void method();
55     void slot();
56     void signal();
57     void constructor();
58     void property();
59     void variantProperty();
60     void notifySignal();
61     void enumerator();
62     void classInfo();
63     void relatedMetaObject();
64     void staticMetacall();
65     void copyMetaObject();
66     void serialize();
67     void relocatableData();
68     void removeNotifySignal();
69
70     void usage_signal();
71     void usage_property();
72     void usage_slot();
73     void usage_method();
74     void usage_constructor();
75     void usage_connect();
76     void usage_templateConnect();
77
78     void classNameFirstInStringData();
79
80 private:
81     static bool checkForSideEffects
82         (const QMetaObjectBuilder& builder,
83          QMetaObjectBuilder::AddMembers members);
84     static bool sameMetaObject
85         (const QMetaObject *meta1, const QMetaObject *meta2);
86 };
87
88 // Dummy class that has something of every type of thing moc can generate.
89 class SomethingOfEverything : public QObject
90 {
91     Q_OBJECT
92     Q_CLASSINFO("ci_foo", "ABC")
93     Q_CLASSINFO("ci_bar", "DEF")
94     Q_PROPERTY(QString prop READ prop WRITE setProp NOTIFY propChanged)
95     Q_PROPERTY(QString prop2 READ prop WRITE setProp)
96     Q_PROPERTY(QString revisionProp READ prop WRITE setProp REVISION 42)
97     Q_PROPERTY(SomethingEnum eprop READ eprop)
98     Q_PROPERTY(SomethingFlagEnum fprop READ fprop)
99     Q_PROPERTY(QLocale::Language language READ language)
100     Q_ENUMS(SomethingEnum)
101     Q_FLAGS(SomethingFlagEnum)
102 public:
103     Q_INVOKABLE SomethingOfEverything() {}
104     ~SomethingOfEverything() {}
105
106     enum SomethingEnum
107     {
108         GHI,
109         JKL = 10
110     };
111
112     enum SomethingFlagEnum
113     {
114         XYZ = 1,
115         UVW = 8
116     };
117
118     Q_INVOKABLE Q_SCRIPTABLE void method1() {}
119
120     QString prop() const { return QString(); }
121     void setProp(const QString& v) { Q_UNUSED(v); }
122
123     SomethingOfEverything::SomethingEnum eprop() const { return GHI; }
124     SomethingOfEverything::SomethingFlagEnum fprop() const { return XYZ; }
125     QLocale::Language language() const { return QLocale::English; }
126
127 public slots:
128     void slot1(const QString&) {}
129     void slot2(int, const QString&) {}
130     Q_REVISION(24) void revisionSlot() {}
131
132 private slots:
133     void slot3() {}
134
135 protected slots:
136     Q_SCRIPTABLE void slot4(int) {}
137     void slot5(int a, const QString& b) { Q_UNUSED(a); Q_UNUSED(b); }
138
139 signals:
140     void sig1();
141     void sig2(int x, const QString& y);
142     void propChanged(const QString&);
143 };
144
145 void tst_QMetaObjectBuilder::create()
146 {
147     QMetaObjectBuilder builder;
148     QVERIFY(builder.className().isEmpty());
149     QVERIFY(builder.superClass() == &QObject::staticMetaObject);
150     QCOMPARE(builder.methodCount(), 0);
151     QCOMPARE(builder.constructorCount(), 0);
152     QCOMPARE(builder.propertyCount(), 0);
153     QCOMPARE(builder.enumeratorCount(), 0);
154     QCOMPARE(builder.classInfoCount(), 0);
155     QCOMPARE(builder.relatedMetaObjectCount(), 0);
156     QVERIFY(builder.staticMetacallFunction() == 0);
157 }
158
159 void tst_QMetaObjectBuilder::className()
160 {
161     QMetaObjectBuilder builder;
162
163     // Change the class name.
164     builder.setClassName("Foo");
165     QCOMPARE(builder.className(), QByteArray("Foo"));
166
167     // Change it again.
168     builder.setClassName("Bar");
169     QCOMPARE(builder.className(), QByteArray("Bar"));
170
171     // Clone the class name off a static QMetaObject.
172     builder.addMetaObject(&QObject::staticMetaObject, QMetaObjectBuilder::ClassName);
173     QCOMPARE(builder.className(), QByteArray("QObject"));
174
175     // Check that nothing else changed.
176     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::ClassName));
177 }
178
179 void tst_QMetaObjectBuilder::superClass()
180 {
181     QMetaObjectBuilder builder;
182
183     // Change the super class.
184     builder.setSuperClass(&QObject::staticMetaObject);
185     QVERIFY(builder.superClass() == &QObject::staticMetaObject);
186
187     // Change it again.
188     builder.setSuperClass(&staticMetaObject);
189     QVERIFY(builder.superClass() == &staticMetaObject);
190
191     // Clone the super class off a static QMetaObject.
192     builder.addMetaObject(&QObject::staticMetaObject, QMetaObjectBuilder::SuperClass);
193     QVERIFY(builder.superClass() == 0);
194     builder.addMetaObject(&staticMetaObject, QMetaObjectBuilder::SuperClass);
195     QVERIFY(builder.superClass() == staticMetaObject.superClass());
196
197     // Check that nothing else changed.
198     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::SuperClass));
199 }
200
201 void tst_QMetaObjectBuilder::flags()
202 {
203     QMetaObjectBuilder builder;
204
205     // Check default
206     QVERIFY(builder.flags() == 0);
207
208     // Set flags
209     builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
210     QVERIFY(builder.flags() == QMetaObjectBuilder::DynamicMetaObject);
211 }
212
213 void tst_QMetaObjectBuilder::method()
214 {
215     QMetaObjectBuilder builder;
216
217     // Check null method
218     QMetaMethodBuilder nullMethod;
219     QCOMPARE(nullMethod.signature(), QByteArray());
220     QVERIFY(nullMethod.methodType() == QMetaMethod::Method);
221     QVERIFY(nullMethod.returnType().isEmpty());
222     QVERIFY(nullMethod.parameterTypes().isEmpty());
223     QVERIFY(nullMethod.parameterNames().isEmpty());
224     QVERIFY(nullMethod.tag().isEmpty());
225     QVERIFY(nullMethod.access() == QMetaMethod::Public);
226     QCOMPARE(nullMethod.attributes(), 0);
227     QCOMPARE(nullMethod.revision(), 0);
228     QCOMPARE(nullMethod.index(), 0);
229
230     // Add a method and check its attributes.
231     QMetaMethodBuilder method1 = builder.addMethod("foo(const QString&, int)");
232     QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
233     QVERIFY(method1.methodType() == QMetaMethod::Method);
234     QCOMPARE(method1.returnType(), QByteArray("void"));
235     QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
236     QVERIFY(method1.parameterNames().isEmpty());
237     QVERIFY(method1.tag().isEmpty());
238     QVERIFY(method1.access() == QMetaMethod::Public);
239     QCOMPARE(method1.attributes(), 0);
240     QCOMPARE(method1.revision(), 0);
241     QCOMPARE(method1.index(), 0);
242     QCOMPARE(builder.methodCount(), 1);
243
244     // Add another method and check again.
245     QMetaMethodBuilder method2 = builder.addMethod("bar(QString)", "int");
246     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
247     QVERIFY(method2.methodType() == QMetaMethod::Method);
248     QCOMPARE(method2.returnType(), QByteArray("int"));
249     QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
250     QVERIFY(method2.parameterNames().isEmpty());
251     QVERIFY(method2.tag().isEmpty());
252     QVERIFY(method2.access() == QMetaMethod::Public);
253     QCOMPARE(method2.attributes(), 0);
254     QCOMPARE(method2.revision(), 0);
255     QCOMPARE(method2.index(), 1);
256     QCOMPARE(builder.methodCount(), 2);
257
258     // Perform index-based lookup.
259     QCOMPARE(builder.indexOfMethod("foo(const QString&, int)"), 0);
260     QCOMPARE(builder.indexOfMethod("bar(QString)"), 1);
261     QCOMPARE(builder.indexOfMethod("baz()"), -1);
262
263     // Modify the attributes on method1.
264     method1.setReturnType("int");
265     method1.setParameterNames(QList<QByteArray>() << "a" << "b");
266     method1.setTag("tag");
267     method1.setAccess(QMetaMethod::Private);
268     method1.setAttributes(42);
269     method1.setRevision(123);
270
271     // Check that method1 is changed, but method2 is not.
272     QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
273     QVERIFY(method1.methodType() == QMetaMethod::Method);
274     QCOMPARE(method1.returnType(), QByteArray("int"));
275     QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
276     QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b");
277     QCOMPARE(method1.tag(), QByteArray("tag"));
278     QVERIFY(method1.access() == QMetaMethod::Private);
279     QCOMPARE(method1.attributes(), 42);
280     QCOMPARE(method1.revision(), 123);
281     QCOMPARE(method1.index(), 0);
282     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
283     QVERIFY(method2.methodType() == QMetaMethod::Method);
284     QCOMPARE(method2.returnType(), QByteArray("int"));
285     QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
286     QVERIFY(method2.parameterNames().isEmpty());
287     QVERIFY(method2.tag().isEmpty());
288     QVERIFY(method2.access() == QMetaMethod::Public);
289     QCOMPARE(method2.attributes(), 0);
290     QCOMPARE(method2.revision(), 0);
291     QCOMPARE(method2.index(), 1);
292     QCOMPARE(builder.methodCount(), 2);
293
294     // Modify the attributes on method2.
295     method2.setReturnType("QString");
296     method2.setParameterNames(QList<QByteArray>() << "c");
297     method2.setTag("Q_FOO");
298     method2.setAccess(QMetaMethod::Protected);
299     method2.setAttributes(24);
300     method2.setRevision(321);
301
302     // This time check that only method2 changed.
303     QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
304     QVERIFY(method1.methodType() == QMetaMethod::Method);
305     QCOMPARE(method1.returnType(), QByteArray("int"));
306     QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
307     QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b");
308     QCOMPARE(method1.tag(), QByteArray("tag"));
309     QVERIFY(method1.access() == QMetaMethod::Private);
310     QCOMPARE(method1.attributes(), 42);
311     QCOMPARE(method1.revision(), 123);
312     QCOMPARE(method1.index(), 0);
313     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
314     QVERIFY(method2.methodType() == QMetaMethod::Method);
315     QCOMPARE(method2.returnType(), QByteArray("QString"));
316     QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
317     QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c");
318     QCOMPARE(method2.tag(), QByteArray("Q_FOO"));
319     QVERIFY(method2.access() == QMetaMethod::Protected);
320     QCOMPARE(method2.attributes(), 24);
321     QCOMPARE(method2.revision(), 321);
322     QCOMPARE(method2.index(), 1);
323     QCOMPARE(builder.methodCount(), 2);
324
325     // Remove method1 and check that method2 becomes index 0.
326     builder.removeMethod(0);
327     QCOMPARE(builder.methodCount(), 1);
328     method2 = builder.method(0);
329     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
330     QVERIFY(method2.methodType() == QMetaMethod::Method);
331     QCOMPARE(method2.returnType(), QByteArray("QString"));
332     QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
333     QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c");
334     QCOMPARE(method2.tag(), QByteArray("Q_FOO"));
335     QVERIFY(method2.access() == QMetaMethod::Protected);
336     QCOMPARE(method2.attributes(), 24);
337     QCOMPARE(method2.revision(), 321);
338     QCOMPARE(method2.index(), 0);
339
340     // Perform index-based lookup again.
341     QCOMPARE(builder.indexOfMethod("foo(const QString&, int)"), -1);
342     QCOMPARE(builder.indexOfMethod("bar(QString)"), 0);
343     QCOMPARE(builder.indexOfMethod("baz()"), -1);
344     QCOMPARE(builder.method(0).signature(), QByteArray("bar(QString)"));
345     QCOMPARE(builder.method(9).signature(), QByteArray());
346
347     // Check that nothing else changed.
348     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods));
349 }
350
351 void tst_QMetaObjectBuilder::slot()
352 {
353     QMetaObjectBuilder builder;
354
355     // Add a slot and check its attributes.
356     QMetaMethodBuilder method1 = builder.addSlot("foo(const QString&, int)");
357     QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
358     QVERIFY(method1.methodType() == QMetaMethod::Slot);
359     QCOMPARE(method1.returnType(), QByteArray("void"));
360     QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
361     QVERIFY(method1.parameterNames().isEmpty());
362     QVERIFY(method1.tag().isEmpty());
363     QVERIFY(method1.access() == QMetaMethod::Public);
364     QCOMPARE(method1.attributes(), 0);
365     QCOMPARE(method1.index(), 0);
366     QCOMPARE(builder.methodCount(), 1);
367
368     // Add another slot and check again.
369     QMetaMethodBuilder method2 = builder.addSlot("bar(QString)");
370     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
371     QVERIFY(method2.methodType() == QMetaMethod::Slot);
372     QCOMPARE(method2.returnType(), QByteArray("void"));
373     QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
374     QVERIFY(method2.parameterNames().isEmpty());
375     QVERIFY(method2.tag().isEmpty());
376     QVERIFY(method2.access() == QMetaMethod::Public);
377     QCOMPARE(method2.attributes(), 0);
378     QCOMPARE(method2.index(), 1);
379     QCOMPARE(builder.methodCount(), 2);
380
381     // Perform index-based lookup
382     QCOMPARE(builder.indexOfSlot("foo(const QString &, int)"), 0);
383     QCOMPARE(builder.indexOfSlot("bar(QString)"), 1);
384     QCOMPARE(builder.indexOfSlot("baz()"), -1);
385
386     // Check that nothing else changed.
387     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods));
388 }
389
390 void tst_QMetaObjectBuilder::signal()
391 {
392     QMetaObjectBuilder builder;
393
394     // Add a signal and check its attributes.
395     QMetaMethodBuilder method1 = builder.addSignal("foo(const QString&, int)");
396     QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
397     QVERIFY(method1.methodType() == QMetaMethod::Signal);
398     QCOMPARE(method1.returnType(), QByteArray("void"));
399     QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
400     QVERIFY(method1.parameterNames().isEmpty());
401     QVERIFY(method1.tag().isEmpty());
402     QVERIFY(method1.access() == QMetaMethod::Public);
403     QCOMPARE(method1.attributes(), 0);
404     QCOMPARE(method1.index(), 0);
405     QCOMPARE(builder.methodCount(), 1);
406
407     // Add another signal and check again.
408     QMetaMethodBuilder method2 = builder.addSignal("bar(QString)");
409     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
410     QVERIFY(method2.methodType() == QMetaMethod::Signal);
411     QCOMPARE(method2.returnType(), QByteArray("void"));
412     QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
413     QVERIFY(method2.parameterNames().isEmpty());
414     QVERIFY(method2.tag().isEmpty());
415     QVERIFY(method2.access() == QMetaMethod::Public);
416     QCOMPARE(method2.attributes(), 0);
417     QCOMPARE(method2.index(), 1);
418     QCOMPARE(builder.methodCount(), 2);
419
420     // Perform index-based lookup
421     QCOMPARE(builder.indexOfSignal("foo(const QString &, int)"), 0);
422     QCOMPARE(builder.indexOfSignal("bar(QString)"), 1);
423     QCOMPARE(builder.indexOfSignal("baz()"), -1);
424
425     // Check that nothing else changed.
426     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods));
427 }
428
429 void tst_QMetaObjectBuilder::constructor()
430 {
431     QMetaObjectBuilder builder;
432
433     // Add a constructor and check its attributes.
434     QMetaMethodBuilder ctor1 = builder.addConstructor("foo(const QString&, int)");
435     QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)"));
436     QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
437     QVERIFY(ctor1.returnType().isEmpty());
438     QCOMPARE(ctor1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
439     QVERIFY(ctor1.parameterNames().isEmpty());
440     QVERIFY(ctor1.tag().isEmpty());
441     QVERIFY(ctor1.access() == QMetaMethod::Public);
442     QCOMPARE(ctor1.attributes(), 0);
443     QCOMPARE(ctor1.index(), 0);
444     QCOMPARE(builder.constructorCount(), 1);
445
446     // Add another constructor and check again.
447     QMetaMethodBuilder ctor2 = builder.addConstructor("bar(QString)");
448     QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
449     QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
450     QVERIFY(ctor2.returnType().isEmpty());
451     QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString");
452     QVERIFY(ctor2.parameterNames().isEmpty());
453     QVERIFY(ctor2.tag().isEmpty());
454     QVERIFY(ctor2.access() == QMetaMethod::Public);
455     QCOMPARE(ctor2.attributes(), 0);
456     QCOMPARE(ctor2.index(), 1);
457     QCOMPARE(builder.constructorCount(), 2);
458
459     // Perform index-based lookup.
460     QCOMPARE(builder.indexOfConstructor("foo(const QString&, int)"), 0);
461     QCOMPARE(builder.indexOfConstructor("bar(QString)"), 1);
462     QCOMPARE(builder.indexOfConstructor("baz()"), -1);
463     QCOMPARE(builder.constructor(1).signature(), QByteArray("bar(QString)"));
464     QCOMPARE(builder.constructor(9).signature(), QByteArray());
465
466     // Modify the attributes on ctor1.
467     ctor1.setReturnType("int");
468     ctor1.setParameterNames(QList<QByteArray>() << "a" << "b");
469     ctor1.setTag("tag");
470     ctor1.setAccess(QMetaMethod::Private);
471     ctor1.setAttributes(42);
472
473     // Check that ctor1 is changed, but ctor2 is not.
474     QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)"));
475     QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
476     QCOMPARE(ctor1.returnType(), QByteArray("int"));
477     QCOMPARE(ctor1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
478     QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b");
479     QCOMPARE(ctor1.tag(), QByteArray("tag"));
480     QVERIFY(ctor1.access() == QMetaMethod::Private);
481     QCOMPARE(ctor1.attributes(), 42);
482     QCOMPARE(ctor1.index(), 0);
483     QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
484     QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
485     QVERIFY(ctor2.returnType().isEmpty());
486     QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString");
487     QVERIFY(ctor2.parameterNames().isEmpty());
488     QVERIFY(ctor2.tag().isEmpty());
489     QVERIFY(ctor2.access() == QMetaMethod::Public);
490     QCOMPARE(ctor2.attributes(), 0);
491     QCOMPARE(ctor2.index(), 1);
492     QCOMPARE(builder.constructorCount(), 2);
493
494     // Modify the attributes on ctor2.
495     ctor2.setReturnType("QString");
496     ctor2.setParameterNames(QList<QByteArray>() << "c");
497     ctor2.setTag("Q_FOO");
498     ctor2.setAccess(QMetaMethod::Protected);
499     ctor2.setAttributes(24);
500
501     // This time check that only ctor2 changed.
502     QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)"));
503     QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
504     QCOMPARE(ctor1.returnType(), QByteArray("int"));
505     QCOMPARE(ctor1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
506     QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b");
507     QCOMPARE(ctor1.tag(), QByteArray("tag"));
508     QVERIFY(ctor1.access() == QMetaMethod::Private);
509     QCOMPARE(ctor1.attributes(), 42);
510     QCOMPARE(ctor1.index(), 0);
511     QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
512     QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
513     QCOMPARE(ctor2.returnType(), QByteArray("QString"));
514     QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString");
515     QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c");
516     QCOMPARE(ctor2.tag(), QByteArray("Q_FOO"));
517     QVERIFY(ctor2.access() == QMetaMethod::Protected);
518     QCOMPARE(ctor2.attributes(), 24);
519     QCOMPARE(ctor2.index(), 1);
520     QCOMPARE(builder.constructorCount(), 2);
521
522     // Remove ctor1 and check that ctor2 becomes index 0.
523     builder.removeConstructor(0);
524     QCOMPARE(builder.constructorCount(), 1);
525     ctor2 = builder.constructor(0);
526     QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
527     QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
528     QCOMPARE(ctor2.returnType(), QByteArray("QString"));
529     QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString");
530     QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c");
531     QCOMPARE(ctor2.tag(), QByteArray("Q_FOO"));
532     QVERIFY(ctor2.access() == QMetaMethod::Protected);
533     QCOMPARE(ctor2.attributes(), 24);
534     QCOMPARE(ctor2.index(), 0);
535
536     // Perform index-based lookup again.
537     QCOMPARE(builder.indexOfConstructor("foo(const QString&, int)"), -1);
538     QCOMPARE(builder.indexOfConstructor("bar(QString)"), 0);
539     QCOMPARE(builder.indexOfConstructor("baz()"), -1);
540
541     // Add constructor from prototype
542     QMetaMethod prototype = SomethingOfEverything::staticMetaObject.constructor(0);
543     QMetaMethodBuilder prototypeConstructor = builder.addMethod(prototype);
544     QCOMPARE(builder.constructorCount(), 2);
545
546     QCOMPARE(prototypeConstructor.signature(), QByteArray("SomethingOfEverything()"));
547     QVERIFY(prototypeConstructor.methodType() == QMetaMethod::Constructor);
548     QCOMPARE(prototypeConstructor.returnType(), QByteArray());
549     QVERIFY(prototypeConstructor.parameterTypes().isEmpty());
550     QVERIFY(prototypeConstructor.access() == QMetaMethod::Public);
551     QCOMPARE(prototypeConstructor.index(), 1);
552
553     // Check that nothing else changed.
554     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Constructors));
555 }
556
557 void tst_QMetaObjectBuilder::property()
558 {
559     QMetaObjectBuilder builder;
560
561     // Null property builder
562     QMetaPropertyBuilder nullProp;
563     QCOMPARE(nullProp.name(), QByteArray());
564     QCOMPARE(nullProp.type(), QByteArray());
565     QVERIFY(!nullProp.hasNotifySignal());
566     QVERIFY(!nullProp.isReadable());
567     QVERIFY(!nullProp.isWritable());
568     QVERIFY(!nullProp.isResettable());
569     QVERIFY(!nullProp.isDesignable());
570     QVERIFY(!nullProp.isScriptable());
571     QVERIFY(!nullProp.isStored());
572     QVERIFY(!nullProp.isEditable());
573     QVERIFY(!nullProp.isUser());
574     QVERIFY(!nullProp.hasStdCppSet());
575     QVERIFY(!nullProp.isEnumOrFlag());
576     QVERIFY(!nullProp.isConstant());
577     QVERIFY(!nullProp.isFinal());
578     QCOMPARE(nullProp.index(), 0);
579     QCOMPARE(nullProp.revision(), 0);
580
581     // Add a property and check its attributes.
582     QMetaPropertyBuilder prop1 = builder.addProperty("foo", "const QString &");
583     QCOMPARE(prop1.name(), QByteArray("foo"));
584     QCOMPARE(prop1.type(), QByteArray("QString"));
585     QVERIFY(!prop1.hasNotifySignal());
586     QVERIFY(prop1.isReadable());
587     QVERIFY(prop1.isWritable());
588     QVERIFY(!prop1.isResettable());
589     QVERIFY(!prop1.isDesignable());
590     QVERIFY(prop1.isScriptable());
591     QVERIFY(!prop1.isStored());
592     QVERIFY(!prop1.isEditable());
593     QVERIFY(!prop1.isUser());
594     QVERIFY(!prop1.hasStdCppSet());
595     QVERIFY(!prop1.isEnumOrFlag());
596     QVERIFY(!prop1.isConstant());
597     QVERIFY(!prop1.isFinal());
598     QCOMPARE(prop1.revision(), 0);
599     QCOMPARE(prop1.index(), 0);
600     QCOMPARE(builder.propertyCount(), 1);
601
602     // Add another property and check again.
603     QMetaPropertyBuilder prop2 = builder.addProperty("bar", "int");
604     QCOMPARE(prop2.name(), QByteArray("bar"));
605     QCOMPARE(prop2.type(), QByteArray("int"));
606     QVERIFY(!prop2.hasNotifySignal());
607     QVERIFY(prop2.isReadable());
608     QVERIFY(prop2.isWritable());
609     QVERIFY(!prop2.isResettable());
610     QVERIFY(!prop2.isDesignable());
611     QVERIFY(prop2.isScriptable());
612     QVERIFY(!prop2.isStored());
613     QVERIFY(!prop2.isEditable());
614     QVERIFY(!prop2.isUser());
615     QVERIFY(!prop2.hasStdCppSet());
616     QVERIFY(!prop2.isEnumOrFlag());
617     QVERIFY(!prop2.isConstant());
618     QVERIFY(!prop2.isFinal());
619     QCOMPARE(prop2.revision(), 0);
620     QCOMPARE(prop2.index(), 1);
621     QCOMPARE(builder.propertyCount(), 2);
622
623     // Perform index-based lookup.
624     QCOMPARE(builder.indexOfProperty("foo"), 0);
625     QCOMPARE(builder.indexOfProperty("bar"), 1);
626     QCOMPARE(builder.indexOfProperty("baz"), -1);
627     QCOMPARE(builder.property(1).name(), QByteArray("bar"));
628     QCOMPARE(builder.property(9).name(), QByteArray());
629
630     // Modify the attributes on prop1.
631     prop1.setReadable(false);
632     prop1.setWritable(false);
633     prop1.setResettable(true);
634     prop1.setDesignable(true);
635     prop1.setScriptable(false);
636     prop1.setStored(true);
637     prop1.setEditable(true);
638     prop1.setUser(true);
639     prop1.setStdCppSet(true);
640     prop1.setEnumOrFlag(true);
641     prop1.setConstant(true);
642     prop1.setFinal(true);
643     prop1.setRevision(123);
644
645     // Check that prop1 is changed, but prop2 is not.
646     QCOMPARE(prop1.name(), QByteArray("foo"));
647     QCOMPARE(prop1.type(), QByteArray("QString"));
648     QVERIFY(!prop1.isReadable());
649     QVERIFY(!prop1.isWritable());
650     QVERIFY(prop1.isResettable());
651     QVERIFY(prop1.isDesignable());
652     QVERIFY(!prop1.isScriptable());
653     QVERIFY(prop1.isStored());
654     QVERIFY(prop1.isEditable());
655     QVERIFY(prop1.isUser());
656     QVERIFY(prop1.hasStdCppSet());
657     QVERIFY(prop1.isEnumOrFlag());
658     QVERIFY(prop1.isConstant());
659     QVERIFY(prop1.isFinal());
660     QCOMPARE(prop1.revision(), 123);
661     QVERIFY(prop2.isReadable());
662     QVERIFY(prop2.isWritable());
663     QCOMPARE(prop2.name(), QByteArray("bar"));
664     QCOMPARE(prop2.type(), QByteArray("int"));
665     QVERIFY(!prop2.isResettable());
666     QVERIFY(!prop2.isDesignable());
667     QVERIFY(prop2.isScriptable());
668     QVERIFY(!prop2.isStored());
669     QVERIFY(!prop2.isEditable());
670     QVERIFY(!prop2.isUser());
671     QVERIFY(!prop2.hasStdCppSet());
672     QVERIFY(!prop2.isEnumOrFlag());
673     QVERIFY(!prop2.isConstant());
674     QVERIFY(!prop2.isFinal());
675     QCOMPARE(prop2.revision(), 0);
676
677     // Remove prop1 and check that prop2 becomes index 0.
678     builder.removeProperty(0);
679     QCOMPARE(builder.propertyCount(), 1);
680     prop2 = builder.property(0);
681     QCOMPARE(prop2.name(), QByteArray("bar"));
682     QCOMPARE(prop2.type(), QByteArray("int"));
683     QVERIFY(!prop2.isResettable());
684     QVERIFY(!prop2.isDesignable());
685     QVERIFY(prop2.isScriptable());
686     QVERIFY(!prop2.isStored());
687     QVERIFY(!prop2.isEditable());
688     QVERIFY(!prop2.isUser());
689     QVERIFY(!prop2.hasStdCppSet());
690     QVERIFY(!prop2.isEnumOrFlag());
691     QVERIFY(!prop2.isConstant());
692     QVERIFY(!prop2.isFinal());
693     QCOMPARE(prop2.revision(), 0);
694     QCOMPARE(prop2.index(), 0);
695
696     // Perform index-based lookup again.
697     QCOMPARE(builder.indexOfProperty("foo"), -1);
698     QCOMPARE(builder.indexOfProperty("bar"), 0);
699     QCOMPARE(builder.indexOfProperty("baz"), -1);
700
701     // Check for side-effects between the flags on prop2.
702     // Setting a flag to true shouldn't set any of the others to true.
703     // This checks for cut-and-paste bugs in the implementation where
704     // the flag code was pasted but the flag name was not changed.
705 #define CLEAR_FLAGS() \
706         do { \
707             prop2.setReadable(false); \
708             prop2.setWritable(false); \
709             prop2.setResettable(false); \
710             prop2.setDesignable(false); \
711             prop2.setScriptable(false); \
712             prop2.setStored(false); \
713             prop2.setEditable(false); \
714             prop2.setUser(false); \
715             prop2.setStdCppSet(false); \
716             prop2.setEnumOrFlag(false); \
717             prop2.setConstant(false); \
718             prop2.setFinal(false); \
719         } while (0)
720 #define COUNT_FLAGS() \
721         ((prop2.isReadable() ? 1 : 0) + \
722          (prop2.isWritable() ? 1 : 0) + \
723          (prop2.isResettable() ? 1 : 0) + \
724          (prop2.isDesignable() ? 1 : 0) + \
725          (prop2.isScriptable() ? 1 : 0) + \
726          (prop2.isStored() ? 1 : 0) + \
727          (prop2.isEditable() ? 1 : 0) + \
728          (prop2.isUser() ? 1 : 0) + \
729          (prop2.hasStdCppSet() ? 1 : 0) + \
730          (prop2.isEnumOrFlag() ? 1 : 0) + \
731          (prop2.isConstant() ? 1 : 0) + \
732          (prop2.isFinal() ? 1 : 0))
733 #define CHECK_FLAG(setFunc,isFunc) \
734         do { \
735             CLEAR_FLAGS(); \
736             QCOMPARE(COUNT_FLAGS(), 0); \
737             prop2.setFunc(true); \
738             QVERIFY(prop2.isFunc()); \
739             QCOMPARE(COUNT_FLAGS(), 1); \
740         } while (0)
741     CHECK_FLAG(setReadable, isReadable);
742     CHECK_FLAG(setWritable, isWritable);
743     CHECK_FLAG(setResettable, isResettable);
744     CHECK_FLAG(setDesignable, isDesignable);
745     CHECK_FLAG(setScriptable, isScriptable);
746     CHECK_FLAG(setStored, isStored);
747     CHECK_FLAG(setEditable, isEditable);
748     CHECK_FLAG(setUser, isUser);
749     CHECK_FLAG(setStdCppSet, hasStdCppSet);
750     CHECK_FLAG(setEnumOrFlag, isEnumOrFlag);
751     CHECK_FLAG(setConstant, isConstant);
752     CHECK_FLAG(setFinal, isFinal);
753
754     // Check that nothing else changed.
755     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Properties));
756
757     // Add property from prototype
758     QMetaProperty prototype = SomethingOfEverything::staticMetaObject.property(1);
759     QVERIFY(prototype.name() == QByteArray("prop"));
760     QMetaPropertyBuilder prototypeProp = builder.addProperty(prototype);
761     QCOMPARE(prototypeProp.name(), QByteArray("prop"));
762     QVERIFY(prototypeProp.hasNotifySignal());
763     QCOMPARE(prototypeProp.notifySignal().signature(), QByteArray("propChanged(QString)"));
764     QCOMPARE(builder.methodCount(), 1);
765     QCOMPARE(builder.method(0).signature(), QByteArray("propChanged(QString)"));
766 }
767
768 void tst_QMetaObjectBuilder::variantProperty()
769 {
770     QMetaObjectBuilder builder;
771     builder.addProperty("variant", "const QVariant &");
772     QMetaObject *meta = builder.toMetaObject();
773
774     QMetaProperty prop = meta->property(meta->propertyOffset());
775     QCOMPARE(QMetaType::Type(prop.type()), QMetaType::QVariant);
776     QCOMPARE(QMetaType::Type(prop.userType()), QMetaType::QVariant);
777     QCOMPARE(QByteArray(prop.typeName()), QByteArray("QVariant"));
778
779     free(meta);
780 }
781
782 void tst_QMetaObjectBuilder::notifySignal()
783 {
784     QMetaObjectBuilder builder;
785
786     QMetaPropertyBuilder prop = builder.addProperty("foo", "const QString &");
787     builder.addSlot("setFoo(QString)");
788     QMetaMethodBuilder notify = builder.addSignal("fooChanged(QString)");
789
790     QVERIFY(!prop.hasNotifySignal());
791     QCOMPARE(prop.notifySignal().index(), 0);
792
793     prop.setNotifySignal(notify);
794     QVERIFY(prop.hasNotifySignal());
795     QCOMPARE(prop.notifySignal().index(), 1);
796
797     prop.setNotifySignal(QMetaMethodBuilder());
798     QVERIFY(!prop.hasNotifySignal());
799     QCOMPARE(prop.notifySignal().index(), 0);
800
801     prop.setNotifySignal(notify);
802     prop.removeNotifySignal();
803     QVERIFY(!prop.hasNotifySignal());
804     QCOMPARE(prop.notifySignal().index(), 0);
805
806     QCOMPARE(builder.methodCount(), 2);
807     QCOMPARE(builder.propertyCount(), 1);
808
809     // Check that nothing else changed except methods and properties.
810     QVERIFY(checkForSideEffects
811         (builder, QMetaObjectBuilder::Methods | QMetaObjectBuilder::Properties));
812 }
813
814 void tst_QMetaObjectBuilder::enumerator()
815 {
816     QMetaObjectBuilder builder;
817
818     // Add an enumerator and check its attributes.
819     QMetaEnumBuilder enum1 = builder.addEnumerator("foo");
820     QCOMPARE(enum1.name(), QByteArray("foo"));
821     QVERIFY(!enum1.isFlag());
822     QCOMPARE(enum1.keyCount(), 0);
823     QCOMPARE(enum1.index(), 0);
824     QCOMPARE(builder.enumeratorCount(), 1);
825
826     // Add another enumerator and check again.
827     QMetaEnumBuilder enum2 = builder.addEnumerator("bar");
828     QCOMPARE(enum2.name(), QByteArray("bar"));
829     QVERIFY(!enum2.isFlag());
830     QCOMPARE(enum2.keyCount(), 0);
831     QCOMPARE(enum2.index(), 1);
832     QCOMPARE(builder.enumeratorCount(), 2);
833
834     // Perform index-based lookup.
835     QCOMPARE(builder.indexOfEnumerator("foo"), 0);
836     QCOMPARE(builder.indexOfEnumerator("bar"), 1);
837     QCOMPARE(builder.indexOfEnumerator("baz"), -1);
838     QCOMPARE(builder.enumerator(1).name(), QByteArray("bar"));
839     QCOMPARE(builder.enumerator(9).name(), QByteArray());
840
841     // Modify the attributes on enum1.
842     enum1.setIsFlag(true);
843     QCOMPARE(enum1.addKey("ABC", 0), 0);
844     QCOMPARE(enum1.addKey("DEF", 1), 1);
845     QCOMPARE(enum1.addKey("GHI", -1), 2);
846
847     // Check that enum1 is changed, but enum2 is not.
848     QCOMPARE(enum1.name(), QByteArray("foo"));
849     QVERIFY(enum1.isFlag());
850     QCOMPARE(enum1.keyCount(), 3);
851     QCOMPARE(enum1.index(), 0);
852     QCOMPARE(enum1.key(0), QByteArray("ABC"));
853     QCOMPARE(enum1.key(1), QByteArray("DEF"));
854     QCOMPARE(enum1.key(2), QByteArray("GHI"));
855     QCOMPARE(enum1.key(3), QByteArray());
856     QCOMPARE(enum1.value(0), 0);
857     QCOMPARE(enum1.value(1), 1);
858     QCOMPARE(enum1.value(2), -1);
859     QCOMPARE(enum2.name(), QByteArray("bar"));
860     QVERIFY(!enum2.isFlag());
861     QCOMPARE(enum2.keyCount(), 0);
862     QCOMPARE(enum2.index(), 1);
863
864     // Modify the attributes on enum2.
865     enum2.setIsFlag(true);
866     QCOMPARE(enum2.addKey("XYZ", 10), 0);
867     QCOMPARE(enum2.addKey("UVW", 19), 1);
868
869     // This time check that only method2 changed.
870     QCOMPARE(enum1.name(), QByteArray("foo"));
871     QVERIFY(enum1.isFlag());
872     QCOMPARE(enum1.keyCount(), 3);
873     QCOMPARE(enum1.index(), 0);
874     QCOMPARE(enum1.key(0), QByteArray("ABC"));
875     QCOMPARE(enum1.key(1), QByteArray("DEF"));
876     QCOMPARE(enum1.key(2), QByteArray("GHI"));
877     QCOMPARE(enum1.key(3), QByteArray());
878     QCOMPARE(enum1.value(0), 0);
879     QCOMPARE(enum1.value(1), 1);
880     QCOMPARE(enum1.value(2), -1);
881     QCOMPARE(enum2.name(), QByteArray("bar"));
882     QVERIFY(enum2.isFlag());
883     QCOMPARE(enum2.keyCount(), 2);
884     QCOMPARE(enum2.index(), 1);
885     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
886     QCOMPARE(enum2.key(1), QByteArray("UVW"));
887     QCOMPARE(enum2.key(2), QByteArray());
888     QCOMPARE(enum2.value(0), 10);
889     QCOMPARE(enum2.value(1), 19);
890
891     // Remove enum1 key
892     enum1.removeKey(2);
893     QCOMPARE(enum1.name(), QByteArray("foo"));
894     QVERIFY(enum1.isFlag());
895     QCOMPARE(enum1.keyCount(), 2);
896     QCOMPARE(enum1.index(), 0);
897     QCOMPARE(enum1.key(0), QByteArray("ABC"));
898     QCOMPARE(enum1.key(1), QByteArray("DEF"));
899     QCOMPARE(enum1.key(2), QByteArray());
900     QCOMPARE(enum1.value(0), 0);
901     QCOMPARE(enum1.value(1), 1);
902     QCOMPARE(enum1.value(2), -1);
903     QCOMPARE(enum2.name(), QByteArray("bar"));
904     QVERIFY(enum2.isFlag());
905     QCOMPARE(enum2.keyCount(), 2);
906     QCOMPARE(enum2.index(), 1);
907     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
908     QCOMPARE(enum2.key(1), QByteArray("UVW"));
909     QCOMPARE(enum2.key(2), QByteArray());
910     QCOMPARE(enum2.value(0), 10);
911     QCOMPARE(enum2.value(1), 19);
912
913     // Remove enum1 and check that enum2 becomes index 0.
914     builder.removeEnumerator(0);
915     QCOMPARE(builder.enumeratorCount(), 1);
916     enum2 = builder.enumerator(0);
917     QCOMPARE(enum2.name(), QByteArray("bar"));
918     QVERIFY(enum2.isFlag());
919     QCOMPARE(enum2.keyCount(), 2);
920     QCOMPARE(enum2.index(), 0);
921     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
922     QCOMPARE(enum2.key(1), QByteArray("UVW"));
923     QCOMPARE(enum2.key(2), QByteArray());
924     QCOMPARE(enum2.value(0), 10);
925     QCOMPARE(enum2.value(1), 19);
926
927     // Perform index-based lookup again.
928     QCOMPARE(builder.indexOfEnumerator("foo"), -1);
929     QCOMPARE(builder.indexOfEnumerator("bar"), 0);
930     QCOMPARE(builder.indexOfEnumerator("baz"), -1);
931
932     // Check that nothing else changed.
933     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Enumerators));
934 }
935
936 void tst_QMetaObjectBuilder::classInfo()
937 {
938     QMetaObjectBuilder builder;
939
940     // Add two items of class information and check their attributes.
941     QCOMPARE(builder.addClassInfo("foo", "value1"), 0);
942     QCOMPARE(builder.addClassInfo("bar", "value2"), 1);
943     QCOMPARE(builder.classInfoName(0), QByteArray("foo"));
944     QCOMPARE(builder.classInfoValue(0), QByteArray("value1"));
945     QCOMPARE(builder.classInfoName(1), QByteArray("bar"));
946     QCOMPARE(builder.classInfoValue(1), QByteArray("value2"));
947     QCOMPARE(builder.classInfoName(9), QByteArray());
948     QCOMPARE(builder.classInfoValue(9), QByteArray());
949     QCOMPARE(builder.classInfoCount(), 2);
950
951     // Perform index-based lookup.
952     QCOMPARE(builder.indexOfClassInfo("foo"), 0);
953     QCOMPARE(builder.indexOfClassInfo("bar"), 1);
954     QCOMPARE(builder.indexOfClassInfo("baz"), -1);
955
956     // Remove the first one and check again.
957     builder.removeClassInfo(0);
958     QCOMPARE(builder.classInfoName(0), QByteArray("bar"));
959     QCOMPARE(builder.classInfoValue(0), QByteArray("value2"));
960     QCOMPARE(builder.classInfoCount(), 1);
961
962     // Perform index-based lookup again.
963     QCOMPARE(builder.indexOfClassInfo("foo"), -1);
964     QCOMPARE(builder.indexOfClassInfo("bar"), 0);
965     QCOMPARE(builder.indexOfClassInfo("baz"), -1);
966
967     // Check that nothing else changed.
968     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::ClassInfos));
969 }
970
971 void tst_QMetaObjectBuilder::relatedMetaObject()
972 {
973     QMetaObjectBuilder builder;
974
975     // Add two related meta objects and check their attributes.
976     QCOMPARE(builder.addRelatedMetaObject(&QObject::staticMetaObject), 0);
977     QCOMPARE(builder.addRelatedMetaObject(&staticMetaObject), 1);
978     QVERIFY(builder.relatedMetaObject(0) == &QObject::staticMetaObject);
979     QVERIFY(builder.relatedMetaObject(1) == &staticMetaObject);
980     QCOMPARE(builder.relatedMetaObjectCount(), 2);
981
982     // Remove the first one and check again.
983     builder.removeRelatedMetaObject(0);
984     QVERIFY(builder.relatedMetaObject(0) == &staticMetaObject);
985     QCOMPARE(builder.relatedMetaObjectCount(), 1);
986
987     // Check that nothing else changed.
988     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::RelatedMetaObjects));
989 }
990
991 static void smetacall(QObject *, QMetaObject::Call, int, void **)
992 {
993     return;
994 }
995
996 void tst_QMetaObjectBuilder::staticMetacall()
997 {
998     QMetaObjectBuilder builder;
999     QVERIFY(!builder.staticMetacallFunction());
1000     builder.setStaticMetacallFunction(smetacall);
1001     QVERIFY(builder.staticMetacallFunction() == smetacall);
1002     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::StaticMetacall));
1003 }
1004
1005 // Copy the entire contents of a static QMetaObject and then check
1006 // that QMetaObjectBuilder will produce an exact copy as output.
1007 void tst_QMetaObjectBuilder::copyMetaObject()
1008 {
1009     QMetaObjectBuilder builder(&QObject::staticMetaObject);
1010     QMetaObject *meta = builder.toMetaObject();
1011     QVERIFY(sameMetaObject(meta, &QObject::staticMetaObject));
1012     free(meta);
1013
1014     QMetaObjectBuilder builder2(&staticMetaObject);
1015     meta = builder2.toMetaObject();
1016     QVERIFY(sameMetaObject(meta, &staticMetaObject));
1017     free(meta);
1018
1019     QMetaObjectBuilder builder3(&SomethingOfEverything::staticMetaObject);
1020     meta = builder3.toMetaObject();
1021     QVERIFY(sameMetaObject(meta, &SomethingOfEverything::staticMetaObject));
1022     free(meta);
1023 }
1024
1025 // Serialize and deserialize a meta object and check that
1026 // it round-trips to the exact same value.
1027 void tst_QMetaObjectBuilder::serialize()
1028 {
1029     // Full QMetaObjectBuilder
1030     {
1031     QMetaObjectBuilder builder(&SomethingOfEverything::staticMetaObject);
1032     QMetaObject *meta = builder.toMetaObject();
1033
1034     QByteArray data;
1035     QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append);
1036     builder.serialize(stream);
1037
1038     QMetaObjectBuilder builder2;
1039     QDataStream stream2(data);
1040     QMap<QByteArray, const QMetaObject *> references;
1041     references.insert(QByteArray("QLocale"), &QLocale::staticMetaObject);
1042     builder2.deserialize(stream2, references);
1043     builder2.setStaticMetacallFunction(builder.staticMetacallFunction());
1044     QMetaObject *meta2 = builder2.toMetaObject();
1045
1046     QVERIFY(sameMetaObject(meta, meta2));
1047     free(meta);
1048     free(meta2);
1049     }
1050
1051     // Partial QMetaObjectBuilder
1052     {
1053     QMetaObjectBuilder builder;
1054     builder.setClassName("Test");
1055     builder.addProperty("foo", "int");
1056
1057     QByteArray data;
1058     QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append);
1059     builder.serialize(stream);
1060
1061     QMetaObjectBuilder builder2;
1062     QDataStream stream2(data);
1063     builder2.deserialize(stream2, QMap<QByteArray, const QMetaObject *>());
1064
1065     QCOMPARE(builder.superClass(), builder2.superClass());
1066     QCOMPARE(builder.className(), builder2.className());
1067     QCOMPARE(builder.propertyCount(), builder2.propertyCount());
1068     QCOMPARE(builder.property(0).name(), builder2.property(0).name());
1069     QCOMPARE(builder.property(0).type(), builder2.property(0).type());
1070     }
1071 }
1072
1073 void tst_QMetaObjectBuilder::relocatableData()
1074 {
1075     QMetaObjectBuilder builder;
1076     builder.setClassName("TestObject");
1077
1078     QMetaMethodBuilder intPropChanged = builder.addSignal("intPropChanged(int)");
1079     intPropChanged.setParameterNames(QList<QByteArray>() << "newIntPropValue");
1080
1081     QMetaPropertyBuilder prop = builder.addProperty("intProp", "int");
1082     prop.setNotifySignal(intPropChanged);
1083
1084     QMetaMethodBuilder voidSlotInt = builder.addSlot("voidSlotInt(int)");
1085     voidSlotInt.setParameterNames(QList<QByteArray>() << "slotIntArg");
1086
1087     QMetaMethodBuilder listInvokableQRealQString = builder.addMethod("listInvokableQRealQString(qreal,QString)");
1088     listInvokableQRealQString.setReturnType("QVariantList");
1089     listInvokableQRealQString.setParameterNames(QList<QByteArray>() << "qrealArg" << "qstringArg");
1090
1091     bool ok = false;
1092     QByteArray data = builder.toRelocatableData(&ok);
1093     QVERIFY(ok);
1094
1095     QMetaObjectBuilder builder2;
1096     QMetaObject meta2;
1097     builder2.fromRelocatableData(&meta2, &QObject::staticMetaObject, data);
1098
1099     QMetaObject *meta = builder.toMetaObject();
1100
1101     QVERIFY(sameMetaObject(meta, &meta2));
1102
1103     QVERIFY(!meta2.d.extradata);
1104     QVERIFY(!meta2.d.relatedMetaObjects);
1105     QVERIFY(!meta2.d.static_metacall);
1106
1107     free(meta);
1108 }
1109
1110
1111 // Check that removing a method updates notify signals appropriately
1112 void tst_QMetaObjectBuilder::removeNotifySignal()
1113 {
1114     QMetaObjectBuilder builder;
1115
1116     builder.addSignal("foo(const QString&, int)");
1117     QMetaMethodBuilder method = builder.addSignal("bar(QString)");
1118
1119     // Setup property
1120     QMetaPropertyBuilder prop = builder.addProperty("prop", "const QString &");
1121     prop.setNotifySignal(method);
1122     QVERIFY(prop.hasNotifySignal());
1123     QCOMPARE(prop.notifySignal().index(), 1);
1124
1125     // Remove non-notify signal
1126     builder.removeMethod(0);
1127     QVERIFY(prop.hasNotifySignal());
1128     QCOMPARE(prop.notifySignal().index(), 0);
1129
1130     // Remove notify signal
1131     builder.removeMethod(0);
1132     QVERIFY(!prop.hasNotifySignal());
1133 }
1134
1135 // Check that the only changes to a "builder" relative to the default
1136 // state is specified by "members".
1137 bool tst_QMetaObjectBuilder::checkForSideEffects
1138         (const QMetaObjectBuilder& builder,
1139          QMetaObjectBuilder::AddMembers members)
1140 {
1141     if ((members & QMetaObjectBuilder::ClassName) == 0) {
1142         if (!builder.className().isEmpty())
1143             return false;
1144     }
1145
1146     if ((members & QMetaObjectBuilder::SuperClass) == 0) {
1147         if (builder.superClass() != &QObject::staticMetaObject)
1148             return false;
1149     }
1150
1151     if ((members & QMetaObjectBuilder::Methods) == 0) {
1152         if (builder.methodCount() != 0)
1153             return false;
1154     }
1155
1156     if ((members & QMetaObjectBuilder::Constructors) == 0) {
1157         if (builder.constructorCount() != 0)
1158             return false;
1159     }
1160
1161     if ((members & QMetaObjectBuilder::Properties) == 0) {
1162         if (builder.propertyCount() != 0)
1163             return false;
1164     }
1165
1166     if ((members & QMetaObjectBuilder::Enumerators) == 0) {
1167         if (builder.enumeratorCount() != 0)
1168             return false;
1169     }
1170
1171     if ((members & QMetaObjectBuilder::ClassInfos) == 0) {
1172         if (builder.classInfoCount() != 0)
1173             return false;
1174     }
1175
1176     if ((members & QMetaObjectBuilder::RelatedMetaObjects) == 0) {
1177         if (builder.relatedMetaObjectCount() != 0)
1178             return false;
1179     }
1180
1181     if ((members & QMetaObjectBuilder::StaticMetacall) == 0) {
1182         if (builder.staticMetacallFunction() != 0)
1183             return false;
1184     }
1185
1186     return true;
1187 }
1188
1189 static bool sameMethod(const QMetaMethod& method1, const QMetaMethod& method2)
1190 {
1191     if (method1.methodSignature() != method2.methodSignature())
1192         return false;
1193
1194     if (QByteArray(method1.typeName()) != QByteArray(method2.typeName()))
1195         return false;
1196
1197     if (method1.parameterTypes() != method2.parameterTypes())
1198         return false;
1199
1200     if (method1.parameterNames() != method2.parameterNames())
1201         return false;
1202
1203     if (QByteArray(method1.tag()) != QByteArray(method2.tag()))
1204         return false;
1205
1206     if (method1.access() != method2.access())
1207         return false;
1208
1209     if (method1.methodType() != method2.methodType())
1210         return false;
1211
1212     if (method1.attributes() != method2.attributes())
1213         return false;
1214
1215     if (method1.revision() != method2.revision())
1216         return false;
1217
1218     return true;
1219 }
1220
1221 static bool sameProperty(const QMetaProperty& prop1, const QMetaProperty& prop2)
1222 {
1223     if (QByteArray(prop1.name()) != QByteArray(prop2.name()))
1224         return false;
1225
1226     if (QByteArray(prop1.typeName()) != QByteArray(prop2.typeName()))
1227         return false;
1228
1229     if (prop1.isReadable() != prop2.isReadable() ||
1230         prop1.isWritable() != prop2.isWritable() ||
1231         prop1.isResettable() != prop2.isResettable() ||
1232         prop1.isDesignable() != prop2.isDesignable() ||
1233         prop1.isScriptable() != prop2.isScriptable() ||
1234         prop1.isStored() != prop2.isStored() ||
1235         prop1.isEditable() != prop2.isEditable() ||
1236         prop1.isUser() != prop2.isUser() ||
1237         prop1.isFlagType() != prop2.isFlagType() ||
1238         prop1.isEnumType() != prop2.isEnumType() ||
1239         prop1.hasNotifySignal() != prop2.hasNotifySignal() ||
1240         prop1.hasStdCppSet() != prop2.hasStdCppSet())
1241         return false;
1242
1243     if (prop1.hasNotifySignal()) {
1244         if (prop1.notifySignalIndex() != prop2.notifySignalIndex())
1245             return false;
1246     }
1247
1248     if (prop1.revision() != prop2.revision())
1249         return false;
1250
1251     return true;
1252 }
1253
1254 static bool sameEnumerator(const QMetaEnum& enum1, const QMetaEnum& enum2)
1255 {
1256     if (QByteArray(enum1.name()) != QByteArray(enum2.name()))
1257         return false;
1258
1259     if (enum1.isFlag() != enum2.isFlag())
1260         return false;
1261
1262     if (enum1.keyCount() != enum2.keyCount())
1263         return false;
1264
1265     for (int index = 0; index < enum1.keyCount(); ++index) {
1266         if (QByteArray(enum1.key(index)) != QByteArray(enum2.key(index)))
1267             return false;
1268         if (enum1.value(index) != enum2.value(index))
1269             return false;
1270     }
1271
1272     if (QByteArray(enum1.scope()) != QByteArray(enum2.scope()))
1273         return false;
1274
1275     return true;
1276 }
1277
1278 // Determine if two meta objects are identical.
1279 bool tst_QMetaObjectBuilder::sameMetaObject
1280         (const QMetaObject *meta1, const QMetaObject *meta2)
1281 {
1282     int index;
1283
1284     if (strcmp(meta1->className(), meta2->className()) != 0)
1285         return false;
1286
1287     if (meta1->superClass() != meta2->superClass())
1288         return false;
1289
1290     if (meta1->constructorCount() != meta2->constructorCount() ||
1291         meta1->methodCount() != meta2->methodCount() ||
1292         meta1->enumeratorCount() != meta2->enumeratorCount() ||
1293         meta1->propertyCount() != meta2->propertyCount() ||
1294         meta1->classInfoCount() != meta2->classInfoCount())
1295         return false;
1296
1297     for (index = 0; index < meta1->constructorCount(); ++index) {
1298         if (!sameMethod(meta1->constructor(index), meta2->constructor(index)))
1299             return false;
1300     }
1301
1302     for (index = 0; index < meta1->methodCount(); ++index) {
1303         if (!sameMethod(meta1->method(index), meta2->method(index)))
1304             return false;
1305     }
1306
1307     for (index = 0; index < meta1->propertyCount(); ++index) {
1308         if (!sameProperty(meta1->property(index), meta2->property(index)))
1309             return false;
1310     }
1311
1312     for (index = 0; index < meta1->enumeratorCount(); ++index) {
1313         if (!sameEnumerator(meta1->enumerator(index), meta2->enumerator(index)))
1314             return false;
1315     }
1316
1317     for (index = 0; index < meta1->classInfoCount(); ++index) {
1318         if (QByteArray(meta1->classInfo(index).name()) !=
1319             QByteArray(meta2->classInfo(index).name()))
1320             return false;
1321         if (QByteArray(meta1->classInfo(index).value()) !=
1322             QByteArray(meta2->classInfo(index).value()))
1323             return false;
1324     }
1325
1326     const QMetaObject **objects1 = meta1->d.relatedMetaObjects;
1327     const QMetaObject **objects2 = meta2->d.relatedMetaObjects;
1328     if (objects1 && !objects2)
1329         return false;
1330     if (objects2 && !objects1)
1331         return false;
1332     if (objects1 && objects2) {
1333         while (*objects1 != 0 && *objects2 != 0) {
1334             if (*objects1 != *objects2)
1335                 return false;
1336             ++objects1;
1337             ++objects2;
1338         }
1339     }
1340
1341     return true;
1342 }
1343
1344
1345 // This class is used to test that the meta-object generated by QMOB can be
1346 // used by a real object.
1347 // The class manually implements the functions normally generated by moc, and
1348 // creates the corresponding meta-object using QMOB. The autotests check that
1349 // this object can be used by QObject/QMetaObject functionality (property
1350 // access, signals & slots, constructing instances, ...).
1351
1352 class TestObject : public QObject
1353 {
1354     // Manually expanded from Q_OBJECT macro
1355 public:
1356     Q_OBJECT_CHECK
1357     static QMetaObject staticMetaObject;
1358     virtual const QMetaObject *metaObject() const;
1359     virtual void *qt_metacast(const char *);
1360     virtual int qt_metacall(QMetaObject::Call, int, void **);
1361 private:
1362     Q_DECL_HIDDEN static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
1363
1364     //Q_PROPERTY(int intProp READ intProp WRITE setIntProp NOTIFY intPropChanged)
1365 public:
1366     TestObject(QObject *parent = 0); // Q_INVOKABLE
1367     ~TestObject();
1368
1369     // Property accessors
1370     int intProp() const;
1371     void setIntProp(int v);
1372
1373     void emitIntPropChanged();
1374
1375     int voidSlotIntArgument() const;
1376
1377 // Q_INVOKABLE
1378     QVariantList listInvokableQRealQString(qreal, const QString &);
1379
1380 //public Q_SLOTS:
1381     void voidSlotInt(int);
1382
1383 //Q_SIGNALS:
1384     void intPropChanged(int);
1385
1386 private:
1387     static QMetaObject *buildMetaObject();
1388
1389     QMetaObject *m_metaObject;
1390     int m_intProp;
1391     int m_voidSlotIntArg;
1392 };
1393
1394 QMetaObject TestObject::staticMetaObject = {
1395     { 0, 0, 0, 0, 0, 0 }
1396 };
1397
1398 TestObject::TestObject(QObject *parent)
1399     : QObject(parent), m_metaObject(buildMetaObject()),
1400       m_intProp(-1), m_voidSlotIntArg(-1)
1401 {
1402     staticMetaObject = *m_metaObject;
1403 }
1404
1405 TestObject::~TestObject()
1406 {
1407     free(m_metaObject);
1408 }
1409
1410 QMetaObject *TestObject::buildMetaObject()
1411 {
1412     QMetaObjectBuilder builder;
1413     // NOTE: If you change the meta-object, remember to adapt qt_metacall and
1414     // friends below accordingly.
1415
1416     builder.setClassName("TestObject");
1417
1418     builder.setStaticMetacallFunction(qt_static_metacall);
1419
1420     QMetaMethodBuilder intPropChanged = builder.addSignal("intPropChanged(int)");
1421     intPropChanged.setParameterNames(QList<QByteArray>() << "newIntPropValue");
1422
1423     QMetaPropertyBuilder prop = builder.addProperty("intProp", "int");
1424     prop.setNotifySignal(intPropChanged);
1425
1426     QMetaMethodBuilder voidSlotInt = builder.addSlot("voidSlotInt(int)");
1427     voidSlotInt.setParameterNames(QList<QByteArray>() << "slotIntArg");
1428
1429     QMetaMethodBuilder listInvokableQRealQString = builder.addMethod("listInvokableQRealQString(qreal,QString)");
1430     listInvokableQRealQString.setReturnType("QVariantList");
1431     listInvokableQRealQString.setParameterNames(QList<QByteArray>() << "qrealArg" << "qstringArg");
1432
1433     builder.addConstructor("TestObject(QObject*)");
1434     builder.addConstructor("TestObject()");
1435
1436     return builder.toMetaObject();
1437 }
1438
1439 int TestObject::intProp() const
1440 {
1441     return m_intProp;
1442 }
1443
1444 void TestObject::setIntProp(int value)
1445 {
1446     if (m_intProp != value) {
1447         m_intProp = value;
1448         emit intPropChanged(value);
1449     }
1450 }
1451
1452 void TestObject::emitIntPropChanged()
1453 {
1454     emit intPropChanged(m_intProp);
1455 }
1456
1457 QVariantList TestObject::listInvokableQRealQString(qreal r, const QString &s)
1458 {
1459     return QVariantList() << r << s;
1460 }
1461
1462 void TestObject::voidSlotInt(int value)
1463 {
1464     m_voidSlotIntArg = value;
1465 }
1466
1467 int TestObject::voidSlotIntArgument() const
1468 {
1469     return m_voidSlotIntArg;
1470 }
1471
1472 void TestObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
1473 {
1474     if (_c == QMetaObject::CreateInstance) {
1475         switch (_id) {
1476         case 0: { TestObject *_r = new TestObject((*reinterpret_cast< QObject*(*)>(_a[1])));
1477             if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;
1478         case 1: { TestObject *_r = new TestObject();
1479             if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;
1480         default: {
1481             QMetaMethod ctor = _o->metaObject()->constructor(_id);
1482             qFatal("You forgot to add a case for CreateInstance %s", ctor.methodSignature().constData());
1483           }
1484         }
1485     } else if (_c == QMetaObject::InvokeMetaMethod) {
1486         Q_ASSERT(_o->metaObject()->cast(_o));
1487         TestObject *_t = static_cast<TestObject *>(_o);
1488         switch (_id) {
1489         case 0: _t->intPropChanged((*reinterpret_cast< int(*)>(_a[1]))); break;
1490         case 1: _t->voidSlotInt((*reinterpret_cast< int(*)>(_a[1]))); break;
1491         case 2: *reinterpret_cast<QVariantList(*)>(_a[0]) = _t->listInvokableQRealQString(*reinterpret_cast<qreal(*)>(_a[1]), *reinterpret_cast<QString(*)>(_a[2])); break;
1492         default: {
1493             QMetaMethod method = _o->metaObject()->method(_o->metaObject()->methodOffset() + _id);
1494             qFatal("You forgot to add a case for InvokeMetaMethod %s", method.methodSignature().constData());
1495           }
1496         }
1497     } else if (_c == QMetaObject::IndexOfMethod) {
1498         int *result = reinterpret_cast<int *>(_a[0]);
1499         void **func = reinterpret_cast<void **>(_a[1]);
1500         {
1501             typedef void (TestObject::*_t)(int );
1502             if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestObject::intPropChanged)) {
1503                 *result = 0;
1504             }
1505         }
1506         {
1507             typedef void (TestObject::*_t)(int );
1508             if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestObject::voidSlotInt)) {
1509                 *result = 1;
1510             }
1511         }
1512         {
1513             typedef QVariantList (TestObject::*_t)(qreal, const QString &);
1514             if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestObject::listInvokableQRealQString)) {
1515                 *result = 2;
1516             }
1517         }
1518     }
1519 }
1520
1521 const QMetaObject *TestObject::metaObject() const
1522 {
1523     return m_metaObject;
1524 }
1525
1526 void *TestObject::qt_metacast(const char *_clname)
1527 {
1528     if (!_clname) return 0;
1529     if (!strcmp(_clname, "TestObject"))
1530         return static_cast<void*>(const_cast< TestObject*>(this));
1531     return QObject::qt_metacast(_clname);
1532 }
1533
1534 int TestObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
1535 {
1536     _id = QObject::qt_metacall(_c, _id, _a);
1537     if (_id < 0)
1538         return _id;
1539     int ownMethodCount = m_metaObject->methodCount() - m_metaObject->methodOffset();
1540     int ownPropertyCount = m_metaObject->propertyCount() - m_metaObject->propertyOffset();
1541     if (_c == QMetaObject::InvokeMetaMethod) {
1542         if (_id < ownMethodCount)
1543             qt_static_metacall(this, _c, _id, _a);
1544         _id -= ownMethodCount;
1545     }
1546 #ifndef QT_NO_PROPERTIES
1547       else if (_c == QMetaObject::ReadProperty) {
1548         void *_v = _a[0];
1549         switch (_id) {
1550         case 0: *reinterpret_cast< int*>(_v) = intProp(); break;
1551         default: if (_id < ownPropertyCount) {
1552             QMetaProperty prop = m_metaObject->property(m_metaObject->propertyOffset() + _id);
1553             qFatal("You forgot to add a case for ReadProperty %s", prop.name());
1554           }
1555         }
1556         _id -= ownPropertyCount;
1557     } else if (_c == QMetaObject::WriteProperty) {
1558         void *_v = _a[0];
1559         switch (_id) {
1560         case 0: setIntProp(*reinterpret_cast< int*>(_v)); break;
1561         default: if (_id < ownPropertyCount) {
1562             QMetaProperty prop = m_metaObject->property(m_metaObject->propertyOffset() + _id);
1563             qFatal("You forgot to add a case for WriteProperty %s", prop.name());
1564           }
1565         }
1566         _id -= ownPropertyCount;
1567     } else if (_c == QMetaObject::ResetProperty) {
1568         _id -= ownPropertyCount;
1569     } else if (_c == QMetaObject::QueryPropertyDesignable) {
1570         _id -= ownPropertyCount;
1571     } else if (_c == QMetaObject::QueryPropertyScriptable) {
1572         _id -= ownPropertyCount;
1573     } else if (_c == QMetaObject::QueryPropertyStored) {
1574         _id -= ownPropertyCount;
1575     } else if (_c == QMetaObject::QueryPropertyEditable) {
1576         _id -= ownPropertyCount;
1577     } else if (_c == QMetaObject::QueryPropertyUser) {
1578         _id -= ownPropertyCount;
1579     }
1580 #endif // QT_NO_PROPERTIES
1581     return _id;
1582 }
1583
1584 // SIGNAL 0
1585 void TestObject::intPropChanged(int _t1)
1586 {
1587     void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
1588     QMetaObject::activate(this, m_metaObject, 0, _a);
1589 }
1590
1591
1592 void tst_QMetaObjectBuilder::usage_signal()
1593 {
1594     QScopedPointer<TestObject> testObject(new TestObject);
1595
1596     QSignalSpy propChangedSpy(testObject.data(), SIGNAL(intPropChanged(int)));
1597     testObject->emitIntPropChanged();
1598     QCOMPARE(propChangedSpy.count(), 1);
1599     QCOMPARE(propChangedSpy.at(0).count(), 1);
1600     QCOMPARE(propChangedSpy.at(0).at(0).toInt(), testObject->intProp());
1601 }
1602
1603 void tst_QMetaObjectBuilder::usage_property()
1604 {
1605     QScopedPointer<TestObject> testObject(new TestObject);
1606
1607     QVariant prop = testObject->property("intProp");
1608     QCOMPARE(prop.type(), QVariant::Int);
1609     QCOMPARE(prop.toInt(), testObject->intProp());
1610
1611     QSignalSpy propChangedSpy(testObject.data(), SIGNAL(intPropChanged(int)));
1612     QVERIFY(testObject->intProp() != 123);
1613     testObject->setProperty("intProp", 123);
1614     QCOMPARE(propChangedSpy.count(), 1);
1615     prop = testObject->property("intProp");
1616     QCOMPARE(prop.type(), QVariant::Int);
1617     QCOMPARE(prop.toInt(), 123);
1618 }
1619
1620 void tst_QMetaObjectBuilder::usage_slot()
1621 {
1622     QScopedPointer<TestObject> testObject(new TestObject);
1623
1624     int index = testObject->metaObject()->indexOfMethod("voidSlotInt(int)");
1625     QVERIFY(index != -1);
1626     QMetaMethod voidSlotInt = testObject->metaObject()->method(index);
1627
1628     QVERIFY(testObject->voidSlotIntArgument() == -1);
1629     QVERIFY(voidSlotInt.invoke(testObject.data(), Q_ARG(int, 123)));
1630     QCOMPARE(testObject->voidSlotIntArgument(), 123);
1631 }
1632
1633 void tst_QMetaObjectBuilder::usage_method()
1634 {
1635     QScopedPointer<TestObject> testObject(new TestObject);
1636
1637     int index = testObject->metaObject()->indexOfMethod("listInvokableQRealQString(qreal,QString)");
1638     QVERIFY(index != -1);
1639     QMetaMethod listInvokableQRealQString = testObject->metaObject()->method(index);
1640     QVariantList list;
1641     QVERIFY(listInvokableQRealQString.invoke(testObject.data(), Q_RETURN_ARG(QVariantList, list),
1642                                              Q_ARG(qreal, 123.0), Q_ARG(QString, "ciao")));
1643     QCOMPARE(list.size(), 2);
1644     QCOMPARE(list.at(0).type(), QVariant::Type(QMetaType::QReal));
1645     QCOMPARE(list.at(0).toDouble(), double(123));
1646     QCOMPARE(list.at(1).type(), QVariant::String);
1647     QCOMPARE(list.at(1).toString(), QString::fromLatin1("ciao"));
1648 }
1649
1650 void tst_QMetaObjectBuilder::usage_constructor()
1651 {
1652     QScopedPointer<TestObject> testObject(new TestObject);
1653
1654     QCOMPARE(testObject->metaObject()->constructorCount(), 2);
1655     QScopedPointer<QObject> testInstance(testObject->metaObject()->newInstance());
1656     QVERIFY(testInstance != 0);
1657     QScopedPointer<QObject> testInstance2(testObject->metaObject()->newInstance(Q_ARG(QObject*, testInstance.data())));
1658     QVERIFY(testInstance2 != 0);
1659     QCOMPARE(testInstance2->parent(), testInstance.data());
1660 }
1661
1662 void tst_QMetaObjectBuilder::usage_connect()
1663 {
1664     QScopedPointer<TestObject> testObject(new TestObject);
1665
1666     QVERIFY(QObject::connect(testObject.data(), SIGNAL(intPropChanged(int)),
1667                              testObject.data(), SLOT(voidSlotInt(int))));
1668
1669     QVERIFY(testObject->voidSlotIntArgument() == -1);
1670     testObject->setProperty("intProp", 123);
1671     QCOMPARE(testObject->voidSlotIntArgument(), 123);
1672
1673     QVERIFY(QObject::disconnect(testObject.data(), SIGNAL(intPropChanged(int)),
1674                                 testObject.data(), SLOT(voidSlotInt(int))));
1675 }
1676
1677 void tst_QMetaObjectBuilder::usage_templateConnect()
1678 {
1679     QScopedPointer<TestObject> testObject(new TestObject);
1680
1681     QMetaObject::Connection con = QObject::connect(testObject.data(), &TestObject::intPropChanged,
1682                                                    testObject.data(), &TestObject::voidSlotInt);
1683     QVERIFY(con);
1684
1685     QVERIFY(testObject->voidSlotIntArgument() == -1);
1686     testObject->setProperty("intProp", 123);
1687     QCOMPARE(testObject->voidSlotIntArgument(), 123);
1688
1689     QVERIFY(QObject::disconnect(testObject.data(), &TestObject::intPropChanged,
1690                                 testObject.data(), &TestObject::voidSlotInt));
1691
1692     // Something that isn't a signal
1693     QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in TestObject");
1694     con = QObject::connect(testObject.data(), &TestObject::setIntProp,
1695                            testObject.data(), &TestObject::intPropChanged);
1696     QVERIFY(!con);
1697 }
1698
1699 void tst_QMetaObjectBuilder::classNameFirstInStringData()
1700 {
1701     QMetaObjectBuilder builder;
1702     builder.addMetaObject(&SomethingOfEverything::staticMetaObject);
1703     builder.setClassName(QByteArrayLiteral("TestClass"));
1704     QMetaObject *mo = builder.toMetaObject();
1705
1706     QByteArrayDataPtr header;
1707     header.ptr = const_cast<QByteArrayData*>(mo->d.stringdata);
1708     QCOMPARE(QByteArray(header), QByteArrayLiteral("TestClass"));
1709
1710     free(mo);
1711 }
1712
1713 QTEST_MAIN(tst_QMetaObjectBuilder)
1714
1715 #include "tst_qmetaobjectbuilder.moc"