QQuickCanvas renames
[profile/ivi/qtdeclarative.git] / src / qmltest / quicktestresult.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
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>
59
60 QT_BEGIN_NAMESPACE
61
62 static const char *globalProgramName = 0;
63 static bool loggingStarted = false;
64 static QBenchmarkGlobalData globalBenchmarkData;
65
66 class Q_QUICK_TEST_EXPORT QuickTestImageObject : public QObject
67 {
68     Q_OBJECT
69 public:
70     QuickTestImageObject(const QImage& img, QObject *parent = 0)
71         : QObject(parent)
72         , m_image(img)
73     {
74     }
75
76     ~QuickTestImageObject() {}
77
78 public Q_SLOTS:
79     int red(int x, int y) const
80     {
81         return pixel(x, y).value<QColor>().red();
82     }
83
84     int green(int x, int y) const
85     {
86         return pixel(x, y).value<QColor>().green();
87     }
88
89     int blue(int x, int y) const
90     {
91         return pixel(x, y).value<QColor>().blue();
92     }
93
94     int alpha(int x, int y) const
95     {
96         return pixel(x, y).value<QColor>().alpha();
97     }
98
99     QVariant pixel(int x, int y) const
100     {
101         if (m_image.isNull()
102          || x >= m_image.width()
103          || y >= m_image.height()
104          || x < 0
105          || y < 0
106          || x * y >= m_image.width() * m_image.height())
107             return QVariant();
108
109         const QRgb* pixel = reinterpret_cast<const QRgb*>(m_image.constScanLine(y));
110         pixel += x;
111         return QColor::fromRgba(*pixel);
112     }
113 private:
114     QImage m_image;
115 };
116
117 class QuickTestResultPrivate
118 {
119 public:
120     QuickTestResultPrivate()
121         : table(0)
122         , benchmarkIter(0)
123         , benchmarkData(0)
124         , iterCount(0)
125     {
126     }
127     ~QuickTestResultPrivate()
128     {
129         delete table;
130         delete benchmarkIter;
131         delete benchmarkData;
132     }
133
134     QByteArray intern(const QString &str);
135
136     QString testCaseName;
137     QString functionName;
138     QSet<QByteArray> internedStrings;
139     QTestTable *table;
140     QTest::QBenchmarkIterationController *benchmarkIter;
141     QBenchmarkTestMethodData *benchmarkData;
142     int iterCount;
143     QList<QBenchmarkResult> results;
144 };
145
146 QByteArray QuickTestResultPrivate::intern(const QString &str)
147 {
148     QByteArray bstr = str.toUtf8();
149     return *(internedStrings.insert(bstr));
150 }
151
152 QuickTestResult::QuickTestResult(QObject *parent)
153     : QObject(parent), d_ptr(new QuickTestResultPrivate)
154 {
155     if (!QBenchmarkGlobalData::current)
156         QBenchmarkGlobalData::current = &globalBenchmarkData;
157 }
158
159 QuickTestResult::~QuickTestResult()
160 {
161 }
162
163 /*!
164     \qmlproperty string TestResult::testCaseName
165
166     This property defines the name of current TestCase element
167     that is running test cases.
168
169     \sa functionName
170 */
171 QString QuickTestResult::testCaseName() const
172 {
173     Q_D(const QuickTestResult);
174     return d->testCaseName;
175 }
176
177 void QuickTestResult::setTestCaseName(const QString &name)
178 {
179     Q_D(QuickTestResult);
180     d->testCaseName = name;
181     emit testCaseNameChanged();
182 }
183
184 /*!
185     \qmlproperty string TestResult::functionName
186
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.
190
191     \sa testCaseName
192 */
193 QString QuickTestResult::functionName() const
194 {
195     Q_D(const QuickTestResult);
196     return d->functionName;
197 }
198
199 void QuickTestResult::setFunctionName(const QString &name)
200 {
201     Q_D(QuickTestResult);
202     if (!name.isEmpty()) {
203         if (d->testCaseName.isEmpty()) {
204             QTestResult::setCurrentTestFunction
205                 (d->intern(name).constData());
206         } else {
207             QString fullName = d->testCaseName + QLatin1String("::") + name;
208             QTestResult::setCurrentTestFunction
209                 (d->intern(fullName).constData());
210         }
211     } else {
212         QTestResult::setCurrentTestFunction(0);
213     }
214     d->functionName = name;
215     emit functionNameChanged();
216 }
217
218 /*!
219     \qmlproperty string TestResult::dataTag
220
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.
223 */
224 QString QuickTestResult::dataTag() const
225 {
226     const char *tag = QTestResult::currentDataTag();
227     if (tag)
228         return QString::fromUtf8(tag);
229     else
230         return QString();
231 }
232
233 void QuickTestResult::setDataTag(const QString &tag)
234 {
235     if (!tag.isEmpty()) {
236         QTestData *data = &(QTest::newRow(tag.toUtf8().constData()));
237         QTestResult::setCurrentTestData(data);
238         emit dataTagChanged();
239     } else {
240         QTestResult::setCurrentTestData(0);
241     }
242 }
243
244 /*!
245     \qmlproperty bool TestResult::failed
246
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.
251
252     \sa skipped
253 */
254 bool QuickTestResult::isFailed() const
255 {
256     return QTestResult::currentTestFailed();
257 }
258
259 /*!
260     \qmlproperty bool TestResult::skipped
261
262     This property returns true if the current test function was
263     marked as skipped; false otherwise.
264
265     \sa failed
266 */
267 bool QuickTestResult::isSkipped() const
268 {
269     return QTestResult::skipCurrentTest();
270 }
271
272 void QuickTestResult::setSkipped(bool skip)
273 {
274     QTestResult::setSkipCurrentTest(skip);
275     emit skippedChanged();
276 }
277
278 /*!
279     \qmlproperty int TestResult::passCount
280
281     This property returns the number of tests that have passed.
282
283     \sa failCount, skipCount
284 */
285 int QuickTestResult::passCount() const
286 {
287     return QTestLog::passCount();
288 }
289
290 /*!
291     \qmlproperty int TestResult::failCount
292
293     This property returns the number of tests that have failed.
294
295     \sa passCount, skipCount
296 */
297 int QuickTestResult::failCount() const
298 {
299     return QTestLog::failCount();
300 }
301
302 /*!
303     \qmlproperty int TestResult::skipCount
304
305     This property returns the number of tests that have been skipped.
306
307     \sa passCount, failCount
308 */
309 int QuickTestResult::skipCount() const
310 {
311     return QTestLog::skipCount();
312 }
313
314 /*!
315     \qmlproperty list<string> TestResult::functionsToRun
316
317     This property returns the list of function names to be run.
318 */
319 QStringList QuickTestResult::functionsToRun() const
320 {
321     return QTest::testFunctions;
322 }
323
324 /*!
325     \qmlmethod TestResult::reset()
326
327     Resets all pass/fail/skip counters and prepare for testing.
328 */
329 void QuickTestResult::reset()
330 {
331     if (!globalProgramName)     // Only if run via qmlviewer.
332         QTestResult::reset();
333 }
334
335 /*!
336     \qmlmethod TestResult::startLogging()
337
338     Starts logging to the test output stream and writes the
339     test header.
340
341     \sa stopLogging()
342 */
343 void QuickTestResult::startLogging()
344 {
345     // The program name is used for logging headers and footers if it
346     // is set.  Otherwise the test case name is used.
347     if (loggingStarted)
348         return;
349     QTestLog::startLogging();
350     loggingStarted = true;
351 }
352
353 /*!
354     \qmlmethod TestResult::stopLogging()
355
356     Writes the test footer to the test output stream and then stops logging.
357
358     \sa startLogging()
359 */
360 void QuickTestResult::stopLogging()
361 {
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();
367 }
368
369 void QuickTestResult::initTestTable()
370 {
371     Q_D(QuickTestResult);
372     delete d->table;
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");
377 }
378
379 void QuickTestResult::clearTestTable()
380 {
381     Q_D(QuickTestResult);
382     delete d->table;
383     d->table = 0;
384 }
385
386 void QuickTestResult::finishTestData()
387 {
388     QTestResult::finishedCurrentTestData();
389 }
390
391 void QuickTestResult::finishTestDataCleanup()
392 {
393     QTestResult::finishedCurrentTestDataCleanup();
394 }
395
396 void QuickTestResult::finishTestFunction()
397 {
398     QTestResult::finishedCurrentTestFunction();
399 }
400
401 static QString qtestFixUrl(const QUrl &location)
402 {
403     if (location.isLocalFile()) // Use QUrl's logic for Windows drive letters.
404         return QDir::toNativeSeparators(location.toLocalFile());
405     return location.toString();
406 }
407
408 void QuickTestResult::fail
409     (const QString &message, const QUrl &location, int line)
410 {
411     QTestResult::addFailure(message.toLatin1().constData(),
412                             qtestFixUrl(location).toLatin1().constData(), line);
413 }
414
415 bool QuickTestResult::verify
416     (bool success, const QString &message, const QUrl &location, int line)
417 {
418     if (!success && message.isEmpty()) {
419         return QTestResult::verify
420             (success, "verify()", "",
421              qtestFixUrl(location).toLatin1().constData(), line);
422     } else {
423         return QTestResult::verify
424             (success, message.toLatin1().constData(), "",
425              qtestFixUrl(location).toLatin1().constData(), line);
426     }
427 }
428
429 bool QuickTestResult::compare
430     (bool success, const QString &message,
431      const QString &val1, const QString &val2,
432      const QUrl &location, int line)
433 {
434     return QTestResult::compare
435         (success, message.toLocal8Bit().constData(),
436          QTest::toString(val1.toLatin1().constData()),
437          QTest::toString(val2.toLatin1().constData()),
438          "", "",
439          qtestFixUrl(location).toLatin1().constData(), line);
440 }
441
442 void QuickTestResult::skip
443     (const QString &message, const QUrl &location, int line)
444 {
445     QTestResult::addSkip(message.toLatin1().constData(),
446                          qtestFixUrl(location).toLatin1().constData(), line);
447     QTestResult::setSkipCurrentTest(true);
448 }
449
450 bool QuickTestResult::expectFail
451     (const QString &tag, const QString &comment, const QUrl &location, int line)
452 {
453     return QTestResult::expectFail
454         (tag.toLatin1().constData(),
455          QTest::toString(comment.toLatin1().constData()),
456          QTest::Abort, qtestFixUrl(location).toLatin1().constData(), line);
457 }
458
459 bool QuickTestResult::expectFailContinue
460     (const QString &tag, const QString &comment, const QUrl &location, int line)
461 {
462     return QTestResult::expectFail
463         (tag.toLatin1().constData(),
464          QTest::toString(comment.toLatin1().constData()),
465          QTest::Continue, qtestFixUrl(location).toLatin1().constData(), line);
466 }
467
468 void QuickTestResult::warn(const QString &message, const QUrl &location, int line)
469 {
470     QTestLog::warn(message.toLatin1().constData(), qtestFixUrl(location).toLatin1().constData(), line);
471 }
472
473 void QuickTestResult::ignoreWarning(const QString &message)
474 {
475     QTestLog::ignoreMessage(QtWarningMsg, message.toLatin1().constData());
476 }
477
478 void QuickTestResult::wait(int ms)
479 {
480     QTest::qWait(ms);
481 }
482
483 void QuickTestResult::sleep(int ms)
484 {
485     QTest::qSleep(ms);
486 }
487
488 void QuickTestResult::startMeasurement()
489 {
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;
495     d->results.clear();
496 }
497
498 void QuickTestResult::beginDataRun()
499 {
500     QBenchmarkTestMethodData::current->beginDataRun();
501 }
502
503 void QuickTestResult::endDataRun()
504 {
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);
509
510     if (QBenchmarkGlobalData::current->verboseOutput) {
511         if (d->iterCount == -1) {
512             qDebug() << "warmup stage result      :" << QBenchmarkTestMethodData::current->result.value;
513         } else {
514             qDebug() << "accumulation stage result:" << QBenchmarkTestMethodData::current->result.value;
515         }
516     }
517 }
518
519 bool QuickTestResult::measurementAccepted()
520 {
521     return QBenchmarkTestMethodData::current->resultsAccepted();
522 }
523
524 static QBenchmarkResult qMedian(const QList<QBenchmarkResult> &container)
525 {
526     const int count = container.count();
527     if (count == 0)
528         return QBenchmarkResult();
529
530     if (count == 1)
531         return container.at(0);
532
533     QList<QBenchmarkResult> containerCopy = container;
534     qSort(containerCopy);
535
536     const int middle = count / 2;
537
538     // ### handle even-sized containers here by doing an aritmetic mean of the two middle items.
539     return containerCopy.at(middle);
540 }
541
542 bool QuickTestResult::needsMoreMeasurements()
543 {
544     Q_D(QuickTestResult);
545     ++(d->iterCount);
546     if (d->iterCount < QBenchmarkGlobalData::current->adjustMedianIterationCount())
547         return true;
548     if (QBenchmarkTestMethodData::current->resultsAccepted())
549         QTestLog::addBenchmarkResult(qMedian(d->results));
550     return false;
551 }
552
553 void QuickTestResult::startBenchmark(RunMode runMode, const QString &tag)
554 {
555     QBenchmarkTestMethodData::current->result = QBenchmarkResult();
556     QBenchmarkTestMethodData::current->resultAccepted = false;
557     QBenchmarkGlobalData::current->context.tag = tag;
558     QBenchmarkGlobalData::current->context.slotName = functionName();
559
560     Q_D(QuickTestResult);
561     delete d->benchmarkIter;
562     d->benchmarkIter = new QTest::QBenchmarkIterationController
563         (QTest::QBenchmarkIterationController::RunMode(runMode));
564 }
565
566 bool QuickTestResult::isBenchmarkDone() const
567 {
568     Q_D(const QuickTestResult);
569     if (d->benchmarkIter)
570         return d->benchmarkIter->isDone();
571     else
572         return true;
573 }
574
575 void QuickTestResult::nextBenchmark()
576 {
577     Q_D(QuickTestResult);
578     if (d->benchmarkIter)
579         d->benchmarkIter->next();
580 }
581
582 void QuickTestResult::stopBenchmark()
583 {
584     Q_D(QuickTestResult);
585     delete d->benchmarkIter;
586     d->benchmarkIter = 0;
587 }
588
589 QObject *QuickTestResult::grabImage(QQuickItem *item)
590 {
591     if (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()));
597     }
598     return 0;
599 }
600 namespace QTest {
601     void qtest_qParseArgs(int argc, char *argv[], bool qml);
602 };
603
604 void QuickTestResult::parseArgs(int argc, char *argv[])
605 {
606     if (!QBenchmarkGlobalData::current)
607         QBenchmarkGlobalData::current = &globalBenchmarkData;
608     QTest::qtest_qParseArgs(argc, argv, true);
609 }
610
611 void QuickTestResult::setProgramName(const char *name)
612 {
613     if (name) {
614         QTestResult::reset();
615     } else if (!name && loggingStarted) {
616         QTestResult::setCurrentTestObject(globalProgramName);
617         QTestLog::stopLogging();
618         QTestResult::setCurrentTestObject(0);
619     }
620     globalProgramName = name;
621     QTestResult::setCurrentTestObject(globalProgramName);
622 }
623
624 void QuickTestResult::setCurrentAppname(const char *appname)
625 {
626     QTestResult::setCurrentAppname(appname);
627 }
628
629 int QuickTestResult::exitCode()
630 {
631 #if defined(QTEST_NOEXITCODE)
632     return 0;
633 #else
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);
637 #endif
638 }
639
640 #include "quicktestresult.moc"
641
642 QT_END_NAMESPACE