1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** 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>
56 #include <QtCore/QUrl>
57 #include <QtCore/QDir>
58 #include <QtQuick/qquickwindow.h>
62 static const char *globalProgramName = 0;
63 static bool loggingStarted = false;
64 static QBenchmarkGlobalData globalBenchmarkData;
66 class Q_QUICK_TEST_EXPORT QuickTestImageObject : public QObject
70 QuickTestImageObject(const QImage& img, QObject *parent = 0)
76 ~QuickTestImageObject() {}
79 int red(int x, int y) const
81 return pixel(x, y).value<QColor>().red();
84 int green(int x, int y) const
86 return pixel(x, y).value<QColor>().green();
89 int blue(int x, int y) const
91 return pixel(x, y).value<QColor>().blue();
94 int alpha(int x, int y) const
96 return pixel(x, y).value<QColor>().alpha();
99 QVariant pixel(int x, int y) const
102 || x >= m_image.width()
103 || y >= m_image.height()
106 || x * y >= m_image.width() * m_image.height())
109 const QRgb* pixel = reinterpret_cast<const QRgb*>(m_image.constScanLine(y));
111 return QColor::fromRgba(*pixel);
117 class QuickTestResultPrivate
120 QuickTestResultPrivate()
127 ~QuickTestResultPrivate()
130 delete benchmarkIter;
131 delete benchmarkData;
134 QByteArray intern(const QString &str);
136 QString testCaseName;
137 QString functionName;
138 QSet<QByteArray> internedStrings;
140 QTest::QBenchmarkIterationController *benchmarkIter;
141 QBenchmarkTestMethodData *benchmarkData;
143 QList<QBenchmarkResult> results;
146 QByteArray QuickTestResultPrivate::intern(const QString &str)
148 QByteArray bstr = str.toUtf8();
149 return *(internedStrings.insert(bstr));
152 QuickTestResult::QuickTestResult(QObject *parent)
153 : QObject(parent), d_ptr(new QuickTestResultPrivate)
155 if (!QBenchmarkGlobalData::current)
156 QBenchmarkGlobalData::current = &globalBenchmarkData;
159 QuickTestResult::~QuickTestResult()
164 \qmlproperty string TestResult::testCaseName
166 This property defines the name of current TestCase element
167 that is running test cases.
171 QString QuickTestResult::testCaseName() const
173 Q_D(const QuickTestResult);
174 return d->testCaseName;
177 void QuickTestResult::setTestCaseName(const QString &name)
179 Q_D(QuickTestResult);
180 d->testCaseName = name;
181 emit testCaseNameChanged();
185 \qmlproperty string TestResult::functionName
187 This property defines the name of current test function
188 within a TestCase element that is running. If this string is
189 empty, then no function is currently running.
193 QString QuickTestResult::functionName() const
195 Q_D(const QuickTestResult);
196 return d->functionName;
199 void QuickTestResult::setFunctionName(const QString &name)
201 Q_D(QuickTestResult);
202 if (!name.isEmpty()) {
203 if (d->testCaseName.isEmpty()) {
204 QTestResult::setCurrentTestFunction
205 (d->intern(name).constData());
207 QString fullName = d->testCaseName + QLatin1String("::") + name;
208 QTestResult::setCurrentTestFunction
209 (d->intern(fullName).constData());
212 QTestResult::setCurrentTestFunction(0);
214 d->functionName = name;
215 emit functionNameChanged();
219 \qmlproperty string TestResult::dataTag
221 This property defines the tag for the current row in a
222 data-driven test, or an empty string if not a data-driven test.
224 QString QuickTestResult::dataTag() const
226 const char *tag = QTestResult::currentDataTag();
228 return QString::fromUtf8(tag);
233 void QuickTestResult::setDataTag(const QString &tag)
235 if (!tag.isEmpty()) {
236 QTestData *data = &(QTest::newRow(tag.toUtf8().constData()));
237 QTestResult::setCurrentTestData(data);
238 emit dataTagChanged();
240 QTestResult::setCurrentTestData(0);
245 \qmlproperty bool TestResult::failed
247 This property returns true if the current test function (or
248 current test data row for a data-driven test) has failed;
249 false otherwise. The fail state is reset when functionName
250 is changed or finishTestDataCleanup() is called.
254 bool QuickTestResult::isFailed() const
256 return QTestResult::currentTestFailed();
260 \qmlproperty bool TestResult::skipped
262 This property returns true if the current test function was
263 marked as skipped; false otherwise.
267 bool QuickTestResult::isSkipped() const
269 return QTestResult::skipCurrentTest();
272 void QuickTestResult::setSkipped(bool skip)
274 QTestResult::setSkipCurrentTest(skip);
275 emit skippedChanged();
279 \qmlproperty int TestResult::passCount
281 This property returns the number of tests that have passed.
283 \sa failCount, skipCount
285 int QuickTestResult::passCount() const
287 return QTestLog::passCount();
291 \qmlproperty int TestResult::failCount
293 This property returns the number of tests that have failed.
295 \sa passCount, skipCount
297 int QuickTestResult::failCount() const
299 return QTestLog::failCount();
303 \qmlproperty int TestResult::skipCount
305 This property returns the number of tests that have been skipped.
307 \sa passCount, failCount
309 int QuickTestResult::skipCount() const
311 return QTestLog::skipCount();
315 \qmlproperty list<string> TestResult::functionsToRun
317 This property returns the list of function names to be run.
319 QStringList QuickTestResult::functionsToRun() const
321 return QTest::testFunctions;
325 \qmlmethod TestResult::reset()
327 Resets all pass/fail/skip counters and prepare for testing.
329 void QuickTestResult::reset()
331 if (!globalProgramName) // Only if run via qmlviewer.
332 QTestResult::reset();
336 \qmlmethod TestResult::startLogging()
338 Starts logging to the test output stream and writes the
343 void QuickTestResult::startLogging()
345 // The program name is used for logging headers and footers if it
346 // is set. Otherwise the test case name is used.
349 QTestLog::startLogging();
350 loggingStarted = true;
354 \qmlmethod TestResult::stopLogging()
356 Writes the test footer to the test output stream and then stops logging.
360 void QuickTestResult::stopLogging()
362 Q_D(QuickTestResult);
363 if (globalProgramName)
364 return; // Logging will be stopped by setProgramName(0).
365 QTestResult::setCurrentTestObject(d->intern(d->testCaseName).constData());
366 QTestLog::stopLogging();
369 void QuickTestResult::initTestTable()
371 Q_D(QuickTestResult);
373 d->table = new QTestTable;
374 //qmltest does not really need the column for data driven test
375 //add this to avoid warnings.
376 d->table->addColumn(qMetaTypeId<QString>(), "qmltest_dummy_data_column");
379 void QuickTestResult::clearTestTable()
381 Q_D(QuickTestResult);
386 void QuickTestResult::finishTestData()
388 QTestResult::finishedCurrentTestData();
391 void QuickTestResult::finishTestDataCleanup()
393 QTestResult::finishedCurrentTestDataCleanup();
396 void QuickTestResult::finishTestFunction()
398 QTestResult::finishedCurrentTestFunction();
401 static QString qtestFixUrl(const QUrl &location)
403 if (location.isLocalFile()) // Use QUrl's logic for Windows drive letters.
404 return QDir::toNativeSeparators(location.toLocalFile());
405 return location.toString();
408 void QuickTestResult::fail
409 (const QString &message, const QUrl &location, int line)
411 QTestResult::addFailure(message.toLatin1().constData(),
412 qtestFixUrl(location).toLatin1().constData(), line);
415 bool QuickTestResult::verify
416 (bool success, const QString &message, const QUrl &location, int line)
418 if (!success && message.isEmpty()) {
419 return QTestResult::verify
420 (success, "verify()", "",
421 qtestFixUrl(location).toLatin1().constData(), line);
423 return QTestResult::verify
424 (success, message.toLatin1().constData(), "",
425 qtestFixUrl(location).toLatin1().constData(), line);
429 bool QuickTestResult::compare
430 (bool success, const QString &message,
431 const QString &val1, const QString &val2,
432 const QUrl &location, int line)
434 return QTestResult::compare
435 (success, message.toLocal8Bit().constData(),
436 QTest::toString(val1.toLatin1().constData()),
437 QTest::toString(val2.toLatin1().constData()),
439 qtestFixUrl(location).toLatin1().constData(), line);
442 void QuickTestResult::skip
443 (const QString &message, const QUrl &location, int line)
445 QTestResult::addSkip(message.toLatin1().constData(),
446 qtestFixUrl(location).toLatin1().constData(), line);
447 QTestResult::setSkipCurrentTest(true);
450 bool QuickTestResult::expectFail
451 (const QString &tag, const QString &comment, const QUrl &location, int line)
453 return QTestResult::expectFail
454 (tag.toLatin1().constData(),
455 QTest::toString(comment.toLatin1().constData()),
456 QTest::Abort, qtestFixUrl(location).toLatin1().constData(), line);
459 bool QuickTestResult::expectFailContinue
460 (const QString &tag, const QString &comment, const QUrl &location, int line)
462 return QTestResult::expectFail
463 (tag.toLatin1().constData(),
464 QTest::toString(comment.toLatin1().constData()),
465 QTest::Continue, qtestFixUrl(location).toLatin1().constData(), line);
468 void QuickTestResult::warn(const QString &message, const QUrl &location, int line)
470 QTestLog::warn(message.toLatin1().constData(), qtestFixUrl(location).toLatin1().constData(), line);
473 void QuickTestResult::ignoreWarning(const QString &message)
475 QTestLog::ignoreMessage(QtWarningMsg, message.toLatin1().constData());
478 void QuickTestResult::wait(int ms)
483 void QuickTestResult::sleep(int ms)
488 void QuickTestResult::startMeasurement()
490 Q_D(QuickTestResult);
491 delete d->benchmarkData;
492 d->benchmarkData = new QBenchmarkTestMethodData();
493 QBenchmarkTestMethodData::current = d->benchmarkData;
494 d->iterCount = (QBenchmarkGlobalData::current->measurer->needsWarmupIteration()) ? -1 : 0;
498 void QuickTestResult::beginDataRun()
500 QBenchmarkTestMethodData::current->beginDataRun();
503 void QuickTestResult::endDataRun()
505 Q_D(QuickTestResult);
506 QBenchmarkTestMethodData::current->endDataRun();
507 if (d->iterCount > -1) // iteration -1 is the warmup iteration.
508 d->results.append(QBenchmarkTestMethodData::current->result);
510 if (QBenchmarkGlobalData::current->verboseOutput) {
511 if (d->iterCount == -1) {
512 qDebug() << "warmup stage result :" << QBenchmarkTestMethodData::current->result.value;
514 qDebug() << "accumulation stage result:" << QBenchmarkTestMethodData::current->result.value;
519 bool QuickTestResult::measurementAccepted()
521 return QBenchmarkTestMethodData::current->resultsAccepted();
524 static QBenchmarkResult qMedian(const QList<QBenchmarkResult> &container)
526 const int count = container.count();
528 return QBenchmarkResult();
531 return container.at(0);
533 QList<QBenchmarkResult> containerCopy = container;
534 qSort(containerCopy);
536 const int middle = count / 2;
538 // ### handle even-sized containers here by doing an aritmetic mean of the two middle items.
539 return containerCopy.at(middle);
542 bool QuickTestResult::needsMoreMeasurements()
544 Q_D(QuickTestResult);
546 if (d->iterCount < QBenchmarkGlobalData::current->adjustMedianIterationCount())
548 if (QBenchmarkTestMethodData::current->resultsAccepted())
549 QTestLog::addBenchmarkResult(qMedian(d->results));
553 void QuickTestResult::startBenchmark(RunMode runMode, const QString &tag)
555 QBenchmarkTestMethodData::current->result = QBenchmarkResult();
556 QBenchmarkTestMethodData::current->resultAccepted = false;
557 QBenchmarkGlobalData::current->context.tag = tag;
558 QBenchmarkGlobalData::current->context.slotName = functionName();
560 Q_D(QuickTestResult);
561 delete d->benchmarkIter;
562 d->benchmarkIter = new QTest::QBenchmarkIterationController
563 (QTest::QBenchmarkIterationController::RunMode(runMode));
566 bool QuickTestResult::isBenchmarkDone() const
568 Q_D(const QuickTestResult);
569 if (d->benchmarkIter)
570 return d->benchmarkIter->isDone();
575 void QuickTestResult::nextBenchmark()
577 Q_D(QuickTestResult);
578 if (d->benchmarkIter)
579 d->benchmarkIter->next();
582 void QuickTestResult::stopBenchmark()
584 Q_D(QuickTestResult);
585 delete d->benchmarkIter;
586 d->benchmarkIter = 0;
589 QObject *QuickTestResult::grabImage(QQuickItem *item)
592 QQuickWindow *window = item->window();
593 QImage grabbed = window->grabWindow();
594 QRectF rf(item->x(), item->y(), item->width(), item->height());
595 rf = rf.intersected(QRectF(0, 0, grabbed.width(), grabbed.height()));
596 return new QuickTestImageObject(grabbed.copy(rf.toAlignedRect()));
601 void qtest_qParseArgs(int argc, char *argv[], bool qml);
604 void QuickTestResult::parseArgs(int argc, char *argv[])
606 if (!QBenchmarkGlobalData::current)
607 QBenchmarkGlobalData::current = &globalBenchmarkData;
608 QTest::qtest_qParseArgs(argc, argv, true);
611 void QuickTestResult::setProgramName(const char *name)
614 QTestResult::reset();
615 } else if (!name && loggingStarted) {
616 QTestResult::setCurrentTestObject(globalProgramName);
617 QTestLog::stopLogging();
618 QTestResult::setCurrentTestObject(0);
620 globalProgramName = name;
621 QTestResult::setCurrentTestObject(globalProgramName);
624 void QuickTestResult::setCurrentAppname(const char *appname)
626 QTestResult::setCurrentAppname(appname);
629 int QuickTestResult::exitCode()
631 #if defined(QTEST_NOEXITCODE)
634 // make sure our exit code is never going above 127
635 // since that could wrap and indicate 0 test fails
636 return qMin(QTestLog::failCount(), 127);
640 #include "quicktestresult.moc"