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

source code of qtbase/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp