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