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