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 
tst_qgeoareamonitorinfo_messageHandler(QtMsgType type,const QMessageLogContext &,const QString & msg)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:
initTestCase()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 
init()94     void init()
95     {
96     }
97 
cleanup()98     void cleanup()
99     {
100         QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 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 
cleanupTestCase()114     void cleanupTestCase()
115     {
116     }
117 
tst_monitor()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"), 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(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(QString("MyKey"), 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"), 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 
tst_monitorValid()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 
tst_monitorStreaming()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(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 
tst_createDefaultSource()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"), 0);
328         QVERIFY(obj == 0);
329     }
330 
tst_activeMonitors()331     void tst_activeMonitors()
332     {
333         QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 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(QGeoShape());
366         QCOMPARE(results.count(), 0);
367 
368         results = obj->activeMonitors(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(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(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"), 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(QGeoShape());
399         QCOMPARE(results.count(), 0);
400 
401         results = secondObj->activeMonitors(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(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(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 
tst_testExpiryTimeout()423     void tst_testExpiryTimeout()
424     {
425         QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 0);
426         QVERIFY(obj != 0);
427         QCOMPARE(obj->sourceName(), QStringLiteral("positionpoll"));
428 
429         QGeoAreaMonitorSource *secondObj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 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(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(-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(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(0).value<QGeoAreaMonitorInfo>();
481             QCOMPARE(mon.name(), QString::number(i));
482         }
483 
484         delete obj;
485         delete secondObj;
486     }
487 
tst_enteredExitedSignal()488     void tst_enteredExitedSignal()
489     {
490         QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 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"), 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(0).value<QGeoAreaMonitorInfo>();
573             QGeoPositionInfo posInfo = enteredSpy.takeFirst().at(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(0).value<QGeoAreaMonitorInfo>();
585             posInfo = enteredSpy2.takeFirst().at(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(0).value<QGeoAreaMonitorInfo>();
595             QGeoPositionInfo posInfo = exitedSpy.takeFirst().at(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(0).value<QGeoAreaMonitorInfo>();
607             posInfo = exitedSpy2.takeFirst().at(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 
tst_swapOfPositionSource()621     void tst_swapOfPositionSource()
622     {
623         QGeoAreaMonitorSource *obj = QGeoAreaMonitorSource::createSource(QStringLiteral("positionpoll"), 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"), 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(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(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(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(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 
debug_data()712     void debug_data()
713     {
714         QTest::addColumn<QGeoAreaMonitorInfo>("info");
715         QTest::addColumn<int>("nextValue");
716         QTest::addColumn<QString>("debugString");
717 
718         QGeoAreaMonitorInfo info;
719         QTest::newRow("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("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(QString("foobarKey"), QVariant(45)); //should be ignored
736         info.setNotificationParameters(map);
737         QTest::newRow("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 
debug()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