def version(tool, nlines=1): """ Return version information as reported by the execution of TOOL --version, expected on the first NLINES of output. If TOOL is not available from PATH, return a version text indicating unavailability. If TOOL is 'gcc', append the target for which it was configured to the base version info. """ # If TOOL is not on PATH, return a version text indicating unavailability. # This situation is legitimate here for gnatemu when running through a # probe, and if we happen to actually need the tool later on, we'll see # test failures anyway. if not which(tool): return 'N/A' # --version often dumps more than the version number on a line. A # copyright notice is typically found there as well. Our heuristic # here is to strip everything past the first comma. def version_on_line(text): cprpos = text.find(',') return text[0:cprpos] if cprpos != -1 else text tool_version_output = Run([tool, '--version']).out.split('\n') version_info = '\n'.join( [version_on_line(l) for l in tool_version_output[0:nlines]]) if tool == 'gcc': gcc_target = Run([tool, '-dumpmachine']).out.strip() version_info += ' [%s]' % gcc_target return version_info
def resolve_backtraces(self, executable, out): """ Resolve GNAT backtraces in `out` to symbolic. :param str executable: the binary :return: the modified output that includes symbolic backtraces """ result = [] next_is_backtrace = False for line in out.splitlines(): result.append(line) if 'Call stack traceback locations:' in line: next_is_backtrace = True elif next_is_backtrace: next_is_backtrace = False if platform.system() == 'Darwin': p = Run(['atos', '-o', executable] + line.split()) result.append(p.out) elif platform.system() == 'Linux': p = Run(['addr2line', '--functions', '--demangle=gnat', '--basenames', '--inlines', '-e', executable] + line.split()) result.append(p.out) return '\n'.join(result)
def tear_up(self): super(Testsuite, self).tear_up() # It seems that arguments parsing in GNATpython leaves None in # store_true options when they are not passed. So here we need to # coerce to bool. self.global_env['pretty_print'] = bool( self.global_env['options'].pretty_print) if self.coverage_enabled: # Create a directory that we'll use to: # # 1) collect coverage data for each testcase; # 2) generate the HTML report. os.mkdir(self.coverage_dir) os.mkdir(self.langkit_support_coverage_dir) self.global_env['coverage_dir'] = self.coverage_dir def report(p, pname): if p.status != 0: raise RuntimeError( '{} build failed (GPRbuild returned {})\n{}'.format( pname, p.status, p.out)) # Build Langkit_Support so that each testcase does not try to build it # in parallel. To achieve this, we build+install it with all library # kinds, and then update the environment so that testcases can assume # it is installed. if not self.global_env['options'].disable_tear_up_builds: install_prefix = os.path.join(self.global_env['working_dir'], 'install') if os.path.exists(install_prefix): shutil.rmtree(install_prefix) gargs = ['-p', '-P', self.langkit_support_project_file] cargs = ['-cargs', '-O0', '-g', '-gnatwae'] if self.coverage_enabled: gargs.append('--subdirs=gnatcov') cargs.extend(['-fdump-scos', '-fpreserve-control-flow']) for build in ('static', 'relocatable'): p = Run(['gprbuild'] + gargs + ['-XLIBRARY_TYPE={}'.format(build)] + cargs, output=PIPE) report(p, 'Langkit support - build {}'.format(build)) p = Run([ 'gprinstall', '-P', self.langkit_support_project_file, '-p', '--sources-subdir=include/langkit_support', '-XLIBRARY_TYPE={}'.format(build), '--prefix={}'.format(install_prefix), '--build-var=LIBRARY_TYPE', '--build-name={}'.format(build) ]) report(p, 'Langkit support - install {}'.format(build)) # Make the installed library available to all testcases add_to_path('PATH', os.path.join(install_prefix, 'bin')) add_to_path('LD_LIBRARY_PATH', os.path.join(install_prefix, 'lib')) add_to_path('GPR_PROJECT_PATH', os.path.join(install_prefix, 'share', 'gpr'))
def realize_theories(): for real in gp_realized: process = Run([why3_bin, '-L', '.', '-T', '_gnatprove_standard.' + real, '-o', realize_subdir, '-D', os.path.join(driver_dir, 'coq-realize.drv')]) print process.out for real in am_realized: process = Run([why3_bin, '-L', '.', '-T', 'ada__model.' + real, '-o', realize_subdir, '-D', os.path.join(driver_dir, 'coq-realize.drv')]) print process.out
def init(self): """Initialize a new Git repository and configure the remote.""" self.remote = 'origin' p = Run([self.git, 'init'], cwd=self.dest) if p.status != 0: self.__error('git init failed\n%s' % p.out) p = Run([self.git, 'remote', 'add', self.remote, self.url], cwd=self.dest) if p.status != 0: self.__error('git remote add failed\n%s' % p.out) self.fetch()
def process(debug, file, cbmcargs): """Process Ada file with gnat2goto and cbmc""" unit = os.path.splitext(file)[0] jsout = unit + ".json_symtab" symtab = unit + ".symtab" gotoprog = unit + ".goto_functions" out = unit + ".out" errout = unit + ".error" stdoutp = unit + "stdoutp" cbmcerr = unit + "cbmc_error" cmd = ["gnat2goto", file] g2go_results = Run(["gnat2goto", file], output=stdoutp, error=errout) stdout_file = open(stdoutp) errout_file = open(errout) stdout_text = stdout_file.read() errout_text = errout_file.read() stdout_file.close() errout_file.close() if stdout_text != '': print "Standard_Output from gnat2goto " + unit + ":" print stdout_text if errout_text != '': print "Standard_Error from gnat2goto " + unit + ":" print errout_text if g2go_results.status != 0: print "ERROR code ", g2go_results.status, " returned by gnat2goto when translating " + unit print "CBMC not run" return "" # only run the following if gnat2goto succeeded # Run(["cbmc", jsout, "--show-symbol-table"], output=symtab) # Run(["cbmc", jsout, "--show-goto-functions"], output=gotoprog) cmdline = ["cbmc", jsout] if cbmcargs: cmdline += cbmcargs.split(" ") results = Run(cmdline, error=cbmcerr) cbmcerr_file = open(cbmcerr) cbmcerr_text = cbmcerr_file.read() cbmcerr_file.close() if cbmcerr_text != '': print "Error from cbmc " + unit + ":" print cbmcerr_text if results.status != 0 and results.status != 10: print "ERROR code ", results.status, "returned by cbmc when processing " + unit return filter_timing(results.out)
def gnatmerge(script=None, project=None, options=None, sort_result=True): """Invoke gnatmerge PARAMETERS script: merge script to process project: GNAT project file options: Additional options """ cmd = [ "gnatmerge", ] if script is not None: cmd += ["-e", script] if project is not None: cmd += ["-P", project] if options is not None: cmd += options process = Run(cmd) if process.status: print "gnatmerge exit with status " + str(process.status) strlist = str.splitlines(process.out) if sort_result: strlist.sort() for line in strlist: print line
def run_and_check(self, argv, env=None, for_coverage=False): """ Run a subprocess with `argv` and check it completes with status code 0. In case of failure, the test output is appended to the actual output and a TestError is raised. :param list[str] argv: List of arguments to pass to the subprocess. :param None|dict[str, str] env: If provided, environment variables to pass to the subprocess. :param bool for_coverage: If true and if coverage is enabled, produce a trace file. """ program = argv[0] if for_coverage and self.coverage_enabled: trace_file = self.coverage_file('trace') argv = ['gnatcov', 'run', '-o', trace_file] + argv p = Run(argv, cwd=self.working_dir(), timeout=self.TIMEOUT, output=self.output_file, error=STDOUT, env=env) if p.status != 0: self.result.actual_output += ( '{} returned status code {}\n'.format(program, p.status)) self.result.actual_output += self.read_file(self.output_file) raise TestError( '{} returned status code {}'.format(program, p.status))
def run_and_check(self, argv): """ Run a subprocess with `argv` and check it completes with status code 0. In case of failure, the test output is appended to the actual output and a TestError is raised. """ program = argv[0] p = Run(argv, cwd=self.working_dir(), timeout=self.TIMEOUT, output=self.output_file, error=STDOUT) if p.status != 0: self.result.actual_output += ( '{} returned status code {}\n'.format(program, p.status)) self.result.actual_output += self.read_file(self.output_file) raise TestError('{} returned status code {}'.format( program, p.status)) # convert Windows directory separators to expected one if sys.platform == 'win32': content = string.replace(self.read_file(self.output_file), '\\', '/') with open(self.output_file, 'w') as f: return f.write(content)
def process_cbmc(debug, files, specs, cbmcargs): """Process Ada file with gnat2goto and cbmc""" jsout = [] for file in files: unit = os.path.splitext(file)[0] file_jsout = unit + ".json_symtab" # json_symtab files are not generated for generic bodies if os.path.exists(file_jsout): jsout.append(file_jsout) for file in specs: unit = os.path.splitext(file)[0] file_jsout = unit + ".json_symtab" # json_symtab are only generated for specifications if it is a generic instantiation if os.path.exists(file_jsout): jsout.append(file_jsout) cbmcerr = TEST_NAME + "cbmc_error" cmdline = ["cbmc"] + jsout if cbmcargs: cmdline += cbmcargs.split(" ") results = Run(cmdline, error=cbmcerr) cbmcerr_file = open (cbmcerr) cbmcerr_text = cbmcerr_file.read() cbmcerr_file.close() CBMC_VER_SUCC_CODE=0 CBMC_VER_FAIL_CODE=10 if cbmcerr_text != '': print "Error from cbmc " + unit + ":" print cbmcerr_text if results.status != CBMC_VER_SUCC_CODE and results.status != CBMC_VER_FAIL_CODE: print "ERROR code ", results.status, "returned by cbmc when processing " + unit return filter_timing(results.out)
def process_gnat2goto(debug, file, is_main): """Process Ada file with gnat2goto and cbmc""" unit = os.path.splitext(file)[0] jsout = unit + ".json_symtab" errout = unit + ".error" stdoutp = unit + "stdoutp" gnat2gotoargs = [] if not is_main: gnat2gotoargs.append("--no-cprover-start") cmd = ["gnat2goto", file] + gnat2gotoargs g2go_results = Run(cmd, output=stdoutp, error=errout) stdout_file = open (stdoutp) errout_file = open (errout) stdout_text = stdout_file.read() errout_text = errout_file.read() stdout_file.close() errout_file.close() if stdout_text != '': print "Standard_Output from gnat2goto " + unit + ":" print stdout_text if errout_text != '': print "Standard_Error from gnat2goto " + unit + ":" print errout_text if g2go_results.status != 0: print "ERROR code ", g2go_results.status, " returned by gnat2goto when translating " + unit print "CBMC not run" return False return True
def run_list (cmd, dir=None, env=None): """Execute the provided CMD command-list (command name + arguments), temporarily switching to the DIR directory unless None, dumping a .log file tracking the command output in the directory where the command executes. ENV, if not none, is expected to hold a dictionary of environment variable values to be made visible to the executed command, on top of os.environ.""" oriwd = os.getcwd() print "from : %s" % oriwd if dir: print "hopat : %s" % dir os.chdir (dir) print "run : %s" % ' '.join(cmd) out = os.path.basename(cmd[0])+".log" p = Run (cmd, output=out, env=env, ignore_environ=False) fail_if ( p.status != 0, "execution failed\n" + "log was:\n" + contents_of(out)) os.chdir (oriwd)
def tear_up(self): super(Testsuite, self).tear_up() # It seems that arguments parsing in GNATpython leaves None in # store_true options when they are not passed. So here we need to # coerce to bool. self.global_env['pretty_print'] = bool( self.global_env['options'].pretty_print) if self.coverage_enabled: # Create a directory that we'll use to: # # 1) collect coverage data for each testcase; # 2) generate the HTML report. os.mkdir(self.coverage_dir) os.mkdir(self.langkit_support_coverage_dir) self.global_env['coverage_dir'] = self.coverage_dir def report(p, pname): if p.status != 0: raise RuntimeError( '{} build failed (GPRbuild returned {})\n{}'.format( pname, p.status, p.out)) # Build Langkit_Support so that each testcase does not try to build it # in parallel. if not self.global_env['options'].disable_tear_up_builds: gargs = ['-p', '-P', self.langkit_support_project_file] cargs = ['-cargs', '-O0', '-g', '-gnatwae'] if self.coverage_enabled: gargs.append('--subdirs=gnatcov') cargs.extend(['-fdump-scos', '-fpreserve-control-flow']) p = Run(['gprbuild'] + gargs + cargs, output=PIPE) report(p, "Langkit support")
def cleanup(self, project): """Cleanup possible remnants of previous builds.""" Run([GPRCLEAN, "-P%s" % project] + self.gprconfoptions + self.gprvaroptions) rm('*.xcov') rm('*.bin')
def update(self, ref=None, ignore_diff=False, picks=None): """Update the repository. :param ref: the ref to checkout, by default current_remote/current_branch :type ref: str | None :param ignore_diff: If True do not compute any diff :type ignore_diff: bool :param picks: list of additional git references to cherry-pick :type picks: list[str] | None :return: (last revision, log since last update) :rtype: (str, str) """ if ref is None: ref = "%s/%s" % (self.remote, self.branch) last_rev = self.get_rev('HEAD') # Clean stale / deleted remote branches Run([self.git, 'remote', 'prune', self.remote], cwd=self.dest) self.fetch() self.checkout(ref) # Cherry pick additional changes if picks is not None: for p in picks: self.fetch(p, pick=True) return (self.rev, self.log("%s..%s" % (last_rev, self.rev), ignore_diff=ignore_diff))
def process_cbmc(debug, files, cbmcargs): """Process Ada file with gnat2goto and cbmc""" jsout = [] for file in files: unit = os.path.splitext(file)[0] file_jsout = unit + ".json_symtab" jsout.append(file_jsout) cbmcerr = TEST_NAME + "cbmc_error" cmdline = ["cbmc"] + jsout if cbmcargs: cmdline += cbmcargs.split(" ") results = Run(cmdline, error=cbmcerr) cbmcerr_file = open (cbmcerr) cbmcerr_text = cbmcerr_file.read() cbmcerr_file.close() CBMC_VER_SUCC_CODE=0 CBMC_VER_FAIL_CODE=10 if cbmcerr_text != '': print "Error from cbmc " + unit + ":" print cbmcerr_text if results.status != CBMC_VER_SUCC_CODE and results.status != CBMC_VER_FAIL_CODE: print "ERROR code ", results.status, "returned by cbmc when processing " + unit return filter_timing(results.out)
def exec_cmd(bin, options=None, output_file=None, ignore_error=False): """Execute a binary""" if options is None: options = [] process = Run([bin] + options, output=output_file) if process.status and not ignore_error: # Exit with error logging.error(open(output_file).read())
def run(self): p = Run([ os.path.join(os.path.dirname(os.environ['SHELL']), 'gsh_unit'), './test.adas' ] + [k['input'] for k in self.test_env['table']], cwd=self.test_tmp, error=STDOUT) self.result.actual_output = p.out
def check_realizations(): os.chdir(realize_subdir) for real in gp_realized+am_realized: process = Run(['coqc', '-R', os.path.join('..', 'coq'), 'Why3', real + '.v']) lines = process.out.splitlines() lines = grep(".*Grammar extension", lines, invert=True) for line in lines: print line
def run_and_check(self, argv, for_debug=False, memcheck=False, append_output=True): """ Run a subprocess with `argv` and check it completes with status code 0. If `for_debug` is True, then the program is run under GDB if asked to in the main testsuite driver. For GDB runs, the test is automatically assumed to have failed. If `memcheck` is True then the program is run under Valgrind if asked to in the main testsuite driver. Any memory issue will be reported and turned into a testcase failure. In case of failure, the test output is appended to the actual output and a TestError is raised. """ opts = self.global_env['options'] program = argv[0] # If we are running a debugger, we aren't even interested in the # result. if for_debug and opts.debug: print('Running {} ({}) under a debugger...'.format( program, self.test_env['test_name'])) argv = [opts.debugger, '--args'] + argv print(' '.join(pipes.quote(arg) for arg in argv)) subprocess.check_call(argv, cwd=self.working_dir()) raise TestError('Test was running from a debugger: no result') return # Run valgrind if asked to if memcheck and self.valgrind: argv = self.valgrind.wrap_argv(argv) p = Run(argv, cwd=self.working_dir(), timeout=self.timeout, output=PIPE, error=STDOUT) if append_output: with open(self.output_file, 'a') as f: f.write(p.out) if p.status != 0: self.result.actual_output += ( '{} returned status code {}\n'.format(program, p.status)) self.result.actual_output += p.out raise TestError('{} returned status code {}'.format( program, p.status)) if memcheck and self.valgrind: self.valgrind_errors.extend(self.valgrind.parse_report()) return p.out
def make(self, target): """Run :command:`make target` and return the process. :param str target: The Makefile target to call. :returns: gnatpython.ex.Run """ return Run( ['make', target], cwd=self.install_dir, output=PIPE, error=STDOUT)
def run_and_log(*args, **kwargs): """ Wrapper around gnatpython.ex.Run to collect all processes that are run. """ start = time.time() p = Run(*args, **kwargs) # Register the command for this process as well as the time it took to run # it. try: cmd = kwargs['cmds'] except KeyError: cmd = args[0] p.original_cmd = cmd p.duration = time.time() - start run_processes.append(p) return p
def remote_info(self): """Get info on remote repositories.""" if not os.path.exists(self.dest): self.__error(self.dest + " does not exist") p = Run([self.git, 'remote', '-v'], cwd=self.dest) if p.status != 0: self.__error('git remote -v error:\n' + p.out) else: return [l.split() for l in p.out.splitlines()]
def switch(self): """Perform svn switch to the selected url. :raise SVN_Error: if case of unexpected failure """ svnswitch = Run(['svn', '--non-interactive', 'switch'] + self.ext_args + [self.url, self.dest], error=STDOUT) if svnswitch.status != 0: raise SVN_Error("error during switch: %s" % svnswitch.out)
def localize_distrib(distrib_dir, executables): """Localize a Mac OS distribution by making adjusting library paths. Paths to libraries are made relative so that the distribution can be moved easily from one place to another. The change is done in place Note that we depends on an external tool called :file:`install_name_tool` :param distrib_dir: root directory of the distribution :type distrib_dir: str :param executables: list of relative path to the executables present in the distribution :type executables: list[str] """ # First we need to find the shared libraries present in our distribution dylib_list = find(distrib_dir, pattern="*.dylib") + \ find(distrib_dir, pattern="*.so") dylib_dict = {os.path.basename(k): k for k in dylib_list} # List of files to adjust (executables + shared libraries) for bin_file in dylib_list + \ [os.path.join(distrib_dir, e) for e in executables]: # Retrieve the list of dependencies for that file file_dylibs = get_dylib_deps(bin_file) for d in file_dylibs: base_d = os.path.basename(d) if base_d in dylib_dict: if base_d == 'libgcc_s.1.dylib': # On darwin, we absolutely want to pick the libgcc_s from # the system. shared libgcc_s from our compilers are # broken. Run([ 'install_name_tool', '-change', d, '/usr/lib/libgcc_s.1.dylib', bin_file ]) else: Run([ 'install_name_tool', '-change', d, '@loader_path/' + os.path.relpath( dylib_dict[base_d], os.path.dirname(bin_file)), bin_file ])
def output_of(cmd, dir=None): """Execute CMD and return it's output, switching to DIR before if not None, and switching back to the original cwd as needed.""" cwd = os.getcwd() if dir is not None: cd(dir) output = Run(cmd.split()).out cd(cwd) return output
def diff(self): """Return local changes in the working tree. :rtype: str """ cmd = [self.git, '--no-pager', 'diff', 'HEAD'] p = Run(cmd, cwd=self.dest, error=PIPE) if p.status != 0: self.__error("git diff error:\n" + p.err) return p.out
def call(self, argv): """ Run a subprocess with `argv` """ Run(argv, cwd=self.working_dir(), timeout=self.TIMEOUT, output=self.output_file, error=STDOUT) self.result.actual_output += self.read_file(self.output_file)
def run_coverage_analysis(command): """Run xcov with appropriate arguments to retrieve coverage information Returns an object of type run """ return Run( ['xcov', '--coverage=branch', '--annotate=report', command + ".trace"], output=OUTPUT_FILENAME + '.trace', error=STDOUT, timeout=RLIMIT)
def run(bin, options=None, output_file=None): """Run a test""" if options is None: options = [] if "TIMEOUT" in os.environ: timeout = int(os.environ["TIMEOUT"]) else: timeout = 300 Run([bin] + options, output=output_file, timeout=timeout)
generate_collect_result) from gnatpython.testdriver import add_run_test_options from gnatpython.reports import ReportDiff from glob import glob import os import sys # Compute PATH to global test drivers (testme, print_tree) TARGET = os.environ.get("TARGET") PRJ_BUILD = os.environ.get("PRJ_BUILD") if TARGET is None: TARGET = Run(['gcc', '-dumpmachine']).out.strip('\n') else: TARGET = TARGET.lower() if PRJ_BUILD is None: PRJ_BUILD = "debug" else: PRJ_BUILD = PRJ_BUILD.lower() def makedir(dir): return os.getcwd() + "/../.build/" + dir + "/" \ + TARGET + "/" + PRJ_BUILD + "/static/" os.environ["PATH"] = os.environ.get("PATH") + os.pathsep + makedir("bin") \ + os.pathsep + makedir("rbin")