summaryrefslogtreecommitdiffstats
path: root/tests/auto/tools/moc/tst_moc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/tools/moc/tst_moc.cpp')
-rw-r--r--tests/auto/tools/moc/tst_moc.cpp554
1 files changed, 442 insertions, 112 deletions
diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp
index 97575f5bb7..d24dfa11f7 100644
--- a/tests/auto/tools/moc/tst_moc.cpp
+++ b/tests/auto/tools/moc/tst_moc.cpp
@@ -1,15 +1,18 @@
// Copyright (C) 2020 The Qt Company Ltd.
// Copyright (C) 2020 Olivier Goffart <ogoffart@woboq.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QSignalSpy>
#include <stdio.h>
+#include <optional>
#include <qobject.h>
#include <qmetaobject.h>
#include <qjsondocument.h>
-#include <qversionnumber.h>
#include <qregularexpression.h>
+#include <qtyperevision.h>
+
+#include <private/qobject_p.h>
#include "using-namespaces.h"
#include "assign-namespace.h"
@@ -56,16 +59,69 @@
#include "fwdclass2.h"
#include "fwdclass3.h"
+#include "signal-with-default-arg.h"
+
+#include "qmlmacro.h"
+
+#include "tech-preview.h"
+
+using namespace Qt::StringLiterals;
+
#ifdef Q_MOC_RUN
// check that moc can parse these constructs, they are being used in Windows winsock2.h header
#define STRING_HASH_HASH(x) ("foo" ## x ## "bar")
const char *string_hash_hash = STRING_HASH_HASH("baz");
#endif
+#if defined(Q_MOC_RUN) || __cplusplus > 202002L
+/* Check that nested inline namespaces are at least not causing moc to break.
+ Check it even outside of C++20 mode as moc gets passed the wrong __cplusplus version
+ and also to increase coverage, given how few C++20 configurations exist in the CI at the time
+ of writing this comment.
+*/
+namespace A::inline B {}
+namespace A {
+ namespace B::inline C {}
+}
+#endif
+
+
+namespace TokenStartingWithNumber
+{
+Q_NAMESPACE
+
+#define FOR_EACH_ITEM( CALL ) \
+ CALL( EXAMPLE ) \
+ CALL( 123_EXAMPLE ) \
+ CALL( OTHER_EXAMPLE )
+
+enum FooItems
+{
+
+#define ENUM_ITEM(NAME, ...) FOO ## NAME,
+ FOR_EACH_ITEM( ENUM_ITEM )
+};
+
+Q_ENUM_NS(FooItems)
+}
+
Q_DECLARE_METATYPE(const QMetaObject*);
#define TESTEXPORTMACRO Q_DECL_EXPORT
+#if !defined(Q_MOC_RUN) && !defined(Q_NOREPLY)
+# define Q_NOREPLY
+#endif
+
+struct TagTest : QObject {
+ Q_OBJECT
+
+ Q_INVOKABLE Q_NOREPLY inline int test() {return 0;}
+public slots:
+ Q_NOREPLY virtual inline void pamOpen(int){}
+};
+
+
namespace TestNonQNamespace {
struct TestGadget {
@@ -83,6 +139,12 @@ public:
Key2
};
Q_ENUM(TestGEnum2)
+
+ enum TestGEnum3: quint8 {
+ Key1 = 23,
+ Key2
+ };
+ Q_ENUM(TestGEnum3)
};
}
@@ -101,6 +163,12 @@ namespace TestQNamespace {
};
Q_ENUM_NS(TestEnum2)
+ enum TestEnum3: qint8 {
+ Key1 = 23,
+ Key2
+ };
+ Q_ENUM_NS(TestEnum3)
+
// try to dizzy moc by adding a struct in between
struct TestGadget {
Q_GADGET
@@ -113,8 +181,13 @@ namespace TestQNamespace {
Key1 = 23,
Key2
};
+ enum TestGEnum3: qint16 {
+ Key1 = 33,
+ Key2
+ };
Q_ENUM(TestGEnum1)
Q_ENUM(TestGEnum2)
+ Q_ENUM(TestGEnum3)
};
struct TestGadgetExport {
@@ -131,6 +204,12 @@ namespace TestQNamespace {
Key2
};
Q_ENUM(TestGeEnum2)
+ enum TestGeEnum3: quint16 {
+ Key1 = 26,
+ Key2
+ };
+ Q_ENUM(TestGeEnum3)
+
};
enum class TestFlag1 {
@@ -150,6 +229,27 @@ namespace TestQNamespace {
Q_FLAG_NS(TestFlag2)
}
+namespace TestSameEnumNamespace {
+ Q_NAMESPACE
+
+ enum class TestSameEnumNamespace {
+ Key1 = 1,
+ Key2 = 2,
+ };
+ Q_ENUM_NS(TestSameEnumNamespace)
+}
+
+namespace TestNestedSameEnumNamespace {
+namespace a {
+ Q_NAMESPACE
+ // enum class with the same name as the enclosing nested namespace
+ enum class a {
+ Key11 = 11,
+ Key12 = 12,
+ };
+ Q_ENUM_NS(a)
+}
+}
namespace TestExportNamespace {
Q_NAMESPACE_EXPORT(TESTEXPORTMACRO)
@@ -180,6 +280,24 @@ public:
CreatableGadget creatableGadget; // Force the compiler to use the constructor
+struct ParentWithSignalWithArgument : QObject {
+ Q_OBJECT
+ Q_PROPERTY(int i READ i WRITE setI NOTIFY iChanged)
+
+public:
+ int i() const {return 0;}
+ void setI(int) {}
+
+signals:
+ void iChanged(int);
+};
+
+struct SignalWithArgumentInParent : ParentWithSignalWithArgument
+{
+ Q_OBJECT
+ Q_PROPERTY(int otherI READ i WRITE setI NOTIFY iChanged)
+};
+
struct MyStruct {};
struct MyStruct2 {};
@@ -564,6 +682,10 @@ private slots:
QT_WARNING_POP
+// quick test to verify that moc handles the L suffix
+// correctly in the preprocessor
+#if 2000L < 1
+#else
class PropertyTestClass : public QObject
{
Q_OBJECT
@@ -573,6 +695,7 @@ public:
Q_ENUM(TestEnum)
};
+#endif
class PropertyUseClass : public QObject
{
@@ -691,6 +814,7 @@ private slots:
void templateGtGt();
void qprivateslots();
void qprivateproperties();
+ void anonymousProperties();
void warnOnPropertyWithoutREAD();
void constructors();
void typenameWithUnsigned();
@@ -735,6 +859,7 @@ private slots:
void optionsFileError_data();
void optionsFileError();
void testQNamespace();
+ void testNestedQNamespace();
void cxx17Namespaces();
void cxxAttributes();
void mocJsonOutput();
@@ -744,7 +869,10 @@ private slots:
void observerMetaCall();
void setQPRopertyBinding();
void privateQPropertyShim();
- void readThroughBindable();
+ void readWriteThroughBindable();
+ void invokableCtors();
+ void virtualInlineTaggedSlot();
+ void tokenStartingWithNumber();
signals:
void sigWithUnsignedArg(unsigned foo);
@@ -756,6 +884,7 @@ signals:
void constSignal2(int arg) const;
void member4Changed();
void member5Changed(const QString &newVal);
+ void sigWithDefaultArg(int i = 12);
private:
bool user1() { return true; };
@@ -781,6 +910,14 @@ private:
};
+#define VERIFY_NO_ERRORS(proc) do { \
+ auto &&p = proc; \
+ const QByteArray stderr = p.readAllStandardError(); \
+ QVERIFY2(stderr.isEmpty(), stderr.data()); \
+ QCOMPARE(p.exitCode(), 0); \
+ } while (false)
+
+
void tst_Moc::initTestCase()
{
QString binpath = QLibraryInfo::path(QLibraryInfo::BinariesPath);
@@ -795,10 +932,9 @@ void tst_Moc::initTestCase()
QProcess proc;
proc.start(qtpaths, QStringList() << "-query" << "QT_INSTALL_HEADERS");
QVERIFY(proc.waitForFinished());
- QCOMPARE(proc.exitCode(), 0);
+ VERIFY_NO_ERRORS(proc);
QByteArray output = proc.readAllStandardOutput();
QVERIFY(!output.isEmpty());
- QCOMPARE(proc.readAllStandardError(), QByteArray());
qtIncludePath = QString::fromLocal8Bit(output).trimmed();
QFileInfo fi(qtIncludePath);
QVERIFY(fi.exists());
@@ -833,10 +969,9 @@ void tst_Moc::oldStyleCasts()
QProcess proc;
proc.start(m_moc, QStringList(m_sourceDirectory + QStringLiteral("/oldstyle-casts.h")));
QVERIFY(proc.waitForFinished());
- QCOMPARE(proc.exitCode(), 0);
+ VERIFY_NO_ERRORS(proc);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
- QCOMPARE(proc.readAllStandardError(), QByteArray());
QStringList args;
args << "-c" << "-x" << "c++" << "-Wold-style-cast" << "-I" << "."
@@ -847,8 +982,7 @@ void tst_Moc::oldStyleCasts()
proc.closeWriteChannel();
QVERIFY(proc.waitForFinished());
- QCOMPARE(QString::fromLocal8Bit(proc.readAllStandardError()), QString());
- QCOMPARE(proc.exitCode(), 0);
+ VERIFY_NO_ERRORS(proc);
#else
QSKIP("Only tested on linux/gcc");
#endif
@@ -905,10 +1039,9 @@ void tst_Moc::inputFileNameWithDotsButNoExtension()
proc.setWorkingDirectory(m_sourceDirectory + QStringLiteral("/task71021"));
proc.start(m_moc, QStringList("../Header"));
QVERIFY(proc.waitForFinished());
- QCOMPARE(proc.exitCode(), 0);
+ VERIFY_NO_ERRORS(proc);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
- QCOMPARE(proc.readAllStandardError(), QByteArray());
QStringList args;
args << "-c" << "-x" << "c++" << "-I" << ".."
@@ -919,8 +1052,7 @@ void tst_Moc::inputFileNameWithDotsButNoExtension()
proc.closeWriteChannel();
QVERIFY(proc.waitForFinished());
- QCOMPARE(QString::fromLocal8Bit(proc.readAllStandardError()), QString());
- QCOMPARE(proc.exitCode(), 0);
+ VERIFY_NO_ERRORS(proc);
#else
QSKIP("Only tested on linux/gcc");
#endif
@@ -943,12 +1075,12 @@ void tst_Moc::supportConstSignals()
QSignalSpy spy1(this, SIGNAL(constSignal1()));
QVERIFY(spy1.isEmpty());
emit constSignal1();
- QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy1.size(), 1);
QSignalSpy spy2(this, SIGNAL(constSignal2(int)));
QVERIFY(spy2.isEmpty());
emit constSignal2(42);
- QCOMPARE(spy2.count(), 1);
+ QCOMPARE(spy2.size(), 1);
QCOMPARE(spy2.at(0).at(0).toInt(), 42);
}
@@ -1197,11 +1329,7 @@ void tst_Moc::ignoreOptionClashes()
if (!finished)
qWarning("waitForFinished failed. QProcess error: %d", (int)proc.error());
QVERIFY(finished);
- if (proc.exitCode() != 0) {
- qDebug() << proc.readAllStandardError();
- }
- QCOMPARE(proc.exitCode(), 0);
- QCOMPARE(proc.readAllStandardError(), QByteArray());
+ VERIFY_NO_ERRORS(proc);
QByteArray mocOut = proc.readAllStandardOutput();
// If -pthread wasn't ignored, it was parsed as a prefix of "thread/", which breaks compilation.
@@ -1215,7 +1343,7 @@ void tst_Moc::ignoreOptionClashes()
proc.closeWriteChannel();
QVERIFY(proc.waitForFinished());
- QCOMPARE(QString::fromLocal8Bit(proc.readAllStandardError()), QString());
+ VERIFY_NO_ERRORS(proc);
#else
QSKIP("Only tested on linux/gcc");
#endif
@@ -1320,11 +1448,7 @@ void tst_Moc::frameworkSearchPath()
if (!finished)
qWarning("waitForFinished failed. QProcess error: %d", (int)proc.error());
QVERIFY(finished);
- if (proc.exitCode() != 0) {
- qDebug() << proc.readAllStandardError();
- }
- QCOMPARE(proc.exitCode(), 0);
- QCOMPARE(proc.readAllStandardError(), QByteArray());
+ VERIFY_NO_ERRORS(proc);
#else
QSKIP("Only tested/relevant on unixy platforms");
#endif
@@ -1356,11 +1480,9 @@ void tst_Moc::templateGtGt()
QProcess proc;
proc.start(m_moc, QStringList(m_sourceDirectory + QStringLiteral("/template-gtgt.h")));
QVERIFY(proc.waitForFinished());
- QCOMPARE(proc.exitCode(), 0);
+ VERIFY_NO_ERRORS(proc);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
- QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
- QVERIFY(mocWarning.isEmpty());
#else
QSKIP("Only tested on unix/gcc");
#endif
@@ -1377,8 +1499,7 @@ void tst_Moc::defineMacroViaCmdline()
proc.start(m_moc, args);
QVERIFY(proc.waitForFinished());
- QCOMPARE(proc.exitCode(), 0);
- QCOMPARE(proc.readAllStandardError(), QByteArray());
+ VERIFY_NO_ERRORS(proc);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
#else
@@ -1397,8 +1518,7 @@ void tst_Moc::defineMacroViaForcedInclude()
proc.start(m_moc, args);
QVERIFY(proc.waitForFinished());
- QCOMPARE(proc.exitCode(), 0);
- QCOMPARE(proc.readAllStandardError(), QByteArray());
+ VERIFY_NO_ERRORS(proc);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
#else
@@ -1417,8 +1537,7 @@ void tst_Moc::defineMacroViaForcedIncludeRelative()
proc.start(m_moc, args);
QVERIFY(proc.waitForFinished());
- QCOMPARE(proc.exitCode(), 0);
- QCOMPARE(proc.readAllStandardError(), QByteArray());
+ VERIFY_NO_ERRORS(proc);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
#else
@@ -1463,8 +1582,7 @@ void tst_Moc::environmentIncludePaths()
proc.setProcessEnvironment(env);
proc.start(m_moc, args);
QVERIFY(proc.waitForFinished());
- QCOMPARE(proc.exitCode(), 0);
- QCOMPARE(proc.readAllStandardError(), QByteArray());
+ VERIFY_NO_ERRORS(proc);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
#else
@@ -1487,7 +1605,8 @@ public:
static StaticPluginInstance staticInstance;
void tst_Moc::specifyMetaTagsFromCmdline() {
- foreach (const QStaticPlugin &plugin, QPluginLoader::staticPlugins()) {
+ const auto staticPlugins = QPluginLoader::staticPlugins();
+ for (const QStaticPlugin &plugin : staticPlugins) {
const QString iid = plugin.metaData().value(QLatin1String("IID")).toString();
if (iid == QLatin1String("test.meta.tags")) {
const QJsonArray metaTagsUriList = plugin.metaData().value("uri").toArray();
@@ -1505,41 +1624,43 @@ void tst_Moc::specifyMetaTagsFromCmdline() {
void tst_Moc::invokable()
{
+ const int fooIndex = 4;
{
const QMetaObject &mobj = InvokableBeforeReturnType::staticMetaObject;
- QCOMPARE(mobj.methodCount(), 6);
- QCOMPARE(mobj.method(5).methodSignature(), QByteArray("foo()"));
+ QCOMPARE(mobj.methodCount(), 5);
+ QCOMPARE(mobj.method(fooIndex).methodSignature(), QByteArray("foo()"));
}
{
const QMetaObject &mobj = InvokableBeforeInline::staticMetaObject;
- QCOMPARE(mobj.methodCount(), 7);
- QCOMPARE(mobj.method(5).methodSignature(), QByteArray("foo()"));
- QCOMPARE(mobj.method(6).methodSignature(), QByteArray("bar()"));
+ QCOMPARE(mobj.methodCount(), 6);
+ QCOMPARE(mobj.method(fooIndex).methodSignature(), QByteArray("foo()"));
+ QCOMPARE(mobj.method(fooIndex + 1).methodSignature(), QByteArray("bar()"));
}
}
void tst_Moc::singleFunctionKeywordSignalAndSlot()
{
+ const int mySignalIndex = 4;
{
const QMetaObject &mobj = SingleFunctionKeywordBeforeReturnType::staticMetaObject;
- QCOMPARE(mobj.methodCount(), 7);
- QCOMPARE(mobj.method(5).methodSignature(), QByteArray("mySignal()"));
- QCOMPARE(mobj.method(6).methodSignature(), QByteArray("mySlot()"));
+ QCOMPARE(mobj.methodCount(), 6);
+ QCOMPARE(mobj.method(mySignalIndex).methodSignature(), QByteArray("mySignal()"));
+ QCOMPARE(mobj.method(mySignalIndex + 1).methodSignature(), QByteArray("mySlot()"));
}
{
const QMetaObject &mobj = SingleFunctionKeywordBeforeInline::staticMetaObject;
- QCOMPARE(mobj.methodCount(), 7);
- QCOMPARE(mobj.method(5).methodSignature(), QByteArray("mySignal()"));
- QCOMPARE(mobj.method(6).methodSignature(), QByteArray("mySlot()"));
+ QCOMPARE(mobj.methodCount(), 6);
+ QCOMPARE(mobj.method(mySignalIndex).methodSignature(), QByteArray("mySignal()"));
+ QCOMPARE(mobj.method(mySignalIndex + 1).methodSignature(), QByteArray("mySlot()"));
}
{
const QMetaObject &mobj = SingleFunctionKeywordAfterInline::staticMetaObject;
- QCOMPARE(mobj.methodCount(), 7);
- QCOMPARE(mobj.method(5).methodSignature(), QByteArray("mySignal()"));
- QCOMPARE(mobj.method(6).methodSignature(), QByteArray("mySlot()"));
+ QCOMPARE(mobj.methodCount(), 6);
+ QCOMPARE(mobj.method(mySignalIndex).methodSignature(), QByteArray("mySignal()"));
+ QCOMPARE(mobj.method(mySignalIndex + 1).methodSignature(), QByteArray("mySlot()"));
}
}
@@ -1627,6 +1748,54 @@ void tst_Moc::qprivateproperties()
QVERIFY(zapBindable.isBindable());
}
+
+class AnonymousPropertyTest1 : public QObject
+{
+ Q_OBJECT
+ QT_ANONYMOUS_PROPERTY(int READ foo WRITE setFoo)
+public:
+ int foo() { return mFoo ; }
+ void setFoo(int value) { mFoo = value; }
+
+private:
+ int mFoo = 0;
+};
+
+class AnonymousPropertyTest2 : public QObject
+{
+ Q_OBJECT
+ QT_ANONYMOUS_PRIVATE_PROPERTY(d, int READ bar WRITE setBar)
+
+ class MyDPointer {
+ public:
+ int bar() { return mBar ; }
+ void setBar(int value) { mBar = value; }
+ private:
+ int mBar = 0;
+ };
+
+public:
+ AnonymousPropertyTest2(QObject *parent = nullptr) : QObject(parent), d (new MyDPointer) {}
+ MyDPointer *d_func() {return d.data();}
+ const MyDPointer *d_func() const {return d.data();}
+
+private:
+ QScopedPointer<MyDPointer> d;
+};
+
+void tst_Moc::anonymousProperties()
+{
+ AnonymousPropertyTest1 test1;
+
+ test1.setProperty("", 17);
+ QCOMPARE(test1.property(""), QVariant::fromValue(17));
+
+ AnonymousPropertyTest2 test2;
+
+ test2.setProperty("", 27);
+ QCOMPARE(test2.property(""), QVariant::fromValue(27));
+}
+
void tst_Moc::warnOnPropertyWithoutREAD()
{
#ifdef MOC_CROSS_COMPILED
@@ -1871,11 +2040,10 @@ void tst_Moc::notifyError()
const QString header = m_sourceDirectory + QStringLiteral("/error-on-wrong-notify.h");
proc.start(m_moc, QStringList(header));
QVERIFY(proc.waitForFinished());
- QCOMPARE(proc.exitCode(), 0);
+ VERIFY_NO_ERRORS(proc);
QCOMPARE(proc.exitStatus(), QProcess::NormalExit);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
- QCOMPARE(proc.readAllStandardError(), QByteArray());
QStringList args;
args << "-c" << "-x" << "c++" << "-I" << "."
@@ -2093,7 +2261,7 @@ void tst_Moc::warnings_data()
<< QStringList()
<< 0
<< QString()
- << QString("standard input:0:1: note: No relevant classes found. No output generated.");
+ << QString("standard input: note: No relevant classes found. No output generated.");
// passing "-nn" should suppress "no relevant classes" note
QTest::newRow("-nn")
@@ -2235,7 +2403,7 @@ void tst_Moc::warnings_data()
<< QStringList()
<< 1
<< QString("IGNORE_ALL_STDOUT")
- << QString(":-1:1: error: Unexpected character in macro argument list.");
+ << QString(": error: Unexpected character in macro argument list.");
QTest::newRow("Missing header warning")
<< QByteArray("class X : public QObject { Q_OBJECT };")
@@ -2282,6 +2450,13 @@ void tst_Moc::warnings_data()
<< QString()
<< QString("standard input:3:1: error: Parse error at \"decltype\"");
+ QTest::newRow("QTBUG-36367: report correct error location")
+ << "class X { \n Q_PROPERTY(Foo* foo NONSENSE foo) \n };"_ba
+ << QStringList()
+ << 1
+ << QString()
+ << u"standard input:2:1: error: Parse error at \"NONSENSE\""_s;
+
#ifdef Q_OS_UNIX // Limit to Unix because the error message is platform-dependent
QTest::newRow("Q_PLUGIN_METADATA: unreadable file")
<< QByteArray("class X { \n Q_PLUGIN_METADATA(FILE \".\") \n };")
@@ -2362,23 +2537,29 @@ void tst_Moc::cxx11Enums_data()
QTest::addColumn<QByteArray>("enumName");
QTest::addColumn<char>("prefix");
QTest::addColumn<bool>("isScoped");
+ QTest::addColumn<bool>("isTyped");
const QMetaObject *meta1 = &CXX11Enums::staticMetaObject;
const QMetaObject *meta2 = &CXX11Enums2::staticMetaObject;
-
- QTest::newRow("EnumClass") << meta1 << QByteArray("EnumClass") << QByteArray("EnumClass") << 'A' << true;
- QTest::newRow("EnumClass 2") << meta2 << QByteArray("EnumClass") << QByteArray("EnumClass") << 'A' << true;
- QTest::newRow("TypedEnum") << meta1 << QByteArray("TypedEnum") << QByteArray("TypedEnum") << 'B' << false;
- QTest::newRow("TypedEnum 2") << meta2 << QByteArray("TypedEnum") << QByteArray("TypedEnum") << 'B' << false;
- QTest::newRow("TypedEnumClass") << meta1 << QByteArray("TypedEnumClass") << QByteArray("TypedEnumClass") << 'C' << true;
- QTest::newRow("TypedEnumClass 2") << meta2 << QByteArray("TypedEnumClass") << QByteArray("TypedEnumClass") << 'C' << true;
- QTest::newRow("NormalEnum") << meta1 << QByteArray("NormalEnum") << QByteArray("NormalEnum") << 'D' << false;
- QTest::newRow("NormalEnum 2") << meta2 << QByteArray("NormalEnum") << QByteArray("NormalEnum") << 'D' << false;
- QTest::newRow("ClassFlags") << meta1 << QByteArray("ClassFlags") << QByteArray("ClassFlag") << 'F' << true;
- QTest::newRow("ClassFlags 2") << meta2 << QByteArray("ClassFlags") << QByteArray("ClassFlag") << 'F' << true;
- QTest::newRow("EnumStruct") << meta1 << QByteArray("EnumStruct") << QByteArray("EnumStruct") << 'G' << true;
- QTest::newRow("TypedEnumStruct") << meta1 << QByteArray("TypedEnumStruct") << QByteArray("TypedEnumStruct") << 'H' << true;
- QTest::newRow("StructFlags") << meta1 << QByteArray("StructFlags") << QByteArray("StructFlag") << 'I' << true;
+ const QMetaObject *meta3 = &CXX11Enums3::staticMetaObject;
+
+ QTest::newRow("EnumClass") << meta1 << QByteArray("EnumClass") << QByteArray("EnumClass") << 'A' << true << false;
+ QTest::newRow("EnumClass 2") << meta2 << QByteArray("EnumClass") << QByteArray("EnumClass") << 'A' << true << false;
+ QTest::newRow("EnumClass 3") << meta3 << QByteArray("EnumClass") << QByteArray("EnumClass") << 'A' << true << false;
+ QTest::newRow("TypedEnum") << meta1 << QByteArray("TypedEnum") << QByteArray("TypedEnum") << 'B' << false << true;
+ QTest::newRow("TypedEnum 2") << meta2 << QByteArray("TypedEnum") << QByteArray("TypedEnum") << 'B' << false << true;
+ QTest::newRow("TypedEnum 3") << meta3 << QByteArray("TypedEnum") << QByteArray("TypedEnum") << 'B' << false << true;
+ QTest::newRow("TypedEnumClass") << meta1 << QByteArray("TypedEnumClass") << QByteArray("TypedEnumClass") << 'C' << true << true;
+ QTest::newRow("TypedEnumClass 2") << meta2 << QByteArray("TypedEnumClass") << QByteArray("TypedEnumClass") << 'C' << true << true;
+ QTest::newRow("TypedEnumClass 3") << meta3 << QByteArray("TypedEnumClass") << QByteArray("TypedEnumClass") << 'C' << true << true;
+ QTest::newRow("NormalEnum") << meta1 << QByteArray("NormalEnum") << QByteArray("NormalEnum") << 'D' << false << false;
+ QTest::newRow("NormalEnum 2") << meta2 << QByteArray("NormalEnum") << QByteArray("NormalEnum") << 'D' << false << false;
+ QTest::newRow("NormalEnum 3") << meta3 << QByteArray("NormalEnum") << QByteArray("NormalEnum") << 'D' << false << false;
+ QTest::newRow("ClassFlags") << meta1 << QByteArray("ClassFlags") << QByteArray("ClassFlag") << 'F' << true << false;
+ QTest::newRow("ClassFlags 2") << meta2 << QByteArray("ClassFlags") << QByteArray("ClassFlag") << 'F' << true << false;
+ QTest::newRow("EnumStruct") << meta1 << QByteArray("EnumStruct") << QByteArray("EnumStruct") << 'G' << true << false;
+ QTest::newRow("TypedEnumStruct") << meta1 << QByteArray("TypedEnumStruct") << QByteArray("TypedEnumStruct") << 'H' << true << true;
+ QTest::newRow("StructFlags") << meta1 << QByteArray("StructFlags") << QByteArray("StructFlag") << 'I' << true << false;
}
void tst_Moc::cxx11Enums()
@@ -2390,24 +2571,39 @@ void tst_Moc::cxx11Enums()
QFETCH(QByteArray, enumName);
QFETCH(char, prefix);
QFETCH(bool, isScoped);
+ QFETCH(bool, isTyped);
int idx = meta->indexOfEnumerator(typeName);
QVERIFY(idx != -1);
QCOMPARE(meta->indexOfEnumerator(enumName), idx);
- QCOMPARE(meta->enumerator(idx).enclosingMetaObject(), meta);
- QCOMPARE(meta->enumerator(idx).isValid(), true);
- QCOMPARE(meta->enumerator(idx).keyCount(), 4);
- QCOMPARE(meta->enumerator(idx).name(), typeName.constData());
- QCOMPARE(meta->enumerator(idx).enumName(), enumName.constData());
- bool isFlag = meta->enumerator(idx).isFlag();
+ const QMetaEnum metaEnum = meta->enumerator(idx);
+ QCOMPARE(metaEnum.enclosingMetaObject(), meta);
+ QCOMPARE(metaEnum.isValid(), true);
+ QCOMPARE(metaEnum.keyCount(), 4);
+ QCOMPARE(metaEnum.name(), typeName.constData());
+ QCOMPARE(metaEnum.enumName(), enumName.constData());
+
+ const QMetaType metaType = metaEnum.metaType();
+ const bool isUnsigned = metaType.flags() & QMetaType::IsUnsignedEnumeration;
+ if (isTyped) {
+ QCOMPARE(size_t(metaType.sizeOf()), sizeof(char));
+ QCOMPARE(isUnsigned, !std::is_signed_v<char>);
+ } else if (isScoped) {
+ QCOMPARE(size_t(metaType.sizeOf()), sizeof(int));
+ QCOMPARE(isUnsigned, !std::is_signed_v<int>);
+ } else {
+ // underlying type is implementation defined
+ }
+
+ bool isFlag = metaEnum.isFlag();
for (int i = 0; i < 4; i++) {
QByteArray v = prefix + QByteArray::number(i);
const int value = isFlag ? (1 << i) : i;
- QCOMPARE(meta->enumerator(idx).keyToValue(v), value);
- QCOMPARE(meta->enumerator(idx).valueToKey(value), v.constData());
+ QCOMPARE(metaEnum.keyToValue(v), value);
+ QCOMPARE(metaEnum.valueToKey(value), v.constData());
}
- QCOMPARE(meta->enumerator(idx).isScoped(), isScoped);
+ QCOMPARE(metaEnum.isScoped(), isScoped);
}
void tst_Moc::cxx11TrailingReturn()
@@ -2502,7 +2698,7 @@ void tst_Moc::memberProperties()
if (!signal.isEmpty())
{
- QCOMPARE(notifySpy.count(), 1);
+ QCOMPARE(notifySpy.size(), 1);
if (prop.notifySignal().parameterNames().size() > 0) {
QList<QVariant> arguments = notifySpy.takeFirst();
QCOMPARE(arguments.size(), 1);
@@ -2512,7 +2708,7 @@ void tst_Moc::memberProperties()
notifySpy.clear();
// a second write with the same value should not cause the signal to be emitted again
QCOMPARE(prop.write(pObj, writeValue), expectedWriteResult);
- QCOMPARE(notifySpy.count(), 0);
+ QCOMPARE(notifySpy.size(), 0);
}
}
@@ -3592,10 +3788,9 @@ void tst_Moc::preprocessorOnly()
QProcess proc;
proc.start(m_moc, QStringList() << "-E" << m_sourceDirectory + QStringLiteral("/pp-dollar-signs.h"));
QVERIFY(proc.waitForFinished());
- QCOMPARE(proc.exitCode(), 0);
+ VERIFY_NO_ERRORS(proc);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
- QCOMPARE(proc.readAllStandardError(), QByteArray());
QVERIFY(mocOut.contains("$$ = parser->createFoo()"));
#else
@@ -3746,7 +3941,7 @@ void tst_Moc::relatedMetaObjectsNameConflict()
{
typedef QList<const QMetaObject *> QMetaObjects;
QFETCH(const QMetaObject*, dependingObject);
- QFETCH(QMetaObjects, relatedMetaObjects);
+ QFETCH(const QMetaObjects, relatedMetaObjects);
// load all specified metaobjects int a set
QSet<const QMetaObject*> dependency;
@@ -3757,7 +3952,7 @@ void tst_Moc::relatedMetaObjectsNameConflict()
}
// check if all required metaobjects are specified
- foreach (const QMetaObject *mo, relatedMetaObjects)
+ for (const QMetaObject *mo : relatedMetaObjects)
QVERIFY(dependency.contains(mo));
// check if no additional metaobjects ara specified
@@ -3928,10 +4123,12 @@ void tst_Moc::optionsFileError()
}
static void checkEnum(const QMetaEnum &enumerator, const QByteArray &name,
- const QList<QPair<QByteArray, int>> &keys)
+ const QList<QPair<QByteArray, int>> &keys,
+ const QMetaType underlyingType = QMetaType::fromType<int>())
{
QCOMPARE(name, QByteArray{enumerator.name()});
QCOMPARE(keys.size(), enumerator.keyCount());
+ QCOMPARE(underlyingType, enumerator.metaType().underlyingType());
for (int i = 0; i < enumerator.keyCount(); ++i) {
QCOMPARE(keys[i].first, QByteArray{enumerator.key(i)});
QCOMPARE(keys[i].second, enumerator.value(i));
@@ -3946,29 +4143,57 @@ public:
FooNamespace::Enum1 prop() { return FooNamespace::Enum1::Key2; }
};
+void tst_Moc::testNestedQNamespace()
+{
+ QCOMPARE(TestSameEnumNamespace::staticMetaObject.enumeratorCount(), 1);
+ checkEnum(TestSameEnumNamespace::staticMetaObject.enumerator(0), "TestSameEnumNamespace",
+ {{"Key1", 1}, {"Key2", 2}});
+ QMetaEnum meta1 = QMetaEnum::fromType<TestSameEnumNamespace::TestSameEnumNamespace>();
+ QVERIFY(meta1.isValid());
+ QCOMPARE(meta1.name(), "TestSameEnumNamespace");
+ QCOMPARE(meta1.enclosingMetaObject(), &TestSameEnumNamespace::staticMetaObject);
+ QCOMPARE(meta1.keyCount(), 2);
+
+ // QTBUG-112996
+ QCOMPARE(TestNestedSameEnumNamespace::a::staticMetaObject.enumeratorCount(), 1);
+ checkEnum(TestNestedSameEnumNamespace::a::staticMetaObject.enumerator(0), "a",
+ {{"Key11", 11}, {"Key12", 12}});
+ QMetaEnum meta2 = QMetaEnum::fromType<TestNestedSameEnumNamespace::a::a>();
+ QVERIFY(meta2.isValid());
+ QCOMPARE(meta2.name(), "a");
+ QCOMPARE(meta2.enclosingMetaObject(), &TestNestedSameEnumNamespace::a::staticMetaObject);
+ QCOMPARE(meta2.keyCount(), 2);
+}
+
void tst_Moc::testQNamespace()
{
- QCOMPARE(TestQNamespace::staticMetaObject.enumeratorCount(), 4);
+ QCOMPARE(TestQNamespace::staticMetaObject.enumeratorCount(), 5);
checkEnum(TestQNamespace::staticMetaObject.enumerator(0), "TestEnum1",
{{"Key1", 11}, {"Key2", 12}});
checkEnum(TestQNamespace::staticMetaObject.enumerator(1), "TestEnum2",
{{"Key1", 17}, {"Key2", 18}});
- checkEnum(TestQNamespace::staticMetaObject.enumerator(2), "TestFlag1",
+ checkEnum(TestQNamespace::staticMetaObject.enumerator(2), "TestEnum3",
+ {{"Key1", 23}, {"Key2", 24}}, QMetaType::fromType<qint8>());
+ checkEnum(TestQNamespace::staticMetaObject.enumerator(3), "TestFlag1",
{{"None", 0}, {"Flag1", 1}, {"Flag2", 2}, {"Any", 1 | 2}});
- checkEnum(TestQNamespace::staticMetaObject.enumerator(3), "TestFlag2",
+ checkEnum(TestQNamespace::staticMetaObject.enumerator(4), "TestFlag2",
{{"None", 0}, {"Flag1", 4}, {"Flag2", 8}, {"Any", 4 | 8}});
- QCOMPARE(TestQNamespace::TestGadget::staticMetaObject.enumeratorCount(), 2);
+ QCOMPARE(TestQNamespace::TestGadget::staticMetaObject.enumeratorCount(), 3);
checkEnum(TestQNamespace::TestGadget::staticMetaObject.enumerator(0), "TestGEnum1",
{{"Key1", 13}, {"Key2", 14}});
checkEnum(TestQNamespace::TestGadget::staticMetaObject.enumerator(1), "TestGEnum2",
{{"Key1", 23}, {"Key2", 24}});
+ checkEnum(TestQNamespace::TestGadget::staticMetaObject.enumerator(2), "TestGEnum3",
+ {{"Key1", 33}, {"Key2", 34}}, QMetaType::fromType<qint16>());
- QCOMPARE(TestQNamespace::TestGadgetExport::staticMetaObject.enumeratorCount(), 2);
+ QCOMPARE(TestQNamespace::TestGadgetExport::staticMetaObject.enumeratorCount(), 3);
checkEnum(TestQNamespace::TestGadgetExport::staticMetaObject.enumerator(0), "TestGeEnum1",
{{"Key1", 20}, {"Key2", 21}});
checkEnum(TestQNamespace::TestGadgetExport::staticMetaObject.enumerator(1), "TestGeEnum2",
{{"Key1", 23}, {"Key2", 24}});
+ checkEnum(TestQNamespace::TestGadgetExport::staticMetaObject.enumerator(2), "TestGeEnum3",
+ {{"Key1", 26}, {"Key2", 27}}, QMetaType::fromType<quint16>());
QMetaEnum meta = QMetaEnum::fromType<TestQNamespace::TestEnum1>();
QVERIFY(meta.isValid());
@@ -4011,7 +4236,9 @@ void tst_Moc::cxx17Namespaces()
void tst_Moc::cxxAttributes()
{
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
auto so = CppAttribute::staticMetaObject;
+QT_WARNING_POP
QCOMPARE(so.className(), "CppAttribute");
QCOMPARE(so.enumeratorCount(), 0);
QVERIFY(so.indexOfSignal("deprecatedSignal") != 1);
@@ -4046,9 +4273,12 @@ void tst_Moc::cxxAttributes()
void tst_Moc::mocJsonOutput()
{
- const auto readFile = [](const QString &fileName) {
+ const auto readFile = [](const QString &fileName) -> std::optional<QJsonDocument> {
QFile f(fileName);
- f.open(QIODevice::ReadOnly);
+ if (!f.open(QIODevice::ReadOnly)) {
+ qWarning() << "Could not open file" << fileName << f.errorString();
+ return std::nullopt;
+ }
return QJsonDocument::fromJson(f.readAll());
};
@@ -4064,8 +4294,10 @@ void tst_Moc::mocJsonOutput()
QVERIFY2(QFile::exists(actualFile), qPrintable(actualFile));
QVERIFY2(QFile::exists(expectedFile), qPrintable(expectedFile));
- QJsonDocument actualOutput = readFile(actualFile);
- QJsonDocument expectedOutput = readFile(expectedFile);
+ std::optional<QJsonDocument> actualOutput = readFile(actualFile);
+ QVERIFY(actualOutput);
+ std::optional<QJsonDocument> expectedOutput = readFile(expectedFile);
+ QVERIFY(expectedOutput);
const auto showPotentialDiff = [](const QJsonDocument &actual, const QJsonDocument &expected) -> QByteArray {
#if defined(Q_OS_UNIX)
@@ -4094,11 +4326,13 @@ void tst_Moc::mocJsonOutput()
return "Error waiting for diff process to finish.";
return diffProc.readAllStandardOutput();
#else
+ Q_UNUSED(actual);
+ Q_UNUSED(expected);
return "Cannot launch diff. Please check allmocs.json and allmocs_baseline.json on disk.";
#endif
};
- QVERIFY2(actualOutput == expectedOutput, showPotentialDiff(actualOutput, expectedOutput).constData());
+ QVERIFY2(*actualOutput == *expectedOutput, showPotentialDiff(*actualOutput, *expectedOutput).constData());
}
void TestFwdProperties::setProp1(const FwdClass1 &v)
@@ -4194,7 +4428,7 @@ void tst_Moc::qpropertyMembers()
instance.publicProperty.setValue(100);
QCOMPARE(prop.read(&instance).toInt(), 100);
- QCOMPARE(publicPropertySpy.count(), 1);
+ QCOMPARE(publicPropertySpy.size(), 1);
QCOMPARE(prop.metaType(), QMetaType(QMetaType::Int));
@@ -4339,7 +4573,7 @@ void tst_Moc::privateQPropertyShim()
class BindableOnly : public QObject
{
Q_OBJECT
- Q_PROPERTY(int score BINDABLE scoreBindable READ default)
+ Q_PROPERTY(int score BINDABLE scoreBindable READ default WRITE default)
public:
BindableOnly(QObject *parent = nullptr)
: QObject(parent)
@@ -4350,27 +4584,123 @@ private:
QProperty<int> m_score;
};
+class BindableAndNotifyable : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int score BINDABLE scoreBindable NOTIFY scoreChanged READ default WRITE default)
+public:
+ BindableAndNotifyable(QObject *parent = nullptr)
+ : QObject(parent)
+ , m_score(4)
+ {}
+ QBindable<int> scoreBindable() { return QBindable<int>(&m_score); }
+signals:
+ void scoreChanged();
+private:
+ QProperty<int> m_score;
+};
-void tst_Moc::readThroughBindable()
+void tst_Moc::readWriteThroughBindable()
{
- BindableOnly o;
+ {
+ BindableOnly o;
+ QCOMPARE(o.scoreBindable().value(), 4);
+ QCOMPARE(o.property("score").toInt(), 4);
+ o.scoreBindable().setValue(5);
+ QCOMPARE(o.scoreBindable().value(), 5);
+ QCOMPARE(o.property("score").toInt(), 5);
+ const QMetaObject *mo = o.metaObject();
+ const int i = mo->indexOfProperty("score");
+ QVERIFY(i > 0);
+ QMetaProperty p = mo->property(i);
+ QCOMPARE(p.name(), "score");
+ QVERIFY(p.isValid());
+ QVERIFY(p.isWritable());
+ QCOMPARE(p.read(&o), 5);
+ QVERIFY(o.setProperty("score", 6));
+ QCOMPARE(o.property("score").toInt(), 6);
+ QVERIFY(p.write(&o, 7));
+ QCOMPARE(p.read(&o), 7);
+ }
+ {
+ BindableAndNotifyable o;
+ QCOMPARE(o.scoreBindable().value(), 4);
+ QCOMPARE(o.property("score").toInt(), 4);
+ o.scoreBindable().setValue(5);
+ QCOMPARE(o.scoreBindable().value(), 5);
+ QCOMPARE(o.property("score").toInt(), 5);
+ const QMetaObject *mo = o.metaObject();
+ const int i = mo->indexOfProperty("score");
+ QVERIFY(i > 0);
+ QMetaProperty p = mo->property(i);
+ QCOMPARE(p.name(), "score");
+ QVERIFY(p.isValid());
+ QVERIFY(p.isWritable());
+ QCOMPARE(p.read(&o), 5);
+ QVERIFY(o.setProperty("score", 6));
+ QCOMPARE(o.property("score").toInt(), 6);
+ QVERIFY(p.write(&o, 7));
+ QCOMPARE(p.read(&o), 7);
+ }
+}
- QCOMPARE(o.scoreBindable().value(), 4);
- QCOMPARE(o.property("score").toInt(), 4);
- o.scoreBindable().setValue(5);
- QCOMPARE(o.scoreBindable().value(), 5);
- QCOMPARE(o.property("score").toInt(), 5);
+struct WithInvokableCtor
+{
+ Q_GADGET
+ Q_PROPERTY(int thing MEMBER m_thing CONSTANT FINAL)
+public:
+ WithInvokableCtor() = default;
+ Q_INVOKABLE WithInvokableCtor(int theThing) : m_thing(theThing) {}
+ int m_thing = 10;
+};
- const QMetaObject *mo = o.metaObject();
- const int i = mo->indexOfProperty("score");
- QVERIFY(i > 0);
+void tst_Moc::invokableCtors()
+{
+ const QMetaType metaType = QMetaType::fromType<WithInvokableCtor>();
+ Q_ASSERT(metaType.sizeOf() > 0);
+ const QMetaObject *metaObject = metaType.metaObject();
+ QVERIFY(metaObject);
+
+ QCOMPARE(metaObject->constructorCount(), 1);
+ WithInvokableCtor *result = nullptr;
+ const auto guard = qScopeGuard([&]() { delete result; });
+ int argument = 17;
+ void *a[] = { &result, &argument };
+ metaObject->static_metacall(QMetaObject::CreateInstance, 0, a);
+ QVERIFY(result);
+ QCOMPARE(result->m_thing, 17);
+
+ // Call dtor so that we're left with "uninitialized" memory.
+ WithInvokableCtor result2;
+ result2.~WithInvokableCtor();
+
+ void *b[] = { &result2, &argument };
+ metaObject->static_metacall(QMetaObject::ConstructInPlace, 0, b);
+ QCOMPARE(result2.m_thing, 17);
+}
- QMetaProperty p = mo->property(i);
- QCOMPARE(p.name(), "score");
+void tst_Moc::virtualInlineTaggedSlot()
+{
+ auto mo = TagTest::staticMetaObject;
+ auto idx = mo.indexOfMethod("pamOpen(int)");
+ auto method = mo.method(idx);
+ QVERIFY(method.isValid()); // fails!
+ QCOMPARE(method.tag(), "Q_NOREPLY");
+ idx = mo.indexOfMethod("test()");
+ method = mo.method(idx);
+ QVERIFY(method.isValid());
+ QCOMPARE(method.tag(), "Q_NOREPLY");
+ QCOMPARE(method.returnMetaType(), QMetaType::fromType<int>());
+}
- QVERIFY(p.isValid());
- QCOMPARE(p.read(&o), 5);
+void tst_Moc::tokenStartingWithNumber()
+{
+ auto *mo = &TokenStartingWithNumber::staticMetaObject;
+ int index = mo->indexOfEnumerator("FooItems");
+ QMetaEnum metaEnum = mo->enumerator(index);
+ QVERIFY(metaEnum.isValid());
+ QCOMPARE(metaEnum.keyCount(), 3);
}
QTEST_MAIN(tst_Moc)