You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libcutefish/bluetooth/tests/fakebluez.h

168 lines
7.5 KiB
C++

#pragma once
#include "../bluetoothmanager.h"
#include <QDBusPendingCall>
#include <QDBusVariant>
#include <QDBusVirtualObject>
static const QString adapter = QStringLiteral("/org/bluez/hci0");
static const QString device = adapter + QStringLiteral("/dev_AA_BB_CC_DD_EE_FF");
static const QString adapterInterface = QStringLiteral("org.bluez.Adapter1");
static const QString deviceInterface = QStringLiteral("org.bluez.Device1");
class FakeBluez : public QDBusVirtualObject
{
public:
explicit FakeBluez(const QDBusConnection &bus)
: bus(bus)
{
objects[QDBusObjectPath(adapter)][adapterInterface] = {{"Address", "11:22:33:44:55:66"},
{"Alias", "Test adapter"},
{"Powered", true},
{"Pairable", true}};
objects[QDBusObjectPath(device)][deviceInterface] = {
{"Address", "AA:BB:CC:DD:EE:FF"},
{"Alias", "Headphones"},
{"Adapter", QVariant::fromValue(QDBusObjectPath(adapter))},
{"Paired", false},
{"Connected", false}};
}
QString introspect(const QString &) const override { return {}; }
bool handleMessage(const QDBusMessage &message, const QDBusConnection &connection) override
{
calls.append(message.member());
lastPath = message.path();
if (message.member() == failMethod) {
connection.send(message.createErrorReply(failName, failMessage));
return true;
}
const auto args = message.arguments();
if (message.member() == QStringLiteral("GetManagedObjects")) {
if (holdSnapshot) {
message.setDelayedReply(true);
pendingSnapshot = message;
snapshot = objects;
} else {
connection.send(message.createReply({QVariant::fromValue(objects)}));
}
} else if (message.member() == QStringLiteral("Set")) {
set(message.path(), args[0].toString(), args[1].toString(),
qvariant_cast<QDBusVariant>(args[2]).variant());
connection.send(message.createReply());
} else if (message.member() == QStringLiteral("GetAll")) {
if (holdGetAll) {
message.setDelayedReply(true);
pendingGetAll = message;
oldProperties =
objects.value(QDBusObjectPath(message.path())).value(args[0].toString());
} else {
connection.send(message.createReply(QVariantList {
objects.value(QDBusObjectPath(message.path())).value(args[0].toString())}));
}
} else if (message.member() == QStringLiteral("RegisterAgent")) {
agentOwner = message.service();
agentPath = qvariant_cast<QDBusObjectPath>(args[0]).path();
connection.send(message.createReply());
} else if (message.member() == QStringLiteral("Pair")) {
if (holdPair) {
message.setDelayedReply(true);
pendingPair = message;
} else {
set(message.path(), deviceInterface, QStringLiteral("Paired"), true);
connection.send(message.createReply());
}
} else if (message.member() == QStringLiteral("CancelPairing")) {
if (pendingPair.type() == QDBusMessage::MethodCallMessage) {
connection.send(pendingPair.createErrorReply(
QStringLiteral("org.bluez.Error.AuthenticationCanceled"),
QStringLiteral("Canceled")));
pendingPair = {};
}
connection.send(message.createReply());
} else if (message.member() == QStringLiteral("Connect")
|| message.member() == QStringLiteral("Disconnect")) {
set(message.path(), deviceInterface, QStringLiteral("Connected"),
message.member() == QStringLiteral("Connect"));
connection.send(message.createReply());
} else if (message.member() == QStringLiteral("ReadValue")) {
const auto value = objects.value(QDBusObjectPath(message.path()))
.value(QStringLiteral("org.bluez.GattCharacteristic1"))
.value(QStringLiteral("Value"));
connection.send(message.createReply(QVariantList {value.toByteArray()}));
} else if (message.member() == QStringLiteral("RemoveDevice")) {
remove(qvariant_cast<QDBusObjectPath>(args[0]).path(), {deviceInterface});
connection.send(message.createReply());
} else if (message.member().endsWith(QStringLiteral("Discovery"))) {
set(message.path(), adapterInterface, QStringLiteral("Discovering"),
message.member() == QStringLiteral("StartDiscovery"));
connection.send(message.createReply());
} else {
connection.send(message.createReply());
}
return true;
}
void set(const QString &path, const QString &interface, const QString &key,
const QVariant &value)
{
objects[QDBusObjectPath(path)][interface][key] = value;
auto signal =
QDBusMessage::createSignal(path, QStringLiteral("org.freedesktop.DBus.Properties"),
QStringLiteral("PropertiesChanged"));
signal << interface << QVariantMap {{key, value}} << QStringList {};
bus.send(signal);
}
void add(const QString &path, const BluetoothInterfaces &interfaces)
{
for (auto it = interfaces.cbegin(); it != interfaces.cend(); ++it)
objects[QDBusObjectPath(path)][it.key()] = it.value();
auto signal = QDBusMessage::createSignal(
QStringLiteral("/"), QStringLiteral("org.freedesktop.DBus.ObjectManager"),
QStringLiteral("InterfacesAdded"));
signal << QVariant::fromValue(QDBusObjectPath(path)) << QVariant::fromValue(interfaces);
bus.send(signal);
}
void remove(const QString &path, const QStringList &interfaces)
{
for (const auto &interface : interfaces)
objects[QDBusObjectPath(path)].remove(interface);
if (objects[QDBusObjectPath(path)].isEmpty())
objects.remove(QDBusObjectPath(path));
auto signal = QDBusMessage::createSignal(
QStringLiteral("/"), QStringLiteral("org.freedesktop.DBus.ObjectManager"),
QStringLiteral("InterfacesRemoved"));
signal << QVariant::fromValue(QDBusObjectPath(path)) << interfaces;
bus.send(signal);
}
QDBusPendingCall ask(const QString &method, const QVariantList &arguments)
{
auto message = QDBusMessage::createMethodCall(agentOwner, agentPath,
QStringLiteral("org.bluez.Agent1"), method);
message.setArguments(arguments);
return bus.asyncCall(message);
}
QDBusConnection bus;
BluetoothObjects objects;
QStringList calls;
QString lastPath;
QString failMethod;
QString failName = QStringLiteral("org.bluez.Error.Failed");
QString failMessage = QStringLiteral("Injected failure");
QString agentOwner;
QString agentPath;
bool holdPair = false;
bool holdSnapshot = false;
bool holdGetAll = false;
QDBusMessage pendingPair;
QDBusMessage pendingSnapshot;
QDBusMessage pendingGetAll;
BluetoothObjects snapshot;
QVariantMap oldProperties;
};