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