|
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" |