1/*
2 * SPDX-FileCopyrightText: 2014-2015 David Rosca <nowrep@gmail.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6
7#include "autotests.h"
8#include "adapter.h"
9#include "battery.h"
10#include "bluezqt_dbustypes.h"
11#include "device.h"
12#include "gattserviceremote.h"
13#include "gattcharacteristicremote.h"
14#include "gattdescriptorremote.h"
15#include "mediaplayer.h"
16#include "mediaplayertrack.h"
17#include "mediatransport.h"
18
19#include <QCoreApplication>
20#include <QDebug>
21#include <QEventLoop>
22
23#include <QDBusConnectionInterface>
24#include <QDBusServiceWatcher>
25
26QProcess *FakeBluez::s_process = nullptr;
27
28class StartJob : public QObject
29{
30 Q_OBJECT
31
32public:
33 explicit StartJob();
34
35 void exec();
36
37 bool foundFakeBluez() const
38 {
39 return !m_fakebluezPath.isEmpty();
40 }
41
42private Q_SLOTS:
43 void processError(QProcess::ProcessError error);
44 void processFinished(int code, QProcess::ExitStatus status);
45
46private:
47 QString m_fakebluezPath;
48 QEventLoop m_eventLoop;
49};
50
51StartJob::StartJob()
52 : QObject(nullptr)
53 , m_fakebluezPath(QCoreApplication::applicationDirPath() + QStringLiteral("/fakebluez"))
54{
55}
56
57void StartJob::exec()
58{
59 QDBusServiceWatcher watcher(QStringLiteral("org.kde.bluezqt.test"), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForRegistration);
60
61 connect(&watcher, &QDBusServiceWatcher::serviceRegistered, &m_eventLoop, &QEventLoop::quit);
62 connect(FakeBluez::s_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError)));
63 connect(FakeBluez::s_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus)));
64
65 FakeBluez::s_process->start(m_fakebluezPath, QStringList());
66
67 m_eventLoop.exec();
68}
69
70void StartJob::processError(QProcess::ProcessError error)
71{
72 QString errorString;
73 switch (error) {
74 case QProcess::FailedToStart:
75 errorString = QStringLiteral("Failed to Start");
76 break;
77 case QProcess::Crashed:
78 errorString = QStringLiteral("Crashed");
79 break;
80 case QProcess::Timedout:
81 errorString = QStringLiteral("Timedout");
82 break;
83 default:
84 errorString = QStringLiteral("Unknown");
85 }
86
87 qWarning() << "Fakebluez binary:" << m_fakebluezPath;
88 qWarning() << "Process error:" << error << errorString;
89 qWarning() << "Error output:" << FakeBluez::s_process->readAllStandardError();
90
91 m_eventLoop.quit();
92}
93
94void StartJob::processFinished(int code, QProcess::ExitStatus status)
95{
96 QString statusString = status == QProcess::NormalExit ? QStringLiteral("Normal Exit") : QStringLiteral("Crash Exit");
97
98 qWarning() << "Fakebluez binary:" << m_fakebluezPath;
99 qWarning() << "Process finished:" << code << statusString;
100 qWarning() << "Error output:" << FakeBluez::s_process->readAllStandardError();
101
102 m_eventLoop.quit();
103}
104
105void FakeBluez::start()
106{
107 if (isRunning()) {
108 return;
109 }
110 if (!s_process) {
111 s_process = new QProcess();
112 }
113
114 StartJob job;
115 QVERIFY(job.foundFakeBluez());
116 job.exec();
117}
118
119void FakeBluez::stop()
120{
121 if (s_process && s_process->state() == QProcess::Running) {
122 s_process->terminate();
123 s_process->waitForFinished();
124 }
125}
126
127bool FakeBluez::isRunning()
128{
129 return s_process && s_process->state() == QProcess::Running;
130}
131
132void FakeBluez::runTest(const QString &testName)
133{
134 if (!isRunning()) {
135 return;
136 }
137
138 QDBusMessage call = QDBusMessage::createMethodCall(QStringLiteral("org.kde.bluezqt.test"),
139 QStringLiteral("/"),
140 QStringLiteral("org.kde.bluezqt.fakebluez.Test"),
141 QStringLiteral("runTest"));
142
143 call << testName;
144 QDBusConnection::sessionBus().call(call);
145}
146
147void FakeBluez::runAction(const QString &object, const QString &actionName, const QVariantMap &properties)
148{
149 if (!isRunning()) {
150 return;
151 }
152
153 QDBusMessage call = QDBusMessage::createMethodCall(QStringLiteral("org.kde.bluezqt.test"),
154 QStringLiteral("/"),
155 QStringLiteral("org.kde.bluezqt.fakebluez.Test"),
156 QStringLiteral("runAction"));
157
158 call << object;
159 call << actionName;
160 call << properties;
161
162 QDBusConnection::sessionBus().call(call);
163}
164
165void Autotests::registerMetatypes()
166{
167 qRegisterMetaType<BluezQt::GattDescriptorRemotePtr>("GattDescriptorRemotePtr");
168 qRegisterMetaType<BluezQt::GattCharacteristicRemotePtr>("GattCharacteristicRemotePtr");
169 qRegisterMetaType<BluezQt::GattServiceRemotePtr>("GattServiceRemotePtr");
170 qRegisterMetaType<BluezQt::DevicePtr>("DevicePtr");
171 qRegisterMetaType<BluezQt::AdapterPtr>("AdapterPtr");
172 qRegisterMetaType<BluezQt::BatteryPtr>("BatteryPtr");
173 qRegisterMetaType<BluezQt::MediaPlayerPtr>("MediaPlayerPtr");
174 qRegisterMetaType<BluezQt::MediaTransportPtr>("MediaTransportPtr");
175}
176
177void Autotests::verifyPropertiesChangedSignal(const QSignalSpy &spy, const QString &propertyName, const QVariant &propertyValue)
178{
179 int changes = 0;
180
181 for (int i = 0; i < spy.count(); ++i) {
182 QList<QVariant> arguments = spy.at(i);
183 QVariantMap properties = arguments.at(1).toMap();
184
185 QVariantMap::const_iterator it;
186 for (it = properties.constBegin(); it != properties.constEnd(); ++it) {
187 const QVariant &changedValue = it.value();
188 const QString &property = it.key();
189 if (property == propertyName && changedValue == propertyValue) {
190 changes++;
191 }
192 }
193 }
194
195 QCOMPARE(changes, 1);
196}
197
198#include "autotests.moc"
199

source code of bluez-qt/autotests/autotests.cpp