Add QVERIFY_EXCEPTION_THROWN macro for testing exceptions using QtTest

New macro QVERIFY_EXCEPTION_THROWN may be used to check that some code
really throws an exception of specified type.

Change-Id: I7cf499c7c37a35407862bc604c6eb862c5f329d3
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Jason McDonald <macadder1@gmail.com>
This commit is contained in:
Dmitry Ashkadov 2013-10-11 14:05:01 +04:00 committed by The Qt Project
parent 5d8c05baf4
commit 4a9092eaad
11 changed files with 396 additions and 0 deletions

View File

@ -165,6 +165,25 @@ QT_BEGIN_NAMESPACE
\sa QVERIFY(), QTRY_COMPARE(), QTest::toString()
*/
/*! \macro QVERIFY_EXCEPTION_THROWN(expression, exceptiontype)
\since 5.3
\relates QTest
The QVERIFY_EXCEPTION_THROWN macro executes an \a expression and tries
to catch an exception thrown from the \a expression. If the \a expression
throws an exception and its type is the same as \a exceptiontype
or \a exceptiontype is substitutable with the type of thrown exception
(i.e. usually the type of thrown exception is publically derived
from \a exceptiontype) then execution will be continued. If not-substitutable
type of exception is thrown or the \a expression doesn't throw an exception
at all, then a failure will be recorded in the test log and
the test won't be executed further.
\note This macro can only be used in a test function that is invoked
by the test framework.
*/
/*! \macro QTRY_VERIFY_WITH_TIMEOUT(condition, timeout)
\since 5.0

View File

@ -51,6 +51,11 @@
#include <string.h>
#ifndef QT_NO_EXCEPTIONS
# include <exception>
#endif // QT_NO_EXCEPTIONS
QT_BEGIN_NAMESPACE
class QRegularExpression;
@ -84,6 +89,46 @@ do {\
return;\
} while (0)
#ifndef QT_NO_EXCEPTIONS
# define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \
do {\
QT_TRY {\
QT_TRY {\
expression;\
QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \
" but no exception caught", __FILE__, __LINE__);\
return;\
} QT_CATCH (const exceptiontype &) {\
}\
} QT_CATCH (const std::exception &e) {\
QByteArray msg = QByteArray() + "Expected exception of type " #exceptiontype \
" to be thrown but std::exception caught with message: " + e.what(); \
QTest::qFail(msg.constData(), __FILE__, __LINE__);\
return;\
} QT_CATCH (...) {\
QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \
" but unknown exception caught", __FILE__, __LINE__);\
return;\
}\
} while (0)
#else // QT_NO_EXCEPTIONS
/*
* The expression passed to the macro should throw an exception and we can't
* catch it because Qt has been compiled without exception support. We can't
* skip the expression because it may have side effects and must be executed.
* So, users must use Qt with exception support enabled if they use exceptions
* in their code.
*/
# define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \
Q_STATIC_ASSERT_X(false, "Support of exceptions is disabled")
#endif // !QT_NO_EXCEPTIONS
// Will try to wait for the expression to become true while allowing event processing
#define QTRY_VERIFY_WITH_TIMEOUT(__expr, __timeout) \
do { \

View File

@ -0,0 +1,49 @@
<Environment>
<QtVersion>@INSERT_QT_VERSION_HERE@</QtVersion>
<QTestVersion>@INSERT_QT_VERSION_HERE@</QTestVersion>
</Environment>
<TestFunction name="initTestCase">
<Incident type="pass" file="" line="0" />
</TestFunction>
<TestFunction name="testCorrectStdTypes">
<Incident type="pass" file="" line="0" />
</TestFunction>
<TestFunction name="testCorrectStdExceptions">
<Incident type="pass" file="" line="0" />
</TestFunction>
<TestFunction name="testCorrectMyExceptions">
<Incident type="pass" file="" line="0" />
</TestFunction>
<TestFunction name="testFailInt">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="128">
<Description><![CDATA[Expected exception of type double to be thrown but unknown exception caught]]></Description>
</Incident>
</TestFunction>
<TestFunction name="testFailStdString">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="133">
<Description><![CDATA[Expected exception of type char* to be thrown but unknown exception caught]]></Description>
</Incident>
</TestFunction>
<TestFunction name="testFailStdRuntimeError">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="138">
<Description><![CDATA[Expected exception of type std::runtime_error to be thrown but std::exception caught with message: logic error]]></Description>
</Incident>
</TestFunction>
<TestFunction name="testFailMyException">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="143">
<Description><![CDATA[Expected exception of type MyBaseException to be thrown but std::exception caught with message: logic error]]></Description>
</Incident>
</TestFunction>
<TestFunction name="testFailMyDerivedException">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="148">
<Description><![CDATA[Expected exception of type std::runtime_error to be thrown but std::exception caught with message: MyDerivedException]]></Description>
</Incident>
</TestFunction>
<TestFunction name="testFailNoException">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="153">
<Description><![CDATA[Expected exception of type std::exception to be thrown but no exception caught]]></Description>
</Incident>
</TestFunction>
<TestFunction name="cleanupTestCase">
<Incident type="pass" file="" line="0" />
</TestFunction>

View File

@ -0,0 +1,21 @@
********* Start testing of tst_VerifyExceptionThrown *********
Config: Using QtTest library @INSERT_QT_VERSION_HERE@, Qt @INSERT_QT_VERSION_HERE@
PASS : tst_VerifyExceptionThrown::initTestCase()
PASS : tst_VerifyExceptionThrown::testCorrectStdTypes()
PASS : tst_VerifyExceptionThrown::testCorrectStdExceptions()
PASS : tst_VerifyExceptionThrown::testCorrectMyExceptions()
FAIL! : tst_VerifyExceptionThrown::testFailInt() Expected exception of type double to be thrown but unknown exception caught
Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp(128)]
FAIL! : tst_VerifyExceptionThrown::testFailStdString() Expected exception of type char* to be thrown but unknown exception caught
Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp(133)]
FAIL! : tst_VerifyExceptionThrown::testFailStdRuntimeError() Expected exception of type std::runtime_error to be thrown but std::exception caught with message: logic error
Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp(138)]
FAIL! : tst_VerifyExceptionThrown::testFailMyException() Expected exception of type MyBaseException to be thrown but std::exception caught with message: logic error
Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp(143)]
FAIL! : tst_VerifyExceptionThrown::testFailMyDerivedException() Expected exception of type std::runtime_error to be thrown but std::exception caught with message: MyDerivedException
Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp(148)]
FAIL! : tst_VerifyExceptionThrown::testFailNoException() Expected exception of type std::exception to be thrown but no exception caught
Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp(153)]
PASS : tst_VerifyExceptionThrown::cleanupTestCase()
Totals: 5 passed, 6 failed, 0 skipped
********* Finished testing of tst_VerifyExceptionThrown *********

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<TestCase name="tst_VerifyExceptionThrown">
<Environment>
<QtVersion>@INSERT_QT_VERSION_HERE@</QtVersion>
<QTestVersion>@INSERT_QT_VERSION_HERE@</QTestVersion>
</Environment>
<TestFunction name="initTestCase">
<Incident type="pass" file="" line="0" />
</TestFunction>
<TestFunction name="testCorrectStdTypes">
<Incident type="pass" file="" line="0" />
</TestFunction>
<TestFunction name="testCorrectStdExceptions">
<Incident type="pass" file="" line="0" />
</TestFunction>
<TestFunction name="testCorrectMyExceptions">
<Incident type="pass" file="" line="0" />
</TestFunction>
<TestFunction name="testFailInt">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="128">
<Description><![CDATA[Expected exception of type double to be thrown but unknown exception caught]]></Description>
</Incident>
</TestFunction>
<TestFunction name="testFailStdString">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="133">
<Description><![CDATA[Expected exception of type char* to be thrown but unknown exception caught]]></Description>
</Incident>
</TestFunction>
<TestFunction name="testFailStdRuntimeError">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="138">
<Description><![CDATA[Expected exception of type std::runtime_error to be thrown but std::exception caught with message: logic error]]></Description>
</Incident>
</TestFunction>
<TestFunction name="testFailMyException">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="143">
<Description><![CDATA[Expected exception of type MyBaseException to be thrown but std::exception caught with message: logic error]]></Description>
</Incident>
</TestFunction>
<TestFunction name="testFailMyDerivedException">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="148">
<Description><![CDATA[Expected exception of type std::runtime_error to be thrown but std::exception caught with message: MyDerivedException]]></Description>
</Incident>
</TestFunction>
<TestFunction name="testFailNoException">
<Incident type="fail" file="/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/verifyexceptionthrown/tst_verifyexceptionthrown.cpp" line="153">
<Description><![CDATA[Expected exception of type std::exception to be thrown but no exception caught]]></Description>
</Incident>
</TestFunction>
<TestFunction name="cleanupTestCase">
<Incident type="pass" file="" line="0" />
</TestFunction>
</TestCase>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" ?>
<testsuite errors="0" failures="6" tests="11" name="tst_VerifyExceptionThrown">
<properties>
<property value="@INSERT_QT_VERSION_HERE@" name="QTestVersion"/>
<property value="@INSERT_QT_VERSION_HERE@" name="QtVersion"/>
</properties>
<testcase result="pass" name="initTestCase"/>
<testcase result="pass" name="testCorrectStdTypes"/>
<testcase result="pass" name="testCorrectStdExceptions"/>
<testcase result="pass" name="testCorrectMyExceptions"/>
<testcase result="fail" name="testFailInt">
<failure message="Expected exception of type double to be thrown but unknown exception caught" result="fail"/>
</testcase>
<testcase result="fail" name="testFailStdString">
<failure message="Expected exception of type char* to be thrown but unknown exception caught" result="fail"/>
</testcase>
<testcase result="fail" name="testFailStdRuntimeError">
<failure message="Expected exception of type std::runtime_error to be thrown but std::exception caught with message: logic error" result="fail"/>
</testcase>
<testcase result="fail" name="testFailMyException">
<failure message="Expected exception of type MyBaseException to be thrown but std::exception caught with message: logic error" result="fail"/>
</testcase>
<testcase result="fail" name="testFailMyDerivedException">
<failure message="Expected exception of type std::runtime_error to be thrown but std::exception caught with message: MyDerivedException" result="fail"/>
</testcase>
<testcase result="fail" name="testFailNoException">
<failure message="Expected exception of type std::exception to be thrown but no exception caught" result="fail"/>
</testcase>
<testcase result="pass" name="cleanupTestCase"/>
<system-err/>
</testsuite>

