UnitTest.h 8.24 KB
Newer Older
Don Gagne's avatar
Don Gagne committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/*=====================================================================
 
 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 Base class for all unit tests
///
///     @author Don Gagne <don@thegagnes.com>

#ifndef UNITTEST_H
#define UNITTEST_H

#include <QObject>
#include <QtTest>
#include <QMessageBox>
35
#include <QFileDialog>
Don Gagne's avatar
Don Gagne committed
36 37 38 39

#define UT_REGISTER_TEST(className) static UnitTestWrapper<className> t(#className);

class QGCMessageBox;
40
class QGCFileDialog;
Don Gagne's avatar
Don Gagne committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
class UnitTest;

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);
    
61 62 63 64 65 66 67 68 69 70 71 72 73
    /// @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);
    
Don Gagne's avatar
Don Gagne committed
74 75
    enum {
        expectFailNoFailure =           1 << 0, ///< not expecting any failures
76 77 78
        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)
Don Gagne's avatar
Don Gagne committed
79 80 81 82 83 84
    };
    
    /// @brief Check whether a message box was displayed and correctly responded to
    //          @param Expected failure response flags
    void checkExpectedMessageBox(int expectFailFlags = expectFailNoFailure);
    
85 86 87 88
    /// @brief Check whether a message box was displayed and correctly responded to
    //          @param Expected failure response flags
    void checkExpectedFileDialog(int expectFailFlags = expectFailNoFailure);
    
Don Gagne's avatar
Don Gagne committed
89
    /// @brief Adds a unit test to the list. Should only be called by UnitTestWrapper.
Don Gagne's avatar
Don Gagne committed
90
    static void _addTest(QObject* test);
Don Gagne's avatar
Don Gagne committed
91

Don Gagne's avatar
Don Gagne committed
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
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 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);
    
118 119 120
    bool _expectMissedFileDialog;   // true: expect a missed file dialog, used for internal testing
    bool _expectMissedMessageBox;   // true: expect a missed message box, used for internal testing
    
Don Gagne's avatar
Don Gagne committed
121 122
private:
    // When the app is running in unit test mode the QGCMessageBox methods are re-routed here.
123 124 125 126 127 128
    
    static QMessageBox::StandardButton _messageBox(QMessageBox::Icon icon,
                                                   const QString& title,
                                                   const QString& text,
                                                   QMessageBox::StandardButtons buttons,
                                                   QMessageBox::StandardButton defaultButton);
Don Gagne's avatar
Don Gagne committed
129 130 131 132
    
    // This allows the private call to _messageBox
    friend class QGCMessageBox;
    
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
    // 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;

Don Gagne's avatar
Don Gagne committed
166
    void _unitTestCalled(void);
Don Gagne's avatar
Don Gagne committed
167 168
	static QList<QObject*>& _testList(void);

169
    // Catch QGCMessageBox calls
Don Gagne's avatar
Don Gagne committed
170 171 172 173 174
    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
    
175 176 177 178 179 180 181
    // 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
    
Don Gagne's avatar
Don Gagne committed
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    bool _unitTestRun;              ///< true: Unit Test was run
    bool _initCalled;               ///< true: UnitTest::_init was called
    bool _cleanupCalled;            ///< true: UnitTest::_cleanup was called
};

template <class T>
class UnitTestWrapper {
public:
    UnitTestWrapper(const QString& name) :
        _unitTest(new T)
    {
        _unitTest->setObjectName(name);
        UnitTest::_addTest(_unitTest.data());
    }

private:
    QSharedPointer<T> _unitTest;
};

#endif