2017-04-19 15 views
1

googletest unit tests의 범위 분석을 위해 gcov/lcov를 사용하고 있습니다.일부 googletest 매크로의 범위 분석은 여러 줄에 걸쳐 퍼져있을 때 불완전한 적용 범위를 보여줍니다 - 이유는 무엇입니까?

반복되는 문제 중 하나는 매크로가 여러 줄에 걸쳐 퍼져있을 때 일부 googletest 매크로에 대해 테스트 코드에서 커버리지 된 줄이 표시된다는 것입니다.

나는 gov/lcov가 한 줄보다 정확할 수는 없다는 것을 알고 있지만, 내가 보는 행동에 당혹 스럽다. 누군가 이것을 설명 할 수 있습니까? 최소 예 :

g++-4.8 -Igtest/googletest/include/ --coverage -o coverage_macropp coverage_macropp.cpp gtest/googletest/make/gtest_main.a -pthread 
./coverage_macropp 
lcov --capture --directory . --output-file coverage.info 
genhtml --demangle-cpp coverage.info --output-directory coverage 

웹 브라우저의 범위 분석은 다음 라인 7, 9가 표시됩니다, 11로는 발견 :

#include <gtest/gtest.h> 

TEST(coverage,incomplete) 
{ 
    // Every second line in every invocation here will show up as uncovered: 
    EXPECT_NO_THROW(40 + 
        2); 
    EXPECT_NO_THROW(40 + 2 
       ); 
    EXPECT_NO_THROW(40 + 2) 
    ; 
} 

TEST(coverage,complete) 
{ 
    // This test does not show uncovered lines 
    EXPECT_NO_THROW(40 + 2); 
    EXPECT_EQ(40 
      + 
      2 
      , // even though this is spread over several lines 
      42 
      ) 
    ; 
} 

범위 분석을 시행 하였다 어떻게

 Line data Source code 

    1    : #include <gtest/gtest.h> 
    2    : 
    3   5 : TEST(coverage,incomplete) 
    4    : { 
    5    : // Every second line in every invocation here will show up as uncovered: 
    6   1 : EXPECT_NO_THROW(40 + 
    7   0 :     2); 
    8   1 : EXPECT_NO_THROW(40 + 2 
    9   0 :     ); 
    10   1 : EXPECT_NO_THROW(40 + 2) 
    11   0 :  ; 
    12   1 : } 
    13    : 
    14   5 : TEST(coverage,complete) 
    15    : { 
    16    : // This test does not show uncovered lines 
    17   1 : EXPECT_NO_THROW(40 + 2); 
    18   1 : EXPECT_EQ(40 
    19    :    + 
    20    :    2 
    21    :    , // even though this is spread over several lines 
    22    :    42 
    23    :   ) 
    24   1 :  ; 
    25   4 : } 

왜? 그리고 EXPECT_EQ 매크로가 영향을받지 않는 이유는 무엇입니까?

+0

gcov가 실제로 입력을 구문 분석하는 방법과 매크로 정의 방법 (예 : 토큰 붙여 넣기 여부)에 따라 달라집니다. 그래서 그것들은 설명을 찾을 두 곳입니다. – Peter

답변

1

이것은 매혹적인 조사였습니다. 이 매크로를 살펴보면 스위치/케이스와 goto에 대해 배웠습니다.

그러나 동작 차이의 원인은 else 분기가 결코 실행되지 않지만 컴파일러가 이미 알고 있는지 여부에 따라 다른 분기가 결코 실행되지 않는다는 점에서 공통점이있는 if/else 구문에서옵니다 .

첫째, 소스 코드에서 여러 줄에 걸쳐 매크로를 확산하는 것은 전처리 농산물을 가지고 (끝까지이 질문에 대한 문제로) 다음과 같은 컴파일러를위한 코드 커버리지 분석기 :

if (condition) statement1; else statement2 


    ; 

그리고 분명히을 , 커버리지 분석기 인 gcov는 코드 라인으로 외로운 세미콜론을 가진 라인을 센다. else 브랜치의 statement2가 실행될 때 실행된다고 간주한다.

이제

, 커버리지 분석의 차이를 재현하는 질문에서 관찰로,이 예제 프로그램을 고려해야합니다

#include <stdio.h> 
#include <time.h> 

int main(int, char*[]) { 
    const bool true_1 = true; 
    const bool true_2 = time(NULL) != 0; 

    if (true_1) 42; else printf("hello\n") 
        ; 
    if (true_2) 42; else printf("hello\n") 
        ; 
    return 0; 
} 

true_1true_2 내 생애에서 (항상 해당를, 나는 컴퓨터와 난장판을하지 않으면 '시계)이지만, true_1의 경우에는 컴파일러가 알고 있지만 true_2의 경우에는 알 수 없습니다. (예, true_2에 대한 더 안전한 초기화 프로그램을 찾을 수 있습니다. 지금 당장 할 것입니다.)

if 분기의 명령문은 아무 것도 수행하지 않지만 else 분기의 명령문은 부작용이 있습니다.

은이 프로그램의 gcov는/lcov 범위 분석은 다음과 같습니다 컴파일러는 이미 다른 지점 사실 true_1 것을 알고있다, 따라서, 라인 (9), 커버리지 분석을 위해 고려되지

 Line data Source code 

    1    : #include <stdio.h> 
    2    : #include <time.h> 
    3    : 
    4   1 : int main(int, char*[]) { 
    5   1 : const bool true_1 = true; 
    6   1 : const bool true_2 = time(NULL) != 0; 
    7    : 
    8    : if (true_1) 42; else printf("hello\n") 
    9    :      ; 
    10   1 : if (true_2) 42; else printf("hello\n") 
    11   0 :      ; 
    12   1 : return 0; 
    13    : } 

때문에 . -O0으로 컴파일 할 때도 마찬가지입니다.

그러나이 프로그램의 11 행은 true_2가 런타임에만 알려지기 때문에 적용 범위 분석으로 간주됩니다.

보조 참고 사항 : else 브랜치 또는 다른 부작용이없는 것으로 알려진 함수 호출 인 printf ("hello") 대신 sin (7)과 같은 다른 더미 문을 사용했다면 ,이 줄은 또한 gcov coverage 분석에 포함되지 않을 것입니다.

완전한 공식 커버리지를 위해 테스트 결과가 컴파일 타임에 이미 알려지지 않은 경우 googletest 매크로를 단일 소스 행으로 제한해야합니다.

+0

좋은 캐치! 그리고 아주 잘 공식화되었습니다. 나는 너 자신의 대답을 받아 들여야한다고 생각한다. – Jonas