#!/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; } """ TEST_SKIPPED_TMPL = r""" int main(void) { printf("$fp: skipping test\n"); return 0; } """ def generate(options, outfile): outfile.write("/* AUTOGENERATED FILE - DO NOT EDIT */\n\n") outfile.write("#include \n") outfile.write("#include \n") outfile.write("#include \n") outfile.write("#include \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") if options['ifdef']: outfile.write("#ifdef %s\n" % options['ifdef']) 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)) if options['ifdef']: outfile.write("#else\n") outfile.write(Template(TEST_SKIPPED_TMPL).substitute(options)) outfile.write("#endif\n") 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': '', 'ifdef': '', # 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()