better progress indicator

master
Marc Wäckerlin 7 years ago
parent e527c94918
commit 32f090c2f0
  1. 193
      src/commands.hxx
  2. 2
      src/webrunner.cxx

@ -117,6 +117,9 @@ class Command: public QObject {
log(QString(" FAILED[")+demangle(typeid(e).name())+"]: "+e.what()); log(QString(" FAILED[")+demangle(typeid(e).name())+"]: "+e.what());
throw e; throw e;
} }
virtual int steps(Script* parent) {
return 1;
}
void line(int linenr) { void line(int linenr) {
_line = linenr; _line = linenr;
} }
@ -187,6 +190,8 @@ class Command: public QObject {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100); QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
} }
protected: protected:
std::shared_ptr<Script> subParser(Script* parent, const QStringList& in,
const QString& file, int line, int indent);
bool runScript(Logger& log, Command* parentCommand, bool runScript(Logger& log, Command* parentCommand,
std::shared_ptr<Script> script, std::shared_ptr<Script> script,
Script* parent, QWebFrame* frame, Script* parent, QWebFrame* frame,
@ -204,7 +209,7 @@ class Command: public QObject {
} }
QStringList quotedStrings(QString value, QStringList quotedStrings(QString value,
QString delimiter = " ", QString delimiter = " ",
bool keepDelimiters = false) { bool keepDelimiters = false) const {
QStringList res; QStringList res;
QString quot("'\""); QString quot("'\"");
while (value=value.trimmed(), value.size()) { while (value=value.trimmed(), value.size()) {
@ -222,17 +227,10 @@ class Command: public QObject {
res += value.mid(start, m.capturedStart()-start); res += value.mid(start, m.capturedStart()-start);
value.remove(0, m.capturedEnd()); value.remove(0, m.capturedEnd());
if (keepDelimiters && m.capturedLength()) res+=m.captured().mid(start).trimmed(); if (keepDelimiters && m.capturedLength()) res+=m.captured().mid(start).trimmed();
// std::cout<<"REMOVE: \""<<m.captured()<<"\" 0 - "<<(m.capturedEnd()+start)
// <<" start="<<start<<" pos="<<pos<<std::endl
// <<"REMAINING: \""<<value<<"\""<<std::endl;
} }
// std::cout<<"FOUND"<<std::endl;
// Q_FOREACH(QString tag, res) {
// std::cout<<" - \""<<tag<<"\""<<std::endl;
// }
return res; return res;
} }
QStringList commaSeparatedList(QString value) { QStringList commaSeparatedList(QString value) const {
return quotedStrings(value, ","); return quotedStrings(value, ",");
} }
static QWebElement find(QWebFrame* frame, QString selector, static QWebElement find(QWebFrame* frame, QString selector,
@ -487,12 +485,14 @@ class Script: public QObject {
.replace("&nbsp;", " ").replace("&amp;", "&"); .replace("&nbsp;", " ").replace("&amp;", "&");
} }
public: public:
Script(): _clicktype(JAVASCRIPT_CLICK), _command(0), _screenshots(true), Script():
_defaultTimeout(20) { _step(0), _clicktype(JAVASCRIPT_CLICK), _command(0),
_screenshots(true), _defaultTimeout(20) {
initPrototypes(); initPrototypes();
} }
Script(const Script& o): Script(const Script& o):
QObject(), QObject(),
_step(0),
_prototypes(o._prototypes), _prototypes(o._prototypes),
_script(o._script), _script(o._script),
_command(0), _command(0),
@ -568,8 +568,8 @@ class Script: public QObject {
reset(); reset();
_variables.clear(); _variables.clear();
_rvariables.clear(); _rvariables.clear();
_functions.clear();
_timeout = _defaultTimeout; _timeout = _defaultTimeout;
_step = 0;
_clicktype = JAVASCRIPT_CLICK; _clicktype = JAVASCRIPT_CLICK;
} }
std::shared_ptr<Command> parseLine(QStringList& in, std::shared_ptr<Command> parseLine(QStringList& in,
@ -600,6 +600,7 @@ class Script: public QObject {
throw; throw;
} }
void parse(QStringList in, QString filename, int line = 1, int indent = 0) { void parse(QStringList in, QString filename, int line = 1, int indent = 0) {
_filename = filename;
for (int linenr(0), oldsize(0); for (int linenr(0), oldsize(0);
oldsize=in.size(), in.size(); oldsize=in.size(), in.size();
linenr+=oldsize-in.size()) linenr+=oldsize-in.size())
@ -619,6 +620,7 @@ class Script: public QObject {
QString td = QString(), bool screenshots = true, QString td = QString(), bool screenshots = true,
int maxretries = 0) { int maxretries = 0) {
bool res(true); bool res(true);
_step = 0;
_testsuites = testsuites; _testsuites = testsuites;
_timeout = _defaultTimeout; // defaults to 20s _timeout = _defaultTimeout; // defaults to 20s
_ignoreSignalsUntil.clear(); _ignoreSignalsUntil.clear();
@ -636,10 +638,11 @@ class Script: public QObject {
testsuite.attr("name") = "Unnamed Test Suite"; testsuite.attr("name") = "Unnamed Test Suite";
(*_testsuites)<<testsuite; (*_testsuites)<<testsuite;
} }
int retries(0), back(0), step(0); int retries(0), back(0);
for (auto cmd(_script.begin()); cmd!=_script.end(); ++cmd, ++step) { for (auto cmd(_script.begin()); cmd!=_script.end();
_step+=(*cmd)->steps(this), ++cmd) {
progress(QString("%1:%2").arg((*cmd)->file()).arg((*cmd)->line()), progress(QString("%1:%2").arg((*cmd)->file()).arg((*cmd)->line()),
step, steps()); _step, countSteps());
xml::Node testcase("testcase"); xml::Node testcase("testcase");
try { try {
testcase.attr("classname") = testcase.attr("classname") =
@ -670,8 +673,7 @@ class Script: public QObject {
break; // test is successfully finished break; // test is successfully finished
} }
progress(QString("%1:%2").arg((*cmd)->file()).arg((*cmd)->line()), progress(QString("%1:%2").arg((*cmd)->file()).arg((*cmd)->line()),
step, steps()); _step, countSteps());
} catch (PossibleRetryLoad& e) { } catch (PossibleRetryLoad& e) {
_timer.stop(); _timer.stop();
// timeout may happen during load due to bad internet connection // timeout may happen during load due to bad internet connection
@ -691,13 +693,13 @@ class Script: public QObject {
QUrl url(frame->url()); QUrl url(frame->url());
if ((*cmd)->command()=="expect loadFinished true") { if ((*cmd)->command()=="expect loadFinished true") {
------cmd; ------cmd;
------step; ------_step;
back += 3; back += 3;
_ignoreSignalsUntil = "loadStarted"; _ignoreSignalsUntil = "loadStarted";
frame->load(url); frame->load(url);
} else if ((*cmd)->command()=="expect loadStarted") { } else if ((*cmd)->command()=="expect loadStarted") {
----cmd; ----cmd;
----step; ----_step;
back += 2; back += 2;
_ignoreSignalsUntil = "loadStarted"; _ignoreSignalsUntil = "loadStarted";
frame->page()->triggerAction(QWebPage::Stop); frame->page()->triggerAction(QWebPage::Stop);
@ -706,7 +708,7 @@ class Script: public QObject {
url2.remove("expect urlChanged"); url2.remove("expect urlChanged");
if (url2.size()) url=url2.trimmed(); if (url2.size()) url=url2.trimmed();
----cmd; ----cmd;
----step; ----_step;
back += 2; back += 2;
_ignoreSignalsUntil = "loadStarted"; _ignoreSignalsUntil = "loadStarted";
frame->load(url); frame->load(url);
@ -715,7 +717,7 @@ class Script: public QObject {
url2.remove("expect load"); url2.remove("expect load");
if (url2.size()) url=url2.trimmed(); if (url2.size()) url=url2.trimmed();
----cmd; ----cmd;
----step; ----_step;
back += 2; back += 2;
_ignoreSignalsUntil = "loadStarted"; _ignoreSignalsUntil = "loadStarted";
frame->load(url); frame->load(url);
@ -791,8 +793,11 @@ class Script: public QObject {
QString& cerr() { QString& cerr() {
return _cerr; return _cerr;
} }
int steps() { int countSteps() {
return _script.size(); int res(0);
for (auto cmd(_script.begin()); cmd!=_script.end(); ++cmd)
res += (*cmd)->steps(this);
return res;
} }
bool screenshots() { bool screenshots() {
return _screenshots; return _screenshots;
@ -839,7 +844,7 @@ class Script: public QObject {
QStringList variables() { QStringList variables() {
return _variables.keys(); return _variables.keys();
} }
QString variable(Logger& log, QString name) { QString variable(QString name) {
QMap<QString, QString>::iterator it(_variables.find(name)); QMap<QString, QString>::iterator it(_variables.find(name));
if (it==_variables.end()) error(VariableNotFound(name)); if (it==_variables.end()) error(VariableNotFound(name));
return *it; return *it;
@ -871,7 +876,7 @@ class Script: public QObject {
void function(QString name, std::shared_ptr<Function> f) { void function(QString name, std::shared_ptr<Function> f) {
_functions[name] = f; _functions[name] = f;
} }
std::shared_ptr<Function> function(Logger& log, QString name) { std::shared_ptr<Function> function(QString name) {
QMap<QString, std::shared_ptr<Function> >::iterator QMap<QString, std::shared_ptr<Function> >::iterator
it(_functions.find(name)); it(_functions.find(name));
if (it==_functions.end()) error(FunctionNotFound(name)); if (it==_functions.end()) error(FunctionNotFound(name));
@ -1017,6 +1022,9 @@ class Script: public QObject {
_prototypes[c->tag()] = std::shared_ptr<Command>(c); _prototypes[c->tag()] = std::shared_ptr<Command>(c);
} }
private Q_SLOTS: private Q_SLOTS:
void innerProgress(QString txt, int delta) {
progress(txt, _step+delta, countSteps());
}
void authenticationRequired(QNetworkReply*, QAuthenticator* a) { void authenticationRequired(QNetworkReply*, QAuthenticator* a) {
if (_auth.contains(a->realm())) { if (_auth.contains(a->realm())) {
log("network: login to "+a->realm()); log("network: login to "+a->realm());
@ -1083,6 +1091,7 @@ class Script: public QObject {
Commands _script; Commands _script;
std::queue<Signal> _signals; std::queue<Signal> _signals;
QTimer _timer; QTimer _timer;
int _step;
QSet<QString> _ignores; QSet<QString> _ignores;
QString _cout; QString _cout;
QString _cerr; QString _cerr;
@ -1100,9 +1109,22 @@ class Script: public QObject {
QString _testclass; QString _testclass;
Command* _command; Command* _command;
QString _path; QString _path;
QString _filename;
QMap<QString, AuthRealm> _auth; QMap<QString, AuthRealm> _auth;
}; };
class CommandContainer: public Command {
public:
int steps(Script* parent) {
return countSteps(parent);
}
protected:
virtual int countSteps(Script* parent) const {
return _script->countSteps()+1;
}
std::shared_ptr<Script> _script;
};
class Do: public Command { class Do: public Command {
public: public:
QString tag() const { QString tag() const {
@ -2083,7 +2105,7 @@ class SetValue: public Command {
QString _value; QString _value;
}; };
class Function: public Command { class Function: public CommandContainer {
public: public:
QString tag() const { QString tag() const {
return "function"; return "function";
@ -2115,8 +2137,7 @@ class Function: public Command {
cmd->_name = allargs.takeFirst().trimmed(); cmd->_name = allargs.takeFirst().trimmed();
cmd->_vars = commaSeparatedList(allargs.join(' ')); cmd->_vars = commaSeparatedList(allargs.join(' '));
script->function(cmd->_name, cmd); script->function(cmd->_name, cmd);
cmd->_script = std::shared_ptr<Script>(new Script); cmd->_script = cmd->subParser(script, subCommandBlock(in), file, line, indent);
cmd->_script->parse(subCommandBlock(in), file, line+1, indent+1);
return cmd; return cmd;
} }
bool execute(Script* script, QWebFrame*) { bool execute(Script* script, QWebFrame*) {
@ -2134,7 +2155,6 @@ class Function: public Command {
private: private:
QString _name; QString _name;
QStringList _vars; QStringList _vars;
std::shared_ptr<Script> _script;
}; };
class Call: public Command { class Call: public Command {
@ -2165,15 +2185,18 @@ class Call: public Command {
} }
bool execute(Script* script, QWebFrame* frame) { bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script); Logger log(this, script);
return script->function(log, _name)->call(log, this, script->replacevars(_args), return script->function(_name)->call(log, this, script->replacevars(_args),
script, frame); script, frame);
} }
int steps(Script* parent) {
return parent->function(_name)->steps(parent);
}
public: public:
QString _name; QString _name;
QStringList _args; QStringList _args;
}; };
class If: public Command { class If: public CommandContainer {
public: public:
QString tag() const { QString tag() const {
return "if"; return "if";
@ -2213,7 +2236,7 @@ class If: public Command {
return tag()+" "+_variable+" "+_cmp+" "+_value return tag()+" "+_variable+" "+_cmp+" "+_value
+(_script.get()?"\n "+_script->print().join("\n "):""); +(_script.get()?"\n "+_script->print().join("\n "):"");
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script* script, QString args,
QStringList& in, QString file, int line, QStringList& in, QString file, int line,
int indent) { int indent) {
std::shared_ptr<If> cmd(new If()); std::shared_ptr<If> cmd(new If());
@ -2229,12 +2252,10 @@ class If: public Command {
} }
cmd->_variable = args.left(pos).trimmed(); cmd->_variable = args.left(pos).trimmed();
cmd->_value = args.mid(pos+len).trimmed(); cmd->_value = args.mid(pos+len).trimmed();
cmd->_script = std::shared_ptr<Script>(new Script); cmd->_script = cmd->subParser(script, subCommandBlock(in), file, line, indent);
cmd->_script->parse(subCommandBlock(in), file, line+1, indent+1);
if (in.size() && in.first().contains(QRegularExpression("^ *else *$"))) { if (in.size() && in.first().contains(QRegularExpression("^ *else *$"))) {
in.removeFirst(); in.removeFirst();
cmd->_else = std::shared_ptr<Script>(new Script); cmd->_else = cmd->subParser(script, subCommandBlock(in), file, line, indent);
cmd->_else->parse(subCommandBlock(in), file, line+1, indent+1);
} }
return cmd; return cmd;
} }
@ -2256,35 +2277,39 @@ class If: public Command {
+selector+" "+_cmp+" "+value); +selector+" "+_cmp+" "+value);
} else { } else {
switch (_cmp[0].toLatin1()) { switch (_cmp[0].toLatin1()) {
case '=': check = script->variable(log, _variable)==value; case '=': check = script->variable(_variable)==value;
break; break;
case '!': check = script->variable(log, _variable)!=value; case '!': check = script->variable(_variable)!=value;
break; break;
case '.': check = script->variable(log, _variable).contains(value); case '.': check = script->variable(_variable).contains(value);
break; break;
case '^': check = !script->variable(log, _variable).contains(value); case '^': check = !script->variable(_variable).contains(value);
break; break;
case '~': check = case '~': check =
script->variable(log, _variable).contains(QRegularExpression(value)); script->variable(_variable).contains(QRegularExpression(value));
break; break;
case '<': check = script->variable(log, _variable).toInt()<value.toInt(); case '<': check = script->variable(_variable).toInt()<value.toInt();
break; break;
case '>': check = script->variable(log, _variable).toInt()>value.toInt(); case '>': check = script->variable(_variable).toInt()>value.toInt();
break; break;
default:; default:;
} }
log(QString("evaluated expression to ")+(check?"true":"false")+": " log(QString("evaluated expression to ")+(check?"true":"false")+": "
+script->variable(log, _variable)+" "+_cmp+" "+value); +script->variable(_variable)+" "+_cmp+" "+value);
} }
if (check) return runScript(log, this, _script, script, frame); if (check) return runScript(log, this, _script, script, frame);
else if (_else) return runScript(log, this, _else, script, frame); else if (_else) return runScript(log, this, _else, script, frame);
return true; return true;
} }
protected:
int countSteps(Script* parent) {
int res1(CommandContainer::countSteps(parent)), res2(_else->countSteps()+1);
return res1 > res2 ? res1 : res2;
}
private: private:
QString _variable; QString _variable;
QString _cmp; QString _cmp;
QString _value; QString _value;
std::shared_ptr<Script> _script;
std::shared_ptr<Script> _else; std::shared_ptr<Script> _else;
}; };
@ -2428,7 +2453,7 @@ class Check: public Command {
std::shared_ptr<Command> _next; std::shared_ptr<Command> _next;
}; };
class For: public Command { class For: public CommandContainer {
public: public:
QString tag() const { QString tag() const {
return "for"; return "for";
@ -2452,29 +2477,35 @@ class For: public Command {
QString command() const { QString command() const {
return tag()+" "+_variable+" "+_vals.join(" "); return tag()+" "+_variable+" "+_vals.join(" ");
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script* script, QString args,
QStringList& in, QString file, int line, int indent) { QStringList& in, QString file, int line, int indent) {
std::shared_ptr<For> cmd(new For()); std::shared_ptr<For> cmd(new For());
if (!args.size()) throw BadArgument(tag()+" requires a <variable>"); if (!args.size()) throw BadArgument(tag()+" requires a <variable>");
QStringList allargs(args.split("->")); QStringList allargs(args.split("->"));
cmd->_variable = allargs.takeFirst().trimmed(); cmd->_variable = allargs.takeFirst().trimmed();
cmd->_vals = commaSeparatedList(allargs.join("->")); cmd->_vals = commaSeparatedList(allargs.join("->"));
cmd->_script = std::shared_ptr<Script>(new Script); cmd->_script = cmd->subParser(script, subCommandBlock(in), file, line, indent);
cmd->_script->parse(subCommandBlock(in), file, line+1, indent+1);
return cmd; return cmd;
} }
bool execute(Script* script, QWebFrame* frame) { bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script); Logger log(this, script);
Q_FOREACH(QString i, _vals.size()?_vals:commaSeparatedList(script->variable(log, _variable))) { Q_FOREACH(QString i, _vals.size()?_vals:commaSeparatedList(script->variable(_variable))) {
if (!runScript(log, this, _script, script, frame, QStringList()<<_variable, QStringList()<<i)) if (!runScript(log, this, _script, script, frame, QStringList()<<_variable, QStringList()<<i))
return false; return false;
} }
return true; return true;
} }
int countSteps(Script* parent) const {
int sz(1);
if (_vals.size())
sz = _vals.size();
else if (parent->variables().contains(_variable))
sz = commaSeparatedList(parent->variable(_variable)).size();
return (sz?sz:1)*CommandContainer::countSteps(parent);
}
private: private:
QString _variable; QString _variable;
QStringList _vals; QStringList _vals;
std::shared_ptr<Script> _script;
}; };
class Echo: public Command { class Echo: public Command {
@ -2575,7 +2606,7 @@ class ClearCookies: public Command {
QString _url; QString _url;
}; };
class Include: public Command { class Include: public CommandContainer {
public: public:
QString tag() const { QString tag() const {
return "include"; return "include";
@ -2597,11 +2628,12 @@ class Include: public Command {
if (!f.open(QIODevice::ReadOnly)) throw OpenIncludeFailed(cmd->_filename); if (!f.open(QIODevice::ReadOnly)) throw OpenIncludeFailed(cmd->_filename);
QString txt(QString::fromUtf8(f.readAll())); QString txt(QString::fromUtf8(f.readAll()));
try { try {
cmd->_script = std::shared_ptr<Script>(new Script); cmd->_script = cmd->subParser(script, txt.split('\n'), cmd->_filename, 0, indent);
cmd->_script->parse(txt.split('\n'), cmd->_filename, 1, indent+1);
} catch (Exception& e) { } catch (Exception& e) {
throw ParseIncludeFailed(cmd->_filename, e.what()); throw ParseIncludeFailed(cmd->_filename, e.what());
} }
Q_FOREACH(QString key, cmd->_script->functions()) // copy new functions to parent
script->function(key, cmd->_script->function(key));
return cmd; return cmd;
} }
bool execute(Script* script, QWebFrame* frame) { bool execute(Script* script, QWebFrame* frame) {
@ -2614,7 +2646,6 @@ class Include: public Command {
} }
private: private:
QString _filename; QString _filename;
std::shared_ptr<Script> _script;
}; };
class Case: public Command { class Case: public Command {
@ -2670,7 +2701,7 @@ class Case: public Command {
} }
return tag()+" "+_variable+body; return tag()+" "+_variable+body;
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script* script, QString args,
QStringList& in, QString file, int line, QStringList& in, QString file, int line,
int indent) { int indent) {
std::shared_ptr<Case> cmd(new Case()); std::shared_ptr<Case> cmd(new Case());
@ -2684,9 +2715,9 @@ class Case: public Command {
QString value(parts.join(' ')); QString value(parts.join(' '));
if (!cmp.contains(QRegularExpression("^[=!.^~<>]|->|default$"))) if (!cmp.contains(QRegularExpression("^[=!.^~<>]|->|default$")))
throw BadArgument(tag()+" needs a comparision, not: "+cmp); throw BadArgument(tag()+" needs a comparision, not: "+cmp);
std::shared_ptr<Script> script(std::shared_ptr<Script>(new Script)); std::shared_ptr<Script> sub
script->parse(subCommandBlock(body), file, line+1, indent+2); (cmd->subParser(script, subCommandBlock(body), file, line, indent+1));
cmd->_conditions.append(Condition(cmp, value, script)); cmd->_conditions.append(Condition(cmp, value, sub));
} }
return cmd; return cmd;
} }
@ -2712,31 +2743,39 @@ class Case: public Command {
+selector+" "+condition.cmp+" "+value); +selector+" "+condition.cmp+" "+value);
} else { } else {
switch (condition.cmp[0].toLatin1()) { switch (condition.cmp[0].toLatin1()) {
case '=': check = script->variable(log, _variable)==value; case '=': check = script->variable(_variable)==value;
break; break;
case '!': check = script->variable(log, _variable)!=value; case '!': check = script->variable(_variable)!=value;
break; break;
case '.': check = script->variable(log, _variable).contains(value); case '.': check = script->variable(_variable).contains(value);
break; break;
case '^': check = !script->variable(log, _variable).contains(value); case '^': check = !script->variable(_variable).contains(value);
break; break;
case '~': check = case '~': check =
script->variable(log, _variable).contains(QRegularExpression(value)); script->variable(_variable).contains(QRegularExpression(value));
break; break;
case '<': check = script->variable(log, _variable).toInt()<value.toInt(); case '<': check = script->variable(_variable).toInt()<value.toInt();
break; break;
case '>': check = script->variable(log, _variable).toInt()>value.toInt(); case '>': check = script->variable(_variable).toInt()>value.toInt();
break; break;
default:; default:;
} }
log(QString("evaluated expression to ")+(check?"true":"false")+": " log(QString("evaluated expression to ")+(check?"true":"false")+": "
+script->variable(log, _variable)+" "+condition.cmp+" "+value); +script->variable(_variable)+" "+condition.cmp+" "+value);
} }
if (check) return runScript(log, this, condition.script, script, frame); if (check) return runScript(log, this, condition.script, script, frame);
} }
return true; return true;
} }
private: private:
int countSteps(Script* parent) {
int res1(0);
for (auto condition: _conditions) {
int res2(condition.script->countSteps()+1);
if (res2>res1) res1=res2;
}
return res1;
}
struct Condition { struct Condition {
Condition(QString c, QString v, std::shared_ptr<Script> s): Condition(QString c, QString v, std::shared_ptr<Script> s):
cmp(c), value(v), script(s) { cmp(c), value(v), script(s) {
@ -2888,6 +2927,16 @@ inline Logger::~Logger() {
} }
} }
inline std::shared_ptr<Script> Command::subParser(Script* parent, const QStringList& in,
const QString& file,
int line, int indent) {
std::shared_ptr<Script> res(new Script);
Q_FOREACH(QString key, parent->functions()) // copy functions from parent
res->function(key, parent->function(key));
res->parse(in, file, line+1, indent+1);
return res;
}
inline bool Command::runScript(Logger& log, Command* parentCommand, inline bool Command::runScript(Logger& log, Command* parentCommand,
std::shared_ptr<Script> script, std::shared_ptr<Script> script,
Script* parent, QWebFrame* frame, Script* parent, QWebFrame* frame,
@ -2906,21 +2955,25 @@ inline bool Command::runScript(Logger& log, Command* parentCommand,
try { try {
assert(connect(&scriptCopy, SIGNAL(logging(QString)), assert(connect(&scriptCopy, SIGNAL(logging(QString)),
parent, SLOT(parentlog(QString)))); parent, SLOT(parentlog(QString))));
assert(connect(&scriptCopy, SIGNAL(progress(QString, int, int)),
parent, SLOT(innerProgress(QString, int))));
parent->removeSignals(frame); parent->removeSignals(frame);
bool res(scriptCopy.run(frame)); bool res(scriptCopy.run(frame));
parent->addSignals(frame); parent->addSignals(frame);
disconnect(&scriptCopy, SIGNAL(progress(QString, int, int)),
parent, SLOT(innerProgress(QString, int)));
disconnect(&scriptCopy, SIGNAL(logging(QString)), disconnect(&scriptCopy, SIGNAL(logging(QString)),
parent, SLOT(parentlog(QString))); parent, SLOT(parentlog(QString)));
parentCommand->_result = scriptCopy.result(); parentCommand->_result = scriptCopy.result();
Q_FOREACH(QString key, scriptCopy.variables()) // copy new variables to parent Q_FOREACH(QString key, scriptCopy.variables()) // copy new variables to parent
if (!vars.contains(key)) parent->set(key, scriptCopy.variable(log, key)); if (!vars.contains(key)) parent->set(key, scriptCopy.variable(key));
Q_FOREACH(QString key, scriptCopy.functions()) // copy new functions to parent
parent->function(key, scriptCopy.function(log, key));
if (parentCommand->_result.size()) if (parentCommand->_result.size())
parent->log("result: "+parentCommand->_result); parent->log("result: "+parentCommand->_result);
return res; return res;
} catch (const Exception& x) { } catch (const Exception& x) {
parent->addSignals(frame); parent->addSignals(frame);
disconnect(&scriptCopy, SIGNAL(progress(QString, int, int)),
parent, SLOT(innerProgress(QString, int)));
disconnect(&scriptCopy, SIGNAL(logging(QString)), disconnect(&scriptCopy, SIGNAL(logging(QString)),
parent, SLOT(parentlog(QString))); parent, SLOT(parentlog(QString)));
throw; throw;

@ -174,7 +174,7 @@ int main(int argc, char *argv[]) try {
testcase.attr("name") = "parse test suite file"; testcase.attr("name") = "parse test suite file";
testsuite<<testcase; testsuite<<testcase;
script.parse(txt.split('\n'), file); script.parse(txt.split('\n'), file);
expectedtestcases = script.steps()+2; expectedtestcases = script.countSteps()+2;
if (failed) { if (failed) {
script.log("FAILED: "+file+" skipped due to previous error"); script.log("FAILED: "+file+" skipped due to previous error");
testcase.attr("name") = "testsuite"; testcase.attr("name") = "testsuite";

Loading…
Cancel
Save