Skip to content

Source-code based coverage is failing to identify some executable lines #83985

Closed
@wpbrown

Description

@wpbrown

I tried to generate test code coverage with this source file using -Zinstrument-coverage and the LLVM tools.

Source File:
https://github.com/wpbrown/rust-codecov/blob/main/codecovsample/src/main.rs

I expected to see this happen: 76% line coverage

Instead, this happened: 83% line coverage.

cargo-kcov, -Zprofile+grcov, and tarpaulin agree on 76%.

In the output below lines 65-67, 116-118, 163-165 were not executable but should have been executable+uncovered. Line 169-170 should be executable+covered.

coverage output

#![allow(dead_code)]#![allow(dead_code)]
    2|       |
    3|       |use async_trait::async_trait;
    4|       |
    5|      1|fn main() {
    6|      1|    println!("codecovsample::main");
    7|      1|}
    8|       |
    9|       |enum Covered {
   10|       |    Variant1,
   11|       |    Variant2,
   12|       |}
   13|       |enum Uncovered {
   14|       |    Variant1,
   15|       |    Variant2,
   16|       |}
   17|       |enum PartiallyCovered {
   18|       |    Variant1,
   19|       |    Variant2,
   20|       |}
   21|       |
   22|      2|fn fn_covered_enum(input: Covered) {
   23|      2|    match input {
   24|      2|        Covered::Variant1 => { println!("Variant1"); }
                                           ^1
   25|      1|        Covered::Variant2 => { println!("Variant2"); }
   26|       |    }
   27|      2|}
   28|       |
   29|      0|fn fn_uncovered_enum(input: Uncovered) {
   30|      0|    match input {
   31|      0|        Uncovered::Variant1 => { println!("Variant1"); }
   32|      0|        Uncovered::Variant2 => { println!("Variant2"); }
   33|       |    }
   34|      0|}
   35|       |
   36|      1|fn fn_partially_covered_enum(input: PartiallyCovered) {
   37|      1|    match input {
   38|      1|        PartiallyCovered::Variant1 => { println!("Variant1"); }
   39|      0|        PartiallyCovered::Variant2 => { println!("Variant2"); }
   40|       |    }
   41|      1|}
   42|       |
   43|       |trait ATrait {
   44|       |    fn covered(&self);
   45|       |    fn uncovered(&self);
   46|       |    fn func_covered();    
   47|       |    fn func_uncovered();
   48|       |
   49|      2|    fn default_covered(&self) {
   50|      2|        println!("default_covered");
   51|      2|    }
  ------------------
  | <codecovsample::ATraitImplDirect as codecovsample::ATrait>::default_covered:
  |   49|      1|    fn default_covered(&self) {
  |   50|      1|        println!("default_covered");
  |   51|      1|    }
  ------------------
  | <codecovsample::ATraitImplGeneric as codecovsample::ATrait>::default_covered:
  |   49|      1|    fn default_covered(&self) {
  |   50|      1|        println!("default_covered");
  |   51|      1|    }
  ------------------
   52|       |    
   53|      0|    fn default_uncovered(&self) {
   54|      0|        println!("default_uncovered");
   55|      0|    }
   56|       |}
   57|       |trait BTrait {
   58|       |    fn covered(&self);
   59|       |    fn uncovered(&self);
   60|       |
   61|      1|    fn default_covered(&self) {
   62|      1|        println!("default_covered");
   63|      1|    }
   64|       |    
   65|       |    fn default_uncovered(&self) {
   66|       |        println!("default_uncovered");
   67|       |    }
   68|       |}
   69|       |
   70|       |struct ATraitImplDirect;
   71|       |
   72|       |impl ATrait for ATraitImplDirect {
   73|      1|    fn covered(&self) {
   74|      1|        println!("covered")
   75|      1|    }
   76|       |
   77|      0|    fn uncovered(&self) {
   78|      0|        println!("uncovered");
   79|      0|    }
   80|       |
   81|      1|    fn func_covered() {
   82|      1|        println!("func_covered");
   83|      1|    }
   84|       |
   85|      0|    fn func_uncovered() {
   86|      0|        println!("func_covered");
   87|      0|    }
   88|       |}
   89|       |
   90|       |struct ATraitImplGeneric;
   91|       |
   92|       |impl ATrait for ATraitImplGeneric {
   93|      1|    fn covered(&self) {
   94|      1|        println!("covered")
   95|      1|    }
   96|       |
   97|      0|    fn uncovered(&self) {
   98|      0|        println!("uncovered");
   99|      0|    }
  100|       |
  101|      1|    fn func_covered() {
  102|      1|        println!("func_covered");
  103|      1|    }
  104|       |
  105|      0|    fn func_uncovered() {
  106|      0|        println!("func_covered");
  107|      0|    }
  108|       |}
  109|       |struct BTraitImplBoxed;
  110|       |
  111|       |impl BTrait for BTraitImplBoxed {
  112|      1|    fn covered(&self) {
  113|      1|        println!("covered")
  114|      1|    }
  115|       |
  116|       |    fn uncovered(&self) {
  117|       |        println!("uncovered");
  118|       |    }
  119|       |}
  120|       |
  121|       |macro_rules! simple_rule {
  122|       |    () => {
  123|       |        println!("simple rule");
  124|       |    };
  125|       |}
  126|       |
  127|      1|fn call_simple_rule() {
  128|      1|    simple_rule!();
  129|      1|}
  130|       |
  131|      1|fn call_generic_atrait<T: ATrait>(input: T) {
  132|      1|    input.covered();
  133|      1|    input.default_covered();
  134|      1|    T::func_covered();
  135|      1|}
  136|       |
  137|      1|async fn async_func() {
  138|       |    println!("async_func");
  139|       |}
  140|       |
  141|      1|async fn async_func_anon() {
  142|      1|    let x = async {
  143|      1|        println!("async_func");
  144|      1|    };
  145|      1|    x.await;
  146|      1|}
  147|       |
  148|       |#[async_trait]
  149|       |trait AsyncTrait {
  150|       |    async fn covered(&self);
  151|       |    async fn uncovered(&self);
  152|       |}
  153|       |
  154|       |struct AsyncTraitImpl;
  155|       |
  156|       |#[async_trait]
  157|       |impl AsyncTrait for AsyncTraitImpl {
  158|      1|    async fn covered(&self) {
  159|      1|        println!("covered");
  160|      1|        async_func_from_trait_covered().await;
  161|      1|    }
  162|       |
  163|       |    async fn uncovered(&self) {
  164|       |        println!("uncovered");
  165|       |    }
  166|       |}
  167|       |
  168|      1|async fn async_func_from_trait_covered() {
  169|       |    println!("covered async func from trait");
  170|       |}
  171|       |
  172|       |#[cfg(test)]
  173|       |mod tests {
  174|       |    use futures::executor::block_on;
  175|       |
  176|       |    use super::*;
  177|       |
  178|       |    #[test]
  179|      1|    fn test_main() {
  ------------------
  | codecovsample::tests::test_main::{closure#0}:
  |  179|      1|    fn test_main() {
  ------------------
  180|      1|        main();
  181|      1|    }
  ------------------
  | codecovsample::tests::test_main:
  |  179|      1|    fn test_main() {
  |  180|      1|        main();
  |  181|      1|    }
  ------------------
  182|       |
  183|       |    #[test]
  184|      1|    fn cover_enum() {
  ------------------
  | codecovsample::tests::cover_enum::{closure#0}:
  |  184|      1|    fn cover_enum() {
  ------------------
  185|      1|        fn_covered_enum(Covered::Variant1);
  186|      1|        fn_covered_enum(Covered::Variant2);
  187|      1|    }
  ------------------
  | codecovsample::tests::cover_enum:
  |  184|      1|    fn cover_enum() {
  |  185|      1|        fn_covered_enum(Covered::Variant1);
  |  186|      1|        fn_covered_enum(Covered::Variant2);
  |  187|      1|    }
  ------------------
  188|       |
  189|       |    #[test]
  190|      1|    fn partially_cover_enum() {
  ------------------
  | codecovsample::tests::partially_cover_enum::{closure#0}:
  |  190|      1|    fn partially_cover_enum() {
  ------------------
  191|      1|        fn_partially_covered_enum(PartiallyCovered::Variant1);
  192|      1|    }
  ------------------
  | codecovsample::tests::partially_cover_enum:
  |  190|      1|    fn partially_cover_enum() {
  |  191|      1|        fn_partially_covered_enum(PartiallyCovered::Variant1);
  |  192|      1|    }
  ------------------
  193|       |
  194|       |    #[test]
  195|      1|    fn cover_atrait_direct() {
  ------------------
  | codecovsample::tests::cover_atrait_direct::{closure#0}:
  |  195|      1|    fn cover_atrait_direct() {
  ------------------
  196|      1|        let x = ATraitImplDirect;
  197|      1|        x.covered();
  198|      1|        x.default_covered();
  199|      1|        <ATraitImplDirect as ATrait>::func_covered();
  200|      1|    }
  ------------------
  | codecovsample::tests::cover_atrait_direct:
  |  195|      1|    fn cover_atrait_direct() {
  |  196|      1|        let x = ATraitImplDirect;
  |  197|      1|        x.covered();
  |  198|      1|        x.default_covered();
  |  199|      1|        <ATraitImplDirect as ATrait>::func_covered();
  |  200|      1|    }
  ------------------
  201|       |    #[test]
  202|      1|    fn cover_atrait_boxed() {
  ------------------
  | codecovsample::tests::cover_atrait_boxed::{closure#0}:
  |  202|      1|    fn cover_atrait_boxed() {
  ------------------
  203|      1|        let x: Box<dyn BTrait> = Box::new(BTraitImplBoxed);
  204|      1|        x.covered();
  205|      1|        x.default_covered();
  206|      1|    }
  ------------------
  | codecovsample::tests::cover_atrait_boxed:
  |  202|      1|    fn cover_atrait_boxed() {
  |  203|      1|        let x: Box<dyn BTrait> = Box::new(BTraitImplBoxed);
  |  204|      1|        x.covered();
  |  205|      1|        x.default_covered();
  |  206|      1|    }
  ------------------
  207|       |
  208|       |    #[test]
  209|      1|    fn cover_simple_rule() {
  ------------------
  | codecovsample::tests::cover_simple_rule::{closure#0}:
  |  209|      1|    fn cover_simple_rule() {
  ------------------
  210|      1|        call_simple_rule();
  211|      1|    }
  ------------------
  | codecovsample::tests::cover_simple_rule:
  |  209|      1|    fn cover_simple_rule() {
  |  210|      1|        call_simple_rule();
  |  211|      1|    }
  ------------------
  212|       |
  213|       |    #[test]
  214|      1|    fn cover_generic_atrait() {
  ------------------
  | codecovsample::tests::cover_generic_atrait::{closure#0}:
  |  214|      1|    fn cover_generic_atrait() {
  ------------------
  215|      1|        let x = ATraitImplGeneric;
  216|      1|        call_generic_atrait(x);
  217|      1|    }
  ------------------
  | codecovsample::tests::cover_generic_atrait:
  |  214|      1|    fn cover_generic_atrait() {
  |  215|      1|        let x = ATraitImplGeneric;
  |  216|      1|        call_generic_atrait(x);
  |  217|      1|    }
  ------------------
  218|       |
  219|       |    #[test]
  220|      1|    fn cover_async_funcs() {
  ------------------
  | codecovsample::tests::cover_async_funcs::{closure#0}:
  |  220|      1|    fn cover_async_funcs() {
  ------------------
  221|      1|        block_on(async {
  222|      1|            async_func().await;
  223|      1|            async_func_anon().await;
  224|      1|        });
  225|      1|    }
  ------------------
  | codecovsample::tests::cover_async_funcs:
  |  220|      1|    fn cover_async_funcs() {
  |  221|      1|        block_on(async {
  |  222|       |            async_func().await;
  |  223|       |            async_func_anon().await;
  |  224|      1|        });
  |  225|      1|    }
  ------------------
  226|       |
  227|       |    #[test]
  228|      1|    fn cover_async_trait() {
  ------------------
  | codecovsample::tests::cover_async_trait::{closure#0}:
  |  228|      1|    fn cover_async_trait() {
  ------------------
  229|      1|        block_on(async {
  230|      1|            let x: Box<dyn AsyncTrait> = Box::new(AsyncTraitImpl);
  231|      1|            x.covered().await;
  232|      1|        });
  233|      1|    }
  ------------------
  | codecovsample::tests::cover_async_trait:
  |  228|      1|    fn cover_async_trait() {
  |  229|      1|        block_on(async {
  |  230|       |            let x: Box<dyn AsyncTrait> = Box::new(AsyncTraitImpl);
  |  231|       |            x.covered().await;
  |  232|      1|        });
  |  233|      1|    }
  ------------------
  234|       |}


Meta

rustc --version --verbose:

rustc 1.53.0-nightly (07e0e2ec2 2021-03-24)
binary: rustc
commit-hash: 07e0e2ec268c140e607e1ac7f49f145612d0f597
commit-date: 2021-03-24
host: x86_64-unknown-linux-gnu
release: 1.53.0-nightly
LLVM version: 12.0.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-code-coverageArea: Source-based code coverage (-Cinstrument-coverage)C-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions