diff options
Diffstat (limited to 'old/interpreter/qtscript_bindings.cpp')
-rw-r--r-- | old/interpreter/qtscript_bindings.cpp | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/old/interpreter/qtscript_bindings.cpp b/old/interpreter/qtscript_bindings.cpp new file mode 100644 index 0000000..dc66659 --- /dev/null +++ b/old/interpreter/qtscript_bindings.cpp @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of QtUiTest. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <qtestide.h> +#include "qscriptengine.h" +#include "qscriptvalue.h" +#include "qscriptvalueiterator.h" +#include "qscriptcontext.h" +#include "qscriptcontextinfo.h" + +#include "qtscript_bindings.h" + +QStringList builtinFiles; + +void QtScript::addInternalFile(QString const &filename) +{ + builtinFiles << filename; +} + +static QString readFile(const QString &filename) +{ + QFile file(filename); + if (!file.open(QFile::ReadOnly)) + return QString(); + QTextStream stream(&file); + return stream.readAll(); +} + +static void appendCString(QVector<char> *v, const char *s) +{ + char c; + do { + c = *(s++); + *v << c; + } while (c != '\0'); +} + +void QtScript::getLocation(QScriptContext *ctx, QString *fileName, int *lineNumber) +{ + Q_ASSERT(ctx); + if (fileName) *fileName = QString(); + if (lineNumber) *lineNumber = 0; + + while (ctx) { + QScriptContextInfo ctxInfo(ctx); + QString fn = ctxInfo.fileName(); + if (!fn.isEmpty() && !builtinFiles.contains(fn)) { + if (fileName) *fileName = fn; + if (lineNumber) *lineNumber = ctxInfo.lineNumber(); + return; + } + ctx = ctx->parentContext(); + } +} + +QMetaObject QtScriptTest::staticMetaObject; + +Q_GLOBAL_STATIC(QVector<uint>, qt_meta_data_QtScriptTest) +Q_GLOBAL_STATIC(QVector<char>, qt_meta_stringdata_QtScriptTest) + +const QMetaObject *QtScriptTest::metaObject() const +{ + return &staticMetaObject; +} + +void *QtScriptTest::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_QtScriptTest()->constData())) + return static_cast<void*>(const_cast<QtScriptTest*>(this)); + return QObject::qt_metacast(_clname); +} + +int QtScriptTest::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + const QMetaObject *mo = metaObject(); + QMetaMethod method = mo->method(mo->methodOffset() + _id); + QByteArray sig = method.signature(); + QString name = sig.left(sig.lastIndexOf('(')); + QScriptValue testcase = m_engine->globalObject().property("testcase"); + QScriptValue val = testcase.property(name); + if (name.endsWith("_data")) { + QTest::addColumn<int>("dummy"); + QScriptValueIterator it(val); + while (it.hasNext()) { + it.next(); + QString tag = it.name(); + QTest::newRow(tag.toLatin1()); + } + } else { + QScriptValue args; + QScriptValue data = testcase.property(name + "_data"); + if (data.isObject()) { + QString tag = QTest::currentDataTag(); + QScriptValue v = data.property(tag); + if (v.isValid()) { + if (v.isArray()) { + args = v; + } else { + args = m_engine->newArray(); + args.setProperty(0, v); + } + } + } + if (!args.isArray()) + args = m_engine->newArray(); + QScriptValue ret; + if (name == "init") { + ret = m_engine->evaluate("init_global();"); + } + else if (name == "initTestCase") { + ret = m_engine->evaluate("initTestCase_global();"); + } + else if (name != "cleanup" && name != "cleanupTestCase") { + m_engine->evaluate("qtuitest_pre_test_function();"); + } + if (!ret.isError() || ret.property("name").toString() == "QTestFailure") { + ret = val.call(m_engine->globalObject(), args); + QTest::compare_helper( true, "expectFail() not followed by a test statement", + m_testFilePath.toAscii(), property("expectFailLineNumber").toInt() ); + } + if (name != "init" && name != "initTestCase" && name != "cleanup" && name != "cleanupTestCase") { + m_engine->evaluate("qtuitest_post_test_function();"); + } + if (name == "cleanup") { + m_engine->evaluate("cleanup_global();"); + } + else if (name == "cleanupTestCase") { + m_engine->evaluate("cleanupTestCase_global();"); + } + if (ret.isError() && (ret.property("name").toString() != "QTestFailure")) { + QString backtrace = m_engine->uncaughtExceptionBacktrace().join("\n"); + QString message = ret.toString() + // xxx makes the failure message look cluttered; correct fix + // xxx is to implement proper generic saving of backtrace info + // xxx in test results + // + "\n" + backtrace + ; + QString fileName = "unknown"; + int lineNumber = -1; + QRegExp locationRe("@([^:]+):([0-9]+)"); + if (-1 != locationRe.indexIn(backtrace)) { + fileName = locationRe.cap(1); + lineNumber = locationRe.cap(2).toInt(); + } + QTest::qFail(qPrintable(message), qPrintable(fileName), lineNumber); + } + } + + _id = -1; + } + return _id; +} + +QtScriptTest::QtScriptTest(QString const &testFilePath, QString const &scriptData, QScriptEngine *engine) + : QObject(), m_testFilePath(testFilePath), m_engine(engine), m_status(StatusNotStarted) +{ + if (m_testFilePath.isEmpty()) + m_testFilePath = qgetenv("Q_TEST_FILE"); + if (m_testFilePath.isEmpty()) + m_testFilePath="testcase.js"; + +// m_engine->importExtension("qt.core"); + + QScriptValue qtestObject = m_engine->newObject(); + qtestObject.setProperty("SkipSingle", QScriptValue(m_engine, QTest::SkipSingle)); + qtestObject.setProperty("SkipAll", QScriptValue(m_engine, QTest::SkipAll)); + qtestObject.setProperty("Abort", QScriptValue(m_engine, QTest::Abort)); + qtestObject.setProperty("Continue", QScriptValue(m_engine, QTest::Continue)); + m_engine->globalObject().setProperty("QTest", qtestObject); + + m_engine->evaluate("function QTestFailure() { Error.apply(this, arguments); }" + "QTestFailure.prototype = new Error();" + "QTestFailure.prototype.name = 'QTestFailure';"); + + QStringList slotNames; + QString script = scriptData; + if (script.isEmpty()) script = readFile(m_testFilePath); + if (!script.isEmpty()) { + QScriptSyntaxCheckResult synChk = m_engine->checkSyntax(script); + if (synChk.state() != QScriptSyntaxCheckResult::Valid) { + QTestIDE::instance()->scriptSyntaxError(synChk.errorMessage(), m_testFilePath, synChk.errorLineNumber()); + m_status = StatusSyntaxError; + return; + } + + QScriptValue ret = m_engine->evaluate(script, m_testFilePath); + QString error; + if (m_engine->hasUncaughtException()) { + error = m_engine->uncaughtException().toString(); + } else if (ret.isError()) { + error = ret.toString(); + } + if (!error.isEmpty()) { + QString backtrace = m_engine->uncaughtExceptionBacktrace().join("\n"); + qWarning("%s\n%s", qPrintable(error), qPrintable(backtrace)); + m_status = StatusException; + return; + } + QScriptValue testcase = m_engine->globalObject().property("testcase"); + QScriptValueIterator it(testcase); + while (it.hasNext()) { + it.next(); + QScriptValue val = it.value(); + if (val.isFunction() || (val.isObject() && it.name().endsWith("_data"))) + slotNames << it.name(); + } + + QStringList requiredSlots; + requiredSlots + << "init" + << "cleanup" + << "initTestCase" + << "cleanupTestCase"; + + foreach (QString required, requiredSlots) { + if (!slotNames.contains(required)) { + m_engine->evaluate("testcase." + required + " = function() {}"); + slotNames << required; + } + } + } else { + qWarning("*** Failed to read testcase!"); + } + + QVector<uint> *data = qt_meta_data_QtScriptTest(); + data->clear(); + // content: + *data << 1 // revision + << 0 // classname + << 0 << 0 // classinfo + << slotNames.count() << 10 // methods + << 0 << 0 // properties + << 0 << 0 // enums/sets + ; + + QString testcaseName = QFileInfo(m_testFilePath).baseName(); + + QVector<char> *stringdata = qt_meta_stringdata_QtScriptTest(); + stringdata->clear(); + appendCString(stringdata, testcaseName.toLocal8Bit() ); + int namelen = stringdata->size(); + appendCString(stringdata, ""); + + // slots: signature, parameters, type, tag, flags + foreach (QString slotName, slotNames) { + QString slot = slotName + QLatin1String("()"); + *data << stringdata->size() << namelen << namelen << namelen << 0x08; + appendCString(stringdata, slot.toLatin1()); + } + *data << 0; // eod + + // initialize staticMetaObject + staticMetaObject.d.superdata = &QObject::staticMetaObject; + staticMetaObject.d.stringdata = stringdata->constData(); + staticMetaObject.d.data = data->constData(); + staticMetaObject.d.extradata = 0; + + m_status = StatusNormal; +} + +QtScriptTest::~QtScriptTest() +{ +} + +QtScriptTest::Status QtScriptTest::status() +{ + return m_status; +}
\ No newline at end of file |