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
28class tst_Basic : public QObject
29{
30 W_OBJECT(tst_Basic)
31
32 struct SubObject;
33
34private 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
83W_OBJECT_IMPL(tst_Basic)
84
85void tst_Basic::firstTest()
86{
87 QCOMPARE(metaObject()->className(), "tst_Basic");
88 QCOMPARE(metaObject()->superClass()->className(), "QObject");
89}
90
91
92class BTestObj : public QObject
93{ W_OBJECT(BTestObj)
94 W_CONSTRUCTOR()
95 QString value;
96public:
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
112public: /*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)
124public:
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
137W_OBJECT_IMPL(BTestObj)
138
139void tst_Basic::signalSlot_data()
140{
141 QTest::addColumn<bool>("old");
142 QTest::newRow("old") << true;
143 QTest::newRow("new") << false;
144}
145
146
147void 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
165void 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
175void 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
185void 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
193struct My {};
194
195class OverloadForm : public QObject
196{ W_OBJECT(OverloadForm)
197public:
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
205W_OBJECT_IMPL(OverloadForm)
206
207void 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
217void 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
225struct tst_Basic::SubObject : QObject {
226 W_OBJECT(SubObject)
227public:
228 void mySignal() W_SIGNAL(mySignal)
229};
230
231W_OBJECT_IMPL(tst_Basic::SubObject)
232
233void tst_Basic::subObject()
234{
235 QVERIFY(QMetaMethod::fromSignal(&tst_Basic::SubObject::mySignal).isValid());
236}
237
238class AbstractClass : public QObject {
239 W_OBJECT(AbstractClass)
240 int prop;
241 W_PROPERTY(int, prop MEMBER prop)
242
243public:
244 void mySignal() W_SIGNAL(mySignal)
245 virtual void pureSlot() = 0; W_SLOT(pureSlot)
246};
247W_OBJECT_IMPL(AbstractClass)
248
249class ConcreateClass : public AbstractClass {
250 W_OBJECT(ConcreateClass)
251 int prop2;
252 W_PROPERTY(int, prop2 MEMBER prop2)
253
254public:
255 void mySignal2() W_SIGNAL(mySignal2)
256 void pureSlot() override {}
257};
258W_OBJECT_IMPL(ConcreateClass)
259
260void 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
273namespace 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}
292W_NAMESPACE_IMPL(TestQNamespace)
293
294static 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
305void 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
343struct TestAccess : QObject {
344 W_OBJECT(TestAccess)
345
346public:
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)
351protected:
352 void protectedSlot(){} W_SLOT(protectedSlot)
353 void protectedMethod(){} W_INVOKABLE(protectedMethod)
354private:
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};
360W_OBJECT_IMPL(TestAccess)
361
362struct TestAccess2 final {
363 W_GADGET(TestAccess2)
364private:
365 void slot(int){} W_SLOT(slot, (int))
366public:
367 void slot(double){} W_SLOT(slot, (double))
368
369};
370W_GADGET_IMPL(TestAccess2)
371
372void 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
392void 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
405struct TestFinalObject final : public QObject {
406 W_OBJECT(TestFinalObject)
407public:
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};
413W_OBJECT_IMPL(TestFinalObject)
414
415struct TestFinalGadget final {
416 W_GADGET(TestFinalGadget)
417public:
418 int foo() { return 0;}
419 void setFoo(int) { }
420 W_PROPERTY(int, foo READ foo WRITE setFoo)
421};
422W_GADGET_IMPL(TestFinalGadget)
423
424void 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
441class OverloadedAddressOperator : public QObject
442{
443 W_OBJECT(OverloadedAddressOperator)
444public:
445 void* operator&() { return nullptr; }
446signals:
447 void self(OverloadedAddressOperator &s) W_SIGNAL(self, s)
448public slots:
449 void assertSelf(OverloadedAddressOperator &o)
450 {
451 QCOMPARE(std::addressof(o), this);
452 testResult = (std::addressof(o) == this);
453 }
454 W_SLOT(assertSelf)
455public:
456 bool testResult = false;
457};
458
459W_REGISTER_ARGTYPE(OverloadedAddressOperator&)
460
461W_OBJECT_IMPL(OverloadedAddressOperator)
462
463void 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
474QTEST_MAIN(tst_Basic)
475