blob: af7f0354e0479c9f7e6d60b45735bd3f44e13e95 [file] [log] [blame]
/****************************************************************************
**
** 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 <QVariant>
#include <private/qtbluetoothglobal_p.h>
#include <qbluetoothaddress.h>
#include <qbluetoothlocaldevice.h>
QT_USE_NAMESPACE
/*
* Running the manual tests requires another Bluetooth device in the vincinity.
* The remote device's address must be passed via the BT_TEST_DEVICE env variable.
* Every pairing request must be accepted within a 10s interval of appearing.
* If BT_TEST_DEVICE is not set manual tests will be skipped.
**/
class tst_QBluetoothLocalDevice : public QObject
{
Q_OBJECT
public:
tst_QBluetoothLocalDevice();
~tst_QBluetoothLocalDevice();
private slots:
void initTestCase();
void tst_powerOn();
void tst_powerOff();
void tst_hostModes();
void tst_hostModes_data();
void tst_address();
void tst_name();
void tst_isValid();
void tst_allDevices();
void tst_construction();
void tst_pairingStatus_data();
void tst_pairingStatus();
void tst_pairDevice_data();
void tst_pairDevice();
private:
QBluetoothAddress remoteDevice;
bool expectRemoteDevice;
};
tst_QBluetoothLocalDevice::tst_QBluetoothLocalDevice()
: expectRemoteDevice(false)
{
const QString remote = qgetenv("BT_TEST_DEVICE");
if (!remote.isEmpty()) {
remoteDevice = QBluetoothAddress(remote);
expectRemoteDevice = true;
qWarning() << "Using remote device " << remote << " for testing. Ensure that the device is discoverable for pairing requests";
} else {
qWarning() << "Not using any remote device for testing. Set BT_TEST_DEVICE env to run manual tests involving a remote device";
}
// start with host powered off
QBluetoothLocalDevice *device = new QBluetoothLocalDevice();
device->setHostMode(QBluetoothLocalDevice::HostPoweredOff);
delete device;
// wait for the device to switch bluetooth mode.
QTest::qWait(1000);
}
tst_QBluetoothLocalDevice::~tst_QBluetoothLocalDevice()
{
}
void tst_QBluetoothLocalDevice::initTestCase()
{
if (expectRemoteDevice) {
//test passed Bt address here since we cannot do that in the ctor
QVERIFY2(!remoteDevice.isNull(), "BT_TEST_DEVICE is not a valid Bluetooth address" );
}
}
void tst_QBluetoothLocalDevice::tst_powerOn()
{
#ifdef Q_OS_OSX
QSKIP("Not possible on OS X");
#endif
#ifdef Q_OS_WIN
QSKIP("Not possible on Windows");
#endif
QBluetoothLocalDevice localDevice;
QSignalSpy hostModeSpy(&localDevice, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)));
// there should be no changes yet
QVERIFY(hostModeSpy.isValid());
QVERIFY(hostModeSpy.isEmpty());
if (!QBluetoothLocalDevice::allDevices().count())
QSKIP("Skipping test due to missing Bluetooth device");
localDevice.powerOn();
// async, wait for it
QTRY_VERIFY(hostModeSpy.count() > 0);
QBluetoothLocalDevice::HostMode hostMode= localDevice.hostMode();
// we should not be powered off
QVERIFY(hostMode == QBluetoothLocalDevice::HostConnectable
|| hostMode == QBluetoothLocalDevice::HostDiscoverable);
}
void tst_QBluetoothLocalDevice::tst_powerOff()
{
#ifdef Q_OS_OSX
QSKIP("Not possible on OS X");
#endif
#ifdef Q_OS_WIN
QSKIP("Not possible on Windows");
#endif
if (!QBluetoothLocalDevice::allDevices().count())
QSKIP("Skipping test due to missing Bluetooth device");
{
QBluetoothLocalDevice *device = new QBluetoothLocalDevice();
device->powerOn();
delete device;
// wait for the device to switch bluetooth mode.
QTest::qWait(1000);
}
QBluetoothLocalDevice localDevice;
QSignalSpy hostModeSpy(&localDevice, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)));
// there should be no changes yet
QVERIFY(hostModeSpy.isValid());
QVERIFY(hostModeSpy.isEmpty());
localDevice.setHostMode(QBluetoothLocalDevice::HostPoweredOff);
// async, wait for it
QTRY_VERIFY(hostModeSpy.count() > 0);
// we should not be powered off
QVERIFY(localDevice.hostMode() == QBluetoothLocalDevice::HostPoweredOff);
}
void tst_QBluetoothLocalDevice::tst_hostModes_data()
{
QTest::addColumn<QBluetoothLocalDevice::HostMode>("hostModeExpected");
QTest::addColumn<bool>("expectSignal");
QTest::newRow("HostDiscoverable1") << QBluetoothLocalDevice::HostDiscoverable << true;
QTest::newRow("HostPoweredOff1") << QBluetoothLocalDevice::HostPoweredOff << true;
QTest::newRow("HostPoweredOff2") << QBluetoothLocalDevice::HostPoweredOff << false;
QTest::newRow("HostConnectable1") << QBluetoothLocalDevice::HostConnectable << true;
QTest::newRow("HostConnectable2") << QBluetoothLocalDevice::HostConnectable << false;
QTest::newRow("HostDiscoverable2") << QBluetoothLocalDevice::HostDiscoverable << true;
QTest::newRow("HostConnectable3") << QBluetoothLocalDevice::HostConnectable << true;
QTest::newRow("HostPoweredOff3") << QBluetoothLocalDevice::HostPoweredOff << true;
QTest::newRow("HostDiscoverable3") << QBluetoothLocalDevice::HostDiscoverable << true;
QTest::newRow("HostDiscoverable4") << QBluetoothLocalDevice::HostDiscoverable << false;
QTest::newRow("HostConnectable4") << QBluetoothLocalDevice::HostConnectable << true;
}
void tst_QBluetoothLocalDevice::tst_hostModes()
{
#ifdef Q_OS_OSX
QSKIP("Not possible on OS X");
#endif
#ifdef Q_OS_WIN
QSKIP("Not possible on Windows");
#endif
QFETCH(QBluetoothLocalDevice::HostMode, hostModeExpected);
QFETCH(bool, expectSignal);
if (!QBluetoothLocalDevice::allDevices().count())
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
QSignalSpy hostModeSpy(&localDevice, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)));
// there should be no changes yet
QVERIFY(hostModeSpy.isValid());
QVERIFY(hostModeSpy.isEmpty());
QTest::qWait(1000);
localDevice.setHostMode(hostModeExpected);
// wait for the device to switch bluetooth mode.
QTest::qWait(1000);
if (hostModeExpected != localDevice.hostMode()) {
QTRY_VERIFY(hostModeSpy.count() > 0);
}
// test the actual signal values.
if (expectSignal)
QVERIFY(hostModeSpy.count() > 0);
else
QVERIFY(hostModeSpy.count() == 0);
if (expectSignal) {
QList<QVariant> arguments = hostModeSpy.takeLast();
QBluetoothLocalDevice::HostMode hostMode = qvariant_cast<QBluetoothLocalDevice::HostMode>(arguments.at(0));
QCOMPARE(hostModeExpected, hostMode);
}
// test actual
QCOMPARE(hostModeExpected, localDevice.hostMode());
}
void tst_QBluetoothLocalDevice::tst_address()
{
if (!QBluetoothLocalDevice::allDevices().count())
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
QVERIFY(!localDevice.address().toString().isEmpty());
QVERIFY(!localDevice.address().isNull());
}
void tst_QBluetoothLocalDevice::tst_name()
{
if (!QBluetoothLocalDevice::allDevices().count())
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
QVERIFY(!localDevice.name().isEmpty());
}
void tst_QBluetoothLocalDevice::tst_isValid()
{
#if defined(Q_OS_MACOS) || QT_CONFIG(winrt_bt)
// On OS X we can have a valid device (device.isValid() == true),
// that has neither a name nor a valid address - this happens
// if a Bluetooth adapter is OFF.
if (!QBluetoothLocalDevice::allDevices().count())
QSKIP("Skipping test due to missing Bluetooth device");
#endif
QBluetoothLocalDevice localDevice;
QBluetoothAddress invalidAddress("FF:FF:FF:FF:FF:FF");
const QList<QBluetoothHostInfo> devices = QBluetoothLocalDevice::allDevices();
if (devices.count()) {
QVERIFY(localDevice.isValid());
bool defaultFound = false;
for (int i = 0; i<devices.count(); i++) {
QVERIFY(devices.at(i).address() != invalidAddress);
if (devices.at(i).address() == localDevice.address() ) {
defaultFound = true;
} else {
QBluetoothLocalDevice otherDevice(devices.at(i).address());
QVERIFY(otherDevice.isValid());
}
}
QVERIFY(defaultFound);
} else {
QVERIFY(!localDevice.isValid());
}
//ensure common behavior of invalid local device
QBluetoothLocalDevice invalidLocalDevice(invalidAddress);
QVERIFY(!invalidLocalDevice.isValid());
QCOMPARE(invalidLocalDevice.address(), QBluetoothAddress());
QCOMPARE(invalidLocalDevice.name(), QString());
#if !QT_CONFIG(winrt_bt)
QCOMPARE(invalidLocalDevice.pairingStatus(QBluetoothAddress()), QBluetoothLocalDevice::Unpaired );
QCOMPARE(invalidLocalDevice.hostMode(), QBluetoothLocalDevice::HostPoweredOff);
#else
// When QTBUG-62294 is fixed, the pairingStatus part is consistent across platforms
QCOMPARE(invalidLocalDevice.pairingStatus(QBluetoothAddress()), QBluetoothLocalDevice::Paired);
QCOMPARE(invalidLocalDevice.hostMode(), QBluetoothLocalDevice::HostConnectable);
#endif
}
void tst_QBluetoothLocalDevice::tst_allDevices()
{
//nothing we can really test here
}
void tst_QBluetoothLocalDevice::tst_construction()
{
if (!QBluetoothLocalDevice::allDevices().count())
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
QVERIFY(localDevice.isValid());
QBluetoothLocalDevice anotherDevice(QBluetoothAddress(000000000000));
QVERIFY(anotherDevice.isValid());
QVERIFY(anotherDevice.address().toUInt64() != 0);
}
void tst_QBluetoothLocalDevice::tst_pairDevice_data()
{
QTest::addColumn<QBluetoothAddress>("deviceAddress");
QTest::addColumn<QBluetoothLocalDevice::Pairing>("pairingExpected");
//waiting time larger for manual tests -> requires device interaction
QTest::addColumn<int>("pairingWaitTime");
QTest::addColumn<bool>("expectErrorSignal");
QTest::newRow("UnPaired Device: DUMMY->unpaired") << QBluetoothAddress("11:00:00:00:00:00")
<< QBluetoothLocalDevice::Unpaired << 1000 << false;
//Bluez5 may have to do a device search which can take up to 20s
QTest::newRow("UnPaired Device: DUMMY->paired") << QBluetoothAddress("11:00:00:00:00:00")
<< QBluetoothLocalDevice::Paired << 21000 << true;
QTest::newRow("UnPaired Device: DUMMY") << QBluetoothAddress()
<< QBluetoothLocalDevice::Unpaired << 1000 << true;
if (!remoteDevice.isNull()) {
QTest::newRow("UnParing Test device 1") << QBluetoothAddress(remoteDevice)
<< QBluetoothLocalDevice::Unpaired << 1000 << false;
//Bluez5 may have to do a device search which can take up to 20s
QTest::newRow("Pairing Test Device") << QBluetoothAddress(remoteDevice)
<< QBluetoothLocalDevice::Paired << 21000 << false;
QTest::newRow("Pairing upgrade for Authorization") << QBluetoothAddress(remoteDevice)
<< QBluetoothLocalDevice::AuthorizedPaired << 1000 << false;
QTest::newRow("Unpairing Test device 2") << QBluetoothAddress(remoteDevice)
<< QBluetoothLocalDevice::Unpaired << 1000 << false;
QTest::newRow("Authorized Pairing") << QBluetoothAddress(remoteDevice)
<< QBluetoothLocalDevice::AuthorizedPaired << 10000 << false;
QTest::newRow("Pairing Test Device after Authorization Pairing") << QBluetoothAddress(remoteDevice)
<< QBluetoothLocalDevice::Paired << 1000 << false;
QTest::newRow("Pairing Test Device after Authorization2") << QBluetoothAddress(remoteDevice)
<< QBluetoothLocalDevice::Paired << 1000 << false; //same again
QTest::newRow("Unpairing Test device 3") << QBluetoothAddress(remoteDevice)
<< QBluetoothLocalDevice::Unpaired << 1000 << false;
QTest::newRow("UnParing Test device 4") << QBluetoothAddress(remoteDevice)
<< QBluetoothLocalDevice::Unpaired << 1000 << false;
}
}
void tst_QBluetoothLocalDevice::tst_pairDevice()
{
#ifdef Q_OS_WIN
QSKIP("Programmatic pairing not supported on Windows");
#endif
QFETCH(QBluetoothAddress, deviceAddress);
QFETCH(QBluetoothLocalDevice::Pairing, pairingExpected);
QFETCH(int, pairingWaitTime);
QFETCH(bool, expectErrorSignal);
if (!QBluetoothLocalDevice::allDevices().count())
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
//powerOn if not already
localDevice.powerOn();
QVERIFY(localDevice.hostMode() != QBluetoothLocalDevice::HostPoweredOff);
QSignalSpy pairingSpy(&localDevice, SIGNAL(pairingFinished(QBluetoothAddress,QBluetoothLocalDevice::Pairing)) );
QSignalSpy errorSpy(&localDevice, SIGNAL(error(QBluetoothLocalDevice::Error)));
// there should be no signals yet
QVERIFY(pairingSpy.isValid());
QVERIFY(pairingSpy.isEmpty());
QVERIFY(errorSpy.isValid());
QVERIFY(errorSpy.isEmpty());
QVERIFY(localDevice.isValid());
localDevice.requestPairing(deviceAddress, pairingExpected);
// async, wait for it
QTest::qWait(pairingWaitTime);
if (expectErrorSignal) {
QTRY_VERIFY(!errorSpy.isEmpty());
QVERIFY(pairingSpy.isEmpty());
QList<QVariant> arguments = errorSpy.first();
QBluetoothLocalDevice::Error e = qvariant_cast<QBluetoothLocalDevice::Error>(arguments.at(0));
QCOMPARE(e, QBluetoothLocalDevice::PairingError);
} else {
QTRY_VERIFY(!pairingSpy.isEmpty());
QVERIFY(errorSpy.isEmpty());
// test the actual signal values.
QList<QVariant> arguments = pairingSpy.takeFirst();
QBluetoothAddress address = qvariant_cast<QBluetoothAddress>(arguments.at(0));
QBluetoothLocalDevice::Pairing pairingResult = qvariant_cast<QBluetoothLocalDevice::Pairing>(arguments.at(1));
QCOMPARE(deviceAddress, address);
QCOMPARE(pairingExpected, pairingResult);
}
if (!expectErrorSignal)
QCOMPARE(pairingExpected, localDevice.pairingStatus(deviceAddress));
}
void tst_QBluetoothLocalDevice::tst_pairingStatus_data()
{
QTest::addColumn<QBluetoothAddress>("deviceAddress");
QTest::addColumn<QBluetoothLocalDevice::Pairing>("pairingExpected");
#if !QT_CONFIG(winrt_bt)
QTest::newRow("UnPaired Device: DUMMY") << QBluetoothAddress("11:00:00:00:00:00")
<< QBluetoothLocalDevice::Unpaired;
QTest::newRow("Invalid device") << QBluetoothAddress() << QBluetoothLocalDevice::Unpaired;
#else
// Remove special case when QTBUG-62294 is fixed
QTest::newRow("UnPaired Device: DUMMY") << QBluetoothAddress("11:00:00:00:00:00")
<< QBluetoothLocalDevice::Paired;
QTest::newRow("Invalid device") << QBluetoothAddress() << QBluetoothLocalDevice::Paired;
#endif
//valid devices are already tested by tst_pairDevice()
}
void tst_QBluetoothLocalDevice::tst_pairingStatus()
{
QFETCH(QBluetoothAddress, deviceAddress);
QFETCH(QBluetoothLocalDevice::Pairing, pairingExpected);
if (!QBluetoothLocalDevice::allDevices().count())
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
QCOMPARE(pairingExpected, localDevice.pairingStatus(deviceAddress));
}
QTEST_MAIN(tst_QBluetoothLocalDevice)
#include "tst_qbluetoothlocaldevice.moc"