1 | /**************************************************************************** |
2 | * Copyright (C) 2013-2015 Woboq GmbH |
3 | * Olivier Goffart <contact at woboq.com> |
4 | * https://woboq.com/ |
5 | * |
6 | * This program is free software: you can redistribute it and/or modify |
7 | * it under the terms of the GNU Lesser General Public License as |
8 | * published by the Free Software Foundation, either version 3 of the |
9 | * License, or (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this program. |
18 | * If not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | #include <wobjectdefs.h> |
21 | #include <QtCore/QObject> |
22 | #include <QtCore/QMetaObject> |
23 | |
24 | #include <QtWidgets/qgraphicsitem.h> // only for compilation check |
25 | |
26 | #include "anothertu.h" |
27 | |
28 | class tst_Basic : public QObject |
29 | { |
30 | W_OBJECT(tst_Basic) |
31 | |
32 | struct SubObject; |
33 | |
34 | private slots: |
35 | void firstTest(); |
36 | W_SLOT(firstTest, W_Access::Private) |
37 | |
38 | void signalSlot_data(); |
39 | W_SLOT(signalSlot_data, W_Access::Private) |
40 | void signalSlot(); |
41 | W_SLOT(signalSlot, W_Access::Private) |
42 | |
43 | void property_data(); |
44 | W_SLOT(property_data, W_Access::Private) |
45 | void property(); |
46 | W_SLOT(property, W_Access::Private) |
47 | |
48 | void signalArgs(); |
49 | W_SLOT(signalArgs, W_Access::Private) |
50 | |
51 | void overloadForm(); |
52 | W_SLOT(overloadForm,(), W_Access::Private) |
53 | |
54 | void enumBase(); |
55 | W_SLOT(enumBase, W_Access::Private) |
56 | |
57 | void subObject(); |
58 | W_SLOT(subObject, W_Access::Private) |
59 | |
60 | void abstractParent(); |
61 | W_SLOT(abstractParent, W_Access::Private) |
62 | |
63 | void testQNamespace(); |
64 | W_SLOT(testQNamespace, W_Access::Private) |
65 | |
66 | void testAccess(); |
67 | W_SLOT(testAccess, W_Access::Private) |
68 | |
69 | void testAnotherTU(); |
70 | W_SLOT(testAnotherTU, W_Access::Private) |
71 | |
72 | void testFinal(); |
73 | W_SLOT(testFinal, W_Access::Private) |
74 | |
75 | void overloadedAddressOperator(); |
76 | W_SLOT(overloadedAddressOperator, W_Access::Private) |
77 | }; |
78 | |
79 | #include <wobjectimpl.h> |
80 | |
81 | #include <QtTest/QtTest> |
82 | |
83 | W_OBJECT_IMPL(tst_Basic) |
84 | |
85 | void tst_Basic::firstTest() |
86 | { |
87 | QCOMPARE(metaObject()->className(), "tst_Basic" ); |
88 | QCOMPARE(metaObject()->superClass()->className(), "QObject" ); |
89 | } |
90 | |
91 | |
92 | class BTestObj : public QObject |
93 | { W_OBJECT(BTestObj) |
94 | W_CONSTRUCTOR() |
95 | QString value; |
96 | public: |
97 | void setValue(const QString &s) { value = s; emit valueChanged(s); } |
98 | W_SLOT(setValue) |
99 | |
100 | void resetValue() { value = QString(); } |
101 | W_SLOT(resetValue) |
102 | |
103 | QString getValue() const { return value; } |
104 | |
105 | enum XXX { X1, X2, X3 = 45 }; |
106 | W_ENUM(XXX, X1, X2, X3) |
107 | |
108 | void setValueNoex(const QString &s) noexcept { value = s; emit valueChanged(s); } |
109 | W_SLOT(setValueNoex) |
110 | QString getValueNoex() const noexcept { return value; } |
111 | |
112 | public: /*signals*/ |
113 | void valueChanged(const QString &s) |
114 | W_SIGNAL(valueChanged, s) |
115 | |
116 | void simpleSignal() |
117 | W_SIGNAL(simpleSignal) |
118 | |
119 | void signalSeveralArgs(int a, const QString &b, char * c = nullptr) |
120 | W_SIGNAL(signalSeveralArgs, a, b, c) |
121 | |
122 | void anotherSignal() |
123 | W_SIGNAL(anotherSignal) |
124 | public: |
125 | W_PROPERTY(QString, value1, &BTestObj::setValue, &BTestObj::getValue ) |
126 | QString member; |
127 | W_PROPERTY(QString, member1, &BTestObj::member) |
128 | W_PROPERTY(QString, all, &BTestObj::value, &BTestObj::setValue, &BTestObj::getValue) |
129 | |
130 | W_PROPERTY(QString, notify1 MEMBER member NOTIFY simpleSignal) |
131 | W_PROPERTY(QString, notify2 MEMBER member NOTIFY anotherSignal) |
132 | |
133 | W_PROPERTY(QString, valueNoex, &BTestObj::setValueNoex, &BTestObj::getValueNoex) |
134 | }; |
135 | |
136 | |
137 | W_OBJECT_IMPL(BTestObj) |
138 | |
139 | void tst_Basic::signalSlot_data() |
140 | { |
141 | QTest::addColumn<bool>("old" ); |
142 | QTest::newRow("old" ) << true; |
143 | QTest::newRow("new" ) << false; |
144 | } |
145 | |
146 | |
147 | void tst_Basic::signalSlot() |
148 | { |
149 | BTestObj obj1, obj2; |
150 | QFETCH(bool, old); |
151 | if (old) { |
152 | QVERIFY(connect(&obj1, SIGNAL(valueChanged(QString)), &obj2, SLOT(setValue(QString)))); |
153 | QVERIFY(connect(&obj1, SIGNAL(simpleSignal()), &obj2, SLOT(resetValue()))); |
154 | } else { |
155 | QVERIFY(connect(&obj1, &BTestObj::valueChanged, &obj2, &BTestObj::setValue)); |
156 | QVERIFY(connect(&obj1, &BTestObj::simpleSignal, &obj2, &BTestObj::resetValue)); |
157 | } |
158 | obj1.setValue("HOLLA" ); |
159 | QCOMPARE(obj2.getValue(), QString("HOLLA" )); |
160 | emit obj1.simpleSignal(); |
161 | QCOMPARE(obj2.getValue(), QString()); |
162 | } |
163 | |
164 | |
165 | void tst_Basic::property_data() |
166 | { |
167 | QTest::addColumn<QByteArray>("name" ); |
168 | QTest::newRow("value1" ) << QByteArrayLiteral("value1" ); |
169 | QTest::newRow("member1" ) << QByteArrayLiteral("member1" ); |
170 | QTest::newRow("all" ) << QByteArrayLiteral("all" ); |
171 | QTest::newRow("valueNoex" ) << QByteArrayLiteral("valueNoex" ); |
172 | } |
173 | |
174 | |
175 | void tst_Basic::property() |
176 | { |
177 | QFETCH(QByteArray, name); |
178 | |
179 | BTestObj obj; |
180 | QString str = "TRALAL" ; |
181 | QVERIFY(obj.setProperty(name, str)); |
182 | QCOMPARE(obj.property(name), QVariant(str)); |
183 | } |
184 | |
185 | void tst_Basic::signalArgs() |
186 | { |
187 | auto method = QMetaMethod::fromSignal(&BTestObj::signalSeveralArgs); |
188 | QCOMPARE(method.parameterTypes(), (QByteArrayList{ "int" , "QString" , "char*" })); |
189 | QCOMPARE(method.parameterNames(), (QByteArrayList{ "a" , "b" , "c" })); |
190 | } |
191 | |
192 | |
193 | struct My {}; |
194 | |
195 | class OverloadForm : public QObject |
196 | { W_OBJECT(OverloadForm) |
197 | public: |
198 | int over1(My, int x) { return x; } |
199 | W_SLOT(over1,(My,int)) |
200 | int over1() const { return 34; } |
201 | W_INVOKABLE(over1,()) |
202 | }; |
203 | |
204 | |
205 | W_OBJECT_IMPL(OverloadForm) |
206 | |
207 | void tst_Basic::overloadForm() |
208 | { |
209 | OverloadForm obj; |
210 | int result; |
211 | QVERIFY(QMetaObject::invokeMethod(&obj, "over1" , Q_RETURN_ARG(int, result), Q_ARG(My, {}), Q_ARG(int, 23))); |
212 | QCOMPARE(result, 23); |
213 | QVERIFY(QMetaObject::invokeMethod(&obj, "over1" , Q_RETURN_ARG(int, result))); |
214 | QCOMPARE(result, 34); |
215 | } |
216 | |
217 | void tst_Basic::enumBase() |
218 | { |
219 | QMetaEnum em = BTestObj::staticMetaObject.enumerator( |
220 | BTestObj::staticMetaObject.indexOfEnumerator("XXX" )); |
221 | QVERIFY(em.isValid()); |
222 | QCOMPARE(em.keyCount(), 3); |
223 | } |
224 | |
225 | struct tst_Basic::SubObject : QObject { |
226 | W_OBJECT(SubObject) |
227 | public: |
228 | void mySignal() W_SIGNAL(mySignal) |
229 | }; |
230 | |
231 | W_OBJECT_IMPL(tst_Basic::SubObject) |
232 | |
233 | void tst_Basic::subObject() |
234 | { |
235 | QVERIFY(QMetaMethod::fromSignal(&tst_Basic::SubObject::mySignal).isValid()); |
236 | } |
237 | |
238 | class AbstractClass : public QObject { |
239 | W_OBJECT(AbstractClass) |
240 | int prop; |
241 | W_PROPERTY(int, prop MEMBER prop) |
242 | |
243 | public: |
244 | void mySignal() W_SIGNAL(mySignal) |
245 | virtual void pureSlot() = 0; W_SLOT(pureSlot) |
246 | }; |
247 | W_OBJECT_IMPL(AbstractClass) |
248 | |
249 | class ConcreateClass : public AbstractClass { |
250 | W_OBJECT(ConcreateClass) |
251 | int prop2; |
252 | W_PROPERTY(int, prop2 MEMBER prop2) |
253 | |
254 | public: |
255 | void mySignal2() W_SIGNAL(mySignal2) |
256 | void pureSlot() override {} |
257 | }; |
258 | W_OBJECT_IMPL(ConcreateClass) |
259 | |
260 | void tst_Basic::abstractParent() |
261 | { |
262 | QVERIFY(QMetaMethod::fromSignal(&AbstractClass::mySignal).isValid()); |
263 | QVERIFY(QMetaMethod::fromSignal(&ConcreateClass::mySignal2).isValid()); |
264 | ConcreateClass cl; |
265 | AbstractClass *ab = &cl; |
266 | QCOMPARE(ab->metaObject()->superClass(), &AbstractClass::staticMetaObject); |
267 | QVERIFY(ab->setProperty("prop" , 8989)); |
268 | QCOMPARE(ab->property("prop" ), QVariant(8989)); |
269 | } |
270 | |
271 | |
272 | #ifdef Q_NAMESPACE // since Qt 5.8 |
273 | namespace TestQNamespace { |
274 | W_NAMESPACE(TestQNamespace) |
275 | enum TestEnum1 { |
276 | Key1 = 11, |
277 | Key2 |
278 | }; |
279 | W_ENUM_NS(TestEnum1, Key1, Key2) |
280 | |
281 | enum TestFlag1 { |
282 | None = 0, |
283 | Flag1 = 1, |
284 | Flag2 = 2, |
285 | Any = Flag1 | Flag2 |
286 | }; |
287 | W_FLAG_NS(TestFlag1, None, Flag1, Flag2, Any) |
288 | |
289 | W_CLASSINFO_NS("Foo" , "Bar" ) |
290 | |
291 | } |
292 | W_NAMESPACE_IMPL(TestQNamespace) |
293 | |
294 | static void checkEnum(const QMetaEnum &enumerator, const QByteArray &name, const QVector<QPair<QByteArray, int >> &keys) |
295 | { |
296 | QCOMPARE(name, QByteArray{enumerator.name()}); |
297 | QCOMPARE(keys.size(), enumerator.keyCount()); |
298 | for (int i = 0; i < enumerator.keyCount(); ++i) { |
299 | QCOMPARE(keys[i].first, QByteArray{enumerator.key(i)}); |
300 | QCOMPARE(keys[i].second, enumerator.value(i)); |
301 | } |
302 | } |
303 | #endif |
304 | |
305 | void tst_Basic::testQNamespace() |
306 | { |
307 | #ifdef Q_NAMESPACE |
308 | QCOMPARE(TestQNamespace::staticMetaObject.enumeratorCount(), 2); |
309 | checkEnum(TestQNamespace::staticMetaObject.enumerator(0), "TestEnum1" , |
310 | {{"Key1" , 11}, {"Key2" , 12}}); |
311 | checkEnum(TestQNamespace::staticMetaObject.enumerator(1), "TestFlag1" , |
312 | {{"None" , 0}, {"Flag1" , 1}, {"Flag2" , 2}, {"Any" , 1 | 2}}); |
313 | |
314 | QMetaEnum meta = QMetaEnum::fromType<TestQNamespace::TestEnum1>(); |
315 | QVERIFY(meta.isValid()); |
316 | QCOMPARE(meta.name(), "TestEnum1" ); |
317 | QCOMPARE(meta.enclosingMetaObject(), &TestQNamespace::staticMetaObject); |
318 | QCOMPARE(meta.keyCount(), 2); |
319 | |
320 | QCOMPARE(TestQNamespace::staticMetaObject.classInfoCount(), 1); |
321 | QMetaClassInfo info = TestQNamespace::staticMetaObject.classInfo(0); |
322 | QCOMPARE(info.name(), "Foo" ); |
323 | QCOMPARE(info.value(), "Bar" ); |
324 | QCOMPARE(info.enclosingMetaObject(), &TestQNamespace::staticMetaObject); |
325 | |
326 | QCOMPARE(TestQNamespace::staticMetaObject.className(), "TestQNamespace" ); |
327 | |
328 | QCOMPARE(AnotherTU::staticMetaObject.className(), "AnotherTU" ); |
329 | QCOMPARE(AnotherTU::staticMetaObject.enumeratorCount(), 1); |
330 | QCOMPARE(AnotherTU::staticMetaObject.enumerator(0).name(), "ATTestEnum" ); |
331 | QCOMPARE(QMetaEnum::fromType<AnotherTU::ATTestEnum>().name(), "ATTestEnum" ); |
332 | |
333 | #if defined (__cpp_inline_variables) && Q_CC_MSVC > 192000000 |
334 | QCOMPARE(Inline_NS::staticMetaObject.className(), "Inline_NS" ); |
335 | QCOMPARE(Inline_NS::staticMetaObject.enumeratorCount(), 1); |
336 | QCOMPARE(Inline_NS::staticMetaObject.enumerator(0).name(), "InlineEnum" ); |
337 | QCOMPARE(QMetaEnum::fromType<Inline_NS::InlineEnum>().name(), "InlineEnum" ); |
338 | #endif |
339 | #endif |
340 | } |
341 | |
342 | |
343 | struct TestAccess : QObject { |
344 | W_OBJECT(TestAccess) |
345 | |
346 | public: |
347 | void publicSlot(){} W_SLOT(publicSlot) |
348 | void publicMethod(){} W_INVOKABLE(publicMethod) |
349 | void forcePrivateSlot(){} W_SLOT(forcePrivateSlot, W_Access::Private) |
350 | void forcePrivateMethod(){} W_INVOKABLE(forcePrivateMethod, W_Access::Private) |
351 | protected: |
352 | void protectedSlot(){} W_SLOT(protectedSlot) |
353 | void protectedMethod(){} W_INVOKABLE(protectedMethod) |
354 | private: |
355 | void privateSlot(){} W_SLOT(privateSlot) |
356 | void privateMethod(){} W_INVOKABLE(privateMethod) |
357 | void forcePublicSlot(){} W_SLOT(forcePublicSlot, W_Access::Public) |
358 | void forcePublicMethod(){} W_INVOKABLE(forcePublicMethod, W_Access::Public) |
359 | }; |
360 | W_OBJECT_IMPL(TestAccess) |
361 | |
362 | struct TestAccess2 final { |
363 | W_GADGET(TestAccess2) |
364 | private: |
365 | void slot(int){} W_SLOT(slot, (int)) |
366 | public: |
367 | void slot(double){} W_SLOT(slot, (double)) |
368 | |
369 | }; |
370 | W_GADGET_IMPL(TestAccess2) |
371 | |
372 | void tst_Basic::testAccess() |
373 | { |
374 | auto mo = &TestAccess::staticMetaObject; |
375 | QCOMPARE(mo->method(mo->indexOfMethod("publicSlot()" )).access(), QMetaMethod::Public); |
376 | QCOMPARE(mo->method(mo->indexOfMethod("publicMethod()" )).access(), QMetaMethod::Public); |
377 | QCOMPARE(mo->method(mo->indexOfMethod("protectedSlot()" )).access(), QMetaMethod::Protected); |
378 | QCOMPARE(mo->method(mo->indexOfMethod("protectedMethod()" )).access(), QMetaMethod::Protected); |
379 | QCOMPARE(mo->method(mo->indexOfMethod("privateSlot()" )).access(), QMetaMethod::Private); |
380 | QCOMPARE(mo->method(mo->indexOfMethod("privateMethod()" )).access(), QMetaMethod::Private); |
381 | QCOMPARE(mo->method(mo->indexOfMethod("forcePublicSlot()" )).access(), QMetaMethod::Public); |
382 | QCOMPARE(mo->method(mo->indexOfMethod("forcePublicMethod()" )).access(), QMetaMethod::Public); |
383 | QCOMPARE(mo->method(mo->indexOfMethod("forcePrivateSlot()" )).access(), QMetaMethod::Private); |
384 | QCOMPARE(mo->method(mo->indexOfMethod("forcePrivateMethod()" )).access(), QMetaMethod::Private); |
385 | |
386 | auto mo2 = &TestAccess2::staticMetaObject; |
387 | QCOMPARE(mo2->method(mo2->indexOfMethod("slot(int)" )).access(), QMetaMethod::Private); |
388 | QCOMPARE(mo2->method(mo2->indexOfMethod("slot(double)" )).access(), QMetaMethod::Public); |
389 | |
390 | } |
391 | |
392 | void tst_Basic::testAnotherTU() |
393 | { |
394 | auto mo = &AnotherTU::Gaga::staticMetaObject; |
395 | QCOMPARE(mo->className(), "AnotherTU::Gaga" ); |
396 | |
397 | #if defined (__cpp_inline_variables) && Q_CC_MSVC > 192000000 |
398 | auto mo2 = &AnotherTU::InlineGadget::staticMetaObject; |
399 | QCOMPARE(mo2->className(), "AnotherTU::InlineGadget" ); |
400 | auto mo3 = &AnotherTU::InlineObject::staticMetaObject; |
401 | QCOMPARE(mo3->className(), "AnotherTU::InlineObject" ); |
402 | #endif |
403 | } |
404 | |
405 | struct TestFinalObject final : public QObject { |
406 | W_OBJECT(TestFinalObject) |
407 | public: |
408 | int foo() { return 0;} |
409 | void setFoo(int) { } |
410 | void fooChanged(int v) W_SIGNAL(fooChanged, v) |
411 | W_PROPERTY(int, foo READ foo WRITE setFoo NOTIFY fooChanged) |
412 | }; |
413 | W_OBJECT_IMPL(TestFinalObject) |
414 | |
415 | struct TestFinalGadget final { |
416 | W_GADGET(TestFinalGadget) |
417 | public: |
418 | int foo() { return 0;} |
419 | void setFoo(int) { } |
420 | W_PROPERTY(int, foo READ foo WRITE setFoo) |
421 | }; |
422 | W_GADGET_IMPL(TestFinalGadget) |
423 | |
424 | void tst_Basic::testFinal() |
425 | { |
426 | { |
427 | auto mo = &TestFinalObject::staticMetaObject; |
428 | QVERIFY(mo->property(mo->propertyOffset()).isFinal()); |
429 | } |
430 | { |
431 | auto mo = &TestFinalGadget::staticMetaObject; |
432 | QVERIFY(mo->property(mo->propertyOffset()).isFinal()); |
433 | } |
434 | { |
435 | // Don't put final by default |
436 | auto mo = &ConcreateClass::staticMetaObject; |
437 | QVERIFY(!mo->property(mo->propertyOffset()).isFinal()); |
438 | } |
439 | } |
440 | |
441 | class OverloadedAddressOperator : public QObject |
442 | { |
443 | W_OBJECT(OverloadedAddressOperator) |
444 | public: |
445 | void* operator&() { return nullptr; } |
446 | signals: |
447 | void self(OverloadedAddressOperator &s) W_SIGNAL(self, s) |
448 | public slots: |
449 | void assertSelf(OverloadedAddressOperator &o) |
450 | { |
451 | QCOMPARE(std::addressof(o), this); |
452 | testResult = (std::addressof(o) == this); |
453 | } |
454 | W_SLOT(assertSelf) |
455 | public: |
456 | bool testResult = false; |
457 | }; |
458 | |
459 | W_REGISTER_ARGTYPE(OverloadedAddressOperator&) |
460 | |
461 | W_OBJECT_IMPL(OverloadedAddressOperator) |
462 | |
463 | void tst_Basic::overloadedAddressOperator() |
464 | { |
465 | OverloadedAddressOperator o; |
466 | OverloadedAddressOperator *p = std::addressof(o); |
467 | QCOMPARE(&o, static_cast<void *>(nullptr)); |
468 | QVERIFY(p); |
469 | QObject::connect(p, &OverloadedAddressOperator::self, p, &OverloadedAddressOperator::assertSelf); |
470 | emit o.self(o); |
471 | QVERIFY(o.testResult); |
472 | } |
473 | |
474 | QTEST_MAIN(tst_Basic) |
475 | |