blob: 51f996fb729101d6febbede2845ba19d4fbdc9ca [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 Jolla Ltd.
** Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
//TESTED_COMPONENT=src/location
#include "tst_qnmeapositioninfosource.h"
#include <QtCore/QDateTime>
#include <QtCore/QElapsedTimer>
#include <QtCore/QtNumeric>
#ifdef Q_OS_WIN
// Windows seems to require longer timeouts and step length
// We override the standard QTestCase related macros
#ifdef QTRY_COMPARE_WITH_TIMEOUT
#undef QTRY_COMPARE_WITH_TIMEOUT
#endif
#define QTRY_COMPARE_WITH_TIMEOUT(__expr, __expected, __timeout) \
do { \
const int __step = 100; \
const int __timeoutValue = __timeout; \
if ((__expr) != (__expected)) { \
QTest::qWait(0); \
} \
for (int __i = 0; __i < __timeoutValue && ((__expr) != (__expected)); __i+=__step) { \
QTest::qWait(__step); \
} \
QCOMPARE(__expr, __expected); \
} while (0)
#ifdef QTRY_COMPARE
#undef QTRY_COMPARE
#endif
#define QTRY_COMPARE(__expr, __expected) QTRY_COMPARE_WITH_TIMEOUT(__expr, __expected, 10000)
#endif
tst_QNmeaPositionInfoSource::tst_QNmeaPositionInfoSource(QNmeaPositionInfoSource::UpdateMode mode, QObject *parent)
: QObject(parent),
m_mode(mode)
{
}
void tst_QNmeaPositionInfoSource::initTestCase()
{
qRegisterMetaType<QNmeaPositionInfoSource::UpdateMode>();
}
void tst_QNmeaPositionInfoSource::constructor()
{
QObject o;
QNmeaPositionInfoSource source(m_mode, &o);
QCOMPARE(source.updateMode(), m_mode);
QCOMPARE(source.parent(), &o);
}
void tst_QNmeaPositionInfoSource::supportedPositioningMethods()
{
QNmeaPositionInfoSource source(m_mode);
QCOMPARE(source.supportedPositioningMethods(), QNmeaPositionInfoSource::SatellitePositioningMethods);
}
void tst_QNmeaPositionInfoSource::minimumUpdateInterval()
{
QNmeaPositionInfoSource source(m_mode);
QCOMPARE(source.minimumUpdateInterval(), 2);
}
void tst_QNmeaPositionInfoSource::userEquivalentRangeError()
{
QNmeaPositionInfoSource source(m_mode);
QVERIFY(qIsNaN(source.userEquivalentRangeError()));
source.setUserEquivalentRangeError(5.1);
QVERIFY(qFuzzyCompare(source.userEquivalentRangeError(), 5.1));
}
void tst_QNmeaPositionInfoSource::setUpdateInterval_delayedUpdate()
{
// If an update interval is set, and an update is not available at a
// particular interval, the source should emit the next update as soon
// as it becomes available
QNmeaPositionInfoSource source(m_mode);
QNmeaPositionInfoSourceProxyFactory factory;
QNmeaPositionInfoSourceProxy *proxy = static_cast<QNmeaPositionInfoSourceProxy*>(factory.createProxy(&source));
QSignalSpy spyUpdate(proxy->source(), SIGNAL(positionUpdated(QGeoPositionInfo)));
proxy->source()->setUpdateInterval(500);
proxy->source()->startUpdates();
QTest::qWait(600);
QDateTime now = QDateTime::currentDateTime();
proxy->feedUpdate(now);
QTRY_COMPARE(spyUpdate.count(), 1);
// should have gotten the update immediately, and not have needed to
// wait until the next interval
QVERIFY(now.time().msecsTo(QDateTime::currentDateTime().time()) < 200);
}
void tst_QNmeaPositionInfoSource::lastKnownPosition()
{
QNmeaPositionInfoSource source(m_mode);
QNmeaPositionInfoSourceProxyFactory factory;
QNmeaPositionInfoSourceProxy *proxy = static_cast<QNmeaPositionInfoSourceProxy*>(factory.createProxy(&source));
QCOMPARE(proxy->source()->lastKnownPosition(), QGeoPositionInfo());
// source may need requestUpdate() or startUpdates() to be called to
// trigger reading of data channel
QSignalSpy spyTimeout(proxy->source(), SIGNAL(updateTimeout()));
proxy->source()->requestUpdate(proxy->source()->minimumUpdateInterval());
QTRY_COMPARE(spyTimeout.count(), 1);
// If an update is received and startUpdates() or requestUpdate() hasn't
// been called, it should still be available through lastKnownPosition()
QDateTime dt = QDateTime::currentDateTime().toUTC();
proxy->feedUpdate(dt);
QTRY_COMPARE(proxy->source()->lastKnownPosition().timestamp(), dt);
QList<QDateTime> dateTimes = createDateTimes(5);
for (int i=0; i<dateTimes.count(); i++) {
proxy->source()->requestUpdate(); // Irrelevant for this test
proxy->feedUpdate(dateTimes[i]);
QTRY_COMPARE(proxy->source()->lastKnownPosition().timestamp(), dateTimes[i]);
}
proxy->source()->startUpdates();
// if dateTimes are older than before, they will be ignored.
dateTimes = createDateTimes(dateTimes.last().addMSecs(100), 5);
for (int i=0; i<dateTimes.count(); i++) {
proxy->feedUpdate(dateTimes[i]);
QTRY_COMPARE(proxy->source()->lastKnownPosition().timestamp(), dateTimes[i]);
}
}
void tst_QNmeaPositionInfoSource::beginWithBufferedData()
{
// In SimulationMode, data stored in the QIODevice is read when
// startUpdates() or requestUpdate() is called.
// In RealTimeMode, all existing data in the QIODevice is ignored -
// only new data will be read.
QFETCH(QList<QDateTime>, dateTimes);
QFETCH(UpdateTriggerMethod, trigger);
QByteArray bytes;
for (int i=0; i<dateTimes.count(); i++)
bytes += QLocationTestUtils::createRmcSentence(dateTimes[i]).toLatin1();
QBuffer buffer;
buffer.setData(bytes);
QNmeaPositionInfoSource source(m_mode);
QSignalSpy spy(&source, SIGNAL(positionUpdated(QGeoPositionInfo)));
source.setDevice(&buffer);
if (trigger == StartUpdatesMethod)
source.startUpdates();
else if (trigger == RequestUpdatesMethod)
source.requestUpdate();
if (m_mode == QNmeaPositionInfoSource::RealTimeMode) {
QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 0, 300);
} else {
if (trigger == StartUpdatesMethod) {
QTRY_COMPARE(spy.count(), dateTimes.count());
for (int i=0; i<dateTimes.count(); i++)
QCOMPARE(spy.at(i).at(0).value<QGeoPositionInfo>().timestamp(), dateTimes[i]);
} else if (trigger == RequestUpdatesMethod) {
QTRY_COMPARE(spy.count(), 1);
QCOMPARE(spy.at(0).at(0).value<QGeoPositionInfo>().timestamp(), dateTimes.first());
}
}
}
void tst_QNmeaPositionInfoSource::beginWithBufferedData_data()
{
QTest::addColumn<QList<QDateTime> >("dateTimes");
QTest::addColumn<UpdateTriggerMethod>("trigger");
QList<QDateTime> dateTimes;
dateTimes << QDateTime::currentDateTime().toUTC();
QTest::newRow("startUpdates(), 1 update in buffer") << dateTimes << StartUpdatesMethod;
QTest::newRow("requestUpdate(), 1 update in buffer") << dateTimes << RequestUpdatesMethod;
for (int i=1; i<3; i++)
dateTimes << dateTimes[0].addMSecs(i * 100);
QTest::newRow("startUpdates(), multiple updates in buffer") << dateTimes << StartUpdatesMethod;
QTest::newRow("requestUpdate(), multiple updates in buffer") << dateTimes << RequestUpdatesMethod;
}
void tst_QNmeaPositionInfoSource::startUpdates()
{
QFETCH(QList<QDateTime>, dateTimes);
QNmeaPositionInfoSource source(m_mode);
QNmeaPositionInfoSourceProxyFactory factory;
QNmeaPositionInfoSourceProxy *proxy = static_cast<QNmeaPositionInfoSourceProxy*>(factory.createProxy(&source));
QSignalSpy spyUpdate(proxy->source(), SIGNAL(positionUpdated(QGeoPositionInfo)));
proxy->source()->startUpdates();
for (int i=0; i<dateTimes.count(); i++)
proxy->feedUpdate(dateTimes[i]);
QTRY_COMPARE(spyUpdate.count(), dateTimes.count());
}
void tst_QNmeaPositionInfoSource::startUpdates_data()
{
QTest::addColumn<QList<QDateTime> >("dateTimes");
QTest::newRow("1 update") << createDateTimes(1);
QTest::newRow("2 updates") << createDateTimes(2);
QTest::newRow("10 updates") << createDateTimes(10);
}
void tst_QNmeaPositionInfoSource::startUpdates_withTimeout()
{
QNmeaPositionInfoSource source(m_mode);
QNmeaPositionInfoSourceProxyFactory factory;
QNmeaPositionInfoSourceProxy *proxy = static_cast<QNmeaPositionInfoSourceProxy*>(factory.createProxy(&source));
QSignalSpy spyUpdate(proxy->source(), SIGNAL(positionUpdated(QGeoPositionInfo)));
QSignalSpy spyTimeout(proxy->source(), SIGNAL(updateTimeout()));
proxy->source()->setUpdateInterval(1000);
proxy->source()->startUpdates();
QDateTime dt = QDateTime::currentDateTime().toUTC();
if (m_mode == QNmeaPositionInfoSource::SimulationMode) {
// the first sentence primes the simulation
proxy->feedBytes(QLocationTestUtils::createRmcSentence(dt).toLatin1());
proxy->feedBytes(QLocationTestUtils::createRmcSentence(dt.addMSecs(10)).toLatin1());
proxy->feedBytes(QLocationTestUtils::createRmcSentence(dt.addMSecs(1100)).toLatin1());
proxy->feedBytes(QLocationTestUtils::createRmcSentence(dt.addMSecs(2200)).toLatin1());
proxy->feedBytes(QLocationTestUtils::createRmcSentence(dt.addSecs(9)).toLatin1());
QElapsedTimer t;
t.start();
for (int j = 1; j < 4; ++j) {
QTRY_COMPARE(spyUpdate.count(), j);
QCOMPARE(spyTimeout.count(), 0);
int time = t.elapsed();
QVERIFY((time > j*1000 - 300) && (time < j*1000 + 300));
}
spyUpdate.clear();
QTRY_VERIFY_WITH_TIMEOUT((spyUpdate.count() == 0) && (spyTimeout.count() == 1), 7500);
spyTimeout.clear();
QTRY_VERIFY_WITH_TIMEOUT((spyUpdate.count() == 1) && (spyTimeout.count() == 0), 7500);
} else {
// dt + 900
QTRY_VERIFY(spyUpdate.count() == 0 && spyTimeout.count() == 0);
proxy->feedBytes(QLocationTestUtils::createRmcSentence(dt.addSecs(1)).toLatin1());
// dt + 1200
QTRY_VERIFY(spyUpdate.count() == 1 && spyTimeout.count() == 0);
spyUpdate.clear();
// dt + 1900
QTRY_VERIFY(spyUpdate.count() == 0 && spyTimeout.count() == 0);
proxy->feedBytes(QLocationTestUtils::createRmcSentence(dt.addSecs(2)).toLatin1());
// dt + 2200
QTRY_VERIFY(spyUpdate.count() == 1 && spyTimeout.count() == 0);
spyUpdate.clear();
// dt + 2900
QTRY_VERIFY(spyUpdate.count() == 0 && spyTimeout.count() == 0);
proxy->feedBytes(QLocationTestUtils::createRmcSentence(dt.addSecs(3)).toLatin1());
// dt + 3200
QTRY_VERIFY(spyUpdate.count() == 1 && spyTimeout.count() == 0);
spyUpdate.clear();
// dt + 6900
QTRY_VERIFY(spyUpdate.count() == 0 && spyTimeout.count() == 1);
spyTimeout.clear();
proxy->feedBytes(QLocationTestUtils::createRmcSentence(dt.addSecs(7)).toLatin1());
// dt + 7200
QTRY_VERIFY(spyUpdate.count() == 1 && spyTimeout.count() == 0);
spyUpdate.clear();
}
}
void tst_QNmeaPositionInfoSource::startUpdates_expectLatestUpdateOnly()
{
// If startUpdates() is called and an interval has been set, if multiple'
// updates are in the buffer, only the latest update should be emitted
QNmeaPositionInfoSource source(m_mode);
QNmeaPositionInfoSourceProxyFactory factory;
QNmeaPositionInfoSourceProxy *proxy = static_cast<QNmeaPositionInfoSourceProxy*>(factory.createProxy(&source));
QSignalSpy spyUpdate(proxy->source(), SIGNAL(positionUpdated(QGeoPositionInfo)));
proxy->source()->setUpdateInterval(500);
proxy->source()->startUpdates();
QList<QDateTime> dateTimes = createDateTimes(3);
for (int i=0; i<dateTimes.count(); i++)
proxy->feedUpdate(dateTimes[i]);
QTRY_COMPARE(spyUpdate.count(), 1);
QCOMPARE(spyUpdate[0][0].value<QGeoPositionInfo>().timestamp(), dateTimes.last());
}
void tst_QNmeaPositionInfoSource::startUpdates_waitForValidDateTime()
{
// Tests that the class does not emit an update until it receives a
// sentences with a valid date *and* time. All sentences before this
// should be ignored, and any sentences received after this that do
// not have a date should use the known date.
QFETCH(QByteArray, bytes);
QFETCH(QList<QDateTime>, dateTimes);
QFETCH(QList<bool>, expectHorizontalAccuracy);
QFETCH(QList<bool>, expectVerticalAccuracy);
QNmeaPositionInfoSource source(m_mode);
source.setUserEquivalentRangeError(5.1);
QNmeaPositionInfoSourceProxyFactory factory;
QNmeaPositionInfoSourceProxy *proxy = static_cast<QNmeaPositionInfoSourceProxy*>(factory.createProxy(&source));
QSignalSpy spy(proxy->source(), SIGNAL(positionUpdated(QGeoPositionInfo)));
QObject::connect(proxy->source(), &QNmeaPositionInfoSource::positionUpdated, [](const QGeoPositionInfo &info) {
qDebug() << info.timestamp();
});
proxy->source()->startUpdates();
proxy->feedBytes(bytes);
QTest::qWait(1000); // default push delay is 20ms
QTRY_COMPARE(spy.count(), dateTimes.count());
for (int i=0; i<spy.count(); i++) {
QGeoPositionInfo pInfo = spy[i][0].value<QGeoPositionInfo>();
QCOMPARE(pInfo.timestamp(), dateTimes[i]);
// Generated GGA/GSA sentences have hard coded HDOP of 3.5, which corrisponds to a
// horizontal accuracy of 35.7, for the user equivalent range error of 5.1 set above.
QCOMPARE(pInfo.hasAttribute(QGeoPositionInfo::HorizontalAccuracy),
expectHorizontalAccuracy[i]);
if (pInfo.hasAttribute(QGeoPositionInfo::HorizontalAccuracy))
QVERIFY(qFuzzyCompare(pInfo.attribute(QGeoPositionInfo::HorizontalAccuracy), 35.7));
// Generated GSA sentences have hard coded VDOP of 4.0, which corrisponds to a vertical
// accuracy of 40.8, for the user equivalent range error of 5.1 set above.
QCOMPARE(pInfo.hasAttribute(QGeoPositionInfo::VerticalAccuracy),
expectVerticalAccuracy[i]);
if (pInfo.hasAttribute(QGeoPositionInfo::VerticalAccuracy))
QVERIFY(qFuzzyCompare(pInfo.attribute(QGeoPositionInfo::VerticalAccuracy), 40.8));
}
}
void tst_QNmeaPositionInfoSource::startUpdates_waitForValidDateTime_data()
{
QTest::addColumn<QByteArray>("bytes");
QTest::addColumn<QList<QDateTime> >("dateTimes");
QTest::addColumn<QList<bool> >("expectHorizontalAccuracy");
QTest::addColumn<QList<bool> >("expectVerticalAccuracy");
QDateTime dt = QDateTime::currentDateTime().toUTC();
QByteArray bytes;
// should only receive RMC sentence and the GGA sentence *after* it
bytes += QLocationTestUtils::createGgaSentence(dt.addMSecs(100).time()).toLatin1();
bytes += QLocationTestUtils::createRmcSentence(dt.addMSecs(200)).toLatin1();
bytes += QLocationTestUtils::createGgaSentence(dt.addMSecs(300).time()).toLatin1();
// The first GGA does not have date, and there's no cached date to inject, so that update will be invalid
QTest::newRow("Feed GGA,RMC,GGA; expect RMC, second GGA only")
<< bytes << (QList<QDateTime>() << dt.addMSecs(200) << dt.addMSecs(300))
<< (QList<bool>() << true << true) // accuracies are currently cached and injected in QGeoPositionInfos that do not have it
<< (QList<bool>() << false << false);
// should not receive ZDA (has no coordinates) but should get the GGA
// sentence after it since it got the date/time from ZDA
bytes.clear();
bytes += QLocationTestUtils::createGgaSentence(dt.addMSecs(100).time()).toLatin1();
bytes += QLocationTestUtils::createZdaSentence(dt.addMSecs(200)).toLatin1();
bytes += QLocationTestUtils::createGgaSentence(dt.addMSecs(300).time()).toLatin1();
QTest::newRow("Feed GGA,ZDA,GGA; expect second GGA only")
<< bytes << (QList<QDateTime>() << dt.addMSecs(300))
<< (QList<bool>() << true)
<< (QList<bool>() << false);
// Feed ZDA,GGA,GSA,GGA; expect vertical accuracy from second GGA.
bytes.clear();
bytes += QLocationTestUtils::createZdaSentence(dt.addMSecs(100)).toLatin1();
bytes += QLocationTestUtils::createGgaSentence(dt.addMSecs(200).time()).toLatin1();
bytes += QLocationTestUtils::createGsaSentence().toLatin1();
bytes += QLocationTestUtils::createGgaSentence(dt.addMSecs(300).time()).toLatin1();
if (m_mode == QNmeaPositionInfoSource::SimulationMode) {
QTest::newRow("Feed ZDA,GGA,GSA,GGA; expect vertical accuracy from second GGA")
<< bytes << (QList<QDateTime>() << dt.addMSecs(200) << dt.addMSecs(300))
<< (QList<bool>() << true << true)
<< (QList<bool>() << true << true); // First GGA gets VDOP from GSA bundled into previous, as it has no timestamp, second GGA gets the cached value.
}
if (m_mode == QNmeaPositionInfoSource::SimulationMode) {
// In sim m_mode, should ignore sentence with a date/time before the known date/time
// (in real time m_mode, everything is passed on regardless)
bytes.clear();
bytes += QLocationTestUtils::createRmcSentence(dt.addMSecs(100)).toLatin1();
bytes += QLocationTestUtils::createRmcSentence(dt.addMSecs(-200)).toLatin1();
bytes += QLocationTestUtils::createRmcSentence(dt.addMSecs(200)).toLatin1();
QTest::newRow("Feed good RMC, RMC with bad date/time, good RMC; expect first and third RMC only")
<< bytes << (QList<QDateTime>() << dt.addMSecs(100) << dt.addMSecs(200))
<< (QList<bool>() << false << false)
<< (QList<bool>() << false << false);
}
}
void tst_QNmeaPositionInfoSource::requestUpdate_waitForValidDateTime()
{
QFETCH(QByteArray, bytes);
QFETCH(QList<QDateTime>, dateTimes);
QNmeaPositionInfoSource source(m_mode);
QNmeaPositionInfoSourceProxyFactory factory;
QNmeaPositionInfoSourceProxy *proxy = static_cast<QNmeaPositionInfoSourceProxy*>(factory.createProxy(&source));
QSignalSpy spy(proxy->source(), SIGNAL(positionUpdated(QGeoPositionInfo)));
proxy->source()->requestUpdate();
proxy->feedBytes(bytes);
QTRY_COMPARE(spy.count(), 1);
QCOMPARE(spy[0][0].value<QGeoPositionInfo>().timestamp(), dateTimes[0]);
}
void tst_QNmeaPositionInfoSource::requestUpdate_waitForValidDateTime_data()
{
startUpdates_waitForValidDateTime_data();
}
void tst_QNmeaPositionInfoSource::requestUpdate()
{
QNmeaPositionInfoSource source(m_mode);
QNmeaPositionInfoSourceProxyFactory factory;
QNmeaPositionInfoSourceProxy *proxy = static_cast<QNmeaPositionInfoSourceProxy*>(factory.createProxy(&source));
QSignalSpy spyUpdate(proxy->source(), SIGNAL(positionUpdated(QGeoPositionInfo)));
QSignalSpy spyTimeout(proxy->source(), SIGNAL(updateTimeout()));
QDateTime dt;
proxy->source()->requestUpdate(100);
QTRY_COMPARE(spyTimeout.count(), 1);
spyTimeout.clear();
dt = QDateTime::currentDateTime().toUTC();
proxy->feedUpdate(dt);
proxy->source()->requestUpdate();
QTRY_COMPARE(spyUpdate.count(), 1);
QCOMPARE(spyUpdate[0][0].value<QGeoPositionInfo>().timestamp(), dt);
QCOMPARE(spyTimeout.count(), 0);
spyUpdate.clear();
// delay the update and expect it to be emitted after 300ms
dt = QDateTime::currentDateTime().toUTC();
proxy->source()->requestUpdate(1000);
QTest::qWait(300);
proxy->feedUpdate(dt);
QTRY_COMPARE(spyUpdate.count(), 1);
QCOMPARE(spyUpdate[0][0].value<QGeoPositionInfo>().timestamp(), dt);
QCOMPARE(spyTimeout.count(), 0);
spyUpdate.clear();
// delay the update and expect updateTimeout() to be emitted
dt = QDateTime::currentDateTime().toUTC();
proxy->source()->requestUpdate(500);
QTest::qWait(1000);
proxy->feedUpdate(dt);
QCOMPARE(spyTimeout.count(), 1);
QCOMPARE(spyUpdate.count(), 0);
spyUpdate.clear();
}
void tst_QNmeaPositionInfoSource::requestUpdate_after_start()
{
QNmeaPositionInfoSource source(m_mode);
QNmeaPositionInfoSourceProxyFactory factory;
QNmeaPositionInfoSourceProxy *proxy = static_cast<QNmeaPositionInfoSourceProxy*>(factory.createProxy(&source));
QSignalSpy spyUpdate(proxy->source(), SIGNAL(positionUpdated(QGeoPositionInfo)));
QSignalSpy spyTimeout(proxy->source(), SIGNAL(updateTimeout()));
// Start updates with 500ms interval and requestUpdate() with 100ms
// timeout. Feed an update, and it should be emitted immediately due to
// the requestUpdate(). The update should not be emitted again after that
// (i.e. the startUpdates() interval should not cause it to be re-emitted).
QDateTime dt = QDateTime::currentDateTime().toUTC();
proxy->source()->setUpdateInterval(500);
proxy->source()->startUpdates();
proxy->source()->requestUpdate(100);
proxy->feedUpdate(dt);
QTRY_COMPARE(spyUpdate.count(), 1);
QCOMPARE(spyUpdate[0][0].value<QGeoPositionInfo>().timestamp(), dt);
QCOMPARE(spyTimeout.count(), 0);
spyUpdate.clear();
// Update has been emitted for requestUpdate(), shouldn't be emitted for startUpdates()
QTRY_COMPARE_WITH_TIMEOUT(spyUpdate.count(), 0, 1000);
}
void tst_QNmeaPositionInfoSource::testWithBadNmea()
{
QFETCH(QByteArray, bytes);
QFETCH(QList<QDateTime>, dateTimes);
QFETCH(UpdateTriggerMethod, trigger);
QNmeaPositionInfoSource source(m_mode);
QNmeaPositionInfoSourceProxyFactory factory;
QNmeaPositionInfoSourceProxy *proxy = static_cast<QNmeaPositionInfoSourceProxy*>(factory.createProxy(&source));
QSignalSpy spy(proxy->source(), SIGNAL(positionUpdated(QGeoPositionInfo)));
if (trigger == StartUpdatesMethod)
proxy->source()->startUpdates();
else
proxy->source()->requestUpdate();
proxy->feedBytes(bytes);
QTRY_COMPARE(spy.count(), dateTimes.count());
for (int i=0; i<dateTimes.count(); i++)
QCOMPARE(spy[i][0].value<QGeoPositionInfo>().timestamp(), dateTimes[i]);
}
void tst_QNmeaPositionInfoSource::testWithBadNmea_data()
{
QTest::addColumn<QByteArray>("bytes");
QTest::addColumn<QList<QDateTime> >("dateTimes");
QTest::addColumn<UpdateTriggerMethod>("trigger");
QDateTime firstDateTime = QDateTime::currentDateTime().toUTC();
QByteArray bad = QLocationTestUtils::createRmcSentence(firstDateTime.addSecs(1)).toLatin1();
bad = bad.mid(bad.length()/2);
QDateTime lastDateTime = firstDateTime.addSecs(2);
QByteArray bytes;
bytes += QLocationTestUtils::createRmcSentence(firstDateTime).toLatin1();
bytes += bad;
bytes += QLocationTestUtils::createRmcSentence(lastDateTime).toLatin1();
QTest::newRow("requestUpdate(), bad second sentence") << bytes
<< (QList<QDateTime>() << firstDateTime) << RequestUpdatesMethod;
QTest::newRow("startUpdates(), bad second sentence") << bytes
<< (QList<QDateTime>() << firstDateTime << lastDateTime) << StartUpdatesMethod;
}