diff options
author | Kari Oikarinen <kari.oikarinen@qt.io> | 2016-09-22 16:23:20 +0300 |
---|---|---|
committer | Kari Oikarinen <kari.oikarinen@qt.io> | 2016-09-23 08:57:54 +0000 |
commit | c8cda60d49adb562405794ab5ac496c2fd01e1e3 (patch) | |
tree | 4219948d4307f0866e93ff526802f946d5bf7470 /tests | |
parent | a132c64b5d590516869a252a4a6fc823787c4b61 (diff) |
Rename test/ folder to tests/ to comply with CI
Also change the install targets to be under QT_INSTALL_BINS and
QT_INSTALL_LIBS.
Task-number: QTBUG-56066
Change-Id: Icaf309ebb6e62bbf35df09fd6a72795f64f6f041
Reviewed-by: Samuli Piippo <samuli.piippo@qt.io>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/servicetest.cpp | 508 | ||||
-rw-r--r-- | tests/servicetest.pro | 55 | ||||
-rw-r--r-- | tests/streamtest.cpp | 515 | ||||
-rw-r--r-- | tests/streamtest.pro | 34 | ||||
-rw-r--r-- | tests/tests.pro | 7 | ||||
-rw-r--r-- | tests/tst_qdbmessage.cpp | 148 | ||||
-rw-r--r-- | tests/tst_qdbmessage.pro | 19 | ||||
-rw-r--r-- | tests/tst_stream.cpp | 143 | ||||
-rw-r--r-- | tests/tst_stream.pro | 44 |
9 files changed, 1473 insertions, 0 deletions
diff --git a/tests/servicetest.cpp b/tests/servicetest.cpp new file mode 100644 index 0000000..c87d429 --- /dev/null +++ b/tests/servicetest.cpp @@ -0,0 +1,508 @@ +/****************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Debug Bridge. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ +#include "../client/connection.h" +#include "../client/filepullservice.h" +#include "../client/filepushservice.h" +#include "../client/processservice.h" +#include "../client/echoservice.h" +#include "../utils/make_unique.h" +#include "usb/usbconnection.h" +#include "protocol/qdbtransport.h" +#include "protocol/services.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qregularexpression.h> +#include <QtCore/qtimer.h> +#include <QtTest/QtTest> + +const int testTimeout = 500; // in milliseconds + +// Helper to initialize Connection in testcases +struct ConnectionContext +{ + ConnectionContext() + : connection{new QdbTransport{new UsbConnection{}}} + { + QVERIFY(connection.initialize()); + + connection.connect(); + } + Connection connection; +}; + +class ServiceTest : public QObject +{ + Q_OBJECT +private slots: + void initTestCase(); + void echo(); + void processOutput(); + void processMultipleOutput(); + void processErrorCode(); + void processNonExistent(); + void processCrash(); + void processInput(); + void processMultipleInput(); + void filePush(); + void filePushNonexistent(); + void filePull(); + void filePullNonexistent(); + void filePullToUnopenable(); +}; + +const QString pushPullFileName = "qdbtestfile1"; +static QByteArray pushPullFileContents = "abcd\nefgh\n"; +const QString nonexistentFileName{"qdbtestfile2"}; + +void ServiceTest::initTestCase() +{ + qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); + qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus"); +} + +void ServiceTest::echo() +{ + ConnectionContext ctx; + + EchoService echo{&ctx.connection}; + connect(&echo, &EchoService::initialized, [&]() { + echo.send("ABCD"); + }); + QSignalSpy spy{&echo, &EchoService::echo}; + + echo.initialize(); + + spy.wait(testTimeout); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy[0][0].toByteArray(), QByteArray{"ABCD"}); +} + +void ServiceTest::processOutput() +{ + ConnectionContext ctx; + + QByteArray output; + + ProcessService processService{&ctx.connection}; + connect(&processService, &ProcessService::executionError, [](QProcess::ProcessError error) { + qDebug() << "Command not run, error:" << error; + QFAIL("Command was not run successfully"); + }); + connect(&processService, &Service::initialized, [&]() { + processService.execute("echo", {"ABCD"}); + }); + connect(&processService, &ProcessService::readyRead, [&]() { + output.append(processService.read()); + }); + QSignalSpy spy{&processService, &ProcessService::executed}; + + processService.initialize(); + + spy.wait(testTimeout); + QCOMPARE(spy.count(), 1); + auto exitCode = spy[0][0].toInt(); + QProcess::ExitStatus exitStatus = spy[0][1].value<QProcess::ExitStatus>(); + auto finalOutput = spy[0][2].toByteArray(); + output.append(finalOutput); + QCOMPARE(exitCode, 0); + QCOMPARE(exitStatus, QProcess::NormalExit); + QCOMPARE(output, QByteArray{"ABCD\n"}); +} + +void ServiceTest::processMultipleOutput() +{ + ConnectionContext ctx; + + QByteArray output; + + ProcessService processService{&ctx.connection}; + connect(&processService, &ProcessService::executionError, [](QProcess::ProcessError error) { + qDebug() << "Command not run, error:" << error; + QFAIL("Command was not run successfully"); + }); + + connect(&processService, &Service::initialized, [&]() { + processService.execute("sh", {"-c", "echo abcd && sleep 1 && echo defg"}); + }); + connect(&processService, &ProcessService::readyRead, [&]() { + output.append(processService.read()); + }); + QSignalSpy readyReadSpy{&processService, &ProcessService::readyRead}; + QSignalSpy executedSpy{&processService, &ProcessService::executed}; + + processService.initialize(); + + executedSpy.wait(1000 + testTimeout); + QCOMPARE(executedSpy.count(), 1); + // In principle there could be only one (or more than two) readyRead, but in + // practice the above command seems split into two outputs and otherwise + // this test is not fulfilling its purpose. + QCOMPARE(readyReadSpy.count(), 2); + auto exitCode = executedSpy[0][0].toInt(); + QProcess::ExitStatus exitStatus = executedSpy[0][1].value<QProcess::ExitStatus>(); + auto finalOutput = executedSpy[0][2].toByteArray(); + output.append(finalOutput); + QCOMPARE(exitCode, 0); + QCOMPARE(exitStatus, QProcess::NormalExit); + QCOMPARE(output, QByteArray{"abcd\ndefg\n"}); +} + +void ServiceTest::processErrorCode() +{ + ConnectionContext ctx; + + ProcessService processService{&ctx.connection}; + connect(&processService, &ProcessService::executionError, [](QProcess::ProcessError error) { + qDebug() << "Command not run, error:" << error; + QFAIL("Command was not run successfully"); + }); + connect(&processService, &Service::initialized, [&]() { + processService.execute("test", {"-z", "ABCD"}); + }); + QSignalSpy spy{&processService, &ProcessService::executed}; + + processService.initialize(); + + spy.wait(testTimeout); + QCOMPARE(spy.count(), 1); + auto exitCode = spy[0][0].toInt(); + QProcess::ExitStatus exitStatus = spy[0][1].value<QProcess::ExitStatus>(); + auto output = spy[0][2].toString(); + QCOMPARE(exitCode, 1); + QCOMPARE(exitStatus, QProcess::NormalExit); + QCOMPARE(output, QString{""}); +} + +void ServiceTest::processNonExistent() +{ + ConnectionContext ctx; + + ProcessService processService{&ctx.connection}; + connect(&processService, &ProcessService::executed, [](int, QProcess::ExitStatus, QString) { + QFAIL("Command was unexpectedly run successfully"); + }); + connect(&processService, &Service::initialized, [&]() { + processService.execute("lsfdajlvaie", {}); + }); + QSignalSpy spy{&processService, &ProcessService::executionError}; + + processService.initialize(); + + spy.wait(testTimeout); + QCOMPARE(spy.count(), 1); + auto error = spy[0][0].value<QProcess::ProcessError>(); + QCOMPARE(error, QProcess::FailedToStart); +} + +void ServiceTest::processCrash() +{ + ConnectionContext ctx; + + ProcessService processService{&ctx.connection}; + connect(&processService, &Service::initialized, [&]() { + // Crash the process by having it send SIGSEGV to itself + processService.execute("sh", {"-c", "kill -SEGV $$"}); + }); + QSignalSpy errorSpy{&processService, &ProcessService::executionError}; + QSignalSpy executedSpy{&processService, &ProcessService::executed}; + + processService.initialize(); + + errorSpy.wait(testTimeout); + QCOMPARE(errorSpy.count(), 1); + auto error = errorSpy[0][0].value<QProcess::ProcessError>(); + QCOMPARE(error, QProcess::Crashed); + + executedSpy.wait(testTimeout); + QCOMPARE(executedSpy.count(), 1); + auto exitCode = executedSpy[0][0].toInt(); + auto exitStatus = executedSpy[0][1].value<QProcess::ExitStatus>(); + auto output = executedSpy[0][2].toString(); + QCOMPARE(exitCode, 11); // 11 for segfault + QCOMPARE(exitStatus, QProcess::CrashExit); + QCOMPARE(output, QString{""}); +} + +void ServiceTest::processInput() +{ + ConnectionContext ctx; + + QByteArray output; + + ProcessService processService{&ctx.connection}; + connect(&processService, &ProcessService::executionError, [](QProcess::ProcessError error) { + qDebug() << "Command not run, error:" << error; + QFAIL("Command was not run successfully"); + }); + connect(&processService, &Service::initialized, [&]() { + processService.execute("sh", {"-c", "read input; echo $input"}); + }); + connect(&processService, &ProcessService::readyRead, [&]() { + output.append(processService.read()); + }); + connect(&processService, &ProcessService::started, [&]() { + processService.write("abcd\n"); + }); + QSignalSpy spy{&processService, &ProcessService::executed}; + + processService.initialize(); + + spy.wait(testTimeout); + QCOMPARE(spy.count(), 1); + auto exitCode = spy[0][0].toInt(); + QProcess::ExitStatus exitStatus = spy[0][1].value<QProcess::ExitStatus>(); + auto finalOutput = spy[0][2].toByteArray(); + output.append(finalOutput); + QCOMPARE(exitCode, 0); + QCOMPARE(exitStatus, QProcess::NormalExit); + QCOMPARE(output, QByteArray{"abcd\n"}); +} + +void ServiceTest::processMultipleInput() +{ + ConnectionContext ctx; + + QByteArray output; + + ProcessService processService{&ctx.connection}; + connect(&processService, &ProcessService::executionError, [](QProcess::ProcessError error) { + qDebug() << "Command not run, error:" << error; + QFAIL("Command was not run successfully"); + }); + connect(&processService, &Service::initialized, [&]() { + processService.execute("sh", {"-c", "for i in {1..2}; do read input; echo $input; done"}); + }); + connect(&processService, &ProcessService::readyRead, [&]() { + output.append(processService.read()); + }); + connect(&processService, &ProcessService::started, [&]() { + processService.write("abcd\n"); + processService.write("efgh\n"); + }); + QSignalSpy spy{&processService, &ProcessService::executed}; + + processService.initialize(); + + spy.wait(testTimeout); + QCOMPARE(spy.count(), 1); + auto exitCode = spy[0][0].toInt(); + QProcess::ExitStatus exitStatus = spy[0][1].value<QProcess::ExitStatus>(); + auto finalOutput = spy[0][2].toByteArray(); + output.append(finalOutput); + QCOMPARE(exitCode, 0); + QCOMPARE(exitStatus, QProcess::NormalExit); + QCOMPARE(output, QByteArray{"abcd\nefgh\n"}); +} + +void ServiceTest::filePush() +{ + ConnectionContext ctx; + + // Write source file + QFile source{pushPullFileName}; + QVERIFY(source.open(QIODevice::WriteOnly)); + source.write(pushPullFileContents); + source.close(); + + // Push source file to device (it's cleaned up in filePullToUnopenable()) + FilePushService filePushService{&ctx.connection}; + connect(&filePushService, &FilePushService::error, [](QString error) { + qCritical() << error; + QFAIL("Error while pushing file."); + }); + connect(&filePushService, &Service::initialized, [&]() { + filePushService.push(pushPullFileName, pushPullFileName); + }); + QSignalSpy pushSpy{&filePushService, &FilePushService::pushed}; + + filePushService.initialize(); + + pushSpy.wait(testTimeout); + QCOMPARE(pushSpy.count(), 1); + + // Remove source file + source.remove(); + + // Check contents on device + QByteArray output; + + ProcessService processService{&ctx.connection}; + connect(&processService, &ProcessService::executionError, [](QProcess::ProcessError error) { + qDebug() << "Command not run, error:" << error; + QFAIL("Command was not run successfully"); + }); + connect(&processService, &Service::initialized, [&]() { + processService.execute("cat", {pushPullFileName}); + }); + connect(&processService, &ProcessService::readyRead, [&]() { + output.append(processService.read()); + }); + QSignalSpy processSpy{&processService, &ProcessService::executed}; + + processService.initialize(); + + processSpy.wait(testTimeout); + QCOMPARE(processSpy.count(), 1); + auto exitCode = processSpy[0][0].toInt(); + QProcess::ExitStatus exitStatus = processSpy[0][1].value<QProcess::ExitStatus>(); + auto finalOutput = processSpy[0][2].toByteArray(); + output.append(finalOutput); + QCOMPARE(exitCode, 0); + QCOMPARE(exitStatus, QProcess::NormalExit); + QCOMPARE(output, pushPullFileContents); +} + +void ServiceTest::filePushNonexistent() +{ + QVERIFY(!QFile::exists(nonexistentFileName)); + + ConnectionContext ctx; + + FilePushService filePushService{&ctx.connection}; + connect(&filePushService, &FilePushService::pushed, []() { + QFAIL("Unexpectedly succeeded pushing nonexistent file."); + }); + connect(&filePushService, &Service::initialized, [&]() { + filePushService.push(nonexistentFileName, nonexistentFileName); + }); + QSignalSpy spy{&filePushService, &FilePushService::error}; + + filePushService.initialize(); + + spy.wait(testTimeout); + QCOMPARE(spy.count(), 1); + QRegularExpression regexp{"^Could not open.+host$"}; + auto errorMessage = spy[0][0].toString(); + QVERIFY(regexp.match(errorMessage).hasMatch()); +} + +// This test relies on the file pushed in filePush() +void ServiceTest::filePull() +{ + ConnectionContext ctx; + + // Pull source file from device + FilePullService filePullService{&ctx.connection}; + connect(&filePullService, &FilePullService::error, [](QString error) { + qCritical() << error; + QFAIL("Error while pulling file"); + }); + connect(&filePullService, &Service::initialized, [&]() { + filePullService.pull(pushPullFileName, pushPullFileName); + }); + QSignalSpy pullSpy{&filePullService, &FilePullService::pulled}; + + filePullService.initialize(); + + pullSpy.wait(testTimeout); + QCOMPARE(pullSpy.count(), 1); + + // Check contents + QFile sink{pushPullFileName}; + QVERIFY(sink.open(QIODevice::ReadOnly)); + auto contents = sink.readAll(); + QCOMPARE(contents, pushPullFileContents); + + sink.close(); + sink.remove(); +} + +void ServiceTest::filePullNonexistent() +{ + const QString nonexistentFileName{"qdbtestfile2"}; + + ConnectionContext ctx; + + // Pull source file from device + FilePullService filePullService{&ctx.connection}; + connect(&filePullService, &FilePullService::pulled, []() { + QFAIL("Unexpectedly succeeded pulling nonexistent file"); + }); + connect(&filePullService, &Service::initialized, [&]() { + filePullService.pull(nonexistentFileName, nonexistentFileName); + }); + QSignalSpy spy{&filePullService, &FilePullService::error}; + + filePullService.initialize(); + + spy.wait(testTimeout); + QCOMPARE(spy.count(), 1); + QRegularExpression regexp{"^Could not open.+device$"}; + auto errorMessage = spy[0][0].toString(); + QVERIFY(regexp.match(errorMessage).hasMatch()); +} + +// This test relies on the file pushed in filePush() and removes it in the end +void ServiceTest::filePullToUnopenable() +{ + const QString fileName{"qdbtestfile2"}; + + QFile blocker{fileName}; + blocker.open(QIODevice::WriteOnly); + blocker.setPermissions(QFileDevice::ReadUser); + blocker.close(); + + ConnectionContext ctx; + + // Pull source file from device + FilePullService filePullService{&ctx.connection}; + connect(&filePullService, &FilePullService::pulled, []() { + QFAIL("Unexpectedly succeeded pulling into file that can't be written to"); + }); + connect(&filePullService, &Service::initialized, [&]() { + filePullService.pull(pushPullFileName, fileName); + }); + QSignalSpy spy{&filePullService, &FilePullService::error}; + + filePullService.initialize(); + + spy.wait(testTimeout); + + blocker.remove(); + + QCOMPARE(spy.count(), 1); + QRegularExpression regexp{"^Could not open.+host$"}; + auto errorMessage = spy[0][0].toString(); + QVERIFY(regexp.match(errorMessage).hasMatch()); + + // Remove file from device + ProcessService processService{&ctx.connection}; + connect(&processService, &ProcessService::executionError, [](QProcess::ProcessError error) { + qDebug() << "Command not run, error:" << error; + QFAIL("Command was not run successfully"); + }); + connect(&processService, &Service::initialized, [&]() { + processService.execute("rm", {pushPullFileName}); + }); + QSignalSpy processSpy{&processService, &ProcessService::executed}; + + processService.initialize(); + + processSpy.wait(testTimeout); + QCOMPARE(processSpy.count(), 1); + auto exitCode = processSpy[0][0].toInt(); + QProcess::ExitStatus exitStatus = processSpy[0][1].value<QProcess::ExitStatus>(); + QCOMPARE(exitCode, 0); + QCOMPARE(exitStatus, QProcess::NormalExit); +} + +QTEST_GUILESS_MAIN(ServiceTest) +#include "servicetest.moc" diff --git a/tests/servicetest.pro b/tests/servicetest.pro new file mode 100644 index 0000000..a5914f8 --- /dev/null +++ b/tests/servicetest.pro @@ -0,0 +1,55 @@ +QT -= gui +QT += testlib + +win32: CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +HEADERS += \ + ../client/connection.h \ + ../client/filepullservice.h \ + ../client/filepushservice.h \ + ../client/processservice.h \ + ../client/echoservice.h \ + ../client/service.h + +SOURCES += \ + servicetest.cpp \ + ../client/connection.cpp \ + ../client/filepullservice.cpp \ + ../client/filepushservice.cpp \ + ../client/processservice.cpp \ + ../client/echoservice.cpp \ + ../client/service.cpp + +INCLUDEPATH += $$PWD/../libqdb + +unix { + LIBS = -L$$OUT_PWD/../libqdb -lqdb + QMAKE_RPATHDIR += ../libqdb +} + +win32 { +HEADERS += \ + ../libqdb/protocol/protocol.h \ + ../libqdb/protocol/qdbmessage.h \ + ../libqdb/protocol/qdbtransport.h \ + ../libqdb/stream.h \ + ../libqdb/abstractconnection.h \ + ../libqdb/streampacket.h + +SOURCES += \ + ../libqdb/protocol/qdbmessage.cpp \ + ../libqdb/protocol/qdbtransport.cpp \ + ../libqdb/stream.cpp \ + ../libqdb/abstractconnection.cpp \ + ../libqdb/streampacket.cpp + +CONFIG(debug, debug|release) { + LIBQDBDIR = $$OUT_PWD/../libqdb/debug +} else { + LIBQDBDIR = $$OUT_PWD/../libqdb/release +} +LIBS = -L$$LIBQDBDIR -lqdb +} diff --git a/tests/streamtest.cpp b/tests/streamtest.cpp new file mode 100644 index 0000000..df0c814 --- /dev/null +++ b/tests/streamtest.cpp @@ -0,0 +1,515 @@ +/****************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Debug Bridge. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ +#include "../utils/make_unique.h" +#include "usb/usbconnection.h" +#include "protocol/protocol.h" +#include "protocol/qdbmessage.h" +#include "protocol/qdbtransport.h" +#include "protocol/services.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qtimer.h> +#include <QtTest/QtTest> + +const int testTimeout = 500; // in milliseconds + +class TestCase : public QObject +{ + Q_OBJECT +public: + TestCase() + : m_transport{nullptr}, m_versionBuffer{}, m_phase{0} + { + QDataStream dataStream{&m_versionBuffer, QIODevice::WriteOnly}; + dataStream << qdbProtocolVersion; + } +public slots: + void run() + { + m_transport = make_unique<QdbTransport>(new UsbConnection{}); + if (m_transport->open()) { + qDebug() << "opened transport"; + connect(m_transport.get(), &QdbTransport::messageAvailable, this, &TestCase::testPhases); + testPhases(); + } else { + qDebug() << "failed to open transport"; + } + } + + virtual void testPhases() = 0; +signals: + void passed(); +protected: + std::unique_ptr<QdbTransport> m_transport; + QByteArray m_versionBuffer; + int m_phase; +}; + +class OpenWriteCloseEchoTest : public TestCase +{ + Q_OBJECT +public slots: + void testPhases() override + { + switch (m_phase) { + case 0: { + QdbMessage cnxn{QdbMessage::Connect, 0, 0, m_versionBuffer}; + QVERIFY(m_transport->send(cnxn)); + break; + } + case 1: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Connect); + QCOMPARE(response.data(), m_versionBuffer); + + QdbMessage open{QdbMessage::Open, m_hostId, 0, tagBuffer(EchoTag)}; + QVERIFY(m_transport->send(open)); + break; + } + case 2: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Ok); + QCOMPARE(response.hostStream(), m_hostId); + QVERIFY(response.deviceStream() != 0); + QCOMPARE(response.data(), QByteArray{}); + + m_deviceId = response.deviceStream(); + + QdbMessage write{QdbMessage::Write, m_hostId, m_deviceId, QByteArray{"\x00\x00\x00\x04""ABCD", 8}}; + QVERIFY(m_transport->send(write)); + break; + } + case 3: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Ok); + QCOMPARE(response.hostStream(), m_hostId); + QCOMPARE(response.deviceStream(), m_deviceId); + QCOMPARE(response.data(), QByteArray{}); + break; + } + case 4: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Write); + QCOMPARE(response.hostStream(), m_hostId); + QCOMPARE(response.deviceStream(), m_deviceId); + QByteArray data{"\x00\x00\x00\x04""ABCD", 8}; + QCOMPARE(response.data(), data); + + QdbMessage ok{QdbMessage::Ok, m_hostId, m_deviceId}; + QVERIFY(m_transport->send(ok)); + + QdbMessage close{QdbMessage::Close, m_hostId, m_deviceId}; + QVERIFY(m_transport->send(close)); + + emit passed(); + break; + } + } + ++m_phase; + } + +private: + const StreamId m_hostId = 1; + StreamId m_deviceId = 0; +}; + +class DoubleConnectTest : public TestCase +{ + Q_OBJECT +public slots: + void testPhases() override + { + switch (m_phase) { + case 0: { + QdbMessage connect{QdbMessage::Connect, 0, 0, m_versionBuffer}; + QVERIFY(m_transport->send(connect)); + break; + } + case 1: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Connect); + QCOMPARE(response.hostStream(), 0u); + QCOMPARE(response.deviceStream(), 0u); + QCOMPARE(response.data(), m_versionBuffer); + + QdbMessage connect{QdbMessage::Connect, 0, 0, m_versionBuffer}; + QVERIFY(m_transport->send(connect)); + break; + } + case 2: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Connect); + QCOMPARE(response.hostStream(), 0u); + QCOMPARE(response.deviceStream(), 0u); + QCOMPARE(response.data(), m_versionBuffer); + + emit passed(); + break; + } + } + ++m_phase; + } +}; + +class ConnectWithUnsupportedVersionTest : public TestCase +{ + Q_OBJECT +public slots: + void testPhases() override + { + switch (m_phase) { + case 0: { + QByteArray unsupported{}; + QDataStream dataStream{&unsupported, QIODevice::WriteOnly}; + dataStream << (qdbProtocolVersion + 1); + QdbMessage connect{QdbMessage::Connect, 0, 0, unsupported}; + QVERIFY(m_transport->send(connect)); + break; + } + case 1: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Connect); + QCOMPARE(response.hostStream(), 0u); + QCOMPARE(response.deviceStream(), 0u); + QCOMPARE(response.data(), m_versionBuffer); + + emit passed(); + break; + } + } + ++m_phase; + } +}; + +// Closing a stream twice caused a segmentation fault at one point. This is +// guarding against that regression. +class DoubleCloseTest : public TestCase +{ + Q_OBJECT +public slots: + void testPhases() override + { + switch (m_phase) { + case 0: { + QdbMessage cnxn{QdbMessage::Connect, 0, 0}; + QVERIFY(m_transport->send(cnxn)); + break; + } + case 1: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Connect); + + QdbMessage open{QdbMessage::Open, m_hostId, 0, tagBuffer(EchoTag)}; + QVERIFY(m_transport->send(open)); + break; + } + case 2: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Ok); + QCOMPARE(response.hostStream(), m_hostId); + QVERIFY(response.deviceStream() != 0); + QCOMPARE(response.data(), QByteArray{}); + + m_deviceId = response.deviceStream(); + + QdbMessage close{QdbMessage::Close, m_hostId, m_deviceId}; + QVERIFY(m_transport->send(close)); + QVERIFY(m_transport->send(close)); + + // do a write to check whether qdbd is still alive + + QdbMessage write{QdbMessage::Write, m_hostId, m_deviceId, QByteArray{"\x00\x00\x00\x04""ABCD", 8}}; + QVERIFY(m_transport->send(write)); + break; + } + case 3: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Close); + QCOMPARE(response.hostStream(), m_hostId); + QCOMPARE(response.deviceStream(), m_deviceId); + QCOMPARE(response.data(), QByteArray{}); + + emit passed(); + break; + } + } + ++m_phase; + } + +private: + const StreamId m_hostId = 1; + StreamId m_deviceId = 0; +}; + +class WriteToNonExistentStreamTest : public TestCase +{ + Q_OBJECT +public slots: + void testPhases() override + { + switch (m_phase) { + case 0: { + QdbMessage connect{QdbMessage::Connect, 0, 0, m_versionBuffer}; + QVERIFY(m_transport->send(connect)); + break; + } + case 1: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Connect); + QCOMPARE(response.hostStream(), 0u); + QCOMPARE(response.deviceStream(), 0u); + QCOMPARE(response.data(), m_versionBuffer); + + // Try to directly write to an unopened stream + QdbMessage write{QdbMessage::Write, m_hostId, m_deviceId}; + QVERIFY(m_transport->send(write)); + break; + } + case 2: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Close); + QCOMPARE(response.hostStream(), m_hostId); + QCOMPARE(response.deviceStream(), m_deviceId); + QCOMPARE(response.data(), QByteArray{}); + + // Open and close a stream and then try to write to it + QdbMessage open{QdbMessage::Open, m_hostId, 0, tagBuffer(EchoTag)}; + QVERIFY(m_transport->send(open)); + break; + } + case 3: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Ok); + QCOMPARE(response.hostStream(), m_hostId); + QVERIFY(response.deviceStream() != 0); + QCOMPARE(response.data(), QByteArray{}); + + m_deviceId2 = response.deviceStream(); + + QdbMessage close{QdbMessage::Close, m_hostId, m_deviceId2}; + QVERIFY(m_transport->send(close)); + + QdbMessage write{QdbMessage::Write, m_hostId, m_deviceId2, QByteArray{"\x00\x00\x00\x04""ABCD", 8}}; + QVERIFY(m_transport->send(write)); + break; + } + case 4: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Close); + QCOMPARE(response.hostStream(), m_hostId); + // Device stream ID does not matter, since device already closed it + QCOMPARE(response.data(), QByteArray{}); + emit passed(); + break; + } + } + ++m_phase; + } +private: + const StreamId m_hostId = 435; + const StreamId m_deviceId = 7542; + StreamId m_deviceId2 = 0; +}; + +class TwoEchoStreamsTest : public TestCase +{ + Q_OBJECT +public slots: + void testPhases() override + { + switch (m_phase) { + case 0: { + QdbMessage cnxn{QdbMessage::Connect, 0, 0, m_versionBuffer}; + QVERIFY(m_transport->send(cnxn)); + break; + } + case 1: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Connect); + + QdbMessage open{QdbMessage::Open, m_hostId1, 0, tagBuffer(EchoTag)}; + QVERIFY(m_transport->send(open)); + break; + } + case 2: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Ok); + QCOMPARE(response.hostStream(), m_hostId1); + QVERIFY(response.deviceStream() != 0); + QCOMPARE(response.data(), QByteArray{}); + + m_deviceId1 = response.deviceStream(); + + qDebug() << "writing ABCD"; + QdbMessage write{QdbMessage::Write, m_hostId1, m_deviceId1, QByteArray{"\x00\x00\x00\x04""ABCD", 8}}; + QVERIFY(m_transport->send(write)); + qDebug() << "wrote"; + break; + } + case 3: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Ok); + QCOMPARE(response.hostStream(), m_hostId1); + QCOMPARE(response.deviceStream(), m_deviceId1); + QCOMPARE(response.data(), QByteArray{}); + break; + } + case 4: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Write); + QCOMPARE(response.hostStream(), m_hostId1); + QCOMPARE(response.deviceStream(), m_deviceId1); + QByteArray data{"\x00\x00\x00\x04""ABCD", 8}; + QCOMPARE(response.data(), data); + + QdbMessage ok{QdbMessage::Ok, m_hostId1, m_deviceId1}; + QVERIFY(m_transport->send(ok)); + + QdbMessage open{QdbMessage::Open, m_hostId2, 0, tagBuffer(EchoTag)}; + QVERIFY(m_transport->send(open)); + break; + } + case 5: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Ok); + QCOMPARE(response.hostStream(), m_hostId2); + QVERIFY(response.deviceStream() != 0); + QCOMPARE(response.data(), QByteArray{}); + + m_deviceId2 = response.deviceStream(); + + QdbMessage write{QdbMessage::Write, m_hostId2, m_deviceId2, + QByteArray{"\x00\x00\x00\x05\x00\x01\x02\x03\x04", 9}}; + QVERIFY(m_transport->send(write)); + break; + } + case 6: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Ok); + QCOMPARE(response.hostStream(), m_hostId2); + QCOMPARE(response.deviceStream(), m_deviceId2); + QCOMPARE(response.data(), QByteArray{}); + break; + } + case 7: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Write); + QCOMPARE(response.hostStream(), m_hostId2); + QCOMPARE(response.deviceStream(), m_deviceId2); + auto data = QByteArray{"\x00\x00\x00\x05\x00\x01\x02\x03\x04", 9}; + QCOMPARE(response.data(), data); + + QdbMessage ok{QdbMessage::Ok, m_hostId2, m_deviceId2}; + QVERIFY(m_transport->send(ok)); + + QdbMessage close{QdbMessage::Close, m_hostId2, m_deviceId2}; + QVERIFY(m_transport->send(close)); + + QdbMessage write{QdbMessage::Write, m_hostId1, m_deviceId1, QByteArray{"\x00\x00\x00\x03QDB", 7}}; + QVERIFY(m_transport->send(write)); + break; + } + case 8: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Ok); + QCOMPARE(response.hostStream(), m_hostId1); + QCOMPARE(response.deviceStream(), m_deviceId1); + QCOMPARE(response.data(), QByteArray{}); + break; + } + case 9: { + QdbMessage response = m_transport->receive(); + QCOMPARE(response.command(), QdbMessage::Write); + QCOMPARE(response.hostStream(), m_hostId1); + QCOMPARE(response.deviceStream(), m_deviceId1); + QByteArray data{"\x00\x00\x00\x03QDB", 7}; + QCOMPARE(response.data(), data); + + QdbMessage ok{QdbMessage::Ok, m_hostId1, m_deviceId1}; + QVERIFY(m_transport->send(ok)); + + QdbMessage close{QdbMessage::Close, m_hostId1, m_deviceId1}; + QVERIFY(m_transport->send(close)); + + emit passed(); + break; + } + } + ++m_phase; + } +private: + const StreamId m_hostId1 = 1; + StreamId m_deviceId1 = 0; + const StreamId m_hostId2 = 2; + StreamId m_deviceId2 = 0; +}; + +void testCase(TestCase *test) +{ + QSignalSpy spy{test, &TestCase::passed}; + QTimer::singleShot(0, test, &TestCase::run); + spy.wait(testTimeout); + QCOMPARE(spy.count(), 1); +} + +class StreamTest : public QObject +{ + Q_OBJECT +private slots: + void openWriteCloseEcho() + { + OpenWriteCloseEchoTest test; + testCase(&test); + } + + void doubleConnect() + { + DoubleConnectTest test; + testCase(&test); + } + + void doubleClose() + { + DoubleCloseTest test; + testCase(&test); + } + + void connectWithUnsupportedVersion() + { + ConnectWithUnsupportedVersionTest test; + testCase(&test); + } + + void writeToNonexistentStream() + { + WriteToNonExistentStreamTest test; + testCase(&test); + } + + void twoEchoStreamsTest() + { + TwoEchoStreamsTest test; + testCase(&test); + } +}; + +QTEST_GUILESS_MAIN(StreamTest) +#include "streamtest.moc" diff --git a/tests/streamtest.pro b/tests/streamtest.pro new file mode 100644 index 0000000..6ff8223 --- /dev/null +++ b/tests/streamtest.pro @@ -0,0 +1,34 @@ +QT -= gui +QT += testlib + +win32: CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +SOURCES += streamtest.cpp + +INCLUDEPATH += $$PWD/../libqdb + +unix { +LIBS = -L$$OUT_PWD/../libqdb -lqdb +QMAKE_RPATHDIR += ../libqdb +} + +win32 { +HEADERS += \ + ../libqdb/protocol/qdbmessage.h \ + ../libqdb/protocol/qdbtransport.h + +SOURCES += \ + ../libqdb/protocol/qdbmessage.cpp \ + ../libqdb/protocol/qdbtransport.cpp + +CONFIG(debug, debug|release) { + LIBQDBDIR = $$OUT_PWD/../libqdb/debug +} else { + LIBQDBDIR = $$OUT_PWD/../libqdb/release +} +LIBS = -L$$LIBQDBDIR -lqdb +} + diff --git a/tests/tests.pro b/tests/tests.pro new file mode 100644 index 0000000..28b6fad --- /dev/null +++ b/tests/tests.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs + +SUBDIRS = \ + tst_qdbmessage.pro \ + tst_stream.pro \ + servicetest.pro \ + streamtest.pro diff --git a/tests/tst_qdbmessage.cpp b/tests/tst_qdbmessage.cpp new file mode 100644 index 0000000..121d65d --- /dev/null +++ b/tests/tst_qdbmessage.cpp @@ -0,0 +1,148 @@ +/****************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Debug Bridge. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ +#include <QtTest/QtTest> + +#include "../libqdb/protocol/protocol.h" +#include "../libqdb/protocol/qdbmessage.h" + +class tst_QdbMessage : public QObject +{ + Q_OBJECT +private slots: + void construction_data(); + void construction(); + void setters(); + void roundtrip_data(); + void roundtrip(); + void gettingSize_data(); + void gettingSize(); +}; + +void testData() +{ + QTest::addColumn<QdbMessage::CommandType>("command"); + QTest::addColumn<StreamId>("hostStream"); + QTest::addColumn<StreamId>("deviceStream"); + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<int>("dataSize"); + + QTest::newRow("connect") << QdbMessage::Connect << 0u << 0u << QByteArray() << 0; + QTest::newRow("open") << QdbMessage::Open << 1u << 0u << QByteArray("\x05\x04\x03\x02\x01") << 5; + QTest::newRow("write") << QdbMessage::Write << 255u << 254u << QByteArray("\x01\x02\x03") << 3; + QTest::newRow("close") << QdbMessage::Write << 0u << 1u << QByteArray("1234") << 4; + QTest::newRow("ok") << QdbMessage::Ok << 3u << 5u << QByteArray("\x0A\x0B\x0C\x0D") << 4; +} + +void tst_QdbMessage::construction_data() +{ + testData(); +} + +void tst_QdbMessage::construction() +{ + QFETCH(QdbMessage::CommandType, command); + QFETCH(StreamId, hostStream); + QFETCH(StreamId, deviceStream); + + QdbMessage message{command, hostStream, deviceStream}; + QCOMPARE(message.command(), command); + QCOMPARE(message.hostStream(), hostStream); + QCOMPARE(message.deviceStream(), deviceStream); + QCOMPARE(message.data().isEmpty(), true); + + QFETCH(QByteArray, data); + + message = QdbMessage{command, hostStream, deviceStream, data}; + QCOMPARE(message.command(), command); + QCOMPARE(message.hostStream(), hostStream); + QCOMPARE(message.deviceStream(), deviceStream); + QCOMPARE(message.data(), data); +} + +void tst_QdbMessage::setters() +{ + QdbMessage message{QdbMessage::Open, 0, 0}; + + message.setHostStream(255u); + QCOMPARE(message.hostStream(), 255u); + + message.setDeviceStream((12u)); + QCOMPARE(message.deviceStream(), 12u); + + message.setData("ABCD", 4); + QCOMPARE(message.data(), QByteArray("ABCD", 4)); +} + +void tst_QdbMessage::roundtrip_data() +{ + testData(); +} + +void tst_QdbMessage::roundtrip() +{ + QFETCH(QdbMessage::CommandType, command); + QFETCH(StreamId, hostStream); + QFETCH(StreamId, deviceStream); + QFETCH(QByteArray, data); + + QByteArray buf{qdbMessageSize, '\0'}; + QDataStream writeStream{&buf, QIODevice::WriteOnly}; + + QdbMessage message{command, hostStream, deviceStream, data}; + writeStream << message; + + QDataStream readStream{buf}; + QdbMessage readMessage; + readStream >> readMessage; + + QCOMPARE(readMessage.command(), message.command()); + QCOMPARE(readMessage.hostStream(), message.hostStream()); + QCOMPARE(readMessage.deviceStream(), message.deviceStream()); + QCOMPARE(readMessage.data(), message.data()); +} + +void tst_QdbMessage::gettingSize_data() +{ + testData(); +} + +void tst_QdbMessage::gettingSize() +{ + QFETCH(QdbMessage::CommandType, command); + QFETCH(StreamId, hostStream); + QFETCH(StreamId, deviceStream); + QFETCH(QByteArray, data); + + QByteArray buf{qdbMessageSize, '\0'}; + QDataStream writeStream{&buf, QIODevice::WriteOnly}; + + QdbMessage message{command, hostStream, deviceStream, data}; + writeStream << message; + + QFETCH(int, dataSize); + + int size = QdbMessage::GetDataSize(buf); + + QCOMPARE(size, dataSize); +} + +QTEST_APPLESS_MAIN(tst_QdbMessage) +#include "tst_qdbmessage.moc" diff --git a/tests/tst_qdbmessage.pro b/tests/tst_qdbmessage.pro new file mode 100644 index 0000000..180f616 --- /dev/null +++ b/tests/tst_qdbmessage.pro @@ -0,0 +1,19 @@ +QT -= gui +QT += testlib + +CONFIG += c++11 +CONFIG += testcase + +TARGET = tst_qdbmessage +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +HEADERS += \ + ../libqdb/protocol/protocol.h \ + ../libqdb/protocol/qdbmessage.h + +SOURCES += \ + tst_qdbmessage.cpp \ + ../libqdb/protocol/qdbmessage.cpp diff --git a/tests/tst_stream.cpp b/tests/tst_stream.cpp new file mode 100644 index 0000000..8bdace1 --- /dev/null +++ b/tests/tst_stream.cpp @@ -0,0 +1,143 @@ +/****************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Debug Bridge. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ +#include <QtTest/QtTest> + +#include "abstractconnection.h" +#include "stream.h" + +class ConnectionStub : public AbstractConnection +{ +public: + ConnectionStub() : AbstractConnection{nullptr} {} + + bool initialize() override + { + return true; + } + + void enqueueMessage(const QdbMessage &message) override + { + enqueued.append(message); + } + + void handleMessage() override + { + + } + + void reset() + { + enqueued.clear(); + } + + QList<QdbMessage> enqueued; +}; + +class tst_Stream : public QObject +{ + Q_OBJECT +public: + tst_Stream() + : m_connection{}, + m_stream{&m_connection, 13, 26}, + m_hostId{13}, + m_deviceId{26} + { } + +private slots: + void singleWrite(); + void doubleWrite(); + void singleMessagePacket(); + void splitPacket(); + void closedIsEmitted(); + +private: + ConnectionStub m_connection; + Stream m_stream; + StreamId m_hostId; + StreamId m_deviceId; +}; + +void tst_Stream::singleWrite() +{ + m_connection.reset(); + + StreamPacket packet{QByteArray{"ABCD"}}; + m_stream.write(packet); + + QCOMPARE(m_connection.enqueued.size(), 1); + QByteArray expected{"\x00\x00\x00\x04""ABCD", 8}; + QCOMPARE(m_connection.enqueued[0].data(), expected); +} + +void tst_Stream::doubleWrite() +{ + m_connection.reset(); + + StreamPacket packet{QByteArray{"ABCD"}}; + m_stream.write(packet); + StreamPacket packet2{QByteArray{"QDB"}}; + m_stream.write(packet2); + + QCOMPARE(m_connection.enqueued.size(), 2); + QByteArray expected{"\x00\x00\x00\x04""ABCD", 8}; + QCOMPARE(m_connection.enqueued[0].data(), expected); + expected = QByteArray{"\x00\x00\x00\x03QDB", 7}; + QCOMPARE(m_connection.enqueued[1].data(), expected); +} + +void tst_Stream::singleMessagePacket() +{ + QSignalSpy spy{&m_stream, &Stream::packetAvailable}; + m_stream.receiveMessage(QdbMessage{QdbMessage::Write, m_hostId, m_deviceId, + QByteArray{"\x00\x00\x00\x02OK", 6}}); + + QCOMPARE(spy.count(), 1); + QCOMPARE(static_cast<int>(spy[0][0].type()), QMetaType::type("StreamPacket")); + auto packet = spy[0][0].value<StreamPacket>(); + QCOMPARE(packet.buffer(), QByteArray{"OK"}); +} + +void tst_Stream::splitPacket() +{ + QSignalSpy spy{&m_stream, &Stream::packetAvailable}; + m_stream.receiveMessage(QdbMessage{QdbMessage::Write, m_hostId, m_deviceId, + QByteArray{"\x00\x00\x00\x05""AB", 6}}); + m_stream.receiveMessage(QdbMessage{QdbMessage::Write, m_hostId, m_deviceId, + QByteArray{"C"}}); + m_stream.receiveMessage(QdbMessage{QdbMessage::Write, m_hostId, m_deviceId, + QByteArray{"DE"}}); + + QCOMPARE(spy.count(), 1); + QCOMPARE(static_cast<int>(spy[0][0].type()), QMetaType::type("StreamPacket")); + auto packet = spy[0][0].value<StreamPacket>(); + QCOMPARE(packet.buffer(), QByteArray{"ABCDE"}); +} + +void tst_Stream::closedIsEmitted() +{ + QSignalSpy spy{&m_stream, &Stream::closed}; + m_stream.close(); + QCOMPARE(spy.count(), 1); +} + +QTEST_APPLESS_MAIN(tst_Stream) +#include "tst_stream.moc" diff --git a/tests/tst_stream.pro b/tests/tst_stream.pro new file mode 100644 index 0000000..fb690f5 --- /dev/null +++ b/tests/tst_stream.pro @@ -0,0 +1,44 @@ +QT -= gui +QT += testlib + +CONFIG += c++11 +CONFIG += testcase + +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +SOURCES += \ + tst_stream.cpp \ + +INCLUDEPATH += $$PWD/../libqdb + +unix { +LIBS = -L$$OUT_PWD/../libqdb -lqdb +QMAKE_RPATHDIR += ../libqdb +} + +win32 { +HEADERS += \ + ../libqdb/protocol/qdbmessage.h \ + ../libqdb/protocol/qdbtransport.h \ + ../libqdb/stream.h \ + ../libqdb/abstractconnection.h \ + ../libqdb/streampacket.h + +SOURCES += \ + ../libqdb/protocol/qdbmessage.cpp \ + ../libqdb/protocol/qdbtransport.cpp \ + ../libqdb/stream.cpp \ + ../libqdb/abstractconnection.cpp \ + ../libqdb/streampacket.cpp + +CONFIG(debug, debug|release) { + LIBQDBDIR = $$OUT_PWD/../libqdb/debug +} else { + LIBQDBDIR = $$OUT_PWD/../libqdb/release +} +LIBS = -L$$LIBQDBDIR -lqdb +} + |