about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2024-04-09 13:39:22 +0200
committerGitHub <noreply@github.com>2024-04-09 13:39:22 +0200
commitfb0aab19760a46a6e8ccfd635c8507ae4f562f7f (patch)
treefa2c2069d34fd36da9023432c2f5bc596bf8b7f8
parent1c5db28ec3b4ad20156a210046f19583db3d1cae (diff)
parent4b3538352dae7fed4097d92fd373f8de9d22229f (diff)
downloadrust-fb0aab19760a46a6e8ccfd635c8507ae4f562f7f.tar.gz
rust-fb0aab19760a46a6e8ccfd635c8507ae4f562f7f.zip
Rollup merge of #123626 - Zalathar:test-tools-mcdc, r=oli-obk
Add MC/DC support to coverage test tools

Extracted and squashed from #123409 by `@ZhuUx.`

These updates to the coverage test tools can land ahead of the main changes, slightly reducing the size and complexity of that PR.

---

The `coverage-dump` changes aren't directly tested in this PR, but the tests in #123409 demonstrate that they do work on real MC/DC coverage output.

`@rustbot` label +A-code-coverage
-rw-r--r--src/tools/compiletest/src/runtest.rs13
-rw-r--r--src/tools/compiletest/src/runtest/tests.rs100
-rw-r--r--src/tools/coverage-dump/src/covfun.rs46
3 files changed, 105 insertions, 54 deletions
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 770496289e2..327e34ea36b 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -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()
     }
 
diff --git a/src/tools/compiletest/src/runtest/tests.rs b/src/tools/compiletest/src/runtest/tests.rs
index ee42243e83d..817b56109a5 100644
--- a/src/tools/compiletest/src/runtest/tests.rs
+++ b/src/tools/compiletest/src/runtest/tests.rs
@@ -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);
diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs
index 49e3a6ed583..b308c8de14f 100644
--- a/src/tools/coverage-dump/src/covfun.rs
+++ b/src/tools/coverage-dump/src/covfun.rs
@@ -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));
                     }
@@ -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}")),
             }
         }
@@ -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 {