Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ //TESTED_COMPONENT=src/sensors
++
++ #include <QtCore/QObject>
++ #include <QTest>
++ #include <QtCore/QDebug>
++ #include <QtCore/QFile>
++ #include <QSignalSpy>
++ #include <QtSensors/QSensorManager>
++
++ #include "qsensor.h"
++ #include "test_sensor.h"
++ #include "test_sensor2.h"
++ #include "test_sensorimpl.h"
++ #include "../common/test_backends.h"
++
++ QT_BEGIN_NAMESPACE
++
++ bool operator==(const qoutputrange &orl1, const qoutputrange &orl2)
++ {
++ return (orl1.minimum == orl2.minimum &&
++ orl1.maximum == orl2.maximum &&
++ orl1.accuracy == orl2.accuracy);
++ }
++
++ namespace QTest {
++ // QCOMPARE calls this upon failure (and if a list of these elements is compared,
++ // it will call this individually for each element)
++ template<> char* toString(const qoutputrange& range)
++ {
++ QString ret = QString("%1-%2%3%4").arg(range.minimum).arg(range.maximum)
++ .arg(QString::fromWCharArray(L"\u00B1")).arg(range.accuracy);
++ return qstrdup(ret.toLatin1().data());
++ }
++ }
++
++ class MyFilter : public TestSensorFilter { bool filter(TestSensorReading *) override { return false; } };
++
++ class ModFilter : public TestSensorFilter
++ {
++ bool filter(TestSensorReading *reading) override
++ {
++ reading->setTest(3);
++ return true;
++ }
++ };
++
++ class MyFactory : public QSensorBackendFactory
++ {
++ QSensorBackend *createBackend(QSensor * /*sensor*/) override
++ {
++ return 0;
++ }
++ };
++
++ /*
++ Unit test for QSensor class.
++ */
++ class tst_QSensor : public QObject
++ {
++ Q_OBJECT
++
++ public:
++ tst_QSensor()
++ {
++ qputenv("QT_SENSORS_LOAD_PLUGINS", "0"); // Do not load plugins
++ }
++
++ private slots:
++ void initTestCase()
++ {
++ }
++
++ void cleanupTestCase()
++ {
++
++ #ifdef WAIT_AT_END
++ QFile _stdin;
++ _stdin.open(1, QIODevice::ReadOnly);
++ _stdin.readLine();
++ #endif
++ }
++
++ // This test MUST be first
++ void testRecursiveLoadPlugins()
++ {
++ TestSensor sensor;
++
++ // The logic for the test is in test_sensorplugin.cpp (which warns and aborts if the test fails)
++ (void)QSensor::sensorTypes();
++
++ // Checking that the availableSensorsChanged() signal was not emitted too many times while loading plugins.
++ QCOMPARE(sensor.sensorsChangedEmitted, 1);
++ }
++
++ void testTypeRegistered()
++ {
++ // Verify type registrations done by the test_sensorplugin
++ QVERIFY(QSensor::sensorTypes().contains(TestSensor::sensorType));
++ QVERIFY(QSensor::sensorTypes().contains(TestSensor2::sensorType));
++ }
++
++ void testSensorRegistered()
++ {
++ QList<QByteArray> expected;
++ expected << "test sensor 2" << "test sensor 3" << testsensorimpl::id;
++ QList<QByteArray> actual = QSensor::sensorsForType(TestSensor::sensorType);
++ std::sort(actual.begin(), actual.end()); // The actual list is not in a defined order
++ QCOMPARE(actual, expected);
++ }
++
++ void testSensorDefault()
++ {
++ QByteArray expected = testsensorimpl::id;
++ QByteArray actual = QSensor::defaultSensorForType(TestSensor::sensorType);
++ QCOMPARE(actual, expected);
++ }
++
++ void testBadDefaultFromConfig()
++ {
++ QSensorManager::setDefaultBackend(QByteArray(TestSensor::sensorType), QByteArray("bogus id"));
++ QByteArray expected = testsensorimpl::id;
++ QByteArray actual = QSensor::defaultSensorForType(TestSensor::sensorType);
++ QCOMPARE(actual, expected);
++ }
++
++ void testGoodDefaultFromConfig()
++ {
++ QSensorManager::setDefaultBackend(QByteArray(TestSensor::sensorType), QByteArray(testsensorimpl::id));
++ QByteArray expected = testsensorimpl::id;
++ QByteArray actual = QSensor::defaultSensorForType(TestSensor::sensorType);
++ QCOMPARE(actual, expected);
++ }
++
++ void testNoSensorsForType()
++ {
++ QList<QByteArray> expected;
++ QList<QByteArray> actual = QSensor::sensorsForType("bogus type");
++ QCOMPARE(actual, expected);
++ }
++
++ void testNoDefaultForType()
++ {
++ QByteArray expected;
++ QByteArray actual = QSensor::defaultSensorForType("bogus type");
++ QCOMPARE(actual, expected);
++ }
++
++ void testCreation()
++ {
++ TestSensor sensor;
++ sensor.connectToBackend();
++ QByteArray expected = testsensorimpl::id;
++ QByteArray actual = sensor.identifier();
++ QCOMPARE(actual, expected);
++ }
++
++ void testSetIdentifierFail()
++ {
++ TestSensor sensor;
++ sensor.setIdentifier(testsensorimpl::id);
++ sensor.connectToBackend();
++ QVERIFY(sensor.isConnectedToBackend());
++ QByteArray expected = testsensorimpl::id;
++ QByteArray actual = sensor.identifier();
++ QCOMPARE(actual, expected);
++
++ QTest::ignoreMessage(QtWarningMsg, "ERROR: Cannot call QSensor::setIdentifier while connected to a backend!");
++ sensor.setIdentifier("dummy.accelerometer");
++ expected = testsensorimpl::id;
++ actual = sensor.identifier();
++ QCOMPARE(actual, expected);
++ }
++
++ void testBadDefaultCreation()
++ {
++ QSensorManager::setDefaultBackend(QByteArray(TestSensor::sensorType), QByteArray("test sensor 2"));
++ TestSensor sensor;
++ QTest::ignoreMessage(QtWarningMsg, "Can't create backend \"test sensor 2\"");
++ sensor.connectToBackend();
++ QByteArray expected = testsensorimpl::id;
++ QByteArray actual = sensor.identifier();
++ QCOMPARE(actual, expected);
++ }
++
++ void testBadCreation()
++ {
++ QSensor sensor("bogus type");
++ sensor.connectToBackend();
++ QByteArray expected; // should be null
++ QByteArray actual = sensor.identifier();
++ QCOMPARE(actual, expected);
++ }
++
++ void testTimestamp()
++ {
++ TestSensor sensor;
++ sensor.connectToBackend();
++ QVERIFY(sensor.reading() != 0);
++ quint64 timestamp = sensor.reading()->timestamp();
++ quint64 timestamp2 = sensor.reading()->timestamp();
++ QVERIFY(timestamp == quint64());
++ QVERIFY(timestamp2 == quint64());
++ sensor.setProperty("doThis", "setOne");
++ sensor.start();
++ timestamp = sensor.reading()->timestamp();
++ timestamp2 = sensor.reading()->timestamp();
++ QVERIFY(timestamp == 1);
++ QVERIFY(timestamp2 == 1);
++ }
++
++ void testStart()
++ {
++ TestSensor sensor;
++ sensor.start();
++ QVERIFY(sensor.isActive());
++ sensor.start();
++ QVERIFY(sensor.isActive());
++ }
++
++ void testBadStart()
++ {
++ QSensor sensor("bogus type");
++ sensor.start();
++ QVERIFY(!sensor.isActive());
++ }
++
++ void testStop()
++ {
++ TestSensor sensor;
++ sensor.stop();
++ QVERIFY(!sensor.isActive());
++ sensor.start();
++ QVERIFY(sensor.isActive());
++ sensor.stop();
++ QVERIFY(!sensor.isActive());
++ }
++
++ void testMetaData()
++ {
++ TestSensor sensor;
++
++ {
++ bool actual = sensor.isConnectedToBackend();
++ bool expected = false;
++ QCOMPARE(actual, expected);
++ }
++
++ sensor.connectToBackend();
++
++ {
++ bool actual = sensor.isConnectedToBackend();
++ bool expected = true;
++ QCOMPARE(actual, expected);
++ }
++
++ {
++ QString actual = sensor.description();
++ QString expected = "sensor description";
++ QCOMPARE(actual, expected);
++ }
++
++ {
++ qoutputrangelist actual = sensor.outputRanges();
++ qoutputrangelist expected;
++ qoutputrange r; r.minimum = 0; r.maximum = 1; r.accuracy = 0.5;
++ expected << r;
++ r.minimum = 0; r.maximum = 2; r.accuracy = 1;
++ expected << r;
++ QCOMPARE(actual, expected);
++ }
++
++ {
++ int actual = sensor.outputRange();
++ int expected = -1;
++ QCOMPARE(actual, expected);
++
++ sensor.setOutputRange(0);
++
++ actual = sensor.outputRange();
++ expected = 0;
++ QCOMPARE(actual, expected);
++ }
++
++ {
++ qrangelist actual = sensor.availableDataRates();
++ qrangelist expected = qrangelist() << qrange(100,100);
++ QCOMPARE(actual, expected);
++ }
++
++ {
++ TestSensor sensor;
++ sensor.setProperty("doThis", "rates");
++ sensor.connectToBackend();
++ qrangelist actual = sensor.availableDataRates();
++ qrangelist expected = qrangelist() << qrange(100,100);
++ QCOMPARE(actual, expected);
++ }
++
++ // Test that a previously-set, valid data rate is retained
++ {
++ TestSensor sensor;
++ sensor.setDataRate(100);
++ sensor.setProperty("doThis", "rates");
++ sensor.connectToBackend();
++ int actual = sensor.dataRate();
++ int expected = 100;
++ QCOMPARE(actual, expected);
++ }
++
++ // Test that a previously-set, invalid data rate is retained
++ {
++ TestSensor sensor;
++ sensor.setDataRate(50);
++ sensor.setProperty("doThis", "rates");
++ sensor.connectToBackend();
++ int actual = sensor.dataRate();
++ int expected = 50;
++ QCOMPARE(actual, expected);
++ }
++
++ {
++ TestSensor sensor;
++ sensor.setProperty("doThis", "rates(0)");
++ QTest::ignoreMessage(QtWarningMsg, "ERROR: Cannot call QSensorBackend::setDataRates with 0");
++ sensor.connectToBackend();
++ }
++
++ {
++ TestSensor sensor;
++ sensor.setProperty("doThis", "rates(nodef)");
++ QTest::ignoreMessage(QtWarningMsg, "ERROR: Cannot call QSensorBackend::setDataRates with an invalid sensor");
++ sensor.connectToBackend();
++ }
++
++ {
++ int actual = sensor.dataRate();
++ int expected = 0;
++ QCOMPARE(actual, expected);
++
++ sensor.setDataRate(100);
++
++ actual = sensor.dataRate();
++ expected = 100;
++ QCOMPARE(actual, expected);
++ }
++
++ // Test the generic accessor functions
++ TestSensorReading *reading = sensor.reading();
++ QCOMPARE(reading->valueCount(), 1);
++ reading->setTest(1);
++ QCOMPARE(reading->test(), reading->value(0).toInt());
++ }
++
++ void testFilter()
++ {
++ TestSensor sensor;
++ sensor.connectToBackend();
++
++ QList<QSensorFilter*> actual = sensor.filters();
++ QList<QSensorFilter*> expected = QList<QSensorFilter*>();
++ QCOMPARE(actual, expected);
++
++ QTest::ignoreMessage(QtWarningMsg, "addFilter: passed a null filter!");
++ sensor.addFilter(0);
++
++ QTest::ignoreMessage(QtWarningMsg, "removeFilter: passed a null filter!");
++ sensor.removeFilter(0);
++
++ MyFilter *filter = new MyFilter;
++ sensor.addFilter(filter);
++
++ actual = sensor.filters();
++ expected = QList<QSensorFilter*>() << filter;
++ QCOMPARE(actual, expected);
++
++ MyFilter *filter2 = new MyFilter;
++ sensor.addFilter(filter2);
++
++ actual = sensor.filters();
++ expected = QList<QSensorFilter*>() << filter << filter2;
++ QCOMPARE(actual, expected);
++
++ delete filter2;
++
++ actual = sensor.filters();
++ expected = QList<QSensorFilter*>() << filter;
++ QCOMPARE(actual, expected);
++
++ sensor.removeFilter(filter);
++
++ actual = sensor.filters();
++ expected = QList<QSensorFilter*>();
++ QCOMPARE(actual, expected);
++
++ delete filter;
++ }
++
++ void testFilter2()
++ {
++ TestSensor sensor;
++ sensor.setProperty("doThis", "setOne");
++ TestSensorFilter *filter1 = new ModFilter;
++ TestSensorFilter *filter2 = new MyFilter;
++ sensor.addFilter(filter1);
++ sensor.start();
++ QCOMPARE(sensor.reading()->test(), 3);
++ sensor.stop();
++ sensor.reading()->setTest(1);
++ sensor.addFilter(filter2);
++ sensor.start();
++ QCOMPARE(sensor.reading()->test(), 1);
++ sensor.stop();
++ delete filter1;
++ delete filter2;
++ }
++
++ void testFilter3()
++ {
++ TestSensor sensor;
++ sensor.setProperty("doThis", "setOne");
++ QSignalSpy spy(&sensor, SIGNAL(readingChanged()));
++ sensor.start();
++ QCOMPARE(spy.size(), 1); // reading changes
++ sensor.stop();
++
++ TestSensorFilter *filter2 = new MyFilter;
++ sensor.addFilter(filter2);
++ sensor.start();
++ QCOMPARE(spy.size(), 1); // filter suppresses reading so it does not change
++ sensor.stop();
++ delete filter2;
++
++ TestSensorFilter *filter1 = new ModFilter;
++ sensor.addFilter(filter1);
++ sensor.start();
++ QCOMPARE(spy.size(), 2); // filter does not suppress reading
++ sensor.stop();
++ delete filter1;
++ }
++
++ void testStart2()
++ {
++ TestSensor sensor;
++ sensor.connectToBackend();
++
++ sensor.setProperty("doThis", "stop");
++ sensor.start();
++ QVERIFY(!sensor.isActive());
++ sensor.stop();
++
++ sensor.setProperty("doThis", "error");
++ sensor.start();
++ QVERIFY(sensor.error() == 1);
++ // Yes, this is non-intuitive but the sensor
++ // decides if an error is fatal or not.
++ // In this case our test sensor is reporting a
++ // non-fatal error so the sensor will start.
++ QVERIFY(sensor.isActive());
++ sensor.stop();
++
++ sensor.setProperty("doThis", "setOne");
++ sensor.start();
++ QCOMPARE(sensor.reading()->timestamp(), quint64(1));
++ QCOMPARE(sensor.reading()->test(), 1);
++ sensor.stop();
++
++ sensor.setProperty("doThis", "setTwo");
++ sensor.start();
++ QCOMPARE(sensor.reading()->timestamp(), quint64(2));
++ QCOMPARE(sensor.reading()->test(), 2);
++ sensor.stop();
++ }
++
++ void testSetBadDataRate()
++ {
++ TestSensor sensor;
++ sensor.connectToBackend();
++
++ sensor.setDataRate(1);
++ QCOMPARE(sensor.dataRate(), 1);
++
++ sensor.setDataRate(1000);
++ QCOMPARE(sensor.dataRate(), 1000);
++ }
++
++ void testSetBadDataRateWhenNotConnected()
++ {
++ TestSensor sensor;
++ sensor.setDataRate(0);
++ QCOMPARE(sensor.dataRate(), 0);
++ sensor.setDataRate(300);
++ QCOMPARE(sensor.dataRate(), 300);
++ sensor.setDataRate(350);
++ sensor.connectToBackend();
++ QCOMPARE(sensor.dataRate(), 350);
++ }
++
++ void testSetBadOutputRange()
++ {
++ TestSensor sensor;
++ sensor.connectToBackend();
++
++ sensor.setOutputRange(-1);
++ QCOMPARE(sensor.outputRange(), -1);
++ QTest::ignoreMessage(QtWarningMsg, "setOutputRange: 300 is not supported by the sensor.");
++ sensor.setOutputRange(300);
++ QCOMPARE(sensor.outputRange(), -1);
++ }
++
++ void testSetBadOutputRangeWhenNotConnected()
++ {
++ TestSensor sensor;
++ sensor.setOutputRange(300);
++ QCOMPARE(sensor.outputRange(), 300);
++ sensor.setOutputRange(350);
++ QTest::ignoreMessage(QtWarningMsg, "setOutputRange: 350 is not supported by the sensor.");
++ sensor.connectToBackend();
++ QCOMPARE(sensor.outputRange(), -1);
++ QTest::ignoreMessage(QtWarningMsg, "setOutputRange: -2 is not supported by the sensor.");
++ sensor.setOutputRange(-2);
++ QCOMPARE(sensor.outputRange(), -1);
++ }
++
++ void testEnumHandling()
++ {
++ {
++ QAmbientLightReading reading;
++ for (int i = 0; i <= 6; i++) {
++ QAmbientLightReading::LightLevel setting = static_cast<QAmbientLightReading::LightLevel>(i);
++ QAmbientLightReading::LightLevel expected = setting;
++ if (i == 6)
++ expected = QAmbientLightReading::Undefined;
++ reading.setLightLevel(setting);
++ QCOMPARE(reading.lightLevel(), expected);
++ }
++ }
++
++ {
++ QOrientationReading reading;
++ for (int i = 0; i <= 7; i++) {
++ QOrientationReading::Orientation setting = static_cast<QOrientationReading::Orientation>(i);
++ QOrientationReading::Orientation expected = setting;
++ if (i == 7)
++ expected = QOrientationReading::Undefined;
++ reading.setOrientation(setting);
++ QCOMPARE(reading.orientation(), expected);
++ }
++ }
++
++ {
++ QTapReading reading;
++ reading.setTapDirection(QTapReading::Undefined);
++ QCOMPARE(reading.tapDirection(), QTapReading::Undefined);
++ reading.setTapDirection(QTapReading::X_Pos);
++ QCOMPARE(reading.tapDirection(), QTapReading::X_Pos);
++ reading.setTapDirection(QTapReading::X_Neg);
++ QCOMPARE(reading.tapDirection(), QTapReading::X_Neg);
++ reading.setTapDirection(QTapReading::Y_Pos);
++ QCOMPARE(reading.tapDirection(), QTapReading::Y_Pos);
++ reading.setTapDirection(QTapReading::Y_Neg);
++ QCOMPARE(reading.tapDirection(), QTapReading::Y_Neg);
++ reading.setTapDirection(QTapReading::Z_Pos);
++ QCOMPARE(reading.tapDirection(), QTapReading::Z_Pos);
++ reading.setTapDirection(QTapReading::Z_Neg);
++ QCOMPARE(reading.tapDirection(), QTapReading::Z_Neg);
++ // Directions can be ORed together
++ reading.setTapDirection(QTapReading::X_Both);
++ QCOMPARE(reading.tapDirection(), QTapReading::X_Both);
++ reading.setTapDirection(QTapReading::Y_Both);
++ QCOMPARE(reading.tapDirection(), QTapReading::Y_Both);
++ reading.setTapDirection(QTapReading::Z_Both);
++ QCOMPARE(reading.tapDirection(), QTapReading::Z_Both);
++ // You can't set just the Axis
++ reading.setTapDirection(QTapReading::X);
++ QCOMPARE(reading.tapDirection(), QTapReading::Undefined);
++ reading.setTapDirection(QTapReading::Y);
++ QCOMPARE(reading.tapDirection(), QTapReading::Undefined);
++ reading.setTapDirection(QTapReading::Z);
++ QCOMPARE(reading.tapDirection(), QTapReading::Undefined);
++ reading.setTapDirection(static_cast<QTapReading::TapDirection>(0x1000));
++ QCOMPARE(reading.tapDirection(), QTapReading::Undefined);
++ }
++ }
++
++ void testDynamicDefaultsAndGenericHandling()
++ {
++ QByteArray expected;
++ QByteArray actual;
++ MyFactory factory;
++
++ // The default for this type is null
++ expected = QByteArray();
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++
++ // Register a bogus backend
++ QSensorManager::registerBackend("random", "generic.random", &factory);
++
++ // The default for this type is the newly-registered backend
++ expected = "generic.random";
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++
++ // Register a non-generic bogus backend
++ QSensorManager::registerBackend("random", "not.generic.random", &factory);
++
++ // The default for this type is the newly-registered backend
++ expected = "not.generic.random";
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++
++ // Unregister the non-generic bogus backend
++ QSensorManager::unregisterBackend("random", "not.generic.random");
++
++ // The default for this type is the generic backend
++ expected = "generic.random";
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++
++ // Unregister a bogus backend
++ QSensorManager::unregisterBackend("random", "generic.random");
++
++ // The default for this type is null again
++ expected = QByteArray();
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++
++
++ // Now test out some more of the logic
++ // Register 2 backends and unregister the first.
++ QSensorManager::registerBackend("random", "random.1", &factory);
++ expected = "random.1";
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++ QSensorManager::registerBackend("random", "random.2", &factory);
++ expected = "random.1";
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++ QSensorManager::unregisterBackend("random", "random.1");
++ expected = "random.2";
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++ QSensorManager::unregisterBackend("random", "random.2");
++ expected = QByteArray();
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++
++ // Now stick a generic backend into the mix and ensure the correct thing happens
++ QSensorManager::registerBackend("random", "random.1", &factory);
++ expected = "random.1";
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++ QSensorManager::registerBackend("random", "generic.random.2", &factory);
++ expected = "random.1";
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++ QSensorManager::registerBackend("random", "random.2", &factory);
++ expected = "random.1";
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++ QSensorManager::unregisterBackend("random", "random.1");
++ expected = "random.2";
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++ QSensorManager::unregisterBackend("random", "generic.random.2");
++ expected = "random.2";
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++ QSensorManager::unregisterBackend("random", "random.2");
++ expected = QByteArray();
++ actual = QSensor::defaultSensorForType("random");
++ QCOMPARE(expected, actual);
++ }
++
++ void testCreation2()
++ {
++ MyFactory factory;
++
++ QSensorManager::registerBackend("random", "random.1", &factory);
++ QSensorManager::registerBackend("random", "random.2", &factory);
++ QSensor random("random");
++ // This is a sensorlog, not a warning
++ //QTest::ignoreMessage(QtWarningMsg, "no suitable backend found for requested identifier \"\" and type \"random\"");
++ random.connectToBackend();
++ QVERIFY(!random.isConnectedToBackend());
++ random.setIdentifier("random.3");
++ // This is a sensorlog, not a warning
++ //QTest::ignoreMessage(QtWarningMsg, "no backend with identifier \"random.3\" for type \"random\"");
++ random.connectToBackend();
++ QVERIFY(!random.isConnectedToBackend());
++ random.setIdentifier("random.1");
++ random.connectToBackend();
++ QVERIFY(!random.isConnectedToBackend());
++ QSensorManager::unregisterBackend("random", "random.1");
++ QSensorManager::unregisterBackend("random", "random.2");
++ }
++
++ void testSensorsChangedSignal()
++ {
++ TestSensor sensor;
++ MyFactory factory;
++
++ // Register a bogus backend
++ sensor.sensorsChangedEmitted = 0;
++ QSensorManager::registerBackend("a random type", "a random id", &factory);
++ QCOMPARE(sensor.sensorsChangedEmitted, 1);
++
++ // Register it again (creates a warning)
++ sensor.sensorsChangedEmitted = 0;
++ QTest::ignoreMessage(QtWarningMsg, "A backend with type \"a random type\" and identifier \"a random id\" has already been registered!");
++ QSensorManager::registerBackend("a random type", "a random id", &factory);
++ QCOMPARE(sensor.sensorsChangedEmitted, 0);
++
++ // Unregister a bogus backend
++ sensor.sensorsChangedEmitted = 0;
++ QSensorManager::unregisterBackend("a random type", "a random id");
++ QCOMPARE(sensor.sensorsChangedEmitted, 1);
++
++ // Unregister an unknown identifier
++ sensor.sensorsChangedEmitted = 0;
++ QTest::ignoreMessage(QtWarningMsg, "Identifier \"a random id\" is not registered");
++ QSensorManager::unregisterBackend(TestSensor::sensorType, "a random id");
++ QCOMPARE(sensor.sensorsChangedEmitted, 0);
++
++ // Unregister for an unknown type
++ sensor.sensorsChangedEmitted = 0;
++ QTest::ignoreMessage(QtWarningMsg, "No backends of type \"foo\" are registered");
++ QSensorManager::unregisterBackend("foo", "bar");
++ QCOMPARE(sensor.sensorsChangedEmitted, 0);
++
++ // Make sure we've cleaned up the list of available types
++ QVERIFY(!QSensor::sensorTypes().contains("a random type"));
++ QVERIFY(QSensor::sensorTypes().contains(TestSensor::sensorType));
++ QVERIFY(QSensor::sensorTypes().contains(TestSensor2::sensorType));
++ }
++
++ void testSetActive()
++ {
++ TestSensor sensor;
++ sensor.setActive(true);
++ // doesn't start till the event loop is hit
++ QVERIFY(!sensor.isActive());
++ // hit the event loop
++ QTest::qWait(0);
++ QVERIFY(sensor.isActive());
++ sensor.setActive(true);
++ QVERIFY(sensor.isActive());
++ // it does stop immediately
++ sensor.setActive(false);
++ QVERIFY(!sensor.isActive());
++ }
++
++ void testAlwaysOn()
++ {
++ TestSensor sensor;
++ QCOMPARE(sensor.isAlwaysOn(), false);
++ sensor.setAlwaysOn(true);
++ QCOMPARE(sensor.isAlwaysOn(), true);
++ sensor.setAlwaysOn(false);
++ QCOMPARE(sensor.isAlwaysOn(), false);
++ }
++
++ void testIsRegistered()
++ {
++ bool expected;
++ bool actual;
++
++ expected = true;
++ actual = QSensorManager::isBackendRegistered(TestSensor::sensorType, testsensorimpl::id);
++ QCOMPARE(expected, actual);
++
++ expected = false;
++ actual = QSensorManager::isBackendRegistered(TestSensor::sensorType, "random");
++ QCOMPARE(expected, actual);
++
++ expected = false;
++ actual = QSensorManager::isBackendRegistered("random", "random");
++ QCOMPARE(expected, actual);
++ }
++
++ void testAllTheInterfaces()
++ {
++ register_test_backends();
++
++ TEST_SENSORINTERFACE(QAccelerometer, QAccelerometerReading, {
++ QCOMPARE(reading->x(), 1.0);
++ QCOMPARE(reading->y(), 1.0);
++ QCOMPARE(reading->z(), 1.0);
++ })
++
++ TEST_SENSORINTERFACE(QAmbientLightSensor, QAmbientLightReading, {
++ QCOMPARE(reading->lightLevel(), QAmbientLightReading::Twilight);
++ })
++
++ TEST_SENSORINTERFACE(QAmbientTemperatureSensor, QAmbientTemperatureReading, {
++ QCOMPARE(reading->temperature(), 30.0);
++ })
++
++ TEST_SENSORINTERFACE(QCompass, QCompassReading, {
++ QCOMPARE(reading->azimuth(), 1.0);
++ QCOMPARE(reading->calibrationLevel(), 1.0);
++ })
++
++ TEST_SENSORINTERFACE(QGyroscope, QGyroscopeReading, {
++ QCOMPARE(reading->x(), 1.0);
++ QCOMPARE(reading->y(), 1.0);
++ QCOMPARE(reading->z(), 1.0);
++ })
++
++ TEST_SENSORINTERFACE(QLightSensor, QLightReading, {
++ QCOMPARE(reading->lux(), 1.0);
++ })
++
++ TEST_SENSORINTERFACE(QMagnetometer, QMagnetometerReading, {
++ QCOMPARE(reading->x(), 1.0);
++ QCOMPARE(reading->y(), 1.0);
++ QCOMPARE(reading->z(), 1.0);
++ QCOMPARE(reading->calibrationLevel(), 1.0);
++ })
++
++ TEST_SENSORINTERFACE(QOrientationSensor, QOrientationReading, {
++ QCOMPARE(reading->orientation(), QOrientationReading::LeftUp);
++ })
++
++ TEST_SENSORINTERFACE(QPressureSensor, QPressureReading, {
++ QCOMPARE(reading->pressure(), 1.0);
++ QCOMPARE(reading->temperature(), 1.0);
++ })
++
++ TEST_SENSORINTERFACE(QProximitySensor, QProximityReading, {
++ QCOMPARE(reading->close(), true);
++ })
++
++ TEST_SENSORINTERFACE(QRotationSensor, QRotationReading, {
++ QCOMPARE(reading->x(), 1.0);
++ QCOMPARE(reading->y(), 1.0);
++ QCOMPARE(reading->z(), 1.0);
++ })
++
++ TEST_SENSORINTERFACE(QTapSensor, QTapReading, {
++ QCOMPARE(reading->tapDirection(), QTapReading::Z_Both);
++ QCOMPARE(reading->isDoubleTap(), true);
++ })
++
++ TEST_SENSORINTERFACE(QTiltSensor, QTiltReading, {
++ QCOMPARE(reading->yRotation(), 1.0);
++ QCOMPARE(reading->xRotation(), 1.0);
++ })
++
++ TEST_SENSORINTERFACE(QIRProximitySensor, QIRProximityReading, {
++ QCOMPARE(reading->reflectance(), 0.5);
++ })
++
++ unregister_test_backends();
++ }
++
++ void testReadingBC()
++ {
++ // QSensorReading changed in 1.0.1 due to QTMOBILITY-226
++ // This test verifies that a backend built against the 1.0.0
++ // version of qsensor.h still runs.
++ TestSensor2 sensor;
++
++ sensor.setProperty("doThis", "setOne");
++ sensor.start();
++ QCOMPARE(sensor.reading()->timestamp(), quint64(1));
++ QCOMPARE(sensor.reading()->test(), 1);
++ sensor.stop();
++
++ sensor.setProperty("doThis", "setTwo");
++ sensor.start();
++ QCOMPARE(sensor.reading()->timestamp(), quint64(2));
++ QCOMPARE(sensor.reading()->test(), 2);
++ sensor.stop();
++ }
++
++ void testBusyChanged()
++ {
++ // Start an exclusive sensor
++ TestSensor sensor1;
++ sensor1.setProperty("exclusive", true);
++ sensor1.start();
++ QVERIFY(sensor1.isActive());
++
++ // Try to start another one, sensor reports busy
++ TestSensor sensor2;
++ sensor2.setProperty("exclusive", true);
++ sensor2.start();
++ QVERIFY(sensor2.isBusy());
++ QVERIFY(!sensor2.isActive());
++
++ // Stopping the first instance causes the busyChanged signal to be emitted from the second instance
++ QSignalSpy spy(&sensor2, SIGNAL(busyChanged()));
++ sensor1.stop();
++ QCOMPARE(spy.size(), 1);
++
++ // Now we can start the second instance
++ sensor2.start();
++ QVERIFY(sensor2.isActive());
++
++ // test 'busy' going back and forth and verify indication to frontend
++ register_test_backends();
++ QAccelerometer accelerometer;
++ accelerometer.setIdentifier("QAccelerometer");
++ QSignalSpy busySpy(&accelerometer, SIGNAL(busyChanged()));
++ QVERIFY(accelerometer.connectToBackend());
++ QVERIFY(!accelerometer.isBusy());
++ QCOMPARE(busySpy.size(), 0);
++
++ set_test_backend_busy(&accelerometer, true);
++ QCOMPARE(busySpy.size(), 1);
++ QVERIFY(accelerometer.isBusy());
++
++ set_test_backend_busy(&accelerometer, false);
++ QCOMPARE(busySpy.size(), 2);
++ QVERIFY(!accelerometer.isBusy());
++ unregister_test_backends();
++ }
++
++ void testIdenfifierChanged()
++ {
++ TestSensor sensor;
++ QSignalSpy spy(&sensor, SIGNAL(identifierChanged()));
++ QCOMPARE(sensor.identifier(), "");
++
++ // Change id and verify change
++ sensor.setIdentifier("a");
++ QCOMPARE(sensor.identifier(), "a");
++ QCOMPARE(spy.size(), 1);
++
++ // Set same id and verify that no changes
++ sensor.setIdentifier("a");
++ QCOMPARE(sensor.identifier(), "a");
++ QCOMPARE(spy.size(), 1);
++
++ // Change id and verify change
++ sensor.setIdentifier(testsensorimpl::id);
++ QCOMPARE(sensor.identifier(), testsensorimpl::id);
++ QCOMPARE(spy.size(), 2);
++
++ // Identifier cant be changed after connected to backend
++ QVERIFY(sensor.connectToBackend());
++ sensor.setIdentifier("c");
++ QCOMPARE(sensor.identifier(), testsensorimpl::id);
++ QCOMPARE(spy.size(), 2);
++ }
++
++ void testSupportedFeatures()
++ {
++ TestSensor sensor;
++
++ // Not connected to backend - should report false for any feature
++ QVERIFY(!sensor.isConnectedToBackend());
++ QVERIFY(!sensor.isFeatureSupported(QSensor::Feature::AlwaysOn));
++ QVERIFY(!sensor.isFeatureSupported(QSensor::Feature::Buffering));
++ QVERIFY(!sensor.isFeatureSupported(QSensor::Feature::GeoValues));
++ QVERIFY(!sensor.isFeatureSupported(QSensor::Feature::FieldOfView));
++ QVERIFY(!sensor.isFeatureSupported(QSensor::Feature::AccelerationMode));
++
++ // Connect to backend - according to the testsensorimpl implementation, AlwaysOn and
++ // GeoValues should be supported afterwards
++ QVERIFY(sensor.connectToBackend());
++
++ QVERIFY(sensor.isFeatureSupported(QSensor::Feature::AlwaysOn));
++ QVERIFY(!sensor.isFeatureSupported(QSensor::Feature::Buffering));
++ QVERIFY(sensor.isFeatureSupported(QSensor::Feature::GeoValues));
++ QVERIFY(!sensor.isFeatureSupported(QSensor::Feature::FieldOfView));
++ QVERIFY(!sensor.isFeatureSupported(QSensor::Feature::AccelerationMode));
++ }
++ };
++
++ QT_END_NAMESPACE
++
++ QTEST_MAIN(tst_QSensor)
++
++ #include "tst_qsensor.moc"