Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MC/DC support to coverage test tools #123626

Merged
merged 2 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,19 @@ impl<'test> TestCx<'test> {
Lazy::new(|| Regex::new(r"(?m:^)(?<prefix>(?: \|)+ Branch \()[0-9]+:").unwrap());
let coverage = BRANCH_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:");

// ` |---> MC/DC Decision Region (1:30) to (2:` => ` |---> MC/DC Decision Region (LL:30) to (LL:`
static MCDC_DECISION_LINE_NUMBER_RE: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"(?m:^)(?<prefix>(?: \|)+---> MC/DC Decision Region \()[0-9]+:(?<middle>[0-9]+\) to \()[0-9]+:").unwrap()
});
let coverage =
MCDC_DECISION_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:${middle}LL:");

// ` | Condition C1 --> (1:` => ` | Condition C1 --> (LL:`
static MCDC_CONDITION_LINE_NUMBER_RE: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"(?m:^)(?<prefix>(?: \|)+ Condition C[0-9]+ --> \()[0-9]+:").unwrap()
});
let coverage = MCDC_CONDITION_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:");

coverage.into_owned()
}

Expand Down
100 changes: 48 additions & 52 deletions src/tools/compiletest/src/runtest/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,72 +50,68 @@ fn normalize_platform_differences() {
}

/// Test for anonymizing line numbers in coverage reports, especially for
/// branch regions.
/// MC/DC regions.
///
/// FIXME(#119681): This test can be removed when we have examples of branch
/// FIXME(#123409): This test can be removed when we have examples of MC/DC
/// coverage in the actual coverage test suite.
#[test]
fn anonymize_coverage_line_numbers() {
let anon = |coverage| TestCx::anonymize_coverage_line_numbers(coverage);

let input = r#"
6| 3|fn print_size<T>() {
7| 3| if std::mem::size_of::<T>() > 4 {
7| 2|fn mcdc_check_neither(a: bool, b: bool) {
8| 2| if a && b {
^0
------------------
| Branch (7:8): [True: 0, False: 1]
| Branch (7:8): [True: 0, False: 1]
| Branch (7:8): [True: 1, False: 0]
|---> MC/DC Decision Region (8:8) to (8:14)
|
| Number of Conditions: 2
| Condition C1 --> (8:8)
| Condition C2 --> (8:13)
|
| Executed MC/DC Test Vectors:
|
| C1, C2 Result
| 1 { F, - = F }
|
| C1-Pair: not covered
| C2-Pair: not covered
| MC/DC Coverage for Decision: 0.00%
|
------------------
8| 1| println!("size > 4");
9| 0| say("a and b");
10| 2| } else {
11| 2| say("not both");
12| 2| }
13| 2|}
"#;

let expected = r#"
LL| 3|fn print_size<T>() {
LL| 3| if std::mem::size_of::<T>() > 4 {
LL| 2|fn mcdc_check_neither(a: bool, b: bool) {
LL| 2| if a && b {
^0
------------------
| Branch (LL:8): [True: 0, False: 1]
| Branch (LL:8): [True: 0, False: 1]
| Branch (LL:8): [True: 1, False: 0]
------------------
LL| 1| println!("size > 4");
"#;

assert_eq!(anon(input), expected);

//////////

let input = r#"
12| 3|}
------------------
| branch_generics::print_size::<()>:
| 6| 1|fn print_size<T>() {
| 7| 1| if std::mem::size_of::<T>() > 4 {
| ------------------
| | Branch (7:8): [True: 0, False: 1]
| ------------------
| 8| 0| println!("size > 4");
| 9| 1| } else {
| 10| 1| println!("size <= 4");
| 11| 1| }
| 12| 1|}
------------------
"#;

let expected = r#"
LL| 3|}
------------------
| branch_generics::print_size::<()>:
| LL| 1|fn print_size<T>() {
| LL| 1| if std::mem::size_of::<T>() > 4 {
| ------------------
| | Branch (LL:8): [True: 0, False: 1]
| ------------------
| LL| 0| println!("size > 4");
| LL| 1| } else {
| LL| 1| println!("size <= 4");
| LL| 1| }
| LL| 1|}
|---> MC/DC Decision Region (LL:8) to (LL:14)
|
| Number of Conditions: 2
| Condition C1 --> (LL:8)
| Condition C2 --> (LL:13)
|
| Executed MC/DC Test Vectors:
|
| C1, C2 Result
| 1 { F, - = F }
|
| C1-Pair: not covered
| C2-Pair: not covered
| MC/DC Coverage for Decision: 0.00%
|
------------------
LL| 0| say("a and b");
LL| 2| } else {
LL| 2| say("not both");
LL| 2| }
LL| 2|}
"#;

assert_eq!(anon(input), expected);
Expand Down
46 changes: 44 additions & 2 deletions src/tools/coverage-dump/src/covfun.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ pub(crate) fn dump_covfun_mappings(
}
// If the mapping is a branch region, print both of its arms
// in resolved form (even if they aren't expressions).
MappingKind::Branch { r#true, r#false } => {
MappingKind::Branch { r#true, r#false }
| MappingKind::MCDCBranch { r#true, r#false, .. } => {
println!(" true = {}", expression_resolver.format_term(r#true));
println!(" false = {}", expression_resolver.format_term(r#false));
}
Expand Down Expand Up @@ -164,6 +165,26 @@ impl<'a> Parser<'a> {
let r#false = self.read_simple_term()?;
Ok(MappingKind::Branch { r#true, r#false })
}
5 => {
let bitmap_idx = self.read_uleb128_u32()?;
let conditions_num = self.read_uleb128_u32()?;
Ok(MappingKind::MCDCDecision { bitmap_idx, conditions_num })
}
6 => {
let r#true = self.read_simple_term()?;
let r#false = self.read_simple_term()?;
let condition_id = self.read_uleb128_u32()?;
let true_next_id = self.read_uleb128_u32()?;
let false_next_id = self.read_uleb128_u32()?;
Ok(MappingKind::MCDCBranch {
r#true,
r#false,
condition_id,
true_next_id,
false_next_id,
})
}

_ => Err(anyhow!("unknown mapping kind: {raw_mapping_kind:#x}")),
}
}
Expand Down Expand Up @@ -224,7 +245,28 @@ enum MappingKind {
// Using raw identifiers here makes the dump output a little bit nicer
// (via the derived Debug), at the expense of making this tool's source
// code a little bit uglier.
Branch { r#true: CovTerm, r#false: CovTerm },
Branch {
r#true: CovTerm,
r#false: CovTerm,
},
MCDCBranch {
r#true: CovTerm,
r#false: CovTerm,
// These attributes are printed in Debug but not used directly.
#[allow(dead_code)]
condition_id: u32,
#[allow(dead_code)]
true_next_id: u32,
#[allow(dead_code)]
false_next_id: u32,
},
MCDCDecision {
// These attributes are printed in Debug but not used directly.
#[allow(dead_code)]
bitmap_idx: u32,
#[allow(dead_code)]
conditions_num: u32,
},
}

struct MappingRegion {
Expand Down
Loading