improved logging, bugfix in function handling

master
Marc Wäckerlin 9 years ago
parent f4a288f156
commit c191ab9c7a
  1. 209
      src/commands.hxx
  2. 8
      src/exceptions.hxx
  3. 8
      src/testgui.hxx
  4. 2
      src/webrunner.cxx

@ -93,7 +93,7 @@ class Command: public QObject {
virtual QString description() const = 0; virtual QString description() const = 0;
virtual QString command() const = 0; virtual QString command() const = 0;
virtual std::shared_ptr<Command> parse(Script*, QString, virtual std::shared_ptr<Command> parse(Script*, QString,
QStringList&, int) = 0; QStringList&, QString, int) = 0;
virtual bool execute(Script*, QWebFrame*) = 0; virtual bool execute(Script*, QWebFrame*) = 0;
void line(int linenr) { void line(int linenr) {
_line = linenr; _line = linenr;
@ -101,6 +101,12 @@ class Command: public QObject {
int line() const { int line() const {
return _line; return _line;
} }
void file(QString filename) {
_file = filename;
}
QString file() const {
return _file;
}
bool log() { bool log() {
return _log; return _log;
} }
@ -170,10 +176,12 @@ class Command: public QObject {
case '"': case '\'': { case '"': case '\'': {
return value.mid(1, value.size()-2) return value.mid(1, value.size()-2)
.split(QRegularExpression(QString(value[0])+", *" .split(QRegularExpression(QString(value[0])+", *"
+QString(value[0]))); +QString(value[0])),
QString::SkipEmptyParts);
} break; } break;
default: { default: {
return value.split(QRegularExpression(", *")); return value.split(QRegularExpression(", *"),
QString::SkipEmptyParts);
} }
} }
} }
@ -210,6 +218,7 @@ class Command: public QObject {
QString _result; QString _result;
private: private:
int _line; int _line;
QString _file;
}; };
class Empty: public Command { class Empty: public Command {
@ -226,7 +235,8 @@ class Empty: public Command {
QString command() const { QString command() const {
return tag(); return tag();
} }
std::shared_ptr<Command> parse(Script*, QString, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString,
QStringList&, QString, int) {
std::shared_ptr<Empty> cmd(new Empty()); std::shared_ptr<Empty> cmd(new Empty());
return cmd; return cmd;
} }
@ -237,7 +247,7 @@ class Empty: public Command {
class Comment: public Command { class Comment: public Command {
public: public:
Comment(QString line): _line(line) {} Comment(QString comment): _comment(comment) {}
QString tag() const { QString tag() const {
return "#"; return "#";
} }
@ -248,9 +258,10 @@ class Comment: public Command {
"Comments are lines that start with #"; "Comments are lines that start with #";
} }
QString command() const { QString command() const {
return _line; return _comment;
} }
std::shared_ptr<Command> parse(Script*, QString args, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int) {
std::shared_ptr<Comment> cmd(new Comment(args)); std::shared_ptr<Comment> cmd(new Comment(args));
return cmd; return cmd;
} }
@ -259,7 +270,7 @@ class Comment: public Command {
return true; return true;
} }
private: private:
QString _line; QString _comment;
}; };
class Screenshot: public Command { class Screenshot: public Command {
@ -321,7 +332,8 @@ class Screenshot: public Command {
QString command() const { QString command() const {
return tag()+" "+_filename; return tag()+" "+_filename;
} }
std::shared_ptr<Command> parse(Script*, QString args, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int) {
std::shared_ptr<Screenshot> cmd(new Screenshot()); std::shared_ptr<Screenshot> cmd(new Screenshot());
cmd->_filename = args; cmd->_filename = args;
return cmd; return cmd;
@ -399,6 +411,12 @@ class Script: public QObject {
} }
}; };
public: public:
Script(const Script& o):
QObject(),
_prototypes(o._prototypes),
_script(o._script) {
set(o);
}
static QString xmlattr(QString attr, bool br = false) { static QString xmlattr(QString attr, bool br = false) {
attr.replace("&", "&amp;")//.replace(" ", "&nbsp;") attr.replace("&", "&amp;")//.replace(" ", "&nbsp;")
.replace("\"", "&quot;"); .replace("\"", "&quot;");
@ -475,7 +493,9 @@ class Script: public QObject {
_timeout = 20; _timeout = 20;
_clicktype = JAVASCRIPT_CLICK; _clicktype = JAVASCRIPT_CLICK;
} }
std::shared_ptr<Command> parse(QStringList& in, int linenr) try { std::shared_ptr<Command> parseLine(QStringList& in,
QString filename, int linenr) try {
std::shared_ptr<Command> command;
QString line(in.takeFirst().trimmed()); QString line(in.takeFirst().trimmed());
QString cmd(line), args; QString cmd(line), args;
int space(line.indexOf(' ')); int space(line.indexOf(' '));
@ -485,22 +505,23 @@ class Script: public QObject {
} }
Prototypes::const_iterator it(_prototypes.find(cmd)); Prototypes::const_iterator it(_prototypes.find(cmd));
if (it!=_prototypes.end()) { if (it!=_prototypes.end()) {
std::shared_ptr<Command> command(it->second->parse command = it->second->parse(this, args, in, filename, linenr);
(this, args, in, linenr));
command->line(linenr);
return command;
} else { } else {
return unknown(line); command = unknown(line);
} }
command->file(filename);
command->line(linenr);
return command;
} catch (Exception& e) { } catch (Exception& e) {
e.line(linenr); e.line(linenr);
e.file(filename);
throw; throw;
} }
void parse(QStringList in) { void parse(QStringList in, QString filename, int line = 1) {
for (int linenr(1), 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())
_script.push_back(parse(in, linenr)); _script.push_back(parseLine(in, filename, line+linenr));
} }
QStringList print() { QStringList print() {
QStringList result; QStringList result;
@ -628,6 +649,7 @@ class Script: public QObject {
_testsuites->last()<<testcase; _testsuites->last()<<testcase;
removeSignals(frame); removeSignals(frame);
e.line((*cmd)->line()); e.line((*cmd)->line());
e.file((*cmd)->file());
if (screenshots) if (screenshots)
try { // write html source and take a last screenshot on error try { // write html source and take a last screenshot on error
{ {
@ -721,7 +743,7 @@ class Script: public QObject {
_cout.clear(); _cout.clear();
_cerr.clear(); _cerr.clear();
_ignoreSignalsUntil.clear(); _ignoreSignalsUntil.clear();
_functions.clear(); _functions.unite(o._functions);
} }
void unset(QString name) { void unset(QString name) {
_rvariables.remove(_variables[name]); _rvariables.remove(_variables[name]);
@ -824,11 +846,17 @@ class Script: public QObject {
std::cout<<text<<std::endl<<std::flush; std::cout<<text<<std::endl<<std::flush;
_cout += text + "\n"; _cout += text + "\n";
} }
void parentlog(QString text) {
logging(text);
_cout += text + "\n";
}
private: private:
std::shared_ptr<Command> unknown(QString line) { std::shared_ptr<Command> unknown(QString command) {
if (!line.size()) return std::shared_ptr<Command>(new Empty()); if (!command.size())
if (line[0]=='#') return std::shared_ptr<Command>(new Comment(line)); return std::shared_ptr<Command>(new Empty());
throw UnknownCommand(line); // error if (command[0]=='#')
return std::shared_ptr<Command>(new Comment(command));
throw UnknownCommand(command); // error
} }
void initPrototypes(); void initPrototypes();
void add(Command* c) { void add(Command* c) {
@ -851,9 +879,7 @@ class Script: public QObject {
return; return;
} }
_ignoreSignalsUntil.clear(); _ignoreSignalsUntil.clear();
log(".... signal"); log("signal received: loadFinished "+QString(ok?"true":"false"));
log("received loadFinished "+QString(ok?"true":"false"));
log(".....................");
_signals.push(std::make_pair("loadFinished", QStringList(sig))); _signals.push(std::make_pair("loadFinished", QStringList(sig)));
} }
void loadStarted() { void loadStarted() {
@ -862,9 +888,7 @@ class Script: public QObject {
return; return;
} }
_ignoreSignalsUntil.clear(); _ignoreSignalsUntil.clear();
log(".... signal"); log("signal received: loadStarted");
log("received loadStarted");
log(".....................");
_signals.push(std::make_pair("loadStarted", QStringList())); _signals.push(std::make_pair("loadStarted", QStringList()));
} }
void frameChanged() { void frameChanged() {
@ -878,9 +902,7 @@ class Script: public QObject {
return; return;
} }
_ignoreSignalsUntil.clear(); _ignoreSignalsUntil.clear();
log(".... signal"); log("signal received: urlChanged "+url.toString());
log("received urlChanged "+url.toString());
log(".....................");
_signals.push(std::make_pair("urlChanged", _signals.push(std::make_pair("urlChanged",
QStringList(url.toString()))); QStringList(url.toString())));
} }
@ -929,7 +951,7 @@ class Do: public Command {
return tag()+" "+_selector+_javascript; return tag()+" "+_selector+_javascript;
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script*, QString args,
QStringList& in, int) { QStringList& in, QString, int) {
std::shared_ptr<Do> cmd(new Do()); std::shared_ptr<Do> cmd(new Do());
cmd->_selector = args.trimmed(); cmd->_selector = args.trimmed();
cmd->_javascript = subCommandBlock(in).join("\n"); cmd->_javascript = subCommandBlock(in).join("\n");
@ -966,7 +988,8 @@ class Load: public Command {
QString command() const { QString command() const {
return tag()+" "+_url; return tag()+" "+_url;
} }
std::shared_ptr<Command> parse(Script*, QString args, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int) {
std::shared_ptr<Load> cmd(new Load()); std::shared_ptr<Load> cmd(new Load());
cmd->_url = args; cmd->_url = args;
return cmd; return cmd;
@ -1009,7 +1032,8 @@ class Expect: public Command {
return tag()+" "+_signal._signal return tag()+" "+_signal._signal
+(_signal._args.size()?" "+_signal._args.join(' '):QString()); +(_signal._args.size()?" "+_signal._args.join(' '):QString());
} }
std::shared_ptr<Command> parse(Script*, QString args, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int) {
std::shared_ptr<Expect> cmd(new Expect()); std::shared_ptr<Expect> cmd(new Expect());
cmd->_signal._args = args.split(" "); cmd->_signal._args = args.split(" ");
cmd->_signal._signal = cmd->_signal._args.takeFirst(); cmd->_signal._signal = cmd->_signal._args.takeFirst();
@ -1064,7 +1088,8 @@ class Open: public Command {
QString command() const { QString command() const {
return tag(); return tag();
} }
std::shared_ptr<Command> parse(Script*, QString, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString,
QStringList&, QString, int) {
std::shared_ptr<Open> cmd(new Open()); std::shared_ptr<Open> cmd(new Open());
return cmd; return cmd;
} }
@ -1091,7 +1116,8 @@ class Sleep: public Command {
QString command() const { QString command() const {
return tag()+" "+_time; return tag()+" "+_time;
} }
std::shared_ptr<Command> parse(Script*, QString time, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString time,
QStringList&, QString, int) {
std::shared_ptr<Sleep> cmd(new Sleep()); std::shared_ptr<Sleep> cmd(new Sleep());
cmd->_time = "10"; // default: 10s cmd->_time = "10"; // default: 10s
if (time.size()) cmd->_time = time; if (time.size()) cmd->_time = time;
@ -1128,7 +1154,8 @@ class Exit: public Command {
QString command() const { QString command() const {
return tag(); return tag();
} }
std::shared_ptr<Command> parse(Script*, QString, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString,
QStringList&, QString, int) {
std::shared_ptr<Exit> cmd(new Exit()); std::shared_ptr<Exit> cmd(new Exit());
return cmd; return cmd;
} }
@ -1155,7 +1182,8 @@ class IgnoreTo: public Command {
QString command() const { QString command() const {
return tag()+" "+_label; return tag()+" "+_label;
} }
std::shared_ptr<Command> parse(Script*, QString args, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int) {
std::shared_ptr<IgnoreTo> cmd(new IgnoreTo()); std::shared_ptr<IgnoreTo> cmd(new IgnoreTo());
if (!args.size()) throw BadArgument("ignoreto needs a label"); if (!args.size()) throw BadArgument("ignoreto needs a label");
cmd->_label=args; cmd->_label=args;
@ -1184,7 +1212,8 @@ class Label: public Command {
QString command() const { QString command() const {
return tag()+" "+_label; return tag()+" "+_label;
} }
std::shared_ptr<Command> parse(Script*, QString args, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int) {
std::shared_ptr<Label> cmd(new Label()); std::shared_ptr<Label> cmd(new Label());
if (!args.size()) throw BadArgument("label needs a label as parameter"); if (!args.size()) throw BadArgument("label needs a label as parameter");
cmd->_label=args; cmd->_label=args;
@ -1215,7 +1244,8 @@ class Upload: public Command {
QString command() const { QString command() const {
return tag()+" "+_selector+" -> "+_filename; return tag()+" "+_selector+" -> "+_filename;
} }
std::shared_ptr<Command> parse(Script*, QString args, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int) {
std::shared_ptr<Upload> cmd(new Upload()); std::shared_ptr<Upload> cmd(new Upload());
QStringList allargs(args.split("->")); QStringList allargs(args.split("->"));
if (allargs.size()<2) if (allargs.size()<2)
@ -1263,7 +1293,8 @@ class Exists: public Command {
QString command() const { QString command() const {
return tag()+" "+_selector+(_text.size()?" -> "+_text:QString()); return tag()+" "+_selector+(_text.size()?" -> "+_text:QString());
} }
std::shared_ptr<Command> parse(Script*, QString args, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int) {
std::shared_ptr<Exists> cmd(new Exists()); std::shared_ptr<Exists> cmd(new Exists());
QStringList allargs(args.split("->")); QStringList allargs(args.split("->"));
if (allargs.size()<2) { if (allargs.size()<2) {
@ -1315,7 +1346,8 @@ class Not: public Command {
QString command() const { QString command() const {
return tag()+" "+_selector+(_text.size()?" -> "+_text:QString()); return tag()+" "+_selector+(_text.size()?" -> "+_text:QString());
} }
std::shared_ptr<Command> parse(Script*, QString args, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int) {
std::shared_ptr<Not> cmd(new Not()); std::shared_ptr<Not> cmd(new Not());
QStringList allargs(args.split("->")); QStringList allargs(args.split("->"));
if (allargs.size()<2) { if (allargs.size()<2) {
@ -1366,7 +1398,7 @@ class Execute: public Command {
+(script.size()?"\n"+script.join("\n"):QString()); +(script.size()?"\n"+script.join("\n"):QString());
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script*, QString args,
QStringList& in, int) { QStringList& in, QString, int) {
std::shared_ptr<Execute> cmd(new Execute()); std::shared_ptr<Execute> cmd(new Execute());
cmd->_args = args.split(' '); cmd->_args = args.split(' ');
cmd->_command = cmd->_args.takeFirst(); cmd->_command = cmd->_args.takeFirst();
@ -1429,10 +1461,10 @@ class Download: public Command {
+_next->command(); +_next->command();
} }
std::shared_ptr<Command> parse(Script* script, QString args, std::shared_ptr<Command> parse(Script* script, QString args,
QStringList& in, int line) { QStringList& in, QString file, int line) {
std::shared_ptr<Download> cmd(new Download()); std::shared_ptr<Download> cmd(new Download());
cmd->_filename = args.trimmed(); cmd->_filename = args.trimmed();
cmd->_next = script->parse(in, line+1); cmd->_next = script->parseLine(in, file, line+1);
cmd->_next->log(false); // suppress logging of subcommand cmd->_next->log(false); // suppress logging of subcommand
return cmd; return cmd;
} }
@ -1508,7 +1540,8 @@ class Click: public Command {
:*_clicktype==Script::JAVASCRIPT_CLICK?" javascript":"") :*_clicktype==Script::JAVASCRIPT_CLICK?" javascript":"")
:"")+" "+_selector; :"")+" "+_selector;
} }
std::shared_ptr<Command> parse(Script*, QString args, QStringList&, int) { std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int) {
std::shared_ptr<Click> cmd(new Click()); std::shared_ptr<Click> cmd(new Click());
if (args.trimmed().contains(QRegularExpression("^realmouse "))) if (args.trimmed().contains(QRegularExpression("^realmouse ")))
cmd->_clicktype = Script::REAL_MOUSE_CLICK; cmd->_clicktype = Script::REAL_MOUSE_CLICK;
@ -1569,14 +1602,14 @@ class Set: public Command {
return tag()+" "+_name+" = "+_value; return tag()+" "+_name+" = "+_value;
} }
std::shared_ptr<Command> parse(Script* script, QString args, std::shared_ptr<Command> parse(Script* script, QString args,
QStringList& in, int line) { QStringList& in, QString file, int line) {
std::shared_ptr<Set> cmd(new Set()); std::shared_ptr<Set> cmd(new Set());
cmd->_next = 0; cmd->_next = 0;
QStringList allargs(args.split("=")); QStringList allargs(args.split("="));
cmd->_name = allargs.takeFirst().trimmed(); cmd->_name = allargs.takeFirst().trimmed();
cmd->_value = allargs.join("=").trimmed(); cmd->_value = allargs.join("=").trimmed();
if (!args.contains('=')) { if (!args.contains('=')) {
cmd->_next = script->parse(in, line+1); cmd->_next = script->parseLine(in, file, line+1);
cmd->_next->log(false); // suppress logging of subcommand cmd->_next->log(false); // suppress logging of subcommand
} }
return cmd; return cmd;
@ -1614,7 +1647,7 @@ class UnSet: public Command {
return tag()+" "+_name; return tag()+" "+_name;
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, int) { QStringList&, QString, int) {
std::shared_ptr<UnSet> cmd(new UnSet()); std::shared_ptr<UnSet> cmd(new UnSet());
cmd->_name = args; cmd->_name = args;
return cmd; return cmd;
@ -1643,7 +1676,7 @@ class Timeout: public Command {
return tag()+" "+_timeout; return tag()+" "+_timeout;
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, int) { QStringList&, QString, int) {
std::shared_ptr<Timeout> cmd(new Timeout()); std::shared_ptr<Timeout> cmd(new Timeout());
cmd->_timeout = args; cmd->_timeout = args;
return cmd; return cmd;
@ -1676,7 +1709,7 @@ class CaCertificate: public Command {
return tag()+" "+_filename; return tag()+" "+_filename;
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, int) { QStringList&, QString, int) {
std::shared_ptr<CaCertificate> cmd(new (CaCertificate)); std::shared_ptr<CaCertificate> cmd(new (CaCertificate));
cmd->_filename = args.trimmed(); cmd->_filename = args.trimmed();
return cmd; return cmd;
@ -1715,7 +1748,7 @@ class ClientCertificate: public Command {
return tag()+" "+_certfile+" "+_keyfile+" "+_password; return tag()+" "+_certfile+" "+_keyfile+" "+_password;
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, int) { QStringList&, QString, int) {
std::shared_ptr<ClientCertificate> cmd(new (ClientCertificate)); std::shared_ptr<ClientCertificate> cmd(new (ClientCertificate));
QStringList s(args.trimmed().split(' ')); QStringList s(args.trimmed().split(' '));
if (s.size()<3) throw MissingArguments(args, "certfile keyfile password"); if (s.size()<3) throw MissingArguments(args, "certfile keyfile password");
@ -1779,7 +1812,7 @@ class ClickType: public Command {
} }
} }
std::shared_ptr<Command> parse(Script* script, QString args, std::shared_ptr<Command> parse(Script* script, QString args,
QStringList&, int) { QStringList&, QString, int) {
std::shared_ptr<ClickType> cmd(new ClickType()); std::shared_ptr<ClickType> cmd(new ClickType());
QString choice(script->replacevars(args).trimmed()); QString choice(script->replacevars(args).trimmed());
if (choice=="realmouse") if (choice=="realmouse")
@ -1823,7 +1856,7 @@ class SetValue: public Command {
return tag()+" "+_selector+" -> "+_value; return tag()+" "+_selector+" -> "+_value;
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, int) { QStringList&, QString, int) {
std::shared_ptr<SetValue> cmd(new SetValue()); std::shared_ptr<SetValue> cmd(new SetValue());
QStringList allargs(args.split("->")); QStringList allargs(args.split("->"));
if (allargs.size()<2) if (allargs.size()<2)
@ -1887,15 +1920,15 @@ class Function: public Command {
return tag()+" "+_name+" "+_vars.join(" "); return tag()+" "+_name+" "+_vars.join(" ");
} }
std::shared_ptr<Command> parse(Script* script, QString args, std::shared_ptr<Command> parse(Script* script, QString args,
QStringList& in, int) { QStringList& in, QString file, int line) {
std::shared_ptr<Function> cmd(new Function()); std::shared_ptr<Function> cmd(new Function());
if (!args.size()) throw BadArgument(tag()+" requires a <name>"); if (!args.size()) throw BadArgument(tag()+" requires a <name>");
QStringList allargs(args.split(" ")); QStringList allargs(args.split(" ", QString::SkipEmptyParts));
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 = std::shared_ptr<Script>(new Script);
cmd->_script->parse(subCommandBlock(in)); cmd->_script->parse(subCommandBlock(in), file, line+1);
return cmd; return cmd;
} }
bool execute(Script* script, QWebFrame*) { bool execute(Script* script, QWebFrame*) {
@ -1935,10 +1968,10 @@ class Call: public Command {
return tag()+" "+_name+(_args.size()?" '"+_args.join("', '")+"'":""); return tag()+" "+_name+(_args.size()?" '"+_args.join("', '")+"'":"");
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, int) { QStringList&, QString, int) {
std::shared_ptr<Call> cmd(new Call()); std::shared_ptr<Call> cmd(new Call());
if (!args.size()) throw BadArgument(tag()+" requires a <name>"); if (!args.size()) throw BadArgument(tag()+" requires a <name>");
QStringList allargs(args.split(" ")); QStringList allargs(args.split(" ", QString::SkipEmptyParts));
cmd->_name = allargs.takeFirst().trimmed(); cmd->_name = allargs.takeFirst().trimmed();
cmd->_args = commaSeparatedList(allargs.join(' ')); cmd->_args = commaSeparatedList(allargs.join(' '));
return cmd; return cmd;
@ -1980,7 +2013,7 @@ class If: public Command {
+(_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*, QString args,
QStringList& in, int) { QStringList& in, QString file, int line) {
std::shared_ptr<If> cmd(new If()); std::shared_ptr<If> cmd(new If());
int pos(args.indexOf(QRegularExpression("[=^~<>]"))); int pos(args.indexOf(QRegularExpression("[=^~<>]")));
if (pos<0) throw BadArgument(tag()+" needs a comparision, not: "+args); if (pos<0) throw BadArgument(tag()+" needs a comparision, not: "+args);
@ -1988,11 +2021,11 @@ class If: public Command {
cmd->_cmp = args[pos].toLatin1(); cmd->_cmp = args[pos].toLatin1();
cmd->_value = args.mid(pos+1).trimmed(); cmd->_value = args.mid(pos+1).trimmed();
cmd->_script = std::shared_ptr<Script>(new Script); cmd->_script = std::shared_ptr<Script>(new Script);
cmd->_script->parse(subCommandBlock(in)); cmd->_script->parse(subCommandBlock(in), file, line+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 = std::shared_ptr<Script>(new Script);
cmd->_else->parse(subCommandBlock(in)); cmd->_else->parse(subCommandBlock(in), file, line+1);
} }
return cmd; return cmd;
} }
@ -2041,7 +2074,7 @@ class TestSuite: public Command {
return tag()+" "+_name; return tag()+" "+_name;
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, int) { QStringList&, QString, int) {
std::shared_ptr<TestSuite> cmd(new TestSuite()); std::shared_ptr<TestSuite> cmd(new TestSuite());
cmd->_name = args; cmd->_name = args;
return cmd; return cmd;
@ -2070,7 +2103,7 @@ class TestCase: public Command {
return tag()+" "+_name; return tag()+" "+_name;
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, int) { QStringList&, QString, int) {
std::shared_ptr<TestCase> cmd(new TestCase()); std::shared_ptr<TestCase> cmd(new TestCase());
cmd->_name = args; cmd->_name = args;
return cmd; return cmd;
@ -2108,7 +2141,7 @@ class Check: public Command {
return tag()+" "+_value1+" "+QString(_cmp)+" "+_value2; return tag()+" "+_value1+" "+QString(_cmp)+" "+_value2;
} }
std::shared_ptr<Command> parse(Script* script, QString args, std::shared_ptr<Command> parse(Script* script, QString args,
QStringList& in, int line) { QStringList& in, QString file, int line) {
std::shared_ptr<Check> cmd(new Check()); std::shared_ptr<Check> cmd(new Check());
cmd->_next = 0; cmd->_next = 0;
int pos(args.indexOf(QRegularExpression("[=^~<>]"))); int pos(args.indexOf(QRegularExpression("[=^~<>]")));
@ -2117,7 +2150,7 @@ class Check: public Command {
cmd->_cmp = args[pos].toLatin1(); cmd->_cmp = args[pos].toLatin1();
cmd->_value2 = args.mid(pos+1).trimmed(); cmd->_value2 = args.mid(pos+1).trimmed();
if (in.size() && in.first().contains(QRegularExpression("^ "))) { if (in.size() && in.first().contains(QRegularExpression("^ "))) {
cmd->_next = script->parse(in, line+1); cmd->_next = script->parseLine(in, file, line+1);
cmd->_next->log(false); // suppress logging of subcommand cmd->_next->log(false); // suppress logging of subcommand
} }
return cmd; return cmd;
@ -2165,7 +2198,7 @@ class : public Command {
return tag(); return tag();
} }
std::shared_ptr<Command> parse(Script*, QString args, std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, int) { QStringList&, QString, int) {
std::shared_ptr<> cmd(new ()); std::shared_ptr<> cmd(new ());
return cmd; return cmd;
} }
@ -2189,20 +2222,29 @@ inline bool Screenshot::execute(Script* script, QWebFrame* frame) {
inline Logger::Logger(Command* command, Script* script): inline Logger::Logger(Command* command, Script* script):
_command(command), _script(script) { _command(command), _script(script) {
if (_command->log()) { if (_command->log()) {
_script->log("---- line: "+QString::number(_command->line())); _script->log(QString
_script->log(_command->command()); ("%1:%2 \\ %3")
.arg(_command->file()).arg(_command->line())
.arg(_command->command()));
} }
} }
inline void Logger::operator()(QString txt) { inline void Logger::operator()(QString txt) {
if (_command->log()) if (_command->log())
_script->log(txt); _script->log(QString
("%1:%2 %3")
.arg(_command->file()).arg(_command->line())
.arg(txt));
} }
inline void Logger::operator[](QString txt) { inline void Logger::operator[](QString txt) {
_script->plainlog(txt); _script->plainlog(txt);
} }
inline Logger::~Logger() { inline Logger::~Logger() {
if (_command->log()) if (_command->log()) {
_script->log("---------------------"); _script->log(QString
("%1:%2 / %3")
.arg(_command->file()).arg(_command->line())
.arg(_command->command()));
}
} }
inline bool Command::runScript(Command* parentCommand, inline bool Command::runScript(Command* parentCommand,
@ -2210,26 +2252,27 @@ inline bool Command::runScript(Command* parentCommand,
Script* parent, QWebFrame* frame, Script* parent, QWebFrame* frame,
QStringList vars, QStringList vars,
QStringList args) { QStringList args) {
script->set(*parent); Script scriptCopy(*script); // only work with a copy of script
scriptCopy.set(*parent);
if (args.size()!=vars.size()) if (args.size()!=vars.size())
throw WrongNumberOfArguments(vars, args); throw WrongNumberOfArguments(vars, args);
for (QStringList::iterator var(vars.begin()), arg(args.begin()); for (QStringList::iterator var(vars.begin()), arg(args.begin());
var<vars.end() && arg<args.end(); ++var, ++arg) var<vars.end() && arg<args.end(); ++var, ++arg)
script->set(*var, parent->replacevars(*arg)); scriptCopy.set(*var, parent->replacevars(*arg));
try { try {
connect(script.get(), SIGNAL(logging(QString)), connect(&scriptCopy, SIGNAL(logging(QString)),
parent, SLOT(log(QString))); parent, SLOT(parentlog(QString)));
parent->removeSignals(frame); parent->removeSignals(frame);
bool res(script->run(frame)); bool res(scriptCopy.run(frame));
parent->addSignals(frame); parent->addSignals(frame);
disconnect(script.get(), SIGNAL(logging(QString)), disconnect(&scriptCopy, SIGNAL(logging(QString)),
parent, SLOT(log(QString))); parent, SLOT(parentlog(QString)));
parentCommand->_result = script->result(); parentCommand->_result = scriptCopy.result();
return res; return res;
} catch (const std::exception& x) { } catch (const std::exception& x) {
parent->addSignals(frame); parent->addSignals(frame);
disconnect(script.get(), SIGNAL(logging(QString)), disconnect(&scriptCopy, SIGNAL(logging(QString)),
parent, SLOT(log(QString))); parent, SLOT(parentlog(QString)));
throw; throw;
} }
} }

@ -19,7 +19,10 @@ class Exception: public std::exception {
return _what.toStdString().c_str(); return _what.toStdString().c_str();
} }
void line(int linenr) { void line(int linenr) {
if (linenr>0) _what="line "+QString::number(linenr)+": "+_what; if (linenr>0) _what=QString::number(linenr)+" "+_what;
}
void file(QString filename) {
if (filename.size()) _what=filename+":"+_what;
} }
protected: protected:
QString _what; QString _what;
@ -241,8 +244,7 @@ class FunctionCallFailed: public TestFailed {
class FunctionNotFound: public TestFailed { class FunctionNotFound: public TestFailed {
public: public:
FunctionNotFound(QString name): FunctionNotFound(QString name): TestFailed("function not found: "+name) {
TestFailed("function not found: "+name) {
} }
}; };

@ -122,13 +122,13 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
std::shared_ptr<xml::Node> testsuites(new xml::Node("testsuite")); std::shared_ptr<xml::Node> testsuites(new xml::Node("testsuite"));
if (_setupscriptactive->isEnabled() if (_setupscriptactive->isEnabled()
&& _setupscriptactive->isChecked()) { && _setupscriptactive->isChecked()) {
script.parse(_setupscript->toPlainText().split('\n')); script.parse(_setupscript->toPlainText().split('\n'), "setup");
script.run(_web->page()->mainFrame(), testsuites, QString(), false); script.run(_web->page()->mainFrame(), testsuites, QString(), false);
script.reset(); script.reset();
} }
QString text(_testscript->textCursor().selection().toPlainText()); QString text(_testscript->textCursor().selection().toPlainText());
if (text.isEmpty()) text = _testscript->toPlainText(); if (text.isEmpty()) text = _testscript->toPlainText();
script.parse(text.split('\n')); script.parse(text.split('\n'), "script");
script.run(_web->page()->mainFrame(), testsuites, QString(), false); script.run(_web->page()->mainFrame(), testsuites, QString(), false);
} catch (std::exception &x) { } catch (std::exception &x) {
QMessageBox::critical(this, tr("Script Failed"), QMessageBox::critical(this, tr("Script Failed"),
@ -222,10 +222,10 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
std::shared_ptr<xml::Node> testsuites(new xml::Node("testsuite")); std::shared_ptr<xml::Node> testsuites(new xml::Node("testsuite"));
Script script; Script script;
TestWebPage page(0, true); TestWebPage page(0, true);
script.parse(_setupscript->toPlainText().split('\n')); script.parse(_setupscript->toPlainText().split('\n'), "setup");
script.run(page.mainFrame(), testsuites, QString(), false); script.run(page.mainFrame(), testsuites, QString(), false);
_setupScript.cleanup(); _setupScript.cleanup();
_setupScript.parse(_setupscript->toPlainText().split('\n')); _setupScript.parse(_setupscript->toPlainText().split('\n'), "setup");
_setupScript.run(page.mainFrame(), testsuites, QString(), false);; _setupScript.run(page.mainFrame(), testsuites, QString(), false);;
_setupscriptstatus->setText(trUtf8("")); _setupscriptstatus->setText(trUtf8(""));
_setupscriptactive->setEnabled(true); _setupscriptactive->setEnabled(true);

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

Loading…
Cancel
Save