From 72367b1679f8176c8f8a2a424a1c9325433dd8cd Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Thu, 8 Mar 2012 23:43:28 +0100 Subject: Bootstrap qdbuscpp2xml. This involves invoking the Moc classes directly and using the data structures it provides instead of invoking the moc exectutable and parsing the generated code. Change-Id: Ia5c654e8ef58d52d0d3376252c13e13885f80da3 Reviewed-by: Thiago Macieira --- src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp | 431 +++++++++++---------- src/tools/qdbuscpp2xml/qdbuscpp2xml.pro | 38 +- src/tools/tools.pro | 5 +- tests/auto/tools/qdbuscpp2xml/qdbuscpp2xml.pro | 11 + tests/auto/tools/qdbuscpp2xml/qdbuscpp2xml.qrc | 5 + tests/auto/tools/qdbuscpp2xml/test1.h | 128 ++++++ tests/auto/tools/qdbuscpp2xml/tst_qdbuscpp2xml.cpp | 181 +++++++++ tests/auto/tools/tools.pro | 1 + 8 files changed, 582 insertions(+), 218 deletions(-) create mode 100644 tests/auto/tools/qdbuscpp2xml/qdbuscpp2xml.pro create mode 100644 tests/auto/tools/qdbuscpp2xml/qdbuscpp2xml.qrc create mode 100644 tests/auto/tools/qdbuscpp2xml/test1.h create mode 100644 tests/auto/tools/qdbuscpp2xml/tst_qdbuscpp2xml.cpp diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp index 5814dc740b..2029147ecf 100644 --- a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp +++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp @@ -43,12 +43,9 @@ #include #include #include -#include -#include #include +#include #include -#include -#include #include #include @@ -56,20 +53,26 @@ #include #include "qdbusconnection.h" // for the Export* flags +#include "qdbusconnection_p.h" // for the qDBusCheckAsyncTag // copied from dbus-protocol.h: static const char docTypeHeader[] = "\n"; -// in qdbusxmlgenerator.cpp -QT_BEGIN_NAMESPACE -extern Q_DBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo, - const QMetaObject *base, int flags); -QT_END_NAMESPACE +#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply" +#define QCLASSINFO_DBUS_INTERFACE "D-Bus Interface" +#define QCLASSINFO_DBUS_INTROSPECTION "D-Bus Introspection" + +#include "qdbusmetatype_p.h" +#include "qdbusmetatype.h" +#include "qdbusutil_p.h" + +#include "moc.h" +#include "generator.h" #define PROGRAMNAME "qdbuscpp2xml" -#define PROGRAMVERSION "0.1" +#define PROGRAMVERSION "0.2" #define PROGRAMCOPYRIGHT "Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)." static QString outputFile; @@ -90,199 +93,218 @@ static const char help[] = " -V Show the program version and quit.\n" "\n"; -class MocParser -{ - void parseError(); - QByteArray readLine(); - void loadIntData(uint *&data); - void loadStringData(char *&stringdata); - - QIODevice *input; - const char *filename; - int lineNumber; -public: - ~MocParser(); - void parse(const char *filename, QIODevice *input, int lineNumber = 0); - - QList objects; -}; - -void MocParser::parseError() + +int qDBusParametersForMethod(const FunctionDef &mm, QList& metaTypes) { - fprintf(stderr, PROGRAMNAME ": error parsing input file '%s' line %d \n", filename, lineNumber); - exit(1); + QList parameterTypes; + + foreach (const ArgumentDef &arg, mm.arguments) + parameterTypes.append(arg.normalizedType); + + return qDBusParametersForMethod(parameterTypes, metaTypes); } -QByteArray MocParser::readLine() + +static inline QString typeNameToXml(const char *typeName) { - ++lineNumber; - return input->readLine(); + QString plain = QLatin1String(typeName); + return plain.toHtmlEscaped(); } -void MocParser::loadIntData(uint *&data) -{ - data = 0; // initialise - QVarLengthArray array; - QRegExp rx(QLatin1String("(\\d+|0x[0-9abcdef]+)"), Qt::CaseInsensitive); - - while (!input->atEnd()) { - QString line = QLatin1String(readLine()); - int pos = line.indexOf(QLatin1String("//")); - if (pos != -1) - line.truncate(pos); // drop comments - - if (line == QLatin1String("};\n")) { - // end of data - data = new uint[array.count()]; - memcpy(data, array.data(), array.count() * sizeof(*data)); - return; +static QString addFunction(const FunctionDef &mm, bool isSignal = false) { + + QString xml = QString::fromLatin1(" <%1 name=\"%2\">\n") + .arg(isSignal ? QLatin1String("signal") : QLatin1String("method")) + .arg(QLatin1String(mm.name)); + + // check the return type first + int typeId = QMetaType::type(mm.normalizedType.constData()); + if (typeId != QMetaType::Void) { + if (typeId) { + const char *typeName = QDBusMetaType::typeToSignature(typeId); + if (typeName) { + xml += QString::fromLatin1(" \n") + .arg(typeNameToXml(typeName)); + + // do we need to describe this argument? + if (QDBusMetaType::signatureToType(typeName) == QVariant::Invalid) + xml += QString::fromLatin1(" \n") + .arg(typeNameToXml(mm.normalizedType.constData())); + } else { + return QString(); + } + } else if (!mm.normalizedType.isEmpty()) { + return QString(); // wasn't a valid type + } + } + QList names = mm.arguments; + QList types; + int inputCount = qDBusParametersForMethod(mm, types); + if (inputCount == -1) + return QString(); // invalid form + if (isSignal && inputCount + 1 != types.count()) + return QString(); // signal with output arguments? + if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message) + return QString(); // signal with QDBusMessage argument? + + bool isScriptable = mm.isScriptable; + for (int j = 1; j < types.count(); ++j) { + // input parameter for a slot or output for a signal + if (types.at(j) == QDBusMetaTypeId::message) { + isScriptable = true; + continue; } - pos = 0; - while ((pos = rx.indexIn(line, pos)) != -1) { - QString num = rx.cap(1); - if (num.startsWith(QLatin1String("0x"))) - array.append(num.mid(2).toUInt(0, 16)); - else - array.append(num.toUInt()); - pos += rx.matchedLength(); + QString name; + if (!names.at(j - 1).name.isEmpty()) + name = QString::fromLatin1("name=\"%1\" ").arg(QString::fromLatin1(names.at(j - 1).name)); + + bool isOutput = isSignal || j > inputCount; + + const char *signature = QDBusMetaType::typeToSignature(types.at(j)); + xml += QString::fromLatin1(" \n") + .arg(name) + .arg(QLatin1String(signature)) + .arg(isOutput ? QLatin1String("out") : QLatin1String("in")); + + // do we need to describe this argument? + if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) { + const char *typeName = QMetaType::typeName(types.at(j)); + xml += QString::fromLatin1(" \n") + .arg(isOutput ? QLatin1String("Out") : QLatin1String("In")) + .arg(isOutput && !isSignal ? j - inputCount : j - 1) + .arg(typeNameToXml(typeName)); } } - parseError(); + int wantedMask; + if (isScriptable) + wantedMask = isSignal ? QDBusConnection::ExportScriptableSignals + : QDBusConnection::ExportScriptableSlots; + else + wantedMask = isSignal ? QDBusConnection::ExportNonScriptableSignals + : QDBusConnection::ExportNonScriptableSlots; + if ((flags & wantedMask) != wantedMask) + return QString(); + + if (qDBusCheckAsyncTag(mm.tag.constData())) + // add the no-reply annotation + xml += QLatin1String(" \n"); + + QString retval = xml; + retval += QString::fromLatin1(" \n") + .arg(isSignal ? QLatin1String("signal") : QLatin1String("method")); + + return retval; } -void MocParser::loadStringData(char *&stringdata) -{ - stringdata = 0; - QVarLengthArray array; - - while (!input->atEnd()) { - QByteArray line = readLine(); - if (line == "};\n") { - // end of data - stringdata = new char[array.count()]; - memcpy(stringdata, array.data(), array.count() * sizeof(*stringdata)); - return; - } - int start = line.indexOf('"'); - if (start == -1) - parseError(); - - int len = line.length() - 1; - line.truncate(len); // drop ending \n - if (line.at(len - 1) != '"') - parseError(); - - --len; - ++start; - for ( ; start < len; ++start) - if (line.at(start) == '\\') { - // parse escaped sequence - ++start; - if (start == len) - parseError(); - - QChar c(QLatin1Char(line.at(start))); - if (!c.isDigit()) { - switch (c.toLatin1()) { - case 'a': - array.append('\a'); - break; - case 'b': - array.append('\b'); - break; - case 'f': - array.append('\f'); - break; - case 'n': - array.append('\n'); - break; - case 'r': - array.append('\r'); - break; - case 't': - array.append('\t'); - break; - case 'v': - array.append('\v'); - break; - case '\\': - case '?': - case '\'': - case '"': - array.append(c.toLatin1()); - break; - - case 'x': - if (start + 2 <= len) - parseError(); - array.append(char(line.mid(start + 1, 2).toInt(0, 16))); - break; - - default: - array.append(c.toLatin1()); - fprintf(stderr, PROGRAMNAME ": warning: invalid escape sequence '\\%c' found in input", - c.toLatin1()); - } - } else { - // octal - QRegExp octal(QLatin1String("([0-7]+)")); - if (octal.indexIn(QLatin1String(line), start) == -1) - parseError(); - array.append(char(octal.cap(1).toInt(0, 8))); - } +static QString generateInterfaceXml(const ClassDef *mo) +{ + QString retval; + + // start with properties: + if (flags & (QDBusConnection::ExportScriptableProperties | + QDBusConnection::ExportNonScriptableProperties)) { + static const char *accessvalues[] = {0, "read", "write", "readwrite"}; + foreach (const PropertyDef &mp, mo->propertyList) { + if (!((!mp.scriptable.isEmpty() && (flags & QDBusConnection::ExportScriptableProperties)) || + (!mp.scriptable.isEmpty() && (flags & QDBusConnection::ExportNonScriptableProperties)))) + continue; + + int access = 0; + if (!mp.read.isEmpty()) + access |= 1; + if (!mp.write.isEmpty()) + access |= 2; + + int typeId = QMetaType::type(mp.type.constData()); + if (!typeId) + continue; + const char *signature = QDBusMetaType::typeToSignature(typeId); + if (!signature) + continue; + + retval += QString::fromLatin1(" \n \n \n") + .arg(typeNameToXml(mp.type.constData())); } else { - array.append(line.at(start)); + retval += QLatin1String("/>\n"); } + } + } + + // now add methods: + + if (flags & (QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportNonScriptableSignals)) { + foreach (const FunctionDef &mm, mo->signalList) { + if (mm.wasCloned) + continue; + + retval += addFunction(mm, true); + } } - parseError(); + if (flags & (QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportNonScriptableSlots)) { + foreach (const FunctionDef &slot, mo->slotList) { + if (slot.access == FunctionDef::Public) + retval += addFunction(slot); + } + foreach (const FunctionDef &method, mo->methodList) { + if (method.access == FunctionDef::Public) + retval += addFunction(method); + } + } + return retval; } -void MocParser::parse(const char *fname, QIODevice *io, int lineNum) +QString qDBusInterfaceFromClassDef(const ClassDef *mo) { - filename = fname; - input = io; - lineNumber = lineNum; - - while (!input->atEnd()) { - QByteArray line = readLine(); - if (line.startsWith("static const uint qt_meta_data_")) { - // start of new class data - uint *data; - loadIntData(data); - - // find the start of the string data - do { - line = readLine(); - if (input->atEnd()) - parseError(); - } while (!line.startsWith("static const char qt_meta_stringdata_")); - - char *stringdata; - loadStringData(stringdata); - - QMetaObject mo; - mo.d.superdata = &QObject::staticMetaObject; - mo.d.stringdata = stringdata; - mo.d.data = data; - mo.d.extradata = 0; - objects.append(mo); - } + QString interface; + + foreach (ClassInfoDef cid, mo->classInfoList) { + if (cid.name == QCLASSINFO_DBUS_INTERFACE) + return QString::fromUtf8(cid.value); + } + interface = QLatin1String(mo->classname); + interface.replace(QLatin1String("::"), QLatin1String(".")); + + if (interface.startsWith(QLatin1String("QDBus"))) { + interface.prepend(QLatin1String("com.trolltech.QtDBus.")); + } else if (interface.startsWith(QLatin1Char('Q')) && + interface.length() >= 2 && interface.at(1).isUpper()) { + // assume it's Qt + interface.prepend(QLatin1String("local.com.trolltech.Qt.")); + } else { + interface.prepend(QLatin1String("local.")); } - fname = 0; - input = 0; + return interface; } -MocParser::~MocParser() + +QString qDBusGenerateClassDefXml(const ClassDef *cdef) { - foreach (QMetaObject mo, objects) { - delete const_cast(mo.d.stringdata); - delete const_cast(mo.d.data); + foreach (const ClassInfoDef &cid, cdef->classInfoList) { + if (cid.name == QCLASSINFO_DBUS_INTROSPECTION) + return QString::fromUtf8(cid.value); } + + // generate the interface name from the meta object + QString interface = qDBusInterfaceFromClassDef(cdef); + + QString xml = generateInterfaceXml(cdef); + + if (xml.isEmpty()) + return QString(); // don't add an empty interface + return QString::fromLatin1(" \n%2 \n") + .arg(interface, xml); } static void showHelp() @@ -300,7 +322,8 @@ static void showVersion() static void parseCmdLine(QStringList &arguments) { - for (int i = 1; i < arguments.count(); ++i) { + flags = 0; + for (int i = 0; i < arguments.count(); ++i) { const QString arg = arguments.at(i); if (arg == QLatin1String("--help")) @@ -369,14 +392,16 @@ static void parseCmdLine(QStringList &arguments) int main(int argc, char **argv) { - QCoreApplication app(argc, argv); - QStringList args = app.arguments(); - - MocParser parser; + QStringList args; + for (int n = 1; n < argc; ++n) + args.append(QString::fromLocal8Bit(argv[n])); parseCmdLine(args); - for (int i = 1; i < args.count(); ++i) { + QList classes; + + for (int i = 0; i < args.count(); ++i) { const QString arg = args.at(i); + if (arg.startsWith(QLatin1Char('-'))) continue; @@ -387,35 +412,22 @@ int main(int argc, char **argv) return 1; } - f.readLine(); + Preprocessor pp; + Moc moc(pp); + pp.macros["Q_MOC_RUN"]; + pp.macros["__cplusplus"]; - QByteArray line = f.readLine(); - if (line.contains("Meta object code from reading C++ file")) - // this is a moc-generated file - parser.parse(argv[i], &f, 3); - else { - // run moc on this file - QProcess proc; - proc.start(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/moc"), QStringList() << QFile::decodeName(argv[i]), QIODevice::ReadOnly | QIODevice::Text); + const QByteArray filename = QFile::decodeName(argv[i]).toLatin1(); - if (!proc.waitForStarted()) { - fprintf(stderr, PROGRAMNAME ": could not execute moc! Aborting.\n"); - return 1; - } + moc.filename = filename; + moc.currentFilenames.push(filename); - proc.closeWriteChannel(); + moc.symbols = pp.preprocessed(moc.filename, &f); + moc.parse(); - if (!proc.waitForFinished() || proc.exitStatus() != QProcess::NormalExit || - proc.exitCode() != 0) { - // output the moc errors: - fprintf(stderr, "%s", proc.readAllStandardError().constData()); - fprintf(stderr, PROGRAMNAME ": exit code %d from moc. Aborting\n", proc.exitCode()); - return 1; - } - fprintf(stderr, "%s", proc.readAllStandardError().constData()); - - parser.parse(argv[i], &proc, 1); - } + if (moc.classList.isEmpty()) + return 0; + classes = moc.classList; f.close(); } @@ -434,9 +446,8 @@ int main(int argc, char **argv) output.write(docTypeHeader); output.write("\n"); - foreach (QMetaObject mo, parser.objects) { - QString xml = qDBusGenerateMetaObjectXml(QString(), &mo, &QObject::staticMetaObject, - flags); + foreach (const ClassDef &cdef, classes) { + QString xml = qDBusGenerateClassDefXml(&cdef); output.write(xml.toLocal8Bit()); } output.write("\n"); diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro b/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro index 4f5f826ce7..33f7937c5b 100644 --- a/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro +++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro @@ -1,10 +1,34 @@ -SOURCES = qdbuscpp2xml.cpp -DESTDIR = $$QT.designer.bins + +TEMPLATE = app TARGET = qdbuscpp2xml -QT = core -CONFIG += qdbus -CONFIG -= app_bundle -win32:CONFIG += console -target.path=$$[QT_INSTALL_BINS] +DESTDIR = ../../../bin + +include(../moc/moc.pri) + +INCLUDEPATH += . +DEPENDPATH += . + +INCLUDEPATH += $$QT_BUILD_TREE/include \ + $$QT_BUILD_TREE/include/QtDBus \ + $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION \ + $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION/QtDBus \ + $$QT_SOURCE_TREE/src/dbus + +QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS + +SOURCES += qdbuscpp2xml.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusmetatype.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusutil.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusmisc.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusargument.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusmarshaller.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusextratypes.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbus_symbols.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusunixfiledescriptor.cpp + +include(../bootstrap/bootstrap.pri) + +target.path = $$[QT_HOST_BINS] INSTALLS += target +load(qt_targets) diff --git a/src/tools/tools.pro b/src/tools/tools.pro index 23666bd4ef..8ad30a998d 100644 --- a/src/tools/tools.pro +++ b/src/tools/tools.pro @@ -1,7 +1,7 @@ TEMPLATE = subdirs TOOLS_SUBDIRS = src_tools_bootstrap src_tools_moc src_tools_rcc src_tools_qdoc -contains(QT_CONFIG, dbus): TOOLS_SUBDIRS += src_tools_qdbusxml2cpp +contains(QT_CONFIG, dbus): TOOLS_SUBDIRS += src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml !contains(QT_CONFIG, no-gui): TOOLS_SUBDIRS += src_tools_uic # Set subdir and respective target name src_tools_bootstrap.subdir = $$PWD/bootstrap @@ -17,6 +17,8 @@ src_tools_qdoc.target = sub-qdoc contains(QT_CONFIG, dbus) { src_tools_qdbusxml2cpp.subdir = $$QT_SOURCE_TREE/src/tools/qdbusxml2cpp src_tools_qdbusxml2cpp.target = sub-qdbusxml2cpp + src_tools_qdbuscpp2xml.subdir = $$QT_SOURCE_TREE/src/tools/qdbuscpp2xml + src_tools_qdbuscpp2xml.target = sub-qdbuscpp2xml } !wince*:!ordered { @@ -27,6 +29,7 @@ contains(QT_CONFIG, dbus) { src_tools_qdoc.depends = src_tools_bootstrap contains(QT_CONFIG, dbus) { src_tools_qdbusxml2cpp.depends = src_tools_bootstrap + src_tools_qdbuscpp2xml.depends = src_tools_bootstrap } } diff --git a/tests/auto/tools/qdbuscpp2xml/qdbuscpp2xml.pro b/tests/auto/tools/qdbuscpp2xml/qdbuscpp2xml.pro new file mode 100644 index 0000000000..4217d5e73c --- /dev/null +++ b/tests/auto/tools/qdbuscpp2xml/qdbuscpp2xml.pro @@ -0,0 +1,11 @@ +CONFIG += testcase +QT = core testlib dbus +TARGET = tst_qdbuscpp2xml + +QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS + +SOURCES += tst_qdbuscpp2xml.cpp \ + +RESOURCES += qdbuscpp2xml.qrc + +HEADERS += test1.h \ No newline at end of file diff --git a/tests/auto/tools/qdbuscpp2xml/qdbuscpp2xml.qrc b/tests/auto/tools/qdbuscpp2xml/qdbuscpp2xml.qrc new file mode 100644 index 0000000000..b4cffb842e --- /dev/null +++ b/tests/auto/tools/qdbuscpp2xml/qdbuscpp2xml.qrc @@ -0,0 +1,5 @@ + + + test1.h + + diff --git a/tests/auto/tools/qdbuscpp2xml/test1.h b/tests/auto/tools/qdbuscpp2xml/test1.h new file mode 100644 index 0000000000..35dee2cc38 --- /dev/null +++ b/tests/auto/tools/qdbuscpp2xml/test1.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDBUSCPP2XML_TEST1_H +#define QDBUSCPP2XML_TEST1_H + +#include + +class QDBusObjectPath; +class QDBusUnixFileDescriptor; +class QDBusSignature; + +class Test1 : public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.qtProject.qdbuscpp2xmlTests.Test1") + Q_PROPERTY(int numProperty1 READ numProperty1 CONSTANT) + Q_PROPERTY(int numProperty2 READ numProperty2 WRITE setNumProperty2) +public: + Test1(QObject *parent = 0) : QObject(parent) {} + + int numProperty1() { return 42; } + + int numProperty2() { return 42; } + void setNumProperty2(int) {} + +signals: + void signalVoidType(); + int signalIntType(); + void signal_primitive_args(int a1, bool a2, short a3, ushort a4, uint a5, qlonglong a6, double a7, qlonglong a8 = 0); + void signal_string_args(const QByteArray &ba, const QString &a2); + void signal_Qt_args1(const QDate &a1, const QTime &a2, const QDateTime &a3, + const QRect &a4, const QRectF &a5, const QSize &a6, const QSizeF &a7); + void signal_Qt_args2(const QPoint &a1, const QPointF &a2, const QLine &a3, const QLineF &a4, + const QVariantList &a5, const QVariantMap &a6, const QVariantHash &a7); + + void signal_QDBus_args(const QDBusObjectPath &a1, const QDBusSignature &a2, const QDBusUnixFileDescriptor &a3); + + void signal_container_args1(const QList &a1, const QList &a2, const QList &a3, const QList &a4, const QList &a5); + void signal_container_args2(const QList &a1, const QList &a2, const QList &a3, const QList &a4, const QList &a5, const QList &a6); + + Q_SCRIPTABLE void signalVoidType_scriptable(); + Q_SCRIPTABLE int signalIntType_scriptable(); + Q_SCRIPTABLE void signal_primitive_args_scriptable(int a1, bool a2, short a3, ushort a4, uint a5, qlonglong a6, double a7, qlonglong a8 = 0); + Q_SCRIPTABLE void signal_string_args_scriptable(const QByteArray &ba, const QString &a2); + Q_SCRIPTABLE void signal_Qt_args1_scriptable(const QDate &a1, const QTime &a2, const QDateTime &a3, + const QRect &a4, const QRectF &a5, const QSize &a6, const QSizeF &a7); + Q_SCRIPTABLE void signal_Qt_args2_scriptable(const QPoint &a1, const QPointF &a2, const QLine &a3, const QLineF &a4, + const QVariantList &a5, const QVariantMap &a6, const QVariantHash &a7); + + Q_SCRIPTABLE void signal_QDBus_args_scriptable(const QDBusObjectPath &a1, const QDBusSignature &a2, const QDBusUnixFileDescriptor &a3); + + Q_SCRIPTABLE void signal_container_args1_scriptable(const QList &a1, const QList &a2, const QList &a3, const QList &a4, const QList &a5); + Q_SCRIPTABLE void signal_container_args2_scriptable(const QList &a1, const QList &a2, const QList &a3, const QList &a4, const QList &a5, const QList &a6); + +public slots: + void slotVoidType() {} + int slotIntType() { return 42; } + + Q_SCRIPTABLE void slotVoidType_scriptable() {} + Q_SCRIPTABLE int slotIntType_scriptable() { return 42; } + +protected slots: + void neverExported1() {} + int neverExported2() { return 42; } + + Q_SCRIPTABLE void neverExported3() {} + Q_SCRIPTABLE int neverExported4() { return 42; } + +private slots: + void neverExported5() {} + int neverExported6() { return 42; } + + Q_SCRIPTABLE void neverExported7() {} + Q_SCRIPTABLE int neverExported8() { return 42; } + +public: + Q_SCRIPTABLE void methodVoidType() {} + Q_SCRIPTABLE int methodIntType() { return 42; } + +protected: + Q_SCRIPTABLE void neverExported9() {} + Q_SCRIPTABLE int neverExported10() { return 42; } + +private: + Q_SCRIPTABLE void neverExported11() {} + Q_SCRIPTABLE int neverExported12() { return 42; } +}; + +#endif diff --git a/tests/auto/tools/qdbuscpp2xml/tst_qdbuscpp2xml.cpp b/tests/auto/tools/qdbuscpp2xml/tst_qdbuscpp2xml.cpp new file mode 100644 index 0000000000..5510c656e1 --- /dev/null +++ b/tests/auto/tools/qdbuscpp2xml/tst_qdbuscpp2xml.cpp @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "test1.h" + +#include + +// in qdbusxmlgenerator.cpp +QT_BEGIN_NAMESPACE +extern Q_DBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, + const QMetaObject *mo, + const QMetaObject *base, + int flags); +QT_END_NAMESPACE + +static QString addXmlHeader(const QString &input) +{ + return + "\n" + + (input.isEmpty() ? QString() : QString("\n " + input.trimmed())) + + "\n\n"; +} + +class tst_qdbuscpp2xml : public QObject +{ + Q_OBJECT + +private slots: + void qdbuscpp2xml_data(); + void qdbuscpp2xml(); + + void initTestCase(); + void cleanupTestCase(); + +private: + QHash m_tests; +}; + +void tst_qdbuscpp2xml::initTestCase() +{ + m_tests.insert("test1", new Test1); +} + +void tst_qdbuscpp2xml::cleanupTestCase() +{ + qDeleteAll(m_tests); +} + +void tst_qdbuscpp2xml::qdbuscpp2xml_data() +{ + QTest::addColumn("inputfile"); + QTest::addColumn("flags"); + + QBitArray doneFlags(QDBusConnection::ExportAllContents + 1); + for (int flag = 0x10; flag < QDBusConnection::ExportScriptableContents; flag += 0x10) { + QTest::newRow("xmlgenerator-" + QByteArray::number(flag)) << "test1" << flag; + doneFlags.setBit(flag); + for (int mask = QDBusConnection::ExportAllSlots; mask <= QDBusConnection::ExportAllContents; mask += 0x110) { + int flags = flag | mask; + if (doneFlags.testBit(flags)) + continue; + QTest::newRow("xmlgenerator-" + QByteArray::number(flags)) << "test1" << flags; + doneFlags.setBit(flags); + } + } +} + +void tst_qdbuscpp2xml::qdbuscpp2xml() +{ + QFETCH(QString, inputfile); + QFETCH(int, flags); + + // qdbuscpp2xml considers these equivalent + if (flags & QDBusConnection::ExportScriptableSlots) + flags |= QDBusConnection::ExportScriptableInvokables; + if (flags & QDBusConnection::ExportNonScriptableSlots) + flags |= QDBusConnection::ExportNonScriptableInvokables; + + if (flags & QDBusConnection::ExportScriptableInvokables) + flags |= QDBusConnection::ExportScriptableSlots; + if (flags & QDBusConnection::ExportNonScriptableInvokables) + flags |= QDBusConnection::ExportNonScriptableSlots; + + QStringList options; + if (flags & QDBusConnection::ExportScriptableProperties) { + if (flags & QDBusConnection::ExportNonScriptableProperties) + options << "-P"; + else + options << "-p"; + } + if (flags & QDBusConnection::ExportScriptableSignals) { + if (flags & QDBusConnection::ExportNonScriptableSignals) + options << "-S"; + else + options << "-s"; + } + if (flags & QDBusConnection::ExportScriptableSlots) { + if (flags & QDBusConnection::ExportNonScriptableSlots) + options << "-M"; + else + options << "-m"; + } + + // Launch + const QString command = QLatin1String("qdbuscpp2xml"); + QProcess process; + process.start(command, QStringList() << options << (QFINDTESTDATA(inputfile + QStringLiteral(".h")))); + if (!process.waitForFinished()) { + const QString path = QString::fromLocal8Bit(qgetenv("PATH")); + QString message = QString::fromLatin1("'%1' could not be found when run from '%2'. Path: '%3' "). + arg(command, QDir::currentPath(), path); + QFAIL(qPrintable(message)); + } + const QChar cr = QLatin1Char('\r'); + const QString err = QString::fromLocal8Bit(process.readAllStandardError()).remove(cr); + const QString out = QString::fromAscii(process.readAllStandardOutput()).remove(cr); + + if (!err.isEmpty()) { + qDebug() << "UNEXPECTED STDERR CONTENTS: " << err; + QFAIL("UNEXPECTED STDERR CONTENTS"); + } + + const QChar nl = QLatin1Char('\n'); + const QStringList actualLines = out.split(nl); + + QObject *testObject = m_tests.value(inputfile); + + if (flags == 0) + flags = QDBusConnection::ExportScriptableContents + | QDBusConnection::ExportNonScriptableContents; + + QString expected = qDBusGenerateMetaObjectXml(QString(), testObject->metaObject(), &QObject::staticMetaObject, flags); + + expected = addXmlHeader(expected); + + QCOMPARE(out, expected); +} + +QTEST_APPLESS_MAIN(tst_qdbuscpp2xml) + +#include "tst_qdbuscpp2xml.moc" diff --git a/tests/auto/tools/tools.pro b/tests/auto/tools/tools.pro index 6bf6ddf64f..0a2821773f 100644 --- a/tests/auto/tools/tools.pro +++ b/tests/auto/tools/tools.pro @@ -5,3 +5,4 @@ SUBDIRS=\ moc \ rcc \ +contains(QT_CONFIG, dbus):SUBDIRS += qdbuscpp2xml -- cgit v1.2.3