diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 4adb8287201db313000a85c764509c7de8a89c5c..b7fbd30729bd0405ab626847ae280ce315f5dd74 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -633,7 +633,8 @@ INCLUDEPATH += \ src/qgcunittest HEADERS += \ - src/qgcunittest/AutoTest.h \ + src/qgcunittest/UnitTest.h \ + src/qgcunittest/MessageBoxTest.h \ src/qgcunittest/UASUnitTest.h \ src/qgcunittest/MockLink.h \ src/qgcunittest/MockLinkMissionItemHandler.h \ @@ -651,7 +652,9 @@ HEADERS += \ src/qgcunittest/LinkManagerTest.h SOURCES += \ + src/qgcunittest/UnitTest.cc \ src/qgcunittest/UASUnitTest.cc \ + src/qgcunittest/MessageBoxTest.cc \ src/qgcunittest/MockLink.cc \ src/qgcunittest/MockLinkMissionItemHandler.cc \ src/qgcunittest/MockUASManager.cc \ diff --git a/src/QGCApplication.cc b/src/QGCApplication.cc index 05d6341b50b9d6e91793418df7b21d2c6cc9e5d4..445fe74f2b31cb8cb886a89dc6abfcf5af897f56 100644 --- a/src/QGCApplication.cc +++ b/src/QGCApplication.cc @@ -84,8 +84,9 @@ const char* QGCApplication::_savedFileParameterDirectoryName = "SavedParameters" **/ -QGCApplication::QGCApplication(int &argc, char* argv[]) : - QApplication(argc, argv) +QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting) : + QApplication(argc, argv), + _runningUnitTests(unitTesting) { Q_ASSERT(_app == NULL); _app = this; @@ -120,6 +121,13 @@ QGCApplication::QGCApplication(int &argc, char* argv[]) : // The setting will delete all settings on this boot fClearSettingsOptions |= settings.contains(_deleteAllSettingsKey); + // We don't want unit tests to use the same QSettings space as the normal app. So we tweak the app + // name. Also we want to run unit tests with clean settings every time. + if (_runningUnitTests) { + setApplicationName(applicationName().append("UnitTest")); + fClearSettingsOptions = true; + } + if (fClearSettingsOptions) { // User requested settings to be cleared on command line settings.clear(); diff --git a/src/QGCApplication.h b/src/QGCApplication.h index e51e20f9e238cf52d19fcb83a8fd7ae0585505a8..dc402e6f623c5f5faf9f8463a39dca8fbd84add6 100644 --- a/src/QGCApplication.h +++ b/src/QGCApplication.h @@ -54,7 +54,7 @@ class QGCApplication : public QApplication Q_OBJECT public: - QGCApplication(int &argc, char* argv[]); + QGCApplication(int &argc, char* argv[], bool unitTesting); ~QGCApplication(); /// @brief Sets the persistent flag to delete all settings the next time QGroundControl is started. @@ -94,6 +94,9 @@ public: /// @brief Destroys all singletons. Used by unit test code to reset global state. void destroySingletonsForUnitTest(void); + /// @brief Returns truee if unit test are being run + bool runningUnitTests(void) { return _runningUnitTests; } + public: /// @brief Perform initialize which is common to both normal application running and unit tests. /// Although public should only be called by main. @@ -122,6 +125,8 @@ private: static const char* _savedFileParameterDirectoryName; ///< Name of parameter subdirectory QList _singletons; ///< List of registered global singletons + + bool _runningUnitTests; ///< true: running unit tests, false: normal app }; /// @brief Returns the QGCApplication object singleton. diff --git a/src/QGCMessageBox.h b/src/QGCMessageBox.h index 4c16a5ddb18292eea44eb9db2a9d8a613ac49b86..54d54d8c3362a7a5980c11c9eba3cda2415f4d49 100644 --- a/src/QGCMessageBox.h +++ b/src/QGCMessageBox.h @@ -27,6 +27,8 @@ #include #include "MainWindow.h" +#include "QGCApplication.h" +#include "UnitTest.h" /// @file /// @brief Subclass of QMessageBox which re-implements the static public functions. There are two reasons for this: @@ -50,30 +52,81 @@ public: static StandardButton warning(const QString& title, const QString& text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton, QWidget* parent = NULL) { return _messageBox(QMessageBox::Warning, title, text, buttons, defaultButton, parent); } +private slots: + /// @brief The exec slot is private becasue when only want QGCMessageBox users to use the static methods. Otherwise it will break + /// unit testing. + int exec(void) { return QMessageBox::exec(); } + private: + static QWidget* _validateParameters(StandardButtons buttons, StandardButton* defaultButton, QWidget* parent) + { + // This is an obsolete bit which unit tests use for signalling. It should not be used in regular code. + Q_ASSERT(!(buttons & QMessageBox::Escape)); + + // If there is more than one button displayed, make sure a default button is set. Without this unit test code + // will not be able to respond to unexpected message boxes. + + unsigned int bits = static_cast(buttons); + int buttonCount = 0; + for (size_t i=0; i 1) { + Q_ASSERT(buttons & *defaultButton); + } else { + // Force default button to be set correctly for single button case to make unit test code simpler + *defaultButton = static_cast(static_cast(buttons)); + } + + return (parent == NULL) ? MainWindow::instance() : parent; + } + #ifdef Q_OS_MAC static StandardButton _messageBox(Icon icon, const QString& title, const QString& text, StandardButtons buttons, StandardButton defaultButton, QWidget* parent) { - if (parent == NULL) { - parent = MainWindow::instance(); + // You can't use QGCMessageBox if QGCApplication is not created yet. + Q_ASSERT(qgcApp()); + + parent = _validateParameters(buttons, &defaultButton, parent); + +#ifdef QT_DEBUG + if (qgcApp()->runningUnitTests()) { + return UnitTest::_messageBox(icon, title, text, buttons, defaultButton); + } else +#endif // QT_DEBUG + { + QString emptyTitle; + QMessageBox box(icon, emptyTitle, title, buttons, parent); + box.setDefaultButton(defaultButton); + box.setInformativeText(text); + return static_cast(box.exec()); } - QString emptyTitle; - QMessageBox box(icon, emptyTitle, title, buttons, parent); - box.setDefaultButton(defaultButton); - box.setInformativeText(text); - return static_cast(box.exec()); } #else static StandardButton _messageBox(Icon icon, const QString& title, const QString& text, StandardButtons buttons, StandardButton defaultButton, QWidget* parent) { - if (parent == NULL) { - parent = MainWindow::instance(); + // You can't use QGCMessageBox if QGCApplication is not created yet. + Q_ASSERT(qgcApp()); + + parent = _validateParameters(buttons, &defaultButton, parent); + +#ifdef QT_DEBUG + if (qgcApp()->runningUnitTests()) { + return UnitTest::_messageBox(icon, title, text, buttons, defaultButton); + } else +#endif // QT_DEBUG + { + QMessageBox box(icon, title, text, buttons, parent); + box.setDefaultButton(defaultButton); + return static_cast(box.exec()); } - QMessageBox box(icon, title, text, buttons, parent); - box.setDefaultButton(defaultButton); - return static_cast(box.exec()); } -#endif + +#endif // Q_OS_MAC }; #endif diff --git a/src/main.cc b/src/main.cc index 363658493258fda1fdf2ca18c563c8166293fcda..6a54ef6e295f580ba972ee9d4f14abd0a3c75412 100644 --- a/src/main.cc +++ b/src/main.cc @@ -37,7 +37,7 @@ This file is part of the QGROUNDCONTROL project #include "SerialLink.h" #include "TCPLink.h" #ifdef QT_DEBUG -#include "AutoTest.h" +#include "UnitTest.h" #include "CmdLineOptParser.h" #ifdef Q_OS_WIN #include @@ -104,11 +104,12 @@ int main(int argc, char *argv[]) qRegisterMetaType(); qRegisterMetaType(); + bool runUnitTests = false; // Run unit tests + #ifdef QT_DEBUG // We parse a small set of command line options here prior to QGCApplication in order to handle the ones // which need to be handled before a QApplication object is started. - bool runUnitTests = false; // Run unit test bool quietWindowsAsserts = false; // Don't let asserts pop dialog boxes CmdLineOpt_t rgCmdLineOptions[] = { @@ -126,7 +127,7 @@ int main(int argc, char *argv[]) } #endif - QGCApplication* app = new QGCApplication(argc, argv); + QGCApplication* app = new QGCApplication(argc, argv, runUnitTests); Q_CHECK_PTR(app); app->_initCommon(); @@ -140,13 +141,10 @@ int main(int argc, char *argv[]) } // Run the test - int failures = AutoTest::run(argc-1, argv, rgCmdLineOptions[0].optionArg); - if (failures == 0) - { + int failures = UnitTest::run(argc-1, argv, rgCmdLineOptions[0].optionArg); + if (failures == 0) { qDebug() << "ALL TESTS PASSED"; - } - else - { + } else { qDebug() << failures << " TESTS FAILED!"; } exitCode = -failures; diff --git a/src/qgcunittest/AutoTest.h b/src/qgcunittest/AutoTest.h deleted file mode 100755 index 5fcf5f857d574d70c75d16d1885a97ff9917845c..0000000000000000000000000000000000000000 --- a/src/qgcunittest/AutoTest.h +++ /dev/null @@ -1,83 +0,0 @@ -/** -* @author Rob Caldecott -* @note This was obtained from http://qtcreator.blogspot.com/2010/04/sample-multiple-unit-test-project.html -* -*/ - -#ifndef AUTOTEST_H -#define AUTOTEST_H - -#include -#include -#include -#include -#include "QGCApplication.h" - -namespace AutoTest -{ - typedef QList TestList; - - inline TestList& testList() - { - static TestList list; - return list; - } - - inline bool findObject(QObject* object) - { - TestList& list = testList(); - if (list.contains(object)) - { - return true; - } - foreach (QObject* test, list) - { - if (test->objectName() == object->objectName()) - { - return true; - } - } - return false; - } - - inline void addTest(QObject* object) - { - TestList& list = testList(); - if (!findObject(object)) - { - list.append(object); - } - } - - inline int run(int argc, char *argv[], QString& singleTest) - { - int ret = 0; - foreach (QObject* test, testList()) - { - if (singleTest.isEmpty() || singleTest == test->objectName()) { - qgcApp()->destroySingletonsForUnitTest(); - qgcApp()->createSingletonsForUnitTest(); - ret += QTest::qExec(test, argc, argv); - } - } - - return ret; - } -} - -template -class Test -{ -public: - QSharedPointer child; - - Test(const QString& name) : child(new T) - { - child->setObjectName(name); - AutoTest::addTest(child.data()); - } -}; - -#define DECLARE_TEST(className) static Test t(#className); - -#endif // AUTOTEST_H diff --git a/src/qgcunittest/FlightGearTest.cc b/src/qgcunittest/FlightGearTest.cc index 28b970501cf3b663d8f8aa4052b268ad545a1527..da6cdc3fa1eed41b0e09ae481674ead082081488 100644 --- a/src/qgcunittest/FlightGearTest.cc +++ b/src/qgcunittest/FlightGearTest.cc @@ -29,23 +29,13 @@ /// /// @author Don Gagne +UT_REGISTER_TEST(FlightGearUnitTest) + FlightGearUnitTest::FlightGearUnitTest(void) { } -// Called before every test -void FlightGearUnitTest::init(void) -{ - // Nothing here yet -} - -// Called after every test -void FlightGearUnitTest::cleanup(void) -{ - // Nothing here yet -} - /// @brief The QGCFlightGearLink::parseUIArguments method is fairly involved so we have a unit // test for it. void FlightGearUnitTest::_parseUIArguments_test(void) diff --git a/src/qgcunittest/FlightGearTest.h b/src/qgcunittest/FlightGearTest.h index 898006c6936bdc17fc8f35554da79afc71690814..a78aa4c4a09fea94a587ef5853b3c49a02313bcc 100644 --- a/src/qgcunittest/FlightGearTest.h +++ b/src/qgcunittest/FlightGearTest.h @@ -24,11 +24,7 @@ #ifndef TCPLINKTEST_H #define TCPLINKTEST_H -#include -#include -#include - -#include "AutoTest.h" +#include "UnitTest.h" #include "TCPLink.h" #include "MultiSignalSpy.h" @@ -37,7 +33,7 @@ /// /// @author Don Gagne -class FlightGearUnitTest : public QObject +class FlightGearUnitTest : public UnitTest { Q_OBJECT @@ -45,14 +41,12 @@ public: FlightGearUnitTest(void); private slots: - void init(void); - void cleanup(void); + UT_DECLARE_DEFAULT_initTestCase + UT_DECLARE_DEFAULT_cleanupTestCase + UT_DECLARE_DEFAULT_init + UT_DECLARE_DEFAULT_cleanup void _parseUIArguments_test(void); - -private: }; -DECLARE_TEST(FlightGearUnitTest) - #endif diff --git a/src/qgcunittest/LinkManagerTest.cc b/src/qgcunittest/LinkManagerTest.cc index fac38c407d4b264ace3b6c6064396c3ab4b85773..21f5f9feedab4310c72867c2932fe8d619f91e43 100644 --- a/src/qgcunittest/LinkManagerTest.cc +++ b/src/qgcunittest/LinkManagerTest.cc @@ -29,6 +29,8 @@ #include "LinkManagerTest.h" #include "MockLink.h" +UT_REGISTER_TEST(LinkManagerTest) + LinkManagerTest::LinkManagerTest(void) : _linkMgr(NULL), _multiSpy(NULL) @@ -38,6 +40,8 @@ LinkManagerTest::LinkManagerTest(void) : void LinkManagerTest::init(void) { + UnitTest::init(); + Q_ASSERT(_linkMgr == NULL); Q_ASSERT(_multiSpy == NULL); @@ -53,6 +57,8 @@ void LinkManagerTest::init(void) void LinkManagerTest::cleanup(void) { + UnitTest::cleanup(); + Q_ASSERT(_linkMgr); Q_ASSERT(_multiSpy); diff --git a/src/qgcunittest/LinkManagerTest.h b/src/qgcunittest/LinkManagerTest.h index d388f3c375fa43b2f5b569f874dd9a391f6bd2cc..220be0050b1af6337d61763780d2682f8173eccb 100644 --- a/src/qgcunittest/LinkManagerTest.h +++ b/src/qgcunittest/LinkManagerTest.h @@ -24,10 +24,7 @@ #ifndef UASUNITTEST_H #define UASUNITTEST_H -#include -#include - -#include "AutoTest.h" +#include "UnitTest.h" #include "LinkManager.h" #include "MultiSignalSpy.h" @@ -36,7 +33,7 @@ /// /// @author Don Gagne -class LinkManagerTest : public QObject +class LinkManagerTest : public UnitTest { Q_OBJECT @@ -44,6 +41,9 @@ public: LinkManagerTest(void); private slots: + UT_DECLARE_DEFAULT_initTestCase + UT_DECLARE_DEFAULT_cleanupTestCase + void init(void); void cleanup(void); @@ -69,9 +69,6 @@ private: MultiSignalSpy* _multiSpy; static const size_t _cSignals = maxSignalIndex; const char* _rgSignals[_cSignals]; - }; -DECLARE_TEST(LinkManagerTest) - #endif diff --git a/src/qgcunittest/MessageBoxTest.cc b/src/qgcunittest/MessageBoxTest.cc new file mode 100644 index 0000000000000000000000000000000000000000..45d796696a4776f790ea9dba9e8bfac1be072b9f --- /dev/null +++ b/src/qgcunittest/MessageBoxTest.cc @@ -0,0 +1,90 @@ +/*===================================================================== + + 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 . + + ======================================================================*/ + +/// @file +/// @brief The tests the unit test QGCMessageBox catching mechanism. +/// +/// @author Don Gagne + +#include "MessageBoxTest.h" +#include "QGCMessageBox.h" + +UT_REGISTER_TEST(MessageBoxTest) + +MessageBoxTest::MessageBoxTest(void) : + _expectMissedMessageBox(false) +{ + +} + +void MessageBoxTest::cleanup(void) +{ + if (_expectMissedMessageBox) { + _expectMissedMessageBox = false; + QEXPECT_FAIL("", "Supposed to fail in cleanup with a missed message box", Continue); + } + UnitTest::cleanup(); +} + +void MessageBoxTest::_messageBoxExpected_test(void) +{ + setExpectedMessageBox(QMessageBox::Ok); + + QCOMPARE(QGCMessageBox::information(QString(), QString()), QMessageBox::Ok); + + checkExpectedMessageBox(); +} + +void MessageBoxTest::_messageBoxUnexpected_test(void) +{ + // This should cause the test to fail in the cleanup method + QGCMessageBox::information(QString(), QString()); + _expectMissedMessageBox = true; +} + +void MessageBoxTest::_previousMessageBox_test(void) +{ + // This is the previous unexpected message box + QGCMessageBox::information(QString(), QString()); + + // Setup for an expected message box. + QEXPECT_FAIL("", "Expecting failure due to previous message boxes", Continue); + setExpectedMessageBox(QMessageBox::Ok); +} + +void MessageBoxTest::_noMessageBox_test(void) +{ + setExpectedMessageBox(QMessageBox::Ok); + checkExpectedMessageBox(expectFailNoMessageBox); +} + +void MessageBoxTest::_badResponseButton_test(void) +{ + setExpectedMessageBox(QMessageBox::Cancel); + + // Will return Ok even though Cancel was specified, since that was wrong + QCOMPARE(QGCMessageBox::information(QString(), QString()), QMessageBox::Ok); + + checkExpectedMessageBox(expectFailBadResponseButton); +} + diff --git a/src/qgcunittest/MessageBoxTest.h b/src/qgcunittest/MessageBoxTest.h new file mode 100644 index 0000000000000000000000000000000000000000..49602342ed8715cd97a354c287980d7a77206900 --- /dev/null +++ b/src/qgcunittest/MessageBoxTest.h @@ -0,0 +1,57 @@ +/*===================================================================== + + 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 . + + ======================================================================*/ + +/// @file +/// @brief The tests the unit test QGCMessageBox catching mechanism. +/// +/// @author Don Gagne + +#ifndef MESSAGEBOXTEST_H +#define MESSAGEBOXTEST_H + +#include "UnitTest.h" + +class MessageBoxTest : public UnitTest +{ + Q_OBJECT + +public: + MessageBoxTest(void); + +private slots: + UT_DECLARE_DEFAULT_initTestCase + UT_DECLARE_DEFAULT_cleanupTestCase + UT_DECLARE_DEFAULT_init + void cleanup(void); + + void _messageBoxExpected_test(void); + void _messageBoxUnexpected_test(void); + void _previousMessageBox_test(void); + void _noMessageBox_test(void); + void _badResponseButton_test(void); + +private: + bool _expectMissedMessageBox; +}; + +#endif diff --git a/src/qgcunittest/PX4RCCalibrationTest.cc b/src/qgcunittest/PX4RCCalibrationTest.cc index ce1af611635a557610eae6e093bbd273acf944a7..a1550bbc84ce63f4dfe02a1ebf8fc8bcfbfc63e1 100644 --- a/src/qgcunittest/PX4RCCalibrationTest.cc +++ b/src/qgcunittest/PX4RCCalibrationTest.cc @@ -30,6 +30,8 @@ /// /// @author Don Gagne +UT_REGISTER_TEST(PX4RCCalibrationTest) + // This will check for the wizard buttons being enabled of disabled according to the mask you pass in. // We use a macro instead of a method so that we get better line number reporting on failure. #define CHK_BUTTONS(mask) \ @@ -137,6 +139,8 @@ PX4RCCalibrationTest::PX4RCCalibrationTest(void) : /// @brief Called one time before any test cases are run. void PX4RCCalibrationTest::initTestCase(void) { + UnitTest::initTestCase(); + // Validate that our function to channel mapping is still correct. for (int function=0; function /// @brief PX4RCCalibration Widget unit test -class PX4RCCalibrationTest : public QObject +class PX4RCCalibrationTest : public UnitTest { Q_OBJECT @@ -45,6 +45,7 @@ public: private slots: void initTestCase(void); + UT_DECLARE_DEFAULT_cleanupTestCase void init(void); void cleanup(void); @@ -129,6 +130,4 @@ private: static const int _rgFunctionChannelMap[PX4RCCalibration::rcCalFunctionMax]; }; -DECLARE_TEST(PX4RCCalibrationTest) - #endif diff --git a/src/qgcunittest/QGCUASFileManagerTest.cc b/src/qgcunittest/QGCUASFileManagerTest.cc index 40d0ae20f7505f66e6f7047596878c0804fe93c3..47668c64f2d146a9f18d3723ca5f7b243a0434b9 100644 --- a/src/qgcunittest/QGCUASFileManagerTest.cc +++ b/src/qgcunittest/QGCUASFileManagerTest.cc @@ -30,17 +30,20 @@ /// /// @author Don Gagne +UT_REGISTER_TEST(QGCUASFileManagerUnitTest) + QGCUASFileManagerUnitTest::QGCUASFileManagerUnitTest(void) : _mockFileServer(_systemIdQGC, _systemIdServer), _fileManager(NULL), _multiSpy(NULL) { - } // Called once before all test cases are run void QGCUASFileManagerUnitTest::initTestCase(void) { + UnitTest::initTestCase(); + _mockUAS.setMockSystemId(_systemIdServer); _mockUAS.setMockMavlinkPlugin(&_mockFileServer); } @@ -48,6 +51,8 @@ void QGCUASFileManagerUnitTest::initTestCase(void) // Called before every test case void QGCUASFileManagerUnitTest::init(void) { + UnitTest::init(); + Q_ASSERT(_multiSpy == NULL); _fileManager = new QGCUASFileManager(NULL, &_mockUAS, _systemIdQGC); @@ -77,6 +82,8 @@ void QGCUASFileManagerUnitTest::init(void) // Called after every test case void QGCUASFileManagerUnitTest::cleanup(void) { + UnitTest::cleanup(); + Q_ASSERT(_multiSpy); Q_ASSERT(_fileManager); diff --git a/src/qgcunittest/QGCUASFileManagerTest.h b/src/qgcunittest/QGCUASFileManagerTest.h index 9b241747d3129c6154552ba8c54937e94ebc97ac..282ea56d3d10e68109ed5cfc55d43dbb94f14943 100644 --- a/src/qgcunittest/QGCUASFileManagerTest.h +++ b/src/qgcunittest/QGCUASFileManagerTest.h @@ -27,7 +27,7 @@ #include #include -#include "AutoTest.h" +#include "UnitTest.h" #include "MockUAS.h" #include "MockMavlinkFileServer.h" #include "QGCUASFileManager.h" @@ -38,7 +38,7 @@ /// /// @author Don Gagne -class QGCUASFileManagerUnitTest : public QObject +class QGCUASFileManagerUnitTest : public UnitTest { Q_OBJECT @@ -48,6 +48,7 @@ public: private slots: // Test case initialization void initTestCase(void); + UT_DECLARE_DEFAULT_cleanupTestCase void init(void); void cleanup(void); @@ -100,6 +101,4 @@ private: QStringList _fileListReceived; }; -DECLARE_TEST(QGCUASFileManagerUnitTest) - #endif diff --git a/src/qgcunittest/TCPLinkTest.cc b/src/qgcunittest/TCPLinkTest.cc index 4bf04a8c8adce555fc1b3974c6cc224b5df67f77..0dfa99000b693e2b66ffdb917873280adc7f873f 100644 --- a/src/qgcunittest/TCPLinkTest.cc +++ b/src/qgcunittest/TCPLinkTest.cc @@ -29,18 +29,24 @@ /// /// @author Don Gagne +// This unit test has gotten too flaky to run reliably under TeamCity. Removing for now till there is +// time to debug. +//UT_REGISTER_TEST(TCPLinkUnitTest) + TCPLinkUnitTest::TCPLinkUnitTest(void) : _link(NULL), _hostAddress(QHostAddress::LocalHost), _port(5760), _multiSpy(NULL) { - + } // Called before every test void TCPLinkUnitTest::init(void) { + UnitTest::init(); + Q_ASSERT(_link == NULL); Q_ASSERT(_multiSpy == NULL); @@ -63,6 +69,8 @@ void TCPLinkUnitTest::init(void) // Called after every test void TCPLinkUnitTest::cleanup(void) { + UnitTest::cleanup(); + Q_ASSERT(_multiSpy); Q_ASSERT(_link); diff --git a/src/qgcunittest/TCPLinkTest.h b/src/qgcunittest/TCPLinkTest.h index 30813bf87b40a3e0e93bce5dcf61249ba46de3e3..a4c21588a5d27302c1b6a3a5257503d1ffc1badf 100644 --- a/src/qgcunittest/TCPLinkTest.h +++ b/src/qgcunittest/TCPLinkTest.h @@ -24,11 +24,7 @@ #ifndef TCPLINKTEST_H #define TCPLINKTEST_H -#include -#include -#include - -#include "AutoTest.h" +#include "UnitTest.h" #include "TCPLink.h" #include "MultiSignalSpy.h" @@ -37,7 +33,7 @@ /// /// @author Don Gagne -class TCPLinkUnitTest : public QObject +class TCPLinkUnitTest : public UnitTest { Q_OBJECT @@ -49,6 +45,8 @@ signals: void waitForReadyRead(int msecs); private slots: + UT_DECLARE_DEFAULT_initTestCase + UT_DECLARE_DEFAULT_cleanupTestCase void init(void); void cleanup(void); @@ -89,8 +87,4 @@ private: const char* _rgSignals[_cSignals]; }; -// This unit test has gotten too flaky to run reliably under TeamCity. Removing for now till there is -// time to debug. -//DECLARE_TEST(TCPLinkUnitTest) - #endif diff --git a/src/qgcunittest/UASUnitTest.cc b/src/qgcunittest/UASUnitTest.cc index f42f5c32fafe9e8c767b7aa7e6ed0ef55b01836a..594b8b239371b0dde0df52b87817d9f205876c2a 100644 --- a/src/qgcunittest/UASUnitTest.cc +++ b/src/qgcunittest/UASUnitTest.cc @@ -3,55 +3,61 @@ #include #include +UT_REGISTER_TEST(UASUnitTest) + UASUnitTest::UASUnitTest() { } //This function is called after every test void UASUnitTest::init() { - mav = new MAVLinkProtocol(); - uas = new UAS(mav, QThread::currentThread(), UASID); - uas->deleteSettings(); + UnitTest::init(); + + _mavlink = new MAVLinkProtocol(); + _uas = new UAS(_mavlink, QThread::currentThread(), UASID); + _uas->deleteSettings(); } //this function is called after every test void UASUnitTest::cleanup() { - delete uas; - uas = NULL; + UnitTest::cleanup(); + + delete _uas; + _uas = NULL; - delete mav; - mav = NULL; + delete _mavlink; + _mavlink = NULL; } void UASUnitTest::getUASID_test() { // Test a default ID of zero is assigned - UAS* uas2 = new UAS(mav, QThread::currentThread()); + UAS* uas2 = new UAS(_mavlink, QThread::currentThread()); QCOMPARE(uas2->getUASID(), 0); delete uas2; // Test that the chosen ID was assigned at construction - QCOMPARE(uas->getUASID(), UASID); + QCOMPARE(_uas->getUASID(), UASID); // Make sure that no other ID was set QEXPECT_FAIL("", "When you set an ID it does not use the default ID of 0", Continue); - QCOMPARE(uas->getUASID(), 0); + QCOMPARE(_uas->getUASID(), 0); // Make sure that ID >= 0 - QCOMPARE(uas->getUASID(), 100); + QCOMPARE(_uas->getUASID(), 100); } void UASUnitTest::getUASName_test() { // Test that the name is build as MAV + ID - QCOMPARE(uas->getUASName(), "MAV " + QString::number(UASID)); + QCOMPARE(_uas->getUASName(), "MAV " + QString::number(UASID)); } void UASUnitTest::getUpTime_test() { - UAS* uas2 = new UAS(mav, QThread::currentThread()); + UAS* uas2 = new UAS(_mavlink, QThread::currentThread()); // Test that the uptime starts at zero to a // precision of seconds QCOMPARE(floor(uas2->getUptime()/1000.0), 0.0); @@ -69,12 +75,12 @@ void UASUnitTest::getUpTime_test() void UASUnitTest::getCommunicationStatus_test() { // Verify that upon construction the Comm status is disconnected - QCOMPARE(uas->getCommunicationStatus(), static_cast(UASInterface::COMM_DISCONNECTED)); + QCOMPARE(_uas->getCommunicationStatus(), static_cast(UASInterface::COMM_DISCONNECTED)); } void UASUnitTest::filterVoltage_test() { - float verificar=uas->filterVoltage(0.4f); + float verificar=_uas->filterVoltage(0.4f); // We allow the voltage returned to be within a small delta const float allowedDelta = 0.05f; @@ -84,153 +90,153 @@ void UASUnitTest::filterVoltage_test() void UASUnitTest:: getAutopilotType_test() { - int type = uas->getAutopilotType(); + int type = _uas->getAutopilotType(); // Verify that upon construction the autopilot is set to -1 QCOMPARE(type, -1); } void UASUnitTest::setAutopilotType_test() { - uas->setAutopilotType(2); + _uas->setAutopilotType(2); // Verify that the autopilot is set - QCOMPARE(uas->getAutopilotType(), 2); + QCOMPARE(_uas->getAutopilotType(), 2); } -//verify that the correct status is returned if a certain statue is given to uas +//verify that the correct status is returned if a certain statue is given to _uas void UASUnitTest::getStatusForCode_test() { QString state, desc; state = ""; desc = ""; - uas->getStatusForCode(MAV_STATE_UNINIT, state, desc); + _uas->getStatusForCode(MAV_STATE_UNINIT, state, desc); QVERIFY(state == "UNINIT"); - uas->getStatusForCode(MAV_STATE_UNINIT, state, desc); + _uas->getStatusForCode(MAV_STATE_UNINIT, state, desc); QVERIFY(state == "UNINIT"); - uas->getStatusForCode(MAV_STATE_BOOT, state, desc); + _uas->getStatusForCode(MAV_STATE_BOOT, state, desc); QVERIFY(state == "BOOT"); - uas->getStatusForCode(MAV_STATE_CALIBRATING, state, desc); + _uas->getStatusForCode(MAV_STATE_CALIBRATING, state, desc); QVERIFY(state == "CALIBRATING"); - uas->getStatusForCode(MAV_STATE_ACTIVE, state, desc); + _uas->getStatusForCode(MAV_STATE_ACTIVE, state, desc); QVERIFY(state == "ACTIVE"); - uas->getStatusForCode(MAV_STATE_STANDBY, state, desc); + _uas->getStatusForCode(MAV_STATE_STANDBY, state, desc); QVERIFY(state == "STANDBY"); - uas->getStatusForCode(MAV_STATE_CRITICAL, state, desc); + _uas->getStatusForCode(MAV_STATE_CRITICAL, state, desc); QVERIFY(state == "CRITICAL"); - uas->getStatusForCode(MAV_STATE_EMERGENCY, state, desc); + _uas->getStatusForCode(MAV_STATE_EMERGENCY, state, desc); QVERIFY(state == "EMERGENCY"); - uas->getStatusForCode(MAV_STATE_POWEROFF, state, desc); + _uas->getStatusForCode(MAV_STATE_POWEROFF, state, desc); QVERIFY(state == "SHUTDOWN"); - uas->getStatusForCode(5325, state, desc); + _uas->getStatusForCode(5325, state, desc); QVERIFY(state == "UNKNOWN"); } void UASUnitTest::getLocalX_test() { - QCOMPARE(uas->getLocalX(), 0.0); + QCOMPARE(_uas->getLocalX(), 0.0); } void UASUnitTest::getLocalY_test() { - QCOMPARE(uas->getLocalY(), 0.0); + QCOMPARE(_uas->getLocalY(), 0.0); } void UASUnitTest::getLocalZ_test() { - QCOMPARE(uas->getLocalZ(), 0.0); + QCOMPARE(_uas->getLocalZ(), 0.0); } void UASUnitTest::getLatitude_test() { - QCOMPARE(uas->getLatitude(), 0.0); + QCOMPARE(_uas->getLatitude(), 0.0); } void UASUnitTest::getLongitude_test() { - QCOMPARE(uas->getLongitude(), 0.0); + QCOMPARE(_uas->getLongitude(), 0.0); } void UASUnitTest::getAltitudeAMSL_test() { - QCOMPARE(uas->getAltitudeAMSL(), 0.0); + QCOMPARE(_uas->getAltitudeAMSL(), 0.0); } void UASUnitTest::getAltitudeRelative_test() { - QCOMPARE(uas->getAltitudeRelative(), 0.0); + QCOMPARE(_uas->getAltitudeRelative(), 0.0); } void UASUnitTest::getRoll_test() { - QCOMPARE(uas->getRoll(), 0.0); + QCOMPARE(_uas->getRoll(), 0.0); } void UASUnitTest::getPitch_test() { - QCOMPARE(uas->getPitch(), 0.0); + QCOMPARE(_uas->getPitch(), 0.0); } void UASUnitTest::getYaw_test() { - QCOMPARE(uas->getYaw(), 0.0); + QCOMPARE(_uas->getYaw(), 0.0); } void UASUnitTest::getSelected_test() { - QCOMPARE(uas->getSelected(), false); + QCOMPARE(_uas->getSelected(), false); } void UASUnitTest::getSystemType_test() { //check that system type is set to MAV_TYPE_GENERIC when initialized - QCOMPARE(uas->getSystemType(), 0); - uas->setSystemType(13); - QCOMPARE(uas->getSystemType(), 13); + QCOMPARE(_uas->getSystemType(), 0); + _uas->setSystemType(13); + QCOMPARE(_uas->getSystemType(), 13); } void UASUnitTest::getAirframe_test() { - //when uas is constructed, airframe is set to QGC_AIRFRAME_GENERIC - QVERIFY(uas->getAirframe() == UASInterface::QGC_AIRFRAME_GENERIC); + //when _uas is constructed, airframe is set to QGC_AIRFRAME_GENERIC + QVERIFY(_uas->getAirframe() == UASInterface::QGC_AIRFRAME_GENERIC); } void UASUnitTest::setAirframe_test() { //check at construction, that airframe=0 (GENERIC) - QVERIFY(uas->getAirframe() == UASInterface::QGC_AIRFRAME_GENERIC); + QVERIFY(_uas->getAirframe() == UASInterface::QGC_AIRFRAME_GENERIC); //check that set airframe works - uas->setAirframe(UASInterface::QGC_AIRFRAME_HEXCOPTER); - QVERIFY(uas->getAirframe() == UASInterface::QGC_AIRFRAME_HEXCOPTER); + _uas->setAirframe(UASInterface::QGC_AIRFRAME_HEXCOPTER); + QVERIFY(_uas->getAirframe() == UASInterface::QGC_AIRFRAME_HEXCOPTER); //check that setAirframe will not assign a number to airframe, that is //not defined in the enum - uas->setAirframe(UASInterface::QGC_AIRFRAME_END_OF_ENUM); - QVERIFY(uas->getAirframe() == UASInterface::QGC_AIRFRAME_HEXCOPTER); + _uas->setAirframe(UASInterface::QGC_AIRFRAME_END_OF_ENUM); + QVERIFY(_uas->getAirframe() == UASInterface::QGC_AIRFRAME_HEXCOPTER); } void UASUnitTest::getWaypointList_test() { - QList kk = uas->getWaypointManager()->getWaypointEditableList(); + QList kk = _uas->getWaypointManager()->getWaypointEditableList(); QCOMPARE(kk.count(), 0); Waypoint* wp = new Waypoint(0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,false, false, MAV_FRAME_GLOBAL, MAV_CMD_MISSION_START, "blah"); - uas->getWaypointManager()->addWaypointEditable(wp, true); + _uas->getWaypointManager()->addWaypointEditable(wp, true); - kk = uas->getWaypointManager()->getWaypointEditableList(); + kk = _uas->getWaypointManager()->getWaypointEditableList(); QCOMPARE(kk.count(), 1); wp = new Waypoint(); - uas->getWaypointManager()->addWaypointEditable(wp, false); + _uas->getWaypointManager()->addWaypointEditable(wp, false); - kk = uas->getWaypointManager()->getWaypointEditableList(); + kk = _uas->getWaypointManager()->getWaypointEditableList(); QCOMPARE(kk.count(), 2); - uas->getWaypointManager()->removeWaypoint(1); - kk = uas->getWaypointManager()->getWaypointEditableList(); + _uas->getWaypointManager()->removeWaypoint(1); + kk = _uas->getWaypointManager()->getWaypointEditableList(); QCOMPARE(kk.count(), 1); - uas->getWaypointManager()->removeWaypoint(0); - kk = uas->getWaypointManager()->getWaypointEditableList(); + _uas->getWaypointManager()->removeWaypoint(0); + kk = _uas->getWaypointManager()->getWaypointEditableList(); QCOMPARE(kk.count(), 0); qDebug()<<"disconnect SIGNAL waypointListChanged"; @@ -241,16 +247,16 @@ void UASUnitTest::getWaypoint_test() { Waypoint* wp = new Waypoint(0,5.6,2.0,3.0,0.0,0.0,0.0,0.0,false, false, MAV_FRAME_GLOBAL, MAV_CMD_MISSION_START, "blah"); - uas->getWaypointManager()->addWaypointEditable(wp, true); + _uas->getWaypointManager()->addWaypointEditable(wp, true); - QList wpList = uas->getWaypointManager()->getWaypointEditableList(); + QList wpList = _uas->getWaypointManager()->getWaypointEditableList(); QCOMPARE(wpList.count(), 1); QCOMPARE(static_cast(0), static_cast(wpList.at(0))->getId()); Waypoint* wp3 = new Waypoint(1, 5.6, 2.0, 3.0); - uas->getWaypointManager()->addWaypointEditable(wp3, true); - wpList = uas->getWaypointManager()->getWaypointEditableList(); + _uas->getWaypointManager()->addWaypointEditable(wp3, true); + wpList = _uas->getWaypointManager()->getWaypointEditableList(); Waypoint* wp2 = static_cast(wpList.at(0)); QCOMPARE(wpList.count(), 2); @@ -267,34 +273,34 @@ void UASUnitTest::getWaypoint_test() void UASUnitTest::signalWayPoint_test() { - QSignalSpy spy(uas->getWaypointManager(), SIGNAL(waypointEditableListChanged())); + QSignalSpy spy(_uas->getWaypointManager(), SIGNAL(waypointEditableListChanged())); Waypoint* wp = new Waypoint(0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,false, false, MAV_FRAME_GLOBAL, MAV_CMD_MISSION_START, "blah"); - uas->getWaypointManager()->addWaypointEditable(wp, true); + _uas->getWaypointManager()->addWaypointEditable(wp, true); QCOMPARE(spy.count(), 1); // 1 listChanged for add wayPoint - uas->getWaypointManager()->removeWaypoint(0); + _uas->getWaypointManager()->removeWaypoint(0); QCOMPARE(spy.count(), 2); // 2 listChanged for remove wayPoint - QSignalSpy spyDestroyed(uas->getWaypointManager(), SIGNAL(destroyed())); + QSignalSpy spyDestroyed(_uas->getWaypointManager(), SIGNAL(destroyed())); QVERIFY(spyDestroyed.isValid()); QCOMPARE( spyDestroyed.count(), 0 ); - delete uas;// delete(destroyed) uas for validating - uas = NULL; - QCOMPARE(spyDestroyed.count(), 1);// count destroyed uas should are 1 - uas = new UAS(mav, QThread::currentThread(), UASID); - QSignalSpy spy2(uas->getWaypointManager(), SIGNAL(waypointEditableListChanged())); + delete _uas;// delete(destroyed) _uas for validating + _uas = NULL; + QCOMPARE(spyDestroyed.count(), 1);// count destroyed _uas should are 1 + _uas = new UAS(_mavlink, QThread::currentThread(), UASID); + QSignalSpy spy2(_uas->getWaypointManager(), SIGNAL(waypointEditableListChanged())); QCOMPARE(spy2.count(), 0); Waypoint* wp2 = new Waypoint(0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,false, false, MAV_FRAME_GLOBAL, MAV_CMD_MISSION_START, "blah"); - uas->getWaypointManager()->addWaypointEditable(wp2, true); + _uas->getWaypointManager()->addWaypointEditable(wp2, true); QCOMPARE(spy2.count(), 1); - uas->getWaypointManager()->clearWaypointList(); - QList wpList = uas->getWaypointManager()->getWaypointEditableList(); + _uas->getWaypointManager()->clearWaypointList(); + QList wpList = _uas->getWaypointManager()->getWaypointEditableList(); QCOMPARE(wpList.count(), 1); - delete uas; - uas = NULL; + delete _uas; + _uas = NULL; delete wp2; } diff --git a/src/qgcunittest/UASUnitTest.h b/src/qgcunittest/UASUnitTest.h index ea2e1897c242f6697fa5eb3d42773d9087a0e4c8..d84e3fb09bcf8bed509d26836c0c52116519b833 100644 --- a/src/qgcunittest/UASUnitTest.h +++ b/src/qgcunittest/UASUnitTest.h @@ -1,60 +1,60 @@ #ifndef UASUNITTEST_H #define UASUNITTEST_H -#include -#include -#include -#include - #include "UAS.h" #include "MAVLinkProtocol.h" #include "SerialLink.h" #include "UASInterface.h" -#include "AutoTest.h" +#include "UnitTest.h" #include "LinkManager.h" #include "UASWaypointManager.h" #include "SerialLink.h" #include "LinkInterface.h" -class UASUnitTest : public QObject +#define UASID 100 + +class UASUnitTest : public UnitTest { Q_OBJECT + public: - #define UASID 100 - MAVLinkProtocol* mav; - UAS* uas; - UASUnitTest(); + UASUnitTest(void); private slots: - void init(); - void cleanup(); - - void getUASID_test(); - void getUASName_test(); - void getUpTime_test(); - void getCommunicationStatus_test(); - void filterVoltage_test(); - void getAutopilotType_test(); - void setAutopilotType_test(); - void getStatusForCode_test(); - void getLocalX_test(); - void getLocalY_test(); - void getLocalZ_test(); - void getLatitude_test(); - void getLongitude_test(); - void getAltitudeAMSL_test(); - void getAltitudeRelative_test(); - void getRoll_test(); - void getPitch_test(); - void getYaw_test(); - void getSelected_test(); - void getSystemType_test(); - void getAirframe_test(); - void setAirframe_test(); - void getWaypointList_test(); - void signalWayPoint_test(); - void getWaypoint_test(); + UT_DECLARE_DEFAULT_initTestCase + UT_DECLARE_DEFAULT_cleanupTestCase + void init(void); + void cleanup(void); + + void getUASID_test(void); + void getUASName_test(void); + void getUpTime_test(void); + void getCommunicationStatus_test(void); + void filterVoltage_test(void); + void getAutopilotType_test(void); + void setAutopilotType_test(void); + void getStatusForCode_test(void); + void getLocalX_test(void); + void getLocalY_test(void); + void getLocalZ_test(void); + void getLatitude_test(void); + void getLongitude_test(void); + void getAltitudeAMSL_test(void); + void getAltitudeRelative_test(void); + void getRoll_test(void); + void getPitch_test(void); + void getYaw_test(void); + void getSelected_test(void); + void getSystemType_test(void); + void getAirframe_test(void); + void setAirframe_test(void); + void getWaypointList_test(void); + void signalWayPoint_test(void); + void getWaypoint_test(void); + +private: + MAVLinkProtocol* _mavlink; + UAS* _uas; }; -DECLARE_TEST(UASUnitTest) -#endif // UASUNITTEST_H +#endif diff --git a/src/qgcunittest/UnitTest.cc b/src/qgcunittest/UnitTest.cc new file mode 100644 index 0000000000000000000000000000000000000000..a00627e08aa2d626ed9e0b7891843380853df603 --- /dev/null +++ b/src/qgcunittest/UnitTest.cc @@ -0,0 +1,202 @@ +/*===================================================================== + + 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 . + + ======================================================================*/ + +/// @file +/// @brief Base class for all unit tests +/// +/// @author Don Gagne + +#include "UnitTest.h" +#include "QGCApplication.h" + +bool UnitTest::_messageBoxRespondedTo = false; +bool UnitTest::_badResponseButton = false; +QMessageBox::StandardButton UnitTest::_messageBoxResponseButton = QMessageBox::NoButton; +int UnitTest::_missedMessageBoxCount = 0; +UnitTest::UnitTestList_t UnitTest::_tests; + +UnitTest::UnitTest(void) : + _unitTestRun(false), + _initTestCaseCalled(false), + _cleanupTestCaseCalled(false), + _initCalled(false), + _cleanupCalled(false) +{ + +} + +UnitTest::~UnitTest() +{ + if (_unitTestRun) { + // Derived classes must call base class implementations + Q_ASSERT(_initTestCaseCalled); + Q_ASSERT(_cleanupTestCaseCalled); + Q_ASSERT(_initCalled); + Q_ASSERT(_cleanupCalled); + } +} + +void UnitTest::_addTest(QObject* test) +{ + Q_ASSERT(!_tests.contains(test)); + + _tests.append(test); +} + +void UnitTest::_unitTestCalled(void) +{ + _unitTestRun = true; +} + +int UnitTest::run(int argc, char *argv[], QString& singleTest) +{ + int ret = 0; + + foreach (QObject* test, _tests) { + if (singleTest.isEmpty() || singleTest == test->objectName()) { + ret += QTest::qExec(test, argc, argv); + } + } + + return ret; +} + +/// @brief Called at the initialization of the entire unit test. +/// Make sure to call first in your derived class +void UnitTest::initTestCase(void) +{ + _initTestCaseCalled = true; + + _activeUnitTest = this; + _missedMessageBoxCount = 0; + _badResponseButton = false; +} + +/// @brief Called at the end of the entire unit test. +/// Make sure to call first in your derived class +void UnitTest::cleanupTestCase(void) +{ + _cleanupTestCaseCalled = true; + + Q_ASSERT(_activeUnitTest != NULL); + _activeUnitTest = NULL; + + int missedMessageBoxCount = _missedMessageBoxCount; + _missedMessageBoxCount = 0; + + // Make sure to reset any needed variables since this can fall and cause the rest of the method to be skipped + QCOMPARE(missedMessageBoxCount, 0); +} + +/// @brief Called before each test. +/// Make sure to call first in your derived class +void UnitTest::init(void) +{ + _initCalled = true; + + _messageBoxRespondedTo = false; + _missedMessageBoxCount = 0; + _badResponseButton = false; + _messageBoxResponseButton = QMessageBox::NoButton; + + // Each test gets a clean global state + qgcApp()->destroySingletonsForUnitTest(); + qgcApp()->createSingletonsForUnitTest(); +} + +/// @brief Called after each test. +/// Make sure to call first in your derived class +void UnitTest::cleanup(void) +{ + _cleanupCalled = true; + + int missedMessageBoxCount = _missedMessageBoxCount; + _missedMessageBoxCount = 0; + + // Make sure to reset any needed variables since this can fall and cause the rest of the method to be skipped + QCOMPARE(missedMessageBoxCount, 0); +} + +void UnitTest::setExpectedMessageBox(QMessageBox::StandardButton response) +{ + Q_ASSERT(!_messageBoxRespondedTo); + + // We use an obsolete StandardButton value to signal that response button has not been set. So you can't use this. + Q_ASSERT(response != QMessageBox::NoButton); + Q_ASSERT(_messageBoxResponseButton == QMessageBox::NoButton); + + int missedMessageBoxCount = _missedMessageBoxCount; + _missedMessageBoxCount = 0; + + QCOMPARE(missedMessageBoxCount, 0); + + _messageBoxResponseButton = response; +} + +void UnitTest::checkExpectedMessageBox(int expectFailFlags) +{ + // Previous call to setExpectedMessageBox should have already checked this + Q_ASSERT(_missedMessageBoxCount == 0); + + // Check for a valid response + + if (expectFailFlags & expectFailBadResponseButton) { + QEXPECT_FAIL("", "Expecting failure due to bad button response", Continue); + } + QCOMPARE(_badResponseButton, false); + + if (expectFailFlags & expectFailNoMessageBox) { + QEXPECT_FAIL("", "Expecting failure due to no message box", Continue); + } + QCOMPARE(_messageBoxRespondedTo, true); +} + +QMessageBox::StandardButton UnitTest::_messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) +{ + QMessageBox::StandardButton retButton; + + Q_UNUSED(icon); + Q_UNUSED(title); + Q_UNUSED(text); + + if (_messageBoxResponseButton == QMessageBox::NoButton) { + // If no response button is set it means we were not expecting this message box. Response with default + _missedMessageBoxCount++; + retButton = defaultButton; + } else { + if (_messageBoxResponseButton & buttons) { + // Everything is correct, use the specified response + retButton = _messageBoxResponseButton; + } else { + // Trying to respond with a button not in the dialog. This is an error. Respond with default + _badResponseButton = true; + retButton = defaultButton; + } + _messageBoxRespondedTo = true; + } + + // Clear response for next message box + _messageBoxResponseButton = QMessageBox::NoButton; + + return retButton; +} diff --git a/src/qgcunittest/UnitTest.h b/src/qgcunittest/UnitTest.h new file mode 100644 index 0000000000000000000000000000000000000000..5dd7668de1f02474a0ad4e369ae8284de6866551 --- /dev/null +++ b/src/qgcunittest/UnitTest.h @@ -0,0 +1,160 @@ +/*===================================================================== + + 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 . + + ======================================================================*/ + +/// @file +/// @brief Base class for all unit tests +/// +/// @author Don Gagne + +#ifndef UNITTEST_H +#define UNITTEST_H + +#include +#include +#include + +#define UT_REGISTER_TEST(className) static UnitTestWrapper t(#className); + +/// @brief If you don't need you own specific implemenation of the test case setup methods +/// you can use these macros to declare the default implementation which just calls +/// the base class. + +#define UT_DECLARE_DEFAULT_initTestCase +//virtual void initTestCase(void) { UnitTest::_initTestCase(); } +#define UT_DECLARE_DEFAULT_cleanupTestCase +// virtual void cleanupTestCase(void) { UnitTest::_cleanupTestCase(); } +#define UT_DECLARE_DEFAULT_init +//virtual void init(void) { UnitTest::_init(); } +#define UT_DECLARE_DEFAULT_cleanup +//virtual void cleanup(void) { UnitTest::_cleanup(); } + +class QGCMessageBox; +class UnitTest; + +static UnitTest* _activeUnitTest = NULL; ///< Currently active unit test + +class UnitTest : public QObject +{ + Q_OBJECT + +public: + UnitTest(void); + virtual ~UnitTest(void); + + /// @brief Called to run all the registered unit tests + /// @param argc argc from main + /// @param argv argv from main + /// @param singleTest Name of test to just run a single test + static int run(int argc, char *argv[], QString& singleTest); + + /// @brief Sets up for an expected QGCMessageBox + /// @param response Response to take on message box + void setExpectedMessageBox(QMessageBox::StandardButton response); + + enum { + expectFailNoFailure = 1 << 0, ///< not expecting any failures + expectFailNoMessageBox = 1 << 1, ///< expecting a failure due to no message box displayed + expectFailBadResponseButton = 1 << 2 ///< expecting a failure due to bad button response + }; + + /// @brief Check whether a message box was displayed and correctly responded to + // @param Expected failure response flags + void checkExpectedMessageBox(int expectFailFlags = expectFailNoFailure); + + // Should only be called by UnitTestWrapper + static void _addTest(QObject* test); + +protected slots: + + // These are all pure virtuals to force the derived class to implement each one and in turn + // call the UnitTest private implementation. + + /// @brief Called at the initialization of the entire unit test. + /// Make sure to call _initTestCase first in your derived class. + virtual void initTestCase(void); + + /// @brief Called at the end of the entire unit test. + /// Make sure to call _cleanupTestCase first in your derived class. + virtual void cleanupTestCase(void); + + /// @brief Called before each test. + /// Make sure to call _init first in your derived class. + virtual void init(void); + + /// @brief Called after each test. + /// Make sure to call _cleanup first in your derived class. + virtual void cleanup(void); + +protected: + /// @brief Must be called first by derived class implementation + void _initTestCase(void); + + /// @brief Must be called first by derived class implementation + void _cleanupTestCase(void); + + /// @brief Must be called first by derived class implementation + void _init(void); + + /// @brief Must be called first by derived class implementation + void _cleanup(void); + +private: + // When the app is running in unit test mode the QGCMessageBox methods are re-routed here. + static QMessageBox::StandardButton _messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton); + + // This allows the private call to _messageBox + friend class QGCMessageBox; + + void _unitTestCalled(void); + + static bool _messageBoxRespondedTo; ///< Message box was responded to + static bool _badResponseButton; ///< Attempt to repond to expected message box with button not being displayed + static QMessageBox::StandardButton _messageBoxResponseButton; ///< Response to next message box + static int _missedMessageBoxCount; ///< Count of message box not checked with call to messageBoxWasDisplayed + + bool _unitTestRun; ///< true: Unit Test was run + bool _initTestCaseCalled; ///< true: UnitTest::_initTestCase was called + bool _cleanupTestCaseCalled; ///< true: UnitTest::_cleanupTestCase was called + bool _initCalled; ///< true: UnitTest::_init was called + bool _cleanupCalled; ///< true: UnitTest::_cleanup was called + + typedef QList UnitTestList_t; + + static UnitTestList_t _tests; +}; + +template +class UnitTestWrapper { +public: + UnitTestWrapper(const QString& name) : + _unitTest(new T) + { + _unitTest->setObjectName(name); + UnitTest::_addTest(_unitTest.data()); + } + +private: + QSharedPointer _unitTest; +}; + +#endif