summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesper K. Pedersen <jesper.pedersen@kdab.com>2013-05-14 10:44:09 +0200
committerJesper K. Pedersen <jesper.pedersen@kdab.com>2013-05-14 19:33:07 +0200
commitb52c0d5d00ee100eddd0215ad4c891f8067df76e (patch)
tree2c732ccdef0a38ab6edf6dc7e2008c5e85c5cce9
parent8020bb26e2ad7c2d9ee60d644f81a20830f0b7f1 (diff)
the birth of a unit testing framework
Change-Id: Ibb634bce4db330167b1492bc7ce13f7af53a18c7 Reviewed-by: Jesper K. Pedersen <jesper.pedersen@kdab.com> Reviewed-by: Nicolas Arnaud-Cormos <nicolas@kdab.com>
-rw-r--r--objects/editors.cpp3
-rw-r--r--scripting.pro14
-rw-r--r--scriptrunner.cpp41
-rw-r--r--scriptrunner.h3
-rw-r--r--tests/mark/mark.qs61
-rw-r--r--tests/mark/test.cpp5
-rw-r--r--tests/positions/positions.qs18
-rw-r--r--tests/positions/test.cpp5
-rw-r--r--tests/runtests.qs19
-rw-r--r--tests/test.js53
-rw-r--r--utils/utils.cpp64
-rw-r--r--utils/utils.h56
12 files changed, 332 insertions, 10 deletions
diff --git a/objects/editors.cpp b/objects/editors.cpp
index 85e73c3..17fad9f 100644
--- a/objects/editors.cpp
+++ b/objects/editors.cpp
@@ -40,6 +40,7 @@
#include <coreplugin/idocument.h>
#include <coreplugin/editormanager/ieditor.h>
#include <cpptools/cppmodelmanagerinterface.h>
+#include "scriptrunner.h"
using namespace Scripting;
using namespace Scripting::Internal;
@@ -84,7 +85,7 @@ QStringList Editors::existingEditors()
Editor *Editors::openFile(const QString &fileName)
{
- Core::IEditor* editor = Core::EditorManager::instance()->openEditor(fileName);
+ Core::IEditor* editor = Core::EditorManager::instance()->openEditor(ScriptRunner::absolutePath(fileName));
if (editor) {
Editor* wrapper = wrapEditor(editor);
wrapper->waitForInitialized();
diff --git a/scripting.pro b/scripting.pro
index ac421bb..fed3031 100644
--- a/scripting.pro
+++ b/scripting.pro
@@ -22,7 +22,8 @@ SOURCES += scriptingplugin.cpp \
objects/cppfunction.cpp \
objects/cppargument.cpp \
objects/mark.cpp \
- utils/position.cpp
+ utils/position.cpp \
+ utils/utils.cpp
HEADERS += scriptingplugin.h \
scripting_global.h \
@@ -44,7 +45,8 @@ HEADERS += scriptingplugin.h \
objects/cppfunction.h \
objects/cppargument.h \
objects/mark.h \
- utils/position.h
+ utils/position.h \
+ utils/utils.h
# Qt Creator linking
@@ -69,7 +71,13 @@ PROVIDER = KDAB
include($$QTCREATOR_SOURCES/src/qtcreatorplugin.pri)
OTHER_FILES += \
- examples/*
+ examples/* \
+ tests/mark/test.cpp \
+ tests/mark/mark.qs \
+ tests/runtests.qs \
+ tests/positions/test.cpp \
+ tests/positions/positions.qs \
+ tests/test.js
diff --git a/scriptrunner.cpp b/scriptrunner.cpp
index 44a34fa..7f8d8ac 100644
--- a/scriptrunner.cpp
+++ b/scriptrunner.cpp
@@ -51,23 +51,32 @@
#include <utils/outputformat.h>
#include <QFileInfo>
#include "objects/mark.h"
+#include "utils/utils.h"
using namespace Scripting;
using namespace Scripting::Internal;
+namespace {
+ QString rootDir;
+}
+
+ScriptRunner* ScriptRunner::m_instance = 0;
ScriptRunner::ScriptRunner(QObject *parent) :
QObject(parent),
m_engine(0)
{
+ m_instance = this;
}
-ScriptRunner::~ScriptRunner()
+ScriptRunner *ScriptRunner::instance()
{
+ return m_instance;
}
-// Path to the topmost script loaded.
-static QString currentPath;
+ScriptRunner::~ScriptRunner()
+{
+}
// The backtrace does unfortunately not include the file in which an error occurred,
// we therefore need this variable to store this information.
@@ -108,8 +117,14 @@ static QScriptValue run(QScriptEngine* engine, const QString& fileName, bool rec
static QScriptValue load(QScriptContext *context, QScriptEngine *engine)
{
QScriptValue callee = context->callee();
- if (context->argumentCount() == 1)
- return run(engine, currentPath + QLatin1String("/") + context->argument(0).toString(), true);
+ if (context->argumentCount() == 1) {
+ QString oldRoot = rootDir;
+ QString path = rootDir + QLatin1String("/") + context->argument(0).toString();
+ rootDir = QFileInfo(path).absolutePath();
+ const QScriptValue result = run(engine, path, true);
+ rootDir = oldRoot;
+ return result;
+ }
else
context->throwError(QObject::tr("Wrong number of arguments given to import"));
return QScriptValue();
@@ -118,7 +133,7 @@ static QScriptValue load(QScriptContext *context, QScriptEngine *engine)
ErrorMessage ScriptRunner::runScript(const QString fileName)
{
errorFileName = QString();
- currentPath = QFileInfo(fileName).absolutePath();
+ rootDir = QFileInfo(fileName).absolutePath();
ensureEngineInitialized();
// Ensure no polution of environment between script runs
@@ -140,6 +155,19 @@ ErrorMessage ScriptRunner::runScript(const QString fileName)
return ErrorMessage();
}
+/**
+ @brief Convert a relative path to an absolute path relative to the loaded scripts direcotry
+
+ Relative files referenced in the scripts, should always be relative to the script loaded.
+ */
+QString ScriptRunner::absolutePath(const QString &path)
+{
+ if (QFileInfo(path).isRelative() )
+ return rootDir + QLatin1String("/") + path;
+ else
+ return path;
+}
+
Q_DECLARE_METATYPE(QList<CppArgument*>)
ScriptRunner::QScriptEnginePtr ScriptRunner::ensureEngineInitialized()
@@ -167,6 +195,7 @@ ScriptRunner::QScriptEnginePtr ScriptRunner::ensureEngineInitialized()
registerGlobal(new Console, QLatin1String("console"));
registerGlobal(new Editors, QLatin1String("editors"));
registerGlobal(new Dialogs, QLatin1String("dialogs"));
+ registerGlobal(new Utils, QLatin1String("utils"));
registerWrappers(m_engine.data());
registerEnums(m_engine.data());
diff --git a/scriptrunner.h b/scriptrunner.h
index 86dea44..c26eefb 100644
--- a/scriptrunner.h
+++ b/scriptrunner.h
@@ -64,12 +64,14 @@ public:
typedef QSharedPointer<QScriptEngine> QScriptEnginePtr;
explicit ScriptRunner(QObject *parent = 0);
+ static ScriptRunner* instance();
virtual ~ScriptRunner();
// Run a script
ErrorMessage runScript(const QString fileName);
QScriptEnginePtr scriptEngine() { return ensureEngineInitialized(); }
+ static QString absolutePath(const QString& path);
private:
QScriptEnginePtr ensureEngineInitialized();
@@ -77,6 +79,7 @@ private:
private:
QScriptEnginePtr m_engine;
+ static ScriptRunner* m_instance;
};
} // namespace Internal
diff --git a/tests/mark/mark.qs b/tests/mark/mark.qs
new file mode 100644
index 0000000..1c2521a
--- /dev/null
+++ b/tests/mark/mark.qs
@@ -0,0 +1,61 @@
+include("../test.js")
+
+markMove()
+markStays()
+markMoveOnPrevChar()
+markStaysOnNextChar()
+
+function findYay(editor) {
+ editor.gotoLine(1,0)
+ editor.find("yay")
+}
+
+function markMove() {
+ var editor = editors.openFile("test.cpp")
+ findYay(editor)
+ var mark = editor.createMark()
+ editor.gotoLine(1,0)
+ editor.insert("Hello World\n")
+ findYay(editor)
+ comparePositions(editor.position(),mark, "ensure mark moves on new lines")
+ editor.close()
+}
+
+function markStays() {
+ var editor = editors.openFile("test.cpp")
+ findYay(editor)
+ var mark = editor.createMark()
+ editor.gotoLineEnd()
+ editor.insert("Hello world")
+ findYay(editor)
+ comparePositions(editor.position(),mark, "ensure mark stays when inserting after the mark")
+ editor.close()
+}
+
+function markMoveOnPrevChar() {
+ var editor = editors.openFile("test.cpp")
+ findYay(editor)
+ var mark = editor.createMark()
+ var pos = editor.position()
+ editor.gotoPreviousCharacter(3)
+ editor.insert("WOW")
+ findYay(editor)
+ comparePositions(editor.position(),mark, "ensure mark moves on insert at prev character")
+ compare(mark.line,pos.line)
+ compare(mark.column, pos.column+3)
+ editor.close()
+}
+
+function markStaysOnNextChar() {
+ var editor = editors.openFile("test.cpp")
+ findYay(editor)
+ var mark = editor.createMark()
+ var pos = editor.position()
+ editor.insert("WOW")
+ findYay(editor)
+ comparePositions(editor.position(),mark, "ensure mark stays the same when inserting after point")
+ compare(mark.line,pos.line)
+ compare(mark.column, pos.column)
+ editor.close()
+
+}
diff --git a/tests/mark/test.cpp b/tests/mark/test.cpp
new file mode 100644
index 0000000..4304ec5
--- /dev/null
+++ b/tests/mark/test.cpp
@@ -0,0 +1,5 @@
+class Foo {
+ void bar() {
+ qDebug("yay");
+ }
+};
diff --git a/tests/positions/positions.qs b/tests/positions/positions.qs
new file mode 100644
index 0000000..13d7955
--- /dev/null
+++ b/tests/positions/positions.qs
@@ -0,0 +1,18 @@
+include("../test.js")
+
+var editor = editors.openFile("test.cpp")
+
+editor.gotoLine(1,0)
+verifyPosition(1,0, "beginning of file")
+
+editor.gotoLineEnd()
+verifyPosition(1,11, "end of line")
+
+editor.gotoLineStart()
+verifyPosition(1,0, "start of line")
+
+editor.gotoLineEnd()
+editor.gotoBlockEnd()
+verifyPosition(5,1, "end of block")
+
+editor.close()
diff --git a/tests/positions/test.cpp b/tests/positions/test.cpp
new file mode 100644
index 0000000..4304ec5
--- /dev/null
+++ b/tests/positions/test.cpp
@@ -0,0 +1,5 @@
+class Foo {
+ void bar() {
+ qDebug("yay");
+ }
+};
diff --git a/tests/runtests.qs b/tests/runtests.qs
new file mode 100644
index 0000000..9d74e00
--- /dev/null
+++ b/tests/runtests.qs
@@ -0,0 +1,19 @@
+include("test.js")
+//-------------------- Main --------------------
+
+tests = utils.subDirectories(".")
+for (var i = 0; i < tests.length; i++) {
+ runTest(tests[i])
+}
+
+if ( errorCount == 0)
+ console.log("There were no errors")
+else
+ console.log("+++++++++ There were " + errorCount + " error(s) ++++++++++")
+
+
+function runTest(name) {
+ console.log("Running test " + name)
+ include(name+"/" + name + ".qs")
+}
+
diff --git a/tests/test.js b/tests/test.js
new file mode 100644
index 0000000..5202f5c
--- /dev/null
+++ b/tests/test.js
@@ -0,0 +1,53 @@
+var TEST_JS_LOADED // Purposfully left undefined - this is to avoid the global variables being loaded more than once
+if (TEST_JS_LOADED == undefined) {
+ TEST_JS_LOADED = true
+ // Set to true to print out every single comparison
+ var verbose = false
+
+ // Set to true to "break" on the first error
+ var haltOnError = false
+
+ var errorCount = 0
+
+ function error(message) {
+ console.log("+++ " + message)
+ printBackTrace()
+ errorCount++
+ if ( haltOnError )
+ throw "error"
+ }
+
+ function printBackTrace() {
+ var bt = utils.backtrace()
+ // We start at 3, so we don't show backtrakce(), printBackTrace() and error()
+ for ( var i=3;i<bt.length;i++) {
+ console.log("\t" + bt[i])
+ }
+ }
+
+ function compare(act, exp, message) {
+ if ( verbose ) {
+ if ( message != undefined )
+ console.log("comparing(" + message + ") " + act + " with " + exp)
+ else
+ console.log("comparing " + act + " with " + exp)
+ }
+ if (act != exp) {
+ if ( message != undefined )
+ error("Compare failed (" + message +"): actual=" + act + " expected=" + exp)
+ else
+ error("Compare failed: actual=" + act + " expected=" + exp)
+ }
+ }
+
+ function comparePositions(act, exp, message) {
+ compare(act.line, exp.line, message)
+ compare(act.column, exp.column, message)
+ }
+
+ function verifyPosition(line,column, message) {
+ compare(editor.currentLine(), line, message)
+ compare(editor.currentColumn(), column, message)
+ }
+
+}
diff --git a/utils/utils.cpp b/utils/utils.cpp
new file mode 100644
index 0000000..8ecf7ca
--- /dev/null
+++ b/utils/utils.cpp
@@ -0,0 +1,64 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (C) 2013 Kläralvdalens Datakonsult AB, a KDAB Group company.
+**
+** Contact: Kläralvdalens Datakonsult AB (info@kdab.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "utils.h"
+#include <QDir>
+#include "scriptrunner.h"
+
+namespace Scripting {
+namespace Internal {
+
+Utils::Utils(QObject *parent) :
+ QObject(parent)
+{
+}
+
+QStringList Utils::subDirectories(const QString &directory) const
+{
+ QDir dir(ScriptRunner::absolutePath(directory));
+ return dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+}
+
+QStringList Utils::backtrace() const
+{
+ QStringList result;
+ foreach ( const QString& str, ScriptRunner::instance()->scriptEngine()->currentContext()->backtrace() ) {
+ // Remove internal calls that is of no use to the script side
+ if ( !str.startsWith(QLatin1String("<")))
+ result.append(QLatin1String("\t") + str);
+ }
+ return result;
+}
+
+
+} // namespace Internal
+} // namespace Scripting
diff --git a/utils/utils.h b/utils/utils.h
new file mode 100644
index 0000000..09044c9
--- /dev/null
+++ b/utils/utils.h
@@ -0,0 +1,56 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (C) 2013 Kläralvdalens Datakonsult AB, a KDAB Group company.
+**
+** Contact: Kläralvdalens Datakonsult AB (info@kdab.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef SCRIPTING_INTERNAL_UTILS_H
+#define SCRIPTING_INTERNAL_UTILS_H
+
+#include <QObject>
+#include <QStringList>
+
+namespace Scripting {
+namespace Internal {
+
+class Utils : public QObject
+{
+ Q_OBJECT
+public:
+ explicit Utils(QObject *parent = 0);
+
+public slots:
+ QStringList subDirectories(const QString& directory) const;
+ QStringList backtrace() const;
+};
+
+} // namespace Internal
+} // namespace Scripting
+
+#endif // SCRIPTING_INTERNAL_UTILS_H