new commands testsuite and testcase

master
Marc Wäckerlin 10 years ago
parent ee1ebd8ca9
commit 9335d5f6bb
  1. 7
      ChangeLog
  2. 33
      ax_check_qt.m4
  3. 46
      ax_init_standard_project.m4
  4. 96
      bootstrap.sh
  5. 9
      doc/makefile.amto
  6. 151
      src/commands.hxx
  7. 21
      src/testgui.hxx
  8. 71
      src/webrunner.cxx

@ -1,3 +1,10 @@
2015-05-08 15:34 marc
* ChangeLog, ax_init_standard_project.m4, bootstrap.sh,
docker/Dockerfile, src/commands.hxx, src/exceptions.hxx,
src/testgui.hxx: new feature: if tatement for conditions in
functions
2015-05-06 23:09 marc 2015-05-06 23:09 marc
* ChangeLog, bootstrap.sh, doc/doxyfile.in, * ChangeLog, bootstrap.sh, doc/doxyfile.in,

@ -104,12 +104,24 @@ AC_DEFUN([AX_CHECK_QT], [
MOC_FLAGS+=" -DHAVE_$1=1 ${[$1]5_CFLAGS}" MOC_FLAGS+=" -DHAVE_$1=1 ${[$1]5_CFLAGS}"
AM_CXXFLAGS+=" ${[$1]5_CFLAGS}" AM_CXXFLAGS+=" ${[$1]5_CFLAGS}"
LIBS+=" ${[$1]5_LIBS}" LIBS+=" ${[$1]5_LIBS}"
modules=${qt_modules//Qt/Qt5}
if test -z "$PKG_REQUIREMENTS"; then
PKG_REQUIREMENTS="${modules// /, }"
else
PKG_REQUIREMENTS="${PKG_REQUIREMENTS}, ${modules// /, }"
fi
if test -n "${qt_modules_optional}"; then if test -n "${qt_modules_optional}"; then
PKG_CHECK_MODULES([$1]5_OPTIONAL, [${qt_modules_optional//Qt/Qt5}], [ PKG_CHECK_MODULES([$1]5_OPTIONAL, [${qt_modules_optional//Qt/Qt5}], [
AM_CPPFLAGS+=" ${[$1]5_OPTIONAL_CFLAGS}" AM_CPPFLAGS+=" ${[$1]5_OPTIONAL_CFLAGS}"
MOC_FLAGS+=" ${[$1]5_OPTIONAL_CFLAGS}" MOC_FLAGS+=" ${[$1]5_OPTIONAL_CFLAGS}"
AM_CXXFLAGS+=" ${[$1]5_OPTIONAL_CFLAGS}" AM_CXXFLAGS+=" ${[$1]5_OPTIONAL_CFLAGS}"
LIBS+=" ${[$1]5_OPTIONAL_LIBS}" LIBS+=" ${[$1]5_OPTIONAL_LIBS}"
modules=${qt_modules_optional//Qt/Qt5}
if test -z "$PKG_REQUIREMENTS"; then
PKG_REQUIREMENTS="${modules// /, }"
else
PKG_REQUIREMENTS="${PKG_REQUIREMENTS}, ${modules// /, }"
fi
], [ ], [
AC_MSG_NOTICE([Not found: ${qt_modules_optional//Qt/Qt5}]) AC_MSG_NOTICE([Not found: ${qt_modules_optional//Qt/Qt5}])
]) ])
@ -122,12 +134,24 @@ AC_DEFUN([AX_CHECK_QT], [
MOC_FLAGS+=" -DHAVE_$1=1 ${$1_CFLAGS}" MOC_FLAGS+=" -DHAVE_$1=1 ${$1_CFLAGS}"
AM_CXXFLAGS+=" ${$1_CFLAGS}" AM_CXXFLAGS+=" ${$1_CFLAGS}"
LIBS+=" ${$1_LIBS}" LIBS+=" ${$1_LIBS}"
modules=${qt_modules}
if test -z "$PKG_REQUIREMENTS"; then
PKG_REQUIREMENTS="${modules// /, }"
else
PKG_REQUIREMENTS="${PKG_REQUIREMENTS}, ${modules// /, }"
fi
if test -n "$3"; then if test -n "$3"; then
PKG_CHECK_MODULES($1_OPTIONAL, [${qt_modules_optional}], [ PKG_CHECK_MODULES($1_OPTIONAL, [${qt_modules_optional}], [
AM_CPPFLAGS+=" ${$1_OPTIONAL_CFLAGS}" AM_CPPFLAGS+=" ${$1_OPTIONAL_CFLAGS}"
MOC_FLAGS+=" ${$1_OPTIONAL_CFLAGS}" MOC_FLAGS+=" ${$1_OPTIONAL_CFLAGS}"
AM_CXXFLAGS+=" ${$1_OPTIONAL_CFLAGS}" AM_CXXFLAGS+=" ${$1_OPTIONAL_CFLAGS}"
LIBS+=" ${$1_OPTIONAL_LIBS}" LIBS+=" ${$1_OPTIONAL_LIBS}"
modules=${qt_modules_optional}
if test -z "$PKG_REQUIREMENTS"; then
PKG_REQUIREMENTS="${modules// /, }"
else
PKG_REQUIREMENTS="${PKG_REQUIREMENTS}, ${modules// /, }"
fi
], [ ], [
AC_MSG_NOTICE([Not found: ${qt_modules_optional}]) AC_MSG_NOTICE([Not found: ${qt_modules_optional}])
]) ])
@ -139,6 +163,7 @@ AC_DEFUN([AX_CHECK_QT], [
AC_SUBST(AM_CPPFLAGS) AC_SUBST(AM_CPPFLAGS)
AC_SUBST(MOC_FLAGS) AC_SUBST(MOC_FLAGS)
AC_SUBST(AM_CXXFLAGS) AC_SUBST(AM_CXXFLAGS)
AC_SUBST(PKG_REQUIREMENTS)
AX_ADDITIONAL_QT_RULES_HACK=' AX_ADDITIONAL_QT_RULES_HACK='
ui_%.hxx: %.ui ui_%.hxx: %.ui
$(UIC) -o [$][@] $< $(UIC) -o [$][@] $<
@ -191,3 +216,11 @@ AC_DEFUN([AX_REQUIRE_QT], [
AC_MSG_ERROR([Required Qt modules not found: $2]) AC_MSG_ERROR([Required Qt modules not found: $2])
fi fi
]) ])
# Omit Qt Keywords
# AX_QT_NO_KEYWORDS
AC_DEFUN([AX_QT_NO_KEYWORDS], [
AM_CPPFLAGS+=" -DQT_NO_KEYWORDS"
])

@ -5,7 +5,7 @@
# define least version number from subversion's revision number: # define least version number from subversion's revision number:
# it is taken modulo 256 due to a bug on Apple's MacOSX # it is taken modulo 256 due to a bug on Apple's MacOSX
m4_define(x_version, m4_esyscmd_s( m4_define(x_least, m4_esyscmd_s(
SVN_REVISION="ERROR-UNDEFINED-REVISION-to-be-built-in-subdirectory-of-svn-checkout" SVN_REVISION="ERROR-UNDEFINED-REVISION-to-be-built-in-subdirectory-of-svn-checkout"
for path in . .. ../..; do for path in . .. ../..; do
if svn info $path 2>&1 > /dev/null; then if svn info $path 2>&1 > /dev/null; then
@ -15,7 +15,26 @@ m4_define(x_version, m4_esyscmd_s(
fi fi
done done
# Mac does not support LEAST > 255 # Mac does not support LEAST > 255
echo $ECHO_N x_major.$((x_minor+$SVN_REVISION/256)).$(($SVN_REVISION%256)) echo $ECHO_N $(($SVN_REVISION%256))
))
# define version number from subversion's revision number:
# it is taken modulo 256 due to a bug on Apple's MacOSX
# add to x_minor if revision number is > 256
m4_define(x_minor_fixed, m4_esyscmd_s(
SVN_REVISION="ERROR-UNDEFINED-REVISION-to-be-built-in-subdirectory-of-svn-checkout"
for path in . .. ../..; do
if svn info $path 2>&1 > /dev/null; then
SVN_REVISION=$(LANG= svn info $path | sed -n 's/Last Changed Rev: //p')
(cd $path && svn2cl)
break;
fi
done
# Mac does not support LEAST > 255
echo $ECHO_N $((x_minor+$SVN_REVISION/256))
))
# setup version number
m4_define(x_version, m4_esyscmd_s(
echo $ECHO_N x_major.x_minor_fixed.x_least
)) ))
## bugreport mail address is taken from <user@host> in first line of AUTHORS ## bugreport mail address is taken from <user@host> in first line of AUTHORS
@ -81,7 +100,7 @@ AC_DEFUN([AX_SUBST], [
# m4_define(x_major, MAJOR_NUMBER) # project's major version # m4_define(x_major, MAJOR_NUMBER) # project's major version
# m4_define(x_minor, MINOR_NUMBER) # project's minor version # m4_define(x_minor, MINOR_NUMBER) # project's minor version
# m4_include(ax_init_standard_project.m4) # m4_include(ax_init_standard_project.m4)
# AC_INIT(x_package_name, x_major.x_minor.x_least, x_bugreport, x_package_name) # AC_INIT(x_package_name, x_version, x_bugreport, x_package_name)
# AM_INIT_AUTOMAKE([1.9 tar-pax]) # AM_INIT_AUTOMAKE([1.9 tar-pax])
# AX_INIT_STANDARD_PROJECT # AX_INIT_STANDARD_PROJECT
# #
@ -105,7 +124,7 @@ AC_DEFUN([AX_INIT_STANDARD_PROJECT], [
AX_SUBST(DISTRO) AX_SUBST(DISTRO)
BUILD_NUMBER=${BUILD_NUMBER:-1} BUILD_NUMBER=${BUILD_NUMBER:-1}
AX_SUBST(BUILD_NUMBER) AX_SUBST(BUILD_NUMBER)
BUILD_DATE=$(date +"%Y-%m-%d %H:%M %Z") BUILD_DATE=$(LANG= date +"%a, %d %B %Y %H:%M:%S %z")
AX_SUBST(BUILD_DATE) AX_SUBST(BUILD_DATE)
if test -f "${PROJECT_NAME}-logo.png"; then if test -f "${PROJECT_NAME}-logo.png"; then
PROJECT_LOGO="${PROJECT_NAME}-logo.png" PROJECT_LOGO="${PROJECT_NAME}-logo.png"
@ -225,7 +244,7 @@ AC_DEFUN([AX_USE_LIBTOOL], [
# libtool versioning # libtool versioning
LIB_MAJOR=m4_eval(x_major+x_minor) LIB_MAJOR=m4_eval(x_major+x_minor)
LIB_MINOR=x_least LIB_MINOR=x_least
LIB_LEAST=x_minor LIB_LEAST=x_minor_fixed
LIB_VERSION="${LIB_MAJOR}:${LIB_MINOR}:${LIB_LEAST}" LIB_VERSION="${LIB_MAJOR}:${LIB_MINOR}:${LIB_LEAST}"
AM_LDFLAGS="-version-info ${LIB_VERSION}" AM_LDFLAGS="-version-info ${LIB_VERSION}"
AC_SUBST(AM_LDFLAGS) AC_SUBST(AM_LDFLAGS)
@ -380,6 +399,11 @@ AC_DEFUN([AX_PKG_REQUIRE], [
AM_CPPFLAGS+=" ${$1_CFLAGS}" AM_CPPFLAGS+=" ${$1_CFLAGS}"
AM_CXXFLAGS+=" ${$1_CFLAGS}" AM_CXXFLAGS+=" ${$1_CFLAGS}"
LIBS+=" ${$1_LIBS}" LIBS+=" ${$1_LIBS}"
if test -z "$PKG_REQUIREMENTS"; then
PKG_REQUIREMENTS="$2"
else
PKG_REQUIREMENTS="${PKG_REQUIREMENTS}, $2"
fi
], [ ], [
AC_MSG_WARN([Recommended package $2 for feature $1 not installed]) AC_MSG_WARN([Recommended package $2 for feature $1 not installed])
if test -n "$4"; then if test -n "$4"; then
@ -411,6 +435,11 @@ AC_DEFUN([AX_PKG_REQUIRE], [
AM_CPPFLAGS+=" ${$1_CFLAGS}" AM_CPPFLAGS+=" ${$1_CFLAGS}"
AM_CXXFLAGS+=" ${$1_CFLAGS}" AM_CXXFLAGS+=" ${$1_CFLAGS}"
LIBS+=" ${$1_LIBS}" LIBS+=" ${$1_LIBS}"
if test -z "$PKG_REQUIREMENTS"; then
PKG_REQUIREMENTS="$pkg"
else
PKG_REQUIREMENTS="${PKG_REQUIREMENTS}, $pkg"
fi
], [ ], [
AC_MSG_WARN([Recommended package $pkg for feature $1 not installed]) AC_MSG_WARN([Recommended package $pkg for feature $1 not installed])
]) ])
@ -419,6 +448,7 @@ AC_DEFUN([AX_PKG_REQUIRE], [
]) ])
AC_SUBST(AM_CPPFLAGS) AC_SUBST(AM_CPPFLAGS)
AC_SUBST(AM_CXXFLAGS) AC_SUBST(AM_CXXFLAGS)
AC_SUBST(PKG_REQUIREMENTS)
if test -n "$3"; then if test -n "$3"; then
old_CPPFLAGS=${CPPFLAGS} old_CPPFLAGS=${CPPFLAGS}
CPPFLAGS=" ${$1_CFLAGS} ${CPPFLAGS}" CPPFLAGS=" ${$1_CFLAGS} ${CPPFLAGS}"
@ -445,6 +475,11 @@ AC_DEFUN([AX_PKG_CHECK], [
AM_CPPFLAGS+=" ${$1_CFLAGS}" AM_CPPFLAGS+=" ${$1_CFLAGS}"
AM_CXXFLAGS+=" ${$1_CFLAGS}" AM_CXXFLAGS+=" ${$1_CFLAGS}"
LIBS+=" ${$1_LIBS}" LIBS+=" ${$1_LIBS}"
if test -z "$PKG_REQUIREMENTS"; then
PKG_REQUIREMENTS="m4_default([$2], [$1])"
else
PKG_REQUIREMENTS="${PKG_REQUIREMENTS}, m4_default([$2], [$1])"
fi
], [ ], [
HAVE_$1=0 HAVE_$1=0
]) ])
@ -452,4 +487,5 @@ AC_DEFUN([AX_PKG_CHECK], [
AC_SUBST(HAVE_$1) AC_SUBST(HAVE_$1)
AC_SUBST(AM_CPPFLAGS) AC_SUBST(AM_CPPFLAGS)
AC_SUBST(AM_CXXFLAGS) AC_SUBST(AM_CXXFLAGS)
AC_SUBST(PKG_REQUIREMENTS)
]) ])

@ -22,28 +22,31 @@ configure=0
build=0 build=0
overwrite=0 overwrite=0
rebuild=0 rebuild=0
rebuildfiles=()
while test $# -gt 0; do while test $# -gt 0; do
case "$1" in case "$1" in
(--configure|-c) configure=1;; (--configure|-c) configure=1;;
(--build|-b) configure=1; build=1;; (--build|-b) configure=1; build=1;;
(--overwrite|-o) overwrite=1;; (--overwrite|-o) overwrite=1;;
(--rebuild|-r) rebuild=1;; (--rebuild|-r) rebuild=1;;
(--rebuild-file|-f) shift; rebuildfiles+=("$1");;
(--version|-v) (--version|-v)
echo "$Id$"; echo "$Id$";
exit;; exit;;
(--help|-h) less <<EOF (--help|-h) less <<EOF
SYNOPSIS SYNOPSIS
${MY_NAME} [--help|-h] [--configure|-c] ${MY_NAME} [--help|-h] [OPTIOS]
OPTIONS OPTIONS
--configure, -c call ./configure after initialization --configure, -c call ./configure after initialization
--build, -c build, call ./configure && make after initialization --build, -c build, also call ./configure && make
--overwrite, -o overwrite all basic files (bootstrap.sh, m4-macros) --overwrite, -o overwrite all basic files (bootstrap.sh, m4-macros)
--rebuild -r force rebuild of generated files, even if modified --rebuild, -r force rebuild of generated files, even if modified
--help, -h show this help --rebuild-file, -f <file> rebild specific file (can be added multiple times)
--version, -v show version and date of this file --help, -h show this help
--version, -v show version and date of this file
DESCRIPTION DESCRIPTION
@ -122,9 +125,15 @@ GENERATED FILES
REBUILDING FILES REBUILDING FILES
To rebuild all these files, just run "${MY_NAME} -o". You can also To rebuild all these files, just run "${MY_NAME} -r".
remove and rebuild a single file by removing it from subversion,
just call "svn rm <file>" and "${MY_NAME}" to rebuild file "<file>". To copy only the files provided by this package, that means those
files you must never change, that means to update the build system
to the latest release, run "${MY_NAME} -o"
You can also rebuild a list of singleany list of specific file files
by adding option "${MY_NAME} -f <file>" to rebuild file
"<file>". You can add option "-f" more than once.
FILES TO EDIT FILES TO EDIT
@ -216,7 +225,7 @@ done
HEADER='## @id '"\$Id\$"' HEADER='## @id '"\$Id\$"'
# #
# This file has been added by '${MY_NAME}' on '$(date +"%Y-%m-%d %H:%M %Z")' # This file has been added by '${MY_NAME}' on '$(LANG= date +"%a, %d %B %Y %H:%M:%S %z")'
# Feel free to change it or even remove and rebuild it, up to your needs # Feel free to change it or even remove and rebuild it, up to your needs
# #
## 1 2 3 4 5 6 7 8 ## 1 2 3 4 5 6 7 8
@ -224,6 +233,10 @@ HEADER='## @id '"\$Id\$"'
' '
notice() {
echo -e "\e[1;33m$*\e[0m"
}
run() { run() {
check=1 check=1
while test $# -gt 0; do while test $# -gt 0; do
@ -256,6 +269,12 @@ testtag() {
egrep -q '^ *'"$1" configure.ac egrep -q '^ *'"$1" configure.ac
} }
contains() {
local e
for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
return 1
}
checkdir() { checkdir() {
if ! test -d "$1"; then # create path if ! test -d "$1"; then # create path
run mkdir -p "$1" run mkdir -p "$1"
@ -285,8 +304,10 @@ to() {
esac esac
shift; shift;
done done
if checkfile "$1" && test $rebuild -eq 0; then # file already exists if checkfile "$1" && test $rebuild -eq 0 \
return && ! contains "$1" "${rebuildfiles[@]}"; then
# file already exists and must not be rebuilt
return 1
fi fi
checkdir "$(dirname ${1})" checkdir "$(dirname ${1})"
echo -en "\e[1m-> generating:\e[0m $1 ..." echo -en "\e[1m-> generating:\e[0m $1 ..."
@ -307,10 +328,13 @@ to() {
run svn add "$1" run svn add "$1"
run svn propset svn:keywords "Id" "$1" run svn propset svn:keywords "Id" "$1"
fi fi
return 0
} }
copy() { copy() {
if checkfile "$1" && test $overwrite -eq 0; then if checkfile "$1" && test $overwrite -eq 0 \
&& ! contains "$1" "${rebuildfiles[@]}"; then
# file already exists and must not be rebuilt
return return
fi fi
run cp "${0%/*}/$1" "$1" run cp "${0%/*}/$1" "$1"
@ -347,14 +371,18 @@ copy ${MY_NAME}
copy ax_init_standard_project.m4 copy ax_init_standard_project.m4
copy ax_cxx_compile_stdcxx_11.m4 copy ax_cxx_compile_stdcxx_11.m4
copy ax_check_qt.m4 copy ax_check_qt.m4
copy AUTHORS AUTHOR=$(gpg -K | sed -n 's,uid *,,p' | sort | head -1)
if ! test -f configure.ac; then if test -z "${AUTHOR}"; then
to configure.ac <<EOF AUTHOR="FIRSTNAME LASTNAME (URL) <EMAIL>"
fi
echo "$AUTHOR" | to AUTHORS && notice "please edit AUTHORS"
to configure.ac <<EOF && \
( notice "please edit configure.ac, then rerun $0"; exit 0 )
${HEADER}m4_define(x_package_name, ${DEFAULT_PROJECT_NAME}) # project's name ${HEADER}m4_define(x_package_name, ${DEFAULT_PROJECT_NAME}) # project's name
m4_define(x_major, 0) # project's major version m4_define(x_major, 0) # project's major version
m4_define(x_minor, 0) # project's minor version m4_define(x_minor, 0) # project's minor version
m4_include(ax_init_standard_project.m4) m4_include(ax_init_standard_project.m4)
AC_INIT(x_package_name, x_major.x_minor.x_least, x_bugreport, x_package_name) AC_INIT(x_package_name, x_version, x_package_name)
AM_INIT_AUTOMAKE([1.9 tar-pax]) AM_INIT_AUTOMAKE([1.9 tar-pax])
AX_INIT_STANDARD_PROJECT AX_INIT_STANDARD_PROJECT
@ -370,14 +398,11 @@ AX_INIT_STANDARD_PROJECT
# qt features, uncomment, what you need: # qt features, uncomment, what you need:
#AX_CHECK_QT([QT], [QtCore QtGui QtNetwork], [QtWidgets]) #AX_CHECK_QT([QT], [QtCore QtGui QtNetwork], [QtWidgets])
#AM_CPPFLAGS="${AM_CPPFLAGS} -DQT_NO_KEYWORDS" #AX_QT_NO_KEYWORDS
# create output # create output
AC_OUTPUT AC_OUTPUT
EOF EOF
echo "please edit configure.ac, then rerun $0"
exit 0
fi
PACKAGE_NAME=$(sed -n 's/.*m4_define *( *x_package_name *, *\([^ ]*\) *).*/\1/p' configure.ac) PACKAGE_NAME=$(sed -n 's/.*m4_define *( *x_package_name *, *\([^ ]*\) *).*/\1/p' configure.ac)
echo "${HEADER}MAINTAINERCLEANFILES = makefile.in" | to --condition AX_USE_CXX src/makefile.am echo "${HEADER}MAINTAINERCLEANFILES = makefile.in" | to --condition AX_USE_CXX src/makefile.am
to --condition AX_USE_CXX src/version.hxx <<EOF to --condition AX_USE_CXX src/version.hxx <<EOF
@ -473,10 +498,14 @@ LDADD = -l${PACKAGE_NAME}
MAINTAINERCLEANFILES = makefile.in MAINTAINERCLEANFILES = makefile.in
EOF EOF
if testtag AX_USE_DOXYGEN && ! test -f doc/doxyfile.in; then if testtag AX_USE_DOXYGEN && \
( ! checkfile doc/doxyfile.in || \
contains doc/doxyfile.in "${rebuildfiles[@]}" ); then
run doxygen -g doc/doxyfile.in run doxygen -g doc/doxyfile.in
run svn add doc/doxyfile.in if test $exists -eq 0; then
run svn propset svn:keywords "Id" doc/doxyfile.in run svn add doc/doxyfile.in
run svn propset svn:keywords "Id" doc/doxyfile.in
fi
doxyreplace PROJECT_NAME "@PACKAGE_NAME@" doxyreplace PROJECT_NAME "@PACKAGE_NAME@"
doxyreplace PROJECT_NUMBER "@PACKAGE_VERSION@" doxyreplace PROJECT_NUMBER "@PACKAGE_VERSION@"
doxyreplace PROJECT_BRIEF "@DESCRIPTION@" doxyreplace PROJECT_BRIEF "@DESCRIPTION@"
@ -595,13 +624,15 @@ ${HEADER}%:
EOF EOF
echo 7 | to debian/compat echo 7 | to debian/compat
fi fi
if ! test -f makefile.am; then SUBDIRS=""
SUBDIRS="" for d in src test scripts doc examples; do
for d in src test scripts doc examples; do test -d $d && SUBDIRS="${SUBDIRS} $d"
test -d $d && SUBDIRS="${SUBDIRS} $d" done
done to makefile.am<<EOF
echo "${HEADER}SUBDIRS =${SUBDIRS}\n\nMAINTAINERCLEANFILES = makefile.in" | to makefile.am ${HEADER}SUBDIRS =${SUBDIRS}
fi
MAINTAINERCLEANFILES = makefile.in
EOF
to --condition AX_USE_LIBTOOL src/${PACKAGE_NAME}.pc.in <<EOF to --condition AX_USE_LIBTOOL src/${PACKAGE_NAME}.pc.in <<EOF
${HEADER}prefix=@prefix@ ${HEADER}prefix=@prefix@
exec_prefix=@exec_prefix@ exec_prefix=@exec_prefix@
@ -613,6 +644,7 @@ Description: @DESCRIPTION@
Version: @VERSION@ Version: @VERSION@
Libs: -L\${libdir} -l@PACKAGE_NAME@ @LDFLAGS@ Libs: -L\${libdir} -l@PACKAGE_NAME@ @LDFLAGS@
Cflags: -I\${includedir} @CPPFLAGS@ Cflags: -I\${includedir} @CPPFLAGS@
Requires: @PKG_REQUIREMENTS@
EOF EOF
#### Cleanup If Makefile Exists #### #### Cleanup If Makefile Exists ####

@ -0,0 +1,9 @@
## @id $Id$
#
# This file has been added by bootstrap.sh on Sat, 09 May 2015 14:15:27 +0200
# Feel free to change it or even remove and rebuild it, up to your needs
#
## 1 2 3 4 5 6 7 8
## 45678901234567890123456789012345678901234567890123456789012345678901234567890
MAINTAINERCLEANFILES = makefile.in

@ -462,35 +462,45 @@ class Script: public QObject {
linenr+=oldsize-in.size()) linenr+=oldsize-in.size())
_script.push_back(parse(in, linenr)); _script.push_back(parse(in, linenr));
} }
void run(QWebFrame* frame, QString td = QString(), bool screenshots = true, QStringList print() {
int maxretries = 0) { QStringList result;
assert(_internalTestsuiteNode); for (auto cmd(_script.begin()); cmd!=_script.end(); ++cmd) {
run(frame, *_internalTestsuiteNode, td, result += (*cmd)->command();
screenshots, maxretries); //( @todo extract from parent }
return result;
}
void run(QWebFrame* frame) {
run(frame, _testsuites, targetdir(), _screenshots, _maxretries);
} }
void run(QWebFrame* frame, xml::Node& testsuiteNode, void 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) {
_internalTestsuiteNode = &testsuiteNode; _testsuites = testsuites;
assert(_internalTestsuiteNode);
_timeout = 20; // defaults to 20s _timeout = 20; // defaults to 20s
_ignoreSignalsUntil.clear(); _ignoreSignalsUntil.clear();
addSignals(frame); addSignals(frame);
_screenshots = screenshots; _screenshots = screenshots;
_maxretries = maxretries;
_timer.setSingleShot(true); _timer.setSingleShot(true);
targetdir(!td.isEmpty()
? td
: _testsuites->children()
? xmlstr(_testsuites->last().attr("name"))
: "attachments");
if (!_testsuites->children()) {
xml::Node testsuite("testsuite");
testsuite.attr("name") = "Unnamed Test Suite";
(*_testsuites)<<testsuite;
}
int retries(0), back(0); int retries(0), back(0);
for (auto cmd(_script.begin()); cmd!=_script.end(); ++cmd) { for (auto cmd(_script.begin()); cmd!=_script.end(); ++cmd) {
xml::Node testcase("testcase"); xml::Node testcase("testcase");
try { try {
testcase.attr("classname") = testcase.attr("classname") = xmlattr(_testclass, true).toStdString();
testsuiteNode.attr("name");
//xmlattr((*cmd)->command(), true).toStdString();
testcase.attr("name") = testcase.attr("name") =
xmlattr((*cmd)->tag(), true).toStdString(); xmlattr((*cmd)->command(), true).toStdString();
if (!_ignores.size() || (*cmd)->tag()=="label") { // not ignored if (!_ignores.size() || (*cmd)->tag()=="label") { // not ignored
_timer.start(_timeout*1000); _timer.start(_timeout*1000);
testsuite(xmlstr(testsuiteNode.attr("name")));
targetdir(!td.isEmpty() ? td : xmlstr(testsuiteNode.attr("name")));
try { try {
if (!(*cmd)->execute(this, frame)) { if (!(*cmd)->execute(this, frame)) {
_timer.stop(); _timer.stop();
@ -501,7 +511,7 @@ class Script: public QObject {
xmlattr(_cerr).toStdString()); xmlattr(_cerr).toStdString());
_cout.clear(); _cout.clear();
_cerr.clear(); _cerr.clear();
testsuiteNode<<testcase; _testsuites->last()<<testcase;
break; // test is successfully finished break; // test is successfully finished
} }
} catch (PossibleRetryLoad& e) { } catch (PossibleRetryLoad& e) {
@ -511,7 +521,7 @@ class Script: public QObject {
try { // take a screenshot on error try { // take a screenshot on error
QString filename(Screenshot::screenshot QString filename(Screenshot::screenshot
((*cmd)->line(), targetdir(), ((*cmd)->line(), targetdir(),
QFileInfo(testsuite()).baseName(), _testclass,
QString("retry-%1") QString("retry-%1")
.arg((ulong)retries, 2, 10, .arg((ulong)retries, 2, 10,
QLatin1Char('0')), QLatin1Char('0')),
@ -563,7 +573,7 @@ class Script: public QObject {
xmlattr(_cerr).toStdString()); xmlattr(_cerr).toStdString());
_cout.clear(); _cout.clear();
_cerr.clear(); _cerr.clear();
testsuiteNode<<testcase; _testsuites->last()<<testcase;
} }
} catch (Exception& e) { } catch (Exception& e) {
_timer.stop(); _timer.stop();
@ -574,7 +584,7 @@ class Script: public QObject {
xmlattr(_cerr).toStdString()); xmlattr(_cerr).toStdString());
_cout.clear(); _cout.clear();
_cerr.clear(); _cerr.clear();
testsuiteNode<<testcase; _testsuites->last()<<testcase;
removeSignals(frame); removeSignals(frame);
e.line((*cmd)->line()); e.line((*cmd)->line());
if (screenshots) if (screenshots)
@ -582,22 +592,20 @@ class Script: public QObject {
{ {
QString filename(Screenshot::sourceHtml QString filename(Screenshot::sourceHtml
((*cmd)->line(), targetdir(), ((*cmd)->line(), targetdir(),
QFileInfo(testsuite()).baseName(), _testclass,
"error", frame)); "error", frame));
plainlog("[[ATTACHMENT|"+filename+"]]"); plainlog("[[ATTACHMENT|"+filename+"]]");
} { } {
QString filename(Screenshot::screenshot QString filename(Screenshot::screenshot
((*cmd)->line(), targetdir(), ((*cmd)->line(), targetdir(),
QFileInfo(testsuite()).baseName(), _testclass,
"error", frame)); "error", frame));
plainlog("[[ATTACHMENT|"+filename+"]]"); plainlog("[[ATTACHMENT|"+filename+"]]");
} }
} catch (... ) {} // ignore exception in screenshot } catch (... ) {} // ignore exception in screenshot
_internalTestsuiteNode = 0;
throw; throw;
} }
} }
_internalTestsuiteNode = 0;
removeSignals(frame); removeSignals(frame);
if (!_signals.empty()) throw UnhandledSignals(_signals); if (!_signals.empty()) throw UnhandledSignals(_signals);
} }
@ -613,18 +621,26 @@ class Script: public QObject {
bool screenshots() { bool screenshots() {
return _screenshots; return _screenshots;
} }
void testsuite(QString name) {
_testsuite = name;
}
QString testsuite() {
return _testsuite;
}
void targetdir(QString name) { void targetdir(QString name) {
_targetdir = name; _targetdir = name;
} }
QString targetdir() { QString targetdir() {
return _targetdir; return _targetdir;
} }
void testclass(QString tc) {
_testclass = tc;
}
QString testclass() {
return _testclass;
}
void testsuite(QString name) {
xml::Node testsuite("testsuite");
testsuite.attr("name") = xmlattr(name, true).toStdString();
testsuite.attr("timestamp") =
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString();
_testsuites->last().attr("failures") = "0";
(*_testsuites)<<testsuite;
}
Signal getSignal() { Signal getSignal() {
while (!_signals.size()) QCoreApplication::processEvents(); while (!_signals.size()) QCoreApplication::processEvents();
Signal res(_signals.front()); Signal res(_signals.front());
@ -655,10 +671,11 @@ class Script: public QObject {
_rvariables = o._rvariables; _rvariables = o._rvariables;
_timeout = o._timeout; _timeout = o._timeout;
_clicktype = o._clicktype; _clicktype = o._clicktype;
_testsuite = o._testsuite; _testsuites = o._testsuites;
_internalTestsuiteNode = o._internalTestsuiteNode; _testclass = o._testclass;
assert(_internalTestsuiteNode);
_targetdir = o._targetdir; _targetdir = o._targetdir;
_maxretries = o._maxretries;
_screenshots = o._screenshots;
_cout.clear(); _cout.clear();
_cerr.clear(); _cerr.clear();
_ignoreSignalsUntil.clear(); _ignoreSignalsUntil.clear();
@ -835,15 +852,16 @@ class Script: public QObject {
QString _cout; QString _cout;
QString _cerr; QString _cerr;
bool _screenshots; bool _screenshots;
int _maxretries;
QString _ignoreSignalsUntil; QString _ignoreSignalsUntil;
QMap<QString, QString> _variables; ///< variable mapping QMap<QString, QString> _variables; ///< variable mapping
QMap<LenString, LenString> _rvariables; ///< reverse variable mapping QMap<LenString, LenString> _rvariables; ///< reverse variable mapping
QMap<QString, std::shared_ptr<Function> > _functions; QMap<QString, std::shared_ptr<Function> > _functions;
int _timeout; int _timeout;
ClickType _clicktype; ClickType _clicktype;
QString _testsuite;
QString _targetdir; QString _targetdir;
xml::Node* _internalTestsuiteNode; ///< only valid within run std::shared_ptr<xml::Node> _testsuites; ///< only valid within run
QString _testclass;
}; };
class Do: public Command { class Do: public Command {
@ -1892,7 +1910,8 @@ class If: public Command {
"Match allows a regular expression."; "Match allows a regular expression.";
} }
QString command() const { QString command() const {
return tag(); return tag()+" "+_variable+" "+QString(_cmp)+" "+_value
+(_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, int) {
@ -1934,6 +1953,64 @@ class If: public Command {
std::shared_ptr<Script> _script; std::shared_ptr<Script> _script;
}; };
class TestSuite: public Command {
public:
QString tag() const {
return "testsuite";
}
QString description() const {
return
tag()+" <name>"
"\n\n"
"Start a testsuite and give it a name.";
}
QString command() const {
return tag()+" "+_name;
}
std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, int) {
std::shared_ptr<TestSuite> cmd(new TestSuite());
cmd->_name = args;
return cmd;
}
bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script);
script->testsuite(script->replacevars(_name));
return true;
}
private:
QString _name;
};
class TestCase: public Command {
public:
QString tag() const {
return "testcase";
}
QString description() const {
return
tag()+" <name>"
"\n\n"
"Start a testcase and give it a name.";
}
QString command() const {
return tag()+" "+_name;
}
std::shared_ptr<Command> parse(Script*, QString args,
QStringList&, int) {
std::shared_ptr<TestCase> cmd(new TestCase());
cmd->_name = args;
return cmd;
}
bool execute(Script* script, QWebFrame* frame) {
Logger log(this, script);
script->testclass(script->replacevars(_name));
return true;
}
private:
QString _name;
};
/* Template: /* Template:
class : public Command { class : public Command {
public: public:
@ -1965,7 +2042,7 @@ inline bool Screenshot::execute(Script* script, QWebFrame* frame) {
if (!script->screenshots()) return true; if (!script->screenshots()) return true;
Logger log(this, script); Logger log(this, script);
QString filename(screenshot(line(), script->targetdir(), QString filename(screenshot(line(), script->targetdir(),
QFileInfo(script->testsuite()).baseName(), script->testclass(),
script->replacevars(_filename), frame)); script->replacevars(_filename), frame));
log["[[ATTACHMENT|"+filename+"]]"]; log["[[ATTACHMENT|"+filename+"]]"];
return true; return true;
@ -2004,7 +2081,7 @@ inline void Command::subScript(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, parent->targetdir()); 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)));
@ -2042,6 +2119,8 @@ inline void Script::initPrototypes() {
add(new Function); add(new Function);
add(new Call); add(new Call);
add(new If); add(new If);
add(new TestSuite);
add(new TestCase);
} }
#endif #endif

@ -117,23 +117,17 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
try { try {
Script script; Script script;
connect(&script, SIGNAL(logging(QString)), SLOT(logging(QString))); connect(&script, SIGNAL(logging(QString)), SLOT(logging(QString)));
xml::Node testsuite("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'));
testsuite.attr("name") = "setup-script"; script.run(_web->page()->mainFrame(), testsuites, QString(), false);
testsuite.attr("timestamp") =
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString();
script.run(_web->page()->mainFrame(), testsuite, 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'));
testsuite.attr("name") = "setup-script"; script.run(_web->page()->mainFrame(), testsuites, QString(), false);
testsuite.attr("timestamp") =
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString();
script.run(_web->page()->mainFrame(), testsuite, QString(), false);
} catch (std::exception &x) { } catch (std::exception &x) {
QMessageBox::critical(this, tr("Script Failed"), QMessageBox::critical(this, tr("Script Failed"),
tr("Script failed with message:\n%1") tr("Script failed with message:\n%1")
@ -222,17 +216,14 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
_setupscriptactive->setEnabled(false); _setupscriptactive->setEnabled(false);
try { try {
_setupscriptstatus->setText(trUtf8("?")); _setupscriptstatus->setText(trUtf8("?"));
xml::Node testsuite("testsuite"); std::shared_ptr<xml::Node> testsuites(new xml::Node("testsuite"));
testsuite.attr("name") = "setup-script";
testsuite.attr("timestamp") =
QDateTime::currentDateTime().toString(Qt::ISODate).toStdString();
Script script; Script script;
TestWebPage page(0, true); TestWebPage page(0, true);
script.parse(_setupscript->toPlainText().split('\n')); script.parse(_setupscript->toPlainText().split('\n'));
script.run(page.mainFrame(), testsuite, 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'));
_setupScript.run(page.mainFrame(), testsuite, QString(), false);; _setupScript.run(page.mainFrame(), testsuites, QString(), false);;
_setupscriptstatus->setText(trUtf8("")); _setupscriptstatus->setText(trUtf8(""));
_setupscriptactive->setEnabled(true); _setupscriptactive->setEnabled(true);
} catch (std::exception &x) { } catch (std::exception &x) {

@ -16,6 +16,42 @@
#include <version.hxx> #include <version.hxx>
using namespace NAMESPACE; using namespace NAMESPACE;
/** @page junitXml Test Output XML Format
The test output XML format emulates JUnit's format, so that JUnit
tools can be used to evaluate ist, namely on tools like jenkins.
@code{.xml}
<testsuites>
<testsuite name="..." timestamp="..." failures="...">
<testcase classname="..." name="...">
<failure message="..." />
<system-out>...</system-out>
<system-err>...</system-err>
</testcase>
<testcase ... />
</testsuite>
<testsuite ...>
...
</testsuite>
<testsuites>
@endcode
The default name for a testsuite is the name of the test script
file. it can be overwritten using the @c testsuite statement. The
attribute @c failures contains the number of failed test cases.
The default classname for a testcase is @c testsuite-preparation
before the script runs, then in the script it is the name of the
current command and the classname equals to the testsuite's name.
If you specify testsuites, testcases in your script file, then
this overwrites the defaults. Here @c testsuite maps to the
testsuite's name, @c testcase maps to the next testcase's
classname.
*/
QString format(QString txt, int indent = 2, int cpl = 60) { QString format(QString txt, int indent = 2, int cpl = 60) {
QStringList res; QStringList res;
QStringList lines(txt.split('\n')); QStringList lines(txt.split('\n'));
@ -102,7 +138,7 @@ int main(int argc, char *argv[]) try {
int height(parser.value("height").toInt()); int height(parser.value("height").toInt());
QString target(parser.value("target-path")); QString target(parser.value("target-path"));
p.resize(width, height); p.resize(width, height);
xml::Node testsuites("testsuites"); std::shared_ptr<xml::Node> testsuites(new xml::Node("testsuites"));
Q_FOREACH(QString file, parser.positionalArguments()) { Q_FOREACH(QString file, parser.positionalArguments()) {
int expectedtestcases(-1); int expectedtestcases(-1);
xml::Node testsuite("testsuite"); xml::Node testsuite("testsuite");
@ -142,47 +178,48 @@ int main(int argc, char *argv[]) try {
testsuite<<testcase; testsuite<<testcase;
} }
} else { } else {
script.run(p.page()->mainFrame(), testsuite, testsuite.attr("failures") = "0";
(*testsuites)<<testsuite;
script.run(p.page()->mainFrame(), testsuites,
target+QDir::separator()+QFileInfo(file).baseName(), target+QDir::separator()+QFileInfo(file).baseName(),
true, retries); true, retries);
testsuite.attr("failures") = "0";
script.log("SUCCESS: "+file); script.log("SUCCESS: "+file);
} }
} catch (std::exception& e) { } catch (std::exception& e) {
script.log("FAILED: "+file+" with "+e.what()); script.log("FAILED: "+file+" with "+e.what());
xml::Node failure("failure"); xml::Node failure("failure");
failure.attr("message") = Script::xmlattr(e.what()).toStdString(); failure.attr("message") = Script::xmlattr(e.what()).toStdString();
testsuite[testsuite.children()-1]<<failure; testsuites->last().last()<<failure;
if (expectedtestcases==-1) if (expectedtestcases==-1)
testsuite.attr("failures") = "1"; testsuites->last().attr("failures") = "1";
else else
testsuite.attr("failures") = testsuites->last().attr("failures") =
mrw::string(expectedtestcases+1-testsuite.children()); mrw::string(expectedtestcases+1-testsuites->last().children());
if (parser.isSet("skipped")) { if (parser.isSet("skipped")) {
testcase.attr("name") = "skipped test case"; testcase.attr("name") = "skipped test case";
failure.attr("message") = "skipped due to previous failure"; failure.attr("message") = "skipped due to previous failure";
testcase<<failure; testcase<<failure;
for (int i(testsuite.children()); i<expectedtestcases; ++i) for (int i(testsuites->last().children()); i<expectedtestcases; ++i)
testsuite<<testcase; testsuites->last()<<testcase;
failed = true; failed = true;
} }
} }
if (expectedtestcases==-1) { if (expectedtestcases==-1) {
testsuite.attr("tests") = mrw::string(testsuite.children()); testsuites->last().attr("tests") =
mrw::string(testsuites->last().children());
} else { } else {
testsuite.attr("tests") = mrw::string(expectedtestcases); testsuites->last().attr("tests") = mrw::string(expectedtestcases);
} }
if (script.cout().size()) if (script.cout().size())
testsuite<<(xml::String("system-out") = testsuites->last()<<(xml::String("system-out") =
script.xmlattr(script.cout()).toStdString()); script.xmlattr(script.cout()).toStdString());
if (script.cerr().size()) if (script.cerr().size())
testsuite<<(xml::String("system-err") = testsuites->last()<<(xml::String("system-err") =
script.xmlattr(script.cerr()).toStdString()); script.xmlattr(script.cerr()).toStdString());
testsuites<<testsuite;
} }
if (parser.isSet("xml")) { // todo: write xml file if (parser.isSet("xml")) { // todo: write xml file
std::ofstream xmlfile(parser.value("xml").toStdString()); std::ofstream xmlfile(parser.value("xml").toStdString());
xmlfile<<testsuites<<std::endl; xmlfile<<(*testsuites)<<std::endl;
} }
return failed ? 1 : 0; return failed ? 1 : 0;
} catch (std::exception& e) { } catch (std::exception& e) {

Loading…
Cancel
Save