tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
changeset 30 5dc02b23752f
child 37 758a864f9613
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QtTest/QtTest>
       
    43 #include <QtCore/qlocale.h>
       
    44 #include <private/qmetaobjectbuilder_p.h>
       
    45 
       
    46 class tst_QMetaObjectBuilder : public QObject
       
    47 {
       
    48     Q_OBJECT
       
    49 public:
       
    50     tst_QMetaObjectBuilder() {}
       
    51     ~tst_QMetaObjectBuilder() {}
       
    52 
       
    53 private slots:
       
    54     void mocVersionCheck();
       
    55     void create();
       
    56     void className();
       
    57     void superClass();
       
    58     void flags();
       
    59     void method();
       
    60     void slot();
       
    61     void signal();
       
    62     void constructor();
       
    63     void property();
       
    64     void notifySignal();
       
    65     void enumerator();
       
    66     void classInfo();
       
    67     void relatedMetaObject();
       
    68     void staticMetacall();
       
    69     void copyMetaObject();
       
    70     void serialize();
       
    71     void removeNotifySignal();
       
    72 
       
    73 private:
       
    74     static bool checkForSideEffects
       
    75         (const QMetaObjectBuilder& builder,
       
    76          QMetaObjectBuilder::AddMembers members);
       
    77     static bool sameMetaObject
       
    78         (const QMetaObject *meta1, const QMetaObject *meta2);
       
    79 };
       
    80 
       
    81 // Dummy class that has something of every type of thing moc can generate.
       
    82 class SomethingOfEverything : public QObject
       
    83 {
       
    84     Q_OBJECT
       
    85     Q_CLASSINFO("ci_foo", "ABC")
       
    86     Q_CLASSINFO("ci_bar", "DEF")
       
    87     Q_PROPERTY(QString prop READ prop WRITE setProp NOTIFY propChanged)
       
    88     Q_PROPERTY(QString prop2 READ prop WRITE setProp)
       
    89     Q_PROPERTY(SomethingEnum eprop READ eprop)
       
    90     Q_PROPERTY(SomethingFlagEnum fprop READ fprop)
       
    91     Q_PROPERTY(QLocale::Language language READ language)
       
    92     Q_ENUMS(SomethingEnum)
       
    93     Q_FLAGS(SomethingFlagEnum)
       
    94 public:
       
    95     Q_INVOKABLE SomethingOfEverything() {}
       
    96     ~SomethingOfEverything() {}
       
    97 
       
    98     enum SomethingEnum
       
    99     {
       
   100         GHI,
       
   101         JKL = 10
       
   102     };
       
   103 
       
   104     enum SomethingFlagEnum
       
   105     {
       
   106         XYZ = 1,
       
   107         UVW = 8
       
   108     };
       
   109 
       
   110     Q_INVOKABLE Q_SCRIPTABLE void method1() {}
       
   111 
       
   112     QString prop() const { return QString(); }
       
   113     void setProp(const QString& v) { Q_UNUSED(v); }
       
   114 
       
   115     SomethingOfEverything::SomethingEnum eprop() const { return GHI; }
       
   116     SomethingOfEverything::SomethingFlagEnum fprop() const { return XYZ; }
       
   117     QLocale::Language language() const { return QLocale::English; }
       
   118 
       
   119 public slots:
       
   120     void slot1(const QString&) {}
       
   121     void slot2(int, const QString&) {}
       
   122 
       
   123 private slots:
       
   124     void slot3() {}
       
   125 
       
   126 protected slots:
       
   127     Q_SCRIPTABLE void slot4(int) {}
       
   128     void slot5(int a, const QString& b) { Q_UNUSED(a); Q_UNUSED(b); }
       
   129 
       
   130 signals:
       
   131     void sig1();
       
   132     void sig2(int x, const QString& y);
       
   133     void propChanged(const QString&);
       
   134 };
       
   135 
       
   136 void tst_QMetaObjectBuilder::mocVersionCheck()
       
   137 {
       
   138     // This test will fail when the moc version number is changed.
       
   139     // It is intended as a reminder to also update QMetaObjectBuilder
       
   140     // whenenver moc changes.  Once QMetaObjectBuilder has been
       
   141     // updated, this test can be changed to check for the next version.
       
   142     int version = int(QObject::staticMetaObject.d.data[0]);
       
   143     QVERIFY(version == 4 || version == 5);
       
   144     version = int(staticMetaObject.d.data[0]);
       
   145     QVERIFY(version == 4 || version == 5);
       
   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.isDynamic());
       
   550     QCOMPARE(nullProp.index(), 0);
       
   551 
       
   552     // Add a property and check its attributes.
       
   553     QMetaPropertyBuilder prop1 = builder.addProperty("foo", "const QString &");
       
   554     QCOMPARE(prop1.name(), QByteArray("foo"));
       
   555     QCOMPARE(prop1.type(), QByteArray("QString"));
       
   556     QVERIFY(!prop1.hasNotifySignal());
       
   557     QVERIFY(prop1.isReadable());
       
   558     QVERIFY(prop1.isWritable());
       
   559     QVERIFY(!prop1.isResettable());
       
   560     QVERIFY(!prop1.isDesignable());
       
   561     QVERIFY(!prop1.isScriptable());
       
   562     QVERIFY(!prop1.isStored());
       
   563     QVERIFY(!prop1.isEditable());
       
   564     QVERIFY(!prop1.isUser());
       
   565     QVERIFY(!prop1.hasStdCppSet());
       
   566     QVERIFY(!prop1.isEnumOrFlag());
       
   567     QVERIFY(!prop1.isDynamic());
       
   568     QCOMPARE(prop1.index(), 0);
       
   569     QCOMPARE(builder.propertyCount(), 1);
       
   570 
       
   571     // Add another property and check again.
       
   572     QMetaPropertyBuilder prop2 = builder.addProperty("bar", "int");
       
   573     QCOMPARE(prop2.name(), QByteArray("bar"));
       
   574     QCOMPARE(prop2.type(), QByteArray("int"));
       
   575     QVERIFY(!prop2.hasNotifySignal());
       
   576     QVERIFY(prop2.isReadable());
       
   577     QVERIFY(prop2.isWritable());
       
   578     QVERIFY(!prop2.isResettable());
       
   579     QVERIFY(!prop2.isDesignable());
       
   580     QVERIFY(!prop2.isScriptable());
       
   581     QVERIFY(!prop2.isStored());
       
   582     QVERIFY(!prop2.isEditable());
       
   583     QVERIFY(!prop2.isUser());
       
   584     QVERIFY(!prop2.hasStdCppSet());
       
   585     QVERIFY(!prop2.isEnumOrFlag());
       
   586     QVERIFY(!prop2.isDynamic());
       
   587     QCOMPARE(prop2.index(), 1);
       
   588     QCOMPARE(builder.propertyCount(), 2);
       
   589 
       
   590     // Perform index-based lookup.
       
   591     QCOMPARE(builder.indexOfProperty("foo"), 0);
       
   592     QCOMPARE(builder.indexOfProperty("bar"), 1);
       
   593     QCOMPARE(builder.indexOfProperty("baz"), -1);
       
   594     QCOMPARE(builder.property(1).name(), QByteArray("bar"));
       
   595     QCOMPARE(builder.property(9).name(), QByteArray());
       
   596 
       
   597     // Modify the attributes on prop1.
       
   598     prop1.setReadable(false);
       
   599     prop1.setWritable(false);
       
   600     prop1.setResettable(true);
       
   601     prop1.setDesignable(true);
       
   602     prop1.setScriptable(true);
       
   603     prop1.setStored(true);
       
   604     prop1.setEditable(true);
       
   605     prop1.setUser(true);
       
   606     prop1.setStdCppSet(true);
       
   607     prop1.setEnumOrFlag(true);
       
   608     prop1.setDynamic(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.isDynamic());
       
   624     QVERIFY(prop2.isReadable());
       
   625     QVERIFY(prop2.isWritable());
       
   626     QCOMPARE(prop2.name(), QByteArray("bar"));
       
   627     QCOMPARE(prop2.type(), QByteArray("int"));
       
   628     QVERIFY(!prop2.isResettable());
       
   629     QVERIFY(!prop2.isDesignable());
       
   630     QVERIFY(!prop2.isScriptable());
       
   631     QVERIFY(!prop2.isStored());
       
   632     QVERIFY(!prop2.isEditable());
       
   633     QVERIFY(!prop2.isUser());
       
   634     QVERIFY(!prop2.hasStdCppSet());
       
   635     QVERIFY(!prop2.isEnumOrFlag());
       
   636     QVERIFY(!prop2.isDynamic());
       
   637 
       
   638     // Remove prop1 and check that prop2 becomes index 0.
       
   639     builder.removeProperty(0);
       
   640     QCOMPARE(builder.propertyCount(), 1);
       
   641     prop2 = builder.property(0);
       
   642     QCOMPARE(prop2.name(), QByteArray("bar"));
       
   643     QCOMPARE(prop2.type(), QByteArray("int"));
       
   644     QVERIFY(!prop2.isResettable());
       
   645     QVERIFY(!prop2.isDesignable());
       
   646     QVERIFY(!prop2.isScriptable());
       
   647     QVERIFY(!prop2.isStored());
       
   648     QVERIFY(!prop2.isEditable());
       
   649     QVERIFY(!prop2.isUser());
       
   650     QVERIFY(!prop2.hasStdCppSet());
       
   651     QVERIFY(!prop2.isEnumOrFlag());
       
   652     QVERIFY(!prop2.isDynamic());
       
   653     QCOMPARE(prop2.index(), 0);
       
   654 
       
   655     // Perform index-based lookup again.
       
   656     QCOMPARE(builder.indexOfProperty("foo"), -1);
       
   657     QCOMPARE(builder.indexOfProperty("bar"), 0);
       
   658     QCOMPARE(builder.indexOfProperty("baz"), -1);
       
   659 
       
   660     // Check for side-effects between the flags on prop2.
       
   661     // Setting a flag to true shouldn't set any of the others to true.
       
   662     // This checks for cut-and-paste bugs in the implementation where
       
   663     // the flag code was pasted but the flag name was not changed.
       
   664 #define CLEAR_FLAGS() \
       
   665         do { \
       
   666             prop2.setReadable(false); \
       
   667             prop2.setWritable(false); \
       
   668             prop2.setResettable(false); \
       
   669             prop2.setDesignable(false); \
       
   670             prop2.setScriptable(false); \
       
   671             prop2.setStored(false); \
       
   672             prop2.setEditable(false); \
       
   673             prop2.setUser(false); \
       
   674             prop2.setStdCppSet(false); \
       
   675             prop2.setEnumOrFlag(false); \
       
   676             prop2.setDynamic(false); \
       
   677         } while (0)
       
   678 #define COUNT_FLAGS() \
       
   679         ((prop2.isReadable() ? 1 : 0) + \
       
   680          (prop2.isWritable() ? 1 : 0) + \
       
   681          (prop2.isResettable() ? 1 : 0) + \
       
   682          (prop2.isDesignable() ? 1 : 0) + \
       
   683          (prop2.isScriptable() ? 1 : 0) + \
       
   684          (prop2.isStored() ? 1 : 0) + \
       
   685          (prop2.isEditable() ? 1 : 0) + \
       
   686          (prop2.isUser() ? 1 : 0) + \
       
   687          (prop2.hasStdCppSet() ? 1 : 0) + \
       
   688          (prop2.isEnumOrFlag() ? 1 : 0) + \
       
   689          (prop2.isDynamic() ? 1 : 0)) 
       
   690 #define CHECK_FLAG(setFunc,isFunc) \
       
   691         do { \
       
   692             CLEAR_FLAGS(); \
       
   693             QCOMPARE(COUNT_FLAGS(), 0); \
       
   694             prop2.setFunc(true); \
       
   695             QVERIFY(prop2.isFunc()); \
       
   696             QCOMPARE(COUNT_FLAGS(), 1); \
       
   697         } while (0)
       
   698     CHECK_FLAG(setReadable, isReadable);
       
   699     CHECK_FLAG(setWritable, isWritable);
       
   700     CHECK_FLAG(setResettable, isResettable);
       
   701     CHECK_FLAG(setDesignable, isDesignable);
       
   702     CHECK_FLAG(setScriptable, isScriptable);
       
   703     CHECK_FLAG(setStored, isStored);
       
   704     CHECK_FLAG(setEditable, isEditable);
       
   705     CHECK_FLAG(setUser, isUser);
       
   706     CHECK_FLAG(setStdCppSet, hasStdCppSet);
       
   707     CHECK_FLAG(setEnumOrFlag, isEnumOrFlag);
       
   708     CHECK_FLAG(setDynamic, isDynamic);
       
   709 
       
   710     // Check that nothing else changed.
       
   711     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Properties));
       
   712 
       
   713     // Add property from prototype
       
   714     QMetaProperty prototype = SomethingOfEverything::staticMetaObject.property(1);
       
   715     QVERIFY(prototype.name() == QByteArray("prop"));
       
   716     QMetaPropertyBuilder prototypeProp = builder.addProperty(prototype);
       
   717     QCOMPARE(prototypeProp.name(), QByteArray("prop"));
       
   718     QVERIFY(prototypeProp.hasNotifySignal());
       
   719     QCOMPARE(prototypeProp.notifySignal().signature(), QByteArray("propChanged(QString)"));
       
   720     QCOMPARE(builder.methodCount(), 1);
       
   721     QCOMPARE(builder.method(0).signature(), QByteArray("propChanged(QString)"));
       
   722 }
       
   723 
       
   724 void tst_QMetaObjectBuilder::notifySignal()
       
   725 {
       
   726     QMetaObjectBuilder builder;
       
   727 
       
   728     QMetaPropertyBuilder prop = builder.addProperty("foo", "const QString &");
       
   729     builder.addSlot("setFoo(QString)");
       
   730     QMetaMethodBuilder notify = builder.addSignal("fooChanged(QString)");
       
   731 
       
   732     QVERIFY(!prop.hasNotifySignal());
       
   733     QCOMPARE(prop.notifySignal().index(), 0);
       
   734 
       
   735     prop.setNotifySignal(notify);
       
   736     QVERIFY(prop.hasNotifySignal());
       
   737     QCOMPARE(prop.notifySignal().index(), 1);
       
   738 
       
   739     prop.setNotifySignal(QMetaMethodBuilder());
       
   740     QVERIFY(!prop.hasNotifySignal());
       
   741     QCOMPARE(prop.notifySignal().index(), 0);
       
   742 
       
   743     prop.setNotifySignal(notify);
       
   744     prop.removeNotifySignal();
       
   745     QVERIFY(!prop.hasNotifySignal());
       
   746     QCOMPARE(prop.notifySignal().index(), 0);
       
   747 
       
   748     QCOMPARE(builder.methodCount(), 2);
       
   749     QCOMPARE(builder.propertyCount(), 1);
       
   750 
       
   751     // Check that nothing else changed except methods and properties.
       
   752     QVERIFY(checkForSideEffects
       
   753         (builder, QMetaObjectBuilder::Methods | QMetaObjectBuilder::Properties));
       
   754 }
       
   755 
       
   756 void tst_QMetaObjectBuilder::enumerator()
       
   757 {
       
   758     QMetaObjectBuilder builder;
       
   759 
       
   760     // Add an enumerator and check its attributes.
       
   761     QMetaEnumBuilder enum1 = builder.addEnumerator("foo");
       
   762     QCOMPARE(enum1.name(), QByteArray("foo"));
       
   763     QVERIFY(!enum1.isFlag());
       
   764     QCOMPARE(enum1.keyCount(), 0);
       
   765     QCOMPARE(enum1.index(), 0);
       
   766     QCOMPARE(builder.enumeratorCount(), 1);
       
   767 
       
   768     // Add another enumerator and check again.
       
   769     QMetaEnumBuilder enum2 = builder.addEnumerator("bar");
       
   770     QCOMPARE(enum2.name(), QByteArray("bar"));
       
   771     QVERIFY(!enum2.isFlag());
       
   772     QCOMPARE(enum2.keyCount(), 0);
       
   773     QCOMPARE(enum2.index(), 1);
       
   774     QCOMPARE(builder.enumeratorCount(), 2);
       
   775 
       
   776     // Perform index-based lookup.
       
   777     QCOMPARE(builder.indexOfEnumerator("foo"), 0);
       
   778     QCOMPARE(builder.indexOfEnumerator("bar"), 1);
       
   779     QCOMPARE(builder.indexOfEnumerator("baz"), -1);
       
   780     QCOMPARE(builder.enumerator(1).name(), QByteArray("bar"));
       
   781     QCOMPARE(builder.enumerator(9).name(), QByteArray());
       
   782 
       
   783     // Modify the attributes on enum1.
       
   784     enum1.setIsFlag(true);
       
   785     QCOMPARE(enum1.addKey("ABC", 0), 0);
       
   786     QCOMPARE(enum1.addKey("DEF", 1), 1);
       
   787     QCOMPARE(enum1.addKey("GHI", -1), 2);
       
   788 
       
   789     // Check that enum1 is changed, but enum2 is not.
       
   790     QCOMPARE(enum1.name(), QByteArray("foo"));
       
   791     QVERIFY(enum1.isFlag());
       
   792     QCOMPARE(enum1.keyCount(), 3);
       
   793     QCOMPARE(enum1.index(), 0);
       
   794     QCOMPARE(enum1.key(0), QByteArray("ABC"));
       
   795     QCOMPARE(enum1.key(1), QByteArray("DEF"));
       
   796     QCOMPARE(enum1.key(2), QByteArray("GHI"));
       
   797     QCOMPARE(enum1.key(3), QByteArray());
       
   798     QCOMPARE(enum1.value(0), 0);
       
   799     QCOMPARE(enum1.value(1), 1);
       
   800     QCOMPARE(enum1.value(2), -1);
       
   801     QCOMPARE(enum2.name(), QByteArray("bar"));
       
   802     QVERIFY(!enum2.isFlag());
       
   803     QCOMPARE(enum2.keyCount(), 0);
       
   804     QCOMPARE(enum2.index(), 1);
       
   805 
       
   806     // Modify the attributes on enum2.
       
   807     enum2.setIsFlag(true);
       
   808     QCOMPARE(enum2.addKey("XYZ", 10), 0);
       
   809     QCOMPARE(enum2.addKey("UVW", 19), 1);
       
   810 
       
   811     // This time check that only method2 changed.
       
   812     QCOMPARE(enum1.name(), QByteArray("foo"));
       
   813     QVERIFY(enum1.isFlag());
       
   814     QCOMPARE(enum1.keyCount(), 3);
       
   815     QCOMPARE(enum1.index(), 0);
       
   816     QCOMPARE(enum1.key(0), QByteArray("ABC"));
       
   817     QCOMPARE(enum1.key(1), QByteArray("DEF"));
       
   818     QCOMPARE(enum1.key(2), QByteArray("GHI"));
       
   819     QCOMPARE(enum1.key(3), QByteArray());
       
   820     QCOMPARE(enum1.value(0), 0);
       
   821     QCOMPARE(enum1.value(1), 1);
       
   822     QCOMPARE(enum1.value(2), -1);
       
   823     QCOMPARE(enum2.name(), QByteArray("bar"));
       
   824     QVERIFY(enum2.isFlag());
       
   825     QCOMPARE(enum2.keyCount(), 2);
       
   826     QCOMPARE(enum2.index(), 1);
       
   827     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
       
   828     QCOMPARE(enum2.key(1), QByteArray("UVW"));
       
   829     QCOMPARE(enum2.key(2), QByteArray());
       
   830     QCOMPARE(enum2.value(0), 10);
       
   831     QCOMPARE(enum2.value(1), 19);
       
   832 
       
   833     // Remove enum1 key
       
   834     enum1.removeKey(2);
       
   835     QCOMPARE(enum1.name(), QByteArray("foo"));
       
   836     QVERIFY(enum1.isFlag());
       
   837     QCOMPARE(enum1.keyCount(), 2);
       
   838     QCOMPARE(enum1.index(), 0);
       
   839     QCOMPARE(enum1.key(0), QByteArray("ABC"));
       
   840     QCOMPARE(enum1.key(1), QByteArray("DEF"));
       
   841     QCOMPARE(enum1.key(2), QByteArray());
       
   842     QCOMPARE(enum1.value(0), 0);
       
   843     QCOMPARE(enum1.value(1), 1);
       
   844     QCOMPARE(enum1.value(2), -1);
       
   845     QCOMPARE(enum2.name(), QByteArray("bar"));
       
   846     QVERIFY(enum2.isFlag());
       
   847     QCOMPARE(enum2.keyCount(), 2);
       
   848     QCOMPARE(enum2.index(), 1);
       
   849     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
       
   850     QCOMPARE(enum2.key(1), QByteArray("UVW"));
       
   851     QCOMPARE(enum2.key(2), QByteArray());
       
   852     QCOMPARE(enum2.value(0), 10);
       
   853     QCOMPARE(enum2.value(1), 19);
       
   854 
       
   855     // Remove enum1 and check that enum2 becomes index 0.
       
   856     builder.removeEnumerator(0);
       
   857     QCOMPARE(builder.enumeratorCount(), 1);
       
   858     enum2 = builder.enumerator(0);
       
   859     QCOMPARE(enum2.name(), QByteArray("bar"));
       
   860     QVERIFY(enum2.isFlag());
       
   861     QCOMPARE(enum2.keyCount(), 2);
       
   862     QCOMPARE(enum2.index(), 0);
       
   863     QCOMPARE(enum2.key(0), QByteArray("XYZ"));
       
   864     QCOMPARE(enum2.key(1), QByteArray("UVW"));
       
   865     QCOMPARE(enum2.key(2), QByteArray());
       
   866     QCOMPARE(enum2.value(0), 10);
       
   867     QCOMPARE(enum2.value(1), 19);
       
   868 
       
   869     // Perform index-based lookup again.
       
   870     QCOMPARE(builder.indexOfEnumerator("foo"), -1);
       
   871     QCOMPARE(builder.indexOfEnumerator("bar"), 0);
       
   872     QCOMPARE(builder.indexOfEnumerator("baz"), -1);
       
   873 
       
   874     // Check that nothing else changed.
       
   875     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Enumerators));
       
   876 }
       
   877 
       
   878 void tst_QMetaObjectBuilder::classInfo()
       
   879 {
       
   880     QMetaObjectBuilder builder;
       
   881 
       
   882     // Add two items of class information and check their attributes.
       
   883     QCOMPARE(builder.addClassInfo("foo", "value1"), 0);
       
   884     QCOMPARE(builder.addClassInfo("bar", "value2"), 1);
       
   885     QCOMPARE(builder.classInfoName(0), QByteArray("foo"));
       
   886     QCOMPARE(builder.classInfoValue(0), QByteArray("value1"));
       
   887     QCOMPARE(builder.classInfoName(1), QByteArray("bar"));
       
   888     QCOMPARE(builder.classInfoValue(1), QByteArray("value2"));
       
   889     QCOMPARE(builder.classInfoName(9), QByteArray());
       
   890     QCOMPARE(builder.classInfoValue(9), QByteArray());
       
   891     QCOMPARE(builder.classInfoCount(), 2);
       
   892 
       
   893     // Perform index-based lookup.
       
   894     QCOMPARE(builder.indexOfClassInfo("foo"), 0);
       
   895     QCOMPARE(builder.indexOfClassInfo("bar"), 1);
       
   896     QCOMPARE(builder.indexOfClassInfo("baz"), -1);
       
   897 
       
   898     // Remove the first one and check again.
       
   899     builder.removeClassInfo(0);
       
   900     QCOMPARE(builder.classInfoName(0), QByteArray("bar"));
       
   901     QCOMPARE(builder.classInfoValue(0), QByteArray("value2"));
       
   902     QCOMPARE(builder.classInfoCount(), 1);
       
   903 
       
   904     // Perform index-based lookup again.
       
   905     QCOMPARE(builder.indexOfClassInfo("foo"), -1);
       
   906     QCOMPARE(builder.indexOfClassInfo("bar"), 0);
       
   907     QCOMPARE(builder.indexOfClassInfo("baz"), -1);
       
   908 
       
   909     // Check that nothing else changed.
       
   910     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::ClassInfos));
       
   911 }
       
   912 
       
   913 void tst_QMetaObjectBuilder::relatedMetaObject()
       
   914 {
       
   915     QMetaObjectBuilder builder;
       
   916 
       
   917     // Add two related meta objects and check their attributes.
       
   918     QCOMPARE(builder.addRelatedMetaObject(&QObject::staticMetaObject), 0);
       
   919     QCOMPARE(builder.addRelatedMetaObject(&staticMetaObject), 1);
       
   920     QVERIFY(builder.relatedMetaObject(0) == &QObject::staticMetaObject);
       
   921     QVERIFY(builder.relatedMetaObject(1) == &staticMetaObject);
       
   922     QCOMPARE(builder.relatedMetaObjectCount(), 2);
       
   923 
       
   924     // Remove the first one and check again.
       
   925     builder.removeRelatedMetaObject(0);
       
   926     QVERIFY(builder.relatedMetaObject(0) == &staticMetaObject);
       
   927     QCOMPARE(builder.relatedMetaObjectCount(), 1);
       
   928 
       
   929     // Check that nothing else changed.
       
   930     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::RelatedMetaObjects));
       
   931 }
       
   932 
       
   933 static int smetacall(QMetaObject::Call, int, void **)
       
   934 {
       
   935     return 0;
       
   936 }
       
   937 
       
   938 void tst_QMetaObjectBuilder::staticMetacall()
       
   939 {
       
   940     QMetaObjectBuilder builder;
       
   941     QVERIFY(!builder.staticMetacallFunction());
       
   942     builder.setStaticMetacallFunction(smetacall);
       
   943     QVERIFY(builder.staticMetacallFunction() == smetacall);
       
   944     QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::StaticMetacall));
       
   945 }
       
   946 
       
   947 // Copy the entire contents of a static QMetaObject and then check
       
   948 // that QMetaObjectBuilder will produce an exact copy as output.
       
   949 void tst_QMetaObjectBuilder::copyMetaObject()
       
   950 {
       
   951     QMetaObjectBuilder builder(&QObject::staticMetaObject);
       
   952     QMetaObject *meta = builder.toMetaObject();
       
   953     QVERIFY(sameMetaObject(meta, &QObject::staticMetaObject));
       
   954     qFree(meta);
       
   955 
       
   956     QMetaObjectBuilder builder2(&staticMetaObject);
       
   957     meta = builder2.toMetaObject();
       
   958     QVERIFY(sameMetaObject(meta, &staticMetaObject));
       
   959     qFree(meta);
       
   960 
       
   961     QMetaObjectBuilder builder3(&SomethingOfEverything::staticMetaObject);
       
   962     meta = builder3.toMetaObject();
       
   963     QVERIFY(sameMetaObject(meta, &SomethingOfEverything::staticMetaObject));
       
   964     qFree(meta);
       
   965 }
       
   966 
       
   967 // Serialize and deserialize a meta object and check that
       
   968 // it round-trips to the exact same value.
       
   969 void tst_QMetaObjectBuilder::serialize()
       
   970 {
       
   971     // Full QMetaObjectBuilder
       
   972     {
       
   973     QMetaObjectBuilder builder(&SomethingOfEverything::staticMetaObject);
       
   974     QMetaObject *meta = builder.toMetaObject();
       
   975 
       
   976     QByteArray data;
       
   977     QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append);
       
   978     builder.serialize(stream);
       
   979 
       
   980     QMetaObjectBuilder builder2;
       
   981     QDataStream stream2(data);
       
   982     QMap<QByteArray, const QMetaObject *> references;
       
   983     references.insert(QByteArray("QLocale"), &QLocale::staticMetaObject);
       
   984     builder2.deserialize(stream2, references);
       
   985     builder2.setStaticMetacallFunction(builder.staticMetacallFunction());
       
   986     QMetaObject *meta2 = builder2.toMetaObject();
       
   987 
       
   988     QVERIFY(sameMetaObject(meta, meta2));
       
   989     qFree(meta);
       
   990     qFree(meta2);
       
   991     }
       
   992 
       
   993     // Partial QMetaObjectBuilder
       
   994     {
       
   995     QMetaObjectBuilder builder;
       
   996     builder.setClassName("Test");
       
   997     builder.addProperty("foo", "int");
       
   998 
       
   999     QByteArray data;
       
  1000     QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append);
       
  1001     builder.serialize(stream);
       
  1002 
       
  1003     QMetaObjectBuilder builder2;
       
  1004     QDataStream stream2(data);
       
  1005     builder2.deserialize(stream2, QMap<QByteArray, const QMetaObject *>());
       
  1006 
       
  1007     QCOMPARE(builder.superClass(), builder2.superClass());
       
  1008     QCOMPARE(builder.className(), builder2.className());
       
  1009     QCOMPARE(builder.propertyCount(), builder2.propertyCount());
       
  1010     QCOMPARE(builder.property(0).name(), builder2.property(0).name());
       
  1011     QCOMPARE(builder.property(0).type(), builder2.property(0).type());
       
  1012     }
       
  1013 }
       
  1014 
       
  1015 // Check that removing a method updates notify signals appropriately
       
  1016 void tst_QMetaObjectBuilder::removeNotifySignal()
       
  1017 {
       
  1018     QMetaObjectBuilder builder;
       
  1019 
       
  1020     QMetaMethodBuilder method1 = builder.addSignal("foo(const QString&, int)");
       
  1021     QMetaMethodBuilder method2 = builder.addSignal("bar(QString)");
       
  1022 
       
  1023     // Setup property
       
  1024     QMetaPropertyBuilder prop = builder.addProperty("prop", "const QString &");
       
  1025     prop.setNotifySignal(method2);
       
  1026     QVERIFY(prop.hasNotifySignal());
       
  1027     QCOMPARE(prop.notifySignal().index(), 1);
       
  1028 
       
  1029     // Remove non-notify signal
       
  1030     builder.removeMethod(0);
       
  1031     QVERIFY(prop.hasNotifySignal());
       
  1032     QCOMPARE(prop.notifySignal().index(), 0);
       
  1033 
       
  1034     // Remove notify signal
       
  1035     builder.removeMethod(0);
       
  1036     QVERIFY(!prop.hasNotifySignal());
       
  1037 }
       
  1038 
       
  1039 // Check that the only changes to a "builder" relative to the default
       
  1040 // state is specified by "members".
       
  1041 bool tst_QMetaObjectBuilder::checkForSideEffects
       
  1042         (const QMetaObjectBuilder& builder,
       
  1043          QMetaObjectBuilder::AddMembers members)
       
  1044 {
       
  1045     if ((members & QMetaObjectBuilder::ClassName) == 0) {
       
  1046         if (!builder.className().isEmpty())
       
  1047             return false;
       
  1048     }
       
  1049 
       
  1050     if ((members & QMetaObjectBuilder::SuperClass) == 0) {
       
  1051         if (builder.superClass() != &QObject::staticMetaObject)
       
  1052             return false;
       
  1053     }
       
  1054 
       
  1055     if ((members & QMetaObjectBuilder::Methods) == 0) {
       
  1056         if (builder.methodCount() != 0)
       
  1057             return false;
       
  1058     }
       
  1059 
       
  1060     if ((members & QMetaObjectBuilder::Constructors) == 0) {
       
  1061         if (builder.constructorCount() != 0)
       
  1062             return false;
       
  1063     }
       
  1064 
       
  1065     if ((members & QMetaObjectBuilder::Properties) == 0) {
       
  1066         if (builder.propertyCount() != 0)
       
  1067             return false;
       
  1068     }
       
  1069 
       
  1070     if ((members & QMetaObjectBuilder::Enumerators) == 0) {
       
  1071         if (builder.enumeratorCount() != 0)
       
  1072             return false;
       
  1073     }
       
  1074 
       
  1075     if ((members & QMetaObjectBuilder::ClassInfos) == 0) {
       
  1076         if (builder.classInfoCount() != 0)
       
  1077             return false;
       
  1078     }
       
  1079 
       
  1080     if ((members & QMetaObjectBuilder::RelatedMetaObjects) == 0) {
       
  1081         if (builder.relatedMetaObjectCount() != 0)
       
  1082             return false;
       
  1083     }
       
  1084 
       
  1085     if ((members & QMetaObjectBuilder::StaticMetacall) == 0) {
       
  1086         if (builder.staticMetacallFunction() != 0)
       
  1087             return false;
       
  1088     }
       
  1089 
       
  1090     return true;
       
  1091 }
       
  1092 
       
  1093 static bool sameMethod(const QMetaMethod& method1, const QMetaMethod& method2)
       
  1094 {
       
  1095     if (QByteArray(method1.signature()) != QByteArray(method2.signature()))
       
  1096         return false;
       
  1097 
       
  1098     if (QByteArray(method1.typeName()) != QByteArray(method2.typeName()))
       
  1099         return false;
       
  1100 
       
  1101     if (method1.parameterNames() != method2.parameterNames())
       
  1102         return false;
       
  1103 
       
  1104     if (QByteArray(method1.tag()) != QByteArray(method2.tag()))
       
  1105         return false;
       
  1106 
       
  1107     if (method1.access() != method2.access())
       
  1108         return false;
       
  1109 
       
  1110     if (method1.methodType() != method2.methodType())
       
  1111         return false;
       
  1112 
       
  1113     if (method1.attributes() != method2.attributes())
       
  1114         return false;
       
  1115 
       
  1116     return true;
       
  1117 }
       
  1118 
       
  1119 static bool sameProperty(const QMetaProperty& prop1, const QMetaProperty& prop2)
       
  1120 {
       
  1121     if (QByteArray(prop1.name()) != QByteArray(prop2.name()))
       
  1122         return false;
       
  1123 
       
  1124     if (QByteArray(prop1.typeName()) != QByteArray(prop2.typeName()))
       
  1125         return false;
       
  1126 
       
  1127     if (prop1.isReadable() != prop2.isReadable() ||
       
  1128         prop1.isWritable() != prop2.isWritable() ||
       
  1129         prop1.isResettable() != prop2.isResettable() ||
       
  1130         prop1.isDesignable() != prop2.isDesignable() ||
       
  1131         prop1.isScriptable() != prop2.isScriptable() ||
       
  1132         prop1.isStored() != prop2.isStored() ||
       
  1133         prop1.isEditable() != prop2.isEditable() ||
       
  1134         prop1.isUser() != prop2.isUser() ||
       
  1135         prop1.isFlagType() != prop2.isFlagType() ||
       
  1136         prop1.isEnumType() != prop2.isEnumType() ||
       
  1137         prop1.hasNotifySignal() != prop2.hasNotifySignal() ||
       
  1138         prop1.hasStdCppSet() != prop2.hasStdCppSet())
       
  1139         return false;
       
  1140 
       
  1141     if (prop1.hasNotifySignal()) {
       
  1142         if (prop1.notifySignalIndex() != prop2.notifySignalIndex())
       
  1143             return false;
       
  1144     }
       
  1145 
       
  1146     return true;
       
  1147 }
       
  1148 
       
  1149 static bool sameEnumerator(const QMetaEnum& enum1, const QMetaEnum& enum2)
       
  1150 {
       
  1151     if (QByteArray(enum1.name()) != QByteArray(enum2.name()))
       
  1152         return false;
       
  1153 
       
  1154     if (enum1.isFlag() != enum2.isFlag())
       
  1155         return false;
       
  1156 
       
  1157     if (enum1.keyCount() != enum2.keyCount())
       
  1158         return false;
       
  1159 
       
  1160     for (int index = 0; index < enum1.keyCount(); ++index) {
       
  1161         if (QByteArray(enum1.key(index)) != QByteArray(enum2.key(index)))
       
  1162             return false;
       
  1163         if (enum1.value(index) != enum2.value(index))
       
  1164             return false;
       
  1165     }
       
  1166 
       
  1167     if (QByteArray(enum1.scope()) != QByteArray(enum2.scope()))
       
  1168         return false;
       
  1169 
       
  1170     return true;
       
  1171 }
       
  1172 
       
  1173 // Determine if two meta objects are identical.
       
  1174 bool tst_QMetaObjectBuilder::sameMetaObject
       
  1175         (const QMetaObject *meta1, const QMetaObject *meta2)
       
  1176 {
       
  1177     int index;
       
  1178 
       
  1179     if (strcmp(meta1->className(), meta2->className()) != 0)
       
  1180         return false;
       
  1181 
       
  1182     if (meta1->superClass() != meta2->superClass())
       
  1183         return false;
       
  1184 
       
  1185     if (meta1->constructorCount() != meta2->constructorCount() ||
       
  1186         meta1->methodCount() != meta2->methodCount() ||
       
  1187         meta1->enumeratorCount() != meta2->enumeratorCount() ||
       
  1188         meta1->propertyCount() != meta2->propertyCount() ||
       
  1189         meta1->classInfoCount() != meta2->classInfoCount())
       
  1190         return false;
       
  1191 
       
  1192     for (index = 0; index < meta1->constructorCount(); ++index) {
       
  1193         if (!sameMethod(meta1->constructor(index), meta2->constructor(index)))
       
  1194             return false;
       
  1195     }
       
  1196 
       
  1197     for (index = 0; index < meta1->methodCount(); ++index) {
       
  1198         if (!sameMethod(meta1->method(index), meta2->method(index)))
       
  1199             return false;
       
  1200     }
       
  1201 
       
  1202     for (index = 0; index < meta1->propertyCount(); ++index) {
       
  1203         if (!sameProperty(meta1->property(index), meta2->property(index)))
       
  1204             return false;
       
  1205     }
       
  1206 
       
  1207     for (index = 0; index < meta1->enumeratorCount(); ++index) {
       
  1208         if (!sameEnumerator(meta1->enumerator(index), meta2->enumerator(index)))
       
  1209             return false;
       
  1210     }
       
  1211 
       
  1212     for (index = 0; index < meta1->classInfoCount(); ++index) {
       
  1213         if (QByteArray(meta1->classInfo(index).name()) !=
       
  1214             QByteArray(meta2->classInfo(index).name()))
       
  1215             return false;
       
  1216         if (QByteArray(meta1->classInfo(index).value()) !=
       
  1217             QByteArray(meta2->classInfo(index).value()))
       
  1218             return false;
       
  1219     }
       
  1220 
       
  1221     const QMetaObject **objects1 = 0;
       
  1222     const QMetaObject **objects2 = 0;
       
  1223     if (meta1->d.data[0] == meta2->d.data[0] && meta1->d.data[0] >= 2) {
       
  1224         QMetaObjectExtraData *extra1 = (QMetaObjectExtraData *)(meta1->d.extradata);
       
  1225         QMetaObjectExtraData *extra2 = (QMetaObjectExtraData *)(meta2->d.extradata);
       
  1226         if (extra1 && !extra2)
       
  1227             return false;
       
  1228         if (extra2 && !extra1)
       
  1229             return false;
       
  1230         if (extra1 && extra2) {
       
  1231             if (extra1->static_metacall != extra2->static_metacall)
       
  1232                 return false;
       
  1233             objects1 = extra1->objects;
       
  1234             objects2 = extra1->objects;
       
  1235         }
       
  1236     } else if (meta1->d.data[0] == meta2->d.data[0] && meta1->d.data[0] == 1) {
       
  1237         objects1 = (const QMetaObject **)(meta1->d.extradata);
       
  1238         objects2 = (const QMetaObject **)(meta2->d.extradata);
       
  1239     }
       
  1240     if (objects1 && !objects2)
       
  1241         return false;
       
  1242     if (objects2 && !objects1)
       
  1243         return false;
       
  1244     if (objects1 && objects2) {
       
  1245         while (*objects1 != 0 && *objects2 != 0) {
       
  1246             if (*objects1 != *objects2)
       
  1247                 return false;
       
  1248             ++objects1;
       
  1249             ++objects2;
       
  1250         }
       
  1251     }
       
  1252 
       
  1253     return true;
       
  1254 }
       
  1255 
       
  1256 QTEST_MAIN(tst_QMetaObjectBuilder)
       
  1257 
       
  1258 #include "tst_qmetaobjectbuilder.moc"