查找未执行的c ++代码行 [英] Find unexecuted lines of c++ code

查看:162
本文介绍了查找未执行的c ++代码行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为我的单元测试的一部分,我想确保测试的代码覆盖率。目的是在代码中某处放置类似 REQUIRE_TEST 的宏,并检查是否所有这些都被调用。

  void foo(bool b){
if(b){
REQUIRE_TEST
...
} else {
REQUIRE_TEST
...
}
}

void main(){
foo(true);

output_all_missed_REQUIRE_macros();
}

理想情况下,输出将包括源文件和宏的行。 p>

我最初的想法是让宏创建静态对象,在一些地图中注册自己,然后检查是否所有这些都被调用

  #define REQUIRE_TEST \ 
do {\
static ___RequiredTest requiredTest(__ func__,__FILE__,__LINE __); \
)requiredTest; \
___ RequiredTest :: increaseCounter(__ func__,__FILE__,__LINE __); \
} while(false)

但静态对象只有在第一次调用代码时才会创建。因此,映射仅包含也在下一行中计数的函数 - 找不到缺少REQUIRE_TEST宏。在这种情况下,将忽略 __ attribute __((used))



gcc有一个不错的属性 __ attribute __((constructor)),但显然选择忽略它放置在这里(下面的代码,而不是静态对象)

  struct teststruct {\ 
__attribute __((constructor))static void bla(){\
___ RequiredTest :: register(__ func__,__FILE__,__LINE__); \
} \
}; \

  []()__attribute __((constructor)){\ 
___ RequiredTest :: register(__ func__,__FILE__, __线__); \
}; \

我现在想到的唯一出路是)手动(或通过脚本)分析正常编译之外的代码(uargh)或b)使用 __ COUNTER __ 宏来计算宏 - 但是我不知道特定的REQUIRE_TEST宏未被调用...(如果有人决定使用 __ COUNTER __ 宏,则一切都会中断...)


这个问题有没有可行的解决方案?我缺少什么?它
将是很好的有一个宏追加当前行和文件
所以一些预处理器变量每当它被调用 - 但是不是
可能,对吧?有没有其他方法可以在 main()之前执行
,这可以在函数体内完成?



解决方案

如何:

  #include< iostream> 

static size_t cover(){return 1; }

#define COV()do {static size_t cov [2] __attribute __((section(cov)))= {__LINE__,cover } while(0)

static void dump_cov()
{
extern size_t __start_cov,__stop_cov;

for(size_t * p =& __ start_cov; p<& __ stop_cov; p + = 2)
{
std :: cout< p [0]<< :<< p [1]<< \\\
;
}
}

int main(int argc,char * argv [])
{
COV();

if(argc> 1)
COV();

if(argc> 2)
COV();

dump_cov();
return 0;
}

结果:

  $ ./cov_test 
19:1
22:0
25:0

和:

  $ ./cov_test x 
:1
22:1
25:0

和:

  $ ./cov_test xy 
19:1
22:1
25:1

基本上,我们在命名的内存段中设置了一个coverage数组(显然我们使用了GCC特定的机制



我们依赖于在启动时执行的本地静态的常量初始化 - 这将获取行号到覆盖范围数组中覆盖标志设置通过在语句的第一次执行时执行 cover()的函数调用,将覆盖标志设置为1,以便执行初始化。我不是100%肯定所有这一切是由标准保证,也不是通过哪个版本的标准(我编译的 - std = c ++ 11 )。 / p>

最后,使用-O3构建也会产生正确的结果(虽然以不同的顺序分配):

  $ ./a 
25:0
22:0
19:1

和:

  $ ./ax 
25:0
22:1
19:1

  $ ./axy 
25:1
22:1
19:1


As part of my unit testing I want to ensure code coverage of the tests. The aim is to place something like REQUIRE_TEST macros somewhere in the code and check whether all of these were called.

void foo(bool b) {
  if (b) {
    REQUIRE_TEST
    ...
  } else {
    REQUIRE_TEST
    ...
  }
}

void main() {
  foo(true);

  output_all_missed_REQUIRE_macros();
}

Ideally the output would include source-file and line of the macro.

My initial idea was to have the macros create static objects that would register themselves in some map and later check whether all of these were called

#define REQUIRE_TEST \
        do { \
            static ___RequiredTest requiredTest(__func__, __FILE__, __LINE__);\
            (void)requiredTest;\
            ___RequiredTest::increaseCounter(__func__, __FILE__, __LINE__);\
        } while(false)

but the static object are only created when the code is called the first time. So the map only contains functions that are also counted in the next line - missing REQUIRE_TEST macros are not found. the __attribute__((used)) is ignored in this case.

The gcc has a nice attribute __attribute__((constructor)), but apparently chooses to ignore it when placed here (following code instead of the static object)

struct teststruct { \
  __attribute__((constructor)) static void bla() {\
    ___RequiredTest::register(__func__, __FILE__, __LINE__); \
  } \
};\

as well as for

[]() __attribute__((constructor)) { \
  ___RequiredTest::register(__func__, __FILE__, __LINE__); \
};\

The only way out I can think of now is a) manually (or via script) analyse the code outside of the regular compilation (uargh) or b) use the __COUNTER__ macro to count the macros - but then I would not know which specific REQUIRE_TEST macros were not called... (and everything breaks if somebody else decides to use the __COUNTER__ macro as well...)

Are there any decent solutions to this problem? What am I missing? It would be nice to have a macro that appends the current line and file so some preprocessor variable whenever it is called - but that is not possible, right? Are there any other ways to register something to be executed before main() that can be done within a function body?

解决方案

How about this:

#include <iostream>

static size_t cover() { return 1; }

#define COV() do { static size_t cov[2] __attribute__((section("cov"))) = { __LINE__, cover() }; } while(0)

static void dump_cov()
{
        extern size_t __start_cov, __stop_cov;

        for (size_t* p = &__start_cov; p < &__stop_cov; p += 2)
        {
                std::cout << p[0] << ": " << p[1] << "\n";
        }
}

int main(int argc, char* argv[])
{
        COV();

        if (argc > 1)
                COV();

        if (argc > 2)
                COV();

        dump_cov();
        return 0;
}

Results:

$ ./cov_test
19: 1
22: 0
25: 0

and:

$ ./cov_test x
19: 1
22: 1
25: 0

and:

$ ./cov_test x y
19: 1
22: 1
25: 1

Basically, we set up a coverage array in a named memory section (obviously we've used GCC-specific mechanisms for this), which we dump after execution.

We rely on constant initialisation of local statics being performed at startup - which gets the line numbers into the coverage array with coverage flag set to zero - and on initialisation via the function call to cover() being performed at first execution of the statement, which sets the coverage flags to 1 for executed lines. I'm not 100% sure all this is guaranteed by the standard, nor by which versions of the standard (I compiled with --std=c++11).

Finally, building with '-O3' also produces correct results (albeit allocated in a different order):

$ ./a
25: 0
22: 0
19: 1

and:

$ ./a x
25: 0
22: 1
19: 1

and

$ ./a x y
25: 1
22: 1
19: 1

这篇关于查找未执行的c ++代码行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