diff --git a/.gitignore b/.gitignore index c89dffc5e..f66bd5b09 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ autom4te.cache semantic.cache wiki/backups/* doc/devel/draw/*.png +m4/* diff --git a/SConstruct b/SConstruct index 9b4ce1dcb..dc4dc392a 100644 --- a/SConstruct +++ b/SConstruct @@ -33,7 +33,7 @@ TESTDIR = 'tests' ICONDIR = 'icons' VERSION = '0.1+pre.01' TOOLDIR = './admin/scons' -SVGRENDERER = 'admin/render-icon' +SCRIPTDIR = './admin' #-----------------------------------Configuration # NOTE: scons -h for help. @@ -47,6 +47,7 @@ import os import sys sys.path.append(TOOLDIR) +sys.path.append(SCRIPTDIR) from Buildhelper import * from LumieraEnvironment import * @@ -58,10 +59,12 @@ def setupBasicEnvironment(): """ define cmdline options, build type decisions """ EnsurePythonVersion(2,3) - EnsureSConsVersion(0,96,90) + EnsureSConsVersion(1,0) - opts = defineCmdlineOptions() - env = LumieraEnvironment(options=opts + Decider('MD5-timestamp') # detect changed files by timestamp, then do a MD5 + + vars = defineCmdlineVariables() + env = LumieraEnvironment(variables=vars ,toolpath = [TOOLDIR] ,tools = ["default", "BuilderGCH", "BuilderDoxygen"] ) @@ -82,7 +85,7 @@ def setupBasicEnvironment(): , CCFLAGS='-Wall -Wextra ' , CFLAGS='-std=gnu99' ) - RegisterIcon_Builder(env,SVGRENDERER) + RegisterIcon_Builder(env) handleNoBugSwitches(env) env.Append(CPPDEFINES = '_GNU_SOURCE') @@ -98,8 +101,8 @@ def setupBasicEnvironment(): appendCppDefine(env,'PKGDATADIR','LUMIERA_CONFIG_PATH=\\"$PKGLIBDIR/:.\\"' ,'LUMIERA_CONFIG_PATH=\\"$DESTDIR/share/lumiera/:.\\"') - prepareOptionsHelp(opts,env) - opts.Save(OPTIONSCACHEFILE, env) + prepareOptionsHelp(vars,env) + vars.Save(OPTIONSCACHEFILE, env) return env def appendCppDefine(env,var,cppVar, elseVal=''): @@ -139,40 +142,40 @@ def handleVerboseMessages(env): -def defineCmdlineOptions(): - """ current options will be persisted in a options cache file. - you may define custom options in a separate file. +def defineCmdlineVariables(): + """ several toggles and configuration variables can be set on the commandline, + current settings will be persisted in a options cache file. + you may define custom variable settings in a separate file. Commandline will override both. """ - opts = Options([OPTIONSCACHEFILE, CUSTOPTIONSFILE]) - opts.AddOptions( + vars = Variables([OPTIONSCACHEFILE, CUSTOPTIONSFILE]) + vars.AddVariables( ('ARCHFLAGS', 'Set architecture-specific compilation flags (passed literally to gcc)','') ,('CC', 'Set the C compiler to use.', 'gcc') ,('CXX', 'Set the C++ compiler to use.', 'g++') - ,PathOption('CCACHE', 'Integrate with CCache', '', PathOption.PathAccept) - ,PathOption('DISTCC', 'Invoke C/C++ compiler commands through DistCC', '', PathOption.PathAccept) - ,EnumOption('BUILDLEVEL', 'NoBug build level for debugging', 'ALPHA', - allowed_values=('ALPHA', 'BETA', 'RELEASE')) - ,BoolOption('DEBUG', 'Build with debugging information and no optimisations', False) - ,BoolOption('OPTIMIZE', 'Build with strong optimisation (-O3)', False) - ,BoolOption('VALGRIND', 'Run Testsuite under valgrind control', True) - ,BoolOption('VERBOSE', 'Print full build commands', False) + ,PathVariable('CCACHE', 'Integrate with CCache', '', PathVariable.PathAccept) + ,PathVariable('DISTCC', 'Invoke C/C++ compiler commands through DistCC', '', PathVariable.PathAccept) + ,EnumVariable('BUILDLEVEL', 'NoBug build level for debugging', 'ALPHA', allowed_values=('ALPHA', 'BETA', 'RELEASE')) + ,BoolVariable('DEBUG', 'Build with debugging information and no optimisations', False) + ,BoolVariable('OPTIMIZE', 'Build with strong optimisation (-O3)', False) + ,BoolVariable('VALGRIND', 'Run Testsuite under valgrind control', True) + ,BoolVariable('VERBOSE', 'Print full build commands', False) ,('TESTSUITES', 'Run only Testsuites matching the given pattern', '') -# ,BoolOption('OPENGL', 'Include support for OpenGL preview rendering', False) -# ,EnumOption('DIST_TARGET', 'Build target architecture', 'auto', +# ,BoolVariable('OPENGL', 'Include support for OpenGL preview rendering', False) +# ,EnumVariable('DIST_TARGET', 'Build target architecture', 'auto', # allowed_values=('auto', 'i386', 'i686', 'x86_64' ), ignorecase=2) - ,PathOption('DESTDIR', 'Installation dir prefix', '/usr/local') - ,PathOption('PKGLIBDIR', 'Installation dir for plugins, defaults to DESTDIR/lib/lumiera', '',PathOption.PathAccept) - ,PathOption('PKGDATADIR', 'Installation dir for default config, usually DESTDIR/share/lumiera', '',PathOption.PathAccept) - ,PathOption('SRCTAR', 'Create source tarball prior to compiling', '..', PathOption.PathAccept) - ,PathOption('DOCTAR', 'Create tarball with developer documentation', '..', PathOption.PathAccept) + ,PathVariable('DESTDIR', 'Installation dir prefix', '/usr/local') + ,PathVariable('PKGLIBDIR', 'Installation dir for plugins, defaults to DESTDIR/lib/lumiera', '',PathVariable.PathAccept) + ,PathVariable('PKGDATADIR', 'Installation dir for default config, usually DESTDIR/share/lumiera', '',PathVariable.PathAccept) + ,PathVariable('SRCTAR', 'Create source tarball prior to compiling', '..', PathVariable.PathAccept) + ,PathVariable('DOCTAR', 'Create tarball with developer documentation', '..', PathVariable.PathAccept) ) - return opts + return vars -def prepareOptionsHelp(opts,env): +def prepareOptionsHelp(vars,env): prelude = """ USAGE: scons [-c] [OPTS] [key=val [key=val...]] [TARGETS] Build and optionally install Lumiera. @@ -191,7 +194,7 @@ Special Targets: Configuration Options: """ - Help(prelude + opts.GenerateHelpText(env)) + Help(prelude + vars.GenerateHelpText(env)) @@ -215,11 +218,6 @@ def configurePlatform(env): if not conf.CheckLibWithHeader('dl', 'dlfcn.h', 'C'): problems.append('Functions for runtime dynamic loading not available.') - if not conf.CheckPkgConfig('nobugmt', 200909.1): - problems.append('Did not find NoBug [http://www.pipapo.org/pipawiki/NoBug].') - else: - conf.env.mergeConf('nobugmt') - if not conf.CheckLibWithHeader('pthread', 'pthread.h', 'C'): problems.append('Did not find the pthread lib or pthread.h.') else: @@ -234,6 +232,11 @@ def configurePlatform(env): else: print 'Valgrind not found. The use of Valgrind is optional; building without.' + if not conf.CheckPkgConfig('nobugmt', 201005.1): + problems.append('Did not find NoBug [http://www.lumiera.org/nobug_manual.html].') + else: + conf.env.mergeConf('nobugmt') + if not conf.CheckCXXHeader('tr1/memory'): problems.append('We rely on the std::tr1 proposed standard extension for shared_ptr.') @@ -248,6 +251,12 @@ def configurePlatform(env): problems.append('We need the boost regular expression lib (incl. binary lib for linking).') + if conf.CheckLib(symbol='clock_gettime'): + print 'Using function clock_gettime() as defined in the C-lib...' + else: + if not conf.CheckLib(symbol='clock_gettime', library='rt'): + problems.append('No library known to provide the clock_gettime() function.') + if not conf.CheckPkgConfig('gavl', 1.0): problems.append('Did not find Gmerlin Audio Video Lib [http://gmerlin.sourceforge.net/gavl.html].') else: @@ -280,9 +289,6 @@ def configurePlatform(env): if not conf.CheckPkgConfig('xv') : problems.append('Need libXv...') if not conf.CheckPkgConfig('xext'): problems.append('Need libXext.') -# if not conf.CheckPkgConfig('sm'): Exit(1) -# -# obviously not needed? # report missing dependencies @@ -323,7 +329,8 @@ def defineBuildTargets(env, artifacts): setup sub-environments with special build options if necessary. We use a custom function to declare a whole tree of srcfiles. """ - # use PCH to speed up building + + # use PCH to speed up building // disabled for now due to strange failures # env['GCH'] = ( env.PrecompiledHeader('$SRCDIR/pre.hpp') # + env.PrecompiledHeader('$SRCDIR/pre_a.hpp') # ) @@ -355,7 +362,7 @@ def defineBuildTargets(env, artifacts): # the Lumiera GTK GUI envGtk = env.Clone() - envGtk.mergeConf(['gtkmm-2.4','cairomm-1.0','gdl','gthread-2.0','xv','xext','sm']) + envGtk.mergeConf(['gtkmm-2.4','gthread-2.0','cairomm-1.0','gdl','xv','xext','sm']) envGtk.Append(CPPDEFINES='LUMIERA_PLUGIN', LIBS=core) objgui = srcSubtree(envGtk,'$SRCDIR/gui') diff --git a/admin/render-icon.py b/admin/render_icon.py similarity index 99% rename from admin/render-icon.py rename to admin/render_icon.py index 0f9cee294..e3f76c129 100755 --- a/admin/render-icon.py +++ b/admin/render_icon.py @@ -1,6 +1,6 @@ #!/usr/bin/python # -# render-icons.py - Icon rendering utility script +# render_icons.py - Icon rendering utility script # # Copyright (C) Lumiera.org # 2008, Joel Holdsworth diff --git a/admin/scons/Buildhelper.py b/admin/scons/Buildhelper.py index 159dc4721..f8e349a5e 100644 --- a/admin/scons/Buildhelper.py +++ b/admin/scons/Buildhelper.py @@ -196,12 +196,13 @@ def checkCommandOption(env, optID, val=None, cmdName=None): -def RegisterIcon_Builder(env, renderer): +def RegisterIcon_Builder(env): """ Registers Custom Builders for generating and installing Icons. Additionally you need to build the tool (rsvg-convert.c) used to generate png from the svg source using librsvg. """ - renderer = __import__(renderer) # load python script for invoking the render + + import render_icon as renderer # load Joel's python script for invoking the rsvg-convert (SVG render) renderer.rsvgPath = env.subst("$BINDIR/rsvg-convert") def invokeRenderer(target, source, env): diff --git a/admin/scons/LumieraEnvironment.py b/admin/scons/LumieraEnvironment.py index 44b76ed07..8b6a4b594 100644 --- a/admin/scons/LumieraEnvironment.py +++ b/admin/scons/LumieraEnvironment.py @@ -74,32 +74,19 @@ class LumieraEnvironment(Environment): return False self.libInfo[libID] = libInfo = LumieraEnvironment() + libInfo["ENV"]["PKG_CONFIG_PATH"] = os.environ.get("PKG_CONFIG_PATH") libInfo.ParseConfig ('pkg-config --cflags --libs '+ libID ) if alias: self.libInfo[alias] = libInfo return libInfo - - def Glob (self, pattern): - """ temporary workaround; newer versions of SCons provide this as a global function """ - pattern = self.subst(pattern) - return glob.glob(pattern) - - def AddMethod (self, function): - """ temporary workaround; newer versions of SCons provide this as a global function """ - self.__dict__[function.__name__] = function.__get__(self) - - -#### temporary pre 1.0 SCons compatibility hack #### -_ver = map(int, SCons.__version__.split('.')[:2]) -_old = (_ver[0]<1 and _ver[1]<97) -if _old: - ConfigBase = SCons.SConf.SConf -else: - ConfigBase = SCons.SConf.SConfBase - del LumieraEnvironment.Glob - del LumieraEnvironment.AddMethod - # use the official impl present since SCons 0.98 - # use the new name of the config context base class + + + + + +# extending the 'Configure' functionality of SCons, +# especially for library dependency checking +ConfigBase = SCons.SConf.SConfBase diff --git a/admin/vg-run.sh b/admin/vg-run.sh new file mode 100644 index 000000000..f8d82040b --- /dev/null +++ b/admin/vg-run.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# +# vg-run.sh - convenience wrapper script to run an executable with valgrind +# using "typical options"; output goes to a logfile, which is +# fed to less afterwards. +# +# a valgrind suppression file is generated automatically, in +# case there is an executable "vgsuppression" located in the same +# directory as the target executable +# +# Ichthyo 8/2007 +# +LOGFILE=,valgrind.log +SUPPRESS=vgsuppression +VALGRINDFLAGS=${VALGRINDFLAGS:---leak-check=yes --show-reachable=yes --demangle=yes} + +EXECUTABLE=$1 +if [[ ! -x $EXECUTABLE ]]; then + echo -e "ERROR: executable \"$EXECUTABLE\" not found.\n\n" + exit -1 +fi + + +PATHPREFIX=${EXECUTABLE%/*} +SUPPRESS="$PATHPREFIX/$SUPPRESS" + +if [[ -x $SUPPRESS ]]; then + if [[ $SUPPRESS -nt $SUPPRESS.supp ]]; then + echo 'generating valgrind supression file...' + + valgrind $VALGRINDFLAGS -q --gen-suppressions=all $SUPPRESS 2>&1 \ + | awk '/^{/ {i = 1;} /^}/ {i = 0; print $0;} {if (i == 1) print $0;}' >$SUPPRESS.supp + echo 'done.' + fi + SUPPRESSIONFLAG="--suppressions=$SUPPRESS.supp" +else + echo 'no suppression.' +fi + +echo "running......$@" + +valgrind $VALGRINDFLAGS --log-file=$LOGFILE.%p $SUPPRESSIONFLAG $@ & +PID=$! +wait $PID +less $LOGFILE.$PID + diff --git a/oldsrc/DIR_INFO b/oldsrc/DIR_INFO deleted file mode 100644 index e3f9d5b47..000000000 --- a/oldsrc/DIR_INFO +++ /dev/null @@ -1 +0,0 @@ -Cinelerra2 sources, added per case when needed diff --git a/src/lib/nobugcfg.cpp b/src/lib/nobugcfg.cpp index ecbde0e79..c66760cd8 100644 --- a/src/lib/nobugcfg.cpp +++ b/src/lib/nobugcfg.cpp @@ -37,11 +37,11 @@ namespace lumiera { { NOBUG_INIT; -#ifdef DEBUG +#if NOBUG_MODE_ALPHA static uint callCount = 0; ASSERT ( 0 == callCount++ ); #endif } - + + } - diff --git a/src/tool/rsvg-convert.c b/src/tool/rsvg-convert.c index 655a25720..d8216e608 100644 --- a/src/tool/rsvg-convert.c +++ b/src/tool/rsvg-convert.c @@ -129,8 +129,6 @@ main (int argc, char **argv) /* Set the locale so that UTF-8 filenames work */ setlocale(LC_ALL, ""); - g_thread_init(NULL); - g_option_context = g_option_context_new (_("- SVG Converter")); g_option_context_add_main_entries (g_option_context, options_table, NULL); g_option_context_set_help_enabled (g_option_context, TRUE); diff --git a/src/tool/try.cpp b/src/tool/try.cpp index 14eb754ff..16ad0dad2 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -13,6 +13,8 @@ // 7/08 - combining partial specialisation and subclasses // 10/8 - abusing the STL containers to hold noncopyable values // 6/09 - investigating how to build a mixin template providing an operator bool() +// 12/9 - tracking down a strange "warning: type qualifiers ignored on function return type" +// 1/10 - can we determine at compile time the presence of a certain function (for duck-typing)? #include "include/nobugcfg.h" diff --git a/src/tool/vgsuppression.c b/src/tool/vgsuppression.c index 514be9ecb..2cca0e68e 100644 --- a/src/tool/vgsuppression.c +++ b/src/tool/vgsuppression.c @@ -23,6 +23,7 @@ just place any problematic calls where valgrind whines about in main (with comments please) */ +#include int diff --git a/tests/SConscript b/tests/SConscript index 65ac7aa79..5fe43738d 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -90,6 +90,10 @@ if testsuites: pluginpath = os.environ.get('LUMIERA_PLUGIN_PATH') if testsuites: testEnv['ENV']['LUMIERA_PLUGIN_PATH'] = pluginpath + +# specify path to test.conf +testEnv['ENV']['TEST_CONF'] = env.File("test.conf").abspath + testDir = env.Dir('#$BINDIR') runTest = env.File("test.sh").abspath diff --git a/tests/test.conf b/tests/test.conf new file mode 100755 index 000000000..38cf8082d --- /dev/null +++ b/tests/test.conf @@ -0,0 +1 @@ +LOGSUPPRESS='^\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}[:!] \(TRACE\|INFO\|NOTICE\|WARNING\|ERR\|TODO\|PLANNED\|FIXME\|DEPRECATED\|UNIMPLEMENTED\|RESOURCE_ANNOUNCE\|RESOURCE_ENTER\|RESOURCE_STATE\|RESOURCE_LEAVE\):' diff --git a/tests/test.h b/tests/test.h index 987892956..01374701a 100644 --- a/tests/test.h +++ b/tests/test.h @@ -28,7 +28,7 @@ #include -NOBUG_DEFINE_FLAG (tests); +NOBUG_DEFINE_FLAG (TESTS); LUMIERA_ERROR_DEFINE (TEST, "test error"); #define TESTS_BEGIN \ @@ -36,7 +36,7 @@ int \ main (int argc, const char** argv) \ { \ NOBUG_INIT; \ - NOBUG_INIT_FLAG (tests); \ + NOBUG_INIT_FLAG (TESTS); \ \ if (argc == 1) \ { \ diff --git a/tests/test.sh b/tests/test.sh index 89de9ae54..77eae39e7 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright (C) Lumiera.org -# 2007 - 2008, Christian Thaeter +# Copyright (C) Lumiera.org +# 2007, 2008, 2009, 2010, Christian Thaeter # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as @@ -25,35 +25,134 @@ # TESTMODE=FIRSTFAIL # stop testing on the first failure -export LC_ALL=C -NOBUG_LOGREGEX='^\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}: \(TRACE\|INFO\|NOTICE\|WARNING\|ERR\|TODO\|PLANNED\|FIXME\|DEPRECATED\|UNIMPLEMENTED\):' +#intro Test.sh +#intro ======= +#intro Christian Thäter +#intro +#intro A shell script driving software tests. +#intro + +#=intro +#=tests Writing tests +# =run +#=config +#=configf +# =make +# =control +#=valgrind +#=libtool +#_ +#_ Index +#_ ----- +#_ +#=index +#_ + +LC_ALL=C + +#config HEAD- Configuration; configuration; configure tests +#config +#config PARA LOGSUPPRESS; LOGSUPPRESS; suppress certain lines from stderr +#config LOGSUPPRESS='^\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}: \(TRACE\|INFO\|NOTICE\|WARNING\|ERR\):' +#config +#config Programms sometimes emit additional diagnostics on stderr which is volatile and not necessary for +#config validating the output the `LOGSUPRESS` variable can be set to a regex to filter this things out. +#config The default as shown above filters some NoBug annotations and non fatal logging out. +#config +LOGSUPPRESS='^\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}[:!] \(TRACE\|INFO\|NOTICE\|WARNING\|ERR\):' + +#config PARA Resource Limits; ulimit; constrain resource limits +#config It is possible to set some limits for tests to protect the system against really broken cases. +#config Since running under valgrind takes consinderable more resources there are separate variants for +#config limits when running under valgrind. +#config +#config LIMIT_CPU=5 +#config Maximal CPU time the test may take after it will be killed with SIGXCPU. This protects agaist Lifelocks. +#config +#config LIMIT_TIME=10 +#config Maximal wall-time a test may take after this it will be killed with SIGKILL. Protects against Deadlocks. +#config +#config LIMIT_VSZ=524288 +#config Maximal virtual memory size the process may map, allocations/mappings will fail when this limit is reached. +#config Protects against memory leaks. +#config +#config LIMIT_VG_CPU=20 +#config LIMIT_VG_TIME=30 +#config LIMIT_VG_VSZ=524288 +#config Same variables again with limits when running under valgrind. +#config +LIMIT_CPU=5 +LIMIT_TIME=10 +LIMIT_VSZ=524288 +LIMIT_VG_CPU=20 +LIMIT_VG_TIME=30 +LIMIT_VG_VSZ=524288 + + +#configf HEAD~ Configuration Files; configuration files; define variables to configure the test +#configf +#configf `test.sh` reads config files from the following location if they are exist +#configf * 'test.conf' from the current directory +#configf * '$srcdir/test.conf' `$srcdir` is set by autotools +#configf * '$srcdir/tests/test.conf' `tests/` is suspected as default directory for tests +#configf * '$TEST_CONF' a user defineable variable to point to a config file +#configf +test -f 'test.conf' && source test.conf +test -n "$srcdir" -a -e "$srcdir/test.conf" && source "$srcdir/test.conf" +test -n "$srcdir" -a -e "$srcdir/tests/test.conf" && source "$srcdir/tests/test.conf" +test -n "$TEST_CONF" -a -e "$TEST_CONF" && source "$TEST_CONF" + + arg0="$0" -srcdir="$(dirname "$arg0")" -vgsuppression_mangle='/^\(\(==\)\|\(\*\*\)[0-9]*\(==\)\|\(\*\*\)\)\|\(\(\*\*[0-9]*\*\* \)\?[0-9]\{10,\}: ECHO:\)/d;' +TESTDIR="$(dirname "$arg0")" -ulimit -S -t 5 -v 524288 + +#libtool HEAD Libtool; libtool; support for libtool +#libtool When test.sh detects the presence of './libtool' it runs all tests with +#libtool `./libtool --mode=execute`. +#libtool +LIBTOOL_EX= +if test -x ./libtool; then + LIBTOOL_EX="./libtool --mode=execute" +fi + +#valgrind HEAD- Valgrind; valgrind; valgrind support +#valgrind Test are run under valgrind supervision by default, if not disabled. +#valgrind +#valgrind PARA VALGRINDFLAGS; VALGRINDFLAGS; control valgrind options +#valgrind VALGRINDFLAGS="--leak-check=yes --show-reachable=yes" +#valgrind +#valgrind `VALGRINDFLAGS` define the options which are passed to valgrind. This can be used to override +#valgrind the defaults or switching the valgrind tool. The special case `VALGRINDFLAGS=DISABLE` will disable +#valgrind valgrind for the tests. +#valgrind +#valgrind HEAD~ Generating Valgrind Suppression Files; vgsuppression; ignore false positives +#valgrind When there is a 'vgsuppression' executable in the current dir (build by something external) then +#valgrind test.sh uses this to generate a local 'vgsuppression.supp' file and uses that to suppress +#valgrind all errors generated by 'vgsuppression'. The Idea here is that one adds code which triggers known +#valgrind false positives in 'vgsuppression'. Care must be taken that this file is simple and does +#valgrind not generate true positives. +#valgrind +ulimit -S -t ${LIMIT_CPU:-5} -v ${LIMIT_VSZ:-524288} valgrind="" +LIMIT_TIME_REAL="$LIMIT_TIME" if [ "$VALGRINDFLAGS" = 'DISABLE' ]; then echo "valgrind explicit disabled" else if [ "$(which valgrind)" ]; then - ulimit -S -t 20 + ulimit -S -t ${ULIMIT_VG_CPU:-20} -v ${ULIMIT_VG_VSZ:-524288} + LIMIT_TIME_REAL="$LIMIT_VG_TIME" if [[ -x 'vgsuppression' ]]; then if [[ 'vgsuppression' -nt 'vgsuppression.supp' ]]; then echo 'generating valgrind supression file' - if [[ -x ".libs/vgsuppression" ]]; then - ./libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes -q --gen-suppressions=all vgsuppression 2>&1 \ - | sed -e "$vgsuppression_mangle" >vgsuppression.supp - else - valgrind --leak-check=yes --show-reachable=yes -q --gen-suppressions=all ./vgsuppression 2>&1 \ - | sed -e "$vgsuppression_mangle" >vgsuppression.supp - fi + $LIBTOOL_EX $(which valgrind) ${VALGRINDFLAGS:---leak-check=yes --show-reachable=yes} -q --gen-suppressions=all vgsuppression 2>&1 \ + | awk '/^{/ {i = 1;} /^}/ {i = 0; print $0;} {if (i == 1) print $0;}' >vgsuppression.supp fi - valgrind="$(which valgrind) --leak-check=yes --show-reachable=no --suppressions=vgsuppression.supp -q $VALGRINDFLAGS" + valgrind="$(which valgrind) ${VALGRINDFLAGS:---leak-check=yes --show-reachable=no} --suppressions=vgsuppression.supp -q" else - valgrind="$(which valgrind) --leak-check=yes --show-reachable=no -q $VALGRINDFLAGS" + valgrind="$(which valgrind) ${VALGRINDFLAGS:---leak-check=yes --show-reachable=no -q}" fi else echo "no valgrind found, go without it" @@ -77,40 +176,193 @@ fi date >,testlog -function compare_regex() # rxfile plainfile +function compare_template() # template plainfile { - local regex + local template local line local miss local lineno=1 - local regexno=1 + local templateno=1 { - IFS='' read -u 3 -r regex || return 0 + IFS='' read -u 3 -r template || return 0 IFS='' read -u 4 -r line || { echo "no output"; return 1; } while true; do - if [[ $line =~ $regex ]]; then - IFS='' read -u 4 -r line || - if IFS='' read -u 3 -r regex; then - echo "premature end in output, expecting: '$regex':$regexno" - return 1 + local cmd="${template%%:*}:" + local arg="${template#*: }" + + case $cmd in + 'regex_cont:') + if [[ $line =~ $arg ]]; then + IFS='' read -u 4 -r line || + if IFS='' read -u 3 -r template; then + echo "premature end in output, expecting $template:$templateno" + return 1 + else + return 0 + fi + : $((++lineno)) + miss=0 else - return 0 + if [[ $((++miss)) -gt 1 ]]; then + echo -e "'$line':$lineno\ndoes not match\n$template:$templateno" + return 1 + fi + IFS='' read -u 3 -r template || { echo "more output than expected: '$line':$lineno"; return 1; } + : $((++templateno)) fi - : $((++lineno)) - miss=0 - else - if [[ $((++miss)) -gt 1 ]]; then - echo -e "'$line':$lineno\ndoes not match\n'$regex':$regexno" + ;; + 'literal:') + if [[ "$line" = "$arg" ]]; then + IFS='' read -u 3 -r template && IFS='' read -u 4 -r line || { + return 0 + } + else + echo -e "'$line':$lineno\ndoes not match\n$template:$templateno" return 1 fi - IFS='' read -u 3 -r regex || { echo "more output than expected: '$line':$lineno"; return 1; } - : $((++regexno)) - fi + ;; + *) + echo "UNKOWN MATCH COMMAND '$cmd'" 1>&2 + exit + ;; + esac done } 3<"$1" 4<"$2" } +#tests HEAD- Writing Tests; tests; how to write testsuites +#tests Tests are nothing more than bash scripts with some functions from the test.sh +#tests framework defined. Test.sh looks in the current directory for all files which ending in .test +#tests and runs them in alphabetical order. The selection of this tests can be constrained with the +#tests `TESTSUITES` environment variable. +#tests +#tests HEAD~ Testsuites; test files; writing tests +#tests It is common to start the name of the '.test' files with a 2 digi number to give them a proper +#tests order: '10foo.test', '20bar.test' and so on. Each such test should only test a certain aspect of +#tests the system. You have to select the testing binary with the `TESTING` function and then write +#tests certain TEST's defining how the test should react. Since tests are shell scripts it is possible +#tests to add some supplemental commands there to set and clean up the given test environment. +#tests +#tests HEAD^ TESTING; TESTING; set the test binary +#tests TESTING "message" test_program +#tests +#tests Selects the test binary for the follwing tests, prints an informal message. +#tests +#tests `message`:: +#tests message to be printed +#tests `test_program`:: +#tests an existing program to drive the tests or a shell function +#tests +#tests ---- +#tests TESTING "Testing a.out" ./a.out +#tests ---- +#tests +function TESTING() +{ + echo + echo "$1" + echo -e "\n#### $1, $TESTFILE, $2" >>,testlog + TESTBIN="$2" +} + +#tests HEAD^ TEST; TEST; single test +#tests TEST "title" arguments.. <>,send_stdin + 'if:') + if $arg; then + condstack="1$condstack" + else + condstack="0$condstack" + fi ;; - 'out') - echo "$arg" >>,expect_stdout + 'elseif:') + if [[ "${condstack:0:1}" = "0" ]]; then + if $arg; then + condstack="1${condstack:1}" + else + condstack="0${condstack:1}" + fi + else + condstack="2${condstack:1}" + fi ;; - 'err') - echo "$arg" >>,expect_stderr + 'else:') + if [[ "${condstack:0:1}" != "0" ]]; then + condstack="0${condstack:1}" + else + condstack="1${condstack:1}" + fi ;; - 'return') - expect_return="$arg" - ;; - '#'*|'') - : + 'endif:') + condstack="${condstack:1}" ;; *) - echo "UNKOWN TEST COMMAND '$cmd'" 1>&2 - exit + if [[ "${condstack:0:1}" = "1" ]]; then + case $cmd in + 'msg:') + echo "MSG $arg" + ;; + 'in:') + echo "$arg" >>,send_stdin + ;; + 'out:') + echo "regex_cont: $arg" >>,expect_stdout + ;; + 'err:') + echo "regex_cont: $arg" >>,expect_stderr + ;; + 'out-lit:') + echo "literal: $arg" >>,expect_stdout + ;; + 'err-lit:') + echo "literal: $arg" >>,expect_stderr + ;; + 'return:') + expect_return="$arg" + ;; + '#'*|':') + : + ;; + *) + echo "UNKOWN TEST COMMAND '$cmd'" 1>&2 + exit + ;; + esac + fi ;; esac done @@ -185,7 +486,7 @@ function TEST() if declare -F | grep $TESTBIN >&/dev/null; then CALL= elif test -x $TESTBIN; then - CALL="env $TESTBIN_PREFIX" + CALL="env $LIBTOOL_EX $valgrind" else CALL='-' echo -n >,stdout @@ -194,17 +495,31 @@ function TEST() fi if test "$CALL" != '-'; then - if test -f ,send_stdin; then - $CALL $TESTBIN "$@" <,send_stdin 2>,stderr >,stdout + ( + $CALL $TESTBIN "$@" <,send_stdin 2>,stderr >,stdout + echo $? >,return + ) & else - $CALL $TESTBIN "$@" 2>,stderr >,stdout + ( + $CALL $TESTBIN "$@" 2>,stderr >,stdout + echo $? >,return + ) & fi &>/dev/null - return=$? + pid=$! + + # watchdog + ( sleep $LIMIT_TIME_REAL && kill -KILL $pid ) &>/dev/null & + wpid=$! + wait $pid + return=$(<,return) + if [[ "$return" -le 128 ]]; then + kill -INT $wpid >&/dev/null + fi if test -f ,expect_stdout; then - grep -v "$NOBUG_LOGREGEX" <,stdout >,tmp - if ! compare_regex ,expect_stdout ,tmp >>,cmptmp; then + grep -v "$LOGSUPPRESS" <,stdout >,tmp + if ! compare_template ,expect_stdout ,tmp >>,cmptmp; then echo "unexpected data on stdout" >>,testtmp cat ,cmptmp >>,testtmp ((fails+=1)) @@ -213,9 +528,9 @@ function TEST() fi if test -f ,expect_stderr; then - grep -v "$NOBUG_LOGREGEX" <,stderr >,tmp + grep -v "$LOGSUPPRESS" <,stderr >,tmp cat ,tmp >>,testtmp - if ! compare_regex ,expect_stderr ,tmp >>,cmptmp; then + if ! compare_template ,expect_stderr ,tmp >>,cmptmp; then echo "unexpected data on stderr" >>,testtmp cat ,cmptmp >>,testtmp ((fails+=1)) @@ -256,6 +571,23 @@ function TEST() fi } +#tests HEAD^ PLANNED; PLANNED; deactivated test +#tests PLANNED "title" arguments.. <&2 - if test -f $i; then - source $i + echo "### $TESTFILE" >&2 + if test -f $TESTFILE; then + source $TESTFILE fi done echo @@ -295,20 +627,6 @@ function RUNTESTS() } } -function TESTING() -{ - echo - echo "$1" - echo -e "\n#### $1" >>,testlog - - if [[ -x ".libs/$2" ]]; then - TESTBIN_PREFIX="./libtool --mode=execute $valgrind" - else - TESTBIN_PREFIX="$valgrind" - fi - TESTBIN="$2" -} - TESTSUITES="${TESTSUITES}${1:+${TESTSUITES:+,}$1}" RUNTESTS