494 lines
19 KiB
C++
494 lines
19 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the QtBluetooth module of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
|
** 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 https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include <QtTest/QtTest>
|
|
|
|
#include <QDebug>
|
|
#include <QLoggingCategory>
|
|
#include <QVariant>
|
|
#include <QList>
|
|
#include "../../shared/bttestutil_p.h"
|
|
|
|
#include <qbluetoothaddress.h>
|
|
#include <qbluetoothdevicediscoveryagent.h>
|
|
#include <qbluetoothservicediscoveryagent.h>
|
|
#include <qbluetoothlocaldevice.h>
|
|
#include <qbluetoothserver.h>
|
|
#include <qbluetoothserviceinfo.h>
|
|
|
|
QT_USE_NAMESPACE
|
|
|
|
// Maximum time to for bluetooth device scan
|
|
const int MaxScanTime = 5 * 60 * 1000; // 5 minutes in ms
|
|
|
|
class tst_QBluetoothServiceDiscoveryAgent : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
tst_QBluetoothServiceDiscoveryAgent();
|
|
~tst_QBluetoothServiceDiscoveryAgent();
|
|
|
|
public slots:
|
|
void deviceDiscoveryDebug(const QBluetoothDeviceInfo &info);
|
|
void serviceDiscoveryDebug(const QBluetoothServiceInfo &info);
|
|
void serviceError(const QBluetoothServiceDiscoveryAgent::Error err);
|
|
|
|
private slots:
|
|
void initTestCase();
|
|
|
|
void tst_invalidBtAddress();
|
|
void tst_serviceDiscovery_data();
|
|
void tst_serviceDiscovery();
|
|
void tst_serviceDiscoveryStop();
|
|
void tst_serviceDiscoveryAdapters();
|
|
|
|
private:
|
|
QList<QBluetoothDeviceInfo> devices;
|
|
bool localDeviceAvailable;
|
|
};
|
|
|
|
tst_QBluetoothServiceDiscoveryAgent::tst_QBluetoothServiceDiscoveryAgent()
|
|
{
|
|
QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
|
|
if (androidBluetoothEmulator())
|
|
return;
|
|
// start Bluetooth if not started
|
|
#ifndef Q_OS_OSX
|
|
QBluetoothLocalDevice *device = new QBluetoothLocalDevice();
|
|
localDeviceAvailable = device->isValid();
|
|
if (localDeviceAvailable) {
|
|
device->powerOn();
|
|
// wait for the device to switch bluetooth mode.
|
|
QTest::qWait(1000);
|
|
}
|
|
delete device;
|
|
#else
|
|
QBluetoothLocalDevice device;
|
|
localDeviceAvailable = QBluetoothLocalDevice().hostMode() != QBluetoothLocalDevice::HostPoweredOff;
|
|
#endif
|
|
|
|
qRegisterMetaType<QBluetoothDeviceInfo>();
|
|
qRegisterMetaType<QList<QBluetoothUuid> >();
|
|
qRegisterMetaType<QBluetoothServiceDiscoveryAgent::Error>();
|
|
qRegisterMetaType<QBluetoothDeviceDiscoveryAgent::Error>();
|
|
|
|
}
|
|
|
|
tst_QBluetoothServiceDiscoveryAgent::~tst_QBluetoothServiceDiscoveryAgent()
|
|
{
|
|
}
|
|
|
|
void tst_QBluetoothServiceDiscoveryAgent::deviceDiscoveryDebug(const QBluetoothDeviceInfo &info)
|
|
{
|
|
qDebug() << "Discovered device:" << info.address().toString() << info.name();
|
|
}
|
|
|
|
|
|
void tst_QBluetoothServiceDiscoveryAgent::serviceError(const QBluetoothServiceDiscoveryAgent::Error err)
|
|
{
|
|
qDebug() << "Service discovery error" << err;
|
|
}
|
|
|
|
void tst_QBluetoothServiceDiscoveryAgent::initTestCase()
|
|
{
|
|
if (androidBluetoothEmulator())
|
|
QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input");
|
|
|
|
if (localDeviceAvailable) {
|
|
QBluetoothDeviceDiscoveryAgent discoveryAgent;
|
|
|
|
QSignalSpy finishedSpy(&discoveryAgent, SIGNAL(finished()));
|
|
QSignalSpy errorSpy(&discoveryAgent,
|
|
SIGNAL(errorOccurred(QBluetoothDeviceDiscoveryAgent::Error)));
|
|
QSignalSpy discoveredSpy(&discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)));
|
|
// connect(&discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
|
|
// this, SLOT(deviceDiscoveryDebug(QBluetoothDeviceInfo)));
|
|
|
|
discoveryAgent.start();
|
|
|
|
// Wait for up to MaxScanTime for the scan to finish
|
|
int scanTime = MaxScanTime;
|
|
while (finishedSpy.count() == 0 && scanTime > 0) {
|
|
QTest::qWait(1000);
|
|
scanTime -= 1000;
|
|
}
|
|
// qDebug() << "Scan time left:" << scanTime;
|
|
|
|
// Expect finished signal with no error
|
|
QVERIFY(finishedSpy.count() == 1);
|
|
QVERIFY(errorSpy.isEmpty());
|
|
|
|
devices = discoveryAgent.discoveredDevices();
|
|
}
|
|
}
|
|
|
|
void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscoveryStop()
|
|
{
|
|
if (!localDeviceAvailable)
|
|
QSKIP("This test requires Bluetooth adapter in powered ON state");
|
|
|
|
QBluetoothServiceDiscoveryAgent discoveryAgent;
|
|
QSignalSpy finishedSpy(&discoveryAgent, SIGNAL(finished()));
|
|
QSignalSpy canceledSpy(&discoveryAgent, SIGNAL(canceled()));
|
|
|
|
// Verify we get the correct signals on start-stop
|
|
discoveryAgent.start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
|
|
QVERIFY(discoveryAgent.isActive());
|
|
discoveryAgent.stop();
|
|
QTRY_COMPARE(canceledSpy.count(), 1);
|
|
QVERIFY(!discoveryAgent.isActive());
|
|
// Wait a bit to see that there are no latent signals
|
|
QTest::qWait(200);
|
|
QCOMPARE(canceledSpy.count(), 1);
|
|
QCOMPARE(finishedSpy.count(), 0);
|
|
}
|
|
|
|
|
|
void tst_QBluetoothServiceDiscoveryAgent::tst_invalidBtAddress()
|
|
{
|
|
#ifdef Q_OS_OSX
|
|
if (!localDeviceAvailable)
|
|
QSKIP("On OS X this test requires Bluetooth adapter in powered ON state");
|
|
#endif
|
|
QBluetoothServiceDiscoveryAgent *discoveryAgent = new QBluetoothServiceDiscoveryAgent(QBluetoothAddress("11:11:11:11:11:11"));
|
|
|
|
QCOMPARE(discoveryAgent->error(), QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError);
|
|
discoveryAgent->start();
|
|
QCOMPARE(discoveryAgent->isActive(), false);
|
|
delete discoveryAgent;
|
|
|
|
discoveryAgent = new QBluetoothServiceDiscoveryAgent(QBluetoothAddress());
|
|
QCOMPARE(discoveryAgent->error(), QBluetoothServiceDiscoveryAgent::NoError);
|
|
if (QBluetoothLocalDevice::allDevices().count() > 0) {
|
|
discoveryAgent->start();
|
|
QCOMPARE(discoveryAgent->isActive(), true);
|
|
}
|
|
delete discoveryAgent;
|
|
}
|
|
|
|
void tst_QBluetoothServiceDiscoveryAgent::serviceDiscoveryDebug(const QBluetoothServiceInfo &info)
|
|
{
|
|
qDebug() << "Discovered service on"
|
|
<< info.device().name() << info.device().address().toString();
|
|
qDebug() << "\tService name:" << info.serviceName() << "cached" << info.device().isCached();
|
|
qDebug() << "\tDescription:"
|
|
<< info.attribute(QBluetoothServiceInfo::ServiceDescription).toString();
|
|
qDebug() << "\tProvider:" << info.attribute(QBluetoothServiceInfo::ServiceProvider).toString();
|
|
qDebug() << "\tL2CAP protocol service multiplexer:" << info.protocolServiceMultiplexer();
|
|
qDebug() << "\tRFCOMM server channel:" << info.serverChannel();
|
|
}
|
|
|
|
#if 0
|
|
static void dumpAttributeVariant(const QVariant &var, const QString indent)
|
|
{
|
|
if (!var.isValid()) {
|
|
qDebug("%sEmpty", indent.toLocal8Bit().constData());
|
|
return;
|
|
}
|
|
|
|
if (var.typeId() == qMetaTypeId<QBluetoothServiceInfo::Sequence>()) {
|
|
qDebug("%sSequence", indent.toLocal8Bit().constData());
|
|
const QBluetoothServiceInfo::Sequence *sequence = static_cast<const QBluetoothServiceInfo::Sequence *>(var.data());
|
|
for (const QVariant &v : *sequence)
|
|
dumpAttributeVariant(v, indent + '\t');
|
|
} else if (var.typeId() == qMetaTypeId<QBluetoothServiceInfo::Alternative>()) {
|
|
qDebug("%sAlternative", indent.toLocal8Bit().constData());
|
|
const QBluetoothServiceInfo::Alternative *alternative = static_cast<const QBluetoothServiceInfo::Alternative *>(var.data());
|
|
for (const QVariant &v : *alternative)
|
|
dumpAttributeVariant(v, indent + '\t');
|
|
} else if (var.typeId() == qMetaTypeId<QBluetoothUuid>()) {
|
|
QBluetoothUuid uuid = var.value<QBluetoothUuid>();
|
|
switch (uuid.minimumSize()) {
|
|
case 0:
|
|
qDebug("%suuid NULL", indent.toLocal8Bit().constData());
|
|
break;
|
|
case 2:
|
|
qDebug("%suuid %04x", indent.toLocal8Bit().constData(), uuid.toUInt16());
|
|
break;
|
|
case 4:
|
|
qDebug("%suuid %08x", indent.toLocal8Bit().constData(), uuid.toUInt32());
|
|
break;
|
|
case 16: {
|
|
qDebug("%suuid %s", indent.toLocal8Bit().constData(), QByteArray(reinterpret_cast<const char *>(uuid.toUInt128().data), 16).toHex().constData());
|
|
break;
|
|
}
|
|
default:
|
|
qDebug("%suuid ???", indent.toLocal8Bit().constData());
|
|
}
|
|
} else {
|
|
switch (var.typeId()) {
|
|
case QMetaType::UInt:
|
|
qDebug("%suint %u", indent.toLocal8Bit().constData(), var.toUInt());
|
|
break;
|
|
case QMetaType::Int:
|
|
qDebug("%sint %d", indent.toLocal8Bit().constData(), var.toInt());
|
|
break;
|
|
case QMetaType::QString:
|
|
qDebug("%sstring %s", indent.toLocal8Bit().constData(), var.toString().toLocal8Bit().constData());
|
|
break;
|
|
case QMetaType::Bool:
|
|
qDebug("%sbool %d", indent.toLocal8Bit().constData(), var.toBool());
|
|
break;
|
|
case QMetaType::QUrl:
|
|
qDebug("%surl %s", indent.toLocal8Bit().constData(), var.toUrl().toString().toLocal8Bit().constData());
|
|
break;
|
|
default:
|
|
qDebug("%sunknown", indent.toLocal8Bit().constData());
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void dumpServiceInfoAttributes(const QBluetoothServiceInfo &info)
|
|
{
|
|
const QList<quint16> attributes = info.attributes();
|
|
for (quint16 id : attributes) {
|
|
dumpAttributeVariant(info.attribute(id), QString("\t"));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery_data()
|
|
{
|
|
if (devices.isEmpty())
|
|
QSKIP("This test requires an in-range bluetooth device");
|
|
|
|
QTest::addColumn<QBluetoothDeviceInfo>("deviceInfo");
|
|
QTest::addColumn<QList<QBluetoothUuid> >("uuidFilter");
|
|
QTest::addColumn<QBluetoothServiceDiscoveryAgent::Error>("serviceDiscoveryError");
|
|
|
|
// Only need to test the first 5 live devices
|
|
int max = 5;
|
|
for (const QBluetoothDeviceInfo &info : qAsConst(devices)) {
|
|
if (info.isCached())
|
|
continue;
|
|
QTest::newRow("default filter") << info << QList<QBluetoothUuid>()
|
|
<< QBluetoothServiceDiscoveryAgent::NoError;
|
|
if (!--max)
|
|
break;
|
|
//QTest::newRow("public browse group") << info << (QList<QBluetoothUuid>() << QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup);
|
|
//QTest::newRow("l2cap") << info << (QList<QBluetoothUuid>() << QBluetoothUuid::ProtocolUuid::L2cap);
|
|
}
|
|
QTest::newRow("all devices") << QBluetoothDeviceInfo() << QList<QBluetoothUuid>()
|
|
<< QBluetoothServiceDiscoveryAgent::NoError;
|
|
}
|
|
|
|
void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscoveryAdapters()
|
|
{
|
|
QBluetoothLocalDevice localDevice;
|
|
int numberOfAdapters = (localDevice.allDevices()).size();
|
|
if (numberOfAdapters>1) {
|
|
if (devices.isEmpty())
|
|
QSKIP("This test requires an in-range bluetooth device");
|
|
|
|
QList<QBluetoothAddress> addresses;
|
|
|
|
for (int i=0; i<numberOfAdapters; i++) {
|
|
addresses.append(((QBluetoothHostInfo)localDevice.allDevices().at(i)).address());
|
|
}
|
|
QBluetoothServer server(QBluetoothServiceInfo::RfcommProtocol);
|
|
QBluetoothUuid uuid(QBluetoothUuid::ProtocolUuid::Ftp);
|
|
server.listen(addresses[0]);
|
|
QBluetoothServiceInfo serviceInfo;
|
|
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, "serviceName");
|
|
QBluetoothServiceInfo::Sequence publicBrowse;
|
|
publicBrowse << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup));
|
|
serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, publicBrowse);
|
|
|
|
QBluetoothServiceInfo::Sequence profileSequence;
|
|
QBluetoothServiceInfo::Sequence classId;
|
|
classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
|
|
classId << QVariant::fromValue(quint16(0x100));
|
|
profileSequence.append(QVariant::fromValue(classId));
|
|
serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,
|
|
profileSequence);
|
|
|
|
serviceInfo.setServiceUuid(uuid);
|
|
|
|
QBluetoothServiceInfo::Sequence protocolDescriptorList;
|
|
QBluetoothServiceInfo::Sequence protocol;
|
|
protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::L2cap));
|
|
protocolDescriptorList.append(QVariant::fromValue(protocol));
|
|
protocol.clear();
|
|
|
|
protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm))
|
|
<< QVariant::fromValue(quint8(server.serverPort()));
|
|
|
|
protocolDescriptorList.append(QVariant::fromValue(protocol));
|
|
serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList,
|
|
protocolDescriptorList);
|
|
QVERIFY(serviceInfo.registerService());
|
|
|
|
QVERIFY(server.isListening());
|
|
qDebug() << "Scanning address " << addresses[0].toString();
|
|
QBluetoothServiceDiscoveryAgent discoveryAgent(addresses[1]);
|
|
bool setAddress = discoveryAgent.setRemoteAddress(addresses[0]);
|
|
|
|
QVERIFY(setAddress);
|
|
|
|
QVERIFY(!discoveryAgent.isActive());
|
|
|
|
QVERIFY(discoveryAgent.discoveredServices().isEmpty());
|
|
|
|
QSignalSpy finishedSpy(&discoveryAgent, SIGNAL(finished()));
|
|
|
|
discoveryAgent.start();
|
|
int scanTime = MaxScanTime;
|
|
while (finishedSpy.count() == 0 && scanTime > 0) {
|
|
QTest::qWait(1000);
|
|
scanTime -= 1000;
|
|
}
|
|
|
|
QList<QBluetoothServiceInfo> discServices = discoveryAgent.discoveredServices();
|
|
QVERIFY(!discServices.empty());
|
|
|
|
int counter = 0;
|
|
for (int i = 0; i<discServices.size(); i++)
|
|
{
|
|
QBluetoothServiceInfo service((QBluetoothServiceInfo)discServices.at(i));
|
|
if (uuid == service.serviceUuid())
|
|
counter++;
|
|
}
|
|
QVERIFY(counter == 1);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery()
|
|
{
|
|
if (devices.isEmpty())
|
|
QSKIP("This test requires an in-range bluetooth device");
|
|
|
|
QFETCH(QBluetoothDeviceInfo, deviceInfo);
|
|
QFETCH(QList<QBluetoothUuid>, uuidFilter);
|
|
QFETCH(QBluetoothServiceDiscoveryAgent::Error, serviceDiscoveryError);
|
|
|
|
QBluetoothLocalDevice localDevice;
|
|
qDebug() << "Scanning address" << deviceInfo.address().toString();
|
|
QBluetoothServiceDiscoveryAgent discoveryAgent(localDevice.address());
|
|
bool setAddress = discoveryAgent.setRemoteAddress(deviceInfo.address());
|
|
|
|
QVERIFY(setAddress);
|
|
|
|
QVERIFY(!discoveryAgent.isActive());
|
|
|
|
QVERIFY(discoveryAgent.discoveredServices().isEmpty());
|
|
|
|
QVERIFY(discoveryAgent.uuidFilter().isEmpty());
|
|
|
|
discoveryAgent.setUuidFilter(uuidFilter);
|
|
|
|
QVERIFY(discoveryAgent.uuidFilter() == uuidFilter);
|
|
|
|
QSignalSpy finishedSpy(&discoveryAgent, SIGNAL(finished()));
|
|
QSignalSpy errorSpy(&discoveryAgent,
|
|
SIGNAL(errorOccurred(QBluetoothServiceDiscoveryAgent::Error)));
|
|
QSignalSpy discoveredSpy(&discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)));
|
|
// connect(&discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)),
|
|
// this, SLOT(serviceDiscoveryDebug(QBluetoothServiceInfo)));
|
|
connect(&discoveryAgent, SIGNAL(errorOccurred(QBluetoothServiceDiscoveryAgent::Error)), this,
|
|
SLOT(serviceError(QBluetoothServiceDiscoveryAgent::Error)));
|
|
|
|
discoveryAgent.start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
|
|
|
|
/*
|
|
* Either we wait for discovery agent to run its course (e.g. Bluez 4) or
|
|
* we have an immediate result (e.g. Bluez 5)
|
|
*/
|
|
QVERIFY(discoveryAgent.isActive() || !finishedSpy.isEmpty());
|
|
|
|
// Wait for up to MaxScanTime for the scan to finish
|
|
int scanTime = MaxScanTime;
|
|
while (finishedSpy.count() == 0 && scanTime > 0) {
|
|
QTest::qWait(1000);
|
|
scanTime -= 1000;
|
|
}
|
|
|
|
if (discoveryAgent.error()) {
|
|
qDebug() << "Device failed to respond to SDP, skipping device" << discoveryAgent.error() << discoveryAgent.errorString();
|
|
return;
|
|
}
|
|
|
|
QVERIFY(discoveryAgent.error() == serviceDiscoveryError);
|
|
QVERIFY(discoveryAgent.errorString() == QString());
|
|
|
|
// Expect finished signal with no error
|
|
QVERIFY(finishedSpy.count() == 1);
|
|
QVERIFY(errorSpy.isEmpty());
|
|
|
|
//if (discoveryAgent.discoveredServices().count() && expected_failures++ <2){
|
|
if (discoveredSpy.isEmpty()) {
|
|
qDebug() << "Device failed to return any results, skipping device" << discoveryAgent.discoveredServices().count();
|
|
return;
|
|
}
|
|
|
|
// All returned QBluetoothServiceInfo should be valid.
|
|
bool servicesFound = !discoveredSpy.isEmpty();
|
|
while (!discoveredSpy.isEmpty()) {
|
|
const QVariant v = discoveredSpy.takeFirst().at(0);
|
|
// Work around limitation in QMetaType and moc.
|
|
// QBluetoothServiceInfo is registered with metatype as QBluetoothServiceInfo
|
|
// moc sees it as the unqualified QBluetoothServiceInfo.
|
|
if (v.userType() == qMetaTypeId<QBluetoothServiceInfo>())
|
|
{
|
|
const QBluetoothServiceInfo info =
|
|
*reinterpret_cast<const QBluetoothServiceInfo*>(v.constData());
|
|
|
|
QVERIFY(info.isValid());
|
|
QVERIFY(!info.isRegistered());
|
|
|
|
#if 0
|
|
qDebug() << info.device().name() << info.device().address().toString();
|
|
qDebug() << "\tService name:" << info.serviceName();
|
|
if (info.protocolServiceMultiplexer() >= 0)
|
|
qDebug() << "\tL2CAP protocol service multiplexer:" << info.protocolServiceMultiplexer();
|
|
if (info.serverChannel() >= 0)
|
|
qDebug() << "\tRFCOMM server channel:" << info.serverChannel();
|
|
//dumpServiceInfoAttributes(info);
|
|
#endif
|
|
} else {
|
|
QFAIL("Unknown type returned by service discovery");
|
|
}
|
|
|
|
}
|
|
|
|
if (servicesFound)
|
|
QVERIFY(discoveryAgent.discoveredServices().count() != 0);
|
|
discoveryAgent.clear();
|
|
QVERIFY(discoveryAgent.discoveredServices().count() == 0);
|
|
|
|
discoveryAgent.stop();
|
|
QVERIFY(!discoveryAgent.isActive());
|
|
}
|
|
|
|
QTEST_MAIN(tst_QBluetoothServiceDiscoveryAgent)
|
|
|
|
#include "tst_qbluetoothservicediscoveryagent.moc"
|