1/****************************************************************************
2**
3** Copyright (C) 2017 Crimson AS <info@crimson.no>
4** Copyright (C) 2016 The Qt Company Ltd.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "quicktestresult_p.h"
42#include "quicktest.h"
43#include <QtTest/qtestcase.h>
44#include <QtTest/qtestsystem.h>
45#include <QtTest/private/qtestblacklist_p.h>
46#include <QtTest/private/qtestresult_p.h>
47#include <QtTest/private/qtesttable_p.h>
48#include <QtTest/private/qtestlog_p.h>
49#include "qtestoptions_p.h"
50#include <QtTest/qbenchmark.h>
51// qbenchmark_p.h pulls windows.h via 3rd party; prevent it from defining
52// the min/max macros which would clash with qnumeric_p.h's usage of min()/max().
53#if defined(Q_OS_WIN32) && !defined(NOMINMAX)
54# define NOMINMAX
55#endif
56#include <QtTest/private/qbenchmark_p.h>
57#include <QtCore/qset.h>
58#include <QtCore/qmap.h>
59#include <QtCore/qbytearray.h>
60#include <QtCore/qcoreapplication.h>
61#include <QtCore/qdatetime.h>
62#include <QtCore/qdebug.h>
63#include <QtCore/QUrl>
64#include <QtCore/QDir>
65#if QT_CONFIG(regularexpression)
66#include <QtCore/qregularexpression.h>
67#endif
68#include <QtQuick/qquickwindow.h>
69#include <QtGui/qvector3d.h>
70#include <QtGui/qimagewriter.h>
71#include <QtQml/private/qqmlglobal_p.h>
72#include <QtQml/QQmlEngine>
73#include <QtQml/QQmlContext>
74#include <private/qv4qobjectwrapper_p.h>
75
76#include <algorithm>
77
78QT_BEGIN_NAMESPACE
79
80static const char *globalProgramName = nullptr;
81static bool loggingStarted = false;
82static QBenchmarkGlobalData globalBenchmarkData;
83
84extern bool qWaitForSignal(QObject *obj, const char* signal, int timeout = 5000);
85
86class Q_QUICK_TEST_EXPORT QuickTestImageObject : public QObject
87{
88 Q_OBJECT
89
90 Q_PROPERTY(int width READ width CONSTANT)
91 Q_PROPERTY(int height READ height CONSTANT)
92 Q_PROPERTY(QSize size READ size CONSTANT)
93
94public:
95 QuickTestImageObject(const QImage& img, QObject *parent = nullptr)
96 : QObject(parent)
97 , m_image(img)
98 {
99 }
100
101 ~QuickTestImageObject() {}
102
103public Q_SLOTS:
104 int red(int x, int y) const
105 {
106 return pixel(x, y).value<QColor>().red();
107 }
108
109 int green(int x, int y) const
110 {
111 return pixel(x, y).value<QColor>().green();
112 }
113
114 int blue(int x, int y) const
115 {
116 return pixel(x, y).value<QColor>().blue();
117 }
118
119 int alpha(int x, int y) const
120 {
121 return pixel(x, y).value<QColor>().alpha();
122 }
123
124 QVariant pixel(int x, int y) const
125 {
126 if (m_image.isNull()
127 || x >= m_image.width()
128 || y >= m_image.height()
129 || x < 0
130 || y < 0
131 || x * y >= m_image.width() * m_image.height())
132 return QVariant();
133
134 return QColor::fromRgba(rgba: m_image.pixel(pt: QPoint(x, y)));
135 }
136
137 bool equals(QuickTestImageObject *other) const
138 {
139 if (!other)
140 return m_image.isNull();
141
142 return m_image == other->m_image;
143 }
144
145 void save(const QString &filePath)
146 {
147 QImageWriter writer(filePath);
148 if (!writer.write(image: m_image)) {
149 QQmlEngine *engine = qmlContext(this)->engine();
150 QV4::ExecutionEngine *v4 = engine->handle();
151 v4->throwError(QStringLiteral("Can't save to %1: %2").arg(args: filePath, args: writer.errorString()));
152 }
153 }
154
155public:
156 int width() const
157 {
158 return m_image.width();
159 }
160
161 int height() const
162 {
163 return m_image.height();
164 }
165
166 QSize size() const
167 {
168 return m_image.size();
169 }
170
171private:
172 QImage m_image;
173};
174
175class QuickTestResultPrivate
176{
177public:
178 QuickTestResultPrivate()
179 : table(nullptr)
180 , benchmarkIter(nullptr)
181 , benchmarkData(nullptr)
182 , iterCount(0)
183 {
184 }
185 ~QuickTestResultPrivate()
186 {
187 delete table;
188 delete benchmarkIter;
189 delete benchmarkData;
190 }
191
192 QByteArray intern(const QString &str);
193
194 QString testCaseName;
195 QString functionName;
196 QSet<QByteArray> internedStrings;
197 QTestTable *table;
198 QTest::QBenchmarkIterationController *benchmarkIter;
199 QBenchmarkTestMethodData *benchmarkData;
200 int iterCount;
201 QList<QBenchmarkResult> results;
202};
203
204QByteArray QuickTestResultPrivate::intern(const QString &str)
205{
206 QByteArray bstr = str.toUtf8();
207 return *(internedStrings.insert(value: bstr));
208}
209
210QuickTestResult::QuickTestResult(QObject *parent)
211 : QObject(parent), d_ptr(new QuickTestResultPrivate)
212{
213 if (!QBenchmarkGlobalData::current)
214 QBenchmarkGlobalData::current = &globalBenchmarkData;
215}
216
217QuickTestResult::~QuickTestResult()
218{
219}
220
221/*!
222 \qmlproperty string TestResult::testCaseName
223
224 This property defines the name of current TestCase element
225 that is running test cases.
226
227 \sa functionName
228*/
229QString QuickTestResult::testCaseName() const
230{
231 Q_D(const QuickTestResult);
232 return d->testCaseName;
233}
234
235void QuickTestResult::setTestCaseName(const QString &name)
236{
237 Q_D(QuickTestResult);
238 d->testCaseName = name;
239 emit testCaseNameChanged();
240}
241
242/*!
243 \qmlproperty string TestResult::functionName
244
245 This property defines the name of current test function
246 within a TestCase element that is running. If this string is
247 empty, then no function is currently running.
248
249 \sa testCaseName
250*/
251QString QuickTestResult::functionName() const
252{
253 Q_D(const QuickTestResult);
254 return d->functionName;
255}
256
257void QuickTestResult::setFunctionName(const QString &name)
258{
259 Q_D(QuickTestResult);
260 if (!name.isEmpty()) {
261 if (d->testCaseName.isEmpty()) {
262 QTestResult::setCurrentTestFunction
263 (d->intern(str: name).constData());
264 } else {
265 QString fullName = d->testCaseName + QLatin1String("::") + name;
266 QTestResult::setCurrentTestFunction
267 (d->intern(str: fullName).constData());
268 QTestPrivate::checkBlackLists(slot: fullName.toUtf8().constData(), data: nullptr);
269 }
270 } else {
271 QTestResult::setCurrentTestFunction(nullptr);
272 }
273 d->functionName = name;
274 emit functionNameChanged();
275}
276
277/*!
278 \qmlproperty string TestResult::dataTag
279
280 This property defines the tag for the current row in a
281 data-driven test, or an empty string if not a data-driven test.
282*/
283QString QuickTestResult::dataTag() const
284{
285 const char *tag = QTestResult::currentDataTag();
286 if (tag)
287 return QString::fromUtf8(str: tag);
288 else
289 return QString();
290}
291
292void QuickTestResult::setDataTag(const QString &tag)
293{
294 if (!tag.isEmpty()) {
295 QTestData *data = &(QTest::newRow(dataTag: tag.toUtf8().constData()));
296 QTestResult::setCurrentTestData(data);
297 QTestPrivate::checkBlackLists(slot: (testCaseName() + QLatin1String("::") + functionName()).toUtf8().constData(), data: tag.toUtf8().constData());
298 emit dataTagChanged();
299 } else {
300 QTestResult::setCurrentTestData(nullptr);
301 }
302}
303
304/*!
305 \qmlproperty bool TestResult::failed
306
307 This property returns true if the current test function (or
308 current test data row for a data-driven test) has failed;
309 false otherwise. The fail state is reset when functionName
310 is changed or finishTestDataCleanup() is called.
311
312 \sa skipped
313*/
314bool QuickTestResult::isFailed() const
315{
316 return QTestResult::currentTestFailed();
317}
318
319/*!
320 \qmlproperty bool TestResult::skipped
321
322 This property returns true if the current test function was
323 marked as skipped; false otherwise.
324
325 \sa failed
326*/
327bool QuickTestResult::isSkipped() const
328{
329 return QTestResult::skipCurrentTest();
330}
331
332void QuickTestResult::setSkipped(bool skip)
333{
334 QTestResult::setSkipCurrentTest(skip);
335 if (!skip)
336 QTestResult::setBlacklistCurrentTest(false);
337 emit skippedChanged();
338}
339
340/*!
341 \qmlproperty int TestResult::passCount
342
343 This property returns the number of tests that have passed.
344
345 \sa failCount, skipCount
346*/
347int QuickTestResult::passCount() const
348{
349 return QTestLog::passCount();
350}
351
352/*!
353 \qmlproperty int TestResult::failCount
354
355 This property returns the number of tests that have failed.
356
357 \sa passCount, skipCount
358*/
359int QuickTestResult::failCount() const
360{
361 return QTestLog::failCount();
362}
363
364/*!
365 \qmlproperty int TestResult::skipCount
366
367 This property returns the number of tests that have been skipped.
368
369 \sa passCount, failCount
370*/
371int QuickTestResult::skipCount() const
372{
373 return QTestLog::skipCount();
374}
375
376/*!
377 \qmlproperty list<string> TestResult::functionsToRun
378
379 This property returns the list of function names to be run.
380*/
381QStringList QuickTestResult::functionsToRun() const
382{
383 return QTest::testFunctions;
384}
385
386/*!
387 \qmlproperty list<string> TestResult::tagsToRun
388
389 This property returns the list of test function's data tags to be run
390*/
391QStringList QuickTestResult::tagsToRun() const
392{
393 return QTest::testTags;
394}
395
396/*!
397 \qmlmethod TestResult::reset()
398
399 Resets all pass/fail/skip counters and prepare for testing.
400*/
401void QuickTestResult::reset()
402{
403 if (!globalProgramName) // Only if run via qmlviewer.
404 QTestResult::reset();
405}
406
407/*!
408 \qmlmethod TestResult::startLogging()
409
410 Starts logging to the test output stream and writes the
411 test header.
412
413 \sa stopLogging()
414*/
415void QuickTestResult::startLogging()
416{
417 // The program name is used for logging headers and footers if it
418 // is set. Otherwise the test case name is used.
419 if (loggingStarted)
420 return;
421 QTestLog::startLogging();
422 loggingStarted = true;
423}
424
425/*!
426 \qmlmethod TestResult::stopLogging()
427
428 Writes the test footer to the test output stream and then stops logging.
429
430 \sa startLogging()
431*/
432void QuickTestResult::stopLogging()
433{
434 Q_D(QuickTestResult);
435 if (globalProgramName)
436 return; // Logging will be stopped by setProgramName(0).
437 QTestResult::setCurrentTestObject(d->intern(str: d->testCaseName).constData());
438 QTestLog::stopLogging();
439}
440
441void QuickTestResult::initTestTable()
442{
443 Q_D(QuickTestResult);
444 delete d->table;
445 d->table = new QTestTable;
446 //qmltest does not really need the column for data driven test
447 //add this to avoid warnings.
448 d->table->addColumn(elementType: qMetaTypeId<QString>(), elementName: "qmltest_dummy_data_column");
449}
450
451void QuickTestResult::clearTestTable()
452{
453 Q_D(QuickTestResult);
454 delete d->table;
455 d->table = nullptr;
456}
457
458void QuickTestResult::finishTestData()
459{
460 QTestResult::finishedCurrentTestData();
461}
462
463void QuickTestResult::finishTestDataCleanup()
464{
465 QTestResult::finishedCurrentTestDataCleanup();
466}
467
468void QuickTestResult::finishTestFunction()
469{
470 QTestResult::finishedCurrentTestFunction();
471}
472
473static QString qtestFixUrl(const QUrl &location)
474{
475 if (location.isLocalFile()) // Use QUrl's logic for Windows drive letters.
476 return QDir::toNativeSeparators(pathName: location.toLocalFile());
477 return location.toString();
478}
479
480void QuickTestResult::fail
481 (const QString &message, const QUrl &location, int line)
482{
483 QTestResult::addFailure(message: message.toUtf8().constData(),
484 file: qtestFixUrl(location).toLatin1().constData(), line);
485}
486
487bool QuickTestResult::verify
488 (bool success, const QString &message, const QUrl &location, int line)
489{
490 if (!success && message.isEmpty()) {
491 return QTestResult::verify
492 (statement: success, statementStr: "verify()", extraInfo: "",
493 file: qtestFixUrl(location).toLatin1().constData(), line);
494 } else {
495 return QTestResult::verify
496 (statement: success, statementStr: message.toUtf8().constData(), extraInfo: "",
497 file: qtestFixUrl(location).toLatin1().constData(), line);
498 }
499}
500
501bool QuickTestResult::fuzzyCompare(const QVariant &actual, const QVariant &expected, qreal delta)
502{
503 if (actual.userType() == QMetaType::QColor || expected.userType() == QMetaType::QColor) {
504 if (!actual.canConvert(targetTypeId: QMetaType::QColor) || !expected.canConvert(targetTypeId: QMetaType::QColor))
505 return false;
506
507 //fuzzy color comparison
508 QColor act;
509 QColor exp;
510 bool ok(false);
511
512 QVariant var = QQml_colorProvider()->colorFromString(actual.toString(), &ok);
513 if (!ok)
514 return false;
515 act = var.value<QColor>();
516
517 QQml_colorProvider()->colorFromString(expected.toString(), &ok);
518 if (!ok)
519 return false;
520 exp = var.value<QColor>();
521
522 return ( qAbs(t: act.red() - exp.red()) <= delta
523 && qAbs(t: act.green() - exp.green()) <= delta
524 && qAbs(t: act.blue() - exp.blue()) <= delta
525 && qAbs(t: act.alpha() - exp.alpha()) <= delta);
526 } else {
527 //number comparison
528 bool ok = true;
529 qreal act = actual.toFloat(ok: &ok);
530 if (!ok)
531 return false;
532
533 qreal exp = expected.toFloat(ok: &ok);
534 if (!ok)
535 return false;
536
537 return (qAbs(t: act - exp) <= delta);
538 }
539
540 return false;
541}
542
543void QuickTestResult::stringify(QQmlV4Function *args)
544{
545 if (args->length() < 1)
546 args->setReturnValue(QV4::Encode::null());
547
548 QV4::Scope scope(args->v4engine());
549 QV4::ScopedValue value(scope, (*args)[0]);
550
551 QString result;
552
553 //Check for Object Type
554 if (value->isObject()
555 && !value->as<QV4::FunctionObject>()
556 && !value->as<QV4::ArrayObject>()) {
557 QVariant v = scope.engine->toVariant(value, typeHint: QMetaType::UnknownType);
558 if (v.isValid()) {
559 switch (v.userType()) {
560 case QMetaType::QVector3D:
561 {
562 QVector3D v3d = v.value<QVector3D>();
563 result = QString::fromLatin1(str: "Qt.vector3d(%1, %2, %3)").arg(a: v3d.x()).arg(a: v3d.y()).arg(a: v3d.z());
564 break;
565 }
566 case QMetaType::QUrl:
567 {
568 QUrl url = v.value<QUrl>();
569 result = QString::fromLatin1(str: "Qt.url(%1)").arg(a: url.toString());
570 break;
571 }
572 case QMetaType::QDateTime:
573 {
574 QDateTime dt = v.value<QDateTime>();
575 result = dt.toString(format: Qt::ISODateWithMs);
576 break;
577 }
578 default:
579 result = v.toString();
580 }
581
582 } else {
583 result = QLatin1String("Object");
584 }
585 }
586
587 if (result.isEmpty()) {
588 QString tmp = value->toQStringNoThrow();
589 if (value->as<QV4::ArrayObject>())
590 result += QLatin1Char('[') + tmp + QLatin1Char(']');
591 else
592 result.append(s: tmp);
593 }
594
595 args->setReturnValue(QV4::Encode(args->v4engine()->newString(s: result)));
596}
597
598bool QuickTestResult::compare
599 (bool success, const QString &message,
600 const QVariant &val1, const QVariant &val2,
601 const QUrl &location, int line)
602{
603 return QTestResult::compare
604 (success, failureMsg: message.toUtf8().constData(),
605 val1: QTest::toString(val1.toString().toLatin1().constData()),
606 val2: QTest::toString(val2.toString().toLatin1().constData()),
607 actual: "", expected: "",
608 file: qtestFixUrl(location).toLatin1().constData(), line);
609}
610
611void QuickTestResult::skip
612 (const QString &message, const QUrl &location, int line)
613{
614 QTestResult::addSkip(message: message.toUtf8().constData(),
615 file: qtestFixUrl(location).toLatin1().constData(), line);
616 QTestResult::setSkipCurrentTest(true);
617}
618
619bool QuickTestResult::expectFail
620 (const QString &tag, const QString &comment, const QUrl &location, int line)
621{
622 return QTestResult::expectFail
623 (dataIndex: tag.toLatin1().constData(),
624 comment: QTest::toString(comment.toLatin1().constData()),
625 mode: QTest::Abort, file: qtestFixUrl(location).toLatin1().constData(), line);
626}
627
628bool QuickTestResult::expectFailContinue
629 (const QString &tag, const QString &comment, const QUrl &location, int line)
630{
631 return QTestResult::expectFail
632 (dataIndex: tag.toLatin1().constData(),
633 comment: QTest::toString(comment.toUtf8().constData()),
634 mode: QTest::Continue, file: qtestFixUrl(location).toLatin1().constData(), line);
635}
636
637void QuickTestResult::warn(const QString &message, const QUrl &location, int line)
638{
639 QTestLog::warn(msg: message.toUtf8().constData(), file: qtestFixUrl(location).toLatin1().constData(), line);
640}
641
642void QuickTestResult::ignoreWarning(const QJSValue &message)
643{
644 if (message.isRegExp()) {
645#if QT_CONFIG(regularexpression)
646 QTestLog::ignoreMessage(type: QtWarningMsg, expression: message.toVariant().toRegularExpression());
647#endif
648 } else {
649 QTestLog::ignoreMessage(type: QtWarningMsg, msg: message.toString().toUtf8());
650 }
651}
652
653void QuickTestResult::wait(int ms)
654{
655 QTest::qWait(ms);
656}
657
658void QuickTestResult::sleep(int ms)
659{
660 QTest::qSleep(ms);
661}
662
663bool QuickTestResult::waitForRendering(QQuickItem *item, int timeout)
664{
665 Q_ASSERT(item);
666
667 return qWaitForSignal(obj: item->window(), SIGNAL(frameSwapped()), timeout);
668}
669
670void QuickTestResult::startMeasurement()
671{
672 Q_D(QuickTestResult);
673 delete d->benchmarkData;
674 d->benchmarkData = new QBenchmarkTestMethodData();
675 QBenchmarkTestMethodData::current = d->benchmarkData;
676 d->iterCount = (QBenchmarkGlobalData::current->measurer->needsWarmupIteration()) ? -1 : 0;
677 d->results.clear();
678}
679
680void QuickTestResult::beginDataRun()
681{
682 QBenchmarkTestMethodData::current->beginDataRun();
683}
684
685void QuickTestResult::endDataRun()
686{
687 Q_D(QuickTestResult);
688 QBenchmarkTestMethodData::current->endDataRun();
689 if (d->iterCount > -1) // iteration -1 is the warmup iteration.
690 d->results.append(t: QBenchmarkTestMethodData::current->result);
691
692 if (QBenchmarkGlobalData::current->verboseOutput) {
693 if (d->iterCount == -1) {
694 qDebug() << "warmup stage result :" << QBenchmarkTestMethodData::current->result.value;
695 } else {
696 qDebug() << "accumulation stage result:" << QBenchmarkTestMethodData::current->result.value;
697 }
698 }
699}
700
701bool QuickTestResult::measurementAccepted()
702{
703 return QBenchmarkTestMethodData::current->resultsAccepted();
704}
705
706static QBenchmarkResult qMedian(const QList<QBenchmarkResult> &container)
707{
708 const int count = container.count();
709 if (count == 0)
710 return QBenchmarkResult();
711
712 if (count == 1)
713 return container.at(i: 0);
714
715 QList<QBenchmarkResult> containerCopy = container;
716 std::sort(first: containerCopy.begin(), last: containerCopy.end());
717
718 const int middle = count / 2;
719
720 // ### handle even-sized containers here by doing an aritmetic mean of the two middle items.
721 return containerCopy.at(i: middle);
722}
723
724bool QuickTestResult::needsMoreMeasurements()
725{
726 Q_D(QuickTestResult);
727 ++(d->iterCount);
728 if (d->iterCount < QBenchmarkGlobalData::current->adjustMedianIterationCount())
729 return true;
730 if (QBenchmarkTestMethodData::current->resultsAccepted())
731 QTestLog::addBenchmarkResult(result: qMedian(container: d->results));
732 return false;
733}
734
735void QuickTestResult::startBenchmark(RunMode runMode, const QString &tag)
736{
737 QBenchmarkTestMethodData::current->result = QBenchmarkResult();
738 QBenchmarkTestMethodData::current->resultAccepted = false;
739 QBenchmarkGlobalData::current->context.tag = tag;
740 QBenchmarkGlobalData::current->context.slotName = functionName();
741
742 Q_D(QuickTestResult);
743 delete d->benchmarkIter;
744 d->benchmarkIter = new QTest::QBenchmarkIterationController
745 (QTest::QBenchmarkIterationController::RunMode(runMode));
746}
747
748bool QuickTestResult::isBenchmarkDone() const
749{
750 Q_D(const QuickTestResult);
751 if (d->benchmarkIter)
752 return d->benchmarkIter->isDone();
753 else
754 return true;
755}
756
757void QuickTestResult::nextBenchmark()
758{
759 Q_D(QuickTestResult);
760 if (d->benchmarkIter)
761 d->benchmarkIter->next();
762}
763
764void QuickTestResult::stopBenchmark()
765{
766 Q_D(QuickTestResult);
767 delete d->benchmarkIter;
768 d->benchmarkIter = nullptr;
769}
770
771QObject *QuickTestResult::grabImage(QQuickItem *item)
772{
773 if (item && item->window()) {
774 QQuickWindow *window = item->window();
775 QImage grabbed = window->grabWindow();
776 QRectF rf(item->x(), item->y(), item->width(), item->height());
777 rf = rf.intersected(r: QRectF(0, 0, grabbed.width(), grabbed.height()));
778 QObject *o = new QuickTestImageObject(grabbed.copy(rect: rf.toAlignedRect()));
779 QQmlEngine::setContextForObject(o, qmlContext(this));
780 return o;
781 }
782 return nullptr;
783}
784
785QObject *QuickTestResult::findChild(QObject *parent, const QString &objectName)
786{
787 return parent ? parent->findChild<QObject*>(aName: objectName) : 0;
788}
789
790bool QuickTestResult::isPolishScheduled(QQuickItem *item) const
791{
792 return QQuickTest::qIsPolishScheduled(item);
793}
794
795bool QuickTestResult::waitForItemPolished(QQuickItem *item, int timeout)
796{
797 return QQuickTest::qWaitForItemPolished(item, timeout);
798}
799
800namespace QTest {
801 void qtest_qParseArgs(int argc, char *argv[], bool qml);
802};
803
804void QuickTestResult::parseArgs(int argc, char *argv[])
805{
806 if (!QBenchmarkGlobalData::current)
807 QBenchmarkGlobalData::current = &globalBenchmarkData;
808 QTest::qtest_qParseArgs(argc, argv, qml: true);
809}
810
811void QuickTestResult::setProgramName(const char *name)
812{
813 if (name) {
814 QTestPrivate::parseBlackList();
815 QTestResult::reset();
816 } else if (!name && loggingStarted) {
817 QTestResult::setCurrentTestObject(globalProgramName);
818 QTestLog::stopLogging();
819 QTestResult::setCurrentTestObject(nullptr);
820 }
821 globalProgramName = name;
822 QTestResult::setCurrentTestObject(globalProgramName);
823}
824
825void QuickTestResult::setCurrentAppname(const char *appname)
826{
827 QTestResult::setCurrentAppName(appname);
828}
829
830int QuickTestResult::exitCode()
831{
832#if defined(QTEST_NOEXITCODE)
833 return 0;
834#else
835 // make sure our exit code is never going above 127
836 // since that could wrap and indicate 0 test fails
837 return qMin(a: QTestLog::failCount(), b: 127);
838#endif
839}
840
841QT_END_NAMESPACE
842
843#include "quicktestresult.moc"
844#include "moc_quicktestresult_p.cpp"
845

source code of qtdeclarative/src/qmltest/quicktestresult.cpp