tests/auto/qscriptv8testsuite/tst_qscriptv8testsuite.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 
       
    43 #include <QtTest/QtTest>
       
    44 #include <QByteArray>
       
    45 
       
    46 #include <QtScript>
       
    47 
       
    48 #if defined(Q_OS_SYMBIAN)
       
    49 # define SRCDIR ""
       
    50 #endif
       
    51 
       
    52 //TESTED_CLASS=
       
    53 //TESTED_FILES=
       
    54 
       
    55 // Uncomment the following define to have the autotest generate
       
    56 // addExpectedFailure() code for all the tests that fail.
       
    57 // This is useful when a whole new test (sub)suite is added.
       
    58 // The code is stored in addexpectedfailures.cpp.
       
    59 // Paste the contents into this file after the existing
       
    60 // addExpectedFailure() calls.
       
    61 
       
    62 //#define GENERATE_ADDEXPECTEDFAILURE_CODE
       
    63 
       
    64 static QString readFile(const QString &filename)
       
    65 {
       
    66     QFile file(filename);
       
    67     if (!file.open(QFile::ReadOnly))
       
    68         return QString();
       
    69     QTextStream stream(&file);
       
    70     stream.setCodec("UTF-8");
       
    71     return stream.readAll();
       
    72 }
       
    73 
       
    74 static void appendCString(QVector<char> *v, const char *s)
       
    75 {
       
    76     char c;
       
    77     do {
       
    78         c = *(s++);
       
    79         *v << c;
       
    80     } while (c != '\0');
       
    81 }
       
    82 
       
    83 struct ExpectedFailure
       
    84 {
       
    85     ExpectedFailure(const QString &name, const QString &act,
       
    86                     const QString &exp, const QString &msg)
       
    87         : testName(name), actual(act), expected(exp), message(msg)
       
    88         { }
       
    89 
       
    90     QString testName;
       
    91     QString actual;
       
    92     QString expected;
       
    93     QString message;
       
    94 };
       
    95 
       
    96 class tst_Suite : public QObject
       
    97 {
       
    98 
       
    99 public:
       
   100     tst_Suite();
       
   101     virtual ~tst_Suite();
       
   102 
       
   103     static QMetaObject staticMetaObject;
       
   104     virtual const QMetaObject *metaObject() const;
       
   105     virtual void *qt_metacast(const char *);
       
   106     virtual int qt_metacall(QMetaObject::Call, int, void **argv);
       
   107 
       
   108 private:
       
   109     void addExpectedFailure(const QString &testName, const QString &actual,
       
   110                             const QString &expected, const QString &message);
       
   111     bool isExpectedFailure(const QString &testName, const QString &actual,
       
   112                            const QString &expected, QString *message) const;
       
   113     void addTestExclusion(const QString &testName, const QString &message);
       
   114     void addTestExclusion(const QRegExp &rx, const QString &message);
       
   115     bool isExcludedTest(const QString &testName, QString *message) const;
       
   116 
       
   117     QDir testsDir;
       
   118     QStringList testNames;
       
   119     QList<ExpectedFailure> expectedFailures;
       
   120     QList<QPair<QRegExp, QString> > testExclusions;
       
   121     QString mjsunitContents;
       
   122 #ifdef GENERATE_ADDEXPECTEDFAILURE_CODE
       
   123     QString generatedAddExpectedFailureCode;
       
   124 #endif
       
   125 };
       
   126 
       
   127 QMetaObject tst_Suite::staticMetaObject;
       
   128 
       
   129 Q_GLOBAL_STATIC(QVector<uint>, qt_meta_data_tst_Suite)
       
   130 Q_GLOBAL_STATIC(QVector<char>, qt_meta_stringdata_tst_Suite)
       
   131 
       
   132 const QMetaObject *tst_Suite::metaObject() const
       
   133 {
       
   134     return &staticMetaObject;
       
   135 }
       
   136 
       
   137 void *tst_Suite::qt_metacast(const char *_clname)
       
   138 {
       
   139     if (!_clname) return 0;
       
   140     if (!strcmp(_clname, qt_meta_stringdata_tst_Suite()->constData()))
       
   141         return static_cast<void*>(const_cast<tst_Suite*>(this));
       
   142     return QObject::qt_metacast(_clname);
       
   143 }
       
   144 
       
   145 static QScriptValue qscript_fail(QScriptContext *ctx, QScriptEngine *eng)
       
   146 {
       
   147     QScriptValue realFail = ctx->callee().data();
       
   148     Q_ASSERT(realFail.isFunction());
       
   149     QScriptValue ret = realFail.call(ctx->thisObject(), ctx->argumentsObject());
       
   150     Q_ASSERT(eng->hasUncaughtException());
       
   151     ret.setProperty("expected", ctx->argument(0));
       
   152     ret.setProperty("actual", ctx->argument(1));
       
   153     QScriptContextInfo info(ctx->parentContext()->parentContext());
       
   154     ret.setProperty("lineNumber", info.lineNumber());
       
   155     return ret;
       
   156 }
       
   157 
       
   158 int tst_Suite::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
       
   159 {
       
   160     _id = QObject::qt_metacall(_c, _id, _a);
       
   161     if (_id < 0)
       
   162         return _id;
       
   163     if (_c == QMetaObject::InvokeMetaMethod) {
       
   164         QString name = testNames.at(_id);
       
   165         QString path = testsDir.absoluteFilePath(name + ".js");
       
   166         QString excludeMessage;
       
   167         if (isExcludedTest(name, &excludeMessage)) {
       
   168             QTest::qSkip(excludeMessage.toLatin1(), QTest::SkipAll, path.toLatin1(), -1);
       
   169         } else {
       
   170             QScriptEngine engine;
       
   171             engine.evaluate(mjsunitContents).toString();
       
   172             if (engine.hasUncaughtException()) {
       
   173                 QStringList bt = engine.uncaughtExceptionBacktrace();
       
   174                 QString err = engine.uncaughtException().toString();
       
   175                 qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n")));
       
   176             } else {
       
   177                 QScriptValue fakeFail = engine.newFunction(qscript_fail);
       
   178                 fakeFail.setData(engine.globalObject().property("fail"));
       
   179                 engine.globalObject().setProperty("fail", fakeFail);
       
   180                 QString contents = readFile(path);
       
   181                 QScriptValue ret = engine.evaluate(contents);
       
   182                 if (engine.hasUncaughtException()) {
       
   183                     if (!ret.isError()) {
       
   184                         Q_ASSERT(ret.instanceOf(engine.globalObject().property("MjsUnitAssertionError")));
       
   185                         QString actual = ret.property("actual").toString();
       
   186                         QString expected = ret.property("expected").toString();
       
   187                         int lineNumber = ret.property("lineNumber").toInt32();
       
   188                         QString failMessage;
       
   189                         if (isExpectedFailure(name, actual, expected, &failMessage)) {
       
   190                             QTest::qExpectFail("", failMessage.toLatin1(),
       
   191                                                QTest::Continue, path.toLatin1(),
       
   192                                                lineNumber);
       
   193                         }
       
   194 #ifdef GENERATE_ADDEXPECTEDFAILURE_CODE
       
   195                         else {
       
   196                             generatedAddExpectedFailureCode.append(
       
   197                                 "    addExpectedFailure(\"" + name
       
   198                                 + "\", \"" + actual + "\", \"" + expected
       
   199                                 + "\", willFixInNextReleaseMessage);\n");
       
   200                         }
       
   201 #endif
       
   202                         QTest::qCompare(actual, expected, "actual", "expect",
       
   203                                         path.toLatin1(), lineNumber);
       
   204                     } else {
       
   205                         int lineNumber = ret.property("lineNumber").toInt32();
       
   206                         QTest::qExpectFail("", ret.toString().toLatin1(),
       
   207                                            QTest::Continue, path.toLatin1(), lineNumber);
       
   208                         QTest::qVerify(false, ret.toString().toLatin1(), "", path.toLatin1(), lineNumber);
       
   209                     }
       
   210                 }
       
   211             }
       
   212         }
       
   213         _id -= testNames.size();
       
   214     }
       
   215     return _id;
       
   216 }
       
   217 
       
   218 tst_Suite::tst_Suite()
       
   219 {
       
   220     testsDir = QDir(SRCDIR);
       
   221     bool testsFound = testsDir.cd("tests");
       
   222     if (!testsFound) {
       
   223         qWarning("*** no tests/ dir!");
       
   224     } else {
       
   225         if (!testsDir.exists("mjsunit.js"))
       
   226             qWarning("*** no tests/mjsunit.js file!");
       
   227         else {
       
   228             mjsunitContents = readFile(testsDir.absoluteFilePath("mjsunit.js"));
       
   229             if (mjsunitContents.isEmpty())
       
   230                 qWarning("*** tests/mjsunit.js is empty!");
       
   231         }
       
   232     }
       
   233     QString willFixInNextReleaseMessage = QString::fromLatin1("Will fix in next release");
       
   234     addExpectedFailure("arguments-enum", "2", "0", willFixInNextReleaseMessage);
       
   235     addExpectedFailure("const-redecl", "undefined", "TypeError", willFixInNextReleaseMessage);
       
   236     addExpectedFailure("global-const-var-conflicts", "false", "true", willFixInNextReleaseMessage);
       
   237     addExpectedFailure("string-lastindexof", "0", "-1", "test is wrong?");
       
   238 
       
   239     addTestExclusion("debug-*", "not applicable");
       
   240     addTestExclusion("mirror-*", "not applicable");
       
   241 
       
   242     addTestExclusion("array-concat", "Hangs on JSC backend");
       
   243     addTestExclusion("array-splice", "Hangs on JSC backend");
       
   244     addTestExclusion("sparse-array-reverse", "Hangs on JSC backend");
       
   245 
       
   246     addTestExclusion("string-case", "V8-specific behavior? (Doesn't pass on SpiderMonkey either)");
       
   247 
       
   248 #ifdef Q_OS_WINCE
       
   249     addTestExclusion("deep-recursion", "Demands too much memory on WinCE");
       
   250     addTestExclusion("nested-repetition-count-overflow", "Demands too much memory on WinCE");
       
   251     addTestExclusion("unicode-test", "Demands too much memory on WinCE");
       
   252     addTestExclusion("mul-exhaustive", "Demands too much memory on WinCE");
       
   253 #endif
       
   254 
       
   255 #ifdef Q_OS_SYMBIAN
       
   256     addTestExclusion("nested-repetition-count-overflow", "Demands too much memory on Symbian");
       
   257     addTestExclusion("unicode-test", "Demands too much memory on Symbian");
       
   258 #endif
       
   259     // Failures due to switch to JSC as back-end
       
   260     addExpectedFailure("date-parse", "NaN", "946713600000", willFixInNextReleaseMessage);
       
   261     addExpectedFailure("delete-global-properties", "true", "false", willFixInNextReleaseMessage);
       
   262     addExpectedFailure("delete", "false", "true", willFixInNextReleaseMessage);
       
   263     addExpectedFailure("function-arguments-null", "false", "true", willFixInNextReleaseMessage);
       
   264     addExpectedFailure("function-caller", "null", "function eval() {\n    [native code]\n}", willFixInNextReleaseMessage);
       
   265     addExpectedFailure("function-prototype", "prototype", "disconnectconnect", willFixInNextReleaseMessage);
       
   266     addExpectedFailure("number-tostring", "0", "0.0000a7c5ac471b4788", willFixInNextReleaseMessage);
       
   267     addExpectedFailure("parse-int-float", "1e+21", "1", willFixInNextReleaseMessage);
       
   268     addExpectedFailure("regexp", "false", "true", willFixInNextReleaseMessage);
       
   269     addExpectedFailure("smi-negative-zero", "-Infinity", "Infinity", willFixInNextReleaseMessage);
       
   270     addExpectedFailure("string-split", "4", "3", willFixInNextReleaseMessage);
       
   271     addExpectedFailure("substr", "abcdefghijklmn", "", willFixInNextReleaseMessage);
       
   272 
       
   273     static const char klass[] = "tst_QScriptV8TestSuite";
       
   274 
       
   275     QVector<uint> *data = qt_meta_data_tst_Suite();
       
   276     // content:
       
   277     *data << 1 // revision
       
   278           << 0 // classname
       
   279           << 0 << 0 // classinfo
       
   280           << 0 << 10 // methods (backpatched later)
       
   281           << 0 << 0 // properties
       
   282           << 0 << 0 // enums/sets
       
   283         ;
       
   284 
       
   285     QVector<char> *stringdata = qt_meta_stringdata_tst_Suite();
       
   286     appendCString(stringdata, klass);
       
   287     appendCString(stringdata, "");
       
   288 
       
   289     QFileInfoList testFileInfos;
       
   290     if (testsFound)
       
   291         testFileInfos = testsDir.entryInfoList(QStringList() << "*.js", QDir::Files);
       
   292     foreach (QFileInfo tfi, testFileInfos) {
       
   293         QString name = tfi.baseName();
       
   294         // slot: signature, parameters, type, tag, flags
       
   295         QString slot = QString::fromLatin1("%0()").arg(name);
       
   296         static const int nullbyte = sizeof(klass);
       
   297         *data << stringdata->size() << nullbyte << nullbyte << nullbyte << 0x08;
       
   298         appendCString(stringdata, slot.toLatin1());
       
   299         testNames.append(name);
       
   300     }
       
   301 
       
   302     (*data)[4] = testFileInfos.size();
       
   303 
       
   304     *data << 0; // eod
       
   305 
       
   306     // initialize staticMetaObject
       
   307     staticMetaObject.d.superdata = &QObject::staticMetaObject;
       
   308     staticMetaObject.d.stringdata = stringdata->constData();
       
   309     staticMetaObject.d.data = data->constData();
       
   310     staticMetaObject.d.extradata = 0;
       
   311 }
       
   312 
       
   313 tst_Suite::~tst_Suite()
       
   314 {
       
   315 #ifdef GENERATE_ADDEXPECTEDFAILURE_CODE
       
   316     if (!generatedAddExpectedFailureCode.isEmpty()) {
       
   317         QFile file("addexpectedfailures.cpp");
       
   318         file.open(QFile::WriteOnly);
       
   319         QTextStream ts(&file);
       
   320         ts << generatedAddExpectedFailureCode;
       
   321     }
       
   322 #endif
       
   323 }
       
   324 
       
   325 void tst_Suite::addExpectedFailure(const QString &testName, const QString &actual,
       
   326                                    const QString &expected, const QString &message)
       
   327 {
       
   328     expectedFailures.append(ExpectedFailure(testName, actual, expected, message));
       
   329 }
       
   330 
       
   331 bool tst_Suite::isExpectedFailure(const QString &testName, const QString &actual,
       
   332                                   const QString &expected, QString *message) const
       
   333 {
       
   334     for (int i = 0; i < expectedFailures.size(); ++i) {
       
   335         const ExpectedFailure &ef = expectedFailures.at(i);
       
   336         if ((testName == ef.testName) && (actual == ef.actual) && (expected == ef.expected)) {
       
   337             if (message)
       
   338                 *message = ef.message;
       
   339             return true;
       
   340         }
       
   341     }
       
   342     return false;
       
   343 }
       
   344 
       
   345 void tst_Suite::addTestExclusion(const QString &testName, const QString &message)
       
   346 {
       
   347     testExclusions.append(qMakePair(QRegExp(testName), message));
       
   348 }
       
   349 
       
   350 void tst_Suite::addTestExclusion(const QRegExp &rx, const QString &message)
       
   351 {
       
   352     testExclusions.append(qMakePair(rx, message));
       
   353 }
       
   354 
       
   355 bool tst_Suite::isExcludedTest(const QString &testName, QString *message) const
       
   356 {
       
   357     for (int i = 0; i < testExclusions.size(); ++i) {
       
   358         if (testExclusions.at(i).first.indexIn(testName) != -1) {
       
   359             if (message)
       
   360                 *message = testExclusions.at(i).second;
       
   361             return true;
       
   362         }
       
   363     }
       
   364     return false;
       
   365 }
       
   366 
       
   367 QTEST_MAIN(tst_Suite)