| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. |
| 4 | ** Contact: https://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the QtSensors module of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| 9 | ** Commercial License Usage |
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 11 | ** accordance with the commercial license agreement provided with the |
| 12 | ** Software or, alternatively, in accordance with the terms contained in |
| 13 | ** a written agreement between you and The Qt Company. For licensing terms |
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at https://www.qt.io/contact-us. |
| 16 | ** |
| 17 | ** GNU General Public License Usage |
| 18 | ** Alternatively, this file may be used under the terms of the GNU |
| 19 | ** General Public License version 3 as published by the Free Software |
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| 21 | ** included in the packaging of this file. Please review the following |
| 22 | ** information to ensure the GNU General Public License requirements will |
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| 24 | ** |
| 25 | ** $QT_END_LICENSE$ |
| 26 | ** |
| 27 | ****************************************************************************/ |
| 28 | |
| 29 | #include <QtTest/QtTest> |
| 30 | #include <QtTest/QSignalSpy> |
| 31 | #include <QtCore/QDebug> |
| 32 | |
| 33 | #include "../../../src/imports/sensors/qmlsensor.h" |
| 34 | #include "../../../src/imports/sensors/qmlsensorgesture.h" |
| 35 | |
| 36 | #include "qtemplategestureplugin.h" |
| 37 | #include "qtemplaterecognizer.h" |
| 38 | #include <qsensorgesturemanager.h> |
| 39 | #include <qsensorbackend.h> |
| 40 | #include "qsensormanager.h" |
| 41 | |
| 42 | QT_USE_NAMESPACE |
| 43 | |
| 44 | QT_BEGIN_NAMESPACE |
| 45 | |
| 46 | class tst_Sensors2QMLAPI : public QObject |
| 47 | { |
| 48 | Q_OBJECT |
| 49 | |
| 50 | private slots: |
| 51 | void initTestCase(); |
| 52 | void testGesture(); |
| 53 | void testSensorRanges(); |
| 54 | }; |
| 55 | |
| 56 | void tst_Sensors2QMLAPI::initTestCase() |
| 57 | { |
| 58 | qputenv(varName: "QT_SENSORS_LOAD_PLUGINS" , value: "0" ); // Do not load plugins |
| 59 | } |
| 60 | |
| 61 | void tst_Sensors2QMLAPI::testGesture() |
| 62 | { |
| 63 | QTemplateGesturePlugin* plugin = new QTemplateGesturePlugin(); |
| 64 | QList <QSensorGestureRecognizer *> recognizers = plugin->createRecognizers(); |
| 65 | QSensorGestureManager manager; |
| 66 | |
| 67 | QmlSensorGesture* gs = new QmlSensorGesture(this); |
| 68 | gs->componentComplete(); |
| 69 | QSignalSpy spy_availableGesturesChanged(gs, SIGNAL(availableGesturesChanged())); |
| 70 | QSignalSpy spy_detected(gs, SIGNAL(detected(QString))); |
| 71 | QSignalSpy spy_gesturesChanged(gs, SIGNAL(gesturesChanged())); |
| 72 | QSignalSpy spy_validGesturesChanged(gs, SIGNAL(validGesturesChanged())); |
| 73 | QSignalSpy spy_invalidGesturesChanged(gs, SIGNAL(invalidGesturesChanged())); |
| 74 | QSignalSpy spy_enabledChanged(gs, SIGNAL(enabledChanged())); |
| 75 | |
| 76 | //This flag is needed if you run this unit test with an alread installed template plugin |
| 77 | bool registered = false; |
| 78 | for (int i = 0; i < recognizers.count(); i++){ |
| 79 | registered = manager.registerSensorGestureRecognizer(recognizer: recognizers[i]); |
| 80 | } |
| 81 | if (registered) { |
| 82 | QCOMPARE(spy_availableGesturesChanged.count(), 2); |
| 83 | } |
| 84 | |
| 85 | //check creation of a not known plugin |
| 86 | QCOMPARE(spy_invalidGesturesChanged.count(), 0); |
| 87 | QCOMPARE(spy_gesturesChanged.count(), 0); |
| 88 | gs->setGestures(QStringList() << "lollipop" ); |
| 89 | QCOMPARE(spy_gesturesChanged.count(), 1); |
| 90 | QCOMPARE(spy_invalidGesturesChanged.count(), 1); |
| 91 | |
| 92 | //check creation of a known plugin |
| 93 | QCOMPARE(spy_validGesturesChanged.count(), 0); |
| 94 | QCOMPARE(spy_gesturesChanged.count(), 1); |
| 95 | spy_invalidGesturesChanged.clear(); |
| 96 | spy_validGesturesChanged.clear(); |
| 97 | gs->setGestures(QStringList() << "QtSensors.template" ); |
| 98 | QCOMPARE(spy_gesturesChanged.count(), 2); |
| 99 | QCOMPARE(spy_invalidGesturesChanged.count(), 1); |
| 100 | QCOMPARE(spy_validGesturesChanged.count(), 1); |
| 101 | |
| 102 | //enable "QtSensors.template" |
| 103 | QCOMPARE(spy_enabledChanged.count(), 0); |
| 104 | QCOMPARE(spy_detected.count(), 0); |
| 105 | gs->setEnabled(true); |
| 106 | QCOMPARE(spy_enabledChanged.count(), 1); |
| 107 | QCOMPARE(spy_detected.count(), 1); |
| 108 | |
| 109 | //set gesture during running sensor should not emit gesture changed |
| 110 | spy_gesturesChanged.clear(); |
| 111 | gs->setGestures(QStringList() << "QtSensors.template2" ); |
| 112 | QCOMPARE(spy_gesturesChanged.count(), 0); |
| 113 | |
| 114 | gs->setEnabled(false); |
| 115 | |
| 116 | QmlSensorGesture* gs1 = new QmlSensorGesture(this); |
| 117 | QSignalSpy spy1_detected(gs1, SIGNAL(detected(QString))); |
| 118 | QSignalSpy spy1_gesturesChanged(gs1, SIGNAL(gesturesChanged())); |
| 119 | QSignalSpy spy1_validGesturesChanged(gs1, SIGNAL(validGesturesChanged())); |
| 120 | QSignalSpy spy1_invalidGesturesChanged(gs1, SIGNAL(invalidGesturesChanged())); |
| 121 | QSignalSpy spy1_enabledChanged(gs1, SIGNAL(enabledChanged())); |
| 122 | gs1->componentComplete(); |
| 123 | |
| 124 | //set enable = true without gesture should |
| 125 | gs1->setEnabled(true); |
| 126 | QCOMPARE(spy1_enabledChanged.count(), 1); |
| 127 | gs1->setEnabled(false); |
| 128 | spy1_enabledChanged.clear(); |
| 129 | |
| 130 | //reding gestures check if we get back an empty string list |
| 131 | QStringList gestures = gs1->gestures(); |
| 132 | QCOMPARE(gestures.count(), 0); |
| 133 | QStringList validgestures = gs1->validGestures(); |
| 134 | QCOMPARE(validgestures.count(), 0); |
| 135 | QStringList invalidgestures = gs1->invalidGestures(); |
| 136 | QCOMPARE(invalidgestures.count(), 0); |
| 137 | |
| 138 | //check types "QtSensors.template" "QtSensors.template1" "lollipop" |
| 139 | //expect valid 2 not available 1 |
| 140 | gestures << "QtSensors.template" << "QtSensors.template1" << "lollipop" ; |
| 141 | gs1->setGestures(gestures); |
| 142 | gestures = gs1->gestures(); |
| 143 | QCOMPARE(gestures.count(), 3); |
| 144 | QCOMPARE(spy1_validGesturesChanged.count(), 1); |
| 145 | QCOMPARE(spy1_invalidGesturesChanged.count(), 1); |
| 146 | QCOMPARE(spy1_gesturesChanged.count(), 1); |
| 147 | //set same gesture again should not emit gesture changed |
| 148 | gs1->setGestures(gestures); |
| 149 | QCOMPARE(spy1_gesturesChanged.count(), 1); |
| 150 | |
| 151 | spy1_gesturesChanged.clear(); |
| 152 | gestures.clear(); |
| 153 | gs1->setGestures(gestures); |
| 154 | QCOMPARE(spy1_gesturesChanged.count(), 1); |
| 155 | |
| 156 | //enable "QtSensors.template" and "QtSensors.template1" |
| 157 | gestures << "QtSensors.template" << "QtSensors.template1" ; |
| 158 | gs1->setEnabled(false); |
| 159 | gs1->setGestures(gestures); |
| 160 | spy1_enabledChanged.clear(); |
| 161 | spy1_detected.clear(); |
| 162 | gs1->setEnabled(true); |
| 163 | QCOMPARE(spy1_enabledChanged.count(), 1); |
| 164 | QCOMPARE(spy1_detected.count(), 2); |
| 165 | gs1->setEnabled(false); |
| 166 | |
| 167 | //check sensor shouldn't run until the componentComplete gets called |
| 168 | QmlSensorGesture* gs2 = new QmlSensorGesture(this); |
| 169 | QSignalSpy spy2_detected(gs2, SIGNAL(detected(QString))); |
| 170 | gs2->setGestures(QStringList() << "QtSensors.template" ); |
| 171 | gs2->setEnabled(true); |
| 172 | QCOMPARE(spy2_detected.count(), 0); |
| 173 | gs2->componentComplete(); |
| 174 | QCOMPARE(spy2_detected.count(), 1); |
| 175 | } |
| 176 | |
| 177 | class QDummySensorBackend : public QSensorBackend |
| 178 | { |
| 179 | Q_OBJECT |
| 180 | public: |
| 181 | QDummySensorBackend(QSensor *sensor) : QSensorBackend(sensor) |
| 182 | { |
| 183 | addDataRate(min: 2, max: 3); |
| 184 | addDataRate(min: 5, max: 7); |
| 185 | addOutputRange(min: 100, max: 200, accuracy: 1); |
| 186 | addOutputRange(min: 600, max: 700, accuracy: 10); |
| 187 | addOutputRange(min: 0, max: 1, accuracy: 2); |
| 188 | } |
| 189 | |
| 190 | void start() override {} |
| 191 | void stop() override {} |
| 192 | }; |
| 193 | |
| 194 | class QDummySensorReading : public QSensorReading |
| 195 | { |
| 196 | Q_OBJECT |
| 197 | public: |
| 198 | QDummySensorReading(QObject *parent) : QSensorReading(parent, nullptr) {} |
| 199 | }; |
| 200 | |
| 201 | class QmlDummySensorReading : public QmlSensorReading |
| 202 | { |
| 203 | Q_OBJECT |
| 204 | public: |
| 205 | QmlDummySensorReading(QSensor *sensor) : |
| 206 | QmlSensorReading(sensor), |
| 207 | m_reading(new QDummySensorReading(this)) |
| 208 | {} |
| 209 | |
| 210 | QSensorReading *reading() const override { return m_reading; } |
| 211 | void readingUpdate() override {} |
| 212 | |
| 213 | private: |
| 214 | QSensorReading *m_reading = nullptr; |
| 215 | }; |
| 216 | |
| 217 | class QmlDummySensor : public QmlSensor |
| 218 | { |
| 219 | Q_OBJECT |
| 220 | public: |
| 221 | QmlDummySensor(QObject *parent = nullptr) : |
| 222 | QmlSensor(parent), |
| 223 | m_sensor(new QSensor("dummy" , this)) |
| 224 | { |
| 225 | QDummySensorBackend b(m_sensor); |
| 226 | Q_UNUSED(b); |
| 227 | } |
| 228 | |
| 229 | QSensor *sensor() const override { return m_sensor; } |
| 230 | QmlSensorReading *createReading() const override { return new QmlDummySensorReading(m_sensor); } |
| 231 | |
| 232 | void componentComplete() override { QmlSensor::componentComplete(); } |
| 233 | |
| 234 | private: |
| 235 | QSensor *m_sensor = nullptr; |
| 236 | }; |
| 237 | |
| 238 | void tst_Sensors2QMLAPI::testSensorRanges() |
| 239 | { |
| 240 | QScopedPointer<QmlDummySensor> qmlSensor(new QmlDummySensor); |
| 241 | qmlSensor->componentComplete(); |
| 242 | |
| 243 | auto ranges = qmlSensor->availableDataRates(); |
| 244 | QCOMPARE(ranges.count(&ranges), 2); |
| 245 | |
| 246 | const auto range0 = ranges.at(&ranges, 0); |
| 247 | QCOMPARE(range0->minimum(), 2); |
| 248 | QCOMPARE(range0->maximum(), 3); |
| 249 | QSignalSpy range0Spy(range0, SIGNAL(destroyed())); |
| 250 | |
| 251 | const auto range1 = ranges.at(&ranges, 1); |
| 252 | QCOMPARE(range1->minimum(), 5); |
| 253 | QCOMPARE(range1->maximum(), 7); |
| 254 | QSignalSpy range1Spy(range1, SIGNAL(destroyed())); |
| 255 | |
| 256 | auto outputs = qmlSensor->outputRanges(); |
| 257 | QCOMPARE(outputs.count(&outputs), 3); |
| 258 | |
| 259 | const auto output0 = outputs.at(&outputs, 0); |
| 260 | QCOMPARE(output0->minimum(), 100); |
| 261 | QCOMPARE(output0->maximum(), 200); |
| 262 | QCOMPARE(output0->accuracy(), 1); |
| 263 | QSignalSpy output0Spy(output0, SIGNAL(destroyed())); |
| 264 | |
| 265 | const auto output1 = outputs.at(&outputs, 1); |
| 266 | QCOMPARE(output1->minimum(), 600); |
| 267 | QCOMPARE(output1->maximum(), 700); |
| 268 | QCOMPARE(output1->accuracy(), 10); |
| 269 | QSignalSpy output1Spy(output1, SIGNAL(destroyed())); |
| 270 | |
| 271 | const auto output2 = outputs.at(&outputs, 2); |
| 272 | QCOMPARE(output2->minimum(), 0); |
| 273 | QCOMPARE(output2->maximum(), 1); |
| 274 | QCOMPARE(output2->accuracy(), 2); |
| 275 | QSignalSpy output2Spy(output2, SIGNAL(destroyed())); |
| 276 | |
| 277 | qmlSensor.reset(); |
| 278 | QCOMPARE(range0Spy.count(), 1); |
| 279 | QCOMPARE(range1Spy.count(), 1); |
| 280 | QCOMPARE(output0Spy.count(), 1); |
| 281 | QCOMPARE(output1Spy.count(), 1); |
| 282 | QCOMPARE(output2Spy.count(), 1); |
| 283 | } |
| 284 | |
| 285 | QT_END_NAMESPACE |
| 286 | |
| 287 | QTEST_MAIN(tst_Sensors2QMLAPI) |
| 288 | #include "tst_sensors2qmlapi.moc" |
| 289 | |