From 8afec7dd2803f6878c957c569b8d0670b17d0fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Tue, 5 May 2015 15:06:08 +0000 Subject: [PATCH] massively improved build system --- README | 17 +++- ax_check_qt.m4 | 41 ++++++++- ax_init_standard_project.m4 | 67 +++++++++++++-- bootstrap.sh | 162 +++++++++++++++++++++++++++++++++--- src/version.cxx | 13 +-- src/version.hxx | 14 +++- src/webrunner.cxx | 2 + 7 files changed, 290 insertions(+), 26 deletions(-) diff --git a/README b/README index 1606ac7..aa5112c 100644 --- a/README +++ b/README @@ -1,3 +1,18 @@ Test Your Web Application: GUI Web Testing Environment + Script Runner -Webtester consists of two binaries: webtester to interactively create your web application tests and webrunner to run your test scripts. \ No newline at end of file +Webtester consists of two binaries: webtester to interactively create your web application tests and webrunner to run your test scripts. + +There is a test GUI including browser to record user input while he surfs on the web and a test runner to run (recorded) test scripts. The tests can be integrated e.g. in a jenkins build job. It has been tested on Wordpress, Dokuwiki and Joomla pages. Joomla is difficult due to Javascript-Moo-Tools pollution. There's some specific support, that may help a bit, but to test Joomla sites, you need a lot of experience. Concluson: Avoid Joomla. + +Sample Script to search my old homepage on Google, klick on the link, there click on tab «Computer» and check the title for the text «Marcs Computerblog»: + +load https://google.com +expect load +setvalue input[name="q"] -> 'Marc Wäckerlin'; +click input[name="btnG"] +expect load +click a[href^="/url?q=https://marc.waeckerlin.org/&"] +expect load https://marc.waeckerlin.org/doku.php +click a[href="/computer/index"] +expect load https://marc.waeckerlin.org/computer/index +exists h1.sectionedit1 -> Marcs Computerblog diff --git a/ax_check_qt.m4 b/ax_check_qt.m4 index 7f8f73e..ce7628b 100644 --- a/ax_check_qt.m4 +++ b/ax_check_qt.m4 @@ -1,6 +1,10 @@ # SYNOPSIS # -# AX_CXX_CHECK_QT([qt_prefix], [list-of-qt-modules], [optional-modules]) +# Check if a module exists: +# AX_CXX_CHECK_QT([qt_prefix], [list-of-qt-modules], [optional-modules]) +# +# Abort if a module does not exist: +# AX_CXX_REQUIRE_QT([qt_prefix], [list-of-qt-modules], [optional-modules]) # # DESCRIPTIONS # @@ -32,6 +36,7 @@ # exist only in Qt5, but not in Qt4, such as QtWidgets or # QtWebKitWidgets + AC_DEFUN([AX_CXX_QT_TOOL], [ if test -z "$HAVE_$1"; then HAVE_$1=1 @@ -146,6 +151,40 @@ qrc_%.cxx: %.qrc AC_SUBST(AX_ADDITIONAL_QT_RULES_HACK) ]) +# SYNOPSIS +# +# AX_CXX_CHECK_QT([qt_prefix], [list-of-qt-modules], [optional-modules]) +# +# DESCRIPTIONS +# +# qt_prefix +# +# Each call to AX_CXX_CHECK_QT should have a different prefix +# value (with a few exceptions discussed later on). This value, +# usually provided in uppercase, is used as prefix to the +# variables holding the compiler flags and libraries reported by +# pkg-config. +# +# For instance, if your prefix was to be FOO you'll be provided +# two variables FOO_CFLAGS and FOO_LIBS. +# +# This will also be used as message during the configure checks: +# checking for FOO.... +# +# list-of-modules +# +# A single call to the macro can check for the presence of one or +# more qt modules; you'll see later how to make good use of this +# feature. Each entry in the list can have a version comparison +# specifier, with the same syntax as the Requires keyword in the +# data files themselves. +# +# optional-modules +# +# Optional list of more, optional modules, e.g. modules that +# exist only in Qt5, but not in Qt4, such as QtWidgets or +# QtWebKitWidgets + AC_DEFUN([AX_REQUIRE_QT], [ AX_CHECK_QT([$1], [$2], [$3]) if ! test "$HAVE_$1" -eq 1; then diff --git a/ax_init_standard_project.m4 b/ax_init_standard_project.m4 index befb629..4d98d08 100644 --- a/ax_init_standard_project.m4 +++ b/ax_init_standard_project.m4 @@ -3,6 +3,8 @@ ## 1 2 3 4 5 6 7 8 ## 45678901234567890123456789012345678901234567890123456789012345678901234567890 +# define least version number from subversion's revision number: +# it is taken modulo 256 due to a bug on Apple's MacOSX m4_define(x_least, m4_esyscmd_s( LEAST="ERROR-UNDEFINED-REVISION-to-be-built-in-subdirectory-of-svn-checkout" for path in . .. ../..; do @@ -15,6 +17,8 @@ m4_define(x_least, m4_esyscmd_s( done echo $ECHO_N $LEAST )) + +## bugreport mail address is taken from in first line of AUTHORS m4_define(x_bugreport, m4_esyscmd_s( head -1 AUTHORS | \ sed -n 's,.*<\([-_.a-z0-9A-Z]*@[-_.a-z0-9A-Z]*\)>.*,\1,gp' @@ -38,6 +42,11 @@ dnl refers to ${prefix}. Thus we have to use `eval' twice. test "$exec_prefix_NONE" && exec_prefix=NONE ]) +# add target dependencies to an existing makefile.in +# - parameters: +# $1 = existing target +# $2 = new dependency for that target +# $3 = filename of makefile.in AC_DEFUN([AX_ADD_MAKEFILE_TARGET_DEP], [ sh_add_makefile_target_dep() { sed -i ':a;/^'${1}':.*\\$/{N;s/\\\n//;ta};s/^'${1}':.*$/& '${2}'/' "${srcdir}/${3}" @@ -51,13 +60,34 @@ AC_DEFUN([AX_ADD_MAKEFILE_TARGET_DEP], [ fi ]) +# Same as AC_SUBST, but adds -Dname="value" option to CPPFLAGS +# - parameters: +# $1 = variable name AC_DEFUN([AX_SUBST], [ AC_SUBST([$1]) - tmp_var="${$1//$'\n'/\n}" - AM_CPPFLAGS+=' -D$1='"'${tmp_var//#/\\#}'" + tmp_var=$(echo "${$1}" | sed ':a;N;$!ba;s/\n/\\n/g') + tmp_var=${tmp_var//\"/\\\"} + tmp_var=${tmp_var//\'/\'\"\'\"\'} + tmp_var=${tmp_var//#/\\#} + AM_CPPFLAGS+=" '-D$1=\"${tmp_var}\"'" AC_SUBST(AM_CPPFLAGS) ]) +# must be called on the right position in configure.ac +# +# configure.ac must start with: +# +# m4_define(x_package_name, YOUR_PACKAGE_NAME) # project's name +# m4_define(x_major, MAJOR_NUMBER) # project's major version +# m4_define(x_minor, MINOR_NUMBER) # project's minor version +# m4_include(ax_init_standard_project.m4) +# AC_INIT(x_package_name, x_major.x_minor.x_least, x_bugreport, x_package_name) +# AM_INIT_AUTOMAKE([1.9 tar-pax]) +# AX_INIT_STANDARD_PROJECT +# +# you change nothing but: YOUR_PACKAGE_NAME, MAJOR_NUMBER, MINOR_NUMBER +# +# configures the basic environment AC_DEFUN([AX_INIT_STANDARD_PROJECT], [ AM_CPPFLAGS+=" '-DMAKE_STRING(X)=\#X' '-DNAMESPACE=${PACKAGE_NAME}'" AX_SUBST(NUMBERS) @@ -65,31 +95,25 @@ AC_DEFUN([AX_INIT_STANDARD_PROJECT], [ README=$(tail -n +3 README) AX_SUBST(README) _AM_SUBST_NOTMAKE([README]) - README_STR=$(sed 's,",\\",g; :a;N;$!ba;s/\n/\\n/g' README) - AM_CPPFLAGS+=" '-DREADME_STR=\"${README_STR}\"'" DESCRIPTION=$(head -1 README) AX_SUBST(DESCRIPTION) _AM_SUBST_NOTMAKE([DESCRIPTION]) AUTHOR=$(head -1 AUTHORS) AX_SUBST(AUTHOR) _AM_SUBST_NOTMAKE([AUTHOR]) - AM_CPPFLAGS+=" '-DAUTHOR_STR=\"${AUTHOR}\"'" DISTRO=$(lsb_release -sc) AX_SUBST(DISTRO) BUILD_NUMBER=${BUILD_NUMBER:-1} AX_SUBST(BUILD_NUMBER) BUILD_DATE=$(date -R) AX_SUBST(BUILD_DATE) - AM_CPPFLAGS+=" '-DBUILD_DATE_STR=\"${BUILD_DATE}\"'" if test -f "${PROJECT_NAME}-logo.png"; then PROJECT_LOGO="${PROJECT_NAME}-logo.png" fi AX_SUBST(PROJECT_LOGO) - AM_CPPFLAGS+=" '-DPROJECT_LOGO_STR=\"${PROJECT_LOGO}\"'" if test -f "${PROJECT_NAME}-icon.png"; then PROJECT_ICON="${PROJECT_NAME}-icon.png" fi - AM_CPPFLAGS+=" '-DPROJECT_ICON_STR=\"${PROJECT_ICON}\"'" AX_SUBST(PROJECT_ICON) AC_CONFIG_FILES([makefile]) AX_ADD_MAKEFILE_TARGET_DEP([clean-am], [clean-standard-project-targets], [makefile.in]) @@ -111,6 +135,7 @@ maintainer-clean-standard-project-targets: EOF ]) +# use this in configure.ac to support C++ AC_DEFUN([AX_USE_CXX], [ m4_include(ax_cxx_compile_stdcxx_11.m4) AC_LANG(C++) @@ -165,6 +190,7 @@ maintainer-clean-cxx-targets: EOF ]) +# use this in configure.ac to support CppUnit for C++ unit tests AC_DEFUN([AX_USE_CPPUNIT], [ AM_PATH_CPPUNIT([1.0.0], [have_cppunit="yes"], [have_cppunit="no"]) # infos and warnings @@ -182,6 +208,7 @@ maintainer-clean-test-targets: EOF ]) +# use this in configure.ac to support C++ examples AC_DEFUN([AX_BUILD_EXAMPLES], [ AC_CONFIG_FILES([examples/makefile]) AX_ADD_MAKEFILE_TARGET_DEP([maintainer-clean-am], [maintainer-clean-example-targets], [examples/makefile.in]) @@ -193,6 +220,7 @@ maintainer-clean-example-targets: EOF ]) +# use this in configure.ac to support C++ libraries AC_DEFUN([AX_USE_LIBTOOL], [ # libtool versioning LIB_MAJOR=m4_eval(x_major+x_minor) @@ -220,6 +248,7 @@ uninstall-data-libtool-pkg: EOF ]) +# use this in configure.ac to support debian packages AC_DEFUN([AX_USE_DEBIAN_PACKAGING], [ README_DEB=$(tail -n +3 README | sed -e 's/^$/./g' -e 's/^/ /g') AC_SUBST(README_DEB) @@ -240,6 +269,7 @@ distclean-debian-targets: EOF ]) +# use this in configure.ac to support RPM packages AC_DEFUN([AX_USE_RPM_PACKAGING], [ # m4_include(ax_rpm_rules.m4) AC_CONFIG_FILES([${PACKAGE_NAME}.spec]) @@ -253,6 +283,7 @@ rpm: dist EOF ]) +# use this in configure.ac to support Doxygen documentation generation AC_DEFUN([AX_USE_DOXYGEN], [ AC_CHECK_PROG(have_doxygen, doxygen, yes, no) AC_CHECK_PROG(have_dot, dot, yes, no) @@ -303,6 +334,18 @@ uninstall-documentation: EOF ]) +# require a specific package, with fallback: test for a header +# - parameter: +# $1 = unique id (no special characters) +# $2 = module name +# $3 = a header file to find (optional) +# $4 = alternative module names (space separated, optional) +# +# uses PKG_CHECK_MODULES to test for a module +# then, if given, looks for the header file +# if header file is not found, searches in alternative modules +# sets all flags, so that the module can be used everywhere +# fails if not found AC_DEFUN([AX_PKG_REQUIRE], [ PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES([$1], [$2], [ @@ -380,6 +423,14 @@ AC_DEFUN([AX_PKG_REQUIRE], [ fi ]) +# check if a specific package exists +# - parameter: +# $1 = unique id (no special characters) +# $2 = module name (optional, if different from id) +# +# uses PKG_CHECK_MODULES to test for a module +# sets automake conditional HAVE_$1 to 0 (not found) or 1 (found) +# sets all flags, so that the module can be used everywhere AC_DEFUN([AX_PKG_CHECK], [ PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES([$1], [m4_default([$2], [$1])], [ diff --git a/bootstrap.sh b/bootstrap.sh index 1d3da55..5b19c13 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -14,20 +14,147 @@ ## added file header ## +MY_NAME=${0##*/} +PROJECT_PATH=$(pwd) +DEFAULT_PROJECT_NAME=${PROJECT_PATH##*/} + configure=0 while test $# -gt 0; do case "$1" in (--configure|-c) configure=1;; + (--version|-v) echo "$Id$"; exit;; + (--help|-h) less <" and run ${MY_NAME} again. + +FILES TO EDIT + + After creation of the files, you can edit them according to your needs. Please don't forget to redo your edits after rebuilding a file. Most files don't even need to be edited, they work out of the box. + + The following files normally require editing: + * AUTHORS + * README + * configure.ac + * src/makefile.am + * test/makefile.am + * examples/makefile.am + +FILE DEPENDENCIES + + You should rebuild (remove and run (see above) the files, whenever you change the configuration a dependent, i.e.: + + * test/makefile.am depends on AX_USE_LIBTOOL + * doc/doxyfile.in depends on AX_BUILD_EXAMPLES + * debian/control.in depends on AX_USE_DOXYGEN, AX_USE_CPPUNIT, AX_CXX_QT, AX_CXX_CHECK_QT, AX_USE_LIBTOOL + * debian/${DEFAULT_PROJECT_NAME}.install depends on AX_USE_LIBTOOL + * debian/${DEFAULT_PROJECT_NAME}.dirs depends on AX_USE_LIBTOOL + * debian/${DEFAULT_PROJECT_NAME}-dev.install depends on AX_USE_LIBTOOL + * debian/${DEFAULT_PROJECT_NAME}-dev.dirs depends on AX_USE_LIBTOOL + +FILES + + * AUTHORS: First line is the main author and used in Debian and RPM packaging, so there must be a GPG key that matches to this line. + * README: First line is a short description of your project, then an empty line must follow. All remaining lines are a long description of your project. this information is copied, e.g. in Debian or RPM packages. In C++ namespace NAMESPACE { + /// get package string which consists of package name and package version std::string package_string(); + /// get package name std::string package_name(); + /// get package version std::string version(); + /// get code build date std::string build_date(); + /// get author, i.e. copyright holder std::string author(); + /// get short package description (1st line of README) std::string description(); + /// get long package description (starting at 3rd line in README) + std::string readme(); + /// get package logo file name std::string logo(); + /// get package icon file name std::string icon(); + /// used for what filename extern const std::string WHAT; + /// used for ident filename extern const std::string IDENT; } EOF @@ -209,19 +348,22 @@ namespace NAMESPACE { return PACKAGE_VERSION; } std::string build_date() { - return BUILD_DATE_STR; + return BUILD_DATE; } std::string author() { - return AUTHOR_STR; + return AUTHOR; } std::string description() { - return README_STR; + return DESCRIPTION; + } + std::string readme() { + return README; } std::string logo() { - return PROJECT_LOGO_STR; + return PROJECT_LOGO; } std::string icon() { - return PROJECT_ICON_STR; + return PROJECT_ICON; } const std::string WHAT("#(@) " PACKAGE_STRING); const std::string IDENT("\$Id: " PACKAGE_STRING); diff --git a/src/version.cxx b/src/version.cxx index 51fb800..c87b294 100644 --- a/src/version.cxx +++ b/src/version.cxx @@ -18,19 +18,22 @@ namespace NAMESPACE { return PACKAGE_VERSION; } std::string build_date() { - return BUILD_DATE_STR; + return BUILD_DATE; } std::string author() { - return AUTHOR_STR; + return AUTHOR; } std::string description() { - return README_STR; + return DESCRIPTION; + } + std::string readme() { + return README; } std::string logo() { - return PROJECT_LOGO_STR; + return PROJECT_LOGO; } std::string icon() { - return PROJECT_ICON_STR; + return PROJECT_ICON; } const std::string WHAT("#(@) " PACKAGE_STRING); const std::string IDENT("$Id: " PACKAGE_STRING); diff --git a/src/version.hxx b/src/version.hxx index be12a0c..3a560af 100644 --- a/src/version.hxx +++ b/src/version.hxx @@ -1,6 +1,6 @@ /*! @file - @id $ + @id $Id$ */ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 @@ -8,14 +8,26 @@ #include namespace NAMESPACE { + /// get package string which consists of package name and package version std::string package_string(); + /// get package name std::string package_name(); + /// get package version std::string version(); + /// get code build date std::string build_date(); + /// get author, i.e. copyright holder std::string author(); + /// get short package description (1st line of README) std::string description(); + /// get long package description (starting at 3rd line in README) + std::string readme(); + /// get package logo file name std::string logo(); + /// get package icon file name std::string icon(); + /// used for what filename extern const std::string WHAT; + /// used for ident filename extern const std::string IDENT; } diff --git a/src/webrunner.cxx b/src/webrunner.cxx index 622965c..e8e174d 100644 --- a/src/webrunner.cxx +++ b/src/webrunner.cxx @@ -45,6 +45,8 @@ QString help(const Script& s) { <