1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the test suite of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
43
#include "abstracttestsuite.h"
44
#include <QtTest/QtTest>
48
#if defined(Q_OS_SYMBIAN)
54
TestRecord() : lineNumber(-1) { }
55
TestRecord(const QString &desc,
59
const QString &fn, int ln)
60
: description(desc), passed(pass),
61
actual(act), expected(exp),
62
fileName(fn), lineNumber(ln)
64
TestRecord(const QString &skipReason, const QString &fn)
65
: description(skipReason), actual("QSKIP"),
66
fileName(fn), lineNumber(-1)
76
Q_DECLARE_METATYPE(TestRecord)
84
FailureItem(Action act, const QRegExp &rx, const QString &desc, const QString &msg)
85
: action(act), pathRegExp(rx), description(desc), message(msg)
94
class tst_QScriptJSTestSuite : public AbstractTestSuite
98
tst_QScriptJSTestSuite();
99
virtual ~tst_QScriptJSTestSuite();
102
virtual void configData(TestConfig::Mode mode, const QStringList &parts);
103
virtual void writeSkipConfigFile(QTextStream &);
104
virtual void writeExpectFailConfigFile(QTextStream &);
105
virtual void runTestFunction(int testIndex);
108
void addExpectedFailure(const QString &fileName, const QString &description, const QString &message);
109
void addExpectedFailure(const QRegExp &path, const QString &description, const QString &message);
110
void addSkip(const QString &fileName, const QString &description, const QString &message);
111
void addSkip(const QRegExp &path, const QString &description, const QString &message);
112
bool isExpectedFailure(const QString &fileName, const QString &description,
113
QString *message, FailureItem::Action *action) const;
114
void addFileExclusion(const QString &fileName, const QString &message);
115
void addFileExclusion(const QRegExp &rx, const QString &message);
116
bool isExcludedFile(const QString &fileName, QString *message) const;
118
QList<QString> subSuitePaths;
119
QList<FailureItem> expectedFailures;
120
QList<QPair<QRegExp, QString> > fileExclusions;
123
static QScriptValue qscript_void(QScriptContext *, QScriptEngine *eng)
125
return eng->undefinedValue();
128
static QScriptValue qscript_quit(QScriptContext *ctx, QScriptEngine *)
130
return ctx->throwError("Test quit");
133
static QString optionsToString(int options)
137
set.insert("strict");
139
set.insert("werror");
141
set.insert("atline");
144
return QStringList(set.values()).join(",");
147
static QScriptValue qscript_options(QScriptContext *ctx, QScriptEngine *)
149
static QHash<QString, int> stringToFlagHash;
150
if (stringToFlagHash.isEmpty()) {
151
stringToFlagHash["strict"] = 1;
152
stringToFlagHash["werror"] = 2;
153
stringToFlagHash["atline"] = 4;
154
stringToFlagHash["xml"] = 8;
156
QScriptValue callee = ctx->callee();
157
int opts = callee.data().toInt32();
158
QString result = optionsToString(opts);
159
for (int i = 0; i < ctx->argumentCount(); ++i)
160
opts |= stringToFlagHash.value(ctx->argument(0).toString());
161
callee.setData(opts);
165
static QScriptValue qscript_TestCase(QScriptContext *ctx, QScriptEngine *eng)
167
QScriptValue origTestCaseCtor = ctx->callee().data();
168
QScriptValue kase = ctx->thisObject();
169
QScriptValue ret = origTestCaseCtor.call(kase, ctx->argumentsObject());
170
QScriptContextInfo info(ctx->parentContext());
171
kase.setProperty("__lineNumber__", QScriptValue(eng, info.lineNumber()));
175
void tst_QScriptJSTestSuite::runTestFunction(int testIndex)
177
if (!(testIndex & 1)) {
179
QTest::addColumn<TestRecord>("record");
180
bool hasData = false;
182
QString testsShellPath = testsDir.absoluteFilePath("shell.js");
183
QString testsShellContents = readFile(testsShellPath);
185
QDir subSuiteDir(subSuitePaths.at(testIndex / 2));
186
QString subSuiteShellPath = subSuiteDir.absoluteFilePath("shell.js");
187
QString subSuiteShellContents = readFile(subSuiteShellPath);
189
QDir testSuiteDir(subSuiteDir);
191
QString suiteJsrefPath = testSuiteDir.absoluteFilePath("jsref.js");
192
QString suiteJsrefContents = readFile(suiteJsrefPath);
193
QString suiteShellPath = testSuiteDir.absoluteFilePath("shell.js");
194
QString suiteShellContents = readFile(suiteShellPath);
196
QFileInfoList testFileInfos = subSuiteDir.entryInfoList(QStringList() << "*.js", QDir::Files);
197
foreach (QFileInfo tfi, testFileInfos) {
198
if ((tfi.fileName() == "shell.js") || (tfi.fileName() == "browser.js"))
201
QString abspath = tfi.absoluteFilePath();
202
QString relpath = testsDir.relativeFilePath(abspath);
203
QString excludeMessage;
204
if (isExcludedFile(relpath, &excludeMessage)) {
205
QTest::newRow(relpath.toLatin1()) << TestRecord(excludeMessage, relpath);
210
QScriptValue global = eng.globalObject();
211
global.setProperty("print", eng.newFunction(qscript_void));
212
global.setProperty("quit", eng.newFunction(qscript_quit));
213
global.setProperty("options", eng.newFunction(qscript_options));
215
eng.evaluate(testsShellContents, testsShellPath);
216
if (eng.hasUncaughtException()) {
217
QStringList bt = eng.uncaughtExceptionBacktrace();
218
QString err = eng.uncaughtException().toString();
219
qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n")));
223
eng.evaluate(suiteJsrefContents, suiteJsrefPath);
224
if (eng.hasUncaughtException()) {
225
QStringList bt = eng.uncaughtExceptionBacktrace();
226
QString err = eng.uncaughtException().toString();
227
qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n")));
231
eng.evaluate(suiteShellContents, suiteShellPath);
232
if (eng.hasUncaughtException()) {
233
QStringList bt = eng.uncaughtExceptionBacktrace();
234
QString err = eng.uncaughtException().toString();
235
qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n")));
239
eng.evaluate(subSuiteShellContents, subSuiteShellPath);
240
if (eng.hasUncaughtException()) {
241
QStringList bt = eng.uncaughtExceptionBacktrace();
242
QString err = eng.uncaughtException().toString();
243
qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n")));
247
QScriptValue origTestCaseCtor = global.property("TestCase");
248
QScriptValue myTestCaseCtor = eng.newFunction(qscript_TestCase);
249
myTestCaseCtor.setData(origTestCaseCtor);
250
global.setProperty("TestCase", myTestCaseCtor);
252
global.setProperty("gTestfile", tfi.fileName());
253
global.setProperty("gTestsuite", testSuiteDir.dirName());
254
global.setProperty("gTestsubsuite", subSuiteDir.dirName());
255
QString testFileContents = readFile(abspath);
256
// qDebug() << relpath;
257
eng.evaluate(testFileContents, abspath);
258
if (eng.hasUncaughtException() && !relpath.endsWith("-n.js")) {
259
QStringList bt = eng.uncaughtExceptionBacktrace();
260
QString err = eng.uncaughtException().toString();
261
qWarning("%s\n%s\n", qPrintable(err), qPrintable(bt.join("\n")));
265
QScriptValue testcases = global.property("testcases");
266
if (!testcases.isArray())
267
testcases = global.property("gTestcases");
268
int count = testcases.property("length").toInt32();
273
QString title = global.property("TITLE").toString();
274
for (int i = 0; i < count; ++i) {
275
QScriptValue kase = testcases.property(i);
276
QString description = kase.property("description").toString();
277
QScriptValue expect = kase.property("expect");
278
QScriptValue actual = kase.property("actual");
279
bool passed = kase.property("passed").toBoolean();
280
int lineNumber = kase.property("__lineNumber__").toInt32();
282
TestRecord rec(description, passed,
283
actual.toString(), expect.toString(),
284
relpath, lineNumber);
286
QTest::newRow(description.toLatin1()) << rec;
290
QTest::newRow("") << TestRecord(); // dummy
292
QFETCH(TestRecord, record);
293
if ((record.lineNumber == -1) && (record.actual == "QSKIP")) {
294
QTest::qSkip(record.description.toLatin1(), record.fileName.toLatin1(), -1);
297
FailureItem::Action failAct;
298
bool expectFail = isExpectedFailure(record.fileName, record.description, &msg, &failAct);
301
case FailureItem::ExpectFail:
302
QTest::qExpectFail("", msg.toLatin1(),
303
QTest::Continue, record.fileName.toLatin1(),
306
case FailureItem::Skip:
307
QTest::qSkip(msg.toLatin1(), record.fileName.toLatin1(), record.lineNumber);
311
if (!expectFail || (failAct == FailureItem::ExpectFail)) {
312
if (!record.passed) {
313
if (!expectFail && shouldGenerateExpectedFailures) {
314
addExpectedFailure(record.fileName,
318
QTest::qCompare(record.actual, record.expected, "actual", "expect",
319
record.fileName.toLatin1(), record.lineNumber);
321
QTest::qCompare(record.actual, record.actual, "actual", "expect",
322
record.fileName.toLatin1(), record.lineNumber);
329
tst_QScriptJSTestSuite::tst_QScriptJSTestSuite()
330
: AbstractTestSuite("tst_QScriptJsTestSuite",
331
QString::fromLatin1("%0/tests").arg(SRCDIR),
334
// don't execute any tests on slow machines
335
#if !defined(Q_OS_IRIX)
336
// do all the test suites
337
QFileInfoList testSuiteDirInfos = testsDir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot);
338
foreach (QFileInfo tsdi, testSuiteDirInfos) {
339
QDir testSuiteDir(tsdi.absoluteFilePath());
340
// do all the dirs in the test suite
341
QFileInfoList subSuiteDirInfos = testSuiteDir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot);
342
foreach (QFileInfo ssdi, subSuiteDirInfos) {
343
subSuitePaths.append(ssdi.absoluteFilePath());
344
QString function = QString::fromLatin1("%0/%1")
345
.arg(testSuiteDir.dirName()).arg(ssdi.fileName());
346
addTestFunction(function, CreateDataFunction);
351
finalizeMetaObject();
354
tst_QScriptJSTestSuite::~tst_QScriptJSTestSuite()
358
void tst_QScriptJSTestSuite::configData(TestConfig::Mode mode, const QStringList &parts)
361
case TestConfig::Skip:
362
addFileExclusion(parts.at(0), parts.value(1));
365
case TestConfig::ExpectFail:
366
addExpectedFailure(parts.at(0), parts.value(1), parts.value(2));
371
void tst_QScriptJSTestSuite::writeSkipConfigFile(QTextStream &stream)
373
stream << QString::fromLatin1("# testcase | message") << endl;
376
void tst_QScriptJSTestSuite::writeExpectFailConfigFile(QTextStream &stream)
378
stream << QString::fromLatin1("# testcase | description | message") << endl;
379
for (int i = 0; i < expectedFailures.size(); ++i) {
380
const FailureItem &fail = expectedFailures.at(i);
381
if (fail.pathRegExp.pattern().isEmpty())
383
stream << QString::fromLatin1("%0 | %1")
384
.arg(fail.pathRegExp.pattern())
385
.arg(escape(fail.description));
386
if (!fail.message.isEmpty())
387
stream << QString::fromLatin1(" | %0").arg(escape(fail.message));
392
void tst_QScriptJSTestSuite::addExpectedFailure(const QRegExp &path, const QString &description, const QString &message)
394
expectedFailures.append(FailureItem(FailureItem::ExpectFail, path, description, message));
397
void tst_QScriptJSTestSuite::addExpectedFailure(const QString &fileName, const QString &description, const QString &message)
399
expectedFailures.append(FailureItem(FailureItem::ExpectFail, QRegExp(fileName), description, message));
402
void tst_QScriptJSTestSuite::addSkip(const QRegExp &path, const QString &description, const QString &message)
404
expectedFailures.append(FailureItem(FailureItem::Skip, path, description, message));
407
void tst_QScriptJSTestSuite::addSkip(const QString &fileName, const QString &description, const QString &message)
409
expectedFailures.append(FailureItem(FailureItem::Skip, QRegExp(fileName), description, message));
412
bool tst_QScriptJSTestSuite::isExpectedFailure(const QString &fileName, const QString &description,
413
QString *message, FailureItem::Action *action) const
415
for (int i = 0; i < expectedFailures.size(); ++i) {
416
QRegExp pathRegExp = expectedFailures.at(i).pathRegExp;
417
if (pathRegExp.indexIn(fileName) != -1) {
418
if (description == expectedFailures.at(i).description) {
420
*message = expectedFailures.at(i).message;
422
*action = expectedFailures.at(i).action;
430
void tst_QScriptJSTestSuite::addFileExclusion(const QString &fileName, const QString &message)
432
fileExclusions.append(qMakePair(QRegExp(fileName), message));
435
void tst_QScriptJSTestSuite::addFileExclusion(const QRegExp &rx, const QString &message)
437
fileExclusions.append(qMakePair(rx, message));
440
bool tst_QScriptJSTestSuite::isExcludedFile(const QString &fileName, QString *message) const
442
for (int i = 0; i < fileExclusions.size(); ++i) {
443
QRegExp copy = fileExclusions.at(i).first;
444
if (copy.indexIn(fileName) != -1) {
446
*message = fileExclusions.at(i).second;
453
QTEST_MAIN(tst_QScriptJSTestSuite)