Commit 46a647e1 authored by Don Gagne's avatar Don Gagne

Merge pull request #1034 from DonLakeFlyer/FileDialogTest

QGCFileDialog can now be handled by unit test code
parents 6a7d5d42 e8c7680d
......@@ -615,7 +615,9 @@ SOURCES += \
src/ui/QGCUASFileView.cc \
src/uas/QGCUASWorker.cc \
src/CmdLineOptParser.cc \
src/uas/QGXPX4UAS.cc
src/uas/QGXPX4UAS.cc \
src/QGCFileDialog.cc
#
# Unit Test specific configuration goes here
......@@ -636,6 +638,7 @@ INCLUDEPATH += \
HEADERS += \
src/qgcunittest/UnitTest.h \
src/qgcunittest/MessageBoxTest.h \
src/qgcunittest/FileDialogTest.h \
src/qgcunittest/UASUnitTest.h \
src/qgcunittest/MockLink.h \
src/qgcunittest/MockLinkMissionItemHandler.h \
......@@ -655,8 +658,9 @@ HEADERS += \
SOURCES += \
src/qgcunittest/UnitTest.cc \
src/qgcunittest/UASUnitTest.cc \
src/qgcunittest/MessageBoxTest.cc \
src/qgcunittest/FileDialogTest.cc \
src/qgcunittest/UASUnitTest.cc \
src/qgcunittest/MockLink.cc \
src/qgcunittest/MockLinkMissionItemHandler.cc \
src/qgcunittest/MockUASManager.cc \
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
#include "QGCFileDialog.h"
#include "QGCApplication.h"
#ifdef QT_DEBUG
#include "UnitTest.h"
#endif
QString QGCFileDialog::getExistingDirectory(QWidget* parent,
const QString& caption,
const QString& dir,
Options options)
{
_validate(NULL, options);
#ifdef QT_DEBUG
if (qgcApp()->runningUnitTests()) {
return UnitTest::_getExistingDirectory(parent, caption, dir, options);
} else
#endif
{
return QFileDialog::getExistingDirectory(parent, caption, dir, options);
}
}
QString QGCFileDialog::getOpenFileName(QWidget* parent,
const QString& caption,
const QString& dir,
const QString& filter,
QString* selectedFilter,
Options options)
{
_validate(selectedFilter, options);
#ifdef QT_DEBUG
if (qgcApp()->runningUnitTests()) {
return UnitTest::_getOpenFileName(parent, caption, dir, filter, selectedFilter, options);
} else
#endif
{
return QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options);
}
}
QStringList QGCFileDialog::getOpenFileNames(QWidget* parent,
const QString& caption,
const QString& dir,
const QString& filter,
QString* selectedFilter,
Options options)
{
_validate(selectedFilter, options);
#ifdef QT_DEBUG
if (qgcApp()->runningUnitTests()) {
return UnitTest::_getOpenFileNames(parent, caption, dir, filter, selectedFilter, options);
} else
#endif
{
return QFileDialog::getOpenFileNames(parent, caption, dir, filter, selectedFilter, options);
}
}
QString QGCFileDialog::getSaveFileName(QWidget* parent,
const QString& caption,
const QString& dir,
const QString& filter,
QString* selectedFilter,
Options options)
{
_validate(selectedFilter, options);
#ifdef QT_DEBUG
if (qgcApp()->runningUnitTests()) {
return UnitTest::_getSaveFileName(parent, caption, dir, filter, selectedFilter, options);
} else
#endif
{
return QFileDialog::getSaveFileName(parent, caption, dir, filter, selectedFilter, options);
}
}
/// @brief Validates and updates the parameters for the file dialog calls
void QGCFileDialog::_validate(QString* selectedFilter, Options& options)
{
// You can't use QGCFileDialog if QGCApplication is not created yet.
Q_ASSERT(qgcApp());
// Support for selectedFilter is not yet implemented through the unit test framework
Q_UNUSED(selectedFilter);
Q_ASSERT(selectedFilter == NULL);
// On OSX native dialog can hang so we always use Qt dialogs
options | DontUseNativeDialog;
}
......@@ -29,23 +29,46 @@
/// @file
/// @brief Subclass of QFileDialog which re-implements the static public functions. The reason for this
/// is that the QFileDialog implementations of these use the native os dialogs. On OSX these
/// these can intermittently hang. So instead here we use the native dialogs.
/// these can intermittently hang. So instead here we use the native dialogs. It also allows
/// use to catch these dialogs for unit testing.
/// @author Don Gagne <don@thegagnes.com>
class QGCFileDialog : public QFileDialog {
public:
static QString getExistingDirectory(QWidget* parent = 0, const QString& caption = QString(), const QString& dir = QString(), Options options = ShowDirsOnly)
{ return QFileDialog::getExistingDirectory(parent, caption, dir, options | DontUseNativeDialog); }
static QString getExistingDirectory(QWidget* parent = 0,
const QString& caption = QString(),
const QString& dir = QString(),
Options options = ShowDirsOnly);
static QString getOpenFileName(QWidget* parent = 0, const QString& caption = QString(), const QString& dir = QString(), const QString& filter = QString(), QString* selectedFilter = 0, Options options = 0)
{ return QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options | DontUseNativeDialog); }
static QString getOpenFileName(QWidget* parent = 0,
const QString& caption = QString(),
const QString& dir = QString(),
const QString& filter = QString(),
QString* selectedFilter = 0,
Options options = 0);
static QStringList getOpenFileNames(QWidget* parent = 0, const QString& caption = QString(), const QString& dir = QString(), const QString& filter = QString(), QString* selectedFilter = 0, Options options = 0)
{ return QFileDialog::getOpenFileNames(parent, caption, dir, filter, selectedFilter, options | DontUseNativeDialog); }
static QStringList getOpenFileNames(QWidget* parent = 0,
const QString& caption = QString(),
const QString& dir = QString(),
const QString& filter = QString(),
QString* selectedFilter = 0,
Options options = 0);
static QString getSaveFileName(QWidget* parent = 0, const QString& caption = QString(), const QString& dir = QString(), const QString& filter = QString(), QString* selectedFilter = 0, Options options = 0)
{ return QFileDialog::getSaveFileName(parent, caption, dir, filter, selectedFilter, options | DontUseNativeDialog); }
static QString getSaveFileName(QWidget* parent = 0,
const QString& caption = QString(),
const QString& dir = QString(),
const QString& filter = QString(),
QString* selectedFilter = 0,
Options options = 0);
private slots:
/// @brief The exec slot is private becasue when only want QGCFileDialog users to use the static methods. Otherwise it will break
/// unit testing.
int exec(void) { return QGCFileDialog::exec(); }
private:
static void _validate(QString* selectedFilter, Options& options);
};
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
/// @file
/// @brief Unit test for QGCFileDialog catching mechanism.
///
/// @author Don Gagne <don@thegagnes.com>
#include "FileDialogTest.h"
#include "QGCFileDialog.h"
UT_REGISTER_TEST(FileDialogTest)
FileDialogTest::FileDialogTest(void)
{
}
void FileDialogTest::_fileDialogExpected_test(void)
{
QStringList response;
response << "" << "response";
for (int i=0; i<response.count(); i++) {
setExpectedFileDialog(getExistingDirectory, QStringList(response[i]));
QCOMPARE(QGCFileDialog::getExistingDirectory(), response[i]);
checkExpectedFileDialog();
}
for (int i=0; i<response.count(); i++) {
setExpectedFileDialog(getOpenFileName, QStringList(response[i]));
QCOMPARE(QGCFileDialog::getOpenFileName(), response[i]);
checkExpectedFileDialog();
}
for (int i=0; i<response.count(); i++) {
setExpectedFileDialog(getSaveFileName, QStringList(response[i]));
QCOMPARE(QGCFileDialog::getSaveFileName(), response[i]);
checkExpectedFileDialog();
}
QList<QStringList> responseList;
QStringList list;
responseList.append(QStringList());
responseList.append(QStringList("response1"));
list << "response1" << "response2";
responseList.append(list);
for (int i=0; i<responseList.count(); i++) {
setExpectedFileDialog(getOpenFileNames, responseList[i]);
QStringList retResponse = QGCFileDialog::getOpenFileNames();
checkExpectedFileDialog();
QCOMPARE(retResponse.count(), responseList[i].count());
for (int j=0; j<retResponse.count(); j++) {
QCOMPARE(retResponse[j], responseList[i][j]);
}
}
}
void FileDialogTest::_fileDialogUnexpected_test(void)
{
// This should cause an expected failure in the cleanup method
QGCFileDialog::getOpenFileName();
_expectMissedFileDialog = true;
}
void FileDialogTest::_previousFileDialog_test(void)
{
// This is the previous unexpected file dialog
QGCFileDialog::getOpenFileName();
// Setup for an expected message box.
QEXPECT_FAIL("", "Expecting failure due to previous file dialog", Continue);
setExpectedFileDialog(getOpenFileName, QStringList());
}
void FileDialogTest::_noFileDialog_test(void)
{
setExpectedFileDialog(getOpenFileName, QStringList());
checkExpectedFileDialog(expectFailNoDialog);
}
void FileDialogTest::_fileDialogExpectedIncorrect_test(void)
{
// Expecting save but get open dialog
setExpectedFileDialog(getSaveFileName, QStringList());
QGCFileDialog::getOpenFileName();
checkExpectedFileDialog(expectFailWrongFileDialog);
// This is going to fail in cleanup as well since we have a missed file dialog
_expectMissedFileDialog = true;
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
/// @file
/// @brief Unit test for QGCFileDialog catching mechanism.
///
/// @author Don Gagne <don@thegagnes.com>
#ifndef FILEDIALOGTEST_H
#define FILEDIALOGTEST_H
#include "UnitTest.h"
class FileDialogTest : public UnitTest
{
Q_OBJECT
public:
FileDialogTest(void);
private slots:
void _fileDialogExpected_test(void);
void _fileDialogUnexpected_test(void);
void _previousFileDialog_test(void);
void _noFileDialog_test(void);
void _fileDialogExpectedIncorrect_test(void);
};
#endif
......@@ -31,21 +31,11 @@
UT_REGISTER_TEST(MessageBoxTest)
MessageBoxTest::MessageBoxTest(void) :
_expectMissedMessageBox(false)
MessageBoxTest::MessageBoxTest(void)
{
}
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);
......@@ -57,7 +47,7 @@ void MessageBoxTest::_messageBoxExpected_test(void)
void MessageBoxTest::_messageBoxUnexpected_test(void)
{
// This should cause the test to fail in the cleanup method
// This should cause an expected failure in the cleanup method
QGCMessageBox::information(QString(), QString());
_expectMissedMessageBox = true;
}
......@@ -75,7 +65,7 @@ void MessageBoxTest::_previousMessageBox_test(void)
void MessageBoxTest::_noMessageBox_test(void)
{
setExpectedMessageBox(QMessageBox::Ok);
checkExpectedMessageBox(expectFailNoMessageBox);
checkExpectedMessageBox(expectFailNoDialog);
}
void MessageBoxTest::_badResponseButton_test(void)
......
......@@ -39,16 +39,11 @@ public:
MessageBoxTest(void);
private slots:
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
......@@ -139,8 +139,6 @@ 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<PX4RCCalibration::rcCalFunctionMax; function++) {
int chanIndex = _rgFunctionChannelMap[function];
......
......@@ -42,8 +42,6 @@ QGCUASFileManagerUnitTest::QGCUASFileManagerUnitTest(void) :
// Called once before all test cases are run
void QGCUASFileManagerUnitTest::initTestCase(void)
{
UnitTest::initTestCase();
_mockUAS.setMockSystemId(_systemIdServer);
_mockUAS.setMockMavlinkPlugin(&_mockFileServer);
}
......
This diff is collapsed.
......@@ -32,10 +32,12 @@
#include <QObject>
#include <QtTest>
#include <QMessageBox>
#include <QFileDialog>
#define UT_REGISTER_TEST(className) static UnitTestWrapper<className> t(#className);
class QGCMessageBox;
class QGCFileDialog;
class UnitTest;
class UnitTest : public QObject
......@@ -56,16 +58,34 @@ public:
/// @param response Response to take on message box
void setExpectedMessageBox(QMessageBox::StandardButton response);
/// @brief Types for UnitTest::setExpectedFileDialog
enum FileDialogType {
getExistingDirectory,
getOpenFileName,
getOpenFileNames,
getSaveFileName
};
/// @brief Sets up for an expected QGCFileDialog
/// @param type Type of expected file dialog
/// @param response Files to return from call. Multiple files only supported by getOpenFileNames
void setExpectedFileDialog(enum FileDialogType type, QStringList 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
expectFailNoDialog = 1 << 1, ///< expecting a failure due to no dialog displayed
expectFailBadResponseButton = 1 << 2, ///< expecting a failure due to bad button response (QGCMessageBox only)
expectFailWrongFileDialog = 1 << 3 ///< expecting one dialog type, got the wrong type (QGCFileDialog ony)
};
/// @brief Check whether a message box was displayed and correctly responded to
// @param Expected failure response flags
void checkExpectedMessageBox(int expectFailFlags = expectFailNoFailure);
/// @brief Check whether a message box was displayed and correctly responded to
// @param Expected failure response flags
void checkExpectedFileDialog(int expectFailFlags = expectFailNoFailure);
/// @brief Adds a unit test to the list. Should only be called by UnitTestWrapper.
static void _addTest(QObject* test);
......@@ -74,14 +94,6 @@ 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);
......@@ -103,24 +115,71 @@ protected:
/// @brief Must be called first by derived class implementation
void _cleanup(void);
bool _expectMissedFileDialog; // true: expect a missed file dialog, used for internal testing
bool _expectMissedMessageBox; // true: expect a missed message box, used for internal testing
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);
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;
// When the app is running in unit test mode the QGCFileDialog methods are re-routed here.
static QString _getExistingDirectory(QWidget* parent,
const QString& caption,
const QString& dir,
QFileDialog::Options options);
static QString _getOpenFileName(QWidget* parent,
const QString& caption,
const QString& dir,
const QString& filter,
QString* selectedFilter,
QFileDialog::Options options);
static QStringList _getOpenFileNames(QWidget* parent,
const QString& caption,
const QString& dir,
const QString& filter,
QString* selectedFilter,
QFileDialog::Options options);
static QString _getSaveFileName(QWidget* parent,
const QString& caption,
const QString& dir,
const QString& filter,
QString* selectedFilter,
QFileDialog::Options options);
static QString _fileDialogResponseSingle(enum FileDialogType type);
// This allows the private calls to the file dialog methods
friend class QGCFileDialog;
void _unitTestCalled(void);
static QList<QObject*>& _testList(void);
// Catch QGCMessageBox calls
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
// Catch QGCFileDialog calls
static bool _fileDialogRespondedTo; ///< File dialog was responded to
static bool _fileDialogResponseSet; ///< true: _fileDialogResponse was set by a call to UnitTest::setExpectedFileDialog
static QStringList _fileDialogResponse; ///< Response to next file dialog
static enum FileDialogType _fileDialogExpectedType; ///< type of file dialog expected to show
static int _missedFileDialogCount; ///< Count of file dialogs not checked with call to UnitTest::fileDialogWasDisplayed
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
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment