summaryrefslogtreecommitdiffstats
path: root/src/interpreter/runner/scripts/QstRunner.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/interpreter/runner/scripts/QstRunner.js')
-rw-r--r--src/interpreter/runner/scripts/QstRunner.js358
1 files changed, 358 insertions, 0 deletions
diff --git a/src/interpreter/runner/scripts/QstRunner.js b/src/interpreter/runner/scripts/QstRunner.js
new file mode 100644
index 0000000..da34bc6
--- /dev/null
+++ b/src/interpreter/runner/scripts/QstRunner.js
@@ -0,0 +1,358 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of QtSystemTest.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+.pragma library
+
+var create = function(Core){
+// import to this namespace
+var
+ InternalError = 1<<6,
+ Console = Core.Console,
+ Class = Core.Class,
+ Js = Core.Js,
+ Qtt = Core.Qtt,
+ runner,
+ Topic = Console.topic('Runner')
+;
+
+function relevantStack(e){
+ relevantStack.currentFile = relevantStack.currentFile
+ || Js.Engine.currentFile();
+
+ Topic.debug('Runner: file: ', relevantStack.currentFile);
+ var filtered = [];
+ e.stack.some(function(callSite) {
+ var hasReachedRunner = callSite.fileName === relevantStack.currentFile;
+ if (!hasReachedRunner) {
+ filtered.push(callSite);
+ }
+ return hasReachedRunner;
+ });
+ return (e instanceof Qtt.Error)
+ ? filtered
+ : filtered.length > 0 ? filtered
+ : e.stack;
+}
+
+var AbstractTestRunner = Class.create(function(item) {
+ var Topic = Console.topic('Runner').topic('AbstractTestRunner');
+
+ function validate(fnName, config){
+ config = config || { }
+ config.mustExist = config.mustExist === undefined ? true : config.mustExist;
+
+ if ( !(fnName in item) ) {
+ if (config.mustExist === true) {
+ throw new ReferenceError( 'Missing mandatory property or function "'
+ + fnName + '" in test item (Name:' + item.name + ')')
+ }
+ Topic.debug('Name: ', fnName, ' is missing, but ok to ignore' );
+ return {ok: true, exists : false};
+ }
+
+ var m = item[fnName];
+ if (typeof (m) !== 'function') {
+ throw new TypeError(fnName + ' not a function');
+ }
+ return {ok: true, exists : true};
+ }
+
+ function exec() {
+ var Topic = Console.topic('Runner').topic('exec');
+ Topic.debug( 'Running .............', item);
+
+ // skip disabled items
+ var result = true;
+ if (item.enabled === false) {
+ Topic.debug(item, 'is disabled ');
+ return result;
+ }
+
+ this.start();
+ runner.currentTestItem = item;
+ try {
+ var ok = invokeSetup.call(this);
+ if (ok) {
+ this.run();
+ }
+ } catch (e) {
+ /// FIXME: Qt5, remove this as e.stack *can be* enabled by default
+ e.__addStack(1);
+ this.setStatus(Qtt.Status.Failed);
+ console.log("Internal error: ", e.status || 'JsError', e.message);
+ ok = false;
+ e.stack.forEach( function(s) {
+ console.log(s.fileName, ': ', s.lineNumber, ' : ', s.functionName); });
+
+ var error = {
+ message: e.message,
+ stack: relevantStack(e),
+ formatted: e.formatted,
+ meta: e.meta
+ };
+ runner.logEvent(e.status || 'JsError', error);
+ throw e;
+ } finally {
+ invokeCleanup.call(this);
+ this.end();
+ }
+ }
+
+
+ function invokeSetup() {
+ var Topic = Console.topic('AbstractTestRunner').topic('invokeSetup');
+
+ Topic.debug( 'validating setup');
+ var setup = 'setup';
+ var result = validate(setup, {mustExist: false});
+ if ( result.ok && result.exists === false ) {
+ return true;
+ }
+
+ setup = item.setup;
+ var ok = true;
+ try {
+ runner.methodStart(setup.name);
+ runner.currentMethod = setup.name;
+ setup();
+ runner.methodEnd(setup.name);
+ } catch (e) {
+ /// FIXME: Qt5, remove this as e.stack *can be* enabled by default
+ e.__addStack(1);
+ Topic.debug('Exception caught: ', e);
+ ok = false;
+ var status = (e instanceof Qtt.Error)
+ ? Qtt.Status.Untested
+ : Qtt.Status.Failed;
+ var error = {
+ message: e.message,
+ stack: relevantStack(e),
+ formatted: e.formatted,
+ meta: e.meta
+ };
+ runner.logEvent(e.status || 'JsError', error);
+ runner.methodEnd(setup.name);
+ this.setStatus(status);
+ }
+ return ok;
+ }
+
+ // don't throw any errors, just report them and end the cleanup
+ function invokeCleanup() {
+ var Topic = Console.topic('TestRunner').topic('runCleanup');
+
+ var cleanup = 'cleanup';
+ var result = validate(cleanup, {mustExist: false});
+ if ( result.ok && result.exists === false ) {
+ return;
+ }
+
+ cleanup = item.cleanup;
+ runner.methodStart(cleanup.name);
+ runner.currentMethod = cleanup.name;
+
+ try {
+ cleanup();
+ } catch (e) {
+ /// FIXME: Qt5, remove this as e.stack *can be* enabled by default
+ e.__addStack(1);
+ Topic.debug('Exception in cleanup: ', e);
+
+ var error = {
+ message: e.message,
+ stack: e.stack,
+ formatted: e.formatted,
+ meta: e.meta
+ };
+
+ runner.logEvent('WARNING', error);
+ } finally {
+ Topic.debug('run finally - finishing method : cleanup ');
+ runner.methodEnd(cleanup.name);
+ }
+ }
+
+ return {
+ validate: validate,
+ item: function() { return item },
+ exec: exec,
+ start: function() { throw new Error('Must override start')},
+ run: function() { throw new Error('Must override run')},
+ end: function() { throw new Error('Must override end')},
+ setStatus: function() { throw new Error('Must override setStatus')},
+ };
+});
+
+var TestRunner = AbstractTestRunner.extend(function(item) {
+ this._super(item);
+ var Topic = Console.topic('TestRunner').topic('AbstractTestRunner');
+ Topic.debug(' Creating a Test runner for ', item.name);
+
+ function start() { runner.testStart(item); }
+
+ function end() { runner.testEnd(item); }
+
+ function setStatus(status) {
+ Topic.debug('Setting ... ', item.name , ' :', status)
+ item.__status = status;
+ /// FIXME Qt5: change report to var and runner.report[status]++
+ var report = runner.report;
+ report[status]++;
+ runner.report = report;
+ }
+
+ function run() {
+ var Topic = Console.topic('TestRunner').topic('runRun');
+
+ Topic.debug( 'validating run');
+ var run = 'run';
+ var status = Qtt.Status.Failed;
+ try {
+ this.validate(run);
+
+ run = item.run;
+ runner.methodStart(run.name);
+ runner.currentMethod = run.name;
+
+ Topic.debug('Going to run ... run');
+ run();
+ status = Qtt.Status.Passed;
+ } catch (e) {
+ /// FIXME: Qt5, remove this as e.stack *can be* enabled by default
+ e.__addStack(1);
+ status = (e instanceof Qtt.Error)
+ ? e.status
+ : Qtt.Status.Failed;
+ var error = {
+ message: e.message,
+ stack: relevantStack(e),
+ formatted: e.formatted,
+ meta: e.meta
+ };
+ Topic.debug(status, Core.stringify(error));
+ runner.logEvent(status, error);
+ } finally {
+ runner.methodEnd(run.name);
+ this.setStatus(status);
+ }
+ }
+
+ return {
+ start: start,
+ end: end,
+ run: run,
+ setStatus: setStatus
+ };
+});
+
+var TestCollectionRunner = AbstractTestRunner.extend(function(item) {
+ this._super(item);
+
+
+ function start() { runner.testCollectionStart(item); }
+
+ function end() { runner.testCollectionEnd(item); }
+
+
+ function setStatus(status) {
+ // recurse and run the subsets ...
+ var subset = item.children;
+ for (var i = 0; i< subset.length; ++i) {
+ var testItem = subset[i];
+ if ( !testItem.enabled ) {
+ continue;
+ }
+ var tr = runnerForItem(testItem);
+ tr.start();
+ tr.setStatus(status);
+ tr.end();
+ }
+ }
+
+ function run() {
+ // recurse and run the subsets ...
+ var subset = item.__subset;
+ for (var i = 0; i< subset.length; ++i) {
+ var tr = runnerForItem(subset[i]);
+ tr.exec();
+ }
+ }
+
+ return {
+ start: start,
+ end: end,
+ run: run,
+ setStatus: setStatus
+ };
+});
+
+
+function runnerForItem(item) {
+ var Runner = item.__isTest ? TestRunner : TestCollectionRunner;
+ return new Runner(item);
+}
+
+function exec(qmlRunner, item){
+ runner = qmlRunner
+ try {
+ runner.aboutToStartExecution();
+ var tr = runnerForItem(item);
+ tr.exec();
+ runner.finishedExecution();
+
+ var report = runner.report;
+ var result = (report.failed > 0)
+ | (report.skipped > 0) << 1
+ | (report.untested > 0) << 2
+ | (report.error > 0) << 3;
+ } catch (e) {
+ /// FIXME: Qt5, remove this as e.stack *can be* enabled by default
+ e.__addStack(1);
+ result = InternalError;
+ }
+ return result;
+}
+
+ return {
+ exec: exec
+ }
+
+};