qt6windows7/tests/auto/tools/moc/tst_moc.cpp
2023-11-01 18:02:52 +01:00

4479 lines
150 KiB
C++

// 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
#include <QTest>
#include <QSignalSpy>
#include <stdio.h>
#include <qobject.h>
#include <qmetaobject.h>
#include <qjsondocument.h>
#include <qversionnumber.h>
#include <qregularexpression.h>
#include "using-namespaces.h"
#include "assign-namespace.h"
#include "no-keywords.h"
#include "single_function_keyword.h"
#include "backslash-newlines.h"
#include "slots-with-void-template.h"
#include "qinvokable.h"
// msvc and friends crap out on it
#if !defined(Q_CC_GNU) || defined(Q_OS_WIN)
#define SKIP_NEWLINE_TEST
#endif
#if !defined(SKIP_NEWLINE_TEST)
#include "os9-newlines.h"
// msvc and friends crap out on this file too,
// it seems to contain Mac 9 EOLs, and not windows EOLs.
#include "win-newlines.h"
#endif
#include "escapes-in-string-literals.h"
#include "cstyle-enums.h"
#if defined(PARSE_BOOST)
#include "parse-boost.h"
#endif
#include "cxx11-enums.h"
#include "cxx11-final-classes.h"
#include "cxx11-explicit-override-control.h"
#include "cxx11-trailing-return.h"
#include "parse-defines.h"
#include "related-metaobjects-in-namespaces.h"
#include "related-metaobjects-in-gadget.h"
#include "related-metaobjects-name-conflict.h"
#include "non-gadget-parent-class.h"
#include "grand-parent-gadget-class.h"
#include "namespace.h"
#include "cxx17-namespaces.h"
#include "cxx-attributes.h"
#include "moc_include.h"
#include "pointery_to_incomplete.h"
#include "fwdclass1.h"
#include "fwdclass2.h"
#include "fwdclass3.h"
#include "signal-with-default-arg.h"
#include "qmlmacro.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 {}
#endif
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 {
Q_GADGET
Q_CLASSINFO("key", "value")
public:
enum class TestGEnum1 {
Key1 = 11,
Key2
};
Q_ENUM(TestGEnum1)
enum class TestGEnum2 {
Key1 = 17,
Key2
};
Q_ENUM(TestGEnum2)
};
}
namespace TestQNamespace {
Q_NAMESPACE
enum class TestEnum1 {
Key1 = 11,
Key2
};
Q_ENUM_NS(TestEnum1)
enum class TestEnum2 {
Key1 = 17,
Key2
};
Q_ENUM_NS(TestEnum2)
// try to dizzy moc by adding a struct in between
struct TestGadget {
Q_GADGET
public:
enum class TestGEnum1 {
Key1 = 13,
Key2
};
enum class TestGEnum2 {
Key1 = 23,
Key2
};
Q_ENUM(TestGEnum1)
Q_ENUM(TestGEnum2)
};
struct TestGadgetExport {
Q_GADGET_EXPORT(TESTEXPORTMACRO)
Q_CLASSINFO("key", "exported")
public:
enum class TestGeEnum1 {
Key1 = 20,
Key2
};
Q_ENUM(TestGeEnum1)
enum class TestGeEnum2 {
Key1 = 23,
Key2
};
Q_ENUM(TestGeEnum2)
};
enum class TestFlag1 {
None = 0,
Flag1 = 1,
Flag2 = 2,
Any = Flag1 | Flag2
};
Q_FLAG_NS(TestFlag1)
enum class TestFlag2 {
None = 0,
Flag1 = 4,
Flag2 = 8,
Any = Flag1 | Flag2
};
Q_FLAG_NS(TestFlag2)
}
namespace TestExportNamespace {
Q_NAMESPACE_EXPORT(TESTEXPORTMACRO)
enum class MyEnum {
Key1, Key2
};
Q_ENUM_NS(MyEnum)
}
QT_USE_NAMESPACE
template <bool b> struct QTBUG_31218 {};
struct QTBUG_31218_Derived : QTBUG_31218<-1<0> {};
#if defined(Q_MOC_RUN)
class QTBUG_45790 : Bug() { };
#endif
class CreatableGadget
{
Q_GADGET
public:
Q_INVOKABLE CreatableGadget()
{
CreatableGadget::qt_static_metacall((QObject*)this, QMetaObject::ReadProperty, -1, nullptr);
}
};
CreatableGadget creatableGadget; // Force the compiler to use the constructor
struct MyStruct {};
struct MyStruct2 {};
struct SuperClass {};
// Try to avoid inserting for instance a comment with a quote between the following line and the Q_OBJECT
// That will make the test give a false positive.
const char* test_multiple_number_of_escapes = "\\\"";
namespace MyNamespace
{
class TestSuperClass : public QObject
{
Q_OBJECT
public:
inline TestSuperClass() {}
};
}
namespace String
{
typedef QString Type;
}
namespace Int
{
typedef int Type;
}
typedef struct {
int doNotConfuseMoc;
} OldStyleCStruct;
namespace {
class GadgetInUnnamedNS
{
Q_GADGET
Q_PROPERTY(int x READ x WRITE setX)
Q_PROPERTY(int y READ y WRITE setY)
public:
explicit GadgetInUnnamedNS(int x, int y) : m_x(x), m_y(y) {}
int x() const { return m_x; }
int y() const { return m_y; }
void setX(int x) { m_x = x; }
void setY(int y) { m_y = y; }
private:
int m_x, m_y;
};
class ObjectInUnnamedNS : public QObject
{
Q_OBJECT
public:
explicit ObjectInUnnamedNS(QObject *parent = nullptr) : QObject(parent) {}
};
}
class Sender : public QObject
{
Q_OBJECT
public:
void sendValue(const String::Type& value)
{
emit send(value);
}
void sendValue(const Int::Type& value)
{
emit send(value);
}
bool operator< ( const Sender & ) const { /* QTBUG-36834 */ return true;}
signals:
void send(const String::Type&);
void send(const Int::Type&);
};
class Receiver : public QObject
{
Q_OBJECT
public:
Receiver() : stringCallCount(0), intCallCount(0) {}
int stringCallCount;
int intCallCount;
public slots:
void receive(const String::Type&) { stringCallCount++; }
void receive(const Int::Type&) { intCallCount++; }
};
#define MACRO_WITH_POSSIBLE_COMPILER_SPECIFIC_ATTRIBUTES
#define DONT_CONFUSE_MOC(klass) klass
#define DONT_CONFUSE_MOC_EVEN_MORE(klass, dummy, dummy2) klass
Q_DECLARE_METATYPE(MyStruct)
Q_DECLARE_METATYPE(MyStruct*)
namespace myNS {
struct Points
{
Points() : p1(0xBEEF), p2(0xBABE) { }
int p1, p2;
};
}
Q_DECLARE_METATYPE(myNS::Points)
class TestClassinfoWithEscapes: public QObject
{
Q_OBJECT
Q_CLASSINFO("escaped", "\"bar\"")
Q_CLASSINFO("\"escaped\"", "foo")
Q_CLASSINFO("cpp c*/omment", "f/*oo")
Q_CLASSINFO("endswith\\", "Or?\?/")
Q_CLASSINFO("newline\n inside\n", "Or \r")
Q_CLASSINFO("\xffz", "\0012")
public slots:
void slotWithAReallyLongName(int)
{ }
};
#define CLASSINFO_VAARGS(...) Q_CLASSINFO("classinfo_va_args", #__VA_ARGS__)
class TestClassinfoFromVaArgs : public QObject
{
Q_OBJECT
CLASSINFO_VAARGS(a, b, c, d)
};
#undef CLASSINFO_VAARGS
struct ForwardDeclaredStruct;
struct StructQObject : public QObject
{
Q_OBJECT
public:
void foo(struct ForwardDeclaredStruct *);
};
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wunused-variable")
void StructQObject::foo(struct ForwardDeclaredStruct *)
{
struct Inner {
bool field;
};
Q_DECL_UNUSED_MEMBER struct Inner unusedVariable;
}
QT_WARNING_POP
QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG("-Wignored-qualifiers")
QT_WARNING_DISABLE_GCC("-Wignored-qualifiers")
using ObjectCRef = const QObject &;
class TestClass : public MyNamespace::TestSuperClass, public DONT_CONFUSE_MOC(MyStruct),
public DONT_CONFUSE_MOC_EVEN_MORE(MyStruct2, dummy, ignored)
{
Q_OBJECT
Q_CLASSINFO("help", QT_TR_NOOP("Opening this will let you configure something"))
Q_PROPERTY(short int shortIntProperty READ shortIntProperty)
Q_PROPERTY(unsigned short int unsignedShortIntProperty READ unsignedShortIntProperty)
Q_PROPERTY(signed short int signedShortIntProperty READ signedShortIntProperty)
Q_PROPERTY(long int longIntProperty READ longIntProperty)
Q_PROPERTY(unsigned long int unsignedLongIntProperty READ unsignedLongIntProperty)
Q_PROPERTY(signed long int signedLongIntProperty READ signedLongIntProperty)
Q_PROPERTY(long double longDoubleProperty READ longDoubleProperty)
Q_PROPERTY(myNS::Points points READ points WRITE setPoints)
Q_CLASSINFO("Multi"
"line",
""
"This is a "
"multiline Q_CLASSINFO"
"")
// a really really long string that we have to cut into pieces in the generated stringdata
// table, otherwise msvc craps out
Q_CLASSINFO("D-Bus Introspection", ""
" <interface name=\"org.kde.KCookieServer\" >\n"
" <method name=\"findCookies\" >\n"
" <arg direction=\"in\" type=\"s\" name=\"url\" />\n"
" <arg direction=\"in\" type=\"x\" name=\"windowId\" />\n"
" <arg direction=\"out\" type=\"s\" name=\"cookies\" />\n"
" </method>\n"
" <method name=\"findDomains\" >\n"
" <arg direction=\"out\" type=\"as\" name=\"domains\" />\n"
" </method>\n"
" <method name=\"findCookies\" >\n"
" <arg direction=\"in\" type=\"ai\" name=\"fields\" />\n"
" <arg direction=\"in\" type=\"s\" name=\"domain\" />\n"
" <arg direction=\"in\" type=\"s\" name=\"fqdn\" />\n"
" <arg direction=\"in\" type=\"s\" name=\"path\" />\n"
" <arg direction=\"in\" type=\"s\" name=\"name\" />\n"
" <arg direction=\"out\" type=\"as\" name=\"cookies\" />\n"
" <annotation value=\"QList&lt;int>\" name=\"com.trolltech.QtDBus.QtTypeName.In0\" />\n"
" </method>\n"
" <method name=\"findDOMCookies\" >\n"
" <arg direction=\"in\" type=\"s\" name=\"url\" />\n"
" <arg direction=\"in\" type=\"x\" name=\"windowId\" />\n"
" <arg direction=\"out\" type=\"s\" name=\"cookies\" />\n"
" </method>\n"
" <method name=\"addCookies\" >\n"
" <arg direction=\"in\" type=\"s\" name=\"url\" />\n"
" <arg direction=\"in\" type=\"ay\" name=\"cookieHeader\" />\n"
" <arg direction=\"in\" type=\"x\" name=\"windowId\" />\n"
" </method>\n"
" <method name=\"deleteCookie\" >\n"
" <arg direction=\"in\" type=\"s\" name=\"domain\" />\n"
" <arg direction=\"in\" type=\"s\" name=\"fqdn\" />\n"
" <arg direction=\"in\" type=\"s\" name=\"path\" />\n"
" <arg direction=\"in\" type=\"s\" name=\"name\" />\n"
" </method>\n"
" <method name=\"deleteCookiesFromDomain\" >\n"
" <arg direction=\"in\" type=\"s\" name=\"domain\" />\n"
" </method>\n"
" <method name=\"deleteSessionCookies\" >\n"
" <arg direction=\"in\" type=\"x\" name=\"windowId\" />\n"
" </method>\n"
" <method name=\"deleteSessionCookiesFor\" >\n"
" <arg direction=\"in\" type=\"s\" name=\"fqdn\" />\n"
" <arg direction=\"in\" type=\"x\" name=\"windowId\" />\n"
" </method>\n"
" <method name=\"deleteAllCookies\" />\n"
" <method name=\"addDOMCookies\" >\n"
" <arg direction=\"in\" type=\"s\" name=\"url\" />\n"
" <arg direction=\"in\" type=\"ay\" name=\"cookieHeader\" />\n"
" <arg direction=\"in\" type=\"x\" name=\"windowId\" />\n"
" </method>\n"
" <method name=\"setDomainAdvice\" >\n"
" <arg direction=\"in\" type=\"s\" name=\"url\" />\n"
" <arg direction=\"in\" type=\"s\" name=\"advice\" />\n"
" </method>\n"
" <method name=\"getDomainAdvice\" >\n"
" <arg direction=\"in\" type=\"s\" name=\"url\" />\n"
" <arg direction=\"out\" type=\"s\" name=\"advice\" />\n"
" </method>\n"
" <method name=\"reloadPolicy\" />\n"
" <method name=\"shutdown\" />\n"
" </interface>\n"
"")
public:
inline TestClass() {}
private slots:
inline void dummy1() MACRO_WITH_POSSIBLE_COMPILER_SPECIFIC_ATTRIBUTES {}
inline void dummy2() MACRO_WITH_POSSIBLE_COMPILER_SPECIFIC_ATTRIBUTES const {}
inline void dummy3() const MACRO_WITH_POSSIBLE_COMPILER_SPECIFIC_ATTRIBUTES {}
void slotWithULongLong(unsigned long long) {}
void slotWithULongLongP(unsigned long long*) {}
void slotWithULong(unsigned long) {}
void slotWithLongLong(long long) {}
void slotWithLong(long) {}
void slotWithColonColonType(::Int::Type) {}
TestClass &slotWithReferenceReturnType() { return *this; }
#if (0 && 1) || 1
void expressionEvaluationShortcut1() {}
#endif
#if (1 || 0) && 0
#else
void expressionEvaluationShortcut2() {}
#endif
public slots:
void slotWithArray(const double[3]) {}
void slotWithNamedArray(const double namedArray[3]) { Q_UNUSED(namedArray); }
void slotWithMultiArray(const double[3][4]) {}
short int shortIntProperty() { return 0; }
unsigned short int unsignedShortIntProperty() { return 0; }
signed short int signedShortIntProperty() { return 0; }
long int longIntProperty() { return 0; }
unsigned long int unsignedLongIntProperty() { return 0; }
signed long int signedLongIntProperty() { return 0; }
long double longDoubleProperty() { return 0.0; }
myNS::Points points() { return m_points; }
void setPoints(myNS::Points points) { m_points = points; }
signals:
void signalWithArray(const double[3]);
void signalWithNamedArray(const double namedArray[3]);
void signalWithIterator(QList<QUrl>::iterator);
void signalWithListPointer(QList<QUrl>*); //QTBUG-31002
private slots:
// for tst_Moc::preprocessorConditionals
#if 0
void invalidSlot() {}
#else
void slotInElse() {}
#endif
#if 1
void slotInIf() {}
#else
void invalidSlot() {}
#endif
#if 0
void invalidSlot() {}
#elif 0
#else
void slotInLastElse() {}
#endif
#if 0
void invalidSlot() {}
#elif 1
void slotInElif() {}
#else
void invalidSlot() {}
#endif
friend class Receiver; // task #85783
signals:
friend class Sender; // task #85783
#define MACRO_DEFINED
#if !(defined MACRO_UNDEF || defined MACRO_DEFINED) || 1
void signalInIf1();
#else
void doNotExist();
#endif
#if !(!defined MACRO_UNDEF || !defined MACRO_DEFINED) && 1
void doNotExist();
#else
void signalInIf2();
#endif
#if !(!defined (MACRO_DEFINED) || !defined (MACRO_UNDEF)) && 1
void doNotExist();
#else
void signalInIf3();
#endif
# //QTBUG-22717
# /* */
#
# \
//
public slots:
void const slotWithSillyConst() {}
void slotTakingCRefViaTypedef(ObjectCRef o) { this->setObjectName(o.objectName()); }
public:
Q_INVOKABLE void const slotWithSillyConst2() {}
Q_INVOKABLE QObject& myInvokableReturningRef()
{ return *this; }
Q_INVOKABLE const QObject& myInvokableReturningConstRef() const
{ return *this; }
// that one however should be fine
public slots:
void slotWithVoidStar(void *) {}
private:
myNS::Points m_points;
#ifdef Q_MOC_RUN
int xx = 11'11; // digit separator must not confuse moc (QTBUG-59351)
int xx = 0b11'11; // digit separator in a binary literal must not confuse moc (QTBUG-75656)
#endif
private slots:
inline virtual void blub1() {}
virtual inline void blub2() {}
};
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
public:
enum TestEnum { One, Two, Three };
Q_ENUM(TestEnum)
};
#endif
class PropertyUseClass : public QObject
{
Q_OBJECT
Q_PROPERTY(PropertyTestClass::TestEnum foo READ foo)
public:
inline PropertyTestClass::TestEnum foo() const { return PropertyTestClass::One; }
};
class EnumSourceClass : public QObject
{
Q_OBJECT
public:
enum TestEnum { Value = 37 };
Q_ENUM(TestEnum)
};
class EnumUserClass : public QObject
{
Q_OBJECT
public:
Q_ENUMS(EnumSourceClass::TestEnum)
};
class CtorTestClass : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE CtorTestClass(QObject *parent = nullptr);
CtorTestClass(int foo);
inline Q_INVOKABLE CtorTestClass(const QString &str)
{ m_str = str; }
QString m_str;
protected:
CtorTestClass(int foo, int bar, int baz);
private:
CtorTestClass(float, float) {}
};
CtorTestClass::CtorTestClass(QObject *parent)
: QObject(parent) {}
CtorTestClass::CtorTestClass(int, int, int) {}
class PrivatePropertyTest;
class tst_Moc : public QObject
{
Q_OBJECT
Q_PROPERTY(bool user1 READ user1 USER true )
Q_PROPERTY(bool user2 READ user2 USER false)
Q_PROPERTY(QString member1 MEMBER sMember)
Q_PROPERTY(QString member2 MEMBER sMember READ member2)
Q_PROPERTY(QString member3 MEMBER sMember WRITE setMember3)
Q_PROPERTY(QString member4 MEMBER sMember NOTIFY member4Changed)
Q_PROPERTY(QString member5 MEMBER sMember NOTIFY member5Changed)
Q_PROPERTY(QString member6 MEMBER sConst CONSTANT)
Q_PROPERTY(QString sub1 MEMBER (sub.m_string))
Q_PROPERTY(QString sub2 READ (sub.string) WRITE (sub.setString))
public:
inline tst_Moc() : sConst("const") {}
private slots:
void initTestCase();
void dontStripNamespaces();
void oldStyleCasts();
void warnOnExtraSignalSlotQualifiaction();
void uLongLong();
void inputFileNameWithDotsButNoExtension();
void userProperties();
void supportConstSignals();
void task87883();
void multilineComments();
void classinfoWithEscapes();
void classinfoFromVaArgs();
void trNoopInClassInfo();
void ppExpressionEvaluation();
void arrayArguments();
void preprocessorConditionals();
void blackslashNewlines();
void slotWithSillyConst();
void slotTakingCRefViaTypedef();
void testExtraData();
void testExtraDataForEnum();
void namespaceTypeProperty();
void slotsWithVoidTemplate();
void structQObject();
void namespacedFlags();
void warnOnMultipleInheritance();
void ignoreOptionClashes();
void forgottenQInterface();
void os9Newline();
void winNewline();
void escapesInStringLiterals();
void frameworkSearchPath();
void cstyleEnums();
void defineMacroViaCmdline();
void defineMacroViaForcedInclude();
void defineMacroViaForcedIncludeRelative();
void environmentIncludePaths_data();
void environmentIncludePaths();
void specifyMetaTagsFromCmdline();
void invokable();
void singleFunctionKeywordSignalAndSlot();
void templateGtGt();
void qprivateslots();
void qprivateproperties();
void warnOnPropertyWithoutREAD();
void constructors();
void typenameWithUnsigned();
void warnOnVirtualSignal();
void QTBUG5590_dummyProperty();
void QTBUG12260_defaultTemplate();
void notifyError();
void QTBUG17635_invokableAndProperty();
void revisions();
void warnings_data();
void warnings();
void privateClass();
void cxx11Enums_data();
void cxx11Enums();
void cxx11TrailingReturn();
void returnRefs();
void memberProperties_data();
void memberProperties();
void memberProperties2();
void privateSignalConnection();
void finalClasses_data();
void finalClasses();
void explicitOverrideControl_data();
void explicitOverrideControl();
void overloadedAddressOperator();
void autoPropertyMetaTypeRegistration();
void autoMethodArgumentMetaTypeRegistration();
void autoSignalSpyMetaTypeRegistration();
void parseDefines();
void preprocessorOnly();
void unterminatedFunctionMacro();
void QTBUG32933_relatedObjectsDontIncludeItself();
void writeEnumFromUnrelatedClass();
void relatedMetaObjectsWithinNamespaces();
void relatedMetaObjectsInGadget();
void relatedMetaObjectsNameConflict_data();
void relatedMetaObjectsNameConflict();
void strignLiteralsInMacroExtension();
void unnamedNamespaceObjectsAndGadgets();
void veryLongStringData();
void gadgetHierarchy();
void optionsFileError_data();
void optionsFileError();
void testQNamespace();
void cxx17Namespaces();
void cxxAttributes();
void mocJsonOutput();
void mocInclude();
void requiredProperties();
void qpropertyMembers();
void observerMetaCall();
void setQPRopertyBinding();
void privateQPropertyShim();
void readWriteThroughBindable();
void virtualInlineTaggedSlot();
signals:
void sigWithUnsignedArg(unsigned foo);
void sigWithSignedArg(signed foo);
void sigWithConstSignedArg(const signed foo);
void sigWithVolatileConstSignedArg(volatile const signed foo);
void sigWithCustomType(const MyStruct);
void constSignal1() const;
void constSignal2(int arg) const;
void member4Changed();
void member5Changed(const QString &newVal);
void sigWithDefaultArg(int i = 12);
private:
bool user1() { return true; };
bool user2() { return false; };
template <class T> void revisions_T();
QString member2() const { return sMember; }
void setMember3( const QString &sVal ) { sMember = sVal; }
private:
QString m_moc;
QString m_sourceDirectory;
QString qtIncludePath;
class PrivateClass;
QString sMember;
const QString sConst;
PrivatePropertyTest *pPPTest;
struct {
QString m_string;
void setString(const QString &s) { m_string = s; }
QString string() { return m_string; }
} sub;
};
void tst_Moc::initTestCase()
{
QString binpath = QLibraryInfo::path(QLibraryInfo::BinariesPath);
QString qtpaths = QString("%1/qtpaths").arg(binpath);
QString libexecPath = QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath);
m_moc = QString("%1/moc").arg(libexecPath);
const QString testHeader = QFINDTESTDATA("backslash-newlines.h");
QVERIFY(!testHeader.isEmpty());
m_sourceDirectory = QFileInfo(testHeader).absolutePath();
#if defined(Q_OS_UNIX) && QT_CONFIG(process)
QProcess proc;
proc.start(qtpaths, QStringList() << "-query" << "QT_INSTALL_HEADERS");
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QByteArray output = proc.readAllStandardOutput();
QVERIFY(!output.isEmpty());
QCOMPARE(proc.readAllStandardError(), QByteArray());
qtIncludePath = QString::fromLocal8Bit(output).trimmed();
QFileInfo fi(qtIncludePath);
QVERIFY(fi.exists());
QVERIFY(fi.isDir());
#endif
}
void tst_Moc::dontStripNamespaces()
{
Sender sender;
Receiver receiver;
connect(&sender, SIGNAL(send(const String::Type &)),
&receiver, SLOT(receive(const String::Type &)));
connect(&sender, SIGNAL(send(const Int::Type &)),
&receiver, SLOT(receive(const Int::Type &)));
sender.sendValue(String::Type("Hello"));
QCOMPARE(receiver.stringCallCount, 1);
QCOMPARE(receiver.intCallCount, 0);
sender.sendValue(Int::Type(42));
QCOMPARE(receiver.stringCallCount, 1);
QCOMPARE(receiver.intCallCount, 1);
}
void tst_Moc::oldStyleCasts()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
proc.start(m_moc, QStringList(m_sourceDirectory + QStringLiteral("/oldstyle-casts.h")));
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
QCOMPARE(proc.readAllStandardError(), QByteArray());
QStringList args;
args << "-c" << "-x" << "c++" << "-Wold-style-cast" << "-I" << "."
<< "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-std=c++1z" << "-";
proc.start("gcc", args);
QVERIFY(proc.waitForStarted());
proc.write(mocOut);
proc.closeWriteChannel();
QVERIFY(proc.waitForFinished());
QCOMPARE(QString::fromLocal8Bit(proc.readAllStandardError()), QString());
QCOMPARE(proc.exitCode(), 0);
#else
QSKIP("Only tested on linux/gcc");
#endif
}
void tst_Moc::warnOnExtraSignalSlotQualifiaction()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
const QString header = m_sourceDirectory + QStringLiteral("/extraqualification.h");
proc.start(m_moc, QStringList(header));
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QCOMPARE(mocWarning, header +
QString(":18:1: warning: Function declaration Test::badFunctionDeclaration contains extra qualification. Ignoring as signal or slot.\n") +
header + QString(":21:1: warning: parsemaybe: Function declaration Test::anotherOne contains extra qualification. Ignoring as signal or slot.\n"));
#else
QSKIP("Only tested on unix/gcc");
#endif
}
void tst_Moc::uLongLong()
{
TestClass tst;
const QMetaObject *mobj = tst.metaObject();
int idx = mobj->indexOfSlot("slotWithULong(ulong)");
QVERIFY(idx != -1);
idx = mobj->indexOfSlot("slotWithULongLong(unsigned long long)");
QVERIFY(idx != -1);
idx = mobj->indexOfSlot("slotWithULongLong(qulonglong)");
QVERIFY(idx != -1);
idx = mobj->indexOfSlot("slotWithULongLongP(qulonglong*)");
QVERIFY(idx != -1);
idx = mobj->indexOfSlot("slotWithLong(long)");
QVERIFY(idx != -1);
idx = mobj->indexOfSlot("slotWithLongLong(long long)");
QVERIFY(idx != -1);
}
void tst_Moc::inputFileNameWithDotsButNoExtension()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
proc.setWorkingDirectory(m_sourceDirectory + QStringLiteral("/task71021"));
proc.start(m_moc, QStringList("../Header"));
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
QCOMPARE(proc.readAllStandardError(), QByteArray());
QStringList args;
args << "-c" << "-x" << "c++" << "-I" << ".."
<< "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-std=c++1z" << "-";
proc.start("gcc", args);
QVERIFY(proc.waitForStarted());
proc.write(mocOut);
proc.closeWriteChannel();
QVERIFY(proc.waitForFinished());
QCOMPARE(QString::fromLocal8Bit(proc.readAllStandardError()), QString());
QCOMPARE(proc.exitCode(), 0);
#else
QSKIP("Only tested on linux/gcc");
#endif
}
void tst_Moc::userProperties()
{
const QMetaObject *mobj = metaObject();
QMetaProperty property = mobj->property(mobj->indexOfProperty("user1"));
QVERIFY(property.isValid());
QVERIFY(property.isUser());
property = mobj->property(mobj->indexOfProperty("user2"));
QVERIFY(property.isValid());
QVERIFY(!property.isUser());
}
void tst_Moc::supportConstSignals()
{
QSignalSpy spy1(this, SIGNAL(constSignal1()));
QVERIFY(spy1.isEmpty());
emit constSignal1();
QCOMPARE(spy1.size(), 1);
QSignalSpy spy2(this, SIGNAL(constSignal2(int)));
QVERIFY(spy2.isEmpty());
emit constSignal2(42);
QCOMPARE(spy2.size(), 1);
QCOMPARE(spy2.at(0).at(0).toInt(), 42);
}
#include "task87883.h"
void tst_Moc::task87883()
{
QVERIFY(Task87883::staticMetaObject.className());
}
#include "c-comments.h"
void tst_Moc::multilineComments()
{
QVERIFY(IfdefedClass::staticMetaObject.className());
}
void tst_Moc::classinfoWithEscapes()
{
const QMetaObject *mobj = &TestClassinfoWithEscapes::staticMetaObject;
QCOMPARE(mobj->methodCount() - mobj->methodOffset(), 1);
QCOMPARE(mobj->classInfoCount(), 6);
QCOMPARE(mobj->classInfo(2).name(), "cpp c*/omment");
QCOMPARE(mobj->classInfo(2).value(), "f/*oo");
QCOMPARE(mobj->classInfo(3).name(), "endswith\\");
QCOMPARE(mobj->classInfo(3).value(), "Or?\?/");
QCOMPARE(mobj->classInfo(4).name(), "newline\n inside\n");
QCOMPARE(mobj->classInfo(4).value(), "Or \r");
QCOMPARE(mobj->classInfo(5).name(), "\xff" "z");
QCOMPARE(mobj->classInfo(5).value(), "\001" "2");
QMetaMethod mm = mobj->method(mobj->methodOffset());
QCOMPARE(mm.methodSignature(), QByteArray("slotWithAReallyLongName(int)"));
}
void tst_Moc::classinfoFromVaArgs()
{
const QMetaObject *mobj = &TestClassinfoFromVaArgs::staticMetaObject;
QCOMPARE(mobj->classInfoCount(), 1);
QCOMPARE(mobj->classInfo(0).name(), "classinfo_va_args");
QCOMPARE(mobj->classInfo(0).value(), "a,b,c,d");
}
void tst_Moc::trNoopInClassInfo()
{
TestClass t;
const QMetaObject *mobj = t.metaObject();
QVERIFY(mobj);
QCOMPARE(mobj->classInfoCount(), 3);
QCOMPARE(mobj->indexOfClassInfo("help"), 0);
QCOMPARE(QString(mobj->classInfo(0).value()), QString("Opening this will let you configure something"));
}
void tst_Moc::ppExpressionEvaluation()
{
TestClass tst;
const QMetaObject *mobj = tst.metaObject();
int idx = mobj->indexOfSlot("expressionEvaluationShortcut1()");
QVERIFY(idx != -1);
idx = mobj->indexOfSlot("expressionEvaluationShortcut2()");
QVERIFY(idx != -1);
}
void tst_Moc::arrayArguments()
{
TestClass tst;
const QMetaObject *mobj = tst.metaObject();
QVERIFY(mobj->indexOfSlot("slotWithArray(const double[3])") != -1);
QVERIFY(mobj->indexOfSlot("slotWithNamedArray(const double[3])") != -1);
QVERIFY(mobj->indexOfSlot("slotWithMultiArray(const double[3][4])") != -1);
QVERIFY(mobj->indexOfSignal("signalWithArray(const double[3])") != -1);
QVERIFY(mobj->indexOfSignal("signalWithNamedArray(const double[3])") != -1);
}
void tst_Moc::preprocessorConditionals()
{
TestClass tst;
const QMetaObject *mobj = tst.metaObject();
QVERIFY(mobj->indexOfSlot("slotInElse()") != -1);
QVERIFY(mobj->indexOfSlot("slotInIf()") != -1);
QVERIFY(mobj->indexOfSlot("slotInLastElse()") != -1);
QVERIFY(mobj->indexOfSlot("slotInElif()") != -1);
QVERIFY(mobj->indexOfSignal("signalInIf1()") != -1);
QVERIFY(mobj->indexOfSignal("signalInIf2()") != -1);
QVERIFY(mobj->indexOfSignal("signalInIf3()") != -1);
QCOMPARE(mobj->indexOfSignal("doNotExist()"), -1);
}
void tst_Moc::blackslashNewlines()
{
BackslashNewlines tst;
const QMetaObject *mobj = tst.metaObject();
QVERIFY(mobj->indexOfSlot("works()") != -1);
QCOMPARE(mobj->indexOfSlot("buggy()"), -1);
}
void tst_Moc::slotWithSillyConst()
{
TestClass tst;
const QMetaObject *mobj = tst.metaObject();
QVERIFY(mobj->indexOfSlot("slotWithSillyConst()") != -1);
QVERIFY(mobj->indexOfMethod("slotWithSillyConst2()") != -1);
QVERIFY(mobj->indexOfSlot("slotWithVoidStar(void*)") != -1);
}
void tst_Moc::slotTakingCRefViaTypedef()
{
TestClass tst;
QObject obj;
obj.setObjectName("works");
QMetaObject::invokeMethod(&tst, "slotTakingCRefViaTypedef", Q_ARG(ObjectCRef, obj));
QCOMPARE(obj.objectName(), "works");
}
void tst_Moc::testExtraData()
{
const QMetaObject *mobj = &PropertyTestClass::staticMetaObject;
QCOMPARE(mobj->enumeratorCount(), 1);
QCOMPARE(QByteArray(mobj->enumerator(0).name()), QByteArray("TestEnum"));
mobj = &PropertyUseClass::staticMetaObject;
const int idx = mobj->indexOfProperty("foo");
QVERIFY(idx != -1);
const QMetaProperty prop = mobj->property(idx);
QVERIFY(prop.isValid());
QVERIFY(prop.isEnumType());
const QMetaEnum en = prop.enumerator();
QCOMPARE(QByteArray(en.name()), QByteArray("TestEnum"));
}
// QTBUG-20639 - Accept non-local enums for QML signal/slot parameters.
void tst_Moc::testExtraDataForEnum()
{
const QMetaObject *mobjSource = &EnumSourceClass::staticMetaObject;
QCOMPARE(mobjSource->enumeratorCount(), 1);
QCOMPARE(QByteArray(mobjSource->enumerator(0).name()), QByteArray("TestEnum"));
const QMetaObject *mobjUser = &EnumUserClass::staticMetaObject;
QCOMPARE(mobjUser->enumeratorCount(), 0);
const auto *objects = mobjUser->d.relatedMetaObjects;
QVERIFY(objects);
QCOMPARE(objects[0], mobjSource);
QVERIFY(!objects[1]);
}
void tst_Moc::namespaceTypeProperty()
{
qRegisterMetaType<myNS::Points>("myNS::Points");
TestClass tst;
QByteArray ba = QByteArray("points");
QVariant v = tst.property(ba);
QVERIFY(v.isValid());
myNS::Points p = qvariant_cast<myNS::Points>(v);
QCOMPARE(p.p1, 0xBEEF);
QCOMPARE(p.p2, 0xBABE);
p.p1 = 0xCAFE;
p.p2 = 0x1EE7;
QVERIFY(tst.setProperty(ba, QVariant::fromValue(p)));
myNS::Points pp = qvariant_cast<myNS::Points>(tst.property(ba));
QCOMPARE(p.p1, pp.p1);
QCOMPARE(p.p2, pp.p2);
}
void tst_Moc::slotsWithVoidTemplate()
{
SlotsWithVoidTemplateTest test;
QVERIFY(QObject::connect(&test, SIGNAL(myVoidSignal(void)),
&test, SLOT(dummySlot(void))));
QVERIFY(QObject::connect(&test, SIGNAL(mySignal(const TestTemplate<void> &)),
&test, SLOT(anotherSlot(const TestTemplate<void> &))));
QVERIFY(QObject::connect(&test, SIGNAL(myVoidSignal2()),
&test, SLOT(dummySlot2())));
}
void tst_Moc::structQObject()
{
StructQObject o;
QCOMPARE(QByteArray(o.metaObject()->className()), QByteArray("StructQObject"));
}
#include "namespaced-flags.h"
Q_DECLARE_METATYPE(QList<Foo::Bar::Flags>);
void tst_Moc::namespacedFlags()
{
Foo::Baz baz;
Foo::Bar bar;
bar.setFlags(Foo::Bar::Read | Foo::Bar::Write);
QVERIFY(baz.flags() != bar.flags());
const QVariant v = bar.property("flags");
QVERIFY(v.isValid());
QVERIFY(baz.setProperty("flags", v));
QCOMPARE(baz.flags(), bar.flags());
QList<Foo::Bar::Flags> l;
l << baz.flags();
QVariant v2 = baz.setProperty("flagsList", QVariant::fromValue(l));
QCOMPARE(l, baz.flagsList());
QCOMPARE(l, qvariant_cast<QList<Foo::Bar::Flags> >(baz.property("flagsList")));
}
void tst_Moc::warnOnMultipleInheritance()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
QStringList args;
const QString header = m_sourceDirectory + QStringLiteral("/warn-on-multiple-qobject-subclasses.h");
args << "-I" << qtIncludePath + "/QtGui" << header;
proc.start(m_moc, args);
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QCOMPARE(mocWarning, header +
QString(":18:1: warning: Class Bar inherits from two QObject subclasses QWindow and Foo. This is not supported!\n"));
#else
QSKIP("Only tested on linux/gcc");
#endif
}
void tst_Moc::ignoreOptionClashes()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
QStringList args;
const QString header = m_sourceDirectory + QStringLiteral("/interface-from-include.h");
const QString includeDir = m_sourceDirectory + "/Test.framework/Headers";
// given --ignore-option-clashes, -pthread should be ignored, but the -I path should not be.
args << "--ignore-option-clashes" << "-pthread" << "-I" << includeDir << "-fno-builtin" << header;
proc.start(m_moc, args);
bool finished = proc.waitForFinished();
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());
QByteArray mocOut = proc.readAllStandardOutput();
// If -pthread wasn't ignored, it was parsed as a prefix of "thread/", which breaks compilation.
QStringList gccArgs;
gccArgs << "-c" << "-x" << "c++" << "-I" << ".."
<< "-I" << qtIncludePath << "-I" << includeDir << "-o" << "/dev/null"
<< "-fPIC" << "-std=c++1z" << "-";
proc.start("gcc", gccArgs);
QVERIFY(proc.waitForStarted());
proc.write(mocOut);
proc.closeWriteChannel();
QVERIFY(proc.waitForFinished());
QCOMPARE(QString::fromLocal8Bit(proc.readAllStandardError()), QString());
#else
QSKIP("Only tested on linux/gcc");
#endif
}
void tst_Moc::forgottenQInterface()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
QStringList args;
const QString header = m_sourceDirectory + QStringLiteral("/forgotten-qinterface.h");
args << "-I" << qtIncludePath + "/QtCore" << header;
proc.start(m_moc, args);
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QCOMPARE(mocWarning, header +
QString(":20:1: warning: Class Test implements the interface MyInterface but does not list it in Q_INTERFACES. qobject_cast to MyInterface will not work!\n"));
#else
QSKIP("Only tested on linux/gcc");
#endif
}
void tst_Moc::os9Newline()
{
#if !defined(SKIP_NEWLINE_TEST)
const QMetaObject &mo = Os9Newlines::staticMetaObject;
QVERIFY(mo.indexOfSlot("testSlot()") != -1);
QFile f(m_sourceDirectory + QStringLiteral("/os9-newlines.h"));
QVERIFY(f.open(QIODevice::ReadOnly)); // no QIODevice::Text!
QByteArray data = f.readAll();
f.close();
QVERIFY(!data.contains('\n'));
QVERIFY(data.contains('\r'));
#endif
}
void tst_Moc::winNewline()
{
#if !defined(SKIP_NEWLINE_TEST)
const QMetaObject &mo = WinNewlines::staticMetaObject;
QVERIFY(mo.indexOfSlot("testSlot()") != -1);
QFile f(m_sourceDirectory + QStringLiteral("/win-newlines.h"));
QVERIFY(f.open(QIODevice::ReadOnly)); // no QIODevice::Text!
QByteArray data = f.readAll();
f.close();
for (int i = 0; i < data.size(); ++i) {
if (data.at(i) == QLatin1Char('\r')) {
QVERIFY(i < data.size() - 1);
++i;
QCOMPARE(data.at(i), '\n');
} else {
QVERIFY(data.at(i) != '\n');
}
}
#endif
}
void tst_Moc::escapesInStringLiterals()
{
const QMetaObject &mo = StringLiterals::staticMetaObject;
QCOMPARE(mo.classInfoCount(), 3);
int idx = mo.indexOfClassInfo("Test");
QVERIFY(idx != -1);
QMetaClassInfo info = mo.classInfo(idx);
QCOMPARE(QByteArray(info.value()),
QByteArray("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x53"));
QVERIFY(idx != -1);
idx = mo.indexOfClassInfo("Test2");
info = mo.classInfo(idx);
QCOMPARE(QByteArray(info.value()),
QByteArray("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\123"));
QVERIFY(idx != -1);
idx = mo.indexOfClassInfo("Test3");
info = mo.classInfo(idx);
QCOMPARE(QByteArray(info.value()),
QByteArray("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nb"));
}
void tst_Moc::frameworkSearchPath()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_UNIX) && QT_CONFIG(process)
QStringList args;
args << "-F" << m_sourceDirectory + QStringLiteral("/.")
<< m_sourceDirectory + QStringLiteral("/interface-from-framework.h")
;
QProcess proc;
proc.start(m_moc, args);
bool finished = proc.waitForFinished();
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());
#else
QSKIP("Only tested/relevant on unixy platforms");
#endif
}
void tst_Moc::cstyleEnums()
{
const QMetaObject &obj = CStyleEnums::staticMetaObject;
QCOMPARE(obj.enumeratorCount(), 2);
QMetaEnum metaEnum = obj.enumerator(0);
QCOMPARE(metaEnum.name(), "Baz");
QCOMPARE(metaEnum.keyCount(), 2);
QCOMPARE(metaEnum.key(0), "Foo");
QCOMPARE(metaEnum.key(1), "Bar");
QMetaEnum metaEnum2 = obj.enumerator(1);
QCOMPARE(metaEnum2.name(), "Baz2");
QCOMPARE(metaEnum2.keyCount(), 2);
QCOMPARE(metaEnum2.key(0), "Foo2");
QCOMPARE(metaEnum2.key(1), "Bar2");
}
void tst_Moc::templateGtGt()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
proc.start(m_moc, QStringList(m_sourceDirectory + QStringLiteral("/template-gtgt.h")));
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QVERIFY(mocWarning.isEmpty());
#else
QSKIP("Only tested on unix/gcc");
#endif
}
void tst_Moc::defineMacroViaCmdline()
{
#if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
QStringList args;
args << "-DFOO";
args << m_sourceDirectory + QStringLiteral("/macro-on-cmdline.h");
proc.start(m_moc, args);
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QCOMPARE(proc.readAllStandardError(), QByteArray());
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
#else
QSKIP("Only tested on unix/gcc");
#endif
}
void tst_Moc::defineMacroViaForcedInclude()
{
#if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
QStringList args;
args << "--include" << m_sourceDirectory + QLatin1String("/subdir/extradefines.h");
args << m_sourceDirectory + QStringLiteral("/macro-on-cmdline.h");
proc.start(m_moc, args);
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QCOMPARE(proc.readAllStandardError(), QByteArray());
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
#else
QSKIP("Only tested on unix/gcc");
#endif
}
void tst_Moc::defineMacroViaForcedIncludeRelative()
{
#if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
QStringList args;
args << "--include" << QStringLiteral("extradefines.h") << "-I" + m_sourceDirectory + "/subdir";
args << m_sourceDirectory + QStringLiteral("/macro-on-cmdline.h");
proc.start(m_moc, args);
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QCOMPARE(proc.readAllStandardError(), QByteArray());
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
#else
QSKIP("Only tested on unix/gcc");
#endif
}
void tst_Moc::environmentIncludePaths_data()
{
#if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QTest::addColumn<QString>("cmdline");
QTest::addColumn<QString>("varname");
QTest::newRow("INCLUDE") << "--compiler-flavor=msvc" << "INCLUDE";
QTest::newRow("CPATH1") << QString() << "CPATH";
QTest::newRow("CPATH2") << "--compiler-flavor=unix" << "CPATH";
QTest::newRow("CPLUS_INCLUDE_PATH1") << QString() << "CPLUS_INCLUDE_PATH";
QTest::newRow("CPLUS_INCLUDE_PATH2") << "--compiler-flavor=unix" << "CPLUS_INCLUDE_PATH";
#endif
}
void tst_Moc::environmentIncludePaths()
{
#if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QFETCH(QString, cmdline);
QFETCH(QString, varname);
QStringList args;
if (!cmdline.isEmpty())
args << cmdline;
args << "--include" << QStringLiteral("extradefines.h")
<< m_sourceDirectory + QStringLiteral("/macro-on-cmdline.h");
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.remove("INCLUDE");
env.remove("CPATH");
env.remove("CPLUS_INCLUDE_PATH");
env.insert(varname, m_sourceDirectory + "/subdir");
QProcess proc;
proc.setProcessEnvironment(env);
proc.start(m_moc, args);
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QCOMPARE(proc.readAllStandardError(), QByteArray());
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
#else
QSKIP("Only tested on unix/gcc");
#endif
}
// tst_Moc::specifyMetaTagsFromCmdline()
// plugin_metadata.h contains a plugin which we register here. Since we're not building this
// application as a plugin, we need to copy some of the initializer code found in qplugin.h:
extern "C" Q_DECL_EXPORT QObject *qt_plugin_instance();
extern "C" Q_DECL_EXPORT QPluginMetaData qt_plugin_query_metadata_v2();
class StaticPluginInstance{
public:
StaticPluginInstance() {
QStaticPlugin plugin(qt_plugin_instance, qt_plugin_query_metadata_v2);
qRegisterStaticPluginFunction(plugin);
}
};
static StaticPluginInstance staticInstance;
void tst_Moc::specifyMetaTagsFromCmdline() {
foreach (const QStaticPlugin &plugin, QPluginLoader::staticPlugins()) {
const QString iid = plugin.metaData().value(QLatin1String("IID")).toString();
if (iid == QLatin1String("test.meta.tags")) {
const QJsonArray metaTagsUriList = plugin.metaData().value("uri").toArray();
QCOMPARE(metaTagsUriList.size(), 2);
// The following uri-s are set in the pro file using
// -Muri=com.company.app -Muri=com.company.app.private
QCOMPARE(metaTagsUriList[0].toString(), QLatin1String("com.company.app"));
QCOMPARE(metaTagsUriList[1].toString(), QLatin1String("com.company.app.private"));
return;
}
}
QFAIL("Could not find plugin with IID 'test.meta.tags'");
}
void tst_Moc::invokable()
{
{
const QMetaObject &mobj = InvokableBeforeReturnType::staticMetaObject;
QCOMPARE(mobj.methodCount(), 6);
QCOMPARE(mobj.method(5).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()"));
}
}
void tst_Moc::singleFunctionKeywordSignalAndSlot()
{
{
const QMetaObject &mobj = SingleFunctionKeywordBeforeReturnType::staticMetaObject;
QCOMPARE(mobj.methodCount(), 7);
QCOMPARE(mobj.method(5).methodSignature(), QByteArray("mySignal()"));
QCOMPARE(mobj.method(6).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()"));
}
{
const QMetaObject &mobj = SingleFunctionKeywordAfterInline::staticMetaObject;
QCOMPARE(mobj.methodCount(), 7);
QCOMPARE(mobj.method(5).methodSignature(), QByteArray("mySignal()"));
QCOMPARE(mobj.method(6).methodSignature(), QByteArray("mySlot()"));
}
}
#include "qprivateslots.h"
void tst_Moc::qprivateslots()
{
TestQPrivateSlots tst;
const QMetaObject *mobj = tst.metaObject();
QVERIFY(mobj->indexOfSlot("_q_privateslot()") != -1);
QVERIFY(mobj->indexOfMethod("method1()") != -1); //tast204730
}
class PrivatePropertyTest : public QObject
{
Q_OBJECT
Q_PROPERTY(int foo READ foo WRITE setFoo)
Q_PRIVATE_PROPERTY(d, int bar READ bar WRITE setBar)
Q_PRIVATE_PROPERTY(PrivatePropertyTest::d, int plop READ plop WRITE setPlop)
Q_PRIVATE_PROPERTY(PrivatePropertyTest::d_func(), int baz READ baz WRITE setBaz)
Q_PRIVATE_PROPERTY(PrivatePropertyTest::d, QString blub MEMBER mBlub)
Q_PRIVATE_PROPERTY(PrivatePropertyTest::d, QString blub2 MEMBER mBlub READ blub)
Q_PRIVATE_PROPERTY(PrivatePropertyTest::d, QString blub3 MEMBER mBlub WRITE setBlub)
Q_PRIVATE_PROPERTY(PrivatePropertyTest::d, QString blub4 MEMBER mBlub NOTIFY blub4Changed)
Q_PRIVATE_PROPERTY(PrivatePropertyTest::d, QString blub5 MEMBER mBlub NOTIFY blub5Changed)
Q_PRIVATE_PROPERTY(PrivatePropertyTest::d, QString blub6 MEMBER mConst CONSTANT)
Q_PRIVATE_PROPERTY(PrivatePropertyTest::d, int zap READ zap WRITE setZap BINDABLE bindableZap)
class MyDPointer {
public:
MyDPointer() : mConst("const"), mBar(0), mPlop(0) {}
int bar() { return mBar ; }
void setBar(int value) { mBar = value; }
int plop() { return mPlop ; }
void setPlop(int value) { mPlop = value; }
int baz() { return mBaz ; }
void setBaz(int value) { mBaz = value; }
QString blub() const { return mBlub; }
void setBlub(const QString &value) { mBlub = value; }
int zap() { return mZap; }
void setZap(int zap) { mZap = zap; }
QBindable<int> bindableZap() { return QBindable<int>(&mZap); }
QString mBlub;
const QString mConst;
private:
int mBar;
int mPlop;
int mBaz;
QProperty<int> mZap;
};
public:
PrivatePropertyTest(QObject *parent = nullptr) : QObject(parent), mFoo(0), d (new MyDPointer) {}
int foo() { return mFoo ; }
void setFoo(int value) { mFoo = value; }
MyDPointer *d_func() {return d.data();}
const MyDPointer *d_func() const {return d.data();}
signals:
void blub4Changed();
void blub5Changed(const QString &newBlub);
private:
int mFoo;
QScopedPointer<MyDPointer> d;
};
void tst_Moc::qprivateproperties()
{
PrivatePropertyTest test;
test.setProperty("foo", 1);
QCOMPARE(test.property("foo"), QVariant::fromValue(1));
test.setProperty("bar", 2);
QCOMPARE(test.property("bar"), QVariant::fromValue(2));
test.setProperty("plop", 3);
QCOMPARE(test.property("plop"), QVariant::fromValue(3));
test.setProperty("baz", 4);
QCOMPARE(test.property("baz"), QVariant::fromValue(4));
QMetaProperty zap = test.metaObject()->property(test.metaObject()->indexOfProperty("zap"));
QVERIFY(zap.isValid());
QVERIFY(zap.isBindable());
auto zapBindable = zap.bindable(&test);
QVERIFY(zapBindable.isBindable());
}
void tst_Moc::warnOnPropertyWithoutREAD()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
const QString header = m_sourceDirectory + QStringLiteral("/warn-on-property-without-read.h");
proc.start(m_moc, QStringList(header));
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QCOMPARE(mocWarning, header +
QString(":11:1: warning: Property declaration foo has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.\n"));
#else
QSKIP("Only tested on unix/gcc");
#endif
}
void tst_Moc::constructors()
{
const QMetaObject *mo = &CtorTestClass::staticMetaObject;
QCOMPARE(mo->constructorCount(), 3);
{
QMetaMethod mm = mo->constructor(0);
QCOMPARE(mm.access(), QMetaMethod::Public);
QCOMPARE(mm.methodType(), QMetaMethod::Constructor);
QCOMPARE(mm.methodSignature(), QByteArray("CtorTestClass(QObject*)"));
QCOMPARE(mm.typeName(), "");
QList<QByteArray> paramNames = mm.parameterNames();
QCOMPARE(paramNames.size(), 1);
QCOMPARE(paramNames.at(0), QByteArray("parent"));
QList<QByteArray> paramTypes = mm.parameterTypes();
QCOMPARE(paramTypes.size(), 1);
QCOMPARE(paramTypes.at(0), QByteArray("QObject*"));
}
{
QMetaMethod mm = mo->constructor(1);
QCOMPARE(mm.access(), QMetaMethod::Public);
QCOMPARE(mm.methodType(), QMetaMethod::Constructor);
QCOMPARE(mm.methodSignature(), QByteArray("CtorTestClass()"));
QCOMPARE(mm.typeName(), "");
QCOMPARE(mm.parameterNames().size(), 0);
QCOMPARE(mm.parameterTypes().size(), 0);
}
{
QMetaMethod mm = mo->constructor(2);
QCOMPARE(mm.access(), QMetaMethod::Public);
QCOMPARE(mm.methodType(), QMetaMethod::Constructor);
QCOMPARE(mm.methodSignature(), QByteArray("CtorTestClass(QString)"));
QCOMPARE(mm.typeName(), "");
QList<QByteArray> paramNames = mm.parameterNames();
QCOMPARE(paramNames.size(), 1);
QCOMPARE(paramNames.at(0), QByteArray("str"));
QList<QByteArray> paramTypes = mm.parameterTypes();
QCOMPARE(paramTypes.size(), 1);
QCOMPARE(paramTypes.at(0), QByteArray("QString"));
}
QCOMPARE(mo->indexOfConstructor("CtorTestClass(QObject*)"), 0);
QCOMPARE(mo->indexOfConstructor("CtorTestClass()"), 1);
QCOMPARE(mo->indexOfConstructor("CtorTestClass(QString)"), 2);
QCOMPARE(mo->indexOfConstructor("CtorTestClass2(QObject*)"), -1);
QCOMPARE(mo->indexOfConstructor("CtorTestClass(float,float)"), -1);
QScopedPointer<QObject> o1(mo->newInstance());
QVERIFY(o1 != 0);
QCOMPARE(o1->parent(), (QObject*)0);
QVERIFY(qobject_cast<CtorTestClass*>(o1.data()) != 0);
QObject *o2 = mo->newInstance(Q_ARG(QObject*, o1.data()));
QVERIFY(o2 != 0);
QCOMPARE(o2->parent(), o1.data());
QString str = QString::fromLatin1("hello");
QScopedPointer<QObject> o3(mo->newInstance(Q_ARG(QString, str)));
QVERIFY(o3 != 0);
QCOMPARE(qobject_cast<CtorTestClass*>(o3.data())->m_str, str);
{
//explicit constructor
QObject *o = QObject::staticMetaObject.newInstance();
QVERIFY(o);
delete o;
}
}
#include "task234909.h"
#include "task240368.h"
void tst_Moc::typenameWithUnsigned()
{
TypenameWithUnsigned tst;
const QMetaObject *mobj = tst.metaObject();
QVERIFY(mobj->indexOfSlot("a(uint)") != -1);
QVERIFY(mobj->indexOfSlot("b(uint)") != -1);
QVERIFY(mobj->indexOfSlot("c(uint*)") != -1);
QVERIFY(mobj->indexOfSlot("d(uint*)") != -1);
QVERIFY(mobj->indexOfSlot("e(uint&)") != -1);
QVERIFY(mobj->indexOfSlot("f(uint&)") != -1);
QVERIFY(mobj->indexOfSlot("g(unsigned1)") != -1);
QVERIFY(mobj->indexOfSlot("h(unsigned1)") != -1);
QVERIFY(mobj->indexOfSlot("i(uint,unsigned1)") != -1);
QVERIFY(mobj->indexOfSlot("j(unsigned1,uint)") != -1);
QVERIFY(mobj->indexOfSlot("k(unsignedQImage)") != -1);
QVERIFY(mobj->indexOfSlot("l(unsignedQImage)") != -1);
}
void tst_Moc::warnOnVirtualSignal()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
const QString header = m_sourceDirectory + QStringLiteral("/pure-virtual-signals.h");
proc.start(m_moc, QStringList(header));
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
QCOMPARE(mocWarning, header + QString(":13:1: warning: Signals cannot be declared virtual\n") +
header + QString(":15:1: warning: Signals cannot be declared virtual\n"));
#else
QSKIP("Only tested on unix/gcc");
#endif
}
class QTBUG5590_DummyObject: public QObject
{
Q_OBJECT
Q_PROPERTY(bool dummy)
};
class QTBUG5590_PropertyObject: public QTBUG5590_DummyObject
{
Q_OBJECT
Q_PROPERTY(int value READ value WRITE setValue)
Q_PROPERTY(int value2 READ value2 WRITE setValue2)
public:
QTBUG5590_PropertyObject() : m_value(85), m_value2(40) { }
int value() const { return m_value; }
void setValue(int value) { m_value = value; }
int value2() const { return m_value2; }
void setValue2(int value) { m_value2 = value; }
private:
int m_value, m_value2;
};
void tst_Moc::QTBUG5590_dummyProperty()
{
QTBUG5590_PropertyObject o;
QCOMPARE(o.property("value").toInt(), 85);
QCOMPARE(o.property("value2").toInt(), 40);
o.setProperty("value", 32);
QCOMPARE(o.value(), 32);
o.setProperty("value2", 82);
QCOMPARE(o.value2(), 82);
}
QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG("-Wignored-qualifiers")
QT_WARNING_DISABLE_GCC("-Wignored-qualifiers")
class QTBUG7421_ReturnConstTemplate: public QObject
{ Q_OBJECT
public slots:
const QList<int> returnConstTemplate1() { return QList<int>(); }
QList<int> const returnConstTemplate2() { return QList<int>(); }
const int returnConstInt() { return 0; }
const QString returnConstString(const QString s) { return s; }
QString const returnConstString2( QString const s) { return s; }
};
QT_WARNING_POP
struct science_constant {};
struct science_const {};
struct constconst {};
struct const_ {};
class QTBUG9354_constInName: public QObject
{ Q_OBJECT
public slots:
void slotChooseScientificConst0(science_constant const &) {};
void foo(science_const const &) {};
void foo(constconst const &) {};
void foo(constconst *) {};
void foo(const_ *) {};
};
template<typename T1, typename T2>
class TestTemplate2
{
};
class QTBUG11647_constInTemplateParameter : public QObject
{ Q_OBJECT
public slots:
void testSlot(TestTemplate2<const int, const short*>) {}
void testSlot2(TestTemplate2<int, short const * const >) {}
void testSlot3(TestTemplate2<TestTemplate2 < const int, const short* > const *,
TestTemplate2< TestTemplate2 < void, int > , unsigned char *> > ) {}
signals:
void testSignal(TestTemplate2<const int, const short*>);
};
class QTBUG12260_defaultTemplate_Object : public QObject
{ Q_OBJECT
public slots:
void doSomething(QHash<QString, QVariant> = QHash<QString, QVariant>() ) {}
void doSomethingElse(QSharedPointer<QVarLengthArray<QString, (16 >> 2)> >
= QSharedPointer<QVarLengthArray<QString, (16 >> 2)> >() ) {}
void doAnotherThing(bool = (1 < 3), bool = (1 > 4)) {}
void performSomething(QList<QList<QString>> = QList<QList<QString>>(8 < 1),
QHash<int, QList<QString>> = QHash<int, QList<QString>>()) {}
};
void tst_Moc::QTBUG12260_defaultTemplate()
{
QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("doSomething(QHash<QString,QVariant>)") != -1);
QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("doAnotherThing(bool,bool)") != -1);
QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("doSomethingElse(QSharedPointer<QVarLengthArray<QString,(16>>2)>>)") != -1);
QVERIFY(QTBUG12260_defaultTemplate_Object::staticMetaObject.indexOfSlot("performSomething(QList<QList<QString>>,QHash<int,QList<QString>>)") != -1);
}
void tst_Moc::notifyError()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
const QString header = m_sourceDirectory + QStringLiteral("/error-on-wrong-notify.h");
proc.start(m_moc, QStringList(header));
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QCOMPARE(proc.exitStatus(), QProcess::NormalExit);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
QCOMPARE(proc.readAllStandardError(), QByteArray());
QStringList args;
args << "-c" << "-x" << "c++" << "-I" << "."
<< "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-std=c++1z" << "-";
proc.start("gcc", args);
QVERIFY(proc.waitForStarted());
proc.write(mocOut);
proc.closeWriteChannel();
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 1);
const QString gccOutput = QString::fromLocal8Bit(proc.readAllStandardError());
QVERIFY(gccOutput.contains(QLatin1String("error")));
QVERIFY(gccOutput.contains(QLatin1String("fooChanged")));
#else
QSKIP("Only tested on linux/gcc");
#endif
}
class QTBUG_17635_InvokableAndProperty : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(int numberOfEggs READ numberOfEggs)
Q_PROPERTY(int numberOfChickens READ numberOfChickens)
Q_INVOKABLE QString getEgg(int index) { Q_UNUSED(index); return QString::fromLatin1("Egg"); }
Q_INVOKABLE QString getChicken(int index) { Q_UNUSED(index); return QString::fromLatin1("Chicken"); }
int numberOfEggs() { return 2; }
int numberOfChickens() { return 4; }
};
void tst_Moc::QTBUG17635_invokableAndProperty()
{
//Moc used to fail parsing Q_INVOKABLE if they were dirrectly following a Q_PROPERTY;
QTBUG_17635_InvokableAndProperty mc;
QString val;
QMetaObject::invokeMethod(&mc, "getEgg", Q_RETURN_ARG(QString, val), Q_ARG(int, 10));
QCOMPARE(val, QString::fromLatin1("Egg"));
QMetaObject::invokeMethod(&mc, "getChicken", Q_RETURN_ARG(QString, val), Q_ARG(int, 10));
QCOMPARE(val, QString::fromLatin1("Chicken"));
QVERIFY(mc.metaObject()->indexOfProperty("numberOfEggs") != -1);
QVERIFY(mc.metaObject()->indexOfProperty("numberOfChickens") != -1);
}
// If changed, update VersionTestNotify below
class VersionTest : public QObject
{
Q_OBJECT
Q_PROPERTY(int prop1 READ foo)
Q_PROPERTY(int prop2 READ foo REVISION 2)
Q_PROPERTY(int prop514 READ foo REVISION(5, 14))
public:
int foo() const { return 0; }
Q_INVOKABLE void method1() {}
Q_INVOKABLE Q_REVISION(4) void method2() {}
Q_INVOKABLE Q_REVISION(6, 0) void method60() {}
enum TestEnum { One, Two };
Q_ENUM(TestEnum);
public slots:
void slot1() {}
Q_REVISION(3) void slot2() {}
Q_REVISION(6, 1) void slot61() {}
signals:
void signal1();
Q_REVISION(5) void signal2();
Q_REVISION(6, 2) void signal62();
public slots Q_REVISION(6):
void slot3() {}
void slot4() {}
public slots Q_REVISION(5, 12):
void slot512() {}
signals Q_REVISION(7):
void signal3();
void signal4();
signals Q_REVISION(5, 15):
void signal515();
};
// If changed, update VersionTest above
class VersionTestNotify : public QObject
{
Q_OBJECT
Q_PROPERTY(int prop1 READ foo NOTIFY fooChanged)
Q_PROPERTY(int prop2 READ foo REVISION 2)
Q_PROPERTY(int prop514 READ foo REVISION(5, 14))
public:
int foo() const { return 0; }
Q_INVOKABLE void method1() {}
Q_INVOKABLE Q_REVISION(4) void method2() {}
Q_INVOKABLE Q_REVISION(6, 0) void method60() {}
enum TestEnum { One, Two };
Q_ENUM(TestEnum);
public slots:
void slot1() {}
Q_REVISION(3) void slot2() {}
Q_REVISION(6, 1) void slot61() {}
signals:
void fooChanged();
void signal1();
Q_REVISION(5) void signal2();
Q_REVISION(6, 2) void signal62();
public slots Q_REVISION(6):
void slot3() {}
void slot4() {}
public slots Q_REVISION(5, 12):
void slot512() {}
signals Q_REVISION(7):
void signal3();
void signal4();
signals Q_REVISION(5, 15):
void signal515();
};
template <class T>
void tst_Moc::revisions_T()
{
int idx = T::staticMetaObject.indexOfProperty("prop1");
QCOMPARE(T::staticMetaObject.property(idx).revision(), 0);
idx = T::staticMetaObject.indexOfProperty("prop2");
QCOMPARE(T::staticMetaObject.property(idx).revision(),
QTypeRevision::fromMinorVersion(2).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfProperty("prop514");
QCOMPARE(T::staticMetaObject.property(idx).revision(),
QTypeRevision::fromVersion(5, 14).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfMethod("method1()");
QCOMPARE(T::staticMetaObject.method(idx).revision(), 0);
idx = T::staticMetaObject.indexOfMethod("method2()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromMinorVersion(4).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfMethod("method60()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromVersion(6, 0).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfSlot("slot1()");
QCOMPARE(T::staticMetaObject.method(idx).revision(), 0);
idx = T::staticMetaObject.indexOfSlot("slot2()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromMinorVersion(3).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfSlot("slot61()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromVersion(6, 1).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfSlot("slot3()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromMinorVersion(6).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfSlot("slot4()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromMinorVersion(6).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfSlot("slot512()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromVersion(5, 12).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfSignal("signal1()");
QCOMPARE(T::staticMetaObject.method(idx).revision(), 0);
idx = T::staticMetaObject.indexOfSignal("signal2()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromMinorVersion(5).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfSignal("signal62()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromVersion(6, 2).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfSignal("signal3()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromMinorVersion(7).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfSignal("signal4()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromMinorVersion(7).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfSignal("signal515()");
QCOMPARE(T::staticMetaObject.method(idx).revision(),
QTypeRevision::fromVersion(5, 15).toEncodedVersion<int>());
idx = T::staticMetaObject.indexOfEnumerator("TestEnum");
QCOMPARE(T::staticMetaObject.enumerator(idx).keyCount(), 2);
QCOMPARE(T::staticMetaObject.enumerator(idx).key(0), "One");
}
// test using both class that has properties with and without NOTIFY signals
void tst_Moc::revisions()
{
revisions_T<VersionTest>();
revisions_T<VersionTestNotify>();
}
void tst_Moc::warnings_data()
{
QTest::addColumn<QByteArray>("input");
QTest::addColumn<QStringList>("args");
QTest::addColumn<int>("exitCode");
QTest::addColumn<QString>("expectedStdOut");
QTest::addColumn<QString>("expectedStdErr");
// empty input should result in "no relevant classes" note
QTest::newRow("No relevant classes")
<< QByteArray(" ")
<< QStringList()
<< 0
<< QString()
<< QString("standard input:0:1: note: No relevant classes found. No output generated.");
// passing "-nn" should suppress "no relevant classes" note
QTest::newRow("-nn")
<< QByteArray(" ")
<< (QStringList() << "-nn")
<< 0
<< QString()
<< QString();
// passing "-nw" should also suppress "no relevant classes" note
QTest::newRow("-nw")
<< QByteArray(" ")
<< (QStringList() << "-nw")
<< 0
<< QString()
<< QString();
// This should output a warning
QTest::newRow("Invalid property warning")
<< QByteArray("class X : public QObject { Q_OBJECT Q_PROPERTY(int x) };")
<< QStringList()
<< 0
<< QString("IGNORE_ALL_STDOUT")
<< QString("standard input:1:1: warning: Property declaration x has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.");
// This should output a warning
QTest::newRow("Duplicate property warning")
<< QByteArray("class X : public QObject { Q_OBJECT Q_PROPERTY(int x READ x) Q_PROPERTY(int x READ y) };")
<< QStringList()
<< 0
<< QString("IGNORE_ALL_STDOUT")
<< QString("standard input:1:1: warning: The property 'x' is defined multiple times in class X.");
// Passing "-nn" should NOT suppress the warning
QTest::newRow("Invalid property warning with -nn")
<< QByteArray("class X : public QObject { Q_OBJECT Q_PROPERTY(int x) };")
<< (QStringList() << "-nn")
<< 0
<< QString("IGNORE_ALL_STDOUT")
<< QString("standard input:1:1: warning: Property declaration x has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.");
// Passing "-nw" should suppress the warning
QTest::newRow("Invalid property warning with -nw")
<< QByteArray("class X : public QObject { Q_OBJECT Q_PROPERTY(int x) };")
<< (QStringList() << "-nw")
<< 0
<< QString("IGNORE_ALL_STDOUT")
<< QString();
// This should output an error
QTest::newRow("Does not inherit QObject")
<< QByteArray("class X { Q_OBJECT };")
<< QStringList()
<< 1
<< QString()
<< QString("standard input:1:1: error: Class contains Q_OBJECT macro but does not inherit from QObject");
// "-nn" should not suppress the error
QTest::newRow("Does not inherit QObject with -nn")
<< QByteArray("class X { Q_OBJECT };")
<< (QStringList() << "-nn")
<< 1
<< QString()
<< QString("standard input:1:1: error: Class contains Q_OBJECT macro but does not inherit from QObject");
// "-nw" should not suppress the error
QTest::newRow("Does not inherit QObject with -nw")
<< QByteArray("class X { Q_OBJECT };")
<< (QStringList() << "-nw")
<< 1
<< QString()
<< QString("standard input:1:1: error: Class contains Q_OBJECT macro but does not inherit from QObject");
QTest::newRow("Warning on invalid macro")
<< QByteArray("#define Foo(a, b)\n class X : public QObject { Q_OBJECT }; \n Foo(a) \n Foo(a,b,c) \n")
<< QStringList()
<< 0
<< QString("IGNORE_ALL_STDOUT")
<< QString();
QTest::newRow("Class declaration lacks Q_OBJECT macro.")
<< QByteArray("class X : public QObject \n { \n public slots: \n void foo() {} \n };")
<< QStringList()
<< 1
<< QString()
<< QString("standard input:5:1: error: Class declaration lacks Q_OBJECT macro.");
QTest::newRow("Namespace declaration lacks Q_NAMESPACE macro.")
<< QByteArray("namespace X {\nQ_CLASSINFO(\"key\",\"value\")\nenum class MyEnum {Key1 = 1}\nQ_ENUMS(MyEnum)\n}\n")
<< QStringList()
<< 1
<< QString()
<< QString("standard input:1:1: error: Namespace declaration lacks Q_NAMESPACE macro.");
QTest::newRow("Wrong Q_ENUM context.")
<< QByteArray("namespace X {\nQ_NAMESPACE\n\nenum class MyEnum {Key1 = 1}\nQ_ENUM(MyEnum)\n}\n")
<< QStringList()
<< 1
<< QString()
<< QString("standard input:5:1: error: Q_ENUM can't be used in a Q_NAMESPACE, use Q_ENUM_NS instead");
QTest::newRow("Wrong Q_FLAG context.")
<< QByteArray("namespace X {\nQ_NAMESPACE\n\nenum class MyEnum {Key1 = 1}\nQ_FLAG(MyEnum)\n}\n")
<< QStringList()
<< 1
<< QString()
<< QString("standard input:5:1: error: Q_FLAG can't be used in a Q_NAMESPACE, use Q_FLAG_NS instead");
QTest::newRow("Wrong Q_ENUM_NS context.")
<< QByteArray("class X {\nQ_GADGET\n\nenum class MyEnum {Key1 = 1}\nQ_ENUM_NS(MyEnum)\n};\n")
<< QStringList()
<< 1
<< QString()
<< QString("standard input:5:1: error: Q_ENUM_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_ENUM instead");
QTest::newRow("Wrong Q_FLAG_NS context.")
<< QByteArray("class X {\nQ_GADGET\n\nenum class MyEnum {Key1 = 1}\nQ_FLAG_NS(MyEnum)\n};\n")
<< QStringList()
<< 1
<< QString()
<< QString("standard input:5:1: error: Q_FLAG_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_FLAG instead");
QTest::newRow("Invalid macro definition")
<< QByteArray("#define Foo(a, b, c) a b c #a #b #c a##b##c #d\n Foo(45, 42, 39);")
<< QStringList()
<< 1
<< QString("IGNORE_ALL_STDOUT")
<< QString(":2:1: error: '#' is not followed by a macro parameter");
QTest::newRow("QTBUG-46210: crash on invalid macro invocation")
<< QByteArray("#define Foo(a, b, c) a b c #a #b #c a##b##c\n Foo(45);")
<< QStringList()
<< 1
<< QString("IGNORE_ALL_STDOUT")
<< QString(":2:1: error: Macro invoked with too few parameters for a use of '#'");
QTest::newRow("QTBUG-54609: crash on invalid input")
<< QByteArray::fromBase64("EAkJCQkJbGFzcyBjbGFzcyBiYWkcV2kgTUEKcGYjZGVmaW5lIE1BKFEs/4D/FoQ=")
<< QStringList()
<< 1
<< QString("IGNORE_ALL_STDOUT")
<< QString(":-1:1: error: Unexpected character in macro argument list.");
QTest::newRow("Missing header warning")
<< QByteArray("class X : public QObject { Q_OBJECT };")
<< (QStringList() << QStringLiteral("--include") << QStringLiteral("doesnotexist.h"))
<< 0
<< QString("IGNORE_ALL_STDOUT")
<< QStringLiteral("Warning: Failed to resolve include \"doesnotexist.h\" for moc file <standard input>");
QTest::newRow("QTBUG-54815: Crash on invalid input")
<< QByteArray("class M{(})F<{}d000000000000000#0")
<< QStringList()
<< 0
<< QString()
<< QString("standard input:1:1: note: No relevant classes found. No output generated.");
QTest::newRow("Q_PLUGIN_METADATA: invalid file")
<< QByteArray("class X { \n Q_PLUGIN_METADATA(FILE \"does.not.exists\") \n };")
<< QStringList()
<< 1
<< QString()
<< QString("standard input:2:1: error: Plugin Metadata file \"does.not.exists\" does not exist. Declaration will be ignored");
QTest::newRow("Auto-declared, missing trailing return")
<< QByteArray("class X { \n public slots: \n auto fun() { return 1; } };")
<< QStringList()
<< 1
<< QString()
<< QString("standard input:3:1: error: Function declared with auto as return type but missing trailing return type. Return type deduction is not supported.");
QTest::newRow("Auto-declared, volatile auto as trailing return type")
<< QByteArray("class X { \n public slots: \n auto fun() -> volatile auto { return 1; } };")
<< QStringList()
<< 1
<< QString()
<< QString("standard input:3:1: error: Function declared with auto as return type but missing trailing return type. Return type deduction is not supported.");
// We don't currently support the decltype keyword, so it's not the same error as above.
// The test is just here to make sure this keeps generating an error until return type deduction
// is supported.
QTest::newRow("Auto-declared, decltype in trailing return type")
<< QByteArray("class X { \n public slots: \n auto fun() -> decltype(0+1) { return 1; } };")
<< QStringList()
<< 1
<< 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 };")
<< QStringList()
<< 1
<< QString()
<< QString("standard input:2:1: error: Plugin Metadata file \".\" could not be opened: file to open is a directory");
#endif
}
void tst_Moc::warnings()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
QFETCH(QByteArray, input);
QFETCH(QStringList, args);
QFETCH(int, exitCode);
QFETCH(QString, expectedStdOut);
QFETCH(QString, expectedStdErr);
#ifdef Q_CC_MSVC
// moc compiled with MSVC uses a different output format to match MSVC compiler style
QRegularExpression lineNumberRe(":(-?\\d+):(\\d+)", QRegularExpression::InvertedGreedinessOption);
expectedStdErr.replace(lineNumberRe, "(\\1:\\2)");
#endif
#if QT_CONFIG(process)
QProcess proc;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("QT_MESSAGE_PATTERN", "no qDebug or qWarning please");
proc.setProcessEnvironment(env);
proc.start(m_moc, args);
QVERIFY(proc.waitForStarted());
QCOMPARE(proc.write(input), qint64(input.size()));
proc.closeWriteChannel();
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), exitCode);
QCOMPARE(proc.exitStatus(), QProcess::NormalExit);
// magic value "IGNORE_ALL_STDOUT" ignores stdout
if (expectedStdOut != "IGNORE_ALL_STDOUT")
QCOMPARE(QString::fromLocal8Bit(proc.readAllStandardOutput()).trimmed(), expectedStdOut);
QCOMPARE(QString::fromLocal8Bit(proc.readAllStandardError()).trimmed().remove('\r'), expectedStdErr);
#else
QSKIP("Only tested if QProcess is available");
#endif
}
class tst_Moc::PrivateClass : public QObject {
Q_PROPERTY(int someProperty READ someSlot WRITE someSlot2)
Q_OBJECT
Q_SIGNALS:
void someSignal();
public Q_SLOTS:
int someSlot() { return 1; }
void someSlot2(int) {}
public:
Q_INVOKABLE PrivateClass() {}
};
void tst_Moc::privateClass()
{
QCOMPARE(PrivateClass::staticMetaObject.indexOfConstructor("PrivateClass()"), 0);
QVERIFY(PrivateClass::staticMetaObject.indexOfSignal("someSignal()") > 0);
}
void tst_Moc::cxx11Enums_data()
{
QTest::addColumn<const QMetaObject *>("meta");
QTest::addColumn<QByteArray>("typeName");
QTest::addColumn<QByteArray>("enumName");
QTest::addColumn<char>("prefix");
QTest::addColumn<bool>("isScoped");
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;
}
void tst_Moc::cxx11Enums()
{
QFETCH(const QMetaObject *,meta);
QCOMPARE(meta->enumeratorOffset(), 0);
QFETCH(QByteArray, typeName);
QFETCH(QByteArray, enumName);
QFETCH(char, prefix);
QFETCH(bool, isScoped);
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();
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(meta->enumerator(idx).isScoped(), isScoped);
}
void tst_Moc::cxx11TrailingReturn()
{
CXX11TrailingReturn retClass;
const QMetaObject *mobj = retClass.metaObject();
QVERIFY(mobj->indexOfSlot("fun()") != -1);
QVERIFY(mobj->indexOfSlot("arguments(int,char)") != -1);
QVERIFY(mobj->indexOfSlot("inlineFunc(int)") != -1);
QVERIFY(mobj->indexOfSlot("constRefReturn()") != -1);
QVERIFY(mobj->indexOfSlot("constConstRefReturn()") != -1);
QVERIFY(mobj->indexOfSignal("trailingSignalReturn(int)") != -1);
}
void tst_Moc::returnRefs()
{
TestClass tst;
const QMetaObject *mobj = tst.metaObject();
QVERIFY(mobj->indexOfMethod("myInvokableReturningRef()") != -1);
QVERIFY(mobj->indexOfMethod("myInvokableReturningConstRef()") != -1);
// Those two functions are copied from the qscriptextqobject test in qtscript
// they used to cause miscompilation of the moc generated file.
}
void tst_Moc::memberProperties_data()
{
QTest::addColumn<int>("object");
QTest::addColumn<QString>("property");
QTest::addColumn<QString>("signal");
QTest::addColumn<QString>("writeValue");
QTest::addColumn<bool>("expectedWriteResult");
QTest::addColumn<QString>("expectedReadResult");
pPPTest = new PrivatePropertyTest( this );
QTest::newRow("MEMBER property")
<< 0 << "member1" << "" << "abc" << true << "abc";
QTest::newRow("MEMBER property with READ function")
<< 0 << "member2" << "" << "def" << true << "def";
QTest::newRow("MEMBER property with WRITE function")
<< 0 << "member3" << "" << "ghi" << true << "ghi";
QTest::newRow("MEMBER property with NOTIFY")
<< 0 << "member4" << "member4Changed()" << "lmn" << true << "lmn";
QTest::newRow("MEMBER property with NOTIFY(value)")
<< 0 << "member5" << "member5Changed(const QString&)" << "opq" << true << "opq";
QTest::newRow("MEMBER property with CONSTANT")
<< 0 << "member6" << "" << "test" << false << "const";
QTest::newRow("private MEMBER property")
<< 1 << "blub" << "" << "abc" << true << "abc";
QTest::newRow("private MEMBER property with READ function")
<< 1 << "blub2" << "" << "def" << true << "def";
QTest::newRow("private MEMBER property with WRITE function")
<< 1 << "blub3" << "" << "ghi" << true << "ghi";
QTest::newRow("private MEMBER property with NOTIFY")
<< 1 << "blub4" << "blub4Changed()" << "jkl" << true << "jkl";
QTest::newRow("private MEMBER property with NOTIFY(value)")
<< 1 << "blub5" << "blub5Changed(const QString&)" << "mno" << true << "mno";
QTest::newRow("private MEMBER property with CONSTANT")
<< 1 << "blub6" << "" << "test" << false << "const";
QTest::newRow("sub1")
<< 0 << "sub1" << "" << "helloSub1" << true << "helloSub1";
QTest::newRow("sub2")
<< 0 << "sub2" << "" << "helloSub2" << true << "helloSub2";
}
void tst_Moc::memberProperties()
{
QFETCH(int, object);
QFETCH(QString, property);
QFETCH(QString, signal);
QFETCH(QString, writeValue);
QFETCH(bool, expectedWriteResult);
QFETCH(QString, expectedReadResult);
QObject *pObj = (object == 0) ? this : static_cast<QObject*>(pPPTest);
QString sSignalDeclaration;
if (!signal.isEmpty())
sSignalDeclaration = QString(SIGNAL(%1)).arg(signal);
else
QTest::ignoreMessage(QtWarningMsg, "QSignalSpy: Not a valid signal, use the SIGNAL macro");
QSignalSpy notifySpy(pObj, sSignalDeclaration.toLatin1().constData());
int index = pObj->metaObject()->indexOfProperty(property.toLatin1().constData());
QVERIFY(index != -1);
QMetaProperty prop = pObj->metaObject()->property(index);
QCOMPARE(prop.write(pObj, writeValue), expectedWriteResult);
QVariant readValue = prop.read(pObj);
QCOMPARE(readValue.toString(), expectedReadResult);
if (!signal.isEmpty())
{
QCOMPARE(notifySpy.size(), 1);
if (prop.notifySignal().parameterNames().size() > 0) {
QList<QVariant> arguments = notifySpy.takeFirst();
QCOMPARE(arguments.size(), 1);
QCOMPARE(arguments.at(0).toString(), expectedReadResult);
}
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.size(), 0);
}
}
//this used to fail to compile
class ClassWithOneMember : public QObject {
Q_PROPERTY(int member MEMBER member)
Q_OBJECT
public:
int member;
};
void tst_Moc::memberProperties2()
{
ClassWithOneMember o;
o.member = 442;
QCOMPARE(o.property("member").toInt(), 442);
QVERIFY(o.setProperty("member", 6666));
QCOMPARE(o.member, 6666);
}
class SignalConnectionTester : public QObject
{
Q_OBJECT
public:
SignalConnectionTester(QObject *parent = nullptr)
: QObject(parent), testPassed(false)
{
}
public Q_SLOTS:
void testSlot()
{
testPassed = true;
}
void testSlotWith1Arg(int i)
{
testPassed = i == 42;
}
void testSlotWith2Args(int i, const QString &s)
{
testPassed = i == 42 && s == "Hello";
}
public:
bool testPassed;
};
class ClassWithPrivateSignals : public QObject
{
Q_OBJECT
public:
ClassWithPrivateSignals(QObject *parent = nullptr)
: QObject(parent)
{
}
void emitPrivateSignals()
{
emit privateSignal1(QPrivateSignal());
emit privateSignalWith1Arg(42, QPrivateSignal());
emit privateSignalWith2Args(42, "Hello", QPrivateSignal());
emit privateOverloadedSignal(QPrivateSignal());
emit privateOverloadedSignal(42, QPrivateSignal());
emit overloadedMaybePrivate();
emit overloadedMaybePrivate(42, QPrivateSignal());
}
Q_SIGNALS:
void privateSignal1(QPrivateSignal);
void privateSignalWith1Arg(int arg1, QPrivateSignal);
void privateSignalWith2Args(int arg1, const QString &arg2, QPrivateSignal);
void privateOverloadedSignal(QPrivateSignal);
void privateOverloadedSignal(int, QPrivateSignal);
void overloadedMaybePrivate();
void overloadedMaybePrivate(int, QPrivateSignal);
};
class SubClassFromPrivateSignals : public ClassWithPrivateSignals
{
Q_OBJECT
public:
SubClassFromPrivateSignals(QObject *parent = nullptr)
: ClassWithPrivateSignals(parent)
{
}
void emitProtectedSignals()
{
// Compile test: All of this intentionally does not compile:
// emit privateSignal1();
// emit privateSignalWith1Arg(42);
// emit privateSignalWith2Args(42, "Hello");
//
// emit privateSignal1(QPrivateSignal());
// emit privateSignalWith1Arg(42, QPrivateSignal());
// emit privateSignalWith2Args(42, "Hello", QPrivateSignal());
//
// emit privateSignal1(ClassWithPrivateSignals::QPrivateSignal());
// emit privateSignalWith1Arg(42, ClassWithPrivateSignals::QPrivateSignal());
// emit privateSignalWith2Args(42, "Hello", ClassWithPrivateSignals::QPrivateSignal());
// emit privateOverloadedSignal();
// emit privateOverloadedSignal(42);
// emit overloadedMaybePrivate();
// emit overloadedMaybePrivate(42);
}
};
void tst_Moc::privateSignalConnection()
{
// Function pointer connects. Matching signals and slots
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, &ClassWithPrivateSignals::privateSignal1, &tester, &SignalConnectionTester::testSlot);
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
tester.testPassed = false;
QMetaObject::invokeMethod(&classWithPrivateSignals, "privateSignal1");
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, &ClassWithPrivateSignals::privateSignal1, &tester, &SignalConnectionTester::testSlot);
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
tester.testPassed = false;
QMetaObject::invokeMethod(&subClassFromPrivateSignals, "privateSignal1");
QVERIFY(tester.testPassed);
}
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, &ClassWithPrivateSignals::privateSignalWith1Arg, &tester, &SignalConnectionTester::testSlotWith1Arg);
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
tester.testPassed = false;
QMetaObject::invokeMethod(&classWithPrivateSignals, "privateSignalWith1Arg", Q_ARG(int, 42));
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, &ClassWithPrivateSignals::privateSignalWith1Arg, &tester, &SignalConnectionTester::testSlotWith1Arg);
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
tester.testPassed = false;
QMetaObject::invokeMethod(&subClassFromPrivateSignals, "privateSignalWith1Arg", Q_ARG(int, 42));
QVERIFY(tester.testPassed);
}
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, &ClassWithPrivateSignals::privateSignalWith2Args, &tester, &SignalConnectionTester::testSlotWith2Args);
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
tester.testPassed = false;
QMetaObject::invokeMethod(&classWithPrivateSignals, "privateSignalWith2Args", Q_ARG(int, 42), Q_ARG(QString, "Hello"));
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, &ClassWithPrivateSignals::privateSignalWith2Args, &tester, &SignalConnectionTester::testSlotWith2Args);
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
tester.testPassed = false;
QMetaObject::invokeMethod(&subClassFromPrivateSignals, "privateSignalWith2Args", Q_ARG(int, 42), Q_ARG(QString, "Hello"));
QVERIFY(tester.testPassed);
}
// String based connects. Matching signals and slots
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, SIGNAL(privateSignal1()), &tester, SLOT(testSlot()));
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, SIGNAL(privateSignal1()), &tester, SLOT(testSlot()));
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, SIGNAL(privateSignalWith1Arg(int)), &tester, SLOT(testSlotWith1Arg(int)));
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, SIGNAL(privateSignalWith1Arg(int)), &tester, SLOT(testSlotWith1Arg(int)));
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, SIGNAL(privateSignalWith2Args(int,QString)), &tester, SLOT(testSlotWith2Args(int,QString)));
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, SIGNAL(privateSignalWith2Args(int,QString)), &tester, SLOT(testSlotWith2Args(int,QString)));
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
// Function pointer connects. Decayed slot arguments
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, &ClassWithPrivateSignals::privateSignalWith1Arg, &tester, &SignalConnectionTester::testSlot);
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, &ClassWithPrivateSignals::privateSignalWith1Arg, &tester, &SignalConnectionTester::testSlot);
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, &ClassWithPrivateSignals::privateSignalWith1Arg, &tester, &SignalConnectionTester::testSlotWith1Arg);
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, &ClassWithPrivateSignals::privateSignalWith1Arg, &tester, &SignalConnectionTester::testSlotWith1Arg);
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, &ClassWithPrivateSignals::privateSignalWith1Arg, &tester, &SignalConnectionTester::testSlot);
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, &ClassWithPrivateSignals::privateSignalWith1Arg, &tester, &SignalConnectionTester::testSlot);
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
// String based connects. Decayed slot arguments
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, SIGNAL(privateSignalWith1Arg(int)), &tester, SLOT(testSlot()));
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, SIGNAL(privateSignalWith1Arg(int)), &tester, SLOT(testSlot()));
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, SIGNAL(privateSignalWith2Args(int,QString)), &tester, SLOT(testSlotWith1Arg(int)));
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, SIGNAL(privateSignalWith2Args(int,QString)), &tester, SLOT(testSlotWith1Arg(int)));
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, SIGNAL(privateSignalWith2Args(int,QString)), &tester, SLOT(testSlot()));
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
SubClassFromPrivateSignals subClassFromPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&subClassFromPrivateSignals, SIGNAL(privateSignalWith2Args(int,QString)), &tester, SLOT(testSlot()));
QVERIFY(!tester.testPassed);
subClassFromPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
// Overloaded private signals
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, SIGNAL(privateOverloadedSignal()), &tester, SLOT(testSlot()));
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, SIGNAL(privateOverloadedSignal(int)), &tester, SLOT(testSlotWith1Arg(int)));
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
// We can't use function pointer connections to private signals which are overloaded because we would have to cast in this case to:
// static_cast<void (ClassWithPrivateSignals::*)(int, ClassWithPrivateSignals::QPrivateSignal)>(&ClassWithPrivateSignals::privateOverloadedSignal)
// Which doesn't work as ClassWithPrivateSignals::QPrivateSignal is private.
// Overload with either private or not private signals
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, SIGNAL(overloadedMaybePrivate()), &tester, SLOT(testSlot()));
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals, SIGNAL(privateOverloadedSignal(int)), &tester, SLOT(testSlotWith1Arg(int)));
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
{
ClassWithPrivateSignals classWithPrivateSignals;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals,
static_cast<void (ClassWithPrivateSignals::*)()>(&ClassWithPrivateSignals::overloadedMaybePrivate),
&tester, &SignalConnectionTester::testSlot);
QVERIFY(!tester.testPassed);
classWithPrivateSignals.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
// We can't use function pointer connections to private signals which are overloaded because we would have to cast in this case to:
// static_cast<void (ClassWithPrivateSignals::*)(int, ClassWithPrivateSignals::QPrivateSignal)>(&ClassWithPrivateSignals::overloadedMaybePrivate)
// Which doesn't work as ClassWithPrivateSignals::QPrivateSignal is private.
// Connecting from one private signal to another
{
ClassWithPrivateSignals classWithPrivateSignals1;
ClassWithPrivateSignals classWithPrivateSignals2;
SignalConnectionTester tester;
QObject::connect(&classWithPrivateSignals1, &ClassWithPrivateSignals::privateSignal1,
&classWithPrivateSignals2, &ClassWithPrivateSignals::privateSignal1);
QObject::connect(&classWithPrivateSignals2, &ClassWithPrivateSignals::privateSignal1,
&tester, &SignalConnectionTester::testSlot);
QVERIFY(!tester.testPassed);
classWithPrivateSignals1.emitPrivateSignals();
QVERIFY(tester.testPassed);
}
}
void tst_Moc::finalClasses_data()
{
QTest::addColumn<QString>("className");
QTest::addColumn<QString>("expected");
QTest::newRow("FinalTestClassQt") << FinalTestClassQt::staticMetaObject.className() << "FinalTestClassQt";
QTest::newRow("ExportedFinalTestClassQt") << ExportedFinalTestClassQt::staticMetaObject.className() << "ExportedFinalTestClassQt";
QTest::newRow("ExportedFinalTestClassQtX") << ExportedFinalTestClassQtX::staticMetaObject.className() << "ExportedFinalTestClassQtX";
QTest::newRow("FinalTestClassCpp11") << FinalTestClassCpp11::staticMetaObject.className() << "FinalTestClassCpp11";
QTest::newRow("ExportedFinalTestClassCpp11") << ExportedFinalTestClassCpp11::staticMetaObject.className() << "ExportedFinalTestClassCpp11";
QTest::newRow("ExportedFinalTestClassCpp11X") << ExportedFinalTestClassCpp11X::staticMetaObject.className() << "ExportedFinalTestClassCpp11X";
QTest::newRow("SealedTestClass") << SealedTestClass::staticMetaObject.className() << "SealedTestClass";
QTest::newRow("ExportedSealedTestClass") << ExportedSealedTestClass::staticMetaObject.className() << "ExportedSealedTestClass";
QTest::newRow("ExportedSealedTestClassX") << ExportedSealedTestClassX::staticMetaObject.className() << "ExportedSealedTestClassX";
}
void tst_Moc::finalClasses()
{
QFETCH(QString, className);
QFETCH(QString, expected);
QCOMPARE(className, expected);
}
void tst_Moc::explicitOverrideControl_data()
{
QTest::addColumn<const QMetaObject*>("mo");
#define ADD(x) QTest::newRow(#x) << &x::staticMetaObject
ADD(ExplicitOverrideControlFinalQt);
ADD(ExplicitOverrideControlFinalCxx11);
ADD(ExplicitOverrideControlSealed);
ADD(ExplicitOverrideControlOverrideQt);
ADD(ExplicitOverrideControlOverrideCxx11);
ADD(ExplicitOverrideControlFinalQtOverrideQt);
ADD(ExplicitOverrideControlFinalCxx11OverrideCxx11);
ADD(ExplicitOverrideControlSealedOverride);
#undef ADD
}
void tst_Moc::explicitOverrideControl()
{
QFETCH(const QMetaObject*, mo);
QVERIFY(mo);
QCOMPARE(mo->indexOfMethod("pureSlot0()"), mo->methodOffset() + 0);
QCOMPARE(mo->indexOfMethod("pureSlot1()"), mo->methodOffset() + 1);
QCOMPARE(mo->indexOfMethod("pureSlot2()"), mo->methodOffset() + 2);
QCOMPARE(mo->indexOfMethod("pureSlot3()"), mo->methodOffset() + 3);
#if 0 // moc doesn't support volatile slots
QCOMPARE(mo->indexOfMethod("pureSlot4()"), mo->methodOffset() + 4);
QCOMPARE(mo->indexOfMethod("pureSlot5()"), mo->methodOffset() + 5);
QCOMPARE(mo->indexOfMethod("pureSlot6()"), mo->methodOffset() + 6);
QCOMPARE(mo->indexOfMethod("pureSlot7()"), mo->methodOffset() + 7);
QCOMPARE(mo->indexOfMethod("pureSlot8()"), mo->methodOffset() + 8);
QCOMPARE(mo->indexOfMethod("pureSlot9()"), mo->methodOffset() + 9);
#endif
}
class OverloadedAddressOperator : public QObject
{
Q_OBJECT
public:
void* operator&() { return nullptr; }
signals:
void self(OverloadedAddressOperator&);
public slots:
void assertSelf(OverloadedAddressOperator &o)
{
QCOMPARE(std::addressof(o), this);
testResult = (std::addressof(o) == this);
}
public:
bool testResult = false;
};
void tst_Moc::overloadedAddressOperator()
{
OverloadedAddressOperator o;
OverloadedAddressOperator *p = std::addressof(o);
QCOMPARE(&o, nullptr);
QVERIFY(p);
QObject::connect(p, &OverloadedAddressOperator::self, p, &OverloadedAddressOperator::assertSelf);
emit o.self(o);
QVERIFY(o.testResult);
}
class CustomQObject : public QObject
{
Q_OBJECT
Q_ENUMS(Number)
public:
enum Number {
Zero,
One,
Two
};
explicit CustomQObject(QObject *parent = nullptr)
: QObject(parent)
{
}
};
Q_DECLARE_METATYPE(CustomQObject::Number)
typedef CustomQObject* CustomQObjectStar;
Q_DECLARE_METATYPE(CustomQObjectStar);
namespace SomeNamespace {
class NamespacedQObject : public QObject
{
Q_OBJECT
public:
explicit NamespacedQObject(QObject *parent = nullptr)
: QObject(parent)
{
}
};
struct NamespacedNonQObject {};
}
Q_DECLARE_METATYPE(SomeNamespace::NamespacedNonQObject)
// Need different types for the invokable method tests because otherwise the registration
// done in the property test would interfere.
class CustomQObject2 : public QObject
{
Q_OBJECT
Q_ENUMS(Number)
public:
enum Number {
Zero,
One,
Two
};
explicit CustomQObject2(QObject *parent = nullptr)
: QObject(parent)
{
}
};
Q_DECLARE_METATYPE(CustomQObject2::Number)
typedef CustomQObject2* CustomQObject2Star;
Q_DECLARE_METATYPE(CustomQObject2Star);
namespace SomeNamespace2 {
class NamespacedQObject2 : public QObject
{
Q_OBJECT
public:
explicit NamespacedQObject2(QObject *parent = nullptr)
: QObject(parent)
{
}
};
struct NamespacedNonQObject2 {};
}
Q_DECLARE_METATYPE(SomeNamespace2::NamespacedNonQObject2)
struct CustomObject3 {};
struct CustomObject4 {};
struct CustomObject5 {};
struct CustomObject6 {};
struct CustomObject7 {};
struct CustomObject8 {};
struct CustomObject9 {};
struct CustomObject10 {};
struct CustomObject11 {};
struct CustomObject12 {};
Q_DECLARE_METATYPE(CustomObject3)
Q_DECLARE_METATYPE(CustomObject4)
Q_DECLARE_METATYPE(CustomObject5)
Q_DECLARE_METATYPE(CustomObject6)
Q_DECLARE_METATYPE(CustomObject7)
Q_DECLARE_METATYPE(CustomObject8)
Q_DECLARE_METATYPE(CustomObject9)
Q_DECLARE_METATYPE(CustomObject10)
Q_DECLARE_METATYPE(CustomObject11)
Q_DECLARE_METATYPE(CustomObject12)
class AutoRegistrationObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QObject* object READ object CONSTANT)
Q_PROPERTY(CustomQObject* customObject READ customObject CONSTANT)
Q_PROPERTY(QSharedPointer<CustomQObject> customObjectP READ customObjectP CONSTANT)
Q_PROPERTY(QWeakPointer<CustomQObject> customObjectWP READ customObjectWP CONSTANT)
Q_PROPERTY(QPointer<CustomQObject> customObjectTP READ customObjectTP CONSTANT)
Q_PROPERTY(QList<int> listInt READ listInt CONSTANT)
Q_PROPERTY(QList<QVariant> listVariant READ listVariant CONSTANT)
Q_PROPERTY(QList<CustomQObject*> listObject READ listObject CONSTANT)
Q_PROPERTY(QList<QList<int>> listListInt READ listListInt CONSTANT)
Q_PROPERTY(QList<QList<CustomQObject *>> listListObject READ listListObject CONSTANT)
Q_PROPERTY(CustomQObject::Number enumValue READ enumValue CONSTANT)
Q_PROPERTY(CustomQObjectStar customObjectTypedef READ customObjectTypedef CONSTANT)
Q_PROPERTY(SomeNamespace::NamespacedQObject* customObjectNamespaced READ customObjectNamespaced CONSTANT)
Q_PROPERTY(SomeNamespace::NamespacedNonQObject customNonQObjectNamespaced READ customNonQObjectNamespaced CONSTANT)
public:
AutoRegistrationObject(QObject *parent = nullptr)
: QObject(parent)
{
}
QObject* object() const
{
return 0;
}
QSharedPointer<CustomQObject> customObjectP() const
{
return QSharedPointer<CustomQObject>();
}
QWeakPointer<CustomQObject> customObjectWP() const
{
return QWeakPointer<CustomQObject>();
}
QPointer<CustomQObject> customObjectTP() const
{
return QPointer<CustomQObject>();
}
CustomQObject* customObject() const
{
return 0;
}
QList<int> listInt() const
{
return QList<int>();
}
QList<QVariant> listVariant() const { return QList<QVariant>(); }
QList<CustomQObject*> listObject() const
{
return QList<CustomQObject*>();
}
QList<QList<int>> listListInt() const { return QList<QList<int>>(); }
QList<QList<CustomQObject *>> listListObject() const { return QList<QList<CustomQObject *>>(); }
CustomQObject::Number enumValue() const
{
return CustomQObject::Zero;
}
CustomQObjectStar customObjectTypedef() const
{
return 0;
}
SomeNamespace::NamespacedQObject* customObjectNamespaced() const
{
return 0;
}
SomeNamespace::NamespacedNonQObject customNonQObjectNamespaced() const
{
return SomeNamespace::NamespacedNonQObject();
}
public slots:
void objectSlot(QObject*) {}
void customObjectSlot(CustomQObject2*) {}
void sharedPointerSlot(QSharedPointer<CustomQObject2>) {}
void weakPointerSlot(QWeakPointer<CustomQObject2>) {}
void trackingPointerSlot(QPointer<CustomQObject2>) {}
void listIntSlot(QList<int>) {}
void listVariantSlot(QList<QVariant>) { }
void listCustomObjectSlot(QList<CustomQObject2*>) {}
void listListIntSlot(QList<QList<int>>) { }
void listListCustomObjectSlot(QList<QList<CustomQObject2 *>>) { }
void enumSlot(CustomQObject2::Number) {}
void typedefSlot(CustomQObject2Star) {}
void namespacedQObjectSlot(SomeNamespace2::NamespacedQObject2*) {}
void namespacedNonQObjectSlot(SomeNamespace2::NamespacedNonQObject2) {}
void bu1(int, CustomObject3) {}
void bu2(CustomObject4, int) {}
void bu3(CustomObject5, CustomObject6) {}
void bu4(CustomObject7, int, CustomObject8) {}
void bu5(int, CustomObject9, CustomObject10) {}
void bu6(int, CustomObject11, int) {}
// these can't be registered, but they should at least compile
void ref1(int&) {}
void ref2(QList<int>&) {}
void ref3(CustomQObject2&) {}
void ref4(QSharedPointer<CustomQObject2>&) {}
signals:
void someSignal(CustomObject12);
};
void tst_Moc::autoPropertyMetaTypeRegistration()
{
AutoRegistrationObject aro;
static const int numPropertiesUnderTest = 15;
QList<int> propertyMetaTypeIds;
propertyMetaTypeIds.reserve(numPropertiesUnderTest);
const QMetaObject *metaObject = aro.metaObject();
QCOMPARE(metaObject->propertyCount(), numPropertiesUnderTest);
for (int i = 0; i < metaObject->propertyCount(); ++i) {
const QMetaProperty prop = metaObject->property(i);
propertyMetaTypeIds.append(prop.userType());
QVariant var = prop.read(&aro);
QVERIFY(var.isValid());
}
// Verify that QMetaProperty::userType gave us what we expected.
QList<int> expectedMetaTypeIds = QList<int>()
<< QMetaType::QString // QObject::userType
<< QMetaType::QObjectStar // AutoRegistrationObject::object
<< qMetaTypeId<CustomQObject *>() // etc.
<< qMetaTypeId<QSharedPointer<CustomQObject>>()
<< qMetaTypeId<QWeakPointer<CustomQObject>>() << qMetaTypeId<QPointer<CustomQObject>>()
<< qMetaTypeId<QList<int>>() << qMetaTypeId<QList<QVariant>>()
<< qMetaTypeId<QList<CustomQObject *>>() << qMetaTypeId<QList<QList<int>>>()
<< qMetaTypeId<QList<QList<CustomQObject *>>>() << qMetaTypeId<CustomQObject::Number>()
<< qMetaTypeId<CustomQObjectStar>() << qMetaTypeId<SomeNamespace::NamespacedQObject *>()
<< qMetaTypeId<SomeNamespace::NamespacedNonQObject>();
QCOMPARE(propertyMetaTypeIds, expectedMetaTypeIds);
}
template<typename T>
struct DefaultConstructor
{
static inline T construct() { return T(); }
};
template<typename T>
struct DefaultConstructor<T*>
{
static inline T* construct() { return 0; }
};
void tst_Moc::autoMethodArgumentMetaTypeRegistration()
{
AutoRegistrationObject aro;
QList<int> methodArgMetaTypeIds;
const QMetaObject *metaObject = aro.metaObject();
int i = metaObject->methodOffset(); // Start after QObject built-in slots;
while (i < metaObject->methodCount()) {
// Skip over signals so we start at the first slot.
const QMetaMethod method = metaObject->method(i);
if (method.methodType() == QMetaMethod::Signal)
++i;
else
break;
}
#define TYPE_LOOP(TYPE) \
{ \
const QMetaMethod method = metaObject->method(i); \
for (int j = 0; j < method.parameterCount(); ++j) \
methodArgMetaTypeIds.append(method.parameterType(j)); \
QVERIFY(method.invoke(&aro, Q_ARG(TYPE, DefaultConstructor<TYPE>::construct()))); \
++i; \
}
#define FOR_EACH_SLOT_ARG_TYPE(F) \
F(QObject *) \
F(CustomQObject2 *) \
F(QSharedPointer<CustomQObject2>) \
F(QWeakPointer<CustomQObject2>) \
F(QPointer<CustomQObject2>) \
F(QList<int>) \
F(QList<QVariant>) \
F(QList<CustomQObject2 *>) \
F(QList<QList<int>>) \
F(QList<QList<CustomQObject2 *>>) \
F(CustomQObject2::Number) \
F(CustomQObject2Star) \
F(SomeNamespace2::NamespacedQObject2 *) \
F(SomeNamespace2::NamespacedNonQObject2)
// Note: mulit-arg slots are tested below.
FOR_EACH_SLOT_ARG_TYPE(TYPE_LOOP)
#undef TYPE_LOOP
#undef FOR_EACH_SLOT_ARG_TYPE
QList<int> expectedMetaTypeIds = QList<int>()
<< QMetaType::QObjectStar << qMetaTypeId<CustomQObject2 *>()
<< qMetaTypeId<QSharedPointer<CustomQObject2>>()
<< qMetaTypeId<QWeakPointer<CustomQObject2>>()
<< qMetaTypeId<QPointer<CustomQObject2>>() << qMetaTypeId<QList<int>>()
<< qMetaTypeId<QList<QVariant>>() << qMetaTypeId<QList<CustomQObject2 *>>()
<< qMetaTypeId<QList<QList<int>>>() << qMetaTypeId<QList<QList<CustomQObject2 *>>>()
<< qMetaTypeId<CustomQObject2::Number>() << qMetaTypeId<CustomQObject2Star>()
<< qMetaTypeId<SomeNamespace2::NamespacedQObject2 *>()
<< qMetaTypeId<SomeNamespace2::NamespacedNonQObject2>();
QCOMPARE(methodArgMetaTypeIds, expectedMetaTypeIds);
QList<int> methodMultiArgMetaTypeIds;
{
const QMetaMethod method = metaObject->method(i);
QCOMPARE(method.name(), QByteArray("bu1"));
for (int j = 0; j < method.parameterCount(); ++j)
methodMultiArgMetaTypeIds.append(method.parameterType(j));
QVERIFY(method.invoke(&aro, Q_ARG(int, 42), Q_ARG(CustomObject3, CustomObject3())));
++i;
}
{
const QMetaMethod method = metaObject->method(i);
QCOMPARE(method.name(), QByteArray("bu2"));
for (int j = 0; j < method.parameterCount(); ++j)
methodMultiArgMetaTypeIds.append(method.parameterType(j));
QVERIFY(method.invoke(&aro, Q_ARG(CustomObject4, CustomObject4()), Q_ARG(int, 42)));
++i;
}
{
const QMetaMethod method = metaObject->method(i);
QCOMPARE(method.name(), QByteArray("bu3"));
for (int j = 0; j < method.parameterCount(); ++j)
methodMultiArgMetaTypeIds.append(method.parameterType(j));
QVERIFY(method.invoke(&aro, Q_ARG(CustomObject5, CustomObject5()), Q_ARG(CustomObject6, CustomObject6())));
++i;
}
{
const QMetaMethod method = metaObject->method(i);
QCOMPARE(method.name(), QByteArray("bu4"));
for (int j = 0; j < method.parameterCount(); ++j)
methodMultiArgMetaTypeIds.append(method.parameterType(j));
QVERIFY(method.invoke(&aro, Q_ARG(CustomObject7, CustomObject7()), Q_ARG(int, 42), Q_ARG(CustomObject8, CustomObject8())));
++i;
}
{
const QMetaMethod method = metaObject->method(i);
QCOMPARE(method.name(), QByteArray("bu5"));
for (int j = 0; j < method.parameterCount(); ++j)
methodMultiArgMetaTypeIds.append(method.parameterType(j));
QVERIFY(method.invoke(&aro, Q_ARG(int, 42), Q_ARG(CustomObject9, CustomObject9()), Q_ARG(CustomObject10, CustomObject10())));
++i;
}
{
const QMetaMethod method = metaObject->method(i);
QCOMPARE(method.name(), QByteArray("bu6"));
for (int j = 0; j < method.parameterCount(); ++j)
methodMultiArgMetaTypeIds.append(method.parameterType(j));
QVERIFY(method.invoke(&aro, Q_ARG(int, 42), Q_ARG(CustomObject11, CustomObject11()), Q_ARG(int, 42)));
++i;
}
QList<int> expectedMultiMetaTypeIds = QList<int>()
<< QMetaType::Int << qMetaTypeId<CustomObject3>() << qMetaTypeId<CustomObject4>()
<< QMetaType::Int << qMetaTypeId<CustomObject5>() << qMetaTypeId<CustomObject6>()
<< qMetaTypeId<CustomObject7>() << QMetaType::Int << qMetaTypeId<CustomObject8>()
<< QMetaType::Int << qMetaTypeId<CustomObject9>() << qMetaTypeId<CustomObject10>()
<< QMetaType::Int << qMetaTypeId<CustomObject11>() << QMetaType::Int;
QCOMPARE(methodMultiArgMetaTypeIds, expectedMultiMetaTypeIds);
}
void tst_Moc::autoSignalSpyMetaTypeRegistration()
{
AutoRegistrationObject aro;
QList<int> methodArgMetaTypeIds;
const QMetaObject *metaObject = aro.metaObject();
int i = metaObject->indexOfSignal(QMetaObject::normalizedSignature("someSignal(CustomObject12)"));
QVERIFY(i > 0);
QCOMPARE(QMetaType::fromName("CustomObject12").id(), (int)QMetaType::UnknownType);
QSignalSpy spy(&aro, SIGNAL(someSignal(CustomObject12)));
QVERIFY(QMetaType::fromName("CustomObject12").id() != QMetaType::UnknownType);
QCOMPARE(QMetaType::fromName("CustomObject12").id(), qMetaTypeId<CustomObject12>());
}
void tst_Moc::parseDefines()
{
const QMetaObject *mo = &PD_NAMESPACE::PD_CLASSNAME::staticMetaObject;
QCOMPARE(mo->className(), PD_SCOPED_STRING(PD_NAMESPACE, PD_CLASSNAME));
QVERIFY(mo->indexOfSlot("voidFunction()") != -1);
int index = mo->indexOfSlot("stringMethod()");
QVERIFY(index != -1);
QCOMPARE(mo->method(index).returnType(), int(QMetaType::QString));
index = mo->indexOfSlot("combined1()");
QVERIFY(index != -1);
index = mo->indexOfSlot("combined2()");
QVERIFY(index != -1);
index = mo->indexOfSlot("combined3()");
QVERIFY(index != -1);
index = mo->indexOfSlot("combined4(int,int)");
QVERIFY(index != -1);
index = mo->indexOfSlot("combined5()");
QVERIFY(index != -1);
index = mo->indexOfSlot("combined6()");
QVERIFY(index != -1);
index = mo->indexOfSlot("vararg1()");
QVERIFY(index != -1);
index = mo->indexOfSlot("vararg2(int)");
QVERIFY(index != -1);
index = mo->indexOfSlot("vararg3(int,int)");
QVERIFY(index != -1);
index = mo->indexOfSlot("vararg4()");
QVERIFY(index != -1);
index = mo->indexOfSlot("vararg5(int)");
QVERIFY(index != -1);
index = mo->indexOfSlot("vararg6(int,int)");
QVERIFY(index != -1);
index = mo->indexOfSlot("INNERFUNCTION(int)");
QVERIFY(index != -1);
index = mo->indexOfSlot("inner_expanded(int)");
QVERIFY(index != -1);
index = mo->indexOfSlot("expanded_method(int)");
QVERIFY(index != -1);
index = mo->indexOfSlot("conditionSlot()");
QVERIFY(index != -1);
int count = 0;
for (int i = 0; i < mo->classInfoCount(); ++i) {
QMetaClassInfo mci = mo->classInfo(i);
if (!qstrcmp(mci.name(), "TestString")) {
++count;
QVERIFY(!qstrcmp(mci.value(), "PD_CLASSNAME"));
}
if (!qstrcmp(mci.name(), "TestString2")) {
++count;
QVERIFY(!qstrcmp(mci.value(), "ParseDefine"));
}
if (!qstrcmp(mci.name(), "TestString3")) {
++count;
QVERIFY(!qstrcmp(mci.value(), "TestValue"));
}
}
QCOMPARE(count, 3);
index = mo->indexOfSlot("PD_DEFINE_ITSELF_SUFFIX(int)");
QVERIFY(index != -1);
index = mo->indexOfSignal("cmdlineSignal(QMap<int,int>)");
QVERIFY(index != -1);
index = mo->indexOfSignal("signalQTBUG55853()");
QVERIFY(index != -1);
}
void tst_Moc::preprocessorOnly()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
proc.start(m_moc, QStringList() << "-E" << m_sourceDirectory + QStringLiteral("/pp-dollar-signs.h"));
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 0);
QByteArray mocOut = proc.readAllStandardOutput();
QVERIFY(!mocOut.isEmpty());
QCOMPARE(proc.readAllStandardError(), QByteArray());
QVERIFY(mocOut.contains("$$ = parser->createFoo()"));
#else
QSKIP("Only tested on unix/gcc");
#endif
}
void tst_Moc::unterminatedFunctionMacro()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if defined(Q_OS_UNIX) && defined(Q_CC_GNU) && QT_CONFIG(process)
QProcess proc;
proc.start(m_moc, QStringList() << "-E" << m_sourceDirectory + QStringLiteral("/unterminated-function-macro.h"));
QVERIFY(proc.waitForFinished());
QCOMPARE(proc.exitCode(), 1);
QCOMPARE(proc.readAllStandardOutput(), QByteArray());
QByteArray errorOutput = proc.readAllStandardError();
QVERIFY(!errorOutput.isEmpty());
QVERIFY(errorOutput.contains("missing ')' in macro usage"));
#else
QSKIP("Only tested on linux/gcc");
#endif
}
namespace QTBUG32933_relatedObjectsDontIncludeItself {
namespace NS {
class Obj : QObject {
Q_OBJECT
Q_PROPERTY(MyEnum p1 MEMBER member)
Q_PROPERTY(Obj::MyEnum p2 MEMBER member)
Q_PROPERTY(NS::Obj::MyEnum p3 MEMBER member)
Q_PROPERTY(QTBUG32933_relatedObjectsDontIncludeItself::NS::Obj::MyEnum p4 MEMBER member)
Q_ENUMS(MyEnum);
public:
enum MyEnum { Something, SomethingElse };
MyEnum member;
};
}
}
void tst_Moc::QTBUG32933_relatedObjectsDontIncludeItself()
{
const QMetaObject *mo = &QTBUG32933_relatedObjectsDontIncludeItself::NS::Obj::staticMetaObject;
const auto *objects = mo->d.relatedMetaObjects;
// the related objects should be empty because the enums is in the same object.
QVERIFY(!objects);
}
class UnrelatedClass : public QObject
{
Q_OBJECT
Q_ENUMS(UnrelatedEnum)
public:
enum UnrelatedEnum {
UnrelatedInvalidValue = -1,
UnrelatedValue = 42
};
};
// The presence of this macro used to confuse moc and prevent
// UnrelatedClass from being listed in the related meta objects.
Q_DECLARE_METATYPE(UnrelatedClass::UnrelatedEnum)
class TestClassReferencingUnrelatedEnum : public QObject
{
Q_OBJECT
Q_PROPERTY(UnrelatedClass::UnrelatedEnum enumProperty READ enumProperty WRITE setEnumProperty)
public:
TestClassReferencingUnrelatedEnum()
: m_enumProperty(UnrelatedClass::UnrelatedInvalidValue)
{}
UnrelatedClass::UnrelatedEnum enumProperty() const {
return m_enumProperty;
}
void setEnumProperty(UnrelatedClass::UnrelatedEnum arg) {
m_enumProperty = arg;
}
private:
UnrelatedClass::UnrelatedEnum m_enumProperty;
};
void tst_Moc::writeEnumFromUnrelatedClass()
{
TestClassReferencingUnrelatedEnum obj;
QString enumValueAsString("UnrelatedValue");
obj.setProperty("enumProperty", enumValueAsString);
QCOMPARE(int(obj.enumProperty()), int(UnrelatedClass::UnrelatedValue));
}
void tst_Moc::relatedMetaObjectsWithinNamespaces()
{
const QMetaObject *relatedMo = &QTBUG_2151::A::staticMetaObject;
const QMetaObject *testMo = &QTBUG_2151::B::staticMetaObject;
QVERIFY(testMo->d.relatedMetaObjects);
QCOMPARE(testMo->d.relatedMetaObjects[0], relatedMo);
}
void tst_Moc::relatedMetaObjectsInGadget()
{
const QMetaObject *relatedMo = &QTBUG_35657::A::staticMetaObject;
const QMetaObject *testMo = &QTBUG_35657::B::staticMetaObject;
QVERIFY(testMo->d.relatedMetaObjects);
QCOMPARE(testMo->d.relatedMetaObjects[0], relatedMo);
}
void tst_Moc::relatedMetaObjectsNameConflict_data()
{
typedef QList<const QMetaObject *> QMetaObjects;
QTest::addColumn<const QMetaObject*>("dependingObject");
QTest::addColumn<QMetaObjects>("relatedMetaObjects");
//NS1
const QMetaObject *n1gadget = &NS1::Gadget::staticMetaObject;
const QMetaObject *n1object = &NS1::Object::staticMetaObject;
const QMetaObject *n1nestedGadget = &NS1::Nested::Gadget::staticMetaObject;
const QMetaObject *n1nestedObject = &NS1::Nested::Object::staticMetaObject;
//N2
const QMetaObject *n2gadget = &NS2::Gadget::staticMetaObject;
const QMetaObject *n2object = &NS2::Object::staticMetaObject;
const QMetaObject *n2nestedGadget = &NS2::Nested::Gadget::staticMetaObject;
const QMetaObject *n2nestedObject = &NS2::Nested::Object::staticMetaObject;
QTest::newRow("N1::dependingObject") << &NS1::DependingObject::staticMetaObject
<< (QMetaObjects() << n1gadget << n1object);
QTest::newRow("N2::dependingObject") << &NS2::DependingObject::staticMetaObject
<< (QMetaObjects() << n2gadget << n2object);
QTest::newRow("N1::dependingNestedObject") << &NS1::DependingNestedObject::staticMetaObject
<< (QMetaObjects() << n1nestedObject);
QTest::newRow("N2::dependingNestedObject") << &NS2::DependingNestedObject::staticMetaObject
<< (QMetaObjects() << n2nestedObject);
QTest::newRow("N1::dependingNestedGadget") << &NS1::DependingNestedGadget::staticMetaObject
<< (QMetaObjects() << n1nestedGadget);
QTest::newRow("N2::dependingNestedGadget") << &NS2::DependingNestedGadget::staticMetaObject
<< (QMetaObjects() << n2nestedGadget);
}
void tst_Moc::relatedMetaObjectsNameConflict()
{
typedef QList<const QMetaObject *> QMetaObjects;
QFETCH(const QMetaObject*, dependingObject);
QFETCH(QMetaObjects, relatedMetaObjects);
// load all specified metaobjects int a set
QSet<const QMetaObject*> dependency;
const auto *i = dependingObject->d.relatedMetaObjects;
while (*i) {
dependency.insert(*i);
++i;
}
// check if all required metaobjects are specified
foreach (const QMetaObject *mo, relatedMetaObjects)
QVERIFY(dependency.contains(mo));
// check if no additional metaobjects ara specified
QCOMPARE(dependency.size(), relatedMetaObjects.size());
}
class StringLiteralsInMacroExtension: public QObject
{
Q_OBJECT
#define Macro(F) F " " F
Q_CLASSINFO(Macro("String"), Macro("Literal"))
#undef Macro
#define Macro(F) F
Q_CLASSINFO("String" Macro("!"), "Literal" Macro("!"))
Q_CLASSINFO(Macro("!") "String", Macro("!") "Literal")
#undef Macro
#define Macro "foo"
Q_CLASSINFO("String" Macro, "Literal" Macro)
Q_CLASSINFO(Macro "String", Macro "Literal")
#undef Macro
};
void tst_Moc::strignLiteralsInMacroExtension()
{
const QMetaObject *mobj = &StringLiteralsInMacroExtension::staticMetaObject;
QCOMPARE(mobj->classInfoCount(), 5);
QCOMPARE(mobj->classInfo(0).name(), "String String");
QCOMPARE(mobj->classInfo(0).value(), "Literal Literal");
QCOMPARE(mobj->classInfo(1).name(), "String!");
QCOMPARE(mobj->classInfo(1).value(), "Literal!");
QCOMPARE(mobj->classInfo(2).name(), "!String");
QCOMPARE(mobj->classInfo(2).value(), "!Literal");
QCOMPARE(mobj->classInfo(3).name(), "Stringfoo");
QCOMPARE(mobj->classInfo(3).value(), "Literalfoo");
QCOMPARE(mobj->classInfo(4).name(), "fooString");
QCOMPARE(mobj->classInfo(4).value(), "fooLiteral");
}
class VeryLongStringData : public QObject
{
Q_OBJECT
#define repeat2(V) V V
#define repeat4(V) repeat2(V) repeat2(V)
#define repeat8(V) repeat4(V) repeat4(V)
#define repeat16(V) repeat8(V) repeat8(V)
#define repeat32(V) repeat16(V) repeat16(V)
#define repeat64(V) repeat32(V) repeat32(V)
#define repeat128(V) repeat64(V) repeat64(V)
#define repeat256(V) repeat128(V) repeat128(V)
#define repeat512(V) repeat256(V) repeat256(V)
#define repeat1024(V) repeat512(V) repeat512(V)
#define repeat2048(V) repeat1024(V) repeat1024(V)
#define repeat4096(V) repeat2048(V) repeat2048(V)
#define repeat8192(V) repeat4096(V) repeat4096(V)
#define repeat16384(V) repeat8192(V) repeat8192(V)
#define repeat32768(V) repeat16384(V) repeat16384(V)
#define repeat65534(V) repeat32768(V) repeat16384(V) repeat8192(V) repeat4096(V) repeat2048(V) repeat1024(V) repeat512(V) repeat256(V) repeat128(V) repeat64(V) repeat32(V) repeat16(V) repeat8(V) repeat4(V) repeat2(V)
Q_CLASSINFO("\1" "23\xff", "String with CRLF.\r\n")
Q_CLASSINFO(repeat65534("n"), repeat65534("i"))
Q_CLASSINFO(repeat65534("e"), repeat65534("r"))
Q_CLASSINFO(repeat32768("o"), repeat32768("b"))
Q_CLASSINFO(":", ")")
#undef repeat2
#undef repeat4
#undef repeat8
#undef repeat16
#undef repeat32
#undef repeat64
#undef repeat128
#undef repeat256
#undef repeat512
#undef repeat1024
#undef repeat2048
#undef repeat4096
#undef repeat8192
#undef repeat16384
#undef repeat32768
#undef repeat65534
};
void tst_Moc::unnamedNamespaceObjectsAndGadgets()
{
// these just test very basic functionality of gadgets and objects
// defined in unnamed namespaces.
{
GadgetInUnnamedNS gadget(21, 42);
QCOMPARE(gadget.x(), 21);
QCOMPARE(gadget.y(), 42);
gadget.staticMetaObject.property(0).writeOnGadget(&gadget, 12);
gadget.staticMetaObject.property(1).writeOnGadget(&gadget, 24);
QCOMPARE(gadget.x(), 12);
QCOMPARE(gadget.y(), 24);
}
{
ObjectInUnnamedNS object;
QObject *qObject = &object;
QCOMPARE(static_cast<ObjectInUnnamedNS *>(qObject),
qobject_cast<ObjectInUnnamedNS *>(qObject));
}
}
void tst_Moc::veryLongStringData()
{
const QMetaObject *mobj = &VeryLongStringData::staticMetaObject;
int startAt = 1; // some other classinfo added to the beginning
QCOMPARE(mobj->classInfoCount(), startAt + 4);
QCOMPARE(mobj->classInfo(startAt + 0).name()[0], 'n');
QCOMPARE(mobj->classInfo(startAt + 0).value()[0], 'i');
QCOMPARE(mobj->classInfo(startAt + 1).name()[0], 'e');
QCOMPARE(mobj->classInfo(startAt + 1).value()[0], 'r');
QCOMPARE(mobj->classInfo(startAt + 2).name()[0], 'o');
QCOMPARE(mobj->classInfo(startAt + 2).value()[0], 'b');
QCOMPARE(mobj->classInfo(startAt + 3).name()[0], ':');
QCOMPARE(mobj->classInfo(startAt + 3).value()[0], ')');
QCOMPARE(strlen(mobj->classInfo(startAt + 0).name()), static_cast<size_t>(65534));
QCOMPARE(strlen(mobj->classInfo(startAt + 0).value()), static_cast<size_t>(65534));
QCOMPARE(strlen(mobj->classInfo(startAt + 1).name()), static_cast<size_t>(65534));
QCOMPARE(strlen(mobj->classInfo(startAt + 1).value()), static_cast<size_t>(65534));
QCOMPARE(strlen(mobj->classInfo(startAt + 2).name()), static_cast<size_t>(32768));
QCOMPARE(strlen(mobj->classInfo(startAt + 2).value()), static_cast<size_t>(32768));
QCOMPARE(strlen(mobj->classInfo(startAt + 3).name()), static_cast<size_t>(1));
QCOMPARE(strlen(mobj->classInfo(startAt + 3).value()), static_cast<size_t>(1));
}
void tst_Moc::gadgetHierarchy()
{
QCOMPARE(NonGadgetParent::Derived::staticMetaObject.superClass(), static_cast<const QMetaObject*>(nullptr));
QCOMPARE(GrandParentGadget::DerivedGadget::staticMetaObject.superClass(), &GrandParentGadget::BaseGadget::staticMetaObject);
QCOMPARE(GrandParentGadget::CRTPDerivedGadget::staticMetaObject.superClass(), &GrandParentGadget::BaseGadget::staticMetaObject);
}
void tst_Moc::optionsFileError_data()
{
QTest::addColumn<QString>("optionsArgument");
QTest::newRow("no filename") << QStringLiteral("@");
QTest::newRow("nonexistent file") << QStringLiteral("@letshuntasnark");
}
void tst_Moc::optionsFileError()
{
#ifdef MOC_CROSS_COMPILED
QSKIP("Not tested when cross-compiled");
#endif
#if QT_CONFIG(process)
QFETCH(QString, optionsArgument);
QProcess p;
p.start(m_moc, QStringList(optionsArgument));
QVERIFY(p.waitForFinished());
QCOMPARE(p.exitCode(), 1);
QVERIFY(p.readAllStandardOutput().isEmpty());
const QByteArray err = p.readAllStandardError();
QVERIFY(err.contains("moc: "));
QVERIFY(!err.contains("QCommandLineParser"));
#endif
}
static void checkEnum(const QMetaEnum &enumerator, const QByteArray &name,
const QList<QPair<QByteArray, int>> &keys)
{
QCOMPARE(name, QByteArray{enumerator.name()});
QCOMPARE(keys.size(), enumerator.keyCount());
for (int i = 0; i < enumerator.keyCount(); ++i) {
QCOMPARE(keys[i].first, QByteArray{enumerator.key(i)});
QCOMPARE(keys[i].second, enumerator.value(i));
}
}
class EnumFromNamespaceClass : public QObject
{
Q_OBJECT
Q_PROPERTY(FooNamespace::Enum1 prop READ prop CONSTANT)
public:
FooNamespace::Enum1 prop() { return FooNamespace::Enum1::Key2; }
};
void tst_Moc::testQNamespace()
{
QCOMPARE(TestQNamespace::staticMetaObject.enumeratorCount(), 4);
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",
{{"None", 0}, {"Flag1", 1}, {"Flag2", 2}, {"Any", 1 | 2}});
checkEnum(TestQNamespace::staticMetaObject.enumerator(3), "TestFlag2",
{{"None", 0}, {"Flag1", 4}, {"Flag2", 8}, {"Any", 4 | 8}});
QCOMPARE(TestQNamespace::TestGadget::staticMetaObject.enumeratorCount(), 2);
checkEnum(TestQNamespace::TestGadget::staticMetaObject.enumerator(0), "TestGEnum1",
{{"Key1", 13}, {"Key2", 14}});
checkEnum(TestQNamespace::TestGadget::staticMetaObject.enumerator(1), "TestGEnum2",
{{"Key1", 23}, {"Key2", 24}});
QCOMPARE(TestQNamespace::TestGadgetExport::staticMetaObject.enumeratorCount(), 2);
checkEnum(TestQNamespace::TestGadgetExport::staticMetaObject.enumerator(0), "TestGeEnum1",
{{"Key1", 20}, {"Key2", 21}});
checkEnum(TestQNamespace::TestGadgetExport::staticMetaObject.enumerator(1), "TestGeEnum2",
{{"Key1", 23}, {"Key2", 24}});
QMetaEnum meta = QMetaEnum::fromType<TestQNamespace::TestEnum1>();
QVERIFY(meta.isValid());
QCOMPARE(meta.name(), "TestEnum1");
QCOMPARE(meta.enclosingMetaObject(), &TestQNamespace::staticMetaObject);
QCOMPARE(meta.keyCount(), 2);
QCOMPARE(TestExportNamespace::staticMetaObject.enumeratorCount(), 1);
checkEnum(TestExportNamespace::staticMetaObject.enumerator(0), "MyEnum",
{{"Key1", 0}, {"Key2", 1}});
QCOMPARE(FooNamespace::staticMetaObject.enumeratorCount(), 1);
QCOMPARE(FooNamespace::FooNestedNamespace::staticMetaObject.enumeratorCount(), 2);
QCOMPARE(FooNamespace::FooNestedNamespace::FooMoreNestedNamespace::staticMetaObject.enumeratorCount(), 1);
EnumFromNamespaceClass obj;
const QVariant prop = obj.property("prop");
QCOMPARE(prop.userType(), QMetaType::fromType<FooNamespace::Enum1>().id());
QCOMPARE(prop.toInt(), int(FooNamespace::Enum1::Key2));
}
void tst_Moc::cxx17Namespaces()
{
QCOMPARE(CXX17Namespace::A::B::C::D::staticMetaObject.className(),
"CXX17Namespace::A::B::C::D");
QCOMPARE(CXX17Namespace::A::B::C::D::staticMetaObject.enumeratorCount(), 1);
QCOMPARE(CXX17Namespace::A::B::C::D::staticMetaObject.enumerator(0).name(), "NamEn");
QCOMPARE(QMetaEnum::fromType<CXX17Namespace::A::B::C::D::NamEn>().name(), "NamEn");
QCOMPARE(QMetaEnum::fromType<CXX17Namespace::A::B::C::D::NamEn>().keyCount(), 1);
QCOMPARE(QMetaEnum::fromType<CXX17Namespace::A::B::C::D::NamEn>().value(0), 4);
QCOMPARE(CXX17Namespace::A::B::C::D::ClassInNamespace::staticMetaObject.className(),
"CXX17Namespace::A::B::C::D::ClassInNamespace");
QCOMPARE(CXX17Namespace::A::B::C::D::ClassInNamespace::staticMetaObject.enumeratorCount(), 1);
QCOMPARE(CXX17Namespace::A::B::C::D::ClassInNamespace::staticMetaObject.enumerator(0).name(), "GadEn");
QCOMPARE(QMetaEnum::fromType<CXX17Namespace::A::B::C::D::ClassInNamespace::GadEn>().name(), "GadEn");
QCOMPARE(QMetaEnum::fromType<CXX17Namespace::A::B::C::D::ClassInNamespace::GadEn>().keyCount(), 1);
QCOMPARE(QMetaEnum::fromType<CXX17Namespace::A::B::C::D::ClassInNamespace::GadEn>().value(0), 3);
}
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);
for (auto a: {"deprecatedSlot", "deprecatedSlot2", "deprecatedReason", "deprecatedReasonWithLBRACK",
"deprecatedReasonWith2LBRACK", "deprecatedReasonWithRBRACK", "deprecatedReasonWith2RBRACK",
"slotWithArguments"
#if !defined(_MSC_VER) || _MSC_VER >= 1912
, "noreturnSlot", "noreturnSlot2", "returnInt", "noreturnDeprecatedSlot",
"noreturnSlot3"
#endif
}) {
QVERIFY(so.indexOfSlot(a) != 1);
}
QCOMPARE(TestQNamespaceDeprecated::staticMetaObject.enumeratorCount(), 2);
checkEnum(TestQNamespaceDeprecated::staticMetaObject.enumerator(0), "TestEnum1",
{{"Key1", 11}, {"Key2", 12}, {"Key3", 13}, {"Key4", 14}, {"Key5", 15}, {"Key6", 16},
{"Key7", 17}});
checkEnum(TestQNamespaceDeprecated::staticMetaObject.enumerator(1), "TestFlag1",
{{"None", 0}, {"Flag1", 1}, {"Flag2", 2}, {"Flag3", 3}, {"Any", 1 | 2 | 3}});
QCOMPARE(TestQNamespaceDeprecated::TestGadget::staticMetaObject.enumeratorCount(), 1);
checkEnum(TestQNamespaceDeprecated::TestGadget::staticMetaObject.enumerator(0), "TestGEnum1",
{{"Key1", 13}, {"Key2", 14}, {"Key3", 15}});
QMetaEnum meta = QMetaEnum::fromType<TestQNamespaceDeprecated::TestEnum1>();
QVERIFY(meta.isValid());
QCOMPARE(meta.name(), "TestEnum1");
QCOMPARE(meta.enclosingMetaObject(), &TestQNamespaceDeprecated::staticMetaObject);
QCOMPARE(meta.keyCount(), 7);
}
void tst_Moc::mocJsonOutput()
{
const auto readFile = [](const QString &fileName) {
QFile f(fileName);
f.open(QIODevice::ReadOnly);
return QJsonDocument::fromJson(f.readAll());
};
QString actualFile = QStringLiteral(":/allmocs.json");
QString expectedFile = QStringLiteral(":/allmocs_baseline.json");
if (!QFile::exists(actualFile)) {
// TODO: necessary with cmake as we cannot generate the qrc file soon enough
auto const appDir = QCoreApplication::applicationDirPath();
actualFile = appDir + QDir::separator() + QLatin1String("./allmocs.json");
expectedFile = appDir + QDir::separator() + QLatin1String("./allmocs_baseline.json");
}
QVERIFY2(QFile::exists(actualFile), qPrintable(actualFile));
QVERIFY2(QFile::exists(expectedFile), qPrintable(expectedFile));
QJsonDocument actualOutput = readFile(actualFile);
QJsonDocument expectedOutput = readFile(expectedFile);
const auto showPotentialDiff = [](const QJsonDocument &actual, const QJsonDocument &expected) -> QByteArray {
#if defined(Q_OS_UNIX)
QByteArray actualStr = actual.toJson();
QByteArray expectedStr = expected.toJson();
QTemporaryFile actualFile;
if (!actualFile.open())
return "Error opening actual temp file";
actualFile.write(actualStr);
actualFile.flush();
QTemporaryFile expectedFile;
if (!expectedFile.open())
return "Error opening expected temp file";
expectedFile.write(expectedStr);
expectedFile.flush();
QProcess diffProc;
diffProc.setProgram("diff");
diffProc.setArguments(QStringList() << "-ub" << expectedFile.fileName() << actualFile.fileName());
diffProc.start();
if (!diffProc.waitForStarted())
return "Error waiting for diff process to start.";
if (!diffProc.waitForFinished())
return "Error waiting for diff process to finish.";
return diffProc.readAllStandardOutput();
#else
return "Cannot launch diff. Please check allmocs.json and allmocs_baseline.json on disk.";
#endif
};
QVERIFY2(actualOutput == expectedOutput, showPotentialDiff(actualOutput, expectedOutput).constData());
}
void TestFwdProperties::setProp1(const FwdClass1 &v)
{
prop1.reset(new FwdClass1(v));
}
void TestFwdProperties::setProp2(const FwdClass2 &v)
{
prop2.reset(new FwdClass2(v));
}
void TestFwdProperties::setProp3(const FwdClass3 &v)
{
prop3.reset(new FwdClass3(v));
}
TestFwdProperties::~TestFwdProperties() {}
Q_DECLARE_METATYPE(FwdClass1);
void tst_Moc::mocInclude()
{
TestFwdProperties obj;
obj.setProperty("prop1", QVariant::fromValue(FwdClass1 { 45 }));
QCOMPARE(obj.prop1->x, 45);
}
class RequiredTest :public QObject
{
Q_OBJECT
Q_PROPERTY(int required MEMBER m_required REQUIRED)
Q_PROPERTY(int notRequired MEMBER m_notRequired)
private:
int m_required;
int m_notRequired;
};
void tst_Moc::requiredProperties()
{
QMetaObject mo = RequiredTest::staticMetaObject;
QMetaProperty required = mo.property(mo.indexOfProperty("required"));
QVERIFY(required.isValid());
QVERIFY(required.isRequired());
QMetaProperty notRequired = mo.property(mo.indexOfProperty("notRequired"));
QVERIFY(notRequired.isValid());
QVERIFY(!notRequired.isRequired());
}
class ClassWithQPropertyMembers : public QObject
{
Q_OBJECT
Q_PROPERTY(int publicProperty MEMBER publicProperty BINDABLE bindablePublicProperty
NOTIFY publicPropertyChanged)
Q_PROPERTY(int privateExposedProperty MEMBER privateExposedProperty)
public:
signals:
void publicPropertyChanged();
public:
QBindable<int> bindablePublicProperty() { return QBindable<int>(&publicProperty); }
Q_OBJECT_BINDABLE_PROPERTY(ClassWithQPropertyMembers, int, publicProperty, &ClassWithQPropertyMembers::publicPropertyChanged);
QProperty<int> notExposed;
protected:
QProperty<int> protectedProperty;
private:
QProperty<int> privateProperty;
QProperty<int> privateExposedProperty;
};
void tst_Moc::qpropertyMembers()
{
const auto metaObject = &ClassWithQPropertyMembers::staticMetaObject;
QCOMPARE(metaObject->propertyCount() - metaObject->superClass()->propertyCount(), 2);
QCOMPARE(metaObject->indexOfProperty("notExposed"), -1);
QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("publicProperty"));
QVERIFY(prop.isValid());
QVERIFY(metaObject->property(metaObject->indexOfProperty("privateExposedProperty")).isValid());
ClassWithQPropertyMembers instance;
prop.write(&instance, 42);
QCOMPARE(instance.publicProperty.value(), 42);
QSignalSpy publicPropertySpy(&instance, SIGNAL(publicPropertyChanged()));
instance.publicProperty.setValue(100);
QCOMPARE(prop.read(&instance).toInt(), 100);
QCOMPARE(publicPropertySpy.size(), 1);
QCOMPARE(prop.metaType(), QMetaType(QMetaType::Int));
QVERIFY(prop.notifySignal().isValid());
}
void tst_Moc::observerMetaCall()
{
const auto metaObject = &ClassWithQPropertyMembers::staticMetaObject;
QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("publicProperty"));
QVERIFY(prop.isValid());
ClassWithQPropertyMembers instance;
int observerCallCount = 0;
auto observer = [&observerCallCount]() {
++observerCallCount;
};
auto bindable = prop.bindable(&instance);
QVERIFY(bindable.isBindable());
auto handler = bindable.onValueChanged(observer);
QCOMPARE(observerCallCount, 0);
instance.publicProperty.setValue(100);
QCOMPARE(observerCallCount, 1);
instance.publicProperty.setValue(101);
QCOMPARE(observerCallCount, 2);
}
void tst_Moc::setQPRopertyBinding()
{
const auto metaObject = &ClassWithQPropertyMembers::staticMetaObject;
QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("publicProperty"));
QVERIFY(prop.isValid());
ClassWithQPropertyMembers instance;
bool bindingCalled = false;
auto binding = Qt::makePropertyBinding([&bindingCalled]() {
bindingCalled = true;
return 42;
});
auto bindable = prop.bindable(&instance);
QVERIFY(bindable.isBindable());
bindable.setBinding(binding);
QCOMPARE(instance.publicProperty.value(), 42);
QVERIFY(bindingCalled); // but now it should've been called :)
}
class ClassWithPrivateQPropertyShim :public QObject
{
Q_OBJECT
public:
Q_PROPERTY(int testProperty READ testProperty WRITE setTestProperty
BINDABLE bindableTestProperty NOTIFY testPropertyChanged)
Q_PROPERTY(int testProperty2 READ testProperty2 WRITE setTestProperty2
BINDABLE bindableTestProperty2)
//Q_PROPERTY(d_func(), int, lazyTestProperty, setLazyTestProperty, NOTIFY lazyTestPropertyChanged)
signals:
void testPropertyChanged();
void lazyTestPropertyChanged();
public:
int testProperty() const { return priv.testProperty; }
void setTestProperty(int val) { priv.testProperty = val; }
int testProperty2() const { return priv.testProperty2; }
void setTestProperty2(int val) { priv.testProperty2 = val; }
QBindable<int> bindableTestProperty() { return QBindable<int>(&priv.testProperty); }
QBindable<int> bindableTestProperty2() { return QBindable<int>(&priv.testProperty2); }
struct Private {
Private(ClassWithPrivateQPropertyShim *pub)
: q(pub)
{}
QBindingStorage bindingStorage;
ClassWithPrivateQPropertyShim *q = nullptr;
void onTestPropertyChanged() { q->testPropertyChanged(); }
Q_OBJECT_BINDABLE_PROPERTY(Private, int, testProperty, &Private::onTestPropertyChanged);
QProperty<int> testProperty2;
};
Private priv{this};
Private *d_func() { return &priv; }
const Private *d_func() const { return &priv; }
};
inline const QBindingStorage *qGetBindingStorage(const ClassWithPrivateQPropertyShim::Private *o)
{
return &o->bindingStorage;
}
inline QBindingStorage *qGetBindingStorage(ClassWithPrivateQPropertyShim::Private *o)
{
return &o->bindingStorage;
}
void tst_Moc::privateQPropertyShim()
{
ClassWithPrivateQPropertyShim testObject;
{
auto metaObject = &ClassWithPrivateQPropertyShim::staticMetaObject;
QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("testProperty"));
QVERIFY(prop.isValid());
QVERIFY(prop.notifySignal().isValid());
}
testObject.priv.testProperty.setValue(42);
QCOMPARE(testObject.property("testProperty").toInt(), 42);
// Behave like a QProperty
QVERIFY(!testObject.bindableTestProperty().hasBinding());
testObject.bindableTestProperty().setBinding([]() { return 100; });
QCOMPARE(testObject.testProperty(), 100);
QVERIFY(testObject.bindableTestProperty().hasBinding());
// Old style setter getters
testObject.setTestProperty(400);
QVERIFY(!testObject.bindableTestProperty().hasBinding());
QCOMPARE(testObject.testProperty(), 400);
// moc generates correct code for plain QProperty in PIMPL
testObject.setTestProperty2(42);
QCOMPARE(testObject.priv.testProperty2.value(), 42);
}
class BindableOnly : public QObject
{
Q_OBJECT
Q_PROPERTY(int score BINDABLE scoreBindable READ default WRITE default)
public:
BindableOnly(QObject *parent = nullptr)
: QObject(parent)
, m_score(4)
{}
QBindable<int> scoreBindable() { return QBindable<int>(&m_score); }
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::readWriteThroughBindable()
{
{
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);
}
}
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>());
}
QTEST_MAIN(tst_Moc)
// the generated code must compile with QT_NO_KEYWORDS
#undef signals
#undef slots
#undef emit
#include "tst_moc.moc"