LCOV разветвляется в конце функции

Какие ветви в конце этой функции. Как я мог их покрыть?

3 ответа

Решение

Вы наблюдаете сгенерированный gcc код для уничтожения статических (глобальных) переменных продолжительности хранения.

Ваше покрытие показывает, что функция foo был введен три раза, однако счетчик в конце области показывает, что код был выполнен восемь раз, включая ветви, о которых вы спрашиваете.

Теперь вы должны учесть, что компилятор помещает заголовочный файл в модуль перевода и что gcov не видит ваш код в точности так, как он есть, а скорее как граф управляющего потока инструкции по сборке с ветвлением в качестве краев графа.

Таким образом, "конец foo область "в выводе hcml lcov на самом деле не конец foo объем метода, а скорее все, что включено после foo а также во всем модуле перевода, включая уничтожение глобальных переменных, которые были объявлены в заголовочном файле.

Сам заголовок не был включен в вопрос, но даже самый основной __static_initialization_and_destruction сборка, которую генерирует gcc, включает несколько веток.

Обратите внимание, что вы можете включить глобальные переменные или нет - 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

У меня была такая же проблема с концевыми скобками, которые не были включены в пустую функцию;

Я нашел два обходных пути:

  • сначала добавьте конечную скобку к последней строке вызова функции, чтобы они не отображались как отдельная строка

  • второе и лучшее: добавить случайный "возврат"; в конце функции для принудительного выполнения кода

Как супер упрощенный ответ, ветви обозначают ветку 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) новых ветви для покрытия. Два вложенных, родительский вложенный и скрытый другой.

В общем, имейте в виду покрытие веток, это о покрытии условных высказываний.

Другие вопросы по тегам