d7ca8e6f1ed6e7539f15521bfa099c287d5cd920
[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 ** 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 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     QVERIFY(!nullProp.isConstant());
550     QVERIFY(!nullProp.isFinal());
551     QCOMPARE(nullProp.index(), 0);
552
553     // Add a property and check its attributes.
554     QMetaPropertyBuilder prop1 = builder.addProperty("foo", "const QString &");
555     QCOMPARE(prop1.name(), QByteArray("foo"));
556     QCOMPARE(prop1.type(), QByteArray("QString"));
557     QVERIFY(!prop1.hasNotifySignal());
558     QVERIFY(prop1.isReadable());
559     QVERIFY(prop1.isWritable());
560     QVERIFY(!prop1.isResettable());
561     QVERIFY(!prop1.isDesignable());
562     QVERIFY(prop1.isScriptable());
563     QVERIFY(!prop1.isStored());
564     QVERIFY(!prop1.isEditable());
565     QVERIFY(!prop1.isUser());
566     QVERIFY(!prop1.hasStdCppSet());
567     QVERIFY(!prop1.isEnumOrFlag());
568     QVERIFY(!prop1.isConstant());
569     QVERIFY(!prop1.isFinal());
570     QCOMPARE(prop1.index(), 0);
571     QCOMPARE(builder.propertyCount(), 1);
572
573     // Add another property and check again.
574     QMetaPropertyBuilder prop2 = builder.addProperty("bar", "int");
575     QCOMPARE(prop2.name(), QByteArray("bar"));
576     QCOMPARE(prop2.type(), QByteArray("int"));
577     QVERIFY(!prop2.hasNotifySignal());
578     QVERIFY(prop2.isReadable());
579     QVERIFY(prop2.isWritable());
580     QVERIFY(!prop2.isResettable());
581     QVERIFY(!prop2.isDesignable());
582     QVERIFY(prop2.isScriptable());
583     QVERIFY(!prop2.isStored());
584     QVERIFY(!prop2.isEditable());
585     QVERIFY(!prop2.isUser());
586     QVERIFY(!prop2.hasStdCppSet());
587     QVERIFY(!prop2.isEnumOrFlag());
588     QVERIFY(!prop2.isConstant());
589     QVERIFY(!prop2.isFinal());
590     QCOMPARE(prop2.index(), 1);
591     QCOMPARE(builder.propertyCount(), 2);
592
593     // Perform index-based lookup.
594     QCOMPARE(builder.indexOfProperty("foo"), 0);
595     QCOMPARE(builder.indexOfProperty("bar"), 1);
596     QCOMPARE(builder.indexOfProperty("baz"), -1);
597     QCOMPARE(builder.property(1).name(), QByteArray("bar"));
598     QCOMPARE(builder.property(9).name(), QByteArray());
599
600     // Modify the attributes on prop1.
601     prop1.setReadable(false);
602     prop1.setWritable(false);
603     prop1.setResettable(true);
604     prop1.setDesignable(true);
605     prop1.setScriptable(false);
606     prop1.setStored(true);
607     prop1.setEditable(true);
608     prop1.setUser(true);
609     prop1.setStdCppSet(true);
610     prop1.setEnumOrFlag(true);
611     prop1.setConstant(true);
612     prop1.setFinal(true);
613
614     // Check that prop1 is changed, but prop2 is not.
615     QCOMPARE(prop1.name(), QByteArray("foo"));
616     QCOMPARE(prop1.type(), QByteArray("QString"));
617     QVERIFY(!prop1.isReadable());
618     QVERIFY(!prop1.isWritable());
619     QVERIFY(prop1.isResettable());
620     QVERIFY(prop1.isDesignable());
621     QVERIFY(!prop1.isScriptable());
622     QVERIFY(prop1.isStored());
623     QVERIFY(prop1.isEditable());
624     QVERIFY(prop1.isUser());
625     QVERIFY(prop1.hasStdCppSet());
626     QVERIFY(prop1.isEnumOrFlag());
627     QVERIFY(prop1.isConstant());
628     QVERIFY(prop1.isFinal());
629     QVERIFY(prop2.isReadable());
630     QVERIFY(prop2.isWritable());
631     QCOMPARE(prop2.name(), QByteArray("bar"));
632     QCOMPARE(prop2.type(), QByteArray("int"));
633     QVERIFY(!prop2.isResettable());
634     QVERIFY(!prop2.isDesignable());
635     QVERIFY(prop2.isScriptable());
636     QVERIFY(!prop2.isStored());
637     QVERIFY(!prop2.isEditable());
638     QVERIFY(!prop2.isUser());
639     QVERIFY(!prop2.hasStdCppSet());
640     QVERIFY(!prop2.isEnumOrFlag());
641     QVERIFY(!prop2.isConstant());
642     QVERIFY(!prop2.isFinal());
643
644     // Remove prop1 and check that prop2 becomes index 0.
645     builder.removeProperty(0);
646     QCOMPARE(builder.propertyCount(), 1);
647     prop2 = builder.property(0);
648     QCOMPARE(prop2.name(), QByteArray("bar"));
649     QCOMPARE(prop2.type(), QByteArray("int"));
650     QVERIFY(!prop2.isResettable());
651     QVERIFY(!prop2.isDesignable());
652     QVERIFY(prop2.isScriptable());
653     QVERIFY(!prop2.isStored());
654     QVERIFY(!prop2.isEditable());
655     QVERIFY(!prop2.isUser());
656     QVERIFY(!prop2.hasStdCppSet());
657     QVERIFY(!prop2.isEnumOrFlag());
658     QVERIFY(!prop2.isConstant());
659     QVERIFY(!prop2.isFinal());
660     QCOMPARE(prop2.index(), 0);
661
662     // Perform index-based lookup again.
663     QCOMPARE(builder.indexOfProperty("foo"), -1);
664     QCOMPARE(builder.indexOfProperty("bar"), 0);
665     QCOMPARE(builder.indexOfProperty("baz"), -1);
666
667     // Check for side-effects between the flags on prop2.
668     // Setting a flag to true shouldn't set any of the others to true.
669     // This checks for cut-and-paste bugs in the implementation where
670     // the flag code was pasted but the flag name was not changed.
671 #define CLEAR_FLAGS() \
672         do { \
673             prop2.setReadable(false); \
674             prop2.setWritable(false); \
675             prop2.setResettable(false); \
676             prop2.setDesignable(false); \
677             prop2.setScriptable(false); \
678             prop2.setStored(false); \
679             prop2.setEditable(false); \
680             prop2.setUser(false); \
681             prop2.setStdCppSet(false); \
682             prop2.setEnumOrFlag(false); \
683             prop2.setConstant(false); \
684             prop2.setFinal(false); \
685         } while (0)
686 #define COUNT_FLAGS() \
687         ((prop2.isReadable() ? 1 : 0) + \
688          (prop2.isWritable() ? 1 : 0) + \
689          (prop2.isResettable() ? 1 : 0) + \
690          (prop2.isDesignable() ? 1 : 0) + \
691          (prop2.isScriptable() ? 1 : 0) + \
692          (prop2.isStored() ? 1 : 0) + \
693          (prop2.isEditable() ? 1 : 0) + \
694          (prop2.isUser() ? 1 : 0) + \
695          (prop2.hasStdCppSet() ? 1 : 0) + \
696          (prop2.isEnumOrFlag() ? 1 : 0) + \
697          (prop2.isConstant() ? 1 : 0) + \
698          (prop2.isFinal() ? 1 : 0))
699 #define CHECK_FLAG(setFunc,isFunc) \
700         do { \
701             CLEAR_FLAGS(); \
702             QCOMPARE(COUNT_FLAGS(), 0); \
703             prop2.setFunc(true); \
704             QVERIFY(prop2.isFunc()); \
705             QCOMPARE(COUNT_FLAGS(), 1); \
706         } while (0)
707     CHECK_FLAG(setReadable, isReadable);
708     CHECK_FLAG(setWritable, isWritable);
709     CHECK_FLAG(setResettable, isResettable);
710     CHECK_FLAG(setDesignable, isDesignable);
711     CHECK_FLAG(setScriptable, isScriptable);
712     CHECK_FLAG(setStored, isStored);
713     CHECK_FLAG(setEditable, isEditable);
714     CHECK_FLAG(setUser, isUser);
715     CHECK_FLAG(setStdCppSet, hasStdCppSet);
716     CHECK_FLAG(setEnumOrFlag, isEnumOrFlag);
717     CHECK_FLAG(setConstant, isConstant);
718     CHECK_FLAG(setFinal, isFinal);
719
720     // Check that nothing else changed.
721     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Properties));
722
723     // Add property from prototype
724     QMetaProperty prototype = SomethingOfEverything::staticMetaObject.property(1);
725     QVERIFY(prototype.name() == QByteArray("prop"));
726     QMetaPropertyBuilder prototypeProp = builder.addProperty(prototype);
727     QCOMPARE(prototypeProp.name(), QByteArray("prop"));
728     QVERIFY(prototypeProp.hasNotifySignal());
729     QCOMPARE(prototypeProp.notifySignal().signature(), QByteArray("propChanged(QString)"));
730     QCOMPARE(builder.methodCount(), 1);
731     QCOMPARE(builder.method(0).signature(), QByteArray("propChanged(QString)"));
732 }
733
734 void tst_QMetaObjectBuilder::notifySignal()
735 {
736     QMetaObjectBuilder builder;
737
738     QMetaPropertyBuilder prop = builder.addProperty("foo", "const QString &");
739     builder.addSlot("setFoo(QString)");
740     QMetaMethodBuilder notify = builder.addSignal("fooChanged(QString)");
741
742     QVERIFY(!prop.hasNotifySignal());
743     QCOMPARE(prop.notifySignal().index(), 0);
744
745     prop.setNotifySignal(notify);
746     QVERIFY(prop.hasNotifySignal());
747     QCOMPARE(prop.notifySignal().index(), 1);
748
749     prop.setNotifySignal(QMetaMethodBuilder());
750     QVERIFY(!prop.hasNotifySignal());
751     QCOMPARE(prop.notifySignal().index(), 0);
752
753     prop.setNotifySignal(notify);
754     prop.removeNotifySignal();
755     QVERIFY(!prop.hasNotifySignal());
756     QCOMPARE(prop.notifySignal().index(), 0);
757
758     QCOMPARE(builder.methodCount(), 2);
759     QCOMPARE(builder.propertyCount(), 1);
760
761     // Check that nothing else changed except methods and properties.
762     QVERIFY(checkForSideEffects
763         (builder, QMetaObjectBuilder::Methods | QMetaObjectBuilder::Properties));
764 }
765
766 void tst_QMetaObjectBuilder::enumerator()
767 {
768     QMetaObjectBuilder builder;
769
770     // Add an enumerator and check its attributes.
771     QMetaEnumBuilder enum1 = builder.addEnumerator("foo");
772     QCOMPARE(enum1.name(), QByteArray("foo"));
773     QVERIFY(!enum1.isFlag());
774     QCOMPARE(enum1.keyCount(), 0);
775     QCOMPARE(enum1.index(), 0);
776     QCOMPARE(builder.enumeratorCount(), 1);
777
778     // Add another enumerator and check again.
779     QMetaEnumBuilder enum2 = builder.addEnumerator("bar");
780     QCOMPARE(enum2.name(), QByteArray("bar"));
781     QVERIFY(!enum2.isFlag());
782     QCOMPARE(enum2.keyCount(), 0);
783     QCOMPARE(enum2.index(), 1);
784     QCOMPARE(builder.enumeratorCount(), 2);
785
786     // Perform index-based lookup.
787     QCOMPARE(builder.indexOfEnumerator("foo"), 0);
788     QCOMPARE(builder.indexOfEnumerator("bar"), 1);
789     QCOMPARE(builder.indexOfEnumerator("baz"), -1);
790     QCOMPARE(builder.enumerator(1).name(), QByteArray("bar"));
791     QCOMPARE(builder.enumerator(9).name(), QByteArray());
792
793     // Modify the attributes on enum1.
794     enum1.setIsFlag(true);
795     QCOMPARE(enum1.addKey("ABC", 0), 0);
796     QCOMPARE(enum1.addKey("DEF", 1), 1);
797     QCOMPARE(enum1.addKey("GHI", -1), 2);
798
799     // Check that enum1 is changed, but enum2 is not.
800     QCOMPARE(enum1.name(), QByteArray("foo"));
801     QVERIFY(enum1.isFlag());
802     QCOMPARE(enum1.keyCount(), 3);
803     QCOMPARE(enum1.index(), 0);
804     QCOMPARE(enum1.key(0), QByteArray("ABC"));
805     QCOMPARE(enum1.key(1), QByteArray("DEF"));
806     QCOMPARE(enum1.key(2), QByteArray("GHI"));
807     QCOMPARE(enum1.key(3), QByteArray());
808     QCOMPARE(enum1.value(0), 0);
809     QCOMPARE(enum1.value(1), 1);
810     QCOMPARE(enum1.value(2), -1);
811     QCOMPARE(enum2.name(), QByteArray("bar"));
812     QVERIFY(!enum2.isFlag());
813     QCOMPARE(enum2.keyCount(), 0);
814     QCOMPARE(enum2.index(), 1);
815
816     // Modify the attributes on enum2.
817     enum2.setIsFlag(true);
818     QCOMPARE(enum2.addKey("XYZ", 10), 0);
819     QCOMPARE(enum2.addKey("UVW", 19), 1);
820
821     // This time check that only method2 changed.
822     QCOMPARE(enum1.name(), QByteArray("foo"));
823     QVERIFY(enum1.isFlag());
824     QCOMPARE(enum1.keyCount(), 3);
825     QCOMPARE(enum1.index(), 0);
826     QCOMPARE(enum1.key(0), QByteArray("ABC"));
827     QCOMPARE(enum1.key(1), QByteArray("DEF"));
828     QCOMPARE(enum1.key(2), QByteArray("GHI"));
829     QCOMPARE(enum1.key(3), QByteArray());
830     QCOMPARE(enum1.value(0), 0);
831     QCOMPARE(enum1.value(1), 1);
832     QCOMPARE(enum1.value(2), -1);
833     QCOMPARE(enum2.name(), QByteArray("bar"));
834     QVERIFY(enum2.isFlag());
835     QCOMPARE(enum2.keyCount(), 2);
836     QCOMPARE(enum2.index(), 1);
837     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
838     QCOMPARE(enum2.key(1), QByteArray("UVW"));
839     QCOMPARE(enum2.key(2), QByteArray());
840     QCOMPARE(enum2.value(0), 10);
841     QCOMPARE(enum2.value(1), 19);
842
843     // Remove enum1 key
844     enum1.removeKey(2);
845     QCOMPARE(enum1.name(), QByteArray("foo"));
846     QVERIFY(enum1.isFlag());
847     QCOMPARE(enum1.keyCount(), 2);
848     QCOMPARE(enum1.index(), 0);
849     QCOMPARE(enum1.key(0), QByteArray("ABC"));
850     QCOMPARE(enum1.key(1), QByteArray("DEF"));
851     QCOMPARE(enum1.key(2), QByteArray());
852     QCOMPARE(enum1.value(0), 0);
853     QCOMPARE(enum1.value(1), 1);
854     QCOMPARE(enum1.value(2), -1);
855     QCOMPARE(enum2.name(), QByteArray("bar"));
856     QVERIFY(enum2.isFlag());
857     QCOMPARE(enum2.keyCount(), 2);
858     QCOMPARE(enum2.index(), 1);
859     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
860     QCOMPARE(enum2.key(1), QByteArray("UVW"));
861     QCOMPARE(enum2.key(2), QByteArray());
862     QCOMPARE(enum2.value(0), 10);
863     QCOMPARE(enum2.value(1), 19);
864
865     // Remove enum1 and check that enum2 becomes index 0.
866     builder.removeEnumerator(0);
867     QCOMPARE(builder.enumeratorCount(), 1);
868     enum2 = builder.enumerator(0);
869     QCOMPARE(enum2.name(), QByteArray("bar"));
870     QVERIFY(enum2.isFlag());
871     QCOMPARE(enum2.keyCount(), 2);
872     QCOMPARE(enum2.index(), 0);
873     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
874     QCOMPARE(enum2.key(1), QByteArray("UVW"));
875     QCOMPARE(enum2.key(2), QByteArray());
876     QCOMPARE(enum2.value(0), 10);
877     QCOMPARE(enum2.value(1), 19);
878
879     // Perform index-based lookup again.
880     QCOMPARE(builder.indexOfEnumerator("foo"), -1);
881     QCOMPARE(builder.indexOfEnumerator("bar"), 0);
882     QCOMPARE(builder.indexOfEnumerator("baz"), -1);
883
884     // Check that nothing else changed.
885     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Enumerators));
886 }
887
888 void tst_QMetaObjectBuilder::classInfo()
889 {
890     QMetaObjectBuilder builder;
891
892     // Add two items of class information and check their attributes.
893     QCOMPARE(builder.addClassInfo("foo", "value1"), 0);
894     QCOMPARE(builder.addClassInfo("bar", "value2"), 1);
895     QCOMPARE(builder.classInfoName(0), QByteArray("foo"));
896     QCOMPARE(builder.classInfoValue(0), QByteArray("value1"));
897     QCOMPARE(builder.classInfoName(1), QByteArray("bar"));
898     QCOMPARE(builder.classInfoValue(1), QByteArray("value2"));
899     QCOMPARE(builder.classInfoName(9), QByteArray());
900     QCOMPARE(builder.classInfoValue(9), QByteArray());
901     QCOMPARE(builder.classInfoCount(), 2);
902
903     // Perform index-based lookup.
904     QCOMPARE(builder.indexOfClassInfo("foo"), 0);
905     QCOMPARE(builder.indexOfClassInfo("bar"), 1);
906     QCOMPARE(builder.indexOfClassInfo("baz"), -1);
907
908     // Remove the first one and check again.
909     builder.removeClassInfo(0);
910     QCOMPARE(builder.classInfoName(0), QByteArray("bar"));
911     QCOMPARE(builder.classInfoValue(0), QByteArray("value2"));
912     QCOMPARE(builder.classInfoCount(), 1);
913
914     // Perform index-based lookup again.
915     QCOMPARE(builder.indexOfClassInfo("foo"), -1);
916     QCOMPARE(builder.indexOfClassInfo("bar"), 0);
917     QCOMPARE(builder.indexOfClassInfo("baz"), -1);
918
919     // Check that nothing else changed.
920     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::ClassInfos));
921 }
922
923 void tst_QMetaObjectBuilder::relatedMetaObject()
924 {
925     QMetaObjectBuilder builder;
926
927     // Add two related meta objects and check their attributes.
928     QCOMPARE(builder.addRelatedMetaObject(&QObject::staticMetaObject), 0);
929     QCOMPARE(builder.addRelatedMetaObject(&staticMetaObject), 1);
930     QVERIFY(builder.relatedMetaObject(0) == &QObject::staticMetaObject);
931     QVERIFY(builder.relatedMetaObject(1) == &staticMetaObject);
932     QCOMPARE(builder.relatedMetaObjectCount(), 2);
933
934     // Remove the first one and check again.
935     builder.removeRelatedMetaObject(0);
936     QVERIFY(builder.relatedMetaObject(0) == &staticMetaObject);
937     QCOMPARE(builder.relatedMetaObjectCount(), 1);
938
939     // Check that nothing else changed.
940     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::RelatedMetaObjects));
941 }
942
943 static void smetacall(QObject *, QMetaObject::Call, int, void **)
944 {
945     return;
946 }
947
948 void tst_QMetaObjectBuilder::staticMetacall()
949 {
950     QMetaObjectBuilder builder;
951     QVERIFY(!builder.staticMetacallFunction());
952     builder.setStaticMetacallFunction(smetacall);
953     QVERIFY(builder.staticMetacallFunction() == smetacall);
954     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::StaticMetacall));
955 }
956
957 // Copy the entire contents of a static QMetaObject and then check
958 // that QMetaObjectBuilder will produce an exact copy as output.
959 void tst_QMetaObjectBuilder::copyMetaObject()
960 {
961     QMetaObjectBuilder builder(&QObject::staticMetaObject);
962     QMetaObject *meta = builder.toMetaObject();
963     QVERIFY(sameMetaObject(meta, &QObject::staticMetaObject));
964     qFree(meta);
965
966     QMetaObjectBuilder builder2(&staticMetaObject);
967     meta = builder2.toMetaObject();
968     QVERIFY(sameMetaObject(meta, &staticMetaObject));
969     qFree(meta);
970
971     QMetaObjectBuilder builder3(&SomethingOfEverything::staticMetaObject);
972     meta = builder3.toMetaObject();
973     QVERIFY(sameMetaObject(meta, &SomethingOfEverything::staticMetaObject));
974     qFree(meta);
975 }
976
977 // Serialize and deserialize a meta object and check that
978 // it round-trips to the exact same value.
979 void tst_QMetaObjectBuilder::serialize()
980 {
981     // Full QMetaObjectBuilder
982     {
983     QMetaObjectBuilder builder(&SomethingOfEverything::staticMetaObject);
984     QMetaObject *meta = builder.toMetaObject();
985
986     QByteArray data;
987     QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append);
988     builder.serialize(stream);
989
990     QMetaObjectBuilder builder2;
991     QDataStream stream2(data);
992     QMap<QByteArray, const QMetaObject *> references;
993     references.insert(QByteArray("QLocale"), &QLocale::staticMetaObject);
994     builder2.deserialize(stream2, references);
995     builder2.setStaticMetacallFunction(builder.staticMetacallFunction());
996     QMetaObject *meta2 = builder2.toMetaObject();
997
998     QVERIFY(sameMetaObject(meta, meta2));
999     qFree(meta);
1000     qFree(meta2);
1001     }
1002
1003     // Partial QMetaObjectBuilder
1004     {
1005     QMetaObjectBuilder builder;
1006     builder.setClassName("Test");
1007     builder.addProperty("foo", "int");
1008
1009     QByteArray data;
1010     QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append);
1011     builder.serialize(stream);
1012
1013     QMetaObjectBuilder builder2;
1014     QDataStream stream2(data);
1015     builder2.deserialize(stream2, QMap<QByteArray, const QMetaObject *>());
1016
1017     QCOMPARE(builder.superClass(), builder2.superClass());
1018     QCOMPARE(builder.className(), builder2.className());
1019     QCOMPARE(builder.propertyCount(), builder2.propertyCount());
1020     QCOMPARE(builder.property(0).name(), builder2.property(0).name());
1021     QCOMPARE(builder.property(0).type(), builder2.property(0).type());
1022     }
1023 }
1024
1025 // Check that removing a method updates notify signals appropriately
1026 void tst_QMetaObjectBuilder::removeNotifySignal()
1027 {
1028     QMetaObjectBuilder builder;
1029
1030     QMetaMethodBuilder method1 = builder.addSignal("foo(const QString&, int)");
1031     QMetaMethodBuilder method2 = builder.addSignal("bar(QString)");
1032
1033     // Setup property
1034     QMetaPropertyBuilder prop = builder.addProperty("prop", "const QString &");
1035     prop.setNotifySignal(method2);
1036     QVERIFY(prop.hasNotifySignal());
1037     QCOMPARE(prop.notifySignal().index(), 1);
1038
1039     // Remove non-notify signal
1040     builder.removeMethod(0);
1041     QVERIFY(prop.hasNotifySignal());
1042     QCOMPARE(prop.notifySignal().index(), 0);
1043
1044     // Remove notify signal
1045     builder.removeMethod(0);
1046     QVERIFY(!prop.hasNotifySignal());
1047 }
1048
1049 // Check that the only changes to a "builder" relative to the default
1050 // state is specified by "members".
1051 bool tst_QMetaObjectBuilder::checkForSideEffects
1052         (const QMetaObjectBuilder& builder,
1053          QMetaObjectBuilder::AddMembers members)
1054 {
1055     if ((members & QMetaObjectBuilder::ClassName) == 0) {
1056         if (!builder.className().isEmpty())
1057             return false;
1058     }
1059
1060     if ((members & QMetaObjectBuilder::SuperClass) == 0) {
1061         if (builder.superClass() != &QObject::staticMetaObject)
1062             return false;
1063     }
1064
1065     if ((members & QMetaObjectBuilder::Methods) == 0) {
1066         if (builder.methodCount() != 0)
1067             return false;
1068     }
1069
1070     if ((members & QMetaObjectBuilder::Constructors) == 0) {
1071         if (builder.constructorCount() != 0)
1072             return false;
1073     }
1074
1075     if ((members & QMetaObjectBuilder::Properties) == 0) {
1076         if (builder.propertyCount() != 0)
1077             return false;
1078     }
1079
1080     if ((members & QMetaObjectBuilder::Enumerators) == 0) {
1081         if (builder.enumeratorCount() != 0)
1082             return false;
1083     }
1084
1085     if ((members & QMetaObjectBuilder::ClassInfos) == 0) {
1086         if (builder.classInfoCount() != 0)
1087             return false;
1088     }
1089
1090     if ((members & QMetaObjectBuilder::RelatedMetaObjects) == 0) {
1091         if (builder.relatedMetaObjectCount() != 0)
1092             return false;
1093     }
1094
1095     if ((members & QMetaObjectBuilder::StaticMetacall) == 0) {
1096         if (builder.staticMetacallFunction() != 0)
1097             return false;
1098     }
1099
1100     return true;
1101 }
1102
1103 static bool sameMethod(const QMetaMethod& method1, const QMetaMethod& method2)
1104 {
1105     if (QByteArray(method1.signature()) != QByteArray(method2.signature()))
1106         return false;
1107
1108     if (QByteArray(method1.typeName()) != QByteArray(method2.typeName()))
1109         return false;
1110
1111     if (method1.parameterNames() != method2.parameterNames())
1112         return false;
1113
1114     if (QByteArray(method1.tag()) != QByteArray(method2.tag()))
1115         return false;
1116
1117     if (method1.access() != method2.access())
1118         return false;
1119
1120     if (method1.methodType() != method2.methodType())
1121         return false;
1122
1123     if (method1.attributes() != method2.attributes())
1124         return false;
1125
1126     return true;
1127 }
1128
1129 static bool sameProperty(const QMetaProperty& prop1, const QMetaProperty& prop2)
1130 {
1131     if (QByteArray(prop1.name()) != QByteArray(prop2.name()))
1132         return false;
1133
1134     if (QByteArray(prop1.typeName()) != QByteArray(prop2.typeName()))
1135         return false;
1136
1137     if (prop1.isReadable() != prop2.isReadable() ||
1138         prop1.isWritable() != prop2.isWritable() ||
1139         prop1.isResettable() != prop2.isResettable() ||
1140         prop1.isDesignable() != prop2.isDesignable() ||
1141         prop1.isScriptable() != prop2.isScriptable() ||
1142         prop1.isStored() != prop2.isStored() ||
1143         prop1.isEditable() != prop2.isEditable() ||
1144         prop1.isUser() != prop2.isUser() ||
1145         prop1.isFlagType() != prop2.isFlagType() ||
1146         prop1.isEnumType() != prop2.isEnumType() ||
1147         prop1.hasNotifySignal() != prop2.hasNotifySignal() ||
1148         prop1.hasStdCppSet() != prop2.hasStdCppSet())
1149         return false;
1150
1151     if (prop1.hasNotifySignal()) {
1152         if (prop1.notifySignalIndex() != prop2.notifySignalIndex())
1153             return false;
1154     }
1155
1156     return true;
1157 }
1158
1159 static bool sameEnumerator(const QMetaEnum& enum1, const QMetaEnum& enum2)
1160 {
1161     if (QByteArray(enum1.name()) != QByteArray(enum2.name()))
1162         return false;
1163
1164     if (enum1.isFlag() != enum2.isFlag())
1165         return false;
1166
1167     if (enum1.keyCount() != enum2.keyCount())
1168         return false;
1169
1170     for (int index = 0; index < enum1.keyCount(); ++index) {
1171         if (QByteArray(enum1.key(index)) != QByteArray(enum2.key(index)))
1172             return false;
1173         if (enum1.value(index) != enum2.value(index))
1174             return false;
1175     }
1176
1177     if (QByteArray(enum1.scope()) != QByteArray(enum2.scope()))
1178         return false;
1179
1180     return true;
1181 }
1182
1183 // Determine if two meta objects are identical.
1184 bool tst_QMetaObjectBuilder::sameMetaObject
1185         (const QMetaObject *meta1, const QMetaObject *meta2)
1186 {
1187     int index;
1188
1189     if (strcmp(meta1->className(), meta2->className()) != 0)
1190         return false;
1191
1192     if (meta1->superClass() != meta2->superClass())
1193         return false;
1194
1195     if (meta1->constructorCount() != meta2->constructorCount() ||
1196         meta1->methodCount() != meta2->methodCount() ||
1197         meta1->enumeratorCount() != meta2->enumeratorCount() ||
1198         meta1->propertyCount() != meta2->propertyCount() ||
1199         meta1->classInfoCount() != meta2->classInfoCount())
1200         return false;
1201
1202     for (index = 0; index < meta1->constructorCount(); ++index) {
1203         if (!sameMethod(meta1->constructor(index), meta2->constructor(index)))
1204             return false;
1205     }
1206
1207     for (index = 0; index < meta1->methodCount(); ++index) {
1208         if (!sameMethod(meta1->method(index), meta2->method(index)))
1209             return false;
1210     }
1211
1212     for (index = 0; index < meta1->propertyCount(); ++index) {
1213         if (!sameProperty(meta1->property(index), meta2->property(index)))
1214             return false;
1215     }
1216
1217     for (index = 0; index < meta1->enumeratorCount(); ++index) {
1218         if (!sameEnumerator(meta1->enumerator(index), meta2->enumerator(index)))
1219             return false;
1220     }
1221
1222     for (index = 0; index < meta1->classInfoCount(); ++index) {
1223         if (QByteArray(meta1->classInfo(index).name()) !=
1224             QByteArray(meta2->classInfo(index).name()))
1225             return false;
1226         if (QByteArray(meta1->classInfo(index).value()) !=
1227             QByteArray(meta2->classInfo(index).value()))
1228             return false;
1229     }
1230
1231     const QMetaObject **objects1 = 0;
1232     const QMetaObject **objects2 = 0;
1233     if (meta1->d.data[0] == meta2->d.data[0] && meta1->d.data[0] >= 2) {
1234         QMetaObjectExtraData *extra1 = (QMetaObjectExtraData *)(meta1->d.extradata);
1235         QMetaObjectExtraData *extra2 = (QMetaObjectExtraData *)(meta2->d.extradata);
1236         if (extra1 && !extra2)
1237             return false;
1238         if (extra2 && !extra1)
1239             return false;
1240         if (extra1 && extra2) {
1241             if (extra1->static_metacall != extra2->static_metacall)
1242                 return false;
1243             objects1 = extra1->objects;
1244             objects2 = extra1->objects;
1245         }
1246     } else if (meta1->d.data[0] == meta2->d.data[0] && meta1->d.data[0] == 1) {
1247         objects1 = (const QMetaObject **)(meta1->d.extradata);
1248         objects2 = (const QMetaObject **)(meta2->d.extradata);
1249     }
1250     if (objects1 && !objects2)
1251         return false;
1252     if (objects2 && !objects1)
1253         return false;
1254     if (objects1 && objects2) {
1255         while (*objects1 != 0 && *objects2 != 0) {
1256             if (*objects1 != *objects2)
1257                 return false;
1258             ++objects1;
1259             ++objects2;
1260         }
1261     }
1262
1263     return true;
1264 }
1265
1266 QTEST_MAIN(tst_QMetaObjectBuilder)
1267
1268 #include "tst_qmetaobjectbuilder.moc"