author | Alberto Bertogli
<albertito@blitiri.com.ar> 2012-08-25 15:59:11 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2012-08-26 21:46:09 UTC |
parent | 005a56fbcb5ab8045f9d51676c521b335f058552 |
.gitignore | +2 | -0 |
Makefile | +3 | -1 |
tests/Makefile | +12 | -1 |
tests/generated/Makefile | +79 | -0 |
tests/generated/README | +18 | -0 |
tests/generated/generate-test | +152 | -0 |
tests/generated/tests/malloc.conf | +9 | -0 |
tests/generated/tests/open.conf | +10 | -0 |
diff --git a/.gitignore b/.gitignore index 8b1881d..fa4df1a 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ preload/run/build-needlibdl tests/*.o tests/build-flags tests/test-? +tests/generated/build-flags +tests/generated/tests/*.[oc] diff --git a/Makefile b/Makefile index bae9e6b..81405ad 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,9 @@ utils_install: utils utils_uninstall: $(MAKE) -C utils uninstall -test: libfiu bindings +tests: test + +test: libfiu bindings preload $(MAKE) -C tests bindings: python2 python3 diff --git a/tests/Makefile b/tests/Makefile index 40a22a9..2109ee8 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -25,7 +25,7 @@ default: tests all: tests -tests: c-tests py-tests +tests: c-tests py-tests gen-tests # # C tests @@ -68,6 +68,17 @@ py-tests: $(patsubst %.py,py-run-%,$(PY_TESTS)) py-run-%: %.py $(NICE_PY) ./$< +# +# Generated tests +# + +gen-tests: + $(MAKE) -C generated + + +# +# Cleanup +# clean: # Normally, $C_OBJS and $C_BINS are removed by make after building, diff --git a/tests/generated/Makefile b/tests/generated/Makefile new file mode 100644 index 0000000..201f58b --- /dev/null +++ b/tests/generated/Makefile @@ -0,0 +1,79 @@ + +CFLAGS += -std=c99 -pedantic -Wall -rdynamic +ALL_CFLAGS = -I../../libfiu/ -L../../libfiu/ \ + -D_XOPEN_SOURCE=600 -D_GNU_SOURCE -fPIC -DFIU_ENABLE=1 $(CFLAGS) + +ifdef DEBUG +ALL_CFLAGS += -g +endif + +ifdef PROFILE +ALL_CFLAGS += -g -pg -fprofile-arcs -ftest-coverage +endif + +ifneq ($(V), 1) + NICE_CC = @echo " CC $@"; $(CC) + NICE_RUN = @echo " RUN $<"; \ + LD_LIBRARY_PATH=../../libfiu/ \ + LD_PRELOAD="../../preload/run/fiu_run_preload.so \ + ../../preload/posix/fiu_posix_preload.so" + NICE_GEN = @echo " GEN $@"; ./generate-test +else + NICE_CC = $(CC) + NICE_RUN = LD_LIBRARY_PATH=../../libfiu/ \ + LD_PRELOAD="../../preload/run/fiu_run_preload.so \ + ../../preload/posix/fiu_posix_preload.so" + NICE_GEN = ./generate-test +endif + +default: tests + +all: tests + + +CONF := $(wildcard tests/*.conf) +GEN_BIN := $(patsubst %.conf,%.bin,$(CONF)) + +tests: $(patsubst %,%-run,$(GEN_BIN)) + +%-run: % + $(NICE_RUN) ./$< + +# .bin from .c +%.bin: %.c build-flags + $(NICE_CC) $(ALL_CFLAGS) $< -lfiu -o $@ + +# .c from .conf +%.c: %.conf generate-test + $(NICE_GEN) -c $< -o $@ + +# Useful for manually generating the C-files, that otherwise get deleted as +# intermediates. +c-files: $(patsubst %.conf,%.c,$(CONF)) + + +BF = $(ALL_CFLAGS) ~ $(PREFIX) +build-flags: .force-build-flags + @if [ x"$(BF)" != x"`cat build-flags 2>/dev/null`" ]; then \ + if [ -f build-flags ]; then \ + echo "build flags changed, rebuilding"; \ + fi; \ + echo "$(BF)" > build-flags; \ + fi + + +# +# Cleanup +# + +clean: + rm -f $(GEN_BIN) $(patsubst %.bin,%.c,$(GEN_BIN)) + rm -f *.bb *.bbg *.da *.gcov *.gcda *.gcno gmon.out build-flags + +FORCE: + +.PHONY: default all clean \ + tests c-tests py-tests \ + .force-build-flags + + diff --git a/tests/generated/README b/tests/generated/README new file mode 100644 index 0000000..6c672c1 --- /dev/null +++ b/tests/generated/README @@ -0,0 +1,18 @@ + +These are autogenerated tests for testing the posix preload, to make sure the +functions are getting properly wrapped. + +Each test is configured by a .conf file in the conf/ directory. + +These are the allowed options ('-' means mandatory, '*' optional): + - fp: failure point corresponding to the function. + - call: how to call the function. + * prep: preparation steps (usually declaring variables). + * include: list of files to #include, space separated. + * success_cond: condition we expect to be true if the call succeeds. + * failure_cond: condition we expect to be true after we simulate a failure + (if not set, we will only validate that we simulated the failure). + * errno_on_fail: simulate this errno on failure. + +It is mandatory that a single section is defined; however, the name is only +for description purposes. diff --git a/tests/generated/generate-test b/tests/generated/generate-test new file mode 100755 index 0000000..23c9fa4 --- /dev/null +++ b/tests/generated/generate-test @@ -0,0 +1,152 @@ +#!/usr/bin/env python + +""" +Generate C testcases based on the given configuration file. + +It can be useful for testing many C functions in the same way, like when +testing a wrapper. +""" + +import sys +import ConfigParser +import argparse +from string import Template + + +def listify(x): + if isinstance(x, (str, unicode)): + return [x] + return x + + +TEST_SUCCESS_TMPL = r""" +int success(void) { + $prep + + fiu_disable("$fp"); + + $call + + if (! ($success_cond) ) { + printf("$fp - success condition is false\n"); + return -1; + } + + return 0; +} +""" + +TEST_FAILURE_TMPL = r""" +static int external_cb_was_called = 0; +int external_cb(const char *name, int *failnum, + void **failinfo, unsigned int *flags) { + external_cb_was_called++; + + *failinfo = (void *) $errno_on_fail; + + return *failnum; +} + +int failure(void) { + $prep + + fiu_enable_external("$fp", 1, NULL, 0, external_cb); + + $call + + fiu_disable("$fp"); + + if (external_cb_was_called != 1) { + printf("$fp - external callback not invoked\n"); + return -1; + } + + if (! ($errno_cond) ) { + printf("$fp - errno not set appropriately: "); + printf("errno:%d, cond:$errno_cond\n", errno); + return -1; + } + + if (! ($failure_cond) ) { + printf("$fp - failure condition is false\n"); + return -1; + } + + return 0; +} +""" + +TEST_MAIN_TMPL = r""" +int main(void) { + int s, f; + + s = success(); + f = failure(); + + return s + f; +} +""" + +def generate(options, outfile): + outfile.write("/* AUTOGENERATED FILE - DO NOT EDIT */\n\n") + includes = options.get("include", []) + if isinstance(includes, (str, unicode)): + includes = includes.split() + for i in includes: + outfile.write("#include <%s>\n" % i) + else: + outfile.write("\n\n") + + outfile.write("#include <fiu.h>\n") + outfile.write("#include <fiu-control.h>\n") + outfile.write("#include <stdio.h>\n") + outfile.write("#include <errno.h>\n") + + if 'errno_on_fail' in options: + options['errno_cond'] = \ + 'errno == %s' % options['errno_on_fail'] + else: + # Default the cond to true, and set failinfo to 0 in case it's + # used. + options['errno_cond'] = '1' + options['errno_on_fail'] = '0' + + outfile.write(Template(TEST_SUCCESS_TMPL).substitute(options)) + outfile.write(Template(TEST_FAILURE_TMPL).substitute(options)) + outfile.write(Template(TEST_MAIN_TMPL).substitute(options)) + +def main(): + parser = argparse.ArgumentParser( + description ="Generate C testcases") + parser.add_argument("-c", "--conf", metavar = "C", + required = True, type = file, + help = "configuration file") + parser.add_argument("-o", "--out", metavar = "F", + required = True, + help = "generated file") + + args = parser.parse_args() + + # Defaults for the optional configuration parameters. + conf_defaults = { + 'include': (), + 'prep': '', + + # These are C conditions that are always true. + 'success_cond': '1', + 'failure_cond': '1', + + # For errno_on_fail, we have a smarter logic so don't do + # anything. + } + + conf = ConfigParser.SafeConfigParser(conf_defaults) + conf.readfp(args.conf) + + section = conf.sections()[0] + + outfile = open(args.out, 'w') + generate(dict(conf.items(section)), outfile) + +if __name__ == "__main__": + main() diff --git a/tests/generated/tests/malloc.conf b/tests/generated/tests/malloc.conf new file mode 100644 index 0000000..db5f480 --- /dev/null +++ b/tests/generated/tests/malloc.conf @@ -0,0 +1,9 @@ + +[malloc] +fp: libc/mm/malloc +include: stdlib.h +prep: void *p = NULL; +call: p = malloc(8000); +success_cond: p != NULL +failure_cond: p == NULL + diff --git a/tests/generated/tests/open.conf b/tests/generated/tests/open.conf new file mode 100644 index 0000000..0bf367a --- /dev/null +++ b/tests/generated/tests/open.conf @@ -0,0 +1,10 @@ + +[open] +fp: posix/io/oc/open +include: sys/types.h sys/stat.h fcntl.h +prep: int fd = -1; +call: fd = open("/dev/null", O_RDONLY); +success_cond: fd != -1 +failure_cond: fd == -1 +errno_on_fail: ELOOP +