diff options
Diffstat (limited to 'src/testlib/qtestcase.cpp')
-rw-r--r-- | src/testlib/qtestcase.cpp | 157 |
1 files changed, 124 insertions, 33 deletions
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 17f1a6b..5934850 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -826,25 +826,46 @@ namespace QTest { static QObject *currentTestObject = 0; - static struct TestFunction { - TestFunction():function(0), data(0) {} - ~TestFunction() { delete [] data; } - int function; - char *data; - } *testFuncs; - + class TestFunction { + 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_; } + private: + int function_; + char *data_; + }; /** - * Contains the count of test functions that was supplied - * on the command line, if any. Hence, if lastTestFuncIdx is - * more than zero, those functions should be run instead of + * 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 int lastTestFuncIdx = -1; + static TestFunction * testFuncs = 0; + static int testFuncCount = 0; + + /** Don't leak testFuncs on exit even on error */ + static struct TestFuncCleanup + { + void cleanup() + { + delete[] testFuncs; + testFuncCount = 0; + testFuncs = 0; + } + + ~TestFuncCleanup() { cleanup(); } + } testFuncCleaner; static int keyDelay = -1; static int mouseDelay = -1; static int eventDelay = -1; + static bool randomOrder = false; static int keyVerbose = -1; + static unsigned int seed = 0; + static bool seedSet = false; #if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) static bool noCrashHandler = false; #endif @@ -930,6 +951,41 @@ int Q_TESTLIB_EXPORT defaultKeyDelay() return keyDelay; } +void seedRandom() +{ + static bool randomSeeded = false; + if (!randomSeeded) { + if (!QTest::seedSet) { + QTest::seed = QDateTime::currentDateTime().toTime_t(); + } + qsrand(QTest::seed); + randomSeeded = true; + } +} + +int qTestRandomSeed() +{ + Q_ASSERT(QTest::seedSet); + return QTest::seed; +} + +template<typename T> +void swap(T * array, int pos, int otherPos) +{ + T tmp = array[pos]; + array[pos] = array[otherPos]; + array[otherPos] = tmp; +} + +template<typename T> +static void randomizeList(T * array, int size) +{ + for (int i = 0; i != size; i++) { + int pos = qrand() % size; + swap(array, pos, i); + } +} + static bool isValidSlot(const QMetaMethod &sl) { if (sl.access() != QMetaMethod::Private || !sl.parameterTypes().isEmpty() @@ -971,8 +1027,6 @@ static int qToInt(char *str) static void qParseArgs(int argc, char *argv[]) { - lastTestFuncIdx = -1; - const char *testOptions = " options:\n" " -functions : Returns a list of current testfunctions\n" @@ -985,6 +1039,9 @@ static void qParseArgs(int argc, char *argv[]) " -v1 : Print enter messages for each testfunction\n" " -v2 : Also print out each QVERIFY/QCOMPARE/QTEST\n" " -vs : Print every signal emitted\n" + " -random : Run testcases within each test in random order\n" + " -seed n : Positive integer to be used as seed for -random. If not specified,\n" + " the current time will be used as seed.\n" " -eventdelay ms : Set default delay for mouse and keyboard simulation to ms milliseconds\n" " -keydelay ms : Set default delay for keyboard simulation to ms milliseconds\n" " -mousedelay ms : Set default delay for mouse simulation to ms milliseconds\n" @@ -1100,6 +1157,22 @@ static void qParseArgs(int argc, char *argv[]) #endif } else if (strcmp(argv[i], "-eventcounter") == 0) { QBenchmarkGlobalData::current->setMode(QBenchmarkGlobalData::EventCounter); + } else if (strcmp(argv[i], "-random") == 0) { + QTest::randomOrder = true; + } else if (strcmp(argv[i], "-seed") == 0) { + bool argumentOk = false; + if (i + 1 < argc) { + char * endpt = 0; + long longSeed = strtol(argv[++i], &endpt, 10); + argumentOk = (*endpt == '\0' && longSeed >= 0); + QTest::seed = longSeed; + } + if (!argumentOk) { + printf("-seed needs an extra positive integer parameter to specify the seed\n"); + exit(1); + } else { + QTest::seedSet = true; + } } else if (strcmp(argv[i], "-minimumvalue") == 0) { if (i + 1 >= argc) { printf("-minimumvalue needs an extra parameter to indicate the minimum time(ms)\n"); @@ -1140,6 +1213,10 @@ static void qParseArgs(int argc, char *argv[]) printf("Unknown option: '%s'\n\n%s", argv[i], testOptions); exit(1); } else { + if (!QTest::testFuncs) { + QTest::testFuncs = new QTest::TestFunction[512]; + } + int colon = -1; char buf[512], *data=0; int off; @@ -1161,17 +1238,16 @@ static void qParseArgs(int argc, char *argv[]) qPrintTestSlots(); exit(1); } - ++QTest::lastTestFuncIdx; - if (!QTest::testFuncs) { - struct Cleanup { ~Cleanup() { delete[] QTest::testFuncs; } }; - static Cleanup cleanup; - QTest::testFuncs = new TestFunction[512]; - } - QTest::testFuncs[QTest::lastTestFuncIdx].function = idx; - QTest::testFuncs[QTest::lastTestFuncIdx].data = data; - QTEST_ASSERT(QTest::lastTestFuncIdx < 512); + testFuncs[testFuncCount].set(idx, data); + testFuncCount++; + QTEST_ASSERT(QTest::testFuncCount < 512); } } + + if (QTest::seedSet && !QTest::randomOrder) { + printf("-seed requires -random\n"); + exit(1); + } } QBenchmarkResult qMedian(const QList<QBenchmarkResult> &container) @@ -1466,9 +1542,11 @@ static void qInvokeTestMethods(QObject *testObject) { const QMetaObject *metaObject = testObject->metaObject(); QTEST_ASSERT(metaObject); - - QTestLog::startLogging(); - + if (QTest::randomOrder) { + QTestLog::startLogging(QTest::seed); + } else { + QTestLog::startLogging(); + } QTestResult::setCurrentTestFunction("initTestCase"); QTestResult::setCurrentTestLocation(QTestResult::DataFunc); QTestTable::globalTestTable(); @@ -1484,21 +1562,31 @@ static void qInvokeTestMethods(QObject *testObject) if(!QTestResult::skipCurrentTest() && !previousFailed) { - if (lastTestFuncIdx >= 0) { - for (int i = 0; i <= lastTestFuncIdx; ++i) { - if (!qInvokeTestMethod(metaObject->method(testFuncs[i].function).signature(), - testFuncs[i].data)) + if (QTest::testFuncs) { + if (QTest::randomOrder) + randomizeList(QTest::testFuncs, QTest::testFuncCount); + for (int i = 0; i != QTest::testFuncCount; i++) { + if (!qInvokeTestMethod(metaObject->method(QTest::testFuncs[i].function()).signature(), + QTest::testFuncs[i].data())) { break; + } } + testFuncCleaner.cleanup(); } else { int methodCount = metaObject->methodCount(); - for (int i = 0; i < methodCount; ++i) { - QMetaMethod slotMethod = metaObject->method(i); - if (!isValidSlot(slotMethod)) + QMetaMethod *testMethods = new QMetaMethod[methodCount]; + for (int i = 0; i != methodCount; i++) + testMethods[i] = metaObject->method(i); + if (QTest::randomOrder) + randomizeList(testMethods, methodCount); + for (int i = 0; i != methodCount; i++) { + if (!isValidSlot(testMethods[i])) continue; - if (!qInvokeTestMethod(slotMethod.signature())) + if (!qInvokeTestMethod(testMethods[i].signature())) break; } + delete[] testMethods; + testMethods = 0; } } @@ -1689,6 +1777,9 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) QTestResult::setCurrentTestObject(metaObject->className()); qParseArgs(argc, argv); + if (QTest::randomOrder) { + seedRandom(); + } #ifdef QTESTLIB_USE_VALGRIND if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess) { const QStringList origAppArgs(QCoreApplication::arguments()); |