diff --git a/src/qgcunittest/MultiSignalSpy.cc b/src/qgcunittest/MultiSignalSpy.cc new file mode 100644 index 0000000000000000000000000000000000000000..1699dad43900109b6d7d7e2a5daa03d4c8f37b94 --- /dev/null +++ b/src/qgcunittest/MultiSignalSpy.cc @@ -0,0 +1,230 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#include "MultiSignalSpy.h" +#include +#include +#include + +/// @file +/// @brief This class allows you to keep track of signal counts on a set of signals associated with an object. +/// Mainly used for writing object unit tests. +/// +/// @author Don Gagne + +MultiSignalSpy::MultiSignalSpy(QObject* parent) : + QObject(parent), + _signalEmitter(NULL), + _rgSignals(NULL), + _cSignals(0) +{ +} + +MultiSignalSpy::~MultiSignalSpy() +{ + Q_ASSERT(_rgSignals); + + for (size_t i=0; i<_cSignals; i++) { + delete _rgSpys[i]; + } +} + +/// Initializes the class. Must be called once before use. +/// @return true if success, false for failure + +bool MultiSignalSpy::init( + QObject* signalEmitter, ///< [in] object which the signals are emitted from + const char** rgSignals, ///< [in] array of signals to spy on + size_t cSignals) ///< [in] numbers of signals in rgSignals +{ + if (!signalEmitter || !rgSignals || cSignals == 0) { + qDebug() << "Invalid arguments"; + return false; + } + + _signalEmitter = signalEmitter; + _rgSignals = rgSignals; + _cSignals = cSignals; + + // Allocate and connect QSignalSpy's + _rgSpys = new QSignalSpy*[_cSignals]; + Q_ASSERT(_rgSpys != NULL); + for (size_t i=0; i<_cSignals; i++) { + _rgSpys[i] = new QSignalSpy(_signalEmitter, _rgSignals[i]); + if (_rgSpys[i] == NULL) { + qDebug() << "Unabled to allocated QSignalSpy"; + return false; + } + if (!_rgSpys[i]->isValid()) { + qDebug() << "Invalid signal"; + return false; + } + } + + return true; +} + +/// @param mask bit mask specifying which signals to check. The lowest order bit represents +/// index 0 into the rgSignals array and so on up the bit mask. +/// @return true if signal count = 1 for the specified signals +bool MultiSignalSpy::checkSignalByMask(quint16 mask) +{ + for (size_t i=0; i<_cSignals; i++) { + if ((1 << i) & mask) { + QSignalSpy* spy = _rgSpys[i]; + Q_ASSERT(spy != NULL); + + if (spy->count() != 1) { + return false; + } + } + } + + return true; +} + +/// @return true if signal count = 1 for specified signals and signal count of 0 +/// for all other signals +bool MultiSignalSpy::checkOnlySignalByMask(quint16 mask) +{ + for (size_t i=0; i<_cSignals; i++) { + QSignalSpy* spy = _rgSpys[i]; + Q_ASSERT(spy != NULL); + + if ((1 << i) & mask) { + if (spy->count() != 1) { + return false; + } + } else { + if (spy->count() != 0) { + return false; + } + } + } + + return true; +} + +/// @return true if signal count = 0 for specified signals +bool MultiSignalSpy::checkNoSignalByMask(quint16 mask) +{ + for (size_t i=0; i<_cSignals; i++) { + if ((1 << i) & mask) { + QSignalSpy* spy = _rgSpys[i]; + Q_ASSERT(spy != NULL); + + if (spy->count() != 0) { + return false; + } + } + } + + return true; +} + +/// @return true if signal count = 0 on all signals +bool MultiSignalSpy::checkNoSignals(void) +{ + return checkNoSignalByMask(~0); +} + +/// @return QSignalSpy for the specified signal +QSignalSpy* MultiSignalSpy::getSpyByIndex(quint16 index) +{ + Q_ASSERT(index < _cSignals); + Q_ASSERT(_rgSpys[index] != NULL); + + return _rgSpys[index]; +} + +/// Sets the signal count to 0 for the specified signal +void MultiSignalSpy::clearSignalByIndex(quint16 index) +{ + Q_ASSERT(index < _cSignals); + Q_ASSERT(_rgSpys[index] != NULL); + + _rgSpys[index]->clear(); +} + +/// Sets the signal count to 0 for all specified signals +void MultiSignalSpy::clearSignalsByMask(quint16 mask) +{ + for (size_t i=0; i<_cSignals; i++) { + if ((1 << i) & mask) { + QSignalSpy* spy = _rgSpys[i]; + Q_ASSERT(spy != NULL); + + spy->clear(); + } + } +} + +/// Sets the signal count to 0 for all signals +void MultiSignalSpy::clearAllSignals(void) +{ + for (quint16 i=0;i<_cSignals; i++) { + clearSignalByIndex(i); + } +} + +void MultiSignalSpy::timerEvent(QTimerEvent * event) +{ + Q_UNUSED(event); + _timeout = true; +} + +/// Waits the specified signal +/// @return false for timeout +bool MultiSignalSpy::waitForSignalByIndex( + quint16 index, ///< [in] index of signal to wait on + int msec) ///< [in] numbers of milleconds to wait before timeout, -1 wait forever +{ + // Check input parameters + if (msec < -1 || msec == 0) + return false; + + // activate the timeout + _timeout = false; + int timerId; + if (msec != -1) { + timerId = startTimer(msec); + Q_ASSERT(timerId); + } else { + timerId = 0; + } + + // Begin waiting + QSignalSpy* spy = _rgSpys[index]; + Q_ASSERT(spy); + + while (spy->count() == 0 && !_timeout) { + QCoreApplication::processEvents(QEventLoop::AllEvents | QEventLoop::WaitForMoreEvents); + } + + // Clean up and return status + if (timerId) { + killTimer(timerId); + } + + return spy->count() != 0; +} diff --git a/src/qgcunittest/MultiSignalSpy.h b/src/qgcunittest/MultiSignalSpy.h new file mode 100644 index 0000000000000000000000000000000000000000..92fb905c16160f38bbb16a7a4541c92e6b1649ee --- /dev/null +++ b/src/qgcunittest/MultiSignalSpy.h @@ -0,0 +1,70 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#ifndef MULTISIGNALSPY_H +#define MULTISIGNALSPY_H + +#include +#include + +/// @file +/// @brief This class allows you to keep track of signal counts on a set of signals associated with an object. +/// Mainly used for writing object unit tests. +/// +/// @author Don Gagne + +class MultiSignalSpy : public QObject +{ + Q_OBJECT + +public: + MultiSignalSpy(QObject* parent = NULL); + ~MultiSignalSpy(); + + bool init(QObject* signalEmitter, const char** rgSignals, size_t cSignals); + + bool checkSignalByMask(quint16 mask); + bool checkOnlySignalByMask(quint16 mask); + bool checkNoSignalByMask(quint16 mask); + bool checkNoSignals(void); + + void clearSignalByIndex(quint16 index); + void clearSignalsByMask(quint16 mask); + void clearAllSignals(void); + + bool waitForSignalByIndex(quint16 index, int msec); + + QSignalSpy* getSpyByIndex(quint16 index); + +private: + // QObject overrides + void timerEvent(QTimerEvent * event); + + QObject* _signalEmitter; + const char** _rgSignals; + QSignalSpy** _rgSpys; + size_t _cSignals; + bool _timeout; +}; + +#endif