mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Expand run-coverage
to support the remaining coverage-reports
tests
This commit is contained in:
parent
d05653cbe0
commit
9d2564a110
@ -502,11 +502,18 @@ impl<'test> TestCx<'test> {
|
||||
}
|
||||
drop(proc_res);
|
||||
|
||||
let mut profraw_paths = vec![profraw_path];
|
||||
let mut bin_paths = vec![self.make_exe_name()];
|
||||
|
||||
if self.config.suite == "run-coverage-rustdoc" {
|
||||
self.run_doctests_for_coverage(&mut profraw_paths, &mut bin_paths);
|
||||
}
|
||||
|
||||
// Run `llvm-profdata merge` to index the raw coverage output.
|
||||
let proc_res = self.run_llvm_tool("llvm-profdata", |cmd| {
|
||||
cmd.args(["merge", "--sparse", "--output"]);
|
||||
cmd.arg(&profdata_path);
|
||||
cmd.arg(&profraw_path);
|
||||
cmd.args(&profraw_paths);
|
||||
});
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("llvm-profdata merge failed!", &proc_res);
|
||||
@ -523,8 +530,10 @@ impl<'test> TestCx<'test> {
|
||||
cmd.arg("--instr-profile");
|
||||
cmd.arg(&profdata_path);
|
||||
|
||||
cmd.arg("--object");
|
||||
cmd.arg(&self.make_exe_name());
|
||||
for bin in &bin_paths {
|
||||
cmd.arg("--object");
|
||||
cmd.arg(bin);
|
||||
}
|
||||
});
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("llvm-cov show failed!", &proc_res);
|
||||
@ -553,6 +562,82 @@ impl<'test> TestCx<'test> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Run any doctests embedded in this test file, and add any resulting
|
||||
/// `.profraw` files and doctest executables to the given vectors.
|
||||
fn run_doctests_for_coverage(
|
||||
&self,
|
||||
profraw_paths: &mut Vec<PathBuf>,
|
||||
bin_paths: &mut Vec<PathBuf>,
|
||||
) {
|
||||
// Put .profraw files and doctest executables in dedicated directories,
|
||||
// to make it easier to glob them all later.
|
||||
let profraws_dir = self.output_base_dir().join("doc_profraws");
|
||||
let bins_dir = self.output_base_dir().join("doc_bins");
|
||||
|
||||
// Remove existing directories to prevent cross-run interference.
|
||||
if profraws_dir.try_exists().unwrap() {
|
||||
std::fs::remove_dir_all(&profraws_dir).unwrap();
|
||||
}
|
||||
if bins_dir.try_exists().unwrap() {
|
||||
std::fs::remove_dir_all(&bins_dir).unwrap();
|
||||
}
|
||||
|
||||
let mut rustdoc_cmd =
|
||||
Command::new(self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed"));
|
||||
|
||||
// In general there will be multiple doctest binaries running, so we
|
||||
// tell the profiler runtime to write their coverage data into separate
|
||||
// profraw files.
|
||||
rustdoc_cmd.env("LLVM_PROFILE_FILE", profraws_dir.join("%p-%m.profraw"));
|
||||
|
||||
rustdoc_cmd.args(["--test", "-Cinstrument-coverage"]);
|
||||
|
||||
// Without this, the doctests complain about not being able to find
|
||||
// their enclosing file's crate for some reason.
|
||||
rustdoc_cmd.args(["--crate-name", "workaround_for_79771"]);
|
||||
|
||||
// Persist the doctest binaries so that `llvm-cov show` can read their
|
||||
// embedded coverage mappings later.
|
||||
rustdoc_cmd.arg("-Zunstable-options");
|
||||
rustdoc_cmd.arg("--persist-doctests");
|
||||
rustdoc_cmd.arg(&bins_dir);
|
||||
|
||||
rustdoc_cmd.arg("-L");
|
||||
rustdoc_cmd.arg(self.aux_output_dir_name());
|
||||
|
||||
rustdoc_cmd.arg(&self.testpaths.file);
|
||||
|
||||
let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None);
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("rustdoc --test failed!", &proc_res)
|
||||
}
|
||||
|
||||
fn glob_iter(path: impl AsRef<Path>) -> impl Iterator<Item = PathBuf> {
|
||||
let path_str = path.as_ref().to_str().unwrap();
|
||||
let iter = glob(path_str).unwrap();
|
||||
iter.map(Result::unwrap)
|
||||
}
|
||||
|
||||
// Find all profraw files in the profraw directory.
|
||||
for p in glob_iter(profraws_dir.join("*.profraw")) {
|
||||
profraw_paths.push(p);
|
||||
}
|
||||
// Find all executables in the `--persist-doctests` directory, while
|
||||
// avoiding other file types (e.g. `.pdb` on Windows). This doesn't
|
||||
// need to be perfect, as long as it can handle the files actually
|
||||
// produced by `rustdoc --test`.
|
||||
for p in glob_iter(bins_dir.join("**/*")) {
|
||||
let is_bin = p.is_file()
|
||||
&& match p.extension() {
|
||||
None => true,
|
||||
Some(ext) => ext == OsStr::new("exe"),
|
||||
};
|
||||
if is_bin {
|
||||
bin_paths.push(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_llvm_tool(&self, name: &str, configure_cmd_fn: impl FnOnce(&mut Command)) -> ProcRes {
|
||||
let tool_path = self
|
||||
.config
|
||||
@ -582,12 +667,39 @@ impl<'test> TestCx<'test> {
|
||||
|
||||
let mut lines = normalized.lines().collect::<Vec<_>>();
|
||||
|
||||
Self::sort_coverage_file_sections(&mut lines)?;
|
||||
Self::sort_coverage_subviews(&mut lines)?;
|
||||
|
||||
let joined_lines = lines.iter().flat_map(|line| [line, "\n"]).collect::<String>();
|
||||
Ok(joined_lines)
|
||||
}
|
||||
|
||||
/// Coverage reports can describe multiple source files, separated by
|
||||
/// blank lines. The order of these files is unpredictable (since it
|
||||
/// depends on implementation details), so we need to sort the file
|
||||
/// sections into a consistent order before comparing against a snapshot.
|
||||
fn sort_coverage_file_sections(coverage_lines: &mut Vec<&str>) -> Result<(), String> {
|
||||
// Group the lines into file sections, separated by blank lines.
|
||||
let mut sections = coverage_lines.split(|line| line.is_empty()).collect::<Vec<_>>();
|
||||
|
||||
// The last section should be empty, representing an extra trailing blank line.
|
||||
if !sections.last().is_some_and(|last| last.is_empty()) {
|
||||
return Err("coverage report should end with an extra blank line".to_owned());
|
||||
}
|
||||
|
||||
// Sort the file sections (not including the final empty "section").
|
||||
let except_last = sections.len() - 1;
|
||||
(&mut sections[..except_last]).sort();
|
||||
|
||||
// Join the file sections back into a flat list of lines, with
|
||||
// sections separated by blank lines.
|
||||
let joined = sections.join(&[""] as &[_]);
|
||||
assert_eq!(joined.len(), coverage_lines.len());
|
||||
*coverage_lines = joined;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sort_coverage_subviews(coverage_lines: &mut Vec<&str>) -> Result<(), String> {
|
||||
let mut output_lines = Vec::new();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user