|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt Mobility Components. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 //#include "../../../src/location/qlocationutils_p.h" |
|
42 #include "qlocationutils_p.h" |
|
43 #include "qgeopositioninfo.h" |
|
44 |
|
45 #include <QDebug> |
|
46 #include <QTest> |
|
47 #include <QObject> |
|
48 |
|
49 #include <math.h> |
|
50 |
|
51 QTM_USE_NAMESPACE |
|
52 Q_DECLARE_METATYPE(QGeoPositionInfo) |
|
53 Q_DECLARE_METATYPE(QGeoCoordinate) |
|
54 |
|
55 |
|
56 class tst_QLocationUtils : public QObject |
|
57 { |
|
58 Q_OBJECT |
|
59 private: |
|
60 QString addChecksumEtc(const QString &sentence) |
|
61 { |
|
62 Q_ASSERT(sentence[0] == '$' && sentence[sentence.length()-1] == '*'); |
|
63 |
|
64 // XOR byte value of all characters between '$' and '*' |
|
65 int result = 0; |
|
66 for (int i=1; i<sentence.length()-1; i++) |
|
67 result ^= sentence[i].toAscii(); |
|
68 QString sum; |
|
69 sum.sprintf("%02x", result); |
|
70 return sentence + sum + "\r\n"; |
|
71 } |
|
72 |
|
73 double nmeaDegreesToDecimal(double nmeaDegrees) |
|
74 { |
|
75 double deg; |
|
76 double min = 100.0 * modf(nmeaDegrees / 100.0, °); |
|
77 return deg + (min / 60.0); |
|
78 } |
|
79 |
|
80 private slots: |
|
81 |
|
82 void getPosInfoFromNmea() |
|
83 { |
|
84 QFETCH(QString, nmea); |
|
85 QFETCH(QGeoPositionInfo, expectedInfo); |
|
86 QFETCH(bool, expectedHasFix); |
|
87 QFETCH(bool, expectedResult); |
|
88 |
|
89 QGeoPositionInfo info; |
|
90 bool hasFix; |
|
91 bool b = QLocationUtils::getPosInfoFromNmea(nmea.toAscii(), nmea.length(), &info, &hasFix); |
|
92 QCOMPARE(b, expectedResult); |
|
93 QCOMPARE(hasFix, expectedHasFix); |
|
94 QCOMPARE(info, expectedInfo); |
|
95 } |
|
96 |
|
97 void getPosInfoFromNmea_data() |
|
98 { |
|
99 QTest::addColumn<QString>("nmea"); |
|
100 QTest::addColumn<QGeoPositionInfo>("expectedInfo"); |
|
101 QTest::addColumn<bool>("expectedHasFix"); |
|
102 QTest::addColumn<bool>("expectedResult"); |
|
103 |
|
104 QTest::newRow("empty") << QString() << QGeoPositionInfo() << false << false; |
|
105 |
|
106 // must use exact double values or comparisons fail |
|
107 double lat = nmeaDegreesToDecimal(2734.7964); |
|
108 double lng = nmeaDegreesToDecimal(15306.0124); |
|
109 |
|
110 QList<double> dblValues; |
|
111 dblValues << -1.534 << -1.0 << 0.0 << 0.12123 << 3.23 << 123124.11; |
|
112 |
|
113 QGeoPositionInfo info; |
|
114 |
|
115 // all types |
|
116 QList<QString> types; |
|
117 types << "$GPGGA*" << "$GPGLL*" << "$GPRMC*" << "$GPVTG*" << "$GPZDA*"; |
|
118 for (int i=0; i<types.count(); i++) { |
|
119 // the sentence type is valid even if it is empty so the method still returns true |
|
120 QTest::newRow(qPrintable(types[i])) << addChecksumEtc(types[i]) |
|
121 << QGeoPositionInfo() << false << true; |
|
122 } |
|
123 |
|
124 // bad type |
|
125 QTest::newRow("unknown type") << addChecksumEtc("$GPZZZ*") << QGeoPositionInfo() << false << false; |
|
126 |
|
127 // --GGA: |
|
128 |
|
129 QTest::newRow("GGA-time") << addChecksumEtc("$GPGGA,060613.626,,,,,,,,,,,,,*") |
|
130 << QGeoPositionInfo(QGeoCoordinate(), QDateTime(QDate(), QTime(6, 6, 13, 626))) |
|
131 << false << true; |
|
132 |
|
133 QTest::newRow("GGA-lat/long") << addChecksumEtc("$GPGGA,,2734.7964,S,15306.0124,E,,,,,,,,,*") |
|
134 << QGeoPositionInfo(QGeoCoordinate(-lat, lng), QDateTime()) |
|
135 << false << true; |
|
136 |
|
137 QTest::newRow("GGA-lat/long/alt") << addChecksumEtc("$GPGGA,,2734.7964,S,15306.0124,E,,,,26.8,,,,,*") |
|
138 << QGeoPositionInfo(QGeoCoordinate(-lat, lng, 26.8), QDateTime()) |
|
139 << false << true; |
|
140 |
|
141 QTest::newRow("GGA alt but no lat/long") << addChecksumEtc("$GPGGA,,,,,,,,,26.8,,,,,*") |
|
142 << QGeoPositionInfo(QGeoCoordinate(), QDateTime()) |
|
143 << false << true; |
|
144 |
|
145 for (int i=-1; i<10; i++) { |
|
146 bool hasFix = i > 0; |
|
147 QTest::newRow("GGA-fix") << addChecksumEtc(QString("$GPGGA,,,,,,%1,,,,,,,,*").arg(i)) |
|
148 << QGeoPositionInfo(QGeoCoordinate(), QDateTime()) |
|
149 << hasFix << true; |
|
150 } |
|
151 |
|
152 QTest::newRow("GGA-all") << addChecksumEtc("$GPGGA,060613.626,2734.7964,S,15306.0124,E,1,03,2.9,-26.8,M,36.8,M,1,0000*") |
|
153 << QGeoPositionInfo(QGeoCoordinate(-lat, lng, -26.8), QDateTime(QDate(), QTime(6,6,13,626))) |
|
154 << true << true; |
|
155 |
|
156 |
|
157 // --GLL: |
|
158 |
|
159 QTest::newRow("GLL-lat/long") << addChecksumEtc("$GPGLL,2734.7964,S,15306.0124,E,,,*") |
|
160 << QGeoPositionInfo(QGeoCoordinate(-lat, lng), QDateTime()) |
|
161 << false << true; |
|
162 |
|
163 QTest::newRow("GLL-time") << addChecksumEtc("$GPGLL,,,,,060613.626,,*") |
|
164 << QGeoPositionInfo(QGeoCoordinate(), QDateTime(QDate(), QTime(6, 6, 13, 626))) |
|
165 << false << true; |
|
166 |
|
167 QTest::newRow("GLL-fix-ok") << addChecksumEtc("$GPGLL,,,,,,A,*") |
|
168 << QGeoPositionInfo(QGeoCoordinate(), QDateTime()) |
|
169 << true << true; |
|
170 |
|
171 QTest::newRow("GLL-fix-bad") << addChecksumEtc("$GPGLL,,,,,,V,*") |
|
172 << QGeoPositionInfo(QGeoCoordinate(), QDateTime()) |
|
173 << false << true; |
|
174 |
|
175 QTest::newRow("GLL-all") << addChecksumEtc("$GGGLL,2734.7964,S,15306.0124,E,220125.999,A,,*") |
|
176 << QGeoPositionInfo(QGeoCoordinate(-lat, lng), QDateTime(QDate(), QTime(22,1,25,999))) |
|
177 << true << true; |
|
178 |
|
179 |
|
180 // --RMC: |
|
181 |
|
182 QTest::newRow("RMC-time") << addChecksumEtc("$GPRMC,060613.626,,,,,,,,,,,*") |
|
183 << QGeoPositionInfo(QGeoCoordinate(), QDateTime(QDate(), QTime(6, 6, 13, 626))) |
|
184 << false << true; |
|
185 |
|
186 QTest::newRow("RMC-fix-ok") << addChecksumEtc("$GPRMC,,A,,,,,,,,,,*") |
|
187 << QGeoPositionInfo(QGeoCoordinate(), QDateTime()) |
|
188 << true << true; |
|
189 |
|
190 QTest::newRow("RMC-fix-bad") << addChecksumEtc("$GPRMC,,V,,,,,,,,,,*") |
|
191 << QGeoPositionInfo(QGeoCoordinate(), QDateTime()) |
|
192 << false << true; |
|
193 |
|
194 QTest::newRow("RMC-lat/long") << addChecksumEtc("$GPRMC,,,2734.7964,S,15306.0124,E,,,,,*") |
|
195 << QGeoPositionInfo(QGeoCoordinate(-lat, lng), QDateTime()) |
|
196 << false << true; |
|
197 |
|
198 for (int i=0; i<dblValues.count(); i++) { |
|
199 info = QGeoPositionInfo(); |
|
200 info.setAttribute(QGeoPositionInfo::Direction, dblValues[i]); |
|
201 QTest::newRow(qPrintable(QString("RMC-heading %1").arg(dblValues[i]))) << addChecksumEtc(QString("$GPRMC,,,,,,,,%1,,,,*").arg(dblValues[i], 0, 'g', 10)) |
|
202 << info << false << true; |
|
203 } |
|
204 |
|
205 for (int i=0; i<dblValues.count(); i++) { |
|
206 info = QGeoPositionInfo(); |
|
207 info.setAttribute(QGeoPositionInfo::GroundSpeed, dblValues[i] * 1.852 / 3.6); |
|
208 QTest::newRow(qPrintable(QString("RMC-speed %1").arg(dblValues[i]))) << addChecksumEtc(QString("$GPRMC,,,,,,,%1,,,,,*").arg(dblValues[i], 0, 'g', 10)) |
|
209 << info << false << true; |
|
210 } |
|
211 |
|
212 for (int i=0; i<dblValues.count(); i++) { |
|
213 info = QGeoPositionInfo(); |
|
214 info.setAttribute(QGeoPositionInfo::MagneticVariation, dblValues[i]); |
|
215 char direction = dblValues[i] > 0 ? 'E' : 'W'; |
|
216 QTest::newRow(qPrintable(QString("RMC-magVar %1").arg(dblValues[i]))) << addChecksumEtc(QString("$GPRMC,,,,,,,,,,%1,%2,*").arg(qAbs(dblValues[i]), 0, 'g', 10).arg(direction)) |
|
217 << info << false << true; |
|
218 } |
|
219 |
|
220 QTest::newRow("RMC-date") << addChecksumEtc("$GPRMC,,,,,,,,,010520,*") |
|
221 << QGeoPositionInfo(QGeoCoordinate(), QDateTime(QDate(2020,5,1), QTime(), Qt::UTC)) |
|
222 << false << true; |
|
223 |
|
224 QTest::newRow("RMC-date bad format") << addChecksumEtc("$GPRMC,,,,,,,,,10520,,*") |
|
225 << QGeoPositionInfo(QGeoCoordinate(), QDateTime()) |
|
226 << false << true; |
|
227 |
|
228 info = QGeoPositionInfo(QGeoCoordinate(-lat, lng), QDateTime(QDate(2008,4,3), QTime(22,1,25,999), Qt::UTC)); |
|
229 info.setAttribute(QGeoPositionInfo::GroundSpeed, 8.9 * 1.852 / 3.6); |
|
230 info.setAttribute(QGeoPositionInfo::Direction, 47.6); |
|
231 info.setAttribute(QGeoPositionInfo::MagneticVariation, -11.2); |
|
232 QTest::newRow("RMC-all") << addChecksumEtc("$GPRMC,220125.999,A,2734.7964,S,15306.0124,E,8.9,47.6,030408,11.2,W,A*") |
|
233 << info |
|
234 << true << true; |
|
235 |
|
236 // -- VTG: |
|
237 |
|
238 for (int i=0; i<dblValues.count(); i++) { |
|
239 info = QGeoPositionInfo(); |
|
240 info.setAttribute(QGeoPositionInfo::Direction, dblValues[i]); |
|
241 QTest::newRow(qPrintable(QString("VTG-heading %1").arg(dblValues[i]))) << addChecksumEtc(QString("$GPVTG,%1,,,,,,,,*").arg(dblValues[i], 0, 'g', 10)) |
|
242 << info << false << true; |
|
243 } |
|
244 |
|
245 for (int i=0; i<dblValues.count(); i++) { |
|
246 info = QGeoPositionInfo(); |
|
247 info.setAttribute(QGeoPositionInfo::GroundSpeed, dblValues[i] / 3.6); |
|
248 QTest::newRow(qPrintable(QString("VTG-speed %1").arg(dblValues[i]))) << addChecksumEtc(QString("$GPVTG,,,,,,,%1,,*").arg(dblValues[i], 0, 'g', 10)) |
|
249 << info << false << true; |
|
250 } |
|
251 |
|
252 info = QGeoPositionInfo(); |
|
253 info.setAttribute(QGeoPositionInfo::Direction, 158.7); |
|
254 info.setAttribute(QGeoPositionInfo::GroundSpeed, 61.5 / 3.6); |
|
255 QTest::newRow("VTG-all") << addChecksumEtc("$GPVTG,158.7,T,169.9,M,33.2,N,61.5,K,A*") |
|
256 << info |
|
257 << false << true; |
|
258 |
|
259 // ZDA: |
|
260 |
|
261 QTest::newRow("ZDA-time") << addChecksumEtc("$GPZDA,152333.4,,,,*") |
|
262 << QGeoPositionInfo(QGeoCoordinate(), QDateTime(QDate(), QTime(15,23,33, 4), Qt::UTC)) |
|
263 << false << true; |
|
264 |
|
265 QTest::newRow("ZDA-date day only") << addChecksumEtc("$GPZDA,,1,,,,*") |
|
266 << QGeoPositionInfo(QGeoCoordinate(), QDateTime()) |
|
267 << false << true; |
|
268 |
|
269 QTest::newRow("ZDA-date month only") << addChecksumEtc("$GPZDA,,,12,,,*") |
|
270 << QGeoPositionInfo(QGeoCoordinate(), QDateTime()) |
|
271 << false << true; |
|
272 |
|
273 QTest::newRow("ZDA-date bad year only") << addChecksumEtc("$GPZDA,,,,2005,,*") |
|
274 << QGeoPositionInfo(QGeoCoordinate(), QDateTime()) |
|
275 << false << true; |
|
276 |
|
277 QTest::newRow("ZDA-date") << addChecksumEtc("$GPZDA,,1,12,2005,,*") |
|
278 << QGeoPositionInfo(QGeoCoordinate(), QDateTime(QDate(2005,12,1), QTime(), Qt::UTC)) |
|
279 << false << true; |
|
280 |
|
281 QTest::newRow("ZDA-all") << addChecksumEtc("$GPZDA,052953.05,03,04,2008,00,00*") |
|
282 << QGeoPositionInfo(QGeoCoordinate(), QDateTime(QDate(2008, 4, 3), QTime(5, 29, 53, 5), Qt::UTC)) |
|
283 << false << true; |
|
284 |
|
285 // test if multiple sentences are passed in, only first is parsed |
|
286 QTest::newRow("multiple") << (addChecksumEtc("$GPZDA,052953.05,03,04,2008,00,00*") + addChecksumEtc("$GPVTG,158.7,T,169.9,M,33.2,N,61.5,K,A*")) |
|
287 << QGeoPositionInfo(QGeoCoordinate(), QDateTime(QDate(2008, 4, 3), QTime(5, 29, 53, 5), Qt::UTC)) |
|
288 << false << true; |
|
289 } |
|
290 |
|
291 void hasValidNmeaChecksum() { |
|
292 QFETCH(QString, nmea); |
|
293 QFETCH(bool, expectedResult); |
|
294 |
|
295 QCOMPARE(QLocationUtils::hasValidNmeaChecksum(nmea.toAscii().constData(), nmea.length()), expectedResult); |
|
296 } |
|
297 |
|
298 void hasValidNmeaChecksum_data() |
|
299 { |
|
300 QTest::addColumn<QString>("nmea"); |
|
301 QTest::addColumn<bool>("expectedResult"); |
|
302 |
|
303 QTest::newRow("empty") << QString() << false; |
|
304 |
|
305 QString s = addChecksumEtc("$GPGGA,,,,,,,,,,,,,,*"); |
|
306 QString trimmed = s.trimmed(); |
|
307 QTest::newRow("ok") << s << true; |
|
308 QTest::newRow("too short") << trimmed.mid(0, trimmed.length()-1) << false; |
|
309 QTest::newRow("no asterisk") << s.replace("*", "") << false; // modifies test data! |
|
310 } |
|
311 #ifdef QT_BUILD_INTERNAL |
|
312 void getNmeaTime() |
|
313 { |
|
314 QFETCH(QString, str); |
|
315 QFETCH(QTime, expectedTime); |
|
316 QFETCH(bool, expectedResult); |
|
317 |
|
318 QTime time; |
|
319 bool b = QLocationUtils::getNmeaTime(str.toAscii(), &time); |
|
320 QCOMPARE(time, expectedTime); |
|
321 QCOMPARE(b, expectedResult); |
|
322 } |
|
323 |
|
324 void getNmeaTime_data() |
|
325 { |
|
326 QTest::addColumn<QString>("str"); |
|
327 QTest::addColumn<QTime>("expectedTime"); |
|
328 QTest::addColumn<bool>("expectedResult"); |
|
329 |
|
330 QTest::newRow("empty") << QString() << QTime() << false; |
|
331 QTest::newRow("no numbers") << QString("asdl") << QTime() << false; |
|
332 QTest::newRow("one number short") << QString("11223") << QTime() << false; |
|
333 |
|
334 QTest::newRow("112233") << QString("112233") << QTime(11,22,33) << true; |
|
335 QTest::newRow("000000") << QString("000000") << QTime(0,0,0) << true; |
|
336 QTest::newRow("235959") << QString("235959") << QTime(23,59,59) << true; |
|
337 QTest::newRow("235960") << QString("235960") << QTime() << false; |
|
338 QTest::newRow("236059") << QString("236059") << QTime() << false; |
|
339 QTest::newRow("245959") << QString("24959") << QTime() << false; |
|
340 |
|
341 QTest::newRow("112233.0") << QString("112233.0") << QTime(11,22,33) << true; |
|
342 QTest::newRow("112233.1") << QString("112233.1") << QTime(11,22,33, 1) << true; |
|
343 QTest::newRow("112233.12") << QString("112233.12") << QTime(11,22,33, 12) << true; |
|
344 QTest::newRow("112233.123") << QString("112233.123") << QTime(11,22,33, 123) << true; |
|
345 QTest::newRow("112233.999") << QString("112233.999") << QTime(11,22,33, 999) << true; |
|
346 QTest::newRow("112233.9990") << QString("112233.9990") << QTime(11,22,33,999) << true; |
|
347 QTest::newRow("112233.9991") << QString("112233.9991") << QTime(11,22,33,999) << true; |
|
348 } |
|
349 |
|
350 void getNmeaLatLong() |
|
351 { |
|
352 QFETCH(QString, str); |
|
353 QFETCH(double, expectedLat); |
|
354 QFETCH(double, expectedLng); |
|
355 QFETCH(bool, expectedResult); |
|
356 |
|
357 double lat, lng; |
|
358 QList<QByteArray> parts = str.toAscii().split(','); |
|
359 bool b = QLocationUtils::getNmeaLatLong(parts[0], parts[1][0], parts[2], parts[3][0], &lat, &lng); |
|
360 QCOMPARE(b, expectedResult); |
|
361 if (b) { |
|
362 QCOMPARE(lat, expectedLat); |
|
363 QCOMPARE(lng, expectedLng); |
|
364 } |
|
365 } |
|
366 |
|
367 void getNmeaLatLong_data() |
|
368 { |
|
369 QTest::addColumn<QString>("str"); |
|
370 QTest::addColumn<double>("expectedLat"); |
|
371 QTest::addColumn<double>("expectedLng"); |
|
372 QTest::addColumn<bool>("expectedResult"); |
|
373 |
|
374 QTest::newRow("0.0,S,0.0,E") << "0.0,S,0.0,E" << 0.0 << 0.0 << true; |
|
375 QTest::newRow("0.0,S,0.0,E") << "0.0,S,0.0,E" << 0.0 << 0.0 << true; |
|
376 QTest::newRow("0,N,0,W") << "0,N,0,W" << 0.0 << 0.0 << true; |
|
377 QTest::newRow("0,N,0,W") << "0,N,0,W" << 0.0 << 0.0 << true; |
|
378 |
|
379 QTest::newRow("bad N/S indicator") << "0.0,Z,0.0,E" << 0.0 << 0.0 << false; |
|
380 QTest::newRow("bad E/W indicator") << "0.0,S,0.0,P" << 0.0 << 0.0 << false; |
|
381 |
|
382 QTest::newRow("lat too big") << "9000.0001,N,0.0,E" << 0.0 << 0.0 << false; |
|
383 QTest::newRow("lat almost too big") << "9000.0000,N,0.0,E" << 90.0 << 0.0 << true; |
|
384 QTest::newRow("lat too small") << "9000.0001,S,0.0,E" << 0.0 << 0.0 << false; |
|
385 QTest::newRow("lat almost too small") << "9000.0000,S,0.0,E" << -90.0 << 0.0 << true; |
|
386 |
|
387 QTest::newRow("long too big") << "0.0,N,18000.0001,E" << 0.0 << 0.0 << false; |
|
388 QTest::newRow("long almost too big") << "0.0,N,18000.0000,E" << 0.0 << 180.0 << true; |
|
389 QTest::newRow("long too small") << "0.0,N,18000.0001,W" << 0.0 << 0.0 << false; |
|
390 QTest::newRow("long almost too small") << "0.0,N,18000.0000,W" << 0.0 << -180.0 << true; |
|
391 |
|
392 double lat = nmeaDegreesToDecimal(2734.7964); |
|
393 double lng = nmeaDegreesToDecimal(15306.0124); |
|
394 |
|
395 QTest::newRow("Lat N, Long E") |
|
396 << "2734.7964,N,15306.0124,E" |
|
397 << lat << lng << true; |
|
398 |
|
399 QTest::newRow("Lat S, Long E") |
|
400 << "2734.7964,S,15306.0124,E" |
|
401 << -lat << lng << true; |
|
402 |
|
403 QTest::newRow("Lat N, Long W") |
|
404 << "2734.7964,N,15306.0124,W" |
|
405 << lat << -lng << true; |
|
406 |
|
407 QTest::newRow("Lat S, Long W") |
|
408 << "2734.7964,S,15306.0124,W" |
|
409 << -lat << -lng << true; |
|
410 } |
|
411 #endif |
|
412 |
|
413 }; |
|
414 |
|
415 |
|
416 QTEST_MAIN(tst_QLocationUtils) |
|
417 #include "tst_qlocationutils.moc" |
|
418 |