new commands ignore and unignore to (un-) ignore signals

master
Marc Wäckerlin 7 years ago
parent 86cdc6777d
commit be6e52aeb0
  1. 1
      scripts/90wt-mode.el.in
  2. 8
      scripts/makefile.am
  3. 2
      scripts/wt-mode.el
  4. 159
      src/commands.hxx
  5. 2
      src/editor.hxx
  6. 6
      src/exceptions.hxx

@ -4,6 +4,7 @@
;; ;;
;; Set up to autoload ;; Set up to autoload
(add-to-list 'load-path "@emacsdir@")
(autoload 'wt-mode "wt-mode" "Major mode for editing Webtester test scripts" t) (autoload 'wt-mode "wt-mode" "Major mode for editing Webtester test scripts" t)
(setq auto-mode-alist (setq auto-mode-alist
(cons '("\\.wt\\'" . wt-mode) auto-mode-alist)) (cons '("\\.wt\\'" . wt-mode) auto-mode-alist))

@ -12,7 +12,13 @@ emacsdir = ${datadir}/emacs/site-lisp
dist_emacs_SCRIPTS = wt-mode.el dist_emacs_SCRIPTS = wt-mode.el
emacsconfdir = ${sysconfdir}/emacs/site-start.d emacsconfdir = ${sysconfdir}/emacs/site-start.d
dist_emacsconf = 90wt-mode.el emacsconf_DATA = 90wt-mode.el
EXTRA_DIST = 90wt-mode.el.in
90wt-mode.el: 90wt-mode.el.in
sed 's,@emacsdir@,'"${emacsdir}"',g' $< > $@
CLEANFILES = 90wt-mode.el
MAINTAINERCLEANFILES = makefile.in MAINTAINERCLEANFILES = makefile.in

@ -25,7 +25,7 @@
;; echo $(webrunner -h | sed -n 's, COMMAND: ,,p') | sed 's, ,\\\\|,g' ;; echo $(webrunner -h | sed -n 's, COMMAND: ,,p') | sed 's, ,\\\\|,g'
(defconst wt-font-lock-keywords (defconst wt-font-lock-keywords
(list (list
'("^ *\\(auth\\|ca-certificate\\|call\\|case\\|check\\|clear-cookies\\|click\\|clicktype\\|client-certificate\\|do\\|download\\|echo\\|execute\\|exists\\|exit\\|expect\\|fail\\|for\\|function\\|if\\|while\\|ignoreto\\|include\\|label\\|load\\|not\\|offline-storage-path\\|open\\|screenshot\\|set\\|setvalue\\|sleep\\|testcase\\|testsuite\\|timeout\\|unset\\|upload\\) " . font-lock-builtin-face) '("^ *\\(auth\\|ca-certificate\\|call\\|case\\|check\\|clear-cookies\\|click\\|clicktype\\|client-certificate\\|do\\|download\\|echo\\|execute\\|exists\\|exit\\|expect\\|fail\\|for\\|function\\|if\\|while\\|ignore\\|unignore\\|ignoreto\\|include\\|label\\|load\\|not\\|offline-storage-path\\|open\\|screenshot\\|set\\|setvalue\\|sleep\\|testcase\\|testsuite\\|timeout\\|unset\\|upload\\)\\b" . font-lock-builtin-face)
'("^ *#.*$" . font-lock-comment-face)) '("^ *#.*$" . font-lock-comment-face))
"Highlighting expressions for Webtester") "Highlighting expressions for Webtester")

@ -25,6 +25,7 @@
#include <QRegularExpression> #include <QRegularExpression>
#include <QNetworkCookieJar> #include <QNetworkCookieJar>
#include <QNetworkCookie> #include <QNetworkCookie>
#include <QSet>
#include <vector> #include <vector>
#include <queue> #include <queue>
#include <map> #include <map>
@ -566,6 +567,7 @@ class Script: public QObject {
} }
void cleanup() { void cleanup() {
reset(); reset();
_ignore.clear();
_variables.clear(); _variables.clear();
_rvariables.clear(); _rvariables.clear();
_timeout = _defaultTimeout; _timeout = _defaultTimeout;
@ -822,15 +824,58 @@ class Script: public QObject {
_testsuites->last().attr("failures") = "0"; _testsuites->last().attr("failures") = "0";
(*_testsuites)<<testsuite; (*_testsuites)<<testsuite;
} }
QStringList getSignals() {
QStringList res;
for (std::queue<Signal> sigs(_signals); !sigs.empty(); sigs.pop())
res+=sigs.front().first;
return res;
}
Signal getSignal() { Signal getSignal() {
while (!_signals.size()) QCoreApplication::processEvents(); while (_signals.empty()) QCoreApplication::processEvents();
Signal res(_signals.front()); Signal res(_signals.front());
_signals.pop(); _signals.pop();
return res; return res;
} }
bool checkSignal(const QString& name, const QStringList& args = QStringList()) {
if (_ignore.contains(name)) {
log(QString("ignoring signal check for %1").arg(name));
return true;
}
while (_signals.empty()) QCoreApplication::processEvents();
Signal res(_signals.front());
if (res.first==name && (args.empty() || res.second==args)) {
_signals.pop();
return true;
}
return false;
}
QTimer& timer() { QTimer& timer() {
return _timer; return _timer;
} }
void ignore(const Script& o) {
_ignore = o._ignore;
}
bool ignore(const QString& sig) {
return _ignore.contains(sig);
}
void ignore(QStringList sigs = QStringList()) {
if (sigs.empty())
sigs<<"loadFinished"<<"loadStarted"<<"frameChanged"<<"titleChanged"<<"urlChanged";
Q_FOREACH(const QString& sig, sigs) {
log("start ignoring: '"+sig+"'");
_ignore<<sig;
}
}
void unignore(QStringList sigs = QStringList()) {
if (sigs.empty())
sigs<<"loadFinished"<<"loadStarted"<<"frameChanged"<<"titleChanged"<<"urlChanged";
Q_FOREACH(const QString& sig, sigs) {
if (_ignore.contains(sig)) {
log("stop ignoring: '"+sig+"'");
_ignore.erase(_ignore.find(sig));
}
}
}
void ignoreto(const QString& l) { void ignoreto(const QString& l) {
_ignores.insert(l); _ignores.insert(l);
} }
@ -859,6 +904,8 @@ class Script: public QObject {
_testsuites = o._testsuites; _testsuites = o._testsuites;
_testclass = o._testclass; _testclass = o._testclass;
_targetdir = o._targetdir; _targetdir = o._targetdir;
_ignore = o._ignore;
_ignores = o._ignores;
_maxretries = o._maxretries; _maxretries = o._maxretries;
_screenshots = o._screenshots; _screenshots = o._screenshots;
_cout.clear(); _cout.clear();
@ -1043,6 +1090,10 @@ class Script: public QObject {
void javaScriptWindowObjectCleared() { void javaScriptWindowObjectCleared() {
} }
void loadFinished(bool ok) { void loadFinished(bool ok) {
if (_ignore.contains("loadFinished")) {
log("ignored loadFinished");
return;
}
QString sig(ok?"true":"false"); QString sig(ok?"true":"false");
if (_ignoreSignalsUntil.size() && if (_ignoreSignalsUntil.size() &&
_ignoreSignalsUntil != "loadFinished "+sig) { _ignoreSignalsUntil != "loadFinished "+sig) {
@ -1054,6 +1105,10 @@ class Script: public QObject {
_signals.push(std::make_pair("loadFinished", QStringList(sig))); _signals.push(std::make_pair("loadFinished", QStringList(sig)));
} }
void loadStarted() { void loadStarted() {
if (_ignore.contains("loadStarted")) {
log("ignored loadStarted");
return;
}
if (_ignoreSignalsUntil.size() && _ignoreSignalsUntil != "loadStarted") { if (_ignoreSignalsUntil.size() && _ignoreSignalsUntil != "loadStarted") {
log("warning: ignored loadStarted, waiting for "+_ignoreSignalsUntil); log("warning: ignored loadStarted, waiting for "+_ignoreSignalsUntil);
return; return;
@ -1063,11 +1118,23 @@ class Script: public QObject {
_signals.push(std::make_pair("loadStarted", QStringList())); _signals.push(std::make_pair("loadStarted", QStringList()));
} }
void frameChanged() { void frameChanged() {
if (_ignore.contains("frameChanged")) {
log("ignored frameChanged");
return;
}
} }
void titleChanged(const QString&) { void titleChanged(const QString&) {
if (_ignore.contains("titleChanged")) {
log("ignored titleChanged");
return;
}
//_signals.push(std::make_pair("titleChanged", QStringList(title))); //_signals.push(std::make_pair("titleChanged", QStringList(title)));
} }
void urlChanged(const QUrl& url) { void urlChanged(const QUrl& url) {
if (_ignore.contains("urlChanged")) {
log("ignored urlChanged");
return;
}
if (_ignoreSignalsUntil.size() && _ignoreSignalsUntil != "urlChanged") { if (_ignoreSignalsUntil.size() && _ignoreSignalsUntil != "urlChanged") {
log("warning: ignored urlChanged, waiting for "+_ignoreSignalsUntil); log("warning: ignored urlChanged, waiting for "+_ignoreSignalsUntil);
return; return;
@ -1090,6 +1157,7 @@ class Script: public QObject {
Prototypes _prototypes; Prototypes _prototypes;
Commands _script; Commands _script;
std::queue<Signal> _signals; std::queue<Signal> _signals;
QSet<QString> _ignore; ///< signals to ignore
QTimer _timer; QTimer _timer;
int _step; int _step;
QSet<QString> _ignores; QSet<QString> _ignores;
@ -1236,21 +1304,21 @@ class Expect: public Command {
bool execute(Script* script, QWebFrame*) { bool execute(Script* script, QWebFrame*) {
Logger log(this, script); Logger log(this, script);
QStringList args(script->replacevars(_signal._args)); QStringList args(script->replacevars(_signal._args));
Script::Signal lastsignal(script->getSignal());
if (_signal._signal=="load") { // special signal load if (_signal._signal=="load") { // special signal load
while (lastsignal.first=="loadStarted") { while (!script->ignore("loadStarted") && script->checkSignal("loadStarted")) {
log("ignore signal: loadStarted"); log("ignore signal: loadStarted"); // ignore optional loadStarted
lastsignal = script->getSignal(); // ignore optional loadStarted
} }
if (lastsignal.first!="urlChanged" || (args.size() && lastsignal.second!=args)) if (!script->checkSignal("urlChanged", args))
error(log, WrongSignal("urlChanged", args, lastsignal)); error(log, WrongSignal("urlChanged", args, script->getSignal(),
lastsignal = script->getSignal(); script->getSignals()));
args=QStringList("true"); args=QStringList("true");
if (lastsignal.first!="loadFinished" || (lastsignal.second!=args)) if (!script->checkSignal("loadFinished", args))
error(log, WrongSignal("loadFinished", args, lastsignal)); error(log, WrongSignal("loadFinished", args, script->getSignal(),
script->getSignals()));
} else { } else {
if (lastsignal.first!=_signal._signal || (args.size() && lastsignal.second!=args)) if (!script->checkSignal(_signal._signal, args))
error(log, WrongSignal(_signal._signal, args, lastsignal)); error(log, WrongSignal(_signal._signal, args, script->getSignal(),
script->getSignals()));
} }
return true; return true;
} }
@ -2962,6 +3030,70 @@ class Auth: public Command {
QString _password; QString _password;
}; };
class Ignore: public Command {
public:
QString tag() const {
return "ignore";
}
QString description() const {
return
tag()+" <signal1> <signal2> <...>"
"\n\n"
"Ignores a specific signal. It will not be placed in the queue "
"and any expect for this signal is always true. You can call "
"ignore with a space separated list of signal names. You cannot "
"specify signal arguments. An empty ignore ignores all signals.";
}
QString command() const {
return tag()+" "+_signals.join(" ");
}
std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int, int) {
std::shared_ptr<Ignore> cmd(new Ignore());
cmd->_signals = args.split(' ', QString::SkipEmptyParts);
return cmd;
}
bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script);
script->ignore(_signals);
return true;
}
private:
QStringList _signals;
};
class UnIgnore: public Command {
public:
QString tag() const {
return "unignore";
}
QString description() const {
return
tag()+" <signal1> <signal2> <...>"
"\n\n"
"Undo ignoring a specific signal. It will be placed in the queue "
"and any expect this signal checks the queue. You can call "
"unignore with a space separated list of signal names. You cannot "
"specify signal arguments. An empty ignore activates all signals.";
}
QString command() const {
return tag()+" "+_signals.join(" ");
}
std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, QString, int, int) {
std::shared_ptr<UnIgnore> cmd(new UnIgnore());
cmd->_signals = args.split(' ', QString::SkipEmptyParts);
return cmd;
}
bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script);
script->unignore(_signals);
return true;
}
private:
QStringList _signals;
};
/* Template: /* Template:
class : public Command { class : public Command {
public: public:
@ -3067,6 +3199,7 @@ inline bool Command::runScript(Logger& log, Command* parentCommand,
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(key)); if (!vars.contains(key)) parent->set(key, scriptCopy.variable(key));
parent->ignore(scriptCopy); // copy ignore list
if (parentCommand->_result.size()) if (parentCommand->_result.size())
parent->log("result: "+parentCommand->_result); parent->log("result: "+parentCommand->_result);
return res; return res;
@ -3118,6 +3251,8 @@ inline void Script::initPrototypes() {
add(new Case); add(new Case);
add(new Fail); add(new Fail);
add(new Auth); add(new Auth);
add(new Ignore);
add(new UnIgnore);
} }
#endif #endif

@ -19,7 +19,7 @@ class Highlighter: public QSyntaxHighlighter {
void include(QString); void include(QString);
public: public:
Highlighter(QTextDocument *parent): QSyntaxHighlighter(parent) { Highlighter(QTextDocument *parent): QSyntaxHighlighter(parent) {
QString commands="auth|ca-certificate|call|case|check|clear-cookies|click|clicktype|client-certificate|do|download|echo|execute|exists|exit|expect|fail|for|function|if|while|ignoreto|include|label|load|not|offline-storage-path|open|screenshot|set|setvalue|sleep|testcase|testsuite|timeout|unset|upload"; QString commands="auth|ca-certificate|call|case|check|clear-cookies|click|clicktype|client-certificate|do|download|echo|execute|exists|exit|expect|fail|for|function|if|while|ignore|unignore|ignoreto|include|label|load|not|offline-storage-path|open|screenshot|set|setvalue|sleep|testcase|testsuite|timeout|unset|upload";
_expressions<<Expression("^ *("+commands+")\\b").weight(QFont::Bold).fg(Qt::darkBlue) _expressions<<Expression("^ *("+commands+")\\b").weight(QFont::Bold).fg(Qt::darkBlue)
<<Expression("^ *#.*$").weight(QFont::Bold).fg(Qt::black); <<Expression("^ *#.*$").weight(QFont::Bold).fg(Qt::black);
} }

@ -68,10 +68,12 @@ class PossibleRetryLoad: public TestFailed {
class WrongSignal: public PossibleRetryLoad { class WrongSignal: public PossibleRetryLoad {
public: public:
WrongSignal(QString signal, QStringList args, WrongSignal(QString signal, QStringList args,
std::pair<QString, QStringList> received): std::pair<QString, QStringList> received,
QStringList sigs):
PossibleRetryLoad PossibleRetryLoad
("expected: \""+signal+" "+args.join(' ')+"\"; " ("expected: \""+signal+" "+args.join(' ')+"\"; "
"received: \""+received.first+" "+received.second.join(' ')+"\"") { "received: \""+received.first+" "+received.second.join(' ')
+"\"; queue: "+sigs.join(", ")) {
} }
}; };

Loading…
Cancel
Save