diff options
Diffstat (limited to 'tests/auto/tools/qdbusxml2cpp')
-rw-r--r-- | tests/auto/tools/qdbusxml2cpp/CMakeLists.txt | 10 | ||||
-rw-r--r-- | tests/auto/tools/qdbusxml2cpp/tst_qdbusxml2cpp.cpp | 306 |
2 files changed, 259 insertions, 57 deletions
diff --git a/tests/auto/tools/qdbusxml2cpp/CMakeLists.txt b/tests/auto/tools/qdbusxml2cpp/CMakeLists.txt index 0ed55411db..29278377b6 100644 --- a/tests/auto/tools/qdbusxml2cpp/CMakeLists.txt +++ b/tests/auto/tools/qdbusxml2cpp/CMakeLists.txt @@ -1,12 +1,16 @@ # Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -# Generated from qdbusxml2cpp.pro. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qdbusxml2cpp Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qdbusxml2cpp LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qdbusxml2cpp SOURCES tst_qdbusxml2cpp.cpp diff --git a/tests/auto/tools/qdbusxml2cpp/tst_qdbusxml2cpp.cpp b/tests/auto/tools/qdbusxml2cpp/tst_qdbusxml2cpp.cpp index db0c8af0fd..c51a0909f8 100644 --- a/tests/auto/tools/qdbusxml2cpp/tst_qdbusxml2cpp.cpp +++ b/tests/auto/tools/qdbusxml2cpp/tst_qdbusxml2cpp.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2016 Intel Corporation. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QLibraryInfo> @@ -21,6 +21,10 @@ private slots: void process(); void includeStyle_data(); void includeStyle(); + void missingAnnotation_data(); + void missingAnnotation(); + void includeMoc_data(); + void includeMoc(); }; struct BasicTypeList { @@ -57,6 +61,72 @@ static QString stripHeader(QString output) return output.remove(header); } +static void runTool(QProcess &process, const QByteArray &data, + const QStringList &flags) +{ + // test both interface and adaptor generation + QFETCH_GLOBAL(QString, commandLineArg); + + // Run the tool + const QString binpath = QLibraryInfo::path(QLibraryInfo::BinariesPath); + QStringList arguments = { commandLineArg }; + arguments += flags; + process.setArguments(arguments); + process.setProgram(binpath + QLatin1String("/qdbusxml2cpp")); + process.start(QIODevice::Text | QIODevice::ReadWrite); + QVERIFY2(process.waitForStarted(), qPrintable(process.errorString())); + + static const char xmlHeader[] = + "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE // \n is included + "<node>\n" + " <interface name=\"local.name.is.not.important\">\n" + " <!-- begin data -->\n"; + static const char xmlFooter[] = "\n" + " <!-- end data -->\n" + " </interface>\n" + "</node>\n"; + + process.write(xmlHeader, sizeof(xmlHeader) - 1); + process.write(data); + process.write(xmlFooter, sizeof(xmlFooter) - 1); + + while (process.bytesToWrite()) + QVERIFY2(process.waitForBytesWritten(), qPrintable(process.errorString())); + // fprintf(stderr, "%s%s%s", xmlHeader, xmlSnippet.toLatin1().constData(), xmlFooter); + + process.closeWriteChannel(); + QVERIFY2(process.waitForFinished(), qPrintable(process.errorString())); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); +} + +static void checkOneFile(const QString &fileName, const QByteArray &expected) +{ + QFile file(fileName); + QVERIFY(file.exists()); + const auto guard = QScopeGuard([&](){ QFile::remove(fileName); }); + + QVERIFY(file.open(QFile::Text | QFile::ReadOnly)); + QByteArray text = file.readAll(); + QVERIFY(text.contains(expected)); +} + +static void checkTwoFiles(const QString &headerName, const QString &sourceName, const QByteArray &expected) +{ + QFile headerFile(headerName); + QFile sourceFile(sourceName); + + QVERIFY(headerFile.exists()); + const auto headerGuard = QScopeGuard([&](){ QFile::remove(headerName); }); + + QVERIFY(sourceFile.exists()); + const auto sourceGuard = QScopeGuard([&](){ QFile::remove(sourceName); }); + + QVERIFY(sourceFile.open(QFile::Text | QFile::ReadOnly)); + QByteArray text = sourceFile.readAll(); + QVERIFY(text.contains(expected)); +} + void tst_qdbusxml2cpp::initTestCase_data() { QTest::addColumn<int>("outputMode"); @@ -164,11 +234,52 @@ void tst_qdbusxml2cpp::process_data() "<arg type=\"s\" direction=\"out\"/>" "<arg type=\"s\" direction=\"out\"/>" "</method>" - << QRegularExpression("Q_SLOTS:.*QDBusPendingReply<QString, QString> Method\\(const QString &\\w*, const QString &", + << QRegularExpression("Q_SLOTS:.*QDBusPendingReply<QString, QString> Method\\(const QString &\\w*, const QString &\\w*\\)" + ".*inline QDBusReply<QString> Method\\(const QString &\\w*, const QString &\\w*, QString &\\w*\\)", QRegularExpression::DotMatchesEverythingOption) << QRegularExpression("Q_SLOTS:.*QString Method\\(const QString &\\w*, const QString &\\w*, QString &", QRegularExpression::DotMatchesEverythingOption); + QTest::newRow("method-deprecated-0out") + << "<method name=\"Method\">" + "<annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>" + "</method>" + << QRegularExpression("Q_SLOTS:.*Q_DECL_DEPRECATED inline QDBusPendingReply<> Method\\(\\)", + QRegularExpression::DotMatchesEverythingOption) + << QRegularExpression("Q_SLOTS:.*\n\\s*void Method\\(\\)", // no Q_DECL_DEPRECATED + QRegularExpression::DotMatchesEverythingOption); + + QTest::newRow("method-deprecated-2out") + << "<method name=\"Method\">" + "<annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>" + "<arg type=\"s\" direction=\"out\"/>" + "<arg type=\"s\" direction=\"out\"/>" + "</method>" + << QRegularExpression("Q_SLOTS:.*Q_DECL_DEPRECATED inline QDBusPendingReply<QString, QString> Method\\(\\)" + ".*Q_DECL_DEPRECATED inline QDBusReply<QString> Method\\(QString &\\w*\\)", + QRegularExpression::DotMatchesEverythingOption) + << QRegularExpression("Q_SLOTS:.*\n\\s*QString Method\\(QString &", // no Q_DECL_DEPRECATED + QRegularExpression::DotMatchesEverythingOption); + + QTest::newRow("method-noreply") + << "<method name=\"Method\">" + "<annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>" + "</method>" + << QRegularExpression("Q_SLOTS:.*Q_NOREPLY inline void Method\\(\\).*\\bQDBus::NoBlock\\b", + QRegularExpression::DotMatchesEverythingOption) + << QRegularExpression("Q_SLOTS:.*Q_NOREPLY void Method\\(", + QRegularExpression::DotMatchesEverythingOption); + + QTest::newRow("method-deprecated-noreply") + << "<method name=\"Method\">" + "<annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>" + "<annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>" + "</method>" + << QRegularExpression("Q_SLOTS:.*Q_DECL_DEPRECATED Q_NOREPLY inline void Method\\(\\).*\\bQDBus::NoBlock\\b", + QRegularExpression::DotMatchesEverythingOption) + << QRegularExpression("Q_SLOTS:.*Q_NOREPLY void Method\\(", + QRegularExpression::DotMatchesEverythingOption); + // -- signals -- for (int i = 0; i < basicTypeCount; ++i) { QRegularExpression rx(QString("Q_SIGNALS:.*\\bvoid Signal\\((const )?%1\\b") @@ -181,6 +292,24 @@ void tst_qdbusxml2cpp::process_data() .arg(basicTypeList[i].dbusType) << rx << rx; } + + QRegularExpression rx(R"(Q_SIGNALS:.*\b\Qvoid Signal(const QVariantMap &map);\E)", + QRegularExpression::DotMatchesEverythingOption); + QTest::newRow("signal-complex") + << R"(<signal name="Signal"> + <arg type="a{sv}" name="map"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>" + </signal>)" + << rx << rx; + + QTest::newRow("signal-deprecated") + << R"(<signal name="Signal"> + <annotation name="org.freedesktop.DBus.Deprecated" value="true"/> + </signal>)" + << QRegularExpression(R"(Q_SIGNALS:.*\bQ_DECL_DEPRECATED void Signal\(\))", + QRegularExpression::DotMatchesEverythingOption) + << QRegularExpression(R"(Q_SIGNALS:.*\n\s*void Signal\(\))", // no Q_DECL_DEPRECATED + QRegularExpression::DotMatchesEverythingOption); } void tst_qdbusxml2cpp::process() @@ -191,38 +320,11 @@ void tst_qdbusxml2cpp::process() QVERIFY2(interfaceSearch.isValid(), qPrintable(interfaceSearch.errorString())); QVERIFY2(adaptorSearch.isValid(), qPrintable(adaptorSearch.errorString())); - // test both interface and adaptor generation QFETCH_GLOBAL(int, outputMode); - QFETCH_GLOBAL(QString, commandLineArg); - - // Run the tool - const QString binpath = QLibraryInfo::path(QLibraryInfo::BinariesPath); - const QString command = binpath + QLatin1String("/qdbusxml2cpp"); QProcess process; - process.start(command, QStringList() << commandLineArg << "-" << "-N"); - QVERIFY2(process.waitForStarted(), qPrintable(process.errorString())); - - // feed it our XML data - static const char xmlHeader[] = - "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE // \n is included - "<node>\n" - " <interface name=\"local.name.is.not.important\">\n" - " <!-- begin data -->\n"; - static const char xmlFooter[] = "\n" - " <!-- end data -->\n" - " </interface>\n" - "</node>\n"; - - process.write(xmlHeader, int(sizeof xmlHeader) - 1); - process.write(xmlSnippet.toLatin1()); - process.write(xmlFooter, int(sizeof xmlFooter) - 1); - while (process.bytesToWrite()) - QVERIFY2(process.waitForBytesWritten(), qPrintable(process.errorString())); - // fprintf(stderr, "%s%s%s", xmlHeader, xmlSnippet.toLatin1().constData(), xmlFooter); - - process.closeWriteChannel(); - QVERIFY2(process.waitForFinished(), qPrintable(process.errorString())); + QStringList flags = {"-", "-N"}; + runTool(process, xmlSnippet.toLatin1(), flags); + if (QTest::currentTestFailed()) return; QByteArray errOutput = process.readAllStandardError(); QVERIFY2(errOutput.isEmpty(), errOutput); @@ -250,40 +352,136 @@ void tst_qdbusxml2cpp::includeStyle() { QFETCH(bool, isGlobal); QFETCH(QByteArray, expected); - QFETCH_GLOBAL(QString, commandLineArg); - - // feed it our XML data - static const char xml[] = - "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE // \n is included - "<node>\n" - " <interface name=\"local.name.is.not.important\">\n" - " </interface>\n" - "</node>\n"; - // Run the tool - const QString binpath = QLibraryInfo::path(QLibraryInfo::BinariesPath); - const QString command = binpath + QLatin1String("/qdbusxml2cpp"); QProcess process; - process.start(command, QStringList() << commandLineArg << "-" << "-N" << (isGlobal ? "-I" : "-i") << "test.hpp"); - QVERIFY2(process.waitForStarted(), qPrintable(process.errorString())); - - process.write(xml, int(sizeof xml) - 1); - while (process.bytesToWrite()) - QVERIFY2(process.waitForBytesWritten(), qPrintable(process.errorString())); + QStringList flags = {"-", "-N", (isGlobal ? "-I" : "-i"), "test.hpp"}; - process.closeWriteChannel(); - QVERIFY2(process.waitForFinished(), qPrintable(process.errorString())); + runTool(process,QByteArray{},flags); + QCOMPARE(process.exitCode(), 0); QByteArray errOutput = process.readAllStandardError(); QVERIFY2(errOutput.isEmpty(), errOutput); - QCOMPARE(process.exitCode(), 0); QByteArray fullOutput = process.readAll(); QVERIFY(!fullOutput.isEmpty()); QVERIFY(fullOutput.contains(expected)); } +void tst_qdbusxml2cpp::missingAnnotation_data() +{ + QTest::addColumn<QString>("xmlSnippet"); + QTest::addColumn<QString>("annotationName"); + QTest::addColumn<QString>("location"); + + QTest::newRow("property") + << R"(<property type="%1" name="name" access="readwrite"/>)" + << "org.qtproject.QtDBus.QtTypeName" + << "7:2"; + QTest::newRow("method-in") + << R"(<method name="Method"> + <arg type="%1" name="name" direction="in"/> + </method>)" + << "org.qtproject.QtDBus.QtTypeName.In0" + << "8:22"; + QTest::newRow("method-out") + << R"(<method name="Method"> + <arg type="%1" name="name" direction="out"/> + </method>)" + << "org.qtproject.QtDBus.QtTypeName.Out0" + << "8:22"; + QTest::newRow("signal") + << R"(<signal name="Signal"> + <arg type="%1" name="name"/> + </signal>)" + << "org.qtproject.QtDBus.QtTypeName.Out0" + << "8:22"; + QTest::newRow("signal-out") + << R"(<signal name="Signal"> + <arg type="%1" name="name" direction="out"/> + </signal>)" + << "org.qtproject.QtDBus.QtTypeName.Out0" + << "8:22"; +} + +void tst_qdbusxml2cpp::missingAnnotation() +{ + QFETCH(QString, xmlSnippet); + QFETCH(QString, annotationName); + QFETCH(QString, location); + + QString type = "(ii)"; + QProcess process; + QStringList flags = {"-", "-N"}; + runTool(process, xmlSnippet.arg(type).toLatin1(),flags); + if (QTest::currentTestFailed()) return; + + // it must have failed + QString errOutput = QString::fromLatin1(process.readAllStandardError().trimmed()); + QCOMPARE(process.exitCode(), 1); + QCOMPARE(process.readAllStandardOutput(), QByteArray()); + QVERIFY(!errOutput.isEmpty()); + + // check it did suggest the right annotation + QString expected = R"(<standard input>:%3: error: unknown type `%1' +<standard input>:%3: note: you should add <annotation name="%2" value="<type>"/>)"; + expected = expected.arg(type, annotationName, location); + QCOMPARE(errOutput, expected); +} + +void tst_qdbusxml2cpp::includeMoc_data() +{ + QTest::addColumn<QString>("filenames"); + QTest::addColumn<QByteArray>("expected"); + QTest::addColumn<QByteArray>("warning"); + + QTest::newRow("combined-h") << "foo.h" << QByteArray("#include \"foo.moc\"") << QByteArray(""); + QTest::newRow("combined-cpp") << "foo.cpp" << QByteArray("#include \"foo.moc\"") << QByteArray(""); + QTest::newRow("combined-cc") << "foo.cc" << QByteArray("#include \"foo.moc\"") << QByteArray(""); + QTest::newRow("without extension") << "foo" << QByteArray("#include \"moc_foo.cpp\"") << QByteArray(""); + QTest::newRow("cpp-only") << ":foo.cpp" << QByteArray("#include \"moc_foo.cpp\"") + << QByteArray("warning: no header name is provided, assuming it to be \"foo.h\""); + QTest::newRow("header-and-cpp") << "foo_h.h:foo.cpp" << QByteArray("#include \"moc_foo_h.cpp\"") << QByteArray(""); + + QTest::newRow("combined-cpp with dots") << "foo.bar.cpp" << QByteArray("#include \"foo.bar.moc\"") << QByteArray(""); + QTest::newRow("without extension with dots") << "foo.bar" << QByteArray("#include \"moc_foo.bar.cpp\"") << QByteArray(""); + QTest::newRow("header-and-cpp with dots") << "foo.bar_h.h:foo.bar.cpp" << QByteArray("#include \"moc_foo.bar_h.cpp\"") << QByteArray(""); +} + +void tst_qdbusxml2cpp::includeMoc() +{ + QFETCH(QString, filenames); + QFETCH(QByteArray, expected); + QFETCH(QByteArray, warning); + + QProcess process; + QStringList flags = {filenames, "--moc"}; + runTool(process,QByteArray{},flags); + QByteArray errOutput = process.readAllStandardError(); + QVERIFY(errOutput.startsWith(warning)); + QCOMPARE(process.exitCode(), 0); + + QStringList parts = filenames.split(u':'); + QFileInfo first{parts.first()}; + + const bool firstHasSuffix = QStringList({"h", "cpp", "cc"}).contains(first.suffix()); + + if ((parts.size() == 1) && firstHasSuffix) { + checkOneFile(parts.first(), expected); + } else if ((parts.size() == 1) && (!firstHasSuffix)) { + QString headerName{parts.first()}; + headerName += ".h"; + QString sourceName{parts.first()}; + sourceName += ".cpp"; + + checkTwoFiles(headerName, sourceName, expected); + } else if ((parts.size() == 2) && (parts.first().isEmpty())) { + checkOneFile(parts.last(), expected); + } + else if ((parts.size() == 2) && !parts.first().isEmpty() && !parts.last().isEmpty()) { + checkTwoFiles(parts.first(), parts.last(), expected); + } +} + QTEST_MAIN(tst_qdbusxml2cpp) #include "tst_qdbusxml2cpp.moc" |