summaryrefslogtreecommitdiffstats
path: root/src/testlib/qtestcase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/testlib/qtestcase.cpp')
-rw-r--r--src/testlib/qtestcase.cpp1496
1 files changed, 119 insertions, 1377 deletions
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index 286da52be2..9acddcc7ea 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -97,6 +97,8 @@
#include <IOKit/pwr_mgt/IOPMLib.h>
#endif
+#include <vector>
+
QT_BEGIN_NAMESPACE
using QtMiscUtils::toHexUpper;
@@ -136,1261 +138,6 @@ static void stackTrace()
#endif
}
-/*!
- \namespace QTest
- \inmodule QtTest
-
- \brief The QTest namespace contains all the functions and
- declarations that are related to Qt Test.
-
- See the \l{Qt Test Overview} for information about how to write unit tests.
-*/
-
-/*!
- \namespace QTest::Internal
- \internal
-*/
-
-/*! \macro QVERIFY(condition)
-
- \relates QTest
-
- The QVERIFY() macro checks whether the \a condition is true or not. If it is
- true, execution continues. If not, a failure is recorded in the test log
- and the test won't be executed further.
-
- \b {Note:} This macro can only be used in a test function that is invoked
- by the test framework.
-
- Example:
- \snippet code/src_qtestlib_qtestcase.cpp 0
-
- \sa QCOMPARE(), QTRY_VERIFY()
-*/
-
-/*! \macro QVERIFY2(condition, message)
-
- \relates QTest
-
- The QVERIFY2() macro behaves exactly like QVERIFY(), except that it outputs
- a verbose \a message when \a condition is false. The \a message is a plain
- C string.
-
- Example:
- \snippet code/src_qtestlib_qtestcase.cpp 1
-
- \sa QVERIFY(), QCOMPARE()
-*/
-
-/*! \macro QCOMPARE(actual, expected)
-
- \relates QTest
-
- The QCOMPARE macro compares an \a actual value to an \a expected value using
- the equals operator. If \a actual and \a expected are identical, execution
- continues. If not, a failure is recorded in the test log and the test
- won't be executed further.
-
- In the case of comparing floats and doubles, qFuzzyCompare() is used for
- comparing. This means that comparing to 0 will likely fail. One solution
- to this is to compare to 1, and add 1 to the produced output.
-
- QCOMPARE tries to output the contents of the values if the comparison fails,
- so it is visible from the test log why the comparison failed.
-
- QCOMPARE is very strict on the data types. Both \a actual and \a expected
- have to be of the same type, otherwise the test won't compile. This prohibits
- unspecified behavior from being introduced; that is behavior that usually
- occurs when the compiler implicitly casts the argument.
-
- For your own classes, you can use \l QTest::toString() to format values for
- outputting into the test log.
-
- \note This macro can only be used in a test function that is invoked
- by the test framework.
-
- Example:
- \snippet code/src_qtestlib_qtestcase.cpp 2
-
- \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
-
- \relates QTest
-
- The QTRY_VERIFY_WITH_TIMEOUT() macro is similar to QVERIFY(), but checks the \a condition
- repeatedly, until either the condition becomes true or the \a timeout is
- reached. Between each evaluation, events will be processed. If the timeout
- is reached, a failure is 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.
-
- \sa QTRY_VERIFY(), QTRY_VERIFY2_WITH_TIMEOUT(), QVERIFY(), QCOMPARE(), QTRY_COMPARE()
-*/
-
-
-/*! \macro QTRY_VERIFY(condition)
- \since 5.0
-
- \relates QTest
-
- Checks the \a condition by invoking QTRY_VERIFY_WITH_TIMEOUT() with a timeout of five seconds.
-
- \note This macro can only be used in a test function that is invoked
- by the test framework.
-
- \sa QTRY_VERIFY_WITH_TIMEOUT(), QTRY_VERIFY2(), QVERIFY(), QCOMPARE(), QTRY_COMPARE()
-*/
-
-/*! \macro QTRY_VERIFY2_WITH_TIMEOUT(condition, message, timeout)
- \since 5.6
-
- \relates QTest
-
- The QTRY_VERIFY2_WITH_TIMEOUT macro is similar to QTRY_VERIFY_WITH_TIMEOUT()
- except that it outputs a verbose \a message when \a condition is still false
- after the specified \a timeout. The \a message is a plain C string.
-
- Example:
- \code
- QTRY_VERIFY2_WITH_TIMEOUT(list.size() > 2, QByteArray::number(list.size()).constData(), 10000);
- \endcode
-
- \note This macro can only be used in a test function that is invoked
- by the test framework.
-
- \sa QTRY_VERIFY(), QTRY_VERIFY_WITH_TIMEOUT(), QVERIFY(), QCOMPARE(), QTRY_COMPARE()
-*/
-
-/*! \macro QTRY_VERIFY2(condition, message)
- \since 5.6
-
- \relates QTest
-
- Checks the \a condition by invoking QTRY_VERIFY2_WITH_TIMEOUT() with a timeout
- of five seconds. If \a condition is then still false, \a message is output.
- The \a message is a plain C string.
-
- Example:
- \code
- QTRY_VERIFY2_WITH_TIMEOUT(list.size() > 2, QByteArray::number(list.size()).constData());
- \endcode
-
- \note This macro can only be used in a test function that is invoked
- by the test framework.
-
- \sa QTRY_VERIFY2_WITH_TIMEOUT(), QTRY_VERIFY2(), QVERIFY(), QCOMPARE(), QTRY_COMPARE()
-*/
-
-/*! \macro QTRY_COMPARE_WITH_TIMEOUT(actual, expected, timeout)
- \since 5.0
-
- \relates QTest
-
- The QTRY_COMPARE_WITH_TIMEOUT() macro is similar to QCOMPARE(), but performs the comparison
- of the \a actual and \a expected values repeatedly, until either the two values
- are equal or the \a timeout is reached. Between each comparison, events
- will be processed. If the timeout is reached, a failure is 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.
-
- \sa QTRY_COMPARE(), QCOMPARE(), QVERIFY(), QTRY_VERIFY()
-*/
-
-/*! \macro QTRY_COMPARE(actual, expected)
- \since 5.0
-
- \relates QTest
-
- Performs a comparison of the \a actual and \a expected values by
- invoking QTRY_COMPARE_WITH_TIMEOUT() with a timeout of five seconds.
-
- \note This macro can only be used in a test function that is invoked
- by the test framework.
-
- \sa QTRY_COMPARE_WITH_TIMEOUT(), QCOMPARE(), QVERIFY(), QTRY_VERIFY()
-*/
-
-/*! \macro QFETCH(type, name)
-
- \relates QTest
-
- The fetch macro creates a local variable named \a name with the type \a type
- on the stack. \a name has to match the element name from the test's data.
- If no such element exists, the test will assert.
-
- Assuming a test has the following data:
-
- \snippet code/src_qtestlib_qtestcase.cpp 3
-
- The test data has two elements, a QString called \c aString and an integer
- called \c expected. To fetch these values in the actual test:
-
- \snippet code/src_qtestlib_qtestcase.cpp 4
-
- \c aString and \c expected are variables on the stack that are initialized with
- the current test data.
-
- \b {Note:} This macro can only be used in a test function that is invoked
- by the test framework. The test function must have a _data function.
-*/
-
-/*! \macro QWARN(message)
-
- \relates QTest
- \threadsafe
-
- Appends \a message as a warning to the test log. This macro can be used anywhere
- in your tests.
-*/
-
-/*! \macro QFAIL(message)
-
- \relates QTest
-
- This macro can be used to force a test failure. The test stops
- executing and the failure \a message is appended to the test log.
-
- \b {Note:} This macro can only be used in a test function that is invoked
- by the test framework.
-
- Example:
-
- \snippet code/src_qtestlib_qtestcase.cpp 5
-*/
-
-/*! \macro QTEST(actual, testElement)
-
- \relates QTest
-
- QTEST() is a convenience macro for \l QCOMPARE() that compares
- the value \a actual with the element \a testElement from the test's data.
- If there is no such element, the test asserts.
-
- Apart from that, QTEST() behaves exactly as \l QCOMPARE().
-
- Instead of writing:
-
- \snippet code/src_qtestlib_qtestcase.cpp 6
-
- you can write:
-
- \snippet code/src_qtestlib_qtestcase.cpp 7
-
- \sa QCOMPARE()
-*/
-
-/*! \macro QSKIP(description)
-
- \relates QTest
-
- If called from a test function, the QSKIP() macro stops execution of the test
- without adding a failure to the test log. You can use it to skip tests that
- wouldn't make sense in the current configuration. The text \a description is
- appended to the test log and should contain an explanation of why the test
- couldn't be executed.
-
- If the test is data-driven, each call to QSKIP() will skip only the current
- row of test data, so an unconditional call to QSKIP will produce one skip
- message in the test log for each row of test data.
-
- If called from an _data function, the QSKIP() macro will stop execution of
- the _data function and will prevent execution of the associated test
- function.
-
- If called from initTestCase() or initTestCase_data(), the QSKIP() macro will
- skip all test and _data functions.
-
- \b {Note:} This macro can only be used in a test function or _data
- function that is invoked by the test framework.
-
- Example:
- \snippet code/src_qtestlib_qtestcase.cpp 8
-*/
-
-/*! \macro QEXPECT_FAIL(dataIndex, comment, mode)
-
- \relates QTest
-
- The QEXPECT_FAIL() macro marks the next \l QCOMPARE() or \l QVERIFY() as an
- expected failure. Instead of adding a failure to the test log, an expected
- failure will be reported.
-
- If a \l QVERIFY() or \l QCOMPARE() is marked as an expected failure,
- but passes instead, an unexpected pass (XPASS) is written to the test log.
-
- The parameter \a dataIndex describes for which entry in the test data the
- failure is expected. Pass an empty string (\c{""}) if the failure
- is expected for all entries or if no test data exists.
-
- \a comment will be appended to the test log for the expected failure.
-
- \a mode is a \l QTest::TestFailMode and sets whether the test should
- continue to execute or not.
-
- \b {Note:} This macro can only be used in a test function that is invoked
- by the test framework.
-
- Example 1:
- \snippet code/src_qtestlib_qtestcase.cpp 9
-
- In the example above, an expected fail will be written into the test output
- if the variable \c i is not 42. If the variable \c i is 42, an unexpected pass
- is written instead. The QEXPECT_FAIL() has no influence on the second QCOMPARE()
- statement in the example.
-
- Example 2:
- \snippet code/src_qtestlib_qtestcase.cpp 10
-
- The above testfunction will not continue executing for the test data
- entry \c{data27}.
-
- \sa QTest::TestFailMode, QVERIFY(), QCOMPARE()
-*/
-
-/*! \macro QFINDTESTDATA(filename)
- \since 5.0
-
- \relates QTest
-
- Returns a QString for the testdata file referred to by \a filename, or an
- empty QString if the testdata file could not be found.
-
- This macro allows the test to load data from an external file without
- hardcoding an absolute filename into the test, or using relative paths
- which may be error prone.
-
- The returned path will be the first path from the following list which
- resolves to an existing file or directory:
-
- \list
- \li \a filename relative to QCoreApplication::applicationDirPath()
- (only if a QCoreApplication or QApplication object has been created).
- \li \a filename relative to the test's standard install directory
- (QLibraryInfo::TestsPath with the lowercased testcase name appended).
- \li \a filename relative to the directory containing the source file from which
- QFINDTESTDATA is invoked.
- \endlist
-
- If the named file/directory does not exist at any of these locations,
- a warning is printed to the test log.
-
- For example, in this code:
- \snippet code/src_qtestlib_qtestcase.cpp 26
-
- The testdata file will be resolved as the first existing file from:
-
- \list
- \li \c{/home/user/build/myxmlparser/tests/tst_myxmlparser/testxml/simple1.xml}
- \li \c{/usr/local/Qt-5.0.0/tests/tst_myxmlparser/testxml/simple1.xml}
- \li \c{/home/user/sources/myxmlparser/tests/tst_myxmlparser/testxml/simple1.xml}
- \endlist
-
- This allows the test to find its testdata regardless of whether the
- test has been installed, and regardless of whether the test's build tree
- is equal to the test's source tree.
-
- \b {Note:} reliable detection of testdata from the source directory requires
- either that qmake is used, or the \c{QT_TESTCASE_BUILDDIR} macro is defined to
- point to the working directory from which the compiler is invoked, or only
- absolute paths to the source files are passed to the compiler. Otherwise, the
- absolute path of the source directory cannot be determined.
-
- \b {Note:} For tests that use the \l QTEST_APPLESS_MAIN() macro to generate a
- \c{main()} function, \c{QFINDTESTDATA} will not attempt to find test data
- relative to QCoreApplication::applicationDirPath(). In practice, this means that
- tests using \c{QTEST_APPLESS_MAIN()} will fail to find their test data
- if run from a shadow build tree.
-*/
-
-/*! \macro QTEST_MAIN(TestClass)
-
- \relates QTest
-
- Implements a main() function that instantiates an application object and
- the \a TestClass, and executes all tests in the order they were defined.
- Use this macro to build stand-alone executables.
-
- If \c QT_WIDGETS_LIB is defined, the application object will be a QApplication,
- if \c QT_GUI_LIB is defined, the application object will be a QGuiApplication,
- otherwise it will be a QCoreApplication. If qmake is used and the configuration
- includes \c{QT += widgets}, then \c QT_WIDGETS_LIB will be defined automatically.
- Similarly, if qmake is used and the configuration includes \c{QT += gui}, then
- \c QT_GUI_LIB will be defined automatically.
-
- \b {Note:} On platforms that have keypad navigation enabled by default,
- this macro will forcefully disable it if \c QT_WIDGETS_LIB is defined. This is done
- to simplify the usage of key events when writing autotests. If you wish to write a
- test case that uses keypad navigation, you should enable it either in the
- \c {initTestCase()} or \c {init()} functions of your test case by calling
- \l {QApplication::setNavigationMode()}.
-
- Example:
- \snippet code/src_qtestlib_qtestcase.cpp 11
-
- \sa QTEST_APPLESS_MAIN(), QTEST_GUILESS_MAIN(), QTest::qExec(),
- QApplication::setNavigationMode()
-*/
-
-/*! \macro QTEST_APPLESS_MAIN(TestClass)
-
- \relates QTest
-
- Implements a main() function that executes all tests in \a TestClass.
-
- Behaves like \l QTEST_MAIN(), but doesn't instantiate a QApplication
- object. Use this macro for really simple stand-alone non-GUI tests.
-
- \sa QTEST_MAIN()
-*/
-
-/*! \macro QTEST_GUILESS_MAIN(TestClass)
- \since 5.0
-
- \relates QTest
-
- Implements a main() function that instantiates a QCoreApplication object
- and the \a TestClass, and executes all tests in the order they were
- defined. Use this macro to build stand-alone executables.
-
- Behaves like \l QTEST_MAIN(), but instantiates a QCoreApplication instead
- of the QApplication object. Use this macro if your test case doesn't need
- functionality offered by QApplication, but the event loop is still necessary.
-
- \sa QTEST_MAIN()
-*/
-
-/*!
- \macro QBENCHMARK
-
- \relates QTest
-
- This macro is used to measure the performance of code within a test.
- The code to be benchmarked is contained within a code block following
- this macro.
-
- For example:
-
- \snippet code/src_qtestlib_qtestcase.cpp 27
-
- \sa {Qt Test Overview#Creating a Benchmark}{Creating a Benchmark},
- {Chapter 5: Writing a Benchmark}{Writing a Benchmark}
-*/
-
-/*!
- \macro QBENCHMARK_ONCE
- \since 4.6
-
- \relates QTest
-
- \brief The QBENCHMARK_ONCE macro is for measuring performance of a
- code block by running it once.
-
- This macro is used to measure the performance of code within a test.
- The code to be benchmarked is contained within a code block following
- this macro.
-
- Unlike QBENCHMARK, the contents of the contained code block is only run
- once. The elapsed time will be reported as "0" if it's to short to
- be measured by the selected backend. (Use)
-
- \sa {Qt Test Overview#Creating a Benchmark}{Creating a Benchmark},
- {Chapter 5: Writing a Benchmark}{Writing a Benchmark}
-*/
-
-/*! \enum QTest::TestFailMode
-
- This enum describes the modes for handling an expected failure of the
- \l QVERIFY() or \l QCOMPARE() macros.
-
- \value Abort Aborts the execution of the test. Use this mode when it
- doesn't make sense to execute the test any further after the
- expected failure.
-
- \value Continue Continues execution of the test after the expected failure.
-
- \sa QEXPECT_FAIL()
-*/
-
-/*! \enum QTest::KeyAction
-
- This enum describes possible actions for key handling.
-
- \value Press The key is pressed.
- \value Release The key is released.
- \value Click The key is clicked (pressed and released).
-*/
-
-/*! \enum QTest::MouseAction
-
- This enum describes possible actions for mouse handling.
-
- \value MousePress A mouse button is pressed.
- \value MouseRelease A mouse button is released.
- \value MouseClick A mouse button is clicked (pressed and released).
- \value MouseDClick A mouse button is double clicked (pressed and released twice).
- \value MouseMove The mouse pointer has moved.
-*/
-
-/*! \fn void QTest::keyClick(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
-
- Simulates clicking of \a key with an optional \a modifier on a \a widget.
- If \a delay is larger than 0, the test will wait for \a delay milliseconds
- before clicking the key.
-
- Examples:
- \snippet code/src_qtestlib_qtestcase.cpp 14
-
- The first example above simulates clicking the \c escape key on \c
- myWidget without any keyboard modifiers and without delay. The
- second example simulates clicking \c shift-escape on \c myWidget
- following a 200 ms delay of the test.
-
- \sa QTest::keyClicks()
-*/
-
-/*! \fn void QTest::keyClick(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
-
- Simulates clicking of \a key with an optional \a modifier on a \a widget.
- If \a delay is larger than 0, the test will wait for \a delay milliseconds
- before clicking the key.
-
- Example:
- \snippet code/src_qtestlib_qtestcase.cpp 13
-
- The example above simulates clicking \c a on \c myWidget without
- any keyboard modifiers and without delay of the test.
-
- \sa QTest::keyClicks()
-*/
-
-/*! \fn void QTest::keyClick(QWindow *window, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
- \since 5.0
-
- Simulates clicking of \a key with an optional \a modifier on a \a window.
- If \a delay is larger than 0, the test will wait for \a delay milliseconds
- before clicking the key.
-
- Examples:
- \snippet code/src_qtestlib_qtestcase.cpp 29
-
- The first example above simulates clicking the \c escape key on \c
- myWindow without any keyboard modifiers and without delay. The
- second example simulates clicking \c shift-escape on \c myWindow
- following a 200 ms delay of the test.
-
- \sa QTest::keyClicks()
-*/
-
-/*! \fn void QTest::keyClick(QWindow *window, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
- \since 5.0
-
- Simulates clicking of \a key with an optional \a modifier on a \a window.
- If \a delay is larger than 0, the test will wait for \a delay milliseconds
- before clicking the key.
-
- Example:
- \snippet code/src_qtestlib_qtestcase.cpp 28
-
- The example above simulates clicking \c a on \c myWindow without
- any keyboard modifiers and without delay of the test.
-
- \sa QTest::keyClicks()
-*/
-
-/*! \fn void QTest::keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
-
- Sends a Qt key event to \a widget with the given \a key and an associated \a action.
- Optionally, a keyboard \a modifier can be specified, as well as a \a delay
- (in milliseconds) of the test before sending the event.
-*/
-
-/*! \fn void QTest::keyEvent(KeyAction action, QWidget *widget, char ascii, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
-
- Sends a Qt key event to \a widget with the given key \a ascii and an associated \a action.
- Optionally, a keyboard \a modifier can be specified, as well as a \a delay
- (in milliseconds) of the test before sending the event.
-*/
-
-/*! \fn void QTest::keyEvent(KeyAction action, QWindow *window, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
- \since 5.0
-
- Sends a Qt key event to \a window with the given \a key and an associated \a action.
- Optionally, a keyboard \a modifier can be specified, as well as a \a delay
- (in milliseconds) of the test before sending the event.
-*/
-
-/*! \fn void QTest::keyEvent(KeyAction action, QWindow *window, char ascii, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
- \since 5.0
-
- Sends a Qt key event to \a window with the given key \a ascii and an associated \a action.
- Optionally, a keyboard \a modifier can be specified, as well as a \a delay
- (in milliseconds) of the test before sending the event.
-*/
-
-/*! \fn void QTest::keyPress(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
-
- Simulates pressing a \a key with an optional \a modifier on a \a widget. If \a delay
- is larger than 0, the test will wait for \a delay milliseconds before pressing the key.
-
- \b {Note:} At some point you should release the key using \l keyRelease().
-
- \sa QTest::keyRelease(), QTest::keyClick()
-*/
-
-/*! \fn void QTest::keyPress(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
-
- Simulates pressing a \a key with an optional \a modifier on a \a widget.
- If \a delay is larger than 0, the test will wait for \a delay milliseconds
- before pressing the key.
-
- \b {Note:} At some point you should release the key using \l keyRelease().
-
- \sa QTest::keyRelease(), QTest::keyClick()
-*/
-
-/*! \fn void QTest::keyPress(QWindow *window, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
- \since 5.0
-
- Simulates pressing a \a key with an optional \a modifier on a \a window. If \a delay
- is larger than 0, the test will wait for \a delay milliseconds before pressing the key.
-
- \b {Note:} At some point you should release the key using \l keyRelease().
-
- \sa QTest::keyRelease(), QTest::keyClick()
-*/
-
-/*! \fn void QTest::keyPress(QWindow *window, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
- \since 5.0
-
- Simulates pressing a \a key with an optional \a modifier on a \a window.
- If \a delay is larger than 0, the test will wait for \a delay milliseconds
- before pressing the key.
-
- \b {Note:} At some point you should release the key using \l keyRelease().
-
- \sa QTest::keyRelease(), QTest::keyClick()
-*/
-
-/*! \fn void QTest::keyRelease(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
-
- Simulates releasing a \a key with an optional \a modifier on a \a widget.
- If \a delay is larger than 0, the test will wait for \a delay milliseconds
- before releasing the key.
-
- \sa QTest::keyPress(), QTest::keyClick()
-*/
-
-/*! \fn void QTest::keyRelease(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
-
- Simulates releasing a \a key with an optional \a modifier on a \a widget.
- If \a delay is larger than 0, the test will wait for \a delay milliseconds
- before releasing the key.
-
- \sa QTest::keyClick()
-*/
-
-/*! \fn void QTest::keyRelease(QWindow *window, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
- \since 5.0
-
- Simulates releasing a \a key with an optional \a modifier on a \a window.
- If \a delay is larger than 0, the test will wait for \a delay milliseconds
- before releasing the key.
-
- \sa QTest::keyPress(), QTest::keyClick()
-*/
-
-/*! \fn void QTest::keyRelease(QWindow *window, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
- \overload
- \since 5.0
-
- Simulates releasing a \a key with an optional \a modifier on a \a window.
- If \a delay is larger than 0, the test will wait for \a delay milliseconds
- before releasing the key.
-
- \sa QTest::keyClick()
-*/
-
-/*! \fn void QTest::keyClicks(QWidget *widget, const QString &sequence, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
-
- Simulates clicking a \a sequence of keys on a \a
- widget. Optionally, a keyboard \a modifier can be specified as
- well as a \a delay (in milliseconds) of the test before each key
- click.
-
- Example:
- \snippet code/src_qtestlib_qtestcase.cpp 15
-
- The example above simulates clicking the sequence of keys
- representing "hello world" on \c myWidget without any keyboard
- modifiers and without delay of the test.
-
- \sa QTest::keyClick()
-*/
-
-/*! \fn void QTest::waitForEvents()
- \internal
-*/
-
-/*! \fn void QTest::mouseEvent(MouseAction action, QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1)
- \internal
-*/
-
-/*! \fn void QTest::mouseEvent(MouseAction action, QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1)
- \internal
-*/
-
-/*! \fn void QTest::mousePress(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
-
- Simulates pressing a mouse \a button with an optional \a modifier
- on a \a widget. The position is defined by \a pos; the default
- position is the center of the widget. If \a delay is specified,
- the test will wait for the specified amount of milliseconds before
- the press.
-
- \sa QTest::mouseRelease(), QTest::mouseClick()
-*/
-
-/*! \fn void QTest::mousePress(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, QPoint pos = QPoint(), int delay=-1)
- \overload
- \since 5.0
-
- Simulates pressing a mouse \a button with an optional \a stateKey modifier
- on a \a window. The position is defined by \a pos; the default
- position is the center of the window. If \a delay is specified,
- the test will wait for the specified amount of milliseconds before
- the press.
-
- \sa QTest::mouseRelease(), QTest::mouseClick()
-*/
-
-/*! \fn void QTest::mouseRelease(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
-
- Simulates releasing a mouse \a button with an optional \a modifier
- on a \a widget. The position of the release is defined by \a pos;
- the default position is the center of the widget. If \a delay is
- specified, the test will wait for the specified amount of
- milliseconds before releasing the button.
-
- \sa QTest::mousePress(), QTest::mouseClick()
-*/
-
-/*! \fn void QTest::mouseRelease(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, QPoint pos = QPoint(), int delay=-1)
- \overload
- \since 5.0
-
- Simulates releasing a mouse \a button with an optional \a stateKey modifier
- on a \a window. The position of the release is defined by \a pos;
- the default position is the center of the window. If \a delay is
- specified, the test will wait for the specified amount of
- milliseconds before releasing the button.
-
- \sa QTest::mousePress(), QTest::mouseClick()
-*/
-
-/*! \fn void QTest::mouseClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
-
- Simulates clicking a mouse \a button with an optional \a modifier
- on a \a widget. The position of the click is defined by \a pos;
- the default position is the center of the widget. If \a delay is
- specified, the test will wait for the specified amount of
- milliseconds before pressing and before releasing the button.
-
- \sa QTest::mousePress(), QTest::mouseRelease()
-*/
-
-/*! \fn void QTest::mouseClick(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, QPoint pos = QPoint(), int delay=-1)
- \overload
- \since 5.0
-
- Simulates clicking a mouse \a button with an optional \a stateKey modifier
- on a \a window. The position of the click is defined by \a pos;
- the default position is the center of the window. If \a delay is
- specified, the test will wait for the specified amount of
- milliseconds before pressing and before releasing the button.
-
- \sa QTest::mousePress(), QTest::mouseRelease()
-*/
-
-/*! \fn void QTest::mouseDClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
-
- Simulates double clicking a mouse \a button with an optional \a
- modifier on a \a widget. The position of the click is defined by
- \a pos; the default position is the center of the widget. If \a
- delay is specified, the test will wait for the specified amount of
- milliseconds before each press and release.
-
- \sa QTest::mouseClick()
-*/
-
-/*! \fn void QTest::mouseDClick(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, QPoint pos = QPoint(), int delay=-1)
- \overload
- \since 5.0
-
- Simulates double clicking a mouse \a button with an optional \a stateKey
- modifier on a \a window. The position of the click is defined by
- \a pos; the default position is the center of the window. If \a
- delay is specified, the test will wait for the specified amount of
- milliseconds before each press and release.
-
- \sa QTest::mouseClick()
-*/
-
-/*! \fn void QTest::mouseMove(QWidget *widget, QPoint pos = QPoint(), int delay=-1)
-
- Moves the mouse pointer to a \a widget. If \a pos is not
- specified, the mouse pointer moves to the center of the widget. If
- a \a delay (in milliseconds) is given, the test will wait before
- moving the mouse pointer.
-*/
-
-/*! \fn void QTest::mouseMove(QWindow *window, QPoint pos = QPoint(), int delay=-1)
- \overload
- \since 5.0
-
- Moves the mouse pointer to a \a window. If \a pos is not
- specified, the mouse pointer moves to the center of the window. If
- a \a delay (in milliseconds) is given, the test will wait before
- moving the mouse pointer.
-*/
-
-/*!
- \fn char *QTest::toString(const T &value)
-
- Returns a textual representation of \a value. This function is used by
- \l QCOMPARE() to output verbose information in case of a test failure.
-
- You can add specializations or overloads of this function to your test to enable
- verbose output.
-
- \b {Note:} Starting with Qt 5.5, you should prefer to provide a toString() function
- in the type's namespace instead of specializing this template.
- If your code needs to continue to work with the QTestLib from Qt 5.4 or
- earlier, you need to continue to use specialization.
-
- \b {Note:} The caller of toString() must delete the returned data
- using \c{delete[]}. Your implementation should return a string
- created with \c{new[]} or qstrdup(). The easiest way to do so is to
- create a QByteArray or QString and calling QTest::toString() on it
- (see second example below).
-
- Example for specializing (Qt ≤ 5.4):
-
- \snippet code/src_qtestlib_qtestcase.cpp 16
-
- The example above defines a toString() specialization for a class
- called \c MyPoint. Whenever a comparison of two instances of \c
- MyPoint fails, \l QCOMPARE() will call this function to output the
- contents of \c MyPoint to the test log.
-
- Same example, but with overloading (Qt ≥ 5.5):
-
- \snippet code/src_qtestlib_qtestcase.cpp toString-overload
-
- \sa QCOMPARE()
-*/
-
-/*!
- \fn char *QTest::toString(const QLatin1String &string)
- \overload
-
- Returns a textual representation of the given \a string.
-*/
-
-/*!
- \fn char *QTest::toString(const QString &string)
- \overload
-
- Returns a textual representation of the given \a string.
-*/
-
-/*!
- \fn char *QTest::toString(const QByteArray &ba)
- \overload
-
- Returns a textual representation of the byte array \a ba.
-
- \sa QTest::toHexRepresentation()
-*/
-
-/*!
- \fn char *QTest::toString(const QTime &time)
- \overload
-
- Returns a textual representation of the given \a time.
-*/
-
-/*!
- \fn char *QTest::toString(const QDate &date)
- \overload
-
- Returns a textual representation of the given \a date.
-*/
-
-/*!
- \fn char *QTest::toString(const QDateTime &dateTime)
- \overload
-
- Returns a textual representation of the date and time specified by
- \a dateTime.
-*/
-
-/*!
- \fn char *QTest::toString(const QChar &character)
- \overload
-
- Returns a textual representation of the given \a character.
-*/
-
-/*!
- \fn char *QTest::toString(const QPoint &point)
- \overload
-
- Returns a textual representation of the given \a point.
-*/
-
-/*!
- \fn char *QTest::toString(const QSize &size)
- \overload
-
- Returns a textual representation of the given \a size.
-*/
-
-/*!
- \fn char *QTest::toString(const QRect &rectangle)
- \overload
-
- Returns a textual representation of the given \a rectangle.
-*/
-
-/*!
- \fn char *QTest::toString(const QUrl &url)
- \since 4.4
- \overload
-
- Returns a textual representation of the given \a url.
-*/
-
-/*!
- \fn char *QTest::toString(const QPointF &point)
- \overload
-
- Returns a textual representation of the given \a point.
-*/
-
-/*!
- \fn char *QTest::toString(const QSizeF &size)
- \overload
-
- Returns a textual representation of the given \a size.
-*/
-
-/*!
- \fn char *QTest::toString(const QRectF &rectangle)
- \overload
-
- Returns a textual representation of the given \a rectangle.
-*/
-
-/*!
- \fn char *QTest::toString(const QVariant &variant)
- \overload
-
- Returns a textual representation of the given \a variant.
-*/
-
-/*!
- \fn char *QTest::toString(QSizePolicy::ControlType ct)
- \overload
- \since 5.5
-
- Returns a textual representation of control type \a ct.
-*/
-
-/*!
- \fn char *QTest::toString(QSizePolicy::ControlTypes cts)
- \overload
- \since 5.5
-
- Returns a textual representation of control types \a cts.
-*/
-
-/*!
- \fn char *QTest::toString(QSizePolicy::Policy p)
- \overload
- \since 5.5
-
- Returns a textual representation of policy \a p.
-*/
-
-/*!
- \fn char *QTest::toString(QSizePolicy sp)
- \overload
- \since 5.5
-
- Returns a textual representation of size policy \a sp.
-*/
-
-/*! \fn void QTest::qWait(int ms)
-
- Waits for \a ms milliseconds. While waiting, events will be processed and
- your test will stay responsive to user interface events or network communication.
-
- Example:
- \snippet code/src_qtestlib_qtestcase.cpp 17
-
- The code above will wait until the network server is responding for a
- maximum of about 12.5 seconds.
-
- \sa QTest::qSleep(), QSignalSpy::wait()
-*/
-
-/*! \fn bool QTest::qWaitForWindowExposed(QWindow *window, int timeout)
- \since 5.0
-
- Waits for \a timeout milliseconds or until the \a window is exposed.
- Returns \c true if \c window is exposed within \a timeout milliseconds, otherwise returns \c false.
-
- This is mainly useful for asynchronous systems like X11, where a window will be mapped to screen some
- time after being asked to show itself on the screen.
-
- \sa QTest::qWaitForWindowActive(), QWindow::isExposed()
-*/
-
-/*! \fn bool QTest::qWaitForWindowActive(QWindow *window, int timeout)
- \since 5.0
-
- Waits for \a timeout milliseconds or until the \a window is active.
-
- Returns \c true if \c window is active within \a timeout milliseconds, otherwise returns \c false.
-
- \sa QTest::qWaitForWindowExposed(), QWindow::isActive()
-*/
-
-/*! \fn bool QTest::qWaitForWindowExposed(QWidget *widget, int timeout)
- \since 5.0
-
- Waits for \a timeout milliseconds or until the \a widget's window is exposed.
- Returns \c true if \c widget's window is exposed within \a timeout milliseconds, otherwise returns \c false.
-
- This is mainly useful for asynchronous systems like X11, where a window will be mapped to screen some
- time after being asked to show itself on the screen.
-
- \sa QTest::qWaitForWindowActive()
-*/
-
-/*! \fn bool QTest::qWaitForWindowActive(QWidget *widget, int timeout)
- \since 5.0
-
- Waits for \a timeout milliseconds or until the \a widget's window is active.
-
- Returns \c true if \c widget's window is active within \a timeout milliseconds, otherwise returns \c false.
-
- \sa QTest::qWaitForWindowExposed(), QWidget::isActiveWindow()
-*/
-
-/*! \fn bool QTest::qWaitForWindowShown(QWidget *widget, int timeout)
- \since 5.0
- \deprecated
-
- Waits for \a timeout milliseconds or until the \a widget's window is exposed.
- Returns \c true if \c widget's window is exposed within \a timeout milliseconds, otherwise returns \c false.
-
- This function does the same as qWaitForWindowExposed().
-
- Example:
- \snippet code/src_qtestlib_qtestcase.cpp 24
-
- \sa QTest::qWaitForWindowActive(), QTest::qWaitForWindowExposed()
-*/
-
-/*!
- \class QTest::QTouchEventSequence
- \inmodule QtTest
- \since 4.6
-
- \brief The QTouchEventSequence class is used to simulate a sequence of touch events.
-
- To simulate a sequence of touch events on a specific device for a window or widget, call
- QTest::touchEvent to create a QTouchEventSequence instance. Add touch events to
- the sequence by calling press(), move(), release() and stationary(), and let the
- instance run out of scope to commit the sequence to the event system.
-
- Example:
- \snippet code/src_qtestlib_qtestcase.cpp 25
-*/
-
-/*!
- \fn QTest::QTouchEventSequence::~QTouchEventSequence()
-
- Commits this sequence of touch events, unless autoCommit was disabled, and frees allocated resources.
-*/
-
-/*!
- \fn void QTest::QTouchEventSequence::commit(bool processEvents)
-
- Commits this sequence of touch events to the event system. Normally there is no need to call this
- function because it is called from the destructor. However, if autoCommit is disabled, the events
- only get committed upon explicitly calling this function.
-
- In special cases tests may want to disable the processing of the events. This can be achieved by
- setting \a processEvents to false. This results in merely queuing the events, the event loop will
- not be forced to process them.
-*/
-
-/*!
- \fn QTouchEventSequence &QTest::QTouchEventSequence::press(int touchId, const QPoint &pt, QWindow *window)
- \since 5.0
-
- Adds a press event for touchpoint \a touchId at position \a pt to this sequence and returns
- a reference to this QTouchEventSequence.
-
- The position \a pt is interpreted as relative to \a window. If \a window is the null pointer, then
- \a pt is interpreted as relative to the window provided when instantiating this QTouchEventSequence.
-
- Simulates that the user pressed the touch screen or pad with the finger identified by \a touchId.
-*/
-
-/*!
- \fn QTouchEventSequence &QTest::QTouchEventSequence::press(int touchId, const QPoint &pt, QWidget *widget)
-
- Adds a press event for touchpoint \a touchId at position \a pt to this sequence and returns
- a reference to this QTouchEventSequence.
-
- The position \a pt is interpreted as relative to \a widget. If \a widget is the null pointer, then
- \a pt is interpreted as relative to the widget provided when instantiating this QTouchEventSequence.
-
- Simulates that the user pressed the touch screen or pad with the finger identified by \a touchId.
-*/
-
-/*!
- \fn QTouchEventSequence &QTest::QTouchEventSequence::move(int touchId, const QPoint &pt, QWindow *window)
- \since 5.0
-
- Adds a move event for touchpoint \a touchId at position \a pt to this sequence and returns
- a reference to this QTouchEventSequence.
-
- The position \a pt is interpreted as relative to \a window. If \a window is the null pointer, then
- \a pt is interpreted as relative to the window provided when instantiating this QTouchEventSequence.
-
- Simulates that the user moved the finger identified by \a touchId.
-*/
-
-/*!
- \fn QTouchEventSequence &QTest::QTouchEventSequence::move(int touchId, const QPoint &pt, QWidget *widget)
-
- Adds a move event for touchpoint \a touchId at position \a pt to this sequence and returns
- a reference to this QTouchEventSequence.
-
- The position \a pt is interpreted as relative to \a widget. If \a widget is the null pointer, then
- \a pt is interpreted as relative to the widget provided when instantiating this QTouchEventSequence.
-
- Simulates that the user moved the finger identified by \a touchId.
-*/
-
-/*!
- \fn QTouchEventSequence &QTest::QTouchEventSequence::release(int touchId, const QPoint &pt, QWindow *window)
- \since 5.0
-
- Adds a release event for touchpoint \a touchId at position \a pt to this sequence and returns
- a reference to this QTouchEventSequence.
-
- The position \a pt is interpreted as relative to \a window. If \a window is the null pointer, then
- \a pt is interpreted as relative to the window provided when instantiating this QTouchEventSequence.
-
- Simulates that the user lifted the finger identified by \a touchId.
-*/
-
-/*!
- \fn QTouchEventSequence &QTest::QTouchEventSequence::release(int touchId, const QPoint &pt, QWidget *widget)
-
- Adds a release event for touchpoint \a touchId at position \a pt to this sequence and returns
- a reference to this QTouchEventSequence.
-
- The position \a pt is interpreted as relative to \a widget. If \a widget is the null pointer, then
- \a pt is interpreted as relative to the widget provided when instantiating this QTouchEventSequence.
-
- Simulates that the user lifted the finger identified by \a touchId.
-*/
-
-/*!
- \fn QTouchEventSequence &QTest::QTouchEventSequence::stationary(int touchId)
-
- Adds a stationary event for touchpoint \a touchId to this sequence and returns
- a reference to this QTouchEventSequence.
-
- Simulates that the user did not move the finger identified by \a touchId.
-*/
-
-/*!
- \fn QTouchEventSequence QTest::touchEvent(QWindow *window, QTouchDevice *device, bool autoCommit)
- \since 5.0
-
- Creates and returns a QTouchEventSequence for the \a device to
- simulate events for \a window.
-
- When adding touch events to the sequence, \a window will also be used to translate
- the position provided to screen coordinates, unless another window is provided in the
- respective calls to press(), move() etc.
-
- The touch events are committed to the event system when the destructor of the
- QTouchEventSequence is called (ie when the object returned runs out of scope), unless
- \a autoCommit is set to false. When \a autoCommit is false, commit() has to be called
- manually.
-*/
-
-/*!
- \fn QTouchEventSequence QTest::touchEvent(QWidget *widget, QTouchDevice *device, bool autoCommit)
-
- Creates and returns a QTouchEventSequence for the \a device to
- simulate events for \a widget.
-
- When adding touch events to the sequence, \a widget will also be used to translate
- the position provided to screen coordinates, unless another widget is provided in the
- respective calls to press(), move() etc.
-
- The touch events are committed to the event system when the destructor of the
- QTouchEventSequence is called (ie when the object returned runs out of scope), unless
- \a autoCommit is set to false. When \a autoCommit is false, commit() has to be called
- manually.
-*/
-
static bool installCoverageTool(const char * appname, const char * testname)
{
#ifdef __COVERAGESCANNER__
@@ -1412,43 +159,74 @@ static bool installCoverageTool(const char * appname, const char * testname)
#endif
}
+static bool isValidSlot(const QMetaMethod &sl)
+{
+ if (sl.access() != QMetaMethod::Private || sl.parameterCount() != 0
+ || sl.returnType() != QMetaType::Void || sl.methodType() != QMetaMethod::Slot)
+ return false;
+ const QByteArray name = sl.name();
+ return !(name.isEmpty() || name.endsWith("_data")
+ || name == "initTestCase" || name == "cleanupTestCase"
+ || name == "init" || name == "cleanup");
+}
+
namespace QTest
{
+ class WatchDog;
+
static QObject *currentTestObject = 0;
static QString mainSourcePath;
- class TestFunction {
+ class TestMethods {
+ Q_DISABLE_COPY(TestMethods)
public:
- TestFunction() : function_(-1), data_(0) {}
- void set(int function, char *data) { function_ = function; data_ = data; }
- char *data() const { return data_; }
- int function() const { return function_; }
- ~TestFunction() { delete[] data_; }
+ typedef std::vector<QMetaMethod> MetaMethods;
+
+ explicit TestMethods(const QObject *o, const MetaMethods &m = MetaMethods());
+
+ void invokeTests(QObject *testObject) const;
+
+ static QMetaMethod findMethod(const QObject *obj, const char *signature);
+
private:
- int function_;
- char *data_;
+ bool invokeTest(int index, const char *data, WatchDog *watchDog) const;
+ void invokeTestOnData(int index) const;
+
+ QMetaMethod m_initTestCaseMethod; // might not exist, check isValid().
+ QMetaMethod m_initTestCaseDataMethod;
+ QMetaMethod m_cleanupTestCaseMethod;
+ QMetaMethod m_initMethod;
+ QMetaMethod m_cleanupMethod;
+
+ MetaMethods m_methods;
};
- /**
- * Contains the list of test functions that was supplied
- * on the command line, if any. Hence, if not empty,
- * those functions should be run instead of
- * all appearing in the test case.
- */
- static TestFunction * testFuncs = 0;
- static int testFuncCount = 0;
-
- /** Don't leak testFuncs on exit even on error */
- static struct TestFuncCleanup
+
+ TestMethods::TestMethods(const QObject *o, const MetaMethods &m)
+ : m_initTestCaseMethod(TestMethods::findMethod(o, "initTestCase()"))
+ , m_initTestCaseDataMethod(TestMethods::findMethod(o, "initTestCase_data()"))
+ , m_cleanupTestCaseMethod(TestMethods::findMethod(o, "cleanupTestCase()"))
+ , m_initMethod(TestMethods::findMethod(o, "init()"))
+ , m_cleanupMethod(TestMethods::findMethod(o, "cleanup()"))
+ , m_methods(m)
{
- void cleanup()
- {
- delete[] testFuncs;
- testFuncCount = 0;
- testFuncs = 0;
+ if (m.empty()) {
+ const QMetaObject *metaObject = o->metaObject();
+ const int count = metaObject->methodCount();
+ m_methods.reserve(count);
+ for (int i = 0; i < count; ++i) {
+ const QMetaMethod me = metaObject->method(i);
+ if (isValidSlot(me))
+ m_methods.push_back(me);
+ }
}
+ }
- ~TestFuncCleanup() { cleanup(); }
- } testFuncCleaner;
+ QMetaMethod TestMethods::findMethod(const QObject *obj, const char *signature)
+ {
+ const QMetaObject *metaObject = obj->metaObject();
+ const int funcIndex = metaObject->indexOfMethod(signature);
+ return funcIndex >= 0 ? metaObject->method(funcIndex) : QMetaMethod();
+ }
static int keyDelay = -1;
static int mouseDelay = -1;
@@ -1504,22 +282,6 @@ int Q_TESTLIB_EXPORT defaultKeyDelay()
return keyDelay;
}
-static bool isValidSlot(const QMetaMethod &sl)
-{
- if (sl.access() != QMetaMethod::Private || sl.parameterCount() != 0
- || sl.returnType() != QMetaType::Void || sl.methodType() != QMetaMethod::Slot)
- return false;
- QByteArray name = sl.name();
- if (name.isEmpty())
- return false;
- if (name.endsWith("_data"))
- return false;
- if (name == "initTestCase" || name == "cleanupTestCase"
- || name == "cleanup" || name == "init")
- return false;
- return true;
-}
-
Q_TESTLIB_EXPORT bool printAvailableFunctions = false;
Q_TESTLIB_EXPORT QStringList testFunctions;
Q_TESTLIB_EXPORT QStringList testTags;
@@ -1617,6 +379,9 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml)
QTestLog::LogMode logFormat = QTestLog::Plain;
const char *logFilename = 0;
+ QTest::testFunctions.clear();
+ QTest::testTags.clear();
+
#if defined(Q_OS_MAC) && defined(HAVE_XCTEST)
if (QXcodeTestLogger::canLogTestProgress())
logFormat = QTestLog::XCTest;
@@ -1897,7 +662,7 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml)
fprintf(stderr, "\n"
" -help : This help\n");
exit(1);
- } else if (qml) {
+ } else {
// We can't check the availability of test functions until
// we load the QML files. So just store the data for now.
int colon = -1;
@@ -1923,36 +688,6 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml)
QTest::testTags +=
QString::fromLatin1(argv[i] + colon + 1);
}
- } else {
- if (!QTest::testFuncs) {
- QTest::testFuncs = new QTest::TestFunction[512];
- }
-
- int colon = -1;
- char buf[512], *data=0;
- int off;
- for (off = 0; *(argv[i]+off); ++off) {
- if (*(argv[i]+off) == ':') {
- colon = off;
- break;
- }
- }
- if (colon != -1) {
- data = qstrdup(argv[i]+colon+1);
- }
- qsnprintf(buf, qMin(512, off + 1), "%s", argv[i]); // copy text before the ':' into buf
- qsnprintf(buf + off, qMin(512 - off, 3), "()"); // append "()"
- int idx = QTest::currentTestObject->metaObject()->indexOfMethod(buf);
- if (idx < 0 || !isValidSlot(QTest::currentTestObject->metaObject()->method(idx))) {
- fprintf(stderr, "Unknown test function: '%s'. Possible matches:\n", buf);
- buf[off] = 0;
- qPrintTestSlots(stderr, buf);
- fprintf(stderr, "\n%s -functions\nlists all available test functions.\n", argv[0]);
- exit(1);
- }
- testFuncs[testFuncCount].set(idx, data);
- testFuncCount++;
- QTEST_ASSERT(QTest::testFuncCount < 512);
}
}
@@ -2005,7 +740,7 @@ qreal addResult(qreal current, const QBenchmarkResult& r)
}
-static void qInvokeTestMethodDataEntry(char *slot)
+void TestMethods::invokeTestOnData(int index) const
{
/* Benchmarking: for each median iteration*/
@@ -2020,7 +755,8 @@ static void qInvokeTestMethodDataEntry(char *slot)
/* Benchmarking: for each accumulation iteration*/
bool invokeOk;
do {
- invokeMethod(QTest::currentTestObject, "init()");
+ if (m_initMethod.isValid())
+ m_initMethod.invoke(QTest::currentTestObject, Qt::DirectConnection);
if (QTestResult::skipCurrentTest() || QTestResult::currentTestFailed())
break;
@@ -2032,8 +768,7 @@ static void qInvokeTestMethodDataEntry(char *slot)
QTestResult::currentDataTag()
? QTestResult::currentDataTag() : "");
- invokeOk = QMetaObject::invokeMethod(QTest::currentTestObject, slot,
- Qt::DirectConnection);
+ invokeOk = m_methods[index].invoke(QTest::currentTestObject, Qt::DirectConnection);
if (!invokeOk)
QTestResult::addFailure("Unable to execute slot", __FILE__, __LINE__);
@@ -2041,7 +776,8 @@ static void qInvokeTestMethodDataEntry(char *slot)
QTestResult::finishedCurrentTestData();
- invokeMethod(QTest::currentTestObject, "cleanup()");
+ if (m_cleanupMethod.isValid())
+ m_cleanupMethod.invoke(QTest::currentTestObject, Qt::DirectConnection);
// If the test isn't a benchmark, finalize the result after cleanup() has finished.
if (!isBenchmark)
@@ -2132,7 +868,7 @@ public:
int t = timeout.load();
if (!t)
break;
- if (!waitCondition.wait(&mutex, t)) {
+ if (Q_UNLIKELY(!waitCondition.wait(&mutex, t))) {
stackTrace();
qFatal("Test function timed out");
}
@@ -2155,21 +891,18 @@ private:
If the function was successfully called, true is returned, otherwise
false.
*/
-static bool qInvokeTestMethod(const char *slotName, const char *data, WatchDog *watchDog)
+bool TestMethods::invokeTest(int index, const char *data, WatchDog *watchDog) const
{
- QTEST_ASSERT(slotName);
-
QBenchmarkTestMethodData benchmarkData;
QBenchmarkTestMethodData::current = &benchmarkData;
- QBenchmarkGlobalData::current->context.slotName = QLatin1String(slotName);
+ const QByteArray &name = m_methods[index].name();
+ QBenchmarkGlobalData::current->context.slotName = QLatin1String(name) + QStringLiteral("()");
char member[512];
QTestTable table;
- char *slot = qstrdup(slotName);
- slot[strlen(slot) - 2] = '\0';
- QTestResult::setCurrentTestFunction(slot);
+ QTestResult::setCurrentTestFunction(name.constData());
const QTestTable *gTable = QTestTable::globalTestTable();
const int globalDataCount = gTable->dataCount();
@@ -2181,7 +914,7 @@ static bool qInvokeTestMethod(const char *slotName, const char *data, WatchDog *
QTestResult::setCurrentGlobalTestData(gTable->testData(curGlobalDataIndex));
if (curGlobalDataIndex == 0) {
- qsnprintf(member, 512, "%s_data()", slot);
+ qsnprintf(member, 512, "%s_data()", name.constData());
invokeMethod(QTest::currentTestObject, member);
}
@@ -2196,7 +929,7 @@ static bool qInvokeTestMethod(const char *slotName, const char *data, WatchDog *
if (!*data)
data = 0;
else {
- fprintf(stderr, "Unknown testdata for function %s: '%s'\n", slotName, data);
+ fprintf(stderr, "Unknown testdata for function %s(): '%s'\n", name.constData(), data);
fprintf(stderr, "Function has no testdata.\n");
return false;
}
@@ -2209,14 +942,14 @@ static bool qInvokeTestMethod(const char *slotName, const char *data, WatchDog *
if (!data || !qstrcmp(data, table.testData(curDataIndex)->dataTag())) {
foundFunction = true;
- QTestPrivate::checkBlackLists(slot, dataCount ? table.testData(curDataIndex)->dataTag() : 0);
+ QTestPrivate::checkBlackLists(name.constData(), dataCount ? table.testData(curDataIndex)->dataTag() : 0);
QTestDataSetter s(curDataIndex >= dataCount ? static_cast<QTestData *>(0)
: table.testData(curDataIndex));
if (watchDog)
watchDog->beginTest();
- qInvokeTestMethodDataEntry(slot);
+ invokeTestOnData(index);
if (watchDog)
watchDog->testFinished();
@@ -2228,7 +961,7 @@ static bool qInvokeTestMethod(const char *slotName, const char *data, WatchDog *
}
if (data && !foundFunction) {
- fprintf(stderr, "Unknown testdata for function %s: '%s'\n", slotName, data);
+ fprintf(stderr, "Unknown testdata for function %s: '%s()'\n", name.constData(), data);
fprintf(stderr, "Available testdata:\n");
for (int i = 0; i < table.dataCount(); ++i)
fprintf(stderr, "%s\n", table.testData(i)->dataTag());
@@ -2243,7 +976,6 @@ static bool qInvokeTestMethod(const char *slotName, const char *data, WatchDog *
QTestResult::setSkipCurrentTest(false);
QTestResult::setBlacklistCurrentTest(false);
QTestResult::setCurrentTestData(0);
- delete[] slot;
return true;
}
@@ -2256,12 +988,12 @@ void *fetchData(QTestData *data, const char *tagName, int typeId)
int idx = data->parent()->indexOf(tagName);
- if (idx == -1 || idx >= data->dataCount()) {
+ if (Q_UNLIKELY(idx == -1 || idx >= data->dataCount())) {
qFatal("QFETCH: Requested testdata '%s' not available, check your _data function.",
tagName);
}
- if (typeId != data->parent()->elementTypeId(idx)) {
+ if (Q_UNLIKELY(typeId != data->parent()->elementTypeId(idx))) {
qFatal("Requested type '%s' does not match available type '%s'.",
QMetaType::typeName(typeId),
QMetaType::typeName(data->parent()->elementTypeId(idx)));
@@ -2521,21 +1253,23 @@ static bool debuggerPresent()
#endif
}
-static void qInvokeTestMethods(QObject *testObject)
+void TestMethods::invokeTests(QObject *testObject) const
{
const QMetaObject *metaObject = testObject->metaObject();
QTEST_ASSERT(metaObject);
QTestLog::startLogging();
QTestResult::setCurrentTestFunction("initTestCase");
QTestTable::globalTestTable();
- invokeMethod(testObject, "initTestCase_data()");
+ if (m_initTestCaseDataMethod.isValid())
+ m_initTestCaseDataMethod.invoke(testObject, Qt::DirectConnection);
QScopedPointer<WatchDog> watchDog;
if (!debuggerPresent())
watchDog.reset(new WatchDog);
if (!QTestResult::skipCurrentTest() && !QTest::currentTestFailed()) {
- invokeMethod(testObject, "initTestCase()");
+ if (m_initTestCaseMethod.isValid())
+ m_initTestCaseMethod.invoke(testObject, Qt::DirectConnection);
// finishedCurrentTestDataCleanup() resets QTestResult::currentTestFailed(), so use a local copy.
const bool previousFailed = QTestResult::currentTestFailed();
@@ -2544,35 +1278,22 @@ static void qInvokeTestMethods(QObject *testObject)
QTestResult::finishedCurrentTestFunction();
if (!QTestResult::skipCurrentTest() && !previousFailed) {
-
- if (QTest::testFuncs) {
- for (int i = 0; i != QTest::testFuncCount; i++) {
- if (!qInvokeTestMethod(metaObject->method(QTest::testFuncs[i].function()).methodSignature().constData(),
- QTest::testFuncs[i].data(), watchDog.data())) {
- break;
- }
- }
- testFuncCleaner.cleanup();
- } else {
- int methodCount = metaObject->methodCount();
- QMetaMethod *testMethods = new QMetaMethod[methodCount];
- for (int i = 0; i != methodCount; i++)
- testMethods[i] = metaObject->method(i);
- for (int i = 0; i != methodCount; i++) {
- if (!isValidSlot(testMethods[i]))
- continue;
- if (!qInvokeTestMethod(testMethods[i].methodSignature().constData(), 0, watchDog.data()))
- break;
- }
- delete[] testMethods;
- testMethods = 0;
+ for (int i = 0, count = int(m_methods.size()); i < count; ++i) {
+ const char *data = Q_NULLPTR;
+ if (i < QTest::testTags.size() && !QTest::testTags.at(i).isEmpty())
+ data = qstrdup(QTest::testTags.at(i).toLatin1().constData());
+ const bool ok = invokeTest(i, data, watchDog.data());
+ delete [] data;
+ if (!ok)
+ break;
}
}
QTestResult::setSkipCurrentTest(false);
QTestResult::setBlacklistCurrentTest(false);
QTestResult::setCurrentTestFunction("cleanupTestCase");
- invokeMethod(testObject, "cleanupTestCase()");
+ if (m_cleanupTestCaseMethod.isValid())
+ m_cleanupTestCaseMethod.invoke(testObject, Qt::DirectConnection);
QTestResult::finishedCurrentTestData();
QTestResult::finishedCurrentTestDataCleanup();
}
@@ -2940,7 +1661,7 @@ int QTest::qExec(QObject *testObject, int argc, char **argv)
#ifdef QTESTLIB_USE_VALGRIND
if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess) {
- if (!qApp)
+ if (Q_UNLIKELY(!qApp))
qFatal("QtTest: -callgrind option is not available with QTEST_APPLESS_MAIN");
const QStringList origAppArgs(QCoreApplication::arguments());
@@ -2957,7 +1678,23 @@ int QTest::qExec(QObject *testObject, int argc, char **argv)
if (!noCrashHandler)
handler.reset(new FatalSignalHandler);
#endif
- qInvokeTestMethods(testObject);
+ TestMethods::MetaMethods commandLineMethods;
+ if (!QTest::testFunctions.isEmpty()) {
+ foreach (const QString &tf, QTest::testFunctions) {
+ const QByteArray tfB = tf.toLatin1();
+ const QByteArray signature = tfB + QByteArrayLiteral("()");
+ QMetaMethod m = TestMethods::findMethod(testObject, signature.constData());
+ if (!m.isValid() || !isValidSlot(m)) {
+ fprintf(stderr, "Unknown test function: '%s'. Possible matches:\n", tfB.constData());
+ qPrintTestSlots(stderr, tfB.constData());
+ fprintf(stderr, "\n%s -functions\nlists all available test functions.\n", argv[0]);
+ exit(1);
+ }
+ commandLineMethods.push_back(m);
+ }
+ }
+ TestMethods test(testObject, commandLineMethods);
+ test.invokeTests(testObject);
}
#ifndef QT_NO_EXCEPTIONS
@@ -3578,6 +2315,11 @@ bool QTest::compare_string_helper(const char *t1, const char *t2, const char *ac
toString(t1), toString(t2), actual, expected, file, line);
}
+/*!
+ \namespace QTest::Internal
+ \internal
+*/
+
/*! \fn bool QTest::compare_ptr_helper(const void *t1, const void *t2, const char *actual, const char *expected, const char *file, int line);
\internal
*/