Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qmetaobjectbuilder / tst_qmetaobjectbuilder.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
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 public:
50     tst_QMetaObjectBuilder() {}
51     ~tst_QMetaObjectBuilder() {}
52
53 private slots:
54     void mocVersionCheck();
55     void create();
56     void className();
57     void superClass();
58     void flags();
59     void method();
60     void slot();
61     void signal();
62     void constructor();
63     void property();
64     void notifySignal();
65     void enumerator();
66     void classInfo();
67     void relatedMetaObject();
68     void staticMetacall();
69     void copyMetaObject();
70     void serialize();
71     void removeNotifySignal();
72
73 private:
74     static bool checkForSideEffects
75         (const QMetaObjectBuilder& builder,
76          QMetaObjectBuilder::AddMembers members);
77     static bool sameMetaObject
78         (const QMetaObject *meta1, const QMetaObject *meta2);
79 };
80
81 // Dummy class that has something of every type of thing moc can generate.
82 class SomethingOfEverything : public QObject
83 {
84     Q_OBJECT
85     Q_CLASSINFO("ci_foo", "ABC")
86     Q_CLASSINFO("ci_bar", "DEF")
87     Q_PROPERTY(QString prop READ prop WRITE setProp NOTIFY propChanged)
88     Q_PROPERTY(QString prop2 READ prop WRITE setProp)
89     Q_PROPERTY(SomethingEnum eprop READ eprop)
90     Q_PROPERTY(SomethingFlagEnum fprop READ fprop)
91     Q_PROPERTY(QLocale::Language language READ language)
92     Q_ENUMS(SomethingEnum)
93     Q_FLAGS(SomethingFlagEnum)
94 public:
95     Q_INVOKABLE SomethingOfEverything() {}
96     ~SomethingOfEverything() {}
97
98     enum SomethingEnum
99     {
100         GHI,
101         JKL = 10
102     };
103
104     enum SomethingFlagEnum
105     {
106         XYZ = 1,
107         UVW = 8
108     };
109
110     Q_INVOKABLE Q_SCRIPTABLE void method1() {}
111
112     QString prop() const { return QString(); }
113     void setProp(const QString& v) { Q_UNUSED(v); }
114
115     SomethingOfEverything::SomethingEnum eprop() const { return GHI; }
116     SomethingOfEverything::SomethingFlagEnum fprop() const { return XYZ; }
117     QLocale::Language language() const { return QLocale::English; }
118
119 public slots:
120     void slot1(const QString&) {}
121     void slot2(int, const QString&) {}
122
123 private slots:
124     void slot3() {}
125
126 protected slots:
127     Q_SCRIPTABLE void slot4(int) {}
128     void slot5(int a, const QString& b) { Q_UNUSED(a); Q_UNUSED(b); }
129
130 signals:
131     void sig1();
132     void sig2(int x, const QString& y);
133     void propChanged(const QString&);
134 };
135
136 void tst_QMetaObjectBuilder::mocVersionCheck()
137 {
138     // This test will fail when the moc version number is changed.
139     // It is intended as a reminder to also update QMetaObjectBuilder
140     // whenenver moc changes.  Once QMetaObjectBuilder has been
141     // updated, this test can be changed to check for the next version.
142     int version = int(QObject::staticMetaObject.d.data[0]);
143     QVERIFY(version == 4 || version == 5 || version == 6);
144     version = int(staticMetaObject.d.data[0]);
145     QVERIFY(version == 4 || version == 5 || version == 6);
146 }
147
148 void tst_QMetaObjectBuilder::create()
149 {
150     QMetaObjectBuilder builder;
151     QVERIFY(builder.className().isEmpty());
152     QVERIFY(builder.superClass() == &QObject::staticMetaObject);
153     QCOMPARE(builder.methodCount(), 0);
154     QCOMPARE(builder.constructorCount(), 0);
155     QCOMPARE(builder.propertyCount(), 0);
156     QCOMPARE(builder.enumeratorCount(), 0);
157     QCOMPARE(builder.classInfoCount(), 0);
158     QCOMPARE(builder.relatedMetaObjectCount(), 0);
159     QVERIFY(builder.staticMetacallFunction() == 0);
160 }
161
162 void tst_QMetaObjectBuilder::className()
163 {
164     QMetaObjectBuilder builder;
165
166     // Change the class name.
167     builder.setClassName("Foo");
168     QCOMPARE(builder.className(), QByteArray("Foo"));
169
170     // Change it again.
171     builder.setClassName("Bar");
172     QCOMPARE(builder.className(), QByteArray("Bar"));
173
174     // Clone the class name off a static QMetaObject.
175     builder.addMetaObject(&QObject::staticMetaObject, QMetaObjectBuilder::ClassName);
176     QCOMPARE(builder.className(), QByteArray("QObject"));
177
178     // Check that nothing else changed.
179     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::ClassName));
180 }
181
182 void tst_QMetaObjectBuilder::superClass()
183 {
184     QMetaObjectBuilder builder;
185
186     // Change the super class.
187     builder.setSuperClass(&QObject::staticMetaObject);
188     QVERIFY(builder.superClass() == &QObject::staticMetaObject);
189
190     // Change it again.
191     builder.setSuperClass(&staticMetaObject);
192     QVERIFY(builder.superClass() == &staticMetaObject);
193
194     // Clone the super class off a static QMetaObject.
195     builder.addMetaObject(&QObject::staticMetaObject, QMetaObjectBuilder::SuperClass);
196     QVERIFY(builder.superClass() == 0);
197     builder.addMetaObject(&staticMetaObject, QMetaObjectBuilder::SuperClass);
198     QVERIFY(builder.superClass() == staticMetaObject.superClass());
199
200     // Check that nothing else changed.
201     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::SuperClass));
202 }
203
204 void tst_QMetaObjectBuilder::flags()
205 {
206     QMetaObjectBuilder builder;
207
208     // Check default
209     QVERIFY(builder.flags() == 0);
210
211     // Set flags
212     builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
213     QVERIFY(builder.flags() == QMetaObjectBuilder::DynamicMetaObject);
214 }
215
216 void tst_QMetaObjectBuilder::method()
217 {
218     QMetaObjectBuilder builder;
219
220     // Check null method
221     QMetaMethodBuilder nullMethod;
222     QCOMPARE(nullMethod.signature(), QByteArray());
223     QVERIFY(nullMethod.methodType() == QMetaMethod::Method);
224     QVERIFY(nullMethod.returnType().isEmpty());
225     QVERIFY(nullMethod.parameterNames().isEmpty());
226     QVERIFY(nullMethod.tag().isEmpty());
227     QVERIFY(nullMethod.access() == QMetaMethod::Public);
228     QCOMPARE(nullMethod.attributes(), 0);
229     QCOMPARE(nullMethod.index(), 0);
230
231     // Add a method and check its attributes.
232     QMetaMethodBuilder method1 = builder.addMethod("foo(const QString&, int)");
233     QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
234     QVERIFY(method1.methodType() == QMetaMethod::Method);
235     QVERIFY(method1.returnType().isEmpty());
236     QVERIFY(method1.parameterNames().isEmpty());
237     QVERIFY(method1.tag().isEmpty());
238     QVERIFY(method1.access() == QMetaMethod::Public);
239     QCOMPARE(method1.attributes(), 0);
240     QCOMPARE(method1.index(), 0);
241     QCOMPARE(builder.methodCount(), 1);
242
243     // Add another method and check again.
244     QMetaMethodBuilder method2 = builder.addMethod("bar(QString)", "int");
245     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
246     QVERIFY(method2.methodType() == QMetaMethod::Method);
247     QCOMPARE(method2.returnType(), QByteArray("int"));
248     QVERIFY(method2.parameterNames().isEmpty());
249     QVERIFY(method2.tag().isEmpty());
250     QVERIFY(method2.access() == QMetaMethod::Public);
251     QCOMPARE(method2.attributes(), 0);
252     QCOMPARE(method2.index(), 1);
253     QCOMPARE(builder.methodCount(), 2);
254
255     // Perform index-based lookup.
256     QCOMPARE(builder.indexOfMethod("foo(const QString&, int)"), 0);
257     QCOMPARE(builder.indexOfMethod("bar(QString)"), 1);
258     QCOMPARE(builder.indexOfMethod("baz()"), -1);
259
260     // Modify the attributes on method1.
261     method1.setReturnType("int");
262     method1.setParameterNames(QList<QByteArray>() << "a" << "b");
263     method1.setTag("tag");
264     method1.setAccess(QMetaMethod::Private);
265     method1.setAttributes(42);
266
267     // Check that method1 is changed, but method2 is not.
268     QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
269     QVERIFY(method1.methodType() == QMetaMethod::Method);
270     QCOMPARE(method1.returnType(), QByteArray("int"));
271     QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b");
272     QCOMPARE(method1.tag(), QByteArray("tag"));
273     QVERIFY(method1.access() == QMetaMethod::Private);
274     QCOMPARE(method1.attributes(), 42);
275     QCOMPARE(method1.index(), 0);
276     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
277     QVERIFY(method2.methodType() == QMetaMethod::Method);
278     QCOMPARE(method2.returnType(), QByteArray("int"));
279     QVERIFY(method2.parameterNames().isEmpty());
280     QVERIFY(method2.tag().isEmpty());
281     QVERIFY(method2.access() == QMetaMethod::Public);
282     QCOMPARE(method2.attributes(), 0);
283     QCOMPARE(method2.index(), 1);
284     QCOMPARE(builder.methodCount(), 2);
285
286     // Modify the attributes on method2.
287     method2.setReturnType("QString");
288     method2.setParameterNames(QList<QByteArray>() << "c");
289     method2.setTag("Q_FOO");
290     method2.setAccess(QMetaMethod::Protected);
291     method2.setAttributes(24);
292
293     // This time check that only method2 changed.
294     QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
295     QVERIFY(method1.methodType() == QMetaMethod::Method);
296     QCOMPARE(method1.returnType(), QByteArray("int"));
297     QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b");
298     QCOMPARE(method1.tag(), QByteArray("tag"));
299     QVERIFY(method1.access() == QMetaMethod::Private);
300     QCOMPARE(method1.attributes(), 42);
301     QCOMPARE(method1.index(), 0);
302     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
303     QVERIFY(method2.methodType() == QMetaMethod::Method);
304     QCOMPARE(method2.returnType(), QByteArray("QString"));
305     QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c");
306     QCOMPARE(method2.tag(), QByteArray("Q_FOO"));
307     QVERIFY(method2.access() == QMetaMethod::Protected);
308     QCOMPARE(method2.attributes(), 24);
309     QCOMPARE(method2.index(), 1);
310     QCOMPARE(builder.methodCount(), 2);
311
312     // Remove method1 and check that method2 becomes index 0.
313     builder.removeMethod(0);
314     QCOMPARE(builder.methodCount(), 1);
315     method2 = builder.method(0);
316     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
317     QVERIFY(method2.methodType() == QMetaMethod::Method);
318     QCOMPARE(method2.returnType(), QByteArray("QString"));
319     QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c");
320     QCOMPARE(method2.tag(), QByteArray("Q_FOO"));
321     QVERIFY(method2.access() == QMetaMethod::Protected);
322     QCOMPARE(method2.attributes(), 24);
323     QCOMPARE(method2.index(), 0);
324
325     // Perform index-based lookup again.
326     QCOMPARE(builder.indexOfMethod("foo(const QString&, int)"), -1);
327     QCOMPARE(builder.indexOfMethod("bar(QString)"), 0);
328     QCOMPARE(builder.indexOfMethod("baz()"), -1);
329     QCOMPARE(builder.method(0).signature(), QByteArray("bar(QString)"));
330     QCOMPARE(builder.method(9).signature(), QByteArray());
331
332     // Check that nothing else changed.
333     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods));
334 }
335
336 void tst_QMetaObjectBuilder::slot()
337 {
338     QMetaObjectBuilder builder;
339
340     // Add a slot and check its attributes.
341     QMetaMethodBuilder method1 = builder.addSlot("foo(const QString&, int)");
342     QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
343     QVERIFY(method1.methodType() == QMetaMethod::Slot);
344     QVERIFY(method1.returnType().isEmpty());
345     QVERIFY(method1.parameterNames().isEmpty());
346     QVERIFY(method1.tag().isEmpty());
347     QVERIFY(method1.access() == QMetaMethod::Public);
348     QCOMPARE(method1.attributes(), 0);
349     QCOMPARE(method1.index(), 0);
350     QCOMPARE(builder.methodCount(), 1);
351
352     // Add another slot and check again.
353     QMetaMethodBuilder method2 = builder.addSlot("bar(QString)");
354     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
355     QVERIFY(method2.methodType() == QMetaMethod::Slot);
356     QVERIFY(method2.returnType().isEmpty());
357     QVERIFY(method2.parameterNames().isEmpty());
358     QVERIFY(method2.tag().isEmpty());
359     QVERIFY(method2.access() == QMetaMethod::Public);
360     QCOMPARE(method2.attributes(), 0);
361     QCOMPARE(method2.index(), 1);
362     QCOMPARE(builder.methodCount(), 2);
363
364     // Perform index-based lookup
365     QCOMPARE(builder.indexOfSlot("foo(const QString &, int)"), 0);
366     QCOMPARE(builder.indexOfSlot("bar(QString)"), 1);
367     QCOMPARE(builder.indexOfSlot("baz()"), -1);
368
369     // Check that nothing else changed.
370     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods));
371 }
372
373 void tst_QMetaObjectBuilder::signal()
374 {
375     QMetaObjectBuilder builder;
376
377     // Add a signal and check its attributes.
378     QMetaMethodBuilder method1 = builder.addSignal("foo(const QString&, int)");
379     QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
380     QVERIFY(method1.methodType() == QMetaMethod::Signal);
381     QVERIFY(method1.returnType().isEmpty());
382     QVERIFY(method1.parameterNames().isEmpty());
383     QVERIFY(method1.tag().isEmpty());
384     QVERIFY(method1.access() == QMetaMethod::Protected);
385     QCOMPARE(method1.attributes(), 0);
386     QCOMPARE(method1.index(), 0);
387     QCOMPARE(builder.methodCount(), 1);
388
389     // Add another signal and check again.
390     QMetaMethodBuilder method2 = builder.addSignal("bar(QString)");
391     QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
392     QVERIFY(method2.methodType() == QMetaMethod::Signal);
393     QVERIFY(method2.returnType().isEmpty());
394     QVERIFY(method2.parameterNames().isEmpty());
395     QVERIFY(method2.tag().isEmpty());
396     QVERIFY(method2.access() == QMetaMethod::Protected);
397     QCOMPARE(method2.attributes(), 0);
398     QCOMPARE(method2.index(), 1);
399     QCOMPARE(builder.methodCount(), 2);
400
401     // Perform index-based lookup
402     QCOMPARE(builder.indexOfSignal("foo(const QString &, int)"), 0);
403     QCOMPARE(builder.indexOfSignal("bar(QString)"), 1);
404     QCOMPARE(builder.indexOfSignal("baz()"), -1);
405
406     // Check that nothing else changed.
407     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods));
408 }
409
410 void tst_QMetaObjectBuilder::constructor()
411 {
412     QMetaObjectBuilder builder;
413
414     // Add a constructor and check its attributes.
415     QMetaMethodBuilder ctor1 = builder.addConstructor("foo(const QString&, int)");
416     QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)"));
417     QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
418     QVERIFY(ctor1.returnType().isEmpty());
419     QVERIFY(ctor1.parameterNames().isEmpty());
420     QVERIFY(ctor1.tag().isEmpty());
421     QVERIFY(ctor1.access() == QMetaMethod::Public);
422     QCOMPARE(ctor1.attributes(), 0);
423     QCOMPARE(ctor1.index(), 0);
424     QCOMPARE(builder.constructorCount(), 1);
425
426     // Add another constructor and check again.
427     QMetaMethodBuilder ctor2 = builder.addConstructor("bar(QString)");
428     QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
429     QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
430     QVERIFY(ctor2.returnType().isEmpty());
431     QVERIFY(ctor2.parameterNames().isEmpty());
432     QVERIFY(ctor2.tag().isEmpty());
433     QVERIFY(ctor2.access() == QMetaMethod::Public);
434     QCOMPARE(ctor2.attributes(), 0);
435     QCOMPARE(ctor2.index(), 1);
436     QCOMPARE(builder.constructorCount(), 2);
437
438     // Perform index-based lookup.
439     QCOMPARE(builder.indexOfConstructor("foo(const QString&, int)"), 0);
440     QCOMPARE(builder.indexOfConstructor("bar(QString)"), 1);
441     QCOMPARE(builder.indexOfConstructor("baz()"), -1);
442     QCOMPARE(builder.constructor(1).signature(), QByteArray("bar(QString)"));
443     QCOMPARE(builder.constructor(9).signature(), QByteArray());
444
445     // Modify the attributes on ctor1.
446     ctor1.setReturnType("int");
447     ctor1.setParameterNames(QList<QByteArray>() << "a" << "b");
448     ctor1.setTag("tag");
449     ctor1.setAccess(QMetaMethod::Private);
450     ctor1.setAttributes(42);
451
452     // Check that ctor1 is changed, but ctor2 is not.
453     QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)"));
454     QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
455     QCOMPARE(ctor1.returnType(), QByteArray("int"));
456     QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b");
457     QCOMPARE(ctor1.tag(), QByteArray("tag"));
458     QVERIFY(ctor1.access() == QMetaMethod::Private);
459     QCOMPARE(ctor1.attributes(), 42);
460     QCOMPARE(ctor1.index(), 0);
461     QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
462     QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
463     QVERIFY(ctor2.returnType().isEmpty());
464     QVERIFY(ctor2.parameterNames().isEmpty());
465     QVERIFY(ctor2.tag().isEmpty());
466     QVERIFY(ctor2.access() == QMetaMethod::Public);
467     QCOMPARE(ctor2.attributes(), 0);
468     QCOMPARE(ctor2.index(), 1);
469     QCOMPARE(builder.constructorCount(), 2);
470
471     // Modify the attributes on ctor2.
472     ctor2.setReturnType("QString");
473     ctor2.setParameterNames(QList<QByteArray>() << "c");
474     ctor2.setTag("Q_FOO");
475     ctor2.setAccess(QMetaMethod::Protected);
476     ctor2.setAttributes(24);
477
478     // This time check that only ctor2 changed.
479     QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)"));
480     QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
481     QCOMPARE(ctor1.returnType(), QByteArray("int"));
482     QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b");
483     QCOMPARE(ctor1.tag(), QByteArray("tag"));
484     QVERIFY(ctor1.access() == QMetaMethod::Private);
485     QCOMPARE(ctor1.attributes(), 42);
486     QCOMPARE(ctor1.index(), 0);
487     QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
488     QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
489     QCOMPARE(ctor2.returnType(), QByteArray("QString"));
490     QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c");
491     QCOMPARE(ctor2.tag(), QByteArray("Q_FOO"));
492     QVERIFY(ctor2.access() == QMetaMethod::Protected);
493     QCOMPARE(ctor2.attributes(), 24);
494     QCOMPARE(ctor2.index(), 1);
495     QCOMPARE(builder.constructorCount(), 2);
496
497     // Remove ctor1 and check that ctor2 becomes index 0.
498     builder.removeConstructor(0);
499     QCOMPARE(builder.constructorCount(), 1);
500     ctor2 = builder.constructor(0);
501     QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
502     QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
503     QCOMPARE(ctor2.returnType(), QByteArray("QString"));
504     QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c");
505     QCOMPARE(ctor2.tag(), QByteArray("Q_FOO"));
506     QVERIFY(ctor2.access() == QMetaMethod::Protected);
507     QCOMPARE(ctor2.attributes(), 24);
508     QCOMPARE(ctor2.index(), 0);
509
510     // Perform index-based lookup again.
511     QCOMPARE(builder.indexOfConstructor("foo(const QString&, int)"), -1);
512     QCOMPARE(builder.indexOfConstructor("bar(QString)"), 0);
513     QCOMPARE(builder.indexOfConstructor("baz()"), -1);
514
515     // Add constructor from prototype
516     QMetaMethod prototype = SomethingOfEverything::staticMetaObject.constructor(0);
517     QMetaMethodBuilder prototypeConstructor = builder.addMethod(prototype);
518     QCOMPARE(builder.constructorCount(), 2);
519
520     QCOMPARE(prototypeConstructor.signature(), QByteArray("SomethingOfEverything()"));
521     QVERIFY(prototypeConstructor.methodType() == QMetaMethod::Constructor);
522     QCOMPARE(prototypeConstructor.returnType(), QByteArray());
523     QVERIFY(prototypeConstructor.access() == QMetaMethod::Public);
524     QCOMPARE(prototypeConstructor.index(), 1);
525
526     // Check that nothing else changed.
527     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Constructors));
528 }
529
530 void tst_QMetaObjectBuilder::property()
531 {
532     QMetaObjectBuilder builder;
533
534     // Null property builder
535     QMetaPropertyBuilder nullProp;
536     QCOMPARE(nullProp.name(), QByteArray());
537     QCOMPARE(nullProp.type(), QByteArray());
538     QVERIFY(!nullProp.hasNotifySignal());
539     QVERIFY(!nullProp.isReadable());
540     QVERIFY(!nullProp.isWritable());
541     QVERIFY(!nullProp.isResettable());
542     QVERIFY(!nullProp.isDesignable());
543     QVERIFY(!nullProp.isScriptable());
544     QVERIFY(!nullProp.isStored());
545     QVERIFY(!nullProp.isEditable());
546     QVERIFY(!nullProp.isUser());
547     QVERIFY(!nullProp.hasStdCppSet());
548     QVERIFY(!nullProp.isEnumOrFlag());
549     QCOMPARE(nullProp.index(), 0);
550
551     // Add a property and check its attributes.
552     QMetaPropertyBuilder prop1 = builder.addProperty("foo", "const QString &");
553     QCOMPARE(prop1.name(), QByteArray("foo"));
554     QCOMPARE(prop1.type(), QByteArray("QString"));
555     QVERIFY(!prop1.hasNotifySignal());
556     QVERIFY(prop1.isReadable());
557     QVERIFY(prop1.isWritable());
558     QVERIFY(!prop1.isResettable());
559     QVERIFY(!prop1.isDesignable());
560     QVERIFY(prop1.isScriptable());
561     QVERIFY(!prop1.isStored());
562     QVERIFY(!prop1.isEditable());
563     QVERIFY(!prop1.isUser());
564     QVERIFY(!prop1.hasStdCppSet());
565     QVERIFY(!prop1.isEnumOrFlag());
566     QCOMPARE(prop1.index(), 0);
567     QCOMPARE(builder.propertyCount(), 1);
568
569     // Add another property and check again.
570     QMetaPropertyBuilder prop2 = builder.addProperty("bar", "int");
571     QCOMPARE(prop2.name(), QByteArray("bar"));
572     QCOMPARE(prop2.type(), QByteArray("int"));
573     QVERIFY(!prop2.hasNotifySignal());
574     QVERIFY(prop2.isReadable());
575     QVERIFY(prop2.isWritable());
576     QVERIFY(!prop2.isResettable());
577     QVERIFY(!prop2.isDesignable());
578     QVERIFY(prop2.isScriptable());
579     QVERIFY(!prop2.isStored());
580     QVERIFY(!prop2.isEditable());
581     QVERIFY(!prop2.isUser());
582     QVERIFY(!prop2.hasStdCppSet());
583     QVERIFY(!prop2.isEnumOrFlag());
584     QCOMPARE(prop2.index(), 1);
585     QCOMPARE(builder.propertyCount(), 2);
586
587     // Perform index-based lookup.
588     QCOMPARE(builder.indexOfProperty("foo"), 0);
589     QCOMPARE(builder.indexOfProperty("bar"), 1);
590     QCOMPARE(builder.indexOfProperty("baz"), -1);
591     QCOMPARE(builder.property(1).name(), QByteArray("bar"));
592     QCOMPARE(builder.property(9).name(), QByteArray());
593
594     // Modify the attributes on prop1.
595     prop1.setReadable(false);
596     prop1.setWritable(false);
597     prop1.setResettable(true);
598     prop1.setDesignable(true);
599     prop1.setScriptable(false);
600     prop1.setStored(true);
601     prop1.setEditable(true);
602     prop1.setUser(true);
603     prop1.setStdCppSet(true);
604     prop1.setEnumOrFlag(true);
605
606     // Check that prop1 is changed, but prop2 is not.
607     QCOMPARE(prop1.name(), QByteArray("foo"));
608     QCOMPARE(prop1.type(), QByteArray("QString"));
609     QVERIFY(!prop1.isReadable());
610     QVERIFY(!prop1.isWritable());
611     QVERIFY(prop1.isResettable());
612     QVERIFY(prop1.isDesignable());
613     QVERIFY(!prop1.isScriptable());
614     QVERIFY(prop1.isStored());
615     QVERIFY(prop1.isEditable());
616     QVERIFY(prop1.isUser());
617     QVERIFY(prop1.hasStdCppSet());
618     QVERIFY(prop1.isEnumOrFlag());
619     QVERIFY(prop2.isReadable());
620     QVERIFY(prop2.isWritable());
621     QCOMPARE(prop2.name(), QByteArray("bar"));
622     QCOMPARE(prop2.type(), QByteArray("int"));
623     QVERIFY(!prop2.isResettable());
624     QVERIFY(!prop2.isDesignable());
625     QVERIFY(prop2.isScriptable());
626     QVERIFY(!prop2.isStored());
627     QVERIFY(!prop2.isEditable());
628     QVERIFY(!prop2.isUser());
629     QVERIFY(!prop2.hasStdCppSet());
630     QVERIFY(!prop2.isEnumOrFlag());
631
632     // Remove prop1 and check that prop2 becomes index 0.
633     builder.removeProperty(0);
634     QCOMPARE(builder.propertyCount(), 1);
635     prop2 = builder.property(0);
636     QCOMPARE(prop2.name(), QByteArray("bar"));
637     QCOMPARE(prop2.type(), QByteArray("int"));
638     QVERIFY(!prop2.isResettable());
639     QVERIFY(!prop2.isDesignable());
640     QVERIFY(prop2.isScriptable());
641     QVERIFY(!prop2.isStored());
642     QVERIFY(!prop2.isEditable());
643     QVERIFY(!prop2.isUser());
644     QVERIFY(!prop2.hasStdCppSet());
645     QVERIFY(!prop2.isEnumOrFlag());
646     QCOMPARE(prop2.index(), 0);
647
648     // Perform index-based lookup again.
649     QCOMPARE(builder.indexOfProperty("foo"), -1);
650     QCOMPARE(builder.indexOfProperty("bar"), 0);
651     QCOMPARE(builder.indexOfProperty("baz"), -1);
652
653     // Check for side-effects between the flags on prop2.
654     // Setting a flag to true shouldn't set any of the others to true.
655     // This checks for cut-and-paste bugs in the implementation where
656     // the flag code was pasted but the flag name was not changed.
657 #define CLEAR_FLAGS() \
658         do { \
659             prop2.setReadable(false); \
660             prop2.setWritable(false); \
661             prop2.setResettable(false); \
662             prop2.setDesignable(false); \
663             prop2.setScriptable(false); \
664             prop2.setStored(false); \
665             prop2.setEditable(false); \
666             prop2.setUser(false); \
667             prop2.setStdCppSet(false); \
668             prop2.setEnumOrFlag(false); \
669         } while (0)
670 #define COUNT_FLAGS() \
671         ((prop2.isReadable() ? 1 : 0) + \
672          (prop2.isWritable() ? 1 : 0) + \
673          (prop2.isResettable() ? 1 : 0) + \
674          (prop2.isDesignable() ? 1 : 0) + \
675          (prop2.isScriptable() ? 1 : 0) + \
676          (prop2.isStored() ? 1 : 0) + \
677          (prop2.isEditable() ? 1 : 0) + \
678          (prop2.isUser() ? 1 : 0) + \
679          (prop2.hasStdCppSet() ? 1 : 0) + \
680          (prop2.isEnumOrFlag() ? 1 : 0))
681 #define CHECK_FLAG(setFunc,isFunc) \
682         do { \
683             CLEAR_FLAGS(); \
684             QCOMPARE(COUNT_FLAGS(), 0); \
685             prop2.setFunc(true); \
686             QVERIFY(prop2.isFunc()); \
687             QCOMPARE(COUNT_FLAGS(), 1); \
688         } while (0)
689     CHECK_FLAG(setReadable, isReadable);
690     CHECK_FLAG(setWritable, isWritable);
691     CHECK_FLAG(setResettable, isResettable);
692     CHECK_FLAG(setDesignable, isDesignable);
693     CHECK_FLAG(setScriptable, isScriptable);
694     CHECK_FLAG(setStored, isStored);
695     CHECK_FLAG(setEditable, isEditable);
696     CHECK_FLAG(setUser, isUser);
697     CHECK_FLAG(setStdCppSet, hasStdCppSet);
698     CHECK_FLAG(setEnumOrFlag, isEnumOrFlag);
699
700     // Check that nothing else changed.
701     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Properties));
702
703     // Add property from prototype
704     QMetaProperty prototype = SomethingOfEverything::staticMetaObject.property(1);
705     QVERIFY(prototype.name() == QByteArray("prop"));
706     QMetaPropertyBuilder prototypeProp = builder.addProperty(prototype);
707     QCOMPARE(prototypeProp.name(), QByteArray("prop"));
708     QVERIFY(prototypeProp.hasNotifySignal());
709     QCOMPARE(prototypeProp.notifySignal().signature(), QByteArray("propChanged(QString)"));
710     QCOMPARE(builder.methodCount(), 1);
711     QCOMPARE(builder.method(0).signature(), QByteArray("propChanged(QString)"));
712 }
713
714 void tst_QMetaObjectBuilder::notifySignal()
715 {
716     QMetaObjectBuilder builder;
717
718     QMetaPropertyBuilder prop = builder.addProperty("foo", "const QString &");
719     builder.addSlot("setFoo(QString)");
720     QMetaMethodBuilder notify = builder.addSignal("fooChanged(QString)");
721
722     QVERIFY(!prop.hasNotifySignal());
723     QCOMPARE(prop.notifySignal().index(), 0);
724
725     prop.setNotifySignal(notify);
726     QVERIFY(prop.hasNotifySignal());
727     QCOMPARE(prop.notifySignal().index(), 1);
728
729     prop.setNotifySignal(QMetaMethodBuilder());
730     QVERIFY(!prop.hasNotifySignal());
731     QCOMPARE(prop.notifySignal().index(), 0);
732
733     prop.setNotifySignal(notify);
734     prop.removeNotifySignal();
735     QVERIFY(!prop.hasNotifySignal());
736     QCOMPARE(prop.notifySignal().index(), 0);
737
738     QCOMPARE(builder.methodCount(), 2);
739     QCOMPARE(builder.propertyCount(), 1);
740
741     // Check that nothing else changed except methods and properties.
742     QVERIFY(checkForSideEffects
743         (builder, QMetaObjectBuilder::Methods | QMetaObjectBuilder::Properties));
744 }
745
746 void tst_QMetaObjectBuilder::enumerator()
747 {
748     QMetaObjectBuilder builder;
749
750     // Add an enumerator and check its attributes.
751     QMetaEnumBuilder enum1 = builder.addEnumerator("foo");
752     QCOMPARE(enum1.name(), QByteArray("foo"));
753     QVERIFY(!enum1.isFlag());
754     QCOMPARE(enum1.keyCount(), 0);
755     QCOMPARE(enum1.index(), 0);
756     QCOMPARE(builder.enumeratorCount(), 1);
757
758     // Add another enumerator and check again.
759     QMetaEnumBuilder enum2 = builder.addEnumerator("bar");
760     QCOMPARE(enum2.name(), QByteArray("bar"));
761     QVERIFY(!enum2.isFlag());
762     QCOMPARE(enum2.keyCount(), 0);
763     QCOMPARE(enum2.index(), 1);
764     QCOMPARE(builder.enumeratorCount(), 2);
765
766     // Perform index-based lookup.
767     QCOMPARE(builder.indexOfEnumerator("foo"), 0);
768     QCOMPARE(builder.indexOfEnumerator("bar"), 1);
769     QCOMPARE(builder.indexOfEnumerator("baz"), -1);
770     QCOMPARE(builder.enumerator(1).name(), QByteArray("bar"));
771     QCOMPARE(builder.enumerator(9).name(), QByteArray());
772
773     // Modify the attributes on enum1.
774     enum1.setIsFlag(true);
775     QCOMPARE(enum1.addKey("ABC", 0), 0);
776     QCOMPARE(enum1.addKey("DEF", 1), 1);
777     QCOMPARE(enum1.addKey("GHI", -1), 2);
778
779     // Check that enum1 is changed, but enum2 is not.
780     QCOMPARE(enum1.name(), QByteArray("foo"));
781     QVERIFY(enum1.isFlag());
782     QCOMPARE(enum1.keyCount(), 3);
783     QCOMPARE(enum1.index(), 0);
784     QCOMPARE(enum1.key(0), QByteArray("ABC"));
785     QCOMPARE(enum1.key(1), QByteArray("DEF"));
786     QCOMPARE(enum1.key(2), QByteArray("GHI"));
787     QCOMPARE(enum1.key(3), QByteArray());
788     QCOMPARE(enum1.value(0), 0);
789     QCOMPARE(enum1.value(1), 1);
790     QCOMPARE(enum1.value(2), -1);
791     QCOMPARE(enum2.name(), QByteArray("bar"));
792     QVERIFY(!enum2.isFlag());
793     QCOMPARE(enum2.keyCount(), 0);
794     QCOMPARE(enum2.index(), 1);
795
796     // Modify the attributes on enum2.
797     enum2.setIsFlag(true);
798     QCOMPARE(enum2.addKey("XYZ", 10), 0);
799     QCOMPARE(enum2.addKey("UVW", 19), 1);
800
801     // This time check that only method2 changed.
802     QCOMPARE(enum1.name(), QByteArray("foo"));
803     QVERIFY(enum1.isFlag());
804     QCOMPARE(enum1.keyCount(), 3);
805     QCOMPARE(enum1.index(), 0);
806     QCOMPARE(enum1.key(0), QByteArray("ABC"));
807     QCOMPARE(enum1.key(1), QByteArray("DEF"));
808     QCOMPARE(enum1.key(2), QByteArray("GHI"));
809     QCOMPARE(enum1.key(3), QByteArray());
810     QCOMPARE(enum1.value(0), 0);
811     QCOMPARE(enum1.value(1), 1);
812     QCOMPARE(enum1.value(2), -1);
813     QCOMPARE(enum2.name(), QByteArray("bar"));
814     QVERIFY(enum2.isFlag());
815     QCOMPARE(enum2.keyCount(), 2);
816     QCOMPARE(enum2.index(), 1);
817     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
818     QCOMPARE(enum2.key(1), QByteArray("UVW"));
819     QCOMPARE(enum2.key(2), QByteArray());
820     QCOMPARE(enum2.value(0), 10);
821     QCOMPARE(enum2.value(1), 19);
822
823     // Remove enum1 key
824     enum1.removeKey(2);
825     QCOMPARE(enum1.name(), QByteArray("foo"));
826     QVERIFY(enum1.isFlag());
827     QCOMPARE(enum1.keyCount(), 2);
828     QCOMPARE(enum1.index(), 0);
829     QCOMPARE(enum1.key(0), QByteArray("ABC"));
830     QCOMPARE(enum1.key(1), QByteArray("DEF"));
831     QCOMPARE(enum1.key(2), QByteArray());
832     QCOMPARE(enum1.value(0), 0);
833     QCOMPARE(enum1.value(1), 1);
834     QCOMPARE(enum1.value(2), -1);
835     QCOMPARE(enum2.name(), QByteArray("bar"));
836     QVERIFY(enum2.isFlag());
837     QCOMPARE(enum2.keyCount(), 2);
838     QCOMPARE(enum2.index(), 1);
839     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
840     QCOMPARE(enum2.key(1), QByteArray("UVW"));
841     QCOMPARE(enum2.key(2), QByteArray());
842     QCOMPARE(enum2.value(0), 10);
843     QCOMPARE(enum2.value(1), 19);
844
845     // Remove enum1 and check that enum2 becomes index 0.
846     builder.removeEnumerator(0);
847     QCOMPARE(builder.enumeratorCount(), 1);
848     enum2 = builder.enumerator(0);
849     QCOMPARE(enum2.name(), QByteArray("bar"));
850     QVERIFY(enum2.isFlag());
851     QCOMPARE(enum2.keyCount(), 2);
852     QCOMPARE(enum2.index(), 0);
853     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
854     QCOMPARE(enum2.key(1), QByteArray("UVW"));
855     QCOMPARE(enum2.key(2), QByteArray());
856     QCOMPARE(enum2.value(0), 10);
857     QCOMPARE(enum2.value(1), 19);
858
859     // Perform index-based lookup again.
860     QCOMPARE(builder.indexOfEnumerator("foo"), -1);
861     QCOMPARE(builder.indexOfEnumerator("bar"), 0);
862     QCOMPARE(builder.indexOfEnumerator("baz"), -1);
863
864     // Check that nothing else changed.
865     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Enumerators));
866 }
867
868 void tst_QMetaObjectBuilder::classInfo()
869 {
870     QMetaObjectBuilder builder;
871
872     // Add two items of class information and check their attributes.
873     QCOMPARE(builder.addClassInfo("foo", "value1"), 0);
874     QCOMPARE(builder.addClassInfo("bar", "value2"), 1);
875     QCOMPARE(builder.classInfoName(0), QByteArray("foo"));
876     QCOMPARE(builder.classInfoValue(0), QByteArray("value1"));
877     QCOMPARE(builder.classInfoName(1), QByteArray("bar"));
878     QCOMPARE(builder.classInfoValue(1), QByteArray("value2"));
879     QCOMPARE(builder.classInfoName(9), QByteArray());
880     QCOMPARE(builder.classInfoValue(9), QByteArray());
881     QCOMPARE(builder.classInfoCount(), 2);
882
883     // Perform index-based lookup.
884     QCOMPARE(builder.indexOfClassInfo("foo"), 0);
885     QCOMPARE(builder.indexOfClassInfo("bar"), 1);
886     QCOMPARE(builder.indexOfClassInfo("baz"), -1);
887
888     // Remove the first one and check again.
889     builder.removeClassInfo(0);
890     QCOMPARE(builder.classInfoName(0), QByteArray("bar"));
891     QCOMPARE(builder.classInfoValue(0), QByteArray("value2"));
892     QCOMPARE(builder.classInfoCount(), 1);
893
894     // Perform index-based lookup again.
895     QCOMPARE(builder.indexOfClassInfo("foo"), -1);
896     QCOMPARE(builder.indexOfClassInfo("bar"), 0);
897     QCOMPARE(builder.indexOfClassInfo("baz"), -1);
898
899     // Check that nothing else changed.
900     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::ClassInfos));
901 }
902
903 void tst_QMetaObjectBuilder::relatedMetaObject()
904 {
905     QMetaObjectBuilder builder;
906
907     // Add two related meta objects and check their attributes.
908     QCOMPARE(builder.addRelatedMetaObject(&QObject::staticMetaObject), 0);
909     QCOMPARE(builder.addRelatedMetaObject(&staticMetaObject), 1);
910     QVERIFY(builder.relatedMetaObject(0) == &QObject::staticMetaObject);
911     QVERIFY(builder.relatedMetaObject(1) == &staticMetaObject);
912     QCOMPARE(builder.relatedMetaObjectCount(), 2);
913
914     // Remove the first one and check again.
915     builder.removeRelatedMetaObject(0);
916     QVERIFY(builder.relatedMetaObject(0) == &staticMetaObject);
917     QCOMPARE(builder.relatedMetaObjectCount(), 1);
918
919     // Check that nothing else changed.
920     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::RelatedMetaObjects));
921 }
922
923 static void smetacall(QObject *, QMetaObject::Call, int, void **)
924 {
925     return;
926 }
927
928 void tst_QMetaObjectBuilder::staticMetacall()
929 {
930     QMetaObjectBuilder builder;
931     QVERIFY(!builder.staticMetacallFunction());
932     builder.setStaticMetacallFunction(smetacall);
933     QVERIFY(builder.staticMetacallFunction() == smetacall);
934     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::StaticMetacall));
935 }
936
937 // Copy the entire contents of a static QMetaObject and then check
938 // that QMetaObjectBuilder will produce an exact copy as output.
939 void tst_QMetaObjectBuilder::copyMetaObject()
940 {
941     QMetaObjectBuilder builder(&QObject::staticMetaObject);
942     QMetaObject *meta = builder.toMetaObject();
943     QVERIFY(sameMetaObject(meta, &QObject::staticMetaObject));
944     qFree(meta);
945
946     QMetaObjectBuilder builder2(&staticMetaObject);
947     meta = builder2.toMetaObject();
948     QVERIFY(sameMetaObject(meta, &staticMetaObject));
949     qFree(meta);
950
951     QMetaObjectBuilder builder3(&SomethingOfEverything::staticMetaObject);
952     meta = builder3.toMetaObject();
953     QVERIFY(sameMetaObject(meta, &SomethingOfEverything::staticMetaObject));
954     qFree(meta);
955 }
956
957 // Serialize and deserialize a meta object and check that
958 // it round-trips to the exact same value.
959 void tst_QMetaObjectBuilder::serialize()
960 {
961     // Full QMetaObjectBuilder
962     {
963     QMetaObjectBuilder builder(&SomethingOfEverything::staticMetaObject);
964     QMetaObject *meta = builder.toMetaObject();
965
966     QByteArray data;
967     QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append);
968     builder.serialize(stream);
969
970     QMetaObjectBuilder builder2;
971     QDataStream stream2(data);
972     QMap<QByteArray, const QMetaObject *> references;
973     references.insert(QByteArray("QLocale"), &QLocale::staticMetaObject);
974     builder2.deserialize(stream2, references);
975     builder2.setStaticMetacallFunction(builder.staticMetacallFunction());
976     QMetaObject *meta2 = builder2.toMetaObject();
977
978     QVERIFY(sameMetaObject(meta, meta2));
979     qFree(meta);
980     qFree(meta2);
981     }
982
983     // Partial QMetaObjectBuilder
984     {
985     QMetaObjectBuilder builder;
986     builder.setClassName("Test");
987     builder.addProperty("foo", "int");
988
989     QByteArray data;
990     QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append);
991     builder.serialize(stream);
992
993     QMetaObjectBuilder builder2;
994     QDataStream stream2(data);
995     builder2.deserialize(stream2, QMap<QByteArray, const QMetaObject *>());
996
997     QCOMPARE(builder.superClass(), builder2.superClass());
998     QCOMPARE(builder.className(), builder2.className());
999     QCOMPARE(builder.propertyCount(), builder2.propertyCount());
1000     QCOMPARE(builder.property(0).name(), builder2.property(0).name());
1001     QCOMPARE(builder.property(0).type(), builder2.property(0).type());
1002     }
1003 }
1004
1005 // Check that removing a method updates notify signals appropriately
1006 void tst_QMetaObjectBuilder::removeNotifySignal()
1007 {
1008     QMetaObjectBuilder builder;
1009
1010     QMetaMethodBuilder method1 = builder.addSignal("foo(const QString&, int)");
1011     QMetaMethodBuilder method2 = builder.addSignal("bar(QString)");
1012
1013     // Setup property
1014     QMetaPropertyBuilder prop = builder.addProperty("prop", "const QString &");
1015     prop.setNotifySignal(method2);
1016     QVERIFY(prop.hasNotifySignal());
1017     QCOMPARE(prop.notifySignal().index(), 1);
1018
1019     // Remove non-notify signal
1020     builder.removeMethod(0);
1021     QVERIFY(prop.hasNotifySignal());
1022     QCOMPARE(prop.notifySignal().index(), 0);
1023
1024     // Remove notify signal
1025     builder.removeMethod(0);
1026     QVERIFY(!prop.hasNotifySignal());
1027 }
1028
1029 // Check that the only changes to a "builder" relative to the default
1030 // state is specified by "members".
1031 bool tst_QMetaObjectBuilder::checkForSideEffects
1032         (const QMetaObjectBuilder& builder,
1033          QMetaObjectBuilder::AddMembers members)
1034 {
1035     if ((members & QMetaObjectBuilder::ClassName) == 0) {
1036         if (!builder.className().isEmpty())
1037             return false;
1038     }
1039
1040     if ((members & QMetaObjectBuilder::SuperClass) == 0) {
1041         if (builder.superClass() != &QObject::staticMetaObject)
1042             return false;
1043     }
1044
1045     if ((members & QMetaObjectBuilder::Methods) == 0) {
1046         if (builder.methodCount() != 0)
1047             return false;
1048     }
1049
1050     if ((members & QMetaObjectBuilder::Constructors) == 0) {
1051         if (builder.constructorCount() != 0)
1052             return false;
1053     }
1054
1055     if ((members & QMetaObjectBuilder::Properties) == 0) {
1056         if (builder.propertyCount() != 0)
1057             return false;
1058     }
1059
1060     if ((members & QMetaObjectBuilder::Enumerators) == 0) {
1061         if (builder.enumeratorCount() != 0)
1062             return false;
1063     }
1064
1065     if ((members & QMetaObjectBuilder::ClassInfos) == 0) {
1066         if (builder.classInfoCount() != 0)
1067             return false;
1068     }
1069
1070     if ((members & QMetaObjectBuilder::RelatedMetaObjects) == 0) {
1071         if (builder.relatedMetaObjectCount() != 0)
1072             return false;
1073     }
1074
1075     if ((members & QMetaObjectBuilder::StaticMetacall) == 0) {
1076         if (builder.staticMetacallFunction() != 0)
1077             return false;
1078     }
1079
1080     return true;
1081 }
1082
1083 static bool sameMethod(const QMetaMethod& method1, const QMetaMethod& method2)
1084 {
1085     if (QByteArray(method1.signature()) != QByteArray(method2.signature()))
1086         return false;
1087
1088     if (QByteArray(method1.typeName()) != QByteArray(method2.typeName()))
1089         return false;
1090
1091     if (method1.parameterNames() != method2.parameterNames())
1092         return false;
1093
1094     if (QByteArray(method1.tag()) != QByteArray(method2.tag()))
1095         return false;
1096
1097     if (method1.access() != method2.access())
1098         return false;
1099
1100     if (method1.methodType() != method2.methodType())
1101         return false;
1102
1103     if (method1.attributes() != method2.attributes())
1104         return false;
1105
1106     return true;
1107 }
1108
1109 static bool sameProperty(const QMetaProperty& prop1, const QMetaProperty& prop2)
1110 {
1111     if (QByteArray(prop1.name()) != QByteArray(prop2.name()))
1112         return false;
1113
1114     if (QByteArray(prop1.typeName()) != QByteArray(prop2.typeName()))
1115         return false;
1116
1117     if (prop1.isReadable() != prop2.isReadable() ||
1118         prop1.isWritable() != prop2.isWritable() ||
1119         prop1.isResettable() != prop2.isResettable() ||
1120         prop1.isDesignable() != prop2.isDesignable() ||
1121         prop1.isScriptable() != prop2.isScriptable() ||
1122         prop1.isStored() != prop2.isStored() ||
1123         prop1.isEditable() != prop2.isEditable() ||
1124         prop1.isUser() != prop2.isUser() ||
1125         prop1.isFlagType() != prop2.isFlagType() ||
1126         prop1.isEnumType() != prop2.isEnumType() ||
1127         prop1.hasNotifySignal() != prop2.hasNotifySignal() ||
1128         prop1.hasStdCppSet() != prop2.hasStdCppSet())
1129         return false;
1130
1131     if (prop1.hasNotifySignal()) {
1132         if (prop1.notifySignalIndex() != prop2.notifySignalIndex())
1133             return false;
1134     }
1135
1136     return true;
1137 }
1138
1139 static bool sameEnumerator(const QMetaEnum& enum1, const QMetaEnum& enum2)
1140 {
1141     if (QByteArray(enum1.name()) != QByteArray(enum2.name()))
1142         return false;
1143
1144     if (enum1.isFlag() != enum2.isFlag())
1145         return false;
1146
1147     if (enum1.keyCount() != enum2.keyCount())
1148         return false;
1149
1150     for (int index = 0; index < enum1.keyCount(); ++index) {
1151         if (QByteArray(enum1.key(index)) != QByteArray(enum2.key(index)))
1152             return false;
1153         if (enum1.value(index) != enum2.value(index))
1154             return false;
1155     }
1156
1157     if (QByteArray(enum1.scope()) != QByteArray(enum2.scope()))
1158         return false;
1159
1160     return true;
1161 }
1162
1163 // Determine if two meta objects are identical.
1164 bool tst_QMetaObjectBuilder::sameMetaObject
1165         (const QMetaObject *meta1, const QMetaObject *meta2)
1166 {
1167     int index;
1168
1169     if (strcmp(meta1->className(), meta2->className()) != 0)
1170         return false;
1171
1172     if (meta1->superClass() != meta2->superClass())
1173         return false;
1174
1175     if (meta1->constructorCount() != meta2->constructorCount() ||
1176         meta1->methodCount() != meta2->methodCount() ||
1177         meta1->enumeratorCount() != meta2->enumeratorCount() ||
1178         meta1->propertyCount() != meta2->propertyCount() ||
1179         meta1->classInfoCount() != meta2->classInfoCount())
1180         return false;
1181
1182     for (index = 0; index < meta1->constructorCount(); ++index) {
1183         if (!sameMethod(meta1->constructor(index), meta2->constructor(index)))
1184             return false;
1185     }
1186
1187     for (index = 0; index < meta1->methodCount(); ++index) {
1188         if (!sameMethod(meta1->method(index), meta2->method(index)))
1189             return false;
1190     }
1191
1192     for (index = 0; index < meta1->propertyCount(); ++index) {
1193         if (!sameProperty(meta1->property(index), meta2->property(index)))
1194             return false;
1195     }
1196
1197     for (index = 0; index < meta1->enumeratorCount(); ++index) {
1198         if (!sameEnumerator(meta1->enumerator(index), meta2->enumerator(index)))
1199             return false;
1200     }
1201
1202     for (index = 0; index < meta1->classInfoCount(); ++index) {
1203         if (QByteArray(meta1->classInfo(index).name()) !=
1204             QByteArray(meta2->classInfo(index).name()))
1205             return false;
1206         if (QByteArray(meta1->classInfo(index).value()) !=
1207             QByteArray(meta2->classInfo(index).value()))
1208             return false;
1209     }
1210
1211     const QMetaObject **objects1 = 0;
1212     const QMetaObject **objects2 = 0;
1213     if (meta1->d.data[0] == meta2->d.data[0] && meta1->d.data[0] >= 2) {
1214         QMetaObjectExtraData *extra1 = (QMetaObjectExtraData *)(meta1->d.extradata);
1215         QMetaObjectExtraData *extra2 = (QMetaObjectExtraData *)(meta2->d.extradata);
1216         if (extra1 && !extra2)
1217             return false;
1218         if (extra2 && !extra1)
1219             return false;
1220         if (extra1 && extra2) {
1221             if (extra1->static_metacall != extra2->static_metacall)
1222                 return false;
1223             objects1 = extra1->objects;
1224             objects2 = extra1->objects;
1225         }
1226     } else if (meta1->d.data[0] == meta2->d.data[0] && meta1->d.data[0] == 1) {
1227         objects1 = (const QMetaObject **)(meta1->d.extradata);
1228         objects2 = (const QMetaObject **)(meta2->d.extradata);
1229     }
1230     if (objects1 && !objects2)
1231         return false;
1232     if (objects2 && !objects1)
1233         return false;
1234     if (objects1 && objects2) {
1235         while (*objects1 != 0 && *objects2 != 0) {
1236             if (*objects1 != *objects2)
1237                 return false;
1238             ++objects1;
1239             ++objects2;
1240         }
1241     }
1242
1243     return true;
1244 }
1245
1246 QTEST_MAIN(tst_QMetaObjectBuilder)
1247
1248 #include "tst_qmetaobjectbuilder.moc"