View File

@ -41,5 +41,6 @@ SUBPROGRAMS = \
subtest \
verbose1 \
verbose2 \
verifyexceptionthrown \
warnings \
xunit

View File

@ -134,6 +134,10 @@
<file>expected_verbose2.txt</file>
<file>expected_verbose2.xml</file>
<file>expected_verbose2.xunitxml</file>
<file>expected_verifyexceptionthrown.lightxml</file>
<file>expected_verifyexceptionthrown.txt</file>
<file>expected_verifyexceptionthrown.xml</file>
<file>expected_verifyexceptionthrown.xunitxml</file>
<file>expected_warnings.lightxml</file>
<file>expected_warnings.txt</file>
<file>expected_warnings.xml</file>

View File

@ -380,6 +380,10 @@ void tst_Selftests::runSubTest_data()
<< "subtest"
<< "verbose1"
<< "verbose2"
#ifndef QT_NO_EXCEPTIONS
// this test will test nothing if the exceptions are disabled
<< "verifyexceptionthrown"
#endif //!QT_NO_EXCEPTIONS
<< "warnings"
<< "xunit"
;

View File

@ -0,0 +1,162 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#ifndef QT_NO_EXCEPTIONS
# include <stdexcept>
#endif
#ifndef QT_NO_EXCEPTIONS
class MyBaseException
{
};
class MyDerivedException: public MyBaseException, public std::domain_error
{
public:
MyDerivedException(): std::domain_error("MyDerivedException") {}
};
#endif // !QT_NO_EXCEPTIONS
class tst_VerifyExceptionThrown: public QObject
{
Q_OBJECT
private:
void doSomething() const {}
private slots:
// Remove all test cases if exceptions are not available
#ifndef QT_NO_EXCEPTIONS
void testCorrectStdTypes() const;
void testCorrectStdExceptions() const;
void testCorrectMyExceptions() const;
void testFailInt() const;
void testFailStdString() const;
void testFailStdRuntimeError() const;
void testFailMyException() const;
void testFailMyDerivedException() const;
void testFailNoException() const;
#endif // !QT_NO_EXCEPTIONS
};
#ifndef QT_NO_EXCEPTIONS
void tst_VerifyExceptionThrown::testCorrectStdTypes() const
{
QVERIFY_EXCEPTION_THROWN(throw int(5), int);
QVERIFY_EXCEPTION_THROWN(throw float(9.8), float);
QVERIFY_EXCEPTION_THROWN(throw bool(true), bool);
QVERIFY_EXCEPTION_THROWN(throw std::string("some string"), std::string);
}
void tst_VerifyExceptionThrown::testCorrectStdExceptions() const
{
// same type
QVERIFY_EXCEPTION_THROWN(throw std::exception(), std::exception);
QVERIFY_EXCEPTION_THROWN(throw std::runtime_error("runtime error"), std::runtime_error);
QVERIFY_EXCEPTION_THROWN(throw std::overflow_error("overflow error"), std::overflow_error);
// inheritance
QVERIFY_EXCEPTION_THROWN(throw std::overflow_error("overflow error"), std::runtime_error);
QVERIFY_EXCEPTION_THROWN(throw std::overflow_error("overflow error"), std::exception);
}
void tst_VerifyExceptionThrown::testCorrectMyExceptions() const
{
// same type
QVERIFY_EXCEPTION_THROWN(throw MyBaseException(), MyBaseException);
QVERIFY_EXCEPTION_THROWN(throw MyDerivedException(), MyDerivedException);
// inheritance
QVERIFY_EXCEPTION_THROWN(throw MyDerivedException(), MyBaseException);
QVERIFY_EXCEPTION_THROWN(throw MyDerivedException(), std::domain_error);
}
void tst_VerifyExceptionThrown::testFailInt() const
{
QVERIFY_EXCEPTION_THROWN(throw int(5), double);
}
void tst_VerifyExceptionThrown::testFailStdString() const
{
QVERIFY_EXCEPTION_THROWN(throw std::string("some string"), char*);
}
void tst_VerifyExceptionThrown::testFailStdRuntimeError() const
{
QVERIFY_EXCEPTION_THROWN(throw std::logic_error("logic error"), std::runtime_error);
}
void tst_VerifyExceptionThrown::testFailMyException() const
{
QVERIFY_EXCEPTION_THROWN(throw std::logic_error("logic error"), MyBaseException);
}
void tst_VerifyExceptionThrown::testFailMyDerivedException() const
{
QVERIFY_EXCEPTION_THROWN(throw MyDerivedException(), std::runtime_error);
}
void tst_VerifyExceptionThrown::testFailNoException() const
{
QVERIFY_EXCEPTION_THROWN(doSomething(), std::exception);
}
#endif // !QT_NO_EXCEPTIONS
QTEST_MAIN(tst_VerifyExceptionThrown)
#include "tst_verifyexceptionthrown.moc"

View File

@ -0,0 +1,8 @@
SOURCES += tst_verifyexceptionthrown.cpp
QT = core testlib
mac:CONFIG -= app_bundle
CONFIG -= debug_and_release_target
CONFIG += exceptions
TARGET = verifyexceptionthrown