new command check to compare two values or to compare a value to the result of a command - command call now returns the value of the last statement

master
Marc Wäckerlin 10 years ago
parent 13b8752c7a
commit d7ad9f38d6
  1. 112
      src/commands.hxx
  2. 8
      src/exceptions.hxx

@ -111,7 +111,8 @@ class Command: public QObject {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100); QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
} }
protected: protected:
void runScript(std::shared_ptr<Script> script, bool runScript(Command* parentCommand,
std::shared_ptr<Script> script,
Script* parent, QWebFrame* frame, Script* parent, QWebFrame* frame,
QStringList vars = QStringList(), QStringList vars = QStringList(),
QStringList args = QStringList()); QStringList args = QStringList());
@ -469,12 +470,13 @@ class Script: public QObject {
} }
return result; return result;
} }
void run(QWebFrame* frame) { bool run(QWebFrame* frame) {
run(frame, _testsuites, targetdir(), _screenshots, _maxretries); return run(frame, _testsuites, targetdir(), _screenshots, _maxretries);
} }
void run(QWebFrame* frame, std::shared_ptr<xml::Node> testsuites, bool run(QWebFrame* frame, std::shared_ptr<xml::Node> testsuites,
QString td = QString(), bool screenshots = true, QString td = QString(), bool screenshots = true,
int maxretries = 0) { int maxretries = 0) {
bool res(true);
_testsuites = testsuites; _testsuites = testsuites;
_timeout = 20; // defaults to 20s _timeout = 20; // defaults to 20s
_ignoreSignalsUntil.clear(); _ignoreSignalsUntil.clear();
@ -502,7 +504,7 @@ class Script: public QObject {
if (!_ignores.size() || (*cmd)->tag()=="label") { // not ignored if (!_ignores.size() || (*cmd)->tag()=="label") { // not ignored
_timer.start(_timeout*1000); _timer.start(_timeout*1000);
try { try {
if (!(*cmd)->execute(this, frame)) { if (!(res=(*cmd)->execute(this, frame))) {
_timer.stop(); _timer.stop();
if (!back) retries = 0; else --back; if (!back) retries = 0; else --back;
testcase<<(xml::String("system-out") = testcase<<(xml::String("system-out") =
@ -608,6 +610,7 @@ class Script: public QObject {
} }
removeSignals(frame); removeSignals(frame);
if (!_signals.empty()) throw UnhandledSignals(_signals); if (!_signals.empty()) throw UnhandledSignals(_signals);
return res;
} }
QString& cout() { QString& cout() {
return _cout; return _cout;
@ -718,6 +721,10 @@ class Script: public QObject {
} }
return txt; return txt;
} }
QString result() {
if (_script.size()) return (*_script.rbegin())->result();
return QString();
}
void addSignals(QWebFrame* frame) { void addSignals(QWebFrame* frame) {
connect(dynamic_cast<NetworkAccessManager*> connect(dynamic_cast<NetworkAccessManager*>
(frame->page()->networkAccessManager()), (frame->page()->networkAccessManager()),
@ -1496,9 +1503,10 @@ class Set: public Command {
"\n\n" "\n\n"
"Sets the value of a variable either to a constant, or to the output" "Sets the value of a variable either to a constant, or to the output"
" of a command. A command should be a command that produces an" " of a command. A command should be a command that produces an"
" output, such as «do», which returns the result of JavaScript or" " output, such as <do>, which returns the result of JavaScript or"
" «execute», which returns the output of the executed command." " <execute>, which returns the output of the executed command, or"
" All variables are global with regrad to functions."; " <call>, which returns the result of the last command."
" All variables are global with regard to functions.";
} }
QString command() const { QString command() const {
if (_next) if (_next)
@ -1840,14 +1848,14 @@ class Function: public Command {
Logger log(this, script); Logger log(this, script);
return true; return true;
} }
bool call(QStringList args, Script* script, QWebFrame* frame) { bool call(Command* parentCommand, QStringList args,
Script* script, QWebFrame* frame) {
Logger log(this, script); Logger log(this, script);
try { try {
runScript(_script, script, frame, _vars, args); return runScript(parentCommand, _script, script, frame, _vars, args);
} catch (const std::exception& x) { } catch (const std::exception& x) {
throw FunctionCallFailed(_name, _vars, args, x); throw FunctionCallFailed(_name, _vars, args, x);
} }
return true;
} }
private: private:
QString _name; QString _name;
@ -1883,8 +1891,7 @@ class Call: public Command {
} }
bool execute(Script* script, QWebFrame* frame) { bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script); Logger log(this, script);
script->function(_name)->call(_args, script, frame); return script->function(_name)->call(this, _args, script, frame);
return true;
} }
public: public:
QString _name; QString _name;
@ -1953,8 +1960,8 @@ class If: public Command {
break; break;
default:; default:;
} }
if (check) runScript(_script, script, frame); if (check) return runScript(this, _script, script, frame);
else if (_else) runScript(_else, script, frame); else if (_else) return runScript(this, _else, script, frame);
return true; return true;
} }
private: private:
@ -2023,6 +2030,71 @@ class TestCase: public Command {
QString _name; QString _name;
}; };
class Check: public Command {
public:
QString tag() const {
return "check";
}
QString description() const {
return
tag()+" <value1> <op> <value2>\n"+
tag()+" <value1>\n"
" <command>"
"\n\n"
"Compares two values (you can use variables) or compares a value to the"
" result of a command. The command should be a command that produces an"
" output, such as <do>, which returns the result of JavaScript or"
" <execute>, which returns the output of the executed command, or"
" <call>, which returns the result of the last command.";
}
QString command() const {
if (_next)
return tag()+" "+_value1+" "+QString(_cmp)+"\n "+_next->command();
else
return tag()+" "+_value1+" "+QString(_cmp)+" "+_value2;
}
std::shared_ptr<Command> parse(Script* script, QString args,
QStringList& in, int line) {
std::shared_ptr<Check> cmd(new Check());
cmd->_next = 0;
int pos(args.indexOf(QRegularExpression("[=^~<>]")));
if (pos<0) throw BadArgument(tag()+" needs a comparision, not: "+args);
cmd->_value1 = args.left(pos).trimmed();
cmd->_cmp = args[pos].toLatin1();
cmd->_value2 = args.mid(pos+1).trimmed();
if (in.size() && in.first().contains(QRegularExpression("^ "))) {
cmd->_next = script->parse(in, line+1);
cmd->_next->log(false); // suppress logging of subcommand
}
return cmd;
}
bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script);
QString value1(script->replacevars(_value1));
QString value2(script->replacevars(_value2));
if (_next) {
_next->execute(script, frame);
value2 = script->replacevars(_next->result());
}
bool check(false);
switch (_cmp) {
case '=': check = value1==value2; break;
case '^': check = value1!=value2; break;
case '~': check = value1.contains(QRegularExpression(value2)); break;
case '<': check = value1.toInt()<value2.toInt(); break;
case '>': check = value1.toInt()>value2.toInt(); break;
default:;
}
if (!check) throw CheckFailed(value1, _cmp, value2);
return true;
}
private:
QString _value1;
QString _value2;
char _cmp;
std::shared_ptr<Command> _next;
};
/* Template: /* Template:
class : public Command { class : public Command {
public: public:
@ -2079,7 +2151,8 @@ inline Logger::~Logger() {
_script->log("---------------------"); _script->log("---------------------");
} }
inline void Command::runScript(std::shared_ptr<Script> script, inline bool Command::runScript(Command* parentCommand,
std::shared_ptr<Script> script,
Script* parent, QWebFrame* frame, Script* parent, QWebFrame* frame,
QStringList vars, QStringList vars,
QStringList args) { QStringList args) {
@ -2093,10 +2166,12 @@ inline void Command::runScript(std::shared_ptr<Script> script,
connect(script.get(), SIGNAL(logging(QString)), connect(script.get(), SIGNAL(logging(QString)),
parent, SLOT(log(QString))); parent, SLOT(log(QString)));
parent->removeSignals(frame); parent->removeSignals(frame);
script->run(frame); bool res(script->run(frame));
parent->addSignals(frame); parent->addSignals(frame);
disconnect(script.get(), SIGNAL(logging(QString)), disconnect(script.get(), SIGNAL(logging(QString)),
parent, SLOT(log(QString))); parent, SLOT(log(QString)));
parentCommand->_result = script->result();
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(script.get(), SIGNAL(logging(QString)),
@ -2133,6 +2208,7 @@ inline void Script::initPrototypes() {
add(new If); add(new If);
add(new TestSuite); add(new TestSuite);
add(new TestCase); add(new TestCase);
add(new Check);
} }
#endif #endif

@ -253,4 +253,12 @@ class VariableNotFound: public TestFailed {
} }
}; };
class CheckFailed: public TestFailed {
public:
CheckFailed(QString value1, char cmp, QString value2):
TestFailed(QString("check failed: %1 %2 %3")
.arg(value1).arg(cmp).arg(value1)) {
}
};
#endif #endif

Loading…
Cancel
Save