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
52QT_USE_NAMESPACE
53#define UPDATE_INTERVAL 200
54
55Q_DECLARE_METATYPE(QGeoAreaMonitorInfo)
56
57QString tst_qgeoareamonitorinfo_debug;
58
59void 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
72class tst_QGeoAreaMonitorSource : public QObject
73{
74 Q_OBJECT
75
76private 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
759QTEST_GUILESS_MAIN(tst_QGeoAreaMonitorSource)
760#include "tst_qgeoareamonitor.moc"
761

source code of qtlocation/tests/auto/qgeoareamonitor/tst_qgeoareamonitor.cpp