Skip to content

Commit bfb1654

Browse files
committed
coverage: Anonymize line numbers in run-coverage test snapshots
This makes the test snapshots less sensitive to lines being added/removed.
1 parent 07438b0 commit bfb1654

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2672
-2655
lines changed

src/tools/compiletest/src/runtest.rs

+17
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::ColorConfig;
1818
use regex::{Captures, Regex};
1919
use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
2020

21+
use std::borrow::Cow;
2122
use std::collections::hash_map::DefaultHasher;
2223
use std::collections::{HashMap, HashSet};
2324
use std::env;
@@ -664,6 +665,7 @@ impl<'test> TestCx<'test> {
664665

665666
fn normalize_coverage_output(&self, coverage: &str) -> Result<String, String> {
666667
let normalized = self.normalize_output(coverage, &[]);
668+
let normalized = Self::anonymize_coverage_line_numbers(&normalized);
667669

668670
let mut lines = normalized.lines().collect::<Vec<_>>();
669671

@@ -674,6 +676,21 @@ impl<'test> TestCx<'test> {
674676
Ok(joined_lines)
675677
}
676678

679+
/// Replace line numbers in coverage reports with the placeholder `LL`,
680+
/// so that the tests are less sensitive to lines being added/removed.
681+
fn anonymize_coverage_line_numbers(coverage: &str) -> Cow<'_, str> {
682+
// The coverage reporter prints line numbers at the start of a line.
683+
// They are truncated or left-padded to occupy exactly 5 columns.
684+
// (`LineNumberColumnWidth` in `SourceCoverageViewText.cpp`.)
685+
// A pipe character `|` appears immediately after the final digit.
686+
//
687+
// Line numbers that appear inside expansion/instantiation subviews
688+
// have an additional prefix of ` |` for each nesting level.
689+
static LINE_NUMBER_RE: Lazy<Regex> =
690+
Lazy::new(|| Regex::new(r"(?m:^)(?<prefix>(?: \|)*) *[0-9]+\|").unwrap());
691+
LINE_NUMBER_RE.replace_all(coverage, "$prefix LL|")
692+
}
693+
677694
/// Coverage reports can describe multiple source files, separated by
678695
/// blank lines. The order of these files is unpredictable (since it
679696
/// depends on implementation details), so we need to sort the file
+108-108
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,115 @@
11
$DIR/auxiliary/doctest_crate.rs:
2-
1| |/// A function run only from within doctests
3-
2| 3|pub fn fn_run_in_doctests(conditional: usize) {
4-
3| 3| match conditional {
5-
4| 1| 1 => assert_eq!(1, 1), // this is run,
6-
5| 1| 2 => assert_eq!(1, 1), // this,
7-
6| 1| 3 => assert_eq!(1, 1), // and this too
8-
7| 0| _ => assert_eq!(1, 2), // however this is not
9-
8| | }
10-
9| 3|}
2+
LL| |/// A function run only from within doctests
3+
LL| 3|pub fn fn_run_in_doctests(conditional: usize) {
4+
LL| 3| match conditional {
5+
LL| 1| 1 => assert_eq!(1, 1), // this is run,
6+
LL| 1| 2 => assert_eq!(1, 1), // this,
7+
LL| 1| 3 => assert_eq!(1, 1), // and this too
8+
LL| 0| _ => assert_eq!(1, 2), // however this is not
9+
LL| | }
10+
LL| 3|}
1111

1212
$DIR/doctest.rs:
13-
1| |//! This test ensures that code from doctests is properly re-mapped.
14-
2| |//! See <https://github.com/rust-lang/rust/issues/79417> for more info.
15-
3| |//!
16-
4| |//! Just some random code:
17-
5| 1|//! ```
18-
6| 1|//! if true {
19-
7| |//! // this is executed!
20-
8| 1|//! assert_eq!(1, 1);
21-
9| |//! } else {
22-
10| |//! // this is not!
23-
11| 0|//! assert_eq!(1, 2);
24-
12| |//! }
25-
13| 1|//! ```
26-
14| |//!
27-
15| |//! doctest testing external code:
28-
16| |//! ```
29-
17| 1|//! extern crate doctest_crate;
30-
18| 1|//! doctest_crate::fn_run_in_doctests(1);
31-
19| 1|//! ```
32-
20| |//!
33-
21| |//! doctest returning a result:
34-
22| 1|//! ```
35-
23| 2|//! #[derive(Debug, PartialEq)]
13+
LL| |//! This test ensures that code from doctests is properly re-mapped.
14+
LL| |//! See <https://github.com/rust-lang/rust/issues/79417> for more info.
15+
LL| |//!
16+
LL| |//! Just some random code:
17+
LL| 1|//! ```
18+
LL| 1|//! if true {
19+
LL| |//! // this is executed!
20+
LL| 1|//! assert_eq!(1, 1);
21+
LL| |//! } else {
22+
LL| |//! // this is not!
23+
LL| 0|//! assert_eq!(1, 2);
24+
LL| |//! }
25+
LL| 1|//! ```
26+
LL| |//!
27+
LL| |//! doctest testing external code:
28+
LL| |//! ```
29+
LL| 1|//! extern crate doctest_crate;
30+
LL| 1|//! doctest_crate::fn_run_in_doctests(1);
31+
LL| 1|//! ```
32+
LL| |//!
33+
LL| |//! doctest returning a result:
34+
LL| 1|//! ```
35+
LL| 2|//! #[derive(Debug, PartialEq)]
3636
^1
37-
24| 1|//! struct SomeError {
38-
25| 1|//! msg: String,
39-
26| 1|//! }
40-
27| 1|//! let mut res = Err(SomeError { msg: String::from("a message") });
41-
28| 1|//! if res.is_ok() {
42-
29| 0|//! res?;
43-
30| |//! } else {
44-
31| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() {
45-
32| 1|//! println!("{:?}", res);
46-
33| 1|//! }
37+
LL| 1|//! struct SomeError {
38+
LL| 1|//! msg: String,
39+
LL| 1|//! }
40+
LL| 1|//! let mut res = Err(SomeError { msg: String::from("a message") });
41+
LL| 1|//! if res.is_ok() {
42+
LL| 0|//! res?;
43+
LL| |//! } else {
44+
LL| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() {
45+
LL| 1|//! println!("{:?}", res);
46+
LL| 1|//! }
4747
^0
48-
34| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() {
49-
35| 1|//! res = Ok(1);
50-
36| 1|//! }
48+
LL| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() {
49+
LL| 1|//! res = Ok(1);
50+
LL| 1|//! }
5151
^0
52-
37| 1|//! res = Ok(0);
53-
38| |//! }
54-
39| |//! // need to be explicit because rustdoc cant infer the return type
55-
40| 1|//! Ok::<(), SomeError>(())
56-
41| 1|//! ```
57-
42| |//!
58-
43| |//! doctest with custom main:
59-
44| |//! ```
60-
45| 1|//! fn some_func() {
61-
46| 1|//! println!("called some_func()");
62-
47| 1|//! }
63-
48| |//!
64-
49| 0|//! #[derive(Debug)]
65-
50| |//! struct SomeError;
66-
51| |//!
67-
52| |//! extern crate doctest_crate;
68-
53| |//!
69-
54| 1|//! fn doctest_main() -> Result<(), SomeError> {
70-
55| 1|//! some_func();
71-
56| 1|//! doctest_crate::fn_run_in_doctests(2);
72-
57| 1|//! Ok(())
73-
58| 1|//! }
74-
59| |//!
75-
60| |//! // this `main` is not shown as covered, as it clashes with all the other
76-
61| |//! // `main` functions that were automatically generated for doctests
77-
62| |//! fn main() -> Result<(), SomeError> {
78-
63| |//! doctest_main()
79-
64| |//! }
80-
65| |//! ```
81-
66| |// aux-build:doctest_crate.rs
82-
67| |/// doctest attached to fn testing external code:
83-
68| |/// ```
84-
69| 1|/// extern crate doctest_crate;
85-
70| 1|/// doctest_crate::fn_run_in_doctests(3);
86-
71| 1|/// ```
87-
72| |///
88-
73| 1|fn main() {
89-
74| 1| if true {
90-
75| 1| assert_eq!(1, 1);
91-
76| | } else {
92-
77| 0| assert_eq!(1, 2);
93-
78| | }
94-
79| 1|}
95-
80| |
96-
81| |// FIXME(Swatinem): Fix known issue that coverage code region columns need to be offset by the
97-
82| |// doc comment line prefix (`///` or `//!`) and any additional indent (before or after the doc
98-
83| |// comment characters). This test produces `llvm-cov show` results demonstrating the problem.
99-
84| |//
100-
85| |// One of the above tests now includes: `derive(Debug, PartialEq)`, producing an `llvm-cov show`
101-
86| |// result with a distinct count for `Debug`, denoted by `^1`, but the caret points to the wrong
102-
87| |// column. Similarly, the `if` blocks without `else` blocks show `^0`, which should point at, or
103-
88| |// one character past, the `if` block's closing brace. In both cases, these are most likely off
104-
89| |// by the number of characters stripped from the beginning of each doc comment line: indent
105-
90| |// whitespace, if any, doc comment prefix (`//!` in this case) and (I assume) one space character
106-
91| |// (?). Note, when viewing `llvm-cov show` results in `--color` mode, the column offset errors are
107-
92| |// more pronounced, and show up in more places, with background color used to show some distinct
108-
93| |// code regions with different coverage counts.
109-
94| |//
110-
95| |// NOTE: Since the doc comment line prefix may vary, one possible solution is to replace each
111-
96| |// character stripped from the beginning of doc comment lines with a space. This will give coverage
112-
97| |// results the correct column offsets, and I think it should compile correctly, but I don't know
113-
98| |// what affect it might have on diagnostic messages from the compiler, and whether anyone would care
114-
99| |// if the indentation changed. I don't know if there is a more viable solution.
52+
LL| 1|//! res = Ok(0);
53+
LL| |//! }
54+
LL| |//! // need to be explicit because rustdoc cant infer the return type
55+
LL| 1|//! Ok::<(), SomeError>(())
56+
LL| 1|//! ```
57+
LL| |//!
58+
LL| |//! doctest with custom main:
59+
LL| |//! ```
60+
LL| 1|//! fn some_func() {
61+
LL| 1|//! println!("called some_func()");
62+
LL| 1|//! }
63+
LL| |//!
64+
LL| 0|//! #[derive(Debug)]
65+
LL| |//! struct SomeError;
66+
LL| |//!
67+
LL| |//! extern crate doctest_crate;
68+
LL| |//!
69+
LL| 1|//! fn doctest_main() -> Result<(), SomeError> {
70+
LL| 1|//! some_func();
71+
LL| 1|//! doctest_crate::fn_run_in_doctests(2);
72+
LL| 1|//! Ok(())
73+
LL| 1|//! }
74+
LL| |//!
75+
LL| |//! // this `main` is not shown as covered, as it clashes with all the other
76+
LL| |//! // `main` functions that were automatically generated for doctests
77+
LL| |//! fn main() -> Result<(), SomeError> {
78+
LL| |//! doctest_main()
79+
LL| |//! }
80+
LL| |//! ```
81+
LL| |// aux-build:doctest_crate.rs
82+
LL| |/// doctest attached to fn testing external code:
83+
LL| |/// ```
84+
LL| 1|/// extern crate doctest_crate;
85+
LL| 1|/// doctest_crate::fn_run_in_doctests(3);
86+
LL| 1|/// ```
87+
LL| |///
88+
LL| 1|fn main() {
89+
LL| 1| if true {
90+
LL| 1| assert_eq!(1, 1);
91+
LL| | } else {
92+
LL| 0| assert_eq!(1, 2);
93+
LL| | }
94+
LL| 1|}
95+
LL| |
96+
LL| |// FIXME(Swatinem): Fix known issue that coverage code region columns need to be offset by the
97+
LL| |// doc comment line prefix (`///` or `//!`) and any additional indent (before or after the doc
98+
LL| |// comment characters). This test produces `llvm-cov show` results demonstrating the problem.
99+
LL| |//
100+
LL| |// One of the above tests now includes: `derive(Debug, PartialEq)`, producing an `llvm-cov show`
101+
LL| |// result with a distinct count for `Debug`, denoted by `^1`, but the caret points to the wrong
102+
LL| |// column. Similarly, the `if` blocks without `else` blocks show `^0`, which should point at, or
103+
LL| |// one character past, the `if` block's closing brace. In both cases, these are most likely off
104+
LL| |// by the number of characters stripped from the beginning of each doc comment line: indent
105+
LL| |// whitespace, if any, doc comment prefix (`//!` in this case) and (I assume) one space character
106+
LL| |// (?). Note, when viewing `llvm-cov show` results in `--color` mode, the column offset errors are
107+
LL| |// more pronounced, and show up in more places, with background color used to show some distinct
108+
LL| |// code regions with different coverage counts.
109+
LL| |//
110+
LL| |// NOTE: Since the doc comment line prefix may vary, one possible solution is to replace each
111+
LL| |// character stripped from the beginning of doc comment lines with a space. This will give coverage
112+
LL| |// results the correct column offsets, and I think it should compile correctly, but I don't know
113+
LL| |// what affect it might have on diagnostic messages from the compiler, and whether anyone would care
114+
LL| |// if the indentation changed. I don't know if there is a more viable solution.
115115

tests/run-coverage/abort.coverage

+66-66
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,69 @@
1-
1| |#![feature(c_unwind)]
2-
2| |#![allow(unused_assignments)]
3-
3| |
4-
4| 12|extern "C" fn might_abort(should_abort: bool) {
5-
5| 12| if should_abort {
6-
6| 0| println!("aborting...");
7-
7| 0| panic!("panics and aborts");
8-
8| 12| } else {
9-
9| 12| println!("Don't Panic");
10-
10| 12| }
11-
11| 12|}
12-
12| |
13-
13| 1|fn main() -> Result<(), u8> {
14-
14| 1| let mut countdown = 10;
15-
15| 11| while countdown > 0 {
16-
16| 10| if countdown < 5 {
17-
17| 4| might_abort(false);
18-
18| 6| }
19-
19| | // See discussion (below the `Notes` section) on coverage results for the closing brace.
20-
20| 10| if countdown < 5 { might_abort(false); } // Counts for different regions on one line.
1+
LL| |#![feature(c_unwind)]
2+
LL| |#![allow(unused_assignments)]
3+
LL| |
4+
LL| 12|extern "C" fn might_abort(should_abort: bool) {
5+
LL| 12| if should_abort {
6+
LL| 0| println!("aborting...");
7+
LL| 0| panic!("panics and aborts");
8+
LL| 12| } else {
9+
LL| 12| println!("Don't Panic");
10+
LL| 12| }
11+
LL| 12|}
12+
LL| |
13+
LL| 1|fn main() -> Result<(), u8> {
14+
LL| 1| let mut countdown = 10;
15+
LL| 11| while countdown > 0 {
16+
LL| 10| if countdown < 5 {
17+
LL| 4| might_abort(false);
18+
LL| 6| }
19+
LL| | // See discussion (below the `Notes` section) on coverage results for the closing brace.
20+
LL| 10| if countdown < 5 { might_abort(false); } // Counts for different regions on one line.
2121
^4 ^6
22-
21| | // For the following example, the closing brace is the last character on the line.
23-
22| | // This shows the character after the closing brace is highlighted, even if that next
24-
23| | // character is a newline.
25-
24| 10| if countdown < 5 { might_abort(false); }
22+
LL| | // For the following example, the closing brace is the last character on the line.
23+
LL| | // This shows the character after the closing brace is highlighted, even if that next
24+
LL| | // character is a newline.
25+
LL| 10| if countdown < 5 { might_abort(false); }
2626
^4 ^6
27-
25| 10| countdown -= 1;
28-
26| | }
29-
27| 1| Ok(())
30-
28| 1|}
31-
29| |
32-
30| |// Notes:
33-
31| |// 1. Compare this program and its coverage results to those of the similar tests
34-
32| |// `panic_unwind.rs` and `try_error_result.rs`.
35-
33| |// 2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`.
36-
34| |// 3. The test does not invoke the abort. By executing to a successful completion, the coverage
37-
35| |// results show where the program did and did not execute.
38-
36| |// 4. If the program actually aborted, the coverage counters would not be saved (which "works as
39-
37| |// intended"). Coverage results would show no executed coverage regions.
40-
38| |// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status
41-
39| |// (on Linux at least).
42-
40| |
43-
41| |/*
44-
42| |
45-
43| |Expect the following coverage results:
46-
44| |
47-
45| |```text
48-
46| | 16| 11| while countdown > 0 {
49-
47| | 17| 10| if countdown < 5 {
50-
48| | 18| 4| might_abort(false);
51-
49| | 19| 6| }
52-
50| |```
53-
51| |
54-
52| |This is actually correct.
55-
53| |
56-
54| |The condition `countdown < 5` executed 10 times (10 loop iterations).
57-
55| |
58-
56| |It evaluated to `true` 4 times, and executed the `might_abort()` call.
59-
57| |
60-
58| |It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit
61-
59| |`else`, the coverage implementation injects a counter, at the character immediately after the `if`s
62-
60| |closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the
63-
61| |non-true condition.
64-
62| |
65-
63| |As another example of why this is important, say the condition was `countdown < 50`, which is always
66-
64| |`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called.
67-
65| |The closing brace would have a count of `0`, highlighting the missed coverage.
68-
66| |*/
27+
LL| 10| countdown -= 1;
28+
LL| | }
29+
LL| 1| Ok(())
30+
LL| 1|}
31+
LL| |
32+
LL| |// Notes:
33+
LL| |// 1. Compare this program and its coverage results to those of the similar tests
34+
LL| |// `panic_unwind.rs` and `try_error_result.rs`.
35+
LL| |// 2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`.
36+
LL| |// 3. The test does not invoke the abort. By executing to a successful completion, the coverage
37+
LL| |// results show where the program did and did not execute.
38+
LL| |// 4. If the program actually aborted, the coverage counters would not be saved (which "works as
39+
LL| |// intended"). Coverage results would show no executed coverage regions.
40+
LL| |// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status
41+
LL| |// (on Linux at least).
42+
LL| |
43+
LL| |/*
44+
LL| |
45+
LL| |Expect the following coverage results:
46+
LL| |
47+
LL| |```text
48+
LL| | 16| 11| while countdown > 0 {
49+
LL| | 17| 10| if countdown < 5 {
50+
LL| | 18| 4| might_abort(false);
51+
LL| | 19| 6| }
52+
LL| |```
53+
LL| |
54+
LL| |This is actually correct.
55+
LL| |
56+
LL| |The condition `countdown < 5` executed 10 times (10 loop iterations).
57+
LL| |
58+
LL| |It evaluated to `true` 4 times, and executed the `might_abort()` call.
59+
LL| |
60+
LL| |It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit
61+
LL| |`else`, the coverage implementation injects a counter, at the character immediately after the `if`s
62+
LL| |closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the
63+
LL| |non-true condition.
64+
LL| |
65+
LL| |As another example of why this is important, say the condition was `countdown < 50`, which is always
66+
LL| |`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called.
67+
LL| |The closing brace would have a count of `0`, highlighting the missed coverage.
68+
LL| |*/
6969

0 commit comments

Comments
 (0)