【问题标题】:LCOV branches at the end of a functionLCOV 在函数结束时分支
【发布时间】:2014-01-18 22:12:30
【问题描述】:

这个函数末尾的分支是什么。我怎么能覆盖它们?

【问题讨论】:

    标签: c++ gcov lcov


    【解决方案1】:

    作为超级简单的答案,分支表示IF/ELSE 分支。所以对于每一个 if/else 都有两个新的分支(应该被覆盖);如果嵌套,则呈指数增长。

    function twoNewBranches() {
      if () {
        // code
      } else {
        // code
      }
    }
    
    function twoNewBranchesNotAparent() {
      if () {
        // code
      }
    }
    
    function fourNewBranches() {
      if () {
        if () {
          // code
        } else {
          // code
        }
      }
    }
    

    • 第一个函数 twoNewBranches 创建了两个需要覆盖的新分支

    • 第二个函数 twoNewBranchesNotAparent 也创建了两个新分支,因为您仍然需要覆盖不满足 if 语句的测试

    • 第三个函数fourNewBranches 创建四个(2^2=4) 新分支来覆盖。两个嵌套,嵌套的父级和隐藏的else。

    总体记住覆盖分支,就是覆盖条件语句。

    【讨论】:

      【解决方案2】:

      我在 void 函数中没有覆盖的端括号也有同样的问题;

      我找到了两种解决方法:

      • 首先将 endbracket 添加到最后一个函数调用行,这样它们就不会显示为单独的行

      • 秒及更好:添加随机“return;”在函数末尾强制执行代码

      【讨论】:

        【解决方案3】:

        您正在观察 gcc 生成的代码,用于破坏静态存储持续时间(全局)变量。

        您的报道显示函数foo 已被输入了 3 次,但是范围末尾附近的计数器显示代码已执行了 8 次,包括您查询的分支。

        现在您必须考虑编译器将头文件放在翻译单元中,并且 gcov 不会完全按照原样看到您的代码,而是作为汇编指令的控制流图,分支作为图的边缘.

        因此,lcov html 输出中的“foo 范围的结尾”并不是真正的 foo 方法范围的结尾,而是包含在 foo 之后以及整个翻译单元中的所有内容,包括销毁已在头文件中声明的全局变量。

        标题本身没有包含在问题中,但即使是 gcc 生成的最基本的__static_initialization_and_destruction 程序集也包含许多分支。

        请注意,您可能已包含全局变量,也可能未包含 - gcc 仍可能为每个翻译单元生成此代码。


        查看gcov的底层输出:

        function _Z3fooi called 1 returned 100% blocks executed 50%
                1:    4:int foo(int x) {
                1:    5:    if (x==1) {
        branch  0 taken 0% (fallthrough)
        branch  1 taken 100%
            #####:    6:        std::cout << "foo" << std::endl;
        call    0 never executed
        call    1 never executed
            #####:    7:        return 0;
                -:    8:    }
                1:    9:    return 1;
        function _GLOBAL__sub_D__Z3fooi called 1 returned 100% blocks executed 100%
        function _GLOBAL__sub_I__Z3fooi called 1 returned 100% blocks executed 100%
        function _Z41__static_initialization_and_destruction_0ii called 2 returned 100% blocks executed 100%
                6:   10:}
        call    0 returned 100%
        call    1 returned 100%
        branch  2 taken 50% (fallthrough)
        branch  3 taken 50%
        branch  4 taken 100% (fallthrough)
        branch  5 taken 0%
                -:   11:
        

        并查看生成的程序集,修剪以阐明要点:

                ...
                ret
                .seh_endproc
                .def    _Z41__static_initialization_and_destruction_0ii;        .scl    3;      .type   32;     .endef
                .seh_proc       _Z41__static_initialization_and_destruction_0ii
        _Z41__static_initialization_and_destruction_0ii:
        .LFB978:
                ...
                mov     QWORD PTR __gcov0._Z41__static_initialization_and_destruction_0ii[rip], rax
                cmp     DWORD PTR 16[rbp], 1
                jne     .L5                                 <-- BRANCH
                mov     rax, QWORD PTR __gcov0._Z41__static_initialization_and_destruction_0ii[rip+8]
                add     rax, 1
                mov     QWORD PTR __gcov0._Z41__static_initialization_and_destruction_0ii[rip+8], rax
                cmp     DWORD PTR 24[rbp], 65535
                jne     .L5                                 <-- BRANCH
                ...
        .L5:
                cmp     DWORD PTR 16[rbp], 0
                je      .L6                                 <-- BRANCH
        

        【讨论】:

        • 有趣..那么有没有办法通过单元测试故意进入这些分支?
        • 我认为您不想人为地输入它们,最好将其从 lcov 覆盖范围中排除 - 在最后一个大括号上放置一个 LCOV_EXCL_LINE:} // LCOV_EXCL_LINE
        • 哇,LCOV 关键字真是天赐之物!谢谢。
        • @mockinterface delete 声明的情况是否相同?我得到了一个错过的分支,例如:136 [ + - ]: 45 : delete seq;
        猜你喜欢
        • 2017-05-20
        • 2014-01-21
        • 2012-09-03
        • 2013-05-16
        • 1970-01-01
        • 1970-01-01
        • 2015-10-18
        • 2017-06-19
        • 1970-01-01
        相关资源
        最近更新 更多