1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "quicktestresult_p.h"
43 #include <QtTest/qtestcase.h>
44 #include <QtTest/qtestsystem.h>
45 #include <QtTest/private/qtestresult_p.h>
46 #include <QtTest/private/qtesttable_p.h>
47 #include <QtTest/private/qtestlog_p.h>
48 #include "qtestoptions_p.h"
49 #include <QtTest/qbenchmark.h>
50 #include <QtTest/private/qbenchmark_p.h>
51 #include <QtCore/qset.h>
52 #include <QtCore/qmap.h>
53 #include <QtCore/qbytearray.h>
54 #include <QtCore/qcoreapplication.h>
55 #include <QtCore/qdebug.h>
59 static const char *globalProgramName = 0;
60 static bool loggingStarted = false;
61 static QBenchmarkGlobalData globalBenchmarkData;
63 class QuickTestResultPrivate
66 QuickTestResultPrivate()
73 ~QuickTestResultPrivate()
80 QByteArray intern(const QString &str);
84 QSet<QByteArray> internedStrings;
86 QTest::QBenchmarkIterationController *benchmarkIter;
87 QBenchmarkTestMethodData *benchmarkData;
89 QList<QBenchmarkResult> results;
92 QByteArray QuickTestResultPrivate::intern(const QString &str)
94 QByteArray bstr = str.toUtf8();
95 return *(internedStrings.insert(bstr));
98 QuickTestResult::QuickTestResult(QObject *parent)
99 : QObject(parent), d_ptr(new QuickTestResultPrivate)
101 if (!QBenchmarkGlobalData::current)
102 QBenchmarkGlobalData::current = &globalBenchmarkData;
105 QuickTestResult::~QuickTestResult()
110 \qmlproperty string TestResult::testCaseName
112 This property defines the name of current TestCase element
113 that is running test cases.
117 QString QuickTestResult::testCaseName() const
119 Q_D(const QuickTestResult);
120 return d->testCaseName;
123 void QuickTestResult::setTestCaseName(const QString &name)
125 Q_D(QuickTestResult);
126 d->testCaseName = name;
127 emit testCaseNameChanged();
131 \qmlproperty string TestResult::functionName
133 This property defines the name of current test function
134 within a TestCase element that is running. If this string is
135 empty, then no function is currently running.
139 QString QuickTestResult::functionName() const
141 Q_D(const QuickTestResult);
142 return d->functionName;
145 void QuickTestResult::setFunctionName(const QString &name)
147 Q_D(QuickTestResult);
148 if (!name.isEmpty()) {
149 if (d->testCaseName.isEmpty()) {
150 QTestResult::setCurrentTestFunction
151 (d->intern(name).constData());
153 QString fullName = d->testCaseName + QLatin1String("::") + name;
154 QTestResult::setCurrentTestFunction
155 (d->intern(fullName).constData());
158 QTestResult::setCurrentTestFunction(0);
160 d->functionName = name;
161 emit functionNameChanged();
164 QuickTestResult::FunctionType QuickTestResult::functionType() const
166 return FunctionType(QTestResult::currentTestLocation());
169 void QuickTestResult::setFunctionType(FunctionType type)
171 QTestResult::setCurrentTestLocation(QTestResult::TestLocation(type));
172 emit functionTypeChanged();
176 \qmlproperty string TestResult::dataTag
178 This property defines the tag for the current row in a
179 data-driven test, or an empty string if not a data-driven test.
181 QString QuickTestResult::dataTag() const
183 const char *tag = QTestResult::currentDataTag();
185 return QString::fromUtf8(tag);
190 void QuickTestResult::setDataTag(const QString &tag)
192 if (!tag.isEmpty()) {
193 QTestData *data = &(QTest::newRow(tag.toUtf8().constData()));
194 QTestResult::setCurrentTestData(data);
195 emit dataTagChanged();
197 QTestResult::setCurrentTestData(0);
202 \qmlproperty bool TestResult::failed
204 This property returns true if the current test function has
205 failed; false otherwise. The fail state is reset when
206 functionName is changed or finishTestFunction() is called.
208 \sa skipped, dataFailed
210 bool QuickTestResult::isFailed() const
212 return QTestResult::testFailed();
216 \qmlproperty bool TestResult::dataFailed
218 This property returns true if the current data function has
219 failed; false otherwise. The fail state is reset when
220 functionName is changed or finishTestFunction() is called.
224 bool QuickTestResult::isDataFailed() const
226 return QTestResult::currentTestFailed();
230 \qmlproperty bool TestResult::skipped
232 This property returns true if the current test function was
233 marked as skipped; false otherwise.
237 bool QuickTestResult::isSkipped() const
239 return QTestResult::skipCurrentTest();
242 void QuickTestResult::setSkipped(bool skip)
244 QTestResult::setSkipCurrentTest(skip);
245 emit skippedChanged();
249 \qmlproperty int TestResult::passCount
251 This property returns the number of tests that have passed.
253 \sa failCount, skipCount
255 int QuickTestResult::passCount() const
257 return QTestResult::passCount();
261 \qmlproperty int TestResult::failCount
263 This property returns the number of tests that have failed.
265 \sa passCount, skipCount
267 int QuickTestResult::failCount() const
269 return QTestResult::failCount();
273 \qmlproperty int TestResult::skipCount
275 This property returns the number of tests that have been skipped.
277 \sa passCount, failCount
279 int QuickTestResult::skipCount() const
281 return QTestResult::skipCount();
285 \qmlproperty list<string> TestResult::functionsToRun
287 This property returns the list of function names to be run.
289 QStringList QuickTestResult::functionsToRun() const
291 return QTest::testFunctions;
295 \qmlmethod TestResult::reset()
297 Resets all pass/fail/skip counters and prepare for testing.
299 void QuickTestResult::reset()
301 if (!globalProgramName) // Only if run via qmlviewer.
302 QTestResult::reset();
306 \qmlmethod TestResult::startLogging()
308 Starts logging to the test output stream and writes the
313 void QuickTestResult::startLogging()
315 // The program name is used for logging headers and footers if it
316 // is set. Otherwise the test case name is used.
317 Q_D(QuickTestResult);
320 QTestLog::startLogging();
321 loggingStarted = true;
325 \qmlmethod TestResult::stopLogging()
327 Writes the test footer to the test output stream and then stops logging.
331 void QuickTestResult::stopLogging()
333 Q_D(QuickTestResult);
334 if (globalProgramName)
335 return; // Logging will be stopped by setProgramName(0).
336 QTestResult::setCurrentTestObject(d->intern(d->testCaseName).constData());
337 QTestLog::stopLogging();
340 void QuickTestResult::initTestTable()
342 Q_D(QuickTestResult);
344 d->table = new QTestTable;
347 void QuickTestResult::clearTestTable()
349 Q_D(QuickTestResult);
354 void QuickTestResult::finishTestFunction()
356 QTestResult::finishedCurrentTestFunction();
359 static QString qtest_fixFile(const QString &file)
361 if (file.startsWith(QLatin1String("file://")))
367 void QuickTestResult::fail
368 (const QString &message, const QString &file, int line)
370 QTestResult::addFailure(message.toLatin1().constData(),
371 qtest_fixFile(file).toLatin1().constData(), line);
374 bool QuickTestResult::verify
375 (bool success, const QString &message, const QString &file, int line)
377 if (!success && message.isEmpty()) {
378 return QTestResult::verify
379 (success, "verify()", "",
380 qtest_fixFile(file).toLatin1().constData(), line);
382 return QTestResult::verify
383 (success, message.toLatin1().constData(), "",
384 qtest_fixFile(file).toLatin1().constData(), line);
388 bool QuickTestResult::compare
389 (bool success, const QString &message,
390 const QString &val1, const QString &val2,
391 const QString &file, int line)
394 return QTestResult::compare
395 (success, message.toLocal8Bit().constData(),
396 qtest_fixFile(file).toLatin1().constData(), line);
398 return QTestResult::compare
399 (success, message.toLocal8Bit().constData(),
400 QTest::toString(val1.toLatin1().constData()),
401 QTest::toString(val2.toLatin1().constData()),
403 qtest_fixFile(file).toLatin1().constData(), line);
407 void QuickTestResult::skipSingle
408 (const QString &message, const QString &file, int line)
410 QTestResult::addSkip(message.toLatin1().constData(),
411 qtest_fixFile(file).toLatin1().constData(), line);
414 void QuickTestResult::skipAll
415 (const QString &message, const QString &file, int line)
417 QTestResult::addSkip(message.toLatin1().constData(),
418 qtest_fixFile(file).toLatin1().constData(), line);
419 QTestResult::setSkipCurrentTest(true);
422 bool QuickTestResult::expectFail
423 (const QString &tag, const QString &comment, const QString &file, int line)
425 return QTestResult::expectFail
426 (tag.toLatin1().constData(),
427 QTest::toString(comment.toLatin1().constData()),
428 QTest::Abort, qtest_fixFile(file).toLatin1().constData(), line);
431 bool QuickTestResult::expectFailContinue
432 (const QString &tag, const QString &comment, const QString &file, int line)
434 return QTestResult::expectFail
435 (tag.toLatin1().constData(),
436 QTest::toString(comment.toLatin1().constData()),
437 QTest::Continue, qtest_fixFile(file).toLatin1().constData(), line);
440 void QuickTestResult::warn(const QString &message)
442 QTestLog::warn(message.toLatin1().constData(), 0, 0);
445 void QuickTestResult::ignoreWarning(const QString &message)
447 QTestResult::ignoreMessage(QtWarningMsg, message.toLatin1().constData());
450 void QuickTestResult::wait(int ms)
455 void QuickTestResult::sleep(int ms)
460 void QuickTestResult::startMeasurement()
462 Q_D(QuickTestResult);
463 delete d->benchmarkData;
464 d->benchmarkData = new QBenchmarkTestMethodData();
465 QBenchmarkTestMethodData::current = d->benchmarkData;
466 d->iterCount = (QBenchmarkGlobalData::current->measurer->needsWarmupIteration()) ? -1 : 0;
470 void QuickTestResult::beginDataRun()
472 QBenchmarkTestMethodData::current->beginDataRun();
475 void QuickTestResult::endDataRun()
477 Q_D(QuickTestResult);
478 QBenchmarkTestMethodData::current->endDataRun();
479 if (d->iterCount > -1) // iteration -1 is the warmup iteration.
480 d->results.append(QBenchmarkTestMethodData::current->result);
482 if (QBenchmarkGlobalData::current->verboseOutput) {
483 if (d->iterCount == -1) {
484 qDebug() << "warmup stage result :" << QBenchmarkTestMethodData::current->result.value;
486 qDebug() << "accumulation stage result:" << QBenchmarkTestMethodData::current->result.value;
491 bool QuickTestResult::measurementAccepted()
493 return QBenchmarkTestMethodData::current->resultsAccepted();
496 static QBenchmarkResult qMedian(const QList<QBenchmarkResult> &container)
498 const int count = container.count();
500 return QBenchmarkResult();
503 return container.at(0);
505 QList<QBenchmarkResult> containerCopy = container;
506 qSort(containerCopy);
508 const int middle = count / 2;
510 // ### handle even-sized containers here by doing an aritmetic mean of the two middle items.
511 return containerCopy.at(middle);
514 bool QuickTestResult::needsMoreMeasurements()
516 Q_D(QuickTestResult);
518 if (d->iterCount < QBenchmarkGlobalData::current->adjustMedianIterationCount())
520 if (QBenchmarkTestMethodData::current->resultsAccepted())
521 QTestLog::addBenchmarkResult(qMedian(d->results));
525 void QuickTestResult::startBenchmark(RunMode runMode, const QString &tag)
527 QBenchmarkTestMethodData::current->result = QBenchmarkResult();
528 QBenchmarkTestMethodData::current->resultAccepted = false;
529 QBenchmarkGlobalData::current->context.tag = tag;
530 QBenchmarkGlobalData::current->context.slotName = functionName();
532 Q_D(QuickTestResult);
533 delete d->benchmarkIter;
534 d->benchmarkIter = new QTest::QBenchmarkIterationController
535 (QTest::QBenchmarkIterationController::RunMode(runMode));
538 bool QuickTestResult::isBenchmarkDone() const
540 Q_D(const QuickTestResult);
541 if (d->benchmarkIter)
542 return d->benchmarkIter->isDone();
547 void QuickTestResult::nextBenchmark()
549 Q_D(QuickTestResult);
550 if (d->benchmarkIter)
551 d->benchmarkIter->next();
554 void QuickTestResult::stopBenchmark()
556 Q_D(QuickTestResult);
557 delete d->benchmarkIter;
558 d->benchmarkIter = 0;
562 void qtest_qParseArgs(int argc, char *argv[], bool qml);
565 void QuickTestResult::parseArgs(int argc, char *argv[])
567 if (!QBenchmarkGlobalData::current)
568 QBenchmarkGlobalData::current = &globalBenchmarkData;
569 QTest::qtest_qParseArgs(argc, argv, true);
572 void QuickTestResult::setProgramName(const char *name)
575 QTestResult::reset();
576 } else if (!name && loggingStarted) {
577 QTestResult::setCurrentTestObject(globalProgramName);
578 QTestLog::stopLogging();
579 QTestResult::setCurrentTestObject(0);
581 globalProgramName = name;
582 QTestResult::setCurrentTestObject(globalProgramName);
585 int QuickTestResult::exitCode()
587 #if defined(QTEST_NOEXITCODE)
590 // make sure our exit code is never going above 127
591 // since that could wrap and indicate 0 test fails
592 return qMin(QTestResult::failCount(), 127);