Revision control

Copy as Markdown

// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
#include "../../shared/bttestutil_p.h"
#include <private/qtbluetoothglobal_p.h>
#include <qbluetoothserver.h>
#include <qbluetoothsocket.h>
#include <qbluetoothlocaldevice.h>
QT_USE_NAMESPACE
Q_DECLARE_METATYPE(QBluetooth::SecurityFlags)
class tst_QBluetoothServer : public QObject
{
Q_OBJECT
public:
tst_QBluetoothServer();
~tst_QBluetoothServer();
private slots:
void initTestCase();
void cleanupTestCase();
void tst_construction();
void tst_receive_data();
void tst_receive();
void setHostMode(const QBluetoothAddress &localAdapter, QBluetoothLocalDevice::HostMode newHostMode);
private:
QBluetoothLocalDevice *localDevice = nullptr;
QBluetoothLocalDevice::HostMode initialHostMode;
};
tst_QBluetoothServer::tst_QBluetoothServer()
{
}
tst_QBluetoothServer::~tst_QBluetoothServer()
{
}
void tst_QBluetoothServer::setHostMode(const QBluetoothAddress &localAdapter,
QBluetoothLocalDevice::HostMode newHostMode)
{
QBluetoothLocalDevice device(localAdapter);
QSignalSpy hostModeSpy(&device, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)));
if (!device.isValid())
return;
if (device.hostMode() == newHostMode)
return;
//We distinguish powerOn() and setHostMode(HostConnectable) because
//Android uses different permission levels, we want to avoid interaction with user
//which implies usage of powerOn -> unfortunately powerOn() is not equivalent to HostConnectable
//Unfortunately the discoverable mode always requires a user confirmation
switch (newHostMode) {
case QBluetoothLocalDevice::HostPoweredOff:
case QBluetoothLocalDevice::HostDiscoverable:
case QBluetoothLocalDevice::HostDiscoverableLimitedInquiry:
device.setHostMode(newHostMode);
break;
case QBluetoothLocalDevice::HostConnectable:
device.powerOn();
break;
}
int connectTime = 5000; // ms
while (hostModeSpy.isEmpty() && connectTime > 0) {
QTest::qWait(500);
connectTime -= 500;
}
}
void tst_QBluetoothServer::initTestCase()
{
if (androidBluetoothEmulator())
QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input");
qRegisterMetaType<QBluetooth::SecurityFlags>();
qRegisterMetaType<QBluetoothServer::Error>();
localDevice = new QBluetoothLocalDevice(this);
QBluetoothLocalDevice device;
if (!device.isValid())
return;
initialHostMode = device.hostMode();
#ifdef Q_OS_MACOS
if (initialHostMode == QBluetoothLocalDevice::HostPoweredOff)
return;
#endif
setHostMode(device.address(), QBluetoothLocalDevice::HostConnectable);
QBluetoothLocalDevice::HostMode hostMode= localDevice->hostMode();
QVERIFY(hostMode != QBluetoothLocalDevice::HostPoweredOff);
}
void tst_QBluetoothServer::cleanupTestCase()
{
if (localDevice)
setHostMode(localDevice->address(), initialHostMode);
}
void tst_QBluetoothServer::tst_construction()
{
{
QBluetoothServer server(QBluetoothServiceInfo::RfcommProtocol);
QVERIFY(!server.isListening());
QCOMPARE(server.maxPendingConnections(), 1);
QVERIFY(!server.hasPendingConnections());
QVERIFY(server.nextPendingConnection() == 0);
QCOMPARE(server.error(), QBluetoothServer::NoError);
QCOMPARE(server.serverType(), QBluetoothServiceInfo::RfcommProtocol);
}
{
QBluetoothServer server(QBluetoothServiceInfo::L2capProtocol);
QVERIFY(!server.isListening());
QCOMPARE(server.maxPendingConnections(), 1);
QVERIFY(!server.hasPendingConnections());
QVERIFY(server.nextPendingConnection() == 0);
QCOMPARE(server.error(), QBluetoothServer::NoError);
QCOMPARE(server.serverType(), QBluetoothServiceInfo::L2capProtocol);
}
}
void tst_QBluetoothServer::tst_receive_data()
{
QTest::addColumn<QBluetoothLocalDevice::HostMode>("hostmode");
QTest::newRow("offline mode") << QBluetoothLocalDevice::HostPoweredOff;
QTest::newRow("online mode") << QBluetoothLocalDevice::HostConnectable;
}
void tst_QBluetoothServer::tst_receive()
{
QFETCH(QBluetoothLocalDevice::HostMode, hostmode);
QBluetoothLocalDevice localDev;
#ifdef Q_OS_MACOS
if (localDev.hostMode() == QBluetoothLocalDevice::HostPoweredOff)
QSKIP("On OS X this test requires Bluetooth adapter ON");
#endif
const QBluetoothAddress address = localDev.address();
bool localDeviceAvailable = localDev.isValid();
if (localDeviceAvailable) {
// setHostMode is noop on OS X and winrt.
setHostMode(address, hostmode);
if (hostmode == QBluetoothLocalDevice::HostPoweredOff) {
#if !defined(Q_OS_MACOS) && !QT_CONFIG(winrt_bt)
QCOMPARE(localDevice->hostMode(), hostmode);
#endif
} else {
QVERIFY(localDevice->hostMode() != QBluetoothLocalDevice::HostPoweredOff);
}
}
QBluetoothServer server(QBluetoothServiceInfo::RfcommProtocol);
QSignalSpy errorSpy(&server, SIGNAL(errorOccurred(QBluetoothServer::Error)));
bool result = server.listen(address, 20); // port == 20
QTest::qWait(1000);
if (!result) {
#ifndef Q_OS_ANDROID
// Disable address check on Android as an actual device always returns
// a valid address, while the emulator doesn't
QCOMPARE(server.serverAddress(), QBluetoothAddress());
#endif
QCOMPARE(server.serverPort(), quint16(0));
QVERIFY(!errorSpy.isEmpty());
QVERIFY(!server.isListening());
if (!localDeviceAvailable) {
QVERIFY(server.error() != QBluetoothServer::NoError);
} else {
//local device but poweredOff
QCOMPARE(server.error(), QBluetoothServer::PoweredOffError);
}
return;
}
QVERIFY(result);
#if !QT_CONFIG(winrt_bt)
QVERIFY(!QBluetoothLocalDevice::allDevices().isEmpty());
#endif
QCOMPARE(server.error(), QBluetoothServer::NoError);
QCOMPARE(server.serverAddress(), address);
QCOMPARE(server.serverPort(), quint16(20));
QVERIFY(server.isListening());
QVERIFY(!server.hasPendingConnections());
server.close();
QCOMPARE(server.error(), QBluetoothServer::NoError);
QVERIFY(server.serverAddress() == address || server.serverAddress() == QBluetoothAddress());
QVERIFY(server.serverPort() == 0);
QVERIFY(!server.isListening());
QVERIFY(!server.hasPendingConnections());
}
QTEST_MAIN(tst_QBluetoothServer)
#include "tst_qbluetoothserver.moc"