|
|
@ -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 |
|
|
|