9#include <QtTest/qtestcase.h>
10#include <QtTest/qtestsystem.h>
11#include <QtTest/private/qtestblacklist_p.h>
12#include <QtTest/private/qtestresult_p.h>
13#include <QtTest/private/qtesttable_p.h>
14#include <QtTest/private/qtestlog_p.h>
16#include <QtTest/qbenchmark.h>
17#include <QtTest/private/qbenchmark_p.h>
18#include <QtCore/qset.h>
19#include <QtCore/qmap.h>
20#include <QtCore/qbytearray.h>
21#include <QtCore/qcoreapplication.h>
22#include <QtCore/qdatetime.h>
23#include <QtCore/qdebug.h>
26#if QT_CONFIG(regularexpression)
27#include <QtCore/qregularexpression.h>
29#include <QtQuick/qquickwindow.h>
30#include <QtGui/qvector3d.h>
31#include <QtGui/qimagewriter.h>
32#include <QtQml/private/qqmlglobal_p.h>
33#include <QtQml/QQmlEngine>
34#include <QtQml/QQmlContext>
35#include <private/qv4qobjectwrapper_p.h>
49 Q_PROPERTY(
int width READ width CONSTANT)
50 Q_PROPERTY(
int height READ height CONSTANT)
51 Q_PROPERTY(QSize size READ size CONSTANT)
54 QuickTestImageObject(
const QImage& img, QObject *parent =
nullptr)
60 ~QuickTestImageObject() {}
63 int red(
int x,
int y)
const
65 return pixel(x, y).value<QColor>().red();
68 int green(
int x,
int y)
const
70 return pixel(x, y).value<QColor>().green();
73 int blue(
int x,
int y)
const
75 return pixel(x, y).value<QColor>().blue();
78 int alpha(
int x,
int y)
const
80 return pixel(x, y).value<QColor>().alpha();
83 QVariant pixel(
int x,
int y)
const
86 || x >= m_image.width()
87 || y >= m_image.height()
90 || x * y >= m_image.width() * m_image.height())
93 return QColor::fromRgba(m_image.pixel(QPoint(x, y)));
96 bool equals(QuickTestImageObject *other)
const
99 return m_image.isNull();
101 return m_image == other->m_image;
104 void save(
const QString &filePath)
106 QImageWriter writer(filePath);
107 if (!writer.write(m_image)) {
108 QQmlEngine *engine = qmlContext(
this)->engine();
109 QV4::ExecutionEngine *v4 = engine->handle();
110 v4->throwError(QStringLiteral(
"Can't save to %1: %2").arg(filePath, writer.errorString()));
117 return m_image.width();
122 return m_image.height();
127 return m_image.size();
147 delete benchmarkIter;
148 delete benchmarkData;
165 QByteArray bstr = str.toUtf8();
166 return *(internedStrings.insert(bstr));
171
172
173
174QuickTestResult::QuickTestResult(QObject *parent)
175 : QObject(parent), d_ptr(
new QuickTestResultPrivate)
177 if (!QBenchmarkGlobalData::current)
178 QBenchmarkGlobalData::current = &globalBenchmarkData;
181QuickTestResult::~QuickTestResult()
186
187
188
189
190
191
192
193QString QuickTestResult::testCaseName()
const
195 Q_D(
const QuickTestResult);
196 return d->testCaseName;
199void QuickTestResult::setTestCaseName(
const QString &name)
201 Q_D(QuickTestResult);
202 d->testCaseName = name;
203 emit testCaseNameChanged();
207
208
209
210
211
212
213
214
215QString QuickTestResult::functionName()
const
217 Q_D(
const QuickTestResult);
218 return d->functionName;
221void QuickTestResult::setFunctionName(
const QString &name)
223 Q_D(QuickTestResult);
224 if (!name.isEmpty()) {
225 if (d->testCaseName.isEmpty()) {
226 QTestResult::setCurrentTestFunction
227 (d->intern(name).constData());
229 QString fullName = d->testCaseName + QLatin1String(
"::") + name;
230 QTestResult::setCurrentTestFunction
231 (d->intern(fullName).constData());
232 if (QTestPrivate::checkBlackLists(fullName.toUtf8().constData(),
nullptr))
233 QTestResult::setBlacklistCurrentTest(
true);
236 QTestResult::setCurrentTestFunction(
nullptr);
238 d->functionName = name;
239 emit functionNameChanged();
243
244
245
246
247
248QString QuickTestResult::dataTag()
const
250 const char *tag = QTestResult::currentDataTag();
252 return QString::fromUtf8(tag);
257void QuickTestResult::setDataTag(
const QString &tag)
259 if (!tag.isEmpty()) {
260 QTestData *data = &(QTest::newRow(tag.toUtf8().constData()));
261 QTestResult::setCurrentTestData(data);
262 if (QTestPrivate::checkBlackLists((testCaseName() + QLatin1String(
"::")
263 + functionName()).toUtf8().constData(), tag.toUtf8().constData())) {
264 QTestResult::setBlacklistCurrentTest(
true);
266 emit dataTagChanged();
268 QTestResult::setCurrentTestData(
nullptr);
273
274
275
276
277
278
279
280
281
282bool QuickTestResult::isFailed()
const
284 return QTestResult::currentTestFailed();
288
289
290
291
292
293
294
295bool QuickTestResult::isSkipped()
const
297 return QTestResult::skipCurrentTest();
300void QuickTestResult::setSkipped(
bool skip)
302 QTestResult::setSkipCurrentTest(skip);
304 QTestResult::setBlacklistCurrentTest(
false);
305 emit skippedChanged();
309
310
311
312
313
314
315int QuickTestResult::passCount()
const
317 return QTestLog::passCount();
321
322
323
324
325
326
327int QuickTestResult::failCount()
const
329 return QTestLog::failCount();
333
334
335
336
337
338
339int QuickTestResult::skipCount()
const
341 return QTestLog::skipCount();
345
346
347
348
349QStringList QuickTestResult::functionsToRun()
const
351 return QTest::testFunctions;
355
356
357
358
359QStringList QuickTestResult::tagsToRun()
const
361 return QTest::testTags;
365
366
367
368
369void QuickTestResult::reset()
371 if (!globalProgramName)
372 QTestResult::reset();
376
377
378
379
380
381
382
383void QuickTestResult::startLogging()
389 QTestLog::startLogging();
390 loggingStarted =
true;
394
395
396
397
398
399
400void QuickTestResult::stopLogging()
402 Q_D(QuickTestResult);
403 if (globalProgramName)
405 QTestResult::setCurrentTestObject(d->intern(d->testCaseName).constData());
406 QTestLog::stopLogging();
409void QuickTestResult::initTestTable()
411 Q_D(QuickTestResult);
413 d->table =
new QTestTable;
416 d->table->addColumn(qMetaTypeId<QString>(),
"qmltest_dummy_data_column");
419void QuickTestResult::clearTestTable()
421 Q_D(QuickTestResult);
426void QuickTestResult::finishTestData()
428 QTestResult::finishedCurrentTestData();
431void QuickTestResult::finishTestDataCleanup()
433 QTestResult::finishedCurrentTestDataCleanup();
436void QuickTestResult::finishTestFunction()
438 QTestResult::finishedCurrentTestFunction();
443 if (location.isLocalFile())
444 return QDir::toNativeSeparators(location.toLocalFile());
445 return location.toString();
448void QuickTestResult::fail
449 (
const QString &message,
const QUrl &location,
int line)
451 QTestResult::addFailure(message.toUtf8().constData(),
452 qtestFixUrl(location).toLatin1().constData(), line);
455bool QuickTestResult::verify
456 (
bool success,
const QString &message,
const QUrl &location,
int line)
458 if (!success && message.isEmpty()) {
459 return QTestResult::verify
460 (success,
"verify()",
"",
461 qtestFixUrl(location).toLatin1().constData(), line);
463 return QTestResult::verify
464 (success, message.toUtf8().constData(),
"",
465 qtestFixUrl(location).toLatin1().constData(), line);
469bool QuickTestResult::fuzzyCompare(
const QVariant &actual,
const QVariant &expected, qreal delta)
471 if (actual.userType() == QMetaType::QColor || expected.userType() == QMetaType::QColor) {
472 if (!actual.canConvert(QMetaType(QMetaType::QColor))
473 || !expected.canConvert(QMetaType(QMetaType::QColor))) {
482 QVariant var = QQml_colorProvider()->colorFromString(actual.toString(), &ok);
485 act = var.value<QColor>();
487 var = QQml_colorProvider()->colorFromString(expected.toString(), &ok);
490 exp = var.value<QColor>();
492 return ( qAbs(act.red() - exp.red()) <= delta
493 && qAbs(act.green() - exp.green()) <= delta
494 && qAbs(act.blue() - exp.blue()) <= delta
495 && qAbs(act.alpha() - exp.alpha()) <= delta);
499 qreal act = actual.toFloat(&ok);
503 qreal exp = expected.toFloat(&ok);
507 return (qAbs(act - exp) <= delta);
513void QuickTestResult::stringify(QQmlV4FunctionPtr args)
515 if (args->length() < 1)
516 args->setReturnValue(QV4::Encode::null());
518 QV4::Scope scope(args->v4engine());
519 QV4::ScopedValue value(scope, (*args)[0]);
524 if (value->isObject()
525 && !value->as<QV4::FunctionObject>()
526 && !value->as<QV4::ArrayObject>()) {
527 QVariant v = QV4::ExecutionEngine::toVariant(value, QMetaType {});
529 switch (v.userType()) {
530 case QMetaType::QVector3D:
532 QVector3D v3d = v.value<QVector3D>();
533 result = QString::fromLatin1(
"Qt.vector3d(%1, %2, %3)").arg(v3d.x()).arg(v3d.y()).arg(v3d.z());
536 case QMetaType::QUrl:
538 QUrl url = v.value<QUrl>();
539 result = QString::fromLatin1(
"Qt.url(%1)").arg(url.toString());
542 case QMetaType::QDateTime:
544 QDateTime dt = v.value<QDateTime>();
545 result = dt.toString(Qt::ISODateWithMs);
549 result = v.toString();
553 result = QLatin1String(
"Object");
557 if (result.isEmpty()) {
558 QString tmp = value->toQStringNoThrow();
559 if (value->as<QV4::ArrayObject>())
560 result += QLatin1Char(
'[') + tmp + QLatin1Char(
']');
565 args->setReturnValue(QV4::Encode(args->v4engine()->newString(result)));
568bool QuickTestResult::compare
569 (
bool success,
const QString &message,
570 const QVariant &val1,
const QVariant &val2,
571 const QUrl &location,
int line)
573 return QTestResult::compare
574 (success, message.toUtf8().constData(),
575 QTest::toString(val1.toString().toLatin1().constData()),
576 QTest::toString(val2.toString().toLatin1().constData()),
578 qtestFixUrl(location).toLatin1().constData(), line);
581void QuickTestResult::skip
582 (
const QString &message,
const QUrl &location,
int line)
584 QTestResult::addSkip(message.toUtf8().constData(),
585 qtestFixUrl(location).toLatin1().constData(), line);
586 QTestResult::setSkipCurrentTest(
true);
589bool QuickTestResult::expectFail
590 (
const QString &tag,
const QString &comment,
const QUrl &location,
int line)
592 return QTestResult::expectFail
593 (tag.toLatin1().constData(),
594 QTest::toString(comment.toLatin1().constData()),
595 QTest::Abort, qtestFixUrl(location).toLatin1().constData(), line);
598bool QuickTestResult::expectFailContinue
599 (
const QString &tag,
const QString &comment,
const QUrl &location,
int line)
601 return QTestResult::expectFail
602 (tag.toLatin1().constData(),
603 QTest::toString(comment.toUtf8().constData()),
604 QTest::Continue, qtestFixUrl(location).toLatin1().constData(), line);
607void QuickTestResult::warn(
const QString &message,
const QUrl &location,
int line)
609 QTestLog::warn(message.toUtf8().constData(), qtestFixUrl(location).toLatin1().constData(), line);
612void QuickTestResult::ignoreWarning(
const QJSValue &message)
614 if (message.isRegExp()) {
615#if QT_CONFIG(regularexpression)
616 QTestLog::ignoreMessage(QtWarningMsg, qjsvalue_cast<QRegularExpression>(message));
619 QTestLog::ignoreMessage(QtWarningMsg, message.toString().toUtf8());
623void QuickTestResult::failOnWarning(
const QJSValue &message)
625 if (message.isRegExp()) {
626#if QT_CONFIG(regularexpression)
627 QTestLog::failOnWarning(qjsvalue_cast<QRegularExpression>(message));
630 QTestLog::failOnWarning(message.toString().toUtf8());
634void QuickTestResult::wait(
int ms)
639void QuickTestResult::sleep(
int ms)
644bool QuickTestResult::waitForRendering(QQuickItem *item,
int timeout)
648 return qWaitForSignal(item->window(), SIGNAL(frameSwapped()), timeout);
651void QuickTestResult::startMeasurement()
653 Q_D(QuickTestResult);
654 delete d->benchmarkData;
655 d->benchmarkData =
new QBenchmarkTestMethodData();
656 QBenchmarkTestMethodData::current = d->benchmarkData;
657 d->iterCount = (QBenchmarkGlobalData::current->measurer->needsWarmupIteration()) ? -1 : 0;
658 d->resultsList.clear();
661void QuickTestResult::beginDataRun()
663 QBenchmarkTestMethodData::current->beginDataRun();
666void QuickTestResult::endDataRun()
668 Q_D(QuickTestResult);
669 QBenchmarkTestMethodData::current->endDataRun();
670 const QList<QBenchmarkResult> &results = QBenchmarkTestMethodData::current->results;
671 if (results.isEmpty())
673 if (d->iterCount > -1)
674 d->resultsList.append(results);
676 if (QBenchmarkGlobalData::current->verboseOutput) {
677 if (d->iterCount == -1) {
678 qDebug() <<
"warmup stage result :" << results.first().measurement.value;
680 qDebug() <<
"accumulation stage result:" << results.first().measurement.value;
685bool QuickTestResult::measurementAccepted()
687 return QBenchmarkTestMethodData::current->resultsAccepted();
692 const int count = container.size();
697 return container.at(0);
699 QList<QList<QBenchmarkResult>> containerCopy = container;
700 std::sort(containerCopy.begin(), containerCopy.end(),
701 [](
const QList<QBenchmarkResult> &a,
const QList<QBenchmarkResult> &b) {
702 return a.first() < b.first();
705 const int middle = count / 2;
708 return containerCopy.at(middle);
711bool QuickTestResult::needsMoreMeasurements()
713 Q_D(QuickTestResult);
715 if (d->iterCount < QBenchmarkGlobalData::current->adjustMedianIterationCount())
717 if (QBenchmarkTestMethodData::current->resultsAccepted())
718 QTestLog::addBenchmarkResults(qMedian(d->resultsList));
722void QuickTestResult::startBenchmark(RunMode runMode,
const QString &tag)
724 QBenchmarkTestMethodData::current->results = {};
725 QBenchmarkTestMethodData::current->resultAccepted =
false;
726 QBenchmarkGlobalData::current->context.tag = tag;
727 QBenchmarkGlobalData::current->context.slotName = functionName();
729 Q_D(QuickTestResult);
730 delete d->benchmarkIter;
731 d->benchmarkIter =
new QTest::QBenchmarkIterationController
732 (QTest::QBenchmarkIterationController::RunMode(runMode));
735bool QuickTestResult::isBenchmarkDone()
const
737 Q_D(
const QuickTestResult);
738 if (d->benchmarkIter)
739 return d->benchmarkIter->isDone();
744void QuickTestResult::nextBenchmark()
746 Q_D(QuickTestResult);
747 if (d->benchmarkIter)
748 d->benchmarkIter->next();
751void QuickTestResult::stopBenchmark()
753 Q_D(QuickTestResult);
754 delete d->benchmarkIter;
755 d->benchmarkIter =
nullptr;
758QObject *QuickTestResult::grabImage(QQuickItem *item)
760 if (item && item->window()) {
761 QQuickWindow *window = item->window();
762 QImage grabbed = window->grabWindow();
763 const auto dpi = grabbed.devicePixelRatio();
764 QRectF rf(item->x() * dpi, item->y() * dpi, item->width() * dpi, item->height() * dpi);
765 rf = rf.intersected(QRectF(0, 0, grabbed.width(), grabbed.height()));
766 QObject *o =
new QuickTestImageObject(grabbed.copy(rf.toAlignedRect()));
767 QQmlEngine::setContextForObject(o, qmlContext(
this));
773QObject *QuickTestResult::findChild(QObject *parent,
const QString &objectName)
775 return parent ? parent->findChild<QObject*>(objectName) : 0;
778bool QuickTestResult::isPolishScheduled(QObject *itemOrWindow)
const
780 if (
auto item = qobject_cast<QQuickItem*>(itemOrWindow))
781 return QQuickTest::qIsPolishScheduled(item);
783 if (
auto window = qobject_cast<QQuickWindow*>(itemOrWindow))
784 return QQuickTest::qIsPolishScheduled(window);
786 qmlWarning(
this) <<
"isPolishScheduled() expects either an Item or Window, but got"
787 << QDebug::toString(itemOrWindow);
791bool QuickTestResult::waitForPolish(QObject *itemOrWindow,
int timeout)
const
793 if (
auto item = qobject_cast<QQuickItem*>(itemOrWindow))
794 return QQuickTest::qWaitForPolish(item, timeout);
796 if (
auto window = qobject_cast<QQuickWindow*>(itemOrWindow))
797 return QQuickTest::qWaitForPolish(window, timeout);
799 qmlWarning(
this) <<
"waitForItemPolish() expects either an Item or Window, but got"
800 << QDebug::toString(itemOrWindow);
808void QuickTestResult::parseArgs(
int argc,
char *argv[])
810 if (!QBenchmarkGlobalData::current)
811 QBenchmarkGlobalData::current = &globalBenchmarkData;
812 QTest::qtest_qParseArgs(argc, argv,
true);
815void QuickTestResult::setProgramName(
const char *name)
818 QTestPrivate::parseBlackList();
819 QTestResult::reset();
820 }
else if (!name && loggingStarted) {
821 QTestResult::setCurrentTestObject(globalProgramName);
822 QTestLog::stopLogging();
823 QTestResult::setCurrentTestObject(
nullptr);
825 globalProgramName = name;
826 QTestResult::setCurrentTestObject(globalProgramName);
829void QuickTestResult::setCurrentAppname(
const char *appname)
831 QTestResult::setCurrentAppName(appname);
834int QuickTestResult::exitCode()
836#if defined(QTEST_NOEXITCODE)
841 return qMin(QTestLog::failCount(), 127);
847#include "quicktestresult.moc"
848#include "moc_quicktestresult_p.cpp"
QSet< QByteArray > internedStrings
QList< QList< QBenchmarkResult > > resultsList
QByteArray intern(const QString &str)
QBenchmarkTestMethodData * benchmarkData
QTest::QBenchmarkIterationController * benchmarkIter
~QuickTestResultPrivate()
Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml)
static bool loggingStarted
static QT_BEGIN_NAMESPACE const char * globalProgramName
static QString qtestFixUrl(const QUrl &location)
static QBenchmarkGlobalData globalBenchmarkData
static QList< QBenchmarkResult > qMedian(const QList< QList< QBenchmarkResult > > &container)