File indexing completed on 2024-04-14 03:49:53

0001 /*
0002  * SPDX-FileCopyrightText: 2014-2015 David Rosca <nowrep@gmail.com>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 #include "autotests.h"
0008 #include "adapter.h"
0009 #include "battery.h"
0010 #include "bluezqt_dbustypes.h"
0011 #include "device.h"
0012 #include "gattserviceremote.h"
0013 #include "gattcharacteristicremote.h"
0014 #include "gattdescriptorremote.h"
0015 #include "mediaplayer.h"
0016 #include "mediaplayertrack.h"
0017 #include "mediatransport.h"
0018 
0019 #include <QCoreApplication>
0020 #include <QDebug>
0021 #include <QEventLoop>
0022 
0023 #include <QDBusConnectionInterface>
0024 #include <QDBusServiceWatcher>
0025 
0026 QProcess *FakeBluez::s_process = nullptr;
0027 
0028 class StartJob : public QObject
0029 {
0030     Q_OBJECT
0031 
0032 public:
0033     explicit StartJob();
0034 
0035     void exec();
0036 
0037     bool foundFakeBluez() const
0038     {
0039         return !m_fakebluezPath.isEmpty();
0040     }
0041 
0042 private Q_SLOTS:
0043     void processError(QProcess::ProcessError error);
0044     void processFinished(int code, QProcess::ExitStatus status);
0045 
0046 private:
0047     QString m_fakebluezPath;
0048     QEventLoop m_eventLoop;
0049 };
0050 
0051 StartJob::StartJob()
0052     : QObject(nullptr)
0053     , m_fakebluezPath(QCoreApplication::applicationDirPath() + QStringLiteral("/fakebluez"))
0054 {
0055 }
0056 
0057 void StartJob::exec()
0058 {
0059     QDBusServiceWatcher watcher(QStringLiteral("org.kde.bluezqt.test"), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForRegistration);
0060 
0061     connect(&watcher, &QDBusServiceWatcher::serviceRegistered, &m_eventLoop, &QEventLoop::quit);
0062     connect(FakeBluez::s_process, &QProcess::errorOccurred, this, &StartJob::processError);
0063     connect(FakeBluez::s_process, &QProcess::finished, this, &StartJob::processFinished);
0064 
0065     FakeBluez::s_process->start(m_fakebluezPath, QStringList());
0066 
0067     m_eventLoop.exec();
0068 }
0069 
0070 void StartJob::processError(QProcess::ProcessError error)
0071 {
0072     QString errorString;
0073     switch (error) {
0074     case QProcess::FailedToStart:
0075         errorString = QStringLiteral("Failed to Start");
0076         break;
0077     case QProcess::Crashed:
0078         errorString = QStringLiteral("Crashed");
0079         break;
0080     case QProcess::Timedout:
0081         errorString = QStringLiteral("Timedout");
0082         break;
0083     default:
0084         errorString = QStringLiteral("Unknown");
0085     }
0086 
0087     qWarning() << "Fakebluez binary:" << m_fakebluezPath;
0088     qWarning() << "Process error:" << error << errorString;
0089     qWarning() << "Error output:" << FakeBluez::s_process->readAllStandardError();
0090 
0091     m_eventLoop.quit();
0092 }
0093 
0094 void StartJob::processFinished(int code, QProcess::ExitStatus status)
0095 {
0096     QString statusString = status == QProcess::NormalExit ? QStringLiteral("Normal Exit") : QStringLiteral("Crash Exit");
0097 
0098     qWarning() << "Fakebluez binary:" << m_fakebluezPath;
0099     qWarning() << "Process finished:" << code << statusString;
0100     qWarning() << "Error output:" << FakeBluez::s_process->readAllStandardError();
0101 
0102     m_eventLoop.quit();
0103 }
0104 
0105 void FakeBluez::start()
0106 {
0107     if (isRunning()) {
0108         return;
0109     }
0110     if (!s_process) {
0111         s_process = new QProcess();
0112     }
0113 
0114     StartJob job;
0115     QVERIFY(job.foundFakeBluez());
0116     job.exec();
0117 }
0118 
0119 void FakeBluez::stop()
0120 {
0121     if (s_process && s_process->state() == QProcess::Running) {
0122         s_process->terminate();
0123         s_process->waitForFinished();
0124     }
0125 }
0126 
0127 bool FakeBluez::isRunning()
0128 {
0129     return s_process && s_process->state() == QProcess::Running;
0130 }
0131 
0132 void FakeBluez::runTest(const QString &testName)
0133 {
0134     if (!isRunning()) {
0135         return;
0136     }
0137 
0138     QDBusMessage call = QDBusMessage::createMethodCall(QStringLiteral("org.kde.bluezqt.test"),
0139                                                        QStringLiteral("/"),
0140                                                        QStringLiteral("org.kde.bluezqt.fakebluez.Test"),
0141                                                        QStringLiteral("runTest"));
0142 
0143     call << testName;
0144     QDBusConnection::sessionBus().call(call);
0145 }
0146 
0147 void FakeBluez::runAction(const QString &object, const QString &actionName, const QVariantMap &properties)
0148 {
0149     if (!isRunning()) {
0150         return;
0151     }
0152 
0153     QDBusMessage call = QDBusMessage::createMethodCall(QStringLiteral("org.kde.bluezqt.test"),
0154                                                        QStringLiteral("/"),
0155                                                        QStringLiteral("org.kde.bluezqt.fakebluez.Test"),
0156                                                        QStringLiteral("runAction"));
0157 
0158     call << object;
0159     call << actionName;
0160     call << properties;
0161 
0162     QDBusConnection::sessionBus().call(call);
0163 }
0164 
0165 void Autotests::registerMetatypes()
0166 {
0167     qRegisterMetaType<BluezQt::GattDescriptorRemotePtr>("GattDescriptorRemotePtr");
0168     qRegisterMetaType<BluezQt::GattCharacteristicRemotePtr>("GattCharacteristicRemotePtr");
0169     qRegisterMetaType<BluezQt::GattServiceRemotePtr>("GattServiceRemotePtr");
0170     qRegisterMetaType<BluezQt::DevicePtr>("DevicePtr");
0171     qRegisterMetaType<BluezQt::AdapterPtr>("AdapterPtr");
0172     qRegisterMetaType<BluezQt::BatteryPtr>("BatteryPtr");
0173     qRegisterMetaType<BluezQt::MediaPlayerPtr>("MediaPlayerPtr");
0174     qRegisterMetaType<BluezQt::MediaTransportPtr>("MediaTransportPtr");
0175 }
0176 
0177 void Autotests::verifyPropertiesChangedSignal(const QSignalSpy &spy, const QString &propertyName, const QVariant &propertyValue)
0178 {
0179     int changes = 0;
0180 
0181     for (int i = 0; i < spy.count(); ++i) {
0182         QList<QVariant> arguments = spy.at(i);
0183         QVariantMap properties = arguments.at(1).toMap();
0184 
0185         QVariantMap::const_iterator it;
0186         for (it = properties.constBegin(); it != properties.constEnd(); ++it) {
0187             const QVariant &changedValue = it.value();
0188             const QString &property = it.key();
0189             if (property == propertyName && changedValue == propertyValue) {
0190                 changes++;
0191             }
0192         }
0193     }
0194 
0195     QCOMPARE(changes, 1);
0196 }
0197 
0198 #include "autotests.moc"