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 test suite 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 | //TESTED_COMPONENT=src/location |
30 | |
31 | #include <QTest> |
32 | #include <QMetaType> |
33 | #include <QSignalSpy> |
34 | |
35 | #include <limits.h> |
36 | #include <float.h> |
37 | |
38 | #include <QDebug> |
39 | #include <QDataStream> |
40 | |
41 | #include <QtPositioning/qgeoareamonitorinfo.h> |
42 | #include <QtPositioning/qgeoareamonitorsource.h> |
43 | #include <QtPositioning/qgeopositioninfo.h> |
44 | #include <QtPositioning/qgeopositioninfosource.h> |
45 | #include <QtPositioning/qnmeapositioninfosource.h> |
46 | #include <QtPositioning/qgeocircle.h> |
47 | #include <QtPositioning/qgeorectangle.h> |
48 | |
49 | #include "logfilepositionsource.h" |
50 | |
51 | |
52 | QT_USE_NAMESPACE |
53 | #define UPDATE_INTERVAL 200 |
54 | |
55 | Q_DECLARE_METATYPE(QGeoAreaMonitorInfo) |
56 | |
57 | QString tst_qgeoareamonitorinfo_debug; |
58 | |
59 | void tst_qgeoareamonitorinfo_messageHandler(QtMsgType type, |
60 | const QMessageLogContext &, |
61 | const QString &msg) |
62 | { |
63 | switch (type) { |
64 | case QtDebugMsg : |
65 | tst_qgeoareamonitorinfo_debug = msg; |
66 | break; |
67 | default: |
68 | break; |
69 | } |
70 | } |
71 | |
72 | class tst_QGeoAreaMonitorSource : public QObject |
73 | { |
74 | Q_OBJECT |
75 | |
76 | private slots: |
77 | void initTestCase() |
78 | { |
79 | #if QT_CONFIG(library) |
80 | /* |
81 | * Set custom path since CI doesn't install plugins |
82 | */ |
83 | #ifdef Q_OS_WIN |
84 | QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath() + |
85 | QStringLiteral("/../../../../plugins" )); |
86 | #else |
87 | QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath() |
88 | + QStringLiteral("/../../../plugins" )); |
89 | #endif |
90 | #endif |
91 | qRegisterMetaType<QGeoAreaMonitorInfo>(); |
92 | } |
93 | |
94 | void init() |
95 | { |
96 | } |
97 | |
98 | void cleanup() |
99 | { |
100 | QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent: 0); |
101 | QVERIFY(obj != 0); |
102 | QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll" )); |
103 | |
104 | QList<QGeoAreaMonitorInfo> list = obj->activeMonitors(); |
105 | if (list.count() > 0) { |
106 | //cleanup installed monitors |
107 | foreach (const QGeoAreaMonitorInfo& info, list) { |
108 | QVERIFY(obj->stopMonitoring(info)); |
109 | } |
110 | } |
111 | QVERIFY(obj->activeMonitors().count() == 0); |
112 | } |
113 | |
114 | void cleanupTestCase() |
115 | { |
116 | } |
117 | |
118 | void tst_monitor() |
119 | { |
120 | QGeoAreaMonitorInfo defaultMonitor; |
121 | QVERIFY(defaultMonitor.name().isEmpty()); |
122 | QVERIFY(!defaultMonitor.identifier().isEmpty()); |
123 | QCOMPARE(defaultMonitor.isPersistent(), false); |
124 | QVERIFY(!defaultMonitor.area().isValid()); |
125 | QVERIFY(!defaultMonitor.isValid()); |
126 | QCOMPARE(defaultMonitor.expiration(), QDateTime()); |
127 | QCOMPARE(defaultMonitor.notificationParameters(), QVariantMap()); |
128 | |
129 | QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent: 0); |
130 | QVERIFY(obj != 0); |
131 | QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll" )); |
132 | QVERIFY(!obj->startMonitoring(defaultMonitor)); |
133 | QCOMPARE(obj->activeMonitors().count(), 0); |
134 | QVERIFY(!obj->requestUpdate(defaultMonitor, |
135 | SIGNAL(areaEntered(QGeoMonitorInfo,QGeoAreaPositionInfo)))); |
136 | delete obj; |
137 | |
138 | //copy constructor based |
139 | QGeoAreaMonitorInfo copy(defaultMonitor); |
140 | QVERIFY(copy.name().isEmpty()); |
141 | QCOMPARE(copy.identifier(), defaultMonitor.identifier()); |
142 | QVERIFY(copy == defaultMonitor); |
143 | QVERIFY(!(copy != defaultMonitor)); |
144 | QCOMPARE(copy.isPersistent(), false); |
145 | |
146 | copy.setName(QString("my name" )); |
147 | QCOMPARE(copy.name(), QString("my name" )); |
148 | |
149 | |
150 | QDateTime now = QDateTime::currentDateTime().addSecs(secs: 1000); //little bit in the future |
151 | copy.setExpiration(now); |
152 | QVERIFY(copy != defaultMonitor); |
153 | QCOMPARE(copy.expiration(), now); |
154 | |
155 | QCOMPARE(copy.isPersistent(), defaultMonitor.isPersistent()); |
156 | copy.setPersistent(true); |
157 | QCOMPARE(copy.isPersistent(), true); |
158 | QCOMPARE(defaultMonitor.isPersistent(), false); |
159 | copy.setPersistent(false); |
160 | |
161 | QVERIFY(copy.area() == defaultMonitor.area()); |
162 | QVERIFY(!copy.area().isValid()); |
163 | copy.setArea(QGeoCircle(QGeoCoordinate(1, 2), 4)); |
164 | QVERIFY(copy.area().isValid()); |
165 | QVERIFY(copy.area() != defaultMonitor.area()); |
166 | QVERIFY(copy.area().contains(QGeoCoordinate(1, 2))); |
167 | |
168 | QVERIFY(copy.notificationParameters().isEmpty()); |
169 | QVariantMap map; |
170 | map.insert(akey: QString("MyKey" ), avalue: QVariant(123)); |
171 | copy.setNotificationParameters(map); |
172 | QVERIFY(!copy.notificationParameters().isEmpty()); |
173 | QCOMPARE(copy.notificationParameters().value(QString("MyKey" )).toInt(), 123); |
174 | QCOMPARE(defaultMonitor.notificationParameters().value(QString("MyKey" )).toInt(), 0); |
175 | |
176 | QCOMPARE(defaultMonitor.identifier(), copy.identifier()); |
177 | |
178 | //assignment operator based |
179 | QGeoAreaMonitorInfo assignmentCopy; |
180 | assignmentCopy = copy; |
181 | QVERIFY(copy == assignmentCopy); |
182 | QVERIFY(assignmentCopy != defaultMonitor); |
183 | |
184 | QVERIFY(assignmentCopy.area().contains(QGeoCoordinate(1, 2))); |
185 | QCOMPARE(assignmentCopy.expiration(), now); |
186 | QCOMPARE(assignmentCopy.isPersistent(), false); |
187 | QCOMPARE(assignmentCopy.notificationParameters().value(QString("MyKey" )).toInt(), 123); |
188 | QCOMPARE(defaultMonitor.identifier(), assignmentCopy.identifier()); |
189 | QCOMPARE(assignmentCopy.name(), QString("my name" )); |
190 | |
191 | //validity checks for requestUpdate() |
192 | obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent: 0); |
193 | QVERIFY(obj != 0); |
194 | QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll" )); |
195 | QCOMPARE(obj->activeMonitors().count(), 0); |
196 | //reference -> should work |
197 | QVERIFY(obj->requestUpdate(copy, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo)))); |
198 | QCOMPARE(obj->activeMonitors().count(), 1); |
199 | //replaces areaEntered single shot |
200 | QVERIFY(obj->requestUpdate(copy, SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo)))); |
201 | QCOMPARE(obj->activeMonitors().count(), 1); |
202 | //replaces areaExited single shot |
203 | QVERIFY(obj->startMonitoring(copy)); |
204 | QCOMPARE(obj->activeMonitors().count(), 1); |
205 | |
206 | |
207 | //invalid signal |
208 | QVERIFY(!obj->requestUpdate(copy, 0)); |
209 | QCOMPARE(obj->activeMonitors().count(), 1); |
210 | |
211 | //signal that doesn't exist |
212 | QVERIFY(!obj->requestUpdate(copy, SIGNAL(areaEntered(QGeoMonitor)))); |
213 | QCOMPARE(obj->activeMonitors().count(), 1); |
214 | |
215 | QVERIFY(!obj->requestUpdate(copy, "SIGNAL(areaEntered(QGeoMonitor))" )); |
216 | QCOMPARE(obj->activeMonitors().count(), 1); |
217 | |
218 | //ensure that we cannot add a persistent monitor to a source |
219 | //that doesn't support persistence |
220 | QGeoAreaMonitorInfo persistenceMonitor(copy); |
221 | persistenceMonitor.setPersistent(obj->supportedAreaMonitorFeatures() & QGeoAreaMonitorSource::PersistentAreaMonitorFeature); |
222 | persistenceMonitor.setPersistent(!persistenceMonitor.isPersistent()); |
223 | |
224 | QVERIFY(!obj->requestUpdate(persistenceMonitor, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo)))); |
225 | QCOMPARE(obj->activeMonitors().count(), 1); |
226 | QVERIFY(!obj->startMonitoring(persistenceMonitor)); |
227 | QCOMPARE(obj->activeMonitors().count(), 1); |
228 | |
229 | //ensure that persistence was only reason for rejection |
230 | persistenceMonitor.setPersistent(!persistenceMonitor.isPersistent()); |
231 | QVERIFY(obj->startMonitoring(persistenceMonitor)); |
232 | //persistenceMonitor is copy of already added monitor |
233 | //the last call was an update |
234 | QCOMPARE(obj->activeMonitors().count(), 1); |
235 | |
236 | delete obj; |
237 | } |
238 | |
239 | void tst_monitorValid() |
240 | { |
241 | QGeoAreaMonitorInfo mon; |
242 | QVERIFY(!mon.isValid()); |
243 | QCOMPARE(mon.name(), QString()); |
244 | QCOMPARE(mon.area().isValid(), false); |
245 | |
246 | QGeoAreaMonitorInfo mon2 = mon; |
247 | QVERIFY(!mon2.isValid()); |
248 | |
249 | QGeoShape invalidShape; |
250 | QGeoCircle emptyCircle(QGeoCoordinate(0,1), 0); |
251 | QGeoCircle validCircle(QGeoCoordinate(0,1), 1); |
252 | |
253 | //all invalid since no name set yet |
254 | mon2.setArea(invalidShape); |
255 | QVERIFY(mon2.area() == invalidShape); |
256 | QVERIFY(!mon2.isValid()); |
257 | |
258 | mon2.setArea(emptyCircle); |
259 | QVERIFY(mon2.area() == emptyCircle); |
260 | QVERIFY(!mon2.isValid()); |
261 | |
262 | mon2.setArea(validCircle); |
263 | QVERIFY(mon2.area() == validCircle); |
264 | QVERIFY(!mon2.isValid()); |
265 | |
266 | //valid since name and non-empy shape has been set |
267 | QGeoAreaMonitorInfo validMonitor("TestMonitor" ); |
268 | QVERIFY(validMonitor.name() == QString("TestMonitor" )); |
269 | QVERIFY(!validMonitor.isValid()); |
270 | |
271 | validMonitor.setArea(invalidShape); |
272 | QVERIFY(validMonitor.area() == invalidShape); |
273 | QVERIFY(!validMonitor.isValid()); |
274 | |
275 | validMonitor.setArea(emptyCircle); |
276 | QVERIFY(validMonitor.area() == emptyCircle); |
277 | QVERIFY(!validMonitor.isValid()); |
278 | |
279 | validMonitor.setArea(validCircle); |
280 | QVERIFY(validCircle == validMonitor.area()); |
281 | QVERIFY(validMonitor.isValid()); |
282 | } |
283 | |
284 | void tst_monitorStreaming() |
285 | { |
286 | QByteArray container; |
287 | QDataStream stream(&container, QIODevice::ReadWrite); |
288 | |
289 | QGeoAreaMonitorInfo monitor("someName" ); |
290 | monitor.setArea(QGeoCircle(QGeoCoordinate(1,3), 5.4)); |
291 | QVERIFY(monitor.isValid()); |
292 | QCOMPARE(monitor.name(), QString("someName" )); |
293 | |
294 | QGeoAreaMonitorInfo target; |
295 | QVERIFY(!target.isValid()); |
296 | QVERIFY(target.name().isEmpty()); |
297 | |
298 | QVERIFY(target != monitor); |
299 | |
300 | stream << monitor; |
301 | stream.device()->seek(pos: 0); |
302 | stream >> target; |
303 | |
304 | QVERIFY(target == monitor); |
305 | QVERIFY(target.isValid()); |
306 | QCOMPARE(target.name(), QString("someName" )); |
307 | QVERIFY(target.area() == QGeoCircle(QGeoCoordinate(1,3), 5.4)); |
308 | } |
309 | |
310 | void tst_createDefaultSource() |
311 | { |
312 | QObject* parent = new QObject; |
313 | QGeoAreaMonitorSource* obj = QGeoAreaMonitorSource::createDefaultSource(parent); |
314 | QVERIFY(obj != 0); |
315 | QVERIFY(obj->parent() == parent); |
316 | delete obj; |
317 | |
318 | const QStringList monitors = QGeoAreaMonitorSource::availableSources(); |
319 | QVERIFY(!monitors.isEmpty()); |
320 | QVERIFY(monitors.contains(QStringLiteral("positionpoll" ))); |
321 | |
322 | obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent); |
323 | QVERIFY(obj != 0); |
324 | QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll" )); |
325 | delete parent; |
326 | |
327 | obj = QGeoAreaMonitorSource::createSource(QStringLiteral("randomNonExistingName" ), parent: 0); |
328 | QVERIFY(obj == 0); |
329 | } |
330 | |
331 | void tst_activeMonitors() |
332 | { |
333 | QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent: 0); |
334 | QVERIFY(obj != 0); |
335 | QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll" )); |
336 | |
337 | LogFilePositionSource *source = new LogFilePositionSource(this); |
338 | source->setUpdateInterval(UPDATE_INTERVAL); |
339 | obj->setPositionInfoSource(source); |
340 | QCOMPARE(obj->positionInfoSource(), source); |
341 | |
342 | |
343 | QVERIFY(obj->activeMonitors().isEmpty()); |
344 | |
345 | QGeoAreaMonitorInfo mon("Monitor_Circle" ); |
346 | mon.setArea(QGeoCircle(QGeoCoordinate(1,1), 1000)); |
347 | QVERIFY(obj->startMonitoring(mon)); |
348 | |
349 | QGeoAreaMonitorInfo mon2("Monitor_rectangle_below" ); |
350 | QGeoRectangle r_below(QGeoCoordinate(1,1),2,2); |
351 | mon2.setArea(r_below); |
352 | QVERIFY(obj->startMonitoring(mon2)); |
353 | |
354 | QGeoAreaMonitorInfo mon3("Monitor_rectangle_above" ); |
355 | QGeoRectangle r_above(QGeoCoordinate(2,1),2,2); |
356 | mon3.setArea(r_above); |
357 | QVERIFY(obj->startMonitoring(mon3)); |
358 | |
359 | QList<QGeoAreaMonitorInfo> results = obj->activeMonitors(); |
360 | QCOMPARE(results.count(), 3); |
361 | foreach (const QGeoAreaMonitorInfo& info, results) { |
362 | QVERIFY(info == mon || info == mon2 || info == mon3); |
363 | } |
364 | |
365 | results = obj->activeMonitors(lookupArea: QGeoShape()); |
366 | QCOMPARE(results.count(), 0); |
367 | |
368 | results = obj->activeMonitors(lookupArea: QGeoRectangle(QGeoCoordinate(1,1),0.2, 0.2)); |
369 | QCOMPARE(results.count(), 2); |
370 | foreach (const QGeoAreaMonitorInfo& info, results) { |
371 | QVERIFY(info == mon || info == mon2); |
372 | } |
373 | |
374 | results = obj->activeMonitors(lookupArea: QGeoCircle(QGeoCoordinate(1,1),1000)); |
375 | QCOMPARE(results.count(), 2); |
376 | foreach (const QGeoAreaMonitorInfo& info, results) { |
377 | QVERIFY(info == mon || info == mon2); |
378 | } |
379 | |
380 | results = obj->activeMonitors(lookupArea: QGeoCircle(QGeoCoordinate(2,1),1000)); |
381 | QCOMPARE(results.count(), 1); |
382 | foreach (const QGeoAreaMonitorInfo& info, results) { |
383 | QVERIFY(info == mon3); |
384 | } |
385 | |
386 | //same as above except that we use a different monitor source object instance |
387 | //all monitor objects of same type share same active monitors |
388 | QGeoAreaMonitorSource *secondObj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent: 0); |
389 | QVERIFY(secondObj != 0); |
390 | QCOMPARE(secondObj->sourceName(), QStringLiteral("positionpoll" )); |
391 | |
392 | results = secondObj->activeMonitors(); |
393 | QCOMPARE(results.count(), 3); |
394 | foreach (const QGeoAreaMonitorInfo& info, results) { |
395 | QVERIFY(info == mon || info == mon2 || info == mon3); |
396 | } |
397 | |
398 | results = secondObj->activeMonitors(lookupArea: QGeoShape()); |
399 | QCOMPARE(results.count(), 0); |
400 | |
401 | results = secondObj->activeMonitors(lookupArea: QGeoRectangle(QGeoCoordinate(1,1),0.2, 0.2)); |
402 | QCOMPARE(results.count(), 2); |
403 | foreach (const QGeoAreaMonitorInfo& info, results) { |
404 | QVERIFY(info == mon || info == mon2); |
405 | } |
406 | |
407 | results = secondObj->activeMonitors(lookupArea: QGeoCircle(QGeoCoordinate(1,1),1000)); |
408 | QCOMPARE(results.count(), 2); |
409 | foreach (const QGeoAreaMonitorInfo& info, results) { |
410 | QVERIFY(info == mon || info == mon2); |
411 | } |
412 | |
413 | results = secondObj->activeMonitors(lookupArea: QGeoCircle(QGeoCoordinate(2,1),1000)); |
414 | QCOMPARE(results.count(), 1); |
415 | foreach (const QGeoAreaMonitorInfo& info, results) { |
416 | QVERIFY(info == mon3); |
417 | } |
418 | |
419 | delete obj; |
420 | delete secondObj; |
421 | } |
422 | |
423 | void tst_testExpiryTimeout() |
424 | { |
425 | QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent: 0); |
426 | QVERIFY(obj != 0); |
427 | QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll" )); |
428 | |
429 | QGeoAreaMonitorSource *secondObj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent: 0); |
430 | QVERIFY(secondObj != 0); |
431 | QCOMPARE(secondObj->sourceName(), QStringLiteral("positionpoll" )); |
432 | |
433 | LogFilePositionSource *source = new LogFilePositionSource(this); |
434 | source->setUpdateInterval(UPDATE_INTERVAL); |
435 | obj->setPositionInfoSource(source); |
436 | |
437 | //Singleton pattern behind QGeoAreaMonitorSource ensures same position info source |
438 | QCOMPARE(obj->positionInfoSource(), source); |
439 | QCOMPARE(secondObj->positionInfoSource(), source); |
440 | |
441 | QSignalSpy expirySpy(obj, SIGNAL(monitorExpired(QGeoAreaMonitorInfo))); |
442 | QSignalSpy expirySpy2(secondObj, SIGNAL(monitorExpired(QGeoAreaMonitorInfo))); |
443 | |
444 | QDateTime now = QDateTime::currentDateTime(); |
445 | |
446 | const int monitorCount = 4; |
447 | for (int i = 1; i <= monitorCount; i++) { |
448 | QGeoAreaMonitorInfo mon(QString::number(i)); |
449 | mon.setArea(QGeoRectangle(QGeoCoordinate(i,i), i, i)); |
450 | mon.setExpiration(now.addSecs(secs: i*5)); |
451 | QVERIFY(mon.isValid()); |
452 | QVERIFY(obj->startMonitoring(mon)); |
453 | } |
454 | |
455 | |
456 | |
457 | QCOMPARE(obj->activeMonitors().count(), monitorCount); |
458 | QCOMPARE(secondObj->activeMonitors().count(), monitorCount); |
459 | |
460 | QGeoAreaMonitorInfo info("InvalidExpiry" ); |
461 | info.setArea(QGeoRectangle(QGeoCoordinate(10,10), 1, 1 )); |
462 | QVERIFY(info.isValid()); |
463 | info.setExpiration(now.addSecs(secs: -1000)); |
464 | QVERIFY(info.expiration() < now); |
465 | QVERIFY(!obj->startMonitoring(info)); |
466 | QCOMPARE(obj->activeMonitors().count(), monitorCount); |
467 | QVERIFY(!obj->requestUpdate(info, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo)))); |
468 | QCOMPARE(obj->activeMonitors().count(), monitorCount); |
469 | |
470 | for (int i = 1; i <= monitorCount; i++) { |
471 | QTRY_VERIFY_WITH_TIMEOUT(expirySpy.count() == 1, 7000); //each expiry within 5 s |
472 | QGeoAreaMonitorInfo mon = expirySpy.takeFirst().at(i: 0).value<QGeoAreaMonitorInfo>(); |
473 | QCOMPARE(obj->activeMonitors().count(), monitorCount-i); |
474 | QCOMPARE(mon.name(), QString::number(i)); |
475 | } |
476 | |
477 | QCOMPARE(expirySpy2.count(), monitorCount); |
478 | QCOMPARE(secondObj->activeMonitors().count(), 0); //all monitors expired |
479 | for (int i = 1; i <= monitorCount; i++) { |
480 | QGeoAreaMonitorInfo mon = expirySpy2.takeFirst().at(i: 0).value<QGeoAreaMonitorInfo>(); |
481 | QCOMPARE(mon.name(), QString::number(i)); |
482 | } |
483 | |
484 | delete obj; |
485 | delete secondObj; |
486 | } |
487 | |
488 | void tst_enteredExitedSignal() |
489 | { |
490 | QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent: 0); |
491 | QVERIFY(obj != 0); |
492 | QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll" )); |
493 | obj->setObjectName("firstObject" ); |
494 | QSignalSpy enteredSpy(obj, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo))); |
495 | QSignalSpy exitedSpy(obj, SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo))); |
496 | |
497 | LogFilePositionSource *source = new LogFilePositionSource(this); |
498 | source->setUpdateInterval(UPDATE_INTERVAL); |
499 | obj->setPositionInfoSource(source); |
500 | QCOMPARE(obj->positionInfoSource(), source); |
501 | |
502 | QGeoAreaMonitorSource *secondObj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent: 0); |
503 | QVERIFY(secondObj != 0); |
504 | QCOMPARE(secondObj->sourceName(), QStringLiteral("positionpoll" )); |
505 | QSignalSpy enteredSpy2(secondObj, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo))); |
506 | QSignalSpy exitedSpy2(secondObj, SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo))); |
507 | secondObj->setObjectName("secondObject" ); |
508 | |
509 | QGeoAreaMonitorInfo infoRectangle("Rectangle" ); |
510 | infoRectangle.setArea(QGeoRectangle(QGeoCoordinate(-27.65, 153.093), 0.2, 0.2)); |
511 | QVERIFY(infoRectangle.isValid()); |
512 | QVERIFY(obj->startMonitoring(infoRectangle)); |
513 | |
514 | QGeoAreaMonitorInfo infoCircle("Circle" ); |
515 | infoCircle.setArea(QGeoCircle(QGeoCoordinate(-27.70, 153.093),10000)); |
516 | QVERIFY(infoCircle.isValid()); |
517 | QVERIFY(obj->startMonitoring(infoCircle)); |
518 | |
519 | QGeoAreaMonitorInfo singleShot_enter("SingleShot_on_Entered" ); |
520 | singleShot_enter.setArea(QGeoRectangle(QGeoCoordinate(-27.67, 153.093), 0.2, 0.2)); |
521 | QVERIFY(singleShot_enter.isValid()); |
522 | QVERIFY(obj->requestUpdate(singleShot_enter, |
523 | SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo)))); |
524 | |
525 | QGeoAreaMonitorInfo singleShot_exit("SingleShot_on_Exited" ); |
526 | singleShot_exit.setArea(QGeoRectangle(QGeoCoordinate(-27.70, 153.093), 0.2, 0.2)); |
527 | QVERIFY(singleShot_exit.isValid()); |
528 | QVERIFY(obj->requestUpdate(singleShot_exit, |
529 | SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo)))); |
530 | |
531 | QVERIFY(obj->activeMonitors().count() == 4); //all monitors active |
532 | QVERIFY(secondObj->activeMonitors().count() == 4); //all monitors active |
533 | |
534 | static const int Number_Of_Entered_Events = 6; |
535 | static const int Number_Of_Exited_Events = 5; |
536 | //takes 87 (lines)*200(timeout)/1000 seconds to finish |
537 | QTRY_VERIFY_WITH_TIMEOUT(enteredSpy.count() == Number_Of_Entered_Events, 20000); |
538 | QTRY_VERIFY_WITH_TIMEOUT(exitedSpy.count() == Number_Of_Exited_Events, 20000); |
539 | QCOMPARE(enteredSpy.count(), Number_Of_Entered_Events); |
540 | QCOMPARE(exitedSpy.count(), Number_Of_Exited_Events); |
541 | |
542 | QList<QGeoAreaMonitorInfo> monitorsInExpectedEnteredEventOrder; |
543 | monitorsInExpectedEnteredEventOrder << infoRectangle << singleShot_enter << singleShot_exit |
544 | << infoCircle << infoCircle << infoRectangle; |
545 | |
546 | QList<QGeoAreaMonitorInfo> monitorsInExpectedExitedEventOrder; |
547 | monitorsInExpectedExitedEventOrder << infoRectangle << infoCircle |
548 | << singleShot_exit << infoCircle << infoRectangle; |
549 | |
550 | QList<QGeoCoordinate> enteredEventCoordinateOrder; |
551 | enteredEventCoordinateOrder << QGeoCoordinate(-27.55, 153.090718) //infoRectangle |
552 | << QGeoCoordinate(-27.57, 153.090718) //singleshot_enter |
553 | << QGeoCoordinate(-27.60, 153.090908) //singleshot_exit |
554 | << QGeoCoordinate(-27.62, 153.091036) //infoCircle |
555 | << QGeoCoordinate(-27.78, 153.093647) //infoCircle |
556 | << QGeoCoordinate(-27.75, 153.093896);//infoRectangle |
557 | QCOMPARE(enteredEventCoordinateOrder.count(), Number_Of_Entered_Events); |
558 | QCOMPARE(monitorsInExpectedEnteredEventOrder.count(), Number_Of_Entered_Events); |
559 | |
560 | QList<QGeoCoordinate> exitedEventCoordinateOrder; |
561 | exitedEventCoordinateOrder << QGeoCoordinate(-27.78, 153.092218) //infoRectangle |
562 | << QGeoCoordinate(-27.79, 153.092308) //infoCircle |
563 | << QGeoCoordinate(-27.81, 153.092530) //singleshot_exit |
564 | << QGeoCoordinate(-27.61, 153.095231) //infoCircle |
565 | << QGeoCoordinate(-27.54, 153.095995);//infoCircle |
566 | QCOMPARE(exitedEventCoordinateOrder.count(), Number_Of_Exited_Events); |
567 | QCOMPARE(monitorsInExpectedExitedEventOrder.count(), Number_Of_Exited_Events); |
568 | |
569 | //verify that both sources got the same signals |
570 | for (int i = 0; i < Number_Of_Entered_Events; i++) { |
571 | //first source |
572 | QGeoAreaMonitorInfo monInfo = enteredSpy.first().at(i: 0).value<QGeoAreaMonitorInfo>(); |
573 | QGeoPositionInfo posInfo = enteredSpy.takeFirst().at(i: 1).value<QGeoPositionInfo>(); |
574 | QVERIFY2(monInfo == monitorsInExpectedEnteredEventOrder.at(i), |
575 | qPrintable(QString::number(i) + ": " + monInfo.name())); |
576 | QVERIFY2(posInfo.coordinate() == enteredEventCoordinateOrder.at(i), |
577 | qPrintable(QString::number(i) + ". posInfo" )); |
578 | |
579 | //reset info objects to avoid comparing the same |
580 | monInfo = QGeoAreaMonitorInfo(); |
581 | posInfo = QGeoPositionInfo(); |
582 | |
583 | //second source |
584 | monInfo = enteredSpy2.first().at(i: 0).value<QGeoAreaMonitorInfo>(); |
585 | posInfo = enteredSpy2.takeFirst().at(i: 1).value<QGeoPositionInfo>(); |
586 | QVERIFY2(monInfo == monitorsInExpectedEnteredEventOrder.at(i), |
587 | qPrintable(QString::number(i) + ": " + monInfo.name())); |
588 | QVERIFY2(posInfo.coordinate() == enteredEventCoordinateOrder.at(i), |
589 | qPrintable(QString::number(i) + ". posInfo" )); |
590 | } |
591 | |
592 | for (int i = 0; i < Number_Of_Exited_Events; i++) { |
593 | //first source |
594 | QGeoAreaMonitorInfo monInfo = exitedSpy.first().at(i: 0).value<QGeoAreaMonitorInfo>(); |
595 | QGeoPositionInfo posInfo = exitedSpy.takeFirst().at(i: 1).value<QGeoPositionInfo>(); |
596 | QVERIFY2(monInfo == monitorsInExpectedExitedEventOrder.at(i), |
597 | qPrintable(QString::number(i) + ": " + monInfo.name())); |
598 | QVERIFY2(posInfo.coordinate() == exitedEventCoordinateOrder.at(i), |
599 | qPrintable(QString::number(i) + ". posInfo" )); |
600 | |
601 | //reset info objects to avoid comparing the same |
602 | monInfo = QGeoAreaMonitorInfo(); |
603 | posInfo = QGeoPositionInfo(); |
604 | |
605 | //second source |
606 | monInfo = exitedSpy2.first().at(i: 0).value<QGeoAreaMonitorInfo>(); |
607 | posInfo = exitedSpy2.takeFirst().at(i: 1).value<QGeoPositionInfo>(); |
608 | QVERIFY2(monInfo == monitorsInExpectedExitedEventOrder.at(i), |
609 | qPrintable(QString::number(i) + ": " + monInfo.name())); |
610 | QVERIFY2(posInfo.coordinate() == exitedEventCoordinateOrder.at(i), |
611 | qPrintable(QString::number(i) + ". posInfo" )); |
612 | } |
613 | |
614 | QCOMPARE(obj->activeMonitors().count(), 2); //single shot monitors have been removed |
615 | QCOMPARE(secondObj->activeMonitors().count(), 2); |
616 | |
617 | delete obj; |
618 | delete secondObj; |
619 | } |
620 | |
621 | void tst_swapOfPositionSource() |
622 | { |
623 | QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent: 0); |
624 | QVERIFY(obj != 0); |
625 | QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll" )); |
626 | obj->setObjectName("firstObject" ); |
627 | QSignalSpy enteredSpy(obj, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo))); |
628 | QSignalSpy exitedSpy(obj, SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo))); |
629 | |
630 | QGeoAreaMonitorSource *obj2 = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll" ), parent: 0); |
631 | QVERIFY(obj2 != 0); |
632 | QCOMPARE(obj2->sourceName(), QStringLiteral("positionpoll" )); |
633 | obj2->setObjectName("secondObject" ); |
634 | QSignalSpy enteredSpy2(obj2, SIGNAL(areaEntered(QGeoAreaMonitorInfo,QGeoPositionInfo))); |
635 | QSignalSpy exitedSpy2(obj2, SIGNAL(areaExited(QGeoAreaMonitorInfo,QGeoPositionInfo))); |
636 | |
637 | LogFilePositionSource *source = new LogFilePositionSource(this); |
638 | source->setUpdateInterval(UPDATE_INTERVAL); |
639 | source->setObjectName("FirstLogFileSource" ); |
640 | |
641 | LogFilePositionSource *source2 = new LogFilePositionSource(this); |
642 | source2->setUpdateInterval(UPDATE_INTERVAL); |
643 | source2->setObjectName("SecondLogFileSource" ); |
644 | |
645 | obj->setPositionInfoSource(source); |
646 | QCOMPARE(obj->positionInfoSource(), obj2->positionInfoSource()); |
647 | QCOMPARE(obj2->positionInfoSource(), source); |
648 | |
649 | QGeoAreaMonitorInfo infoRectangle("Rectangle" ); |
650 | infoRectangle.setArea(QGeoRectangle(QGeoCoordinate(-27.70, 153.092), 0.2, 0.2)); |
651 | QVERIFY(infoRectangle.isValid()); |
652 | QVERIFY(obj->startMonitoring(infoRectangle)); |
653 | |
654 | QCOMPARE(obj->activeMonitors().count(), 1); |
655 | QCOMPARE(obj2->activeMonitors().count(), 1); |
656 | |
657 | QGeoCoordinate firstBorder(-27.6, 153.090908); |
658 | QGeoCoordinate secondBorder(-27.81, 153.092530); |
659 | |
660 | /***********************************/ |
661 | //1. trigger events on source (until areaExit |
662 | QTRY_VERIFY_WITH_TIMEOUT(exitedSpy.count() == 1, 20000); |
663 | QCOMPARE(enteredSpy.count(), enteredSpy2.count()); |
664 | QCOMPARE(exitedSpy.count(), exitedSpy2.count()); |
665 | |
666 | //compare entered event |
667 | QVERIFY(enteredSpy.first().at(0).value<QGeoAreaMonitorInfo>() == |
668 | enteredSpy2.first().at(0).value<QGeoAreaMonitorInfo>()); |
669 | QGeoPositionInfo info = enteredSpy.takeFirst().at(i: 1).value<QGeoPositionInfo>(); |
670 | QVERIFY(info == enteredSpy2.takeFirst().at(1).value<QGeoPositionInfo>()); |
671 | QVERIFY(info.coordinate() == firstBorder); |
672 | //compare exit event |
673 | QVERIFY(exitedSpy.first().at(0).value<QGeoAreaMonitorInfo>() == |
674 | exitedSpy2.first().at(0).value<QGeoAreaMonitorInfo>()); |
675 | info = exitedSpy.takeFirst().at(i: 1).value<QGeoPositionInfo>(); |
676 | QVERIFY(info == exitedSpy2.takeFirst().at(1).value<QGeoPositionInfo>()); |
677 | QVERIFY(info.coordinate() == secondBorder); |
678 | |
679 | QCOMPARE(exitedSpy.count(), 0); |
680 | QCOMPARE(enteredSpy.count(), 0); |
681 | QCOMPARE(exitedSpy2.count(), 0); |
682 | QCOMPARE(enteredSpy2.count(), 0); |
683 | |
684 | /***********************************/ |
685 | //2. change position source -> which restarts at beginning again |
686 | obj2->setPositionInfoSource(source2); |
687 | QCOMPARE(obj->positionInfoSource(), obj2->positionInfoSource()); |
688 | QCOMPARE(obj2->positionInfoSource(), source2); |
689 | |
690 | QTRY_VERIFY_WITH_TIMEOUT(exitedSpy.count() == 1, 20000); |
691 | QCOMPARE(enteredSpy.count(), enteredSpy2.count()); |
692 | QCOMPARE(exitedSpy.count(), exitedSpy2.count()); |
693 | |
694 | //compare entered event |
695 | QVERIFY(enteredSpy.first().at(0).value<QGeoAreaMonitorInfo>() == |
696 | enteredSpy2.first().at(0).value<QGeoAreaMonitorInfo>()); |
697 | info = enteredSpy.takeFirst().at(i: 1).value<QGeoPositionInfo>(); |
698 | QVERIFY(info == enteredSpy2.takeFirst().at(1).value<QGeoPositionInfo>()); |
699 | QVERIFY(info.coordinate() == firstBorder); |
700 | //compare exit event |
701 | QVERIFY(exitedSpy.first().at(0).value<QGeoAreaMonitorInfo>() == |
702 | exitedSpy2.first().at(0).value<QGeoAreaMonitorInfo>()); |
703 | info = exitedSpy.takeFirst().at(i: 1).value<QGeoPositionInfo>(); |
704 | QVERIFY(info == exitedSpy2.takeFirst().at(1).value<QGeoPositionInfo>()); |
705 | QVERIFY(info.coordinate() == secondBorder); |
706 | |
707 | |
708 | //obj was deleted when setting new source |
709 | delete obj2; |
710 | } |
711 | |
712 | void debug_data() |
713 | { |
714 | QTest::addColumn<QGeoAreaMonitorInfo>(name: "info" ); |
715 | QTest::addColumn<int>(name: "nextValue" ); |
716 | QTest::addColumn<QString>(name: "debugString" ); |
717 | |
718 | QGeoAreaMonitorInfo info; |
719 | QTest::newRow(dataTag: "uninitialized" ) << info << 45 |
720 | << QString("QGeoAreaMonitorInfo(\"\", QGeoShape(Unknown), " |
721 | "persistent: false, expiry: QDateTime(Invalid)) 45" ); |
722 | |
723 | info.setArea(QGeoRectangle()); |
724 | info.setPersistent(true); |
725 | info.setName("RectangleAreaMonitor" ); |
726 | QTest::newRow(dataTag: "Rectangle Test" ) << info << 45 |
727 | << QString("QGeoAreaMonitorInfo(\"RectangleAreaMonitor\", QGeoShape(Rectangle), " |
728 | "persistent: true, expiry: QDateTime(Invalid)) 45" ); |
729 | |
730 | info = QGeoAreaMonitorInfo(); |
731 | info.setArea(QGeoCircle()); |
732 | info.setPersistent(false); |
733 | info.setName("CircleAreaMonitor" ); |
734 | QVariantMap map; |
735 | map.insert(akey: QString("foobarKey" ), avalue: QVariant(45)); //should be ignored |
736 | info.setNotificationParameters(map); |
737 | QTest::newRow(dataTag: "Circle Test" ) << info << 45 |
738 | << QString("QGeoAreaMonitorInfo(\"CircleAreaMonitor\", QGeoShape(Circle), " |
739 | "persistent: false, expiry: QDateTime(Invalid)) 45" ); |
740 | |
741 | // we ignore any further QDateTime related changes to avoid depending on QDateTime related |
742 | // failures in case its QDebug string changes |
743 | } |
744 | |
745 | void debug() |
746 | { |
747 | QFETCH(QGeoAreaMonitorInfo, info); |
748 | QFETCH(int, nextValue); |
749 | QFETCH(QString, debugString); |
750 | |
751 | qInstallMessageHandler(tst_qgeoareamonitorinfo_messageHandler); |
752 | qDebug() << info << nextValue; |
753 | qInstallMessageHandler(0); |
754 | QCOMPARE(tst_qgeoareamonitorinfo_debug, debugString); |
755 | } |
756 | }; |
757 | |
758 | |
759 | QTEST_GUILESS_MAIN(tst_QGeoAreaMonitorSource) |
760 | #include "tst_qgeoareamonitor.moc" |
761 | |