def mode_build(self): # We first need to instrument, with proper selection of the units of # interest. Expect we are to provide this through a project file as # we have no LI file at hand: assert self.gprmode # If we have a request for specific options, honor that. Otherwise, # use the already computed project file for this test: if self.covctl and self.covctl.gprsw: instrument_gprsw = self.covctl.gprsw else: instrument_gprsw = GPRswitches(root_project=self.gpr) xcov_instrument(covlevel=self.xcovlevel, checkpoint='instr.ckpt', gprsw=instrument_gprsw) # Now we can build, instructing gprbuild to fetch the instrumented # sources in their dedicated subdir: gprbuild(self.gpr, extracargs=self.extracargs, gargs='--src-subdirs=gnatcov-instr')
def mode_build(self): # We first need to instrument, with proper selection of the units of # interest. Expect we are to provide this through a project file as # we have no LI file at hand: assert self.gprmode # If we have a request for specific options, honor that. Otherwise, # use the already computed project file for this test: if self.covctl and self.covctl.gprsw: instrument_gprsw = self.covctl.gprsw else: instrument_gprsw = GPRswitches(root_project=self.gpr) out = 'xinstr.out' xcov_instrument( covlevel=self.xcovlevel, isi_file=self.ISI_FILE, extra_args=to_list(self.covctl.covoptions) if self.covctl else [], gprsw=instrument_gprsw, gpr_obj_dir=self.gpr_obj_dir, out=out) # Standard output might contain warnings indicating instrumentation # issues. This should not happen, so simply fail as soon as the output # file is not empty. thistest.fail_if( os.path.getsize(out) > 0, 'xcov instrument standard output not empty ({}):' '\n--' '\n{}'.format(out, contents_of(out))) # Now we can build, instructing gprbuild to fetch the instrumented # sources in their dedicated subdir: gprbuild(self.gpr, extracargs=self.extracargs, gargs='--src-subdirs=gnatcov-instr')
def build_and_run(gprsw, covlevel, mains, extra_coverage_args, scos=None, gpr_obj_dir=None, gpr_exe_dir=None, ignored_source_files=[], separate_coverage=None, extra_args=[], extra_run_args=None, extra_instr_args=None, extra_gprbuild_args=[], extra_gprbuild_cargs=[], absolute_paths=False, dump_trigger="auto", dump_channel="auto", check_gprbuild_output=False, trace_mode=None, runtime_project=None, gprsw_for_coverage=None, scos_for_run=True, register_failure=True, program_env=None, instrument_warnings_as_errors=True, exec_args=None): """ Prepare a project to run a coverage analysis on it. This is a wrapper around gprbuild/xrun/xcov_instrument to do whatever is necessary for the current trace mode to run "gnatcov coverage". It lets one write concise testcases that handle both binary and source trace modes. :param SUITE.gprutils.GPRswitches gprsw: GPRswitches instance used to describe the project and units of interest to analyze. :param None|str covlevel: Coverage level (as passed with gnatcov's --level= argument) for the coverage analysis. Not passed if None. :param list[str] mains: List of names for the various mains to run. These are lower-case names without extension, for instance "foo" for the "foo.adb" main source file. :param list[str] extra_coverage_args: List of arguments to append to the "gnatcov coverage" command-line returned. This is just for convenience: one can pass an empty list here and manually append extra arguments to the result. :param None|list[str] scos: Optional list of SCOs files (ALI or SID) must be passed to gnatcov. These files must have no extension (for instance: 'obj/foo' instead of 'obj/foo.ali'. If absent, we pass "-P" to "gnatcov coverage"/"gnatcov instrument" so that it automatically discovers the units of interest from projects. :param None|str gpr_obj_dir: Optional name of the directory where gprbuild will create build artifacts. If left to None, assume they are produced in "$gpr_exe_dir/obj". :param None|str gpr_exe_dir: Optional name of the directory where gprbuild will create executables to run. If left to None, assume they are produced in the current directory. :param list[str] ignored_source_files: List of file patterns to pass using the --ignore-source-files option. :param None|str separate_coverage: If provided, the argument is forwarded to gnatcov using the -S option. :param list[str] extra_args: List of arguments to pass to any execution of gnatcov (gnatcov run|instrument|coverage). :param list[str] extra_run_args: List of arguments to pass to all executions of "gnatcov run". :param list[str] extra_instr_args: List of arguments to pass to all executions of "gnatcov instrument". :param list[str] extra_gprbuild_args: List of arguments to pass to gprbuild. :param list[str] extra_gprbuild_cargs: List of arguments to pass to gprbuild's -cargs section. :param bool absolute_paths: If true, use absolute paths in the result. :param None|str dump_trigger: See xcov_instrument. :param None|str dump_channel: See xcov_instrument. :param bool check_gprbuild_output: If true, check that gprbuild's output is empty. :param None|str trace_mode: If None, use the testsuite's trace mode. Otherwise, use the given trace mode ('bin', or 'src'). :param None|str runtime_project: If None, use the default name for the instrumentation runtime project. Otherwise, use the name given for this option. :param None|SUITE.gprutils.GPRswitches gprsw_for_coverage: GPRswitches instance used to describe the project and units of interest to analyze in "gnatcov coverage". If left to None, use "gprsw". :param bool scos_for_run: Whether to pass SCOs/project information to "gnatcov run". :param bool register_failure: If true and the execution of one of the mains exits with a non-zero status code, stop with a FatalError. :param None|dict[str, str] program_env: If not none, environment variables for the program to run. :param bool instrument_warnings_as_errors: Whether to make the test fail if there are warnings in the output of "gnatcov instrument". :param None|list[str] exec_args: List of arguments to pass to the executable. This will only work for native configurations. :rtype: list[str] :return: Incomplete list of arguments to pass to `xcov` in order to run "gnatcov coverage". The only mandatory argument that is missing is the annotation format. The last N arguments correspond to trace files for the given N mains. """ def abspath(path): return os.path.abspath(path) if absolute_paths else path def exepath(main): main = os.path.join( gpr_exe_dir, (os.path.join(gprsw.subdirs, main) if gprsw.subdirs else main)) return abspath(exepath_to(main)) def gprbuild_wrapper(root_project): # Honor build relevant switches from gprsw here gprbuild(root_project, gargs=gprsw.build_switches + extra_gprbuild_args, extracargs=extra_gprbuild_cargs, trace_mode=trace_mode, runtime_project=runtime_project) if check_gprbuild_output: gprbuild_out = contents_of('gprbuild.out') thistest.fail_if( gprbuild_out, "gprbuild's output (gprbuild.out) is not empty:\n{}".format( indent(gprbuild_out))) # When instrumenting, we expect units of interest to be provided # through GPR switches: assert not (scos and trace_mode == 'src') gpr_exe_dir = gpr_exe_dir or '.' gpr_obj_dir = gpr_obj_dir or os.path.join(gpr_exe_dir, 'obj') trace_mode = trace_mode or thistest.options.trace_mode # Use a --level=<l> form for --level to faciliate locating and # replacing the switch at once as a whole if need be. covlevel_args = [] if covlevel is None else ['--level={}'.format(covlevel)] xcov_args = ['coverage'] + covlevel_args trace_files = [] # Arguments to pass to "gnatcov coverage" (bin trace mode) or "gnatcov # instrument" (src trace mode), in addition to those conveyed by gprsw. cov_or_instr_args = (extra_args + [ '--ignore-source-files={}'.format(pattern) for pattern in ignored_source_files ]) if separate_coverage: cov_or_instr_args.extend(['-S', separate_coverage]) # Compute arguments to specify units of interest. if trace_mode == 'bin': scos_arg = '--scos' scos_ext = 'ali' else: scos_arg = '--sid' scos_ext = 'sid' scos = (['{}={}.{}'.format(scos_arg, abspath(a), scos_ext) for a in scos] if scos else gprsw.cov_switches) if trace_mode == 'bin': # Build and run each main gprbuild_wrapper(gprsw.root_project) run_args = covlevel_args + extra_args if scos_for_run: run_args.extend(scos) if extra_run_args: run_args.extend(extra_run_args) eargs = [] if exec_args: eargs = ["-eargs"] + exec_args for m in mains: xrun(run_args + [exepath(m)] + eargs, out='run.log', env=program_env, register_failure=register_failure) trace_files = [abspath(tracename_for(m)) for m in mains] xcov_args.extend(cov_or_instr_args) elif trace_mode == 'src': if dump_channel == "auto": dump_channel = default_dump_channel() # Instrument the project and build the result extra_instr_args = cov_or_instr_args + list(extra_instr_args or []) xcov_instrument(gprsw, covlevel, extra_args=extra_instr_args, gpr_obj_dir=gpr_obj_dir, dump_trigger=dump_trigger, dump_channel=dump_channel, runtime_project=runtime_project, out='instrument.log', register_failure=register_failure, warnings_as_errors=instrument_warnings_as_errors) gprbuild_wrapper(gprsw.root_project) # If an explicit dump channel was requested, check that "gnatcov # instrument" used it. In case it was implicit, get the one that was # used. # # The mode in which we do not register failures is tricky: in this case # we may not have an actual dump channel because instrumentation did # not complete. In that case we cannot use source traces, but we must # build and run programs nonetheless. params_file_dir = gpr_obj_dir if gprsw.subdirs: params_file_dir = os.path.join(params_file_dir, gprsw.subdirs) params_file = os.path.join(params_file_dir, "gnatcov-instr.json") try: f = open(params_file) except FileNotFoundError: if register_failure: raise else: actual_dump_channel = None else: with f: params = json.load(f) actual_dump_channel = params["dump-channel"] if dump_channel in (None, "auto"): dump_channel = actual_dump_channel elif dump_channel and actual_dump_channel: thistest.fail_if_not_equal("actual dump channel", dump_channel, actual_dump_channel) # Then execute each main and collect trace files trace_files = [] for m in mains: # Remove potential existing source trace files: the name is # non-deterministic by default, so we want to avoid getting # multiple traces in the current directory. rm(srctrace_pattern_for(m)) out_file = '{}_output.txt'.format(m) run_cov_program(exepath(m), out=out_file, env=program_env, register_failure=register_failure, exec_args=exec_args) # Depending on the dump channel, we also may have to create the # trace file. If we could not determine the actually used dump # channel (see above), do not collect the trace file. if dump_channel is None: continue elif dump_channel == 'bin-file': trace_file = srctracename_for( m, register_failure=register_failure) if trace_file is None: continue elif dump_channel == 'base64-stdout': # Create a trace name that is compatible with srctracename_for trace_file = srctrace_pattern_for(m).replace("*", "unique") xcov_convert_base64(out_file, trace_file, register_failure=register_failure) else: raise ValueError( 'Invalid dump channel: {}'.format(dump_channel)) trace_files.append(abspath(trace_file)) xcov_args.extend(cov_or_instr_args) else: assert False, 'Unknown trace mode: {}'.format(trace_mode) # If provided, pass "gnatcov coverage"-specific project arguments, which # replace the list of SCOS. if gprsw_for_coverage: xcov_args.extend(gprsw_for_coverage.cov_switches) elif scos: xcov_args.extend(scos) return xcov_args + extra_coverage_args + trace_files
def build_and_run(gprsw, covlevel, mains, extra_coverage_args, scos=None, gpr_obj_dir=None, gpr_exe_dir=None, ignored_source_files=[], separate_coverage=None, extra_args=[], extra_gprbuild_args=[], extra_gprbuild_cargs=[], absolute_paths=False, dump_trigger=None, dump_channel=None, check_gprbuild_output=False, trace_mode=None, gprsw_for_coverage=None, scos_for_run=True, register_failure=True): """ Prepare a project to run a coverage analysis on it. This is a wrapper around gprbuild/xrun/xcov_instrument to do whatever is necessary for the current trace mode to run "gnatcov coverage". It lets one write concise testcases that handle both binary and source trace modes. :param SUITE.gprutils.GPRswitches gprsw: GPRswitches instance used to describe the project and units of interest to analyze. :param None|str covlevel: Coverage level (as passed with gnatcov's --level= argument) for the coverage analysis. Not passed if None. :param list[str] mains: List of names for the various mains to run. These are lower-case names without extension, for instance "foo" for the "foo.adb" main source file. :param list[str] extra_coverage_args: List of arguments to append to the "gnatcov coverage" command-line returned. This is just for convenience: one can pass an empty list here and manually append extra arguments to the result. :param None|list[str] scos: Optional list of SCOs files (ALI or SID) must be passed to gnatcov. These files must have no extension (for instance: 'obj/foo' instead of 'obj/foo.ali'. If absent, we pass "-P" to "gnatcov coverage"/"gnatcov instrument" so that it automatically discovers the units of interest from projects. :param None|str gpr_obj_dir: Optional name of the directory where gprbuild will create build artifacts. If left to None, assume they are produced in "$gpr_exe_dir/obj". :param None|str gpr_exe_dir: Optional name of the directory where gprbuild will create executables to run. If left to None, assume they are produced in the current directory. :param list[str] ignored_source_files: List of file patterns to pass using the --ignore-source-files option. :param None|str separate_coverage: If provided, the argument is forwarded to gnatcov using the -S option. :param list[str] extra_args: List of arguments to pass to any execution of gnatcov (gnatcov run|instrument|coverage). :param list[str] extra_gprbuild_args: List of arguments to pass to gprbuild. :param list[str] extra_gprbuild_cargs: List of arguments to pass to gprbuild's -cargs section. :param bool absolute_paths: If true, use absolute paths in the result. :param None|str dump_trigger: Trigger to dump coverage buffers (--dump-trigger argument). If left to None, use SCOV.instr.default_dump_trigger. :param None|str dump_channel: Channel to dump coverage buffers (--dump-channel argument). If left to None, use SCOV.instr.default_dump_channel. :param bool check_gprbuild_output: If true, check that gprbuild's output is empty. :param None|str trace_mode: If None, use the testsuite's trace mode. Otherwise, use the given trace mode ('bin', or 'src'). :param None|SUITE.gprutils.GPRswitches gprsw_for_coverage: GPRswitches instance used to describe the project and units of interest to analyze in "gnatcov coverage". If left to None, use "gprsw". :param bool scos_for_run: Whether to pass SCOs/project information to "gnatcov run". :param bool register_failure: If true and the execution of one of the mains exits with a non-zero status code, stop with a FatalError. :rtype: list[str] :return: Incomplete list of arguments to pass to `xcov` in order to run "gnatcov coverage". The only mandatory argument that is missing is the annotation format. The last N arguments correspond to trace files for the given N mains. """ def abspath(path): return os.path.abspath(path) if absolute_paths else path def exepath(main): main = os.path.join( gpr_exe_dir, (os.path.join(gprsw.subdirs, m) if gprsw.subdirs else m)) return abspath(exepath_to(main)) def gprbuild_wrapper(root_project, gargs): # Honor build relevant switches from gprsw here gprbuild(root_project, gargs=gprsw.build_switches + gargs + extra_gprbuild_args, extracargs=extra_gprbuild_cargs, trace_mode=trace_mode) if check_gprbuild_output: gprbuild_out = contents_of('gprbuild.out') thistest.fail_if( gprbuild_out, "gprbuild's output (gprbuild.out) is not empty:\n{}" .format(indent(gprbuild_out))) # When instrumenting, we expect units of interest to be provided # through GPR switches: assert not (scos and trace_mode == 'src') gpr_exe_dir = gpr_exe_dir or '.' gpr_obj_dir = gpr_obj_dir or os.path.join(gpr_exe_dir, 'obj') trace_mode = trace_mode or thistest.options.trace_mode covlevel_args = [] if covlevel is None else ['--level', covlevel] xcov_args = ['coverage'] + covlevel_args trace_files = [] # Arguments to pass to "gnatcov coverage" (bin trace mode) or "gnatcov # instrument" (src trace mode), in addition to those conveyed by gprsw. cov_or_instr_args = ( extra_args + ['--ignore-source-files={}'.format(pattern) for pattern in ignored_source_files]) if separate_coverage: cov_or_instr_args.extend(['-S', separate_coverage]) # Compute arguments to specify units of interest. if trace_mode == 'bin': scos_arg = '--scos' scos_ext = 'ali' else: scos_arg = '--sid' scos_ext = 'sid' scos = (['{}={}.{}'.format(scos_arg, abspath(a), scos_ext) for a in scos] if scos else gprsw.cov_switches) if trace_mode == 'bin': # Build and run each main gprbuild_wrapper(gprsw.root_project, gargs=[]) run_args = covlevel_args + extra_args if scos_for_run: run_args.extend(scos) for m in mains: xrun(run_args + [exepath(m)], out='run.log', register_failure=register_failure) trace_files = [abspath(tracename_for(m)) for m in mains] xcov_args.extend(cov_or_instr_args) elif trace_mode == 'src': dump_channel = dump_channel or default_dump_channel() # Instrument the project and build the result xcov_instrument(gprsw, covlevel, extra_args=cov_or_instr_args, gpr_obj_dir=gpr_obj_dir, dump_trigger=dump_trigger, dump_channel=dump_channel, out='instrument.log', register_failure=register_failure) gprbuild_wrapper(gprsw.root_project, gargs=['--src-subdirs=gnatcov-instr']) # Then execute each main and collect trace files trace_files = [] for m in mains: out_file = '{}_output.txt'.format(m) trace_file = abspath(srctracename_for(m)) run_cov_program(exepath(m), out=out_file, register_failure=register_failure) trace_files.append(trace_file) # Depending on the dump channel, we also may have to create the # trace file. if dump_channel == 'bin-file': pass elif dump_channel == 'base64-stdout': xcov_convert_base64(out_file, trace_file, register_failure=register_failure) else: raise ValueError('Invalid dump channel: {}' .format(dump_channel)) xcov_args.extend(cov_or_instr_args) else: assert False, 'Unknown trace mode: {}'.format(trace_mode) # If provided, pass "gnatcov coverage"-specific project arguments, which # replace the list of SCOS. if gprsw_for_coverage: xcov_args.extend(gprsw_for_coverage.cov_switches) elif scos: xcov_args.extend(scos) return xcov_args + extra_coverage_args + trace_files
def build_and_run(gprsw, covlevel, mains, extra_coverage_args, scos=None, gpr_obj_dir=None, gpr_exe_dir=None, ignored_source_files=[], separate_coverage=None, extra_args=[], extra_gprbuild_args=[], absolute_paths=False): """ Prepare a project to run a coverage analysis on it. This is a wrapper around gprbuild/xrun/xcov_instrument to do whatever is necessary for the current trace mode to run "gnatcov coverage". It lets one write concise testcases that handle both binary and source trace modes. :param SUITE.gprutils.GPRswitches gprsw: GPRswitches instance used to describe the project and units of interest to analyze. :param str covlevel: Coverage level (as passed with gnatcov's --level= argument) for the coverage analysis. :param list[str] mains: List of names for the various mains to run. These are lower-case names without extension, for instance "foo" for the "foo.adb" main source file. :param list[str] extra_coverage_args: List of arguments to append to the "gnatcov coverage" command-line returned. This is just for convenience: one can pass an empty list here and manually append extra arguments to the result. :param None|list[str] scos: Optional list of SCOs to pass to gnatcov, if the current trace mode is binary. If absent, we pass "-P" to "gnatcov coverage"/"gnatcov instrument" so that it automatically discovers the units of interest. :param None|str gpr_obj_dir: Optional name of the directory where gprbuild will create build artifacts. If left to None, assume they are produced in "$gpr_exe_dir/obj". :param None|str gpr_exe_dir: Optional name of the directory where gprbuild will create executables to run. If left to None, assume they are produced in the current directory. :param list[str] ignored_source_files: List of file patterns to pass using the --ignore-source-files option. :param None|str separate_coverage: If provided, the argument is forwarded to gnatcov using the -S option. :param list[str] extra_args: List of arguments to pass to any execution of gnatcov (gnatcov run|instrument|coverage). :param list[str] extra_gprbuild_args: List of arguments to pass to gprbuild. :param bool absolute_paths: If true, use absolute paths in the result. :rtype: list[str] :return: Incomplete list of arguments to pass to `xcov` in order to run "gnatcov coverage". The only mandatory argument that is missing is the annotation format. The last N arguments correspond to trace files for the given N mains. """ def abspath(path): return os.path.abspath(path) if absolute_paths else path def exepath(main): if gpr_exe_dir: main = os.path.join(gpr_exe_dir, m) return abspath(exepath_to(main)) def gprbuild_wrapper(root_project, gargs=[]): gprbuild(root_project, gargs=gargs + extra_gprbuild_args) gpr_exe_dir = gpr_exe_dir or '.' gpr_obj_dir = gpr_obj_dir or os.path.join(gpr_exe_dir, 'obj') trace_mode = thistest.options.trace_mode xcov_args = ['coverage', '--level', covlevel] trace_files = [] # Arguments to pass to "gnatcov coverage" (bin trace mode) or "gnatcov # instrument" (src trace mode). cov_or_instr_args = (extra_args + [ '--ignore-source-files={}'.format(pattern) for pattern in ignored_source_files ]) if separate_coverage: cov_or_instr_args.extend(['-S', separate_coverage]) if trace_mode == 'bin': # Compute arguments to specify units of interest scos = (['--scos={}'.format(abspath(a)) for a in scos] if scos else gprsw.as_strings) cov_or_instr_args.extend(scos) # Build and run each main gprbuild_wrapper(gprsw.root_project) for m in mains: xrun(['--level', covlevel, exepath(m)] + scos + extra_args, out='run.log') trace_files = [abspath(tracename_for(m)) for m in mains] xcov_args.extend(cov_or_instr_args) elif trace_mode == 'src': # Instrument the project and build the result isi_file = abspath('instr.isi') xcov_instrument(gprsw, covlevel, isi_file, extra_args=cov_or_instr_args, gpr_obj_dir=gpr_obj_dir, out='instrument.log') xcov_args.extend(['--isi', isi_file]) gprbuild_wrapper(gprsw.root_project, gargs=['--src-subdirs=gnatcov-instr']) # Then execute each main for m in mains: Run([exepath(m)]) trace_files = [abspath(srctracename_for(m)) for m in mains] # If we would have passed the project to "gnatcov coverage" in binary # trace mode, pass it here too. This is necessary for instance to # select the default output directory for coverage reports. if not scos: xcov_args.extend(['-P', gprsw.root_project]) xcov_args.extend(extra_args) else: assert False, 'Unknown trace mode: {}'.format(trace_mode) return xcov_args + extra_coverage_args + trace_files