Merge branch 'qtquick2'
[profile/ivi/qtdeclarative.git] / src / qmltest / quicktestresult.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
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
57 QT_BEGIN_NAMESPACE
58
59 static const char *globalProgramName = 0;
60 static bool loggingStarted = false;
61 static QBenchmarkGlobalData globalBenchmarkData;
62
63 class QuickTestResultPrivate
64 {
65 public:
66     QuickTestResultPrivate()
67         : table(0)
68         , benchmarkIter(0)
69         , benchmarkData(0)
70         , iterCount(0)
71     {
72     }
73     ~QuickTestResultPrivate()
74     {
75         delete table;
76         delete benchmarkIter;
77         delete benchmarkData;
78     }
79
80     QByteArray intern(const QString &str);
81     void updateTestObjectName();
82
83     QString testCaseName;
84     QString functionName;
85     QSet<QByteArray> internedStrings;
86     QTestTable *table;
87     QTest::QBenchmarkIterationController *benchmarkIter;
88     QBenchmarkTestMethodData *benchmarkData;
89     int iterCount;
90     QList<QBenchmarkResult> results;
91 };
92
93 QByteArray QuickTestResultPrivate::intern(const QString &str)
94 {
95     QByteArray bstr = str.toUtf8();
96     return *(internedStrings.insert(bstr));
97 }
98
99 void QuickTestResultPrivate::updateTestObjectName()
100 {
101     // In plain logging mode we use the TestCase name as the
102     // class name so that multiple TestCase elements will report
103     // results with "testCase::function".  In XML logging mode,
104     // we use the program name as the class name and report test
105     // functions as "testCase__function".
106     if (QTestLog::logMode() == QTestLog::Plain) {
107         if (testCaseName.isEmpty()) {
108             QTestResult::setCurrentTestObject(globalProgramName);
109         } else if (QTestLog::logMode() == QTestLog::Plain) {
110             QTestResult::setCurrentTestObject
111                 (intern(testCaseName).constData());
112         }
113     } else {
114         QTestResult::setCurrentTestObject(globalProgramName);
115     }
116 }
117
118 QuickTestResult::QuickTestResult(QObject *parent)
119     : QObject(parent), d_ptr(new QuickTestResultPrivate)
120 {
121     if (!QBenchmarkGlobalData::current)
122         QBenchmarkGlobalData::current = &globalBenchmarkData;
123 }
124
125 QuickTestResult::~QuickTestResult()
126 {
127 }
128
129 /*!
130     \qmlproperty string TestResult::testCaseName
131
132     This property defines the name of current TestCase element
133     that is running test cases.
134
135     \sa functionName
136 */
137 QString QuickTestResult::testCaseName() const
138 {
139     Q_D(const QuickTestResult);
140     return d->testCaseName;
141 }
142
143 void QuickTestResult::setTestCaseName(const QString &name)
144 {
145     Q_D(QuickTestResult);
146     d->testCaseName = name;
147     d->updateTestObjectName();
148     emit testCaseNameChanged();
149 }
150
151 /*!
152     \qmlproperty string TestResult::functionName
153
154     This property defines the name of current test function
155     within a TestCase element that is running.  If this string is
156     empty, then no function is currently running.
157
158     \sa testCaseName
159 */
160 QString QuickTestResult::functionName() const
161 {
162     Q_D(const QuickTestResult);
163     return d->functionName;
164 }
165
166 void QuickTestResult::setFunctionName(const QString &name)
167 {
168     Q_D(QuickTestResult);
169     if (!name.isEmpty()) {
170         // In plain logging mode, we use the function name directly.
171         // In XML logging mode, we use "testCase__functionName" as the
172         // program name is acting as the class name.
173         if (QTestLog::logMode() == QTestLog::Plain ||
174                 d->testCaseName.isEmpty()) {
175             QTestResult::setCurrentTestFunction
176                 (d->intern(name).constData());
177         } else {
178             QString fullName = d->testCaseName + QLatin1String("__") + name;
179             QTestResult::setCurrentTestFunction
180                 (d->intern(fullName).constData());
181         }
182     } else {
183         QTestResult::setCurrentTestFunction(0);
184     }
185     d->functionName = name;
186     emit functionNameChanged();
187 }
188
189 QuickTestResult::FunctionType QuickTestResult::functionType() const
190 {
191     return FunctionType(QTestResult::currentTestLocation());
192 }
193
194 void QuickTestResult::setFunctionType(FunctionType type)
195 {
196     QTestResult::setCurrentTestLocation(QTestResult::TestLocation(type));
197     emit functionTypeChanged();
198 }
199
200 /*!
201     \qmlproperty string TestResult::dataTag
202
203     This property defines the tag for the current row in a
204     data-driven test, or an empty string if not a data-driven test.
205 */
206 QString QuickTestResult::dataTag() const
207 {
208     const char *tag = QTestResult::currentDataTag();
209     if (tag)
210         return QString::fromUtf8(tag);
211     else
212         return QString();
213 }
214
215 void QuickTestResult::setDataTag(const QString &tag)
216 {
217     if (!tag.isEmpty()) {
218         QTestData *data = &(QTest::newRow(tag.toUtf8().constData()));
219         QTestResult::setCurrentTestData(data);
220         emit dataTagChanged();
221     } else {
222         QTestResult::setCurrentTestData(0);
223     }
224 }
225
226 /*!
227     \qmlproperty bool TestResult::failed
228
229     This property returns true if the current test function has
230     failed; false otherwise.  The fail state is reset when
231     functionName is changed or finishTestFunction() is called.
232
233     \sa skipped, dataFailed
234 */
235 bool QuickTestResult::isFailed() const
236 {
237     return QTestResult::testFailed();
238 }
239
240 /*!
241     \qmlproperty bool TestResult::dataFailed
242
243     This property returns true if the current data function has
244     failed; false otherwise.  The fail state is reset when
245     functionName is changed or finishTestFunction() is called.
246
247     \sa failed
248 */
249 bool QuickTestResult::isDataFailed() const
250 {
251     return QTestResult::currentTestFailed();
252 }
253
254 /*!
255     \qmlproperty bool TestResult::skipped
256
257     This property returns true if the current test function was
258     marked as skipped; false otherwise.
259
260     \sa failed
261 */
262 bool QuickTestResult::isSkipped() const
263 {
264     return QTestResult::skipCurrentTest();
265 }
266
267 void QuickTestResult::setSkipped(bool skip)
268 {
269     QTestResult::setSkipCurrentTest(skip);
270     emit skippedChanged();
271 }
272
273 /*!
274     \qmlproperty int TestResult::passCount
275
276     This property returns the number of tests that have passed.
277
278     \sa failCount, skipCount
279 */
280 int QuickTestResult::passCount() const
281 {
282     return QTestResult::passCount();
283 }
284
285 /*!
286     \qmlproperty int TestResult::failCount
287
288     This property returns the number of tests that have failed.
289
290     \sa passCount, skipCount
291 */
292 int QuickTestResult::failCount() const
293 {
294     return QTestResult::failCount();
295 }
296
297 /*!
298     \qmlproperty int TestResult::skipCount
299
300     This property returns the number of tests that have been skipped.
301
302     \sa passCount, failCount
303 */
304 int QuickTestResult::skipCount() const
305 {
306     return QTestResult::skipCount();
307 }
308
309 /*!
310     \qmlproperty list<string> TestResult::functionsToRun
311
312     This property returns the list of function names to be run.
313 */
314 QStringList QuickTestResult::functionsToRun() const
315 {
316     return QTest::testFunctions;
317 }
318
319 /*!
320     \qmlmethod TestResult::reset()
321
322     Resets all pass/fail/skip counters and prepare for testing.
323 */
324 void QuickTestResult::reset()
325 {
326     if (!globalProgramName)     // Only if run via qmlviewer.
327         QTestResult::reset();
328 }
329
330 /*!
331     \qmlmethod TestResult::startLogging()
332
333     Starts logging to the test output stream and writes the
334     test header.
335
336     \sa stopLogging()
337 */
338 void QuickTestResult::startLogging()
339 {
340     // The program name is used for logging headers and footers if it
341     // is set.  Otherwise the test case name is used.
342     Q_D(QuickTestResult);
343     if (loggingStarted)
344         return;
345     const char *saved = QTestResult::currentTestObjectName();
346     if (globalProgramName) {
347         QTestResult::setCurrentTestObject(globalProgramName);
348     } else {
349         QTestResult::setCurrentTestObject
350             (d->intern(d->testCaseName).constData());
351     }
352     QTestLog::startLogging();
353     QTestResult::setCurrentTestObject(saved);
354     loggingStarted = true;
355 }
356
357 /*!
358     \qmlmethod TestResult::stopLogging()
359
360     Writes the test footer to the test output stream and then stops logging.
361
362     \sa startLogging()
363 */
364 void QuickTestResult::stopLogging()
365 {
366     Q_D(QuickTestResult);
367     if (globalProgramName)
368         return;     // Logging will be stopped by setProgramName(0).
369     const char *saved = QTestResult::currentTestObjectName();
370     QTestResult::setCurrentTestObject(d->intern(d->testCaseName).constData());
371     QTestLog::stopLogging();
372     QTestResult::setCurrentTestObject(saved);
373 }
374
375 void QuickTestResult::initTestTable()
376 {
377     Q_D(QuickTestResult);
378     delete d->table;
379     d->table = new QTestTable;
380 }
381
382 void QuickTestResult::clearTestTable()
383 {
384     Q_D(QuickTestResult);
385     delete d->table;
386     d->table = 0;
387 }
388
389 void QuickTestResult::finishTestFunction()
390 {
391     QTestResult::finishedCurrentTestFunction();
392 }
393
394 static QString qtest_fixFile(const QString &file)
395 {
396     if (file.startsWith(QLatin1String("file://")))
397         return file.mid(7);
398     else
399         return file;
400 }
401
402 void QuickTestResult::fail
403     (const QString &message, const QString &file, int line)
404 {
405     QTestResult::addFailure(message.toLatin1().constData(),
406                             qtest_fixFile(file).toLatin1().constData(), line);
407 }
408
409 bool QuickTestResult::verify
410     (bool success, const QString &message, const QString &file, int line)
411 {
412     if (!success && message.isEmpty()) {
413         return QTestResult::verify
414             (success, "verify()", "",
415              qtest_fixFile(file).toLatin1().constData(), line);
416     } else {
417         return QTestResult::verify
418             (success, message.toLatin1().constData(), "",
419              qtest_fixFile(file).toLatin1().constData(), line);
420     }
421 }
422
423 bool QuickTestResult::compare
424     (bool success, const QString &message,
425      const QString &val1, const QString &val2,
426      const QString &file, int line)
427 {
428     if (success) {
429         return QTestResult::compare
430             (success, message.toLocal8Bit().constData(),
431              qtest_fixFile(file).toLatin1().constData(), line);
432     } else {
433         return QTestResult::compare
434             (success, message.toLocal8Bit().constData(),
435              QTest::toString(val1.toLatin1().constData()),
436              QTest::toString(val2.toLatin1().constData()),
437              "", "",
438              qtest_fixFile(file).toLatin1().constData(), line);
439     }
440 }
441
442 void QuickTestResult::skipSingle
443     (const QString &message, const QString &file, int line)
444 {
445     QTestResult::addSkip(message.toLatin1().constData(), QTest::SkipSingle,
446                          qtest_fixFile(file).toLatin1().constData(), line);
447 }
448
449 void QuickTestResult::skipAll
450     (const QString &message, const QString &file, int line)
451 {
452     QTestResult::addSkip(message.toLatin1().constData(), QTest::SkipAll,
453                          qtest_fixFile(file).toLatin1().constData(), line);
454     QTestResult::setSkipCurrentTest(true);
455 }
456
457 bool QuickTestResult::expectFail
458     (const QString &tag, const QString &comment, const QString &file, int line)
459 {
460     return QTestResult::expectFail
461         (tag.toLatin1().constData(),
462          QTest::toString(comment.toLatin1().constData()),
463          QTest::Abort, qtest_fixFile(file).toLatin1().constData(), line);
464 }
465
466 bool QuickTestResult::expectFailContinue
467     (const QString &tag, const QString &comment, const QString &file, int line)
468 {
469     return QTestResult::expectFail
470         (tag.toLatin1().constData(),
471          QTest::toString(comment.toLatin1().constData()),
472          QTest::Continue, qtest_fixFile(file).toLatin1().constData(), line);
473 }
474
475 void QuickTestResult::warn(const QString &message)
476 {
477     QTestLog::warn(message.toLatin1().constData());
478 }
479
480 void QuickTestResult::ignoreWarning(const QString &message)
481 {
482     QTestResult::ignoreMessage(QtWarningMsg, message.toLatin1().constData());
483 }
484
485 void QuickTestResult::wait(int ms)
486 {
487     QTest::qWait(ms);
488 }
489
490 void QuickTestResult::sleep(int ms)
491 {
492     QTest::qSleep(ms);
493 }
494
495 void QuickTestResult::startMeasurement()
496 {
497     Q_D(QuickTestResult);
498     delete d->benchmarkData;
499     d->benchmarkData = new QBenchmarkTestMethodData();
500     QBenchmarkTestMethodData::current = d->benchmarkData;
501     d->iterCount = (QBenchmarkGlobalData::current->measurer->needsWarmupIteration()) ? -1 : 0;
502     d->results.clear();
503 }
504
505 void QuickTestResult::beginDataRun()
506 {
507     QBenchmarkTestMethodData::current->beginDataRun();
508 }
509
510 void QuickTestResult::endDataRun()
511 {
512     Q_D(QuickTestResult);
513     QBenchmarkTestMethodData::current->endDataRun();
514     if (d->iterCount > -1)  // iteration -1 is the warmup iteration.
515         d->results.append(QBenchmarkTestMethodData::current->result);
516
517     if (QBenchmarkGlobalData::current->verboseOutput) {
518         if (d->iterCount == -1) {
519             qDebug() << "warmup stage result      :" << QBenchmarkTestMethodData::current->result.value;
520         } else {
521             qDebug() << "accumulation stage result:" << QBenchmarkTestMethodData::current->result.value;
522         }
523     }
524 }
525
526 bool QuickTestResult::measurementAccepted()
527 {
528     return QBenchmarkTestMethodData::current->resultsAccepted();
529 }
530
531 static QBenchmarkResult qMedian(const QList<QBenchmarkResult> &container)
532 {
533     const int count = container.count();
534     if (count == 0)
535         return QBenchmarkResult();
536
537     if (count == 1)
538         return container.at(0);
539
540     QList<QBenchmarkResult> containerCopy = container;
541     qSort(containerCopy);
542
543     const int middle = count / 2;
544
545     // ### handle even-sized containers here by doing an aritmetic mean of the two middle items.
546     return containerCopy.at(middle);
547 }
548
549 bool QuickTestResult::needsMoreMeasurements()
550 {
551     Q_D(QuickTestResult);
552     ++(d->iterCount);
553     if (d->iterCount < QBenchmarkGlobalData::current->adjustMedianIterationCount())
554         return true;
555     if (QBenchmarkTestMethodData::current->resultsAccepted())
556         QTestLog::addBenchmarkResult(qMedian(d->results));
557     return false;
558 }
559
560 void QuickTestResult::startBenchmark(RunMode runMode, const QString &tag)
561 {
562     QBenchmarkTestMethodData::current->result = QBenchmarkResult();
563     QBenchmarkTestMethodData::current->resultAccepted = false;
564     QBenchmarkGlobalData::current->context.tag = tag;
565     QBenchmarkGlobalData::current->context.slotName = functionName();
566
567     Q_D(QuickTestResult);
568     delete d->benchmarkIter;
569     d->benchmarkIter = new QTest::QBenchmarkIterationController
570         (QTest::QBenchmarkIterationController::RunMode(runMode));
571 }
572
573 bool QuickTestResult::isBenchmarkDone() const
574 {
575     Q_D(const QuickTestResult);
576     if (d->benchmarkIter)
577         return d->benchmarkIter->isDone();
578     else
579         return true;
580 }
581
582 void QuickTestResult::nextBenchmark()
583 {
584     Q_D(QuickTestResult);
585     if (d->benchmarkIter)
586         d->benchmarkIter->next();
587 }
588
589 void QuickTestResult::stopBenchmark()
590 {
591     Q_D(QuickTestResult);
592     delete d->benchmarkIter;
593     d->benchmarkIter = 0;
594 }
595
596 namespace QTest {
597     void qtest_qParseArgs(int argc, char *argv[], bool qml);
598 };
599
600 void QuickTestResult::parseArgs(int argc, char *argv[])
601 {
602     if (!QBenchmarkGlobalData::current)
603         QBenchmarkGlobalData::current = &globalBenchmarkData;
604     QTest::qtest_qParseArgs(argc, argv, true);
605 }
606
607 void QuickTestResult::setProgramName(const char *name)
608 {
609     if (name) {
610         QTestResult::reset();
611     } else if (!name && loggingStarted) {
612         QTestResult::setCurrentTestObject(globalProgramName);
613         QTestLog::stopLogging();
614         QTestResult::setCurrentTestObject(0);
615     }
616     globalProgramName = name;
617 }
618
619 int QuickTestResult::exitCode()
620 {
621 #if defined(QTEST_NOEXITCODE)
622     return 0;
623 #else
624     // make sure our exit code is never going above 127
625     // since that could wrap and indicate 0 test fails
626     return qMin(QTestResult::failCount(), 127);
627 #endif
628 }
629
630 QT_END_NAMESPACE